diff --git a/AUTHORS b/AUTHORS index a8d90ac..152cb09 100644 --- a/AUTHORS +++ b/AUTHORS
@@ -76,6 +76,7 @@ anatoly techtonik <techtonik@gmail.com> Ancil George <ancilgeorge@samsung.com> Andra Paraschiv <andra.paraschiv@intel.com> +Andreas Papacharalampous <andreas@apap04.com> Andrei Borza <andrei.borza@gmail.com> Andrei Parvu <andrei.prv@gmail.com> Andrei Parvu <parvu@adobe.com>
diff --git a/DEPS b/DEPS index dc3615d..534a1bc4 100644 --- a/DEPS +++ b/DEPS
@@ -175,11 +175,11 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and whatever else without interference from each other. - 'skia_revision': '6ec5688413840c42afaa72b3a38302e1716dce86', + 'skia_revision': 'b3f96cadd7058b25cd00642c69d7a544a3566528', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. - 'v8_revision': '5e04fbf91e5dad673d29a119904c1b068cdd7996', + 'v8_revision': '76649a7cd9701e25728fd36c96ef1203053b1e4d', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling swarming_client # and whatever else without interference from each other. @@ -187,11 +187,11 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ANGLE # and whatever else without interference from each other. - 'angle_revision': 'bf6b8d4a16ae13243fee8718e98c8658f4fab218', + 'angle_revision': 'f2bee3043a5e55189e775b07548779d2dd4061f9', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. - 'swiftshader_revision': 'cafff78f665b8a591d1f7d2d2cb00b64c8c24312', + 'swiftshader_revision': '02e15b249b12fe4e1ca5e303a5a0de0668950536', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. @@ -238,7 +238,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling catapult # and whatever else without interference from each other. - 'catapult_revision': 'a8bbccaabeff0b1a8fd0c4eaf9f32c5128776976', + 'catapult_revision': '438ea30dcc291b1305568a44bdf6e9922895d789', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other. @@ -246,7 +246,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling devtools-frontend # and whatever else without interference from each other. - 'devtools_frontend_revision': 'd25ae4048565a67dbc63bb91f6b00470f3039f58', + 'devtools_frontend_revision': '60a0e9defc41cc50316a04d743a262314be1026c', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libprotobuf-mutator # and whatever else without interference from each other. @@ -298,15 +298,15 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'shaderc_revision': '3d915b2802667f44a359463f1f420ac33576001b', + 'shaderc_revision': '9472e3eec08587a1c6616fd64d0d38553e9efd04', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'dawn_revision': '0847cb4637366d15efdb09c57d9b53ea720587fb', + 'dawn_revision': '4b1be08ec993dd8a858229abdfd33cb2ebb6a292', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'quiche_revision': '7379c493206bd0fb646cbaaa86b03617bb2fbbd9', + 'quiche_revision': '2542cb728f1119cfbabd91105cc5a3cc44e784a3', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ios_webkit # and whatever else without interference from each other. @@ -877,7 +877,7 @@ }, 'src/third_party/depot_tools': - Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '17aaea21d40dc178638a5e295541fbd8757811c1', + Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '0dd5482c5254e0457062aad7b93954918ced54fd', 'src/third_party/devtools-frontend/src': Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'), @@ -1211,7 +1211,7 @@ Var('chromium_git') + '/external/github.com/cisco/openh264' + '@' + '6f26bce0b1c4e8ce0e13332f7c0083788def5fdf', 'src/third_party/openscreen/src': - Var('chromium_git') + '/openscreen' + '@' + 'b172d257d938ca5bed0a2d62eb5420bcbe0672e9', + Var('chromium_git') + '/openscreen' + '@' + 'fbd8fd2ccff9d1f51b0dec379d18ab7f11bcd4bf', 'src/third_party/openxr/src': { 'url': Var('chromium_git') + '/external/github.com/KhronosGroup/OpenXR-SDK' + '@' + '9e97b73e7dd2bfc07745489d728f6a36665c648f', @@ -1228,7 +1228,7 @@ }, 'src/third_party/perfetto': - Var('android_git') + '/platform/external/perfetto.git' + '@' + '658779b63e6bb8170e7e9e064e86485124fa63c5', + Var('android_git') + '/platform/external/perfetto.git' + '@' + 'edcb5301a064b9a2901d257816b521266608ddf9', 'src/third_party/perl': { 'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3', @@ -1523,7 +1523,7 @@ Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'), 'src-internal': { - 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@6dca61aa30a9ffba2998e97031897d723bd28302', + 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@8c4f7654a023db9ebbe2a0c8c96db721e359b759', 'condition': 'checkout_src_internal', },
diff --git a/android_webview/browser/gfx/aw_draw_fn_impl.cc b/android_webview/browser/gfx/aw_draw_fn_impl.cc index c0a1bcbb..beb6789d 100644 --- a/android_webview/browser/gfx/aw_draw_fn_impl.cc +++ b/android_webview/browser/gfx/aw_draw_fn_impl.cc
@@ -16,6 +16,7 @@ #include "base/trace_event/trace_event.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" +#include "gpu/command_buffer/service/skia_utils.h" #include "gpu/ipc/common/android/android_image_reader_utils.h" #include "gpu/vulkan/vulkan_fence_helper.h" #include "gpu/vulkan/vulkan_function_pointers.h" @@ -478,14 +479,7 @@ return; } - // Create backend texture from the VkImage. - GrVkAlloc alloc(vulkan_image->device_memory(), 0 /* offset */, - vulkan_image->device_size(), 0 /* flags */); - pending_draw->image_info = GrVkImageInfo( - vulkan_image->image(), alloc, vulkan_image->image_tiling(), - VK_IMAGE_LAYOUT_UNDEFINED, vulkan_image->format(), 1 /* levelCount */, - VK_QUEUE_FAMILY_EXTERNAL); - + pending_draw->image_info = gpu::CreateGrVkImageInfo(vulkan_image.get()); pending_draw->vulkan_image = std::move(vulkan_image); }
diff --git a/android_webview/browser/safe_browsing/aw_url_checker_delegate_impl.cc b/android_webview/browser/safe_browsing/aw_url_checker_delegate_impl.cc index 2c6cd06..92a2676 100644 --- a/android_webview/browser/safe_browsing/aw_url_checker_delegate_impl.cc +++ b/android_webview/browser/safe_browsing/aw_url_checker_delegate_impl.cc
@@ -90,6 +90,13 @@ ui_manager_, resource, std::move(request))); } +void AwUrlCheckerDelegateImpl:: + StartObservingInteractionsForDelayedBlockingPageHelper( + const security_interstitials::UnsafeResource& resource, + bool is_main_frame) { + NOTREACHED() << "Delayed warnings not implemented for WebView"; +} + bool AwUrlCheckerDelegateImpl::IsUrlWhitelisted(const GURL& url) { return whitelist_manager_->IsURLWhitelisted(url); }
diff --git a/android_webview/browser/safe_browsing/aw_url_checker_delegate_impl.h b/android_webview/browser/safe_browsing/aw_url_checker_delegate_impl.h index 5098f14..8ac4b5d 100644 --- a/android_webview/browser/safe_browsing/aw_url_checker_delegate_impl.h +++ b/android_webview/browser/safe_browsing/aw_url_checker_delegate_impl.h
@@ -45,6 +45,9 @@ const net::HttpRequestHeaders& headers, bool is_main_frame, bool has_user_gesture) override; + void StartObservingInteractionsForDelayedBlockingPageHelper( + const security_interstitials::UnsafeResource& resource, + bool is_main_frame) override; bool IsUrlWhitelisted(const GURL& url) override; bool ShouldSkipRequestCheck(const GURL& original_url, int frame_tree_node_id,
diff --git a/android_webview/java/src/org/chromium/android_webview/FullScreenView.java b/android_webview/java/src/org/chromium/android_webview/FullScreenView.java index bb4c24a..372b916 100644 --- a/android_webview/java/src/org/chromium/android_webview/FullScreenView.java +++ b/android_webview/java/src/org/chromium/android_webview/FullScreenView.java
@@ -33,11 +33,7 @@ int initialWidth, int initialHeight) { super(context); setRight(initialWidth); - // Setting to the exact same dimensions avoids a layout later in some apps. - // This apparently causes some unexpected behavior such as not receiving key events - // Arbitrarily set the height to 5 pixels less to force a layout while also minimizing - // changes to viewport that can affect the graphics pipeline. - setBottom(Math.max(0, initialHeight - 5)); + setBottom(initialHeight); setAwViewMethods(awViewMethods); mAwContents = awContents; mInternalAccessAdapter = new InternalAccessAdapter();
diff --git a/ash/keyboard/ui/keyboard_ui_controller_unittest.cc b/ash/keyboard/ui/keyboard_ui_controller_unittest.cc index 7506021..6c714dc4 100644 --- a/ash/keyboard/ui/keyboard_ui_controller_unittest.cc +++ b/ash/keyboard/ui/keyboard_ui_controller_unittest.cc
@@ -150,8 +150,8 @@ layout_delegate_ = std::make_unique<TestKeyboardLayoutDelegate>(root_window()); - aura::client::SetScreenPositionClient(root_window(), - &screen_position_client_); + screen_position_client_ = + std::make_unique<wm::DefaultScreenPositionClient>(root_window()); // Force enable the virtual keyboard. controller_.Initialize( @@ -164,6 +164,7 @@ void TearDown() override { SetTouchKeyboardEnabled(false); controller_.RemoveObserver(this); + screen_position_client_.reset(); focus_controller_.reset(); aura::test::AuraTestBase::TearDown(); } @@ -268,7 +269,7 @@ std::unique_ptr<KeyboardLayoutDelegate> layout_delegate_; std::unique_ptr<ui::TextInputClient> test_text_input_client_; bool keyboard_disabled_ = false; - wm::DefaultScreenPositionClient screen_position_client_; + std::unique_ptr<wm::DefaultScreenPositionClient> screen_position_client_; ui::ScopedTestInputMethodFactory scoped_test_input_method_factory_; DISALLOW_COPY_AND_ASSIGN(KeyboardUIControllerTest); };
diff --git a/ash/public/cpp/ash_features.cc b/ash/public/cpp/ash_features.cc index 2be4aae..9e58270 100644 --- a/ash/public/cpp/ash_features.cc +++ b/ash/public/cpp/ash_features.cc
@@ -116,6 +116,9 @@ const base::Feature kHideShelfControlsInTabletMode{ "HideShelfControlsInTabletMode", base::FEATURE_ENABLED_BY_DEFAULT}; +const base::Feature kSystemTrayMicGainSetting{ + "SystemTrayMicGainSetting", base::FEATURE_DISABLED_BY_DEFAULT}; + bool IsAllowAmbientEQEnabled() { return base::FeatureList::IsEnabled(kAllowAmbientEQ); } @@ -245,6 +248,10 @@ return base::FeatureList::IsEnabled(kCornerShortcuts); } +bool IsSystemTrayMicGainSettingEnabled() { + return base::FeatureList::IsEnabled(kSystemTrayMicGainSetting); +} + namespace { // The boolean flag indicating if "WebUITabStrip" feature is enabled in Chrome.
diff --git a/ash/public/cpp/ash_features.h b/ash/public/cpp/ash_features.h index cff486f1..ba63869 100644 --- a/ash/public/cpp/ash_features.h +++ b/ash/public/cpp/ash_features.h
@@ -150,6 +150,10 @@ // preferences, or policy). ASH_PUBLIC_EXPORT extern const base::Feature kHideShelfControlsInTabletMode; +// Enables sliders for setting mic gain levels in the more audio settings +// section in the system tray. +ASH_PUBLIC_EXPORT extern const base::Feature kSystemTrayMicGainSetting; + ASH_PUBLIC_EXPORT bool IsAllowAmbientEQEnabled(); ASH_PUBLIC_EXPORT bool IsAltTabLimitedToActiveDesk(); @@ -204,6 +208,8 @@ ASH_PUBLIC_EXPORT bool IsCornerShortcutsEnabled(); +ASH_PUBLIC_EXPORT bool IsSystemTrayMicGainSettingEnabled(); + // These two functions are supposed to be temporary functions to set or get // whether "WebUITabStrip" feature is enabled from Chrome. ASH_PUBLIC_EXPORT void SetWebUITabStripEnabled(bool enabled);
diff --git a/ash/public/cpp/shelf_ui_info.h b/ash/public/cpp/shelf_ui_info.h index 6f4cb49..9cf752b 100644 --- a/ash/public/cpp/shelf_ui_info.h +++ b/ash/public/cpp/shelf_ui_info.h
@@ -41,6 +41,9 @@ // Screen bounds of visible shelf icons. std::vector<gfx::Rect> icons_bounds_in_screen; + + // Indicates whether shelf widget is animating; + bool is_shelf_widget_animating = false; }; struct ASH_PUBLIC_EXPORT ShelfState {
diff --git a/ash/shelf/shelf_test_api.cc b/ash/shelf/shelf_test_api.cc index e781530..253e850 100644 --- a/ash/shelf/shelf_test_api.cc +++ b/ash/shelf/shelf_test_api.cc
@@ -76,6 +76,8 @@ info.is_animating = scrollable_shelf_view->during_scroll_animation_; info.is_overflow = (scrollable_shelf_view->layout_strategy_ != ScrollableShelfView::kNotShowArrowButtons); + info.is_shelf_widget_animating = + GetShelfWidget()->GetLayer()->GetAnimator()->is_animating(); const ShelfView* const shelf_view = scrollable_shelf_view->shelf_view_; for (int i = shelf_view->first_visible_index(); @@ -103,7 +105,7 @@ info.hotseat_state = hotseat_widget->state(); const gfx::Rect shelf_widget_bounds = - GetShelf()->shelf_widget()->GetTargetBounds(); + GetShelf()->shelf_widget()->GetWindowBoundsInScreen(); info.swipe_up.swipe_start_location = shelf_widget_bounds.CenterPoint(); // The swipe distance is small enough to avoid the window drag from shelf.
diff --git a/ash/system/message_center/unified_message_center_bubble.cc b/ash/system/message_center/unified_message_center_bubble.cc index c946873..8cc5a2cd 100644 --- a/ash/system/message_center/unified_message_center_bubble.cc +++ b/ash/system/message_center/unified_message_center_bubble.cc
@@ -190,6 +190,10 @@ return tray_->FocusQuickSettings(reverse); } +void UnifiedMessageCenterBubble::ActivateQuickSettingsBubble() { + tray_->ActivateBubble(); +} + void UnifiedMessageCenterBubble::FocusFirstNotification() { // Move focus to first notification from notification bar if it is visible. if (message_center_view_->IsNotificationBarVisible())
diff --git a/ash/system/message_center/unified_message_center_bubble.h b/ash/system/message_center/unified_message_center_bubble.h index a7b44581..fc7e9ed 100644 --- a/ash/system/message_center/unified_message_center_bubble.h +++ b/ash/system/message_center/unified_message_center_bubble.h
@@ -54,6 +54,10 @@ // Relinquish focus and transfer it to the quick settings widget. bool FocusOut(bool reverse); + // Activate quick settings bubble. Used when the message center is going + // invisible. + void ActivateQuickSettingsBubble(); + // Move focus to the first notification. void FocusFirstNotification();
diff --git a/ash/system/message_center/unified_message_center_view.cc b/ash/system/message_center/unified_message_center_view.cc index 348cdaf..42aae64 100644 --- a/ash/system/message_center/unified_message_center_view.cc +++ b/ash/system/message_center/unified_message_center_view.cc
@@ -411,7 +411,7 @@ // Transfer focus to quick settings when going invisible. auto* widget = GetWidget(); if (widget && widget->IsActive()) - FocusOut(false); + message_center_bubble_->ActivateQuickSettingsBubble(); } }
diff --git a/ash/system/unified/unified_system_tray_controller_unittest.cc b/ash/system/unified/unified_system_tray_controller_unittest.cc index c2adba1..900762e 100644 --- a/ash/system/unified/unified_system_tray_controller_unittest.cc +++ b/ash/system/unified/unified_system_tray_controller_unittest.cc
@@ -13,7 +13,7 @@ #include "ash/system/unified/unified_system_tray_view.h" #include "ash/test/ash_test_base.h" #include "chromeos/dbus/shill/shill_clients.h" -#include "chromeos/network/network_handler.h" +#include "chromeos/services/network_config/public/cpp/cros_network_config_test_helper.h" #include "components/prefs/testing_pref_service.h" #include "ui/compositor/scoped_animation_duration_scale_mode.h" #include "ui/gfx/animation/slide_animation.h" @@ -39,12 +39,9 @@ // testing::Test: void SetUp() override { - chromeos::shill_clients::InitializeFakes(); - // Initializing NetworkHandler before ash is more like production. - chromeos::NetworkHandler::Initialize(); + network_config_helper_ = std::make_unique< + chromeos::network_config::CrosNetworkConfigTestHelper>(); AshTestBase::SetUp(); - chromeos::NetworkHandler::Get()->InitializePrefServices(&profile_prefs_, - &local_state_); // Networking stubs may have asynchronous initialization. base::RunLoop().RunUntilIdle(); @@ -61,11 +58,7 @@ controller_.reset(); model_.reset(); - // This roughly matches production shutdown order. - chromeos::NetworkHandler::Get()->ShutdownPrefServices(); AshTestBase::TearDown(); - chromeos::NetworkHandler::Shutdown(); - chromeos::shill_clients::Shutdown(); } // views::ViewObserver: @@ -99,13 +92,12 @@ UnifiedSystemTrayView* view() { return view_.get(); } private: + std::unique_ptr<chromeos::network_config::CrosNetworkConfigTestHelper> + network_config_helper_; std::unique_ptr<UnifiedSystemTrayModel> model_; std::unique_ptr<UnifiedSystemTrayController> controller_; std::unique_ptr<UnifiedSystemTrayView> view_; - TestingPrefServiceSimple profile_prefs_; - TestingPrefServiceSimple local_state_; - int preferred_size_changed_count_ = 0; DISALLOW_COPY_AND_ASSIGN(UnifiedSystemTrayControllerTest);
diff --git a/ash/test/ash_test_helper.cc b/ash/test/ash_test_helper.cc index 39713e0..2bd6ae4 100644 --- a/ash/test/ash_test_helper.cc +++ b/ash/test/ash_test_helper.cc
@@ -70,16 +70,55 @@ AshTestHelper::InitParams::InitParams(InitParams&&) = default; AshTestHelper::InitParams::~InitParams() = default; -AshTestHelper::AshTestHelper() - : command_line_(std::make_unique<base::test::ScopedCommandLine>()) {} +AshTestHelper::AshTestHelper() = default; AshTestHelper::~AshTestHelper() { - // Ensure the next test starts with a null display::Screen. Done here because - // some tests use Screen after TearDown(). + // Ensure the next test starts with a null display::Screen. This must be done + // here instead of in TearDown() since some tests test access to the Screen + // after the shell shuts down (which they use TearDown() to trigger). ScreenAsh::DeleteScreenForShutdown(); } void AshTestHelper::SetUp(InitParams init_params) { + // Aura-general setup ------------------------------------------------------- + + wm_state_ = std::make_unique<::wm::WMState>(); + + if (init_params.config_type != kShell) { + ui::test::EnableTestConfigForPlatformWindows(); + ui::InitializeInputMethodForTesting(); + } + + ui::test::EventGeneratorDelegate::SetFactoryFunction( + base::BindRepeating(&aura::test::EventGeneratorDelegateAura::Create)); + + if (init_params.config_type == kUnitTest) { + zero_duration_mode_.reset(new ui::ScopedAnimationDurationScaleMode( + ui::ScopedAnimationDurationScaleMode::ZERO_DURATION)); + } + + if (!init_params.context_factory) { + context_factories_ = std::make_unique<ui::TestContextFactories>(false); + init_params.context_factory = context_factories_->GetContextFactory(); + } + + // Reset aura::Env to eliminate test dependency (https://crbug.com/586514). + aura::test::EnvTestHelper env_helper(aura::Env::GetInstance()); + env_helper.ResetEnvForTesting(); + env_helper.SetInputStateLookup(std::unique_ptr<aura::InputStateLookup>()); + + // Ash-specific setup ------------------------------------------------------- + + command_line_ = std::make_unique<base::test::ScopedCommandLine>(); + statistics_provider_ = + std::make_unique<chromeos::system::ScopedFakeStatisticsProvider>(); + prefs_provider_ = std::make_unique<TestPrefServiceProvider>(); + notifier_settings_controller_ = + std::make_unique<TestNotifierSettingsController>(); + assistant_service_ = std::make_unique<TestAssistantService>(); + system_tray_client_ = std::make_unique<TestSystemTrayClient>(); + photo_controller_ = std::make_unique<TestPhotoController>(); + // TODO(jamescook): Can we do this without changing command line? // Use the origin (1,1) so that it doesn't over // lap with the native mouse cursor. @@ -91,48 +130,11 @@ ::switches::kHostWindowBounds, "10+10-800x600"); } - // Pre shell creation config init. - switch (init_params.config_type) { - case kUnitTest: - // Default for unit tests but not for perf tests. - zero_duration_mode_.reset(new ui::ScopedAnimationDurationScaleMode( - ui::ScopedAnimationDurationScaleMode::ZERO_DURATION)); - TabletModeController::SetUseScreenshotForTest(false); - FALLTHROUGH; - case kPerfTest: - // Default for both unit and perf tests. - ui::test::EnableTestConfigForPlatformWindows(); - display::ResetDisplayIdForTest(); - ui::InitializeInputMethodForTesting(); - break; - case kShell: - break; - } + if (init_params.config_type == kUnitTest) + TabletModeController::SetUseScreenshotForTest(false); - statistics_provider_ = - std::make_unique<chromeos::system::ScopedFakeStatisticsProvider>(); - - ui::test::EventGeneratorDelegate::SetFactoryFunction( - base::BindRepeating(&aura::test::EventGeneratorDelegateAura::Create)); - - wm_state_ = std::make_unique<::wm::WMState>(); - // Only create a ViewsDelegate if the test didn't create one already. - if (!views::ViewsDelegate::GetInstance()) - test_views_delegate_ = std::make_unique<AshTestViewsDelegate>(); - - if (!bluez::BluezDBusManager::IsInitialized()) { - bluez::BluezDBusManager::InitializeFake(); - bluez_dbus_manager_initialized_ = true; - } - - if (!chromeos::PowerManagerClient::Get()) - chromeos::PowerManagerClient::InitializeFake(); - - if (!chromeos::PowerPolicyController::IsInitialized()) { - chromeos::PowerPolicyController::Initialize( - chromeos::PowerManagerClient::Get()); - power_policy_controller_initialized_ = true; - } + if (init_params.config_type != kShell) + display::ResetDisplayIdForTest(); chromeos::CrasAudioClient::InitializeFake(); // Create CrasAudioHandler for testing since g_browser_process is not @@ -143,104 +145,93 @@ // last cursor visibility state, etc. ::wm::CursorManager::ResetCursorVisibilityStateForTest(); + if (!bluez::BluezDBusManager::IsInitialized()) { + bluez::BluezDBusManager::InitializeFake(); + bluez_dbus_manager_initialized_ = true; + } + if (!chromeos::PowerManagerClient::Get()) + chromeos::PowerManagerClient::InitializeFake(); + if (!chromeos::PowerPolicyController::IsInitialized()) { + chromeos::PowerPolicyController::Initialize( + chromeos::PowerManagerClient::Get()); + power_policy_controller_initialized_ = true; + } + if (!NewWindowDelegate::GetInstance()) + new_window_delegate_ = std::make_unique<TestNewWindowDelegate>(); + if (!views::ViewsDelegate::GetInstance()) + test_views_delegate_ = std::make_unique<AshTestViewsDelegate>(); + ShellInitParams shell_init_params; shell_init_params.delegate = std::move(init_params.delegate); if (!shell_init_params.delegate) shell_init_params.delegate = std::make_unique<TestShellDelegate>(); shell_init_params.context_factory = init_params.context_factory; - if (!shell_init_params.context_factory) { - context_factories_ = std::make_unique<ui::TestContextFactories>(false); - shell_init_params.context_factory = context_factories_->GetContextFactory(); - } shell_init_params.local_state = init_params.local_state; shell_init_params.keyboard_ui_factory = std::make_unique<TestKeyboardUIFactory>(); Shell::CreateInstance(std::move(shell_init_params)); - - // Reset aura::Env to eliminate test dependency (https://crbug.com/586514). - aura::test::EnvTestHelper env_helper(aura::Env::GetInstance()); - env_helper.ResetEnvForTesting(); - - env_helper.SetInputStateLookup(std::unique_ptr<aura::InputStateLookup>()); - Shell* shell = Shell::Get(); // Cursor is visible by default in tests. - // CursorManager is null on MASH. - if (shell->cursor_manager()) - shell->cursor_manager()->ShowCursor(); + shell->cursor_manager()->ShowCursor(); - prefs_provider_ = std::make_unique<TestPrefServiceProvider>(); - session_controller_client_.reset(new TestSessionControllerClient( - shell->session_controller(), prefs_provider_.get())); - session_controller_client_->InitializeAndSetClient(); - - notifier_settings_controller_ = - std::make_unique<TestNotifierSettingsController>(); - - assistant_service_ = std::make_unique<TestAssistantService>(); shell->assistant_controller()->SetAssistant( assistant_service_->CreateRemoteAndBind()); - system_tray_client_ = std::make_unique<TestSystemTrayClient>(); shell->system_tray_model()->SetClient(system_tray_client_.get()); - photo_controller_ = std::make_unique<TestPhotoController>(); - + session_controller_client_.reset(new TestSessionControllerClient( + shell->session_controller(), prefs_provider_.get())); + session_controller_client_->InitializeAndSetClient(); if (init_params.start_session) session_controller_client_->CreatePredefinedUserSessions(1); + // Requires the AppListController the Shell creates. app_list_test_helper_ = std::make_unique<AppListTestHelper>(); - if (!NewWindowDelegate::GetInstance()) - new_window_delegate_ = std::make_unique<TestNewWindowDelegate>(); - - // Post shell creation config init. - switch (init_params.config_type) { - case kUnitTest: - // Tests that change the display configuration generally don't care about - // the notifications and the popup UI can interfere with things like - // cursors. - shell->screen_layout_observer()->set_show_notifications_for_testing( - false); - - // Disable display change animations in unit tests. - DisplayConfigurationControllerTestApi( - shell->display_configuration_controller()) - .SetDisplayAnimator(false); - - // Remove the app dragging animations delay for testing purposes. - shell->overview_controller()->set_delayed_animation_task_delay_for_test( - base::TimeDelta()); - // Tests expect empty wallpaper. - shell->wallpaper_controller()->CreateEmptyWallpaperForTesting(); - - FALLTHROUGH; - case kPerfTest: - // Don't change the display size due to host size resize. - display::test::DisplayManagerTestApi(shell->display_manager()) - .DisableChangeDisplayUponHostResize(); - - // Create the test keyboard controller observer to respond to - // OnLoadKeyboardContentsRequested(). - test_keyboard_controller_observer_ = - std::make_unique<TestKeyboardControllerObserver>( - shell->keyboard_controller()); - break; - case kShell: - shell->wallpaper_controller()->ShowDefaultWallpaperForTesting(); - break; + if (init_params.config_type == kShell) { + shell->wallpaper_controller()->ShowDefaultWallpaperForTesting(); + return; } + + // Don't change the display size due to host size resize. + display::test::DisplayManagerTestApi(shell->display_manager()) + .DisableChangeDisplayUponHostResize(); + + // Create the test keyboard controller observer to respond to + // OnLoadKeyboardContentsRequested(). + test_keyboard_controller_observer_ = + std::make_unique<TestKeyboardControllerObserver>( + shell->keyboard_controller()); + + if (init_params.config_type != kUnitTest) + return; + + // Tests that change the display configuration generally don't care about the + // notifications and the popup UI can interfere with things like cursors. + shell->screen_layout_observer()->set_show_notifications_for_testing(false); + + // Disable display change animations in unit tests. + DisplayConfigurationControllerTestApi( + shell->display_configuration_controller()) + .SetDisplayAnimator(false); + + // Remove the app dragging animations delay for testing purposes. + shell->overview_controller()->set_delayed_animation_task_delay_for_test( + base::TimeDelta()); + + // Tests expect empty wallpaper. + shell->wallpaper_controller()->CreateEmptyWallpaperForTesting(); } void AshTestHelper::TearDown() { + // Ash-specific teardown ---------------------------------------------------- + + // The AppListTestHelper holds a pointer to the AppListController the Shell + // owns, so shut the test helper down first. app_list_test_helper_.reset(); Shell::DeleteInstance(); - new_window_delegate_.reset(); - - // Needs to be reset after Shell::Get()->keyboard_controller() is deleted. - test_keyboard_controller_observer_.reset(); // Suspend the tear down until all resources are returned via // CompositorFrameSinkClient::ReclaimResources() @@ -249,6 +240,8 @@ chromeos::CrasAudioHandler::Shutdown(); chromeos::CrasAudioClient::Shutdown(); + // The PowerPolicyController holds a pointer to the PowerManagementClient, so + // shut the controller down first. if (power_policy_controller_initialized_) { chromeos::PowerPolicyController::Shutdown(); power_policy_controller_initialized_ = false; @@ -256,13 +249,29 @@ chromeos::PowerManagerClient::Shutdown(); + TabletModeController::SetUseScreenshotForTest(true); + + // Destroy all owned objects to prevent tests from depending on their state + // after this returns. + test_keyboard_controller_observer_.reset(); + test_views_delegate_.reset(); + new_window_delegate_.reset(); if (bluez_dbus_manager_initialized_) { device::BluetoothAdapterFactory::Shutdown(); bluez::BluezDBusManager::Shutdown(); bluez_dbus_manager_initialized_ = false; } + photo_controller_.reset(); + system_tray_client_.reset(); + assistant_service_.reset(); + notifier_settings_controller_.reset(); + prefs_provider_.reset(); + statistics_provider_.reset(); + command_line_.reset(); - context_factories_.reset(); + // Aura-general teardown ---------------------------------------------------- + + ui::ShutdownInputMethodForTesting(); // Context factory referenced by Env is now destroyed. Reset Env's members in // case some other test tries to use it. This matters if someone else created @@ -270,24 +279,12 @@ if (aura::Env::HasInstance()) aura::Env::GetInstance()->set_context_factory(nullptr); - ui::ShutdownInputMethodForTesting(); - zero_duration_mode_.reset(); - - test_views_delegate_.reset(); - wm_state_.reset(); - - command_line_.reset(); - - display::Display::ResetForceDeviceScaleFactorForTesting(); - - CHECK(!::wm::CaptureController::Get()); - ui::test::EventGeneratorDelegate::SetFactoryFunction( ui::test::EventGeneratorDelegate::FactoryFunction()); - statistics_provider_.reset(); - - TabletModeController::SetUseScreenshotForTest(true); + context_factories_.reset(); + zero_duration_mode_.reset(); + wm_state_.reset(); } PrefService* AshTestHelper::GetLocalStatePrefService() {
diff --git a/ash/test/ash_test_helper.h b/ash/test/ash_test_helper.h index 95524f1..f0fed39 100644 --- a/ash/test/ash_test_helper.h +++ b/ash/test/ash_test_helper.h
@@ -135,32 +135,23 @@ void reset_commandline() { command_line_.reset(); } private: + std::unique_ptr<::wm::WMState> wm_state_; + std::unique_ptr<ui::ScopedAnimationDurationScaleMode> zero_duration_mode_; + std::unique_ptr<ui::TestContextFactories> context_factories_; + std::unique_ptr<base::test::ScopedCommandLine> command_line_; std::unique_ptr<chromeos::system::ScopedFakeStatisticsProvider> statistics_provider_; - - std::unique_ptr<ui::ScopedAnimationDurationScaleMode> zero_duration_mode_; - - std::unique_ptr<::wm::WMState> wm_state_; - std::unique_ptr<AshTestViewsDelegate> test_views_delegate_; - - // Flags for whether various services were initialized here. + std::unique_ptr<TestPrefServiceProvider> prefs_provider_; + std::unique_ptr<TestNotifierSettingsController> notifier_settings_controller_; + std::unique_ptr<TestAssistantService> assistant_service_; + std::unique_ptr<TestSystemTrayClient> system_tray_client_; + std::unique_ptr<TestPhotoController> photo_controller_; + std::unique_ptr<AppListTestHelper> app_list_test_helper_; bool bluez_dbus_manager_initialized_ = false; bool power_policy_controller_initialized_ = false; - - std::unique_ptr<TestSessionControllerClient> session_controller_client_; - std::unique_ptr<TestNotifierSettingsController> notifier_settings_controller_; - std::unique_ptr<TestSystemTrayClient> system_tray_client_; - std::unique_ptr<TestPrefServiceProvider> prefs_provider_; - std::unique_ptr<TestAssistantService> assistant_service_; - std::unique_ptr<ui::TestContextFactories> context_factories_; - std::unique_ptr<TestPhotoController> photo_controller_; - - std::unique_ptr<base::test::ScopedCommandLine> command_line_; - - std::unique_ptr<AppListTestHelper> app_list_test_helper_; - std::unique_ptr<TestNewWindowDelegate> new_window_delegate_; - + std::unique_ptr<AshTestViewsDelegate> test_views_delegate_; + std::unique_ptr<TestSessionControllerClient> session_controller_client_; std::unique_ptr<TestKeyboardControllerObserver> test_keyboard_controller_observer_;
diff --git a/ash/wm/gestures/back_gesture/back_gesture_event_handler.cc b/ash/wm/gestures/back_gesture/back_gesture_event_handler.cc index 0d48e0f..5b8198d 100644 --- a/ash/wm/gestures/back_gesture/back_gesture_event_handler.cc +++ b/ash/wm/gestures/back_gesture/back_gesture_event_handler.cc
@@ -198,12 +198,19 @@ /*is_source_touch_event_set_non_blocking=*/false); // Get the event target from TouchEvent since target of the GestureEvent - // from GetAndResetPendingGestures is nullptr. + // from GetAndResetPendingGestures is nullptr. The coordinate conversion is + // done outside the loop as the previous gesture events in a sequence may + // invalidate the target, for example given a sequence of + // {ET_GESTURE_SCROLL_END, ET_GESTURE_END} on a non-resizable window, the + // first gesture will trigger a minimize event which will delete the backdrop, + // which was the target. See http://crbug.com/1064618. aura::Window* target = static_cast<aura::Window*>(event->target()); + gfx::Point screen_location = event->location(); + ::wm::ConvertPointToScreen(target, &screen_location); const std::vector<std::unique_ptr<ui::GestureEvent>> gestures = gesture_provider_.GetAndResetPendingGestures(); for (const auto& gesture : gestures) { - if (MaybeHandleBackGesture(gesture.get(), target)) + if (MaybeHandleBackGesture(gesture.get(), screen_location)) event->StopPropagation(); } } @@ -214,15 +221,13 @@ // handled at OnTouchEvent() by calling MaybeHandleBackGesture(). } -bool BackGestureEventHandler::MaybeHandleBackGesture(ui::GestureEvent* event, - aura::Window* target) { +bool BackGestureEventHandler::MaybeHandleBackGesture( + ui::GestureEvent* event, + const gfx::Point& screen_location) { DCHECK(features::IsSwipingFromLeftEdgeToGoBackEnabled()); - DCHECK(target); - gfx::Point screen_location = event->location(); - ::wm::ConvertPointToScreen(target, &screen_location); switch (event->type()) { case ui::ET_GESTURE_TAP_DOWN: - going_back_started_ = CanStartGoingBack(target, screen_location); + going_back_started_ = CanStartGoingBack(screen_location); if (!going_back_started_) break; back_gesture_affordance_ = std::make_unique<BackGestureAffordance>( @@ -334,7 +339,6 @@ } bool BackGestureEventHandler::CanStartGoingBack( - aura::Window* target, const gfx::Point& screen_location) { DCHECK(features::IsSwipingFromLeftEdgeToGoBackEnabled()); @@ -363,7 +367,7 @@ if (!top_window && !shell->overview_controller()->InOverviewSession()) return false; - for (aura::Window* window = target; window; window = window->parent()) { + for (aura::Window* window = top_window; window; window = window->parent()) { SkRegion* gesture_exclusion = window->GetProperty(kSystemGestureExclusionKey); if (gesture_exclusion) { @@ -377,7 +381,7 @@ } gfx::Rect hit_bounds_in_screen(display::Screen::GetScreen() - ->GetDisplayNearestWindow(target) + ->GetDisplayNearestWindow(top_window) .work_area()); hit_bounds_in_screen.set_width(kStartGoingBackLeftEdgeInset); if (hit_bounds_in_screen.Contains(screen_location))
diff --git a/ash/wm/gestures/back_gesture/back_gesture_event_handler.h b/ash/wm/gestures/back_gesture/back_gesture_event_handler.h index 9157632..b8551b2 100644 --- a/ash/wm/gestures/back_gesture/back_gesture_event_handler.h +++ b/ash/wm/gestures/back_gesture/back_gesture_event_handler.h
@@ -10,10 +10,6 @@ #include "ui/events/event_handler.h" #include "ui/events/gestures/gesture_provider_aura.h" -namespace aura { -class Window; -} // namespace aura - namespace ash { class BackGestureAffordance; @@ -51,14 +47,14 @@ private: // Returns true if |event| was handled as a go-back gesture. |event| is - // generated by |gesture_provider_| from touch event, its target will be - // nullptr. Gets |target| from corresponding touch event instead. - bool MaybeHandleBackGesture(ui::GestureEvent* event, aura::Window* target); + // generated by |gesture_provider_| from touch event, |screen_location| is + // location of the event in screen coordinates. + bool MaybeHandleBackGesture(ui::GestureEvent* event, + const gfx::Point& screen_location); // True if we can start swiping from left edge of the display or splitview // divider to go back. - bool CanStartGoingBack(aura::Window* window, - const gfx::Point& screen_location); + bool CanStartGoingBack(const gfx::Point& screen_location); void SendBackEvent(const gfx::Point& screen_location);
diff --git a/ash/wm/gestures/back_gesture/back_gesture_event_handler_unittest.cc b/ash/wm/gestures/back_gesture/back_gesture_event_handler_unittest.cc index 8e0c7bd..04aad14 100644 --- a/ash/wm/gestures/back_gesture/back_gesture_event_handler_unittest.cc +++ b/ash/wm/gestures/back_gesture/back_gesture_event_handler_unittest.cc
@@ -29,7 +29,11 @@ #include "ash/wm/window_state.h" #include "ash/wm/window_util.h" #include "ash/wm/wm_event.h" +#include "ash/wm/workspace/backdrop_controller.h" +#include "ash/wm/workspace/workspace_layout_manager.h" +#include "ash/wm/workspace_controller.h" #include "base/test/scoped_feature_list.h" +#include "ui/aura/client/aura_constants.h" #include "ui/base/accelerators/accelerator.h" #include "ui/base/accelerators/test_accelerator_target.h" #include "ui/display/test/display_manager_test_api.h" @@ -606,4 +610,34 @@ EXPECT_FALSE(window_state->IsMinimized()); } +// Tests that swiping on the backdrop to minimize a non-resizable app will not +// cause a crash. Regression test for http://crbug.com/1064618. +TEST_F(BackGestureEventHandlerTestCantGoBack, NonResizableApp) { + // Make the top window non-resizable and set its bounds so that the backdrop + // will take the gesture events. + top_window()->SetProperty(aura::client::kResizeBehaviorKey, + aura::client::kResizeBehaviorCanMinimize); + + WindowState* window_state = WindowState::Get(top_window()); + window_state->Restore(); + SetBoundsWMEvent bounds_event(gfx::Rect(200, 100, 300, 300)); + window_state->OnWMEvent(&bounds_event); + ASSERT_FALSE(window_state->IsMinimized()); + + // Check that the backdrop is visible. + WorkspaceController* workspace_controller = + GetWorkspaceControllerForContext(top_window()); + WorkspaceLayoutManager* layout_manager = + workspace_controller->layout_manager(); + BackdropController* backdrop_controller = + layout_manager->backdrop_controller(); + aura::Window* backdrop_window = backdrop_controller->backdrop_window(); + ASSERT_TRUE(backdrop_window); + ASSERT_TRUE(backdrop_window->IsVisible()); + + // Generate a back seqeuence. There should be no crash. + GenerateBackSequence(); + EXPECT_TRUE(window_state->IsMinimized()); +} + } // namespace ash
diff --git a/base/metrics/field_trial_params.h b/base/metrics/field_trial_params.h index a9bd0c54..7b4bd5b 100644 --- a/base/metrics/field_trial_params.h +++ b/base/metrics/field_trial_params.h
@@ -9,6 +9,7 @@ #include <string> #include "base/base_export.h" +#include "base/logging.h" namespace base { @@ -256,6 +257,16 @@ return default_value; } + // Returns the param-string for the given enum value. + std::string GetName(Enum value) const { + for (size_t i = 0; i < option_count; ++i) { + if (value == options[i].value) + return options[i].name; + } + NOTREACHED(); + return ""; + } + const base::Feature* const feature; const char* const name; const Enum default_value;
diff --git a/base/metrics/ukm_source_id.cc b/base/metrics/ukm_source_id.cc index 5b3b65fa..ce8c886 100644 --- a/base/metrics/ukm_source_id.cc +++ b/base/metrics/ukm_source_id.cc
@@ -13,7 +13,7 @@ namespace { const int64_t kLowBitsMask = (INT64_C(1) << 32) - 1; -const int64_t kNumTypeBits = 3; +const int64_t kNumTypeBits = static_cast<int64_t>(UkmSourceId::Type::kMaxValue); const int64_t kTypeMask = (INT64_C(1) << kNumTypeBits) - 1; } // namespace
diff --git a/base/metrics/ukm_source_id.h b/base/metrics/ukm_source_id.h index e35278b..3672235 100644 --- a/base/metrics/ukm_source_id.h +++ b/base/metrics/ukm_source_id.h
@@ -18,7 +18,7 @@ public: enum class Type : int64_t { // Source ids of this type are created via ukm::AssignNewSourceId, to denote - // 'custom' source other than the 3 types below. Source of this type has + // 'custom' source other than the 4 types below. Source of this type has // additional restrictions with logging, as determined by // IsWhitelistedSourceId. UKM = 0, @@ -40,6 +40,11 @@ // associated events are expected to be recorded within the same report // interval; it will not be kept in memory between different reports. WEBAPK_ID = 4, + // Source ID for service worker based payment handlers. A new source of this + // type and associated events are expected to be recorded within the same + // report interval; it will not be kept in memory between different reports. + PAYMENT_APP_ID = 5, + kMaxValue = PAYMENT_APP_ID, }; // Default constructor has the invalid value.
diff --git a/base/system/sys_info.h b/base/system/sys_info.h index 400d0577..057b0dc 100644 --- a/base/system/sys_info.h +++ b/base/system/sys_info.h
@@ -169,6 +169,9 @@ // Returns the Android build ID. static std::string GetAndroidBuildID(); + // Returns the Android hardware EGL system property. + static std::string GetAndroidHardwareEGL(); + static int DalvikHeapSizeMB(); static int DalvikHeapGrowthLimitMB(); #endif // defined(OS_ANDROID)
diff --git a/base/system/sys_info_android.cc b/base/system/sys_info_android.cc index 3993b876..fa4eeacf 100644 --- a/base/system/sys_info_android.cc +++ b/base/system/sys_info_android.cc
@@ -215,6 +215,12 @@ return std::string(os_build_id_str); } +std::string SysInfo::GetAndroidHardwareEGL() { + char os_hardware_egl_str[PROP_VALUE_MAX]; + __system_property_get("ro.hardware.egl", os_hardware_egl_str); + return std::string(os_hardware_egl_str); +} + int SysInfo::DalvikHeapSizeMB() { static int heap_size = GetDalvikHeapSizeMB(); return heap_size;
diff --git a/base/trace_event/builtin_categories.h b/base/trace_event/builtin_categories.h index 6f07209..73e9b6a 100644 --- a/base/trace_event/builtin_categories.h +++ b/base/trace_event/builtin_categories.h
@@ -60,6 +60,7 @@ X("devtools") \ X("devtools.timeline") \ X("devtools.timeline.async") \ + X("disk_cache") \ X("download") \ X("download_service") \ X("drm") \
diff --git a/base/trace_event/trace_event_memory_overhead.h b/base/trace_event/trace_event_memory_overhead.h index 69468d4..e10a3ec 100644 --- a/base/trace_event/trace_event_memory_overhead.h +++ b/base/trace_event/trace_event_memory_overhead.h
@@ -8,6 +8,7 @@ #include <stddef.h> #include <stdint.h> +#include <string> #include <unordered_map> #include "base/base_export.h"
diff --git a/build/android/bytecode/BUILD.gn b/build/android/bytecode/BUILD.gn index 5d651d2..7a9d304 100644 --- a/build/android/bytecode/BUILD.gn +++ b/build/android/bytecode/BUILD.gn
@@ -8,7 +8,6 @@ java_binary("java_bytecode_rewriter") { sources = [ - "java/org/chromium/bytecode/AssertionEnablerClassAdapter.java", "java/org/chromium/bytecode/ByteCodeProcessor.java", "java/org/chromium/bytecode/ClassPathValidator.java", "java/org/chromium/bytecode/CustomClassLoaderClassWriter.java",
diff --git a/build/android/bytecode/java/org/chromium/bytecode/AssertionEnablerClassAdapter.java b/build/android/bytecode/java/org/chromium/bytecode/AssertionEnablerClassAdapter.java deleted file mode 100644 index 4b04e18..0000000 --- a/build/android/bytecode/java/org/chromium/bytecode/AssertionEnablerClassAdapter.java +++ /dev/null
@@ -1,109 +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. - -package org.chromium.bytecode; - -import static org.chromium.bytecode.TypeUtils.ASSERTION_ERROR; -import static org.chromium.bytecode.TypeUtils.BUILD_HOOKS; -import static org.chromium.bytecode.TypeUtils.VOID; - -import org.objectweb.asm.ClassVisitor; -import org.objectweb.asm.Label; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; - -/** - * An ClassVisitor for replacing Java ASSERT statements with a function by modifying Java bytecode. - * - * We do this in two steps, first step is to enable assert. - * Following bytecode is generated for each class with ASSERT statements: - * 0: ldc #8 // class CLASSNAME - * 2: invokevirtual #9 // Method java/lang/Class.desiredAssertionStatus:()Z - * 5: ifne 12 - * 8: iconst_1 - * 9: goto 13 - * 12: iconst_0 - * 13: putstatic #2 // Field $assertionsDisabled:Z - * Replaces line #13 to the following: - * 13: pop - * Consequently, $assertionsDisabled is assigned the default value FALSE. - * This is done in the first if statement in overridden visitFieldInsn. We do this per per-assert. - * - * Second step is to replace assert statement with a function: - * The followed instructions are generated by a java assert statement: - * getstatic #3 // Field $assertionsDisabled:Z - * ifne 118 // Jump to instruction as if assertion if not enabled - * ... - * ifne 19 - * new #4 // class java/lang/AssertionError - * dup - * ldc #5 // String (don't have this line if no assert message given) - * invokespecial #6 // Method java/lang/AssertionError. - * athrow - * Replace athrow with: - * invokestatic #7 // Method org/chromium/base/JavaExceptionReporter.assertFailureHandler - * goto 118 - * JavaExceptionReporter.assertFailureHandler is a function that handles the AssertionError, - * 118 is the instruction to execute as if assertion if not enabled. - */ -class AssertionEnablerClassAdapter extends ClassVisitor { - AssertionEnablerClassAdapter(ClassVisitor visitor) { - super(Opcodes.ASM7, visitor); - } - - @Override - public MethodVisitor visitMethod(final int access, final String name, String desc, - String signature, String[] exceptions) { - return new RewriteAssertMethodVisitor( - Opcodes.ASM7, super.visitMethod(access, name, desc, signature, exceptions)); - } - - static class RewriteAssertMethodVisitor extends MethodVisitor { - static final String ASSERTION_DISABLED_NAME = "$assertionsDisabled"; - static final String INSERT_INSTRUCTION_NAME = "assertFailureHandler"; - static final String INSERT_INSTRUCTION_DESC = - TypeUtils.getMethodDescriptor(VOID, ASSERTION_ERROR); - static final boolean INSERT_INSTRUCTION_ITF = false; - - boolean mStartLoadingAssert; - Label mGotoLabel; - - public RewriteAssertMethodVisitor(int api, MethodVisitor mv) { - super(api, mv); - } - - @Override - public void visitFieldInsn(int opcode, String owner, String name, String desc) { - if (opcode == Opcodes.PUTSTATIC && name.equals(ASSERTION_DISABLED_NAME)) { - super.visitInsn(Opcodes.POP); // enable assert - } else if (opcode == Opcodes.GETSTATIC && name.equals(ASSERTION_DISABLED_NAME)) { - mStartLoadingAssert = true; - super.visitFieldInsn(opcode, owner, name, desc); - } else { - super.visitFieldInsn(opcode, owner, name, desc); - } - } - - @Override - public void visitJumpInsn(int opcode, Label label) { - if (mStartLoadingAssert && opcode == Opcodes.IFNE && mGotoLabel == null) { - mGotoLabel = label; - } - super.visitJumpInsn(opcode, label); - } - - @Override - public void visitInsn(int opcode) { - if (!mStartLoadingAssert || opcode != Opcodes.ATHROW) { - super.visitInsn(opcode); - } else { - super.visitMethodInsn(Opcodes.INVOKESTATIC, BUILD_HOOKS, INSERT_INSTRUCTION_NAME, - INSERT_INSTRUCTION_DESC, INSERT_INSTRUCTION_ITF); - super.visitJumpInsn(Opcodes.GOTO, mGotoLabel); - mStartLoadingAssert = false; - mGotoLabel = null; - } - } - } -} \ No newline at end of file
diff --git a/build/android/bytecode/java/org/chromium/bytecode/ByteCodeProcessor.java b/build/android/bytecode/java/org/chromium/bytecode/ByteCodeProcessor.java index 2a4d08a..485a42dd 100644 --- a/build/android/bytecode/java/org/chromium/bytecode/ByteCodeProcessor.java +++ b/build/android/bytecode/java/org/chromium/bytecode/ByteCodeProcessor.java
@@ -46,9 +46,8 @@ * Java application that takes in an input jar, performs a series of bytecode transformations, * and generates an output jar. * - * Two types of transformations are performed: - * 1) Enabling assertions via {@link AssertionEnablerClassAdapter} - * 2) Providing support for custom resources via {@link CustomResourcesClassAdapter} + * One type of transformation are performed: + * 1) Providing support for custom resources via {@link CustomResourcesClassAdapter} */ class ByteCodeProcessor { private static final String CLASS_FILE_SUFFIX = ".class"; @@ -56,7 +55,6 @@ private static final int BUFFER_SIZE = 16384; private static boolean sVerbose; private static boolean sIsPrebuilt; - private static boolean sShouldAssert; private static boolean sShouldUseCustomResources; private static boolean sShouldUseThreadAnnotations; private static boolean sShouldCheckClassPath; @@ -129,9 +127,6 @@ if (sShouldUseThreadAnnotations) { chain = new ThreadAssertionClassAdapter(chain); } - if (sShouldAssert) { - chain = new AssertionEnablerClassAdapter(chain); - } if (sShouldUseCustomResources) { chain = new CustomResourcesClassAdapter( chain, reader.getClassName(), reader.getSuperName(), sFullClassPathClassLoader); @@ -252,7 +247,6 @@ String outputJarPath = args[currIndex++]; sVerbose = args[currIndex++].equals("--verbose"); sIsPrebuilt = args[currIndex++].equals("--is-prebuilt"); - sShouldAssert = args[currIndex++].equals("--enable-assert"); sShouldUseCustomResources = args[currIndex++].equals("--enable-custom-resources"); sShouldUseThreadAnnotations = args[currIndex++].equals("--enable-thread-annotations"); sShouldCheckClassPath = args[currIndex++].equals("--enable-check-class-path");
diff --git a/build/android/gyp/bytecode_processor.py b/build/android/gyp/bytecode_processor.py index 76775d3..86aa46ec 100755 --- a/build/android/gyp/bytecode_processor.py +++ b/build/android/gyp/bytecode_processor.py
@@ -33,7 +33,6 @@ parser.add_argument('-v', '--verbose', action='store_true') _AddSwitch(parser, '--is-prebuilt') _AddSwitch(parser, '--enable-custom-resources') - _AddSwitch(parser, '--enable-assert') _AddSwitch(parser, '--enable-thread-annotations') _AddSwitch(parser, '--enable-check-class-path') args = parser.parse_args(argv) @@ -55,8 +54,8 @@ cmd = ([ args.script, args.input_jar, args.output_jar, verbose, args.is_prebuilt, - args.enable_assert, args.enable_custom_resources, - args.enable_thread_annotations, args.enable_check_class_path, + args.enable_custom_resources, args.enable_thread_annotations, + args.enable_check_class_path, str(len(sdk_jars)) ] + sdk_jars + [str(len(direct_jars))] + direct_jars + extra_classpath_jars) subprocess.check_call(cmd)
diff --git a/build/android/gyp/dex.py b/build/android/gyp/dex.py index 0285ce3..813b180 100755 --- a/build/android/gyp/dex.py +++ b/build/android/gyp/dex.py
@@ -82,6 +82,11 @@ 'unobfuscated symbols present in the code. If not present, the jar ' 'is assumed not to be obfuscated.')) + parser.add_argument( + '--force-enable-assertions', + action='store_true', + help='Forcefully enable javac generated assertion code.') + options = parser.parse_args(args) if options.dexlayout_profile: @@ -427,6 +432,9 @@ if options.min_api: dex_cmd += ['--min-api', options.min_api] + if options.force_enable_assertions: + dex_cmd += ['--force-enable-assertions'] + md5_check.CallAndWriteDepfileIfStale( lambda changes: _OnStaleMd5(changes, options, final_dex_inputs, dex_cmd), options,
diff --git a/build/android/gyp/proguard.py b/build/android/gyp/proguard.py index 5acd831..aabbfeaf 100755 --- a/build/android/gyp/proguard.py +++ b/build/android/gyp/proguard.py
@@ -161,6 +161,11 @@ action='store_true', help='Disable -checkdiscard directives') parser.add_argument('--sourcefile', help='Value for source file attribute') + parser.add_argument( + '--force-enable-assertions', + action='store_true', + help='Forcefully enable javac generated assertion code.') + options = parser.parse_args(args) @@ -241,6 +246,9 @@ if options.min_api: cmd += ['--min-api', options.min_api] + if options.force_enable_assertions: + cmd += ['--force-enable-assertions'] + if options.main_dex_rules_path: for main_dex_rule in options.main_dex_rules_path: cmd += ['--main-dex-rules', main_dex_rule]
diff --git a/build/android/pylib/utils/gold_utils.py b/build/android/pylib/utils/gold_utils.py index 1702553e..28b0118 100644 --- a/build/android/pylib/utils/gold_utils.py +++ b/build/android/pylib/utils/gold_utils.py
@@ -128,6 +128,11 @@ authentication process. |output| is the stdout + stderr of the authentication process. """ + if self._gold_properties.bypass_skia_gold_functionality: + logging.warning('Not actually authenticating with Gold due to ' + '--bypass-skia-gold-functionality being present.') + return 0, '' + auth_cmd = [GOLDCTL_BINARY, 'auth', '--work-dir', self._working_dir] if use_luci: auth_cmd.append('--luci') @@ -158,6 +163,11 @@ comparison process. |output| is the stdout + stderr of the comparison process. """ + if self._gold_properties.bypass_skia_gold_functionality: + logging.warning('Not actually comparing with Gold due to ' + '--bypass-skia-gold-functionality being present.') + return 0, '' + compare_cmd = [ GOLDCTL_BINARY, 'imgtest', @@ -243,6 +253,14 @@ A tuple (return_code, output). |return_code| is the return code of the diff process. |output| is the stdout + stderr of the diff process. """ + # Instead of returning that everything is okay and putting in dummy links, + # just fail since this should only be called when running locally and + # --bypass-skia-gold-functionality is only meant for use on the bots. + if self._gold_properties.bypass_skia_gold_functionality: + raise RuntimeError( + '--bypass-skia-gold-functionality is not supported when running ' + 'tests locally.') + # Output managers only support archived files, not directories, so we have # to use a temporary directory and later move the data into the archived # files. @@ -392,6 +410,7 @@ self._job_id = None self._local_pixel_tests = None self._no_luci_auth = None + self._bypass_skia_gold_functionality = None # Could in theory be configurable, but hard-coded for now since there's # no plan to support anything else. @@ -435,6 +454,10 @@ def patchset(self): return self._patchset + @property + def bypass_skia_gold_functionality(self): + return self._bypass_skia_gold_functionality + def _GetGitRevision(self): if not self._git_revision: # Automated tests should always pass the revision, so assume we're on @@ -469,6 +492,9 @@ if hasattr(args, 'no_luci_auth'): self._no_luci_auth = args.no_luci_auth + if hasattr(args, 'bypass_skia_gold_functionality'): + self._bypass_skia_gold_functionality = args.bypass_skia_gold_functionality + # Will be automatically determined later if needed. if not hasattr(args, 'git_revision') or not args.git_revision: return
diff --git a/build/android/pylib/utils/gold_utils_test.py b/build/android/pylib/utils/gold_utils_test.py index 924a6302..3882fe7 100755 --- a/build/android/pylib/utils/gold_utils_test.py +++ b/build/android/pylib/utils/gold_utils_test.py
@@ -25,6 +25,7 @@ 'gerrit_issue', 'gerrit_patchset', 'buildbucket_id', + 'bypass_skia_gold_functionality', ]) @@ -33,9 +34,11 @@ git_revision=None, gerrit_issue=None, gerrit_patchset=None, - buildbucket_id=None): + buildbucket_id=None, + bypass_skia_gold_functionality=None): return _SkiaGoldArgs(local_pixel_tests, no_luci_auth, git_revision, - gerrit_issue, gerrit_patchset, buildbucket_id) + gerrit_issue, gerrit_patchset, buildbucket_id, + bypass_skia_gold_functionality) def assertArgWith(test, arg_list, arg, value): @@ -212,18 +215,34 @@ @mock.patch('devil.utils.cmd_helper.GetCmdStatusOutputAndError') def test_commandOutputReturned(self, cmd_mock): cmd_mock.return_value = (1, 'Something bad :(', None) + args = createSkiaGoldArgs(git_revision='a') + sgp = gold_utils.SkiaGoldProperties(args) with tempfile_ext.NamedTemporaryDirectory() as working_dir: - session = gold_utils.SkiaGoldSession(working_dir, None) + session = gold_utils.SkiaGoldSession(working_dir, sgp) rc, stdout = session.Authenticate() self.assertEqual(cmd_mock.call_count, 1) self.assertEqual(rc, 1) self.assertEqual(stdout, 'Something bad :(') @mock.patch('devil.utils.cmd_helper.GetCmdStatusOutputAndError') + def test_bypassSkiaGoldFunctionality(self, cmd_mock): + cmd_mock.return_value = (None, None, None) + args = createSkiaGoldArgs( + git_revision='a', bypass_skia_gold_functionality=True) + sgp = gold_utils.SkiaGoldProperties(args) + with tempfile_ext.NamedTemporaryDirectory() as working_dir: + session = gold_utils.SkiaGoldSession(working_dir, sgp) + rc, _ = session.Authenticate() + self.assertEqual(rc, 0) + cmd_mock.assert_not_called() + + @mock.patch('devil.utils.cmd_helper.GetCmdStatusOutputAndError') def test_commandWithUseLuciTrue(self, cmd_mock): cmd_mock.return_value = (None, None, None) + args = createSkiaGoldArgs(git_revision='a') + sgp = gold_utils.SkiaGoldProperties(args) with tempfile_ext.NamedTemporaryDirectory() as working_dir: - session = gold_utils.SkiaGoldSession(working_dir, None) + session = gold_utils.SkiaGoldSession(working_dir, sgp) session.Authenticate(use_luci=True) self.assertIn('--luci', cmd_mock.call_args[0][0]) @@ -250,8 +269,10 @@ @mock.patch('devil.utils.cmd_helper.GetCmdStatusOutputAndError') def test_commandCommonArgs(self, cmd_mock): cmd_mock.return_value = (None, None, None) + args = createSkiaGoldArgs(git_revision='a') + sgp = gold_utils.SkiaGoldProperties(args) with tempfile_ext.NamedTemporaryDirectory() as working_dir: - session = gold_utils.SkiaGoldSession(working_dir, None) + session = gold_utils.SkiaGoldSession(working_dir, sgp) session.Authenticate() call_args = cmd_mock.call_args[0][0] self.assertIn('auth', call_args) @@ -274,6 +295,18 @@ self.assertEqual(stdout, 'Something bad :(') @mock.patch('devil.utils.cmd_helper.GetCmdStatusOutputAndError') + def test_bypassSkiaGoldFunctionality(self, cmd_mock): + cmd_mock.return_value = (None, None, None) + args = createSkiaGoldArgs( + git_revision='a', bypass_skia_gold_functionality=True) + sgp = gold_utils.SkiaGoldProperties(args) + with tempfile_ext.NamedTemporaryDirectory() as working_dir: + session = gold_utils.SkiaGoldSession(working_dir, sgp) + rc, _ = session.Compare(None, None, None, None) + self.assertEqual(rc, 0) + cmd_mock.assert_not_called() + + @mock.patch('devil.utils.cmd_helper.GetCmdStatusOutputAndError') def test_commandWithLocalPixelTestsTrue(self, cmd_mock): cmd_mock.return_value = (None, None, None) args = createSkiaGoldArgs(git_revision='a', local_pixel_tests=True) @@ -426,6 +459,17 @@ self.assertEqual(stdout, 'Something bad :(') @mock.patch('devil.utils.cmd_helper.GetCmdStatusOutputAndError') + def test_bypassSkiaGoldFunctionality(self, cmd_mock): + cmd_mock.return_value = (None, None, None) + args = createSkiaGoldArgs( + git_revision='a', bypass_skia_gold_functionality=True) + sgp = gold_utils.SkiaGoldProperties(args) + with tempfile_ext.NamedTemporaryDirectory() as working_dir: + session = gold_utils.SkiaGoldSession(working_dir, sgp) + with self.assertRaises(RuntimeError): + session.Diff(None, None, None, None) + + @mock.patch('devil.utils.cmd_helper.GetCmdStatusOutputAndError') def test_commandCommonArgs(self, cmd_mock): cmd_mock.return_value = (None, None, None) args = createSkiaGoldArgs(git_revision='a', local_pixel_tests=False) @@ -497,6 +541,8 @@ self.assertEqual(instance._issue, expected.get('gerrit_issue')) self.assertEqual(instance._patchset, expected.get('gerrit_patchset')) self.assertEqual(instance._job_id, expected.get('buildbucket_id')) + self.assertEqual(instance._bypass_skia_gold_functionality, + expected.get('bypass_skia_gold_functionality')) def test_initializeSkiaGoldAttributes_unsetLocal(self): args = createSkiaGoldArgs() @@ -518,6 +564,11 @@ sgp = gold_utils.SkiaGoldProperties(args) self.verifySkiaGoldProperties(sgp, {'no_luci_auth': True}) + def test_initializeSkiaGoldAttributes_bypassExplicitTrue(self): + args = createSkiaGoldArgs(bypass_skia_gold_functionality=True) + sgp = gold_utils.SkiaGoldProperties(args) + self.verifySkiaGoldProperties(sgp, {'bypass_skia_gold_functionality': True}) + def test_initializeSkiaGoldAttributes_explicitGitRevision(self): args = createSkiaGoldArgs(git_revision='a') sgp = gold_utils.SkiaGoldProperties(args)
diff --git a/build/android/test_runner.py b/build/android/test_runner.py index 539210f..fdf43e0 100755 --- a/build/android/test_runner.py +++ b/build/android/test_runner.py
@@ -588,6 +588,13 @@ help="Don't use the serve account provided by LUCI for authentication " 'with Skia Gold, instead relying on gsutil to be pre-authenticated. ' 'Meant for testing locally instead of on the bots.') + parser.add_argument( + '--bypass-skia-gold-functionality', + action='store_true', + default=False, + help='Bypass all interaction with Skia Gold, effectively disabling the ' + 'image comparison portion of any tests that use Gold. Only meant to be ' + 'used in case a Gold outage occurs and cannot be fixed quickly.') def AddJUnitTestOptions(parser):
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni index 40332f7..d40ac31 100644 --- a/build/config/android/internal_rules.gni +++ b/build/config/android/internal_rules.gni
@@ -1077,6 +1077,13 @@ inputs += [ _proguard_jar_path ] } + _enable_assert = is_java_debug || dcheck_always_on || report_java_assert + if (_enable_assert) { + # The default for generating dex file format is + # --force-disable-assertions. + args += [ "--force-enable-assertions" ] + } + if (defined(invoker.args)) { args += invoker.args } @@ -1439,6 +1446,13 @@ "--r8-jar-path", rebase_path(_r8_path, root_build_dir), ] + + _enable_assert = is_java_debug || dcheck_always_on || report_java_assert + if (_enable_assert) { + # The default for generating dex file format is + # --force-disable-assertions. + args += [ "--force-enable-assertions" ] + } } } } @@ -1522,10 +1536,6 @@ _input_jar_path = invoker.input_jar_path _output_jar_path = invoker.output_jar_path - _enable_assert = - defined(invoker.enable_build_hooks) && invoker.enable_build_hooks && - (is_java_debug || dcheck_always_on || report_java_assert) - _enable_custom_resources = defined(invoker.enable_build_hooks_android) && invoker.enable_build_hooks_android @@ -1537,7 +1547,7 @@ _skip_jetify = defined(invoker.skip_jetify) && invoker.skip_jetify _enable_bytecode_rewriter = - _enable_assert || _enable_custom_resources || _enable_thread_annotations + _enable_custom_resources || _enable_thread_annotations _is_prebuilt = defined(invoker.is_prebuilt) && invoker.is_prebuilt _enable_bytecode_checks = !defined(invoker.enable_bytecode_checks) || invoker.enable_bytecode_checks @@ -1552,7 +1562,6 @@ ]) if (defined(invoker.enable_bytecode_rewriter)) { not_needed([ - "_enable_assert", "_enable_custom_resources", "_enable_thread_annotations", ]) @@ -1644,9 +1653,6 @@ if (_is_prebuilt) { args += [ "--is-prebuilt" ] } - if (_enable_assert) { - args += [ "--enable-assert" ] - } if (_enable_custom_resources) { args += [ "--enable-custom-resources" ] } @@ -3542,7 +3548,6 @@ ]) is_prebuilt = _is_prebuilt supports_android = _supports_android - enable_build_hooks = _enable_build_hooks enable_build_hooks_android = _enable_build_hooks_android build_config = _build_config input_jar_path = _unprocessed_jar_path
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni index 49d6640..13a9631 100644 --- a/build/config/android/rules.gni +++ b/build/config/android/rules.gni
@@ -4076,6 +4076,7 @@ # See also extract_native_libraries. # ignore_proguard_configs: Whether to ignore proguard configs. # strip_resources: Whether to ignore android resources found in the .aar. + # custom_package: Java package for generated R.java files. # extract_native_libraries: Whether to extract .so files found in the .aar. # If the file contains .so, either extract_native_libraries or # ignore_native_libraries must be set. @@ -4205,6 +4206,7 @@ android_resources(_res_target_name) { forward_variables_from(invoker, [ + "custom_package", "create_srcjar", "deps", "testonly", @@ -4214,8 +4216,8 @@ deps = [] } deps += [ ":$_unpack_target_name" ] - android_manifest_dep = ":$_unpack_target_name" if (!_ignore_manifest) { + android_manifest_dep = ":$_unpack_target_name" android_manifest = "${_output_path}/AndroidManifest.xml" } sources = []
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1 index 55de6e6..e6a98ecee 100644 --- a/build/fuchsia/linux.sdk.sha1 +++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@ -0.20200326.1.1 \ No newline at end of file +0.20200326.2.1 \ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1 index 55de6e6..e6a98ecee 100644 --- a/build/fuchsia/mac.sdk.sha1 +++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@ -0.20200326.1.1 \ No newline at end of file +0.20200326.2.1 \ No newline at end of file
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogTest.java index c4876e9..cabdd9e 100644 --- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogTest.java +++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogTest.java
@@ -72,6 +72,7 @@ import org.junit.runner.RunWith; import org.chromium.base.test.util.CommandLineFlags; +import org.chromium.base.test.util.DisabledTest; import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.Restriction; import org.chromium.chrome.browser.ChromeActivity; @@ -560,6 +561,7 @@ @Test @MediumTest @Feature({"RenderTest"}) + @DisabledTest(message = "crbug.com/1065242") public void testRenderDialog_3Tabs_Landscape() throws Exception { final ChromeTabbedActivity cta = mActivityTestRule.getActivity(); prepareTabsWithThumbnail(mActivityTestRule, 3, 0, "about:blank");
diff --git a/chrome/android/java/monochrome_public_bundle__base_bundle_module.AndroidManifest.expected b/chrome/android/java/monochrome_public_bundle__base_bundle_module.AndroidManifest.expected index 3900b7e..e58e0c33 100644 --- a/chrome/android/java/monochrome_public_bundle__base_bundle_module.AndroidManifest.expected +++ b/chrome/android/java/monochrome_public_bundle__base_bundle_module.AndroidManifest.expected
@@ -80,7 +80,6 @@ android:protectionLevel="signature"/> <application android:allowBackup="false" - android:appComponentFactory="androidx.core.app.CoreComponentFactory" android:extractNativeLibs="false" android:icon="@drawable/ic_launcher" android:label="@string/app_name"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/Layout.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/Layout.java index a9159300..badc5bfa 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/Layout.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/Layout.java
@@ -24,7 +24,6 @@ import org.chromium.chrome.browser.compositor.scene_layer.SceneOverlayLayer; import org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager; import org.chromium.chrome.browser.tab.Tab; -import org.chromium.chrome.browser.tab.TabImpl; import org.chromium.chrome.browser.tabmodel.TabModel; import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.browser.tabmodel.TabModelUtils; @@ -885,16 +884,4 @@ protected void updateSceneLayer(RectF viewport, RectF contentViewport, LayerTitleCache layerTitleCache, TabContentManager tabContentManager, ResourceManager resourceManager, ChromeFullscreenManager fullscreenManager) {} - - /** - * Gets the full screen manager. - * @return The {@link ChromeFullscreenManager} manager, possibly null - */ - public ChromeFullscreenManager getFullscreenManager() { - if (mTabModelSelector == null) return null; - Tab tab = mTabModelSelector.getCurrentTab(); - if (tab == null) return null; - if (((TabImpl) tab).getActivity() == null) return null; - return ((TabImpl) tab).getActivity().getFullscreenManager(); - } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/JourneyLogger.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/JourneyLogger.java index 49f2d09a..6d1fada 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/payments/JourneyLogger.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/JourneyLogger.java
@@ -211,6 +211,15 @@ JourneyLoggerJni.get().setTriggerTime(mJourneyLoggerAndroid, JourneyLogger.this); } + /** + * Sets the ukm source id of payment app. + * @param sourceId A long indicating the ukm source id of the invoked payment app. + */ + public void setPaymentAppUkmSourceId(long sourceId) { + JourneyLoggerJni.get().setPaymentAppUkmSourceId( + mJourneyLoggerAndroid, JourneyLogger.this, sourceId); + } + @NativeMethods interface Natives { long initJourneyLoggerAndroid( @@ -241,5 +250,7 @@ void recordTransactionAmount(long nativeJourneyLoggerAndroid, JourneyLogger caller, String currency, String value, boolean completed); void setTriggerTime(long nativeJourneyLoggerAndroid, JourneyLogger caller); + void setPaymentAppUkmSourceId( + long nativeJourneyLoggerAndroid, JourneyLogger caller, long sourceId); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentApp.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentApp.java index a644bc89..fd16b971 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentApp.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentApp.java
@@ -351,4 +351,11 @@ public Set<String> getApplicationIdentifiersThatHideThisApp() { return null; } + + /** + * @return The ukm source id assigned to the payment app. + */ + public long getUkmSourceId() { + return 0; + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java index b9f5b54..9d354ad 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
@@ -1380,8 +1380,15 @@ mPaymentHandlerUi = new PaymentHandlerCoordinator(); ChromeActivity chromeActivity = ChromeActivity.fromWebContents(mWebContents); if (chromeActivity == null) return false; - return mPaymentHandlerUi.show(chromeActivity, url, mIsIncognito, + + boolean success = mPaymentHandlerUi.show(chromeActivity, url, mIsIncognito, paymentHandlerWebContentsObserver, /*uiObserver=*/this); + if (success) { + // UKM for payment app origin should get recorded only when the origin of the invoked + // payment app is shown to the user. + mJourneyLogger.setPaymentAppUkmSourceId(mInvokedPaymentApp.getUkmSourceId()); + } + return success; } @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/ServiceWorkerPaymentApp.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/ServiceWorkerPaymentApp.java index 43ece8c..0edc3b62 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/payments/ServiceWorkerPaymentApp.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/ServiceWorkerPaymentApp.java
@@ -62,6 +62,9 @@ /** Whether the app is ready for minial UI flow. */ private boolean mIsReadyForMinimalUI; + /** UKM source Id generated using the app's origin. */ + private long mUkmSourceId; + /** The account balance to be used in the minimal UI flow. */ @Nullable private String mAccountBalance; @@ -147,6 +150,7 @@ mAppName = name; mSwUri = null; mUseCache = false; + mUkmSourceId = 0; } /** @@ -193,6 +197,7 @@ mAppName = name; mSwUri = swUri; mUseCache = useCache; + mUkmSourceId = 0; } /** @@ -370,4 +375,12 @@ public Set<String> getApplicationIdentifiersThatHideThisApp() { return mPreferredRelatedApplicationIds; } + + @Override + public long getUkmSourceId() { + if (mUkmSourceId == 0) { + mUkmSourceId = ServiceWorkerPaymentAppBridge.getSourceIdForPaymentAppFromScope(mScope); + } + return mUkmSourceId; + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/ServiceWorkerPaymentAppBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/ServiceWorkerPaymentAppBridge.java index 229e09e8..fe255f4 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/payments/ServiceWorkerPaymentAppBridge.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/ServiceWorkerPaymentAppBridge.java
@@ -460,6 +460,15 @@ webContents, PaymentEventResponseType.PAYMENT_HANDLER_WINDOW_CLOSING); } + /** + * Get the ukm source id for the invoked payment app. + * @param swScope The scope of the invoked payment app. + */ + public static long getSourceIdForPaymentAppFromScope(URI swScope) { + return ServiceWorkerPaymentAppBridgeJni.get().getSourceIdForPaymentAppFromScope( + swScope.toString()); + } + @CalledByNative private static String getSupportedMethodFromMethodData(PaymentMethodData data) { return data.supportedMethod; @@ -685,5 +694,6 @@ PaymentDetailsModifier[] modifiers, String currency, PaymentHandlerFinder callback, ServiceWorkerPaymentApp app); void onClosingPaymentAppWindow(WebContents webContents, int reason); + long getSourceIdForPaymentAppFromScope(String swScope); } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/LocationBarLayoutTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/LocationBarLayoutTest.java index da0f564..2e2eadf 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/LocationBarLayoutTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/LocationBarLayoutTest.java
@@ -5,10 +5,15 @@ package org.chromium.chrome.browser.omnibox; import static android.support.test.espresso.Espresso.onView; +import static android.support.test.espresso.action.ViewActions.click; +import static android.support.test.espresso.assertion.ViewAssertions.matches; +import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; import static android.support.test.espresso.matcher.ViewMatchers.withId; import static android.view.View.GONE; import static android.view.View.VISIBLE; +import static org.hamcrest.Matchers.not; + import android.support.test.filters.SmallTest; import android.view.View; import android.widget.ImageButton; @@ -164,10 +169,11 @@ } private void setUrlBarTextAndFocus(String text) throws ExecutionException { + onView(withId(R.id.url_bar)).perform(click()); + TestThreadUtils.runOnUiThreadBlocking(new Callable<Void>() { @Override public Void call() throws InterruptedException { - getLocationBar().onUrlFocusChange(true); mActivityTestRule.typeInOmnibox(text, false); return null; } @@ -178,20 +184,22 @@ @SmallTest @Restriction(UiRestriction.RESTRICTION_TYPE_PHONE) public void testNotShowingVoiceSearchButtonIfUrlBarContainsText() throws ExecutionException { + // When there is text, the delete button should be visible. setUrlBarTextAndFocus("testing"); - Assert.assertEquals(getDeleteButton().getVisibility(), VISIBLE); - Assert.assertNotEquals(getMicButton().getVisibility(), VISIBLE); + onView(withId(R.id.delete_button)).check(matches(isDisplayed())); + onView(withId(R.id.mic_button)).check(matches(not(isDisplayed()))); } @Test @SmallTest @Restriction(UiRestriction.RESTRICTION_TYPE_PHONE) public void testShowingVoiceSearchButtonIfUrlBarIsEmpty() throws ExecutionException { + // When there's no text, the mic button should be visible. setUrlBarTextAndFocus(""); - Assert.assertNotEquals(getDeleteButton().getVisibility(), VISIBLE); - Assert.assertEquals(getMicButton().getVisibility(), VISIBLE); + onView(withId(R.id.mic_button)).check(matches(isDisplayed())); + onView(withId(R.id.delete_button)).check(matches(not(isDisplayed()))); } @Test
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index 43221a9..1b28de45 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -3106,6 +3106,8 @@ "apps/app_service/app_service_proxy.h", "apps/app_service/app_service_proxy_factory.cc", "apps/app_service/app_service_proxy_factory.h", + "apps/app_service/browser_app_launcher.cc", + "apps/app_service/browser_app_launcher.h", "apps/app_service/dip_px_util.cc", "apps/app_service/dip_px_util.h", "apps/app_service/launch_utils.cc",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 321a91a..2a901b0 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -4017,6 +4017,13 @@ kOsAll, FEATURE_VALUE_TYPE(features::kEnableAmbientAuthenticationInGuestSession)}, + {"enable-send-tab-to-self-omnibox-sending-animation", + flag_descriptions::kSendTabToSelfOmniboxSendingAnimationName, + flag_descriptions::kSendTabToSelfOmniboxSendingAnimationDescription, + kOsDesktop, + FEATURE_VALUE_TYPE( + send_tab_to_self::kSendTabToSelfOmniboxSendingAnimation)}, + {"enable-send-tab-to-self-when-signed-in", flag_descriptions::kSendTabToSelfWhenSignedInName, flag_descriptions::kSendTabToSelfWhenSignedInDescription, kOsAll,
diff --git a/chrome/browser/apps/app_service/app_service_proxy.cc b/chrome/browser/apps/app_service/app_service_proxy.cc index 77f913d..28cc51a3 100644 --- a/chrome/browser/apps/app_service/app_service_proxy.cc +++ b/chrome/browser/apps/app_service/app_service_proxy.cc
@@ -119,6 +119,8 @@ return; } + browser_app_launcher_ = std::make_unique<apps::BrowserAppLauncher>(profile_); + app_service_impl_ = std::make_unique<apps::AppServiceImpl>(profile_->GetPrefs()); app_service_impl_->BindReceiver(app_service_.BindNewPipeAndPassReceiver()); @@ -174,6 +176,10 @@ } #endif +BrowserAppLauncher& AppServiceProxy::BrowserAppLauncher() { + return *browser_app_launcher_; +} + apps::PreferredApps& AppServiceProxy::PreferredApps() { return preferred_apps_; }
diff --git a/chrome/browser/apps/app_service/app_service_proxy.h b/chrome/browser/apps/app_service/app_service_proxy.h index 7124481..1ebadfd0 100644 --- a/chrome/browser/apps/app_service/app_service_proxy.h +++ b/chrome/browser/apps/app_service/app_service_proxy.h
@@ -13,6 +13,7 @@ #include "base/containers/unique_ptr_adapters.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" +#include "chrome/browser/apps/app_service/browser_app_launcher.h" #include "chrome/services/app_service/public/cpp/app_registry_cache.h" #include "chrome/services/app_service/public/cpp/icon_cache.h" #include "chrome/services/app_service/public/cpp/icon_coalescer.h" @@ -73,12 +74,15 @@ mojo::Remote<apps::mojom::AppService>& AppService(); apps::AppRegistryCache& AppRegistryCache(); - apps::PreferredApps& PreferredApps(); #if defined(OS_CHROMEOS) apps::InstanceRegistry& InstanceRegistry(); #endif + BrowserAppLauncher& BrowserAppLauncher(); + + apps::PreferredApps& PreferredApps(); + // apps::IconLoader overrides. apps::mojom::IconKeyPtr GetIconKey(const std::string& app_id) override; std::unique_ptr<IconLoader::Releaser> LoadIconFromIconKey( @@ -364,6 +368,11 @@ Profile* profile_; + // TODO(crbug.com/1061843): Remove BrowserAppLauncher and merge the interfaces + // to AppServiceProxy when publishers(ExtensionApps and WebApps) can run on + // Chrome. + std::unique_ptr<apps::BrowserAppLauncher> browser_app_launcher_; + using UninstallDialogs = std::set<std::unique_ptr<apps::UninstallDialog>, base::UniquePtrComparator>; UninstallDialogs uninstall_dialogs_;
diff --git a/chrome/browser/apps/app_service/browser_app_launcher.cc b/chrome/browser/apps/app_service/browser_app_launcher.cc new file mode 100644 index 0000000..0f1edf1b --- /dev/null +++ b/chrome/browser/apps/app_service/browser_app_launcher.cc
@@ -0,0 +1,59 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/apps/app_service/browser_app_launcher.h" + +#include "base/command_line.h" +#include "base/feature_list.h" +#include "base/files/file_path.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/extensions/application_launch.h" +#include "chrome/browser/ui/web_applications/web_app_launch_manager.h" +#include "chrome/common/chrome_features.h" +#include "extensions/browser/extension_registry.h" +#include "extensions/common/extension.h" + +namespace apps { + +BrowserAppLauncher::BrowserAppLauncher(Profile* profile) : profile_(profile) { + if (base::FeatureList::IsEnabled(features::kDesktopPWAsWithoutExtensions) || + base::FeatureList::IsEnabled(features::kDesktopPWAsUnifiedLaunch)) { + web_app_launch_manager_ = + std::make_unique<web_app::WebAppLaunchManager>(profile); + } +} + +BrowserAppLauncher::~BrowserAppLauncher() = default; + +void BrowserAppLauncher::LaunchAppWithCallback( + const std::string& app_id, + const base::FilePath& current_directory, + base::OnceCallback<void(Browser* browser, + apps::mojom::LaunchContainer container)> callback) { + // TODO(crbug.com/1061843): Remove command_line from AppLaunchParams, and get + // command line from the current process in GetLaunchFilesFromCommandLine + auto& command_line = *base::CommandLine::ForCurrentProcess(); + + // old-style app shortcuts + if (app_id.empty()) { + ::LaunchAppWithCallback(profile_, app_id, command_line, current_directory, + std::move(callback)); + return; + } + + const extensions::Extension* extension = + extensions::ExtensionRegistry::Get(profile_)->GetInstalledExtension( + app_id); + if ((!extension || extension->from_bookmark()) && web_app_launch_manager_) { + web_app_launch_manager_->LaunchApplication( + app_id, command_line, current_directory, std::move(callback)); + return; + } + + ::LaunchAppWithCallback(profile_, app_id, command_line, current_directory, + std::move(callback)); +} + +} // namespace apps
diff --git a/chrome/browser/apps/app_service/browser_app_launcher.h b/chrome/browser/apps/app_service/browser_app_launcher.h new file mode 100644 index 0000000..3812e8dd --- /dev/null +++ b/chrome/browser/apps/app_service/browser_app_launcher.h
@@ -0,0 +1,60 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_APPS_APP_SERVICE_BROWSER_APP_LAUNCHER_H_ +#define CHROME_BROWSER_APPS_APP_SERVICE_BROWSER_APP_LAUNCHER_H_ + +#include <memory> +#include <string> + +#include "base/callback.h" +#include "components/services/app_service/public/mojom/types.mojom.h" + +class Browser; +class Profile; + +namespace base { +class FilePath; +} // namespace base + +namespace web_app { +class WebAppLaunchManager; +} // namespace web_app + +namespace apps { + +// BrowserAppLauncher receives app launch requests and forwards them to +// extensions or WebAppLaunchManager, based on the app type. +// +// TODO(crbug.com/1061843): Remove BrowserAppLauncher and merge the interfaces +// to AppServiceProxy when publishers(ExtensionApps and WebApps) can run on +// Chrome. +class BrowserAppLauncher { + public: + explicit BrowserAppLauncher(Profile* profile); + ~BrowserAppLauncher(); + + BrowserAppLauncher(const BrowserAppLauncher&) = delete; + BrowserAppLauncher& operator=(const BrowserAppLauncher&) = delete; + + // Attempt to open |app_id| in a new window or tab. Open an empty browser + // window if unsuccessful. The user's preferred launch container for the app + // (standalone window or browser tab) is used. |callback| will be called with + // the container type used to open the app, kLaunchContainerNone if an empty + // browser window was opened. + void LaunchAppWithCallback( + const std::string& app_id, + const base::FilePath& current_directory, + base::OnceCallback<void(Browser* browser, + apps::mojom::LaunchContainer container)> + callback); + + private: + Profile* const profile_; + std::unique_ptr<web_app::WebAppLaunchManager> web_app_launch_manager_; +}; + +} // namespace apps + +#endif // CHROME_BROWSER_APPS_APP_SERVICE_BROWSER_APP_LAUNCHER_H_
diff --git a/chrome/browser/apps/app_service/web_apps.cc b/chrome/browser/apps/app_service/web_apps.cc index f7e779d8..b41bc9f 100644 --- a/chrome/browser/apps/app_service/web_apps.cc +++ b/chrome/browser/apps/app_service/web_apps.cc
@@ -595,6 +595,7 @@ app->name = web_app->name(); app->short_name = web_app->name(); app->description = web_app->description(); + app->additional_search_terms = web_app->additional_search_terms(); bool paused = paused_apps_.IsPaused(web_app->app_id()); app->icon_key =
diff --git a/chrome/browser/apps/launch_service/extension_app_launch_manager.cc b/chrome/browser/apps/launch_service/extension_app_launch_manager.cc index 42a50ff9..d3023f89 100644 --- a/chrome/browser/apps/launch_service/extension_app_launch_manager.cc +++ b/chrome/browser/apps/launch_service/extension_app_launch_manager.cc
@@ -43,26 +43,4 @@ return ::OpenApplication(profile(), params); } -void ExtensionAppLaunchManager::LaunchApplication( - const std::string& app_id, - const base::CommandLine& command_line, - const base::FilePath& current_directory, - base::OnceCallback<void(Browser* browser, - apps::mojom::LaunchContainer container)> callback) { - apps::mojom::LaunchContainer container; - if (OpenExtensionApplicationWindow(profile(), app_id, command_line, - current_directory)) { - RecordBookmarkLaunch(profile(), app_id); - container = apps::mojom::LaunchContainer::kLaunchContainerWindow; - } else if (OpenExtensionApplicationTab(profile(), app_id)) { - container = apps::mojom::LaunchContainer::kLaunchContainerTab; - } else { - // Open an empty browser window as the app_id is invalid. - CreateBrowserWithNewTabPage(profile()); - container = apps::mojom::LaunchContainer::kLaunchContainerNone; - } - std::move(callback).Run(BrowserList::GetInstance()->GetLastActive(), - container); -} - } // namespace apps
diff --git a/chrome/browser/apps/launch_service/extension_app_launch_manager.h b/chrome/browser/apps/launch_service/extension_app_launch_manager.h index fab74e4..75758f2d8 100644 --- a/chrome/browser/apps/launch_service/extension_app_launch_manager.h +++ b/chrome/browser/apps/launch_service/extension_app_launch_manager.h
@@ -22,14 +22,6 @@ // apps::LaunchManager: content::WebContents* OpenApplication(const AppLaunchParams& params) override; - void LaunchApplication( - const std::string& app_id, - const base::CommandLine& command_line, - const base::FilePath& current_directory, - base::OnceCallback<void(Browser* browser, - apps::mojom::LaunchContainer container)> callback) - override; - private: DISALLOW_COPY_AND_ASSIGN(ExtensionAppLaunchManager); };
diff --git a/chrome/browser/apps/launch_service/launch_manager.h b/chrome/browser/apps/launch_service/launch_manager.h index 8ca4a123..2ca2699 100644 --- a/chrome/browser/apps/launch_service/launch_manager.h +++ b/chrome/browser/apps/launch_service/launch_manager.h
@@ -6,20 +6,12 @@ #define CHROME_BROWSER_APPS_LAUNCH_SERVICE_LAUNCH_MANAGER_H_ #include <string> -#include <vector> -#include "base/callback.h" #include "base/macros.h" #include "components/services/app_service/public/mojom/types.mojom.h" -class Browser; class Profile; -namespace base { -class CommandLine; -class FilePath; -} // namespace base - namespace content { class WebContents; } @@ -37,19 +29,6 @@ virtual content::WebContents* OpenApplication( const AppLaunchParams& params) = 0; - // Attempt to open |app_id| in a new window or tab. Open an empty browser - // window if unsuccessful. The user's preferred launch container for the app - // (standalone window or browser tab) is used. |callback| will be called with - // the container type used to open the app, kLaunchContainerNone if an empty - // browser window was opened. - virtual void LaunchApplication( - const std::string& app_id, - const base::CommandLine& command_line, - const base::FilePath& current_directory, - base::OnceCallback<void(Browser* browser, - apps::mojom::LaunchContainer container)> - callback) = 0; - protected: explicit LaunchManager(Profile*); Profile* profile() { return profile_; }
diff --git a/chrome/browser/apps/launch_service/launch_service.cc b/chrome/browser/apps/launch_service/launch_service.cc index cbbd0e8..6e4727e 100644 --- a/chrome/browser/apps/launch_service/launch_service.cc +++ b/chrome/browser/apps/launch_service/launch_service.cc
@@ -10,7 +10,6 @@ #include "chrome/browser/apps/launch_service/launch_service_factory.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/web_applications/web_app_launch_manager.h" -#include "chrome/browser/web_applications/web_app_provider.h" #include "chrome/common/chrome_features.h" #include "extensions/browser/extension_registry.h" #include "extensions/common/extension.h" @@ -48,16 +47,6 @@ return GetLaunchManagerForApp(params.app_id).OpenApplication(params); } -void LaunchService::LaunchApplication( - const std::string& app_id, - const base::CommandLine& command_line, - const base::FilePath& current_directory, - base::OnceCallback<void(Browser* browser, - apps::mojom::LaunchContainer container)> callback) { - GetLaunchManagerForApp(app_id).LaunchApplication( - app_id, command_line, current_directory, std::move(callback)); -} - LaunchManager& LaunchService::GetLaunchManagerForApp( const std::string& app_id) { // --app old-style app shortcuts
diff --git a/chrome/browser/apps/launch_service/launch_service.h b/chrome/browser/apps/launch_service/launch_service.h index 50183fa..a779117a5 100644 --- a/chrome/browser/apps/launch_service/launch_service.h +++ b/chrome/browser/apps/launch_service/launch_service.h
@@ -8,19 +8,12 @@ #include <memory> #include <string> -#include "base/callback.h" #include "base/macros.h" #include "components/keyed_service/core/keyed_service.h" #include "components/services/app_service/public/mojom/types.mojom.h" -class Browser; class Profile; -namespace base { -class CommandLine; -class FilePath; -} // namespace base - namespace content { class WebContents; } @@ -47,19 +40,6 @@ // Open the application in a way specified by |params|. content::WebContents* OpenApplication(const AppLaunchParams& params); - // Attempt to open |app_id| in a new window or tab. Open an empty browser - // window if unsuccessful. The user's preferred launch container for the app - // (standalone window or browser tab) is used. |callback| will be called with - // the container type used to open the app, kLaunchContainerNone if an empty - // browser window was opened. - void LaunchApplication( - const std::string& app_id, - const base::CommandLine& command_line, - const base::FilePath& current_directory, - base::OnceCallback<void(Browser* browser, - apps::mojom::LaunchContainer container)> - callback); - private: LaunchManager& GetLaunchManagerForApp(const std::string& app_id);
diff --git a/chrome/browser/browser_keyevents_browsertest.cc b/chrome/browser/browser_keyevents_browsertest.cc index b31f168..7f22a582 100644 --- a/chrome/browser/browser_keyevents_browsertest.cc +++ b/chrome/browser/browser_keyevents_browsertest.cc
@@ -294,13 +294,7 @@ } }; -#if defined(OS_MACOSX) -// http://crbug.com/81451 -#define MAYBE_NormalKeyEvents DISABLED_NormalKeyEvents -#else -#define MAYBE_NormalKeyEvents NormalKeyEvents -#endif -IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, MAYBE_NormalKeyEvents) { +IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, NormalKeyEvents) { static const KeyEventTestData kTestNoInput[] = { // a { ui::VKEY_A, false, false, false, false, @@ -701,9 +695,6 @@ #if defined(OS_MACOSX) IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, EditorKeyBindings) { - // TODO(kbr): re-enable: http://crbug.com/222296 - return; - static const KeyEventTestData kTestCtrlA = { ui::VKEY_A, true, false, false, false, false, false, false, false, 4,
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn index 507294c6..5d29da10 100644 --- a/chrome/browser/chromeos/BUILD.gn +++ b/chrome/browser/chromeos/BUILD.gn
@@ -111,6 +111,7 @@ "//chromeos/components/quick_answers/public/cpp:prefs", "//chromeos/components/smbfs", "//chromeos/components/smbfs/mojom", + "//chromeos/components/sync_wifi", "//chromeos/components/tether", "//chromeos/constants", "//chromeos/cryptohome", @@ -1272,6 +1273,10 @@ "input_method/input_method_syncer.h", "input_method/native_input_method_engine.cc", "input_method/native_input_method_engine.h", + "input_method/personal_info_suggester.cc", + "input_method/personal_info_suggester.h", + "input_method/suggester.h", + "input_method/suggestion_enums.h", "input_method/suggestion_window_controller.cc", "input_method/suggestion_window_controller.h", "input_method/suggestion_window_controller_impl.cc",
diff --git a/chrome/browser/chromeos/accessibility/speech_monitor.cc b/chrome/browser/chromeos/accessibility/speech_monitor.cc index ac0ce3b..0d84ff4 100644 --- a/chrome/browser/chromeos/accessibility/speech_monitor.cc +++ b/chrome/browser/chromeos/accessibility/speech_monitor.cc
@@ -214,6 +214,21 @@ "ExpectNextSpeechIsNot(\"" + text + "\") " + location.ToString()}); } +void SpeechMonitor::ExpectNextSpeechIsNotPattern( + const std::string& pattern, + const base::Location& location) { + CHECK(!replay_loop_runner_.get()); + replay_queue_.push_back({[this, pattern]() { + if (utterance_queue_.empty()) + return false; + + return !base::MatchPattern( + utterance_queue_.front().text, pattern); + }, + "ExpectNextSpeechIsNotPattern(\"" + pattern + + "\") " + location.ToString()}); +} + void SpeechMonitor::Call(std::function<void()> func, const base::Location& location) { CHECK(!replay_loop_runner_.get()); @@ -230,9 +245,19 @@ } void SpeechMonitor::MaybeContinueReplay() { + // This method can be called prior to Replay() being called. + if (!replay_called_) + return; + auto it = replay_queue_.begin(); while (it != replay_queue_.end()) { if (it->first()) { + // Careful here; the above callback may have triggered more speech which + // causes |MaybeContinueReplay| to be called recursively. We have to + // ensure to check |replay_queue_| here. + if (replay_queue_.empty()) + break; + replayed_queue_.push_back(it->second); it = replay_queue_.erase(it); } else { @@ -240,7 +265,7 @@ } } - if (replay_queue_.size() > 0) { + if (!replay_queue_.empty()) { base::PostDelayedTask( FROM_HERE, {content::BrowserThread::UI}, base::BindOnce(&SpeechMonitor::MaybePrintExpectations,
diff --git a/chrome/browser/chromeos/accessibility/speech_monitor.h b/chrome/browser/chromeos/accessibility/speech_monitor.h index 84537857..eb319a6 100644 --- a/chrome/browser/chromeos/accessibility/speech_monitor.h +++ b/chrome/browser/chromeos/accessibility/speech_monitor.h
@@ -69,6 +69,8 @@ const base::Location& location = FROM_HERE); void ExpectNextSpeechIsNot(const std::string& text, const base::Location& location = FROM_HERE); + void ExpectNextSpeechIsNotPattern(const std::string& pattern, + const base::Location& location = FROM_HERE); // Adds a call to be included in replay. void Call(std::function<void()> func,
diff --git a/chrome/browser/chromeos/accessibility/spoken_feedback_app_list_browsertest.cc b/chrome/browser/chromeos/accessibility/spoken_feedback_app_list_browsertest.cc index 0ff8db8..055e0effa 100644 --- a/chrome/browser/chromeos/accessibility/spoken_feedback_app_list_browsertest.cc +++ b/chrome/browser/chromeos/accessibility/spoken_feedback_app_list_browsertest.cc
@@ -140,34 +140,32 @@ EXPECT_TRUE(PerformAcceleratorAction(ash::FOCUS_SHELF)); - while (sm_.GetNextUtterance() != "Press Search plus Space to activate") { - } + sm_.ExpectSpeech("Shelf"); // Press space on the launcher button in shelf, this opens peeking launcher. - SendKeyPressWithSearch(ui::VKEY_SPACE); - while (sm_.GetNextUtterance() != "Launcher, partial view") { - } + sm_.Call([this]() { SendKeyPressWithSearch(ui::VKEY_SPACE); }); + sm_.ExpectSpeech("Launcher, partial view"); // Send a key press to enable keyboard traversal - SendKeyPressWithSearchAndShift(ui::VKEY_TAB); + sm_.Call([this]() { SendKeyPressWithSearchAndShift(ui::VKEY_TAB); }); // Move focus to expand all apps button. - SendKeyPressWithSearchAndShift(ui::VKEY_TAB); - while (sm_.GetNextUtterance() != "Press Search plus Space to activate") { - } + sm_.Call([this]() { SendKeyPressWithSearchAndShift(ui::VKEY_TAB); }); + sm_.ExpectSpeech("Expand to all apps"); // Press space on expand arrow to go to fullscreen launcher. - SendKeyPressWithSearch(ui::VKEY_SPACE); - while (sm_.GetNextUtterance() != "Launcher, all apps") { - } + sm_.Call([this]() { SendKeyPressWithSearch(ui::VKEY_SPACE); }); + sm_.ExpectSpeech("Launcher, all apps"); // Make sure the first traversal left is not the expand arrow button. - SendKeyPressWithSearch(ui::VKEY_LEFT); - EXPECT_NE("Expand to all apps", sm_.GetNextUtterance()); + sm_.Call([this]() { SendKeyPressWithSearch(ui::VKEY_LEFT); }); + sm_.ExpectNextSpeechIsNot("Expand to all apps"); // Make sure the second traversal left is not the expand arrow button. - SendKeyPressWithSearch(ui::VKEY_LEFT); - EXPECT_NE("Expand to all apps", sm_.GetNextUtterance()); + sm_.Call([this]() { SendKeyPressWithSearch(ui::VKEY_LEFT); }); + sm_.ExpectNextSpeechIsNot("Expand to all apps"); + + sm_.Replay(); } IN_PROC_BROWSER_TEST_P(SpokenFeedbackAppListTest, @@ -256,61 +254,49 @@ sm_.Replay(); } -// TODO(newcomer): reimplement this test once the AppListFocus changes are -// complete (http://crbug.com/784942). -IN_PROC_BROWSER_TEST_P(SpokenFeedbackAppListTest, - DISABLED_NavigateAppLauncher) { +IN_PROC_BROWSER_TEST_P(SpokenFeedbackAppListTest, NavigateAppLauncher) { EnableChromeVox(); + // Add one app to the applist. + PopulateApps(1); + EXPECT_TRUE(PerformAcceleratorAction(ash::FOCUS_SHELF)); // Wait for it to say "Launcher", "Button", "Shelf", "Tool bar". - while (true) { - std::string utterance = sm_.GetNextUtterance(); - if (base::MatchPattern(utterance, "Launcher")) - break; - } - EXPECT_EQ("Button", sm_.GetNextUtterance()); - EXPECT_EQ("Shelf", sm_.GetNextUtterance()); - EXPECT_EQ("Tool bar", sm_.GetNextUtterance()); + sm_.ExpectSpeechPattern("Launcher"); + sm_.ExpectSpeech("Button"); + sm_.ExpectSpeech("Shelf"); + sm_.ExpectSpeech("Tool bar"); // Click on the launcher, it brings up the app list UI. - SendKeyPress(ui::VKEY_SPACE); - while ("Search or type URL" != sm_.GetNextUtterance()) { - } - while ("Edit text" != sm_.GetNextUtterance()) { - } + sm_.Call([this]() { SendKeyPress(ui::VKEY_SPACE); }); + sm_.ExpectSpeech( + "Search your device, apps, and web. Use the arrow keys to navigate your " + "apps."); + sm_.ExpectSpeech("Edit text"); // Close it and open it again. - SendKeyPress(ui::VKEY_ESCAPE); - while (true) { - std::string utterance = sm_.GetNextUtterance(); - if (base::MatchPattern(utterance, "*window*")) - break; - } + sm_.Call([this]() { SendKeyPress(ui::VKEY_ESCAPE); }); + sm_.ExpectSpeechPattern("*window*"); - EXPECT_TRUE(PerformAcceleratorAction(ash::FOCUS_SHELF)); - while (true) { - std::string utterance = sm_.GetNextUtterance(); - if (base::MatchPattern(utterance, "Button")) - break; - } - SendKeyPress(ui::VKEY_SPACE); + sm_.Call( + [this]() { EXPECT_TRUE(PerformAcceleratorAction(ash::FOCUS_SHELF)); }); + sm_.ExpectSpeechPattern("Launcher"); + sm_.ExpectSpeech("Button"); - // Now type a space into the text field and wait until we hear "space". - // This makes the test more robust as it allows us to skip over other - // speech along the way. - SendKeyPress(ui::VKEY_SPACE); - while (true) { - if ("space" == sm_.GetNextUtterance()) - break; - } + sm_.Call([this]() { SendKeyPress(ui::VKEY_SPACE); }); + sm_.ExpectSpeech( + "Search your device, apps, and web. Use the arrow keys to navigate your " + "apps."); - // Now press the down arrow and we should be focused on an app button + // Now press the right arrow and we should be focused on an app button // in a dialog. - SendKeyPress(ui::VKEY_DOWN); - while ("Button" != sm_.GetNextUtterance()) { - } + // THis doesn't work though (to be done below). + + // TODO(newcomer): reimplement this test once the AppListFocus changes are + // complete (http://crbug.com/784942). + + sm_.Replay(); } } // namespace chromeos
diff --git a/chrome/browser/chromeos/accessibility/spoken_feedback_browsertest.cc b/chrome/browser/chromeos/accessibility/spoken_feedback_browsertest.cc index bad2403..201bab8 100644 --- a/chrome/browser/chromeos/accessibility/spoken_feedback_browsertest.cc +++ b/chrome/browser/chromeos/accessibility/spoken_feedback_browsertest.cc
@@ -89,6 +89,11 @@ nullptr, key, true, false, false, false))); } +void LoggedInSpokenFeedbackTest::SendKeyPressWithShift(ui::KeyboardCode key) { + ASSERT_NO_FATAL_FAILURE(ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync( + nullptr, key, false, true, false, false))); +} + void LoggedInSpokenFeedbackTest::SendKeyPressWithSearchAndShift( ui::KeyboardCode key) { ASSERT_NO_FATAL_FAILURE(ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync( @@ -112,6 +117,12 @@ nullptr, key, true, true, false, true))); } +void LoggedInSpokenFeedbackTest::SendStickyKeyCommand() { + // To avoid flakes in sending keys, execute the command directly in js. + RunJavaScriptInChromeVoxBackgroundPage( + "CommandHandler.onCommand('toggleStickyMode');"); +} + void LoggedInSpokenFeedbackTest::SendMouseMoveTo(const gfx::Point& location) { ASSERT_NO_FATAL_FAILURE( ASSERT_TRUE(ui_controls::SendMouseMove(location.x(), location.y()))); @@ -123,7 +134,7 @@ extensions::ProcessManager::Get(browser()->profile()) ->GetBackgroundHostForExtension( extension_misc::kChromeVoxExtensionId); - CHECK(content::ExecuteScript(host->host_contents(), script)); + content::ExecuteScriptAsync(host->host_contents(), script); } void LoggedInSpokenFeedbackTest::SimulateTouchScreenInChromeVox() { @@ -174,85 +185,75 @@ } } -// This test is very flakey with ChromeVox Next since we generate a lot more -// utterances for text fields. -// TODO(dtseng): Fix properly. -IN_PROC_BROWSER_TEST_F(LoggedInSpokenFeedbackTest, DISABLED_AddBookmark) { +IN_PROC_BROWSER_TEST_F(LoggedInSpokenFeedbackTest, AddBookmark) { EnableChromeVox(); chrome::ExecuteCommand(browser(), IDC_SHOW_BOOKMARK_BAR); // Create a bookmark with title "foo". chrome::ExecuteCommand(browser(), IDC_BOOKMARK_THIS_TAB); - EXPECT_EQ("Bookmark added! dialog Bookmark name about:blank Edit text", - sm_.GetNextUtterance()); - EXPECT_EQ("about:blank", sm_.GetNextUtterance()); - SendKeyPress(ui::VKEY_F); - EXPECT_EQ("f", sm_.GetNextUtterance()); - SendKeyPress(ui::VKEY_O); - EXPECT_EQ("o", sm_.GetNextUtterance()); - SendKeyPress(ui::VKEY_O); - EXPECT_EQ("o", sm_.GetNextUtterance()); + sm_.ExpectSpeech("Bookmark name"); + sm_.ExpectSpeech("about:blank"); + sm_.ExpectSpeech("selected"); + sm_.ExpectSpeech("Edit text"); + sm_.ExpectSpeech("Bookmark added"); + sm_.ExpectSpeech("Dialog"); + sm_.ExpectSpeech("Bookmark added, window"); - SendKeyPress(ui::VKEY_TAB); - EXPECT_EQ("Bookmark folder combo Box Bookmarks bar", sm_.GetNextUtterance()); + sm_.Call([this]() { + SendKeyPress(ui::VKEY_F); + SendKeyPress(ui::VKEY_O); + SendKeyPress(ui::VKEY_O); + }); + sm_.ExpectSpeech("F"); + sm_.ExpectSpeech("O"); + sm_.ExpectSpeech("O"); - SendKeyPress(ui::VKEY_RETURN); + sm_.Call([this]() { SendKeyPress(ui::VKEY_TAB); }); + sm_.ExpectSpeech("Bookmark folder"); + sm_.ExpectSpeech("Bookmarks bar"); + sm_.ExpectSpeech("Button"); + sm_.ExpectSpeech("has pop up"); - EXPECT_TRUE(base::MatchPattern(sm_.GetNextUtterance(), "*oolbar*")); - // Wait for active window change to be announced to avoid interference from - // that below. - while (sm_.GetNextUtterance() != "window about blank tab") { - // Do nothing. - } + sm_.Call([this]() { SendKeyPress(ui::VKEY_TAB); }); + sm_.ExpectSpeech("More…"); + + sm_.Call([this]() { SendKeyPress(ui::VKEY_TAB); }); + sm_.ExpectSpeech("Remove"); + + sm_.Call([this]() { SendKeyPress(ui::VKEY_TAB); }); + sm_.ExpectSpeech("Done"); + + sm_.Call([this]() { SendKeyPress(ui::VKEY_RETURN); }); + // Focus goes back to window. + sm_.ExpectSpeechPattern("about:blank*"); // Focus bookmarks bar and listen for "foo". - chrome::ExecuteCommand(browser(), IDC_FOCUS_BOOKMARKS); - while (true) { - std::string utterance = sm_.GetNextUtterance(); - VLOG(0) << "Got utterance: " << utterance; - if (utterance == "Bookmarks,") - break; - } - EXPECT_EQ("foo,", sm_.GetNextUtterance()); - EXPECT_EQ("button", sm_.GetNextUtterance()); + sm_.Call( + [this]() { chrome::ExecuteCommand(browser(), IDC_FOCUS_BOOKMARKS); }); + sm_.ExpectSpeech("foo"); + sm_.ExpectSpeech("Button"); + sm_.ExpectSpeech("Bookmarks"); + sm_.ExpectSpeech("Tool bar"); + sm_.Replay(); } -IN_PROC_BROWSER_TEST_F(LoggedInSpokenFeedbackTest, - DISABLED_NavigateNotificationCenter) { +IN_PROC_BROWSER_TEST_F(LoggedInSpokenFeedbackTest, NavigateNotificationCenter) { EnableChromeVox(); EXPECT_TRUE(PerformAcceleratorAction(ash::TOGGLE_MESSAGE_CENTER_BUBBLE)); + sm_.ExpectSpeech( + "Quick Settings, Press search plus left to access the notification " + "center., window"); - // Tab to request the initial focus. - SendKeyPress(ui::VKEY_TAB); + sm_.Call([this]() { SendKeyPressWithSearch(ui::VKEY_LEFT); }); + // If you are hitting this in the course of changing the UI, please fix. This + // item needs a label. + sm_.ExpectSpeech("List item"); - // Wait for it to say "Notification Center, window". - while ("Notification Center, window" != sm_.GetNextUtterance()) { - } + // Furthermore, navigation is generally broken using Search+Left. - // Tab until we get to the Do Not Disturb button. - SendKeyPress(ui::VKEY_TAB); - do { - std::string ut = sm_.GetNextUtterance(); - - if (ut == "Do not disturb") - break; - else if (ut == "Button") - SendKeyPress(ui::VKEY_TAB); - } while (true); - EXPECT_EQ("Button", sm_.GetNextUtterance()); - EXPECT_EQ("Not pressed", sm_.GetNextUtterance()); - - SendKeyPress(ui::VKEY_SPACE); - EXPECT_EQ("Do not disturb", sm_.GetNextUtterance()); - EXPECT_EQ("Button", sm_.GetNextUtterance()); - EXPECT_EQ("Pressed", sm_.GetNextUtterance()); - - SendKeyPress(ui::VKEY_SPACE); - EXPECT_EQ("Do not disturb", sm_.GetNextUtterance()); - EXPECT_EQ("Button", sm_.GetNextUtterance()); - EXPECT_EQ("Not pressed", sm_.GetNextUtterance()); + sm_.Replay(); } // @@ -285,9 +286,7 @@ ::testing::Values(kTestAsNormalUser, kTestAsGuestUser)); -// TODO(tommi): Flakily hitting HasOneRef DCHECK in -// AudioOutputResampler::Shutdown, see crbug.com/630031. -IN_PROC_BROWSER_TEST_P(SpokenFeedbackTest, DISABLED_EnableSpokenFeedback) { +IN_PROC_BROWSER_TEST_P(SpokenFeedbackTest, EnableSpokenFeedback) { EnableChromeVox(); } @@ -299,21 +298,37 @@ EXPECT_EQ("Button", sm_.GetNextUtterance()); } -IN_PROC_BROWSER_TEST_P(SpokenFeedbackTest, DISABLED_TypeInOmnibox) { +IN_PROC_BROWSER_TEST_P(SpokenFeedbackTest, TypeInOmnibox) { EnableChromeVox(); - // Location bar has focus by default so just start typing. - SendKeyPress(ui::VKEY_X); - EXPECT_EQ("x", sm_.GetNextUtterance()); + ui_test_utils::NavigateToURL( + browser(), GURL("data:text/html;charset=utf-8,<p>unused</p>")); - SendKeyPress(ui::VKEY_Y); - EXPECT_EQ("y", sm_.GetNextUtterance()); + sm_.Call([this]() { SendKeyPressWithControl(ui::VKEY_L); }); + sm_.ExpectSpeech("Address and search bar"); - SendKeyPress(ui::VKEY_Z); - EXPECT_EQ("z", sm_.GetNextUtterance()); + sm_.Call([this]() { + // Select all the text. + SendKeyPressWithControl(ui::VKEY_A); - SendKeyPress(ui::VKEY_BACK); - EXPECT_EQ("z", sm_.GetNextUtterance()); + // Type x, y, and z. + SendKeyPress(ui::VKEY_X); + SendKeyPress(ui::VKEY_Y); + SendKeyPress(ui::VKEY_Z); + }); + sm_.ExpectSpeech("X"); + sm_.ExpectSpeech("Y"); + sm_.ExpectSpeech("Z"); + + sm_.Call([this]() { SendKeyPress(ui::VKEY_BACK); }); + sm_.ExpectSpeech("Z"); + + // Auto completions. + sm_.ExpectSpeech("xy search"); + sm_.ExpectSpeech("List item"); + sm_.ExpectSpeech("1 of 1"); + + sm_.Replay(); } IN_PROC_BROWSER_TEST_P(SpokenFeedbackTest, FocusShelf) { @@ -339,9 +354,7 @@ // Verifies that pressing right arrow button with search button should move // focus to the next ShelfItem instead of the last one -// (see https://crbug.com/947683). -// This test is flaky, see http://crbug.com/997628 -IN_PROC_BROWSER_TEST_P(SpokenFeedbackTest, DISABLED_ShelfIconFocusForward) { +IN_PROC_BROWSER_TEST_P(SpokenFeedbackTest, ShelfIconFocusForward) { const std::string title("MockApp"); ChromeLauncherController* controller = ChromeLauncherController::instance(); @@ -353,46 +366,42 @@ ash::ShelfID("FakeApp"), controller->shelf_model()->item_count(), base::ASCIIToUTF16(title)); - // Wait for the change on ShelfModel to reach ash. - base::RunLoop().RunUntilIdle(); - // Focus on the shelf. - EXPECT_TRUE(PerformAcceleratorAction(ash::FOCUS_SHELF)); - while (true) { - std::string utterance = sm_.GetNextUtterance(); - if (base::MatchPattern(utterance, "Launcher")) - break; - } - - ASSERT_EQ("Button", sm_.GetNextUtterance()); - ASSERT_EQ("Shelf", sm_.GetNextUtterance()); - ASSERT_EQ("Tool bar", sm_.GetNextUtterance()); - ASSERT_EQ(", window", sm_.GetNextUtterance()); - ASSERT_EQ("Press Search plus Space to activate", sm_.GetNextUtterance()); + sm_.Call([this]() { PerformAcceleratorAction(ash::FOCUS_SHELF); }); + sm_.ExpectSpeech("Launcher"); + sm_.ExpectSpeech("Button"); + sm_.ExpectSpeech("Shelf"); + sm_.ExpectSpeech("Tool bar"); // Verifies that pressing right key with search key should move the focus of // ShelfItem correctly. - SendKeyPressWithSearch(ui::VKEY_RIGHT); - EXPECT_TRUE(base::MatchPattern(sm_.GetNextUtterance(), "*")); - EXPECT_TRUE(base::MatchPattern(sm_.GetNextUtterance(), "Button")); - EXPECT_TRUE(base::MatchPattern(sm_.GetNextUtterance(), "*")); - SendKeyPressWithSearch(ui::VKEY_RIGHT); - EXPECT_TRUE(base::MatchPattern(sm_.GetNextUtterance(), title)); - EXPECT_TRUE(base::MatchPattern(sm_.GetNextUtterance(), "Button")); - EXPECT_TRUE(base::MatchPattern(sm_.GetNextUtterance(), "*")); + sm_.Call([this]() { SendKeyPressWithSearch(ui::VKEY_RIGHT); }); + // Chromium or Google Chrome button here (not being tested). + sm_.ExpectSpeech("Button"); + sm_.ExpectSpeech("Shelf"); + sm_.ExpectSpeech("Tool bar"); + + sm_.Call([this]() { SendKeyPressWithSearch(ui::VKEY_RIGHT); }); + sm_.ExpectSpeech("MockApp"); + sm_.ExpectSpeech("Button"); + + sm_.Replay(); } // Verifies that speaking text under mouse works for Shelf button and voice // announcements should not be stacked when mouse goes over many Shelf buttons -// (see https://crbug.com/958120 and https://crbug.com/921182). -// TODO(crbug.com/921182): Fix test correctness/reliability and re-enable. -IN_PROC_BROWSER_TEST_P(SpokenFeedbackTest, - DISABLED_SpeakingTextUnderMouseForShelfItem) { +IN_PROC_BROWSER_TEST_P(SpokenFeedbackTest, SpeakingTextUnderMouseForShelfItem) { // Add the ShelfItem to the ShelfModel after enabling the ChromeVox. Because // when an extension is enabled, the ShelfItems which are not recorded as // pinned apps in user preference will be removed. EnableChromeVox(); + ui_test_utils::NavigateToURL( + browser(), + GURL("data:text/html;charset=utf-8,<button autofocus>Click me</button>")); + + sm_.ExpectSpeech("Click me"); + // Add three Shelf buttons. Wait for the change on ShelfModel to reach ash. ChromeLauncherController* controller = ChromeLauncherController::instance(); const int base_index = controller->shelf_model()->item_count(); @@ -405,7 +414,6 @@ controller->CreateAppShortcutLauncherItem( ash::ShelfID(app_id), base_index + i, base::ASCIIToUTF16(app_title)); } - base::RunLoop().RunUntilIdle(); // Enable the function of speaking text under mouse. ash::EventRewriterController::Get()->SetSendMouseEventsToDelegate(true); @@ -413,45 +421,26 @@ // Focus on the Shelf because voice text for focusing on Shelf is fixed. Wait // until voice announcements are finished. EXPECT_TRUE(PerformAcceleratorAction(ash::FOCUS_SHELF)); - while (true) { - std::string utterance = sm_.GetNextUtterance(); - if (base::MatchPattern(utterance, "Launcher")) - break; - } - ASSERT_EQ("Button", sm_.GetNextUtterance()); - ASSERT_EQ("Shelf", sm_.GetNextUtterance()); - ASSERT_EQ("Tool bar", sm_.GetNextUtterance()); - ASSERT_EQ(", window", sm_.GetNextUtterance()); - ASSERT_EQ("Press Search plus Space to activate", sm_.GetNextUtterance()); + sm_.ExpectSpeechPattern("Launcher"); // Hover mouse on the Shelf button. Verifies that text under mouse is spoken. - ash::ShelfView* shelf_view = - ash::Shelf::ForWindow(ash::Shell::Get()->GetPrimaryRootWindow()) - ->shelf_widget() - ->shelf_view_for_testing(); - const int first_app_index = - shelf_view->model()->GetItemIndexForType(ash::TYPE_PINNED_APP); - SendMouseMoveTo(shelf_view->view_model() - ->view_at(first_app_index) - ->GetBoundsInScreen() - .CenterPoint()); - EXPECT_TRUE(base::MatchPattern(sm_.GetNextUtterance(), "MockApp0")); - EXPECT_TRUE(base::MatchPattern(sm_.GetNextUtterance(), "Button")); + sm_.Call([this]() { + ash::ShelfView* shelf_view = + ash::Shelf::ForWindow(ash::Shell::Get()->GetPrimaryRootWindow()) + ->shelf_widget() + ->shelf_view_for_testing(); + const int first_app_index = + shelf_view->model()->GetItemIndexForType(ash::TYPE_PINNED_APP); + SendMouseMoveTo(shelf_view->view_model() + ->view_at(first_app_index) + ->GetBoundsInScreen() + .CenterPoint()); + }); - // Move mouse to the third Shelf button through the second one. Verifies that - // only the last Shelf button is announced by ChromeVox. - const int second_app_index = first_app_index + 1; - SendMouseMoveTo(shelf_view->view_model() - ->view_at(second_app_index) - ->GetBoundsInScreen() - .CenterPoint()); - const int third_app_index = first_app_index + 2; - SendMouseMoveTo(shelf_view->view_model() - ->view_at(third_app_index) - ->GetBoundsInScreen() - .CenterPoint()); - EXPECT_TRUE(base::MatchPattern(sm_.GetNextUtterance(), "MockApp2")); - EXPECT_TRUE(base::MatchPattern(sm_.GetNextUtterance(), "Button")); + sm_.ExpectSpeechPattern("MockApp*"); + sm_.ExpectSpeech("Button"); + + sm_.Replay(); } IN_PROC_BROWSER_TEST_P(SpokenFeedbackTest, OpenStatusTray) { @@ -470,235 +459,159 @@ // Fails on ASAN. See http://crbug.com/776308 . (Note MAYBE_ doesn't work well // with parameterized tests). -#if !defined(ADDRESS_SANITIZER) && !defined(OS_CHROMEOS) +#if !defined(ADDRESS_SANITIZER) IN_PROC_BROWSER_TEST_P(SpokenFeedbackTest, NavigateSystemTray) { EnableChromeVox(); - EXPECT_TRUE(PerformAcceleratorAction(ash::TOGGLE_SYSTEM_TRAY_BUBBLE)); - while (true) { - std::string utterance = sm_.GetNextUtterance(); - if (base::MatchPattern(utterance, "Status tray,")) - break; - } - while (true) { - std::string utterance = sm_.GetNextUtterance(); - if (base::MatchPattern(utterance, "*window")) - break; - } + sm_.Call( + [this]() { (PerformAcceleratorAction(ash::TOGGLE_SYSTEM_TRAY_BUBBLE)); }); + sm_.ExpectSpeechPattern( + "Quick Settings, Press search plus left to access the notification " + "center., window"); - SendKeyPress(ui::VKEY_TAB); - while (true) { - std::string utterance = sm_.GetNextUtterance(); - if (base::MatchPattern(utterance, "Button")) - break; - } - - // Next element. - SendKeyPressWithSearch(ui::VKEY_RIGHT); - EXPECT_TRUE(base::MatchPattern(sm_.GetNextUtterance(), "*")); - EXPECT_TRUE(base::MatchPattern(sm_.GetNextUtterance(), "Button")); + sm_.Call([this]() { SendKeyPress(ui::VKEY_TAB); }); + sm_.ExpectSpeech(GetParam() == kTestAsGuestUser ? "Exit guest" : "Sign out"); + sm_.ExpectSpeech("Button"); // Next button. - SendKeyPressWithSearch(ui::VKEY_B); - EXPECT_TRUE(base::MatchPattern(sm_.GetNextUtterance(), "*")); - EXPECT_TRUE(base::MatchPattern(sm_.GetNextUtterance(), "Button")); + sm_.Call([this]() { SendKeyPressWithSearch(ui::VKEY_B); }); + sm_.ExpectSpeech("Shut down"); + sm_.ExpectSpeech("Button"); - // Navigate to Bluetooth sub-menu and open it. - while (true) { - SendKeyPress(ui::VKEY_TAB); - std::string content = sm_.GetNextUtterance(); - std::string role = sm_.GetNextUtterance(); - if (base::MatchPattern(content, "*Bluetooth*") && - base::MatchPattern(role, "Button")) - break; - } - SendKeyPress(ui::VKEY_RETURN); - - // Navigate to return to previous menu button and press it. - while (true) { - std::string utterance = sm_.GetNextUtterance(); - if (base::MatchPattern(utterance, "Previous menu")) - break; - SendKeyPress(ui::VKEY_TAB); - } - SendKeyPress(ui::VKEY_RETURN); - - while (true) { - std::string utterance = sm_.GetNextUtterance(); - if (base::MatchPattern(utterance, "Bluetooth*")) - break; - } + sm_.Replay(); } -#endif // !defined(ADDRESS_SANITIZER) && !defined(OS_CHROMEOS) +#endif // !defined(ADDRESS_SANITIZER) -// See http://crbug.com/443608 +// TODO: these brightness announcements are actually not made. +// https://crbug.com/1064788 IN_PROC_BROWSER_TEST_P(SpokenFeedbackTest, DISABLED_ScreenBrightness) { EnableChromeVox(); - EXPECT_TRUE(PerformAcceleratorAction(ash::BRIGHTNESS_UP)); - EXPECT_TRUE( - base::MatchPattern(sm_.GetNextUtterance(), "Brightness * percent")); + sm_.Call([this]() { (PerformAcceleratorAction(ash::BRIGHTNESS_UP)); }); + sm_.ExpectSpeechPattern("Brightness * percent"); - EXPECT_TRUE(PerformAcceleratorAction(ash::BRIGHTNESS_DOWN)); - EXPECT_TRUE( - base::MatchPattern(sm_.GetNextUtterance(), "Brightness * percent")); + sm_.Call([this]() { (PerformAcceleratorAction(ash::BRIGHTNESS_DOWN)); }); + sm_.ExpectSpeechPattern("Brightness * percent"); + + sm_.Replay(); } -IN_PROC_BROWSER_TEST_P(SpokenFeedbackTest, DISABLED_VolumeSlider) { +IN_PROC_BROWSER_TEST_P(SpokenFeedbackTest, VolumeSlider) { EnableChromeVox(); - // Volume slider does not fire valueChanged event on first key press because - // it has no widget. - EXPECT_TRUE(PerformAcceleratorAction(ash::VOLUME_UP)); - EXPECT_TRUE(PerformAcceleratorAction(ash::VOLUME_UP)); - EXPECT_TRUE(base::MatchPattern(sm_.GetNextUtterance(), "* percent*")); + sm_.Call([this]() { + // Volume slider does not fire valueChanged event on first key press because + // it has no widget. + PerformAcceleratorAction(ash::VOLUME_UP); + PerformAcceleratorAction(ash::VOLUME_UP); + }); + sm_.ExpectSpeechPattern("* percent*"); + sm_.Replay(); } IN_PROC_BROWSER_TEST_P(SpokenFeedbackTest, OverviewMode) { EnableChromeVox(); + ui_test_utils::NavigateToURL( + browser(), + GURL("data:text/html;charset=utf-8,<button autofocus>Click me</button>")); - EXPECT_TRUE(PerformAcceleratorAction(ash::TOGGLE_OVERVIEW)); - while (true) { - std::string utterance = sm_.GetNextUtterance(); - if (utterance == "Entered window overview mode. Press tab to navigate.") - break; - } + sm_.ExpectSpeech("Click me"); - // On Chrome OS accessibility title for tabbed browser windows contains app - // name ("Chrome" or "Chromium") in overview mode. - while (true) { - // Tabbing may select a desk item in the overview desks bar, so we tab - // repeatedly until the window is selected. - SendKeyPress(ui::VKEY_TAB); - std::string utterance = sm_.GetNextUtterance(); - if (base::MatchPattern(utterance, "Chrom*about:blank, window")) - break; - } + sm_.Call([this]() { (PerformAcceleratorAction(ash::TOGGLE_OVERVIEW)); }); + + sm_.ExpectSpeech("Entered window overview mode. Press tab to navigate."); + + sm_.Call([this]() { SendKeyPressWithShift(ui::VKEY_TAB); }); + sm_.ExpectSpeechPattern( + "Chrom* - data:text slash html;charset equal utf-8, less than button " + "autofocus greater than Click me less than slash button greater than , " + "window"); + + sm_.Replay(); } -#if defined(MEMORY_SANITIZER) || defined(OS_CHROMEOS) -// Fails under MemorySanitizer: http://crbug.com/472125 -// Test is flaky under ChromeOS: http://crbug.com/897249 -#define MAYBE_ChromeVoxShiftSearch DISABLED_ChromeVoxShiftSearch -#else -#define MAYBE_ChromeVoxShiftSearch ChromeVoxShiftSearch -#endif -IN_PROC_BROWSER_TEST_P(SpokenFeedbackTest, MAYBE_ChromeVoxShiftSearch) { +IN_PROC_BROWSER_TEST_P(SpokenFeedbackTest, ChromeVoxFindInPage) { EnableChromeVox(); ui_test_utils::NavigateToURL( browser(), GURL("data:text/html;charset=utf-8,<button autofocus>Click me</button>")); - while (true) { - std::string utterance = sm_.GetNextUtterance(); - if (utterance == "Click me") - break; - } + + sm_.ExpectSpeech("Click me"); // Press Search+/ to enter ChromeVox's "find in page". SendKeyPressWithSearch(ui::VKEY_OEM_2); - - while (true) { - std::string utterance = sm_.GetNextUtterance(); - if (utterance == "Find in page") - break; - } + sm_.ExpectSpeech("Find in page"); + sm_.Replay(); } -#if defined(MEMORY_SANITIZER) || defined(OS_CHROMEOS) -// Fails under MemorySanitizer: http://crbug.com/472125 -// TODO(crbug.com/721475): Flaky on CrOS. -#define MAYBE_ChromeVoxNavigateAndSelect DISABLED_ChromeVoxNavigateAndSelect -#else -#define MAYBE_ChromeVoxNavigateAndSelect ChromeVoxNavigateAndSelect -#endif -IN_PROC_BROWSER_TEST_P(SpokenFeedbackTest, MAYBE_ChromeVoxNavigateAndSelect) { +IN_PROC_BROWSER_TEST_P(SpokenFeedbackTest, ChromeVoxNavigateAndSelect) { EnableChromeVox(); ui_test_utils::NavigateToURL(browser(), GURL("data:text/html;charset=utf-8," "<h1>Title</h1>" "<button autofocus>Click me</button>")); - while (true) { - std::string utterance = sm_.GetNextUtterance(); - if (utterance == "Click me") - break; - } - EXPECT_EQ("Button", sm_.GetNextUtterance()); + + sm_.ExpectSpeech("Click me"); // Press Search+Left to navigate to the previous item. - SendKeyPressWithSearch(ui::VKEY_LEFT); - EXPECT_EQ("Title", sm_.GetNextUtterance()); - EXPECT_EQ("Heading 1", sm_.GetNextUtterance()); + sm_.Call([this]() { SendKeyPressWithSearch(ui::VKEY_LEFT); }); + sm_.ExpectSpeech("Title"); + sm_.ExpectSpeech("Heading 1"); // Press Search+S to select the text. - SendKeyPressWithSearch(ui::VKEY_S); - EXPECT_EQ("Title", sm_.GetNextUtterance()); - EXPECT_EQ("selected", sm_.GetNextUtterance()); + sm_.Call([this]() { SendKeyPressWithSearch(ui::VKEY_S); }); + sm_.ExpectSpeech("Title"); + sm_.ExpectSpeech("selected"); // Press again to end the selection. - SendKeyPressWithSearch(ui::VKEY_S); - EXPECT_EQ("End selection", sm_.GetNextUtterance()); - EXPECT_EQ("Title", sm_.GetNextUtterance()); + sm_.Call([this]() { SendKeyPressWithSearch(ui::VKEY_S); }); + sm_.ExpectSpeech("End selection"); + + sm_.Replay(); } -IN_PROC_BROWSER_TEST_P(SpokenFeedbackTest, DISABLED_ChromeVoxNextStickyMode) { +IN_PROC_BROWSER_TEST_P(SpokenFeedbackTest, ChromeVoxStickyMode) { EnableChromeVox(); ui_test_utils::NavigateToURL( browser(), GURL("data:text/html;charset=utf-8,<button autofocus>Click me</button>")); - while ("Button" != sm_.GetNextUtterance()) { - } + + sm_.ExpectSpeech("Click me"); // Press the sticky-key sequence: Search Search. - SendKeyPress(ui::VKEY_LWIN); + sm_.Call([this]() { SendStickyKeyCommand(); }); - // Sticky key has a minimum 100 ms check to prevent key repeat from toggling - // it. - base::PostDelayedTask( - FROM_HERE, {content::BrowserThread::UI}, - base::BindOnce(&LoggedInSpokenFeedbackTest::SendKeyPress, - base::Unretained(this), ui::VKEY_LWIN), - base::TimeDelta::FromMilliseconds(200)); + sm_.ExpectSpeech("Sticky mode enabled"); - EXPECT_EQ("Sticky mode enabled", sm_.GetNextUtterance()); + sm_.Call([this]() { SendKeyPress(ui::VKEY_H); }); + sm_.ExpectSpeech("No next heading"); - SendKeyPress(ui::VKEY_H); - while ("No next heading" != sm_.GetNextUtterance()) { - } + sm_.Call([this]() { SendStickyKeyCommand(); }); + sm_.ExpectSpeech("Sticky mode disabled"); - SendKeyPress(ui::VKEY_LWIN); - - // Sticky key has a minimum 100 ms check to prevent key repeat from toggling - // it. - base::PostDelayedTask( - FROM_HERE, {content::BrowserThread::UI}, - base::BindOnce(&LoggedInSpokenFeedbackTest::SendKeyPress, - base::Unretained(this), ui::VKEY_LWIN), - base::TimeDelta::FromMilliseconds(200)); - - while ("Sticky mode disabled" != sm_.GetNextUtterance()) { - } + sm_.Replay(); } -// Flaky on Linux ChromiumOS MSan Tests. https://crbug.com/752427 -IN_PROC_BROWSER_TEST_P(SpokenFeedbackTest, DISABLED_TouchExploreStatusTray) { +IN_PROC_BROWSER_TEST_P(SpokenFeedbackTest, TouchExploreStatusTray) { EnableChromeVox(); SimulateTouchScreenInChromeVox(); // Send an accessibility hover event on the system tray, which is // what we get when you tap it on a touch screen when ChromeVox is on. - ash::TrayBackgroundView* tray = ash::Shell::Get() - ->GetPrimaryRootWindowController() - ->GetStatusAreaWidget() - ->unified_system_tray(); - tray->NotifyAccessibilityEvent(ax::mojom::Event::kHover, true); + sm_.Call([]() { + ash::TrayBackgroundView* tray = ash::Shell::Get() + ->GetPrimaryRootWindowController() + ->GetStatusAreaWidget() + ->unified_system_tray(); + tray->NotifyAccessibilityEvent(ax::mojom::Event::kHover, true); + }); + sm_.ExpectSpeechPattern("Status tray, time* Battery at* percent*"); + sm_.ExpectSpeech("Button"); - EXPECT_EQ("Status tray,", sm_.GetNextUtterance()); - EXPECT_TRUE(base::MatchPattern(sm_.GetNextUtterance(), "time*,")); - EXPECT_TRUE(base::MatchPattern(sm_.GetNextUtterance(), "Battery*")); - EXPECT_EQ("Button", sm_.GetNextUtterance()); + sm_.Replay(); } IN_PROC_BROWSER_TEST_P(SpokenFeedbackTest, ChromeVoxNextTabRecovery) { @@ -792,66 +705,22 @@ DISALLOW_COPY_AND_ASSIGN(OobeSpokenFeedbackTest); }; -// Test is flaky: http://crbug.com/346797 -IN_PROC_BROWSER_TEST_F(OobeSpokenFeedbackTest, DISABLED_SpokenFeedbackInOobe) { +IN_PROC_BROWSER_TEST_F(OobeSpokenFeedbackTest, SpokenFeedbackInOobe) { ui_controls::EnableUIControls(); ASSERT_FALSE(AccessibilityManager::Get()->IsSpokenFeedbackEnabled()); - - LoginDisplayHost* login_display_host = LoginDisplayHost::default_host(); - WebUILoginView* web_ui_login_view = login_display_host->GetWebUILoginView(); - views::Widget* widget = web_ui_login_view->GetWidget(); - gfx::NativeWindow window = widget->GetNativeWindow(); - - // We expect to be in the language select dropdown for this test to work, - // so make sure that's the case. - test::OobeJS().ExecuteAsync("$('language-select').focus()"); AccessibilityManager::Get()->EnableSpokenFeedback(true); - ASSERT_TRUE(sm_.SkipChromeVoxEnabledMessage()); - // There's no guarantee that ChromeVox speaks anything when injected after - // the page loads, which is by design. Tab forward and then backward - // to make sure we get the right feedback from the language and keyboard - // selection fields. - ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync( - window, ui::VKEY_TAB, false, false, false, false)); - while (sm_.GetNextUtterance() != "Select your keyboard:") { - } - EXPECT_EQ("U S", sm_.GetNextUtterance()); - EXPECT_TRUE(base::MatchPattern(sm_.GetNextUtterance(), "Combo box * of *")); - ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync( - window, ui::VKEY_TAB, false, true /*shift*/, false, false)); - while (sm_.GetNextUtterance() != "Select your language:") { - } - EXPECT_EQ("English ( United States)", sm_.GetNextUtterance()); - EXPECT_TRUE(base::MatchPattern(sm_.GetNextUtterance(), "Combo box * of *")); -} + // The Let's go button gets initial focus. + sm_.ExpectSpeech("Let's go"); -// This test is flaky (https://crbug.com/1013551). -IN_PROC_BROWSER_TEST_F(OobeSpokenFeedbackTest, - DISABLED_ChromeVoxPanelTabsMenuEmpty) { - // The ChromeVox panel should not populate the tabs menu if we are in the - // OOBE. - ASSERT_FALSE(AccessibilityManager::Get()->IsSpokenFeedbackEnabled()); - AccessibilityManager::Get()->EnableSpokenFeedback(true); - // Included to reduce flakiness. - while (sm_.GetNextUtterance() != "Press Search plus Space to activate") { - } - // Press [search + .] to open ChromeVox Panel - ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync( - nullptr, ui::VKEY_OEM_PERIOD, false, false, false, true)); - while (sm_.GetNextUtterance() != "ChromeVox Panel") { - } - // Go to tabs menu and verify that it has no items. - ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync( - nullptr, ui::VKEY_RIGHT, false, false, false, false)); - while (sm_.GetNextUtterance() != "Speech") { - } - ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync( - nullptr, ui::VKEY_RIGHT, false, false, false, false)); - while (sm_.GetNextUtterance() != "Tabs") { - } - EXPECT_EQ("Menu", sm_.GetNextUtterance()); - EXPECT_EQ("No items", sm_.GetNextUtterance()); + sm_.Call([]() { + ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync( + nullptr, ui::VKEY_TAB, false, false, false, false)); + }); + sm_.ExpectSpeech("Shut down"); + sm_.ExpectSpeech("Button"); + + sm_.Replay(); } IN_PROC_BROWSER_TEST_P(SpokenFeedbackTest, @@ -917,17 +786,13 @@ sm_.Replay(); } -#if defined(OS_CHROMEOS) -// Flaky on ChromeOS: http://crbug.com/1064947 -#define MAYBE_ResetTtsSettings DISABLED_ResetTtsSettings -#else -#define MAYBE_ResetTtsSettings ResetTtsSettings -#endif -IN_PROC_BROWSER_TEST_P(SpokenFeedbackTest, MAYBE_ResetTtsSettings) { +IN_PROC_BROWSER_TEST_P(SpokenFeedbackTest, ResetTtsSettings) { EnableChromeVox(); ui_test_utils::NavigateToURL( browser(), GURL("data:text/html,<button autofocus>Click me</button>")); + sm_.ExpectSpeech("Click me"); + // Reset Tts settings using hotkey and assert speech output. sm_.Call( [this]() { SendKeyPressWithSearchAndControlAndShift(ui::VKEY_OEM_5); }); @@ -951,4 +816,58 @@ sm_.Replay(); } +IN_PROC_BROWSER_TEST_P(SpokenFeedbackTest, SmartStickyMode) { + EnableChromeVox(); + ui_test_utils::NavigateToURL(browser(), + GURL("data:text/html,<p>start</p><input " + "autofocus type='text'><p>end</p>")); + + // The input is autofocused. + sm_.ExpectSpeech("Edit text"); + + // First, navigate with sticky mode on. + sm_.Call([this]() { SendStickyKeyCommand(); }); + sm_.ExpectSpeech("Sticky mode enabled"); + + sm_.Call([this]() { SendKeyPressWithSearch(ui::VKEY_RIGHT); }); + sm_.ExpectNextSpeechIsNotPattern("Sticky mode *abled"); + sm_.ExpectSpeech("end"); + + // Jump to beginning. + sm_.Call([this]() { SendKeyPressWithSearchAndControl(ui::VKEY_LEFT); }); + sm_.ExpectNextSpeechIsNotPattern("Sticky mode *abled"); + sm_.ExpectSpeech("start"); + + // The nextEditText command is explicitly excluded from toggling. + sm_.Call([this]() { SendKeyPressWithSearch(ui::VKEY_E); }); + sm_.ExpectNextSpeechIsNotPattern("Sticky mode *abled"); + sm_.ExpectSpeech("Edit text"); + + sm_.Call([this]() { SendKeyPressWithSearch(ui::VKEY_RIGHT); }); + sm_.ExpectNextSpeechIsNotPattern("Sticky mode *abled"); + sm_.ExpectSpeech("end"); + + sm_.Call([this]() { SendKeyPressWithSearch(ui::VKEY_LEFT); }); + sm_.ExpectSpeech("Sticky mode disabled"); + sm_.ExpectSpeech("Edit text"); + + sm_.Call([this]() { SendKeyPressWithSearch(ui::VKEY_LEFT); }); + sm_.ExpectSpeech("Sticky mode enabled"); + sm_.ExpectSpeech("start"); + + // Now, navigate with sticky mode off. + sm_.Call([this]() { SendStickyKeyCommand(); }); + sm_.ExpectSpeech("Sticky mode disabled"); + + sm_.Call([this]() { SendKeyPressWithSearch(ui::VKEY_RIGHT); }); + sm_.ExpectNextSpeechIsNotPattern("Sticky mode *abled"); + sm_.ExpectSpeech("Edit text"); + + sm_.Call([this]() { SendKeyPressWithSearch(ui::VKEY_RIGHT); }); + sm_.ExpectNextSpeechIsNotPattern("Sticky mode *abled"); + sm_.ExpectSpeech("end"); + + sm_.Replay(); +} + } // namespace chromeos
diff --git a/chrome/browser/chromeos/accessibility/spoken_feedback_browsertest.h b/chrome/browser/chromeos/accessibility/spoken_feedback_browsertest.h index b20d15e..c06f344 100644 --- a/chrome/browser/chromeos/accessibility/spoken_feedback_browsertest.h +++ b/chrome/browser/chromeos/accessibility/spoken_feedback_browsertest.h
@@ -29,11 +29,14 @@ // Simulate key press event. void SendKeyPress(ui::KeyboardCode key); void SendKeyPressWithControl(ui::KeyboardCode key); + void SendKeyPressWithShift(ui::KeyboardCode key); void SendKeyPressWithSearchAndShift(ui::KeyboardCode key); void SendKeyPressWithSearch(ui::KeyboardCode key); void SendKeyPressWithSearchAndControl(ui::KeyboardCode key); void SendKeyPressWithSearchAndControlAndShift(ui::KeyboardCode key); + void SendStickyKeyCommand(); + void SendMouseMoveTo(const gfx::Point& location); void RunJavaScriptInChromeVoxBackgroundPage(const std::string& script);
diff --git a/chrome/browser/chromeos/crostini/crostini_terminal.cc b/chrome/browser/chromeos/crostini/crostini_terminal.cc index d6bcc28..272c3b2f 100644 --- a/chrome/browser/chromeos/crostini/crostini_terminal.cc +++ b/chrome/browser/chromeos/crostini/crostini_terminal.cc
@@ -33,6 +33,10 @@ namespace { constexpr char kSettingPrefix[] = "/hterm/profiles/default/"; const size_t kSettingPrefixSize = base::size(kSettingPrefix) - 1; + +constexpr char kSettingBackgroundColor[] = + "/hterm/profiles/default/background-color"; +constexpr char kDefaultBackgroundColor[] = "#101010"; } // namespace namespace crostini { @@ -236,4 +240,11 @@ } } +std::string GetTerminalSettingBackgroundColor(Profile* profile) { + const base::DictionaryValue* value = profile->GetPrefs()->GetDictionary( + crostini::prefs::kCrostiniTerminalSettings); + const std::string* result = value->FindStringKey(kSettingBackgroundColor); + return result ? *result : kDefaultBackgroundColor; +} + } // namespace crostini
diff --git a/chrome/browser/chromeos/crostini/crostini_terminal.h b/chrome/browser/chromeos/crostini/crostini_terminal.h index 6f8eec30..a91e815 100644 --- a/chrome/browser/chromeos/crostini/crostini_terminal.h +++ b/chrome/browser/chromeos/crostini/crostini_terminal.h
@@ -130,6 +130,8 @@ // Record which terminal settings have been changed by users. void RecordTerminalSettingsChangesUMAs(Profile* profile); +// Returns terminal setting 'background-color'. +std::string GetTerminalSettingBackgroundColor(Profile* profile); } // namespace crostini #endif // CHROME_BROWSER_CHROMEOS_CROSTINI_CROSTINI_TERMINAL_H_
diff --git a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc index e5343a9..f6334d8c 100644 --- a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc +++ b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc
@@ -4152,6 +4152,8 @@ scrollable_shelf_ui_info.is_overflow = fetched_info.is_overflow; scrollable_shelf_ui_info.icons_bounds_in_screen = ToBoundsDictionaryList(fetched_info.icons_bounds_in_screen); + scrollable_shelf_ui_info.is_shelf_widget_animating = + fetched_info.is_shelf_widget_animating; if (state.scroll_distance) { scrollable_shelf_ui_info.target_main_axis_offset =
diff --git a/chrome/browser/chromeos/input_method/assistive_suggester.cc b/chrome/browser/chromeos/input_method/assistive_suggester.cc index d1da6f8..d1b049a 100644 --- a/chrome/browser/chromeos/input_method/assistive_suggester.cc +++ b/chrome/browser/chromeos/input_method/assistive_suggester.cc
@@ -4,14 +4,7 @@ #include "chrome/browser/chromeos/input_method/assistive_suggester.h" -#include "base/feature_list.h" #include "base/metrics/histogram_functions.h" -#include "base/strings/utf_string_conversions.h" -#include "chrome/browser/autofill/personal_data_manager_factory.h" -#include "chrome/browser/profiles/profile_manager.h" -#include "chromeos/constants/chromeos_features.h" -#include "components/autofill/core/browser/data_model/autofill_profile.h" -#include "components/autofill/core/browser/personal_data_manager.h" using input_method::InputMethodEngineBase; @@ -21,10 +14,6 @@ const char kMaxTextBeforeCursorLength = 50; const char kKeydown[] = "keydown"; -const char kAssistEmailPrefix[] = "my email is "; -const char kAssistNamePrefix[] = "my name is "; -const char kAssistAddressPrefix[] = "my address is "; -const char kAssistPhoneNumberPrefix[] = "my phone number is "; void RecordAssistiveCoverage(AssistiveType type) { base::UmaHistogramEnumeration("InputMethod.Assistive.Coverage", type); @@ -34,42 +23,20 @@ base::UmaHistogramEnumeration("InputMethod.Assistive.Success", type); } -AssistiveType ProposeAssistiveAction(const base::string16& text) { - AssistiveType action = AssistiveType::kGenericAction; - if (base::EndsWith(text, base::UTF8ToUTF16(kAssistEmailPrefix), - base::CompareCase::INSENSITIVE_ASCII)) { - action = AssistiveType::kPersonalEmail; - } - if (base::EndsWith(text, base::UTF8ToUTF16(kAssistNamePrefix), - base::CompareCase::INSENSITIVE_ASCII)) { - action = AssistiveType::kPersonalName; - } - if (base::EndsWith(text, base::UTF8ToUTF16(kAssistAddressPrefix), - base::CompareCase::INSENSITIVE_ASCII)) { - action = AssistiveType::kPersonalAddress; - } - if (base::EndsWith(text, base::UTF8ToUTF16(kAssistPhoneNumberPrefix), - base::CompareCase::INSENSITIVE_ASCII)) { - action = AssistiveType::kPersonalPhoneNumber; - } - return action; -} - } // namespace AssistiveSuggester::AssistiveSuggester(InputMethodEngine* engine, Profile* profile) - : engine_(engine), - profile_(profile), - personal_data_manager_( - autofill::PersonalDataManagerFactory::GetForProfile(profile)) {} + : personal_info_suggester_(new PersonalInfoSuggester(engine, profile)) {} void AssistiveSuggester::OnFocus(int context_id) { context_id_ = context_id; + personal_info_suggester_->OnFocus(context_id_); } void AssistiveSuggester::OnBlur() { context_id_ = -1; + personal_info_suggester_->OnBlur(); } bool AssistiveSuggester::OnKeyEvent( @@ -83,18 +50,21 @@ // surrounding text change, which is triggered by a keydown event. As a // result, the next key event after suggesting would be a keyup event of the // same key, and that event is meaningless to us. - if (suggestion_shown_ && event.type == kKeydown) { - suggestion_shown_ = false; - if (event.key == "Tab" || event.key == "Right") { - std::string error; - engine_->AcceptSuggestion(context_id_, &error); - RecordAssistiveSuccess(proposed_action_type_); - return true; + if (IsSuggestionShown() && event.type == kKeydown) { + SuggestionStatus status = current_suggester_->HandleKeyEvent(event); + switch (status) { + case SuggestionStatus::kAccept: + RecordAssistiveSuccess(current_suggester_->GetProposeActionType()); + current_suggester_ = nullptr; + return true; + case SuggestionStatus::kDismiss: + current_suggester_ = nullptr; + suggestion_dismissed_ = true; + return false; + default: + break; } - DismissSuggestion(); - suggestion_dismissed_ = true; } - return false; } @@ -125,12 +95,11 @@ if (context_id_ == -1) return false; - if (suggestion_shown_) { - suggestion_shown_ = false; + if (IsSuggestionShown()) { DismissSuggestion(); } Suggest(text, cursor_pos, anchor_pos); - return suggestion_shown_; + return IsSuggestionShown(); } void AssistiveSuggester::Suggest(const base::string16& text, @@ -146,67 +115,22 @@ int start_pos = std::max(0, cursor_pos - kMaxTextBeforeCursorLength); base::string16 text_before_cursor = text.substr(start_pos, cursor_pos - start_pos); - base::string16 suggestion_text = - GetPersonalInfoSuggestion(text_before_cursor); - if (!suggestion_text.empty()) { - ShowSuggestion(suggestion_text); - suggestion_shown_ = true; + if (personal_info_suggester_->Suggest(text_before_cursor)) { + current_suggester_ = personal_info_suggester_; + } else { + current_suggester_ = nullptr; } } } -base::string16 AssistiveSuggester::GetPersonalInfoSuggestion( - const base::string16& text) { - AssistiveType action = ProposeAssistiveAction(text); - if (action == AssistiveType::kGenericAction) - return base::EmptyString16(); - - proposed_action_type_ = action; - - if (action == AssistiveType::kPersonalEmail) - return base::UTF8ToUTF16(profile_->GetProfileUserName()); - - auto autofill_profiles = personal_data_manager_->GetProfilesToSuggest(); - if (autofill_profiles.empty()) - return base::EmptyString16(); - - // Currently, we are just picking the first candidate, will improve the - // strategy in the future. - auto* data = autofill_profiles[0]; - base::string16 suggestion; - switch (action) { - case AssistiveType::kPersonalName: - suggestion = data->GetRawInfo(autofill::ServerFieldType::NAME_FULL); - break; - case AssistiveType::kPersonalAddress: - suggestion = data->GetRawInfo( - autofill::ServerFieldType::ADDRESS_HOME_STREET_ADDRESS); - break; - case AssistiveType::kPersonalPhoneNumber: - suggestion = - data->GetRawInfo(autofill::ServerFieldType::PHONE_HOME_WHOLE_NUMBER); - break; - default: - NOTREACHED(); - break; - } - return suggestion; -} - -void AssistiveSuggester::ShowSuggestion(const base::string16& text) { - std::string error; - engine_->SetSuggestion(context_id_, text, &error); - if (!error.empty()) { - LOG(ERROR) << "Fail to show suggestion. " << error; - } -} - void AssistiveSuggester::DismissSuggestion() { - std::string error; - engine_->DismissSuggestion(context_id_, &error); - if (!error.empty()) { - LOG(ERROR) << "Failed to dismiss suggestion. " << error; - } + if (current_suggester_) + current_suggester_->DismissSuggestion(); + current_suggester_ = nullptr; +} + +bool AssistiveSuggester::IsSuggestionShown() { + return current_suggester_ != nullptr; } } // namespace chromeos
diff --git a/chrome/browser/chromeos/input_method/assistive_suggester.h b/chrome/browser/chromeos/input_method/assistive_suggester.h index 6963b9c..521bcbd 100644 --- a/chrome/browser/chromeos/input_method/assistive_suggester.h +++ b/chrome/browser/chromeos/input_method/assistive_suggester.h
@@ -8,26 +8,13 @@ #include <string> #include "chrome/browser/chromeos/input_method/input_method_engine.h" +#include "chrome/browser/chromeos/input_method/personal_info_suggester.h" +#include "chrome/browser/chromeos/input_method/suggester.h" +#include "chrome/browser/chromeos/input_method/suggestion_enums.h" #include "chrome/browser/ui/input_method/input_method_engine_base.h" -namespace autofill { -class PersonalDataManager; -} // namespace autofill - -class Profile; - namespace chromeos { -// Must match with IMEAssistiveAction in enums.xml -enum class AssistiveType { - kGenericAction = 0, - kPersonalEmail = 1, - kPersonalAddress = 2, - kPersonalPhoneNumber = 3, - kPersonalName = 4, - kMaxValue = kPersonalName, -}; - // An agent to suggest assistive information when the user types, and adopt or // dismiss the suggestion according to the user action. class AssistiveSuggester { @@ -59,37 +46,26 @@ const ::input_method::InputMethodEngineBase::KeyboardEvent& event); private: - // Get the suggestion according to |text_before_cursor|. - base::string16 GetPersonalInfoSuggestion( - const base::string16& text_before_cursor); - // Check if any suggestion text should be displayed according to the // surrounding text information. void Suggest(const base::string16& text, int cursor_pos, int anchor_pos); - void ShowSuggestion(const base::string16& text); void DismissSuggestion(); - InputMethodEngine* const engine_; + // Check if suggestion is being shown. + bool IsSuggestionShown(); + + PersonalInfoSuggester* const personal_info_suggester_; // ID of the focused text field, 0 if none is focused. int context_id_ = -1; - // User's Chrome user profile. - Profile* const profile_; - - // Personal data manager provided by autofill service. - autofill::PersonalDataManager* const personal_data_manager_; - - // If we are showing a suggestion right now. - bool suggestion_shown_ = false; - - // Assistive type of the last proposed assistive action. - AssistiveType proposed_action_type_ = AssistiveType::kGenericAction; - // If the suggestion is dismissed by the user, this is necessary so that we // will not reshow the suggestion immediately after the user dismisses it. bool suggestion_dismissed_ = false; + + // The current suggester in use, nullptr means no suggestion is shown. + Suggester* current_suggester_ = nullptr; }; } // namespace chromeos
diff --git a/chrome/browser/chromeos/input_method/personal_info_suggester.cc b/chrome/browser/chromeos/input_method/personal_info_suggester.cc new file mode 100644 index 0000000..eab2c98a --- /dev/null +++ b/chrome/browser/chromeos/input_method/personal_info_suggester.cc
@@ -0,0 +1,147 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/chromeos/input_method/personal_info_suggester.h" + +#include "base/strings/utf_string_conversions.h" +#include "chrome/browser/autofill/personal_data_manager_factory.h" +#include "chrome/browser/profiles/profile_manager.h" +#include "components/autofill/core/browser/data_model/autofill_profile.h" +#include "components/autofill/core/browser/personal_data_manager.h" + +using input_method::InputMethodEngineBase; + +namespace chromeos { + +namespace { + +const char kAssistEmailPrefix[] = "my email is "; +const char kAssistNamePrefix[] = "my name is "; +const char kAssistAddressPrefix[] = "my address is "; +const char kAssistPhoneNumberPrefix[] = "my phone number is "; + +} // namespace + +AssistiveType ProposeAssistiveAction(const base::string16& text) { + AssistiveType action = AssistiveType::kGenericAction; + if (base::EndsWith(text, base::UTF8ToUTF16(kAssistEmailPrefix), + base::CompareCase::INSENSITIVE_ASCII)) { + action = AssistiveType::kPersonalEmail; + } + if (base::EndsWith(text, base::UTF8ToUTF16(kAssistNamePrefix), + base::CompareCase::INSENSITIVE_ASCII)) { + action = AssistiveType::kPersonalName; + } + if (base::EndsWith(text, base::UTF8ToUTF16(kAssistAddressPrefix), + base::CompareCase::INSENSITIVE_ASCII)) { + action = AssistiveType::kPersonalAddress; + } + if (base::EndsWith(text, base::UTF8ToUTF16(kAssistPhoneNumberPrefix), + base::CompareCase::INSENSITIVE_ASCII)) { + action = AssistiveType::kPersonalPhoneNumber; + } + return action; +} + +PersonalInfoSuggester::PersonalInfoSuggester(InputMethodEngine* engine, + Profile* profile) + : engine_(engine), + profile_(profile), + personal_data_manager_( + autofill::PersonalDataManagerFactory::GetForProfile(profile)) {} + +PersonalInfoSuggester::~PersonalInfoSuggester() {} + +void PersonalInfoSuggester::OnFocus(int context_id) { + context_id_ = context_id; +} + +void PersonalInfoSuggester::OnBlur() { + context_id_ = -1; +} + +SuggestionStatus PersonalInfoSuggester::HandleKeyEvent( + const InputMethodEngineBase::KeyboardEvent& event) { + if (suggestion_shown_) { + suggestion_shown_ = false; + if (event.key == "Tab" || event.key == "Right") { + std::string error; + engine_->AcceptSuggestion(context_id_, &error); + return SuggestionStatus::kAccept; + } + DismissSuggestion(); + return SuggestionStatus::kDismiss; + } + return SuggestionStatus::kNotHandled; +} + +bool PersonalInfoSuggester::Suggest(const base::string16& text) { + base::string16 suggestion_text = GetPersonalInfoSuggestion(text); + if (!suggestion_text.empty()) { + ShowSuggestion(suggestion_text); + suggestion_shown_ = true; + } + return suggestion_shown_; +} + +base::string16 PersonalInfoSuggester::GetPersonalInfoSuggestion( + const base::string16& text) { + AssistiveType action = ProposeAssistiveAction(text); + proposed_action_type_ = action; + + if (action == AssistiveType::kGenericAction) + return base::EmptyString16(); + + if (action == AssistiveType::kPersonalEmail) + return base::UTF8ToUTF16(profile_->GetProfileUserName()); + + auto autofill_profiles = personal_data_manager_->GetProfilesToSuggest(); + if (autofill_profiles.empty()) + return base::EmptyString16(); + + // Currently, we are just picking the first candidate, will improve the + // strategy in the future. + auto* data = autofill_profiles[0]; + base::string16 suggestion; + switch (action) { + case AssistiveType::kPersonalName: + suggestion = data->GetRawInfo(autofill::ServerFieldType::NAME_FULL); + break; + case AssistiveType::kPersonalAddress: + suggestion = data->GetRawInfo( + autofill::ServerFieldType::ADDRESS_HOME_STREET_ADDRESS); + break; + case AssistiveType::kPersonalPhoneNumber: + suggestion = + data->GetRawInfo(autofill::ServerFieldType::PHONE_HOME_WHOLE_NUMBER); + break; + default: + NOTREACHED(); + break; + } + return suggestion; +} + +void PersonalInfoSuggester::ShowSuggestion(const base::string16& text) { + std::string error; + engine_->SetSuggestion(context_id_, text, &error); + if (!error.empty()) { + LOG(ERROR) << "Fail to show suggestion. " << error; + } +} + +AssistiveType PersonalInfoSuggester::GetProposeActionType() { + return proposed_action_type_; +} + +void PersonalInfoSuggester::DismissSuggestion() { + std::string error; + suggestion_shown_ = false; + engine_->DismissSuggestion(context_id_, &error); + if (!error.empty()) { + LOG(ERROR) << "Failed to dismiss suggestion. " << error; + } +} + +} // namespace chromeos
diff --git a/chrome/browser/chromeos/input_method/personal_info_suggester.h b/chrome/browser/chromeos/input_method/personal_info_suggester.h new file mode 100644 index 0000000..8f3d261 --- /dev/null +++ b/chrome/browser/chromeos/input_method/personal_info_suggester.h
@@ -0,0 +1,69 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_CHROMEOS_INPUT_METHOD_PERSONAL_INFO_SUGGESTER_H_ +#define CHROME_BROWSER_CHROMEOS_INPUT_METHOD_PERSONAL_INFO_SUGGESTER_H_ + +#include <string> + +#include "chrome/browser/chromeos/input_method/input_method_engine.h" +#include "chrome/browser/chromeos/input_method/suggester.h" +#include "chrome/browser/chromeos/input_method/suggestion_enums.h" +#include "chrome/browser/ui/input_method/input_method_engine_base.h" + +namespace autofill { +class PersonalDataManager; +} // namespace autofill + +class Profile; + +namespace chromeos { + +AssistiveType ProposeAssistiveAction(const base::string16& text); + +// An agent to suggest personal information when the user types, and adopt or +// dismiss the suggestion according to the user action. +class PersonalInfoSuggester : public Suggester { + public: + explicit PersonalInfoSuggester(InputMethodEngine* engine, Profile* profile); + ~PersonalInfoSuggester() override; + + // Suggester overrides: + void OnFocus(int context_id) override; + void OnBlur() override; + SuggestionStatus HandleKeyEvent( + const ::input_method::InputMethodEngineBase::KeyboardEvent& event) + override; + bool Suggest(const base::string16& text) override; + void DismissSuggestion() override; + AssistiveType GetProposeActionType() override; + + private: + // Get the suggestion according to |text_before_cursor|. + base::string16 GetPersonalInfoSuggestion( + const base::string16& text_before_cursor); + + void ShowSuggestion(const base::string16& text); + + InputMethodEngine* const engine_; + + // ID of the focused text field, 0 if none is focused. + int context_id_ = -1; + + // Assistive type of the last proposed assistive action. + AssistiveType proposed_action_type_ = AssistiveType::kGenericAction; + + // User's Chrome user profile. + Profile* const profile_; + + // Personal data manager provided by autofill service. + autofill::PersonalDataManager* const personal_data_manager_; + + // If we are showing a suggestion right now. + bool suggestion_shown_ = false; +}; + +} // namespace chromeos + +#endif // CHROME_BROWSER_CHROMEOS_INPUT_METHOD_PERSONAL_INFO_SUGGESTER_H_
diff --git a/chrome/browser/chromeos/input_method/suggester.h b/chrome/browser/chromeos/input_method/suggester.h new file mode 100644 index 0000000..ccab16e --- /dev/null +++ b/chrome/browser/chromeos/input_method/suggester.h
@@ -0,0 +1,45 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_CHROMEOS_INPUT_METHOD_SUGGESTER_H_ +#define CHROME_BROWSER_CHROMEOS_INPUT_METHOD_SUGGESTER_H_ + +#include <string> + +#include "chrome/browser/chromeos/input_method/input_method_engine.h" +#include "chrome/browser/chromeos/input_method/suggestion_enums.h" +#include "chrome/browser/ui/input_method/input_method_engine_base.h" + +namespace chromeos { + +// A generic agent to suggest when the user types, and adopt or dismiss the +// suggestion according to the user action. +class Suggester { + public: + virtual ~Suggester() {} + + // Called when a text field gains focus, and suggester starts working. + virtual void OnFocus(int context_id) = 0; + + // Called when a text field loses focus, and suggester stops working. + virtual void OnBlur() = 0; + + // Called when suggestion is being shown. + // Returns SuggestionStatus as suggester handles the event. + virtual SuggestionStatus HandleKeyEvent( + const ::input_method::InputMethodEngineBase::KeyboardEvent& event) = 0; + + // Check if suggestion should be displayed according to the surrounding text + // information. + virtual bool Suggest(const base::string16& text) = 0; + + virtual void DismissSuggestion() = 0; + + // Return the propose assistive action type. + virtual AssistiveType GetProposeActionType() = 0; +}; + +} // namespace chromeos + +#endif // CHROME_BROWSER_CHROMEOS_INPUT_METHOD_SUGGESTER_H_
diff --git a/chrome/browser/chromeos/input_method/suggestion_enums.h b/chrome/browser/chromeos/input_method/suggestion_enums.h new file mode 100644 index 0000000..cde2958 --- /dev/null +++ b/chrome/browser/chromeos/input_method/suggestion_enums.h
@@ -0,0 +1,33 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_CHROMEOS_INPUT_METHOD_SUGGESTION_ENUMS_H_ +#define CHROME_BROWSER_CHROMEOS_INPUT_METHOD_SUGGESTION_ENUMS_H_ + +#include <string> + +#include "chrome/browser/chromeos/input_method/input_method_engine.h" +#include "chrome/browser/ui/input_method/input_method_engine_base.h" + +namespace chromeos { + +// Must match with IMEAssistiveAction in enums.xml +enum class AssistiveType { + kGenericAction = 0, + kPersonalEmail = 1, + kPersonalAddress = 2, + kPersonalPhoneNumber = 3, + kPersonalName = 4, + kMaxValue = kPersonalName, +}; + +enum class SuggestionStatus { + kNotHandled = 0, + kAccept = 1, + kDismiss = 2, +}; + +} // namespace chromeos + +#endif // CHROME_BROWSER_CHROMEOS_INPUT_METHOD_SUGGESTION_ENUMS_H_
diff --git a/chrome/browser/chromeos/net/network_pref_state_observer.cc b/chrome/browser/chromeos/net/network_pref_state_observer.cc index 232a051..a1fd64d4f 100644 --- a/chrome/browser/chromeos/net/network_pref_state_observer.cc +++ b/chrome/browser/chromeos/net/network_pref_state_observer.cc
@@ -8,7 +8,10 @@ #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/chromeos/profiles/profile_helper.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/sync/wifi_configuration_sync_service_factory.h" +#include "chromeos/components/sync_wifi/wifi_configuration_sync_service.h" #include "chromeos/network/network_handler.h" +#include "chromeos/network/network_metadata_store.h" #include "content/public/browser/notification_service.h" namespace chromeos { @@ -40,6 +43,14 @@ if (ProfileHelper::IsPrimaryProfile(profile)) { InitializeNetworkPrefServices(profile); notification_registrar_.RemoveAll(); + + auto* wifi_sync_service = + WifiConfigurationSyncServiceFactory::GetForProfile(profile, + /*create=*/false); + if (wifi_sync_service) { + wifi_sync_service->SetNetworkMetadataStore( + NetworkHandler::Get()->network_metadata_store()->GetWeakPtr()); + } } }
diff --git a/chrome/browser/chromeos/policy/configuration_policy_handler_chromeos.cc b/chrome/browser/chromeos/policy/configuration_policy_handler_chromeos.cc index f9ea7db..b88af694 100644 --- a/chrome/browser/chromeos/policy/configuration_policy_handler_chromeos.cc +++ b/chrome/browser/chromeos/policy/configuration_policy_handler_chromeos.cc
@@ -324,11 +324,11 @@ return crx_file::id_util::IdIsValid(str); } -void PinnedLauncherAppsPolicyHandler::ApplyList( - std::unique_ptr<base::ListValue> filtered_list, - PrefValueMap* prefs) { +void PinnedLauncherAppsPolicyHandler::ApplyList(base::Value filtered_list, + PrefValueMap* prefs) { + DCHECK(filtered_list.is_list()); std::vector<base::Value> pinned_apps_list; - for (const base::Value& entry : filtered_list->GetList()) { + for (const base::Value& entry : filtered_list.GetList()) { base::Value app_dict(base::Value::Type::DICTIONARY); app_dict.SetKey(kPinnedAppsPrefAppIDKey, entry.Clone()); pinned_apps_list.push_back(std::move(app_dict));
diff --git a/chrome/browser/chromeos/policy/configuration_policy_handler_chromeos.h b/chrome/browser/chromeos/policy/configuration_policy_handler_chromeos.h index ce8d736..936dce6 100644 --- a/chrome/browser/chromeos/policy/configuration_policy_handler_chromeos.h +++ b/chrome/browser/chromeos/policy/configuration_policy_handler_chromeos.h
@@ -9,15 +9,12 @@ #include "base/compiler_specific.h" #include "base/macros.h" +#include "base/values.h" #include "chrome/browser/extensions/policy_handlers.h" #include "chromeos/network/network_ui_data.h" #include "components/onc/onc_constants.h" #include "components/policy/core/browser/configuration_policy_handler.h" -namespace base { -class Value; -} - namespace policy { class Schema; @@ -95,8 +92,7 @@ // Converts the list of strings |filtered_list| to a list of dictionaries and // sets the pref. - void ApplyList(std::unique_ptr<base::ListValue> filtered_list, - PrefValueMap* prefs) override; + void ApplyList(base::Value filtered_list, PrefValueMap* prefs) override; private: DISALLOW_COPY_AND_ASSIGN(PinnedLauncherAppsPolicyHandler);
diff --git a/chrome/browser/chromeos/policy/system_features_disable_list_policy_handler.cc b/chrome/browser/chromeos/policy/system_features_disable_list_policy_handler.cc index 961e7c9..dc8efe0 100644 --- a/chrome/browser/chromeos/policy/system_features_disable_list_policy_handler.cc +++ b/chrome/browser/chromeos/policy/system_features_disable_list_policy_handler.cc
@@ -24,10 +24,11 @@ } void SystemFeaturesDisableListPolicyHandler::ApplyList( - std::unique_ptr<base::ListValue> filtered_list, + base::Value filtered_list, PrefValueMap* prefs) { + DCHECK(filtered_list.is_list()); prefs->SetValue(policy_prefs::kSystemFeaturesDisableList, - base::Value::FromUniquePtrValue(std::move(filtered_list))); + std::move(filtered_list)); } } // namespace policy
diff --git a/chrome/browser/chromeos/policy/system_features_disable_list_policy_handler.h b/chrome/browser/chromeos/policy/system_features_disable_list_policy_handler.h index cf854170..2971cc80 100644 --- a/chrome/browser/chromeos/policy/system_features_disable_list_policy_handler.h +++ b/chrome/browser/chromeos/policy/system_features_disable_list_policy_handler.h
@@ -7,11 +7,9 @@ #include <memory> +#include "base/values.h" #include "components/policy/core/browser/configuration_policy_handler.h" -namespace base { -class ListValue; -} class PrefValueMap; class PrefRegistrySimple; @@ -27,8 +25,7 @@ protected: // ListPolicyHandler: - void ApplyList(std::unique_ptr<base::ListValue> filtered_list, - PrefValueMap* prefs) override; + void ApplyList(base::Value filtered_list, PrefValueMap* prefs) override; }; } // namespace policy
diff --git a/chrome/browser/chromeos/printing/print_servers_provider.cc b/chrome/browser/chromeos/printing/print_servers_provider.cc index 71ab3e8bc..c972e52ec 100644 --- a/chrome/browser/chromeos/printing/print_servers_provider.cc +++ b/chrome/browser/chromeos/printing/print_servers_provider.cc
@@ -40,8 +40,9 @@ // Parses |data|, a JSON blob, into a vector of PrintServers. If |data| cannot // be parsed, returns data with empty list of servers. -// This needs to run on a sequence that may block as it can be very slow. +// This needs to not run on UI thread as it can be very slow. TaskResults ParseData(int task_id, std::unique_ptr<std::string> data) { + DCHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); TaskResults task_data; task_data.task_id = task_id; @@ -50,9 +51,6 @@ return task_data; } - // This could be really slow. - base::ScopedBlockingCall scoped_blocking_call(FROM_HERE, - base::BlockingType::MAY_BLOCK); base::JSONReader::ValueWithError value_with_error = base::JSONReader::ReadAndReturnValueWithError( *data, base::JSONParserOptions::JSON_ALLOW_TRAILING_COMMAS);
diff --git a/chrome/browser/chromeos/web_applications/terminal_source.cc b/chrome/browser/chromeos/web_applications/terminal_source.cc index b51e3b6f..297d225 100644 --- a/chrome/browser/chromeos/web_applications/terminal_source.cc +++ b/chrome/browser/chromeos/web_applications/terminal_source.cc
@@ -13,7 +13,7 @@ #include "base/task/post_task.h" #include "base/task/task_traits.h" #include "base/task/thread_pool.h" -#include "chrome/browser/chromeos/crostini/crostini_pref_names.h" +#include "chrome/browser/chromeos/crostini/crostini_terminal.h" #include "chrome/browser/profiles/profile.h" #include "chrome/common/url_constants.h" #include "chrome/common/webui_url_constants.h" @@ -30,8 +30,6 @@ constexpr base::FilePath::CharType kDefaultFile[] = FILE_PATH_LITERAL("html/crosh.html"); constexpr char kDefaultMime[] = "text/html"; -constexpr char kDefaultTheme[] = "#101010"; -constexpr char kPrefKeyTheme[] = "/hterm/profiles/default/background-color"; void ReadFile(const std::string& relative_path, content::URLDataSource::GotDataCallback callback) { @@ -105,8 +103,10 @@ path = kDefaultFile; // Replace $i8n{themeColor} in *.html. - if (base::EndsWith(path, ".html", base::CompareCase::INSENSITIVE_ASCII)) - replacements_["themeColor"] = GetThemeColorFromPrefs(); + if (base::EndsWith(path, ".html", base::CompareCase::INSENSITIVE_ASCII)) { + replacements_["themeColor"] = net::EscapeForHTML( + crostini::GetTerminalSettingBackgroundColor(profile_)); + } base::ThreadPool::PostTask( FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_BLOCKING}, @@ -129,10 +129,3 @@ const ui::TemplateReplacements* TerminalSource::GetReplacements() { return &replacements_; } - -std::string TerminalSource::GetThemeColorFromPrefs() { - const base::DictionaryValue* value = profile_->GetPrefs()->GetDictionary( - crostini::prefs::kCrostiniTerminalSettings); - const std::string* theme = value->FindStringKey(kPrefKeyTheme); - return theme ? net::EscapeForHTML(*theme) : kDefaultTheme; -}
diff --git a/chrome/browser/chromeos/web_applications/terminal_source.h b/chrome/browser/chromeos/web_applications/terminal_source.h index a3b566a..5722d838 100644 --- a/chrome/browser/chromeos/web_applications/terminal_source.h +++ b/chrome/browser/chromeos/web_applications/terminal_source.h
@@ -37,10 +37,6 @@ bool ShouldServeMimeTypeAsContentTypeHeader() override; const ui::TemplateReplacements* GetReplacements() override; - // Get theme color from terminal settings in prefs (with HTML escaping). - // Returns default theme '#101010' if no prefs set. - std::string GetThemeColorFromPrefs(); - Profile* profile_; ui::TemplateReplacements replacements_;
diff --git a/chrome/browser/extensions/DEPS b/chrome/browser/extensions/DEPS index d83152c9..c435384 100644 --- a/chrome/browser/extensions/DEPS +++ b/chrome/browser/extensions/DEPS
@@ -34,4 +34,7 @@ # network::CrossOriginReadBlocking::Action enum. "+services/network/cross_origin_read_blocking.h" ], + "webstore_private_apitest.cc" : [ + "+chrome/browser/ui/views/parent_permission_dialog_view.h", + ], }
diff --git a/chrome/browser/extensions/api/commands/command_service.cc b/chrome/browser/extensions/api/commands/command_service.cc index 6760176..9968178 100644 --- a/chrome/browser/extensions/api/commands/command_service.cc +++ b/chrome/browser/extensions/api/commands/command_service.cc
@@ -19,7 +19,6 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/accelerator_utils.h" #include "chrome/common/extensions/api/commands/commands_handler.h" -#include "chrome/common/extensions/manifest_handlers/ui_overrides_handler.h" #include "chrome/common/pref_names.h" #include "components/pref_registry/pref_registry_syncable.h" #include "components/prefs/scoped_user_pref_update.h" @@ -132,23 +131,6 @@ return BrowserContextKeyedAPIFactory<CommandService>::Get(context); } -// static -bool CommandService::RemovesBookmarkShortcut(const Extension* extension) { - return UIOverrides::RemovesBookmarkShortcut(extension) && - (extension->permissions_data()->HasAPIPermission( - APIPermission::kBookmarkManagerPrivate) || - FeatureSwitch::enable_override_bookmarks_ui()->IsEnabled()); -} - -// static -bool CommandService::RemovesBookmarkAllTabsShortcut( - const Extension* extension) { - return UIOverrides::RemovesBookmarkAllTabsShortcut(extension) && - (extension->permissions_data()->HasAPIPermission( - APIPermission::kBookmarkManagerPrivate) || - FeatureSwitch::enable_override_bookmarks_ui()->IsEnabled()); -} - bool CommandService::GetBrowserActionCommand(const std::string& extension_id, QueryType type, Command* command, @@ -419,14 +401,6 @@ return false; } -bool CommandService::RequestsBookmarkShortcutOverride( - const Extension* extension) const { - return RemovesBookmarkShortcut(extension) && - GetSuggestedExtensionCommand( - extension->id(), - chrome::GetPrimaryChromeAcceleratorForBookmarkTab(), nullptr); -} - void CommandService::AddObserver(Observer* observer) { observers_.AddObserver(observer); } @@ -572,22 +546,10 @@ return false; return (command.accelerator().key_code() >= ui::VKEY_0 && command.accelerator().key_code() <= ui::VKEY_9); - } else { - // Not a global command, check if Chrome shortcut and whether - // we can override it. - if (command.accelerator() == - chrome::GetPrimaryChromeAcceleratorForBookmarkTab() && - CommandService::RemovesBookmarkShortcut(extension)) { - // If this check fails it either means we have an API to override a - // key that isn't a ChromeAccelerator (and the API can therefore be - // deprecated) or the IsChromeAccelerator isn't consistently - // returning true for all accelerators. - DCHECK(chrome::IsChromeAccelerator(command.accelerator(), profile_)); - return true; - } - - return !chrome::IsChromeAccelerator(command.accelerator(), profile_); } + + // Not a global command, check if the command is a Chrome shortcut. + return !chrome::IsChromeAccelerator(command.accelerator(), profile_); } void CommandService::UpdateExtensionSuggestedCommandPrefs(
diff --git a/chrome/browser/extensions/api/commands/command_service.h b/chrome/browser/extensions/api/commands/command_service.h index 73251ed8..0c7f057 100644 --- a/chrome/browser/extensions/api/commands/command_service.h +++ b/chrome/browser/extensions/api/commands/command_service.h
@@ -94,14 +94,6 @@ // Convenience method to get the CommandService for a profile. static CommandService* Get(content::BrowserContext* context); - // Returns true if |extension| is permitted to and does remove the bookmark - // shortcut key. - static bool RemovesBookmarkShortcut(const Extension* extension); - - // Returns true if |extension| is permitted to and does remove the bookmark - // all tabs shortcut key. - static bool RemovesBookmarkAllTabsShortcut(const Extension* extension); - // Gets the command (if any) for the browser action of an extension given // its |extension_id|. The function consults the master list to see if // the command is active. Returns false if the extension has no browser @@ -181,10 +173,6 @@ const ui::Accelerator& accelerator, Command* command) const; - // Returns true if |extension| requests to override the bookmark shortcut key - // and should be allowed to do so. - bool RequestsBookmarkShortcutOverride(const Extension* extension) const; - void AddObserver(Observer* observer); void RemoveObserver(Observer* observer);
diff --git a/chrome/browser/extensions/api/messaging/native_messaging_policy_handler.cc b/chrome/browser/extensions/api/messaging/native_messaging_policy_handler.cc index 4dbc135..e9aa21e 100644 --- a/chrome/browser/extensions/api/messaging/native_messaging_policy_handler.cc +++ b/chrome/browser/extensions/api/messaging/native_messaging_policy_handler.cc
@@ -28,12 +28,10 @@ return NativeMessagingHostManifest::IsValidName(str); } -void NativeMessagingHostListPolicyHandler::ApplyList( - std::unique_ptr<base::ListValue> filtered_list, - PrefValueMap* prefs) { - DCHECK(filtered_list); - prefs->SetValue(pref_path_, - base::Value::FromUniquePtrValue(std::move(filtered_list))); +void NativeMessagingHostListPolicyHandler::ApplyList(base::Value filtered_list, + PrefValueMap* prefs) { + DCHECK(filtered_list.is_list()); + prefs->SetValue(pref_path_, std::move(filtered_list)); } } // namespace extensions
diff --git a/chrome/browser/extensions/api/messaging/native_messaging_policy_handler.h b/chrome/browser/extensions/api/messaging/native_messaging_policy_handler.h index 456f60a4..b6ab5ce 100644 --- a/chrome/browser/extensions/api/messaging/native_messaging_policy_handler.h +++ b/chrome/browser/extensions/api/messaging/native_messaging_policy_handler.h
@@ -29,8 +29,7 @@ bool CheckListEntry(const base::Value& value) override; // Sets |prefs| at pref_path() to |filtered_list|. - void ApplyList(std::unique_ptr<base::ListValue> filtered_list, - PrefValueMap* prefs) override; + void ApplyList(base::Value filtered_list, PrefValueMap* prefs) override; private: const char* pref_path_;
diff --git a/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc b/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc index e1abc29..3349dab 100644 --- a/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc +++ b/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc
@@ -56,9 +56,11 @@ #include "url/gurl.h" #if BUILDFLAG(ENABLE_SUPERVISED_USERS) +// TODO(https://crbug.com/1060801): Here and elsewhere, possibly switch build +// flag to #if defined(OS_CHROMEOS) #include "chrome/browser/supervised_user/supervised_user_service.h" #include "chrome/browser/supervised_user/supervised_user_service_factory.h" -#endif +#endif // BUILDFLAG(ENABLE_SUPERVISED_USERS) using safe_browsing::SafeBrowsingNavigationObserverManager; @@ -159,6 +161,16 @@ const char kEphemeralAppLaunchingNotSupported[] = "Ephemeral launching of apps is no longer supported."; +#if BUILDFLAG(ENABLE_SUPERVISED_USERS) +// Note that the following error doesn't mean an incorrect password was entered, +// nor that the parent permisison request was canceled by the user, but rather +// that the Parent permission request after credential entry and acceptance +// failed due to either a network connection error or some unsatisfied invariant +// that prevented the request from completing. +const char kWebstoreParentPermissionFailedError[] = + "Parent permission request failed"; +#endif // BUILDFLAG(ENABLE_SUPERVISED_USERS) + // The number of user gestures to trace back for the referrer chain. const int kExtensionReferrerUserGestureLimit = 2; @@ -278,17 +290,17 @@ } WebstorePrivateBeginInstallWithManifest3Function:: - WebstorePrivateBeginInstallWithManifest3Function() : chrome_details_(this) { -} + WebstorePrivateBeginInstallWithManifest3Function() + : chrome_details_(this) {} + +WebstorePrivateBeginInstallWithManifest3Function:: + ~WebstorePrivateBeginInstallWithManifest3Function() = default; base::string16 WebstorePrivateBeginInstallWithManifest3Function:: GetBlockedByPolicyErrorMessageForTesting() const { return blocked_by_policy_error_message_; } -WebstorePrivateBeginInstallWithManifest3Function:: - ~WebstorePrivateBeginInstallWithManifest3Function() = default; - ExtensionFunction::ResponseAction WebstorePrivateBeginInstallWithManifest3Function::Run() { params_ = Params::Create(*args_); @@ -439,11 +451,18 @@ : ExtensionInstallPrompt::EXTENSION_PENDING_REQUEST_PROMPT), ExtensionInstallPrompt::GetDefaultShowDialogCallback()); } else { + auto prompt = std::make_unique<ExtensionInstallPrompt::Prompt>( + ExtensionInstallPrompt::INSTALL_PROMPT); + +#if BUILDFLAG(ENABLE_SUPERVISED_USERS) + prompt->set_user_is_child(profile->IsChild()); +#endif // BUILDFLAG(ENABLE_SUPERVISED_USERS) + install_prompt_->ShowDialog( base::BindRepeating(&WebstorePrivateBeginInstallWithManifest3Function:: OnInstallPromptDone, this), - dummy_extension_.get(), &icon_, + dummy_extension_.get(), &icon_, std::move(prompt), ExtensionInstallPrompt::GetDefaultShowDialogCallback()); } // Control flow finishes up in OnInstallPromptDone, OnRequestPromptDone or @@ -463,11 +482,106 @@ Release(); } +#if BUILDFLAG(ENABLE_SUPERVISED_USERS) + +void WebstorePrivateBeginInstallWithManifest3Function::OnParentPermissionDone( + ParentPermissionDialog::Result result) { + switch (result) { + case ParentPermissionDialog::Result::kParentPermissionReceived: + OnParentPermissionReceived(); + break; + case ParentPermissionDialog::Result::kParentPermissionCanceled: + OnParentPermissionCanceled(); + break; + case ParentPermissionDialog::Result::kParentPermissionFailed: + OnParentPermissionFailed(); + break; + } +} + +void WebstorePrivateBeginInstallWithManifest3Function:: + OnParentPermissionReceived() { + SupervisedUserService* service = + SupervisedUserServiceFactory::GetForProfile(chrome_details_.GetProfile()); + service->AddExtensionApproval(*dummy_extension_); + + HandleInstallProceed(); + Release(); // Matches the AddRef in Run(). +} + +void WebstorePrivateBeginInstallWithManifest3Function:: + OnParentPermissionCanceled() { + if (test_webstore_installer_delegate) { + test_webstore_installer_delegate->OnExtensionInstallFailure( + dummy_extension_->id(), kWebstoreParentPermissionFailedError, + WebstoreInstaller::FailureReason::FAILURE_REASON_CANCELLED); + } + + HandleInstallAbort(true /* user_initiated */); + Release(); // Matches the AddRef in Run(). +} + +void WebstorePrivateBeginInstallWithManifest3Function:: + OnParentPermissionFailed() { + if (test_webstore_installer_delegate) { + test_webstore_installer_delegate->OnExtensionInstallFailure( + dummy_extension_->id(), kWebstoreParentPermissionFailedError, + WebstoreInstaller::FailureReason::FAILURE_REASON_OTHER); + } + + Respond(BuildResponse(api::webstore_private::RESULT_UNKNOWN_ERROR, + kWebstoreParentPermissionFailedError)); + + Release(); // Matches the AddRef in Run(). +} + +bool WebstorePrivateBeginInstallWithManifest3Function:: + PromptForParentApproval() { + Profile* profile = chrome_details_.GetProfile(); + DCHECK(profile->IsChild()); + content::WebContents* web_contents = GetSenderWebContents(); + if (!web_contents) { + // The browser window has gone away. + Respond(BuildResponse(api::webstore_private::RESULT_USER_CANCELLED, + kWebstoreUserCancelledError)); + return false; + } + + ParentPermissionDialog::DoneCallback done_callback = base::BindOnce( + &WebstorePrivateBeginInstallWithManifest3Function::OnParentPermissionDone, + this); + + parent_permission_dialog_ = + ParentPermissionDialog::CreateParentPermissionDialogForExtension( + profile, web_contents, web_contents->GetTopLevelNativeWindow(), + gfx::ImageSkia::CreateFrom1xBitmap(icon_), dummy_extension_.get(), + std::move(done_callback)); + parent_permission_dialog_->ShowDialog(); + + return true; +} +#endif // BUILDFLAG(ENABLE_SUPERVISED_USERS) + void WebstorePrivateBeginInstallWithManifest3Function::OnInstallPromptDone( ExtensionInstallPrompt::Result result) { switch (result) { case ExtensionInstallPrompt::Result::ACCEPTED: case ExtensionInstallPrompt::Result::ACCEPTED_AND_OPTION_CHECKED: { +#if BUILDFLAG(ENABLE_SUPERVISED_USERS) + // Handle parent permission for child accounts on ChromeOS. + Profile* profile = chrome_details_.GetProfile(); + if (g_browser_process->profile_manager()->IsValidProfile(profile) && + profile->IsChild()) { + if (PromptForParentApproval()) { + // If are showing parent permission dialog, return instead of + // break, so that we don't release the ref below. + return; + } else { + // An error occurred, break so that we release the ref below. + break; + } + } +#endif // BUILDFLAG(ENABLE_SUPERVISED_USERS) HandleInstallProceed(); break; } @@ -560,7 +674,8 @@ ExtensionFunction::ResponseValue WebstorePrivateBeginInstallWithManifest3Function::BuildResponse( - api::webstore_private::Result result, const std::string& error) { + api::webstore_private::Result result, + const std::string& error) { if (result != api::webstore_private::RESULT_SUCCESS) return ErrorWithArguments(CreateResults(result), error);
diff --git a/chrome/browser/extensions/api/webstore_private/webstore_private_api.h b/chrome/browser/extensions/api/webstore_private/webstore_private_api.h index 417dd62b..f1651c7 100644 --- a/chrome/browser/extensions/api/webstore_private/webstore_private_api.h +++ b/chrome/browser/extensions/api/webstore_private/webstore_private_api.h
@@ -15,11 +15,18 @@ #include "chrome/browser/extensions/extension_install_prompt.h" #include "chrome/browser/extensions/webstore_install_helper.h" #include "chrome/browser/extensions/webstore_installer.h" +#include "chrome/common/buildflags.h" #include "chrome/common/extensions/api/webstore_private.h" #include "chrome/common/extensions/webstore_install_result.h" #include "extensions/browser/extension_function.h" #include "third_party/skia/include/core/SkBitmap.h" +#if BUILDFLAG(ENABLE_SUPERVISED_USERS) +// TODO(https://crbug.com/1060801): Here and elsewhere, possibly switch build +// flag to #if defined(OS_CHROMEOS) +#include "chrome/browser/ui/supervised_user/parent_permission_dialog.h" +#endif // BUILDFLAG(ENABLE_SUPERVISED_USERS) + namespace content { class GpuFeatureChecker; } @@ -71,6 +78,15 @@ InstallHelperResultCode result, const std::string& error_message) override; +#if BUILDFLAG(ENABLE_SUPERVISED_USERS) + void OnParentPermissionDone(ParentPermissionDialog::Result result); + void OnParentPermissionReceived(); + void OnParentPermissionCanceled(); + void OnParentPermissionFailed(); + // Returns true if the parental approval prompt was shown, false if there was + // an error showing it. + bool PromptForParentApproval(); +#endif // BUILDFLAG(ENABLE_SUPERVISED_USERS) void OnInstallPromptDone(ExtensionInstallPrompt::Result result); void OnRequestPromptDone(ExtensionInstallPrompt::Result result); void OnBlockByPolicyPromptDone(); @@ -110,6 +126,10 @@ base::string16 blocked_by_policy_error_message_; +#if BUILDFLAG(ENABLE_SUPERVISED_USERS) + std::unique_ptr<ParentPermissionDialog> parent_permission_dialog_; +#endif + std::unique_ptr<ExtensionInstallPrompt> install_prompt_; };
diff --git a/chrome/browser/extensions/api/webstore_private/webstore_private_apitest.cc b/chrome/browser/extensions/api/webstore_private/webstore_private_apitest.cc index 8e10ae9e..2a9ef3e 100644 --- a/chrome/browser/extensions/api/webstore_private/webstore_private_apitest.cc +++ b/chrome/browser/extensions/api/webstore_private/webstore_private_apitest.cc
@@ -42,8 +42,21 @@ #include "ui/gl/gl_switches.h" #if BUILDFLAG(ENABLE_SUPERVISED_USERS) +// TODO(https://crbug.com/1060801): Here and elsewhere, possibly switch build +// flag to #if defined(OS_CHROMEOS) +#include "base/test/metrics/histogram_tester.h" +#include "base/test/scoped_feature_list.h" #include "chrome/browser/supervised_user/logged_in_user_mixin.h" #include "chrome/browser/supervised_user/supervised_user_constants.h" +#include "chrome/browser/supervised_user/supervised_user_features.h" +#include "chrome/browser/supervised_user/supervised_user_service.h" +#include "chrome/browser/supervised_user/supervised_user_service_factory.h" +#include "chrome/browser/ui/supervised_user/parent_permission_dialog.h" +#include "chrome/browser/ui/views/parent_permission_dialog_view.h" +#include "chrome/common/pref_names.h" +#include "components/account_id/account_id.h" +#include "components/signin/public/identity_manager/identity_test_environment.h" +#include "extensions/common/extension_builder.h" #if defined(OS_CHROMEOS) #include "chromeos/constants/chromeos_switches.h" @@ -79,6 +92,7 @@ received_failure_ = true; id_ = id; error_ = error; + last_failure_reason_ = reason; if (waiting_) { waiting_ = false; @@ -94,12 +108,17 @@ content::RunMessageLoop(); } bool received_success() const { return received_success_; } + bool received_failure() const { return received_failure_; } const std::string& id() const { return id_; } + WebstoreInstaller::FailureReason last_failure_reason() { + return last_failure_reason_; + } private: bool received_failure_; bool received_success_; bool waiting_; + WebstoreInstaller::FailureReason last_failure_reason_; std::string id_; std::string error_; }; @@ -372,15 +391,21 @@ } #if BUILDFLAG(ENABLE_SUPERVISED_USERS) +static constexpr char kTestChildEmail[] = "test_child_user@google.com"; +static constexpr char kTestChildGaiaId[] = "8u8tuw09sufncmnaos"; + class ExtensionWebstorePrivateApiTestChild : public ExtensionWebstorePrivateApiTest { public: ExtensionWebstorePrivateApiTestChild() : embedded_test_server_(std::make_unique<net::EmbeddedTestServer>()), - logged_in_user_mixin_(&mixin_host_, - chromeos::LoggedInUserMixin::LogInType::kChild, - embedded_test_server_.get(), - this) { + logged_in_user_mixin_( + &mixin_host_, + chromeos::LoggedInUserMixin::LogInType::kChild, + embedded_test_server_.get(), + this, + true /* should_launch_browser */, + AccountId::FromUserEmailGaiaId(kTestChildEmail, kTestChildGaiaId)) { // Suppress regular user login to enable child user login. set_chromeos_user_ = false; } @@ -422,10 +447,39 @@ browser_main_parts); } + void InitializeFamilyData() { + // Set up the child user's custodians (i.e. parents). + ASSERT_TRUE(browser()); + PrefService* prefs = browser()->profile()->GetPrefs(); + prefs->SetString(prefs::kSupervisedUserCustodianEmail, + "test_parent_0@google.com"); + prefs->SetString(prefs::kSupervisedUserCustodianObfuscatedGaiaId, + "239029320"); + + prefs->SetString(prefs::kSupervisedUserSecondCustodianEmail, + "test_parent_1@google.com"); + prefs->SetString(prefs::kSupervisedUserSecondCustodianObfuscatedGaiaId, + "85948533"); + + // Set up the identity test environment, which provides fake + // OAuth refresh tokens. + identity_test_env_ = std::make_unique<signin::IdentityTestEnvironment>(); + identity_test_env_->MakeAccountAvailable(kTestChildEmail); + identity_test_env_->SetPrimaryAccount(kTestChildEmail); + identity_test_env_->SetRefreshTokenForPrimaryAccount(); + identity_test_env_->SetAutomaticIssueOfAccessTokens(true); + } + void SetUpOnMainThread() override { mixin_host_.SetUpOnMainThread(); + logged_in_user_mixin_.LogInUser(true /* issue_any_scope_token */); ExtensionWebstorePrivateApiTest::SetUpOnMainThread(); - logged_in_user_mixin_.LogInUser(true /*issue_any_scope_token*/); + + InitializeFamilyData(); + SupervisedUserService* service = + SupervisedUserServiceFactory::GetForProfile(profile()); + service->SetSupervisedUserExtensionsMayRequestPermissionsPrefForTesting( + true); } void TearDownOnMainThread() override { @@ -443,22 +497,143 @@ ExtensionWebstorePrivateApiTest::TearDown(); } + chromeos::LoggedInUserMixin* GetLoggedInUserMixin() { + return &logged_in_user_mixin_; + } + + void SetNextReAuthStatus( + const GaiaAuthConsumer::ReAuthProofTokenStatus next_status) { + GetLoggedInUserMixin() + ->GetFakeGaiaMixin() + ->fake_gaia() + ->SetNextReAuthStatus(next_status); + } + + protected: + std::unique_ptr<signin::IdentityTestEnvironment> identity_test_env_; + private: // Replicate what MixinBasedInProcessBrowserTest does since inheriting from // that class is inconvenient here. InProcessBrowserTestMixinHost mixin_host_; // Create another embedded test server to avoid starting the same one twice. std::unique_ptr<net::EmbeddedTestServer> embedded_test_server_; - chromeos::LoggedInUserMixin logged_in_user_mixin_; }; -// Tests that extension installation is blocked for child accounts, and -// attempting to do so produces a special error code. -// Note: This will have to be updated when we enable child-initiated installs. -IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTestChild, InstallBlocked) { - ASSERT_TRUE(browser()); - ASSERT_TRUE(RunInstallTest("begin_install_fail_child.html", "extension.crx")); +class ExtensionWebstorePrivateApiTestChildInstallDisabled + : public ExtensionWebstorePrivateApiTestChild { + public: + ExtensionWebstorePrivateApiTestChildInstallDisabled() { + feature_list_.InitWithFeatures( + {}, {supervised_users::kSupervisedUserInitiatedExtensionInstall}); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + +// Tests that extension installation is blocked for child accounts when +// the feature flag is disabled. +IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTestChildInstallDisabled, + InstallBlocked) { + ASSERT_TRUE(RunInstallTest("install_blocked_child.html", "app.crx")); +} + +static constexpr char kTestAppId[] = "iladmdjkfniedhfhcfoefgojhgaiaccc"; +static constexpr char kTestAppVersion[] = "0.1"; + +// Test fixture for various cases of installation for child accounts +// when the feature flag is enabled. +class ExtensionWebstorePrivateApiTestChildInstallEnabled + : public ExtensionWebstorePrivateApiTestChild, + public TestParentPermissionDialogViewObserver { + public: + // The next dialog action to take. + enum class NextDialogAction { + kCancel, + kAccept, + }; + + ExtensionWebstorePrivateApiTestChildInstallEnabled() + : TestParentPermissionDialogViewObserver(this) { + feature_list_.InitWithFeatures( + {supervised_users::kSupervisedUserInitiatedExtensionInstall}, {}); + } + + // TestParentPermissionDialogViewObserver override: + void OnTestParentPermissionDialogViewCreated( + ParentPermissionDialogView* view) override { + view->SetRepromptAfterIncorrectCredential(false); + view->SetIdentityManagerForTesting(identity_test_env_->identity_manager()); + // Everything is set up, so take the next action. + if (next_dialog_action_) { + switch (next_dialog_action_.value()) { + case NextDialogAction::kCancel: + view->CancelDialog(); + break; + case NextDialogAction::kAccept: + view->AcceptDialog(); + break; + } + } + } + + void set_next_dialog_action(NextDialogAction action) { + next_dialog_action_ = action; + } + + private: + base::test::ScopedFeatureList feature_list_; + base::Optional<NextDialogAction> next_dialog_action_; +}; + +// Tests install for a child when parent permission is granted. +IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTestChildInstallEnabled, + ParentPermissionGranted) { + WebstoreInstallListener listener; + WebstorePrivateApi::SetWebstoreInstallerDelegateForTesting(&listener); + set_next_dialog_action(NextDialogAction::kAccept); + + // Tell the Reauth API client to return a success for the next reauth + // request. + SetNextReAuthStatus(GaiaAuthConsumer::ReAuthProofTokenStatus::kSuccess); + ASSERT_TRUE(RunInstallTest("install_child.html", "app.crx")); + listener.Wait(); + ASSERT_TRUE(listener.received_success()); + ASSERT_EQ(kTestAppId, listener.id()); + + scoped_refptr<const Extension> extension = + extensions::ExtensionBuilder("test extension") + .SetID(kTestAppId) + .SetVersion(kTestAppVersion) + .Build(); + SupervisedUserService* service = + SupervisedUserServiceFactory::GetForProfile(profile()); + ASSERT_TRUE(service->IsExtensionAllowed(*extension)); +} + +// Tests no install occurs for a child when the parent permission +// dialog is canceled. +IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTestChildInstallEnabled, + ParentPermissionCanceled) { + WebstoreInstallListener listener; + set_next_dialog_action(NextDialogAction::kCancel); + WebstorePrivateApi::SetWebstoreInstallerDelegateForTesting(&listener); + ASSERT_TRUE(RunInstallTest("install_cancel_child.html", "app.crx")); + listener.Wait(); + ASSERT_TRUE(listener.received_failure()); + ASSERT_EQ(kTestAppId, listener.id()); + ASSERT_EQ(listener.last_failure_reason(), + WebstoreInstaller::FailureReason::FAILURE_REASON_CANCELLED); + scoped_refptr<const Extension> extension = + extensions::ExtensionBuilder("test extension") + .SetID(kTestAppId) + .SetVersion(kTestAppVersion) + .Build(); + SupervisedUserService* service = + SupervisedUserServiceFactory::GetForProfile(profile()); + ASSERT_FALSE(service->IsExtensionAllowed(*extension)); } #endif // BUILDFLAG(ENABLE_SUPERVISED_USERS)
diff --git a/chrome/browser/extensions/chrome_ui_overrides_browsertest.cc b/chrome/browser/extensions/chrome_ui_overrides_browsertest.cc deleted file mode 100644 index 1e9157e1..0000000 --- a/chrome/browser/extensions/chrome_ui_overrides_browsertest.cc +++ /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. - -#include "base/command_line.h" -#include "chrome/app/chrome_command_ids.h" -#include "chrome/browser/extensions/extension_browsertest.h" -#include "chrome/browser/ui/browser_commands.h" -#include "chrome/common/url_constants.h" - -using ChromeUIOverridesBrowserTest = extensions::ExtensionBrowserTest; - -IN_PROC_BROWSER_TEST_F(ChromeUIOverridesBrowserTest, - BookmarkShortcutOverrides) { - // This functionality requires a feature flag. - base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( - "--enable-override-bookmarks-ui", "1"); - - ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("bookmarks_ui"))); - EXPECT_FALSE(chrome::IsCommandEnabled(browser(), IDC_BOOKMARK_THIS_TAB)); - - AddTabAtIndex(1, - GURL(chrome::kChromeUINewTabURL), - ui::PAGE_TRANSITION_TYPED); - EXPECT_FALSE(chrome::IsCommandEnabled(browser(), IDC_BOOKMARK_ALL_TABS)); -}
diff --git a/chrome/browser/extensions/corb_and_cors_extension_browsertest.cc b/chrome/browser/extensions/corb_and_cors_extension_browsertest.cc index ad809cbd..d932fbfa 100644 --- a/chrome/browser/extensions/corb_and_cors_extension_browsertest.cc +++ b/chrome/browser/extensions/corb_and_cors_extension_browsertest.cc
@@ -206,6 +206,7 @@ "*://fetch-initiator.com/*", "*://127.0.0.1/*", // Initiator in AppCache tests. "*://cross-site.com/*", + "*://*.subdomain.com/*", "*://other-with-permission.com/*" // This list intentionally does NOT include // other-without-permission.com. @@ -243,6 +244,8 @@ void VerifyPassiveUmaForAllowlistForCors( const base::HistogramTester& histograms, base::Optional<bool> expected_value) { + SubprocessMetricsProvider::MergeHistogramDeltasForTesting(); + const char* kUmaName = "SiteIsolation.XSD.Browser.AllowedByCorbButNotCors.ContentScript"; bool expect_uma_presence = expected_value.has_value(); @@ -796,6 +799,40 @@ "nosniff.xml - body\n"); } +// Coverage of *.subdomain.com extension permissions for CORB-eligible fetches +// (via nosniff.xml). +IN_PROC_BROWSER_TEST_P(CorbAndCorsExtensionBrowserTest, + FromProgrammaticContentScript_SubdomainPermissions) { + ASSERT_TRUE(embedded_test_server()->Start()); + ASSERT_TRUE(InstallExtension()); + + // Navigate to a fetch-initiator.com page. + GURL page_url = GetTestPageUrl("fetch-initiator.com"); + ui_test_utils::NavigateToURL(browser(), page_url); + ASSERT_EQ(page_url, + active_web_contents()->GetMainFrame()->GetLastCommittedURL()); + ASSERT_EQ(url::Origin::Create(page_url), + active_web_contents()->GetMainFrame()->GetLastCommittedOrigin()); + + // Verify behavior for fetching URLs covered by extension permissions. + GURL kAllowedUrls[] = { + embedded_test_server()->GetURL("subdomain.com", "/nosniff.xml"), + embedded_test_server()->GetURL("foo.subdomain.com", "/nosniff.xml"), + }; + for (const GURL& allowed_url : kAllowedUrls) { + SCOPED_TRACE(::testing::Message() << "allowed_url = " << allowed_url); + + base::HistogramTester histograms; + std::string fetch_result = + FetchViaContentScript(allowed_url, active_web_contents()); + + // Verify whether the fetch worked or not (expectations differ depending on + // various factors - see the body of VerifyFetchFromContentScript). + VerifyFetchFromContentScript(histograms, fetch_result, + "nosniff.xml - body\n"); + } +} + // Test that verifies the current, baked-in (but not necessarily desirable // behavior) where a content script injected by an extension can bypass // CORS (and CORB) for any hosts the extension has access to. @@ -833,7 +870,7 @@ // Test that verifies CORS-allowed fetches work for targets that are not // covered by the extension permissions. IN_PROC_BROWSER_TEST_P(CorbAndCorsExtensionBrowserTest, - FromProgrammaticContentScript_NoPermissionToTarget) { + ContentScript_CorsAllowedByServer_NoPermissionToTarget) { ASSERT_TRUE(embedded_test_server()->Start()); ASSERT_TRUE(InstallExtension()); @@ -846,18 +883,53 @@ active_web_contents()->GetMainFrame()->GetLastCommittedOrigin()); // Inject a content script that performs a cross-origin fetch to - // cross-site.com. + // other-without-permission.com. base::HistogramTester histograms; GURL cross_site_resource(embedded_test_server()->GetURL( "other-without-permission.com", "/cors-ok.txt")); std::string fetch_result = FetchViaContentScript(cross_site_resource, active_web_contents()); - // Verify whether the fetch worked or not. + // Verify that the fetch succeeded (because of the server's + // Access-Control-Allow-Origin response header). EXPECT_EQ("cors-ok.txt - body\n", fetch_result); VerifyFetchFromContentScriptWasAllowedByCorb(histograms); } +// Test that verifies that CORS blocks non-CORB-eligible fetches for targets +// that are not covered by the extension permissions. +IN_PROC_BROWSER_TEST_P(CorbAndCorsExtensionBrowserTest, + ContentScript_CorsIgnoredByServer_NoPermissionToTarget) { + ASSERT_TRUE(embedded_test_server()->Start()); + ASSERT_TRUE(InstallExtension()); + + // Navigate to a fetch-initiator.com page. + GURL page_url = GetTestPageUrl("fetch-initiator.com"); + ui_test_utils::NavigateToURL(browser(), page_url); + ASSERT_EQ(page_url, + active_web_contents()->GetMainFrame()->GetLastCommittedURL()); + ASSERT_EQ(url::Origin::Create(page_url), + active_web_contents()->GetMainFrame()->GetLastCommittedOrigin()); + + // Inject a content script that performs a cross-origin fetch to + // other-without-permission.com. + base::HistogramTester histograms; + GURL cross_site_resource(embedded_test_server()->GetURL( + "other-without-permission.com", "/save_page/text.txt")); + std::string fetch_result = + FetchViaContentScript(cross_site_resource, active_web_contents()); + + // Verify that the fetch was blocked by CORS (because the extension has no + // permission to the target + server didn't reply with + // Access-Control-Allow-Origin response header). + EXPECT_EQ(kCorsErrorWhenFetching, fetch_result); + + // Verify that the fetch was allowed by CORB (because the response sniffed as + // didn't sniff as html/xml/json). + VerifyFetchFromContentScriptWasAllowedByCorb(histograms, + true /* expecting_sniffing */); +} + // Tests that same-origin fetches (same-origin relative to the webpage the // content script is injected into) are allowed. See also // https://crbug.com/918660. @@ -913,18 +985,10 @@ embedded_test_server()->GetURL("cross-site.com", "/save_page/text.txt")); std::string fetch_result = FetchViaContentScript(cross_site_resource, active_web_contents()); - SubprocessMetricsProvider::MergeHistogramDeltasForTesting(); - if (IsCorbExpectedToBeTurnedOffAltogether()) { - // Verify that CORB didn't run. - EXPECT_EQ( - 0u, - histograms.GetTotalCountsForPrefix("SiteIsolation.XSD.Browser").size()); - } else { - // Verify that CORB sniffing allowed the response. - VerifyFetchFromContentScriptWasAllowedByCorb(histograms, - true /* expecting_sniffing */); - } + // Verify that CORB sniffing allowed the response. + VerifyFetchFromContentScriptWasAllowedByCorb(histograms, + true /* expecting_sniffing */); if (ShouldAllowlistAlsoApplyToOorCors() && AreContentScriptFetchesExpectedToBeBlocked()) { @@ -946,6 +1010,61 @@ VerifyPassiveUmaForAllowlistForCors(histograms, true); } +// Coverage of *.subdomain.com extension permissions for non-CORB eligible +// fetches (via save_page/text.txt). +IN_PROC_BROWSER_TEST_P( + CorbAndCorsExtensionBrowserTest, + FromProgrammaticContentScript_AllowedTextResource_SubdomainPermissions) { + ASSERT_TRUE(embedded_test_server()->Start()); + ASSERT_TRUE(InstallExtension()); + + // Navigate to a fetch-initiator.com page. + GURL page_url = GetTestPageUrl("fetch-initiator.com"); + ui_test_utils::NavigateToURL(browser(), page_url); + ASSERT_EQ(page_url, + active_web_contents()->GetMainFrame()->GetLastCommittedURL()); + ASSERT_EQ(url::Origin::Create(page_url), + active_web_contents()->GetMainFrame()->GetLastCommittedOrigin()); + + // Verify behavior for fetching URLs covered by extension permissions. + GURL kAllowedUrls[] = { + embedded_test_server()->GetURL("subdomain.com", "/save_page/text.txt"), + embedded_test_server()->GetURL("x.subdomain.com", "/save_page/text.txt"), + }; + for (const GURL& allowed_url : kAllowedUrls) { + SCOPED_TRACE(::testing::Message() << "allowed_url = " << allowed_url); + + // Inject a content script that performs a cross-origin fetch to + // cross-site.com. + base::HistogramTester histograms; + std::string fetch_result = + FetchViaContentScript(allowed_url, active_web_contents()); + + // Verify that CORB sniffing allowed the response. + VerifyFetchFromContentScriptWasAllowedByCorb(histograms, + true /* expecting_sniffing */); + + if (ShouldAllowlistAlsoApplyToOorCors() && + AreContentScriptFetchesExpectedToBeBlocked()) { + // Verify that the response body was blocked by CORS. + EXPECT_EQ(kCorsErrorWhenFetching, fetch_result); + } else { + // Verify that the response body was not blocked by either CORB nor CORS. + // + // StartsWith (rather than equality) is used in the verification step to + // account for \n VS \r\n difference on Windows. + EXPECT_THAT(fetch_result, + ::testing::StartsWith( + "text-object.txt: ae52dd09-9746-4b7e-86a6-6ada5e2680c2")); + } + + // This is the kind of response (i.e., cross-origin fetch of a non-CORB + // type) that could be affected by the planned + // CorbAllowlistAlsoAppliesToOorCors feature. + VerifyPassiveUmaForAllowlistForCors(histograms, true); + } +} + // Test that responses that would have been allowed by CORB after sniffing are // included in the AllowedByCorbButNotCors UMA. IN_PROC_BROWSER_TEST_P(CorbAndCorsExtensionBrowserTest, @@ -969,18 +1088,10 @@ "cross-site.com", "/downloads/image-labeled-as-html.png")); std::string fetch_result = FetchViaContentScript(cross_site_resource, active_web_contents()); - SubprocessMetricsProvider::MergeHistogramDeltasForTesting(); - if (IsCorbExpectedToBeTurnedOffAltogether()) { - // Verify that CORB didn't run. - EXPECT_EQ( - 0u, - histograms.GetTotalCountsForPrefix("SiteIsolation.XSD.Browser").size()); - } else { - // Verify that CORB sniffing allowed the response. - VerifyFetchFromContentScriptWasAllowedByCorb(histograms, - true /* expecting_sniffing */); - } + // Verify that CORB sniffing allowed the response. + VerifyFetchFromContentScriptWasAllowedByCorb(histograms, + true /* expecting_sniffing */); if (ShouldAllowlistAlsoApplyToOorCors() && AreContentScriptFetchesExpectedToBeBlocked()) { @@ -1725,7 +1836,7 @@ // Verify the request headers (e.g. Origin and Sec-Fetch-Site headers). cors_request.WaitForRequest(); - if (IsExtensionAllowlisted()) { + if (IsExtensionAllowlisted() || !ShouldAllowlistAlsoApplyToOorCors()) { // Content scripts of allowlisted extensions should be exempted from CORS, // based on the websites the extension has permission for, via extension // manifest. Therefore, there should be no "Origin" header. @@ -1733,9 +1844,6 @@ cors_request.http_request()->headers, testing::Not(testing::Contains(testing::Pair("Origin", testing::_)))); } else { -#if 0 - // TODO(lukasza): https://crbug.com/920638: - // // Content scripts of non-allowlisted extensions should participate in // regular CORS, just as if the request was issued from the webpage that the // content script got injected into. Therefore we should expect the Origin @@ -1743,7 +1851,6 @@ EXPECT_THAT( cors_request.http_request()->headers, testing::Contains(testing::Pair("Origin", page_origin_string.c_str()))); -#endif } // Respond with Access-Control-Allow-Origin that matches the origin of the web
diff --git a/chrome/browser/extensions/cross_origin_xhr_apitest.cc b/chrome/browser/extensions/cross_origin_xhr_apitest.cc index 5dc3896f..35191b67 100644 --- a/chrome/browser/extensions/cross_origin_xhr_apitest.cc +++ b/chrome/browser/extensions/cross_origin_xhr_apitest.cc
@@ -2,42 +2,19 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "base/test/scoped_feature_list.h" #include "chrome/browser/extensions/extension_apitest.h" #include "net/dns/mock_host_resolver.h" -#include "services/network/public/cpp/features.h" const base::FilePath::CharType kFtpDocRoot[] = FILE_PATH_LITERAL("chrome/test/data"); class CrossOriginXHR : public extensions::ExtensionApiTest { public: - CrossOriginXHR() { - // TODO(lukasza): https://crbug.com/1061567: Migrate tests related to - // content scripts into the CrossOriginReadBlockingExtensionTest suite - // (where it is easier to separately tweak test case expectations based on - // the enabled features + where a big subset of the allowlisting/corb/etc - // test matrix is covered already). - // - // Affected tests (note that some of the tests do not need to be migrated if - // they are already redundant wrt the coverage provided by the - // CrossOriginReadBlockingExtensionTest suite): - // - CrossOriginXHR.ContentScript - // - allowedOrigin - // - allowedSubdomain - // - noSubdomain - scoped_feature_list_.InitAndDisableFeature( - network::features::kCorbAllowlistAlsoAppliesToOorCors); - } - void SetUpOnMainThread() override { extensions::ExtensionApiTest::SetUpOnMainThread(); host_resolver()->AddRule("*.com", "127.0.0.1"); ASSERT_TRUE(StartEmbeddedTestServer()); } - - private: - base::test::ScopedFeatureList scoped_feature_list_; }; IN_PROC_BROWSER_TEST_F(CrossOriginXHR, BackgroundPage) {
diff --git a/chrome/browser/extensions/extension_keybinding_apitest.cc b/chrome/browser/extensions/extension_keybinding_apitest.cc index d0cbdfb1..f333e5c 100644 --- a/chrome/browser/extensions/extension_keybinding_apitest.cc +++ b/chrome/browser/extensions/extension_keybinding_apitest.cc
@@ -56,8 +56,6 @@ // Name of the command for the "basics" test extension. const char kBasicsShortcutCommandName[] = "toggle-feature"; -// Name of the command for the overwrite_bookmark_shortcut test extension. -const char kOverwriteBookmarkShortcutCommandName[] = "send message"; #if defined(OS_MACOSX) const char kBookmarkKeybinding[] = "Command+D"; @@ -535,127 +533,6 @@ } } -// This test validates that an extension can remove the Chrome bookmark shortcut -// if it has requested to do so. -IN_PROC_BROWSER_TEST_F(CommandsApiTest, RemoveBookmarkShortcut) { - ASSERT_TRUE(embedded_test_server()->Start()); - - ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); - - // This functionality requires a feature flag. - base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( - "--enable-override-bookmarks-ui", "1"); - - ASSERT_TRUE(RunExtensionTest("keybinding/remove_bookmark_shortcut")) - << message_; - - EXPECT_FALSE(chrome::IsCommandEnabled(browser(), IDC_BOOKMARK_THIS_TAB)); -} - -// This test validates that an extension cannot remove the Chrome bookmark -// shortcut without being given permission with a feature flag. -IN_PROC_BROWSER_TEST_F(CommandsApiTest, - RemoveBookmarkShortcutWithoutPermission) { - ASSERT_TRUE(embedded_test_server()->Start()); - - ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); - - EXPECT_TRUE(RunExtensionTestIgnoreManifestWarnings( - "keybinding/remove_bookmark_shortcut")); - - EXPECT_TRUE(chrome::IsCommandEnabled(browser(), IDC_BOOKMARK_THIS_TAB)); -} - -// This test validates that an extension that removes the Chrome bookmark -// shortcut continues to remove the bookmark shortcut with a user-assigned -// Ctrl+D shortcut (i.e. it does not trigger the overwrite functionality). -IN_PROC_BROWSER_TEST_F(CommandsApiTest, - RemoveBookmarkShortcutWithUserKeyBinding) { - ASSERT_TRUE(embedded_test_server()->Start()); - - ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); - - // This functionality requires a feature flag. - base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( - "--enable-override-bookmarks-ui", "1"); - - ASSERT_TRUE(RunExtensionTest("keybinding/remove_bookmark_shortcut")) - << message_; - - // Check that the shortcut is removed. - CommandService* command_service = CommandService::Get(browser()->profile()); - const Extension* extension = GetSingleLoadedExtension(); - // Simulate the user setting a keybinding to Ctrl+D. - command_service->UpdateKeybindingPrefs( - extension->id(), manifest_values::kBrowserActionCommandEvent, - kBookmarkKeybinding); - - // Force the command enable state to be recalculated. - browser()->command_controller()->ExtensionStateChanged(); - - EXPECT_FALSE(chrome::IsCommandEnabled(browser(), IDC_BOOKMARK_THIS_TAB)); -} - -// This test validates that an extension can override the Chrome bookmark -// shortcut if it has requested to do so. -IN_PROC_BROWSER_TEST_F(CommandsApiTest, OverwriteBookmarkShortcut) { - ASSERT_TRUE(embedded_test_server()->Start()); - - ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); - - // This functionality requires a feature flag. - base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( - "--enable-override-bookmarks-ui", "1"); - - ASSERT_TRUE(RunExtensionTest("keybinding/overwrite_bookmark_shortcut")) - << message_; - - ui_test_utils::NavigateToURL( - browser(), embedded_test_server()->GetURL("/extensions/test_file.txt")); - - // Activate the shortcut (Ctrl+D) to send a test message. - ExtensionTestMessageListener test_listener(false); // Won't reply. - ASSERT_TRUE(SendBookmarkKeyPressSync(browser())); - EXPECT_TRUE(test_listener.WaitUntilSatisfied()); - EXPECT_EQ(std::string(kOverwriteBookmarkShortcutCommandName), - test_listener.message()); -} - -// This test validates that an extension that requests to override the Chrome -// bookmark shortcut, but does not get the keybinding, does not remove the -// bookmark UI. -IN_PROC_BROWSER_TEST_F(CommandsApiTest, - OverwriteBookmarkShortcutWithoutKeybinding) { - // This functionality requires a feature flag. - base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( - "--enable-override-bookmarks-ui", "1"); - - ASSERT_TRUE(embedded_test_server()->Start()); - - EXPECT_TRUE(chrome::IsCommandEnabled(browser(), IDC_BOOKMARK_THIS_TAB)); - - ASSERT_TRUE(RunExtensionTest("keybinding/overwrite_bookmark_shortcut")) - << message_; - - const Extension* extension = GetSingleLoadedExtension(); - CommandService* command_service = CommandService::Get(browser()->profile()); - CommandMap commands; - // Verify the expected command is present. - EXPECT_TRUE(command_service->GetNamedCommands( - extension->id(), CommandService::SUGGESTED, CommandService::ANY_SCOPE, - &commands)); - EXPECT_EQ(1u, commands.count(kOverwriteBookmarkShortcutCommandName)); - - // Simulate the user removing the Ctrl+D keybinding from the command. - command_service->RemoveKeybindingPrefs( - extension->id(), kOverwriteBookmarkShortcutCommandName); - - // Force the command enable state to be recalculated. - browser()->command_controller()->ExtensionStateChanged(); - - EXPECT_TRUE(chrome::IsCommandEnabled(browser(), IDC_BOOKMARK_THIS_TAB)); -} - // This test validates that an extension override of the Chrome bookmark // shortcut does not supersede the same keybinding by web pages. IN_PROC_BROWSER_TEST_F(CommandsApiTest,
diff --git a/chrome/browser/extensions/policy_handlers.cc b/chrome/browser/extensions/policy_handlers.cc index 5b482c0..1dfda7b 100644 --- a/chrome/browser/extensions/policy_handlers.cc +++ b/chrome/browser/extensions/policy_handlers.cc
@@ -66,12 +66,10 @@ return crx_file::id_util::IdIsValid(str); } -void ExtensionListPolicyHandler::ApplyList( - std::unique_ptr<base::ListValue> filtered_list, - PrefValueMap* prefs) { - DCHECK(filtered_list); - prefs->SetValue(pref_path_, - base::Value::FromUniquePtrValue(std::move(filtered_list))); +void ExtensionListPolicyHandler::ApplyList(base::Value filtered_list, + PrefValueMap* prefs) { + DCHECK(filtered_list.is_list()); + prefs->SetValue(pref_path_, std::move(filtered_list)); } // ExtensionInstallListPolicyHandler implementation ----------------------------
diff --git a/chrome/browser/extensions/policy_handlers.h b/chrome/browser/extensions/policy_handlers.h index db0e0e2..354311f5c 100644 --- a/chrome/browser/extensions/policy_handlers.h +++ b/chrome/browser/extensions/policy_handlers.h
@@ -34,8 +34,7 @@ bool CheckListEntry(const base::Value& value) override; // Sets |prefs| at pref_path() to |filtered_list|. - void ApplyList(std::unique_ptr<base::ListValue> filtered_list, - PrefValueMap* prefs) override; + void ApplyList(base::Value filtered_list, PrefValueMap* prefs) override; private: const char* pref_path_;
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index 8a6749d..827a8f5 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -1876,6 +1876,11 @@ "expiry_milestone": 76 }, { + "name": "enable-send-tab-to-self-omnibox-sending-animation", + "owners": [ "//components/send_tab_to_self/OWNERS" ], + "expiry_milestone": 84 + }, + { "name": "enable-send-tab-to-self-show-sending-ui", "owners": [ "//components/send_tab_to_self/OWNERS" ], "expiry_milestone": 77
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index ad84155..85bd05c 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -1645,6 +1645,12 @@ "Allows users to broadcast the tab they send to all of their devices " "instead of targetting only one device."; +const char kSendTabToSelfOmniboxSendingAnimationName[] = + "Send tab to self omnibox sending animation"; +const char kSendTabToSelfOmniboxSendingAnimationDescription[] = + "If enabled, shows Sending... animation in omnibox instead of Desktop OS " + "notifications for contextual menu entry points."; + const char kSendTabToSelfWhenSignedInName[] = "Send tab to self: enable use when signed-in regardless of sync state"; const char kSendTabToSelfWhenSignedInDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index 31fd57bc7..4a7e82c 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -957,6 +957,9 @@ extern const char kSendTabToSelfBroadcastName[]; extern const char kSendTabToSelfBroadcastDescription[]; +extern const char kSendTabToSelfOmniboxSendingAnimationName[]; +extern const char kSendTabToSelfOmniboxSendingAnimationDescription[]; + extern const char kSendTabToSelfWhenSignedInName[]; extern const char kSendTabToSelfWhenSignedInDescription[];
diff --git a/chrome/browser/media/history/media_history_browsertest.cc b/chrome/browser/media/history/media_history_browsertest.cc index 5d97074..c0e74b3 100644 --- a/chrome/browser/media/history/media_history_browsertest.cc +++ b/chrome/browser/media/history/media_history_browsertest.cc
@@ -276,7 +276,7 @@ ui_test_utils::NavigateToURL(browser, embedded_test_server()->base_url()); // Wait until the session has finished saving. - content::RunAllTasksUntilIdle(); + WaitForDB(GetMediaHistoryService(browser)); } const GURL GetTestURL() const { @@ -301,6 +301,12 @@ browser->profile()->GetOffTheRecordProfile()); } + static void WaitForDB(MediaHistoryKeyedService* service) { + base::RunLoop run_loop; + service->PostTaskToDBForTest(run_loop.QuitClosure()); + run_loop.Run(); + } + Browser* CreateBrowserFromParam() { if (GetParam() == TestState::kIncognito) { return CreateIncognitoBrowser();
diff --git a/chrome/browser/media/webrtc/OWNERS b/chrome/browser/media/webrtc/OWNERS index 818f518..104e9a6 100644 --- a/chrome/browser/media/webrtc/OWNERS +++ b/chrome/browser/media/webrtc/OWNERS
@@ -9,6 +9,7 @@ # For changes related to the tab media indicators. per-file media_stream_capture_indicator*=miu@chromium.org +per-file media_stream_capture_indicator*=mfoltz@chromium.org # For permissions related code. per-file media_stream_device*=raymes@chromium.org
diff --git a/chrome/browser/metrics/metrics_service_user_demographics_browsertest.cc b/chrome/browser/metrics/metrics_service_user_demographics_browsertest.cc index 96d02dd..fc0c5ac0 100644 --- a/chrome/browser/metrics/metrics_service_user_demographics_browsertest.cc +++ b/chrome/browser/metrics/metrics_service_user_demographics_browsertest.cc
@@ -13,6 +13,7 @@ #include "base/memory/weak_ptr.h" #include "base/optional.h" #include "base/test/metrics/histogram_tester.h" +#include "build/build_config.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/metrics/chrome_metrics_service_accessor.h" #include "chrome/browser/metrics/chrome_metrics_services_manager_client.h" @@ -115,8 +116,15 @@ }; // TODO(crbug/1016118): Add the remaining test cases. +#if defined(OS_ANDROID) +#define MAYBE_AddSyncedUserBirthYearAndGenderToProtoData \ + DISABLED_AddSyncedUserBirthYearAndGenderToProtoData +#else +#define MAYBE_AddSyncedUserBirthYearAndGenderToProtoData \ + AddSyncedUserBirthYearAndGenderToProtoData +#endif IN_PROC_BROWSER_TEST_P(MetricsServiceUserDemographicsBrowserTest, - AddSyncedUserBirthYearAndGenderToProtoData) { + MAYBE_AddSyncedUserBirthYearAndGenderToProtoData) { test::DemographicsTestParams param = GetParam(); base::HistogramTester histogram;
diff --git a/chrome/browser/metrics/perf/perf_output.cc b/chrome/browser/metrics/perf/perf_output.cc index f0d46bce..4a57ac1 100644 --- a/chrome/browser/metrics/perf/perf_output.cc +++ b/chrome/browser/metrics/perf/perf_output.cc
@@ -71,7 +71,7 @@ // the callback argument. Callback can safely use |result| after |this| is // deleted. std::move(done_callback_).Run(std::move(result).value_or(std::string())); - // The callback may delete us, so it's hammertime: Can't touch |this|. + // NOTE: |this| may be deleted at this point! } void PerfOutputCall::OnGetPerfOutput(base::Optional<uint64_t> result) { @@ -81,6 +81,8 @@ if (!result.has_value() && perf_data_pipe_reader_.get()) { perf_data_pipe_reader_.reset(); std::move(done_callback_).Run(std::string()); + // NOTE: |this| may be deleted at this point! + return; } // DBus method GetPerfOutputFd returns a generated session ID back to the
diff --git a/chrome/browser/navigation_predictor/navigation_predictor.cc b/chrome/browser/navigation_predictor/navigation_predictor.cc index 29a9971..c641d58 100644 --- a/chrome/browser/navigation_predictor/navigation_predictor.cc +++ b/chrome/browser/navigation_predictor/navigation_predictor.cc
@@ -949,7 +949,11 @@ for (const auto& nav_score : sorted_navigation_scores) { top_urls.push_back(nav_score->url); } - service->OnPredictionUpdated(web_contents(), document_url_, top_urls); + service->OnPredictionUpdated( + web_contents(), document_url_, + NavigationPredictorKeyedService::PredictionSource:: + kAnchorElementsParsedFromWebPage, + top_urls); } void NavigationPredictor::MaybeTakeActionOnLoad(
diff --git a/chrome/browser/navigation_predictor/navigation_predictor_keyed_service.cc b/chrome/browser/navigation_predictor/navigation_predictor_keyed_service.cc index 72a7e78..3f6dc6e7 100644 --- a/chrome/browser/navigation_predictor/navigation_predictor_keyed_service.cc +++ b/chrome/browser/navigation_predictor/navigation_predictor_keyed_service.cc
@@ -14,11 +14,27 @@ NavigationPredictorKeyedService::Prediction::Prediction( const content::WebContents* web_contents, - const GURL& source_document_url, + const base::Optional<GURL>& source_document_url, + const base::Optional<std::vector<std::string>>& external_app_packages_name, + PredictionSource prediction_source, const std::vector<GURL>& sorted_predicted_urls) : web_contents_(web_contents), source_document_url_(source_document_url), - sorted_predicted_urls_(sorted_predicted_urls) {} + external_app_packages_name_(external_app_packages_name), + prediction_source_(prediction_source), + sorted_predicted_urls_(sorted_predicted_urls) { + switch (prediction_source_) { + case PredictionSource::kAnchorElementsParsedFromWebPage: + DCHECK(!source_document_url->is_empty()); + DCHECK(!external_app_packages_name); + break; + case PredictionSource::kExternalAndroidApp: + DCHECK(!web_contents_); + DCHECK(!source_document_url); + DCHECK(!external_app_packages_name->empty()); + break; + } +} NavigationPredictorKeyedService::Prediction::Prediction( const NavigationPredictorKeyedService::Prediction& other) = default; @@ -29,17 +45,29 @@ NavigationPredictorKeyedService::Prediction::~Prediction() = default; -GURL NavigationPredictorKeyedService::Prediction::source_document_url() const { +const base::Optional<GURL>& +NavigationPredictorKeyedService::Prediction::source_document_url() const { + DCHECK_EQ(PredictionSource::kAnchorElementsParsedFromWebPage, + prediction_source_); return source_document_url_; } -std::vector<GURL> +const base::Optional<std::vector<std::string>>& +NavigationPredictorKeyedService::Prediction::external_app_packages_name() + const { + DCHECK_EQ(PredictionSource::kExternalAndroidApp, prediction_source_); + return external_app_packages_name_; +} + +const std::vector<GURL>& NavigationPredictorKeyedService::Prediction::sorted_predicted_urls() const { return sorted_predicted_urls_; } const content::WebContents* NavigationPredictorKeyedService::Prediction::web_contents() const { + DCHECK_EQ(PredictionSource::kAnchorElementsParsedFromWebPage, + prediction_source_); return web_contents_; } @@ -62,20 +90,36 @@ void NavigationPredictorKeyedService::OnPredictionUpdated( const content::WebContents* web_contents, const GURL& document_url, + PredictionSource prediction_source, const std::vector<GURL>& sorted_predicted_urls) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - last_prediction_ = - Prediction(web_contents, document_url, sorted_predicted_urls); + + // Currently, this method is called only for anchor elements parsed from + // webpage. + DCHECK_EQ(PredictionSource::kAnchorElementsParsedFromWebPage, + prediction_source); + + last_prediction_ = Prediction(web_contents, document_url, + /*external_app_packages_name=*/base::nullopt, + prediction_source, sorted_predicted_urls); for (auto& observer : observer_list_) { observer.OnPredictionUpdated(last_prediction_); } } -#ifdef OS_ANDROID void NavigationPredictorKeyedService::OnPredictionUpdatedByExternalAndroidApp( const std::vector<std::string>& external_app_packages_name, const std::vector<GURL>& sorted_predicted_urls) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + if (external_app_packages_name.empty() || sorted_predicted_urls.empty()) { + return; + } + last_prediction_ = + Prediction(nullptr, base::nullopt, external_app_packages_name, + PredictionSource::kExternalAndroidApp, sorted_predicted_urls); + for (auto& observer : observer_list_) { + observer.OnPredictionUpdated(last_prediction_); + } LOCAL_HISTOGRAM_COUNTS_100( "NavigationPredictor.ExternalAndroidApp.CountPredictedURLs", @@ -84,7 +128,6 @@ // TODO(https://crbug.com/1014210): Notify the predicted URLs to the // observers. } -#endif void NavigationPredictorKeyedService::AddObserver(Observer* observer) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
diff --git a/chrome/browser/navigation_predictor/navigation_predictor_keyed_service.h b/chrome/browser/navigation_predictor/navigation_predictor_keyed_service.h index 739a5bc..491e8fd 100644 --- a/chrome/browser/navigation_predictor/navigation_predictor_keyed_service.h +++ b/chrome/browser/navigation_predictor/navigation_predictor_keyed_service.h
@@ -24,17 +24,35 @@ // the next predicted navigation. class NavigationPredictorKeyedService : public KeyedService { public: + // Indicates how the set of next navigation URLs were predicted. + enum class PredictionSource { + // Next navigation URLs were predicted by navigation predictor by parsing + // the anchor element metrics on a webpage. + kAnchorElementsParsedFromWebPage = 0, + + // Next navigation URLs were provided by an external Android app. + kExternalAndroidApp = 1 + }; + // Stores the next set of URLs that the user is expected to navigate to. class Prediction { public: Prediction(const content::WebContents* web_contents, - const GURL& source_document_url, + const base::Optional<GURL>& source_document_url, + const base::Optional<std::vector<std::string>>& + external_app_packages_name, + PredictionSource prediction_source, const std::vector<GURL>& sorted_predicted_urls); Prediction(const Prediction& other); Prediction& operator=(const Prediction& other); ~Prediction(); - GURL source_document_url() const; - std::vector<GURL> sorted_predicted_urls() const; + const base::Optional<GURL>& source_document_url() const; + const base::Optional<std::vector<std::string>>& external_app_packages_name() + const; + PredictionSource prediction_source() const { return prediction_source_; } + const std::vector<GURL>& sorted_predicted_urls() const; + + // Null if the prediction source is kExternalAndroidApp. const content::WebContents* web_contents() const; private: @@ -44,7 +62,22 @@ const content::WebContents* web_contents_; // Current URL of the document from where the navigtion may happen. - GURL source_document_url_; + base::Optional<GURL> source_document_url_; + + // If the |prediction_source_| is kExternalAndroidApp, then + // |external_app_packages_name_| is the set of likely external Android apps + // that generated the predictions. If the prediction source is + // kExternalAndroidApp, then the external Android app that generated the + // prediction is guaranteed to be one of the values in + // |external_app_packages_name_|. + base::Optional<std::vector<std::string>> external_app_packages_name_; + + // |prediction_source_| indicates how the prediction was generated and + // affects how the prediction should be consumed. If the + // |prediction_source_| is kAnchorElementsParsedFromWebPage, then + // |source_document_url_| is the webpage from where the predictions were + // generated. + PredictionSource prediction_source_; // Ordered set of URLs that the user is expected to navigate to next. The // URLs are in the decreasing order of click probability. @@ -57,6 +90,9 @@ // document as well as the ordered list of URLs that the user may navigate to // next. OnPredictionUpdated() may be called multiple times for the same // source document URL. + // + // Observers must follow relevant privacy guidelines when consuming the + // notifications. class Observer { public: virtual void OnPredictionUpdated( @@ -76,9 +112,9 @@ // |document_url| may be invalid. Called by navigation predictor. void OnPredictionUpdated(const content::WebContents* web_contents, const GURL& document_url, + PredictionSource prediction_source, const std::vector<GURL>& sorted_predicted_urls); -#ifdef OS_ANDROID // Notifies |this| of the next set of URLs that the user is expected to // navigate to. The set of URLs are reported by an external Android app. // The reporting app is guaranteed to be one of the apps reported in @@ -87,11 +123,11 @@ void OnPredictionUpdatedByExternalAndroidApp( const std::vector<std::string>& external_app_packages_name, const std::vector<GURL>& sorted_predicted_urls); -#endif // Adds |observer| as the observer for next predicted navigation. When // |observer| is added via AddObserver, it's immediately notified of the last - // known prediction. + // known prediction. Observers must follow relevant privacy guidelines when + // consuming the notifications. void AddObserver(Observer* observer); // Removes |observer| as the observer for next predicted navigation.
diff --git a/chrome/browser/optimization_guide/optimization_guide_hints_manager.cc b/chrome/browser/optimization_guide/optimization_guide_hints_manager.cc index 64f5cdf5..a5477003 100644 --- a/chrome/browser/optimization_guide/optimization_guide_hints_manager.cc +++ b/chrome/browser/optimization_guide/optimization_guide_hints_manager.cc
@@ -734,10 +734,19 @@ if (!prediction.has_value()) return; - const GURL& source_document_url = prediction->source_document_url(); + if (prediction->prediction_source() != + NavigationPredictorKeyedService::PredictionSource:: + kAnchorElementsParsedFromWebPage) { + return; + } + + const base::Optional<GURL>& source_document_url = + prediction->source_document_url(); + if (!source_document_url || source_document_url->is_empty()) + return; // We only extract next predicted navigations from Google URLs. - if (!IsGoogleURL(source_document_url)) + if (!IsGoogleURL(source_document_url.value())) return; // Extract the target hosts and URLs. Use a flat set to remove duplicates.
diff --git a/chrome/browser/optimization_guide/optimization_guide_hints_manager.h b/chrome/browser/optimization_guide/optimization_guide_hints_manager.h index 0d525282..1d5160c 100644 --- a/chrome/browser/optimization_guide/optimization_guide_hints_manager.h +++ b/chrome/browser/optimization_guide/optimization_guide_hints_manager.h
@@ -177,6 +177,9 @@ FRIEND_TEST_ALL_PREFIXES( OptimizationGuideHintsManagerFetchingTest, HintsFetched_AtSRP_ECT_SLOW_2G_NonHTTPOrHTTPSHostsRemoved); + FRIEND_TEST_ALL_PREFIXES( + OptimizationGuideHintsManagerFetchingTest, + HintsFetched_ExternalAndroidApp_ECT_SLOW_2G_NonHTTPOrHTTPSHostsRemoved); // Processes the hints component. //
diff --git a/chrome/browser/optimization_guide/optimization_guide_hints_manager_unittest.cc b/chrome/browser/optimization_guide/optimization_guide_hints_manager_unittest.cc index c89b3cca..21208de 100644 --- a/chrome/browser/optimization_guide/optimization_guide_hints_manager_unittest.cc +++ b/chrome/browser/optimization_guide/optimization_guide_hints_manager_unittest.cc
@@ -2068,7 +2068,11 @@ std::vector<GURL> sorted_predicted_urls; sorted_predicted_urls.push_back(GURL("https://foo.com/")); NavigationPredictorKeyedService::Prediction prediction( - nullptr, GURL("https://www.google.com/"), sorted_predicted_urls); + nullptr, GURL("https://www.google.com/"), + /*external_app_packages_name=*/{}, + NavigationPredictorKeyedService::PredictionSource:: + kAnchorElementsParsedFromWebPage, + sorted_predicted_urls); hints_manager()->OnPredictionUpdated(prediction); histogram_tester.ExpectUniqueSample( @@ -2090,7 +2094,11 @@ std::vector<GURL> sorted_predicted_urls; sorted_predicted_urls.push_back(GURL("https://foo.com/")); NavigationPredictorKeyedService::Prediction prediction( - nullptr, GURL("https://www.google.com/"), sorted_predicted_urls); + nullptr, GURL("https://www.google.com/"), + /*external_app_packages_name=*/{}, + NavigationPredictorKeyedService::PredictionSource:: + kAnchorElementsParsedFromWebPage, + sorted_predicted_urls); hints_manager()->OnPredictionUpdated(prediction); histogram_tester.ExpectTotalCount( @@ -2118,7 +2126,11 @@ sorted_predicted_urls.push_back(GURL("https://bar.com/")); NavigationPredictorKeyedService::Prediction prediction( - nullptr, GURL("https://www.google.com/"), sorted_predicted_urls); + nullptr, GURL("https://www.google.com/"), + /*external_app_packages_name=*/{}, + NavigationPredictorKeyedService::PredictionSource:: + kAnchorElementsParsedFromWebPage, + sorted_predicted_urls); { base::HistogramTester histogram_tester; @@ -2161,7 +2173,11 @@ sorted_predicted_urls.push_back(GURL("http://httppage.com/")); NavigationPredictorKeyedService::Prediction prediction( - nullptr, GURL("https://www.google.com/"), sorted_predicted_urls); + nullptr, GURL("https://www.google.com/"), + /*external_app_packages_name=*/{}, + NavigationPredictorKeyedService::PredictionSource:: + kAnchorElementsParsedFromWebPage, + sorted_predicted_urls); hints_manager()->OnPredictionUpdated(prediction); // Ensure that we include both web hosts in the request. These would be @@ -2173,6 +2189,57 @@ "OptimizationGuide.HintsFetcher.GetHintsRequest.UrlCount", 2, 1); } +// Verify that optimization hints are not fetched if the prediction for the next +// likely navigations are provided by external Android app. +TEST_F(OptimizationGuideHintsManagerFetchingTest, + HintsFetched_ExternalAndroidApp_ECT_SLOW_2G_NonHTTPOrHTTPSHostsRemoved) { + base::CommandLine::ForCurrentProcess()->AppendSwitch( + optimization_guide::switches::kDisableCheckingUserPermissionsForTesting); + hints_manager()->RegisterOptimizationTypes( + {optimization_guide::proto::DEFER_ALL_SCRIPT}); + InitializeWithDefaultConfig("1.0.0.0"); + + // Set ECT estimate so fetch is activated. + hints_manager()->OnEffectiveConnectionTypeChanged( + net::EffectiveConnectionType::EFFECTIVE_CONNECTION_TYPE_SLOW_2G); + base::HistogramTester histogram_tester; + std::vector<GURL> sorted_predicted_urls; + sorted_predicted_urls.push_back(GURL("https://foo.com/page1.html")); + sorted_predicted_urls.push_back(GURL("file://non-web-bar.com/")); + sorted_predicted_urls.push_back(GURL("http://httppage.com/")); + + std::vector<std::string> external_app_packages_name; + external_app_packages_name.push_back("com.example.foo"); + + NavigationPredictorKeyedService::Prediction prediction_external_android_app( + nullptr, base::nullopt, external_app_packages_name, + NavigationPredictorKeyedService::PredictionSource::kExternalAndroidApp, + sorted_predicted_urls); + hints_manager()->OnPredictionUpdated(prediction_external_android_app); + histogram_tester.ExpectTotalCount( + "OptimizationGuide.HintsFetcher.GetHintsRequest.HostCount", 0); + // Ensure that we only include 2 URLs in the request. + histogram_tester.ExpectTotalCount( + "OptimizationGuide.HintsFetcher.GetHintsRequest.UrlCount", 0); + + // Now fetch again with a prediction from anchor elements. This time + // optimization hints should be requested. + NavigationPredictorKeyedService::Prediction prediction_anchor_elements( + nullptr, GURL("https://www.google.com/"), + /*external_app_packages_name=*/{}, + NavigationPredictorKeyedService::PredictionSource:: + kAnchorElementsParsedFromWebPage, + sorted_predicted_urls); + hints_manager()->OnPredictionUpdated(prediction_anchor_elements); + // Ensure that we include both web hosts in the request. These would be + // foo.com and httppage.com. + histogram_tester.ExpectUniqueSample( + "OptimizationGuide.HintsFetcher.GetHintsRequest.HostCount", 2, 1); + // Ensure that we only include 2 URLs in the request. + histogram_tester.ExpectUniqueSample( + "OptimizationGuide.HintsFetcher.GetHintsRequest.UrlCount", 2, 1); +} + TEST_F(OptimizationGuideHintsManagerFetchingTest, HintsFetched_AtSRP_ECT_4G) { base::CommandLine::ForCurrentProcess()->AppendSwitch( optimization_guide::switches::kDisableCheckingUserPermissionsForTesting); @@ -2187,7 +2254,11 @@ std::vector<GURL> sorted_predicted_urls; sorted_predicted_urls.push_back(GURL("https://foo.com/")); NavigationPredictorKeyedService::Prediction prediction( - nullptr, GURL("https://www.google.com/"), sorted_predicted_urls); + nullptr, GURL("https://www.google.com/"), + /*external_app_packages_name=*/{}, + NavigationPredictorKeyedService::PredictionSource:: + kAnchorElementsParsedFromWebPage, + sorted_predicted_urls); hints_manager()->OnPredictionUpdated(prediction); histogram_tester.ExpectTotalCount( @@ -2211,7 +2282,11 @@ std::vector<GURL> sorted_predicted_urls; sorted_predicted_urls.push_back(GURL("https://foo.com/")); NavigationPredictorKeyedService::Prediction prediction( - nullptr, GURL("https://www.not-google.com/"), sorted_predicted_urls); + nullptr, GURL("https://www.not-google.com/"), + /*external_app_packages_name=*/{}, + NavigationPredictorKeyedService::PredictionSource:: + kAnchorElementsParsedFromWebPage, + sorted_predicted_urls); hints_manager()->OnPredictionUpdated(prediction); histogram_tester.ExpectTotalCount(
diff --git a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_unittest.cc index 86c296d6..005140e 100644 --- a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_unittest.cc +++ b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_unittest.cc
@@ -146,7 +146,8 @@ resources, page_load_metrics::mojom::FrameRenderDataUpdatePtr(base::in_place), page_load_metrics::mojom::CpuTimingPtr(base::in_place), - page_load_metrics::mojom::DeferredResourceCountsPtr(base::in_place)); + page_load_metrics::mojom::DeferredResourceCountsPtr(base::in_place), + page_load_metrics::mojom::InputTimingPtr(base::in_place)); } DISALLOW_COPY_AND_ASSIGN(ResourceLoadingCancellingThrottle);
diff --git a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.cc index 5c73a40..8211158c 100644 --- a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.cc +++ b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.cc
@@ -207,6 +207,7 @@ if (!was_hidden_) { RecordPageLoadMetrics(base::TimeTicks::Now()); RecordTimingMetrics(timing); + RecordInputTimingMetrics(); } ReportLayoutStability(); return STOP_OBSERVING; @@ -217,6 +218,7 @@ if (!was_hidden_) { RecordPageLoadMetrics(base::TimeTicks() /* no app_background_time */); RecordTimingMetrics(timing); + RecordInputTimingMetrics(); was_hidden_ = true; } return CONTINUE_OBSERVING; @@ -245,6 +247,7 @@ if (!was_hidden_) { RecordPageLoadMetrics(base::TimeTicks() /* no app_background_time */); RecordTimingMetrics(timing); + RecordInputTimingMetrics(); } ReportLayoutStability(); } @@ -388,22 +391,6 @@ builder.SetInteractiveTiming_LongestInputTimestamp4( longest_input_timestamp.InMilliseconds()); } - if (timing.interactive_timing->total_input_delay) { - base::TimeDelta total_input_delay = - timing.interactive_timing->total_input_delay.value(); - builder.SetInteractiveTiming_TotalInputDelay( - total_input_delay.InMilliseconds()); - } - if (timing.interactive_timing->total_adjusted_input_delay) { - base::TimeDelta total_adjusted_input_delay = - timing.interactive_timing->total_adjusted_input_delay.value(); - builder.SetInteractiveTiming_TotalAdjustedInputDelay( - total_adjusted_input_delay.InMilliseconds()); - } - if (timing.interactive_timing->num_input_events) { - int num_input_events = timing.interactive_timing->num_input_events; - builder.SetInteractiveTiming_NumInputEvents(num_input_events); - } builder.SetCpuTime(total_foreground_cpu_time_.InMilliseconds()); // Use a bucket spacing factor of 1.3 for bytes. @@ -607,6 +594,22 @@ GetDelegate().GetMainFrameRenderData().layout_shift_score)); } +void UkmPageLoadMetricsObserver::RecordInputTimingMetrics() { + if (GetDelegate().GetPageInputTiming().num_input_events == 0) { + return; + } + ukm::builders::PageLoad(GetDelegate().GetSourceId()) + .SetInteractiveTiming_NumInputEvents( + GetDelegate().GetPageInputTiming().num_input_events) + .SetInteractiveTiming_TotalInputDelay( + GetDelegate().GetPageInputTiming().total_input_delay.InMilliseconds()) + .SetInteractiveTiming_TotalAdjustedInputDelay( + GetDelegate() + .GetPageInputTiming() + .total_adjusted_input_delay.InMilliseconds()) + .Record(ukm::UkmRecorder::Get()); +} + base::Optional<int64_t> UkmPageLoadMetricsObserver::GetRoundedSiteEngagementScore() const { if (!browser_context_)
diff --git a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.h b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.h index 3f34854..116560f 100644 --- a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.h +++ b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.h
@@ -111,7 +111,9 @@ void ReportLayoutStability(); - // Captures the site engagement score for the commited URL and + void RecordInputTimingMetrics(); + + // Captures the site engagement score for the committed URL and // returns the score rounded to the nearest 10. base::Optional<int64_t> GetRoundedSiteEngagementScore() const;
diff --git a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer_unittest.cc index b8c18c3..0f7e13e 100644 --- a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer_unittest.cc +++ b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer_unittest.cc
@@ -944,21 +944,16 @@ } } -TEST_F(UkmPageLoadMetricsObserverTest, - TotalInputDelayAndTotalAdjustedInputDelay) { - page_load_metrics::mojom::PageLoadTiming timing; - page_load_metrics::InitPageLoadTimingForTest(&timing); - timing.navigation_start = base::Time::FromDoubleT(1); - timing.interactive_timing->total_input_delay = - base::TimeDelta::FromMilliseconds(500); - timing.interactive_timing->total_adjusted_input_delay = - base::TimeDelta::FromMilliseconds(250); - PopulateRequiredTimingFields(&timing); - +TEST_F(UkmPageLoadMetricsObserverTest, InputTiming) { NavigateAndCommit(GURL(kTestUrl1)); - tester()->SimulateTimingUpdate(timing); - // Simulate closing the tab. + page_load_metrics::mojom::InputTiming input_timing; + input_timing.num_input_events = 2; + input_timing.total_input_delay = base::TimeDelta::FromMilliseconds(100); + input_timing.total_adjusted_input_delay = + base::TimeDelta::FromMilliseconds(10); + tester()->SimulateInputTimingUpdate(input_timing); + DeleteContents(); std::map<ukm::SourceId, ukm::mojom::UkmEntryPtr> merged_entries = @@ -970,36 +965,12 @@ tester()->test_ukm_recorder().ExpectEntrySourceHasUrl(kv.second.get(), GURL(kTestUrl1)); tester()->test_ukm_recorder().ExpectEntryMetric( - kv.second.get(), PageLoad::kInteractiveTiming_TotalInputDelayName, 500); + kv.second.get(), PageLoad::kInteractiveTiming_NumInputEventsName, 2); + tester()->test_ukm_recorder().ExpectEntryMetric( + kv.second.get(), PageLoad::kInteractiveTiming_TotalInputDelayName, 100); tester()->test_ukm_recorder().ExpectEntryMetric( kv.second.get(), - PageLoad::kInteractiveTiming_TotalAdjustedInputDelayName, 250); - } -} - -TEST_F(UkmPageLoadMetricsObserverTest, NumInputEvents) { - page_load_metrics::mojom::PageLoadTiming timing; - page_load_metrics::InitPageLoadTimingForTest(&timing); - timing.navigation_start = base::Time::FromDoubleT(1); - timing.interactive_timing->num_input_events = 5; - PopulateRequiredTimingFields(&timing); - - NavigateAndCommit(GURL(kTestUrl1)); - tester()->SimulateTimingUpdate(timing); - - // Simulate closing the tab. - DeleteContents(); - - std::map<ukm::SourceId, ukm::mojom::UkmEntryPtr> merged_entries = - tester()->test_ukm_recorder().GetMergedEntriesByName( - PageLoad::kEntryName); - EXPECT_EQ(1ul, merged_entries.size()); - - for (const auto& kv : merged_entries) { - tester()->test_ukm_recorder().ExpectEntrySourceHasUrl(kv.second.get(), - GURL(kTestUrl1)); - tester()->test_ukm_recorder().ExpectEntryMetric( - kv.second.get(), PageLoad::kInteractiveTiming_NumInputEventsName, 5); + PageLoad::kInteractiveTiming_TotalAdjustedInputDelayName, 10); } }
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc b/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc index b8f8cd9..ee0eca3 100644 --- a/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc +++ b/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc
@@ -2492,9 +2492,8 @@ // Creates a single frame within the main frame and verifies the intersection // with the main frame. -// TODO(crbug/1062006): Re-enable once chromeos-thinlto build is fixed. IN_PROC_BROWSER_TEST_F(PageLoadMetricsBrowserTest, - DISABLED_MainFrameDocumentIntersectionSingleFrame) { + MainFrameDocumentIntersectionSingleFrame) { ASSERT_TRUE(embedded_test_server()->Start()); auto waiter = CreatePageLoadMetricsTestWaiter(); @@ -2517,9 +2516,8 @@ // Creates a set of nested frames within the main frame and verifies // their intersections with the main frame. -// TODO(crbug/1062006): Re-enable once chromeos-thinlto build is fixed. IN_PROC_BROWSER_TEST_F(PageLoadMetricsBrowserTest, - DISABLED_MainFrameDocumentIntersectionSameOrigin) { + MainFrameDocumentIntersectionSameOrigin) { EXPECT_TRUE(embedded_test_server()->Start()); auto waiter = CreatePageLoadMetricsTestWaiter(); @@ -2559,9 +2557,8 @@ // Creates a set of nested frames, with a cross origin subframe, within the // main frame and verifies their intersections with the main frame. -// TODO(crbug/1062006): Re-enable once chromeos-thinlto build is fixed. IN_PROC_BROWSER_TEST_F(PageLoadMetricsBrowserTest, - DISABLED_MainFrameDocumentIntersectionCrossOrigin) { + MainFrameDocumentIntersectionCrossOrigin) { EXPECT_TRUE(embedded_test_server()->Start()); auto waiter = CreatePageLoadMetricsTestWaiter(); ui_test_utils::NavigateToURL( @@ -2602,10 +2599,8 @@ // Creates a set of nested frames, with a cross origin subframe that is out of // view within the main frame and verifies their intersections with the main // frame. -// TODO(crbug/1062006): Re-enable once chromeos-thinlto build is fixed. -IN_PROC_BROWSER_TEST_F( - PageLoadMetricsBrowserTest, - DISABLED_MainFrameDocumentIntersectionCrossOriginOutOfView) { +IN_PROC_BROWSER_TEST_F(PageLoadMetricsBrowserTest, + MainFrameDocumentIntersectionCrossOriginOutOfView) { EXPECT_TRUE(embedded_test_server()->Start()); auto waiter = CreatePageLoadMetricsTestWaiter(); ui_test_utils::NavigateToURL( @@ -2644,11 +2639,8 @@ // view within the main frame and verifies their intersections with the main // frame. The out of view frame is then scrolled back into view and the // intersection is verified. -// -// TODO(crbug/1062006): Re-enable once chromeos-thinlto build is fixed. -IN_PROC_BROWSER_TEST_F( - PageLoadMetricsBrowserTest, - DISABLED_MainFrameDocumentIntersectionCrossOriginScrolled) { +IN_PROC_BROWSER_TEST_F(PageLoadMetricsBrowserTest, + MainFrameDocumentIntersectionCrossOriginScrolled) { EXPECT_TRUE(embedded_test_server()->Start()); auto waiter = CreatePageLoadMetricsTestWaiter(); ui_test_utils::NavigateToURL(
diff --git a/chrome/browser/payments/android/journey_logger_android.cc b/chrome/browser/payments/android/journey_logger_android.cc index 4a0336c..67bbfaa 100644 --- a/chrome/browser/payments/android/journey_logger_android.cc +++ b/chrome/browser/payments/android/journey_logger_android.cc
@@ -157,6 +157,13 @@ journey_logger_.SetTriggerTime(); } +void JourneyLoggerAndroid::SetPaymentAppUkmSourceId( + JNIEnv* env, + const base::android::JavaParamRef<jobject>& jcaller, + ukm::SourceId source_id) { + journey_logger_.SetPaymentAppUkmSourceId(source_id); +} + static jlong JNI_JourneyLogger_InitJourneyLoggerAndroid( JNIEnv* env, const JavaParamRef<jobject>& jcaller,
diff --git a/chrome/browser/payments/android/journey_logger_android.h b/chrome/browser/payments/android/journey_logger_android.h index bffb292..d6e9fa5 100644 --- a/chrome/browser/payments/android/journey_logger_android.h +++ b/chrome/browser/payments/android/journey_logger_android.h
@@ -80,6 +80,10 @@ jboolean jcompleted); void SetTriggerTime(JNIEnv* env, const base::android::JavaParamRef<jobject>& jcaller); + void SetPaymentAppUkmSourceId( + JNIEnv* env, + const base::android::JavaParamRef<jobject>& jcaller, + ukm::SourceId source_id); private: JourneyLogger journey_logger_;
diff --git a/chrome/browser/payments/android/service_worker_payment_app_bridge.cc b/chrome/browser/payments/android/service_worker_payment_app_bridge.cc index 1f19f7c3..cfaae26b 100644 --- a/chrome/browser/payments/android/service_worker_payment_app_bridge.cc +++ b/chrome/browser/payments/android/service_worker_payment_app_bridge.cc
@@ -25,6 +25,7 @@ #include "content/public/browser/browser_thread.h" #include "content/public/browser/payment_app_provider.h" #include "content/public/browser/web_contents.h" +#include "services/metrics/public/cpp/ukm_recorder.h" #include "third_party/blink/public/mojom/payments/payment_app.mojom.h" #include "ui/gfx/android/java_bitmap.h" #include "url/gurl.h" @@ -672,3 +673,16 @@ web_contents->GetBrowserContext(), static_cast<payments::mojom::PaymentEventResponseType>(reason)); } + +static jlong +JNI_ServiceWorkerPaymentAppBridge_GetSourceIdForPaymentAppFromScope( + JNIEnv* env, + const JavaParamRef<jstring>& jscope) { + // At this point we know that the payment handler window is open for the + // payment app associated with this scope. Since this getter is called inside + // PaymentApp::getUkmSourceId() function which in turn gets called for the + // invoked app inside PaymentRequestImpl::openPaymentHandlerWindowInternal. + return content::PaymentAppProvider::GetInstance() + ->GetSourceIdForPaymentAppFromScope( + GURL(ConvertJavaStringToUTF8(env, jscope)).GetOrigin()); +}
diff --git a/chrome/browser/payments/journey_logger_browsertest.cc b/chrome/browser/payments/journey_logger_browsertest.cc index f238d78d..2869b31 100644 --- a/chrome/browser/payments/journey_logger_browsertest.cc +++ b/chrome/browser/payments/journey_logger_browsertest.cc
@@ -24,6 +24,12 @@ void SetUpOnMainThread() override { PaymentRequestPlatformBrowserTestBase::SetUpOnMainThread(); + main_frame_url_ = https_server()->GetURL("/journey_logger_test.html"); + ASSERT_TRUE( + content::NavigateToURL(GetActiveWebContents(), main_frame_url_)); + } + + void SetUpForGpay() { gpay_server_.ServeFilesFromSourceDirectory( "components/test/data/payments/google.com/"); ASSERT_TRUE(gpay_server_.Start()); @@ -33,12 +39,11 @@ SetDownloaderAndIgnorePortInOriginComparisonForTesting( {{method_name, &gpay_server_}}); - main_frame_url_ = https_server()->GetURL("/journey_logger_test.html"); - ASSERT_TRUE( - content::NavigateToURL(GetActiveWebContents(), main_frame_url_)); + gpay_scope_url_ = gpay_server_.GetURL("google.com", "/"); } const GURL& main_frame_url() const { return main_frame_url_; } + const GURL& gpay_scope_url() const { return gpay_scope_url_; } ukm::TestAutoSetUkmRecorder* test_ukm_recorder() { return test_ukm_recorder_.get(); @@ -47,6 +52,7 @@ private: net::EmbeddedTestServer gpay_server_; GURL main_frame_url_; + GURL gpay_scope_url_; std::unique_ptr<ukm::TestAutoSetUkmRecorder> test_ukm_recorder_; DISALLOW_COPY_AND_ASSIGN(JourneyLoggerTest); @@ -91,6 +97,7 @@ IN_PROC_BROWSER_TEST_F(JourneyLoggerTest, GooglePaymentApp) { base::HistogramTester histogram_tester; + SetUpForGpay(); EXPECT_EQ("{\"apiVersion\":1}", content::EvalJs(GetActiveWebContents(), "testGPay()")); @@ -106,6 +113,7 @@ // Make sure the UKM was logged correctly. IN_PROC_BROWSER_TEST_F(JourneyLoggerTest, UKMTransactionAmountRecorded) { + SetUpForGpay(); EXPECT_EQ("{\"apiVersion\":1}", content::EvalJs(GetActiveWebContents(), "testGPay()")); @@ -128,4 +136,79 @@ } } +IN_PROC_BROWSER_TEST_F(JourneyLoggerTest, + UKMCheckoutEventsRecordedForAppOrigin) { + GURL merchant_url = https_server()->GetURL("/payment_handler.html"); + ASSERT_TRUE(content::NavigateToURL(GetActiveWebContents(), merchant_url)); + EXPECT_EQ("success", content::EvalJs(GetActiveWebContents(), "install()")); + + ResetEventWaiterForSingleEvent(TestEvent::kPaymentCompleted); + EXPECT_EQ("success", content::EvalJs(GetActiveWebContents(), "launch()")); + WaitForObservedEvent(); + + // UKM for merchant's website origin. + auto entries = test_ukm_recorder()->GetEntriesByName( + ukm::builders::PaymentRequest_CheckoutEvents::kEntryName); + size_t num_entries = entries.size(); + EXPECT_EQ(1u, num_entries); + test_ukm_recorder()->ExpectEntrySourceHasUrl(entries[0], merchant_url); + + // UKM for payment app's scope. + entries = test_ukm_recorder()->GetEntriesByName( + ukm::builders::PaymentApp_CheckoutEvents::kEntryName); + num_entries = entries.size(); + EXPECT_EQ(1u, num_entries); + test_ukm_recorder()->ExpectEntrySourceHasUrl(entries[0], + https_server()->GetURL("/")); +} + +IN_PROC_BROWSER_TEST_F( + JourneyLoggerTest, + UKMCheckoutEventsNotRecordedForAppOriginWhenNoWindowShown) { + SetUpForGpay(); + + EXPECT_EQ("{\"apiVersion\":1}", + content::EvalJs(GetActiveWebContents(), "testGPay()")); + + // UKM for merchant's website origin. + auto entries = test_ukm_recorder()->GetEntriesByName( + ukm::builders::PaymentRequest_CheckoutEvents::kEntryName); + size_t num_entries = entries.size(); + EXPECT_EQ(1u, num_entries); + test_ukm_recorder()->ExpectEntrySourceHasUrl(entries[0], main_frame_url()); + + // No UKM for payment app's scope since the app's origin is not shown inside + // the PH modal window. + entries = test_ukm_recorder()->GetEntriesByName( + ukm::builders::PaymentApp_CheckoutEvents::kEntryName); + num_entries = entries.size(); + EXPECT_EQ(0u, num_entries); +} + +IN_PROC_BROWSER_TEST_F( + JourneyLoggerTest, + UKMCheckoutEventsNotRecordedForAppOriginWhenNoAppInvoked) { + CreateAndAddCreditCardForProfile(CreateAndAddAutofillProfile()); + + ResetEventWaiterForSingleEvent(TestEvent::kShowAppsReady); + EXPECT_TRUE(content::ExecJs(GetActiveWebContents(), "testBasicCard()")); + WaitForObservedEvent(); + + EXPECT_EQ(true, content::EvalJs(GetActiveWebContents(), "abort()")); + + // UKM for merchant's website origin. + auto entries = test_ukm_recorder()->GetEntriesByName( + ukm::builders::PaymentRequest_CheckoutEvents::kEntryName); + size_t num_entries = entries.size(); + EXPECT_EQ(1u, num_entries); + test_ukm_recorder()->ExpectEntrySourceHasUrl(entries[0], main_frame_url()); + + // No UKM for payment app's scope since the request got aborted before + // invoking a payment app. + entries = test_ukm_recorder()->GetEntriesByName( + ukm::builders::PaymentApp_CheckoutEvents::kEntryName); + num_entries = entries.size(); + EXPECT_EQ(0u, num_entries); +} + } // namespace payments
diff --git a/chrome/browser/policy/printing_restrictions_policy_handler.cc b/chrome/browser/policy/printing_restrictions_policy_handler.cc index 7c169fe..439120b 100644 --- a/chrome/browser/policy/printing_restrictions_policy_handler.cc +++ b/chrome/browser/policy/printing_restrictions_policy_handler.cc
@@ -156,12 +156,10 @@ return width && height && width->is_int() && height->is_int(); } -void PrintingAllowedPageSizesPolicyHandler::ApplyList( - std::unique_ptr<base::ListValue> filtered_list, - PrefValueMap* prefs) { - DCHECK(filtered_list); - prefs->SetValue(prefs::kPrintingAllowedPageSizes, - base::Value::FromUniquePtrValue(std::move(filtered_list))); +void PrintingAllowedPageSizesPolicyHandler::ApplyList(base::Value filtered_list, + PrefValueMap* prefs) { + DCHECK(filtered_list.is_list()); + prefs->SetValue(prefs::kPrintingAllowedPageSizes, std::move(filtered_list)); } PrintingSizeDefaultPolicyHandler::PrintingSizeDefaultPolicyHandler()
diff --git a/chrome/browser/policy/printing_restrictions_policy_handler.h b/chrome/browser/policy/printing_restrictions_policy_handler.h index 8fd7029b..bb388bd1 100644 --- a/chrome/browser/policy/printing_restrictions_policy_handler.h +++ b/chrome/browser/policy/printing_restrictions_policy_handler.h
@@ -8,6 +8,7 @@ #include <memory> #include "base/containers/flat_map.h" +#include "base/values.h" #include "components/policy/core/browser/configuration_policy_handler.h" #include "printing/backend/printing_restrictions.h" @@ -95,8 +96,7 @@ // ListPolicyHandler implementation: bool CheckListEntry(const base::Value& value) override; - void ApplyList(std::unique_ptr<base::ListValue> filtered_list, - PrefValueMap* prefs) override; + void ApplyList(base::Value filtered_list, PrefValueMap* prefs) override; }; class PrintingSizeDefaultPolicyHandler : public TypeCheckingPolicyHandler {
diff --git a/chrome/browser/prerender/isolated/isolated_prerender_browsertest.cc b/chrome/browser/prerender/isolated/isolated_prerender_browsertest.cc index 667f869d..94765c6 100644 --- a/chrome/browser/prerender/isolated/isolated_prerender_browsertest.cc +++ b/chrome/browser/prerender/isolated/isolated_prerender_browsertest.cc
@@ -185,6 +185,8 @@ NavigationPredictorKeyedServiceFactory::GetForProfile(browser()->profile()) ->OnPredictionUpdated( browser()->tab_strip_model()->GetActiveWebContents(), doc_url, + NavigationPredictorKeyedService::PredictionSource:: + kAnchorElementsParsedFromWebPage, predicted_urls); }
diff --git a/chrome/browser/prerender/isolated/isolated_prerender_tab_helper.cc b/chrome/browser/prerender/isolated/isolated_prerender_tab_helper.cc index 5e2f23a..8ec407a 100644 --- a/chrome/browser/prerender/isolated/isolated_prerender_tab_helper.cc +++ b/chrome/browser/prerender/isolated/isolated_prerender_tab_helper.cc
@@ -300,13 +300,24 @@ return; } + if (prediction->prediction_source() != + NavigationPredictorKeyedService::PredictionSource:: + kAnchorElementsParsedFromWebPage) { + return; + } + if (prediction.value().web_contents() != web_contents()) { // We only care about predictions in this tab. return; } - if (!google_util::IsGoogleSearchUrl( - prediction.value().source_document_url())) { + const base::Optional<GURL>& source_document_url = + prediction->source_document_url(); + + if (!source_document_url || source_document_url->is_empty()) + return; + + if (!google_util::IsGoogleSearchUrl(source_document_url.value())) { return; }
diff --git a/chrome/browser/prerender/isolated/isolated_prerender_tab_helper_unittest.cc b/chrome/browser/prerender/isolated/isolated_prerender_tab_helper_unittest.cc index 74631aad..6c64996 100644 --- a/chrome/browser/prerender/isolated/isolated_prerender_tab_helper_unittest.cc +++ b/chrome/browser/prerender/isolated/isolated_prerender_tab_helper_unittest.cc
@@ -114,7 +114,19 @@ const GURL& doc_url, const std::vector<GURL>& predicted_urls) { NavigationPredictorKeyedServiceFactory::GetForProfile(profile()) - ->OnPredictionUpdated(web_contents, doc_url, predicted_urls); + ->OnPredictionUpdated( + web_contents, doc_url, + NavigationPredictorKeyedService::PredictionSource:: + kAnchorElementsParsedFromWebPage, + predicted_urls); + task_environment()->RunUntilIdle(); + } + + void MakeExternalAndroidAppNavigationPrediction( + const std::vector<GURL>& predicted_urls) { + NavigationPredictorKeyedServiceFactory::GetForProfile(profile()) + ->OnPredictionUpdatedByExternalAndroidApp({"com.example.foo"}, + predicted_urls); task_environment()->RunUntilIdle(); } @@ -421,6 +433,21 @@ EXPECT_EQ(RequestCount(), 0); } +// Verify that isolated prerender is not triggered if the predictions for next +// likely navigations are provided by external Android app. +TEST_F(IsolatedPrerenderTabHelperTest, ExternalAndroidApp) { + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndEnableFeature( + features::kPrefetchSRPNavigationPredictions_HTMLOnly); + + GURL doc_url("https://www.google.com/search?q=cats"); + GURL prediction_url("https://www.cat-food.com/"); + MakeExternalAndroidAppNavigationPrediction({prediction_url}); + base::RunLoop().RunUntilIdle(); + + EXPECT_EQ(RequestCount(), 0); +} + TEST_F(IsolatedPrerenderTabHelperTest, SuccessCase) { base::test::ScopedFeatureList scoped_feature_list; scoped_feature_list.InitAndEnableFeature(
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/BUILD.gn b/chrome/browser/resources/chromeos/accessibility/chromevox/BUILD.gn index 72c226e7..8aa05da 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/BUILD.gn +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/BUILD.gn
@@ -21,11 +21,13 @@ # List of all modules that are included in one or more of the production # chromevox scripts. chromevox_modules = [ + "../common/automation_predicate.js", + "../common/automation_util.js", + "../common/constants.js", + "../common/tree_walker.js", "background/annotation/node_identifier.js", "background/annotation/user_annotation_handler.js", "background/automation_object_constructor_installer.js", - "../common/automation_predicate.js", - "../common/automation_util.js", "background/background.js", "background/base_automation_handler.js", "background/braille_background.js", @@ -36,7 +38,6 @@ "background/classic_background.js", "background/color.js", "background/command_handler.js", - "../common/constants.js", "background/cursors.js", "background/custom_automation_event.js", "background/desktop_automation_handler.js", @@ -51,9 +52,8 @@ "background/injected_script_loader.js", "background/keyboard_handler.js", "background/keymaps/key_map.js", - "background/locale_output_helper.js", - "learn_mode/kbexplorer.js", "background/live_regions.js", + "background/locale_output_helper.js", "background/logging/event_stream_logger.js", "background/logging/log.js", "background/logging/log_store.js", @@ -71,8 +71,8 @@ "background/prefs.js", "background/range_automation_handler.js", "background/recovery_strategy.js", + "background/smart_sticky_mode.js", "background/tabs_api_handler.js", - "../common/tree_walker.js", "braille/bluetooth_braille_display_manager.js", "braille/bluetooth_braille_display_ui.js", "braille/braille_display_manager.js", @@ -108,6 +108,7 @@ "injected/api_implementation.js", "injected/loader.js", "injected/script_installer.js", + "learn_mode/kbexplorer.js", "options/options.js", "panel/annotations_ui.js", "panel/i_search.js",
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/classic_background.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/classic_background.js index 3ebbe32b..9dd0b8c 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/classic_background.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/classic_background.js
@@ -118,13 +118,12 @@ if (pref == 'earcons') { AbstractEarcons.enabled = !!value; } else if (pref == 'sticky' && announce) { - if (value) { - ChromeVox.tts.speak( - Msgs.getMsg('sticky_mode_enabled'), QueueMode.FLUSH); - } else { - ChromeVox.tts.speak( - Msgs.getMsg('sticky_mode_disabled'), QueueMode.FLUSH); - } + new Output() + .withInitialSpeechProperties(AbstractTts.PERSONALITY_ANNOTATION) + .withString( + value ? Msgs.getMsg('sticky_mode_enabled') : + Msgs.getMsg('sticky_mode_disabled')) + .go(); } else if (pref == 'typingEcho' && announce) { let announceStr = ''; switch (value) { @@ -144,7 +143,10 @@ break; } if (announceStr) { - ChromeVox.tts.speak(announceStr, QueueMode.QUEUE); + new Output() + .withInitialSpeechProperties(AbstractTts.PERSONALITY_ANNOTATION) + .withString(announceStr) + .go(); } } else if (pref == 'brailleCaptions') { BrailleCaptionsBackground.setActive(!!value);
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/command_handler.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/command_handler.js index c3e0f26a..4b200e0 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/command_handler.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/command_handler.js
@@ -14,6 +14,7 @@ goog.require('LogStore'); goog.require('Output'); goog.require('PhoneticData'); +goog.require('SmartStickyMode'); goog.require('TreeDumper'); goog.require('ChromeVoxBackground'); goog.require('ChromeVoxKbHandler'); @@ -34,7 +35,13 @@ CommandHandler.incognito_ = !!chrome.runtime.getManifest()['incognito']; /** - * Handles ChromeVox Next commands. + * Handles toggling sticky mode when encountering editables. + * @private {!SmartStickyMode} + */ +CommandHandler.smartStickyMode_ = new SmartStickyMode(); + +/** + * Handles ChromeVox commands. * @param {string} command * @return {boolean} True if the command should propagate. */ @@ -363,11 +370,13 @@ case 'nextEditText': pred = AutomationPredicate.editText; predErrorMsg = 'no_next_edit_text'; + CommandHandler.smartStickyMode_.startIgnoringRangeChanges(); break; case 'previousEditText': dir = Dir.BACKWARD; pred = AutomationPredicate.editText; predErrorMsg = 'no_previous_edit_text'; + CommandHandler.smartStickyMode_.startIgnoringRangeChanges(); break; case 'nextFormField': pred = AutomationPredicate.formField; @@ -1089,6 +1098,7 @@ .withQueueMode(QueueMode.FLUSH) .go(); } + CommandHandler.onFinishCommand(); return false; } @@ -1123,6 +1133,7 @@ .withString(Msgs.getMsg(predErrorMsg)) .withQueueMode(QueueMode.FLUSH) .go(); + CommandHandler.onFinishCommand(); return false; } } @@ -1154,6 +1165,7 @@ // Jump or if there is a valid current range, then move from it // since we have refreshed node data. CommandHandler.onCommand(command); + CommandHandler.onFinishCommand(); return; } @@ -1183,6 +1195,7 @@ } else { scrollable.scrollBackward(callback); } + CommandHandler.onFinishCommand(); return false; } } @@ -1192,10 +1205,18 @@ current, undefined, speechProps, skipSettingSelection); } + CommandHandler.onFinishCommand(); return false; }; /** + * Finishes processing of a command. + */ +CommandHandler.onFinishCommand = function() { + CommandHandler.smartStickyMode_.stopIgnoringRangeChanges(); +}; + +/** * Increase or decrease a speech property and make an announcement. * @param {string} propertyName The name of the property to change. * @param {boolean} increase If true, increases the property value by one @@ -1408,4 +1429,5 @@ } }); }; + }); // goog.scope
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/output.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/output.js index e71cc22..dbd41bb 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/output.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/output.js
@@ -1823,10 +1823,6 @@ return ret; } - if (node.state[StateType.EDITABLE] && ChromeVox.isStickyPrefOn) { - ret.push({msgId: 'sticky_mode_enabled'}); - } - if (node.state[StateType.EDITABLE] && node.state[StateType.FOCUSED] && (node.state[StateType.MULTILINE] || node.state[StateType.RICHLY_EDITABLE])) {
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/prefs.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/prefs.js index a7c1659..63f6c416 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/prefs.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/prefs.js
@@ -216,11 +216,7 @@ 'menuBrailleCommands': false, 'numberReadingStyle': 'asWords', 'position': '{}', - 'siteSpecificEnhancements': true, - 'siteSpecificScriptBase': - 'https://ssl.gstatic.com/accessibility/javascript/ext/', - 'siteSpecificScriptLoader': - 'https://ssl.gstatic.com/accessibility/javascript/ext/loader.js', + 'smartStickyMode': true, 'speakTextUnderMouse': false, 'sticky': false, 'typingEcho': 0,
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/smart_sticky_mode.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/smart_sticky_mode.js new file mode 100644 index 0000000..148075033 --- /dev/null +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/smart_sticky_mode.js
@@ -0,0 +1,87 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview Handles automatic sticky mode toggles. Turns sticky mode off + * when the current range is over an editable; restores sticky mode when not on + * an editable. + */ + +goog.provide('SmartStickyMode'); + +goog.require('ChromeVoxState'); + +/** @implements {ChromeVoxStateObserver} */ +SmartStickyMode = class { + constructor() { + /** @private {boolean} */ + this.ignoreRangeChanges_ = false; + + /** + * Tracks whether we (and not the user) turned off sticky mode when over an + * editable. + * @private {boolean} + */ + this.didTurnOffStickyMode_ = false; + + ChromeVoxState.addObserver(this); + } + + /** @override */ + onCurrentRangeChanged(newRange) { + if (!newRange || this.ignoreRangeChanges_ || + localStorage['smartStickyMode'] !== 'true') { + return; + } + + const isRangeEditable = + newRange.start.node.state[chrome.automation.StateType.EDITABLE]; + + // This toggler should not make any changes when the range isn't editable + // and we haven't previously tracked any sticky mode state from the user. + if (!isRangeEditable && !this.didTurnOffStickyMode_) { + return; + } + + if (isRangeEditable) { + if (!ChromeVox.isStickyPrefOn) { + // Sticky mode was already off; do not track the current sticky state + // since we may have set it ourselves. + return; + } + + if (this.didTurnOffStickyMode_) { + // This should not be possible with |ChromeVox.isStickyPrefOn| set to + // true. + throw 'Unexpected sticky state value encountered.'; + } + + // Save the sticky state for restoration later. + this.didTurnOffStickyMode_ = true; + ChromeVoxBackground.setPref( + 'sticky', false /* value */, true /* announce */); + } else if (this.didTurnOffStickyMode_) { + // Restore the previous sticky mode state. + ChromeVoxBackground.setPref( + 'sticky', true /* value */, true /* announce */); + this.didTurnOffStickyMode_ = false; + } + } + + /** + * When called, ignores all changes in the current range when toggling sticky + * mode without user input. + */ + startIgnoringRangeChanges() { + this.ignoreRangeChanges_ = true; + } + + /** + * When called, stops ignoring changes in the current range when toggling + * sticky mode without user input. + */ + stopIgnoringRangeChanges() { + this.ignoreRangeChanges_ = false; + } +};
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/common/abstract_tts.js b/chrome/browser/resources/chromeos/accessibility/chromevox/common/abstract_tts.js index fb18809..68c75d6 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/common/abstract_tts.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/common/abstract_tts.js
@@ -300,7 +300,7 @@ /** * TTS personality for annotations - text spoken by ChromeVox that * elaborates on a user interface element but isn't displayed on-screen. - * @type {Object} + * @type {!Object} */ AbstractTts.PERSONALITY_ANNOTATION = { 'relativePitch': -0.25,
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/options/options.html b/chrome/browser/resources/chromeos/accessibility/chromevox/options/options.html index cd68d46..1561d4b9 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/options/options.html +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/options/options.html
@@ -100,6 +100,16 @@ aria-labelledby="announceDownloadsLabel"> </div> + <div class="option"> + <label id="smartStickyModeLabel" class="i18n" + msgid="options_smart_sticky_mode"> + Turn off sticky mode when editing text (Smart Sticky Mode) + </label> + <input id="smartStickyMode" type="checkbox" + class="checkbox pref" name="smartStickyMode" + aria-labelledby="smartStickyModeLabel"> + </div> + <h2 class="i18n description" msgid="options_audio_description" id="audioDescription"> When playing audio
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/options/options_test.js b/chrome/browser/resources/chromeos/accessibility/chromevox/options/options_test.js index f4f955d8..0e7efb2 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/options/options_test.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/options/options_test.js
@@ -84,3 +84,31 @@ .replay(); }); }); + +TEST_F('ChromeVoxOptionsTest', 'SmartStickyMode', function() { + this.runOnOptionsPage((mockFeedback, evt) => { + const smartStickyModeCheckbox = evt.target.find({ + role: chrome.automation.RoleType.CHECK_BOX, + attributes: + {name: 'Turn off sticky mode when editing text (Smart Sticky Mode)'} + }); + assertNotNullNorUndefined(smartStickyModeCheckbox); + mockFeedback + .call(smartStickyModeCheckbox.focus.bind(smartStickyModeCheckbox)) + .expectSpeech( + 'Turn off sticky mode when editing text (Smart Sticky Mode)', + 'Check box', 'Checked') + .call(() => { + assertEquals('true', localStorage['smartStickyMode']); + }) + .call(smartStickyModeCheckbox.doDefault.bind(smartStickyModeCheckbox)) + .expectSpeech( + 'Turn off sticky mode when editing text (Smart Sticky Mode)', + 'Check box', 'Not checked') + .call(() => { + assertEquals('false', localStorage['smartStickyMode']); + }) + + .replay(); + }); +});
diff --git a/chrome/browser/resources/chromeos/accessibility/strings/chromevox_strings.grdp b/chrome/browser/resources/chromeos/accessibility/strings/chromevox_strings.grdp index c47fc91..90c6cdf 100644 --- a/chrome/browser/resources/chromeos/accessibility/strings/chromevox_strings.grdp +++ b/chrome/browser/resources/chromeos/accessibility/strings/chromevox_strings.grdp
@@ -2912,5 +2912,8 @@ <message desc="Announced to alert the user that ChromeVox has no current focus." name="IDS_CHROMEVOX_NO_FOCUS"> No current ChromeVox focus. Press Alt+Shift+L to go to the launcher. </message> + <message desc="Labels the checkbox on the options page that enables or disables Smart Sticky Mode. The label explains how the feature works." name="IDS_CHROMEVOX_OPTIONS_SMART_STICKY_MODE"> + Turn off sticky mode when editing text (Smart Sticky Mode) + </message> </grit-part>
diff --git a/chrome/browser/resources/settings/chromeos/BUILD.gn b/chrome/browser/resources/settings/chromeos/BUILD.gn index 70f3bf05..f6fe898 100644 --- a/chrome/browser/resources/settings/chromeos/BUILD.gn +++ b/chrome/browser/resources/settings/chromeos/BUILD.gn
@@ -108,6 +108,7 @@ "os_settings_main:closure_compile", "os_settings_menu:closure_compile", "os_settings_page:closure_compile", + "os_settings_search_box:closure_compile", "os_settings_ui:closure_compile", "parental_controls_page:closure_compile", "personalization_page:closure_compile",
diff --git a/chrome/browser/resources/settings/chromeos/os_settings_search_box/BUILD.gn b/chrome/browser/resources/settings/chromeos/os_settings_search_box/BUILD.gn new file mode 100644 index 0000000..df914cd --- /dev/null +++ b/chrome/browser/resources/settings/chromeos/os_settings_search_box/BUILD.gn
@@ -0,0 +1,29 @@ +# Copyright 2020 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//third_party/closure_compiler/compile_js.gni") + +js_type_check("closure_compile") { + deps = [ + ":os_search_result_row", + ":os_settings_search_box", + ] +} + +js_library("os_settings_search_box") { + deps = [ + "..:metrics_recorder", + "//third_party/polymer/v1_0/components-chromium/iron-dropdown:iron-dropdown-extracted", + "//third_party/polymer/v1_0/components-chromium/iron-list:iron-list-extracted", + "//ui/webui/resources/cr_elements/cr_toolbar:cr_toolbar_search_field", + "//ui/webui/resources/js:assert", + ] +} + +js_library("os_search_result_row") { + deps = [ + "//ui/webui/resources/js/cr/ui:focus_row", + "//ui/webui/resources/js/cr/ui:focus_row_behavior", + ] +}
diff --git a/chrome/browser/resources/settings/chromeos/os_settings_search_box/os_search_result_row.html b/chrome/browser/resources/settings/chromeos/os_settings_search_box/os_search_result_row.html new file mode 100644 index 0000000..46c4c94d --- /dev/null +++ b/chrome/browser/resources/settings/chromeos/os_settings_search_box/os_search_result_row.html
@@ -0,0 +1,41 @@ +<link rel="import" href="chrome://resources/html/polymer.html"> + +<link rel="import" href="chrome://resources/html/cr/ui/focus_row_behavior.html"> +<link rel="import" href="../../settings_shared_css.html"> + +<dom-module id="os-search-result-row"> + <template> + <style include="settings-shared"> + :host { + display: flex; + flex-basis: 100%; + height: 40px; + } + + :host([selected]) .search-result-container { + background-color: var(--cros-menu-button-bg-color-active); + } + + :host(:not([selected])) .search-result-container:hover { + background-color: var(--cros-menu-button-bg-color-hover); + } + + .search-result-container { + display: flex; + flex-basis: 100%; + } + + .text { + flex-basis: 100%; + } + </style> + <div class="search-result-container" focus-row-container> + <!-- TODO(crbug/1056909): Focus right hand icon instead; move + focus-row-control to that icon when available--> + <div class="text" focus-type="rowWrapper" focus-row-control selectable> + [[searchResultText]] + </div> + </div> + </template> + <script src="os_search_result_row.js"></script> +</dom-module>
diff --git a/chrome/browser/resources/settings/chromeos/os_settings_search_box/os_search_result_row.js b/chrome/browser/resources/settings/chromeos/os_settings_search_box/os_search_result_row.js new file mode 100644 index 0000000..da6e8c3 --- /dev/null +++ b/chrome/browser/resources/settings/chromeos/os_settings_search_box/os_search_result_row.js
@@ -0,0 +1,24 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview 'os-search-result-row' is the container for one search result. + */ + +Polymer({ + is: 'os-search-result-row', + + behaviors: [cr.ui.FocusRowBehavior], + + properties: { + // Whether the search result row is selected. + selected: { + type: Boolean, + reflectToAttribute: true, + }, + + // String to be displayed as a result in the UI. + searchResultText: String, + }, +});
diff --git a/chrome/browser/resources/settings/chromeos/os_settings_search_box/os_settings_search_box.html b/chrome/browser/resources/settings/chromeos/os_settings_search_box/os_settings_search_box.html new file mode 100644 index 0000000..703b92d --- /dev/null +++ b/chrome/browser/resources/settings/chromeos/os_settings_search_box/os_settings_search_box.html
@@ -0,0 +1,78 @@ +<link rel="import" href="chrome://resources/html/polymer.html"> + +<link rel="import" href="chrome://resources/cr_elements/cr_toolbar/cr_toolbar_search_field.html"> +<link rel="import" href="chrome://resources/html/assert.html"> +<link rel="import" href="chrome://resources/html/cr/ui/focus_row.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/iron-dropdown/iron-dropdown.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/iron-list/iron-list.html"> +<link rel="import" href="os_search_result_row.html"> +<link rel="import" href="../metrics_recorder.html"> +<link rel="import" href="../../settings_shared_css.html"> + +<dom-module id="os-settings-search-box"> + <template> + <style include="settings-shared"> + :host { + display: flex; + flex-basis: var(--cr-toolbar-field-width, 680px); + transition: width 150ms cubic-bezier(0.4, 0, 0.2, 1); + } + + /* Only search icon is visible in this mode */ + :host([narrow]:not([showing-search])) { + justify-content: flex-end; + } + + :host([narrow][showing-search]) { + flex-basis: 100%; + } + + :host([narrow]) iron-dropdown { + left: 0; + right: 0; + } + + iron-dropdown [slot='dropdown-content'] { + background-color: var(--cr-card-background-color); + box-shadow: var(--cr-card-shadow); + display: table; + } + + :host([narrow]) iron-dropdown [slot='dropdown-content'] { + width: 100%; + } + + :host(:not([narrow])) iron-dropdown [slot='dropdown-content'] { + width: var(--cr-toolbar-field-width, 680px); + } + </style> + <cr-toolbar-search-field id="search" narrow="[[narrow]]" + label="$i18n{searchPrompt}" clear-label="$i18n{clearSearch}" + showing-search="{{showingSearch}}" spinner-active="[[spinnerActive]]"> + </cr-toolbar-search-field> + <iron-dropdown id="searchResults" opened="[[shouldShowDropdown_]]" + no-overlap allow-outside-scroll no-cancel-on-outside-click> + <!-- As part of iron-dropdown's behavior, the slot 'dropdown-content' is + hidden until iron-dropdown's opened attribute is set true, or when + iron-dropdown's open() is called on the JS side. --> + <iron-list id="searchResultList" slot="dropdown-content" + selection-enabled items="[[searchResults_]]" + selected-item="{{selectedItem}}"> + <!-- TODO(crbug/1056909): Use template dom-if if searchResults_ is + empty, show 'No Results' UI --> + <template> + <os-search-result-row actionable search-result-text="[[item]]" + selected="[[isItemSelected_(item, selectedItem)]]" + tabindex$="[[getRowTabIndex_(item, selectedItem)]]" + iron-list-tab-index$="[[getRowTabIndex_(item, selectedItem)]]" + last-focused="{{lastFocused_}}" + list-blurred="{{listBlurred_}}" + focus-row-index="[[index]]" + first$="[[!index]]"> + </os-search-result-row> + </template> + </iron-list> + </iron-dropdown> + </template> + <script src="os_settings_search_box.js"></script> +</dom-module>
diff --git a/chrome/browser/resources/settings/chromeos/os_settings_search_box/os_settings_search_box.js b/chrome/browser/resources/settings/chromeos/os_settings_search_box/os_settings_search_box.js new file mode 100644 index 0000000..8662679 --- /dev/null +++ b/chrome/browser/resources/settings/chromeos/os_settings_search_box/os_settings_search_box.js
@@ -0,0 +1,299 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +(function() { +'use strict'; + +/** + * @fileoverview 'os-settings-search-box' is the container for the search input + * and settings search results. + */ + +/** + * Fake function to simulate async SettingsSearchHandler Search(). + * TODO(crbug/1056909): Remove once Settings Search Handler mojo API is ready. + * @param {string} query The query used to fetch results. + * @return {!Promise<!Array<string>>} A promise that will resolve with an array + * of search results. + */ +function fakeSettingsSearchHandlerSearch(query) { + /** + * @param {number} min The lower bound integer. + * @param {number} max The upper bound integer. + * @return {number} A random integer between min and max inclusive. + */ + function getRandomInt(min, max) { + min = Math.ceil(min); + max = Math.floor(max); + return Math.floor(Math.random() * (max - min + 1)) + min; + } + + const fakeRandomResults = [ + 'bluetooth', 'wifi', 'language', 'people', 'personalization', 'security', + 'touchpad', 'keyboard', 'passcode' + ]; + fakeRandomResults.sort(() => Math.random() - 0.5); + return new Promise(resolve => { + setTimeout(() => { + resolve(fakeRandomResults.splice( + 0, getRandomInt(1, fakeRandomResults.length - 1))); + }, 0); + }); +} + +Polymer({ + is: 'os-settings-search-box', + + properties: { + // True when the toolbar is displaying in narrow mode. + // TODO(hsuregan): Change narrow to isNarrow here and associated elements. + narrow: { + type: Boolean, + reflectToAttribute: true, + }, + + // Controls whether the search field is shown. + showingSearch: { + type: Boolean, + value: false, + notify: true, + reflectToAttribute: true, + }, + + // Value is proxied through to cr-toolbar-search-field. When true, + // the search field will show a processing spinner. + spinnerActive: Boolean, + + // The currently selected search result associated with a + // <os-search-result-row>. This property is bound to <iron-list>. + // Note that when a item is selected, it's associated <os-search-result-row> + // is not focused() at the same time unless it is explicitly clicked/tapped. + selectedItem: { + // TODO(crbug/1056909): Change the type from String to Mojo result type. + type: String, + notify: true, + }, + + /** + * Passed into <iron-list>, one of which is always the selectedItem. + * @private {!Array<string>} + */ + searchResults_: { + type: Array, + notify: true, + observer: 'selectFirstRow_', + }, + + /** @private */ + shouldShowDropdown_: { + type: Boolean, + value: false, + computed: 'computeShouldShowDropdown_(searchResults_)', + }, + + /** + * Used by FocusRowBehavior to track the last focused element inside a + * <os-search-result-row> with the attribute 'focus-row-control'. + * @private {HTMLElement} + */ + lastFocused_: Object, + + /** + * Used by FocusRowBehavior to track if the list has been blurred. + * @private + */ + listBlurred_: Boolean, + }, + + /** + * Mojo OS Settings Search handler used to fetch search results. + * TODO(crbug/1056909): Set in ready() when Mojo bindings are ready or + * eliminate altogether along with fake JS file. + * @private {*} + */ + searchHandler_: undefined, + + listeners: { + 'blur': 'onBlur_', + 'keydown': 'onKeyDown_', + 'search-changed': 'fetchSearchResults_', + }, + + /** @private */ + attached() { + const toolbarSearchField = this.$.search; + const searchInput = toolbarSearchField.getSearchInput(); + searchInput.addEventListener( + 'focus', this.onSearchInputFocused_.bind(this)); + }, + + /** + * @param {*} searchHandler + */ + setSearchHandlerForTesting(searchHandler) { + this.searchHandler_ = searchHandler; + }, + + /** + * @return {boolean} + * @private + */ + computeShouldShowDropdown_() { + return this.searchResults_.length !== 0; + }, + + /** @private */ + fetchSearchResults_() { + const query = this.$.search.getSearchInput().value; + if (query === '') { + this.searchResults_ = []; + return; + } + + this.spinnerActive = true; + + if (!this.searchHandler_) { + // TODO(crbug/1056909): Remove block when mojo interface is ready. + fakeSettingsSearchHandlerSearch(query).then(results => { + this.onSearchResultsReceived_(query, results); + }); + return; + } + + this.searchHandler_.search(query).then(results => { + this.onSearchResultsReceived_(query, results); + }); + }, + + /** + * Updates search results UI when settings search results are fetched. + * @param {string} query The string used to find search results. + * @param {!Array<string>} results Array of search results. + * @private + */ + onSearchResultsReceived_(query, results) { + if (query !== this.$.search.getSearchInput().value) { + // Received search results are invalid as the query has since changed. + return; + } + + this.spinnerActive = false; + this.lastFocused_ = null; + this.searchResults_ = results; + settings.recordSearch(); + }, + + /** @private */ + onBlur_() { + // The user has clicked a region outside the search box or the input has + // been blurred; close the dropdown regardless if there are searchResults_. + this.$.searchResults.close(); + }, + + /** @private */ + onSearchInputFocused_() { + this.lastFocused_ = null; + + if (this.shouldShowDropdown_) { + // Restore previous results instead of re-fetching. + this.$.searchResults.open(); + return; + } + + this.fetchSearchResults_(); + }, + + /** + * @param {string} item The search result item. + * @return {boolean} True if the item is selected. + * @private + */ + isItemSelected_(item) { + return this.searchResults_.indexOf(item) === + this.searchResults_.indexOf(this.selectedItem); + }, + + /** + * Returns the correct tab index since <iron-list>'s default tabIndex property + * does not automatically add selectedItem's <os-search-result-row> to the + * default navigation flow, unless the user explicitly clicks on the row. + * @param {string} item The search result item. + * @return {number} A 0 if the row should be in the navigation flow, or a -1 + * if the row should not be in the navigation flow. + * @private + */ + getRowTabIndex_(item) { + return this.isItemSelected_(item) ? 0 : -1; + }, + + /** @private */ + selectFirstRow_() { + if (!this.shouldShowDropdown_) { + return; + } + + this.selectedItem = this.searchResults_[0]; + }, + + /** + * @param {string} key The string associated with a key. + * @private + */ + selectRowViaKeys_(key) { + assert(key === 'ArrowDown' || key === 'ArrowUp' || key === 'Tab'); + + assert(!!this.selectedItem, 'There should be a selected item already.'); + + // Select the new item. + const selectedRowIndex = this.searchResults_.indexOf(this.selectedItem); + const numRows = this.searchResults_.length; + const delta = key === 'ArrowUp' ? -1 : 1; + const indexOfNewRow = (numRows + selectedRowIndex + delta) % numRows; + this.selectedItem = this.searchResults_[indexOfNewRow]; + + // If a row is focused, ensure it is the selectedResult's row. + if (this.lastFocused_) { + const rowEls = Array.from( + this.$.searchResultList.querySelectorAll('os-search-result-row')); + // Calling focus() on a <os-search-result-row> focuses the element within + // containing the attribute 'focus-row-control'. + rowEls[indexOfNewRow].focus(); + } + }, + + /** + * Keydown handler to specify how enter-key, arrow-up key, and arrow-down-key + * interacts with search results in the dropdown. + * @param {!KeyboardEvent} e + * @private + */ + onKeyDown_(e) { + if (!this.shouldShowDropdown_) { + // No action should be taken if there are no search results. + return; + } + + if (e.key === 'Enter') { + // TODO(crbug/1056909): Take action on selected row. + return; + } + + if (e.key === 'Tab') { + if (this.lastFocused_) { + // Prevent continuous tabbing from leaving search result + e.preventDefault(); + this.selectRowViaKeys_(e.key); + } + return; + } + + if (e.key === 'ArrowUp' || e.key === 'ArrowDown') { + // Do not impact the position of <cr-toolbar-search-field>'s caret. + e.preventDefault(); + this.selectRowViaKeys_(e.key); + return; + } + }, +}); +})();
diff --git a/chrome/browser/resources/settings/chromeos/os_settings_ui/os_settings_ui.html b/chrome/browser/resources/settings/chromeos/os_settings_ui/os_settings_ui.html index a346ea4..f25f9e2 100644 --- a/chrome/browser/resources/settings/chromeos/os_settings_ui/os_settings_ui.html +++ b/chrome/browser/resources/settings/chromeos/os_settings_ui/os_settings_ui.html
@@ -41,7 +41,9 @@ @apply --layout-center; /* TODO(hsuregan): update for dark mode when needed. */ min-height: 56px; - z-index: 2; + /* Needs to be higher than #cr-container-show-top's z-index so that the + * new settings search dropdown is not struck through by the shadow. */ + z-index: 3; } cr-drawer {
diff --git a/chrome/browser/resources/settings/chromeos/os_settings_ui/os_settings_ui.js b/chrome/browser/resources/settings/chromeos/os_settings_ui/os_settings_ui.js index 7f92553..0d7cf8f 100644 --- a/chrome/browser/resources/settings/chromeos/os_settings_ui/os_settings_ui.js +++ b/chrome/browser/resources/settings/chromeos/os_settings_ui/os_settings_ui.js
@@ -248,6 +248,12 @@ this.showDropShadows(); } + if (loadTimeData.getBoolean('newOsSettingsSearch')) { + // TODO(crbug/1056909): Remove when new os settings search complete. This + // block prevents the old settings search code from being executed. + return; + } + const urlSearchQuery = settings.Router.getInstance().getQueryParameters().get('search') || ''; if (urlSearchQuery == this.lastSearchQuery_) { @@ -258,7 +264,16 @@ const toolbar = /** @type {!OsToolbarElement} */ (this.$$('os-toolbar')); const searchField = - /** @type {CrToolbarSearchFieldElement} */ (toolbar.getSearchField()); + /** @type {?CrToolbarSearchFieldElement} */ (toolbar.getSearchField()); + + if (!searchField) { + // TODO(crbug/1056909): Remove this and surrounding code when new os + // settings search complete. If the search field has not been rendered + // yet, do not continue. crbug/1056909 changes the toolbar search field to + // an optional value, so the element is not attached to the DOM the first + // time this runs when the new OS Settings search flag is not flipped on. + return; + } // If the search was initiated by directly entering a search URL, need to // sync the URL parameter to the textbox. @@ -303,10 +318,14 @@ /** * Handles the 'search-changed' event fired from the toolbar. + * TODO(crbug/1056909): Remove when new settings search complete. * @param {!Event} e * @private */ onSearchChanged_(e) { + if (loadTimeData.getBoolean('newOsSettingsSearch')) { + return; + } const query = e.detail; settings.Router.getInstance().navigateTo( settings.routes.BASIC,
diff --git a/chrome/browser/resources/settings/chromeos/os_toolbar/BUILD.gn b/chrome/browser/resources/settings/chromeos/os_toolbar/BUILD.gn index 9c449624..eb6484e5 100644 --- a/chrome/browser/resources/settings/chromeos/os_toolbar/BUILD.gn +++ b/chrome/browser/resources/settings/chromeos/os_toolbar/BUILD.gn
@@ -9,6 +9,8 @@ } js_library("os_toolbar") { - deps = - [ "//ui/webui/resources/cr_elements/cr_toolbar:cr_toolbar_search_field" ] + deps = [ + "../os_settings_search_box", + "//ui/webui/resources/cr_elements/cr_toolbar:cr_toolbar_search_field", + ] }
diff --git a/chrome/browser/resources/settings/chromeos/os_toolbar/os_toolbar.html b/chrome/browser/resources/settings/chromeos/os_toolbar/os_toolbar.html index 09abb92a..5cf35bb 100644 --- a/chrome/browser/resources/settings/chromeos/os_toolbar/os_toolbar.html +++ b/chrome/browser/resources/settings/chromeos/os_toolbar/os_toolbar.html
@@ -6,7 +6,9 @@ <link rel="import" href="chrome://resources/cr_elements/hidden_style_css.html"> <link rel="import" href="chrome://resources/cr_elements/icons.html"> <link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html"> +<link rel="import" href="chrome://resources/html/assert.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-media-query/iron-media-query.html"> +<link rel="import" href="../os_settings_search_box/os_settings_search_box.html"> <dom-module id="os-toolbar"> <template> @@ -89,6 +91,10 @@ flex-basis: var(--settings-main-basis); } + :host([narrow][showing-search_]) #rightContent { + display: none; + } + :host(:not([narrow])) #rightContent { flex: 1 1 0; text-align: end; @@ -108,11 +114,18 @@ </div> <div id="centeredContent" hidden$="[[!showSearch]]"> - <cr-toolbar-search-field id="search" narrow="[[narrow]]" - label="$i18n{searchPrompt}" clear-label="$i18n{clearSearch}" - spinner-active="[[spinnerActive]]" - showing-search="{{showingSearch_}}"> - </cr-toolbar-search-field> + <template is="dom-if" if="[[!newOsSettingsSearch_]]"> + <cr-toolbar-search-field id="search" narrow="[[narrow]]" + label="$i18n{searchPrompt}" clear-label="$i18n{clearSearch}" + spinner-active="[[spinnerActive]]" + showing-search="{{showingSearch_}}"> + </cr-toolbar-search-field> + </template> + <template is="dom-if" if="[[newOsSettingsSearch_]]"> + <os-settings-search-box id="searchBox" narrow="[[narrow]]" + showing-search="{{showingSearch_}}"> + </os-settings-search-box> + </template> <iron-media-query query="(max-width: [[narrowThreshold]]px)" query-matches="{{narrow}}"> </iron-media-query>
diff --git a/chrome/browser/resources/settings/chromeos/os_toolbar/os_toolbar.js b/chrome/browser/resources/settings/chromeos/os_toolbar/os_toolbar.js index 5e0a157a..6ca377a 100644 --- a/chrome/browser/resources/settings/chromeos/os_toolbar/os_toolbar.js +++ b/chrome/browser/resources/settings/chromeos/os_toolbar/os_toolbar.js
@@ -39,11 +39,25 @@ type: Boolean, reflectToAttribute: true, }, + + /** @private */ + newOsSettingsSearch_: { + type: Boolean, + value() { + return loadTimeData.getBoolean('newOsSettingsSearch'); + }, + readOnly: true, + }, }, - /** @return {!CrToolbarSearchFieldElement} */ + /** @return {?CrToolbarSearchFieldElement} */ getSearchField() { - return this.$.search; + if (this.newOsSettingsSearch_) { + assertNotReached( + 'New OS Search should not be using OsToolbar.getSearchField()'); + } + return /** @type {?CrToolbarSearchFieldElement} */ ( + this.$$('cr-toolbar-search-field')); }, /** @private */
diff --git a/chrome/browser/resources/settings/global_scroll_target_behavior.js b/chrome/browser/resources/settings/global_scroll_target_behavior.js index 29ec449..f398c27b 100644 --- a/chrome/browser/resources/settings/global_scroll_target_behavior.js +++ b/chrome/browser/resources/settings/global_scroll_target_behavior.js
@@ -21,7 +21,7 @@ let scrollTargetResolver = new PromiseResolver(); /** @polymerBehavior */ - const GlobalScrollTargetBehaviorImpl = { + /* #export */ const GlobalScrollTargetBehaviorImpl = { properties: { /** * Read only property for the scroll target.
diff --git a/chrome/browser/resources/settings/lazy_load.js b/chrome/browser/resources/settings/lazy_load.js index c798fe1..0f9aabe2 100644 --- a/chrome/browser/resources/settings/lazy_load.js +++ b/chrome/browser/resources/settings/lazy_load.js
@@ -13,20 +13,20 @@ // TODO(https://crbug.com/1026426): Uncomment these imports once the pages have // been migrated to Polymer 3. // import './privacy_page/cookies_page.m.js'; -// import './privacy_page/security_keys_subpage.m.js'; +import './privacy_page/security_keys_subpage.m.js'; // import './privacy_page/security_page.m.js'; -// import './site_settings/all_sites.m.js'; +import './site_settings/all_sites.m.js'; import './site_settings/site_data_details_subpage.m.js'; // import './site_settings_page/site_settings_page.m.js'; import './site_settings/category_default_setting.m.js'; import './site_settings/category_setting_exceptions.m.js'; import './site_settings/chooser_exception_list.m.js'; -// import './site_settings/media_picker.m.js'; -// import './site_settings/pdf_documents.m.js'; -// import './site_settings/protocol_handlers.m.js'; -// import './site_settings/site_data.m.js'; +import './site_settings/media_picker.m.js'; +import './site_settings/pdf_documents.m.js'; +import './site_settings/protocol_handlers.m.js'; +import './site_settings/site_data.m.js'; import './site_settings/site_details.m.js'; -// import './site_settings/zoom_levels.m.js'; +import './site_settings/zoom_levels.m.js'; // <if expr="not chromeos"> import './people_page/import_data_dialog.m.js'; @@ -94,6 +94,11 @@ export {kControlledByLookup} from './site_settings/site_settings_behavior.m.js'; export {LocalDataBrowserProxyImpl} from './site_settings/local_data_browser_proxy.m.js'; export {ContentSettingProvider,SiteSettingsPrefsBrowserProxyImpl} from './site_settings/site_settings_prefs_browser_proxy.m.js'; +export {SecurityKeysResetBrowserProxyImpl, SecurityKeysPINBrowserProxyImpl, SecurityKeysCredentialBrowserProxyImpl, SecurityKeysBioEnrollProxyImpl, SampleStatus, Ctap2Status} from './privacy_page/security_keys_browser_proxy.m.js'; +export {ResetDialogPage} from './privacy_page/security_keys_reset_dialog.m.js'; +export {SetPINDialogPage} from './privacy_page/security_keys_set_pin_dialog.m.js'; +export {CredentialManagementDialogPage} from './privacy_page/security_keys_credential_management_dialog.m.js'; +export {BioEnrollDialogPage} from './privacy_page/security_keys_bio_enroll_dialog.m.js'; export {WebsiteUsageBrowserProxyImpl} from './site_settings/website_usage_browser_proxy.m.js'; // <if expr="not chromeos">
diff --git a/chrome/browser/resources/settings/os_settings_resources.grd b/chrome/browser/resources/settings/os_settings_resources.grd index 819fad9..b28b758e 100644 --- a/chrome/browser/resources/settings/os_settings_resources.grd +++ b/chrome/browser/resources/settings/os_settings_resources.grd
@@ -617,6 +617,18 @@ <structure name="IDR_OS_SETTINGS_LANGUAGES_MANAGE_INPUT_METHODS_PAGE_JS" file="chromeos/os_languages_page/manage_input_methods_page.js" type="chrome_html" /> + <structure name="IDR_OS_SETTINGS_OS_SEARCH_RESULT_ROW_JS" + file="chromeos/os_settings_search_box/os_search_result_row.js" + type="chrome_html" /> + <structure name="IDR_OS_SETTINGS_OS_SEARCH_RESULT_ROW_HTML" + file="chromeos/os_settings_search_box/os_search_result_row.html" + type="chrome_html" /> + <structure name="IDR_OS_SETTINGS_OS_SETTINGS_SEARCH_BOX_JS" + file="chromeos/os_settings_search_box/os_settings_search_box.js" + type="chrome_html" /> + <structure name="IDR_OS_SETTINGS_OS_SETTINGS_SEARCH_BOX_HTML" + file="chromeos/os_settings_search_box/os_settings_search_box.html" + type="chrome_html" /> <structure name="IDR_OS_SETTINGS_OS_TOOLBAR_JS" file="chromeos/os_toolbar/os_toolbar.js" type="chrome_html" />
diff --git a/chrome/browser/resources/settings/privacy_page/BUILD.gn b/chrome/browser/resources/settings/privacy_page/BUILD.gn index 17e24ff..6fb6aa6d 100644 --- a/chrome/browser/resources/settings/privacy_page/BUILD.gn +++ b/chrome/browser/resources/settings/privacy_page/BUILD.gn
@@ -211,14 +211,14 @@ #":privacy_page.m", ":privacy_page_browser_proxy.m", + ":security_keys_bio_enroll_dialog.m", + ":security_keys_browser_proxy.m", + ":security_keys_credential_management_dialog.m", + ":security_keys_pin_field.m", + ":security_keys_reset_dialog.m", + ":security_keys_set_pin_dialog.m", + ":security_keys_subpage.m", - #":security_keys_bio_enroll_dialog.m", - #":security_keys_browser_proxy.m", - #":security_keys_credential_management_dialog.m", - #":security_keys_pin_field.m", - #":security_keys_reset_dialog.m", - #":security_keys_set_pin_dialog.m", - #":security_keys_subpage.m", #":security_page.m", ] } @@ -264,23 +264,33 @@ js_library("security_keys_bio_enroll_dialog.m") { sources = [ "$root_gen_dir/chrome/browser/resources/settings/privacy_page/security_keys_bio_enroll_dialog.m.js" ] deps = [ - # TODO: Fill those in. + ":security_keys_browser_proxy.m", + ":security_keys_pin_field.m", + "//third_party/polymer/v3_0/components-chromium/iron-a11y-announcer", + "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", + "//ui/webui/resources/cr_elements/cr_fingerprint:cr_fingerprint_progress_arc.m", + "//ui/webui/resources/js:assert.m", + "//ui/webui/resources/js:i18n_behavior.m", + "//ui/webui/resources/js:web_ui_listener_behavior.m", ] extra_deps = [ ":security_keys_bio_enroll_dialog_module" ] } js_library("security_keys_browser_proxy.m") { sources = [ "$root_gen_dir/chrome/browser/resources/settings/privacy_page/security_keys_browser_proxy.m.js" ] - deps = [ - # TODO: Fill those in. - ] + deps = [ "//ui/webui/resources/js:cr.m" ] extra_deps = [ ":modulize" ] } js_library("security_keys_credential_management_dialog.m") { sources = [ "$root_gen_dir/chrome/browser/resources/settings/privacy_page/security_keys_credential_management_dialog.m.js" ] deps = [ - # TODO: Fill those in. + ":security_keys_browser_proxy.m", + ":security_keys_pin_field.m", + "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", + "//ui/webui/resources/js:assert.m", + "//ui/webui/resources/js:i18n_behavior.m", + "//ui/webui/resources/js:web_ui_listener_behavior.m", ] extra_deps = [ ":security_keys_credential_management_dialog_module" ] } @@ -288,7 +298,9 @@ js_library("security_keys_pin_field.m") { sources = [ "$root_gen_dir/chrome/browser/resources/settings/privacy_page/security_keys_pin_field.m.js" ] deps = [ - # TODO: Fill those in. + "//third_party/polymer/v3_0/components-chromium/iron-a11y-announcer", + "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", + "//ui/webui/resources/js:i18n_behavior.m", ] extra_deps = [ ":security_keys_pin_field_module" ] } @@ -296,7 +308,9 @@ js_library("security_keys_reset_dialog.m") { sources = [ "$root_gen_dir/chrome/browser/resources/settings/privacy_page/security_keys_reset_dialog.m.js" ] deps = [ - # TODO: Fill those in. + ":security_keys_browser_proxy.m", + "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", + "//ui/webui/resources/js:i18n_behavior.m", ] extra_deps = [ ":security_keys_reset_dialog_module" ] } @@ -304,7 +318,10 @@ js_library("security_keys_set_pin_dialog.m") { sources = [ "$root_gen_dir/chrome/browser/resources/settings/privacy_page/security_keys_set_pin_dialog.m.js" ] deps = [ - # TODO: Fill those in. + ":security_keys_browser_proxy.m", + "//third_party/polymer/v3_0/components-chromium/iron-a11y-announcer", + "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", + "//ui/webui/resources/js:i18n_behavior.m", ] extra_deps = [ ":security_keys_set_pin_dialog_module" ] } @@ -312,7 +329,9 @@ js_library("security_keys_subpage.m") { sources = [ "$root_gen_dir/chrome/browser/resources/settings/privacy_page/security_keys_subpage.m.js" ] deps = [ - # TODO: Fill those in. + "..:i18n_setup.m", + "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", + "//ui/webui/resources/js:assert.m", ] extra_deps = [ ":security_keys_subpage_module" ] } @@ -369,36 +388,61 @@ js_file = "security_keys_bio_enroll_dialog.js" html_file = "security_keys_bio_enroll_dialog.html" html_type = "dom-module" + namespace_rewrites = settings_namespace_rewrites + auto_imports = settings_auto_imports + [ + "chrome/browser/resources/settings/privacy_page/security_keys_browser_proxy.html|SecurityKeysBioEnrollProxy,SecurityKeysBioEnrollProxyImpl,Ctap2Status,SampleStatus,Enrollment,EnrollmentResponse,SampleResponse,", + "ui/webui/resources/html/assert.html|assert,assertNotReached", + "ui/webui/resources/html/polymer.html|afterNextRender,html,Polymer", + ] } polymer_modulizer("security_keys_credential_management_dialog") { js_file = "security_keys_credential_management_dialog.js" html_file = "security_keys_credential_management_dialog.html" html_type = "dom-module" + namespace_rewrites = settings_namespace_rewrites + auto_imports = settings_auto_imports + [ + "chrome/browser/resources/settings/privacy_page/security_keys_browser_proxy.html|SecurityKeysCredentialBrowserProxy,SecurityKeysCredentialBrowserProxyImpl,Credential", + "ui/webui/resources/html/assert.html|assert,assertNotReached", + ] } polymer_modulizer("security_keys_pin_field") { js_file = "security_keys_pin_field.js" html_file = "security_keys_pin_field.html" html_type = "dom-module" + namespace_rewrites = settings_namespace_rewrites + auto_imports = + settings_auto_imports + + [ "ui/webui/resources/html/polymer.html|afterNextRender,html,Polymer" ] } polymer_modulizer("security_keys_reset_dialog") { js_file = "security_keys_reset_dialog.js" html_file = "security_keys_reset_dialog.html" html_type = "dom-module" + namespace_rewrites = settings_namespace_rewrites + auto_imports = settings_auto_imports + [ "chrome/browser/resources/settings/privacy_page/security_keys_browser_proxy.html|SecurityKeysResetBrowserProxy,SecurityKeysResetBrowserProxyImpl" ] } polymer_modulizer("security_keys_set_pin_dialog") { js_file = "security_keys_set_pin_dialog.js" html_file = "security_keys_set_pin_dialog.html" html_type = "dom-module" + namespace_rewrites = settings_namespace_rewrites + auto_imports = settings_auto_imports + [ + "chrome/browser/resources/settings/privacy_page/security_keys_browser_proxy.html|SecurityKeysPINBrowserProxy,SecurityKeysPINBrowserProxyImpl", + "ui/webui/resources/html/polymer.html|afterNextRender,html,Polymer", + ] } polymer_modulizer("security_keys_subpage") { js_file = "security_keys_subpage.js" html_file = "security_keys_subpage.html" html_type = "dom-module" + namespace_rewrites = settings_namespace_rewrites + auto_imports = + settings_auto_imports + [ "ui/webui/resources/html/assert.html|assert" ] } polymer_modulizer("security_page") {
diff --git a/chrome/browser/resources/settings/privacy_page/security_keys_bio_enroll_dialog.html b/chrome/browser/resources/settings/privacy_page/security_keys_bio_enroll_dialog.html index d46583d..76126f0 100644 --- a/chrome/browser/resources/settings/privacy_page/security_keys_bio_enroll_dialog.html +++ b/chrome/browser/resources/settings/privacy_page/security_keys_bio_enroll_dialog.html
@@ -6,6 +6,7 @@ <link rel="import" href="chrome://resources/cr_elements/cr_fingerprint/cr_fingerprint_progress_arc.html"> <link rel="import" href="chrome://resources/cr_elements/cr_icon_button/cr_icon_button.html"> <link rel="import" href="chrome://resources/html/i18n_behavior.html"> +<link rel="import" href="chrome://resources/html/web_ui_listener_behavior.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-a11y-announcer/iron-a11y-announcer.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-list/iron-list.html">
diff --git a/chrome/browser/resources/settings/privacy_page/security_keys_bio_enroll_dialog.js b/chrome/browser/resources/settings/privacy_page/security_keys_bio_enroll_dialog.js index 629a596..691bdfc 100644 --- a/chrome/browser/resources/settings/privacy_page/security_keys_bio_enroll_dialog.js +++ b/chrome/browser/resources/settings/privacy_page/security_keys_bio_enroll_dialog.js
@@ -10,7 +10,7 @@ cr.define('settings', function() { /** @enum {string} */ - const BioEnrollDialogPage = { + /* #export */ const BioEnrollDialogPage = { INITIAL: 'initial', PIN_PROMPT: 'pinPrompt', ENROLLMENTS: 'enrollments', @@ -69,7 +69,7 @@ recentEnrollmentName_: String, }, - /** @private {?settings.SecurityKeysBioEnrollProxyImpl} */ + /** @private {?settings.SecurityKeysBioEnrollProxy} */ browserProxy_: null, /** @private {number} */ @@ -111,7 +111,8 @@ // Disable the confirm button to prevent concurrent submissions. this.confirmButtonDisabled_ = true; - this.$.pin.trySubmit(pin => this.browserProxy_.providePIN(pin)) + /** @type {!SettingsSecurityKeysPinFieldElement} */ (this.$.pin) + .trySubmit(pin => this.browserProxy_.providePIN(pin)) .then( () => { // Leave confirm button disabled while enumerating fingerprints. @@ -186,7 +187,7 @@ assert(this.dialogPage_ == BioEnrollDialogPage.ENROLLMENTS); this.maxSamples_ = -1; // Reset maxSamples_ before enrolling starts. - this.$.arc.reset(); + /** @type {!CrFingerprintProgressArcElement} */ (this.$.arc).reset(); this.progressArcLabel_ = this.i18n('securityKeysBioEnrollmentEnrollingLabel'); @@ -221,10 +222,12 @@ this.maxSamples_ = response.remaining + 1; } - this.$.arc.setProgress( - 100 * (this.maxSamples_ - response.remaining - 1) / this.maxSamples_, - 100 * (this.maxSamples_ - response.remaining) / this.maxSamples_, - false); + /** @type {!CrFingerprintProgressArcElement} */ (this.$.arc) + .setProgress( + 100 * (this.maxSamples_ - response.remaining - 1) / + this.maxSamples_, + 100 * (this.maxSamples_ - response.remaining) / this.maxSamples_, + false); }, /** @@ -243,8 +246,9 @@ } this.maxSamples_ = Math.max(this.maxSamples_, 1); - this.$.arc.setProgress( - 100 * (this.maxSamples_ - 1) / this.maxSamples_, 100, true); + /** @type {!CrFingerprintProgressArcElement} */ (this.$.arc) + .setProgress( + 100 * (this.maxSamples_ - 1) / this.maxSamples_, 100, true); assert(response.enrollment); this.recentEnrollmentId_ = response.enrollment.id;
diff --git a/chrome/browser/resources/settings/privacy_page/security_keys_browser_proxy.js b/chrome/browser/resources/settings/privacy_page/security_keys_browser_proxy.js index a7fe480..fffeab5 100644 --- a/chrome/browser/resources/settings/privacy_page/security_keys_browser_proxy.js +++ b/chrome/browser/resources/settings/privacy_page/security_keys_browser_proxy.js
@@ -2,13 +2,17 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// clang-format off +// #import {addSingletonGetter, sendWithPromise} from 'chrome://resources/js/cr.m.js'; +// clang-format on + cr.define('settings', function() { /** * Ctap2Status contains a subset of CTAP2 status codes. See * device::CtapDeviceResponseCode for the full list. * @enum {number} */ - const Ctap2Status = { + /* #export */ const Ctap2Status = { OK: 0x0, ERR_INVALID_OPTION: 0x2C, ERR_KEEPALIVE_CANCEL: 0x2D, @@ -34,7 +38,7 @@ * userDisplayName: string}} * @see chrome/browser/ui/webui/settings/settings_security_key_handler.cc */ - let Credential; + /* #export */ let Credential; /** * SampleStatus is the result for reading an individual sample ("touch") @@ -42,7 +46,7 @@ * lastEnrollSampleStatus enum defined in the CTAP spec. * @enum {number} */ - const SampleStatus = { + /* #export */ const SampleStatus = { OK: 0x0, }; @@ -54,7 +58,7 @@ * remaining: number}} * @see chrome/browser/ui/webui/settings/settings_security_key_handler.cc */ - let SampleResponse; + /* #export */ let SampleResponse; /** * EnrollmentResponse is the final response to an enrollment suboperation, @@ -63,7 +67,7 @@ * enrollment: ?settings.Enrollment}} * @see chrome/browser/ui/webui/settings/settings_security_key_handler.cc */ - let EnrollmentResponse; + /* #export */ let EnrollmentResponse; /** * Enrollment represents a valid fingerprint template stored on a security @@ -73,10 +77,10 @@ * id: string}} * @see chrome/browser/ui/webui/settings/settings_security_key_handler.cc */ - let Enrollment; + /* #export */ let Enrollment; /** @interface */ - class SecurityKeysPINBrowserProxy { + /* #export */ class SecurityKeysPINBrowserProxy { /** * Starts a PIN set/change operation by flashing all security keys. Resolves * with a pair of numbers. The first is one if the process has immediately @@ -103,7 +107,7 @@ } /** @interface */ - class SecurityKeysCredentialBrowserProxy { + /* #export */ class SecurityKeysCredentialBrowserProxy { /** * Starts a credential management operation. * @@ -147,7 +151,7 @@ } /** @interface */ - class SecurityKeysResetBrowserProxy { + /* #export */ class SecurityKeysResetBrowserProxy { /** * Starts a reset operation by flashing all security keys and sending a * reset command to the one that the user activates. Resolves with a CTAP @@ -167,7 +171,7 @@ } /** @interface */ - class SecurityKeysBioEnrollProxy { + /* #export */ class SecurityKeysBioEnrollProxy { /** * Starts a biometric enrollment operation. * @@ -247,7 +251,7 @@ } /** @implements {settings.SecurityKeysPINBrowserProxy} */ - class SecurityKeysPINBrowserProxyImpl { + /* #export */ class SecurityKeysPINBrowserProxyImpl { /** @override */ startSetPIN() { return cr.sendWithPromise('securityKeyStartSetPIN'); @@ -265,7 +269,7 @@ } /** @implements {settings.SecurityKeysCredentialBrowserProxy} */ - class SecurityKeysCredentialBrowserProxyImpl { + /* #export */ class SecurityKeysCredentialBrowserProxyImpl { /** @override */ startCredentialManagement() { return cr.sendWithPromise('securityKeyCredentialManagementStart'); @@ -293,7 +297,7 @@ } /** @implements {settings.SecurityKeysResetBrowserProxy} */ - class SecurityKeysResetBrowserProxyImpl { + /* #export */ class SecurityKeysResetBrowserProxyImpl { /** @override */ reset() { return cr.sendWithPromise('securityKeyReset'); @@ -311,7 +315,7 @@ } /** @implements {settings.SecurityKeysBioEnrollProxy} */ - class SecurityKeysBioEnrollProxyImpl { + /* #export */ class SecurityKeysBioEnrollProxyImpl { /** @override */ startBioEnroll() { return cr.sendWithPromise('securityKeyBioEnrollStart');
diff --git a/chrome/browser/resources/settings/privacy_page/security_keys_credential_management_dialog.js b/chrome/browser/resources/settings/privacy_page/security_keys_credential_management_dialog.js index ddf5532..19eeffdbc 100644 --- a/chrome/browser/resources/settings/privacy_page/security_keys_credential_management_dialog.js +++ b/chrome/browser/resources/settings/privacy_page/security_keys_credential_management_dialog.js
@@ -9,7 +9,7 @@ cr.define('settings', function() { /** @enum {string} */ - const CredentialManagementDialogPage = { + /* #export */ const CredentialManagementDialogPage = { INITIAL: 'initial', PIN_PROMPT: 'pinPrompt', CREDENTIALS: 'credentials', @@ -100,7 +100,8 @@ // Disable the confirm button to prevent concurrent submissions. this.confirmButtonDisabled_ = true; - this.$.pin.trySubmit(pin => this.browserProxy_.providePIN(pin)) + /** @type {!SettingsSecurityKeysPinFieldElement} */ (this.$.pin) + .trySubmit(pin => this.browserProxy_.providePIN(pin)) .then( () => { // Leave confirm button disabled while enumerating credentials.
diff --git a/chrome/browser/resources/settings/privacy_page/security_keys_reset_dialog.js b/chrome/browser/resources/settings/privacy_page/security_keys_reset_dialog.js index 39d8b00..dd55392 100644 --- a/chrome/browser/resources/settings/privacy_page/security_keys_reset_dialog.js +++ b/chrome/browser/resources/settings/privacy_page/security_keys_reset_dialog.js
@@ -9,7 +9,7 @@ cr.define('settings', function() { /** @enum {string} */ - const ResetDialogPage = { + /* #export */ const ResetDialogPage = { INITIAL: 'initial', NO_RESET: 'noReset', RESET_FAILED: 'resetFailed',
diff --git a/chrome/browser/resources/settings/privacy_page/security_keys_set_pin_dialog.js b/chrome/browser/resources/settings/privacy_page/security_keys_set_pin_dialog.js index 141f45f..f1a6eae 100644 --- a/chrome/browser/resources/settings/privacy_page/security_keys_set_pin_dialog.js +++ b/chrome/browser/resources/settings/privacy_page/security_keys_set_pin_dialog.js
@@ -9,7 +9,7 @@ cr.define('settings', function() { /** @enum {string} */ - const SetPINDialogPage = { + /* #export */ const SetPINDialogPage = { INITIAL: 'initial', NO_PIN_SUPPORT: 'noPINSupport', REINSERT: 'reinsert',
diff --git a/chrome/browser/resources/settings/privacy_page/security_keys_subpage.html b/chrome/browser/resources/settings/privacy_page/security_keys_subpage.html index 255be05..6a5fd43 100644 --- a/chrome/browser/resources/settings/privacy_page/security_keys_subpage.html +++ b/chrome/browser/resources/settings/privacy_page/security_keys_subpage.html
@@ -1,8 +1,10 @@ <link rel="import" href="chrome://resources/html/polymer.html"> <link rel="import" href="chrome://resources/cr_elements/cr_link_row/cr_link_row.html"> +<link rel="import" href="chrome://resources/html/assert.html"> <link rel="import" href="chrome://resources/html/cr.html"> <link rel="import" href="chrome://resources/html/cr/ui/focus_without_ink.html"> +<link rel="import" href="../i18n_setup.html"> <link rel="import" href="../settings_shared_css.html"> <link rel="import" href="security_keys_credential_management_dialog.html">
diff --git a/chrome/browser/resources/settings/settings.gni b/chrome/browser/resources/settings/settings.gni index 969f0e3..00351e8 100644 --- a/chrome/browser/resources/settings/settings.gni +++ b/chrome/browser/resources/settings/settings.gni
@@ -11,11 +11,13 @@ "settings.AboutPageBrowserProxy|AboutPageBrowserProxy", "settings.AccountManagerBrowserProxy|AccountManagerBrowserProxy", "settings.Account|Account", + "settings.ALL_SITES_DIALOG|ALL_SITES_DIALOG", "settings.AllSitesAction2|AllSitesAction2", "settings.AndroidInfoBrowserProxy|AndroidInfoBrowserProxy", "settings.AndroidSmsInfo|AndroidSmsInfo", "settings.AppearanceBrowserProxy|AppearanceBrowserProxy", "settings.AutofillManager|AutofillManager", + "settings.BioEnrollDialogPage|BioEnrollDialogPage", "settings.BlockingRequestManager|BlockingRequestManager", "settings.CaptionsBrowserProxy|CaptionsBrowserProxy", "settings.ChooserType|ChooserType", @@ -49,6 +51,7 @@ "settings.PageStatus|PageStatus", "settings.PaymentsManager|PaymentsManager", "settings.pageVisibility|pageVisibility", + "settings.PINFieldSubmitFunc|PINFieldSubmitFunc", "settings.PluralStringProxy|PluralStringProxy", "Settings.PrefUtil.prefToString|prefToString", "Settings.PrefUtil.stringToPrefValue|stringToPrefValue", @@ -59,6 +62,7 @@ "settings.ProfileInfo|ProfileInfo", "settings.ProfileShortcutStatus|ProfileShortcutStatus", "settings.ResetBrowserProxy|ResetBrowserProxy", + "settings.ResetDialogPage|ResetDialogPage", "settings.ResolverOption|ResolverOption", "settings.Route|Route", "settings.routes|routes", @@ -68,6 +72,18 @@ "settings.SecureDnsMode|SecureDnsMode", "settings.SecureDnsSetting|SecureDnsSetting", "settings.SecureDnsUiManagementMode|SecureDnsUiManagementMode", + "settings.SecurityKeysBioEnrollProxy|SecurityKeysBioEnrollProxy", + "settings.SecurityKeysCredentialBrowserProxy|SecurityKeysCredentialBrowserProxy", + "settings.SecurityKeysResetBrowserProxy|SecurityKeysResetBrowserProxy", + "settings.Enrollment|Enrollment", + "settings.SecurityKeysPINBrowserProxy|SecurityKeysPINBrowserProxy", + "settings.EnrollmentResponse|EnrollmentResponse", + "settings.SetPINDialogPage|SetPINDialogPage", + "settings.CredentialManagementDialogPage|CredentialManagementDialogPage", + "settings.SampleStatus|SampleStatus", + "settings.SampleResponse|SampleResponse", + "settings.Ctap2Status|Ctap2Status", + "settings.Credential|Credential", "settings.MetricsReporting|MetricsReporting", "settings.SITE_EXCEPTION_WILDCARD|SITE_EXCEPTION_WILDCARD", "settings.SiteSettingSource|SiteSettingSource",
diff --git a/chrome/browser/resources/settings/settings_resources.grd b/chrome/browser/resources/settings/settings_resources.grd index a63644b..50f2db3b 100644 --- a/chrome/browser/resources/settings/settings_resources.grd +++ b/chrome/browser/resources/settings/settings_resources.grd
@@ -336,10 +336,10 @@ <structure name="IDR_SETTINGS_HISTORY_DELETION_DIALOG_JS" file="clear_browsing_data_dialog/history_deletion_dialog.js" type="chrome_html" /> - <structure name="IDR_SETTINGS_SECURITY_KEYS_PAGE_HTML" + <structure name="IDR_SETTINGS_SECURITY_KEYS_SUBPAGE_HTML" file="privacy_page/security_keys_subpage.html" type="chrome_html" /> - <structure name="IDR_SETTINGS_SECURITY_KEYS_PAGE_JS" + <structure name="IDR_SETTINGS_SECURITY_KEYS_SUBPAGE_JS" file="privacy_page/security_keys_subpage.js" type="chrome_html"/> <structure name="IDR_SETTINGS_SECURITY_KEYS_SET_PIN_DIALOG_HTML" @@ -372,10 +372,10 @@ <structure name="IDR_SETTINGS_SECURITY_KEYS_BIO_ENROLL_DIALOG_JS" file="privacy_page/security_keys_bio_enroll_dialog.js" type="chrome_html" /> - <structure name="IDR_SETTINGS_SECURITY_KEYS_DIALOG_BROWSER_PROXY_HTML" + <structure name="IDR_SETTINGS_SECURITY_KEYS_BROWSER_PROXY_HTML" file="privacy_page/security_keys_browser_proxy.html" type="chrome_html" /> - <structure name="IDR_SETTINGS_SECURITY_KEYS_DIALOG_BROWSER_PROXY_JS" + <structure name="IDR_SETTINGS_SECURITY_KEYS_BROWSER_PROXY_JS" file="privacy_page/security_keys_browser_proxy.js" type="chrome_html" /> <structure name="IDR_SETTINGS_CONTROLS_BOOLEAN_CONTROL_BEHAVIOR_HTML"
diff --git a/chrome/browser/resources/settings/settings_resources_v3.grdp b/chrome/browser/resources/settings/settings_resources_v3.grdp index 5ba6505..0cdeaf1f 100644 --- a/chrome/browser/resources/settings/settings_resources_v3.grdp +++ b/chrome/browser/resources/settings/settings_resources_v3.grdp
@@ -457,6 +457,34 @@ use_base_dir="false" preprocess="true" type="BINDATA" /> + <include name="IDR_SETTINGS_PRIVACY_PAGE_SECURITY_KEYS_BIO_ENROLL_DIALOG_M_JS" + file="${root_gen_dir}/chrome/browser/resources/settings/privacy_page/security_keys_bio_enroll_dialog.m.js" + use_base_dir="false" + type="BINDATA" /> + <include name="IDR_SETTINGS_PRIVACY_PAGE_SECURITY_KEYS_BROWSER_PROXY_M_JS" + file="${root_gen_dir}/chrome/browser/resources/settings/privacy_page/security_keys_browser_proxy.m.js" + use_base_dir="false" + type="BINDATA" /> + <include name="IDR_SETTINGS_PRIVACY_PAGE_SECURITY_KEYS_CREDENTIAL_MANAGEMENT_DIALOG_M_JS" + file="${root_gen_dir}/chrome/browser/resources/settings/privacy_page/security_keys_credential_management_dialog.m.js" + use_base_dir="false" + type="BINDATA" /> + <include name="IDR_SETTINGS_PRIVACY_PAGE_SECURITY_KEYS_PIN_FIELD_M_JS" + file="${root_gen_dir}/chrome/browser/resources/settings/privacy_page/security_keys_pin_field.m.js" + use_base_dir="false" + type="BINDATA" /> + <include name="IDR_SETTINGS_PRIVACY_PAGE_SECURITY_KEYS_RESET_DIALOG_M_JS" + file="${root_gen_dir}/chrome/browser/resources/settings/privacy_page/security_keys_reset_dialog.m.js" + use_base_dir="false" + type="BINDATA" /> + <include name="IDR_SETTINGS_PRIVACY_PAGE_SECURITY_KEYS_SET_PIN_DIALOG_M_JS" + file="${root_gen_dir}/chrome/browser/resources/settings/privacy_page/security_keys_set_pin_dialog.m.js" + use_base_dir="false" + type="BINDATA" /> + <include name="IDR_SETTINGS_PRIVACY_PAGE_SECURITY_KEYS_SUBPAGE_M_JS" + file="${root_gen_dir}/chrome/browser/resources/settings/privacy_page/security_keys_subpage.m.js" + use_base_dir="false" + type="BINDATA" /> <include name="IDR_SETTINGS_RESET_PAGE_M_JS" file="${root_gen_dir}/chrome/browser/resources/settings/reset_page/reset_page.m.js" use_base_dir="false" @@ -579,6 +607,10 @@ file="${root_gen_dir}/chrome/browser/resources/settings/site_settings/add_site_dialog.m.js" use_base_dir="false" type="BINDATA" /> + <include name="IDR_SETTINGS_SITE_SETTINGS_ALL_SITES_M_JS" + file="${root_gen_dir}/chrome/browser/resources/settings/site_settings/all_sites.m.js" + use_base_dir="false" + type="BINDATA" /> <include name="IDR_SETTINGS_SITE_SETTINGS_ALL_SITES_ICONS_M_JS" file="${root_gen_dir}/chrome/browser/resources/settings/site_settings/all_sites_icons.m.js" use_base_dir="false" @@ -625,10 +657,31 @@ file="${root_gen_dir}/chrome/browser/resources/settings/site_settings/local_data_browser_proxy.m.js" use_base_dir="false" type="BINDATA" /> + <include name="IDR_SETTINGS_SITE_SETTINGS_MEDIA_PICKER_M_JS" + file="${root_gen_dir}/chrome/browser/resources/settings/site_settings/media_picker.m.js" + use_base_dir="false" + type="BINDATA" /> + <include name="IDR_SETTINGS_SITE_SETTINGS_PDF_DOCUMENTS_M_JS" + file="${root_gen_dir}/chrome/browser/resources/settings/site_settings/pdf_documents.m.js" + use_base_dir="false" + type="BINDATA" /> + <include name="IDR_SETTINGS_SITE_SETTINGS_PROTOCOL_HANDLERS_M_JS" + file="${root_gen_dir}/chrome/browser/resources/settings/site_settings/protocol_handlers.m.js" + use_base_dir="false" + type="BINDATA" + preprocess="true" /> + <include name="IDR_SETTINGS_SITE_SETTINGS_SITE_DATA_M_JS" + file="${root_gen_dir}/chrome/browser/resources/settings/site_settings/site_data.m.js" + use_base_dir="false" + type="BINDATA" /> <include name="IDR_SETTINGS_SITE_SETTINGS_SITE_DATA_DETAILS_SUBPAGE_M_JS" file="${root_gen_dir}/chrome/browser/resources/settings/site_settings/site_data_details_subpage.m.js" use_base_dir="false" type="BINDATA" /> + <include name="IDR_SETTINGS_SITE_SETTINGS_SITE_DATA_ENTRY_M_JS" + file="${root_gen_dir}/chrome/browser/resources/settings/site_settings/site_data_entry.m.js" + use_base_dir="false" + type="BINDATA" /> <include name="IDR_SETTINGS_SITE_SETTINGS_SITE_DETAILS_M_JS" file="${root_gen_dir}/chrome/browser/resources/settings/site_settings/site_details.m.js" use_base_dir="false" @@ -666,6 +719,10 @@ file="${root_gen_dir}/chrome/browser/resources/settings/site_settings/website_usage_browser_proxy.m.js" use_base_dir="false" type="BINDATA" /> + <include name="IDR_SETTINGS_SITE_SETTINGS_ZOOM_LEVELS_M_JS" + file="${root_gen_dir}/chrome/browser/resources/settings/site_settings/zoom_levels.m.js" + use_base_dir="false" + type="BINDATA" /> <if expr="not chromeos"> <include name="IDR_SETTINGS_PRINTING_PAGE_PRINTING_BROWSER_PROXY_M_JS" file="${root_gen_dir}/chrome/browser/resources/settings/printing_page/printing_browser_proxy.m.js"
diff --git a/chrome/browser/resources/settings/site_settings/BUILD.gn b/chrome/browser/resources/settings/site_settings/BUILD.gn index 815c344..e98400d 100644 --- a/chrome/browser/resources/settings/site_settings/BUILD.gn +++ b/chrome/browser/resources/settings/site_settings/BUILD.gn
@@ -294,13 +294,11 @@ ] } -# TODO(crbug.com/1026426): Fix and enable. js_type_check("closure_compile_module") { is_polymer3 = true deps = [ ":add_site_dialog.m", - - # ":all_sites.m", + ":all_sites.m", ":android_info_browser_proxy.m", ":category_default_setting.m", ":category_setting_exceptions.m", @@ -310,14 +308,12 @@ ":cookie_info.m", ":edit_exception_dialog.m", ":local_data_browser_proxy.m", - - # ":media_picker.m", - # ":pdf_documents.m", - # ":protocol_handlers.m", - # ":site_data.m", + ":media_picker.m", + ":pdf_documents.m", + ":protocol_handlers.m", + ":site_data.m", ":site_data_details_subpage.m", - - # ":site_data_entry.m", + ":site_data_entry.m", ":site_details.m", ":site_details_permission.m", ":site_entry.m", @@ -326,8 +322,7 @@ ":site_settings_behavior.m", ":site_settings_prefs_browser_proxy.m", ":website_usage_browser_proxy.m", - - # ":zoom_levels.m", + ":zoom_levels.m", ] } @@ -347,8 +342,18 @@ js_library("all_sites.m") { sources = [ "$root_gen_dir/chrome/browser/resources/settings/site_settings/all_sites.m.js" ] deps = [ - # TODO: Fill those in. + ":constants.m", + ":local_data_browser_proxy.m", + ":site_settings_behavior.m", + ":site_settings_prefs_browser_proxy.m", + "..:global_scroll_target_behavior.m", + "..:router.m", + "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", + "//ui/webui/resources/js:i18n_behavior.m", + "//ui/webui/resources/js:load_time_data.m", + "//ui/webui/resources/js:web_ui_listener_behavior.m", ] + externs_list = [ "$externs_path/settings_private.js" ] extra_deps = [ ":all_sites_module" ] } @@ -446,7 +451,10 @@ js_library("media_picker.m") { sources = [ "$root_gen_dir/chrome/browser/resources/settings/site_settings/media_picker.m.js" ] deps = [ - # TODO: Fill those in. + ":site_settings_behavior.m", + ":site_settings_prefs_browser_proxy.m", + "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", + "//ui/webui/resources/js:web_ui_listener_behavior.m", ] extra_deps = [ ":media_picker_module" ] } @@ -454,7 +462,7 @@ js_library("pdf_documents.m") { sources = [ "$root_gen_dir/chrome/browser/resources/settings/site_settings/pdf_documents.m.js" ] deps = [ - # TODO: Fill those in. + "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", ] extra_deps = [ ":pdf_documents_module" ] } @@ -462,7 +470,13 @@ js_library("protocol_handlers.m") { sources = [ "$root_gen_dir/chrome/browser/resources/settings/site_settings/protocol_handlers.m.js" ] deps = [ - # TODO: Fill those in. + ":site_settings_behavior.m", + + # Must be included on all platforms to satisfy closure compiler. + ":android_info_browser_proxy.m", + "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", + "//ui/webui/resources/cr_elements/cr_action_menu:cr_action_menu.m", + "//ui/webui/resources/js:web_ui_listener_behavior.m", ] extra_deps = [ ":protocol_handlers_module" ] } @@ -470,7 +484,20 @@ js_library("site_data.m") { sources = [ "$root_gen_dir/chrome/browser/resources/settings/site_settings/site_data.m.js" ] deps = [ - # TODO: Fill those in. + ":cookie_info.m", + ":local_data_browser_proxy.m", + ":site_data_entry.m", + ":site_settings_behavior.m", + "..:global_scroll_target_behavior.m", + "..:route.m", + "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", + "//ui/webui/resources/cr_elements/cr_search_field:cr_search_field.m", + "//ui/webui/resources/js:assert.m", + "//ui/webui/resources/js:cr.m", + "//ui/webui/resources/js:i18n_behavior.m", + "//ui/webui/resources/js:list_property_update_behavior.m", + "//ui/webui/resources/js:web_ui_listener_behavior.m", + "//ui/webui/resources/js/cr/ui:focus_without_ink.m", ] extra_deps = [ ":site_data_module" ] } @@ -492,7 +519,11 @@ js_library("site_data_entry.m") { sources = [ "$root_gen_dir/chrome/browser/resources/settings/site_settings/site_data_entry.m.js" ] deps = [ - # TODO: Fill those in. + ":cookie_info.m", + ":local_data_browser_proxy.m", + "//ui/webui/resources/js:i18n_behavior.m", + "//ui/webui/resources/js:icon.m", + "//ui/webui/resources/js/cr/ui:focus_row_behavior.m", ] extra_deps = [ ":site_data_entry_module" ] } @@ -611,7 +642,11 @@ js_library("zoom_levels.m") { sources = [ "$root_gen_dir/chrome/browser/resources/settings/site_settings/zoom_levels.m.js" ] deps = [ - # TODO: Fill those in. + ":site_settings_behavior.m", + ":site_settings_prefs_browser_proxy.m", + "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", + "//ui/webui/resources/js:list_property_update_behavior.m", + "//ui/webui/resources/js:web_ui_listener_behavior.m", ] extra_deps = [ ":zoom_levels_module" ] } @@ -658,6 +693,16 @@ js_file = "all_sites.js" html_file = "all_sites.html" html_type = "dom-module" + auto_imports = settings_auto_imports + [ + "chrome/browser/resources/settings/global_scroll_target_behavior.html|GlobalScrollTargetBehavior,GlobalScrollTargetBehaviorImpl", + "chrome/browser/resources/settings/route.html|routes", + "chrome/browser/resources/settings/router.html|Route,Router,RouteObserverBehavior", + "chrome/browser/resources/settings/site_settings/constants.html|ALL_SITES_DIALOG,AllSitesAction2,ContentSetting,ContentSettingsTypes,SortMethod", + "chrome/browser/resources/settings/site_settings/local_data_browser_proxy.html|LocalDataBrowserProxy,LocalDataBrowserProxyImpl", + "chrome/browser/resources/settings/site_settings/site_settings_prefs_browser_proxy.html|SiteGroup", + "ui/webui/resources/html/polymer.html|afterNextRender,html,Polymer", + ] + namespace_rewrites = settings_namespace_rewrites } polymer_modulizer("all_sites_icons") { @@ -726,6 +771,8 @@ js_file = "media_picker.js" html_file = "media_picker.html" html_type = "dom-module" + auto_imports = settings_auto_imports + [ "chrome/browser/resources/settings/site_settings/site_settings_prefs_browser_proxy.html|MediaPickerEntry" ] + namespace_rewrites = settings_namespace_rewrites } polymer_modulizer("pdf_documents") { @@ -738,12 +785,22 @@ js_file = "protocol_handlers.js" html_file = "protocol_handlers.html" html_type = "dom-module" + auto_imports = settings_auto_imports + [ "chrome/browser/resources/settings/site_settings/android_info_browser_proxy.html|AndroidInfoBrowserProxyImpl,AndroidAppsInfo" ] + namespace_rewrites = settings_namespace_rewrites } polymer_modulizer("site_data") { js_file = "site_data.js" html_file = "site_data.html" html_type = "dom-module" + auto_imports = settings_auto_imports + [ + "chrome/browser/resources/settings/global_scroll_target_behavior.html|GlobalScrollTargetBehavior,GlobalScrollTargetBehaviorImpl", + "chrome/browser/resources/settings/route.html|routes", + "chrome/browser/resources/settings/router.html|Route,Router,RouteObserverBehavior", + "chrome/browser/resources/settings/site_settings/local_data_browser_proxy.html|LocalDataBrowserProxy,LocalDataBrowserProxyImpl", + "chrome/browser/resources/settings/site_settings/site_data_entry.html|CookieDataSummaryItem", + ] + namespace_rewrites = settings_namespace_rewrites } polymer_modulizer("site_data_details_subpage") { @@ -763,6 +820,8 @@ js_file = "site_data_entry.js" html_file = "site_data_entry.html" html_type = "dom-module" + auto_imports = settings_auto_imports + [ "chrome/browser/resources/settings/site_settings/local_data_browser_proxy.html|LocalDataBrowserProxy,LocalDataBrowserProxyImpl" ] + namespace_rewrites = settings_namespace_rewrites } polymer_modulizer("site_details") { @@ -838,6 +897,8 @@ js_file = "zoom_levels.js" html_file = "zoom_levels.html" html_type = "dom-module" + auto_imports = settings_auto_imports + [ "chrome/browser/resources/settings/site_settings/site_settings_prefs_browser_proxy.html|ZoomLevelEntry" ] + namespace_rewrites = settings_namespace_rewrites } js_modulizer("modulize") {
diff --git a/chrome/browser/resources/settings/site_settings/all_sites.html b/chrome/browser/resources/settings/site_settings/all_sites.html index cdc959b..28797440 100644 --- a/chrome/browser/resources/settings/site_settings/all_sites.html +++ b/chrome/browser/resources/settings/site_settings/all_sites.html
@@ -1,6 +1,8 @@ <link rel="import" href="chrome://resources/html/polymer.html"> <link rel="import" href="chrome://resources/cr_elements/cr_button/cr_button.html"> +<link rel="import" href="chrome://resources/cr_elements/cr_dialog/cr_dialog.html"> +<link rel="import" href="chrome://resources/cr_elements/cr_lazy_render/cr_lazy_render.html"> <link rel="import" href="chrome://resources/cr_elements/cr_search_field/cr_search_field.html"> <link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html"> <link rel="import" href="chrome://resources/cr_elements/md_select_css.html"> @@ -9,17 +11,21 @@ <link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-list/iron-list.html"> <link rel="import" href="../global_scroll_target_behavior.html"> +<link rel="import" href="../i18n_setup.html"> <link rel="import" href="../route.html"> <link rel="import" href="../router.html"> <link rel="import" href="../settings_shared_css.html"> <link rel="import" href="all_sites_icons.html"> <link rel="import" href="clear_storage_dialog_css.html"> +<link rel="import" href="constants.html"> +<link rel="import" href="local_data_browser_proxy.html"> <link rel="import" href="site_entry.html"> <link rel="import" href="site_settings_behavior.html"> +<link rel="import" href="site_settings_prefs_browser_proxy.html"> <dom-module id="all-sites"> <template> - <style include="settings-shared md-select"> + <style include="settings-shared md-select clear-storage-dialog-shared"> #sort { align-items: center; display: flex; @@ -160,7 +166,6 @@ <!-- New version of confirm clear data dialog to show if storage pressure UI flag is enabled. --> <cr-lazy-render id="confirmClearDataNew"> - <style include="clear-storage-dialog-shared"></style> <template> <cr-dialog close-text="$i18n{close}"> <div slot="title"> @@ -194,7 +199,6 @@ <!-- Confirm clear all data dialog. --> <cr-lazy-render id="confirmClearAllData"> - <style include="clear-storage-dialog-shared"></style> <template> <cr-dialog close-text="$i18n{close}"> <div slot="title">
diff --git a/chrome/browser/resources/settings/site_settings/all_sites.js b/chrome/browser/resources/settings/site_settings/all_sites.js index 99167e4..fc8828a 100644 --- a/chrome/browser/resources/settings/site_settings/all_sites.js +++ b/chrome/browser/resources/settings/site_settings/all_sites.js
@@ -100,8 +100,10 @@ /** * @private {?{ + * actionScope: string, * index: number, * item: !SiteGroup, + * origin: string, * path: string, * target: !HTMLElement * }} @@ -414,7 +416,7 @@ * pane when its menu is opened (it is possible to open off-screen items using * keyboard shortcuts). * @param {!CustomEvent<{ - * index: number, item: !SiteGroup, + * actionScope: string, index: number, item: !SiteGroup, origin: string, * path: string, target: !HTMLElement * }>} e * @private
diff --git a/chrome/browser/resources/settings/site_settings/android_info_browser_proxy.js b/chrome/browser/resources/settings/site_settings/android_info_browser_proxy.js index ea5ccb2..b8ad5fb5 100644 --- a/chrome/browser/resources/settings/site_settings/android_info_browser_proxy.js +++ b/chrome/browser/resources/settings/site_settings/android_info_browser_proxy.js
@@ -16,7 +16,7 @@ * }} * @see chrome/browser/ui/webui/settings/chromeos/android_apps_handler.cc */ -let AndroidAppsInfo; +/* #export */ let AndroidAppsInfo; cr.define('settings', function() { /**
diff --git a/chrome/browser/resources/settings/site_settings/constants.js b/chrome/browser/resources/settings/site_settings/constants.js index e02b4d5e..c0d296d2 100644 --- a/chrome/browser/resources/settings/site_settings/constants.js +++ b/chrome/browser/resources/settings/site_settings/constants.js
@@ -162,7 +162,7 @@ * used for logging userActions. * @enum {string} */ - const ALL_SITES_DIALOG = { + /* #export */ const ALL_SITES_DIALOG = { CLEAR_DATA: 'ClearData', RESET_PERMISSIONS: 'ResetPermissions', };
diff --git a/chrome/browser/resources/settings/site_settings/media_picker.html b/chrome/browser/resources/settings/site_settings/media_picker.html index 92f8c15f..7b28cc4 100644 --- a/chrome/browser/resources/settings/site_settings/media_picker.html +++ b/chrome/browser/resources/settings/site_settings/media_picker.html
@@ -1,8 +1,11 @@ <link rel="import" href="chrome://resources/html/polymer.html"> <link rel="import" href="chrome://resources/cr_elements/md_select_css.html"> +<link rel="import" href="chrome://resources/html/web_ui_listener_behavior.html"> <link rel="import" href="../settings_shared_css.html"> <link rel="import" href="../settings_vars_css.html"> +<link rel="import" href="site_settings_behavior.html"> +<link rel="import" href="site_settings_prefs_browser_proxy.html"> <dom-module id="media-picker"> <template>
diff --git a/chrome/browser/resources/settings/site_settings/protocol_handlers.js b/chrome/browser/resources/settings/site_settings/protocol_handlers.js index a18960f5..8664248 100644 --- a/chrome/browser/resources/settings/site_settings/protocol_handlers.js +++ b/chrome/browser/resources/settings/site_settings/protocol_handlers.js
@@ -90,7 +90,7 @@ // <if expr="chromeos"> /** @override */ attached() { - cr.addWebUIListener( + this.addWebUIListener( 'android-apps-info-update', this.androidAppsInfoUpdate_.bind(this)); settings.AndroidInfoBrowserProxyImpl.getInstance().requestAndroidAppsInfo(); },
diff --git a/chrome/browser/resources/settings/site_settings/site_data.html b/chrome/browser/resources/settings/site_settings/site_data.html index 3ae3aef..2d9c02e 100644 --- a/chrome/browser/resources/settings/site_settings/site_data.html +++ b/chrome/browser/resources/settings/site_settings/site_data.html
@@ -13,6 +13,7 @@ <link rel="import" href="chrome://resources/polymer/v1_0/iron-list/iron-list.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-spinner/paper-spinner-lite.html"> <link rel="import" href="../global_scroll_target_behavior.html"> +<link rel="import" href="../i18n_setup.html"> <link rel="import" href="../route.html"> <link rel="import" href="../router.html"> <link rel="import" href="../settings_shared_css.html">
diff --git a/chrome/browser/resources/settings/site_settings/site_data.js b/chrome/browser/resources/settings/site_settings/site_data.js index 370ff04..66cd119 100644 --- a/chrome/browser/resources/settings/site_settings/site_data.js +++ b/chrome/browser/resources/settings/site_settings/site_data.js
@@ -9,15 +9,6 @@ /** * @typedef {{ - * site: string, - * id: string, - * localData: string, - * }} - */ -let CookieDataSummaryItem; - -/** - * @typedef {{ * id: string, * start: number, * count: number,
diff --git a/chrome/browser/resources/settings/site_settings/site_data_entry.html b/chrome/browser/resources/settings/site_settings/site_data_entry.html index 5585d9a..9914bb27 100644 --- a/chrome/browser/resources/settings/site_settings/site_data_entry.html +++ b/chrome/browser/resources/settings/site_settings/site_data_entry.html
@@ -8,6 +8,7 @@ <link rel="import" href="../settings_shared_css.html"> <link rel="import" href="../site_favicon.html"> <link rel="import" href="cookie_info.html"> +<link rel="import" href="local_data_browser_proxy.html"> <dom-module id="site-data-entry"> <template>
diff --git a/chrome/browser/resources/settings/site_settings/site_data_entry.js b/chrome/browser/resources/settings/site_settings/site_data_entry.js index 6936608..ae0f5d2d 100644 --- a/chrome/browser/resources/settings/site_settings/site_data_entry.js +++ b/chrome/browser/resources/settings/site_settings/site_data_entry.js
@@ -7,6 +7,15 @@ * 'site-data-entry' handles showing the local storage summary for a site. */ +/** + * @typedef {{ + * site: string, + * id: string, + * localData: string, + * }} + */ +/* #export */ let CookieDataSummaryItem; + Polymer({ is: 'site-data-entry',
diff --git a/chrome/browser/resources/settings/site_settings/site_settings_prefs_browser_proxy.js b/chrome/browser/resources/settings/site_settings/site_settings_prefs_browser_proxy.js index 5e722b8..500baa7 100644 --- a/chrome/browser/resources/settings/site_settings/site_settings_prefs_browser_proxy.js +++ b/chrome/browser/resources/settings/site_settings/site_settings_prefs_browser_proxy.js
@@ -151,7 +151,7 @@ * @typedef {{name: string, * id: string}} */ -let MediaPickerEntry; +/* #export */ let MediaPickerEntry; /** * @typedef {{protocol: string, @@ -165,7 +165,7 @@ * source: string, * zoom: string}} */ -let ZoomLevelEntry; +/* #export */ let ZoomLevelEntry; cr.define('settings', function() { /** @interface */
diff --git a/chrome/browser/safe_browsing/BUILD.gn b/chrome/browser/safe_browsing/BUILD.gn index 2c05516..8fed398 100644 --- a/chrome/browser/safe_browsing/BUILD.gn +++ b/chrome/browser/safe_browsing/BUILD.gn
@@ -96,6 +96,8 @@ "trigger_creator.h", "ui_manager.cc", "ui_manager.h", + "user_interaction_observer.cc", + "user_interaction_observer.h", ] deps += [ ":url_lookup_service_factory",
diff --git a/chrome/browser/safe_browsing/certificate_reporting_service_unittest.cc b/chrome/browser/safe_browsing/certificate_reporting_service_unittest.cc index 2b0517be8..00f2964 100644 --- a/chrome/browser/safe_browsing/certificate_reporting_service_unittest.cc +++ b/chrome/browser/safe_browsing/certificate_reporting_service_unittest.cc
@@ -397,6 +397,7 @@ service_->Shutdown(); service_.reset(nullptr); + safe_browsing::SafeBrowsingService::RegisterFactory(nullptr); histogram_test_helper_.CheckHistogram(); event_histogram_tester_.reset();
diff --git a/chrome/browser/safe_browsing/download_protection/deep_scanning_browsertest.cc b/chrome/browser/safe_browsing/download_protection/deep_scanning_browsertest.cc new file mode 100644 index 0000000..59709d5 --- /dev/null +++ b/chrome/browser/safe_browsing/download_protection/deep_scanning_browsertest.cc
@@ -0,0 +1,320 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <memory> + +#include "base/base64.h" +#include "base/path_service.h" +#include "base/test/scoped_feature_list.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/safe_browsing/cloud_content_scanning/binary_fcm_service.h" +#include "chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service.h" +#include "chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service_factory.h" +#include "chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_browsertest_base.h" +#include "chrome/browser/safe_browsing/dm_token_utils.h" +#include "chrome/browser/safe_browsing/download_protection/ppapi_download_request.h" +#include "chrome/browser/safe_browsing/test_safe_browsing_service.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/common/chrome_paths.h" +#include "chrome/test/base/in_process_browser_test.h" +#include "chrome/test/base/ui_test_utils.h" +#include "components/autofill/core/common/mojom/autofill_types.mojom-shared.h" +#include "components/download/public/common/download_danger_type.h" +#include "components/prefs/pref_service.h" +#include "components/safe_browsing/core/common/safe_browsing_prefs.h" +#include "components/safe_browsing/core/db/test_database_manager.h" +#include "components/safe_browsing/core/features.h" +#include "components/safe_browsing/core/proto/csd.pb.h" +#include "components/safe_browsing/core/proto/webprotect.pb.h" +#include "content/public/browser/browser_context.h" +#include "content/public/browser/download_manager.h" +#include "content/public/test/download_test_observer.h" +#include "content/public/test/test_utils.h" +#include "services/network/test/test_utils.h" + +namespace safe_browsing { + +namespace { + +// Extract the metadata proto from the raw request string. Returns true on +// success. +bool GetUploadMetadata(const std::string& upload_request, + DeepScanningClientRequest* out_proto) { + // The request is of the following format, see multipart_uploader.h for + // details: + // ---MultipartBoundary--- + // <Headers for metadata> + // + // <Base64-encoded metadata> + // ---MultipartBoundary--- + // <Headers for uploaded data> + // + // <Uploaded data> + // ---MultipartBoundary--- + size_t boundary_end = upload_request.find("\r\n"); + std::string multipart_boundary = upload_request.substr(0, boundary_end); + + size_t headers_end = upload_request.find("\r\n\r\n"); + size_t metadata_end = + upload_request.find("\r\n" + multipart_boundary, headers_end); + std::string encoded_metadata = + upload_request.substr(headers_end + 4, metadata_end - headers_end - 4); + + std::string serialized_metadata; + base::Base64Decode(encoded_metadata, &serialized_metadata); + DeepScanningClientRequest metadata_proto; + return out_proto->ParseFromString(serialized_metadata); +} + +} // namespace + +class FakeBinaryFCMService : public BinaryFCMService { + public: + FakeBinaryFCMService() {} + + void GetInstanceID(GetInstanceIDCallback callback) override { + std::move(callback).Run("test_instance_id"); + } + + void UnregisterInstanceID(const std::string& token, + UnregisterInstanceIDCallback callback) override { + // Always successfully unregister. + std::move(callback).Run(true); + } +}; + +// Integration tests for download deep scanning behavior, only mocking network +// traffic and FCM dependencies. +class DownloadDeepScanningBrowserTest + : public DeepScanningBrowserTestBase, + public content::DownloadManager::Observer, + public download::DownloadItem::Observer { + public: + DownloadDeepScanningBrowserTest() {} + + void OnDownloadCreated(content::DownloadManager* manager, + download::DownloadItem* item) override { + item->AddObserver(this); + download_items_.insert(item); + } + + void OnDownloadDestroyed(download::DownloadItem* item) override { + download_items_.erase(item); + } + + protected: + void SetUp() override { + test_sb_factory_ = std::make_unique<TestSafeBrowsingServiceFactory>(); + test_sb_factory_->UseV4LocalDatabaseManager(); + SafeBrowsingService::RegisterFactory(test_sb_factory_.get()); + + InProcessBrowserTest::SetUp(); + } + + void TearDown() override { + InProcessBrowserTest::TearDown(); + + SafeBrowsingService::RegisterFactory(nullptr); + } + + void WaitForDownloadToFinish() { + content::DownloadManager* download_manager = + content::BrowserContext::GetDownloadManager(browser()->profile()); + content::DownloadTestObserverTerminal observer( + download_manager, 1, + content::DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_IGNORE); + observer.WaitForFinished(); + } + + void WaitForDeepScanRequest(bool is_advanced_protection) { + if (is_advanced_protection) + waiting_for_app_ = true; + else + waiting_for_enterprise_ = true; + + base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed); + waiting_for_upload_closure_ = run_loop.QuitClosure(); + run_loop.Run(); + + waiting_for_app_ = false; + waiting_for_enterprise_ = false; + } + + void ExpectMetadataResponse(const ClientDownloadResponse& response) { + test_sb_factory_->test_safe_browsing_service() + ->GetTestUrlLoaderFactory() + ->AddResponse(PPAPIDownloadRequest::GetDownloadRequestUrl().spec(), + response.SerializeAsString()); + } + + void ExpectDeepScanSynchronousResponse( + bool is_advanced_protection, + const DeepScanningClientResponse& response) { + test_sb_factory_->test_safe_browsing_service() + ->GetTestUrlLoaderFactory() + ->AddResponse( + BinaryUploadService::GetUploadUrl(is_advanced_protection).spec(), + response.SerializeAsString()); + } + + base::FilePath GetTestDataDirectory() { + base::FilePath test_file_directory; + base::PathService::Get(chrome::DIR_TEST_DATA, &test_file_directory); + return test_file_directory; + } + + FakeBinaryFCMService* binary_fcm_service() { return binary_fcm_service_; } + + TestSafeBrowsingServiceFactory* test_sb_factory() { + return test_sb_factory_.get(); + } + + const DeepScanningClientRequest& last_app_request() { + return last_app_request_; + } + + const DeepScanningClientRequest& last_enterprise_request() { + return last_enterprise_request_; + } + + const base::flat_set<download::DownloadItem*>& download_items() { + return download_items_; + } + + void SetBinaryUploadServiceTestFactory() { + BinaryUploadServiceFactory::GetInstance()->SetTestingFactory( + browser()->profile(), + base::BindRepeating( + &DownloadDeepScanningBrowserTest::CreateBinaryUploadService, + base::Unretained(this))); + } + + void ObserveDownloadManager() { + content::DownloadManager* download_manager = + content::BrowserContext::GetDownloadManager(browser()->profile()); + download_manager->AddObserver(this); + } + + void SetUrlLoaderInterceptor() { + test_sb_factory()->test_safe_browsing_service()->SetUseTestUrlLoaderFactory( + true); + test_sb_factory() + ->test_safe_browsing_service() + ->GetTestUrlLoaderFactory() + ->SetInterceptor(base::BindRepeating( + &DownloadDeepScanningBrowserTest::InterceptRequest, + base::Unretained(this))); + } + + void SendFcmMessage(const DeepScanningClientResponse& response) { + std::string encoded_proto; + base::Base64Encode(response.SerializeAsString(), &encoded_proto); + gcm::IncomingMessage gcm_message; + gcm_message.data["proto"] = encoded_proto; + binary_fcm_service()->OnMessage("app_id", gcm_message); + } + + void AuthorizeForDeepScanning() { + BinaryUploadServiceFactory::GetForProfile(browser()->profile()) + ->SetAuthForTesting(/*authorized=*/true); + } + + private: + std::unique_ptr<KeyedService> CreateBinaryUploadService( + content::BrowserContext* browser_context) { + std::unique_ptr<FakeBinaryFCMService> binary_fcm_service = + std::make_unique<FakeBinaryFCMService>(); + binary_fcm_service_ = binary_fcm_service.get(); + Profile* profile = Profile::FromBrowserContext(browser_context); + return std::make_unique<BinaryUploadService>( + g_browser_process->safe_browsing_service()->GetURLLoaderFactory(), + profile, std::move(binary_fcm_service)); + } + + void InterceptRequest(const network::ResourceRequest& request) { + if (request.url == + BinaryUploadService::GetUploadUrl(/*is_advanced_protection=*/true)) { + ASSERT_TRUE(GetUploadMetadata(network::GetUploadData(request), + &last_app_request_)); + if (waiting_for_app_) + std::move(waiting_for_upload_closure_).Run(); + } + + if (request.url == + BinaryUploadService::GetUploadUrl(/*is_advanced_protection=*/false)) { + ASSERT_TRUE(GetUploadMetadata(network::GetUploadData(request), + &last_enterprise_request_)); + if (waiting_for_enterprise_) + std::move(waiting_for_upload_closure_).Run(); + } + } + + std::unique_ptr<TestSafeBrowsingServiceFactory> test_sb_factory_; + FakeBinaryFCMService* binary_fcm_service_; + + bool waiting_for_app_; + DeepScanningClientRequest last_app_request_; + + bool waiting_for_enterprise_; + DeepScanningClientRequest last_enterprise_request_; + + base::OnceClosure waiting_for_upload_closure_; + + base::flat_set<download::DownloadItem*> download_items_; +}; + +IN_PROC_BROWSER_TEST_F(DownloadDeepScanningBrowserTest, + SafeDownloadHasCorrectDangerType) { + embedded_test_server()->ServeFilesFromDirectory(GetTestDataDirectory()); + ASSERT_TRUE(embedded_test_server()->Start()); + + SetBinaryUploadServiceTestFactory(); + SetUrlLoaderInterceptor(); + ObserveDownloadManager(); + AuthorizeForDeepScanning(); + + SetDMTokenForTesting(policy::DMToken::CreateValidTokenForTesting("dm_token")); + SetDlpPolicy(CheckContentComplianceValues::CHECK_DOWNLOADS); + SetMalwarePolicy(SendFilesForMalwareCheckValues::SEND_DOWNLOADS); + + // The file is SAFE according to the metadata check + ClientDownloadResponse metadata_response; + metadata_response.set_verdict(ClientDownloadResponse::SAFE); + ExpectMetadataResponse(metadata_response); + + // The DLP scan runs synchronously, but doesn't find anything. + DeepScanningClientResponse sync_response; + sync_response.mutable_dlp_scan_verdict()->set_status( + DlpDeepScanningVerdict::SUCCESS); + ExpectDeepScanSynchronousResponse(/*is_advanced_protection=*/false, + sync_response); + + GURL url = embedded_test_server()->GetURL( + "/safe_browsing/download_protection/zipfile_two_archives.zip"); + ui_test_utils::NavigateToURLWithDisposition( + browser(), url, WindowOpenDisposition::CURRENT_TAB, + ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP); + + WaitForDeepScanRequest(/*is_advanced_protection=*/false); + + // The malware scan finishes asynchronously, and doesn't find anything. + DeepScanningClientResponse async_response; + async_response.set_token(last_enterprise_request().request_token()); + async_response.mutable_malware_scan_verdict()->set_verdict( + MalwareDeepScanningVerdict::CLEAN); + SendFcmMessage(async_response); + + WaitForDownloadToFinish(); + + // The file should be deep scanned, and safe. + ASSERT_EQ(download_items().size(), 1u); + download::DownloadItem* item = *download_items().begin(); + EXPECT_EQ( + item->GetDangerType(), + download::DownloadDangerType::DOWNLOAD_DANGER_TYPE_DEEP_SCANNED_SAFE); + EXPECT_EQ(item->GetState(), download::DownloadItem::COMPLETE); +} + +} // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc b/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc index 415a708..548e8ac 100644 --- a/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc +++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc
@@ -70,9 +70,11 @@ #include "content/public/browser/notification_types.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_process_host.h" +#include "content/public/browser/render_view_host.h" #include "content/public/browser/security_style_explanations.h" #include "content/public/browser/web_contents.h" #include "content/public/test/browser_test_utils.h" +#include "content/public/test/render_view_test.h" #include "content/public/test/test_navigation_observer.h" #include "content/public/test/test_utils.h" #include "net/cert/cert_verify_result.h" @@ -95,7 +97,6 @@ namespace safe_browsing { namespace { - const char kEmptyPage[] = "/empty.html"; const char kHTTPSPage[] = "/ssl/google.html"; const char kMaliciousPage[] = "/safe_browsing/malware.html"; @@ -106,8 +107,115 @@ const char kMaliciousIframe[] = "/safe_browsing/malware_iframe.html"; const char kUnrelatedUrl[] = "https://www.google.com"; +} // namespace + +enum Visibility { VISIBILITY_ERROR = -1, HIDDEN = 0, VISIBLE = 1 }; + bool AreCommittedInterstitialsEnabled() { - return base::FeatureList::IsEnabled(kCommittedSBInterstitials); + return base::FeatureList::IsEnabled(safe_browsing::kCommittedSBInterstitials); +} + +bool IsShowingInterstitial(WebContents* contents) { + if (AreCommittedInterstitialsEnabled()) { + security_interstitials::SecurityInterstitialTabHelper* helper = + security_interstitials::SecurityInterstitialTabHelper::FromWebContents( + contents); + return helper && + (helper + ->GetBlockingPageForCurrentlyCommittedNavigationForTesting() != + nullptr); + } + return InterstitialPage::GetInterstitialPage(contents) != nullptr; +} + +content::RenderFrameHost* GetRenderFrameHost(Browser* browser) { + if (AreCommittedInterstitialsEnabled()) { + return browser->tab_strip_model()->GetActiveWebContents()->GetMainFrame(); + } + InterstitialPage* interstitial = InterstitialPage::GetInterstitialPage( + browser->tab_strip_model()->GetActiveWebContents()); + return interstitial ? interstitial->GetMainFrame() : nullptr; +} + +bool WaitForReady(Browser* browser) { + WebContents* contents = browser->tab_strip_model()->GetActiveWebContents(); + if (AreCommittedInterstitialsEnabled()) { + if (!content::WaitForRenderFrameReady(contents->GetMainFrame())) { + return false; + } + return IsShowingInterstitial(contents); + } + content::WaitForInterstitialAttach(contents); + InterstitialPage* interstitial = contents->GetInterstitialPage(); + if (!interstitial) { + return false; + } + return content::WaitForRenderFrameReady(interstitial->GetMainFrame()); +} + +Visibility GetVisibility(Browser* browser, const std::string& node_id) { + content::RenderFrameHost* rfh = GetRenderFrameHost(browser); + if (!rfh) + return VISIBILITY_ERROR; + + // clang-format off + std::string jsFindVisibility = R"( + (function isNodeVisible(node) { + if (!node) return 'node not found'; + if (node.offsetWidth === 0 || node.offsetHeight === 0) return false; + // Do not check opacity, since the css transition may actually leave + // opacity at 0 after it's been unhidden + if (node.classList.contains('hidden')) return false; + // Otherwise, we must check all parent nodes + var parentVisibility = isNodeVisible(node.parentElement); + if (parentVisibility === 'node not found') { + return true; // none of the parents are set invisible + } + return parentVisibility; + }(document.getElementById(')" + node_id + R"(')));)"; + // clang-format on + + base::Value value = content::ExecuteScriptAndGetValue(rfh, jsFindVisibility); + + if (!value.is_bool()) + return VISIBILITY_ERROR; + + return value.GetBool() ? VISIBLE : HIDDEN; +} + +bool Click(Browser* browser, const std::string& node_id) { + DCHECK(node_id == "primary-button" || node_id == "proceed-link" || + node_id == "whitepaper-link" || node_id == "details-button" || + node_id == "opt-in-checkbox") + << "Unexpected node_id: " << node_id; + content::RenderFrameHost* rfh = GetRenderFrameHost(browser); + if (!rfh) + return false; + // We don't use ExecuteScriptAndGetValue for this one, since clicking + // the button/link may navigate away before the injected javascript can + // reply, hanging the test. + rfh->ExecuteJavaScriptForTests( + base::ASCIIToUTF16("document.getElementById('" + node_id + + "').click();\n"), + base::NullCallback()); + return true; +} + +bool ClickAndWaitForDetach(Browser* browser, const std::string& node_id) { + // We wait for interstitial_detached rather than nav_entry_committed, as + // going back from a main-frame safe browsing interstitial page will not + // cause a nav entry committed event. + content::TestNavigationObserver observer( + browser->tab_strip_model()->GetActiveWebContents()); + if (!Click(browser, node_id)) + return false; + if (AreCommittedInterstitialsEnabled()) { + observer.WaitForNavigationFinished(); + return true; + } + content::WaitForInterstitialDetach( + browser->tab_strip_model()->GetActiveWebContents()); + return true; } // A SafeBrowsingDatabaseManager class that allows us to inject the malicious @@ -239,8 +347,6 @@ DISALLOW_COPY_AND_ASSIGN(FakeSafeBrowsingUIManager); }; -} // namespace - class TestThreatDetailsFactory : public ThreatDetailsFactory { public: TestThreatDetailsFactory() : details_() {} @@ -316,6 +422,28 @@ bool wait_for_delete_; }; +void AssertNoInterstitial(Browser* browser, bool wait_for_delete) { + WebContents* contents = browser->tab_strip_model()->GetActiveWebContents(); + if (AreCommittedInterstitialsEnabled()) { + ASSERT_FALSE(IsShowingInterstitial(contents)); + return; + } + + if (contents->ShowingInterstitialPage() && wait_for_delete) { + // We'll get notified when the interstitial is deleted. + TestSafeBrowsingBlockingPage* page = + static_cast<TestSafeBrowsingBlockingPage*>( + contents->GetInterstitialPage()->GetDelegateForTesting()); + ASSERT_EQ(SafeBrowsingBlockingPage::kTypeForTesting, + page->GetTypeForTesting()); + page->WaitForDelete(); + } + + // Can't use InterstitialPage::GetInterstitialPage() because that + // gets updated after the TestSafeBrowsingBlockingPage destructor + ASSERT_FALSE(contents->ShowingInterstitialPage()); +} + class TestSafeBrowsingBlockingPageFactory : public SafeBrowsingBlockingPageFactory { public: @@ -365,8 +493,6 @@ public testing::WithParamInterface< testing::tuple<SBThreatType, bool, bool>> { public: - enum Visibility { VISIBILITY_ERROR = -1, HIDDEN = 0, VISIBLE = 1 }; - SafeBrowsingBlockingPageBrowserTest() : https_server_(net::EmbeddedTestServer::TYPE_HTTPS) { std::map<std::string, std::string> parameters = { @@ -402,9 +528,9 @@ void TearDown() override { InProcessBrowserTest::TearDown(); - SafeBrowsingBlockingPage::RegisterFactory(NULL); - SafeBrowsingService::RegisterFactory(NULL); - ThreatDetails::RegisterFactory(NULL); + SafeBrowsingBlockingPage::RegisterFactory(nullptr); + SafeBrowsingService::RegisterFactory(nullptr); + ThreatDetails::RegisterFactory(nullptr); } void SetUpCommandLine(base::CommandLine* command_line) override { @@ -570,42 +696,6 @@ interstitial_page->CommandReceived(base::NumberToString(command)); } - void AssertNoInterstitial(bool wait_for_delete) { - WebContents* contents = - browser()->tab_strip_model()->GetActiveWebContents(); - if (AreCommittedInterstitialsEnabled()) { - ASSERT_FALSE(IsShowingInterstitial(contents)); - return; - } - - if (contents->ShowingInterstitialPage() && wait_for_delete) { - // We'll get notified when the interstitial is deleted. - TestSafeBrowsingBlockingPage* page = - static_cast<TestSafeBrowsingBlockingPage*>( - contents->GetInterstitialPage()->GetDelegateForTesting()); - ASSERT_EQ(SafeBrowsingBlockingPage::kTypeForTesting, - page->GetTypeForTesting()); - page->WaitForDelete(); - } - - // Can't use InterstitialPage::GetInterstitialPage() because that - // gets updated after the TestSafeBrowsingBlockingPage destructor - ASSERT_FALSE(contents->ShowingInterstitialPage()); - } - - bool IsShowingInterstitial(WebContents* contents) { - if (AreCommittedInterstitialsEnabled()) { - security_interstitials::SecurityInterstitialTabHelper* helper = - security_interstitials::SecurityInterstitialTabHelper:: - FromWebContents(contents); - return helper && - (helper - ->GetBlockingPageForCurrentlyCommittedNavigationForTesting() != - nullptr); - } - return InterstitialPage::GetInterstitialPage(contents) != nullptr; - } - void SetReportSentCallback(base::OnceClosure callback) { static_cast<FakeSafeBrowsingUIManager*>( factory_.test_safe_browsing_service()->ui_manager().get()) @@ -650,94 +740,23 @@ } content::RenderFrameHost* GetRenderFrameHost() { - if (AreCommittedInterstitialsEnabled()) { - return browser() - ->tab_strip_model() - ->GetActiveWebContents() - ->GetMainFrame(); - } - InterstitialPage* interstitial = InterstitialPage::GetInterstitialPage( - browser()->tab_strip_model()->GetActiveWebContents()); - if (!interstitial) - return NULL; - return interstitial->GetMainFrame(); - } - - bool WaitForReady(Browser* browser) { - WebContents* contents = browser->tab_strip_model()->GetActiveWebContents(); - if (AreCommittedInterstitialsEnabled()) { - if (!content::WaitForRenderFrameReady(contents->GetMainFrame())) { - return false; - } - return IsShowingInterstitial(contents); - } - content::WaitForInterstitialAttach(contents); - InterstitialPage* interstitial = contents->GetInterstitialPage(); - if (!interstitial) - return false; - return content::WaitForRenderFrameReady(interstitial->GetMainFrame()); + return ::safe_browsing::GetRenderFrameHost(browser()); } Visibility GetVisibility(const std::string& node_id) { - content::RenderFrameHost* rfh = GetRenderFrameHost(); - if (!rfh) - return VISIBILITY_ERROR; - - // clang-format off - std::string jsFindVisibility = R"( - (function isNodeVisible(node) { - if (!node) return 'node not found'; - if (node.offsetWidth === 0 || node.offsetHeight === 0) return false; - // Do not check opacity, since the css transition may actually leave - // opacity at 0 after it's been unhidden - if (node.classList.contains('hidden')) return false; - // Otherwise, we must check all parent nodes - var parentVisibility = isNodeVisible(node.parentElement); - if (parentVisibility === 'node not found') { - return true; // none of the parents are set invisible - } - return parentVisibility; - }(document.getElementById(')" + node_id + R"(')));)"; - // clang-format on - - base::Value value = - content::ExecuteScriptAndGetValue(rfh, jsFindVisibility); - - if (!value.is_bool()) - return VISIBILITY_ERROR; - - return value.GetBool() ? VISIBLE : HIDDEN; + return ::safe_browsing::GetVisibility(browser(), node_id); } bool Click(const std::string& node_id) { - content::RenderFrameHost* rfh = GetRenderFrameHost(); - if (!rfh) - return false; - // We don't use ExecuteScriptAndGetValue for this one, since clicking - // the button/link may navigate away before the injected javascript can - // reply, hanging the test. - rfh->ExecuteJavaScriptForTests( - base::ASCIIToUTF16("document.getElementById('" + node_id + - "').click();\n"), - base::NullCallback()); - return true; + return ::safe_browsing::Click(browser(), node_id); } bool ClickAndWaitForDetach(const std::string& node_id) { - // We wait for interstitial_detached rather than nav_entry_committed, as - // going back from a main-frame safe browsing interstitial page will not - // cause a nav entry committed event. - content::TestNavigationObserver observer( - browser()->tab_strip_model()->GetActiveWebContents()); - if (!Click(node_id)) - return false; - if (AreCommittedInterstitialsEnabled()) { - observer.WaitForNavigationFinished(); - return true; - } - content::WaitForInterstitialDetach( - browser()->tab_strip_model()->GetActiveWebContents()); - return true; + return ::safe_browsing::ClickAndWaitForDetach(browser(), node_id); + } + + void AssertNoInterstitial(bool wait_for_delete) { + return ::safe_browsing::AssertNoInterstitial(browser(), wait_for_delete); } void TestReportingDisabledAndDontProceed(const GURL& url) { @@ -956,7 +975,7 @@ EXPECT_EQ(HIDDEN, GetVisibility("error-code")); EXPECT_TRUE(ClickAndWaitForDetach("primary-button")); - AssertNoInterstitial(false); // Assert the interstitial is gone + AssertNoInterstitial(false); // Assert the interstitial is gone EXPECT_EQ(GURL(url::kAboutBlankURL), // Back to "about:blank" browser()->tab_strip_model()->GetActiveWebContents()->GetURL()); } @@ -1849,6 +1868,101 @@ browser()->tab_strip_model()->GetActiveWebContents()->GetURL()); } +class SafeBrowsingBlockingPageDelayedWarningBrowserTest + : public InProcessBrowserTest, + public testing::WithParamInterface< + testing::tuple<bool /* IsolateAllSitesForTesting */, + bool /* Committed interstitials enabled */>> { + public: + SafeBrowsingBlockingPageDelayedWarningBrowserTest() { + if (testing::get<1>(GetParam())) { + scoped_feature_list_.InitWithFeatures( + /*enabled_features=*/{kDelayedWarnings, kCommittedSBInterstitials}, + /*disabled_features=*/{}); + } else { + scoped_feature_list_.InitWithFeatures( + /*enabled_features=*/{kDelayedWarnings}, + /*disabled_features=*/{}); + } + } + + void SetUpCommandLine(base::CommandLine* command_line) override { + InProcessBrowserTest::SetUpCommandLine(command_line); + if (testing::get<0>(GetParam())) + content::IsolateAllSitesForTesting(command_line); + } + + void SetUpOnMainThread() override { + host_resolver()->AddRule("*", "127.0.0.1"); + content::SetupCrossSiteRedirector(embedded_test_server()); + ASSERT_TRUE(embedded_test_server()->Start()); + } + + void CreatedBrowserMainParts( + content::BrowserMainParts* browser_main_parts) override { + // Test UI manager and test database manager should be set before + // the browser is started but after threads are created. + factory_.SetTestUIManager(new FakeSafeBrowsingUIManager()); + factory_.SetTestDatabaseManager(new FakeSafeBrowsingDatabaseManager()); + SafeBrowsingService::RegisterFactory(&factory_); + SafeBrowsingBlockingPage::RegisterFactory(&blocking_page_factory_); + ThreatDetails::RegisterFactory(&details_factory_); + } + + static bool TypeAndWaitForInterstitial(Browser* browser) { + // Type something. An interstitial should be shown. + content::WebContents* contents = + browser->tab_strip_model()->GetActiveWebContents(); + content::TestNavigationObserver observer(contents); + content::NativeWebKeyboardEvent event( + blink::WebKeyboardEvent::kRawKeyDown, + blink::WebInputEvent::kNoModifiers, + blink::WebInputEvent::GetStaticTimeStampForTests()); + event.text[0] = 'a'; + content::RenderWidgetHost* rwh = contents->GetRenderViewHost()->GetWidget(); + rwh->ForwardKeyboardEvent(event); + + if (AreCommittedInterstitialsEnabled()) { + observer.WaitForNavigationFinished(); + } + return WaitForReady(browser); + } + + protected: + TestThreatDetailsFactory details_factory_; + + private: + base::test::ScopedFeatureList scoped_feature_list_; + TestSafeBrowsingServiceFactory factory_; + TestSafeBrowsingBlockingPageFactory blocking_page_factory_; + + DISALLOW_COPY_AND_ASSIGN(SafeBrowsingBlockingPageDelayedWarningBrowserTest); +}; + +IN_PROC_BROWSER_TEST_P(SafeBrowsingBlockingPageDelayedWarningBrowserTest, + DelayedWarnings) { + // Navigate to a phishing site. + ui_test_utils::NavigateToURL(browser(), + GURL(kChromeUISafeBrowsingMatchPhishingUrl)); + WaitForReady(browser()); + AssertNoInterstitial(browser(), true); + + // Type something. An interstitial should be shown. + EXPECT_TRUE(TypeAndWaitForInterstitial(browser())); + + EXPECT_TRUE(ClickAndWaitForDetach(browser(), "primary-button")); + AssertNoInterstitial(browser(), false); // Assert the interstitial is gone + EXPECT_EQ(GURL(url::kAboutBlankURL), // Back to "about:blank" + browser()->tab_strip_model()->GetActiveWebContents()->GetURL()); +} + +INSTANTIATE_TEST_SUITE_P( + SafeBrowsingBlockingPageWithDelayedWarningsBrowserTest, + SafeBrowsingBlockingPageDelayedWarningBrowserTest, + testing::Combine( + testing::Values(false, true), /* IsolateAllSitesForTesting */ + testing::Values(false, true) /* Committed interstitials enabled */)); + // Test that SafeBrowsingBlockingPage properly decodes IDN URLs that are // displayed. class SafeBrowsingBlockingPageIDNTest
diff --git a/chrome/browser/safe_browsing/telemetry/android/android_telemetry_service_unittest.cc b/chrome/browser/safe_browsing/telemetry/android/android_telemetry_service_unittest.cc index d92c765..591d4d12 100644 --- a/chrome/browser/safe_browsing/telemetry/android/android_telemetry_service_unittest.cc +++ b/chrome/browser/safe_browsing/telemetry/android/android_telemetry_service_unittest.cc
@@ -79,6 +79,7 @@ // before the NetworkService object.. browser_process_->safe_browsing_service()->ShutDown(); browser_process_->SetSafeBrowsingService(nullptr); + safe_browsing::SafeBrowsingServiceInterface::RegisterFactory(nullptr); base::RunLoop().RunUntilIdle(); }
diff --git a/chrome/browser/safe_browsing/test_safe_browsing_service.cc b/chrome/browser/safe_browsing/test_safe_browsing_service.cc index 0384e23..4488c37 100644 --- a/chrome/browser/safe_browsing/test_safe_browsing_service.cc +++ b/chrome/browser/safe_browsing/test_safe_browsing_service.cc
@@ -16,7 +16,10 @@ namespace safe_browsing { // TestSafeBrowsingService functions: -TestSafeBrowsingService::TestSafeBrowsingService() { +TestSafeBrowsingService::TestSafeBrowsingService() + : test_shared_loader_factory_( + base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>( + &test_url_loader_factory_)) { #if BUILDFLAG(FULL_SAFE_BROWSING) services_delegate_ = ServicesDelegate::CreateForTest(this, this); #endif // BUILDFLAG(FULL_SAFE_BROWSING) @@ -34,6 +37,17 @@ use_v4_local_db_manager_ = true; } +void TestSafeBrowsingService::SetUseTestUrlLoaderFactory( + bool use_test_url_loader_factory) { + use_test_url_loader_factory_ = use_test_url_loader_factory; +} + +network::TestURLLoaderFactory* +TestSafeBrowsingService::GetTestUrlLoaderFactory() { + DCHECK(use_test_url_loader_factory_); + return &test_url_loader_factory_; +} + std::unique_ptr<SafeBrowsingService::StateSubscription> TestSafeBrowsingService::RegisterStateCallback( const base::Callback<void(void)>& callback) { @@ -132,6 +146,13 @@ return nullptr; } +scoped_refptr<network::SharedURLLoaderFactory> +TestSafeBrowsingService::GetURLLoaderFactory() { + if (use_test_url_loader_factory_) + return test_shared_loader_factory_; + return SafeBrowsingService::GetURLLoaderFactory(); +} + // TestSafeBrowsingServiceFactory functions: TestSafeBrowsingServiceFactory::TestSafeBrowsingServiceFactory() : test_safe_browsing_service_(nullptr), use_v4_local_db_manager_(false) {}
diff --git a/chrome/browser/safe_browsing/test_safe_browsing_service.h b/chrome/browser/safe_browsing/test_safe_browsing_service.h index 0a93225..d11f9d4 100644 --- a/chrome/browser/safe_browsing/test_safe_browsing_service.h +++ b/chrome/browser/safe_browsing/test_safe_browsing_service.h
@@ -11,6 +11,8 @@ #include "chrome/browser/safe_browsing/ui_manager.h" #include "components/safe_browsing/buildflags.h" #include "components/safe_browsing/core/db/v4_protocol_manager_util.h" +#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" +#include "services/network/test/test_url_loader_factory.h" namespace safe_browsing { class SafeBrowsingDatabaseManager; @@ -61,8 +63,15 @@ const scoped_refptr<SafeBrowsingDatabaseManager>& database_manager() const override; void UseV4LocalDatabaseManager(); + + // By default, the TestSafeBrowsing service uses a regular URLLoaderFactory. + // This function can be used to override that behavior, exposing a + // TestURLLoaderFactory for mocking network traffic. + void SetUseTestUrlLoaderFactory(bool use_test_url_loader_factory); + std::unique_ptr<SafeBrowsingService::StateSubscription> RegisterStateCallback( const base::Callback<void(void)>& callback) override; + network::TestURLLoaderFactory* GetTestUrlLoaderFactory(); protected: // SafeBrowsingService overrides @@ -84,11 +93,16 @@ IncidentReportingService* CreateIncidentReportingService() override; ResourceRequestDetector* CreateResourceRequestDetector() override; + scoped_refptr<network::SharedURLLoaderFactory> GetURLLoaderFactory() override; + private: std::unique_ptr<V4ProtocolConfig> v4_protocol_config_; std::string serialized_download_report_; scoped_refptr<SafeBrowsingDatabaseManager> test_database_manager_; bool use_v4_local_db_manager_ = false; + bool use_test_url_loader_factory_ = false; + network::TestURLLoaderFactory test_url_loader_factory_; + scoped_refptr<network::SharedURLLoaderFactory> test_shared_loader_factory_; DISALLOW_COPY_AND_ASSIGN(TestSafeBrowsingService); };
diff --git a/chrome/browser/safe_browsing/ui_manager.cc b/chrome/browser/safe_browsing/ui_manager.cc index 746025c..87d9e0d4 100644 --- a/chrome/browser/safe_browsing/ui_manager.cc +++ b/chrome/browser/safe_browsing/ui_manager.cc
@@ -8,12 +8,14 @@ #include "base/callback.h" #include "base/macros.h" #include "base/metrics/histogram_macros.h" +#include "base/task/post_task.h" #include "base/threading/thread.h" #include "base/threading/thread_restrictions.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/history/history_service_factory.h" #include "chrome/browser/interstitials/enterprise_util.h" #include "chrome/browser/metrics/chrome_metrics_service_accessor.h" +#include "chrome/browser/prerender/prerender_contents.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/safe_browsing/safe_browsing_blocking_page.h" #include "chrome/browser/safe_browsing/safe_browsing_service.h" @@ -24,10 +26,12 @@ #include "components/prefs/pref_service.h" #include "components/safe_browsing/content/browser/threat_details.h" #include "components/safe_browsing/core/common/safe_browsing_prefs.h" +#include "components/safe_browsing/core/features.h" #include "components/safe_browsing/core/ping_manager.h" #include "components/security_interstitials/content/security_interstitial_tab_helper.h" #include "components/security_interstitials/content/unsafe_resource_util.h" #include "components/security_interstitials/core/unsafe_resource.h" +#include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/navigation_entry.h" #include "content/public/browser/notification_service.h" @@ -105,6 +109,44 @@ observer.OnSafeBrowsingHit(resource); } +// static +void SafeBrowsingUIManager::StartDisplayingBlockingPage( + scoped_refptr<SafeBrowsingUIManager> ui_manager, + const security_interstitials::UnsafeResource& resource) { + content::WebContents* web_contents = resource.web_contents_getter.Run(); + prerender::PrerenderContents* prerender_contents = + web_contents ? prerender::PrerenderContents::FromWebContents(web_contents) + : nullptr; + if (!web_contents || prerender_contents) { + if (prerender_contents) { + prerender_contents->Destroy(prerender::FINAL_STATUS_SAFE_BROWSING); + } + // Tab is gone or it's being prerendered. + base::PostTask(FROM_HERE, {content::BrowserThread::IO}, + base::BindOnce(resource.callback, false /*proceed*/, + false /*showed_interstitial*/)); + return; + } + + // With committed interstitials, if this is a main frame load, we need to + // get the navigation URL and referrer URL from the navigation entry now, + // since they are required for threat reporting, and the entry will be + // destroyed once the request is failed. + if (base::FeatureList::IsEnabled(kCommittedSBInterstitials) && + resource.IsMainPageLoadBlocked()) { + content::NavigationEntry* entry = + web_contents->GetController().GetPendingEntry(); + if (entry) { + security_interstitials::UnsafeResource resource_copy(resource); + resource_copy.navigation_url = entry->GetURL(); + resource_copy.referrer_url = entry->GetReferrer().url; + ui_manager->DisplayBlockingPage(resource_copy); + return; + } + } + ui_manager->DisplayBlockingPage(resource); +} + void SafeBrowsingUIManager::ShowBlockingPageForResource( const UnsafeResource& resource) { SafeBrowsingBlockingPage::ShowBlockingPage(this, resource);
diff --git a/chrome/browser/safe_browsing/ui_manager.h b/chrome/browser/safe_browsing/ui_manager.h index 862415c9..43da1b3 100644 --- a/chrome/browser/safe_browsing/ui_manager.h +++ b/chrome/browser/safe_browsing/ui_manager.h
@@ -59,6 +59,13 @@ explicit SafeBrowsingUIManager( const scoped_refptr<SafeBrowsingService>& service); + // Displays a SafeBrowsing interstitial. + // |ui_manager| is the manager which eventually displays the blocking page. + // |resource| is the unsafe resource for which the warning is displayed. + static void StartDisplayingBlockingPage( + scoped_refptr<SafeBrowsingUIManager> ui_manager, + const UnsafeResource& resource); + // Called to stop or shutdown operations on the UI thread. This may be called // multiple times during the life of the UIManager. Should be called // on UI thread. If shutdown is true, the manager is disabled permanently.
diff --git a/chrome/browser/safe_browsing/url_checker_delegate_impl.cc b/chrome/browser/safe_browsing/url_checker_delegate_impl.cc index b038cea0..eb71847 100644 --- a/chrome/browser/safe_browsing/url_checker_delegate_impl.cc +++ b/chrome/browser/safe_browsing/url_checker_delegate_impl.cc
@@ -13,6 +13,7 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_io_data.h" #include "chrome/browser/safe_browsing/ui_manager.h" +#include "chrome/browser/safe_browsing/user_interaction_observer.h" #include "components/safe_browsing/buildflags.h" #include "components/safe_browsing/content/triggers/suspicious_site_trigger.h" #include "components/safe_browsing/core/common/safe_browsing_prefs.h" @@ -40,41 +41,13 @@ } } -void StartDisplayingBlockingPage( - scoped_refptr<SafeBrowsingUIManager> ui_manager, - const security_interstitials::UnsafeResource& resource) { - content::WebContents* web_contents = resource.web_contents_getter.Run(); - if (web_contents) { - prerender::PrerenderContents* prerender_contents = - prerender::PrerenderContents::FromWebContents(web_contents); - if (prerender_contents) { - prerender_contents->Destroy(prerender::FINAL_STATUS_SAFE_BROWSING); - } else { - // With committed interstitials, if this is a main frame load, we need to - // get the navigation URL and referrer URL from the navigation entry now, - // since they are required for threat reporting, and the entry will be - // destroyed once the request is failed. - if (base::FeatureList::IsEnabled(kCommittedSBInterstitials) && - resource.IsMainPageLoadBlocked()) { - content::NavigationEntry* entry = - web_contents->GetController().GetPendingEntry(); - if (entry) { - security_interstitials::UnsafeResource resource_copy(resource); - resource_copy.navigation_url = entry->GetURL(); - resource_copy.referrer_url = entry->GetReferrer().url; - ui_manager->DisplayBlockingPage(resource_copy); - return; - } - } - ui_manager->DisplayBlockingPage(resource); - return; - } - } - - // Tab is gone or it's being prerendered. - base::PostTask(FROM_HERE, {content::BrowserThread::IO}, - base::BindOnce(resource.callback, false /*proceed*/, - false /*showed_interstitial*/)); +void CreateSafeBrowsingUserInteractionObserver( + const content::WebContents::Getter& web_contents_getter, + const security_interstitials::UnsafeResource& resource, + bool is_main_frame, + scoped_refptr<SafeBrowsingUIManager> ui_manager) { + SafeBrowsingUserInteractionObserver::CreateForWebContents( + web_contents_getter.Run(), resource, is_main_frame, ui_manager); } } // namespace @@ -114,7 +87,19 @@ bool has_user_gesture) { base::PostTask( FROM_HERE, {content::BrowserThread::UI}, - base::BindOnce(&StartDisplayingBlockingPage, ui_manager_, resource)); + base::BindOnce(&SafeBrowsingUIManager::StartDisplayingBlockingPage, + ui_manager_, resource)); +} + +// Starts displaying the SafeBrowsing interstitial page. +void UrlCheckerDelegateImpl:: + StartObservingInteractionsForDelayedBlockingPageHelper( + const security_interstitials::UnsafeResource& resource, + bool is_main_frame) { + base::PostTask(FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(&CreateSafeBrowsingUserInteractionObserver, + resource.web_contents_getter, resource, + is_main_frame, ui_manager_)); } bool UrlCheckerDelegateImpl::IsUrlWhitelisted(const GURL& url) {
diff --git a/chrome/browser/safe_browsing/url_checker_delegate_impl.h b/chrome/browser/safe_browsing/url_checker_delegate_impl.h index 0ab1467..eef5815 100644 --- a/chrome/browser/safe_browsing/url_checker_delegate_impl.h +++ b/chrome/browser/safe_browsing/url_checker_delegate_impl.h
@@ -33,6 +33,10 @@ const net::HttpRequestHeaders& headers, bool is_main_frame, bool has_user_gesture) override; + void StartObservingInteractionsForDelayedBlockingPageHelper( + const security_interstitials::UnsafeResource& resource, + bool is_main_frame) override; + bool IsUrlWhitelisted(const GURL& url) override; bool ShouldSkipRequestCheck(const GURL& original_url, int frame_tree_node_id,
diff --git a/chrome/browser/safe_browsing/user_interaction_observer.cc b/chrome/browser/safe_browsing/user_interaction_observer.cc new file mode 100644 index 0000000..249349f5 --- /dev/null +++ b/chrome/browser/safe_browsing/user_interaction_observer.cc
@@ -0,0 +1,103 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/safe_browsing/user_interaction_observer.h" + +#include <string> + +#include "components/safe_browsing/core/features.h" +#include "content/public/browser/navigation_handle.h" +#include "content/public/browser/render_view_host.h" +#include "content/public/browser/web_contents.h" + +namespace { +const char kWebContentsUserDataKey[] = + "web_contents_safe_browsing_user_interaction_observer"; +} + +namespace safe_browsing { + +SafeBrowsingUserInteractionObserver::SafeBrowsingUserInteractionObserver( + content::WebContents* web_contents, + const security_interstitials::UnsafeResource& resource, + bool is_main_frame, + scoped_refptr<SafeBrowsingUIManager> ui_manager) + : content::WebContentsObserver(web_contents), + web_contents_(web_contents), + resource_(resource), + ui_manager_(ui_manager) { + DCHECK(base::FeatureList::IsEnabled(kDelayedWarnings)); + key_press_callback_ = + base::BindRepeating(&SafeBrowsingUserInteractionObserver::HandleKeyPress, + base::Unretained(this)); + // Pass a callback to the render widget host instead of implementing + // WebContentsObserver::DidGetUserInteraction(). The reason for this is that + // render widget host handles keyboard events earlier and the callback can + // indicate that it wants the key press to be ignored. + // (DidGetUserInteraction() can only observe and not cancel the event.) + web_contents->GetRenderViewHost()->GetWidget()->AddKeyPressEventCallback( + key_press_callback_); +} + +SafeBrowsingUserInteractionObserver::~SafeBrowsingUserInteractionObserver() { + web_contents_->GetRenderViewHost()->GetWidget()->RemoveKeyPressEventCallback( + key_press_callback_); +} + +// static +void SafeBrowsingUserInteractionObserver::CreateForWebContents( + content::WebContents* web_contents, + const security_interstitials::UnsafeResource& resource, + bool is_main_frame, + scoped_refptr<SafeBrowsingUIManager> ui_manager) { + DCHECK(!FromWebContents(web_contents)); + auto observer = std::make_unique<SafeBrowsingUserInteractionObserver>( + web_contents, resource, is_main_frame, ui_manager); + web_contents->SetUserData(kWebContentsUserDataKey, std::move(observer)); +} + +// static +SafeBrowsingUserInteractionObserver* +SafeBrowsingUserInteractionObserver::FromWebContents( + content::WebContents* web_contents) { + return static_cast<SafeBrowsingUserInteractionObserver*>( + web_contents->GetUserData(kWebContentsUserDataKey)); +} + +void SafeBrowsingUserInteractionObserver::RenderViewHostChanged( + content::RenderViewHost* old_host, + content::RenderViewHost* new_host) { + old_host->GetWidget()->RemoveKeyPressEventCallback(key_press_callback_); + new_host->GetWidget()->AddKeyPressEventCallback(key_press_callback_); +} + +void SafeBrowsingUserInteractionObserver::WebContentsDestroyed() { + CleanUp(); +} + +void SafeBrowsingUserInteractionObserver::DidStartNavigation( + content::NavigationHandle* handle) { + // Ignore subframe navigations and same document navigations. These don't + // show full page interstitials. + if (!handle->IsInMainFrame() || handle->IsSameDocument()) { + return; + } + web_contents()->RemoveUserData(kWebContentsUserDataKey); +} + +bool SafeBrowsingUserInteractionObserver::HandleKeyPress( + const content::NativeWebKeyboardEvent& event) { + CleanUp(); + // Show the interstitial. + SafeBrowsingUIManager::StartDisplayingBlockingPage(ui_manager_, resource_); + // DO NOT add code past this point. |this| is destroyed. + return true; +} + +void SafeBrowsingUserInteractionObserver::CleanUp() { + web_contents_->GetRenderViewHost()->GetWidget()->RemoveKeyPressEventCallback( + key_press_callback_); +} + +} // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/user_interaction_observer.h b/chrome/browser/safe_browsing/user_interaction_observer.h new file mode 100644 index 0000000..caab6cf --- /dev/null +++ b/chrome/browser/safe_browsing/user_interaction_observer.h
@@ -0,0 +1,66 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_SAFE_BROWSING_USER_INTERACTION_OBSERVER_H_ +#define CHROME_BROWSER_SAFE_BROWSING_USER_INTERACTION_OBSERVER_H_ + +#include "chrome/browser/safe_browsing/ui_manager.h" +#include "components/security_interstitials/core/unsafe_resource.h" +#include "content/public/browser/render_widget_host.h" +#include "content/public/browser/web_contents_observer.h" + +#include <memory> + +namespace safe_browsing { + +// Observes user interactions and shows an interstitial if necessary. +// Only created when an interstitial was about to be displayed but was delayed +// due to the Delayed Warnings experiment. Deleted once the interstitial is +// shown, or the tab is closed or navigated away. +class SafeBrowsingUserInteractionObserver + : public base::SupportsUserData::Data, + public content::WebContentsObserver { + public: + // Creates an observer for given |web_contents|. |resource| is the unsafe + // resource for which a delayed interstitial will be displayed. + // |is_main_frame| is true if the interstitial is for the top frame. If false, + // it's for a subresource / subframe. + // |ui_manager| is the UIManager that shows the actual warning. + static void CreateForWebContents( + content::WebContents* web_contents, + const security_interstitials::UnsafeResource& resource, + bool is_main_frame, + scoped_refptr<SafeBrowsingUIManager> ui_manager); + + // See CreateForWebContents() for parameters. These need to be public. + SafeBrowsingUserInteractionObserver( + content::WebContents* web_contents, + const security_interstitials::UnsafeResource& resource, + bool is_main_frame, + scoped_refptr<SafeBrowsingUIManager> ui_manager); + ~SafeBrowsingUserInteractionObserver() override; + + // content::WebContentsObserver methods: + void RenderViewHostChanged(content::RenderViewHost* old_host, + content::RenderViewHost* new_host) override; + void WebContentsDestroyed() override; + void DidStartNavigation(content::NavigationHandle* handle) override; + + private: + static SafeBrowsingUserInteractionObserver* FromWebContents( + content::WebContents* web_contents); + + bool HandleKeyPress(const content::NativeWebKeyboardEvent& event); + void CleanUp(); + + content::RenderWidgetHost::KeyPressEventCallback key_press_callback_; + + content::WebContents* web_contents_; + security_interstitials::UnsafeResource resource_; + scoped_refptr<SafeBrowsingUIManager> ui_manager_; +}; + +} // namespace safe_browsing + +#endif // CHROME_BROWSER_SAFE_BROWSING_USER_INTERACTION_OBSERVER_H_
diff --git a/chrome/browser/send_tab_to_self/send_tab_to_self_desktop_util.cc b/chrome/browser/send_tab_to_self/send_tab_to_self_desktop_util.cc index 4542486..5aec3cd 100644 --- a/chrome/browser/send_tab_to_self/send_tab_to_self_desktop_util.cc +++ b/chrome/browser/send_tab_to_self/send_tab_to_self_desktop_util.cc
@@ -11,6 +11,8 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/browser/send_tab_to_self/desktop_notification_handler.h" #include "chrome/browser/sync/send_tab_to_self_sync_service_factory.h" +#include "chrome/browser/ui/send_tab_to_self/send_tab_to_self_bubble_controller.h" +#include "components/send_tab_to_self/features.h" #include "components/send_tab_to_self/send_tab_to_self_model.h" #include "components/send_tab_to_self/send_tab_to_self_sync_service.h" #include "components/send_tab_to_self/target_device_info.h" @@ -61,8 +63,13 @@ const SendTabToSelfEntry* entry = model->AddEntry(shared_url, title, navigation_time, target_device_guid); - if (!show_notification) + if (!show_notification || + base::FeatureList::IsEnabled(kSendTabToSelfOmniboxSendingAnimation)) { + SendTabToSelfBubbleController* controller = send_tab_to_self:: + SendTabToSelfBubbleController::CreateOrGetFromWebContents(tab); + controller->ShowConfirmationMessage(); return; + } if (entry) { DesktopNotificationHandler(profile).DisplaySendingConfirmation(
diff --git a/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/ShareImageFileUtilsTest.java b/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/ShareImageFileUtilsTest.java index fcf0146..d2e3ea5 100644 --- a/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/ShareImageFileUtilsTest.java +++ b/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/ShareImageFileUtilsTest.java
@@ -14,7 +14,6 @@ import android.graphics.Canvas; import android.graphics.Paint; import android.net.Uri; -import android.os.Build; import android.os.Environment; import android.provider.MediaStore; import android.support.test.filters.SmallTest; @@ -36,6 +35,7 @@ import org.chromium.base.test.util.CallbackHelper; import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.DisableIf; +import org.chromium.base.test.util.DisabledTest; import org.chromium.chrome.browser.ChromeActivity; import org.chromium.chrome.browser.flags.ChromeSwitches; import org.chromium.chrome.test.ChromeActivityTestRule; @@ -237,7 +237,7 @@ @Test @SmallTest - @DisableIf.Build(sdk_is_less_than = Build.VERSION_CODES.LOLLIPOP, message = "crbug.com/1056059") + @DisabledTest(message = "crbug.com/1056059") public void testSaveBitmap() throws IOException, TimeoutException { String fileName = TEST_IMAGE_FILE_NAME + "_save_bitmap"; ShareImageFileUtils.OnImageSaveListener listener =
diff --git a/chrome/browser/supervised_user/supervised_user_features.cc b/chrome/browser/supervised_user/supervised_user_features.cc index f60d3da..f08d2916 100644 --- a/chrome/browser/supervised_user/supervised_user_features.cc +++ b/chrome/browser/supervised_user/supervised_user_features.cc
@@ -11,7 +11,7 @@ const base::Feature kSupervisedUserInitiatedExtensionInstall{ "SupervisedUserInitiatedExtensionInstall", - base::FEATURE_DISABLED_BY_DEFAULT}; + base::FEATURE_ENABLED_BY_DEFAULT}; #if BUILDFLAG(ENABLE_EXTENSIONS) const base::Feature kSupervisedUserAllowlistExtensionInstall{
diff --git a/chrome/browser/supervised_user/supervised_user_url_filter.cc b/chrome/browser/supervised_user/supervised_user_url_filter.cc index 370ec159..e856f8e 100644 --- a/chrome/browser/supervised_user/supervised_user_url_filter.cc +++ b/chrome/browser/supervised_user/supervised_user_url_filter.cc
@@ -20,6 +20,7 @@ #include "base/stl_util.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" +#include "base/strings/utf_string_conversions.h" #include "base/task/post_task.h" #include "base/task/thread_pool.h" #include "base/task_runner_util.h" @@ -29,6 +30,7 @@ #include "chrome/common/chrome_features.h" #include "components/policy/core/browser/url_blacklist_manager.h" #include "components/policy/core/browser/url_util.h" +#include "components/url_formatter/url_formatter.h" #include "components/url_matcher/url_matcher.h" #include "components/variations/service/variations_service.h" #include "content/public/browser/browser_thread.h" @@ -244,8 +246,21 @@ bool SupervisedUserURLFilter::HostMatchesPattern( const std::string& canonical_host, const std::string& pattern) { - std::string trimmed_pattern = pattern; + // If |canonical_host| starts with |www.| but |pattern| starts with neither + // |www.| nor |*.| then trim |www.| part of canonical host. + bool is_host_www = + base::StartsWith(canonical_host, "www.", base::CompareCase::SENSITIVE); + bool patern_accepts = + base::StartsWith(pattern, "www.", base::CompareCase::SENSITIVE) || + base::StartsWith(pattern, "*.", base::CompareCase::SENSITIVE); + std::string trimmed_host = canonical_host; + if (is_host_www && !patern_accepts) { + trimmed_host = base::UTF16ToASCII( + url_formatter::StripWWW(base::ASCIIToUTF16(canonical_host))); + } + + std::string trimmed_pattern = pattern; if (base::EndsWith(pattern, ".*", base::CompareCase::SENSITIVE)) { size_t registry_length = GetCanonicalHostRegistryLength( trimmed_host, EXCLUDE_UNKNOWN_REGISTRIES, EXCLUDE_PRIVATE_REGISTRIES);
diff --git a/chrome/browser/supervised_user/supervised_user_url_filter.h b/chrome/browser/supervised_user/supervised_user_url_filter.h index a0205eb..f14ead53 100644 --- a/chrome/browser/supervised_user/supervised_user_url_filter.h +++ b/chrome/browser/supervised_user/supervised_user_url_filter.h
@@ -92,10 +92,11 @@ // or accounts.google.com). // - If the pattern ends with ".*", it matches the host on any known TLD // (e.g. the pattern "google.*" would match google.com or google.co.uk). - // See the SupervisedUserURLFilterTest.HostMatchesPattern unit test for more - // examples. - // Asterisks in other parts of the pattern are not allowed. - // |host| and |pattern| are assumed to be normalized to lower-case. + // If the |host| starts with "www." but the |pattern| starts with neither + // "www." nor "*.", the function strips the "www." part of |host| and tries to + // match again. See the SupervisedUserURLFilterTest.HostMatchesPattern unit + // test for more examples. Asterisks in other parts of the pattern are not + // allowed. |host| and |pattern| are assumed to be normalized to lower-case. // This method is public for testing. static bool HostMatchesPattern(const std::string& canonical_host, const std::string& pattern);
diff --git a/chrome/browser/supervised_user/supervised_user_url_filter_unittest.cc b/chrome/browser/supervised_user/supervised_user_url_filter_unittest.cc index 64dbc8d..df9ca707 100644 --- a/chrome/browser/supervised_user/supervised_user_url_filter_unittest.cc +++ b/chrome/browser/supervised_user/supervised_user_url_filter_unittest.cc
@@ -336,6 +336,8 @@ } TEST_F(SupervisedUserURLFilterTest, HostMatchesPattern) { + EXPECT_TRUE(SupervisedUserURLFilter::HostMatchesPattern("www.google.com", + "google.com")); EXPECT_TRUE( SupervisedUserURLFilter::HostMatchesPattern("www.google.com", "*.google.com"));
diff --git a/chrome/browser/sync/chrome_sync_client.cc b/chrome/browser/sync/chrome_sync_client.cc index 04188ee..f5b4ab1 100644 --- a/chrome/browser/sync/chrome_sync_client.cc +++ b/chrome/browser/sync/chrome_sync_client.cc
@@ -614,7 +614,8 @@ ->change_processor() ->GetControllerDelegate(); case syncer::WIFI_CONFIGURATIONS: - return WifiConfigurationSyncServiceFactory::GetForProfile(profile_) + return WifiConfigurationSyncServiceFactory::GetForProfile(profile_, + /*create=*/true) ->GetControllerDelegate(); #endif // defined(OS_CHROMEOS) case syncer::SHARING_MESSAGE:
diff --git a/chrome/browser/sync/wifi_configuration_sync_service_factory.cc b/chrome/browser/sync/wifi_configuration_sync_service_factory.cc index 34cc0f9..fc57f86 100644 --- a/chrome/browser/sync/wifi_configuration_sync_service_factory.cc +++ b/chrome/browser/sync/wifi_configuration_sync_service_factory.cc
@@ -17,13 +17,14 @@ // static chromeos::sync_wifi::WifiConfigurationSyncService* -WifiConfigurationSyncServiceFactory::GetForProfile(Profile* profile) { +WifiConfigurationSyncServiceFactory::GetForProfile(Profile* profile, + bool create) { if (!ShouldRunInProfile(profile)) { return nullptr; } return static_cast<chromeos::sync_wifi::WifiConfigurationSyncService*>( - GetInstance()->GetServiceForBrowserContext(profile, true)); + GetInstance()->GetServiceForBrowserContext(profile, create)); } // static
diff --git a/chrome/browser/sync/wifi_configuration_sync_service_factory.h b/chrome/browser/sync/wifi_configuration_sync_service_factory.h index 205b384a..846d348 100644 --- a/chrome/browser/sync/wifi_configuration_sync_service_factory.h +++ b/chrome/browser/sync/wifi_configuration_sync_service_factory.h
@@ -27,7 +27,8 @@ : public BrowserContextKeyedServiceFactory { public: static chromeos::sync_wifi::WifiConfigurationSyncService* GetForProfile( - Profile* profile); + Profile* profile, + bool create); static WifiConfigurationSyncServiceFactory* GetInstance(); static bool ShouldRunInProfile(const Profile* profile);
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index 276d572b..a6f6daef 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -1260,10 +1260,6 @@ "uma_browsing_activity_observer.h", "unload_controller.cc", "unload_controller.h", - "views/intent_picker_bubble_view.cc", - "views/intent_picker_bubble_view.h", - "views/location_bar/intent_picker_view.cc", - "views/location_bar/intent_picker_view.h", "webui/app_launcher_login_handler.cc", "webui/app_launcher_login_handler.h", "webui/app_management/app_management_page_handler.cc", @@ -3051,6 +3047,8 @@ "views/infobars/infobar_container_view.h", "views/infobars/infobar_view.cc", "views/infobars/infobar_view.h", + "views/intent_picker_bubble_view.cc", + "views/intent_picker_bubble_view.h", "views/javascript_tab_modal_dialog_view_views.cc", "views/javascript_tab_modal_dialog_view_views.h", "views/layout/interpolating_layout_manager.cc", @@ -3069,6 +3067,8 @@ "views/location_bar/find_bar_icon.h", "views/location_bar/icon_label_bubble_view.cc", "views/location_bar/icon_label_bubble_view.h", + "views/location_bar/intent_picker_view.cc", + "views/location_bar/intent_picker_view.h", "views/location_bar/keyword_hint_view.cc", "views/location_bar/keyword_hint_view.h", "views/location_bar/location_bar_bubble_delegate_view.cc", @@ -3848,16 +3848,12 @@ "app_list/search/search_result_ranker/app_launch_event_logger.h", "app_list/search/search_result_ranker/app_launch_event_logger_helper.cc", "app_list/search/search_result_ranker/app_launch_event_logger_helper.h", - "app_list/search/search_result_ranker/app_launch_predictor.cc", - "app_list/search/search_result_ranker/app_launch_predictor.h", "app_list/search/search_result_ranker/app_list_launch_metrics_provider.cc", "app_list/search/search_result_ranker/app_list_launch_metrics_provider.h", "app_list/search/search_result_ranker/app_list_launch_recorder.cc", "app_list/search/search_result_ranker/app_list_launch_recorder.h", "app_list/search/search_result_ranker/app_list_launch_recorder_util.cc", "app_list/search/search_result_ranker/app_list_launch_recorder_util.h", - "app_list/search/search_result_ranker/app_search_result_ranker.cc", - "app_list/search/search_result_ranker/app_search_result_ranker.h", "app_list/search/search_result_ranker/chip_ranker.cc", "app_list/search/search_result_ranker/chip_ranker.h", "app_list/search/search_result_ranker/frecency_store.cc", @@ -3999,7 +3995,6 @@ "//chrome/browser/chromeos/crostini:crostini_installer_types_mojom", "//chrome/browser/ui/app_list/search/cros_action_history:cros_action_proto", "//chrome/browser/ui/app_list/search/search_result_ranker:app_launch_event_logger_proto", - "//chrome/browser/ui/app_list/search/search_result_ranker:app_launch_predictor_proto", "//chrome/browser/ui/app_list/search/search_result_ranker:app_list_launch_recorder_proto", "//chrome/browser/ui/app_list/search/search_result_ranker:recurrence_ranker_proto", "//chrome/browser/ui/app_list/search/search_result_ranker:search_ranking_event_proto",
diff --git a/chrome/browser/ui/app_list/search/app_search_provider.cc b/chrome/browser/ui/app_list/search/app_search_provider.cc index 33e5539..b95788fc5d 100644 --- a/chrome/browser/ui/app_list/search/app_search_provider.cc +++ b/chrome/browser/ui/app_list/search/app_search_provider.cc
@@ -40,8 +40,6 @@ #include "chrome/browser/ui/app_list/chrome_app_list_item.h" #include "chrome/browser/ui/app_list/internal_app/internal_app_metadata.h" #include "chrome/browser/ui/app_list/search/app_service_app_result.h" -#include "chrome/browser/ui/app_list/search/search_result_ranker/app_search_result_ranker.h" -#include "chrome/browser/ui/app_list/search/search_result_ranker/ranking_item_util.h" #include "chrome/common/string_matching/fuzzy_tokenized_string_match.h" #include "chrome/common/string_matching/tokenized_string.h" #include "chrome/common/string_matching/tokenized_string_match.h"
diff --git a/chrome/browser/ui/app_list/search/search_result_ranker/BUILD.gn b/chrome/browser/ui/app_list/search/search_result_ranker/BUILD.gn index cdbb313..47bb735 100644 --- a/chrome/browser/ui/app_list/search/search_result_ranker/BUILD.gn +++ b/chrome/browser/ui/app_list/search/search_result_ranker/BUILD.gn
@@ -8,10 +8,6 @@ sources = [ "app_launch_event_logger.proto" ] } -proto_library("app_launch_predictor_proto") { - sources = [ "app_launch_predictor.proto" ] -} - proto_library("app_list_launch_recorder_proto") { sources = [ "app_list_launch_recorder_state.proto" ] }
diff --git a/chrome/browser/ui/app_list/search/search_result_ranker/app_launch_predictor.cc b/chrome/browser/ui/app_list/search/search_result_ranker/app_launch_predictor.cc deleted file mode 100644 index 521673f..0000000 --- a/chrome/browser/ui/app_list/search/search_result_ranker/app_launch_predictor.cc +++ /dev/null
@@ -1,339 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/ui/app_list/search/search_result_ranker/app_launch_predictor.h" - -#include <cmath> - -#include "ash/public/cpp/app_list/app_list_features.h" -#include "base/logging.h" -#include "base/metrics/field_trial_params.h" -#include "base/stl_util.h" - -namespace app_list { -namespace { - -constexpr int kHoursADay = 24; -constexpr base::TimeDelta kSaveInternal = base::TimeDelta::FromHours(1); - -// A bin with index i has 5 adjacent bins as: i + 0, i + 1, i + 2, i + 22, and -// i + 23 which stand for the bin i itself, 1 hour later, 2 hours later, -// 2 hours earlier and 1 hour earlier. Each adjacent bin contributes to the -// final Rank score with weights from BinWeightsFromFlagOrDefault(); -constexpr int kAdjacentHourBin[] = {0, 1, 2, 22, 23}; - -} // namespace - -MrfuAppLaunchPredictor::MrfuAppLaunchPredictor() = default; -MrfuAppLaunchPredictor::~MrfuAppLaunchPredictor() = default; - -void MrfuAppLaunchPredictor::Train(const std::string& app_id) { - // Updates the score for this |app_id|. - ++num_of_trains_; - Score& score = scores_[app_id]; - UpdateScore(&score); - score.last_score += 1.0f - decay_coeff_; -} - -base::flat_map<std::string, float> MrfuAppLaunchPredictor::Rank() { - // Updates all scores and return app_id to score map. - base::flat_map<std::string, float> output; - for (auto& pair : scores_) { - UpdateScore(&pair.second); - output[pair.first] = pair.second.last_score; - } - return output; -} - -const char MrfuAppLaunchPredictor::kPredictorName[] = "MrfuAppLaunchPredictor"; -const char* MrfuAppLaunchPredictor::GetPredictorName() const { - return kPredictorName; -} - -bool MrfuAppLaunchPredictor::ShouldSave() { - // MrfuAppLaunchPredictor doesn't need materialization. - return false; -} - -AppLaunchPredictorProto MrfuAppLaunchPredictor::ToProto() const { - // MrfuAppLaunchPredictor doesn't need materialization. - NOTREACHED(); - return AppLaunchPredictorProto(); -} - -bool MrfuAppLaunchPredictor::FromProto(const AppLaunchPredictorProto& proto) { - // MrfuAppLaunchPredictor doesn't need materialization. - NOTREACHED(); - return false; -} - -void MrfuAppLaunchPredictor::UpdateScore(Score* score) { - // Updates last_score and num_of_trains_at_last_update. - const int trains_since_last_time = - num_of_trains_ - score->num_of_trains_at_last_update; - if (trains_since_last_time > 0) { - score->last_score *= std::pow(decay_coeff_, trains_since_last_time); - score->num_of_trains_at_last_update = num_of_trains_; - } -} - -SerializedMrfuAppLaunchPredictor::SerializedMrfuAppLaunchPredictor() - : MrfuAppLaunchPredictor(), last_save_timestamp_(base::Time::Now()) {} - -SerializedMrfuAppLaunchPredictor::~SerializedMrfuAppLaunchPredictor() = default; - -const char SerializedMrfuAppLaunchPredictor::kPredictorName[] = - "SerializedMrfuAppLaunchPredictor"; -const char* SerializedMrfuAppLaunchPredictor::GetPredictorName() const { - return kPredictorName; -} - -bool SerializedMrfuAppLaunchPredictor::ShouldSave() { - const base::Time now = base::Time::Now(); - if (now - last_save_timestamp_ >= kSaveInternal) { - last_save_timestamp_ = now; - return true; - } - return false; -} - -AppLaunchPredictorProto SerializedMrfuAppLaunchPredictor::ToProto() const { - AppLaunchPredictorProto output; - auto& predictor_proto = - *output.mutable_serialized_mrfu_app_launch_predictor(); - predictor_proto.set_num_of_trains(num_of_trains_); - for (const auto& pair : scores_) { - auto& score_item = (*predictor_proto.mutable_scores())[pair.first]; - score_item.set_last_score(pair.second.last_score); - score_item.set_num_of_trains_at_last_update( - pair.second.num_of_trains_at_last_update); - } - return output; -} - -bool SerializedMrfuAppLaunchPredictor::FromProto( - const AppLaunchPredictorProto& proto) { - if (proto.predictor_case() != - AppLaunchPredictorProto::kSerializedMrfuAppLaunchPredictor) { - return false; - } - - const auto& predictor_proto = proto.serialized_mrfu_app_launch_predictor(); - num_of_trains_ = predictor_proto.num_of_trains(); - - scores_.clear(); - for (const auto& pair : predictor_proto.scores()) { - // Skip the case where the last_score has already dropped to 0.0f. - if (pair.second.last_score() == 0.0f) - continue; - auto& score_item = scores_[pair.first]; - score_item.last_score = pair.second.last_score(); - score_item.num_of_trains_at_last_update = - pair.second.num_of_trains_at_last_update(); - } - - return true; -} - -HourAppLaunchPredictor::HourAppLaunchPredictor() - : last_save_timestamp_(base::Time::Now()), - bin_weights_(BinWeightsFromFlagOrDefault()) {} - -HourAppLaunchPredictor::~HourAppLaunchPredictor() = default; - -void HourAppLaunchPredictor::Train(const std::string& app_id) { - auto& frequency_table = (*proto_.mutable_hour_app_launch_predictor() - ->mutable_binned_frequency_table())[GetBin()]; - - frequency_table.set_total_counts(frequency_table.total_counts() + 1); - (*frequency_table.mutable_frequency())[app_id] += 1; -} - -base::flat_map<std::string, float> HourAppLaunchPredictor::Rank() { - base::flat_map<std::string, float> output; - const int bin = GetBin(); - const bool is_weekend = bin >= kHoursADay; - const int hour = bin % kHoursADay; - const auto& frequency_table_map = - proto_.hour_app_launch_predictor().binned_frequency_table(); - - for (size_t i = 0; i < base::size(kAdjacentHourBin); ++i) { - // Finds adjacent bin and weight. - const int adj_bin = - (hour + kAdjacentHourBin[i]) % kHoursADay + kHoursADay * is_weekend; - const auto find_frequency_table = frequency_table_map.find(adj_bin); - if (find_frequency_table == frequency_table_map.end()) - continue; - - const auto& frequency_table = find_frequency_table->second; - const float weight = bin_weights_[i]; - - // Accumulates the frequency to the output. - if (frequency_table.total_counts() > 0) { - const int total_counts = frequency_table.total_counts(); - for (const auto& pair : frequency_table.frequency()) { - output[pair.first] += - static_cast<float>(pair.second) / total_counts * weight; - } - } - } - return output; -} - -const char HourAppLaunchPredictor::kPredictorName[] = "HourAppLaunchPredictor"; -const char* HourAppLaunchPredictor::GetPredictorName() const { - return kPredictorName; -} - -bool HourAppLaunchPredictor::ShouldSave() { - const base::Time now = base::Time::Now(); - if (now - last_save_timestamp_ >= kSaveInternal) { - last_save_timestamp_ = now; - return true; - } - return false; -} - -AppLaunchPredictorProto HourAppLaunchPredictor::ToProto() const { - return proto_; -} - -bool HourAppLaunchPredictor::FromProto(const AppLaunchPredictorProto& proto) { - if (proto.predictor_case() != - AppLaunchPredictorProto::kHourAppLaunchPredictor) { - return false; - } - - const HourAppLaunchPredictorProto& predictor_proto = - proto.hour_app_launch_predictor(); - - const int today = base::Time::Now().ToDeltaSinceWindowsEpoch().InDays(); - - // If last_decay_timestamp is not set, just copy the proto. - if (!predictor_proto.has_last_decay_timestamp()) { - proto_ = proto; - proto_.mutable_hour_app_launch_predictor()->set_last_decay_timestamp(today); - return true; - } - - // If last decay is within 7 days, just copy the proto. - if (today - predictor_proto.last_decay_timestamp() <= 7) { - proto_ = proto; - return true; - } - - proto_.Clear(); - for (const auto& table : predictor_proto.binned_frequency_table()) { - auto& new_table = (*proto_.mutable_hour_app_launch_predictor() - ->mutable_binned_frequency_table())[table.first]; - - int total_counts = 0; - for (const auto& frequency : table.second.frequency()) { - const int new_frequency = frequency.second * kWeeklyDecayCoeff; - if (new_frequency > 0) { - total_counts += new_frequency; - (*new_table.mutable_frequency())[frequency.first] = new_frequency; - } - } - new_table.set_total_counts(total_counts); - } - proto_.mutable_hour_app_launch_predictor()->set_last_decay_timestamp(today); - return true; -} - -int HourAppLaunchPredictor::GetBin() const { - base::Time::Exploded now; - base::Time::Now().LocalExplode(&now); - - const bool is_weekend = now.day_of_week == 6 || now.day_of_week == 0; - - // To distinguish workdays with weekends, we use now.hour for workdays, and - // now.hour + 24 for weekends. - if (!is_weekend) { - return now.hour; - } else { - return now.hour + kHoursADay; - } -} - -std::vector<float> HourAppLaunchPredictor::BinWeightsFromFlagOrDefault() { - const std::vector<float> default_weights = {0.6, 0.15, 0.05, 0.05, 0.15}; - std::vector<float> weights(5); - - // Get weights for adjacent bins. Every weight has to be within [0.0, 1.0] - // And the sum weights[1] + ..., + weights[4] also needs to be in [0.0, 1.0] - // so that the weight[0] is set to be 1.0 - (weights[1] + ..., + weights[4]). - weights[1] = static_cast<float>(base::GetFieldTrialParamByFeatureAsDouble( - app_list_features::kEnableZeroStateAppsRanker, "weight_1_hour_later_bin", - -1.0)); - if (weights[1] < 0.0 || weights[1] > 1.0) - return default_weights; - - weights[2] = static_cast<float>(base::GetFieldTrialParamByFeatureAsDouble( - app_list_features::kEnableZeroStateAppsRanker, "weight_2_hour_later_bin", - -1.0)); - if (weights[2] < 0.0 || weights[2] > 1.0) - return default_weights; - - weights[3] = static_cast<float>(base::GetFieldTrialParamByFeatureAsDouble( - app_list_features::kEnableZeroStateAppsRanker, - "weight_2_hour_earlier_bin", -1.0)); - if (weights[3] < 0.0 || weights[3] > 1.0) - return default_weights; - - weights[4] = static_cast<float>(base::GetFieldTrialParamByFeatureAsDouble( - app_list_features::kEnableZeroStateAppsRanker, - "weight_1_hour_earlier_bin", -1.0)); - if (weights[4] < 0.0 || weights[4] > 1.0) - return default_weights; - - weights[0] = 1.0 - weights[1] - weights[2] - weights[3] - weights[4]; - if (weights[0] < 0.0 || weights[0] > 1.0) - return default_weights; - - return weights; -} - -void FakeAppLaunchPredictor::SetShouldSave(bool should_save) { - should_save_ = should_save; -} - -void FakeAppLaunchPredictor::Train(const std::string& app_id) { - // Increases 1.0 for rank score of app_id. - (*proto_.mutable_fake_app_launch_predictor() - ->mutable_rank_result())[app_id] += 1.0f; -} - -base::flat_map<std::string, float> FakeAppLaunchPredictor::Rank() { - // Outputs proto_.fake_app_launch_predictor().rank_result() as Rank result. - base::flat_map<std::string, float> output; - for (const auto& pair : proto_.fake_app_launch_predictor().rank_result()) { - output[pair.first] = pair.second; - } - return output; -} - -const char FakeAppLaunchPredictor::kPredictorName[] = "FakeAppLaunchPredictor"; -const char* FakeAppLaunchPredictor::GetPredictorName() const { - return kPredictorName; -} - -bool FakeAppLaunchPredictor::ShouldSave() { - return should_save_; -} - -AppLaunchPredictorProto FakeAppLaunchPredictor::ToProto() const { - return proto_; -} - -bool FakeAppLaunchPredictor::FromProto(const AppLaunchPredictorProto& proto) { - if (proto.predictor_case() != - AppLaunchPredictorProto::kFakeAppLaunchPredictor) { - return false; - } - proto_ = proto; - return true; -} - -} // namespace app_list
diff --git a/chrome/browser/ui/app_list/search/search_result_ranker/app_launch_predictor.h b/chrome/browser/ui/app_list/search/search_result_ranker/app_launch_predictor.h deleted file mode 100644 index 7d25c6cb..0000000 --- a/chrome/browser/ui/app_list/search/search_result_ranker/app_launch_predictor.h +++ /dev/null
@@ -1,195 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_UI_APP_LIST_SEARCH_SEARCH_RESULT_RANKER_APP_LAUNCH_PREDICTOR_H_ -#define CHROME_BROWSER_UI_APP_LIST_SEARCH_SEARCH_RESULT_RANKER_APP_LAUNCH_PREDICTOR_H_ - -#include <string> -#include <vector> - -#include "base/containers/flat_map.h" -#include "base/gtest_prod_util.h" -#include "base/macros.h" -#include "base/time/time.h" -#include "chrome/browser/ui/app_list/search/search_result_ranker/app_launch_predictor.pb.h" - -namespace app_list { - -// AppLaunchPredictor is the interface implemented by all predictors. It defines -// two basic public functions Train and Rank for training and inferencing. -class AppLaunchPredictor { - public: - virtual ~AppLaunchPredictor() = default; - // Trains on the |app_id| and (possibly) updates its internal representation. - virtual void Train(const std::string& app_id) = 0; - // Returns a map of app_id and score. - // (1) Higher score means more relevant. - // (2) Only returns a subset of app_ids seen by this predictor. - // (3) The returned scores should be in range [0.0, 1.0] for - // AppSearchProvider to handle. - virtual base::flat_map<std::string, float> Rank() = 0; - // Returns the name of the predictor. - virtual const char* GetPredictorName() const = 0; - // Whether the model should be saved on disk at this moment. - virtual bool ShouldSave() = 0; - // Converts the predictor to AppLaunchPredictorProto. - virtual AppLaunchPredictorProto ToProto() const = 0; - // Initializes the predictor with |proto|. - virtual bool FromProto(const AppLaunchPredictorProto& proto) = 0; -}; - -// MrfuAppLaunchPredictor is a simple AppLaunchPredictor that balances MRU (most -// recently used) and MFU (most frequently used). It is adopted from LRFU cpu -// cache algorithm. -class MrfuAppLaunchPredictor : public AppLaunchPredictor { - public: - MrfuAppLaunchPredictor(); - ~MrfuAppLaunchPredictor() override; - - // AppLaunchPredictor: - void Train(const std::string& app_id) override; - base::flat_map<std::string, float> Rank() override; - const char* GetPredictorName() const override; - bool ShouldSave() override; - AppLaunchPredictorProto ToProto() const override; - bool FromProto(const AppLaunchPredictorProto& proto) override; - - // Name of the predictor; - static const char kPredictorName[]; - - protected: - // Records last updates of the Score for an app. - struct Score { - int32_t num_of_trains_at_last_update = 0; - float last_score = 0.0f; - }; - - // Updates the Score to now. - void UpdateScore(Score* score); - // Map from app_id to its Score. - base::flat_map<std::string, Score> scores_; - // Increment 1 for each Train() call. - int32_t num_of_trains_ = 0; - - private: - FRIEND_TEST_ALL_PREFIXES(AppLaunchPredictorTest, MrfuAppLaunchPredictor); - friend class SerializedMrfuAppLaunchPredictorTest; - - // Controls how much the score decays for each Train() call. - // This decay_coeff_ should be within [0.5f, 1.0f]. Setting it as 0.5f means - // MRU; setting as 1.0f means MFU; - // TODO(https://crbug.com/871674): - // (1) Set a better initial value based on real user data. - // (2) Dynamically change this coeff instead of setting it as constant. - static constexpr float decay_coeff_ = 0.8f; - - DISALLOW_COPY_AND_ASSIGN(MrfuAppLaunchPredictor); -}; - -// SerializedMrfuAppLaunchPredictor is MrfuAppLaunchPredictor with supporting of -// AppLaunchPredictor::ToProto and AppLaunchPredictor::FromProto. -class SerializedMrfuAppLaunchPredictor : public MrfuAppLaunchPredictor { - public: - SerializedMrfuAppLaunchPredictor(); - ~SerializedMrfuAppLaunchPredictor() override; - - // AppLaunchPredictor: - const char* GetPredictorName() const override; - bool ShouldSave() override; - AppLaunchPredictorProto ToProto() const override; - bool FromProto(const AppLaunchPredictorProto& proto) override; - - // Name of the predictor; - static const char kPredictorName[]; - - private: - // Last time the predictor was saved. - base::Time last_save_timestamp_; - - DISALLOW_COPY_AND_ASSIGN(SerializedMrfuAppLaunchPredictor); -}; - -// HourAppLaunchPredictor is a AppLaunchPredictor that uses hour of the day as -// bins, and uses app-launch frequency of in each bin as the Rank score. -// For example, if it's 8:30 am right now, then only app-launches between 8am to -// 9am in the last a few days are mainly considered. -// NOTE 1: bins of nearby hours also contributes to the final score but less -// significient. For example if current time is 8am, then scores in 6am, -// 7am, 9am, and 10am are also added to the final Rank score with -// smaller weights. -// NOTE 2: workdays and weekends are put into different bins. -class HourAppLaunchPredictor : public AppLaunchPredictor { - public: - HourAppLaunchPredictor(); - ~HourAppLaunchPredictor() override; - - // AppLaunchPredictor: - void Train(const std::string& app_id) override; - base::flat_map<std::string, float> Rank() override; - const char* GetPredictorName() const override; - bool ShouldSave() override; - AppLaunchPredictorProto ToProto() const override; - bool FromProto(const AppLaunchPredictorProto& proto) override; - - // Name of the predictor; - static const char kPredictorName[]; - - private: - FRIEND_TEST_ALL_PREFIXES(HourAppLaunchPredictorTest, GetTheRightBin); - FRIEND_TEST_ALL_PREFIXES(HourAppLaunchPredictorTest, RankFromSingleBin); - FRIEND_TEST_ALL_PREFIXES(HourAppLaunchPredictorTest, RankFromMultipleBin); - FRIEND_TEST_ALL_PREFIXES(HourAppLaunchPredictorTest, CheckDefaultWeights); - FRIEND_TEST_ALL_PREFIXES(HourAppLaunchPredictorTest, SetWeightsFromFlag); - FRIEND_TEST_ALL_PREFIXES(HourAppLaunchPredictorTest, FromProtoDecay); - - // Returns current bin index of this predictor. - int GetBin() const; - - // Get weights of adjacent bins from flag which will be set using finch config - // for exploring possible options. - static std::vector<float> BinWeightsFromFlagOrDefault(); - - // The proto for this predictor. - AppLaunchPredictorProto proto_; - // Last time the predictor was saved. - base::Time last_save_timestamp_; - // Coefficient that controls the decay of previous record. - static constexpr float kWeeklyDecayCoeff = 0.8; - // Weights that are used to combine adjacent bins. - const std::vector<float> bin_weights_; - - DISALLOW_COPY_AND_ASSIGN(HourAppLaunchPredictor); -}; - -// Predictor for testing AppSearchResultRanker only. -class FakeAppLaunchPredictor : public AppLaunchPredictor { - public: - FakeAppLaunchPredictor() = default; - ~FakeAppLaunchPredictor() override = default; - - // Manually set |should_save_|; - void SetShouldSave(bool should_save); - - // AppLaunchPredictor: - void Train(const std::string& app_id) override; - base::flat_map<std::string, float> Rank() override; - const char* GetPredictorName() const override; - bool ShouldSave() override; - AppLaunchPredictorProto ToProto() const override; - bool FromProto(const AppLaunchPredictorProto& proto) override; - - // Name of the predictor; - static const char kPredictorName[]; - - private: - bool should_save_ = false; - // The proto for this predictor. - AppLaunchPredictorProto proto_; - - DISALLOW_COPY_AND_ASSIGN(FakeAppLaunchPredictor); -}; - -} // namespace app_list - -#endif // CHROME_BROWSER_UI_APP_LIST_SEARCH_SEARCH_RESULT_RANKER_APP_LAUNCH_PREDICTOR_H_
diff --git a/chrome/browser/ui/app_list/search/search_result_ranker/app_launch_predictor.proto b/chrome/browser/ui/app_list/search/search_result_ranker/app_launch_predictor.proto deleted file mode 100644 index d56f3b2..0000000 --- a/chrome/browser/ui/app_list/search/search_result_ranker/app_launch_predictor.proto +++ /dev/null
@@ -1,52 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -syntax = "proto2"; - -option optimize_for = LITE_RUNTIME; - -package app_list; - -message SerializedMrfuAppLaunchPredictorProto { - // Records last updates of the Score for an app. - message Score { - optional int32 num_of_trains_at_last_update = 1; - optional float last_score = 2; - } - // Map from app_id to its Score. - map<string, Score> scores = 1; - // Increment 1 for each Train() call. - optional int32 num_of_trains = 2; -} - -// HourAppLaunchPredictorProto is used for materializing HourAppLaunchPredictor. -message HourAppLaunchPredictorProto { - // A frequency table records app launches that happened in a particular bin. - message FrequencyTable { - // Total number of launches (within this bin), should equal to the sum of - // frequency below. - optional int32 total_counts = 1; - // Number of launches for each app (within this bin). - map<string, int32> frequency = 2; - } - // A map from bin indices to each FrequencyTable of that bin. - map<int32, FrequencyTable> binned_frequency_table = 1; - // Timestamp of last decay operation in days since windows epoch. - optional int32 last_decay_timestamp = 2; -} - -// Used only for testing AppSearchResultRanker. -message FakeAppLaunchPredictorProto { - map<string, float> rank_result = 1; -} - -// AppLaunchPredictorProto contains one type of the predictor proto above. -message AppLaunchPredictorProto { - oneof predictor { - FakeAppLaunchPredictorProto fake_app_launch_predictor = 1; - HourAppLaunchPredictorProto hour_app_launch_predictor = 2; - SerializedMrfuAppLaunchPredictorProto serialized_mrfu_app_launch_predictor = - 3; - } -}
diff --git a/chrome/browser/ui/app_list/search/search_result_ranker/app_launch_predictor_unittest.cc b/chrome/browser/ui/app_list/search/search_result_ranker/app_launch_predictor_unittest.cc deleted file mode 100644 index 2b1b185..0000000 --- a/chrome/browser/ui/app_list/search/search_result_ranker/app_launch_predictor_unittest.cc +++ /dev/null
@@ -1,316 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/ui/app_list/search/search_result_ranker/app_launch_predictor.h" - -#include "ash/public/cpp/app_list/app_list_features.h" -#include "base/test/scoped_feature_list.h" -#include "base/test/scoped_mock_clock_override.h" -#include "chrome/browser/ui/app_list/search/search_result_ranker/app_launch_predictor_test_util.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -using testing::ElementsAre; -using testing::UnorderedElementsAre; -using testing::Pair; -using testing::FloatEq; - -namespace app_list { - -namespace { - -constexpr char kTarget1[] = "Target1"; -constexpr char kTarget2[] = "Target2"; - -} // namespace - -TEST(AppLaunchPredictorTest, MrfuAppLaunchPredictor) { - MrfuAppLaunchPredictor predictor; - const float decay = MrfuAppLaunchPredictor::decay_coeff_; - - predictor.Train(kTarget1); - const float score_1 = 1.0f - decay; - EXPECT_THAT(predictor.Rank(), - UnorderedElementsAre(Pair(kTarget1, FloatEq(score_1)))); - - predictor.Train(kTarget1); - const float score_2 = score_1 + score_1 * decay; - EXPECT_THAT(predictor.Rank(), - UnorderedElementsAre(Pair(kTarget1, FloatEq(score_2)))); - - predictor.Train(kTarget2); - const float score_3 = score_2 * decay; - EXPECT_THAT(predictor.Rank(), - UnorderedElementsAre(Pair(kTarget1, FloatEq(score_3)), - Pair(kTarget2, FloatEq(score_1)))); -} - -// Test Serialization logic of SerializedMrfuAppLaunchPredictor. -class SerializedMrfuAppLaunchPredictorTest : public testing::Test { - protected: - void SetUp() override { - score1_ = (1.0f - decay) * decay + (1.0f - decay); - score2_ = 1.0f - decay; - - auto& predictor_proto = - *proto_.mutable_serialized_mrfu_app_launch_predictor(); - - predictor_proto.set_num_of_trains(3); - auto& item1 = (*predictor_proto.mutable_scores())[kTarget1]; - item1.set_last_score(score1_); - item1.set_num_of_trains_at_last_update(2); - - auto& item2 = (*predictor_proto.mutable_scores())[kTarget2]; - item2.set_last_score(score2_); - item2.set_num_of_trains_at_last_update(3); - } - - float score1_ = 0.0f; - float score2_ = 0.0f; - static constexpr float decay = MrfuAppLaunchPredictor::decay_coeff_; - AppLaunchPredictorProto proto_; -}; - -TEST_F(SerializedMrfuAppLaunchPredictorTest, ToProto) { - SerializedMrfuAppLaunchPredictor predictor; - - predictor.Train(kTarget1); - predictor.Train(kTarget1); - predictor.Train(kTarget2); - - // Check predictor.ToProto() is the same as proto_. - EXPECT_TRUE(EquivToProtoLite(predictor.ToProto(), proto_)); -} - -TEST_F(SerializedMrfuAppLaunchPredictorTest, FromProto) { - SerializedMrfuAppLaunchPredictor predictor; - EXPECT_TRUE(predictor.FromProto(proto_)); - - EXPECT_THAT(predictor.Rank(), - UnorderedElementsAre(Pair(kTarget1, FloatEq(score1_ * decay)), - Pair(kTarget2, FloatEq(score2_)))); -} - -class HourAppLaunchPredictorTest : public testing::Test { - protected: - // Sets local time according to |day_of_week| and |hour_of_day|. - void SetLocalTime(const int day_of_week, const int hour_of_day) { - AdvanceToNextLocalSunday(); - const auto advance = base::TimeDelta::FromDays(day_of_week) + - base::TimeDelta::FromHours(hour_of_day); - if (advance > base::TimeDelta()) { - time_.Advance(advance); - } - } - - base::ScopedMockClockOverride time_; - - private: - // Advances time to be 0am next Sunday. - void AdvanceToNextLocalSunday() { - base::Time::Exploded now; - base::Time::Now().LocalExplode(&now); - const auto advance = base::TimeDelta::FromDays(6 - now.day_of_week) + - base::TimeDelta::FromHours(24 - now.hour); - if (advance > base::TimeDelta()) { - time_.Advance(advance); - } - base::Time::Now().LocalExplode(&now); - CHECK_EQ(now.day_of_week, 0); - CHECK_EQ(now.hour, 0); - } - -}; - -// Checks HourAppLaunchPredictor::GetBin returns the right bin index for given -// local time. -TEST_F(HourAppLaunchPredictorTest, GetTheRightBin) { - HourAppLaunchPredictor predictor; - - // Monday. - for (int i = 0; i <= 23; ++i) { - SetLocalTime(1, i); - EXPECT_EQ(predictor.GetBin(), i); - } - - // Friday. - for (int i = 0; i <= 23; ++i) { - SetLocalTime(5, i); - EXPECT_EQ(predictor.GetBin(), i); - } - - // Saturday. - for (int i = 0; i <= 23; ++i) { - SetLocalTime(6, i); - EXPECT_EQ(predictor.GetBin(), i + 24); - } - - // Sunday. - for (int i = 0; i <= 23; ++i) { - SetLocalTime(0, i); - EXPECT_EQ(predictor.GetBin(), i + 24); - } -} - -// Checks the apps are ranked based on frequency in a single bin. -TEST_F(HourAppLaunchPredictorTest, RankFromSingleBin) { - HourAppLaunchPredictor predictor; - const auto& weights = HourAppLaunchPredictor::BinWeightsFromFlagOrDefault(); - - // Create a model that trained on kTarget1 3 times, and kTarget2 2 times. - SetLocalTime(1, 10); - predictor.Train(kTarget1); - SetLocalTime(2, 10); - predictor.Train(kTarget1); - SetLocalTime(3, 10); - predictor.Train(kTarget1); - SetLocalTime(4, 10); - predictor.Train(kTarget2); - SetLocalTime(5, 10); - predictor.Train(kTarget2); - - // Train on weekend will not fail into the same bin. - SetLocalTime(6, 10); - predictor.Train(kTarget1); - SetLocalTime(0, 10); - predictor.Train(kTarget2); - - SetLocalTime(1, 10); - EXPECT_THAT(predictor.Rank(), - UnorderedElementsAre(Pair(kTarget1, FloatEq(weights[0] * 0.6)), - Pair(kTarget2, FloatEq(weights[0] * 0.4)))); -} - -// Checks the apps are ranked based on linearly combined scores from adjacent -// bins. -TEST_F(HourAppLaunchPredictorTest, RankFromMultipleBin) { - HourAppLaunchPredictor predictor; - const auto& weights = HourAppLaunchPredictor::BinWeightsFromFlagOrDefault(); - - // For bin 10 - SetLocalTime(1, 10); - predictor.Train(kTarget1); - predictor.Train(kTarget1); - SetLocalTime(2, 10); - predictor.Train(kTarget2); - - // For bin 11 - SetLocalTime(3, 11); - predictor.Train(kTarget1); - predictor.Train(kTarget2); - - // FOr bin 12 - SetLocalTime(5, 12); - predictor.Train(kTarget2); - - // Train on weekend. - SetLocalTime(6, 10); - predictor.Train(kTarget1); - predictor.Train(kTarget2); - SetLocalTime(0, 11); - predictor.Train(kTarget2); - - // Check workdays. - SetLocalTime(1, 10); - EXPECT_THAT( - predictor.Rank(), - UnorderedElementsAre( - Pair(kTarget1, FloatEq(weights[0] * 2.0 / 3.0 + weights[1] * 0.5)), - Pair(kTarget2, FloatEq(weights[0] * 1.0 / 3.0 + weights[1] * 0.5 + - weights[2] * 1.0)))); - - // Check weekends. - SetLocalTime(0, 9); - EXPECT_THAT( - predictor.Rank(), - UnorderedElementsAre( - Pair(kTarget1, FloatEq(weights[1] * 1.0 / 2.0)), - Pair(kTarget2, FloatEq(weights[1] * 1.0 / 2.0 + weights[2])))); -} - -// Check the default weights are set correctly. -TEST_F(HourAppLaunchPredictorTest, CheckDefaultWeights) { - base::test::ScopedFeatureList scoped_feature_list_; - scoped_feature_list_.InitAndEnableFeature( - app_list_features::kEnableZeroStateAppsRanker); - - EXPECT_THAT(HourAppLaunchPredictor::BinWeightsFromFlagOrDefault(), - ElementsAre(FloatEq(0.6), FloatEq(0.15), FloatEq(0.05), - FloatEq(0.05), FloatEq(0.15))); -} - -// Checks that the weights are set from flag correctly. -TEST_F(HourAppLaunchPredictorTest, SetWeightsFromFlag) { - base::test::ScopedFeatureList scoped_feature_list_; - scoped_feature_list_.InitAndEnableFeatureWithParameters( - app_list_features::kEnableZeroStateAppsRanker, - {{"weight_1_hour_later_bin", "0.1"}, - {"weight_2_hour_later_bin", "0.2"}, - {"weight_2_hour_earlier_bin", "0.22"}, - {"weight_1_hour_earlier_bin", "0.23"}}); - - HourAppLaunchPredictor predictor; - const auto& weights = HourAppLaunchPredictor::BinWeightsFromFlagOrDefault(); - - EXPECT_THAT(weights, ElementsAre(FloatEq(0.25), FloatEq(0.1), FloatEq(0.2), - FloatEq(0.22), FloatEq(0.23))); - - // For bin 0 - SetLocalTime(1, 0); - predictor.Train(kTarget1); - predictor.Train(kTarget1); - predictor.Train(kTarget2); - - // For bin 1 - SetLocalTime(1, 1); - predictor.Train(kTarget1); - predictor.Train(kTarget2); - - SetLocalTime(1, 0); - EXPECT_THAT( - predictor.Rank(), - UnorderedElementsAre( - Pair(kTarget1, FloatEq(weights[0] * 2.0 / 3.0 + weights[1] * 0.5)), - Pair(kTarget2, FloatEq(weights[0] * 1.0 / 3.0 + weights[1] * 0.5)))); -} - -// Checks FromProto applies decay correctly. -TEST_F(HourAppLaunchPredictorTest, FromProtoDecay) { - HourAppLaunchPredictor predictor; - const int bin = predictor.GetBin(); - const int frequency1 = 11; - const int frequency2 = 1; - - AppLaunchPredictorProto proto; - auto& frequency_table = (*proto.mutable_hour_app_launch_predictor() - ->mutable_binned_frequency_table())[bin]; - (*frequency_table.mutable_frequency())[kTarget1] = frequency1; - (*frequency_table.mutable_frequency())[kTarget2] = frequency2; - frequency_table.set_total_counts(frequency1 + frequency2); - - // FromProto will not decay since last_decay_timestamp is not set. - predictor.FromProto(proto); - proto.mutable_hour_app_launch_predictor()->set_last_decay_timestamp( - base::Time::Now().ToDeltaSinceWindowsEpoch().InDays()); - EXPECT_TRUE(EquivToProtoLite(predictor.ToProto(), proto)); - - // FromProto will not decay since last_decay_timestamp is within 7 days. - time_.Advance(base::TimeDelta::FromDays(6)); - predictor.FromProto(proto); - EXPECT_TRUE(EquivToProtoLite(predictor.ToProto(), proto)); - - // FromProto will decay since last_decay_timestamp is over 7 days. - time_.Advance(base::TimeDelta::FromDays(2)); - predictor.FromProto(proto); - const int new_frequency1 = - static_cast<int>(frequency1 * HourAppLaunchPredictor::kWeeklyDecayCoeff); - frequency_table.mutable_frequency()->clear(); - (*frequency_table.mutable_frequency())[kTarget1] = new_frequency1; - frequency_table.set_total_counts(new_frequency1); - proto.mutable_hour_app_launch_predictor()->set_last_decay_timestamp( - base::Time::Now().ToDeltaSinceWindowsEpoch().InDays()); - EXPECT_TRUE(EquivToProtoLite(predictor.ToProto(), proto)); -} - -} // namespace app_list
diff --git a/chrome/browser/ui/app_list/search/search_result_ranker/app_search_result_ranker.cc b/chrome/browser/ui/app_list/search/search_result_ranker/app_search_result_ranker.cc deleted file mode 100644 index 9c30a08..0000000 --- a/chrome/browser/ui/app_list/search/search_result_ranker/app_search_result_ranker.cc +++ /dev/null
@@ -1,167 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/ui/app_list/search/search_result_ranker/app_search_result_ranker.h" - -#include "ash/public/cpp/app_list/app_list_features.h" -#include "base/bind.h" -#include "base/files/file_util.h" -#include "base/files/important_file_writer.h" -#include "base/task/post_task.h" -#include "base/task/task_traits.h" -#include "base/task/thread_pool.h" -#include "base/task_runner_util.h" -#include "base/threading/scoped_blocking_call.h" -#include "chrome/browser/profiles/profile.h" -#include "chrome/browser/ui/app_list/search/search_result_ranker/app_launch_predictor.h" -#include "chrome/browser/ui/app_list/search/search_result_ranker/app_launch_predictor.pb.h" - -namespace app_list { -namespace { - -constexpr char kAppLaunchPredictorFilename[] = "app_launch_predictor"; - -// Returns a AppLaunchPredictor pointer based on the |predictor_name|. -std::unique_ptr<AppLaunchPredictor> CreatePredictor( - const std::string& predictor_name) { - if (predictor_name == MrfuAppLaunchPredictor::kPredictorName) - return std::make_unique<MrfuAppLaunchPredictor>(); - - if (predictor_name == SerializedMrfuAppLaunchPredictor::kPredictorName) - return std::make_unique<SerializedMrfuAppLaunchPredictor>(); - - if (predictor_name == HourAppLaunchPredictor::kPredictorName) - return std::make_unique<HourAppLaunchPredictor>(); - - if (predictor_name == FakeAppLaunchPredictor::kPredictorName) - return std::make_unique<FakeAppLaunchPredictor>(); - - NOTREACHED(); - return nullptr; -} - -// Save |proto| to |predictor_filename|. -void SaveToDiskOnWorkerThread(const base::FilePath& predictor_filename, - const AppLaunchPredictorProto& proto) { - - std::string proto_str; - if (!proto.SerializeToString(&proto_str)) { - LOG(ERROR) - << "Unable to serialize AppLaunchPredictorProto, not saving to disk."; - return; - } - bool write_result; - { - base::ScopedBlockingCall scoped_blocking_call( - FROM_HERE, base::BlockingType::MAY_BLOCK); - write_result = base::ImportantFileWriter::WriteFileAtomically( - predictor_filename, proto_str, "AppSearchResultRanker"); - } - if (!write_result) { - LOG(ERROR) << "Error writing predictor file " << predictor_filename; - } -} - -// Loads a AppLaunchPredictor from |predictor_filename|. -std::unique_ptr<AppLaunchPredictor> LoadPredictorFromDiskOnWorkerThread( - const base::FilePath& predictor_filename, - const std::string predictor_name) { - base::ScopedBlockingCall scoped_blocking_call(FROM_HERE, - base::BlockingType::MAY_BLOCK); - - // Loads proto string from local disk. - std::string proto_str; - if (!base::ReadFileToString(predictor_filename, &proto_str)) - return nullptr; - - // Parses proto string as AppLaunchPredictorProto. - AppLaunchPredictorProto proto; - if (!proto.ParseFromString(proto_str)) - return nullptr; - - auto predictor = CreatePredictor(predictor_name); - // Initializes the |predictor_| from the |proto|. - if (!predictor->FromProto(proto)) - return nullptr; - - return predictor; -} - -} // namespace - -AppSearchResultRanker::AppSearchResultRanker(const base::FilePath& profile_path, - bool is_ephemeral_user) - : predictor_filename_( - profile_path.AppendASCII(kAppLaunchPredictorFilename)) { - if (!app_list_features::IsZeroStateAppsRankerEnabled()) { - LOG(ERROR) << "AppSearchResultRanker: ZeroStateAppsRanker is not enabled."; - return; - } - // TODO(charleszhao): remove these logs once the test review is done. - LOG(ERROR) << "AppSearchResultRanker::AppSearchResultRankerPredictorName " - << app_list_features::AppSearchResultRankerPredictorName(); - predictor_ = - CreatePredictor(app_list_features::AppSearchResultRankerPredictorName()); - - // MrfuAppLaunchPredictor doesn't have materialization, so no loading from - // local disk. - if (predictor_->GetPredictorName() == - MrfuAppLaunchPredictor::kPredictorName) { - load_from_disk_completed_ = true; - return; - } - - // For ephemeral users, we disable AppSearchResultRanker to make finch - // experiment easier. - if (is_ephemeral_user) - return; - - task_runner_ = base::ThreadPool::CreateSequencedTaskRunner( - {base::TaskPriority::BEST_EFFORT, base::MayBlock(), - base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}); - - // Loads the predictor from disk asynchronously. - base::PostTaskAndReplyWithResult( - task_runner_.get(), FROM_HERE, - base::BindOnce(&LoadPredictorFromDiskOnWorkerThread, predictor_filename_, - predictor_->GetPredictorName()), - base::BindOnce(&AppSearchResultRanker::OnLoadFromDiskComplete, - weak_factory_.GetWeakPtr())); -} - -AppSearchResultRanker::~AppSearchResultRanker() = default; - -void AppSearchResultRanker::Train(const std::string& app_id) { - if (load_from_disk_completed_) { - predictor_->Train(app_id); - - if (predictor_->ShouldSave()) { - // Writes the predictor proto to disk asynchronously. - task_runner_->PostTask( - FROM_HERE, - base::BindOnce(&SaveToDiskOnWorkerThread, predictor_filename_, - predictor_->ToProto())); - } - } -} - -base::flat_map<std::string, float> AppSearchResultRanker::Rank() { - if (load_from_disk_completed_) { - return predictor_->Rank(); - } - - return {}; -} - -void AppSearchResultRanker::OnLoadFromDiskComplete( - std::unique_ptr<AppLaunchPredictor> predictor) { - if (predictor) { - predictor_.swap(predictor); - } - load_from_disk_completed_ = true; - LOG(ERROR) << "AppSearchResultRanker::OnLoadFromDiskComplete " - << predictor_->GetPredictorName(); -} - -} // namespace app_list
diff --git a/chrome/browser/ui/app_list/search/search_result_ranker/app_search_result_ranker.h b/chrome/browser/ui/app_list/search/search_result_ranker/app_search_result_ranker.h deleted file mode 100644 index 8b4164e7..0000000 --- a/chrome/browser/ui/app_list/search/search_result_ranker/app_search_result_ranker.h +++ /dev/null
@@ -1,73 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_UI_APP_LIST_SEARCH_SEARCH_RESULT_RANKER_APP_SEARCH_RESULT_RANKER_H_ -#define CHROME_BROWSER_UI_APP_LIST_SEARCH_SEARCH_RESULT_RANKER_APP_SEARCH_RESULT_RANKER_H_ - -#include <memory> -#include <string> - -#include "base/containers/flat_map.h" -#include "base/files/file_path.h" -#include "base/macros.h" -#include "base/memory/scoped_refptr.h" -#include "base/memory/weak_ptr.h" -#include "base/sequenced_task_runner.h" - -namespace app_list { - -class AppLaunchPredictor; - -// AppSearchResultRanker is the main class used to train and re-rank the app -// launches. -class AppSearchResultRanker { - public: - // Construct a AppSearchResultRanker with profile. It (possibly) - // asynchronously loads model from disk from |profile_path|; and sets - // |load_from_disk_success_| to true when the loading finishes. - // The internal |predictor_| is constructed with param - // SearchResultRankerPredictorName() in "app_list_features.h". - // Ephemeral users are speically handled since their profiles are cleaned up - // after logging out. - AppSearchResultRanker(const base::FilePath& profile_path, - bool is_ephemeral_user); - - ~AppSearchResultRanker(); - - // Trains on the |app_id| and (possibly) updates its internal representation. - void Train(const std::string& app_id); - // Returns a map of app_id and score. - // (1) Higher score means more relevant. - // (2) Only returns a subset of app_ids seen by this predictor. - // (3) The returned scores should be in range [0.0, 1.0] for - // AppSearchProvider to handle. - base::flat_map<std::string, float> Rank(); - - private: - FRIEND_TEST_ALL_PREFIXES(AppSearchResultRankerSerializationTest, - LoadFromDiskSucceed); - FRIEND_TEST_ALL_PREFIXES(AppSearchResultRankerSerializationTest, - LoadFromDiskFailIfNoFileExists); - FRIEND_TEST_ALL_PREFIXES(AppSearchResultRankerSerializationTest, - LoadFromDiskFailWithInvalidProto); - FRIEND_TEST_ALL_PREFIXES(AppSearchResultRankerSerializationTest, - SaveToDiskSucceed); - - // Sets |predictor_| and |load_from_disk_completed_| when - // LoadPredictorFromDiskOnWorkerThread completes. - void OnLoadFromDiskComplete(std::unique_ptr<AppLaunchPredictor> predictor); - - // Internal predictor used for train and rank. - std::unique_ptr<AppLaunchPredictor> predictor_; - bool load_from_disk_completed_ = false; - const base::FilePath predictor_filename_; - scoped_refptr<base::SequencedTaskRunner> task_runner_; - base::WeakPtrFactory<AppSearchResultRanker> weak_factory_{this}; - - DISALLOW_COPY_AND_ASSIGN(AppSearchResultRanker); -}; - -} // namespace app_list - -#endif // CHROME_BROWSER_UI_APP_LIST_SEARCH_SEARCH_RESULT_RANKER_APP_SEARCH_RESULT_RANKER_H_
diff --git a/chrome/browser/ui/app_list/search/search_result_ranker/app_search_result_ranker_unittest.cc b/chrome/browser/ui/app_list/search/search_result_ranker/app_search_result_ranker_unittest.cc deleted file mode 100644 index 9823ff9..0000000 --- a/chrome/browser/ui/app_list/search/search_result_ranker/app_search_result_ranker_unittest.cc +++ /dev/null
@@ -1,216 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/ui/app_list/search/search_result_ranker/app_search_result_ranker.h" - -#include "ash/public/cpp/app_list/app_list_features.h" -#include "base/files/file_util.h" -#include "base/files/scoped_temp_dir.h" -#include "base/test/scoped_feature_list.h" -#include "base/test/task_environment.h" -#include "chrome/browser/ui/app_list/search/search_result_ranker/app_launch_predictor.h" -#include "chrome/browser/ui/app_list/search/search_result_ranker/app_launch_predictor.pb.h" -#include "chrome/browser/ui/app_list/search/search_result_ranker/app_launch_predictor_test_util.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -using testing::UnorderedElementsAre; -using testing::Pair; -using testing::FloatEq; - -namespace app_list { - -namespace { - -constexpr char kTarget1[] = "Target1"; -constexpr char kTarget2[] = "Target2"; -constexpr bool kNotAnEphemeralUser = false; - -} // namespace - -// Test flags of AppSearchResultRanker. -class AppSearchResultRankerFlagTest : public testing::Test { - protected: - void SetUp() override { - Test::SetUp(); - // Creates file directory. - ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); - } - - // Waits for all tasks in to finish. - void Wait() { task_environment_.RunUntilIdle(); } - - base::test::TaskEnvironment task_environment_{ - base::test::TaskEnvironment::MainThreadType::DEFAULT, - base::test::TaskEnvironment::ThreadPoolExecutionMode::QUEUED}; - base::ScopedTempDir temp_dir_; - base::test::ScopedFeatureList scoped_feature_list_; -}; - -TEST_F(AppSearchResultRankerFlagTest, TrainAndInfer) { - scoped_feature_list_.InitAndEnableFeatureWithParameters( - app_list_features::kEnableZeroStateAppsRanker, - {{"app_search_result_ranker_predictor_name", - FakeAppLaunchPredictor::kPredictorName}}); - - AppSearchResultRanker ranker(temp_dir_.GetPath(), kNotAnEphemeralUser); - Wait(); - ranker.Train(kTarget1); - ranker.Train(kTarget2); - ranker.Train(kTarget2); - - EXPECT_THAT(ranker.Rank(), - UnorderedElementsAre(Pair(kTarget1, FloatEq(1.0f)), - Pair(kTarget2, FloatEq(2.0f)))); -} - -TEST_F(AppSearchResultRankerFlagTest, EphemeralUsersAreDisabled) { - scoped_feature_list_.InitAndEnableFeatureWithParameters( - app_list_features::kEnableZeroStateAppsRanker, - {{"app_search_result_ranker_predictor_name", - FakeAppLaunchPredictor::kPredictorName}}); - - AppSearchResultRanker ranker(temp_dir_.GetPath(), !kNotAnEphemeralUser); - Wait(); - ranker.Train(kTarget1); - ranker.Train(kTarget2); - ranker.Train(kTarget2); - - EXPECT_TRUE(ranker.Rank().empty()); -} - -TEST_F(AppSearchResultRankerFlagTest, ReturnEmptyIfDisabled) { - scoped_feature_list_.InitWithFeatures( - {}, {app_list_features::kEnableZeroStateAppsRanker}); - - AppSearchResultRanker ranker(temp_dir_.GetPath(), kNotAnEphemeralUser); - Wait(); - ranker.Train(kTarget1); - ranker.Train(kTarget2); - - EXPECT_TRUE(ranker.Rank().empty()); -} - -// Test Serialization of AppSearchResultRanker. -class AppSearchResultRankerSerializationTest - : public AppSearchResultRankerFlagTest { - protected: - void SetUp() override { - AppSearchResultRankerFlagTest::SetUp(); - - predictor_filename_ = - temp_dir_.GetPath().AppendASCII("app_launch_predictor"); - - // Sets proto. - (*proto_.mutable_fake_app_launch_predictor() - ->mutable_rank_result())[kTarget1] = 1.0f; - (*proto_.mutable_fake_app_launch_predictor() - ->mutable_rank_result())[kTarget2] = 2.0f; - - scoped_feature_list_.InitAndEnableFeatureWithParameters( - app_list_features::kEnableZeroStateAppsRanker, - {{"app_search_result_ranker_predictor_name", - FakeAppLaunchPredictor::kPredictorName}}); - } - - base::FilePath predictor_filename_; - AppLaunchPredictorProto proto_; -}; - -TEST_F(AppSearchResultRankerSerializationTest, LoadFromDiskSucceed) { - // Prepare file to be loaded. - const std::string proto_str = proto_.SerializeAsString(); - EXPECT_NE( - base::WriteFile(predictor_filename_, proto_str.c_str(), proto_str.size()), - -1); - // Construct ranker. - AppSearchResultRanker ranker(temp_dir_.GetPath(), kNotAnEphemeralUser); - - // Check that the file loading is executed in non-blocking way. - EXPECT_FALSE(ranker.load_from_disk_completed_); - - // Wait for the loading to finish. - Wait(); - - // Check loading is complete. - EXPECT_TRUE(ranker.load_from_disk_completed_); - - // Check predictor is loaded correctly. - EXPECT_THAT(ranker.Rank(), - UnorderedElementsAre(Pair(kTarget1, FloatEq((1.0f))), - Pair(kTarget2, FloatEq(2.0f)))); -} - -TEST_F(AppSearchResultRankerSerializationTest, LoadFromDiskFailIfNoFileExists) { - // Construct ranker. - AppSearchResultRanker ranker(temp_dir_.GetPath(), kNotAnEphemeralUser); - // Wait for the loading to finish. - Wait(); - - // Check loading is complete. - EXPECT_TRUE(ranker.load_from_disk_completed_); - - // Check predictor is initialized. - EXPECT_TRUE(ranker.Rank().empty()); -} - -TEST_F(AppSearchResultRankerSerializationTest, - LoadFromDiskFailWithInvalidProto) { - const std::string wrong_proto = "abc"; - // Prepare file to be loaded. - EXPECT_NE(base::WriteFile(predictor_filename_, wrong_proto.c_str(), - wrong_proto.size()), - -1); - - // Construct ranker. - AppSearchResultRanker ranker(temp_dir_.GetPath(), kNotAnEphemeralUser); - // Wait for the loading to finish. - Wait(); - - // Check loading is complete. - EXPECT_TRUE(ranker.load_from_disk_completed_); - - // Check predictor is initialized since the proto is not decodable. - EXPECT_TRUE(ranker.Rank().empty()); -} - -TEST_F(AppSearchResultRankerSerializationTest, SaveToDiskSucceed) { - // Construct ranker. - AppSearchResultRanker ranker(temp_dir_.GetPath(), kNotAnEphemeralUser); - // Wait for the loading to finish. - Wait(); - - // Check loading is complete. - EXPECT_TRUE(ranker.load_from_disk_completed_); - // Check predictor is initialized. - EXPECT_TRUE(ranker.Rank().empty()); - - ranker.Train(kTarget1); - ranker.Train(kTarget2); - - // Check the predictor file is not created. - EXPECT_FALSE(base::PathExists(predictor_filename_)); - - // Set should_save to true. - static_cast<FakeAppLaunchPredictor*>(ranker.predictor_.get()) - ->SetShouldSave(true); - - // Train and wait for the writing to finish. - ranker.Train(kTarget2); - Wait(); - - // Expect the predictor file is created. - EXPECT_TRUE(base::PathExists(predictor_filename_)); - - // Parse the content of the file. - std::string str_written; - EXPECT_TRUE(base::ReadFileToString(predictor_filename_, &str_written)); - AppLaunchPredictorProto proto_written; - EXPECT_TRUE(proto_written.ParseFromString(str_written)); - - // Expect the content to be proto_. - EXPECT_TRUE(EquivToProtoLite(proto_written, proto_)); -} - -} // namespace app_list
diff --git a/chrome/browser/ui/app_list/search/search_result_ranker/chip_ranker.cc b/chrome/browser/ui/app_list/search/search_result_ranker/chip_ranker.cc index 4ad6918..a45b1dc 100644 --- a/chrome/browser/ui/app_list/search/search_result_ranker/chip_ranker.cc +++ b/chrome/browser/ui/app_list/search/search_result_ranker/chip_ranker.cc
@@ -13,7 +13,6 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/ui/app_list/search/chrome_search_result.h" -#include "chrome/browser/ui/app_list/search/search_result_ranker/app_search_result_ranker.h" #include "chrome/browser/ui/app_list/search/search_result_ranker/histogram_util.h" #include "chrome/browser/ui/app_list/search/search_result_ranker/ranking_item_util.h" #include "chrome/browser/ui/app_list/search/search_result_ranker/recurrence_ranker.h"
diff --git a/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker.cc b/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker.cc index 0d934715..5f512851 100644 --- a/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker.cc +++ b/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker.cc
@@ -29,7 +29,6 @@ #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/ui/app_list/search/chrome_search_result.h" #include "chrome/browser/ui/app_list/search/cros_action_history/cros_action_recorder.h" -#include "chrome/browser/ui/app_list/search/search_result_ranker/app_search_result_ranker.h" #include "chrome/browser/ui/app_list/search/search_result_ranker/histogram_util.h" #include "chrome/browser/ui/app_list/search/search_result_ranker/ranking_item_util.h" #include "chrome/browser/ui/app_list/search/search_result_ranker/recurrence_ranker.h"
diff --git a/chrome/browser/ui/app_list/search/tests/app_search_provider_unittest.cc b/chrome/browser/ui/app_list/search/tests/app_search_provider_unittest.cc index f40b160..a383264 100644 --- a/chrome/browser/ui/app_list/search/tests/app_search_provider_unittest.cc +++ b/chrome/browser/ui/app_list/search/tests/app_search_provider_unittest.cc
@@ -30,7 +30,6 @@ #include "chrome/browser/ui/app_list/arc/arc_app_test.h" #include "chrome/browser/ui/app_list/arc/arc_default_app_list.h" #include "chrome/browser/ui/app_list/search/chrome_search_result.h" -#include "chrome/browser/ui/app_list/search/search_result_ranker/app_search_result_ranker.h" #include "chrome/browser/ui/app_list/search/search_result_ranker/ranking_item_util.h" #include "chrome/browser/ui/app_list/test/fake_app_list_model_updater.h" #include "chrome/browser/ui/app_list/test/test_app_list_controller_delegate.h"
diff --git a/chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl_unittest.cc b/chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl_unittest.cc index c7a2051..00c803c 100644 --- a/chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl_unittest.cc +++ b/chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl_unittest.cc
@@ -39,6 +39,8 @@ namespace autofill { +const base::Time kArbitraryTime = base::Time::FromTimeT(1234567890); + class TestSaveCardBubbleControllerImpl : public SaveCardBubbleControllerImpl { public: static void CreateForTesting(content::WebContents* web_contents) { @@ -92,6 +94,7 @@ ->SetInteger( prefs::kAutofillAcceptSaveCreditCardPromptState, prefs::PREVIOUS_SAVE_CREDIT_CARD_PROMPT_USER_DECISION_NONE); + test_clock_.SetNow(kArbitraryTime); } void SetLegalMessage(
diff --git a/chrome/browser/ui/bookmarks/bookmark_utils.cc b/chrome/browser/ui/bookmarks/bookmark_utils.cc index 9b4eb05e..fcb7cec 100644 --- a/chrome/browser/ui/bookmarks/bookmark_utils.cc +++ b/chrome/browser/ui/bookmarks/bookmark_utils.cc
@@ -22,17 +22,10 @@ #include "components/user_prefs/user_prefs.h" #include "components/vector_icons/vector_icons.h" #include "content/public/browser/web_contents.h" -#include "extensions/buildflags/buildflags.h" #include "ui/base/dragdrop/drag_drop_types.h" #include "ui/base/dragdrop/drop_target_event.h" #include "ui/base/pointer/touch_ui_controller.h" -#if BUILDFLAG(ENABLE_EXTENSIONS) -#include "chrome/browser/extensions/api/commands/command_service.h" -#include "extensions/browser/extension_registry.h" -#include "extensions/common/extension_set.h" -#endif - #if defined(TOOLKIT_VIEWS) #include "ui/gfx/canvas.h" #include "ui/gfx/color_utils.h" @@ -54,50 +47,6 @@ namespace { -// The ways in which extensions may customize the bookmark shortcut. -enum BookmarkShortcutDisposition { - BOOKMARK_SHORTCUT_DISPOSITION_UNCHANGED, - BOOKMARK_SHORTCUT_DISPOSITION_REMOVED, - BOOKMARK_SHORTCUT_DISPOSITION_OVERRIDE_REQUESTED -}; - -// Indicates how the bookmark shortcut has been changed by extensions associated -// with |profile|, if at all. -BookmarkShortcutDisposition GetBookmarkShortcutDisposition(Profile* profile) { -#if BUILDFLAG(ENABLE_EXTENSIONS) - extensions::CommandService* command_service = - extensions::CommandService::Get(profile); - - extensions::ExtensionRegistry* registry = - extensions::ExtensionRegistry::Get(profile); - if (!registry) - return BOOKMARK_SHORTCUT_DISPOSITION_UNCHANGED; - - const extensions::ExtensionSet& extension_set = - registry->enabled_extensions(); - - // This flag tracks whether any extension wants the disposition to be - // removed. - bool removed = false; - for (extensions::ExtensionSet::const_iterator i = extension_set.begin(); - i != extension_set.end(); - ++i) { - // Use the overridden disposition if any extension wants it. - if (command_service->RequestsBookmarkShortcutOverride(i->get())) - return BOOKMARK_SHORTCUT_DISPOSITION_OVERRIDE_REQUESTED; - - if (!removed && - extensions::CommandService::RemovesBookmarkShortcut(i->get())) { - removed = true; - } - } - - if (removed) - return BOOKMARK_SHORTCUT_DISPOSITION_REMOVED; -#endif - return BOOKMARK_SHORTCUT_DISPOSITION_UNCHANGED; -} - #if defined(TOOLKIT_VIEWS) // Image source that flips the supplied source image in RTL. class RTLFlipSource : public gfx::ImageSkiaSource { @@ -188,32 +137,6 @@ bookmarks::prefs::kShowAppsShortcutInBookmarkBar); } -bool ShouldRemoveBookmarkThisTabUI(Profile* profile) { - return GetBookmarkShortcutDisposition(profile) == - BOOKMARK_SHORTCUT_DISPOSITION_REMOVED; -} - -bool ShouldRemoveBookmarkAllTabsUI(Profile* profile) { -#if BUILDFLAG(ENABLE_EXTENSIONS) - extensions::ExtensionRegistry* registry = - extensions::ExtensionRegistry::Get(profile); - if (!registry) - return false; - - const extensions::ExtensionSet& extension_set = - registry->enabled_extensions(); - - for (extensions::ExtensionSet::const_iterator i = extension_set.begin(); - i != extension_set.end(); - ++i) { - if (extensions::CommandService::RemovesBookmarkAllTabsShortcut(i->get())) - return true; - } -#endif - - return false; -} - int GetBookmarkDragOperation(content::BrowserContext* browser_context, const BookmarkNode* node) { PrefService* prefs = user_prefs::UserPrefs::Get(browser_context);
diff --git a/chrome/browser/ui/bookmarks/bookmark_utils.h b/chrome/browser/ui/bookmarks/bookmark_utils.h index 1626d25..747858d 100644 --- a/chrome/browser/ui/bookmarks/bookmark_utils.h +++ b/chrome/browser/ui/bookmarks/bookmark_utils.h
@@ -64,14 +64,6 @@ // Returns true if the Apps shortcut should be displayed in the bookmark bar. bool ShouldShowAppsShortcutInBookmarkBar(Profile* profile); -// Whether the menu item and shortcut to bookmark a tab should be removed from -// the user interface. -bool ShouldRemoveBookmarkThisTabUI(Profile* profile); - -// Whether the menu item and shortcut to bookmark all tabs should be removed -// from the user interface. -bool ShouldRemoveBookmarkAllTabsUI(Profile* profile); - // Returns the drag operations for the specified node. int GetBookmarkDragOperation(content::BrowserContext* browser_context, const bookmarks::BookmarkNode* node);
diff --git a/chrome/browser/ui/browser_commands.cc b/chrome/browser/ui/browser_commands.cc index e0e19b8..bcf9e2a 100644 --- a/chrome/browser/ui/browser_commands.cc +++ b/chrome/browser/ui/browser_commands.cc
@@ -222,18 +222,6 @@ namespace chrome { namespace { -bool CanBookmarkCurrentTabInternal(const Browser* browser, - bool check_remove_bookmark_ui) { - BookmarkModel* model = - BookmarkModelFactory::GetForBrowserContext(browser->profile()); - return browser_defaults::bookmarks_enabled && - browser->profile()->GetPrefs()->GetBoolean( - bookmarks::prefs::kEditBookmarksEnabled) && - model && model->loaded() && browser->is_type_normal() && - (!check_remove_bookmark_ui || - !chrome::ShouldRemoveBookmarkThisTabUI(browser->profile())); -} - #if BUILDFLAG(ENABLE_EXTENSIONS) const extensions::Extension* GetExtensionForBrowser(Browser* browser) { return extensions::ExtensionRegistry::Get(browser->profile()) @@ -1032,8 +1020,6 @@ } void BookmarkCurrentTabAllowingExtensionOverrides(Browser* browser) { - DCHECK(!chrome::ShouldRemoveBookmarkThisTabUI(browser->profile())); - #if BUILDFLAG(ENABLE_EXTENSIONS) const extensions::Extension* extension = nullptr; extensions::Command command; @@ -1057,7 +1043,12 @@ } bool CanBookmarkCurrentTab(const Browser* browser) { - return CanBookmarkCurrentTabInternal(browser, true); + BookmarkModel* model = + BookmarkModelFactory::GetForBrowserContext(browser->profile()); + return browser_defaults::bookmarks_enabled && + browser->profile()->GetPrefs()->GetBoolean( + bookmarks::prefs::kEditBookmarksEnabled) && + model && model->loaded() && browser->is_type_normal(); } void BookmarkAllTabs(Browser* browser) { @@ -1071,8 +1062,7 @@ bool CanBookmarkAllTabs(const Browser* browser) { return browser->tab_strip_model()->count() > 1 && - !chrome::ShouldRemoveBookmarkAllTabsUI(browser->profile()) && - CanBookmarkCurrentTabInternal(browser, false); + CanBookmarkCurrentTab(browser); } void SaveCreditCard(Browser* browser) {
diff --git a/chrome/browser/ui/extensions/application_launch.cc b/chrome/browser/ui/extensions/application_launch.cc index 2958d23..e8b995b 100644 --- a/chrome/browser/ui/extensions/application_launch.cc +++ b/chrome/browser/ui/extensions/application_launch.cc
@@ -6,15 +6,20 @@ #include <memory> #include <string> +#include <utility> #include "apps/launcher.h" #include "base/bind.h" +#include "base/command_line.h" +#include "base/files/file_path.h" #include "base/macros.h" #include "base/metrics/histogram_macros.h" #include "base/time/time.h" #include "build/build_config.h" #include "chrome/browser/app_mode/app_mode_utils.h" #include "chrome/browser/apps/app_service/app_launch_params.h" +#include "chrome/browser/apps/app_service/launch_utils.h" +#include "chrome/browser/apps/platform_apps/platform_app_launch.h" #include "chrome/browser/banners/app_banner_settings_helper.h" #include "chrome/browser/engagement/site_engagement_service.h" #include "chrome/browser/extensions/extension_service.h" @@ -25,12 +30,14 @@ #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_commands.h" #include "chrome/browser/ui/browser_finder.h" +#include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/browser_navigator_params.h" #include "chrome/browser/ui/browser_tabstrip.h" #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/extensions/extension_enable_flow.h" #include "chrome/browser/ui/extensions/extension_enable_flow_delegate.h" #include "chrome/browser/ui/web_applications/system_web_app_ui_utils.h" +#include "chrome/browser/ui/web_applications/web_app_launch_manager.h" #include "chrome/browser/ui/web_applications/web_app_launch_utils.h" #include "chrome/browser/web_applications/components/file_handler_manager.h" #include "chrome/browser/web_applications/components/web_app_helpers.h" @@ -515,3 +522,32 @@ extensions::FeatureProvider::GetAPIFeature("app.runtime"); return feature && feature->IsAvailableToExtension(extension).is_available(); } + +void LaunchAppWithCallback( + Profile* profile, + const std::string& app_id, + const base::CommandLine& command_line, + const base::FilePath& current_directory, + base::OnceCallback<void(Browser* browser, + apps::mojom::LaunchContainer container)> callback) { + apps::mojom::LaunchContainer container; + if (apps::OpenExtensionApplicationWindow(profile, app_id, command_line, + current_directory)) { + const extensions::Extension* extension = + extensions::ExtensionRegistry::Get(profile)->GetInstalledExtension( + app_id); + // TODO(crbug.com/1061843): Remove this when BMO launches. + if (extension && extension->from_bookmark()) + web_app::RecordAppWindowLaunch(profile, app_id); + + container = apps::mojom::LaunchContainer::kLaunchContainerWindow; + } else if (apps::OpenExtensionApplicationTab(profile, app_id)) { + container = apps::mojom::LaunchContainer::kLaunchContainerTab; + } else { + // Open an empty browser window as the app_id is invalid. + apps::CreateBrowserWithNewTabPage(profile); + container = apps::mojom::LaunchContainer::kLaunchContainerNone; + } + std::move(callback).Run(BrowserList::GetInstance()->GetLastActive(), + container); +}
diff --git a/chrome/browser/ui/extensions/application_launch.h b/chrome/browser/ui/extensions/application_launch.h index 3baed70..52b87f5 100644 --- a/chrome/browser/ui/extensions/application_launch.h +++ b/chrome/browser/ui/extensions/application_launch.h
@@ -11,6 +11,11 @@ class Browser; class Profile; +namespace base { +class CommandLine; +class FilePath; +} // namespace base + namespace content { class WebContents; } @@ -59,4 +64,17 @@ // chrome.app.runtime.onLaunched event. bool CanLaunchViaEvent(const extensions::Extension* extension); +// Attempt to open |app_id| in a new window or tab. Open an empty browser +// window if unsuccessful. The user's preferred launch container for the app +// (standalone window or browser tab) is used. |callback| will be called with +// the container type used to open the app, kLaunchContainerNone if an empty +// browser window was opened. +void LaunchAppWithCallback( + Profile* profile, + const std::string& app_id, + const base::CommandLine& command_line, + const base::FilePath& current_directory, + base::OnceCallback<void(Browser* browser, + apps::mojom::LaunchContainer container)> callback); + #endif // CHROME_BROWSER_UI_EXTENSIONS_APPLICATION_LAUNCH_H_
diff --git a/chrome/browser/ui/gtk/gtk_ui.cc b/chrome/browser/ui/gtk/gtk_ui.cc index 5b57ded..ba30b1ca 100644 --- a/chrome/browser/ui/gtk/gtk_ui.cc +++ b/chrome/browser/ui/gtk/gtk_ui.cc
@@ -1096,7 +1096,12 @@ gint scale = gtk_widget_get_scale_factor(fake_window_); DCHECK_GT(scale, 0); gdouble resolution = gdk_screen_get_resolution(screen); - return resolution <= 0 ? scale : resolution * scale / kDefaultDPI; + const float scale_factor = + resolution <= 0 ? scale : resolution * scale / kDefaultDPI; + + // Blacklist scaling factors <120% (crbug.com/484400) and round + // to 1 decimal to prevent rendering problems (crbug.com/485183). + return scale_factor < 1.2f ? 1.0f : roundf(scale_factor * 10) / 10; } void GtkUi::UpdateDeviceScaleFactor() {
diff --git a/chrome/browser/ui/send_tab_to_self/send_tab_to_self_bubble_controller.cc b/chrome/browser/ui/send_tab_to_self/send_tab_to_self_bubble_controller.cc index e1db7bc..0b4f494 100644 --- a/chrome/browser/ui/send_tab_to_self/send_tab_to_self_bubble_controller.cc +++ b/chrome/browser/ui/send_tab_to_self/send_tab_to_self_bubble_controller.cc
@@ -80,14 +80,18 @@ SendTabToSelfClickResult::kClickItem); CreateNewEntry(web_contents_, target_device_name, target_device_guid, GURL(), false); - show_message_ = true; - UpdateIcon(); } void SendTabToSelfBubbleController::OnBubbleClosed() { send_tab_to_self_bubble_view_ = nullptr; } +void SendTabToSelfBubbleController::ShowConfirmationMessage() { + show_message_ = true; + Browser* browser = chrome::FindBrowserWithWebContents(web_contents_); + browser->window()->UpdatePageActionIcon(PageActionIconType::kSendTabToSelf); +} + bool SendTabToSelfBubbleController::InitialSendAnimationShown() const { return GetProfile()->GetPrefs()->GetBoolean( prefs::kInitialSendAnimationShown); @@ -113,11 +117,6 @@ FetchDeviceInfo(); } -void SendTabToSelfBubbleController::UpdateIcon() { - Browser* browser = chrome::FindBrowserWithWebContents(web_contents_); - browser->window()->UpdatePageActionIcon(PageActionIconType::kSendTabToSelf); -} - void SendTabToSelfBubbleController::FetchDeviceInfo() { valid_devices_.clear(); SendTabToSelfSyncService* service =
diff --git a/chrome/browser/ui/send_tab_to_self/send_tab_to_self_bubble_controller.h b/chrome/browser/ui/send_tab_to_self/send_tab_to_self_bubble_controller.h index 2468c1a..298f00e 100644 --- a/chrome/browser/ui/send_tab_to_self/send_tab_to_self_bubble_controller.h +++ b/chrome/browser/ui/send_tab_to_self/send_tab_to_self_bubble_controller.h
@@ -55,6 +55,9 @@ // Close the bubble when the user click on the close button. void OnBubbleClosed(); + // Shows the confirmation message in the omnibox. + void ShowConfirmationMessage(); + // Returns true if the initial "Send" animation that's displayed once per // profile was shown. bool InitialSendAnimationShown() const; @@ -77,9 +80,6 @@ FRIEND_TEST_ALL_PREFIXES(SendTabToSelfBubbleViewImplTest, PopulateScrollView); FRIEND_TEST_ALL_PREFIXES(SendTabToSelfBubbleViewImplTest, DevicePressed); - // Updates the omnibox icon if available. - void UpdateIcon(); - // Get information of valid devices. void FetchDeviceInfo();
diff --git a/chrome/browser/ui/startup/startup_browser_creator_impl.cc b/chrome/browser/ui/startup/startup_browser_creator_impl.cc index d07c15d..72922150 100644 --- a/chrome/browser/ui/startup/startup_browser_creator_impl.cc +++ b/chrome/browser/ui/startup/startup_browser_creator_impl.cc
@@ -25,8 +25,9 @@ #include "base/version.h" #include "build/branding_buildflags.h" #include "build/build_config.h" +#include "chrome/browser/apps/app_service/app_service_proxy.h" +#include "chrome/browser/apps/app_service/app_service_proxy_factory.h" #include "chrome/browser/apps/apps_launch.h" -#include "chrome/browser/apps/launch_service/launch_service.h" #include "chrome/browser/apps/platform_apps/install_chrome_app.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/content_settings/host_content_settings_map_factory.h" @@ -580,8 +581,10 @@ if (!app_id.empty()) { // Opens an empty browser window if the app_id is invalid. - apps::LaunchService::Get(profile)->LaunchApplication( - app_id, command_line_, cur_dir_, base::BindOnce(&FinalizeWebAppLaunch)); + apps::AppServiceProxyFactory::GetForProfile(profile) + ->BrowserAppLauncher() + .LaunchAppWithCallback(app_id, cur_dir_, + base::BindOnce(&FinalizeWebAppLaunch)); return true; }
diff --git a/chrome/browser/ui/toolbar/app_menu_model.cc b/chrome/browser/ui/toolbar/app_menu_model.cc index e2bc74f..dec6a892 100644 --- a/chrome/browser/ui/toolbar/app_menu_model.cc +++ b/chrome/browser/ui/toolbar/app_menu_model.cc
@@ -698,12 +698,6 @@ return app_menu_icon_controller_->GetTypeAndSeverity().type == AppMenuIconController::IconType::UPGRADE_NOTIFICATION; } -#if !defined(OS_LINUX) || defined(USE_AURA) - case IDC_BOOKMARK_THIS_TAB: - return !chrome::ShouldRemoveBookmarkThisTabUI(browser_->profile()); - case IDC_BOOKMARK_ALL_TABS: - return !chrome::ShouldRemoveBookmarkAllTabsUI(browser_->profile()); -#endif default: return true; }
diff --git a/chrome/browser/ui/views/frame/browser_frame_mac.mm b/chrome/browser/ui/views/frame/browser_frame_mac.mm index ec88c9d..1327e38a 100644 --- a/chrome/browser/ui/views/frame/browser_frame_mac.mm +++ b/chrome/browser/ui/views/frame/browser_frame_mac.mm
@@ -10,7 +10,6 @@ #include "chrome/browser/apps/app_shim/app_shim_manager_mac.h" #include "chrome/browser/global_keyboard_shortcuts_mac.h" #include "chrome/browser/media/router/media_router_feature.h" -#include "chrome/browser/ui/bookmarks/bookmark_utils.h" #include "chrome/browser/ui/browser_command_controller.h" #include "chrome/browser/ui/browser_commands.h" #import "chrome/browser/ui/cocoa/browser_window_command_handler.h" @@ -174,24 +173,6 @@ : IDS_ENTER_FULLSCREEN_MAC)); break; } - case IDC_BOOKMARK_THIS_TAB: { - // Extensions have the ability to hide the bookmark tab menu item. - // This only affects the bookmark tab menu item under the main menu. - // The bookmark tab menu item under the app menu has its visibility - // controlled by AppMenuModel. - result->new_hidden_state = - chrome::ShouldRemoveBookmarkThisTabUI(browser->profile()); - break; - } - case IDC_BOOKMARK_ALL_TABS: { - // Extensions have the ability to hide the bookmark all tabs menu - // item. This only affects the bookmark page menu item under the main - // menu. The bookmark page menu item under the app menu has its - // visibility controlled by AppMenuModel. - result->new_hidden_state = - chrome::ShouldRemoveBookmarkAllTabsUI(browser->profile()); - break; - } case IDC_SHOW_AS_TAB: { // Hide this menu option if the window is tabbed or is the devtools // window.
diff --git a/chrome/browser/ui/views/location_bar/star_view.cc b/chrome/browser/ui/views/location_bar/star_view.cc index 0bd16eb..b5c4f0d 100644 --- a/chrome/browser/ui/views/location_bar/star_view.cc +++ b/chrome/browser/ui/views/location_bar/star_view.cc
@@ -18,16 +18,12 @@ #include "chrome/browser/ui/view_ids.h" #include "chrome/browser/ui/views/bookmarks/bookmark_bubble_view.h" #include "chrome/browser/ui/views/feature_promos/feature_promo_bubble_view.h" -#include "chrome/common/extensions/manifest_handlers/ui_overrides_handler.h" #include "chrome/grit/generated_resources.h" #include "components/bookmarks/common/bookmark_pref_names.h" #include "components/omnibox/browser/vector_icons.h" #include "components/strings/grit/components_strings.h" #include "components/variations/variations_associated_data.h" #include "content/public/browser/web_contents.h" -#include "extensions/common/extension_set.h" -#include "extensions/common/feature_switch.h" -#include "extensions/common/permissions/permissions_data.h" #include "ui/base/l10n/l10n_util.h" #include "ui/gfx/color_utils.h" #include "ui/gfx/paint_vector_icon.h" @@ -61,8 +57,6 @@ page_action_icon_delegate), browser_(browser) { DCHECK(browser_); - extension_observer_.Add( - extensions::ExtensionRegistry::Get(browser_->profile())); edit_bookmarks_enabled_.Init( bookmarks::prefs::kEditBookmarksEnabled, browser_->profile()->GetPrefs(), base::BindRepeating(&StarView::EditBookmarksPrefUpdated, @@ -89,8 +83,7 @@ void StarView::UpdateImpl() { SetVisible(browser_defaults::bookmarks_enabled && - edit_bookmarks_enabled_.GetValue() && - !IsBookmarkStarHiddenByExtension()); + edit_bookmarks_enabled_.GetValue()); } void StarView::OnExecuting(PageActionIconView::ExecuteSource execute_source) { @@ -147,39 +140,6 @@ } } -void StarView::OnExtensionLoaded(content::BrowserContext* browser_context, - const extensions::Extension* extension) { - if (extensions::UIOverrides::RemovesBookmarkButton(extension)) - Update(); -} - -void StarView::OnExtensionUnloaded(content::BrowserContext* browser_context, - const extensions::Extension* extension, - extensions::UnloadedExtensionReason reason) { - if (extensions::UIOverrides::RemovesBookmarkButton(extension)) - Update(); -} - void StarView::EditBookmarksPrefUpdated() { Update(); } - -bool StarView::IsBookmarkStarHiddenByExtension() const { - const extensions::ExtensionSet& extension_set = - extensions::ExtensionRegistry::Get(browser_->profile()) - ->enabled_extensions(); - for (const scoped_refptr<const extensions::Extension>& extension : - extension_set) { - if (!extensions::UIOverrides::RemovesBookmarkButton(extension.get())) - continue; - if (extension->permissions_data()->HasAPIPermission( - extensions::APIPermission::kBookmarkManagerPrivate)) { - return true; - } - if (extensions::FeatureSwitch::enable_override_bookmarks_ui() - ->IsEnabled()) { - return true; - } - } - return false; -}
diff --git a/chrome/browser/ui/views/location_bar/star_view.h b/chrome/browser/ui/views/location_bar/star_view.h index 97cacc82..b95676cd 100644 --- a/chrome/browser/ui/views/location_bar/star_view.h +++ b/chrome/browser/ui/views/location_bar/star_view.h
@@ -9,8 +9,6 @@ #include "base/scoped_observer.h" #include "chrome/browser/ui/views/page_action/page_action_icon_view.h" #include "components/prefs/pref_member.h" -#include "extensions/browser/extension_registry.h" -#include "extensions/browser/extension_registry_observer.h" #include "ui/views/widget/widget.h" #include "ui/views/widget/widget_observer.h" @@ -18,9 +16,7 @@ class CommandUpdater; // The star icon to show a bookmark bubble. -class StarView : public PageActionIconView, - public views::WidgetObserver, - public extensions::ExtensionRegistryObserver { +class StarView : public PageActionIconView, public views::WidgetObserver { public: StarView(CommandUpdater* command_updater, Browser* browser, @@ -45,13 +41,6 @@ // views::WidgetObserver: void OnWidgetDestroying(views::Widget* widget) override; - // extensions::ExtensionRegistryObserver: - void OnExtensionLoaded(content::BrowserContext* browser_context, - const extensions::Extension* extension) override; - void OnExtensionUnloaded(content::BrowserContext* browser_context, - const extensions::Extension* extension, - extensions::UnloadedExtensionReason reason) override; - private: void EditBookmarksPrefUpdated(); bool IsBookmarkStarHiddenByExtension() const; @@ -65,11 +54,6 @@ ScopedObserver<views::Widget, views::WidgetObserver> bookmark_promo_observer_{ this}; - // Observes Extensions for changes to their |extensions::UIOverrides|. - ScopedObserver<extensions::ExtensionRegistry, - extensions::ExtensionRegistryObserver> - extension_observer_{this}; - DISALLOW_COPY_AND_ASSIGN(StarView); };
diff --git a/chrome/browser/ui/views/location_bar/star_view_interactive_uitest.cc b/chrome/browser/ui/views/location_bar/star_view_interactive_uitest.cc index d34f2296..a714cd49 100644 --- a/chrome/browser/ui/views/location_bar/star_view_interactive_uitest.cc +++ b/chrome/browser/ui/views/location_bar/star_view_interactive_uitest.cc
@@ -10,14 +10,13 @@ #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" #include "chrome/browser/bookmarks/bookmark_model_factory.h" -#include "chrome/browser/extensions/extension_browsertest.h" -#include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/browser/ui/views/bookmarks/bookmark_bubble_view.h" #include "chrome/browser/ui/views/frame/browser_view.h" #include "chrome/browser/ui/views/page_action/page_action_icon_view.h" #include "chrome/browser/ui/views/toolbar/toolbar_view.h" #include "chrome/common/pref_names.h" +#include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/interactive_test_utils.h" #include "chrome/test/base/ui_test_utils.h" #include "components/bookmarks/browser/bookmark_model.h" @@ -26,22 +25,15 @@ #include "components/prefs/pref_service.h" #include "content/public/test/browser_test_utils.h" #include "content/public/test/test_utils.h" -#include "extensions/common/extension_builder.h" -#include "extensions/common/feature_switch.h" #include "ui/base/ui_base_switches.h" #include "ui/events/event_utils.h" #include "ui/views/animation/test/ink_drop_host_view_test_api.h" namespace { -class StarViewTest : public extensions::ExtensionBrowserTest { +class StarViewTest : public InProcessBrowserTest { public: - StarViewTest() - // In order to let a vanilla extension override the bookmark star, we have - // to enable the switch. - : enable_override_( - extensions::FeatureSwitch::enable_override_bookmarks_ui(), - true) {} + StarViewTest() = default; ~StarViewTest() override = default; PageActionIconView* GetStarIcon() { @@ -51,8 +43,6 @@ } private: - extensions::FeatureSwitch::ScopedOverride enable_override_; - DISALLOW_COPY_AND_ASSIGN(StarViewTest); }; @@ -129,32 +119,4 @@ } } -// Test that installing an extension that overrides the bookmark star -// successfully hides the star. -IN_PROC_BROWSER_TEST_F(StarViewTest, ExtensionCanOverrideBookmarkStar) { - // By default, we should show the star. - EXPECT_TRUE(GetStarIcon()->GetVisible()); - - // Create and install an extension that overrides the bookmark star. - extensions::DictionaryBuilder chrome_ui_overrides; - chrome_ui_overrides.Set( - "bookmarks_ui", - extensions::DictionaryBuilder().Set("remove_button", true).Build()); - scoped_refptr<const extensions::Extension> extension = - extensions::ExtensionBuilder() - .SetManifest( - extensions::DictionaryBuilder() - .Set("name", "overrides star") - .Set("manifest_version", 2) - .Set("version", "0.1") - .Set("description", "override the star") - .Set("chrome_ui_overrides", chrome_ui_overrides.Build()) - .Build()) - .Build(); - extension_service()->AddExtension(extension.get()); - - // The star should now be hidden. - EXPECT_FALSE(GetStarIcon()->GetVisible()); -} - } // namespace
diff --git a/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc b/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc index 2775be73..d5edd0c 100644 --- a/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc +++ b/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc
@@ -199,6 +199,14 @@ DCHECK(!base::FeatureList::IsEnabled(omnibox::kWebUIOmniboxPopup)) << "With the WebUI omnibox popup enabled, the code should not try to " "fetch the child result view."; + + // TODO(tommycli): https://crbug.com/1063071 + // Making this method public was a mistake. Outside callers have no idea about + // our internal state, and there's now a crash in this area. For now, let's + // return nullptr, but the ultimate fix is orinj's OmniboxPopupModel refactor. + if (i >= children().size()) + return nullptr; + return static_cast<OmniboxResultView*>(children()[i]); }
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc index 2fcd1eb..06c402c4 100644 --- a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc +++ b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
@@ -744,6 +744,12 @@ if (selected_line == OmniboxPopupModel::kNoMatch) return nullptr; + // TODO(tommycli): https://crbug.com/1063071 + // Diving into |popup_view_| was a mistake. Here's a hotfix to stop the crash, + // but the ultimate fix should be to move this logic into OmniboxPopupModel. + if (!popup_view_ || popup_view_->result_view_at(selected_line) == nullptr) + return nullptr; + return popup_view_->result_view_at(selected_line)->GetSecondaryButton(); } @@ -792,6 +798,12 @@ if (selected_line == OmniboxPopupModel::kNoMatch) return false; + // TODO(tommycli): https://crbug.com/1063071 + // Diving into |popup_view_| was a mistake. Here's a hotfix to stop the crash, + // but the ultimate fix should be to move this logic into OmniboxPopupModel. + if (!popup_view_ || popup_view_->result_view_at(selected_line) == nullptr) + return false; + return popup_view_->result_view_at(selected_line) ->MaybeTriggerSecondaryButton(event); }
diff --git a/chrome/browser/ui/views/payments/credit_card_editor_view_controller_browsertest.cc b/chrome/browser/ui/views/payments/credit_card_editor_view_controller_browsertest.cc index 487820bfd..e96cfce9 100644 --- a/chrome/browser/ui/views/payments/credit_card_editor_view_controller_browsertest.cc +++ b/chrome/browser/ui/views/payments/credit_card_editor_view_controller_browsertest.cc
@@ -277,7 +277,7 @@ GetLabelText(static_cast<payments::DialogViewID>( EditorViewController::GetInputFieldViewId( autofill::CREDIT_CARD_NAME_FULL)))); - EXPECT_EQ(base::ASCIIToUTF16("12/2020"), + EXPECT_EQ(card.ExpirationDateForDisplay(), GetLabelText(static_cast<payments::DialogViewID>( EditorViewController::GetInputFieldViewId( autofill::CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR))));
diff --git a/chrome/browser/ui/views/payments/payment_request_browsertest.cc b/chrome/browser/ui/views/payments/payment_request_browsertest.cc index ea48e7b8..d6d466b 100644 --- a/chrome/browser/ui/views/payments/payment_request_browsertest.cc +++ b/chrome/browser/ui/views/payments/payment_request_browsertest.cc
@@ -147,7 +147,10 @@ WaitForObservedEvent(); // The actual structure of the card response is unit-tested. - ExpectBodyContains({"4111111111111111", "Test User", "11", "2022"}); + ExpectBodyContains( + {"4111111111111111", "Test User", + base::UTF16ToUTF8(card.Expiration2DigitMonthAsString()).c_str(), + base::UTF16ToUTF8(card.Expiration4DigitYearAsString()).c_str()}); ExpectBodyContains({"John", "H.", "Doe", "Underworld", "666 Erebus St.", "Apt 8", "Elysium", "CA", "91111", "US", "16502111111"}); }
diff --git a/chrome/browser/ui/views/payments/payment_request_dialog_view.cc b/chrome/browser/ui/views/payments/payment_request_dialog_view.cc index baed14a..de89a85d2 100644 --- a/chrome/browser/ui/views/payments/payment_request_dialog_view.cc +++ b/chrome/browser/ui/views/payments/payment_request_dialog_view.cc
@@ -184,6 +184,7 @@ request_->web_contents(), GetProfile(), url, std::move(callback)), &controller_map_), /* animate = */ !request_->skipped_payment_request_ui()); + request_->OnPaymentHandlerOpenWindowCalled(); HideProcessingSpinner(); }
diff --git a/chrome/browser/ui/views/payments/payment_request_payment_response_browsertest.cc b/chrome/browser/ui/views/payments/payment_request_payment_response_browsertest.cc index fe378e8..e331ea0 100644 --- a/chrome/browser/ui/views/payments/payment_request_payment_response_browsertest.cc +++ b/chrome/browser/ui/views/payments/payment_request_payment_response_browsertest.cc
@@ -5,6 +5,7 @@ #include <vector> #include "base/macros.h" +#include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "chrome/browser/ui/browser_commands.h" #include "chrome/browser/ui/views/payments/payment_request_browsertest_base.h" @@ -45,10 +46,15 @@ PayWithCreditCardAndWait(base::ASCIIToUTF16("123")); // Test that the card details were sent to the merchant. - ExpectBodyContains({"\"cardNumber\": \"4111111111111111\"", - "\"cardSecurityCode\": \"123\"", - "\"cardholderName\": \"Test User\"", - "\"expiryMonth\": \"11\"", "\"expiryYear\": \"2022\""}); + ExpectBodyContains( + {"\"cardNumber\": \"4111111111111111\"", "\"cardSecurityCode\": \"123\"", + "\"cardholderName\": \"Test User\"", + base::StringPrintf( + "\"expiryMonth\": \"%s\"", + base::UTF16ToUTF8(card.Expiration2DigitMonthAsString()).c_str()), + base::StringPrintf( + "\"expiryYear\": \"%s\"", + base::UTF16ToUTF8(card.Expiration4DigitYearAsString()).c_str())}); // Test that the billing address was sent to the merchant. ExpectBodyContains(
diff --git a/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_icon_view.cc b/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_icon_view.cc index 1f53232..5471e6fe 100644 --- a/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_icon_view.cc +++ b/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_icon_view.cc
@@ -13,6 +13,7 @@ #include "chrome/grit/generated_resources.h" #include "components/omnibox/browser/omnibox_edit_model.h" #include "components/omnibox/browser/omnibox_view.h" +#include "components/send_tab_to_self/features.h" #include "ui/base/l10n/l10n_util.h" #include "ui/strings/grit/ui_strings.h" @@ -54,9 +55,13 @@ return; } - if (GetVisible()) { + if (GetVisible() || + base::FeatureList::IsEnabled(kSendTabToSelfOmniboxSendingAnimation)) { SendTabToSelfBubbleController* controller = GetController(); if (controller && controller->show_message()) { + if (!GetVisible()) { + SetVisible(true); + } controller->set_show_message(false); if (initial_animation_state_ == AnimationState::kShowing && label()->GetVisible()) { @@ -67,7 +72,7 @@ AnimateIn(IDS_BROWSER_SHARING_OMNIBOX_SENDING_LABEL); } } - } else if (omnibox_view->model()->has_focus() && + } else if (!GetVisible() && omnibox_view->model()->has_focus() && !omnibox_view->model()->user_input_in_progress()) { SendTabToSelfBubbleController* controller = GetController(); // Shows the "Send" animation once per profile.
diff --git a/chrome/browser/ui/web_applications/web_app_launch_manager.h b/chrome/browser/ui/web_applications/web_app_launch_manager.h index ac8a487..8408f4e 100644 --- a/chrome/browser/ui/web_applications/web_app_launch_manager.h +++ b/chrome/browser/ui/web_applications/web_app_launch_manager.h
@@ -17,6 +17,11 @@ struct AppLaunchParams; } // namespace apps +namespace base { +class CommandLine; +class FilePath; +} // namespace base + namespace content { class WebContents; } // namespace content @@ -41,8 +46,8 @@ const base::CommandLine& command_line, const base::FilePath& current_directory, base::OnceCallback<void(Browser* browser, - apps::mojom::LaunchContainer container)> callback) - override; + apps::mojom::LaunchContainer container)> + callback); private: void LaunchWebApplication(
diff --git a/chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.cc index fc4be59..0875097 100644 --- a/chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.cc
@@ -275,6 +275,12 @@ } } +void AssistantOptInFlowScreenHandler::OnAssistantSettingsEnabled(bool enabled) { + // Close the opt-in screen is the Assistant is disabled. + if (!enabled) + HandleFlowFinished(); +} + void AssistantOptInFlowScreenHandler::OnAssistantStatusChanged( ash::mojom::AssistantState state) { if (state != ash::mojom::AssistantState::NOT_READY) {
diff --git a/chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.h index bad0ee1c..5a43ecb 100644 --- a/chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.h +++ b/chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.h
@@ -96,6 +96,7 @@ void Initialize() override; // ash::AssistantStateObserver: + void OnAssistantSettingsEnabled(bool enabled) override; void OnAssistantStatusChanged(ash::mojom::AssistantState state) override; // Connect to assistant settings manager.
diff --git a/chrome/browser/ui/webui/settings/chromeos/os_settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/chromeos/os_settings_localized_strings_provider.cc index 67bf544..212c0efc 100644 --- a/chrome/browser/ui/webui/settings/chromeos/os_settings_localized_strings_provider.cc +++ b/chrome/browser/ui/webui/settings/chromeos/os_settings_localized_strings_provider.cc
@@ -1723,6 +1723,10 @@ l10n_util::GetStringFUTF16( IDS_SETTINGS_SEARCH_NO_RESULTS_HELP, base::ASCIIToUTF16(chrome::kOsSettingsSearchHelpURL))); + + html_source->AddBoolean( + "newOsSettingsSearch", + base::FeatureList::IsEnabled(chromeos::features::kNewOsSettingsSearch)); } void AddDateTimeStrings(content::WebUIDataSource* html_source) {
diff --git a/chrome/browser/web_applications/components/external_install_options.cc b/chrome/browser/web_applications/components/external_install_options.cc index cb664fc..615a1e2 100644 --- a/chrome/browser/web_applications/components/external_install_options.cc +++ b/chrome/browser/web_applications/components/external_install_options.cc
@@ -37,7 +37,8 @@ add_to_quick_launch_bar, override_previous_user_uninstall, bypass_service_worker_check, require_manifest, force_reinstall, wait_for_windows_closed, install_placeholder, - reinstall_placeholder, uninstall_and_replace) == + reinstall_placeholder, uninstall_and_replace, + additional_search_terms) == std::tie(other.url, other.user_display_mode, other.install_source, other.add_to_applications_menu, other.add_to_desktop, other.add_to_quick_launch_bar, @@ -45,7 +46,7 @@ other.bypass_service_worker_check, other.require_manifest, other.force_reinstall, other.wait_for_windows_closed, other.install_placeholder, other.reinstall_placeholder, - other.uninstall_and_replace); + other.uninstall_and_replace, other.additional_search_terms); } std::ostream& operator<<(std::ostream& out, @@ -72,7 +73,10 @@ << "\n reinstall_placeholder: " << install_options.reinstall_placeholder << "\n uninstall_and_replace:\n " - << base::JoinString(install_options.uninstall_and_replace, "\n "); + << base::JoinString(install_options.uninstall_and_replace, "\n ") + << "\n additional_search_terms:\n " + << base::JoinString(install_options.additional_search_terms, + "\n "); } InstallManager::InstallParams ConvertExternalInstallOptionsToParams( @@ -91,6 +95,8 @@ install_options.bypass_service_worker_check; params.require_manifest = install_options.require_manifest; + params.additional_search_terms = install_options.additional_search_terms; + return params; }
diff --git a/chrome/browser/web_applications/components/external_install_options.h b/chrome/browser/web_applications/components/external_install_options.h index 1a69eb50..d991274 100644 --- a/chrome/browser/web_applications/components/external_install_options.h +++ b/chrome/browser/web_applications/components/external_install_options.h
@@ -83,6 +83,10 @@ // A list of app_ids that the Web App System should attempt to uninstall and // replace with this app (e.g maintain shelf pins, app list positions). std::vector<AppId> uninstall_and_replace; + + // Additional keywords that will be used by the OS when searching for the app. + // Only affects Chrome OS. + std::vector<std::string> additional_search_terms; }; std::ostream& operator<<(std::ostream& out,
diff --git a/chrome/browser/web_applications/components/install_manager.cc b/chrome/browser/web_applications/components/install_manager.cc index 22ea5a9..2142c69a 100644 --- a/chrome/browser/web_applications/components/install_manager.cc +++ b/chrome/browser/web_applications/components/install_manager.cc
@@ -8,6 +8,12 @@ namespace web_app { +InstallManager::InstallParams::InstallParams() = default; + +InstallManager::InstallParams::~InstallParams() = default; + +InstallManager::InstallParams::InstallParams(const InstallParams&) = default; + InstallManager::InstallManager(Profile* profile) : profile_(profile) {} InstallManager::~InstallManager() = default;
diff --git a/chrome/browser/web_applications/components/install_manager.h b/chrome/browser/web_applications/components/install_manager.h index 7233c3c9..d85f4ac 100644 --- a/chrome/browser/web_applications/components/install_manager.h +++ b/chrome/browser/web_applications/components/install_manager.h
@@ -99,6 +99,10 @@ // These params are a subset of ExternalInstallOptions. struct InstallParams { + InstallParams(); + ~InstallParams(); + InstallParams(const InstallParams&); + DisplayMode user_display_mode = DisplayMode::kUndefined; // URL to be used as start_url if manifest is unavailable. @@ -110,6 +114,8 @@ bool bypass_service_worker_check = false; bool require_manifest = false; + + std::vector<std::string> additional_search_terms; }; // Starts a background web app installation process for a given // |web_contents|.
diff --git a/chrome/browser/web_applications/proto/web_app.proto b/chrome/browser/web_applications/proto/web_app.proto index c5634b9..f24bee9 100644 --- a/chrome/browser/web_applications/proto/web_app.proto +++ b/chrome/browser/web_applications/proto/web_app.proto
@@ -82,4 +82,6 @@ repeated int32 downloaded_icon_sizes = 11; // A list of file handlers. repeated WebAppFileHandlerProto file_handlers = 12; + // A list of additional search terms to use when searching for the app. + repeated string additional_search_terms = 13; }
diff --git a/chrome/browser/web_applications/system_web_app_manager.cc b/chrome/browser/web_applications/system_web_app_manager.cc index 80f36dd8..d9960f9 100644 --- a/chrome/browser/web_applications/system_web_app_manager.cc +++ b/chrome/browser/web_applications/system_web_app_manager.cc
@@ -169,6 +169,11 @@ install_options.bypass_service_worker_check = true; install_options.force_reinstall = force_update; install_options.uninstall_and_replace = info.uninstall_and_replace; + + const auto& search_terms = info.additional_search_terms; + std::transform(search_terms.begin(), search_terms.end(), + std::back_inserter(install_options.additional_search_terms), + [](int term) { return l10n_util::GetStringUTF8(term); }); return install_options; }
diff --git a/chrome/browser/web_applications/system_web_app_manager_browsertest.cc b/chrome/browser/web_applications/system_web_app_manager_browsertest.cc index 994c732..53cf771 100644 --- a/chrome/browser/web_applications/system_web_app_manager_browsertest.cc +++ b/chrome/browser/web_applications/system_web_app_manager_browsertest.cc
@@ -650,24 +650,15 @@ IN_PROC_BROWSER_TEST_P(SystemWebAppManagerAdditionalSearchTermsTest, AdditionalSearchTerms) { - // TODO(crbug.com/1054195): Make the expectation unconditional. - const web_app::ProviderType provider = provider_type(); - WaitForSystemAppInstallAndLaunch(GetMockAppType()); AppId app_id = GetManager().GetAppIdForSystemApp(GetMockAppType()).value(); apps::AppServiceProxy* proxy = apps::AppServiceProxyFactory::GetForProfile(browser()->profile()); proxy->AppRegistryCache().ForOneApp( - app_id, [provider](const apps::AppUpdate& update) { - // TODO(crbug.com/1054195): Unconditionally expect "Security". - if (provider == ProviderType::kBookmarkApps) { - EXPECT_EQ(std::vector<std::string>({"Security"}), - update.AdditionalSearchTerms()); - } else { - EXPECT_EQ(std::vector<std::string>({}), - update.AdditionalSearchTerms()); - } + app_id, [](const apps::AppUpdate& update) { + EXPECT_EQ(std::vector<std::string>({"Security"}), + update.AdditionalSearchTerms()); }); }
diff --git a/chrome/browser/web_applications/web_app.cc b/chrome/browser/web_applications/web_app.cc index 5dac424..4c869e8 100644 --- a/chrome/browser/web_applications/web_app.cc +++ b/chrome/browser/web_applications/web_app.cc
@@ -162,6 +162,11 @@ file_handlers_ = std::move(file_handlers); } +void WebApp::SetAdditionalSearchTerms( + std::vector<std::string> additional_search_terms) { + additional_search_terms_ = std::move(additional_search_terms); +} + void WebApp::SetSyncData(SyncData sync_data) { sync_data_ = std::move(sync_data); } @@ -205,6 +210,8 @@ out << " icon_size_on_disk: " << size << std::endl; for (const apps::FileHandler& file_handler : app.file_handlers_) out << " file_handler: " << file_handler << std::endl; + for (const std::string& additional_search_term : app.additional_search_terms_) + out << " additional_search_term: " << additional_search_term << std::endl; return out; } @@ -226,13 +233,15 @@ app1.icon_infos_, app1.downloaded_icon_sizes_, app1.display_mode_, app1.user_display_mode_, app1.is_locally_installed_, app1.is_in_sync_install_, - app1.file_handlers_, app1.sync_data_) == + app1.file_handlers_, app1.additional_search_terms_, + app1.sync_data_) == std::tie(app2.app_id_, app2.sources_, app2.name_, app2.launch_url_, app2.description_, app2.scope_, app2.theme_color_, app2.icon_infos_, app2.downloaded_icon_sizes_, app2.display_mode_, app2.user_display_mode_, app2.is_locally_installed_, app2.is_in_sync_install_, - app2.file_handlers_, app2.sync_data_); + app2.file_handlers_, app2.additional_search_terms_, + app2.sync_data_); } bool operator!=(const WebApp& app1, const WebApp& app2) {
diff --git a/chrome/browser/web_applications/web_app.h b/chrome/browser/web_applications/web_app.h index bddcba866..0469b28 100644 --- a/chrome/browser/web_applications/web_app.h +++ b/chrome/browser/web_applications/web_app.h
@@ -74,6 +74,10 @@ const apps::FileHandlers& file_handlers() const { return file_handlers_; } + const std::vector<std::string>& additional_search_terms() const { + return additional_search_terms_; + } + // While local |name| and |theme_color| may vary from device to device, the // synced copies of these fields are replicated to all devices. The synced // copies are read by a device to generate a placeholder icon (if needed). Any @@ -119,6 +123,8 @@ // Performs sorting of |sizes| vector. Must be called rarely. void SetDownloadedIconSizes(std::vector<SquareSizePx> sizes); void SetFileHandlers(apps::FileHandlers file_handlers); + void SetAdditionalSearchTerms( + std::vector<std::string> additional_search_terms); void SetSyncData(SyncData sync_data); @@ -149,6 +155,7 @@ std::vector<WebApplicationIconInfo> icon_infos_; std::vector<SquareSizePx> downloaded_icon_sizes_; apps::FileHandlers file_handlers_; + std::vector<std::string> additional_search_terms_; SyncData sync_data_; };
diff --git a/chrome/browser/web_applications/web_app_database.cc b/chrome/browser/web_applications/web_app_database.cc index a4284fb..8cf0baed 100644 --- a/chrome/browser/web_applications/web_app_database.cc +++ b/chrome/browser/web_applications/web_app_database.cc
@@ -151,6 +151,12 @@ } } + for (const auto& additional_search_term : web_app.additional_search_terms()) { + // Additional search terms should be sanitized before being added here. + DCHECK(!additional_search_term.empty()); + local_data->add_additional_search_terms(additional_search_term); + } + return local_data; } @@ -299,6 +305,17 @@ } web_app->SetFileHandlers(std::move(file_handlers)); + std::vector<std::string> additional_search_terms; + for (const std::string& additional_search_term : + local_data.additional_search_terms()) { + if (additional_search_term.empty()) { + DLOG(ERROR) << "WebApp AdditionalSearchTerms proto action parse error"; + return nullptr; + } + additional_search_terms.push_back(additional_search_term); + } + web_app->SetAdditionalSearchTerms(std::move(additional_search_terms)); + return web_app; }
diff --git a/chrome/browser/web_applications/web_app_database_unittest.cc b/chrome/browser/web_applications/web_app_database_unittest.cc index 3f88259..9fbfdb81 100644 --- a/chrome/browser/web_applications/web_app_database_unittest.cc +++ b/chrome/browser/web_applications/web_app_database_unittest.cc
@@ -117,6 +117,15 @@ app->SetFileHandlers(CreateFileHandlers(suffix)); + const int num_additional_search_terms = suffix & 7; + std::vector<std::string> additional_search_terms( + num_additional_search_terms); + for (int i = 0; i < num_additional_search_terms; ++i) { + additional_search_terms[i] = + "Foo_" + base::NumberToString(suffix) + "_" + base::NumberToString(i); + } + app->SetAdditionalSearchTerms(std::move(additional_search_terms)); + WebApp::SyncData sync_data; sync_data.name = "Sync" + name; sync_data.theme_color = synced_theme_color; @@ -310,6 +319,7 @@ EXPECT_TRUE(app->sync_data().name.empty()); EXPECT_FALSE(app->sync_data().theme_color.has_value()); EXPECT_TRUE(app->file_handlers().empty()); + EXPECT_TRUE(app->additional_search_terms().empty()); controller().RegisterApp(std::move(app)); Registry registry = database_factory().ReadRegistry(); @@ -341,6 +351,7 @@ EXPECT_TRUE(app_copy->sync_data().name.empty()); EXPECT_FALSE(app_copy->sync_data().theme_color.has_value()); EXPECT_TRUE(app_copy->file_handlers().empty()); + EXPECT_TRUE(app_copy->additional_search_terms().empty()); } TEST_F(WebAppDatabaseTest, WebAppWithManyIcons) {
diff --git a/chrome/browser/web_applications/web_app_install_finalizer.cc b/chrome/browser/web_applications/web_app_install_finalizer.cc index cd85101..55404515 100644 --- a/chrome/browser/web_applications/web_app_install_finalizer.cc +++ b/chrome/browser/web_applications/web_app_install_finalizer.cc
@@ -162,6 +162,7 @@ : DisplayMode::kBrowser); } + web_app->SetAdditionalSearchTerms(web_app_info.additional_search_terms); web_app->AddSource(source); web_app->SetIsInSyncInstall(false);
diff --git a/chrome/browser/web_applications/web_app_install_task.cc b/chrome/browser/web_applications/web_app_install_task.cc index d34e0dd78..1048ac7 100644 --- a/chrome/browser/web_applications/web_app_install_task.cc +++ b/chrome/browser/web_applications/web_app_install_task.cc
@@ -456,6 +456,14 @@ // redirected. Will be overridden by manifest values if present. DCHECK(install_params_->fallback_start_url.is_valid()); web_app_info->app_url = install_params_->fallback_start_url; + + // If `additional_search_terms` was a manifest property, it would be + // sanitized while parsing the manifest. Since it's not, we sanitize it + // here. + for (std::string& search_term : install_params_->additional_search_terms) { + if (!search_term.empty()) + web_app_info->additional_search_terms.push_back(std::move(search_term)); + } } data_retriever_->CheckInstallabilityAndRetrieveManifest(
diff --git a/chrome/common/OWNERS b/chrome/common/OWNERS index 163695ae..b9db373a 100644 --- a/chrome/common/OWNERS +++ b/chrome/common/OWNERS
@@ -62,3 +62,6 @@ # Heap profiler per-file heap_profiler*=alph@chromium.org + +# Web Applications +per-file web_application_info.*=file://chrome/browser/web_applications/OWNERS
diff --git a/chrome/common/extensions/api/autotest_private.idl b/chrome/common/extensions/api/autotest_private.idl index 649cc99..78ad6c8d 100644 --- a/chrome/common/extensions/api/autotest_private.idl +++ b/chrome/common/extensions/api/autotest_private.idl
@@ -459,6 +459,7 @@ boolean isAnimating; boolean isOverflow; Bounds[] iconsBoundsInScreen; + boolean isShelfWidgetAnimating; }; // Mapped to HotseatSwipeDescriptor in ash/public/cpp/shelf_ui_info.h.
diff --git a/chrome/common/extensions/api/notifications.idl b/chrome/common/extensions/api/notifications.idl index 3100d6a..dc6c9502 100644 --- a/chrome/common/extensions/api/notifications.idl +++ b/chrome/common/extensions/api/notifications.idl
@@ -175,7 +175,7 @@ static void clear(DOMString notificationId, optional ClearCallback callback); - // Retrieves all the notifications. + // Retrieves all the notifications of this app or extension. // |callback|: Returns the set of notification_ids currently in the system. static void getAll(GetAllCallback callback);
diff --git a/chrome/common/web_application_info.h b/chrome/common/web_application_info.h index f6e4826..8a7edcb 100644 --- a/chrome/common/web_application_info.h +++ b/chrome/common/web_application_info.h
@@ -88,6 +88,9 @@ // The extensions and mime types the app can handle. std::vector<blink::Manifest::FileHandler> file_handlers; + + // Additional search terms that users can use to find the app. + std::vector<std::string> additional_search_terms; }; std::ostream& operator<<(std::ostream& out,
diff --git a/chrome/credential_provider/gaiacp/event_logs_upload_manager.cc b/chrome/credential_provider/gaiacp/event_logs_upload_manager.cc index 63666de7..1dc72112 100644 --- a/chrome/credential_provider/gaiacp/event_logs_upload_manager.cc +++ b/chrome/credential_provider/gaiacp/event_logs_upload_manager.cc
@@ -56,6 +56,9 @@ // Maximum number of upload requests to make per upload invocation. constexpr int kMaxAllowedNumberOfUploadRequests = 5; +// Maximum number of retries if a HTTP call to the backend fails. +constexpr unsigned int kMaxNumHttpRetries = 3; + // Maximum size of the log entries payload in bytes per HTTP request. // TODO (crbug.com/1043195): Change this to use an experiment flag once an // experiment framework for GCPW is available. @@ -498,7 +501,7 @@ hr = WinHttpUrlFetcher::BuildRequestAndFetchResultFromHttpService( EventLogsUploadManager::Get()->GetGcpwServiceUploadEventViewerLogsUrl(), access_token, {}, request_dict, kDefaultUploadLogsRequestTimeout, - &request_result); + kMaxNumHttpRetries, &request_result); if (FAILED(hr)) { LOGFN(ERROR) << "BuildRequestAndFetchResultFromHttpService hr=" @@ -506,13 +509,6 @@ return hr; } - if (!request_result.has_value() || - request_result->FindDictKey(kErrorKeyInRequestResult)) { - LOGFN(ERROR) << "error=" - << *request_result->FindDictKey(kErrorKeyInRequestResult); - return E_FAIL; - } - // Store the chunk id which is the last uploaded event log id // in registry so we know where to start next time. SetGlobalFlag(kEventLogUploadLastUploadedIdRegKey, chunk_id);
diff --git a/chrome/credential_provider/gaiacp/gem_device_details_manager.cc b/chrome/credential_provider/gaiacp/gem_device_details_manager.cc index 6f37a2a4..375923a9 100644 --- a/chrome/credential_provider/gaiacp/gem_device_details_manager.cc +++ b/chrome/credential_provider/gaiacp/gem_device_details_manager.cc
@@ -49,6 +49,9 @@ const char kMacAddressParameterName[] = "wlan_mac_addr"; const char kUploadDeviceDetailsResponseDeviceResourceIdParameterName[] = "deviceResourceId"; + +// Maximum number of retries if a HTTP call to the backend fails. +constexpr unsigned int kMaxNumHttpRetries = 3; } // namespace // static @@ -127,7 +130,7 @@ hr = WinHttpUrlFetcher::BuildRequestAndFetchResultFromHttpService( GemDeviceDetailsManager::Get()->GetGemServiceUploadDeviceDetailsUrl(), access_token, {}, *request_dict_, upload_device_details_request_timeout_, - &request_result); + kMaxNumHttpRetries, &request_result); if (FAILED(hr)) { LOGFN(ERROR) << "BuildRequestAndFetchResultFromHttpService hr=" @@ -135,13 +138,6 @@ return E_FAIL; } - base::Value* error_detail = - request_result->FindDictKey(kErrorKeyInRequestResult); - if (error_detail) { - LOGFN(ERROR) << "error=" << *error_detail; - hr = E_FAIL; - } - std::string* resource_id = request_result->FindStringKey( kUploadDeviceDetailsResponseDeviceResourceIdParameterName); if (resource_id) {
diff --git a/chrome/credential_provider/gaiacp/password_recovery_manager.cc b/chrome/credential_provider/gaiacp/password_recovery_manager.cc index 5fa34af..437967ba 100644 --- a/chrome/credential_provider/gaiacp/password_recovery_manager.cc +++ b/chrome/credential_provider/gaiacp/password_recovery_manager.cc
@@ -80,6 +80,9 @@ constexpr size_t kSessionKeyLength = 32; +// Maximum number of retries if a HTTP call to the backend fails. +constexpr unsigned int kMaxNumHttpRetries = 3; + bool Base64DecodeCryptographicKey(const std::string& cryptographic_key, std::string* out) { std::string cryptographic_key_copy; @@ -275,7 +278,8 @@ // |public_key| to be used for encryption. HRESULT hr = WinHttpUrlFetcher::BuildRequestAndFetchResultFromHttpService( PasswordRecoveryManager::Get()->GetEscrowServiceGenerateKeyPairUrl(), - access_token, {}, request_dict, request_timeout, &request_result); + access_token, {}, request_dict, request_timeout, kMaxNumHttpRetries, + &request_result); if (FAILED(hr)) { LOGFN(ERROR) << "BuildRequestAndFetchResultFromHttpService hr=" @@ -363,7 +367,8 @@ HRESULT hr = WinHttpUrlFetcher::BuildRequestAndFetchResultFromHttpService( PasswordRecoveryManager::Get()->GetEscrowServiceGetPrivateKeyUrl( *resource_id), - access_token, {}, {}, request_timeout, &request_result); + access_token, {}, {}, request_timeout, kMaxNumHttpRetries, + &request_result); if (FAILED(hr)) { LOGFN(ERROR) << "BuildRequestAndFetchResultFromHttpService hr="
diff --git a/chrome/credential_provider/gaiacp/win_http_url_fetcher.cc b/chrome/credential_provider/gaiacp/win_http_url_fetcher.cc index 0e20189..7e0fb1d3 100644 --- a/chrome/credential_provider/gaiacp/win_http_url_fetcher.cc +++ b/chrome/credential_provider/gaiacp/win_http_url_fetcher.cc
@@ -10,6 +10,8 @@ #include <atlconv.h> #include <process.h> +#include <set> + #include "base/base64.h" #include "base/containers/span.h" #include "base/json/json_reader.h" @@ -20,6 +22,18 @@ #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "chrome/credential_provider/gaiacp/logging.h" +#include "chrome/credential_provider/gaiacp/mdm_utils.h" + +namespace { +// Key name containing the HTTP error code within the dictionary returned by the +// server in case of errors. +constexpr char kHttpErrorCodeKeyNameInResponse[] = "code"; + +// The HTTP response codes for which the request is re-tried on failure. +const std::set<int> kRetryableHttpErrorCodes = { + 503, // Service Unavailable + 504 // Gateway Timeout +}; // Self deleting http service requester. This class will try to make a query // using the given url fetcher. It will delete itself when the request is @@ -41,11 +55,12 @@ // thread can self delete. class HttpServiceRequest { public: - explicit HttpServiceRequest( - std::unique_ptr<credential_provider::WinHttpUrlFetcher> fetcher) - : fetcher_(std::move(fetcher)) { - DCHECK(fetcher_); - } + static HttpServiceRequest* Create( + const GURL& request_url, + const std::string& access_token, + const std::vector<std::pair<std::string, std::string>>& headers, + const std::string& request_body, + const base::TimeDelta& request_timeout); // Tries to fetch the request stored in |fetcher_| in a background thread // within the given |request_timeout|. If the background thread returns before @@ -103,6 +118,12 @@ } private: + explicit HttpServiceRequest( + std::unique_ptr<credential_provider::WinHttpUrlFetcher> fetcher) + : fetcher_(std::move(fetcher)) { + DCHECK(fetcher_); + } + void OrphanRequest() { bool delete_self = false; { @@ -158,6 +179,44 @@ bool is_processing_ = true; }; +HttpServiceRequest* HttpServiceRequest::Create( + const GURL& request_url, + const std::string& access_token, + const std::vector<std::pair<std::string, std::string>>& headers, + const std::string& request_body, + const base::TimeDelta& request_timeout) { + auto url_fetcher = + credential_provider::WinHttpUrlFetcher::Create(request_url); + if (!url_fetcher) { + LOGFN(ERROR) << "Could not create valid fetcher for url=" + << request_url.spec(); + return nullptr; + } + + url_fetcher->SetRequestHeader("Content-Type", "application/json"); + url_fetcher->SetRequestHeader("Authorization", + ("Bearer " + access_token).c_str()); + for (auto& header : headers) + url_fetcher->SetRequestHeader(header.first.c_str(), header.second.c_str()); + + if (!request_body.empty()) { + HRESULT hr = url_fetcher->SetRequestBody(request_body.c_str()); + if (FAILED(hr)) { + LOGFN(ERROR) << "fetcher.SetRequestBody hr=" + << credential_provider::putHR(hr); + return nullptr; + } + } + + if (!request_timeout.is_zero()) { + url_fetcher->SetHttpRequestTimeout(request_timeout.InMilliseconds()); + } + + return (new HttpServiceRequest(std::move(url_fetcher))); +} + +} // namespace + namespace credential_provider { // static @@ -353,50 +412,56 @@ const std::vector<std::pair<std::string, std::string>>& headers, const base::Value& request_dict, const base::TimeDelta& request_timeout, + unsigned int request_retries, base::Optional<base::Value>* request_result) { DCHECK(request_result); - - auto url_fetcher = WinHttpUrlFetcher::Create(request_url); - if (!url_fetcher) { - LOGFN(ERROR) << "Could not create valid fetcher for url=" - << request_url.spec(); - return E_FAIL; - } - - url_fetcher->SetRequestHeader("Content-Type", "application/json"); - url_fetcher->SetRequestHeader("Authorization", - ("Bearer " + access_token).c_str()); - for (auto& header : headers) - url_fetcher->SetRequestHeader(header.first.c_str(), header.second.c_str()); - HRESULT hr = S_OK; + std::string request_body; if (request_dict.is_dict()) { - std::string body; - if (!base::JSONWriter::Write(request_dict, &body)) { + if (!base::JSONWriter::Write(request_dict, &request_body)) { LOGFN(ERROR) << "base::JSONWriter::Write failed"; return E_FAIL; } + } - hr = url_fetcher->SetRequestBody(body.c_str()); - if (FAILED(hr)) { - LOGFN(ERROR) << "fetcher.SetRequestBody hr=" << putHR(hr); + for (unsigned int try_count = 0; try_count <= request_retries; ++try_count) { + HttpServiceRequest* request = HttpServiceRequest::Create( + request_url, access_token, headers, request_body, request_timeout); + + if (!request) return E_FAIL; + + auto extracted_param = + request->WaitForResponseFromHttpService(request_timeout); + + if (!extracted_param) { + hr = E_FAIL; + continue; } + *request_result = std::move(extracted_param); + + base::Value* error_detail = + (*request_result)->FindDictKey(kErrorKeyInRequestResult); + if (error_detail) { + hr = E_FAIL; + LOGFN(ERROR) << "error: " << *error_detail; + + // If error code is known, retry only on retryable server errors. + base::Optional<int> error_code = + error_detail->FindIntKey(kHttpErrorCodeKeyNameInResponse); + if (error_code.has_value() && + kRetryableHttpErrorCodes.find(error_code.value()) == + kRetryableHttpErrorCodes.end()) + break; + + continue; + } + + hr = S_OK; + break; } - if (!request_timeout.is_zero()) { - url_fetcher->SetHttpRequestTimeout(request_timeout.InMilliseconds()); - } - - auto extracted_param = (new HttpServiceRequest(std::move(url_fetcher))) - ->WaitForResponseFromHttpService(request_timeout); - - if (!extracted_param) - return E_FAIL; - - *request_result = std::move(extracted_param); - return hr; } } // namespace credential_provider
diff --git a/chrome/credential_provider/gaiacp/win_http_url_fetcher.h b/chrome/credential_provider/gaiacp/win_http_url_fetcher.h index c53c079..a22a519 100644 --- a/chrome/credential_provider/gaiacp/win_http_url_fetcher.h +++ b/chrome/credential_provider/gaiacp/win_http_url_fetcher.h
@@ -30,13 +30,17 @@ // value pairs to be sent with the request. |request_dict| is a dictionary of // json parameters to be sent with the request. This argument will be // converted to a json string and sent as the body of the request. - // |request_timeout| is the maximum time to wait for a response. + // |request_timeout| is the maximum time to wait for a response. If the HTTP + // request times out or fails with an error response code that signifies an + // internal server error (HTTP codes >= 500) then the request will be retried + // |request_retries| number of times before the call is marked failed. static HRESULT BuildRequestAndFetchResultFromHttpService( const GURL& request_url, std::string access_token, const std::vector<std::pair<std::string, std::string>>& headers, const base::Value& request_dict, const base::TimeDelta& request_timeout, + unsigned int request_retries, base::Optional<base::Value>* request_result); virtual ~WinHttpUrlFetcher();
diff --git a/chrome/credential_provider/gaiacp/win_http_url_fetcher_unittests.cc b/chrome/credential_provider/gaiacp/win_http_url_fetcher_unittests.cc index 8daeca47..07e510c 100644 --- a/chrome/credential_provider/gaiacp/win_http_url_fetcher_unittests.cc +++ b/chrome/credential_provider/gaiacp/win_http_url_fetcher_unittests.cc
@@ -13,14 +13,22 @@ // Test the WinHttpUrlFetcher::BuildRequestAndFetchResultFromHttpService method // used to make various HTTP requests. // Parameters are: -// bool true: HTTP call succeeds. -// false: Fails due to invalid response from server. -class GcpWinHttpUrlFetcherTest : public GlsRunnerTestBase, - public ::testing::WithParamInterface<bool> {}; +// 1. int - 0: HTTP call succeeds. +// 1: Fails due to invalid response from server. +// 2: Fails due to a retryable HTTP error (like 503). +// 3: Fails due to a non-retryable HTTP error (like 404). +// 2. int - Number of retries allowed for a HTTP request. +class GcpWinHttpUrlFetcherTest + : public GlsRunnerTestBase, + public ::testing::WithParamInterface<std::tuple<int, int>> {}; TEST_P(GcpWinHttpUrlFetcherTest, BuildRequestAndFetchResultFromHttpServiceTest) { - bool invalid_response = GetParam(); + bool valid_response = std::get<0>(GetParam()) == 0; + bool invalid_response = std::get<0>(GetParam()) == 1; + bool retryable_error_response = std::get<0>(GetParam()) == 2; + bool nonretryable_error_response = std::get<0>(GetParam()) == 3; + int num_retries = std::get<1>(GetParam()); const int timeout_in_millis = 12000; const std::string header1 = "test-header-1"; @@ -42,23 +50,64 @@ std::string expected_response; base::JSONWriter::Write(expected_result, &expected_response); - fake_http_url_fetcher_factory()->SetFakeResponse( - test_url, FakeWinHttpUrlFetcher::Headers(), - invalid_response ? "Invalid json response" : expected_response); + std::string response; + if (invalid_response) { + response = "Invalid json response"; + } else if (retryable_error_response) { + response = + "{\n\"error\": {" + "\"code\": 503,\n" + "\"message\": \"Service unavailable\"," + "\"status\": \"UNAVAILABLE\"\n}\n}"; + } else if (nonretryable_error_response) { + response = + "{\n\"error\": {" + "\"code\": 403,\n" + "\"message\": \"The caller does not have permission\"," + "\"status\": \"PERMISSION_DENIED\"\n}\n}"; + } else { + response = expected_response; + } + + if (num_retries == 0) { + fake_http_url_fetcher_factory()->SetFakeResponse( + test_url, FakeWinHttpUrlFetcher::Headers(), response); + } else { + fake_http_url_fetcher_factory()->SetFakeResponseForSpecifiedNumRequests( + test_url, FakeWinHttpUrlFetcher::Headers(), response, num_retries); + fake_http_url_fetcher_factory()->SetFakeResponseForSpecifiedNumRequests( + test_url, FakeWinHttpUrlFetcher::Headers(), expected_response, 1); + } fake_http_url_fetcher_factory()->SetCollectRequestData(true); HRESULT hr = WinHttpUrlFetcher::BuildRequestAndFetchResultFromHttpService( test_url, access_token, {{header1, header1_value}}, request, - request_timeout, &request_result); + request_timeout, num_retries, &request_result); - if (invalid_response) { - ASSERT_TRUE(FAILED(hr)); + if (num_retries == 0) { + if (invalid_response || retryable_error_response || + nonretryable_error_response) { + ASSERT_TRUE(FAILED(hr)); + } else { + ASSERT_EQ(S_OK, hr); + ASSERT_EQ(expected_result, request_result.value()); + } } else { - ASSERT_EQ(S_OK, hr); - ASSERT_EQ(expected_result, request_result.value()); + if (nonretryable_error_response) { + ASSERT_TRUE(FAILED(hr)); + } else { + ASSERT_EQ(S_OK, hr); + ASSERT_EQ(expected_result, request_result.value()); + } } - ASSERT_TRUE(fake_http_url_fetcher_factory()->requests_created() > 0); + if (valid_response || nonretryable_error_response) { + ASSERT_EQ(1UL, fake_http_url_fetcher_factory()->requests_created()); + } else { + ASSERT_EQ(num_retries + 1UL, + fake_http_url_fetcher_factory()->requests_created()); + } + for (size_t idx = 0; idx < fake_http_url_fetcher_factory()->requests_created(); ++idx) { FakeWinHttpUrlFetcherFactory::RequestData request_data = @@ -78,7 +127,8 @@ INSTANTIATE_TEST_SUITE_P(All, GcpWinHttpUrlFetcherTest, - ::testing::Values(true, false)); + ::testing::Combine(::testing::Values(0, 1, 2, 3), + ::testing::Values(0, 1, 3))); } // namespace testing } // namespace credential_provider
diff --git a/chrome/credential_provider/test/gcp_fakes.cc b/chrome/credential_provider/test/gcp_fakes.cc index 8d098ae2..ee8e868 100644 --- a/chrome/credential_provider/test/gcp_fakes.cc +++ b/chrome/credential_provider/test/gcp_fakes.cc
@@ -641,8 +641,26 @@ const WinHttpUrlFetcher::Headers& headers, const std::string& response, HANDLE send_response_event_handle /*=INVALID_HANDLE_VALUE*/) { - fake_responses_[url] = - Response(headers, response, send_response_event_handle); + fake_responses_[url].clear(); + fake_responses_[url].push_back( + Response(headers, response, send_response_event_handle)); + remove_fake_response_when_created_ = false; +} + +void FakeWinHttpUrlFetcherFactory::SetFakeResponseForSpecifiedNumRequests( + const GURL& url, + const WinHttpUrlFetcher::Headers& headers, + const std::string& response, + unsigned int num_requests, + HANDLE send_response_event_handle /* =INVALID_HANDLE_VALUE */) { + if (fake_responses_.find(url) == fake_responses_.end()) { + fake_responses_[url] = std::deque<Response>(); + } + for (unsigned int i = 0; i < num_requests; ++i) { + fake_responses_[url].push_back( + Response(headers, response, send_response_event_handle)); + } + remove_fake_response_when_created_ = true; } void FakeWinHttpUrlFetcherFactory::SetFakeFailedResponse(const GURL& url, @@ -667,11 +685,17 @@ FakeWinHttpUrlFetcher* fetcher = new FakeWinHttpUrlFetcher(std::move(url)); if (fake_responses_.count(url) != 0) { - const Response& response = fake_responses_[url]; + const Response& response = fake_responses_[url].front(); fetcher->response_headers_ = response.headers; fetcher->response_ = response.response; fetcher->send_response_event_handle_ = response.send_response_event_handle; + + if (remove_fake_response_when_created_) { + fake_responses_[url].pop_front(); + if (fake_responses_[url].empty()) + fake_responses_.erase(url); + } } else { DCHECK(failed_http_fetch_hr_.count(url) > 0); fetcher->response_hr_ = failed_http_fetch_hr_[url];
diff --git a/chrome/credential_provider/test/gcp_fakes.h b/chrome/credential_provider/test/gcp_fakes.h index 5faf444f..2d2c973 100644 --- a/chrome/credential_provider/test/gcp_fakes.h +++ b/chrome/credential_provider/test/gcp_fakes.h
@@ -5,6 +5,7 @@ #ifndef CHROME_CREDENTIAL_PROVIDER_TEST_GCP_FAKES_H_ #define CHROME_CREDENTIAL_PROVIDER_TEST_GCP_FAKES_H_ +#include <deque> #include <map> #include <memory> #include <string> @@ -296,12 +297,23 @@ FakeWinHttpUrlFetcherFactory(); ~FakeWinHttpUrlFetcherFactory(); + // Sets the given |response| for any number of HTTP requests made for |url|. void SetFakeResponse( const GURL& url, const WinHttpUrlFetcher::Headers& headers, const std::string& response, HANDLE send_response_event_handle = INVALID_HANDLE_VALUE); + // Queues the given |response| for the specified |num_requests| number of HTTP + // requests made for |url|. Different responses for the URL can be set by + // calling this function multiple times with different responses. + void SetFakeResponseForSpecifiedNumRequests( + const GURL& url, + const WinHttpUrlFetcher::Headers& headers, + const std::string& response, + unsigned int num_requests, + HANDLE send_response_event_handle = INVALID_HANDLE_VALUE); + // Sets the response as a failed http attempt. The return result // from http_url_fetcher.Fetch() would be set as the input HRESULT // to this method. @@ -343,10 +355,11 @@ HANDLE send_response_event_handle; }; - std::map<GURL, Response> fake_responses_; + std::map<GURL, std::deque<Response>> fake_responses_; std::map<GURL, HRESULT> failed_http_fetch_hr_; size_t requests_created_ = 0; bool collect_request_data_ = false; + bool remove_fake_response_when_created_ = false; std::vector<RequestData> requests_data_; };
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 6cb0bdd2..82b4975 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -1130,6 +1130,7 @@ "../browser/safe_browsing/cloud_content_scanning/deep_scanning_dialog_views_browsertest.cc", "../browser/safe_browsing/cloud_content_scanning/deep_scanning_test_utils.cc", "../browser/safe_browsing/cloud_content_scanning/deep_scanning_test_utils.h", + "../browser/safe_browsing/download_protection/deep_scanning_browsertest.cc", "../browser/safe_browsing/download_protection/download_protection_service_browsertest.cc", "../browser/safe_browsing/test_safe_browsing_database_helper.cc", "../browser/safe_browsing/test_safe_browsing_database_helper.h", @@ -1728,7 +1729,6 @@ "../browser/extensions/chrome_app_api_browsertest.cc", "../browser/extensions/chrome_test_extension_loader_browsertest.cc", "../browser/extensions/chrome_theme_url_browsertest.cc", - "../browser/extensions/chrome_ui_overrides_browsertest.cc", "../browser/extensions/content_capabilities_browsertest.cc", "../browser/extensions/content_script_apitest.cc", "../browser/extensions/content_security_policy_apitest.cc", @@ -4372,9 +4372,7 @@ "../browser/ui/app_list/search/cros_action_history/cros_action_recorder_unittest.cc", "../browser/ui/app_list/search/launcher_search/launcher_search_icon_image_loader_unittest.cc", "../browser/ui/app_list/search/search_result_ranker/app_launch_event_logger_unittest.cc", - "../browser/ui/app_list/search/search_result_ranker/app_launch_predictor_unittest.cc", "../browser/ui/app_list/search/search_result_ranker/app_list_launch_metrics_provider_unittest.cc", - "../browser/ui/app_list/search/search_result_ranker/app_search_result_ranker_unittest.cc", "../browser/ui/app_list/search/search_result_ranker/chip_ranker_unittest.cc", "../browser/ui/app_list/search/search_result_ranker/frecency_store_unittest.cc", "../browser/ui/app_list/search/search_result_ranker/histogram_util_unittest.cc", @@ -6831,8 +6829,8 @@ testonly = true deps = [ + "base:closure_compile", "data:closure_compile", - # TODO(crbug/1000989): Add a dep for base/js2gtest.js. ] }
diff --git a/chrome/test/base/BUILD.gn b/chrome/test/base/BUILD.gn new file mode 100644 index 0000000..f06af47 --- /dev/null +++ b/chrome/test/base/BUILD.gn
@@ -0,0 +1,14 @@ +# Copyright 2020 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//third_party/closure_compiler/compile_js.gni") + +js_type_check("closure_compile") { + deps = [ ":js2gtest" ] +} + +js_library("js2gtest") { + deps = [ "//chrome/test/data:test_api_js" ] + externs_list = [ "d8_externs.js" ] +}
diff --git a/chrome/test/base/OWNERS b/chrome/test/base/OWNERS index 5ab77afc..28da547c 100644 --- a/chrome/test/base/OWNERS +++ b/chrome/test/base/OWNERS
@@ -7,6 +7,7 @@ per-file javascript_browser_test.*=dtseng@chromium.org per-file js2gtest.*=dtseng@chromium.org per-file js2gtest.*=file://ui/webui/PLATFORM_OWNERS +per-file *.js=file://ui/webui/PLATFORM_OWNERS per-file *javascript*=file://ui/webui/PLATFORM_OWNERS per-file *web_ui*=file://ui/webui/PLATFORM_OWNERS
diff --git a/chrome/test/base/d8_externs.js b/chrome/test/base/d8_externs.js new file mode 100644 index 0000000..affe3ed --- /dev/null +++ b/chrome/test/base/d8_externs.js
@@ -0,0 +1,20 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** @fileoverview + * Externs for d8, v8's shell at v8/src/d8/. + * @externs + */ + +/** @param {...string} var_args */ +function print(var_args) {} + +/** @param {number} code */ +function quit(code) {} + +/** + * @param {string} path + * @return {string} + */ +function read(path) {}
diff --git a/chrome/test/base/js2gtest.js b/chrome/test/base/js2gtest.js index de0be48..6939664e 100644 --- a/chrome/test/base/js2gtest.js +++ b/chrome/test/base/js2gtest.js
@@ -24,7 +24,7 @@ quit(-1); } -[_, +const [_, // Full path to the test input file, relative to the current working // directory. fullTestFilePath, @@ -94,7 +94,7 @@ * Helpful hint pointing back to the source js. * @type {string} */ -const argHint = '// ' + arguments.join(' '); +const argHint = '// ' + Array.from(arguments).join(' '); /** * @type {Array<string>} @@ -117,6 +117,7 @@ /** * Generates the header of the cc file to stdout. * @param {string?} testFixture Name of test fixture. + * @this {!Object} */ function maybeGenHeader(testFixture) { if (!needGenHeader) { @@ -181,9 +182,7 @@ } -/** - * @type {Array<{path: string, base: string>} - */ +/** @type {!Array<string>} */ const pathStack = []; @@ -204,6 +203,7 @@ 'Only relative "foo/bar" or source-absolute "//foo/bar" paths are ' + 'supported - not file-system absolute: "/foo/bar"'); quit(-1); + return ''; } else { // The include-file path is relative to the file that included it. const currentPath = pathStack[pathStack.length - 1]; @@ -252,8 +252,8 @@ * Called by the javascript in the deps file to add modules and their * dependencies. * @param {string} path Relative path to the file. - * @param Array<string> provides Objects provided by this file. - * @param Array<string> requires Objects required by this file. + * @param {!Array<string>} provides Objects provided by this file. + * @param {!Array<string>} requires Objects required by this file. */ goog.addDependency = function(path, provides, requires) { provides.forEach(function(provide) { @@ -373,9 +373,10 @@ * will invoke the |testBody| for |testFixture|.|testFunction|. * @param {string} testFixture The name of this test's fixture. * @param {string} testFunction The name of this test's function. - * @param {Function} testBody The function body to execute for this test. + * @param {!Function} testBody The function body to execute for this test. * @param {string=} opt_preamble C++ to be generated before the TEST_F block. * Useful for including #ifdef blocks. See TEST_F_WITH_PREAMBLE. + * @this {!Object} */ function TEST_F(testFixture, testFunction, testBody, opt_preamble) { maybeGenHeader(testFixture); @@ -563,7 +564,7 @@ * Useful for including #ifdef blocks. * @param {string} testFixture The name of this test's fixture. * @param {string} testFunction The name of this test's function. - * @param {Function} testBody The function body to execute for this test. + * @param {!Function} testBody The function body to execute for this test. */ function TEST_F_WITH_PREAMBLE(preamble, testFixture, testFunction, testBody) { TEST_F(testFixture, testFunction, testBody, preamble);
diff --git a/chrome/test/data/extensions/api_test/cross_origin_xhr/content_script/manifest.json b/chrome/test/data/extensions/api_test/cross_origin_xhr/content_script/manifest.json index 1c533b1..8b67ac0 100644 --- a/chrome/test/data/extensions/api_test/cross_origin_xhr/content_script/manifest.json +++ b/chrome/test/data/extensions/api_test/cross_origin_xhr/content_script/manifest.json
@@ -10,5 +10,5 @@ "js": [ "content_script.js" ], "matches": [ "http://localhost/*" ] } ], - "permissions": ["http://a.com/", "http://*.b.com/", "ftp://127.0.0.1/*"] + "permissions": ["ftp://127.0.0.1/*"] }
diff --git a/chrome/test/data/extensions/api_test/cross_origin_xhr/content_script/test.js b/chrome/test/data/extensions/api_test/cross_origin_xhr/content_script/test.js index 97ce1fa..d4e6f3f 100644 --- a/chrome/test/data/extensions/api_test/cross_origin_xhr/content_script/test.js +++ b/chrome/test/data/extensions/api_test/cross_origin_xhr/content_script/test.js
@@ -45,21 +45,6 @@ chrome.test.assertEq('injected', message); chrome.test.runTests([ - function allowedOrigin() { - doReq('http://a.com', true); - }, - function diallowedOrigin() { - doReq('http://c.com', false); - }, - function allowedSubdomain() { - doReq('http://foo.b.com', true); - }, - function noSubdomain() { - doReq('http://b.com', true); - }, - function disallowedSubdomain() { - doReq('http://foob.com', false); - }, // TODO(asargent): Explicitly create SSL test server and enable the test. // function disallowedSSL() { // doReq('https://a.com', false);
diff --git a/chrome/test/data/extensions/api_test/keybinding/remove_bookmark_shortcut/background.js b/chrome/test/data/extensions/api_test/keybinding/remove_bookmark_shortcut/background.js deleted file mode 100644 index e9a4164..0000000 --- a/chrome/test/data/extensions/api_test/keybinding/remove_bookmark_shortcut/background.js +++ /dev/null
@@ -1,5 +0,0 @@ -// 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. - -chrome.test.notifyPass();
diff --git a/chrome/test/data/extensions/api_test/keybinding/remove_bookmark_shortcut/manifest.json b/chrome/test/data/extensions/api_test/keybinding/remove_bookmark_shortcut/manifest.json deleted file mode 100644 index 553a9e9..0000000 --- a/chrome/test/data/extensions/api_test/keybinding/remove_bookmark_shortcut/manifest.json +++ /dev/null
@@ -1,19 +0,0 @@ -{ - "name": "An extension that removes the bookmark shortcut", - "version": "1.0", - "manifest_version": 2, - "background": { - "scripts": ["background.js"] - }, - "permissions": ["activeTab"], - "chrome_ui_overrides": { - "bookmarks_ui": { - "remove_bookmark_shortcut": true - } - }, - "commands": { - "_execute_browser_action": { - "suggested_key": "Ctrl+Shift+F" - } - } -}
diff --git a/chrome/test/data/extensions/api_test/webstore_private/install_blocked_child.html b/chrome/test/data/extensions/api_test/webstore_private/install_blocked_child.html new file mode 100644 index 0000000..b0892bf3 --- /dev/null +++ b/chrome/test/data/extensions/api_test/webstore_private/install_blocked_child.html
@@ -0,0 +1,22 @@ +<!-- + * 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. +--> +<script src="common.js"></script> +<script> + +runTests([ + function installBlockedChild() { + var manifest = getManifest(); + var expectedError = + "Apps and extensions can only be modified by the manager (test_parent_0@google.com)." + chrome.webstorePrivate.beginInstallWithManifest3( + {id: appId, manifest: manifest}, + callbackFail(expectedError, function(result) { + assertEq("blocked_for_child_account", result); + })); + }, +]); + +</script>
diff --git a/chrome/test/data/extensions/api_test/webstore_private/install_cancel_child.html b/chrome/test/data/extensions/api_test/webstore_private/install_cancel_child.html new file mode 100644 index 0000000..777b320 --- /dev/null +++ b/chrome/test/data/extensions/api_test/webstore_private/install_cancel_child.html
@@ -0,0 +1,21 @@ +<!-- + * Copyright 2020 The Chromium Authors. All rights reserved. Use of this + * source code is governed by a BSD-style license that can be found in the + * LICENSE file. +--> +<script src="common.js"></script> +<script> + +runTests([ + function installCanceledChild() { + var manifest = getManifest(); + chrome.webstorePrivate.beginInstallWithManifest3( + {id: appId, manifest: manifest}, + function(result) { + assertEq(result, "user_cancelled"); + succeed(); + }); + }, +]); + +</script>
diff --git a/chrome/test/data/extensions/api_test/webstore_private/install_child.html b/chrome/test/data/extensions/api_test/webstore_private/install_child.html new file mode 100644 index 0000000..3c7487d0 --- /dev/null +++ b/chrome/test/data/extensions/api_test/webstore_private/install_child.html
@@ -0,0 +1,23 @@ +<!-- + * Copyright 2020 The Chromium Authors. All rights reserved. Use of this + * source code is governed by a BSD-style license that can be found in the + * LICENSE file. +--> +<script src="common.js"></script> +<script> + +runTests([ + function installChild() { + var manifest = getManifest(); + chrome.webstorePrivate.beginInstallWithManifest3( + {id: appId, manifest: manifest}, + callbackPass(function(result) { + assertEq("", result); + + // Complete the installation + chrome.webstorePrivate.completeInstall(appId, callbackPass()); + })); + }, +]); + +</script>
diff --git a/chrome/test/data/extensions/bookmarks_ui/manifest.json b/chrome/test/data/extensions/bookmarks_ui/manifest.json deleted file mode 100644 index 9794387..0000000 --- a/chrome/test/data/extensions/bookmarks_ui/manifest.json +++ /dev/null
@@ -1,12 +0,0 @@ -{ - "name": "chrome_ui_overrides.bookmarks_ui", - "version": "0.1", - "manifest_version": 2, - "description": "end-to-end browser test for chrome_ui_overrides.bookmarks_ui shortcut removal", - "chrome_ui_overrides": { - "bookmarks_ui": { - "remove_bookmark_shortcut": true, - "remove_bookmark_open_pages_shortcut": true - } - } -}
diff --git a/chrome/test/data/webui/BUILD.gn b/chrome/test/data/webui/BUILD.gn index cf4ec7c..5304b75b 100644 --- a/chrome/test/data/webui/BUILD.gn +++ b/chrome/test/data/webui/BUILD.gn
@@ -2,7 +2,6 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -import("//build/config/sanitizers/sanitizers.gni") import("//chrome/common/features.gni") import("//chrome/test/base/js2gtest.gni") import("//ui/webui/resources/tools/js_modulizer.gni") @@ -214,6 +213,7 @@ "$root_gen_dir/chrome/test/data/webui/mock_timer.m.js", "$root_gen_dir/chrome/test/data/webui/resources/list_property_update_behavior_tests.m.js", "$root_gen_dir/chrome/test/data/webui/settings/about_page_tests.m.js", + "$root_gen_dir/chrome/test/data/webui/settings/all_sites_tests.m.js", "$root_gen_dir/chrome/test/data/webui/settings/appearance_page_test.m.js", "$root_gen_dir/chrome/test/data/webui/settings/appearance_fonts_page_test.m.js", "$root_gen_dir/chrome/test/data/webui/settings/autofill_page_test.m.js", @@ -250,10 +250,12 @@ "$root_gen_dir/chrome/test/data/webui/settings/pref_util_tests.m.js", "$root_gen_dir/chrome/test/data/webui/settings/prefs_test_cases.m.js", "$root_gen_dir/chrome/test/data/webui/settings/prefs_tests.m.js", + "$root_gen_dir/chrome/test/data/webui/settings/protocol_handlers_tests.m.js", "$root_gen_dir/chrome/test/data/webui/settings/reset_page_test.m.js", "$root_gen_dir/chrome/test/data/webui/settings/search_engines_page_test.m.js", "$root_gen_dir/chrome/test/data/webui/settings/search_page_test.m.js", "$root_gen_dir/chrome/test/data/webui/settings/search_settings_test.m.js", + "$root_gen_dir/chrome/test/data/webui/settings/security_keys_subpage_test.m.js", "$root_gen_dir/chrome/test/data/webui/settings/settings_main_test.m.js", "$root_gen_dir/chrome/test/data/webui/settings/settings_menu_test.m.js", "$root_gen_dir/chrome/test/data/webui/settings/settings_slider_tests.m.js", @@ -265,6 +267,7 @@ "$root_gen_dir/chrome/test/data/webui/settings/test_about_page_browser_proxy.m.js", "$root_gen_dir/chrome/test/data/webui/settings/test_local_data_browser_proxy.m.js", "$root_gen_dir/chrome/test/data/webui/settings/test_metrics_browser_proxy.m.js", + "$root_gen_dir/chrome/test/data/webui/settings/site_data_test.m.js", "$root_gen_dir/chrome/test/data/webui/settings/site_data_details_subpage_tests.m.js", "$root_gen_dir/chrome/test/data/webui/settings/site_details_tests.m.js", "$root_gen_dir/chrome/test/data/webui/settings/site_details_permission_tests.m.js", @@ -311,11 +314,6 @@ ] } defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ] - - # https://crbug.com/1013656 - if (is_cfi) { - defines += [ "IS_CFI" ] - } } js2gtest("browser_tests_js_mojo_lite_webui") {
diff --git a/chrome/test/data/webui/cr_elements/cr_elements_browsertest.js b/chrome/test/data/webui/cr_elements/cr_elements_browsertest.js index f40919b..9d91b74 100644 --- a/chrome/test/data/webui/cr_elements/cr_elements_browsertest.js +++ b/chrome/test/data/webui/cr_elements/cr_elements_browsertest.js
@@ -94,6 +94,7 @@ /** @override */ extraLibraries: CrElementsBrowserTest.prototype.extraLibraries.concat([ + '../test_util.js', 'cr_toolbar_search_field_tests.js', ]), }; @@ -121,14 +122,7 @@ ]), }; -// https://crbug.com/1013656 - Flaky on Linux CFI. -GEN('#if defined(OS_LINUX) && defined(IS_CFI)'); -GEN('#define MAYBE_Drawer DISABLED_Drawer'); -GEN('#else'); -GEN('#define MAYBE_Drawer Drawer'); -GEN('#endif'); - -TEST_F('CrElementsDrawerTest', 'MAYBE_Drawer', function() { +TEST_F('CrElementsDrawerTest', 'Drawer', function() { mocha.run(); });
diff --git a/chrome/test/data/webui/cr_elements/cr_elements_v3_browsertest.js b/chrome/test/data/webui/cr_elements/cr_elements_v3_browsertest.js index 4ae0ba7d..1e025439 100644 --- a/chrome/test/data/webui/cr_elements/cr_elements_v3_browsertest.js +++ b/chrome/test/data/webui/cr_elements/cr_elements_v3_browsertest.js
@@ -76,8 +76,8 @@ } }; -// https://crbug.com/1008122 - Flaky on Linux CFI and Mac 10.10. -GEN('#if (defined(OS_LINUX) && defined(IS_CFI)) || defined(OS_MACOSX)'); +// https://crbug.com/1008122 - Flaky on Mac 10.10. +GEN('#if defined(OS_MACOSX)'); GEN('#define MAYBE_Drawer DISABLED_Drawer'); GEN('#else'); GEN('#define MAYBE_Drawer Drawer');
diff --git a/chrome/test/data/webui/settings/BUILD.gn b/chrome/test/data/webui/settings/BUILD.gn index 1fa8194..052ad04e 100644 --- a/chrome/test/data/webui/settings/BUILD.gn +++ b/chrome/test/data/webui/settings/BUILD.gn
@@ -9,6 +9,7 @@ js_modulizer("modulize") { input_files = [ "about_page_tests.js", + "all_sites_tests.js", "appearance_fonts_page_test.js", "appearance_page_test.js", "autofill_page_test.js", @@ -46,10 +47,12 @@ "prefs_test_cases.js", "prefs_tests.js", "pref_util_tests.js", + "protocol_handlers_tests.js", "reset_page_test.js", "search_engines_page_test.js", "search_page_test.js", "search_settings_test.js", + "security_keys_subpage_test.js", "settings_animated_pages_test.js", "settings_main_test.js", "settings_menu_test.js", @@ -58,6 +61,7 @@ "settings_textarea_tests.js", "settings_toggle_button_tests.js", "settings_ui_tests.js", + "site_data_test.js", "site_data_details_subpage_tests.js", "site_details_tests.js", "site_details_permission_tests.js", @@ -137,6 +141,7 @@ "sync_test_util.simulateStoredAccounts|simulateStoredAccounts", "test_util.createContentSettingTypeToValuePair|createContentSettingTypeToValuePair", "test_util.createDefaultContentSetting|createDefaultContentSetting", + "test_util.createOriginInfo|createOriginInfo", "test_util.createRawChooserException|createRawChooserException", "test_util.createRawSiteException|createRawSiteException", "test_util.createSiteGroup|createSiteGroup",
diff --git a/chrome/test/data/webui/settings/a11y/edit_dictionary_a11y_test.js b/chrome/test/data/webui/settings/a11y/edit_dictionary_a11y_test.js index a3e79bed..b470cf4 100644 --- a/chrome/test/data/webui/settings/a11y/edit_dictionary_a11y_test.js +++ b/chrome/test/data/webui/settings/a11y/edit_dictionary_a11y_test.js
@@ -46,14 +46,6 @@ /** @override */ name: 'EDIT_DICTIONARY', - /** @override */ - axeOptions: Object.assign({}, SettingsAccessibilityTest.axeOptions, { - 'rules': Object.assign({}, SettingsAccessibilityTest.axeOptions.rules, { - // TODO(crbug.com/1012370): Disable because of timeout in CFI build. - 'hidden-content': {enabled: false}, - }), - }), - /** @type {settings.FakeLanguageSettingsPrivate} */ languageSettingsPrivate_: null,
diff --git a/chrome/test/data/webui/settings/a11y/passwords_a11y_test.js b/chrome/test/data/webui/settings/a11y/passwords_a11y_test.js index ee98ee5..c5d65c5 100644 --- a/chrome/test/data/webui/settings/a11y/passwords_a11y_test.js +++ b/chrome/test/data/webui/settings/a11y/passwords_a11y_test.js
@@ -37,20 +37,7 @@ passwordManager: null, /** @type {PasswordsSectionElement}*/ passwordsSection: null, - // TODO(hcarmona): Create function that overrides defaults to simplify this. - axeOptions: Object.assign({}, SettingsAccessibilityTest.axeOptions, { - 'rules': Object.assign({}, SettingsAccessibilityTest.axeOptions.rules, { - // TODO(hcarmona): Investigate flakyness and enable these tests. - // Disable rules flaky for CFI build. - 'meta-viewport': {enabled: false}, - 'list': {enabled: false}, - 'frame-title': {enabled: false}, - 'label': {enabled: false}, - 'hidden-content': {enabled: false}, - 'aria-valid-attr-value': {enabled: false}, - 'button-name': {enabled: false}, - }), - }), + /** @override */ setup: function() { return new Promise((resolve) => {
diff --git a/chrome/test/data/webui/settings/all_sites_tests.js b/chrome/test/data/webui/settings/all_sites_tests.js index 1da58f3d..5bd9c41 100644 --- a/chrome/test/data/webui/settings/all_sites_tests.js +++ b/chrome/test/data/webui/settings/all_sites_tests.js
@@ -2,6 +2,17 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// clang-format off +// #import {beforeNextRender,flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +// #import {ContentSetting,ContentSettingsTypes,SiteSettingsPrefsBrowserProxyImpl,LocalDataBrowserProxyImpl} from 'chrome://settings/lazy_load.js'; +// #import {CrSettingsPrefs,routes, Router} from 'chrome://settings/settings.js'; +// #import {createContentSettingTypeToValuePair,createOriginInfo,createRawSiteException,createSiteGroup,createSiteSettingsPrefs} from 'chrome://test/settings/test_util.m.js'; +// #import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js'; +// #import {PromiseResolver} from 'chrome://resources/js/promise_resolver.m.js'; +// #import {TestLocalDataBrowserProxy} from 'chrome://test/settings/test_local_data_browser_proxy.m.js'; +// #import {TestSiteSettingsPrefsBrowserProxy} from 'chrome://test/settings/test_site_settings_prefs_browser_proxy.m.js'; +// clang-format on + suite('AllSites', function() { const TEST_COOKIE_LIST = { id: 'example', @@ -61,7 +72,7 @@ // Initialize a site-list before each test. setup(async function() { PolymerTest.clearBody(); - await settings.forceLazyLoaded(); + /* #ignore */ await settings.forceLazyLoaded(); prefsVarious = test_util.createSiteSettingsPrefs([], [ test_util.createContentSettingTypeToValuePair( @@ -403,7 +414,8 @@ assertTrue( buttonType === 'cancel-button' || buttonType === 'action-button'); Polymer.dom.flush(); - siteEntries = testElement.$.listContainer.querySelectorAll('site-entry'); + const siteEntries = + testElement.$.listContainer.querySelectorAll('site-entry'); assertEquals(1, siteEntries.length); const overflowMenuButton = siteEntries[0].$.overflowMenuButton; assertFalse(overflowMenuButton.closest('.row-aligned').hidden); @@ -497,7 +509,8 @@ assertTrue( buttonType === 'cancel-button' || buttonType === 'action-button'); Polymer.dom.flush(); - siteEntries = testElement.$.listContainer.querySelectorAll('site-entry'); + const siteEntries = + testElement.$.listContainer.querySelectorAll('site-entry'); assertEquals(1, siteEntries.length); const overflowMenuButton = siteEntries[0].$.overflowMenuButton; assertFalse(overflowMenuButton.closest('.row-aligned').hidden); @@ -567,7 +580,7 @@ function() { // Test when one origin has permission settings and data, clear data // only clears the data and cookies. - siteGroup = JSON.parse(JSON.stringify(TEST_MULTIPLE_SITE_GROUP)); + const siteGroup = JSON.parse(JSON.stringify(TEST_MULTIPLE_SITE_GROUP)); siteGroup.origins[0].hasPermissionSettings = true; siteGroup.origins[0].usage = 100; siteGroup.origins[0].numCookies = 3; @@ -587,7 +600,8 @@ assertTrue( buttonType === 'cancel-button' || buttonType === 'action-button'); Polymer.dom.flush(); - siteEntries = testElement.$.listContainer.querySelectorAll('site-entry'); + const siteEntries = + testElement.$.listContainer.querySelectorAll('site-entry'); assertTrue(siteEntries.length >= 1); const clearAllButton = testElement.$.clearAllButton.querySelector('cr-button'); @@ -677,7 +691,8 @@ assertTrue( buttonType === 'cancel-button' || buttonType === 'action-button'); Polymer.dom.flush(); - siteEntries = testElement.$.listContainer.querySelectorAll('site-entry'); + const siteEntries = + testElement.$.listContainer.querySelectorAll('site-entry'); assertEquals(1, siteEntries.length); const expandButton = siteEntries[0].$.expandIcon; @@ -716,7 +731,7 @@ } test('cancelling the confirm dialog on clear data works', function() { - siteGroup = JSON.parse(JSON.stringify(TEST_MULTIPLE_SITE_GROUP)); + const siteGroup = JSON.parse(JSON.stringify(TEST_MULTIPLE_SITE_GROUP)); testElement.siteGroupMap.set(siteGroup.etldPlus1, siteGroup); testElement.forceListUpdate_(); assertEquals(1, testElement.filteredList_.length); @@ -727,7 +742,7 @@ }); test('clear single origin data via overflow menu', function() { - siteGroup = JSON.parse(JSON.stringify(TEST_MULTIPLE_SITE_GROUP)); + const siteGroup = JSON.parse(JSON.stringify(TEST_MULTIPLE_SITE_GROUP)); siteGroup.origins[0].hasPermissionSettings = false; siteGroup.origins[0].usage = 100; siteGroup.origins[0].numCookies = 3; @@ -742,7 +757,7 @@ test( 'clear single origin data via overflow menu (has permissions)', function() { - siteGroup = JSON.parse(JSON.stringify(TEST_MULTIPLE_SITE_GROUP)); + const siteGroup = JSON.parse(JSON.stringify(TEST_MULTIPLE_SITE_GROUP)); siteGroup.origins[0].hasPermissionSettings = true; siteGroup.origins[0].usage = 100; siteGroup.origins[0].numCookies = 3; @@ -774,7 +789,8 @@ assertTrue( buttonType === 'cancel-button' || buttonType === 'action-button'); Polymer.dom.flush(); - siteEntries = testElement.$.listContainer.querySelectorAll('site-entry'); + const siteEntries = + testElement.$.listContainer.querySelectorAll('site-entry'); assertEquals(1, siteEntries.length); const expandButton = siteEntries[0].$.expandIcon; @@ -814,7 +830,7 @@ } test('cancelling the confirm dialog on resetting settings works', function() { - siteGroup = JSON.parse(JSON.stringify(TEST_MULTIPLE_SITE_GROUP)); + const siteGroup = JSON.parse(JSON.stringify(TEST_MULTIPLE_SITE_GROUP)); testElement.siteGroupMap.set(siteGroup.etldPlus1, siteGroup); testElement.forceListUpdate_(); assertEquals(1, testElement.filteredList_.length); @@ -827,7 +843,7 @@ test( 'clear single origin permissions via overflow menu (no usage/cookies)', function() { - siteGroup = JSON.parse(JSON.stringify(TEST_MULTIPLE_SITE_GROUP)); + const siteGroup = JSON.parse(JSON.stringify(TEST_MULTIPLE_SITE_GROUP)); siteGroup.origins[0].hasPermissionSettings = true; siteGroup.origins[0].usage = 0; siteGroup.origins[0].numCookies = 0; @@ -842,7 +858,7 @@ test( 'clear single origin permissions via overflow menu (has usage/cookies)', function() { - siteGroup = JSON.parse(JSON.stringify(TEST_MULTIPLE_SITE_GROUP)); + const siteGroup = JSON.parse(JSON.stringify(TEST_MULTIPLE_SITE_GROUP)); siteGroup.origins[0].hasPermissionSettings = true; siteGroup.origins[0].usage = 100; siteGroup.origins[0].numCookies = 10;
diff --git a/chrome/test/data/webui/settings/chromeos/BUILD.gn b/chrome/test/data/webui/settings/chromeos/BUILD.gn index ef360e50..6ee3399 100644 --- a/chrome/test/data/webui/settings/chromeos/BUILD.gn +++ b/chrome/test/data/webui/settings/chromeos/BUILD.gn
@@ -5,7 +5,10 @@ import("//third_party/closure_compiler/compile_js.gni") js_type_check("closure_compile") { - deps = [ ":fake_user_action_recorder" ] + deps = [ + ":fake_settings_search_handler", + ":fake_user_action_recorder", + ] } js_library("fake_user_action_recorder") { @@ -14,3 +17,7 @@ "//ui/webui/resources/js:cr", ] } + +js_library("fake_settings_search_handler") { + deps = [ "//ui/webui/resources/js:cr" ] +}
diff --git a/chrome/test/data/webui/settings/chromeos/fake_settings_search_handler.js b/chrome/test/data/webui/settings/chromeos/fake_settings_search_handler.js new file mode 100644 index 0000000..70c51b6 --- /dev/null +++ b/chrome/test/data/webui/settings/chromeos/fake_settings_search_handler.js
@@ -0,0 +1,35 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview Fake implementation of SettingsSearchHandler for testing. + */ +cr.define('settings', function() { + /** + * Fake implementation of chromeos.settings.mojom.SettingsSearchHandlerRemote. + */ + class FakeSettingsSearchHandler { + constructor() { + /** @private {!Array<string>} */ + this.fakeResults_ = []; + } + + /** + * @param {!Array<string>} results fake results that will be returned + * when Search() is called. + */ + setFakeResults(results) { + this.fakeResults_ = results; + } + + /** + * @param {string} query fake query used to compile search results. + */ + async search(query) { + return this.fakeResults_; + } + } + + return {FakeSettingsSearchHandler: FakeSettingsSearchHandler}; +});
diff --git a/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js b/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js index d79194fc..31f37bb 100644 --- a/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js +++ b/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js
@@ -712,6 +712,29 @@ mocha.run(); }); +// Tests for the new OS Settings Search Box +// eslint-disable-next-line no-var +var OSSettingsSearchBoxBrowserTest = class extends OSSettingsBrowserTest { + /** @override */ + get featureList() { + return {enabled: ['chromeos::features::kNewOsSettingsSearch']}; + } + + /** @override */ + get extraLibraries() { + return super.extraLibraries.concat([ + BROWSER_SETTINGS_PATH + '../test_util.js', + 'fake_settings_search_handler.js', + 'fake_user_action_recorder.js', + 'os_settings_search_box_test.js', + ]); + } +}; + +TEST_F('OSSettingsSearchBoxBrowserTest', 'AllJsTests', () => { + mocha.run(); +}); + // Tests for the side-nav menu. // eslint-disable-next-line no-var var OSSettingsMenuTest = class extends OSSettingsBrowserTest {
diff --git a/chrome/test/data/webui/settings/chromeos/os_settings_search_box_test.js b/chrome/test/data/webui/settings/chromeos/os_settings_search_box_test.js new file mode 100644 index 0000000..df20183 --- /dev/null +++ b/chrome/test/data/webui/settings/chromeos/os_settings_search_box_test.js
@@ -0,0 +1,168 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** @fileoverview Runs tests for the OS settings search box. */ + +suite('OSSettingsSearchBox', () => { + /** @type {?OsToolbar} */ + let toolbar; + + /** @type {?OsSettingsSearchBox} */ + let searchBox; + + /** @type {?CrSearchFieldElement} */ + let field; + + /** @type {?IronDropdownElement} */ + let dropDown; + + /** @type {?IronListElement} */ + let resultList; + + /** @type {*} */ + let settingsSearchHandler; + + /** @type {?chromeos.settings.mojom.UserActionRecorderInterface} */ + let userActionRecorder; + + /** @param {string} term */ + async function simulateSearch(term) { + field.$.searchInput.value = term; + field.onSearchTermInput(); + field.onSearchTermSearch(); + await settingsSearchHandler.search; + Polymer.dom.flush(); + } + + setup(function() { + toolbar = document.querySelector('os-settings-ui').$$('os-toolbar'); + assertTrue(!!toolbar); + searchBox = toolbar.$$('os-settings-search-box'); + assertTrue(!!searchBox); + field = searchBox.$$('cr-toolbar-search-field'); + assertTrue(!!field); + dropDown = searchBox.$$('iron-dropdown'); + assertTrue(!!dropDown); + resultList = searchBox.$$('iron-list'); + assertTrue(!!resultList); + + settingsSearchHandler = new settings.FakeSettingsSearchHandler(); + searchBox.setSearchHandlerForTesting(settingsSearchHandler); + + userActionRecorder = new settings.FakeUserActionRecorder(); + settings.setUserActionRecorderForTesting(userActionRecorder); + }); + + teardown(async () => { + // Clear search field for next test. + await simulateSearch(''); + settings.setUserActionRecorderForTesting(null); + searchBox.setSearchHandlerForTesting(undefined); + }); + + test('User action search event', async () => { + settingsSearchHandler.setFakeResults([]); + + assertEquals(userActionRecorder.searchCount, 0); + await simulateSearch('query'); + assertEquals(userActionRecorder.searchCount, 1); + }); + + test('Dropdown opens correctly when results are fetched', async () => { + // Closed dropdown if no results are returned. + settingsSearchHandler.setFakeResults([]); + assertFalse(dropDown.opened); + await simulateSearch('query 1'); + assertFalse(dropDown.opened); + assertEquals(userActionRecorder.searchCount, 1); + + // Open dropdown if results are returned. + settingsSearchHandler.setFakeResults(['result']); + await simulateSearch('query 2'); + assertTrue(dropDown.opened); + }); + + test('Restore previous existing search results', async () => { + settingsSearchHandler.setFakeResults(['result 1']); + await simulateSearch('query'); + assertTrue(dropDown.opened); + const resultRow = resultList.items[0]; + + // Child blur elements except field should not trigger closing of dropdown. + resultList.blur(); + assertTrue(dropDown.opened); + dropDown.blur(); + assertTrue(dropDown.opened); + + // User clicks outside the search box, closing the dropdown. + searchBox.blur(); + assertFalse(dropDown.opened); + + // User clicks on input, restoring old results and opening dropdown. + field.$.searchInput.focus(); + assertEquals('query', field.$.searchInput.value); + assertTrue(dropDown.opened); + + // The same result row exists. + assertEquals(resultRow, resultList.items[0]); + + // Search field is blurred, closing the dropdown. + field.$.searchInput.blur(); + assertFalse(dropDown.opened); + + // User clicks on input, restoring old results and opening dropdown. + field.$.searchInput.focus(); + assertEquals('query', field.$.searchInput.value); + assertTrue(dropDown.opened); + + // The same result row exists. + assertEquals(resultRow, resultList.items[0]); + }); + + test('Search result rows are selected correctly', async () => { + settingsSearchHandler.setFakeResults(['result 1', 'result 2']); + await simulateSearch('query'); + assertTrue(dropDown.opened); + assertEquals(resultList.items.length, 2); + + // The first row should be selected when results are fetched. + assertEquals(resultList.selectedItem, resultList.items[0]); + + // Test ArrowUp and ArrowDown interaction with selecting. + const arrowUpEvent = new KeyboardEvent( + 'keydown', {cancelable: true, key: 'ArrowUp', keyCode: 38}); + const arrowDownEvent = new KeyboardEvent( + 'keydown', {cancelable: true, key: 'ArrowDown', keyCode: 40}); + + // ArrowDown event should select next row. + searchBox.dispatchEvent(arrowDownEvent); + assertEquals(resultList.selectedItem, resultList.items[1]); + + // If last row selected, ArrowDown brings select back to first row. + searchBox.dispatchEvent(arrowDownEvent); + assertEquals(resultList.selectedItem, resultList.items[0]); + + // If first row selected, ArrowUp brings select back to last row. + searchBox.dispatchEvent(arrowUpEvent); + assertEquals(resultList.selectedItem, resultList.items[1]); + + // ArrowUp should bring select previous row. + searchBox.dispatchEvent(arrowUpEvent); + assertEquals(resultList.selectedItem, resultList.items[0]); + + // Test that ArrowLeft and ArrowRight do nothing. + const arrowLeftEvent = new KeyboardEvent( + 'keydown', {cancelable: true, key: 'ArrowLeft', keyCode: 37}); + const arrowRightEvent = new KeyboardEvent( + 'keydown', {cancelable: true, key: 'ArrowRight', keyCode: 39}); + + // No change on ArrowLeft + searchBox.dispatchEvent(arrowLeftEvent); + assertEquals(resultList.selectedItem, resultList.items[0]); + + // No change on ArrowRight + searchBox.dispatchEvent(arrowRightEvent); + assertEquals(resultList.selectedItem, resultList.items[0]); + }); +});
diff --git a/chrome/test/data/webui/settings/cr_settings_browsertest.js b/chrome/test/data/webui/settings/cr_settings_browsertest.js index e04bb67..98453f01 100644 --- a/chrome/test/data/webui/settings/cr_settings_browsertest.js +++ b/chrome/test/data/webui/settings/cr_settings_browsertest.js
@@ -370,17 +370,9 @@ ]), }; -// Flakily times out on Linux CFI. -// TODO(crbug.com/1063723): Fix this by splitting up the test suite. -GEN('#if defined(OS_LINUX) && defined(IS_CFI)'); -GEN('#define MAYBE_All DISABLED_All'); -GEN('#else'); -GEN('#define MAYBE_All All'); -GEN('#endif'); -TEST_F('CrSettingsPasswordsSectionTest', 'MAYBE_All', function() { +TEST_F('CrSettingsPasswordsSectionTest', 'All', function() { mocha.run(); }); -GEN('#undef MAYBE_All'); /** * Test fixture for @@ -1478,8 +1470,7 @@ // Disabling on debug due to flaky timeout on Win7 Tests (dbg)(1) bot. // https://crbug.com/825304 - later for other platforms in crbug.com/1021219. -// Disabling on Linux CFI due to flaky timeout (crbug.com/1031960). -GEN('#if (!defined(NDEBUG)) || (defined(OS_LINUX) && defined(IS_CFI))'); +GEN('#if !defined(NDEBUG)'); GEN('#define MAYBE_All DISABLED_All'); GEN('#else'); GEN('#define MAYBE_All All'); @@ -1488,6 +1479,8 @@ TEST_F('CrSettingsSiteDetailsTest', 'MAYBE_All', function() { mocha.run(); }); +GEN('#undef MAYBE_All'); + /** * Test fixture for @@ -1761,6 +1754,7 @@ ]), }; +// Disabled for flakiness, see https://crbug.com/1061249 TEST_F('CrSettingsSiteDataTest', 'DISABLED_All', function() { mocha.run(); }); @@ -2101,8 +2095,7 @@ // Times out on Windows Tests (dbg). See https://crbug.com/651296. // Times out / crashes on chromium.linux/Linux Tests (dbg) crbug.com/667882 -// Times out on Linux CFI. See http://crbug.com/929288. -GEN('#if !defined(NDEBUG) || (defined(OS_LINUX) && defined(IS_CFI))'); +GEN('#if !defined(NDEBUG)'); GEN('#define MAYBE_MainPage DISABLED_MainPage'); GEN('#else'); GEN('#define MAYBE_MainPage MainPage');
diff --git a/chrome/test/data/webui/settings/cr_settings_interactive_ui_tests.js b/chrome/test/data/webui/settings/cr_settings_interactive_ui_tests.js index 85d4da5..666aa47f 100644 --- a/chrome/test/data/webui/settings/cr_settings_interactive_ui_tests.js +++ b/chrome/test/data/webui/settings/cr_settings_interactive_ui_tests.js
@@ -132,8 +132,8 @@ ]), }; -// Fails on Linux CFI and Mac10.13 Tests (dbg) (see crbug/1063844). -GEN('#if !(defined(OS_LINUX) && defined(IS_CFI)) && !(defined(OS_MACOSX) && !defined(NDEBUG))'); +// Fails on Mac10.13 Tests (dbg) (see crbug/1063844). +GEN('#if !(defined(OS_MACOSX) && !defined(NDEBUG))'); TEST_F('SettingsUIInteractiveTest', 'All', function() { mocha.run(); });
diff --git a/chrome/test/data/webui/settings/cr_settings_v3_browsertest.js b/chrome/test/data/webui/settings/cr_settings_v3_browsertest.js index 34a2eac..3bea7da 100644 --- a/chrome/test/data/webui/settings/cr_settings_v3_browsertest.js +++ b/chrome/test/data/webui/settings/cr_settings_v3_browsertest.js
@@ -116,8 +116,7 @@ // Copied from Polymer 2 version of tests: // Times out on Windows Tests (dbg). See https://crbug.com/651296. // Times out / crashes on chromium.linux/Linux Tests (dbg) crbug.com/667882 -// Times out on Linux CFI. See http://crbug.com/929288. -GEN('#if !defined(NDEBUG) || (defined(OS_LINUX) && defined(IS_CFI))'); +GEN('#if !defined(NDEBUG)'); GEN('#define MAYBE_MainPageV3 DISABLED_MainPageV3'); GEN('#else'); GEN('#define MAYBE_MainPageV3 MainPageV3'); @@ -277,7 +276,8 @@ runMochaSuite('PersonalizationOptionsTests_AllBuilds_Old'); }); -[['AppearanceFontsPage', 'appearance_fonts_page_test.m.js'], +[['AllSites', 'all_sites_tests.m.js'], + ['AppearanceFontsPage', 'appearance_fonts_page_test.m.js'], ['AppearancePage', 'appearance_page_test.m.js'], ['AutofillPage', 'autofill_page_test.m.js'], ['BasicPage', 'basic_page_test.m.js'], @@ -300,10 +300,14 @@ ['PeoplePageSyncPage', 'people_page_sync_page_test.m.js'], ['Prefs', 'prefs_tests.m.js'], ['PrefUtil', 'pref_util_tests.m.js'], + ['ProtocolHandlers', 'protocol_handlers_tests.m.js'], ['ResetPage', 'reset_page_test.m.js'], ['SearchEngines', 'search_engines_page_test.m.js'], ['SearchPage', 'search_page_test.m.js'], ['Search', 'search_settings_test.m.js'], + ['SecurityKeysSubpage', 'security_keys_subpage_test.m.js'], + // Copied from P2 test: Disabled for flakiness, see https://crbug.com/1061249 + ['SiteData', 'site_data_test.m.js', 'DISABLED_All'], ['SiteDataDetails', 'site_data_details_subpage_tests.m.js'], ['SiteDetailsPermission', 'site_details_permission_tests.m.js'], ['SiteEntry', 'site_entry_tests.m.js'],
diff --git a/chrome/test/data/webui/settings/protocol_handlers_tests.js b/chrome/test/data/webui/settings/protocol_handlers_tests.js index c289519..4fba124b 100644 --- a/chrome/test/data/webui/settings/protocol_handlers_tests.js +++ b/chrome/test/data/webui/settings/protocol_handlers_tests.js
@@ -2,6 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// clang-format off +// #import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +// #import {SiteSettingsPrefsBrowserProxyImpl} from 'chrome://settings/lazy_load.js'; +// #import {TestSiteSettingsPrefsBrowserProxy} from 'chrome://test/settings/test_site_settings_prefs_browser_proxy.m.js'; +// clang-format on + /** @fileoverview Suite of tests for protocol_handlers. */ suite('ProtocolHandlers', function() { /** @@ -65,7 +71,7 @@ let browserProxy = null; setup(async function() { - await settings.forceLazyLoaded(); + /* #ignore */ await settings.forceLazyLoaded(); browserProxy = new TestSiteSettingsPrefsBrowserProxy(); settings.SiteSettingsPrefsBrowserProxyImpl.instance_ = browserProxy; });
diff --git a/chrome/test/data/webui/settings/security_keys_subpage_test.js b/chrome/test/data/webui/settings/security_keys_subpage_test.js index 63aed64..8364737 100644 --- a/chrome/test/data/webui/settings/security_keys_subpage_test.js +++ b/chrome/test/data/webui/settings/security_keys_subpage_test.js
@@ -2,6 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// clang-format off +// #import {TestBrowserProxy} from 'chrome://test/test_browser_proxy.m.js'; +// #import {eventToPromise} from 'chrome://test/test_util.m.js'; +// #import {PromiseResolver} from 'chrome://resources/js/promise_resolver.m.js'; +// #import {SecurityKeysResetBrowserProxyImpl, SecurityKeysPINBrowserProxyImpl, SecurityKeysCredentialBrowserProxyImpl, SecurityKeysBioEnrollProxyImpl, ResetDialogPage, SetPINDialogPage, CredentialManagementDialogPage, BioEnrollDialogPage, SampleStatus, Ctap2Status} from 'chrome://settings/lazy_load.js'; +// #import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +// clang-format on + /** * A base class for all security key subpage test browser proxies to * inherit from. Provides a |promiseMap_| that proxies can be used to @@ -207,6 +215,7 @@ suite('SecurityKeysResetDialog', function() { let dialog = null; let allDivs = null; + let browserProxy = null; setup(function() { browserProxy = new TestSecurityKeysResetBrowserProxy(); @@ -315,6 +324,7 @@ suite('SecurityKeysSetPINDialog', function() { let dialog = null; let allDivs = null; + let browserProxy = null; setup(function() { browserProxy = new TestSecurityKeysPINBrowserProxy(); @@ -437,7 +447,7 @@ const setPINResolver = new PromiseResolver(); browserProxy.setResponseFor('setPIN', setPINResolver.promise); setNewPINEntries('1234', '1234'); - ({oldPIN, newPIN} = await browserProxy.whenCalled('setPIN')); + const {oldPIN, newPIN} = await browserProxy.whenCalled('setPIN'); assertTrue(dialog.$.pinSubmit.disabled); assertEquals(oldPIN, ''); assertEquals(newPIN, '1234'); @@ -554,6 +564,7 @@ suite('SecurityKeysCredentialManagement', function() { let dialog = null; let allDivs = null; + let browserProxy = null; setup(function() { browserProxy = new TestSecurityKeysCredentialBrowserProxy(); @@ -654,10 +665,10 @@ assertEquals(dialog.$.credentialList.items, credentials); // Select two of the credentials and delete them. - Polymer.flush(); + Polymer.dom.flush(); assertTrue(dialog.$.confirmButton.disabled); - const checkboxes = Array.from( - Polymer.dom(dialog.$.credentialList).querySelectorAll('cr-checkbox')); + const checkboxes = + Array.from(dialog.$.credentialList.querySelectorAll('cr-checkbox')); assertEquals(checkboxes.length, 3); assertEquals(checkboxes.filter(el => el.checked).length, 0); checkboxes[1].click(); @@ -679,6 +690,7 @@ suite('SecurityKeysBioEnrollment', function() { let dialog = null; let allDivs = null; + let browserProxy = null; setup(function() { browserProxy = new TestSecurityKeysBioEnrollProxy(); @@ -770,10 +782,8 @@ assertEquals(dialog.$.enrollmentList.items, enrollments); // Delete the second enrollments and refresh the list. - Polymer.flush(); - Polymer.dom(dialog.$.enrollmentList) - .querySelectorAll('cr-icon-button')[1] - .click(); + Polymer.dom.flush(); + dialog.$.enrollmentList.querySelectorAll('cr-icon-button')[1].click(); const id = await browserProxy.whenCalled('deleteEnrollment'); assertEquals(enrollments[1].id, id); enrollments.splice(1, 1); @@ -834,7 +844,7 @@ Polymer.dom.flush(); assertFalse(dialog.$.arc.isComplete()); assertFalse(dialog.$.cancelButton.hidden); - assert(dialog.$.confirmButton.hidden); + assertTrue(dialog.$.confirmButton.hidden); uiReady = test_util.eventToPromise('bio-enroll-dialog-ready-for-testing', dialog); @@ -848,8 +858,8 @@ }, }); await uiReady; - assert(dialog.$.arc.isComplete()); - assert(dialog.$.cancelButton.hidden); + assertTrue(dialog.$.arc.isComplete()); + assertTrue(dialog.$.cancelButton.hidden); assertFalse(dialog.$.confirmButton.hidden); // Proceeding brings up rename dialog page. @@ -903,8 +913,8 @@ await uiReady; assertShown(allDivs, dialog, 'enroll'); - assert(dialog.$.cancelButton.disabled == false); - assert(dialog.$.cancelButton.hidden == false); + assertFalse(dialog.$.cancelButton.disabled); + assertFalse(dialog.$.cancelButton.hidden); uiReady = test_util.eventToPromise('bio-enroll-dialog-ready-for-testing', dialog);
diff --git a/chrome/test/data/webui/settings/site_data_test.js b/chrome/test/data/webui/settings/site_data_test.js index 2bcc24f..16b9c12 100644 --- a/chrome/test/data/webui/settings/site_data_test.js +++ b/chrome/test/data/webui/settings/site_data_test.js
@@ -2,6 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// clang-format off +// #import {eventToPromise} from 'chrome://test/test_util.m.js'; +// #import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +// #import {LocalDataBrowserProxyImpl} from 'chrome://settings/lazy_load.js'; +// #import {Router,routes} from 'chrome://settings/settings.js'; +// #import {TestLocalDataBrowserProxy} from 'chrome://test/settings/test_local_data_browser_proxy.m.js'; +// clang-format on + suite('SiteDataTest', function() { /** @type {SiteDataElement} */ let siteData;
diff --git a/chrome/test/data/webui/settings/test_site_settings_prefs_browser_proxy.js b/chrome/test/data/webui/settings/test_site_settings_prefs_browser_proxy.js index edd8fef..91ed9cf0 100644 --- a/chrome/test/data/webui/settings/test_site_settings_prefs_browser_proxy.js +++ b/chrome/test/data/webui/settings/test_site_settings_prefs_browser_proxy.js
@@ -5,7 +5,7 @@ // clang-format off // #import {assert} from 'chrome://resources/js/assert.m.js'; // #import {ContentSetting,SiteSettingSource} from 'chrome://settings/lazy_load.js'; -// #import {createSiteSettingsPrefs, getContentSettingsTypeFromChooserType} from 'chrome://test/settings/test_util.m.js'; +// #import {createSiteGroup,createSiteSettingsPrefs, getContentSettingsTypeFromChooserType} from 'chrome://test/settings/test_util.m.js'; // #import {TestBrowserProxy} from 'chrome://test/test_browser_proxy.m.js'; // clang-format on
diff --git a/chrome/test/data/webui/settings/test_util.js b/chrome/test/data/webui/settings/test_util.js index 5f628e68..b8940b7 100644 --- a/chrome/test/data/webui/settings/test_util.js +++ b/chrome/test/data/webui/settings/test_util.js
@@ -178,7 +178,7 @@ }; } - function createOriginInfo(origin, override) { + /* #export */ function createOriginInfo(origin, override) { if (override === undefined) { override = {}; }
diff --git a/chrome/test/data/webui/test_api.js b/chrome/test/data/webui/test_api.js index 1fbfcd1e..47e3f8d7 100644 --- a/chrome/test/data/webui/test_api.js +++ b/chrome/test/data/webui/test_api.js
@@ -109,6 +109,9 @@ */ browsePreload: null, + /** @type {?string} */ + webuiHost: null, + /** * When set to a string value representing an html page in the test * directory, generate BrowsePrintPreload call, which will browse to a url @@ -133,6 +136,9 @@ */ testGenPostamble: null, + /** @type {?function()} */ + testGenCppIncludes: null, + /** * When set to a non-null string, auto-generate typedef before generating * TEST*: {@code typedef typedefCppFixture testFixture}. @@ -140,6 +146,19 @@ */ typedefCppFixture: 'WebUIBrowserTest', + /** @type {?Array<{switchName: string, switchValue: string}>} */ + commandLineSwitches: null, + + /** @type {?{enabled: !Array<string>, disabled: !Array<string>}} */ + featureList: null, + + /** + * @type {?Array<!{ + * featureName: string, + * parameters: !Array<{name: string, value: string}>}>} + */ + featuresWithParameters: null, + /** * This should be initialized by the test fixture and can be referenced * during the test run. It holds any mocked handler methods.
diff --git a/chrome/test/include_js_tests.gni b/chrome/test/include_js_tests.gni index d0df501..72a4398 100644 --- a/chrome/test/include_js_tests.gni +++ b/chrome/test/include_js_tests.gni
@@ -3,5 +3,5 @@ if (!is_android) { # js_tests don't work in cross builds, https://crbug.com/1010561 include_js_tests = - !(is_asan || is_msan || is_tsan || (is_win && host_os != "win")) + !(is_asan || is_msan || is_tsan || is_cfi || (is_win && host_os != "win")) }
diff --git a/chrome/tools/build/mac/FILES.cfg b/chrome/tools/build/mac/FILES.cfg index b270e6f..3f19bd2 100644 --- a/chrome/tools/build/mac/FILES.cfg +++ b/chrome/tools/build/mac/FILES.cfg
@@ -136,11 +136,6 @@ 'archive': 'updater.zip', }, { - 'filename': 'updater_setup', - 'buildtype': ['official'], - 'archive': 'updater.zip', - }, - { 'filename': 'chrome/updater/.install', 'buildtype': ['official'], 'archive': 'updater.zip',
diff --git a/chrome/updater/BUILD.gn b/chrome/updater/BUILD.gn index 324d75a..d6ea3fd 100644 --- a/chrome/updater/BUILD.gn +++ b/chrome/updater/BUILD.gn
@@ -213,14 +213,10 @@ "//chrome/common/mac:launchd", "//chrome/updater/mac:updater_bundle", "//chrome/updater/mac:updater_setup_tests", - "//chrome/updater/mac:updater_tests", "//chrome/updater/mac:xpc_names", ] - data_deps = [ - "//chrome/updater/mac:updater_bundle", - "//chrome/updater/mac:updater_setup", - ] + data_deps = [ "//chrome/updater/mac:updater_bundle" ] } if (is_win || is_mac) {
diff --git a/chrome/updater/constants.cc b/chrome/updater/constants.cc index 7bf0ac6f..16af159 100644 --- a/chrome/updater/constants.cc +++ b/chrome/updater/constants.cc
@@ -25,6 +25,7 @@ const char kEnableLoggingSwitch[] = "enable-logging"; const char kLoggingModuleSwitch[] = "vmodule"; const char kSingleProcessSwitch[] = "single-process"; +const char kAppIdSwitch[] = "appid"; // URLs. const char kUpdaterJSONDefaultUrl[] =
diff --git a/chrome/updater/constants.h b/chrome/updater/constants.h index 1799efa..f887baec 100644 --- a/chrome/updater/constants.h +++ b/chrome/updater/constants.h
@@ -86,6 +86,9 @@ // only and it may be removed at any time. extern const char kSingleProcessSwitch[]; +// Specifies the application that the Updater needs to install. +extern const char kAppIdSwitch[]; + // URLs. // // Omaha server end point.
diff --git a/chrome/updater/mac/BUILD.gn b/chrome/updater/mac/BUILD.gn index 83a68e72..9ccf4cf0 100644 --- a/chrome/updater/mac/BUILD.gn +++ b/chrome/updater/mac/BUILD.gn
@@ -8,9 +8,9 @@ group("mac") { deps = [ + ":install_app", ":updater_bundle", ":updater_install_script", - ":updater_setup", "//chrome/updater/mac/signing", ] } @@ -53,6 +53,7 @@ sources = [ "main.cc" ] deps = [ + ":install_app", ":network_fetcher_sources", ":updater_setup_sources", "//chrome/updater:lib", @@ -97,13 +98,19 @@ ] } -executable("updater_setup") { - sources = [ "setup/main.cc" ] +source_set("install_app") { + sources = [ + "setup/install_app.cc", + "setup/install_app.h", + ] deps = [ - ":updater_bundle", ":updater_setup_sources", + "//base", + "//chrome/updater:lib", ] + + allow_circular_includes_from = [ "//chrome/updater:lib" ] } action("updater_install_script") { @@ -143,7 +150,9 @@ data = [ "//chrome/test/data/updater/updater_setup_test_dmg.dmg" ] deps = [ + ":install_app", ":installer_sources", + ":updater_setup_sources", "//base", "//base/test:test_support", "//chrome/common:constants",
diff --git a/chrome/updater/mac/setup/install_app.cc b/chrome/updater/mac/setup/install_app.cc new file mode 100644 index 0000000..99f7e2fd --- /dev/null +++ b/chrome/updater/mac/setup/install_app.cc
@@ -0,0 +1,35 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/updater/mac/setup/install_app.h" + +#include "base/bind.h" +#include "base/task/task_traits.h" +#include "base/task/thread_pool.h" +#include "chrome/updater/app/app.h" +#include "chrome/updater/mac/setup/setup.h" + +namespace updater { + +namespace { + +class AppInstall : public App { + private: + ~AppInstall() override = default; + void FirstTaskRun() override; +}; + +void AppInstall::FirstTaskRun() { + base::ThreadPool::PostTaskAndReplyWithResult( + FROM_HERE, {base::MayBlock()}, base::BindOnce(&SetupUpdater), + base::BindOnce(&AppInstall::Shutdown, this)); +} + +} // namespace + +scoped_refptr<App> AppInstallInstance() { + return AppInstance<AppInstall>(); +} + +} // namespace updater
diff --git a/chrome/updater/mac/setup/install_app.h b/chrome/updater/mac/setup/install_app.h new file mode 100644 index 0000000..0d9fe78 --- /dev/null +++ b/chrome/updater/mac/setup/install_app.h
@@ -0,0 +1,18 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_UPDATER_MAC_SETUP_INSTALL_APP_H_ +#define CHROME_UPDATER_MAC_SETUP_INSTALL_APP_H_ + +#include "base/memory/scoped_refptr.h" + +namespace updater { + +class App; + +scoped_refptr<App> AppInstallInstance(); + +} // namespace updater + +#endif // CHROME_UPDATER_MAC_SETUP_INSTALL_APP_H_
diff --git a/chrome/updater/mac/setup/main.cc b/chrome/updater/mac/setup/main.cc deleted file mode 100644 index be7673d..0000000 --- a/chrome/updater/mac/setup/main.cc +++ /dev/null
@@ -1,9 +0,0 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/updater/mac/setup/setup.h" - -int main(int argc, const char* argv[]) { - return updater::setup::UpdaterSetupMain(argc, argv); -}
diff --git a/chrome/updater/mac/setup/setup.h b/chrome/updater/mac/setup/setup.h index 14932c16..b21ec0b 100644 --- a/chrome/updater/mac/setup/setup.h +++ b/chrome/updater/mac/setup/setup.h
@@ -7,14 +7,14 @@ namespace updater { +// Set up the updater by copying the bundle, creating launchd plists for +// scheduled tasks and xpc service, and start both launchd jobs. +int SetupUpdater(); + +// Remove the launchd plists for scheduled tasks and xpc service. Delete the +// updater bundle from its installed location. int Uninstall(bool is_machine); -namespace setup { - -int UpdaterSetupMain(int argc, const char* const* argv); - -} // namespace setup - } // namespace updater #endif // CHROME_UPDATER_MAC_SETUP_SETUP_H_
diff --git a/chrome/updater/mac/setup/setup.mm b/chrome/updater/mac/setup/setup.mm index 8c72620..0f174ad0 100644 --- a/chrome/updater/mac/setup/setup.mm +++ b/chrome/updater/mac/setup/setup.mm
@@ -11,6 +11,7 @@ #include "base/files/file_path.h" #include "base/files/file_util.h" #include "base/logging.h" +#include "base/mac/bundle_locations.h" #include "base/mac/foundation_util.h" #include "base/mac/scoped_nsobject.h" #include "base/path_service.h" @@ -29,8 +30,6 @@ namespace updater { -namespace setup { - namespace { const base::FilePath GetUpdateFolderName() { return base::FilePath(COMPANY_SHORTNAME_STRING) @@ -43,51 +42,6 @@ return base::FilePath("Contents/MacOS").AppendASCII(PRODUCT_FULLNAME_STRING); } -void ThreadPoolStart() { - base::ThreadPoolInstance::CreateAndStartWithDefaultParams("UpdaterSetup"); -} - -void ThreadPoolStop() { - base::ThreadPoolInstance::Get()->Shutdown(); -} - -// The log file is created in DIR_LOCAL_APP_DATA or DIR_APP_DATA. -void InitLogging(const base::CommandLine& command_line) { - logging::LoggingSettings settings; - base::FilePath log_dir; - updater::GetProductDirectory(&log_dir); - const auto log_file = log_dir.Append(FILE_PATH_LITERAL("updater_setup.log")); - settings.log_file_path = log_file.value().c_str(); - settings.logging_dest = logging::LOG_TO_ALL; - logging::InitLogging(settings); - logging::SetLogItems(true, // enable_process_id - true, // enable_thread_id - true, // enable_timestamp - false); // enable_tickcount - VLOG(1) << "Log file " << settings.log_file_path; -} - -void InitializeUpdaterSetupMain() { - crash_reporter::InitializeCrashKeys(); - - static crash_reporter::CrashKeyString<16> crash_key_process_type( - "process_type"); - crash_key_process_type.Set("updater_setup"); - - if (updater::CrashClient::GetInstance()->InitializeCrashReporting()) - VLOG(1) << "Crash reporting initialized."; - else - VLOG(1) << "Crash reporting is not available."; - - updater::StartCrashReporter(UPDATER_VERSION_STRING); - - ThreadPoolStart(); -} - -void TerminateUpdaterSetupMain() { - ThreadPoolStop(); -} - bool CopyBundle() { // Copy bundle to ~/Library/COMPANY_SHORTNAME_STRING/PRODUCT_FULLNAME_STRING. // e.g. ~/Library/Google/GoogleUpdater @@ -102,11 +56,7 @@ } } - base::FilePath this_executable_path; - base::PathService::Get(base::FILE_EXE, &this_executable_path); - const base::FilePath src_path = - this_executable_path.DirName().Append(GetUpdaterAppName()); - + const base::FilePath src_path = base::mac::OuterBundlePath(); if (!base::CopyDirectory(src_path, dest_path, true)) { LOG(ERROR) << "Copying app to ~/Library failed"; return false; @@ -219,6 +169,8 @@ CFSTR("Aqua")); } +} // namespace + int SetupUpdater() { if (!CopyBundle()) return -1; @@ -238,47 +190,12 @@ return 0; } -} // namespace - -int HandleUpdaterSetupCommands(const base::CommandLine* command_line) { - DCHECK(!command_line->HasSwitch(updater::kCrashHandlerSwitch)); - - if (command_line->HasSwitch(updater::kCrashMeSwitch)) { - LOG(FATAL) << "Crashing deliberately."; - return -100; - } - - return SetupUpdater(); -} - -int UpdaterSetupMain(int argc, const char* const* argv) { - base::PlatformThread::SetName("UpdaterSetupMain"); - base::AtExitManager exit_manager; - - base::CommandLine::Init(argc, argv); - const auto* command_line = base::CommandLine::ForCurrentProcess(); - if (command_line->HasSwitch(updater::kTestSwitch)) - return 0; - - InitLogging(*command_line); - - if (command_line->HasSwitch(updater::kCrashHandlerSwitch)) - return updater::CrashReporterMain(); - - InitializeUpdaterSetupMain(); - const auto result = HandleUpdaterSetupCommands(command_line); - TerminateUpdaterSetupMain(); - return result; -} - -} // namespace setup - int Uninstall(bool is_machine) { ALLOW_UNUSED_LOCAL(is_machine); - if (!setup::RemoveFromLaunchd()) + if (!RemoveFromLaunchd()) return -1; - if (!setup::DeleteInstallFolder()) + if (!DeleteInstallFolder()) return -2; return 0;
diff --git a/chrome/updater/test/integration_tests_mac.mm b/chrome/updater/test/integration_tests_mac.mm index 85fc865b..24ec7dd 100644 --- a/chrome/updater/test/integration_tests_mac.mm +++ b/chrome/updater/test/integration_tests_mac.mm
@@ -31,13 +31,6 @@ .Append(FILE_PATH_LITERAL(PRODUCT_FULLNAME_STRING)); } -base::FilePath GetInstallerPath() { - base::FilePath test_executable; - if (!base::PathService::Get(base::FILE_EXE, &test_executable)) - return base::FilePath(); - return test_executable.DirName().Append("updater_setup"); -} - base::FilePath GetProductPath() { return base::mac::GetUserLibraryPath() .AppendASCII(COMPANY_SHORTNAME_STRING) @@ -89,10 +82,12 @@ } void Install() { - base::FilePath path = GetInstallerPath(); + base::FilePath path = GetExecutablePath(); ASSERT_FALSE(path.empty()); + base::CommandLine command_line(path); + command_line.AppendSwitch("install"); int exit_code = -1; - ASSERT_TRUE(Run(base::CommandLine(path), &exit_code)); + ASSERT_TRUE(Run(command_line, &exit_code)); EXPECT_EQ(0, exit_code); }
diff --git a/chrome/updater/updater.cc b/chrome/updater/updater.cc index a5f709bb..2248889 100644 --- a/chrome/updater/updater.cc +++ b/chrome/updater/updater.cc
@@ -27,6 +27,7 @@ #endif #if defined(OS_MACOSX) +#include "chrome/updater/mac/setup/install_app.h" #include "chrome/updater/server/mac/server.h" #endif @@ -96,10 +97,10 @@ #if defined(OS_WIN) if (command_line->HasSwitch(kComServiceSwitch)) return ServiceMain::RunComService(command_line); +#endif // OS_WIN if (command_line->HasSwitch(kInstallSwitch)) return AppInstallInstance()->Run(); -#endif // OS_WIN if (command_line->HasSwitch(kUninstallSwitch)) return AppUninstallInstance()->Run();
diff --git a/chrome/updater/win/install_app.cc b/chrome/updater/win/install_app.cc index 2d51647..442dbc0 100644 --- a/chrome/updater/win/install_app.cc +++ b/chrome/updater/win/install_app.cc
@@ -706,10 +706,6 @@ void SetupDone(int result); - // TODO(sorin): remove the hardcoding of the application id. - // https://crbug.com/1014298 - const std::string app_id_ = {kChromeAppId}; - scoped_refptr<Configurator> config_; scoped_refptr<InstallAppController> app_install_controller_; @@ -747,7 +743,9 @@ } void AppInstall::SetupDone(int result) { - if (result != 0) { + const auto app_id = + base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(kAppIdSwitch); + if (result != 0 || app_id.empty()) { Shutdown(result); return; } @@ -757,7 +755,7 @@ app_install_controller_ = base::MakeRefCounted<InstallAppController>(config_); app_install_controller_->InstallApp( - app_id_, base::BindOnce(&AppInstall::Shutdown, this)); + app_id, base::BindOnce(&AppInstall::Shutdown, this)); } scoped_refptr<App> AppInstallInstance() {
diff --git a/chromecast/graphics/accessibility/partial_magnification_controller_unittest.cc b/chromecast/graphics/accessibility/partial_magnification_controller_unittest.cc index 2f1b074..456756d 100644 --- a/chromecast/graphics/accessibility/partial_magnification_controller_unittest.cc +++ b/chromecast/graphics/accessibility/partial_magnification_controller_unittest.cc
@@ -63,9 +63,8 @@ void SetUp() override { views::ViewsTestBase::SetUp(); - screen_position_client_.reset(new wm::DefaultScreenPositionClient()); - aura::client::SetScreenPositionClient(root_window(), - screen_position_client_.get()); + screen_position_client_.reset( + new wm::DefaultScreenPositionClient(root_window())); controller_ = std::make_unique<PartialMagnificationController>(root_window()); } @@ -74,6 +73,7 @@ // PartialMagnificationController needs to be deleted before the root window // is torn down by ViewsTestBase. controller_.reset(); + screen_position_client_.reset(); views::ViewsTestBase::TearDown(); }
diff --git a/chromecast/graphics/cast_window_manager_aura.cc b/chromecast/graphics/cast_window_manager_aura.cc index a89faa6..d7b2202 100644 --- a/chromecast/graphics/cast_window_manager_aura.cc +++ b/chromecast/graphics/cast_window_manager_aura.cc
@@ -19,7 +19,6 @@ #include "chromecast/graphics/rounded_window_corners.h" #include "ui/aura/client/default_capture_client.h" #include "ui/aura/client/focus_change_observer.h" -#include "ui/aura/client/screen_position_client.h" #include "ui/aura/env.h" #include "ui/aura/layout_manager.h" #include "ui/aura/window.h" @@ -227,12 +226,10 @@ aura::client::SetWindowParentingClient(tree_window, this); capture_client_.reset(new aura::client::DefaultCaptureClient(tree_window)); - screen_position_client_ = std::make_unique<wm::DefaultScreenPositionClient>(); - // TODO(seantopping): Is |root_window| different from |tree_window|? aura::Window* root_window = tree_window->GetRootWindow(); - aura::client::SetScreenPositionClient(root_window, - screen_position_client_.get()); + screen_position_client_ = + std::make_unique<wm::DefaultScreenPositionClient>(root_window); window_tree_host_->Show(); @@ -300,6 +297,7 @@ capture_client_.reset(); aura::client::SetWindowParentingClient(window_tree_host_->window(), nullptr); wm::SetActivationClient(window_tree_host_->window(), nullptr); + screen_position_client_.reset(); aura::client::SetFocusClient(window_tree_host_->window(), nullptr); focus_client_.reset(); system_gesture_event_handler_.reset();
diff --git a/chromecast/graphics/gestures/multiple_tap_detector_test.cc b/chromecast/graphics/gestures/multiple_tap_detector_test.cc index ef5a3d3c..7753c6d 100644 --- a/chromecast/graphics/gestures/multiple_tap_detector_test.cc +++ b/chromecast/graphics/gestures/multiple_tap_detector_test.cc
@@ -7,7 +7,6 @@ #include "base/run_loop.h" #include "base/test/simple_test_tick_clock.h" #include "testing/gmock/include/gmock/gmock.h" -#include "ui/aura/client/screen_position_client.h" #include "ui/aura/test/aura_test_base.h" #include "ui/aura/window.h" #include "ui/events/event_utils.h" @@ -40,9 +39,8 @@ void SetUp() override { aura::test::AuraTestBase::SetUp(); - screen_position_client_.reset(new wm::DefaultScreenPositionClient()); - aura::client::SetScreenPositionClient(root_window(), - screen_position_client_.get()); + screen_position_client_.reset( + new wm::DefaultScreenPositionClient(root_window())); triple_tap_delegate_ = std::make_unique<MockMultipleTapDetectorDelegate>(); triple_tap_detector_ = std::make_unique<MultipleTapDetector>( @@ -59,6 +57,7 @@ void TearDown() override { ui::SetEventTickClockForTesting(nullptr); triple_tap_detector_.reset(); + screen_position_client_.reset(); aura::test::AuraTestBase::TearDown(); }
diff --git a/chromecast/graphics/gestures/side_swipe_detector_test.cc b/chromecast/graphics/gestures/side_swipe_detector_test.cc index f3c3584..ebc6aad1 100644 --- a/chromecast/graphics/gestures/side_swipe_detector_test.cc +++ b/chromecast/graphics/gestures/side_swipe_detector_test.cc
@@ -72,9 +72,8 @@ void SetUp() override { aura::test::AuraTestBase::SetUp(); - screen_position_client_.reset(new wm::DefaultScreenPositionClient()); - aura::client::SetScreenPositionClient(root_window(), - screen_position_client_.get()); + screen_position_client_.reset( + new wm::DefaultScreenPositionClient(root_window())); gesture_handler_ = std::make_unique<MockCastGestureHandler>(); side_swipe_detector_ = std::make_unique<SideSwipeDetector>( @@ -92,6 +91,7 @@ void TearDown() override { side_swipe_detector_.reset(); gesture_handler_.reset(); + screen_position_client_.reset(); aura::test::AuraTestBase::TearDown(); }
diff --git a/chromeos/components/security_token_pin/error_generator_unittest.cc b/chromeos/components/security_token_pin/error_generator_unittest.cc index 7a5f810..211d19a 100644 --- a/chromeos/components/security_token_pin/error_generator_unittest.cc +++ b/chromeos/components/security_token_pin/error_generator_unittest.cc
@@ -24,7 +24,9 @@ protected: SecurityTokenPinErrorGeneratorTest() { InitI18n(); } - ~SecurityTokenPinErrorGeneratorTest() override = default; + ~SecurityTokenPinErrorGeneratorTest() override { + ui::ResourceBundle::CleanupSharedInstance(); + } private: // Initializes the i18n stack and loads the necessary strings. Uses a specific
diff --git a/chromeos/components/sync_wifi/BUILD.gn b/chromeos/components/sync_wifi/BUILD.gn index ca8cdcc9..d28618b 100644 --- a/chromeos/components/sync_wifi/BUILD.gn +++ b/chromeos/components/sync_wifi/BUILD.gn
@@ -95,6 +95,7 @@ "//chromeos/services/network_config", "//chromeos/services/network_config:in_process_instance", "//chromeos/services/network_config/public/cpp:test_support", + "//components/prefs:test_support", "//components/sync:test_support", "//components/sync_preferences:test_support", "//components/user_manager:test_support",
diff --git a/chromeos/components/sync_wifi/fake_local_network_collector.cc b/chromeos/components/sync_wifi/fake_local_network_collector.cc index d6e6866..0e83c5a 100644 --- a/chromeos/components/sync_wifi/fake_local_network_collector.cc +++ b/chromeos/components/sync_wifi/fake_local_network_collector.cc
@@ -19,10 +19,10 @@ std::move(callback).Run(networks_); } -void FakeLocalNetworkCollector::GetSyncableNetwork(const NetworkIdentifier& id, +void FakeLocalNetworkCollector::GetSyncableNetwork(const std::string& guid, ProtoCallback callback) { for (sync_pb::WifiConfigurationSpecifics proto : networks_) { - if (NetworkIdentifier::FromProto(proto) == id) { + if (NetworkIdentifier::FromProto(proto).SerializeToString() == guid) { std::move(callback).Run(proto); return; } @@ -31,6 +31,18 @@ std::move(callback).Run(base::nullopt); } +base::Optional<NetworkIdentifier> +FakeLocalNetworkCollector::GetNetworkIdentifierFromGuid( + const std::string& guid) { + for (sync_pb::WifiConfigurationSpecifics proto : networks_) { + auto id = NetworkIdentifier::FromProto(proto); + if (id.SerializeToString() == guid) { + return id; + } + } + return base::nullopt; +} + void FakeLocalNetworkCollector::AddNetwork( sync_pb::WifiConfigurationSpecifics proto) { networks_.push_back(proto); @@ -40,6 +52,9 @@ networks_.clear(); } +void FakeLocalNetworkCollector::SetNetworkMetadataStore( + base::WeakPtr<NetworkMetadataStore> network_metadata_store) {} + } // namespace sync_wifi -} // namespace chromeos \ No newline at end of file +} // namespace chromeos
diff --git a/chromeos/components/sync_wifi/fake_local_network_collector.h b/chromeos/components/sync_wifi/fake_local_network_collector.h index d7d07a50..f4976aa2 100644 --- a/chromeos/components/sync_wifi/fake_local_network_collector.h +++ b/chromeos/components/sync_wifi/fake_local_network_collector.h
@@ -24,11 +24,17 @@ // sync_wifi::LocalNetworkCollector:: void GetAllSyncableNetworks(ProtoListCallback callback) override; - void GetSyncableNetwork(const NetworkIdentifier& id, + // For test purposes, |guid| == serialized NetworkIdentifier. + void GetSyncableNetwork(const std::string& guid, ProtoCallback callback) override; + // For test purposes, |guid| == serialized NetworkIdentifier. + base::Optional<NetworkIdentifier> GetNetworkIdentifierFromGuid( + const std::string& guid) override; void AddNetwork(sync_pb::WifiConfigurationSpecifics proto); void ClearNetworks(); + void SetNetworkMetadataStore( + base::WeakPtr<NetworkMetadataStore> network_metadata_store) override; private: std::vector<sync_pb::WifiConfigurationSpecifics> networks_;
diff --git a/chromeos/components/sync_wifi/local_network_collector.h b/chromeos/components/sync_wifi/local_network_collector.h index 95b3e1a0..f9e73b3 100644 --- a/chromeos/components/sync_wifi/local_network_collector.h +++ b/chromeos/components/sync_wifi/local_network_collector.h
@@ -10,6 +10,7 @@ #include "base/memory/weak_ptr.h" #include "base/optional.h" +#include "chromeos/components/sync_wifi/network_identifier.h" #include "chromeos/services/network_config/public/mojom/cros_network_config.mojom.h" #include "mojo/public/cpp/bindings/receiver.h" @@ -19,9 +20,9 @@ namespace chromeos { -namespace sync_wifi { +class NetworkMetadataStore; -class NetworkIdentifier; +namespace sync_wifi { // Handles the retrieval, filtering, and conversion of local network // configurations to syncable protos. @@ -46,8 +47,17 @@ // Creates a WifiConfigurationSpecifics proto with the relevant network // details for the network with the given |id|. If that network doesn't // exist or isn't syncable it will provide base::nullopt to the callback. - virtual void GetSyncableNetwork(const NetworkIdentifier& id, + virtual void GetSyncableNetwork(const std::string& guid, ProtoCallback callback) = 0; + + // Retrieves the NetworkIdentifier for a given local network's |guid| + // if the network no longer exists it returns nullopt. + virtual base::Optional<NetworkIdentifier> GetNetworkIdentifierFromGuid( + const std::string& guid) = 0; + + // Provides the metadata store which gets constructed later. + virtual void SetNetworkMetadataStore( + base::WeakPtr<NetworkMetadataStore> network_metadata_store) = 0; }; } // namespace sync_wifi
diff --git a/chromeos/components/sync_wifi/local_network_collector_impl.cc b/chromeos/components/sync_wifi/local_network_collector_impl.cc index a233bf46..27d9b83 100644 --- a/chromeos/components/sync_wifi/local_network_collector_impl.cc +++ b/chromeos/components/sync_wifi/local_network_collector_impl.cc
@@ -36,10 +36,8 @@ } // namespace LocalNetworkCollectorImpl::LocalNetworkCollectorImpl( - network_config::mojom::CrosNetworkConfig* cros_network_config, - NetworkMetadataStore* network_metadata_store) - : cros_network_config_(cros_network_config), - network_metadata_store_(network_metadata_store) { + network_config::mojom::CrosNetworkConfig* cros_network_config) + : cros_network_config_(cros_network_config) { cros_network_config_->AddObserver( cros_network_config_observer_receiver_.BindNewPipeAndPassRemote()); @@ -72,12 +70,12 @@ } } -void LocalNetworkCollectorImpl::GetSyncableNetwork(const NetworkIdentifier& id, +void LocalNetworkCollectorImpl::GetSyncableNetwork(const std::string& guid, ProtoCallback callback) { const network_config::mojom::NetworkStateProperties* network = nullptr; for (const network_config::mojom::NetworkStatePropertiesPtr& n : mojo_networks_) { - if (NetworkIdentifier::FromMojoNetwork(n) == id) { + if (n->guid == guid) { if (IsEligible(n)) { network = n.get(); } @@ -97,6 +95,23 @@ StartGetNetworkDetails(network, request_guid); } +base::Optional<NetworkIdentifier> +LocalNetworkCollectorImpl::GetNetworkIdentifierFromGuid( + const std::string& guid) { + for (const network_config::mojom::NetworkStatePropertiesPtr& network : + mojo_networks_) { + if (network->guid == guid) { + return NetworkIdentifier::FromMojoNetwork(network); + } + } + return base::nullopt; +} + +void LocalNetworkCollectorImpl::SetNetworkMetadataStore( + base::WeakPtr<NetworkMetadataStore> network_metadata_store) { + network_metadata_store_ = network_metadata_store; +} + std::string LocalNetworkCollectorImpl::InitializeRequest() { std::string request_guid = base::GenerateGUID(); request_guid_to_complete_protos_[request_guid] =
diff --git a/chromeos/components/sync_wifi/local_network_collector_impl.h b/chromeos/components/sync_wifi/local_network_collector_impl.h index f7aa0ae..3883367 100644 --- a/chromeos/components/sync_wifi/local_network_collector_impl.h +++ b/chromeos/components/sync_wifi/local_network_collector_impl.h
@@ -38,18 +38,23 @@ // LocalNetworkCollector: // |cros_network_config| and |network_metadata_store| must outlive this class. - LocalNetworkCollectorImpl( - network_config::mojom::CrosNetworkConfig* cros_network_config, - NetworkMetadataStore* network_metadata_store); + explicit LocalNetworkCollectorImpl( + network_config::mojom::CrosNetworkConfig* cros_network_config); ~LocalNetworkCollectorImpl() override; // Can only execute one request at a time. void GetAllSyncableNetworks(ProtoListCallback callback) override; // Can be called on multiple networks simultaneously. - void GetSyncableNetwork(const NetworkIdentifier& id, + void GetSyncableNetwork(const std::string& guid, ProtoCallback callback) override; + base::Optional<NetworkIdentifier> GetNetworkIdentifierFromGuid( + const std::string& guid) override; + + void SetNetworkMetadataStore( + base::WeakPtr<NetworkMetadataStore> network_metadata_store) override; + // CrosNetworkConfigObserver: void OnNetworkStateListChanged() override; void OnActiveNetworksChanged( @@ -100,7 +105,7 @@ mojo::Receiver<chromeos::network_config::mojom::CrosNetworkConfigObserver> cros_network_config_observer_receiver_{this}; std::vector<network_config::mojom::NetworkStatePropertiesPtr> mojo_networks_; - NetworkMetadataStore* network_metadata_store_; + base::WeakPtr<NetworkMetadataStore> network_metadata_store_; base::flat_map<std::string, std::vector<sync_pb::WifiConfigurationSpecifics>> request_guid_to_complete_protos_;
diff --git a/chromeos/components/sync_wifi/local_network_collector_impl_unittest.cc b/chromeos/components/sync_wifi/local_network_collector_impl_unittest.cc index f9f7c9d..b06f62a8 100644 --- a/chromeos/components/sync_wifi/local_network_collector_impl_unittest.cc +++ b/chromeos/components/sync_wifi/local_network_collector_impl_unittest.cc
@@ -19,6 +19,7 @@ #include "chromeos/components/sync_wifi/test_data_generator.h" #include "chromeos/dbus/shill/fake_shill_simulated_result.h" #include "chromeos/network/network_handler.h" +#include "chromeos/network/network_metadata_store.h" #include "chromeos/services/network_config/cros_network_config.h" #include "chromeos/services/network_config/in_process_instance.h" #include "chromeos/services/network_config/public/cpp/cros_network_config_test_helper.h" @@ -58,8 +59,9 @@ testing::Test::SetUp(); helper()->SetUp(); local_network_collector_ = std::make_unique<LocalNetworkCollectorImpl>( - remote_cros_network_config_.get(), - NetworkHandler::Get()->network_metadata_store()); + remote_cros_network_config_.get()); + local_network_collector_->SetNetworkMetadataStore( + NetworkHandler::Get()->network_metadata_store()->GetWeakPtr()); } void TearDown() override { @@ -144,30 +146,29 @@ } TEST_F(LocalNetworkCollectorImplTest, TestGetSyncableNetwork) { - helper()->ConfigureWiFiNetwork(kFredSsid, /*is_secured=*/true, - /*in_profile=*/true, /*has_connected=*/true); - - NetworkIdentifier id = GeneratePskNetworkId(kFredSsid); + std::string guid = helper()->ConfigureWiFiNetwork( + kFredSsid, /*is_secured=*/true, + /*in_profile=*/true, /*has_connected=*/true); local_network_collector()->GetSyncableNetwork( - id, base::BindOnce(&LocalNetworkCollectorImplTest::OnGetSyncableNetwork, - base::Unretained(this), kFredSsid)); + guid, base::BindOnce(&LocalNetworkCollectorImplTest::OnGetSyncableNetwork, + base::Unretained(this), kFredSsid)); } TEST_F(LocalNetworkCollectorImplTest, TestGetSyncableNetwork_DoesntExist) { - NetworkIdentifier id = GeneratePskNetworkId(kFredSsid); local_network_collector()->GetSyncableNetwork( - id, base::BindOnce(&LocalNetworkCollectorImplTest::OnGetSyncableNetwork, - base::Unretained(this), std::string())); + "test_guid", + base::BindOnce(&LocalNetworkCollectorImplTest::OnGetSyncableNetwork, + base::Unretained(this), std::string())); } TEST_F(LocalNetworkCollectorImplTest, TestGetSyncableNetwork_NeverConnected) { - helper()->ConfigureWiFiNetwork(kFredSsid, /*is_secured=*/true, - /*in_profile=*/true, /*has_connected=*/false); + std::string guid = helper()->ConfigureWiFiNetwork( + kFredSsid, /*is_secured=*/true, + /*in_profile=*/true, /*has_connected=*/false); - NetworkIdentifier id = GeneratePskNetworkId(kFredSsid); local_network_collector()->GetSyncableNetwork( - id, base::BindOnce(&LocalNetworkCollectorImplTest::OnGetSyncableNetwork, - base::Unretained(this), std::string())); + guid, base::BindOnce(&LocalNetworkCollectorImplTest::OnGetSyncableNetwork, + base::Unretained(this), std::string())); } } // namespace sync_wifi
diff --git a/chromeos/components/sync_wifi/network_identifier.cc b/chromeos/components/sync_wifi/network_identifier.cc index 2d6d91f..bc86888 100644 --- a/chromeos/components/sync_wifi/network_identifier.cc +++ b/chromeos/components/sync_wifi/network_identifier.cc
@@ -8,6 +8,7 @@ #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "chromeos/components/sync_wifi/network_type_conversions.h" +#include "chromeos/network/network_state.h" #include "chromeos/services/network_config/public/mojom/cros_network_config.mojom.h" #include "components/sync/protocol/wifi_configuration_specifics.pb.h" #include "third_party/cros_system_api/dbus/shill/dbus-constants.h" @@ -48,6 +49,12 @@ return NetworkIdentifier(pieces[0], pieces[1]); } +// static +NetworkIdentifier NetworkIdentifier::FromNetworkState( + const NetworkState* network) { + return NetworkIdentifier(network->GetHexSsid(), network->security_class()); +} + NetworkIdentifier::NetworkIdentifier(const std::string& hex_ssid, const std::string& security_type) : security_type_(security_type) {
diff --git a/chromeos/components/sync_wifi/network_identifier.h b/chromeos/components/sync_wifi/network_identifier.h index 1acd914..7dfc7a4 100644 --- a/chromeos/components/sync_wifi/network_identifier.h +++ b/chromeos/components/sync_wifi/network_identifier.h
@@ -15,6 +15,8 @@ namespace chromeos { +class NetworkState; + namespace sync_wifi { // A unique identifier for synced networks which contains the properties @@ -25,6 +27,7 @@ const sync_pb::WifiConfigurationSpecifics& specifics); static NetworkIdentifier FromMojoNetwork( const network_config::mojom::NetworkStatePropertiesPtr& network); + static NetworkIdentifier FromNetworkState(const NetworkState* network); // |serialized_string| is in the format of hex_ssid and security_type // concatenated with an underscore. security_type is the shill constant // returned from NetworkState::security_class(). For example, it would be
diff --git a/chromeos/components/sync_wifi/network_test_helper.cc b/chromeos/components/sync_wifi/network_test_helper.cc index 5e988fbf..b1ee0e1 100644 --- a/chromeos/components/sync_wifi/network_test_helper.cc +++ b/chromeos/components/sync_wifi/network_test_helper.cc
@@ -77,10 +77,10 @@ base::RunLoop().RunUntilIdle(); } -void NetworkTestHelper::ConfigureWiFiNetwork(const std::string& ssid, - bool is_secured, - bool in_profile, - bool has_connected) { +std::string NetworkTestHelper::ConfigureWiFiNetwork(const std::string& ssid, + bool is_secured, + bool in_profile, + bool has_connected) { std::string security_entry = is_secured ? R"("SecurityClass": "psk", "Passphrase": "secretsauce", )" : R"("SecurityClass": "none", )"; @@ -88,12 +88,13 @@ in_profile ? base::StringPrintf(R"("Profile": "%s", )", network_state_helper_->UserHash()) : std::string(); + std::string guid = base::StringPrintf("%s_guid", ssid.c_str()); std::string service_path = network_state_helper_->ConfigureService(base::StringPrintf( - R"({"GUID": "%s_guid", "Type": "wifi", "SSID": "%s", + R"({"GUID": "%s", "Type": "wifi", "SSID": "%s", %s "State": "ready", "Strength": 100, %s "AutoConnect": true, "Connectable": true})", - ssid.c_str(), ssid.c_str(), security_entry.c_str(), + guid.c_str(), ssid.c_str(), security_entry.c_str(), profile_entry.c_str())); base::RunLoop().RunUntilIdle(); @@ -102,6 +103,8 @@ NetworkHandler::Get()->network_metadata_store()->ConnectSucceeded( service_path); } + + return guid; } NetworkStateTestHelper* NetworkTestHelper::network_state_test_helper() {
diff --git a/chromeos/components/sync_wifi/network_test_helper.h b/chromeos/components/sync_wifi/network_test_helper.h index b2c4e4c..afba862 100644 --- a/chromeos/components/sync_wifi/network_test_helper.h +++ b/chromeos/components/sync_wifi/network_test_helper.h
@@ -29,10 +29,12 @@ virtual ~NetworkTestHelper(); void SetUp(); - void ConfigureWiFiNetwork(const std::string& ssid, - bool is_secured, - bool in_profile, - bool has_connected); + + // Returns the |guid| of the newly configured network. + std::string ConfigureWiFiNetwork(const std::string& ssid, + bool is_secured, + bool in_profile, + bool has_connected); NetworkStateTestHelper* network_state_test_helper();
diff --git a/chromeos/components/sync_wifi/wifi_configuration_bridge.cc b/chromeos/components/sync_wifi/wifi_configuration_bridge.cc index b144a53..82e5607d 100644 --- a/chromeos/components/sync_wifi/wifi_configuration_bridge.cc +++ b/chromeos/components/sync_wifi/wifi_configuration_bridge.cc
@@ -11,10 +11,13 @@ #include "base/memory/ptr_util.h" #include "base/metrics/histogram_macros.h" #include "base/optional.h" +#include "base/strings/stringprintf.h" #include "base/time/clock.h" #include "base/time/time.h" #include "chromeos/components/sync_wifi/network_identifier.h" #include "chromeos/components/sync_wifi/synced_network_updater.h" +#include "chromeos/network/network_configuration_handler.h" +#include "chromeos/network/network_metadata_store.h" #include "components/device_event_log/device_event_log.h" #include "components/sync/model/entity_change.h" #include "components/sync/model/metadata_batch.h" @@ -22,6 +25,7 @@ #include "components/sync/model/model_type_change_processor.h" #include "components/sync/model/mutable_data_batch.h" #include "components/sync/protocol/model_type_state.pb.h" +#include "third_party/cros_system_api/dbus/shill/dbus-constants.h" namespace chromeos { @@ -41,18 +45,31 @@ WifiConfigurationBridge::WifiConfigurationBridge( SyncedNetworkUpdater* synced_network_updater, LocalNetworkCollector* local_network_collector, + NetworkConfigurationHandler* network_configuration_handler, std::unique_ptr<syncer::ModelTypeChangeProcessor> change_processor, syncer::OnceModelTypeStoreFactory create_store_callback) : ModelTypeSyncBridge(std::move(change_processor)), synced_network_updater_(synced_network_updater), - local_network_collector_(local_network_collector) { + local_network_collector_(local_network_collector), + network_configuration_handler_(network_configuration_handler), + network_metadata_store_(nullptr) { std::move(create_store_callback) .Run(syncer::WIFI_CONFIGURATIONS, base::BindOnce(&WifiConfigurationBridge::OnStoreCreated, weak_ptr_factory_.GetWeakPtr())); + if (network_configuration_handler_) { + network_configuration_handler_->AddObserver(this); + } } -WifiConfigurationBridge::~WifiConfigurationBridge() {} +WifiConfigurationBridge::~WifiConfigurationBridge() { + if (network_metadata_store_) { + network_metadata_store_->RemoveObserver(this); + } + if (network_configuration_handler_) { + network_configuration_handler_->RemoveObserver(this); + } +} std::unique_ptr<syncer::MetadataChangeList> WifiConfigurationBridge::CreateMetadataChangeList() { @@ -294,6 +311,100 @@ return ids; } +void WifiConfigurationBridge::OnFirstConnectionToNetwork( + const std::string& guid) { + if (network_metadata_store_->GetIsConfiguredBySync(guid)) { + // Don't have to upload a configuration that came from sync. + return; + } + + local_network_collector_->GetSyncableNetwork( + guid, base::BindOnce(&WifiConfigurationBridge::SaveNetworkToSync, + weak_ptr_factory_.GetWeakPtr())); +} + +void WifiConfigurationBridge::SaveNetworkToSync( + base::Optional<sync_pb::WifiConfigurationSpecifics> proto) { + if (!proto) { + return; + } + + std::unique_ptr<syncer::EntityData> entity_data = + GenerateWifiEntityData(*proto); + std::string storage_key = GetStorageKey(*entity_data); + + std::unique_ptr<syncer::ModelTypeStore::WriteBatch> batch = + store_->CreateWriteBatch(); + batch->WriteData(storage_key, proto->SerializeAsString()); + change_processor()->Put(storage_key, std::move(entity_data), + batch->GetMetadataChangeList()); + entries_[storage_key] = *proto; + Commit(std::move(batch)); +} + +void WifiConfigurationBridge::OnBeforeConfigurationRemoved( + const std::string& service_path, + const std::string& guid) { + base::Optional<NetworkIdentifier> id = + local_network_collector_->GetNetworkIdentifierFromGuid(guid); + if (!id) { + return; + } + + std::string storage_key = id->SerializeToString(); + if (entries_.contains(storage_key)) + pending_deletes_[guid] = storage_key; +} + +void WifiConfigurationBridge::OnConfigurationRemoved( + const std::string& service_path, + const std::string& network_guid) { + LOG(ERROR) << "WifiConfigurationBridge::RemoveNetworkFromSync" << this; + if (!pending_deletes_.contains(network_guid)) + return; + + std::string storage_key = pending_deletes_[network_guid]; + + std::unique_ptr<syncer::ModelTypeStore::WriteBatch> batch = + store_->CreateWriteBatch(); + batch->DeleteData(storage_key); + change_processor()->Delete(storage_key, batch->GetMetadataChangeList()); + entries_.erase(storage_key); + Commit(std::move(batch)); +} + +void WifiConfigurationBridge::OnConfigurationModified( + const std::string& service_path, + const std::string& guid, + base::DictionaryValue* set_properties) { + if (!set_properties) + return; + + if (network_metadata_store_->GetIsConfiguredBySync(guid)) { + // Don't have to upload a configuration that came from sync. + return; + } + if (set_properties->HasKey(shill::kAutoConnectProperty) || + set_properties->HasKey(shill::kPriorityProperty) || + set_properties->HasKey(shill::kProxyConfigProperty) || + set_properties->FindPath( + base::StringPrintf("%s.%s", shill::kStaticIPConfigProperty, + shill::kNameServersProperty))) { + local_network_collector_->GetSyncableNetwork( + guid, base::BindOnce(&WifiConfigurationBridge::SaveNetworkToSync, + weak_ptr_factory_.GetWeakPtr())); + } +} + +void WifiConfigurationBridge::SetNetworkMetadataStore( + base::WeakPtr<NetworkMetadataStore> network_metadata_store) { + if (network_metadata_store_) { + network_metadata_store->RemoveObserver(this); + } + network_metadata_store_ = network_metadata_store; + network_metadata_store->AddObserver(this); +} + } // namespace sync_wifi } // namespace chromeos
diff --git a/chromeos/components/sync_wifi/wifi_configuration_bridge.h b/chromeos/components/sync_wifi/wifi_configuration_bridge.h index ccd37c7e..889e87f6 100644 --- a/chromeos/components/sync_wifi/wifi_configuration_bridge.h +++ b/chromeos/components/sync_wifi/wifi_configuration_bridge.h
@@ -16,6 +16,8 @@ #include "base/time/time.h" #include "chromeos/components/sync_wifi/local_network_collector.h" #include "chromeos/components/sync_wifi/synced_network_updater.h" +#include "chromeos/network/network_configuration_observer.h" +#include "chromeos/network/network_metadata_observer.h" #include "components/sync/base/model_type.h" #include "components/sync/model/model_type_store.h" #include "components/sync/model/model_type_sync_bridge.h" @@ -26,15 +28,21 @@ namespace chromeos { +class NetworkConfigurationHandler; +class NetworkMetadataStore; + namespace sync_wifi { // Receives updates to network configurations from the Chrome sync back end and // from the system network stack and keeps both lists in sync. -class WifiConfigurationBridge : public syncer::ModelTypeSyncBridge { +class WifiConfigurationBridge : public syncer::ModelTypeSyncBridge, + public NetworkConfigurationObserver, + public NetworkMetadataObserver { public: WifiConfigurationBridge( SyncedNetworkUpdater* synced_network_updater, LocalNetworkCollector* local_network_collector, + NetworkConfigurationHandler* network_configuration_handler, std::unique_ptr<syncer::ModelTypeChangeProcessor> change_processor, syncer::OnceModelTypeStoreFactory create_store_callback); ~WifiConfigurationBridge() override; @@ -53,9 +61,24 @@ std::string GetClientTag(const syncer::EntityData& entity_data) override; std::string GetStorageKey(const syncer::EntityData& entity_data) override; + // NetworkMetadataObserver: + void OnFirstConnectionToNetwork(const std::string& guid) override; + + // NetworkConfigurationObserver:: + void OnConfigurationModified(const std::string& service_path, + const std::string& guid, + base::DictionaryValue* set_properties) override; + void OnBeforeConfigurationRemoved(const std::string& service_path, + const std::string& guid) override; + void OnConfigurationRemoved(const std::string& service_path, + const std::string& guid) override; + // Comes from |entries_| the in-memory map. std::vector<NetworkIdentifier> GetAllIdsForTesting(); + void SetNetworkMetadataStore( + base::WeakPtr<NetworkMetadataStore> network_metadata_store); + private: void Commit(std::unique_ptr<syncer::ModelTypeStore::WriteBatch> batch); @@ -74,20 +97,31 @@ syncer::EntityChangeList change_list, std::vector<sync_pb::WifiConfigurationSpecifics> local_network_list); + void SaveNetworkToSync( + base::Optional<sync_pb::WifiConfigurationSpecifics> proto); + void RemoveNetworkFromSync( + base::Optional<sync_pb::WifiConfigurationSpecifics> proto); + // An in-memory list of the proto's that mirrors what is on the sync server. // This gets updated when changes are received from the server and after local // changes have been committed. On initialization of this class, it is // populated with the contents of |store_|. base::flat_map<std::string, sync_pb::WifiConfigurationSpecifics> entries_; + // Map of network |guid| to |storage_key|. After a network is deleted, we + // no longer have access to its metadata so this stores the necessary + // information to delete it from sync. + base::flat_map<std::string, std::string> pending_deletes_; + // The on disk store of WifiConfigurationSpecifics protos that mirrors what // is on the sync server. This gets updated when changes are received from // the server and after local changes have been committed to the server. std::unique_ptr<syncer::ModelTypeStore> store_; SyncedNetworkUpdater* synced_network_updater_; - LocalNetworkCollector* local_network_collector_; + NetworkConfigurationHandler* network_configuration_handler_; + base::WeakPtr<NetworkMetadataStore> network_metadata_store_; base::WeakPtrFactory<WifiConfigurationBridge> weak_ptr_factory_{this};
diff --git a/chromeos/components/sync_wifi/wifi_configuration_bridge_unittest.cc b/chromeos/components/sync_wifi/wifi_configuration_bridge_unittest.cc index 1f63555b..a5547d9e 100644 --- a/chromeos/components/sync_wifi/wifi_configuration_bridge_unittest.cc +++ b/chromeos/components/sync_wifi/wifi_configuration_bridge_unittest.cc
@@ -16,6 +16,9 @@ #include "chromeos/components/sync_wifi/network_identifier.h" #include "chromeos/components/sync_wifi/synced_network_updater.h" #include "chromeos/components/sync_wifi/test_data_generator.h" +#include "chromeos/network/network_metadata_store.h" +#include "components/prefs/pref_registry_simple.h" +#include "components/prefs/testing_pref_service.h" #include "components/sync/model/data_batch.h" #include "components/sync/model/entity_change.h" #include "components/sync/model/metadata_batch.h" @@ -24,8 +27,10 @@ #include "components/sync/model_impl/in_memory_metadata_change_list.h" #include "components/sync/protocol/model_type_state.pb.h" #include "components/sync/test/test_matchers.h" +#include "components/sync_preferences/testing_pref_service_syncable.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/cros_system_api/dbus/shill/dbus-constants.h" namespace chromeos { @@ -46,12 +51,13 @@ const char kSsidMeow[] = "meow"; const char kSsidWoof[] = "woof"; const char kSsidHonk[] = "honk"; +const char kSyncPsk[] = "sync_psk"; +const char kLocalPsk[] = "local_psk"; syncer::EntityData GenerateWifiEntityData( const sync_pb::WifiConfigurationSpecifics& data) { syncer::EntityData entity_data; - entity_data.specifics.mutable_wifi_configuration() - ->CopyFrom(data); + entity_data.specifics.mutable_wifi_configuration()->CopyFrom(data); entity_data.name = data.hex_ssid(); return entity_data; } @@ -117,10 +123,24 @@ ON_CALL(mock_processor_, IsTrackingMetadata()).WillByDefault(Return(true)); synced_network_updater_ = std::make_unique<TestSyncedNetworkUpdater>(); local_network_collector_ = std::make_unique<FakeLocalNetworkCollector>(); + + user_prefs_ = + std::make_unique<sync_preferences::TestingPrefServiceSyncable>(); + device_prefs_ = std::make_unique<TestingPrefServiceSimple>(); + NetworkMetadataStore::RegisterPrefs(user_prefs_->registry()); + NetworkMetadataStore::RegisterPrefs(device_prefs_->registry()); + network_metadata_store_ = std::make_unique<NetworkMetadataStore>( + /*network_configuration_handler=*/nullptr, + /*network_connection_handler=*/nullptr, + /*network_state_handler=*/nullptr, user_prefs_.get(), + device_prefs_.get()); + bridge_ = std::make_unique<WifiConfigurationBridge>( synced_network_updater(), local_network_collector(), + /*network_configuration_handler=*/nullptr, mock_processor_.CreateForwardingProcessor(), syncer::ModelTypeStoreTestUtil::MoveStoreToFactory(std::move(store_))); + bridge_->SetNetworkMetadataStore(network_metadata_store_->GetWeakPtr()); } void DisableBridge() { @@ -166,28 +186,22 @@ } const NetworkIdentifier& woof_network_id() const { return woof_network_id_; } - const NetworkIdentifier& meow_network_id() const { return meow_network_id_; } - const NetworkIdentifier& honk_network_id() const { return honk_network_id_; } private: base::test::TaskEnvironment task_environment_; - std::unique_ptr<syncer::ModelTypeStore> store_; - testing::NiceMock<syncer::MockModelTypeChangeProcessor> mock_processor_; - std::unique_ptr<WifiConfigurationBridge> bridge_; - std::unique_ptr<TestSyncedNetworkUpdater> synced_network_updater_; - std::unique_ptr<FakeLocalNetworkCollector> local_network_collector_; + std::unique_ptr<TestingPrefServiceSimple> device_prefs_; + std::unique_ptr<sync_preferences::TestingPrefServiceSyncable> user_prefs_; + std::unique_ptr<NetworkMetadataStore> network_metadata_store_; const NetworkIdentifier woof_network_id_ = GeneratePskNetworkId(kSsidWoof); - const NetworkIdentifier meow_network_id_ = GeneratePskNetworkId(kSsidMeow); - const NetworkIdentifier honk_network_id_ = GeneratePskNetworkId(kSsidHonk); DISALLOW_COPY_AND_ASSIGN(WifiConfigurationBridgeTest); @@ -307,8 +321,6 @@ auto metadata_change_list = std::make_unique<syncer::InMemoryMetadataChangeList>(); syncer::EntityChangeList entity_data; - const char kSyncPsk[] = "sync_psk"; - const char kLocalPsk[] = "local_psk"; WifiConfigurationSpecifics meow_sync = GenerateTestWifiSpecifics(meow_network_id(), kSyncPsk, /*timestamp=*/100); @@ -359,6 +371,67 @@ EXPECT_TRUE(VectorContainsProto(sync_networks, honk_sync)); } +TEST_F(WifiConfigurationBridgeTest, LocalFirstConnect) { + WifiConfigurationSpecifics meow_local = + GenerateTestWifiSpecifics(meow_network_id(), kSyncPsk, /*timestamp=*/100); + local_network_collector()->AddNetwork(meow_local); + + std::string storage_key; + EXPECT_CALL(*processor(), Put(_, _, _)) + .WillOnce(testing::SaveArg<0>(&storage_key)); + bridge()->OnFirstConnectionToNetwork(meow_network_id().SerializeToString()); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(storage_key, meow_network_id().SerializeToString()); +} + +TEST_F(WifiConfigurationBridgeTest, LocalUpdate) { + WifiConfigurationSpecifics meow_local = + GenerateTestWifiSpecifics(meow_network_id(), kSyncPsk, /*timestamp=*/100); + local_network_collector()->AddNetwork(meow_local); + + std::string storage_key; + EXPECT_CALL(*processor(), Put(_, _, _)) + .WillOnce(testing::SaveArg<0>(&storage_key)); + std::string guid = meow_network_id().SerializeToString(); + base::DictionaryValue set_properties; + set_properties.SetBoolean(shill::kAutoConnectProperty, true); + bridge()->OnConfigurationModified("service_path", guid, &set_properties); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(storage_key, meow_network_id().SerializeToString()); +} + +TEST_F(WifiConfigurationBridgeTest, LocalUpdate_UntrackedField) { + WifiConfigurationSpecifics meow_local = + GenerateTestWifiSpecifics(meow_network_id(), kSyncPsk, /*timestamp=*/100); + local_network_collector()->AddNetwork(meow_local); + + EXPECT_CALL(*processor(), Put(_, _, _)).Times(testing::Exactly(0)); + std::string guid = meow_network_id().SerializeToString(); + base::DictionaryValue set_properties; + set_properties.SetString(shill::kUIDataProperty, "random_change"); + bridge()->OnConfigurationModified("service_path", guid, &set_properties); + base::RunLoop().RunUntilIdle(); +} + +TEST_F(WifiConfigurationBridgeTest, LocalRemove) { + WifiConfigurationSpecifics meow_local = + GenerateTestWifiSpecifics(meow_network_id(), kSyncPsk, /*timestamp=*/100); + local_network_collector()->AddNetwork(meow_local); + std::string guid = meow_network_id().SerializeToString(); + + bridge()->OnFirstConnectionToNetwork(guid); + base::RunLoop().RunUntilIdle(); + + bridge()->OnBeforeConfigurationRemoved("service_path", guid); + + std::string storage_key; + EXPECT_CALL(*processor(), Delete(_, _)) + .WillOnce(testing::SaveArg<0>(&storage_key)); + bridge()->OnConfigurationRemoved("service_path", guid); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(storage_key, meow_network_id().SerializeToString()); +} + } // namespace } // namespace sync_wifi
diff --git a/chromeos/components/sync_wifi/wifi_configuration_sync_service.cc b/chromeos/components/sync_wifi/wifi_configuration_sync_service.cc index e14083f8..7c20f38 100644 --- a/chromeos/components/sync_wifi/wifi_configuration_sync_service.cc +++ b/chromeos/components/sync_wifi/wifi_configuration_sync_service.cc
@@ -15,6 +15,7 @@ #include "chromeos/components/sync_wifi/timer_factory.h" #include "chromeos/components/sync_wifi/wifi_configuration_bridge.h" #include "chromeos/network/network_handler.h" +#include "chromeos/network/network_metadata_store.h" #include "chromeos/services/network_config/public/mojom/cros_network_config.mojom.h" #include "components/sync/base/report_unrecoverable_error.h" #include "components/sync/model/model_type_store.h" @@ -34,10 +35,11 @@ std::make_unique<PendingNetworkConfigurationTrackerImpl>(pref_service), remote_cros_network_config_.get(), std::make_unique<TimerFactory>()); collector_ = std::make_unique<LocalNetworkCollectorImpl>( - remote_cros_network_config_.get(), - NetworkHandler::Get()->network_metadata_store()); + remote_cros_network_config_.get()); + NetworkHandler* network_handler = NetworkHandler::Get(); bridge_ = std::make_unique<sync_wifi::WifiConfigurationBridge>( updater_.get(), collector_.get(), + network_handler->network_configuration_handler(), std::make_unique<syncer::ClientTagBasedModelTypeProcessor>( syncer::WIFI_CONFIGURATIONS, base::BindRepeating(&syncer::ReportUnrecoverableError, channel)), @@ -51,6 +53,12 @@ return bridge_->change_processor()->GetControllerDelegate(); } +void WifiConfigurationSyncService::SetNetworkMetadataStore( + base::WeakPtr<NetworkMetadataStore> network_metadata_store) { + bridge_->SetNetworkMetadataStore(network_metadata_store); + collector_->SetNetworkMetadataStore(network_metadata_store); +} + } // namespace sync_wifi } // namespace chromeos
diff --git a/chromeos/components/sync_wifi/wifi_configuration_sync_service.h b/chromeos/components/sync_wifi/wifi_configuration_sync_service.h index 6cfe06b..12fca400 100644 --- a/chromeos/components/sync_wifi/wifi_configuration_sync_service.h +++ b/chromeos/components/sync_wifi/wifi_configuration_sync_service.h
@@ -23,6 +23,8 @@ namespace chromeos { +class NetworkMetadataStore; + namespace sync_wifi { class LocalNetworkCollectorImpl; @@ -40,6 +42,8 @@ ~WifiConfigurationSyncService() override; base::WeakPtr<syncer::ModelTypeControllerDelegate> GetControllerDelegate(); + void SetNetworkMetadataStore( + base::WeakPtr<NetworkMetadataStore> network_metadata_store); private: std::unique_ptr<WifiConfigurationBridge> bridge_;
diff --git a/chromeos/network/network_configuration_handler.cc b/chromeos/network/network_configuration_handler.cc index 9c4a1e3..12c60c6b 100644 --- a/chromeos/network/network_configuration_handler.cc +++ b/chromeos/network/network_configuration_handler.cc
@@ -422,6 +422,8 @@ NET_LOG(USER) << "Remove Configuration: " << NetworkPathId(service_path) << " from profiles: " << (!profile_path.empty() ? profile_path : "all"); + for (auto& observer : observers_) + observer.OnBeforeConfigurationRemoved(service_path, guid); ProfileEntryDeleter* deleter = new ProfileEntryDeleter( this, service_path, guid, callback, error_callback); if (!profile_path.empty())
diff --git a/chromeos/network/network_configuration_handler_unittest.cc b/chromeos/network/network_configuration_handler_unittest.cc index e208b28..4992b70 100644 --- a/chromeos/network/network_configuration_handler_unittest.cc +++ b/chromeos/network/network_configuration_handler_unittest.cc
@@ -95,6 +95,13 @@ TestNetworkConfigurationObserver() = default; // NetworkConfigurationObserver + void OnBeforeConfigurationRemoved(const std::string& service_path, + const std::string& guid) override { + ASSERT_EQ(before_remove_configurations_.end(), + before_remove_configurations_.find(service_path)); + before_remove_configurations_[service_path] = guid; + } + void OnConfigurationRemoved(const std::string& service_path, const std::string& guid) override { ASSERT_EQ(removed_configurations_.end(), @@ -108,6 +115,11 @@ updated_configurations_[service_path] = guid; } + bool HasCalledBeforeRemoveConfiguration(const std::string& service_path) { + return before_remove_configurations_.find(service_path) != + before_remove_configurations_.end(); + } + bool HasRemovedConfiguration(const std::string& service_path) { return removed_configurations_.find(service_path) != removed_configurations_.end(); @@ -119,6 +131,7 @@ } private: + std::map<std::string, std::string> before_remove_configurations_; std::map<std::string, std::string> removed_configurations_; std::map<std::string, std::string> updated_configurations_; @@ -669,6 +682,9 @@ EXPECT_FALSE( network_configuration_observer->HasRemovedConfiguration(service_path)); + EXPECT_FALSE( + network_configuration_observer->HasCalledBeforeRemoveConfiguration( + service_path)); network_configuration_handler_->RemoveConfiguration( service_path, base::DoNothing(), base::Bind(&ErrorCallback)); @@ -676,6 +692,9 @@ EXPECT_TRUE( network_configuration_observer->HasRemovedConfiguration(service_path)); + EXPECT_TRUE( + network_configuration_observer->HasCalledBeforeRemoveConfiguration( + service_path)); network_configuration_handler_->RemoveObserver( network_configuration_observer.get());
diff --git a/chromeos/network/network_configuration_observer.cc b/chromeos/network/network_configuration_observer.cc index 4142020..f810947 100644 --- a/chromeos/network/network_configuration_observer.cc +++ b/chromeos/network/network_configuration_observer.cc
@@ -15,6 +15,10 @@ const std::string& guid, base::DictionaryValue* set_properties) {} +void NetworkConfigurationObserver::OnBeforeConfigurationRemoved( + const std::string& service_path, + const std::string& guid) {} + void NetworkConfigurationObserver::OnConfigurationRemoved( const std::string& service_path, const std::string& guid) {}
diff --git a/chromeos/network/network_configuration_observer.h b/chromeos/network/network_configuration_observer.h index 59dd8451..4570268 100644 --- a/chromeos/network/network_configuration_observer.h +++ b/chromeos/network/network_configuration_observer.h
@@ -24,6 +24,10 @@ const std::string& guid, base::DictionaryValue* set_properties); + // Called before a delete is attempted. + virtual void OnBeforeConfigurationRemoved(const std::string& service_path, + const std::string& guid); + // Called whenever a network configuration is removed. |service_path| // provides the Shill current identifier for the network. |guid| will be set // to the corresponding GUID for the network if known at the time of removal,
diff --git a/chromeos/network/network_metadata_store.h b/chromeos/network/network_metadata_store.h index be54a1e..0ad50125 100644 --- a/chromeos/network/network_metadata_store.h +++ b/chromeos/network/network_metadata_store.h
@@ -72,6 +72,10 @@ void AddObserver(NetworkMetadataObserver* observer); void RemoveObserver(NetworkMetadataObserver* observer); + base::WeakPtr<NetworkMetadataStore> GetWeakPtr() { + return weak_ptr_factory_.GetWeakPtr(); + } + private: void RemoveNetworkFromPref(const std::string& network_guid, PrefService* pref_service); @@ -88,6 +92,7 @@ NetworkStateHandler* network_state_handler_; PrefService* profile_pref_service_; PrefService* device_pref_service_; + base::WeakPtrFactory<NetworkMetadataStore> weak_ptr_factory_{this}; }; } // namespace chromeos
diff --git a/chromeos/profiles/airmont.afdo.newest.txt b/chromeos/profiles/airmont.afdo.newest.txt index dd7b68d..571a247b 100644 --- a/chromeos/profiles/airmont.afdo.newest.txt +++ b/chromeos/profiles/airmont.afdo.newest.txt
@@ -1 +1 @@ -chromeos-chrome-amd64-airmont-83-4085.6-1584959535-benchmark-82.0.4085.16-r1-redacted.afdo.xz \ No newline at end of file +chromeos-chrome-amd64-airmont-83-4085.6-1584959535-benchmark-83.0.4091.0-r2-redacted.afdo.xz \ No newline at end of file
diff --git a/components/autofill/core/browser/autofill_test_utils.cc b/components/autofill/core/browser/autofill_test_utils.cc index 511443c2..f0f8cc5 100644 --- a/components/autofill/core/browser/autofill_test_utils.cc +++ b/components/autofill/core/browser/autofill_test_utils.cc
@@ -373,33 +373,29 @@ CreditCard GetCreditCard() { CreditCard credit_card(base::GenerateGUID(), kEmptyOrigin); - // TODO(crbug/1059087): Change hardcoded year to NextYear. SetCreditCardInfo(&credit_card, "Test User", "4111111111111111" /* Visa */, - "11", "2022", "1"); + NextMonth().c_str(), NextYear().c_str(), "1"); return credit_card; } CreditCard GetCreditCard2() { CreditCard credit_card(base::GenerateGUID(), kEmptyOrigin); - // TODO(crbug/1059087): Change hardcoded year to NextYear. SetCreditCardInfo(&credit_card, "Someone Else", "378282246310005" /* AmEx */, - "07", "2022", "1"); + NextMonth().c_str(), TenYearsFromNow().c_str(), "1"); return credit_card; } CreditCard GetExpiredCreditCard() { CreditCard credit_card(base::GenerateGUID(), kEmptyOrigin); - // TODO(crbug/1059087): Change hardcoded year to NextYear. SetCreditCardInfo(&credit_card, "Test User", "4111111111111111" /* Visa */, - "11", "2002", "1"); + NextMonth().c_str(), LastYear().c_str(), "1"); return credit_card; } CreditCard GetIncompleteCreditCard() { CreditCard credit_card(base::GenerateGUID(), kEmptyOrigin); - // TODO(crbug/1059087): Change hardcoded year to NextYear. - SetCreditCardInfo(&credit_card, "", "4111111111111111" /* Visa */, "11", - "2022", "1"); + SetCreditCardInfo(&credit_card, "", "4111111111111111" /* Visa */, + NextMonth().c_str(), NextYear().c_str(), "1"); return credit_card; } @@ -757,22 +753,22 @@ std::string NextMonth() { base::Time::Exploded now; - base::Time::Now().LocalExplode(&now); - return base::NumberToString(now.month % 12 + 1); + AutofillClock::Now().LocalExplode(&now); + return base::StringPrintf("%02d", now.month % 12 + 1); } std::string LastYear() { base::Time::Exploded now; - base::Time::Now().LocalExplode(&now); + AutofillClock::Now().LocalExplode(&now); return base::NumberToString(now.year - 1); } std::string NextYear() { base::Time::Exploded now; - base::Time::Now().LocalExplode(&now); + AutofillClock::Now().LocalExplode(&now); return base::NumberToString(now.year + 1); } std::string TenYearsFromNow() { base::Time::Exploded now; - base::Time::Now().LocalExplode(&now); + AutofillClock::Now().LocalExplode(&now); return base::NumberToString(now.year + 10); }
diff --git a/components/autofill/core/browser/autofill_test_utils.h b/components/autofill/core/browser/autofill_test_utils.h index 870be0f..49dd131 100644 --- a/components/autofill/core/browser/autofill_test_utils.h +++ b/components/autofill/core/browser/autofill_test_utils.h
@@ -275,6 +275,7 @@ std::string ObfuscatedCardDigitsAsUTF8(const std::string& str); +// Returns 2-digit month string, like "02", "10". std::string NextMonth(); std::string LastYear(); std::string NextYear();
diff --git a/components/autofill/core/browser/payments/credit_card_save_manager_unittest.cc b/components/autofill/core/browser/payments/credit_card_save_manager_unittest.cc index f7f53cd..6cbc240 100644 --- a/components/autofill/core/browser/payments/credit_card_save_manager_unittest.cc +++ b/components/autofill/core/browser/payments/credit_card_save_manager_unittest.cc
@@ -74,8 +74,9 @@ using UkmCardUploadDecisionType = ukm::builders::Autofill_CardUploadDecision; using UkmDeveloperEngagementType = ukm::builders::Autofill_DeveloperEngagement; -const base::Time kArbitraryTime = base::Time::FromDoubleT(25); -const base::Time kMuchLaterTime = base::Time::FromDoubleT(5000); +// time_t representation of 9th Sep, 2001 01:46:40 GMT +const base::Time kArbitraryTime = base::Time::FromTimeT(1000000000); +const base::Time kMuchLaterTime = base::Time::FromTimeT(1234567890); // Used to configure form for |CreateTestCreditCardFormData|. struct CreditCardFormOptions {
diff --git a/components/background_task_scheduler/internal/android/java/src/org/chromium/components/background_task_scheduler/internal/BackgroundTaskSchedulerUma.java b/components/background_task_scheduler/internal/android/java/src/org/chromium/components/background_task_scheduler/internal/BackgroundTaskSchedulerUma.java index 0cfdafa3..90d3677d 100644 --- a/components/background_task_scheduler/internal/android/java/src/org/chromium/components/background_task_scheduler/internal/BackgroundTaskSchedulerUma.java +++ b/components/background_task_scheduler/internal/android/java/src/org/chromium/components/background_task_scheduler/internal/BackgroundTaskSchedulerUma.java
@@ -276,18 +276,26 @@ @VisibleForTesting static Set<String> getCachedUmaEntries(SharedPreferences prefs) { - return prefs.getStringSet(KEY_CACHED_UMA, new HashSet<String>(1)); + Set<String> cachedUmaEntries = prefs.getStringSet(KEY_CACHED_UMA, new HashSet<>()); + return sanitizeEntrySet(cachedUmaEntries); } @VisibleForTesting static void updateCachedUma(SharedPreferences prefs, Set<String> cachedUma) { ThreadUtils.assertOnUiThread(); SharedPreferences.Editor editor = prefs.edit(); - editor.putStringSet(KEY_CACHED_UMA, cachedUma); + editor.putStringSet(KEY_CACHED_UMA, sanitizeEntrySet(cachedUma)); editor.apply(); } void assertNativeIsLoaded() { assert LibraryLoader.getInstance().isInitialized(); } + + private static Set<String> sanitizeEntrySet(Set<String> set) { + if (set != null && set.contains(null)) { + set.remove(null); + } + return set; + } }
diff --git a/components/background_task_scheduler/internal/android/junit/src/org/chromium/components/background_task_scheduler/internal/BackgroundTaskSchedulerUmaTest.java b/components/background_task_scheduler/internal/android/junit/src/org/chromium/components/background_task_scheduler/internal/BackgroundTaskSchedulerUmaTest.java index a9f60ae5..b0fd24c 100644 --- a/components/background_task_scheduler/internal/android/junit/src/org/chromium/components/background_task_scheduler/internal/BackgroundTaskSchedulerUmaTest.java +++ b/components/background_task_scheduler/internal/android/junit/src/org/chromium/components/background_task_scheduler/internal/BackgroundTaskSchedulerUmaTest.java
@@ -5,6 +5,7 @@ package org.chromium.components.background_task_scheduler.internal; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.anyString; @@ -14,6 +15,8 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import android.content.SharedPreferences; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -28,6 +31,7 @@ import org.chromium.components.background_task_scheduler.BackgroundTaskSchedulerExternalUma; import org.chromium.components.background_task_scheduler.TaskIds; +import java.util.HashSet; import java.util.Set; /** Unit tests for {@link BackgroundTaskSchedulerUma}. */ @@ -150,6 +154,28 @@ @Test @Feature({"BackgroundTaskScheduler"}) + public void testCacheEvent_StringStartWithNpe() { + // Set up preferences with a null entry. + SharedPreferences.Editor editor = ContextUtils.getAppSharedPreferences().edit(); + HashSet<String> setWithNullValue = new HashSet<>(); + setWithNullValue.add(null); + editor.putStringSet(BackgroundTaskSchedulerUma.KEY_CACHED_UMA, setWithNullValue); + editor.apply(); + + Set<String> cachedUmaEntries = BackgroundTaskSchedulerUma.getCachedUmaEntries( + ContextUtils.getAppSharedPreferences()); + assertTrue(cachedUmaEntries.isEmpty()); + + mUmaSpy.cacheEvent("NpeTestEvent", 77); + + cachedUmaEntries = BackgroundTaskSchedulerUma.getCachedUmaEntries( + ContextUtils.getAppSharedPreferences()); + assertTrue(cachedUmaEntries.contains("NpeTestEvent:77:1")); + assertFalse(cachedUmaEntries.contains(null)); + } + + @Test + @Feature({"BackgroundTaskScheduler"}) public void testFlushStats() { doNothing().when(mUmaSpy).recordEnumeratedHistogram(anyString(), anyInt(), anyInt());
diff --git a/components/feed/core/v2/BUILD.gn b/components/feed/core/v2/BUILD.gn index c6b96dc2..58e363b 100644 --- a/components/feed/core/v2/BUILD.gn +++ b/components/feed/core/v2/BUILD.gn
@@ -68,6 +68,7 @@ testonly = true sources = [ "feed_network_impl_unittest.cc", + "feed_store_unittest.cc", "feed_stream_unittest.cc", "stream_model_unittest.cc", "stream_model_update_request_unittest.cc", @@ -82,6 +83,7 @@ "//base/test:test_support", "//components/feed/core:feed_core", "//components/feed/core/common:feed_core_common", + "//components/leveldb_proto:test_support", "//components/prefs:test_support", "//components/signin/public/identity_manager", "//components/signin/public/identity_manager:test_support",
diff --git a/components/feed/core/v2/feed_store.cc b/components/feed/core/v2/feed_store.cc index f9d193d7..c7ef851 100644 --- a/components/feed/core/v2/feed_store.cc +++ b/components/feed/core/v2/feed_store.cc
@@ -75,12 +75,22 @@ leveldb_proto::ProtoDbType::FEED_STREAM_DATABASE, feed_directory, task_runner_)) { - database_->Init(base::BindOnce(&FeedStore::OnDatabaseInitialized, - weak_ptr_factory_.GetWeakPtr())); + Initialize(); +} + +FeedStore::FeedStore( + std::unique_ptr<leveldb_proto::ProtoDatabase<feedstore::Record>> database) + : database_(std::move(database)) { + Initialize(); } FeedStore::~FeedStore() = default; +void FeedStore::Initialize() { + database_->Init(base::BindOnce(&FeedStore::OnDatabaseInitialized, + weak_ptr_factory_.GetWeakPtr())); +} + void FeedStore::OnDatabaseInitialized(leveldb_proto::Enums::InitStatus status) { database_status_ = status; } @@ -89,6 +99,10 @@ return database_status_ == leveldb_proto::Enums::InitStatus::kOK; } +bool FeedStore::IsInitializedForTesting() const { + return IsInitialized(); +} + void FeedStore::ReadSingle( const std::string& key, base::OnceCallback<void(bool, std::unique_ptr<feedstore::Record>)> @@ -129,7 +143,7 @@ base::OnceCallback<void(std::unique_ptr<feedstore::StreamData>)> callback, bool success, std::unique_ptr<feedstore::Record> record) { - if (!success) { + if (!success || !record) { std::move(callback).Run(nullptr); return; } @@ -138,16 +152,19 @@ } void FeedStore::ReadContent( - std::vector<feedwire::ContentId> ids, - base::OnceCallback< - void(std::unique_ptr<std::vector<feedstore::Content>>, - std::unique_ptr<std::vector<feedstore::StreamSharedState>>)> + std::vector<feedwire::ContentId> content_ids, + std::vector<feedwire::ContentId> shared_state_ids, + base::OnceCallback<void(std::vector<feedstore::Content>, + std::vector<feedstore::StreamSharedState>)> content_callback) { std::vector<std::string> key_vector; - key_vector.reserve(ids.size()); - for (auto& content_id : ids) + key_vector.reserve(content_ids.size() + shared_state_ids.size()); + for (auto& content_id : content_ids) key_vector.push_back(ContentKey(content_id)); + for (auto& shared_state_id : shared_state_ids) + key_vector.push_back(SharedStateKey(shared_state_id)); + ReadMany(base::flat_set<std::string>(std::move(key_vector)), base::BindOnce(&FeedStore::OnReadContentFinished, weak_ptr_factory_.GetWeakPtr(), @@ -155,26 +172,25 @@ } void FeedStore::OnReadContentFinished( - base::OnceCallback<void( - std::unique_ptr<std::vector<feedstore::Content>>, - std::unique_ptr<std::vector<feedstore::StreamSharedState>>)> callback, + base::OnceCallback<void(std::vector<feedstore::Content>, + std::vector<feedstore::StreamSharedState>)> + callback, bool success, std::unique_ptr<std::vector<feedstore::Record>> records) { - if (!success) { - std::move(callback).Run(nullptr, nullptr); + if (!success || !records) { + std::move(callback).Run({}, {}); return; } - auto content = std::make_unique<std::vector<feedstore::Content>>(); + std::vector<feedstore::Content> content; // Most of records will be content. - content->reserve(records->size()); - auto shared_states = - std::make_unique<std::vector<feedstore::StreamSharedState>>(); + content.reserve(records->size()); + std::vector<feedstore::StreamSharedState> shared_states; for (auto& record : *records) { if (record.data_case() == feedstore::Record::kContent) - content->push_back(std::move(record.content())); + content.push_back(std::move(record.content())); else if (record.data_case() == feedstore::Record::kSharedState) - shared_states->push_back(std::move(record.shared_state())); + shared_states.push_back(std::move(record.shared_state())); } std::move(callback).Run(std::move(content), std::move(shared_states)); @@ -194,7 +210,7 @@ callback, bool success, std::unique_ptr<feedstore::Record> record) { - if (!success) { + if (!success || !record) { std::move(callback).Run(nullptr); return; }
diff --git a/components/feed/core/v2/feed_store.h b/components/feed/core/v2/feed_store.h index 551ff21a..dfdc7506 100644 --- a/components/feed/core/v2/feed_store.h +++ b/components/feed/core/v2/feed_store.h
@@ -20,8 +20,15 @@ public: FeedStore(leveldb_proto::ProtoDatabaseProvider* database_provider, const base::FilePath& feed_directory); + FeedStore(const FeedStore&) = delete; + FeedStore& operator=(const FeedStore&) = delete; ~FeedStore(); + // For testing. + explicit FeedStore( + std::unique_ptr<leveldb_proto::ProtoDatabase<feedstore::Record>> + database); + // Read StreamData and pass it to stream_data_callback, or nullptr on failure. void ReadStreamData( base::OnceCallback<void(std::unique_ptr<feedstore::StreamData>)> @@ -29,10 +36,10 @@ // Read Content and StreamSharedStates and pass them to content_callback, or // nullptrs on failure. void ReadContent( - std::vector<feedwire::ContentId> ids, - base::OnceCallback< - void(std::unique_ptr<std::vector<feedstore::Content>>, - std::unique_ptr<std::vector<feedstore::StreamSharedState>>)> + std::vector<feedwire::ContentId> content_ids, + std::vector<feedwire::ContentId> shared_state_ids, + base::OnceCallback<void(std::vector<feedstore::Content>, + std::vector<feedstore::StreamSharedState>)> content_callback); void ReadNextStreamState( @@ -47,7 +54,11 @@ // TODO(iwells): implement this // Deletes old records that are no longer needed // void RemoveOldData(base::OnceCallback<void(bool)> callback); + + bool IsInitializedForTesting() const; + private: + void Initialize(); void OnDatabaseInitialized(leveldb_proto::Enums::InitStatus status); bool IsInitialized() const; @@ -65,9 +76,9 @@ bool success, std::unique_ptr<feedstore::Record> record); void OnReadContentFinished( - base::OnceCallback<void( - std::unique_ptr<std::vector<feedstore::Content>>, - std::unique_ptr<std::vector<feedstore::StreamSharedState>>)> callback, + base::OnceCallback<void(std::vector<feedstore::Content>, + std::vector<feedstore::StreamSharedState>)> + callback, bool success, std::unique_ptr<std::vector<feedstore::Record>> records); void OnReadNextStreamStateFinished(
diff --git a/components/feed/core/v2/feed_store_unittest.cc b/components/feed/core/v2/feed_store_unittest.cc new file mode 100644 index 0000000..59396072 --- /dev/null +++ b/components/feed/core/v2/feed_store_unittest.cc
@@ -0,0 +1,317 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/feed/core/v2/feed_store.h" +#include "base/strings/strcat.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_piece.h" +#include "base/test/bind_test_util.h" +#include "components/feed/core/proto/v2/wire/content_id.pb.h" +#include "components/feed/core/v2/test/stream_builder.h" +#include "components/leveldb_proto/testing/fake_db.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace feed { +namespace { + +const char kNextPageToken[] = "next page token"; +const char kConsistencyToken[] = "consistency token"; +const int64_t kLastAddedTimeMs = 100; + +feedstore::StreamData MakeStreamData() { + feedstore::StreamData stream_data; + *stream_data.mutable_content_id() = MakeRootId(); + stream_data.set_next_page_token(kNextPageToken); + stream_data.set_consistency_token(kConsistencyToken); + stream_data.set_last_added_time_millis(kLastAddedTimeMs); + + std::vector<feedstore::DataOperation> operations = + MakeTypicalStreamOperations(); + for (auto& operation : operations) { + *stream_data.add_structures() = std::move(operation.structure()); + } + + return stream_data; +} + +std::string ContentIdToString(const feedwire::ContentId& content_id) { + return base::StrCat( + {"{content_domain: \"", content_id.content_domain(), + "\", id: ", base::NumberToString(content_id.id()), ", type: \"", + feedwire::ContentId::Type_Name(content_id.type()), "\"}"}); +} + +std::string KeyForContentId(base::StringPiece prefix, + const feedwire::ContentId& content_id) { + return base::StrCat({prefix, content_id.content_domain(), ",", + base::NumberToString(content_id.type()), ",", + base::NumberToString(content_id.id())}); +} + +feedstore::Record RecordForContent(feedstore::Content content) { + feedstore::Record record; + *record.mutable_content() = std::move(content); + return record; +} + +feedstore::Record RecordForSharedState(feedstore::StreamSharedState shared) { + feedstore::Record record; + *record.mutable_shared_state() = std::move(shared); + return record; +} + +const char kRootKey[] = "S/0"; + +} // namespace + +class FeedStoreTest : public testing::Test { + public: + void MakeFeedStore(std::map<std::string, feedstore::Record> entries, + leveldb_proto::Enums::InitStatus init_status = + leveldb_proto::Enums::InitStatus::kOK) { + db_entries_ = std::move(entries); + auto fake_db = + std::make_unique<leveldb_proto::test::FakeDB<feedstore::Record>>( + &db_entries_); + fake_db_ = fake_db.get(); + store_ = std::make_unique<FeedStore>(std::move(fake_db)); + fake_db_->InitStatusCallback(init_status); + } + + std::unique_ptr<FeedStore> store_; + std::map<std::string, feedstore::Record> db_entries_; + leveldb_proto::test::FakeDB<feedstore::Record>* fake_db_; +}; + +TEST_F(FeedStoreTest, InitSuccess) { + MakeFeedStore({}); + EXPECT_TRUE(store_->IsInitializedForTesting()); +} + +TEST_F(FeedStoreTest, InitFailure) { + std::map<std::string, feedstore::Record> entries; + auto fake_db = + std::make_unique<leveldb_proto::test::FakeDB<feedstore::Record>>( + &entries); + leveldb_proto::test::FakeDB<feedstore::Record>* fake_db_raw = fake_db.get(); + + auto store = std::make_unique<FeedStore>(std::move(fake_db)); + EXPECT_FALSE(store->IsInitializedForTesting()); + + fake_db_raw->InitStatusCallback(leveldb_proto::Enums::InitStatus::kError); + EXPECT_FALSE(store->IsInitializedForTesting()); +} + +TEST_F(FeedStoreTest, ReadStreamData) { + feedstore::Record record; + *record.mutable_stream_data() = MakeStreamData(); + MakeFeedStore({{kRootKey, record}}); + + // Successful read + bool did_successful_read = false; + store_->ReadStreamData(base::BindLambdaForTesting( + [&](std::unique_ptr<feedstore::StreamData> stream_data) { + did_successful_read = true; + ASSERT_TRUE(stream_data); + EXPECT_EQ(ContentIdToString(stream_data->content_id()), + ContentIdToString(record.stream_data().content_id())); + EXPECT_EQ(stream_data->structures_size(), + record.stream_data().structures_size()); + EXPECT_EQ(stream_data->next_page_token(), + record.stream_data().next_page_token()); + EXPECT_EQ(stream_data->consistency_token(), + record.stream_data().consistency_token()); + EXPECT_EQ(stream_data->last_added_time_millis(), + record.stream_data().last_added_time_millis()); + EXPECT_EQ(stream_data->next_action_id(), + record.stream_data().next_action_id()); + })); + fake_db_->GetCallback(true); + EXPECT_TRUE(did_successful_read); + + // Failed read + bool did_failed_read = false; + store_->ReadStreamData(base::BindLambdaForTesting( + [&](std::unique_ptr<feedstore::StreamData> stream_data) { + did_failed_read = true; + EXPECT_FALSE(stream_data); + })); + fake_db_->GetCallback(false); + EXPECT_TRUE(did_failed_read); +} + +TEST_F(FeedStoreTest, ReadNonexistentStreamData) { + MakeFeedStore({}); + + bool did_read = false; + store_->ReadStreamData(base::BindLambdaForTesting( + [&](std::unique_ptr<feedstore::StreamData> stream_data) { + did_read = true; + EXPECT_FALSE(stream_data); + })); + fake_db_->GetCallback(true); + EXPECT_TRUE(did_read); +} + +TEST_F(FeedStoreTest, ReadNonexistentContentAndSharedStates) { + MakeFeedStore({}); + + bool did_read = false; + store_->ReadContent( + {MakeContentContentId(0)}, {MakeSharedStateContentId(0)}, + base::BindLambdaForTesting( + [&](std::vector<feedstore::Content> content, + std::vector<feedstore::StreamSharedState> shared_states) { + did_read = true; + EXPECT_EQ(content.size(), 0ul); + EXPECT_EQ(shared_states.size(), 0ul); + })); + fake_db_->LoadCallback(true); + EXPECT_TRUE(did_read); +} + +TEST_F(FeedStoreTest, ReadContentAndSharedStates) { + feedstore::Content content1 = MakeContent(1); + feedstore::Content content2 = MakeContent(2); + feedstore::StreamSharedState shared1 = MakeSharedState(1); + feedstore::StreamSharedState shared2 = MakeSharedState(2); + + MakeFeedStore({{KeyForContentId("c/", content1.content_id()), + RecordForContent(content1)}, + {KeyForContentId("c/", content2.content_id()), + RecordForContent(content2)}, + {KeyForContentId("s/", shared1.content_id()), + RecordForSharedState(shared1)}, + {KeyForContentId("s/", shared2.content_id()), + RecordForSharedState(shared2)}}); + + std::vector<feedwire::ContentId> content_ids = {content1.content_id(), + content2.content_id()}; + std::vector<feedwire::ContentId> shared_state_ids = {shared1.content_id(), + shared2.content_id()}; + + // Successful read + bool did_successful_read = false; + store_->ReadContent( + content_ids, shared_state_ids, + base::BindLambdaForTesting( + [&](std::vector<feedstore::Content> content, + std::vector<feedstore::StreamSharedState> shared_states) { + did_successful_read = true; + ASSERT_EQ(content.size(), 2ul); + EXPECT_EQ(ContentIdToString(content[0].content_id()), + ContentIdToString(content1.content_id())); + EXPECT_EQ(content[0].frame(), content1.frame()); + + ASSERT_EQ(shared_states.size(), 2ul); + EXPECT_EQ(ContentIdToString(shared_states[0].content_id()), + ContentIdToString(shared1.content_id())); + EXPECT_EQ(shared_states[0].shared_state_data(), + shared1.shared_state_data()); + })); + fake_db_->LoadCallback(true); + EXPECT_TRUE(did_successful_read); + + // Failed read + bool did_failed_read = false; + store_->ReadContent( + content_ids, shared_state_ids, + base::BindLambdaForTesting( + [&](std::vector<feedstore::Content> content, + std::vector<feedstore::StreamSharedState> shared_states) { + did_failed_read = true; + EXPECT_EQ(content.size(), 0ul); + EXPECT_EQ(shared_states.size(), 0ul); + })); + fake_db_->LoadCallback(false); + EXPECT_TRUE(did_failed_read); +} + +TEST_F(FeedStoreTest, ReadNextStreamState) { + feedstore::Record record; + feedstore::StreamAndContentState* next_stream_state = + record.mutable_next_stream_state(); + *next_stream_state->mutable_stream_data() = MakeStreamData(); + *next_stream_state->add_content() = MakeContent(0); + *next_stream_state->add_shared_state() = MakeSharedState(0); + + MakeFeedStore({{"N", record}}); + + // Successful read + bool did_successful_read = false; + store_->ReadNextStreamState(base::BindLambdaForTesting( + [&](std::unique_ptr<feedstore::StreamAndContentState> result) { + did_successful_read = true; + ASSERT_TRUE(result); + EXPECT_TRUE(result->has_stream_data()); + EXPECT_EQ(result->content_size(), 1); + EXPECT_EQ(result->shared_state_size(), 1); + })); + fake_db_->GetCallback(true); + EXPECT_TRUE(did_successful_read); + + // Failed read + bool did_failed_read = false; + store_->ReadNextStreamState(base::BindLambdaForTesting( + [&](std::unique_ptr<feedstore::StreamAndContentState> result) { + did_failed_read = true; + EXPECT_FALSE(result); + })); + fake_db_->GetCallback(false); + EXPECT_TRUE(did_failed_read); +} + +TEST_F(FeedStoreTest, WriteThenRead) { + MakeFeedStore({}); + + std::vector<feedstore::Record> records(4); + *records[0].mutable_stream_data() = MakeStreamData(); + *records[1].mutable_content() = MakeContent(0); + *records[2].mutable_shared_state() = MakeSharedState(0); + *records[3].mutable_next_stream_state()->mutable_stream_data() = + MakeStreamData(); + + store_->Write(records, base::BindLambdaForTesting([](bool success) {})); + fake_db_->UpdateCallback(true); + + bool did_read_stream_data = false; + store_->ReadStreamData(base::BindLambdaForTesting( + [&](std::unique_ptr<feedstore::StreamData> stream_data) { + did_read_stream_data = true; + ASSERT_TRUE(stream_data); + // Just make sure stream_data isn't a default empty StreamData. + EXPECT_TRUE(stream_data->has_content_id()); + })); + fake_db_->GetCallback(true); + EXPECT_TRUE(did_read_stream_data); + + bool did_read_content = false; + store_->ReadContent( + {records[1].content().content_id()}, + {records[2].shared_state().content_id()}, + base::BindLambdaForTesting( + [&](std::vector<feedstore::Content> content, + std::vector<feedstore::StreamSharedState> shared_states) { + did_read_content = true; + ASSERT_EQ(content.size(), 1ul); + EXPECT_TRUE(content[0].has_content_id()); + + ASSERT_EQ(shared_states.size(), 1ul); + EXPECT_TRUE(shared_states[0].has_content_id()); + })); + fake_db_->LoadCallback(true); + EXPECT_TRUE(did_read_content); + + bool did_read_next_stream_state = false; + store_->ReadNextStreamState(base::BindLambdaForTesting( + [&](std::unique_ptr<feedstore::StreamAndContentState> result) { + did_read_next_stream_state = true; + ASSERT_TRUE(result); + EXPECT_TRUE(result->has_stream_data()); + })); + fake_db_->GetCallback(true); + EXPECT_TRUE(did_read_next_stream_state); +} + +} // namespace feed
diff --git a/components/feed/core/v2/test/stream_builder.cc b/components/feed/core/v2/test/stream_builder.cc index d43c57c..c7721ad 100644 --- a/components/feed/core/v2/test/stream_builder.cc +++ b/components/feed/core/v2/test/stream_builder.cc
@@ -29,6 +29,10 @@ return MakeContentId(ContentId::FEATURE, "stories", id_number); } +ContentId MakeSharedStateContentId(int id_number) { + return MakeContentId(ContentId::TYPE_UNDEFINED, "shared", id_number); +} + ContentId MakeRootId(int id_number) { return MakeContentId(ContentId::TYPE_UNDEFINED, "root", id_number); }
diff --git a/components/feed/core/v2/test/stream_builder.h b/components/feed/core/v2/test/stream_builder.h index e0f73d3d..446baee 100644 --- a/components/feed/core/v2/test/stream_builder.h +++ b/components/feed/core/v2/test/stream_builder.h
@@ -21,6 +21,7 @@ int id_number); ContentId MakeClusterId(int id_number); ContentId MakeContentContentId(int id_number); +ContentId MakeSharedStateContentId(int id_number); ContentId MakeRootId(int id_number = 0); ContentId MakeSharedStateId(int id_number = 0); feedstore::StreamStructure MakeStream(int id_number = 0); @@ -30,6 +31,7 @@ feedstore::StreamStructure MakeRemove(ContentId id); feedstore::StreamStructure MakeClearAll(); feedstore::Content MakeContent(int id_number); +feedstore::StreamSharedState MakeSharedState(int id_number); feedstore::DataOperation MakeOperation(feedstore::StreamStructure structure); feedstore::DataOperation MakeOperation(feedstore::Content content);
diff --git a/components/omnibox/browser/autocomplete_result_unittest.cc b/components/omnibox/browser/autocomplete_result_unittest.cc index 54aa4600..f8b25d2 100644 --- a/components/omnibox/browser/autocomplete_result_unittest.cc +++ b/components/omnibox/browser/autocomplete_result_unittest.cc
@@ -73,13 +73,13 @@ } // A simple AutocompleteProvider that does nothing. -class MockAutocompleteProvider : public AutocompleteProvider { +class FakeAutocompleteProvider : public AutocompleteProvider { public: - explicit MockAutocompleteProvider(Type type): AutocompleteProvider(type) {} + explicit FakeAutocompleteProvider(Type type) : AutocompleteProvider(type) {} void Start(const AutocompleteInput& input, bool minimal_changes) override {} - // For simplicity, |MockAutocompleteProvider|'s retrieved through + // For simplicity, |FakeAutocompleteProvider|'s retrieved through // |GetProvider| have types 0, 1, ... 5. This is fine for most tests, but for // tests where the provider type matters (e.g. tests that involve deduping // document suggestions), provider types need to be consistent with @@ -87,7 +87,7 @@ void SetType(Type type) { type_ = type; } private: - ~MockAutocompleteProvider() override {} + ~FakeAutocompleteProvider() override = default; }; } // namespace @@ -117,8 +117,8 @@ // Create the list of mock providers. 5 is enough. for (size_t i = 0; i < 5; ++i) { - mock_provider_list_.push_back(new MockAutocompleteProvider( - static_cast<AutocompleteProvider::Type>(i))); + mock_provider_list_.push_back(new FakeAutocompleteProvider( + static_cast<AutocompleteProvider::Type>(i))); } } @@ -152,7 +152,7 @@ const TestData* expected, size_t expected_size); - void SortMatchesAndVerfiyOrder( + void SortMatchesAndVerifyOrder( const std::string& input_text, OmniboxEventProto::PageClassification page_classification, const ACMatches& matches, @@ -160,7 +160,7 @@ const AutocompleteMatchTestData data[]); // Returns a (mock) AutocompleteProvider of given |provider_id|. - MockAutocompleteProvider* GetProvider(int provider_id) { + FakeAutocompleteProvider* GetProvider(int provider_id) { EXPECT_LT(provider_id, static_cast<int>(mock_provider_list_.size())); return mock_provider_list_[provider_id].get(); } @@ -172,7 +172,7 @@ base::test::TaskEnvironment task_environment_; // For every provider mentioned in TestData, we need a mock provider. - std::vector<scoped_refptr<MockAutocompleteProvider> > mock_provider_list_; + std::vector<scoped_refptr<FakeAutocompleteProvider>> mock_provider_list_; DISALLOW_COPY_AND_ASSIGN(AutocompleteResultTest); }; @@ -245,7 +245,7 @@ AssertResultMatches(current_result, expected, expected_size); } -void AutocompleteResultTest::SortMatchesAndVerfiyOrder( +void AutocompleteResultTest::SortMatchesAndVerifyOrder( const std::string& input_text, OmniboxEventProto::PageClassification page_classification, const ACMatches& matches, @@ -1083,7 +1083,7 @@ // is the default match despite demotion. // Make sure history-URL is the last match due to the logic which groups // searches and URLs together. - SortMatchesAndVerfiyOrder("a", OmniboxEventProto::HOME_PAGE, matches, + SortMatchesAndVerifyOrder("a", OmniboxEventProto::HOME_PAGE, matches, {1, 2, 3, 0}, data); // However, in the fakebox/realbox, we do want to use the demoted score when @@ -1092,10 +1092,10 @@ // page classification of fakebox/realbox, and make sure history-title is now // demoted. We also make sure history-URL is the last match due to the logic // which groups searches and URLs together. - SortMatchesAndVerfiyOrder( + SortMatchesAndVerifyOrder( "a", OmniboxEventProto::INSTANT_NTP_WITH_FAKEBOX_AS_STARTING_FOCUS, matches, {3, 2, 0, 1}, data); - SortMatchesAndVerfiyOrder("a", OmniboxEventProto::NTP_REALBOX, matches, + SortMatchesAndVerifyOrder("a", OmniboxEventProto::NTP_REALBOX, matches, {3, 2, 0, 1}, data); // Unless, the user's input looks like a URL, in which case we want to use @@ -1103,11 +1103,11 @@ // clearly trying to navigate. So here we re-sort with a page classification // of fakebox/realbox and an input that's a URL, and make sure history-title // is once again the default match. - SortMatchesAndVerfiyOrder( + SortMatchesAndVerifyOrder( "www.example.com", OmniboxEventProto::INSTANT_NTP_WITH_FAKEBOX_AS_STARTING_FOCUS, matches, {1, 2, 3, 0}, data); - SortMatchesAndVerfiyOrder("www.example.com", OmniboxEventProto::NTP_REALBOX, + SortMatchesAndVerifyOrder("www.example.com", OmniboxEventProto::NTP_REALBOX, matches, {1, 2, 3, 0}, data); } @@ -1221,7 +1221,7 @@ struct EntityTestData { AutocompleteMatchType::Type type; - MockAutocompleteProvider* provider; + FakeAutocompleteProvider* provider; std::string destination_url; int relevance; bool allowed_to_be_default_match; @@ -1701,15 +1701,15 @@ ACMatches matches; PopulateAutocompleteMatches(data, base::size(data), &matches); matches[0].type = AutocompleteMatchType::DOCUMENT_SUGGESTION; - static_cast<MockAutocompleteProvider*>(matches[0].provider) + static_cast<FakeAutocompleteProvider*>(matches[0].provider) ->SetType(AutocompleteProvider::Type::TYPE_DOCUMENT); matches[1].type = AutocompleteMatchType::HISTORY_URL; matches[2].type = AutocompleteMatchType::DOCUMENT_SUGGESTION; - static_cast<MockAutocompleteProvider*>(matches[2].provider) + static_cast<FakeAutocompleteProvider*>(matches[2].provider) ->SetType(AutocompleteProvider::Type::TYPE_DOCUMENT); matches[3].type = AutocompleteMatchType::HISTORY_URL; matches[4].type = AutocompleteMatchType::DOCUMENT_SUGGESTION; - static_cast<MockAutocompleteProvider*>(matches[4].provider) + static_cast<FakeAutocompleteProvider*>(matches[4].provider) ->SetType(AutocompleteProvider::Type::TYPE_DOCUMENT); matches[5].type = AutocompleteMatchType::HISTORY_URL;
diff --git a/components/omnibox/browser/titled_url_match_utils_unittest.cc b/components/omnibox/browser/titled_url_match_utils_unittest.cc index 81feb9d1..6bfbd52 100644 --- a/components/omnibox/browser/titled_url_match_utils_unittest.cc +++ b/components/omnibox/browser/titled_url_match_utils_unittest.cc
@@ -25,14 +25,14 @@ namespace { // A simple AutocompleteProvider that does nothing. -class MockAutocompleteProvider : public AutocompleteProvider { +class FakeAutocompleteProvider : public AutocompleteProvider { public: - explicit MockAutocompleteProvider(Type type) : AutocompleteProvider(type) {} + explicit FakeAutocompleteProvider(Type type) : AutocompleteProvider(type) {} void Start(const AutocompleteInput& input, bool minimal_changes) override {} private: - ~MockAutocompleteProvider() override {} + ~FakeAutocompleteProvider() override = default; }; class MockTitledUrlNode : public bookmarks::TitledUrlNode { @@ -78,8 +78,8 @@ titled_url_match.title_match_positions = {{0, 3}}; titled_url_match.url_match_positions = {{12, 15}}; - scoped_refptr<MockAutocompleteProvider> provider = - new MockAutocompleteProvider(AutocompleteProvider::Type::TYPE_BOOKMARK); + scoped_refptr<FakeAutocompleteProvider> provider = + new FakeAutocompleteProvider(AutocompleteProvider::Type::TYPE_BOOKMARK); TestSchemeClassifier classifier; AutocompleteInput input(input_text, metrics::OmniboxEventProto::NTP, classifier); @@ -136,8 +136,8 @@ // Don't capture the scheme, so that it doesn't match. titled_url_match.url_match_positions = match_positions; - scoped_refptr<MockAutocompleteProvider> provider = - new MockAutocompleteProvider(AutocompleteProvider::Type::TYPE_BOOKMARK); + scoped_refptr<FakeAutocompleteProvider> provider = + new FakeAutocompleteProvider(AutocompleteProvider::Type::TYPE_BOOKMARK); TestSchemeClassifier classifier; AutocompleteInput input(input_text, metrics::OmniboxEventProto::NTP, classifier); @@ -251,8 +251,8 @@ titled_url_match.title_match_positions = {{9, 12}}; titled_url_match.url_match_positions = {}; - scoped_refptr<MockAutocompleteProvider> provider = - new MockAutocompleteProvider(AutocompleteProvider::Type::TYPE_BOOKMARK); + scoped_refptr<FakeAutocompleteProvider> provider = + new FakeAutocompleteProvider(AutocompleteProvider::Type::TYPE_BOOKMARK); TestSchemeClassifier classifier; AutocompleteInput input(input_text, metrics::OmniboxEventProto::NTP, classifier);
diff --git a/components/page_load_metrics/browser/metrics_web_contents_observer.cc b/components/page_load_metrics/browser/metrics_web_contents_observer.cc index 0fccdcc3..304f273 100644 --- a/components/page_load_metrics/browser/metrics_web_contents_observer.cc +++ b/components/page_load_metrics/browser/metrics_web_contents_observer.cc
@@ -690,7 +690,8 @@ const std::vector<mojom::ResourceDataUpdatePtr>& resources, mojom::FrameRenderDataUpdatePtr render_data, mojom::CpuTimingPtr cpu_timing, - mojom::DeferredResourceCountsPtr new_deferred_resource_data) { + mojom::DeferredResourceCountsPtr new_deferred_resource_data, + mojom::InputTimingPtr input_timing_delta) { // We may receive notifications from frames that have been navigated away // from. We simply ignore them. // TODO(crbug.com/1061060): We should not ignore page timings if the page is @@ -737,7 +738,8 @@ committed_load_->metrics_update_dispatcher()->UpdateMetrics( render_frame_host, std::move(timing), std::move(metadata), std::move(new_features), resources, std::move(render_data), - std::move(cpu_timing), std::move(new_deferred_resource_data)); + std::move(cpu_timing), std::move(new_deferred_resource_data), + std::move(input_timing_delta)); } } @@ -748,12 +750,14 @@ std::vector<mojom::ResourceDataUpdatePtr> resources, mojom::FrameRenderDataUpdatePtr render_data, mojom::CpuTimingPtr cpu_timing, - mojom::DeferredResourceCountsPtr new_deferred_resource_data) { + mojom::DeferredResourceCountsPtr new_deferred_resource_data, + mojom::InputTimingPtr input_timing_delta) { content::RenderFrameHost* render_frame_host = page_load_metrics_receiver_.GetCurrentTargetFrame(); OnTimingUpdated(render_frame_host, std::move(timing), std::move(metadata), std::move(new_features), resources, std::move(render_data), - std::move(cpu_timing), std::move(new_deferred_resource_data)); + std::move(cpu_timing), std::move(new_deferred_resource_data), + std::move(input_timing_delta)); } bool MetricsWebContentsObserver::ShouldTrackMainFrameNavigation(
diff --git a/components/page_load_metrics/browser/metrics_web_contents_observer.h b/components/page_load_metrics/browser/metrics_web_contents_observer.h index fe68929..99bf77b 100644 --- a/components/page_load_metrics/browser/metrics_web_contents_observer.h +++ b/components/page_load_metrics/browser/metrics_web_contents_observer.h
@@ -163,7 +163,8 @@ const std::vector<mojom::ResourceDataUpdatePtr>& resources, mojom::FrameRenderDataUpdatePtr render_data, mojom::CpuTimingPtr cpu_timing, - mojom::DeferredResourceCountsPtr new_deferred_resource_data); + mojom::DeferredResourceCountsPtr new_deferred_resource_data, + mojom::InputTimingPtr input_timing_delta); // Informs the observers of the currently committed load that the event // corresponding to |event_key| has occurred. This should not be called within @@ -178,14 +179,14 @@ content::NavigationHandle* navigation_handle); // page_load_metrics::mojom::PageLoadMetrics implementation. - void UpdateTiming( - mojom::PageLoadTimingPtr timing, - mojom::FrameMetadataPtr metadata, - mojom::PageLoadFeaturesPtr new_features, - std::vector<mojom::ResourceDataUpdatePtr> resources, - mojom::FrameRenderDataUpdatePtr render_data, - mojom::CpuTimingPtr cpu_timing, - mojom::DeferredResourceCountsPtr new_deferred_resource_data) override; + void UpdateTiming(mojom::PageLoadTimingPtr timing, + mojom::FrameMetadataPtr metadata, + mojom::PageLoadFeaturesPtr new_features, + std::vector<mojom::ResourceDataUpdatePtr> resources, + mojom::FrameRenderDataUpdatePtr render_data, + mojom::CpuTimingPtr cpu_timing, + mojom::DeferredResourceCountsPtr new_deferred_resource_data, + mojom::InputTimingPtr input_timing) override; void HandleFailedNavigationForTrackedLoad( content::NavigationHandle* navigation_handle,
diff --git a/components/page_load_metrics/browser/metrics_web_contents_observer_unittest.cc b/components/page_load_metrics/browser/metrics_web_contents_observer_unittest.cc index 2cc2d86..de6d186 100644 --- a/components/page_load_metrics/browser/metrics_web_contents_observer_unittest.cc +++ b/components/page_load_metrics/browser/metrics_web_contents_observer_unittest.cc
@@ -112,7 +112,8 @@ mojom::PageLoadFeaturesPtr(base::in_place), std::vector<mojom::ResourceDataUpdatePtr>(), mojom::FrameRenderDataUpdatePtr(base::in_place), timing.Clone(), - mojom::DeferredResourceCountsPtr(base::in_place)); + mojom::DeferredResourceCountsPtr(base::in_place), + mojom::InputTimingPtr(base::in_place)); } void SimulateTimingUpdate(const mojom::PageLoadTiming& timing, @@ -137,7 +138,8 @@ std::vector<mojom::ResourceDataUpdatePtr>(), mojom::FrameRenderDataUpdatePtr(base::in_place), mojom::CpuTimingPtr(base::in_place), - mojom::DeferredResourceCountsPtr(base::in_place)); + mojom::DeferredResourceCountsPtr(base::in_place), + mojom::InputTimingPtr(base::in_place)); } void AttachObserver() {
diff --git a/components/page_load_metrics/browser/observers/page_load_metrics_observer_tester.cc b/components/page_load_metrics/browser/observers/page_load_metrics_observer_tester.cc index b927215b..9de891f7 100644 --- a/components/page_load_metrics/browser/observers/page_load_metrics_observer_tester.cc +++ b/components/page_load_metrics/browser/observers/page_load_metrics_observer_tester.cc
@@ -111,7 +111,7 @@ SimulatePageLoadTimingUpdate( timing, mojom::FrameMetadata(), mojom::PageLoadFeatures(), mojom::FrameRenderDataUpdate(), mojom::CpuTiming(), - mojom::DeferredResourceCounts(), rfh); + mojom::DeferredResourceCounts(), mojom::InputTiming(), rfh); } void PageLoadMetricsObserverTester::SimulateCpuTimingUpdate( @@ -124,10 +124,26 @@ content::RenderFrameHost* rfh) { auto timing = page_load_metrics::mojom::PageLoadTimingPtr(base::in_place); page_load_metrics::InitPageLoadTimingForTest(timing.get()); - SimulatePageLoadTimingUpdate(*timing, mojom::FrameMetadata(), - mojom::PageLoadFeatures(), - mojom::FrameRenderDataUpdate(), cpu_timing, - mojom::DeferredResourceCounts(), rfh); + SimulatePageLoadTimingUpdate( + *timing, mojom::FrameMetadata(), mojom::PageLoadFeatures(), + mojom::FrameRenderDataUpdate(), cpu_timing, + mojom::DeferredResourceCounts(), mojom::InputTiming(), rfh); +} + +void PageLoadMetricsObserverTester::SimulateInputTimingUpdate( + const mojom::InputTiming& input_timing) { + SimulateInputTimingUpdate(input_timing, web_contents()->GetMainFrame()); +} + +void PageLoadMetricsObserverTester::SimulateInputTimingUpdate( + const mojom::InputTiming& input_timing, + content::RenderFrameHost* rfh) { + auto timing = page_load_metrics::mojom::PageLoadTimingPtr(base::in_place); + page_load_metrics::InitPageLoadTimingForTest(timing.get()); + SimulatePageLoadTimingUpdate( + *timing, mojom::FrameMetadata(), mojom::PageLoadFeatures(), + mojom::FrameRenderDataUpdate(), mojom::CpuTiming(), + mojom::DeferredResourceCounts(), input_timing, rfh); } void PageLoadMetricsObserverTester::SimulateTimingAndMetadataUpdate( @@ -136,7 +152,8 @@ SimulatePageLoadTimingUpdate( timing, metadata, mojom::PageLoadFeatures(), mojom::FrameRenderDataUpdate(), mojom::CpuTiming(), - mojom::DeferredResourceCounts(), web_contents()->GetMainFrame()); + mojom::DeferredResourceCounts(), mojom::InputTiming(), + web_contents()->GetMainFrame()); } void PageLoadMetricsObserverTester::SimulateMetadataUpdate( @@ -144,10 +161,10 @@ content::RenderFrameHost* rfh) { mojom::PageLoadTiming timing; InitPageLoadTimingForTest(&timing); - SimulatePageLoadTimingUpdate(timing, metadata, mojom::PageLoadFeatures(), - mojom::FrameRenderDataUpdate(), - mojom::CpuTiming(), - mojom::DeferredResourceCounts(), rfh); + SimulatePageLoadTimingUpdate( + timing, metadata, mojom::PageLoadFeatures(), + mojom::FrameRenderDataUpdate(), mojom::CpuTiming(), + mojom::DeferredResourceCounts(), mojom::InputTiming(), rfh); } void PageLoadMetricsObserverTester::SimulateFeaturesUpdate( @@ -155,7 +172,8 @@ SimulatePageLoadTimingUpdate( mojom::PageLoadTiming(), mojom::FrameMetadata(), new_features, mojom::FrameRenderDataUpdate(), mojom::CpuTiming(), - mojom::DeferredResourceCounts(), web_contents()->GetMainFrame()); + mojom::DeferredResourceCounts(), mojom::InputTiming(), + web_contents()->GetMainFrame()); } void PageLoadMetricsObserverTester::SimulateRenderDataUpdate( @@ -170,7 +188,8 @@ InitPageLoadTimingForTest(&timing); SimulatePageLoadTimingUpdate( timing, mojom::FrameMetadata(), mojom::PageLoadFeatures(), render_data, - mojom::CpuTiming(), mojom::DeferredResourceCounts(), rfh); + mojom::CpuTiming(), mojom::DeferredResourceCounts(), mojom::InputTiming(), + rfh); } void PageLoadMetricsObserverTester::SimulatePageLoadTimingUpdate( @@ -180,11 +199,13 @@ const mojom::FrameRenderDataUpdate& render_data, const mojom::CpuTiming& cpu_timing, const mojom::DeferredResourceCounts& new_deferred_resource_data, + const mojom::InputTiming& input_timing, content::RenderFrameHost* rfh) { metrics_web_contents_observer_->OnTimingUpdated( rfh, timing.Clone(), metadata.Clone(), new_features.Clone(), std::vector<mojom::ResourceDataUpdatePtr>(), render_data.Clone(), - cpu_timing.Clone(), new_deferred_resource_data.Clone()); + cpu_timing.Clone(), new_deferred_resource_data.Clone(), + input_timing.Clone()); // If sending the timing update caused the PageLoadMetricsUpdateDispatcher to // schedule a buffering timer, then fire it now so metrics are dispatched to // observers. @@ -209,7 +230,8 @@ mojom::PageLoadFeaturesPtr(base::in_place), resources, mojom::FrameRenderDataUpdatePtr(base::in_place), mojom::CpuTimingPtr(base::in_place), - mojom::DeferredResourceCountsPtr(base::in_place)); + mojom::DeferredResourceCountsPtr(base::in_place), + mojom::InputTimingPtr(base::in_place)); } void PageLoadMetricsObserverTester::SimulateLoadedResource(
diff --git a/components/page_load_metrics/browser/observers/page_load_metrics_observer_tester.h b/components/page_load_metrics/browser/observers/page_load_metrics_observer_tester.h index 50f90161..84e19a8 100644 --- a/components/page_load_metrics/browser/observers/page_load_metrics_observer_tester.h +++ b/components/page_load_metrics/browser/observers/page_load_metrics_observer_tester.h
@@ -91,6 +91,9 @@ void SimulateCpuTimingUpdate(const mojom::CpuTiming& cpu_timing); void SimulateCpuTimingUpdate(const mojom::CpuTiming& cpu_timing, content::RenderFrameHost* rfh); + void SimulateInputTimingUpdate(const mojom::InputTiming& input_timing); + void SimulateInputTimingUpdate(const mojom::InputTiming& input_timing, + content::RenderFrameHost* rfh); void SimulateTimingAndMetadataUpdate(const mojom::PageLoadTiming& timing, const mojom::FrameMetadata& metadata); void SimulateMetadataUpdate(const mojom::FrameMetadata& metadata, @@ -166,6 +169,7 @@ const mojom::FrameRenderDataUpdate& render_data, const mojom::CpuTiming& cpu_timing, const mojom::DeferredResourceCounts& new_deferred_resource_data, + const mojom::InputTiming& input_timing, content::RenderFrameHost* rfh); content::WebContents* web_contents() const { return web_contents_; }
diff --git a/components/page_load_metrics/browser/page_load_metrics_observer_delegate.h b/components/page_load_metrics/browser/page_load_metrics_observer_delegate.h index 9f2091f9..00199f5f 100644 --- a/components/page_load_metrics/browser/page_load_metrics_observer_delegate.h +++ b/components/page_load_metrics/browser/page_load_metrics_observer_delegate.h
@@ -98,6 +98,8 @@ // such as subframe intersections is initialized to defaults. virtual const mojom::FrameMetadata& GetSubframeMetadata() const = 0; virtual const PageRenderData& GetPageRenderData() const = 0; + // InputTiming data accumulated across all frames. + virtual const mojom::InputTiming& GetPageInputTiming() const = 0; virtual const PageRenderData& GetMainFrameRenderData() const = 0; virtual const ui::ScopedVisibilityTracker& GetVisibilityTracker() const = 0; virtual const ResourceTracker& GetResourceTracker() const = 0;
diff --git a/components/page_load_metrics/browser/page_load_metrics_update_dispatcher.cc b/components/page_load_metrics/browser/page_load_metrics_update_dispatcher.cc index d71204c..2c03cc5 100644 --- a/components/page_load_metrics/browser/page_load_metrics_update_dispatcher.cc +++ b/components/page_load_metrics/browser/page_load_metrics_update_dispatcher.cc
@@ -347,22 +347,6 @@ mojom::InteractiveTiming* target_interactive_timing = target_->interactive_timing.get(); - target_interactive_timing->num_input_events += - new_interactive_timing.num_input_events; - - if (new_interactive_timing.total_input_delay.has_value()) { - target_interactive_timing->total_input_delay = - target_interactive_timing->total_input_delay.value_or( - base::TimeDelta()) + - new_interactive_timing.total_input_delay.value(); - } - - if (new_interactive_timing.total_adjusted_input_delay.has_value()) { - target_interactive_timing->total_adjusted_input_delay = - target_interactive_timing->total_adjusted_input_delay.value_or( - base::TimeDelta()) + - new_interactive_timing.total_adjusted_input_delay.value(); - } if (MaybeUpdateTimeDelta(&target_interactive_timing->first_input_timestamp, navigation_start_offset, new_interactive_timing.first_input_timestamp)) { @@ -409,7 +393,8 @@ current_merged_page_timing_(CreatePageLoadTiming()), pending_merged_page_timing_(CreatePageLoadTiming()), main_frame_metadata_(mojom::FrameMetadata::New()), - subframe_metadata_(mojom::FrameMetadata::New()) {} + subframe_metadata_(mojom::FrameMetadata::New()), + page_input_timing_(mojom::InputTiming()) {} PageLoadMetricsUpdateDispatcher::~PageLoadMetricsUpdateDispatcher() { ShutDown(); @@ -436,7 +421,8 @@ const std::vector<mojom::ResourceDataUpdatePtr>& resources, mojom::FrameRenderDataUpdatePtr render_data, mojom::CpuTimingPtr new_cpu_timing, - mojom::DeferredResourceCountsPtr new_deferred_resource_data) { + mojom::DeferredResourceCountsPtr new_deferred_resource_data, + mojom::InputTimingPtr input_timing_delta) { if (embedder_interface_->IsExtensionUrl( render_frame_host->GetLastCommittedURL())) { // Extensions can inject child frames into a page. We don't want to track @@ -462,7 +448,7 @@ UpdateSubFrameMetadata(render_frame_host, std::move(new_metadata)); UpdateSubFrameTiming(render_frame_host, std::move(new_timing)); } - + UpdatePageInputTiming(*input_timing_delta); UpdatePageRenderData(*render_data); if (!is_main_frame) { // This path is just for the AMP metrics. @@ -640,6 +626,14 @@ client_->OnMainFrameMetadataChanged(); } +void PageLoadMetricsUpdateDispatcher::UpdatePageInputTiming( + const mojom::InputTiming& input_timing_delta) { + page_input_timing_.num_input_events += input_timing_delta.num_input_events; + page_input_timing_.total_input_delay += input_timing_delta.total_input_delay; + page_input_timing_.total_adjusted_input_delay += + input_timing_delta.total_adjusted_input_delay; +} + void PageLoadMetricsUpdateDispatcher::UpdatePageRenderData( const mojom::FrameRenderDataUpdate& render_data) { page_render_data_.layout_shift_score += render_data.layout_shift_delta;
diff --git a/components/page_load_metrics/browser/page_load_metrics_update_dispatcher.h b/components/page_load_metrics/browser/page_load_metrics_update_dispatcher.h index 5739c01..95649de8 100644 --- a/components/page_load_metrics/browser/page_load_metrics_update_dispatcher.h +++ b/components/page_load_metrics/browser/page_load_metrics_update_dispatcher.h
@@ -144,7 +144,8 @@ const std::vector<mojom::ResourceDataUpdatePtr>& resources, mojom::FrameRenderDataUpdatePtr render_data, mojom::CpuTimingPtr new_cpu_timing, - mojom::DeferredResourceCountsPtr new_deferred_resource_data); + mojom::DeferredResourceCountsPtr new_deferred_resource_data, + mojom::InputTimingPtr input_timing_delta); // This method is only intended to be called for PageLoadFeatures being // recorded directly from the browser process. Features coming from the @@ -171,6 +172,9 @@ const PageRenderData& main_frame_render_data() const { return main_frame_render_data_; } + const mojom::InputTiming& page_input_timing() const { + return page_input_timing_; + } private: using FrameTreeNodeId = int; @@ -185,6 +189,7 @@ void UpdateSubFrameMetadata(content::RenderFrameHost* render_frame_host, mojom::FrameMetadataPtr subframe_metadata); + void UpdatePageInputTiming(const mojom::InputTiming& input_timing_delta); void UpdatePageRenderData(const mojom::FrameRenderDataUpdate& render_data); void UpdateMainFrameRenderData( const mojom::FrameRenderDataUpdate& render_data); @@ -222,6 +227,9 @@ mojom::FrameMetadataPtr main_frame_metadata_; mojom::FrameMetadataPtr subframe_metadata_; + // InputTiming data accumulated across all frames. + mojom::InputTiming page_input_timing_; + PageRenderData page_render_data_; PageRenderData main_frame_render_data_;
diff --git a/components/page_load_metrics/browser/page_load_tracker.cc b/components/page_load_metrics/browser/page_load_tracker.cc index f136027..e8d6cc91 100644 --- a/components/page_load_metrics/browser/page_load_tracker.cc +++ b/components/page_load_metrics/browser/page_load_tracker.cc
@@ -790,6 +790,10 @@ return metrics_update_dispatcher_.page_render_data(); } +const mojom::InputTiming& PageLoadTracker::GetPageInputTiming() const { + return metrics_update_dispatcher_.page_input_timing(); +} + const PageRenderData& PageLoadTracker::GetMainFrameRenderData() const { return metrics_update_dispatcher_.main_frame_render_data(); }
diff --git a/components/page_load_metrics/browser/page_load_tracker.h b/components/page_load_metrics/browser/page_load_tracker.h index 4913899..5f253963 100644 --- a/components/page_load_metrics/browser/page_load_tracker.h +++ b/components/page_load_metrics/browser/page_load_tracker.h
@@ -222,6 +222,7 @@ const mojom::FrameMetadata& GetMainFrameMetadata() const override; const mojom::FrameMetadata& GetSubframeMetadata() const override; const PageRenderData& GetPageRenderData() const override; + const mojom::InputTiming& GetPageInputTiming() const override; const PageRenderData& GetMainFrameRenderData() const override; const ui::ScopedVisibilityTracker& GetVisibilityTracker() const override; const ResourceTracker& GetResourceTracker() const override;
diff --git a/components/page_load_metrics/common/page_load_metrics.mojom b/components/page_load_metrics/common/page_load_metrics.mojom index a4718e6..0ba2b52 100644 --- a/components/page_load_metrics/common/page_load_metrics.mojom +++ b/components/page_load_metrics/common/page_load_metrics.mojom
@@ -105,21 +105,8 @@ // The timestamp of the event whose delay is reported as longest_input_delay. mojo_base.mojom.TimeDelta? longest_input_timestamp; - - // The sum of all input delay. - mojo_base.mojom.TimeDelta? total_input_delay; - - // The sum of all adjusted input delay. We adjust each input delay by - // subtracting a small number, e.g. 50ms. And if the subtraction result is - // negative, we will use 0ms instead. - mojo_base.mojom.TimeDelta? total_adjusted_input_delay; - - // The number of user interactions, including click, tap, key press, - // cancellable touchstart, or pointer down followed by a pointer up. - uint64 num_input_events = 0; }; - // PageLoadTiming contains timing metrics associated with a page load. Many of // the metrics here are based on the Navigation Timing spec: // http://www.w3.org/TR/navigation-timing/. @@ -274,6 +261,21 @@ uint64 images_loaded_after_deferral = 0; }; +// Metrics about general input delay. +struct InputTiming { + // The sum of all input delay. + mojo_base.mojom.TimeDelta total_input_delay; + + // The sum of all adjusted input delay. We adjust each input delay by + // subtracting a small number, currently 50ms but subject to change in the + // future. And if the subtraction result is negative, we will use 0ms. + mojo_base.mojom.TimeDelta total_adjusted_input_delay; + + // The number of user interactions, including click, tap, key press, + // cancellable touchstart, or pointer down followed by a pointer up. + uint64 num_input_events = 0; +}; + // Sent from renderer to browser process when the PageLoadTiming for the // associated frame changed. interface PageLoadMetrics { @@ -287,5 +289,6 @@ array<ResourceDataUpdate> resources, FrameRenderDataUpdate render_data, CpuTiming cpu_load_timing, - DeferredResourceCounts new_deferred_resource_data); + DeferredResourceCounts new_deferred_resource_data, + InputTiming input_timing_delta); };
diff --git a/components/page_load_metrics/common/page_load_timing.cc b/components/page_load_metrics/common/page_load_timing.cc index bae1d3d..6ec07e6 100644 --- a/components/page_load_metrics/common/page_load_timing.cc +++ b/components/page_load_metrics/common/page_load_timing.cc
@@ -20,10 +20,15 @@ bool IsEmpty(const page_load_metrics::mojom::InteractiveTiming& timing) { return !timing.first_input_delay && !timing.first_input_timestamp && - !timing.longest_input_delay && !timing.longest_input_timestamp && - !timing.total_input_delay && !timing.total_adjusted_input_delay && + !timing.longest_input_delay && !timing.longest_input_timestamp; +} + +bool IsEmpty(const page_load_metrics::mojom::InputTiming& timing) { + return !timing.total_input_delay.InMilliseconds() && + !timing.total_adjusted_input_delay.InMilliseconds() && !timing.num_input_events; } + bool IsEmpty(const page_load_metrics::mojom::PaintTiming& timing) { return !timing.first_paint && !timing.first_image_paint && !timing.first_contentful_paint && !timing.first_meaningful_paint &&
diff --git a/components/page_load_metrics/common/page_load_timing.h b/components/page_load_metrics/common/page_load_timing.h index 6dbfb67..2520e20c 100644 --- a/components/page_load_metrics/common/page_load_timing.h +++ b/components/page_load_metrics/common/page_load_timing.h
@@ -19,6 +19,7 @@ bool IsEmpty(const mojom::PaintTiming& timing); bool IsEmpty(const mojom::ParseTiming& timing); bool IsEmpty(const mojom::PageLoadTiming& timing); +bool IsEmpty(const mojom::InteractiveTiming& timing); void InitPageLoadTimingForTest(mojom::PageLoadTiming* timing);
diff --git a/components/page_load_metrics/renderer/fake_page_timing_sender.cc b/components/page_load_metrics/renderer/fake_page_timing_sender.cc index a19c5b1..681e840 100644 --- a/components/page_load_metrics/renderer/fake_page_timing_sender.cc +++ b/components/page_load_metrics/renderer/fake_page_timing_sender.cc
@@ -22,12 +22,16 @@ std::vector<mojom::ResourceDataUpdatePtr> resources, const mojom::FrameRenderDataUpdate& render_data, const mojom::CpuTimingPtr& cpu_timing, - mojom::DeferredResourceCountsPtr new_deferred_resource_data) { + mojom::DeferredResourceCountsPtr new_deferred_resource_data, + const mojom::InputTimingPtr new_input_timing) { validator_->UpdateTiming(timing, metadata, new_features, resources, - render_data, cpu_timing, new_deferred_resource_data); + render_data, cpu_timing, new_deferred_resource_data, + new_input_timing); } -FakePageTimingSender::PageTimingValidator::PageTimingValidator() = default; +FakePageTimingSender::PageTimingValidator::PageTimingValidator() + : expected_input_timing(mojom::InputTiming::New()), + actual_input_timing(mojom::InputTiming::New()) {} FakePageTimingSender::PageTimingValidator::~PageTimingValidator() { VerifyExpectedTimings(); @@ -57,6 +61,25 @@ } } +void FakePageTimingSender::PageTimingValidator::UpdateExpectedInputTiming( + const base::TimeDelta input_delay) { + expected_input_timing->num_input_events++; + expected_input_timing->total_input_delay += input_delay; + expected_input_timing->total_adjusted_input_delay += + base::TimeDelta::FromMilliseconds( + std::max(int64_t(0), input_delay.InMilliseconds() - int64_t(50))); +} +void FakePageTimingSender::PageTimingValidator::VerifyExpectedInputTiming() + const { + ASSERT_EQ(expected_input_timing.is_null(), actual_input_timing.is_null()); + ASSERT_EQ(expected_input_timing->num_input_events, + actual_input_timing->num_input_events); + ASSERT_EQ(expected_input_timing->total_input_delay, + actual_input_timing->total_input_delay); + ASSERT_EQ(expected_input_timing->total_adjusted_input_delay, + actual_input_timing->total_adjusted_input_delay); +} + void FakePageTimingSender::PageTimingValidator::VerifyExpectedCpuTimings() const { ASSERT_EQ(actual_cpu_timings_.size(), expected_cpu_timings_.size()); @@ -136,7 +159,8 @@ const std::vector<mojom::ResourceDataUpdatePtr>& resources, const mojom::FrameRenderDataUpdate& render_data, const mojom::CpuTimingPtr& cpu_timing, - const mojom::DeferredResourceCountsPtr& new_deferred_resource_data) { + const mojom::DeferredResourceCountsPtr& new_deferred_resource_data, + const mojom::InputTimingPtr& new_input_timing) { actual_timings_.push_back(timing.Clone()); if (!cpu_timing->task_time.is_zero()) { actual_cpu_timings_.push_back(cpu_timing.Clone()); @@ -155,6 +179,12 @@ } actual_render_data_.layout_shift_delta = render_data.layout_shift_delta; actual_frame_intersection_update_ = metadata->intersection_update.Clone(); + + actual_input_timing->num_input_events += new_input_timing->num_input_events; + actual_input_timing->total_input_delay += new_input_timing->total_input_delay; + actual_input_timing->total_adjusted_input_delay += + new_input_timing->total_adjusted_input_delay; + VerifyExpectedTimings(); VerifyExpectedCpuTimings(); VerifyExpectedFeatures();
diff --git a/components/page_load_metrics/renderer/fake_page_timing_sender.h b/components/page_load_metrics/renderer/fake_page_timing_sender.h index 9c432596..f099df6f 100644 --- a/components/page_load_metrics/renderer/fake_page_timing_sender.h +++ b/components/page_load_metrics/renderer/fake_page_timing_sender.h
@@ -55,6 +55,8 @@ // expected timings provided via ExpectCpuTiming. void VerifyExpectedCpuTimings() const; + void VerifyExpectedInputTiming() const; + // PageLoad features that are expected to be sent through SendTiming() // should be passed via UpdateExpectedPageLoadFeatures. void UpdateExpectPageLoadFeatures(const blink::mojom::WebFeature feature); @@ -68,6 +70,8 @@ expected_render_data_ = render_data; } + void UpdateExpectedInputTiming(const base::TimeDelta input_delay); + void UpdateExpectFrameIntersectionUpdate( const mojom::FrameIntersectionUpdate& frame_intersection_update) { expected_frame_intersection_update_ = frame_intersection_update.Clone(); @@ -96,7 +100,8 @@ const std::vector<mojom::ResourceDataUpdatePtr>& resources, const mojom::FrameRenderDataUpdate& render_data, const mojom::CpuTimingPtr& cpu_timing, - const mojom::DeferredResourceCountsPtr& new_deferred_resource_data); + const mojom::DeferredResourceCountsPtr& new_deferred_resource_data, + const mojom::InputTimingPtr& input_timing); private: std::vector<mojom::PageLoadTimingPtr> expected_timings_; @@ -111,19 +116,21 @@ mojom::FrameRenderDataUpdate actual_render_data_; mojom::FrameIntersectionUpdatePtr expected_frame_intersection_update_; mojom::FrameIntersectionUpdatePtr actual_frame_intersection_update_; + mojom::InputTimingPtr expected_input_timing; + mojom::InputTimingPtr actual_input_timing; DISALLOW_COPY_AND_ASSIGN(PageTimingValidator); }; explicit FakePageTimingSender(PageTimingValidator* validator); ~FakePageTimingSender() override; - void SendTiming( - const mojom::PageLoadTimingPtr& timing, - const mojom::FrameMetadataPtr& metadata, - mojom::PageLoadFeaturesPtr new_features, - std::vector<mojom::ResourceDataUpdatePtr> resources, - const mojom::FrameRenderDataUpdate& render_data, - const mojom::CpuTimingPtr& cpu_timing, - mojom::DeferredResourceCountsPtr new_deferred_resource_data) override; + void SendTiming(const mojom::PageLoadTimingPtr& timing, + const mojom::FrameMetadataPtr& metadata, + mojom::PageLoadFeaturesPtr new_features, + std::vector<mojom::ResourceDataUpdatePtr> resources, + const mojom::FrameRenderDataUpdate& render_data, + const mojom::CpuTimingPtr& cpu_timing, + mojom::DeferredResourceCountsPtr new_deferred_resource_data, + mojom::InputTimingPtr new_input_timing) override; private: PageTimingValidator* const validator_;
diff --git a/components/page_load_metrics/renderer/metrics_render_frame_observer.cc b/components/page_load_metrics/renderer/metrics_render_frame_observer.cc index 1377d2a87..b37fcf3b 100644 --- a/components/page_load_metrics/renderer/metrics_render_frame_observer.cc +++ b/components/page_load_metrics/renderer/metrics_render_frame_observer.cc
@@ -45,19 +45,19 @@ &page_load_metrics_); } ~MojoPageTimingSender() override = default; - void SendTiming( - const mojom::PageLoadTimingPtr& timing, - const mojom::FrameMetadataPtr& metadata, - mojom::PageLoadFeaturesPtr new_features, - std::vector<mojom::ResourceDataUpdatePtr> resources, - const mojom::FrameRenderDataUpdate& render_data, - const mojom::CpuTimingPtr& cpu_timing, - mojom::DeferredResourceCountsPtr new_deferred_resource_data) override { + void SendTiming(const mojom::PageLoadTimingPtr& timing, + const mojom::FrameMetadataPtr& metadata, + mojom::PageLoadFeaturesPtr new_features, + std::vector<mojom::ResourceDataUpdatePtr> resources, + const mojom::FrameRenderDataUpdate& render_data, + const mojom::CpuTimingPtr& cpu_timing, + mojom::DeferredResourceCountsPtr new_deferred_resource_data, + mojom::InputTimingPtr input_timing_delta) override { DCHECK(page_load_metrics_); page_load_metrics_->UpdateTiming( timing->Clone(), metadata->Clone(), std::move(new_features), std::move(resources), render_data.Clone(), cpu_timing->Clone(), - std::move(new_deferred_resource_data)); + std::move(new_deferred_resource_data), std::move(input_timing_delta)); } private: @@ -82,6 +82,14 @@ SendMetrics(); } +void MetricsRenderFrameObserver::DidObserveInputDelay( + base::TimeDelta input_delay) { + if (!page_timing_metrics_sender_ || HasNoRenderFrame()) { + return; + } + page_timing_metrics_sender_->DidObserveInputDelay(input_delay); +} + void MetricsRenderFrameObserver::DidChangeCpuTiming(base::TimeDelta time) { if (!page_timing_metrics_sender_) return; @@ -395,17 +403,6 @@ timing->interactive_timing->longest_input_timestamp = ClampDelta((*perf.LongestInputTimestamp()).InSecondsF(), start); } - if (perf.TotalInputDelay() > 0.0) { - timing->interactive_timing->total_input_delay = - base::TimeDelta::FromSecondsD(perf.TotalInputDelay()); - } - if (perf.TotalAdjustedInputDelay() > 0.0) { - timing->interactive_timing->total_adjusted_input_delay = - base::TimeDelta::FromSecondsD(perf.TotalAdjustedInputDelay()); - } - if (perf.NumInputEvents() > 0) { - timing->interactive_timing->num_input_events = perf.NumInputEvents(); - } if (perf.ResponseStart() > 0.0) timing->response_start = ClampDelta(perf.ResponseStart(), start); if (perf.DomContentLoadedEventStart() > 0.0) {
diff --git a/components/page_load_metrics/renderer/metrics_render_frame_observer.h b/components/page_load_metrics/renderer/metrics_render_frame_observer.h index 559167c..0d82c407 100644 --- a/components/page_load_metrics/renderer/metrics_render_frame_observer.h +++ b/components/page_load_metrics/renderer/metrics_render_frame_observer.h
@@ -45,6 +45,7 @@ // RenderFrameObserver implementation void DidChangePerformanceTiming() override; + void DidObserveInputDelay(base::TimeDelta input_delay) override; void DidChangeCpuTiming(base::TimeDelta time) override; void DidObserveLoadingBehavior(blink::LoadingBehaviorFlag behavior) override; void DidObserveNewFeatureUsage(blink::mojom::WebFeature feature) override;
diff --git a/components/page_load_metrics/renderer/page_timing_metrics_sender.cc b/components/page_load_metrics/renderer/page_timing_metrics_sender.cc index aefb357..a649d2f8 100644 --- a/components/page_load_metrics/renderer/page_timing_metrics_sender.cc +++ b/components/page_load_metrics/renderer/page_timing_metrics_sender.cc
@@ -23,6 +23,7 @@ namespace { const int kInitialTimerDelayMillis = 50; +const int64_t kInputDelayAdjustmentMillis = int64_t(50); const base::Feature kPageLoadMetricsTimerDelayFeature{ "PageLoadMetricsTimerDelay", base::FEATURE_DISABLED_BY_DEFAULT}; } // namespace @@ -37,6 +38,7 @@ timer_(std::move(timer)), last_timing_(std::move(initial_timing)), last_cpu_timing_(mojom::CpuTiming::New()), + input_timing_delta_(mojom::InputTiming::New()), metadata_(mojom::FrameMetadata::New()), new_features_(mojom::PageLoadFeatures::New()), new_deferred_resource_data_(mojom::DeferredResourceCounts::New()), @@ -290,9 +292,12 @@ page_resource_data_use_.erase(resource->resource_id()); } } + sender_->SendTiming(last_timing_, metadata_, std::move(new_features_), std::move(resources), render_data_, last_cpu_timing_, - std::move(new_deferred_resource_data_)); + std::move(new_deferred_resource_data_), + std::move(input_timing_delta_)); + input_timing_delta_ = mojom::InputTiming::New(); new_deferred_resource_data_ = mojom::DeferredResourceCounts::New(); new_features_ = mojom::PageLoadFeatures::New(); metadata_->intersection_update.reset(); @@ -302,4 +307,15 @@ render_data_.layout_shift_delta_before_input_or_scroll = 0; } +void PageTimingMetricsSender::DidObserveInputDelay( + base::TimeDelta input_delay) { + input_timing_delta_->num_input_events++; + input_timing_delta_->total_input_delay += input_delay; + input_timing_delta_->total_adjusted_input_delay += + base::TimeDelta::FromMilliseconds( + std::max(int64_t(0), + input_delay.InMilliseconds() - kInputDelayAdjustmentMillis)); + EnsureSendTimer(); +} + } // namespace page_load_metrics
diff --git a/components/page_load_metrics/renderer/page_timing_metrics_sender.h b/components/page_load_metrics/renderer/page_timing_metrics_sender.h index b379d322..24df4c0 100644 --- a/components/page_load_metrics/renderer/page_timing_metrics_sender.h +++ b/components/page_load_metrics/renderer/page_timing_metrics_sender.h
@@ -72,6 +72,7 @@ void OnMainFrameDocumentIntersectionChanged( const blink::WebRect& intersect_rect); + void DidObserveInputDelay(base::TimeDelta input_delay); // Updates the timing information. Buffers |timing| to be sent over mojo // sometime 'soon'. void Update( @@ -101,6 +102,7 @@ std::unique_ptr<base::OneShotTimer> timer_; mojom::PageLoadTimingPtr last_timing_; mojom::CpuTimingPtr last_cpu_timing_; + mojom::InputTimingPtr input_timing_delta_; // The the sender keep track of metadata as it comes in, because the sender is // scoped to a single committed load.
diff --git a/components/page_load_metrics/renderer/page_timing_metrics_sender_unittest.cc b/components/page_load_metrics/renderer/page_timing_metrics_sender_unittest.cc index 6ee825a..57b17a8b 100644 --- a/components/page_load_metrics/renderer/page_timing_metrics_sender_unittest.cc +++ b/components/page_load_metrics/renderer/page_timing_metrics_sender_unittest.cc
@@ -140,6 +140,27 @@ metrics_sender_->SendLatest(); } +TEST_F(PageTimingMetricsSenderTest, SendInputEvents) { + mojom::PageLoadTiming timing; + InitPageLoadTimingForTest(&timing); + base::TimeDelta input_delay_1 = base::TimeDelta::FromMilliseconds(40); + base::TimeDelta input_delay_2 = base::TimeDelta::FromMilliseconds(60); + + metrics_sender_->Update(timing.Clone(), + PageTimingMetadataRecorder::MonotonicTiming()); + validator_.ExpectPageLoadTiming(timing); + + metrics_sender_->DidObserveInputDelay(input_delay_1); + validator_.UpdateExpectedInputTiming(input_delay_1); + + metrics_sender_->DidObserveInputDelay(input_delay_2); + validator_.UpdateExpectedInputTiming(input_delay_2); + + // Fire the timer to trigger sending of features via an SendTiming call. + metrics_sender_->mock_timer()->Fire(); + validator_.VerifyExpectedInputTiming(); +} + TEST_F(PageTimingMetricsSenderTest, SendSingleFeature) { mojom::PageLoadTiming timing; InitPageLoadTimingForTest(&timing);
diff --git a/components/page_load_metrics/renderer/page_timing_sender.h b/components/page_load_metrics/renderer/page_timing_sender.h index 38190a2..f839f61 100644 --- a/components/page_load_metrics/renderer/page_timing_sender.h +++ b/components/page_load_metrics/renderer/page_timing_sender.h
@@ -21,7 +21,8 @@ std::vector<mojom::ResourceDataUpdatePtr> resources, const mojom::FrameRenderDataUpdate& render_data, const mojom::CpuTimingPtr& cpu_timing, - mojom::DeferredResourceCountsPtr new_deferred_resource_data) = 0; + mojom::DeferredResourceCountsPtr new_deferred_resource_data, + mojom::InputTimingPtr input_timing_delta) = 0; }; } // namespace page_load_metrics
diff --git a/components/payments/content/payment_request.cc b/components/payments/content/payment_request.cc index 62a88251..a55904d1 100644 --- a/components/payments/content/payment_request.cc +++ b/components/payments/content/payment_request.cc
@@ -38,6 +38,7 @@ #include "content/public/browser/web_contents.h" #include "content/public/common/content_features.h" #include "content/public/common/origin_util.h" +#include "services/metrics/public/cpp/ukm_source_id.h" namespace payments { namespace { @@ -764,6 +765,14 @@ return delegate_->IsIncognito(); } +void PaymentRequest::OnPaymentHandlerOpenWindowCalled() { + DCHECK(state_->selected_app()); + // UKM for payment app origin should get recorded only when the origin of the + // invoked payment app is shown to the user. + journey_logger_.SetPaymentAppUkmSourceId( + state_->selected_app()->UkmSourceId()); +} + void PaymentRequest::RecordFirstAbortReason( JourneyLogger::AbortReason abort_reason) { if (!has_recorded_completion_) {
diff --git a/components/payments/content/payment_request.h b/components/payments/content/payment_request.h index 18ec889..8444bd9e 100644 --- a/components/payments/content/payment_request.h +++ b/components/payments/content/payment_request.h
@@ -126,6 +126,9 @@ bool IsIncognito() const; + // Called when the payment handler requests to open a payment handler window. + void OnPaymentHandlerOpenWindowCalled(); + content::WebContents* web_contents() { return web_contents_; } bool skipped_payment_request_ui() { return skipped_payment_request_ui_; }
diff --git a/components/payments/content/payment_response_helper_unittest.cc b/components/payments/content/payment_response_helper_unittest.cc index 01e9874..96c67a2f 100644 --- a/components/payments/content/payment_response_helper_unittest.cc +++ b/components/payments/content/payment_response_helper_unittest.cc
@@ -33,11 +33,11 @@ test_personal_data_manager_.AddProfile(address_); // Set up the autofill payment app. - autofill::CreditCard visa_card = autofill::test::GetCreditCard(); - visa_card.set_billing_address_id(address_.guid()); - visa_card.set_use_count(5u); + visa_card_ = autofill::test::GetCreditCard(); + visa_card_.set_billing_address_id(address_.guid()); + visa_card_.set_use_count(5u); autofill_app_ = std::make_unique<AutofillPaymentApp>( - "visa", visa_card, billing_addresses_, "en-US", + "visa", visa_card_, billing_addresses_, "en-US", &test_payment_request_delegate_); } ~PaymentResponseHelperTest() override {} @@ -90,6 +90,7 @@ PaymentRequestSpec* spec() { return spec_.get(); } const mojom::PaymentResponsePtr& response() { return payment_response_; } autofill::AutofillProfile* test_address() { return &address_; } + const autofill::CreditCard& test_credit_card() { return visa_card_; } PaymentApp* test_app() { return autofill_app_.get(); } PaymentRequestDelegate* test_payment_request_delegate() { return &test_payment_request_delegate_; @@ -103,6 +104,7 @@ // Test data. autofill::AutofillProfile address_; + autofill::CreditCard visa_card_; const std::vector<autofill::AutofillProfile*> billing_addresses_; std::unique_ptr<AutofillPaymentApp> autofill_app_; }; @@ -119,22 +121,27 @@ test_address(), this); EXPECT_EQ("visa", response()->method_name); EXPECT_EQ( - "{\"billingAddress\":" - "{\"addressLine\":[\"666 Erebus St.\",\"Apt 8\"]," - "\"city\":\"Elysium\"," - "\"country\":\"US\"," - "\"dependentLocality\":\"\"," - "\"organization\":\"Underworld\"," - "\"phone\":\"16502111111\"," - "\"postalCode\":\"91111\"," - "\"recipient\":\"John H. Doe\"," - "\"region\":\"CA\"," - "\"sortingCode\":\"\"}," - "\"cardNumber\":\"4111111111111111\"," - "\"cardSecurityCode\":\"123\"," - "\"cardholderName\":\"Test User\"," - "\"expiryMonth\":\"11\"," - "\"expiryYear\":\"2022\"}", + base::StringPrintf( + "{\"billingAddress\":" + "{\"addressLine\":[\"666 Erebus St.\",\"Apt 8\"]," + "\"city\":\"Elysium\"," + "\"country\":\"US\"," + "\"dependentLocality\":\"\"," + "\"organization\":\"Underworld\"," + "\"phone\":\"16502111111\"," + "\"postalCode\":\"91111\"," + "\"recipient\":\"John H. Doe\"," + "\"region\":\"CA\"," + "\"sortingCode\":\"\"}," + "\"cardNumber\":\"4111111111111111\"," + "\"cardSecurityCode\":\"123\"," + "\"cardholderName\":\"Test User\"," + "\"expiryMonth\":\"%s\"," + "\"expiryYear\":\"%s\"}", + base::UTF16ToUTF8(test_credit_card().Expiration2DigitMonthAsString()) + .c_str(), + base::UTF16ToUTF8(test_credit_card().Expiration4DigitYearAsString()) + .c_str()), response()->stringified_details); } @@ -157,22 +164,27 @@ test_address(), this); EXPECT_EQ("basic-card", response()->method_name); EXPECT_EQ( - "{\"billingAddress\":" - "{\"addressLine\":[\"666 Erebus St.\",\"Apt 8\"]," - "\"city\":\"Elysium\"," - "\"country\":\"US\"," - "\"dependentLocality\":\"\"," - "\"organization\":\"Underworld\"," - "\"phone\":\"16502111111\"," - "\"postalCode\":\"91111\"," - "\"recipient\":\"John H. Doe\"," - "\"region\":\"CA\"," - "\"sortingCode\":\"\"}," - "\"cardNumber\":\"4111111111111111\"," - "\"cardSecurityCode\":\"123\"," - "\"cardholderName\":\"Test User\"," - "\"expiryMonth\":\"11\"," - "\"expiryYear\":\"2022\"}", + base::StringPrintf( + "{\"billingAddress\":" + "{\"addressLine\":[\"666 Erebus St.\",\"Apt 8\"]," + "\"city\":\"Elysium\"," + "\"country\":\"US\"," + "\"dependentLocality\":\"\"," + "\"organization\":\"Underworld\"," + "\"phone\":\"16502111111\"," + "\"postalCode\":\"91111\"," + "\"recipient\":\"John H. Doe\"," + "\"region\":\"CA\"," + "\"sortingCode\":\"\"}," + "\"cardNumber\":\"4111111111111111\"," + "\"cardSecurityCode\":\"123\"," + "\"cardholderName\":\"Test User\"," + "\"expiryMonth\":\"%s\"," + "\"expiryYear\":\"%s\"}", + base::UTF16ToUTF8(test_credit_card().Expiration2DigitMonthAsString()) + .c_str(), + base::UTF16ToUTF8(test_credit_card().Expiration4DigitYearAsString()) + .c_str()), response()->stringified_details); }
diff --git a/components/payments/content/service_worker_payment_app.cc b/components/payments/content/service_worker_payment_app.cc index 8d9b29ac..25fa9d7 100644 --- a/components/payments/content/service_worker_payment_app.cc +++ b/components/payments/content/service_worker_payment_app.cc
@@ -531,4 +531,16 @@ identity_callback_.Run(origin, registration_id); } +ukm::SourceId ServiceWorkerPaymentApp::UkmSourceId() { + if (ukm_source_id_ == ukm::kInvalidSourceId) { + // At this point we know that the payment handler window is open for this + // app since this getter is called for the invoked app inside the + // PaymentRequest::OnPaymentHandlerOpenWindowCalled function. + ukm_source_id_ = content::PaymentAppProvider::GetInstance() + ->GetSourceIdForPaymentAppFromScope( + GURL(stored_payment_app_info_->scope).GetOrigin()); + } + return ukm_source_id_; +} + } // namespace payments
diff --git a/components/payments/content/service_worker_payment_app.h b/components/payments/content/service_worker_payment_app.h index d58a692c..f6e51300 100644 --- a/components/payments/content/service_worker_payment_app.h +++ b/components/payments/content/service_worker_payment_app.h
@@ -97,6 +97,7 @@ bool HandlesPayerName() const override; bool HandlesPayerEmail() const override; bool HandlesPayerPhone() const override; + ukm::SourceId UkmSourceId() override; void set_payment_handler_host( mojo::PendingRemote<mojom::PaymentHandlerHost> payment_handler_host) { @@ -153,6 +154,8 @@ std::unique_ptr<WebAppInstallationInfo> installable_web_app_info_; std::string installable_enabled_method_; + ukm::SourceId ukm_source_id_ = ukm::kInvalidSourceId; + base::WeakPtrFactory<ServiceWorkerPaymentApp> weak_ptr_factory_{this}; DISALLOW_COPY_AND_ASSIGN(ServiceWorkerPaymentApp);
diff --git a/components/payments/core/journey_logger.cc b/components/payments/core/journey_logger.cc index 95188ee..92e7b95 100644 --- a/components/payments/core/journey_logger.cc +++ b/components/payments/core/journey_logger.cc
@@ -82,10 +82,11 @@ } // namespace -JourneyLogger::JourneyLogger(bool is_incognito, ukm::SourceId source_id) +JourneyLogger::JourneyLogger(bool is_incognito, + ukm::SourceId payment_request_source_id) : is_incognito_(is_incognito), events_(EVENT_INITIATED), - source_id_(source_id) {} + payment_request_source_id_(payment_request_source_id) {} JourneyLogger::~JourneyLogger() { // has_recorded_ is false in cases that the page gets closed. To see more @@ -253,11 +254,11 @@ base::UmaHistogramEnumeration( "PaymentRequest.TransactionAmount" + completion_suffix, transaction_size); - if (source_id_ == ukm::kInvalidSourceId) + if (payment_request_source_id_ == ukm::kInvalidSourceId) return; // Record the transaction amount in UKM. - ukm::builders::PaymentRequest_TransactionAmount(source_id_) + ukm::builders::PaymentRequest_TransactionAmount(payment_request_source_id_) .SetCompletionStatus(completed) .SetCategory(static_cast<int64_t>(transaction_size)) .Record(ukm::UkmRecorder::Get()); @@ -353,14 +354,26 @@ ValidateEventBits(); base::UmaHistogramSparse("PaymentRequest.Events", events_); - if (source_id_ == ukm::kInvalidSourceId) + if (payment_request_source_id_ == ukm::kInvalidSourceId) return; // Record the events in UKM. - ukm::builders::PaymentRequest_CheckoutEvents(source_id_) + ukm::builders::PaymentRequest_CheckoutEvents(payment_request_source_id_) .SetCompletionStatus(completion_status) .SetEvents(events_) .Record(ukm::UkmRecorder::Get()); + + if (payment_app_source_id_ == ukm::kInvalidSourceId) + return; + + // Record the events in UKM for payment app. + ukm::builders::PaymentApp_CheckoutEvents(payment_app_source_id_) + .SetCompletionStatus(completion_status) + .SetEvents(events_) + .Record(ukm::UkmRecorder::Get()); + + // Clear payment app source id since it gets deleted after recording. + payment_app_source_id_ = ukm::kInvalidSourceId; } void JourneyLogger::RecordTimeToCheckout( @@ -490,4 +503,9 @@ trigger_time_ = base::TimeTicks::Now(); } +void JourneyLogger::SetPaymentAppUkmSourceId( + ukm::SourceId payment_app_source_id) { + payment_app_source_id_ = payment_app_source_id; +} + } // namespace payments
diff --git a/components/payments/core/journey_logger.h b/components/payments/core/journey_logger.h index 69615f6..47cf99c 100644 --- a/components/payments/core/journey_logger.h +++ b/components/payments/core/journey_logger.h
@@ -152,7 +152,7 @@ kMaxValue = kRegularTransaction, }; - JourneyLogger(bool is_incognito, ukm::SourceId source_id); + JourneyLogger(bool is_incognito, ukm::SourceId payment_request_source_id); ~JourneyLogger(); // Increments the number of selection adds for the specified section. @@ -215,6 +215,9 @@ // Records when Payment Request .show is called. void SetTriggerTime(); + // Sets the ukm source id of the selected app when it gets invoked. + void SetPaymentAppUkmSourceId(ukm::SourceId payment_app_source_id); + private: static const int NUMBER_OF_SECTIONS = 3; @@ -285,7 +288,8 @@ // checkout duration. base::TimeTicks trigger_time_; - ukm::SourceId source_id_; + ukm::SourceId payment_request_source_id_; + ukm::SourceId payment_app_source_id_ = ukm::kInvalidSourceId; DISALLOW_COPY_AND_ASSIGN(JourneyLogger); };
diff --git a/components/payments/core/payment_app.cc b/components/payments/core/payment_app.cc index 703024e..6cfe02e 100644 --- a/components/payments/core/payment_app.cc +++ b/components/payments/core/payment_app.cc
@@ -62,6 +62,10 @@ return app_method_names_; } +ukm::SourceId PaymentApp::UkmSourceId() { + return ukm::kInvalidSourceId; +} + // static void PaymentApp::SortApps(std::vector<std::unique_ptr<PaymentApp>>* apps) { DCHECK(apps);
diff --git a/components/payments/core/payment_app.h b/components/payments/core/payment_app.h index 0e245575..5cf771dc 100644 --- a/components/payments/core/payment_app.h +++ b/components/payments/core/payment_app.h
@@ -15,6 +15,7 @@ #include "build/build_config.h" #include "components/autofill/core/browser/data_model/credit_card.h" #include "components/payments/core/payer_data.h" +#include "services/metrics/public/cpp/ukm_source_id.h" #include "ui/gfx/image/image_skia.h" namespace payments { @@ -110,6 +111,8 @@ int icon_resource_id() const { return icon_resource_id_; } Type type() const { return type_; } + virtual ukm::SourceId UkmSourceId(); + protected: PaymentApp(int icon_resource_id, Type type);
diff --git a/components/payments/core/payment_request_data_util_unittest.cc b/components/payments/core/payment_request_data_util_unittest.cc index 1076648..b034fca 100644 --- a/components/payments/core/payment_request_data_util_unittest.cc +++ b/components/payments/core/payment_request_data_util_unittest.cc
@@ -8,6 +8,7 @@ #include "base/json/json_writer.h" #include "base/macros.h" +#include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "base/values.h" #include "build/build_config.h" @@ -69,24 +70,26 @@ ->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\"," - "\"dependentLocality\":\"\"," - "\"organization\":\"Underworld\"," - "\"phone\":\"16502111111\"," - "\"postalCode\":\"91111\"," - "\"recipient\":\"John H. Doe\"," - "\"region\":\"CA\"," - "\"sortingCode\":\"\"}," - "\"cardNumber\":\"4111111111111111\"," - "\"cardSecurityCode\":\"123\"," - "\"cardholderName\":\"Test User\"," - "\"expiryMonth\":\"11\"," - "\"expiryYear\":\"2022\"}", - json_response); + EXPECT_EQ(base::StringPrintf( + "{\"billingAddress\":" + "{\"addressLine\":[\"666 Erebus St.\",\"Apt 8\"]," + "\"city\":\"Elysium\"," + "\"country\":\"US\"," + "\"dependentLocality\":\"\"," + "\"organization\":\"Underworld\"," + "\"phone\":\"16502111111\"," + "\"postalCode\":\"91111\"," + "\"recipient\":\"John H. Doe\"," + "\"region\":\"CA\"," + "\"sortingCode\":\"\"}," + "\"cardNumber\":\"4111111111111111\"," + "\"cardSecurityCode\":\"123\"," + "\"cardholderName\":\"Test User\"," + "\"expiryMonth\":\"%s\"," + "\"expiryYear\":\"%s\"}", + base::UTF16ToUTF8(card.Expiration2DigitMonthAsString()).c_str(), + base::UTF16ToUTF8(card.Expiration4DigitYearAsString()).c_str()), + json_response); } // A test fixture to check ParseSupportedMethods() returns empty supported
diff --git a/components/policy/core/browser/configuration_policy_handler.cc b/components/policy/core/browser/configuration_policy_handler.cc index 20e2d97..d170260 100644 --- a/components/policy/core/browser/configuration_policy_handler.cc +++ b/components/policy/core/browser/configuration_policy_handler.cc
@@ -93,18 +93,14 @@ void ListPolicyHandler::ApplyPolicySettings(const policy::PolicyMap& policies, PrefValueMap* prefs) { - std::unique_ptr<base::ListValue> list; - if (CheckAndGetList(policies, nullptr, &list) && list) + base::Value list(base::Value::Type::NONE); + if (CheckAndGetList(policies, nullptr, &list) && list.is_list()) ApplyList(std::move(list), prefs); } -bool ListPolicyHandler::CheckAndGetList( - const policy::PolicyMap& policies, - policy::PolicyErrorMap* errors, - std::unique_ptr<base::ListValue>* filtered_list) { - if (filtered_list) - filtered_list->reset(); - +bool ListPolicyHandler::CheckAndGetList(const policy::PolicyMap& policies, + policy::PolicyErrorMap* errors, + base::Value* filtered_list) { const base::Value* value = nullptr; if (!CheckAndGetValue(policies, errors, &value)) return false; @@ -115,7 +111,7 @@ // Filter the list, rejecting any invalid strings. base::Value::ConstListView list = value->GetList(); if (filtered_list) - *filtered_list = std::make_unique<base::ListValue>(); + *filtered_list = base::Value(base::Value::Type::LIST); for (size_t list_index = 0; list_index < list.size(); ++list_index) { const base::Value& entry = list[list_index]; if (entry.type() != list_entry_type_) { @@ -135,7 +131,7 @@ } if (filtered_list) - (*filtered_list)->Append(entry.CreateDeepCopy()); + filtered_list->Append(entry.Clone()); } return true;
diff --git a/components/policy/core/browser/configuration_policy_handler.h b/components/policy/core/browser/configuration_policy_handler.h index 573a7a3e..0583453 100644 --- a/components/policy/core/browser/configuration_policy_handler.h +++ b/components/policy/core/browser/configuration_policy_handler.h
@@ -128,8 +128,7 @@ // Implement this method to apply the |filtered_list| of values of type // |list_entry_type_| as returned from CheckAndGetList() to |prefs|. - virtual void ApplyList(std::unique_ptr<base::ListValue> filtered_list, - PrefValueMap* prefs) = 0; + virtual void ApplyList(base::Value filtered_list, PrefValueMap* prefs) = 0; private: // Checks whether the policy value is indeed a list, filters out all entries @@ -138,7 +137,7 @@ // filtered list entries if |errors| is not nullptr. bool CheckAndGetList(const policy::PolicyMap& policies, policy::PolicyErrorMap* errors, - std::unique_ptr<base::ListValue>* filtered_list); + base::Value* filtered_list); // Expected value type for list entries. All other types are filtered out. base::Value::Type list_entry_type_;
diff --git a/components/policy/core/browser/configuration_policy_handler_unittest.cc b/components/policy/core/browser/configuration_policy_handler_unittest.cc index 0bb1036..3849a735 100644 --- a/components/policy/core/browser/configuration_policy_handler_unittest.cc +++ b/components/policy/core/browser/configuration_policy_handler_unittest.cc
@@ -115,11 +115,9 @@ : ListPolicyHandler(kPolicyName, base::Value::Type::STRING) {} protected: - void ApplyList(std::unique_ptr<base::ListValue> filtered_list, - PrefValueMap* prefs) override { - DCHECK(filtered_list); - prefs->SetValue(kTestPref, - base::Value::FromUniquePtrValue(std::move(filtered_list))); + void ApplyList(base::Value filtered_list, PrefValueMap* prefs) override { + DCHECK(filtered_list.is_list()); + prefs->SetValue(kTestPref, std::move(filtered_list)); } };
diff --git a/components/safe_browsing/content/base_ui_manager.cc b/components/safe_browsing/content/base_ui_manager.cc index e27a738..1df8979 100644 --- a/components/safe_browsing/content/base_ui_manager.cc +++ b/components/safe_browsing/content/base_ui_manager.cc
@@ -254,20 +254,28 @@ ? resource.url : GetNavigationEntryForResource(resource)->GetURL(); AddUnsafeResource(unsafe_url, resource); - // With committed interstitials we just cancel the load from here, the - // actual interstitial will be shown from the - // SafeBrowsingNavigationThrottle. + // If the delayed warnings experiment is not enabled, with committed + // interstitials we just cancel the load from here, the actual interstitial + // will be shown from the SafeBrowsingNavigationThrottle. // showed_interstitial is set to false for subresources since this // cancellation doesn't correspond to the navigation that triggers the error // page (the call to LoadPostCommitErrorPage creates another navigation). + // + // If the experiment is enabled, the interstitial is shown below. if (!resource.callback.is_null()) { resource.callback_thread->PostTask( FROM_HERE, base::BindOnce( - resource.callback, /*proceed=*/false, - /*showed_interstitial=*/resource.IsMainPageLoadBlocked())); + resource.callback, false /* proceed */, + resource.IsMainPageLoadBlocked() /* showed_interstitial */)); } - if (!resource.IsMainPageLoadBlocked() && !IsWhitelisted(resource)) { + + if (!base::FeatureList::IsEnabled(safe_browsing::kDelayedWarnings)) { + DCHECK(!resource.is_delayed_warning); + } + + if ((!resource.IsMainPageLoadBlocked() || resource.is_delayed_warning) && + !IsWhitelisted(resource)) { // For subresource triggered interstitials, we trigger the error page // navigation from here since there will be no navigation to intercept // in the throttle.
diff --git a/components/safe_browsing/core/browser/safe_browsing_url_checker_impl.cc b/components/safe_browsing/core/browser/safe_browsing_url_checker_impl.cc index f84a37fb..bd21644 100644 --- a/components/safe_browsing/core/browser/safe_browsing_url_checker_impl.cc +++ b/components/safe_browsing/core/browser/safe_browsing_url_checker_impl.cc
@@ -13,6 +13,7 @@ #include "components/safe_browsing/core/browser/url_checker_delegate.h" #include "components/safe_browsing/core/common/safebrowsing_constants.h" #include "components/safe_browsing/core/common/thread_utils.h" +#include "components/safe_browsing/core/features.h" #include "components/safe_browsing/core/realtime/policy_engine.h" #include "components/safe_browsing/core/realtime/url_lookup_service.h" #include "components/safe_browsing/core/web_ui/constants.h" @@ -135,6 +136,32 @@ CheckUrlImpl(url, method, Notifier(std::move(callback))); } +security_interstitials::UnsafeResource +SafeBrowsingUrlCheckerImpl::MakeUnsafeResource(const GURL& url, + SBThreatType threat_type, + const ThreatMetadata& metadata) { + security_interstitials::UnsafeResource resource; + resource.url = url; + resource.original_url = urls_[0].url; + if (urls_.size() > 1) { + resource.redirect_urls.reserve(urls_.size() - 1); + for (size_t i = 1; i < urls_.size(); ++i) + resource.redirect_urls.push_back(urls_[i].url); + } + resource.is_subresource = resource_type_ != ResourceType::kMainFrame; + resource.is_subframe = resource_type_ == ResourceType::kSubFrame; + resource.threat_type = threat_type; + resource.threat_metadata = metadata; + resource.callback = + base::BindRepeating(&SafeBrowsingUrlCheckerImpl::OnBlockingPageComplete, + weak_factory_.GetWeakPtr()); + resource.callback_thread = + base::CreateSingleThreadTaskRunner(CreateTaskTraits(ThreadID::IO)); + resource.web_contents_getter = web_contents_getter_; + resource.threat_source = database_manager_->GetThreatSource(); + return resource; +} + void SafeBrowsingUrlCheckerImpl::OnCheckBrowseUrlResult( const GURL& url, SBThreatType threat_type, @@ -154,6 +181,26 @@ TRACE_EVENT_ASYNC_END1("safe_browsing", "CheckUrl", this, "url", url.spec()); + if (base::FeatureList::IsEnabled(kDelayedWarnings)) { + // Delayed warnings experiment delays the warning until a user interaction + // happens. Create an interaction observer and continue like there wasn't + // a warning. The observer will create the interstitial when necessary. + security_interstitials::UnsafeResource unsafe_resource = + MakeUnsafeResource(url, threat_type, metadata); + unsafe_resource.is_delayed_warning = true; + url_checker_delegate_ + ->StartObservingInteractionsForDelayedBlockingPageHelper( + unsafe_resource, resource_type_ == ResourceType::kMainFrame); + + // Let the navigation continue. + threat_type = SB_THREAT_TYPE_SAFE; + state_ = STATE_DELAYED_BLOCKING_PAGE; + if (!RunNextCallback(true, false)) + return; + // No need to call ProcessUrls, it'll return early. + return; + } + if (threat_type == SB_THREAT_TYPE_SAFE || threat_type == SB_THREAT_TYPE_SUSPICIOUS_SITE) { state_ = STATE_NONE; @@ -186,25 +233,8 @@ UMA_HISTOGRAM_ENUMERATION("SB2.ResourceTypes2.Unsafe", resource_type_); - security_interstitials::UnsafeResource resource; - resource.url = url; - resource.original_url = urls_[0].url; - if (urls_.size() > 1) { - resource.redirect_urls.reserve(urls_.size() - 1); - for (size_t i = 1; i < urls_.size(); ++i) - resource.redirect_urls.push_back(urls_[i].url); - } - resource.is_subresource = resource_type_ != ResourceType::kMainFrame; - resource.is_subframe = resource_type_ == ResourceType::kSubFrame; - resource.threat_type = threat_type; - resource.threat_metadata = metadata; - resource.callback = - base::BindRepeating(&SafeBrowsingUrlCheckerImpl::OnBlockingPageComplete, - weak_factory_.GetWeakPtr()); - resource.callback_thread = - base::CreateSingleThreadTaskRunner(CreateTaskTraits(ThreadID::IO)); - resource.web_contents_getter = web_contents_getter_; - resource.threat_source = database_manager_->GetThreatSource(); + security_interstitials::UnsafeResource resource = + MakeUnsafeResource(url, threat_type, metadata); state_ = STATE_DISPLAYING_BLOCKING_PAGE; url_checker_delegate_->StartDisplayingBlockingPageHelper( @@ -238,9 +268,13 @@ void SafeBrowsingUrlCheckerImpl::ProcessUrls() { DCHECK(CurrentlyOnThread(ThreadID::IO)); DCHECK_NE(STATE_BLOCKED, state_); + if (!base::FeatureList::IsEnabled(kDelayedWarnings)) { + DCHECK_NE(STATE_DELAYED_BLOCKING_PAGE, state_); + } if (state_ == STATE_CHECKING_URL || - state_ == STATE_DISPLAYING_BLOCKING_PAGE) { + state_ == STATE_DISPLAYING_BLOCKING_PAGE || + state_ == STATE_DELAYED_BLOCKING_PAGE) { return; }
diff --git a/components/safe_browsing/core/browser/safe_browsing_url_checker_impl.h b/components/safe_browsing/core/browser/safe_browsing_url_checker_impl.h index 5e4f087..2840117f 100644 --- a/components/safe_browsing/core/browser/safe_browsing_url_checker_impl.h +++ b/components/safe_browsing/core/browser/safe_browsing_url_checker_impl.h
@@ -14,6 +14,7 @@ #include "components/safe_browsing/core/common/safe_browsing_url_checker.mojom.h" #include "components/safe_browsing/core/db/database_manager.h" #include "components/safe_browsing/core/proto/realtimeapi.pb.h" +#include "components/security_interstitials/core/unsafe_resource.h" #include "mojo/public/cpp/bindings/remote.h" #include "net/http/http_request_headers.h" #include "url/gurl.h" @@ -183,11 +184,19 @@ void SetWebUIToken(int token); + security_interstitials::UnsafeResource MakeUnsafeResource( + const GURL& url, + SBThreatType threat_type, + const ThreatMetadata& metadata); + enum State { // Haven't started checking or checking is complete. STATE_NONE, // We have one outstanding URL-check. STATE_CHECKING_URL, + // A warning must be shown, but it's delayed because of the Delayed Warnings + // experiment. + STATE_DELAYED_BLOCKING_PAGE, // We're displaying a blocking page. STATE_DISPLAYING_BLOCKING_PAGE, // The blocking page has returned *not* to proceed.
diff --git a/components/safe_browsing/core/browser/url_checker_delegate.h b/components/safe_browsing/core/browser/url_checker_delegate.h index 1cbb75f..4482a5a 100644 --- a/components/safe_browsing/core/browser/url_checker_delegate.h +++ b/components/safe_browsing/core/browser/url_checker_delegate.h
@@ -50,6 +50,12 @@ bool is_main_frame, bool has_user_gesture) = 0; + // Starts observing user input events to display a SafeBrowsing interstitial + // page when an event is received. + virtual void StartObservingInteractionsForDelayedBlockingPageHelper( + const security_interstitials::UnsafeResource& resource, + bool is_main_frame) = 0; + // A whitelisted URL is considered safe and therefore won't be checked with // the SafeBrowsing database. virtual bool IsUrlWhitelisted(const GURL& url) = 0;
diff --git a/components/safe_browsing/core/features.cc b/components/safe_browsing/core/features.cc index e29b0f19..3c3b57c8 100644 --- a/components/safe_browsing/core/features.cc +++ b/components/safe_browsing/core/features.cc
@@ -41,6 +41,9 @@ const base::Feature kContentComplianceEnabled{ "SafeBrowsingContentComplianceEnabled", base::FEATURE_DISABLED_BY_DEFAULT}; +const base::Feature kDelayedWarnings{"SafeBrowsingDelayedWarnings", + base::FEATURE_DISABLED_BY_DEFAULT}; + const base::Feature kDownloadRequestWithToken{ "SafeBrowsingDownloadRequestWithToken", base::FEATURE_ENABLED_BY_DEFAULT}; @@ -135,6 +138,7 @@ {&kAdSamplerTriggerFeature, false}, {&kCaptureInlineJavascriptForGoogleAds, true}, {&kCaptureSafetyNetId, true}, + {&kDelayedWarnings, true}, {&kCommittedSBInterstitials, true}, {&kContentComplianceEnabled, true}, {&kDownloadRequestWithToken, true},
diff --git a/components/safe_browsing/core/features.h b/components/safe_browsing/core/features.h index be2f38c..89a4ad1 100644 --- a/components/safe_browsing/core/features.h +++ b/components/safe_browsing/core/features.h
@@ -120,6 +120,9 @@ // Controls whether Chrome uses new download warning UX. extern const base::Feature kUseNewDownloadWarnings; +// Controls whether the delayed warning experiment is enabled. +extern const base::Feature kDelayedWarnings; + base::ListValue GetFeatureStatusList(); // Returns whether or not to stop filling in the SyncAccountType and
diff --git a/components/security_interstitials/core/unsafe_resource.cc b/components/security_interstitials/core/unsafe_resource.cc index 65234d1..2a75b2a 100644 --- a/components/security_interstitials/core/unsafe_resource.cc +++ b/components/security_interstitials/core/unsafe_resource.cc
@@ -12,7 +12,8 @@ : is_subresource(false), is_subframe(false), threat_type(safe_browsing::SB_THREAT_TYPE_SAFE), - threat_source(safe_browsing::ThreatSource::UNKNOWN) {} + threat_source(safe_browsing::ThreatSource::UNKNOWN), + is_delayed_warning(false) {} UnsafeResource::UnsafeResource(const UnsafeResource& other) = default;
diff --git a/components/security_interstitials/core/unsafe_resource.h b/components/security_interstitials/core/unsafe_resource.h index 5f108a5..6283f90 100644 --- a/components/security_interstitials/core/unsafe_resource.h +++ b/components/security_interstitials/core/unsafe_resource.h
@@ -59,6 +59,10 @@ // |token| field is only set if |threat_type| is // SB_THREAT_TYPE_*_PASSWORD_REUSE. std::string token; + + // If true, this UnsafeResource is created because of the Delayed Warnings + // experiment. + bool is_delayed_warning; }; } // namespace security_interstitials
diff --git a/components/send_tab_to_self/features.cc b/components/send_tab_to_self/features.cc index bd1df36d..a601490 100644 --- a/components/send_tab_to_self/features.cc +++ b/components/send_tab_to_self/features.cc
@@ -12,6 +12,9 @@ const base::Feature kSendTabToSelfBroadcast{"SendTabToSelfBroadcast", base::FEATURE_DISABLED_BY_DEFAULT}; +const base::Feature kSendTabToSelfOmniboxSendingAnimation{ + "SendTabToSelfOmniboxSendingAnimation", base::FEATURE_DISABLED_BY_DEFAULT}; + const base::Feature kSendTabToSelfWhenSignedIn{ "SendTabToSelfWhenSignedIn", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/components/send_tab_to_self/features.h b/components/send_tab_to_self/features.h index 2689d2a2..50cf8a4 100644 --- a/components/send_tab_to_self/features.h +++ b/components/send_tab_to_self/features.h
@@ -15,6 +15,10 @@ // targeted to a specific device. This only affects the receiving side. extern const base::Feature kSendTabToSelfBroadcast; +// If this feature is enabled, the Sending... animation will show in the omnibox +// instead of sending Desktop OS notifications for contextual menu entry points. +extern const base::Feature kSendTabToSelfOmniboxSendingAnimation; + // If this feature is enabled, we will use signed-in, ephemeral data rather than // persistent sync data. Users who are signed in can use the feature regardless // of whether they have the sync feature enabled.
diff --git a/components/ukm/ukm_recorder_impl.cc b/components/ukm/ukm_recorder_impl.cc index 94b712f..6b507d49 100644 --- a/components/ukm/ukm_recorder_impl.cc +++ b/components/ukm/ukm_recorder_impl.cc
@@ -48,7 +48,8 @@ return GetSourceIdType(source_id) == SourceIdType::NAVIGATION_ID || GetSourceIdType(source_id) == SourceIdType::APP_ID || GetSourceIdType(source_id) == SourceIdType::HISTORY_ID || - GetSourceIdType(source_id) == SourceIdType::WEBAPK_ID; + GetSourceIdType(source_id) == SourceIdType::WEBAPK_ID || + GetSourceIdType(source_id) == SourceIdType::PAYMENT_APP_ID; } // Gets the maximum number of Sources we'll keep in memory before discarding any @@ -322,7 +323,8 @@ // entries are logged only at source creation time. if (GetSourceIdType(kv.first) == base::UkmSourceId::Type::APP_ID || GetSourceIdType(kv.first) == base::UkmSourceId::Type::HISTORY_ID || - GetSourceIdType(kv.first) == base::UkmSourceId::Type::WEBAPK_ID) { + GetSourceIdType(kv.first) == base::UkmSourceId::Type::WEBAPK_ID || + GetSourceIdType(kv.first) == SourceIdType::PAYMENT_APP_ID) { MarkSourceForDeletion(kv.first); } // If the source id is not whitelisted, don't send it unless it has
diff --git a/components/ukm/ukm_recorder_impl.h b/components/ukm/ukm_recorder_impl.h index f5eeaa2..7c8e27b 100644 --- a/components/ukm/ukm_recorder_impl.h +++ b/components/ukm/ukm_recorder_impl.h
@@ -136,6 +136,7 @@ FRIEND_TEST_ALL_PREFIXES(UkmRecorderImplTest, IsSampledIn); FRIEND_TEST_ALL_PREFIXES(UkmRecorderImplTest, PurgeExtensionRecordings); FRIEND_TEST_ALL_PREFIXES(UkmRecorderImplTest, WebApkSourceUrl); + FRIEND_TEST_ALL_PREFIXES(UkmRecorderImplTest, PaymentAppScopeUrl); struct MetricAggregate { uint64_t total_count = 0;
diff --git a/components/ukm/ukm_recorder_impl_unittest.cc b/components/ukm/ukm_recorder_impl_unittest.cc index 8794294a..9c1c397e 100644 --- a/components/ukm/ukm_recorder_impl_unittest.cc +++ b/components/ukm/ukm_recorder_impl_unittest.cc
@@ -125,4 +125,22 @@ EXPECT_EQ(SourceIdType::WEBAPK_ID, GetSourceIdType(id)); } +TEST(UkmRecorderImplTest, PaymentAppScopeUrl) { + base::test::TaskEnvironment env; + ukm::TestAutoSetUkmRecorder test_ukm_recorder; + + GURL url("https://bobpay.com"); + SourceId id = UkmRecorderImpl::GetSourceIdForPaymentAppFromScope(url); + + ASSERT_NE(kInvalidSourceId, id); + + const auto& sources = test_ukm_recorder.GetSources(); + ASSERT_EQ(1ul, sources.size()); + auto it = sources.find(id); + ASSERT_NE(sources.end(), it); + EXPECT_EQ(url, it->second->url()); + EXPECT_EQ(1u, it->second->urls().size()); + EXPECT_EQ(SourceIdType::PAYMENT_APP_ID, GetSourceIdType(id)); +} + } // namespace ukm
diff --git a/components/ukm/ukm_service_unittest.cc b/components/ukm/ukm_service_unittest.cc index 903c6e85..994b2a7 100644 --- a/components/ukm/ukm_service_unittest.cc +++ b/components/ukm/ukm_service_unittest.cc
@@ -1397,39 +1397,45 @@ service.EnableRecording(/*extensions=*/false); service.EnableReporting(); - // Seed some dummy sources. - SourceId id0 = ConvertToSourceId(0, SourceIdType::UKM); - recorder.UpdateSourceURL(id0, GURL("https://www.example0.com/")); - SourceId id1 = + // Seed some fake sources. + SourceId ukm_id = ConvertToSourceId(0, SourceIdType::UKM); + recorder.UpdateSourceURL(ukm_id, GURL("https://www.example0.com/")); + SourceId navigation_id = ConvertSourceIdToWhitelistedType(1, SourceIdType::NAVIGATION_ID); - recorder.UpdateSourceURL(id1, GURL("https://www.example1.com/")); - SourceId id2 = ConvertSourceIdToWhitelistedType(2, SourceIdType::APP_ID); - recorder.UpdateSourceURL(id2, GURL("https://www.example2.com/")); - SourceId id3 = ConvertSourceIdToWhitelistedType(3, SourceIdType::HISTORY_ID); - recorder.UpdateSourceURL(id3, GURL("https://www.example3.com/")); - SourceId id4 = ConvertSourceIdToWhitelistedType(4, SourceIdType::WEBAPK_ID); - recorder.UpdateSourceURL(id4, GURL("https://www.example3.com/")); + recorder.UpdateSourceURL(navigation_id, GURL("https://www.example1.com/")); + SourceId app_id = ConvertSourceIdToWhitelistedType(2, SourceIdType::APP_ID); + recorder.UpdateSourceURL(app_id, GURL("https://www.example2.com/")); + SourceId history_id = + ConvertSourceIdToWhitelistedType(3, SourceIdType::HISTORY_ID); + recorder.UpdateSourceURL(history_id, GURL("https://www.example3.com/")); + SourceId webapk_id = + ConvertSourceIdToWhitelistedType(4, SourceIdType::WEBAPK_ID); + recorder.UpdateSourceURL(webapk_id, GURL("https://www.example4.com/")); + SourceId payment_app_id = + ConvertSourceIdToWhitelistedType(5, SourceIdType::PAYMENT_APP_ID); + recorder.UpdateSourceURL(payment_app_id, GURL("https://www.example5.com/")); service.Flush(); int logs_count = 0; EXPECT_EQ(++logs_count, GetPersistedLogCount()); - // All sources are present except id0 of non-whitelisted UKM type. + // All sources are present except ukm_id of non-whitelisted UKM type. Report proto_report = GetPersistedReport(); - ASSERT_EQ(4, proto_report.sources_size()); - EXPECT_EQ(id1, proto_report.sources(0).id()); - EXPECT_EQ(id2, proto_report.sources(1).id()); - EXPECT_EQ(id3, proto_report.sources(2).id()); - EXPECT_EQ(id4, proto_report.sources(3).id()); + ASSERT_EQ(5, proto_report.sources_size()); + EXPECT_EQ(navigation_id, proto_report.sources(0).id()); + EXPECT_EQ(app_id, proto_report.sources(1).id()); + EXPECT_EQ(history_id, proto_report.sources(2).id()); + EXPECT_EQ(webapk_id, proto_report.sources(3).id()); + EXPECT_EQ(payment_app_id, proto_report.sources(4).id()); service.Flush(); EXPECT_EQ(++logs_count, GetPersistedLogCount()); - // Sources of APP_ID, HISTORY_ID and WEBAPK_ID types are not kept between - // reporting cycles, thus only 1 navigation type source remains. + // Sources of APP_ID, HISTORY_ID, WEBAPK_ID and PAYMENT_APP_ID types are not + // kept between reporting cycles, thus only 1 navigation type source remains. proto_report = GetPersistedReport(); ASSERT_EQ(1, proto_report.sources_size()); - EXPECT_EQ(id1, proto_report.sources(0).id()); + EXPECT_EQ(navigation_id, proto_report.sources(0).id()); } } // namespace ukm
diff --git a/components/viz/common/display/renderer_settings.h b/components/viz/common/display/renderer_settings.h index a27d84c..8bde479 100644 --- a/components/viz/common/display/renderer_settings.h +++ b/components/viz/common/display/renderer_settings.h
@@ -43,9 +43,6 @@ int slow_down_compositing_scale_factor = 1; - // The required minimum size for DrawQuad to apply Draw Occlusion on. - gfx::Size kMinimumDrawOcclusionSize = gfx::Size(60, 60); - // The maximum number of occluding Rects to track during occlusion culling. int kMaximumOccluderComplexity = 10;
diff --git a/components/viz/service/display/display.cc b/components/viz/service/display/display.cc index 71e0e4a..e7c7b5d 100644 --- a/components/viz/service/display/display.cc +++ b/components/viz/service/display/display.cc
@@ -928,10 +928,6 @@ cc::Region occlusion_in_target_space; cc::Region backdrop_filters_in_target_space; bool current_sqs_intersects_occlusion = false; - int minimum_draw_occlusion_height = - settings_.kMinimumDrawOcclusionSize.height() * device_scale_factor_; - int minimum_draw_occlusion_width = - settings_.kMinimumDrawOcclusionSize.width() * device_scale_factor_; base::flat_map<RenderPassId, gfx::Rect> backdrop_filter_rects; for (const auto& pass : frame->render_pass_list) { @@ -969,9 +965,7 @@ } // Also skip quad if the DrawQuad size is smaller than the // kMinimumDrawOcclusionSize; or the DrawQuad is inside a 3d object. - if ((quad->visible_rect.width() <= minimum_draw_occlusion_width && - quad->visible_rect.height() <= minimum_draw_occlusion_height) || - quad->shared_quad_state->sorting_context_id != 0) { + if (quad->shared_quad_state->sorting_context_id != 0) { ++quad; continue; }
diff --git a/components/viz/service/display/display_unittest.cc b/components/viz/service/display/display_unittest.cc index 5b51257c..951829a 100644 --- a/components/viz/service/display/display_unittest.cc +++ b/components/viz/service/display/display_unittest.cc
@@ -913,7 +913,6 @@ RendererSettings settings; settings.minimum_fragments_reduced = 0; - settings.kMinimumDrawOcclusionSize.set_width(0); SetUpGpuDisplay(settings); StubDisplayClient client; display_->Initialize(&client, manager_.surface_manager()); @@ -1214,7 +1213,6 @@ // defined by |rects[2]| will not be occluded (removed). TEST_F(DisplayTest, DrawOcclusionWithSingleOverlapBehindDisjointedDrawQuads) { RendererSettings settings; - settings.kMinimumDrawOcclusionSize.set_width(0); SetUpGpuDisplay(settings); StubDisplayClient client; @@ -1272,7 +1270,6 @@ // defined by |rects[2]| will not be occluded (removed). TEST_F(DisplayTest, DrawOcclusionWithMultipleOverlapBehindDisjointedDrawQuads) { RendererSettings settings; - settings.kMinimumDrawOcclusionSize.set_width(0); SetUpGpuDisplay(settings); StubDisplayClient client; @@ -1328,7 +1325,6 @@ // Check if draw occlusion removes DrawQuads that are not shown on screen. TEST_F(DisplayTest, CompositorFrameWithOverlapDrawQuad) { RendererSettings settings; - settings.kMinimumDrawOcclusionSize.set_width(0); SetUpGpuDisplay(settings); StubDisplayClient client; @@ -1456,197 +1452,9 @@ TearDownDisplay(); } -// Check if draw occlusion is not applied on DrawQuads that are smaller than -// skip_rect size, such that DrawQuads that are smaller than the |skip_rect| -// are drawn on the screen regardless is shown or not. -TEST_F(DisplayTest, DrawOcclusionWithSkipRect) { - SetUpGpuDisplay(RendererSettings()); - - StubDisplayClient client; - display_->Initialize(&client, manager_.surface_manager()); - - CompositorFrame frame = MakeDefaultCompositorFrame(); - gfx::Rect more_then_minimum_size( - RendererSettings().kMinimumDrawOcclusionSize); - more_then_minimum_size.set_width(more_then_minimum_size.width() + 1); - - gfx::Rect minimum_size(RendererSettings().kMinimumDrawOcclusionSize); - - gfx::Rect less_than_minimum_size( - RendererSettings().kMinimumDrawOcclusionSize); - less_than_minimum_size.set_width(more_then_minimum_size.width() - 1); - less_than_minimum_size.set_height(more_then_minimum_size.height() - 1); - - gfx::Rect rect(0, 0, 100, 100); - - bool is_clipped = false; - bool are_contents_opaque = true; - float opacity = 1.f; - SharedQuadState* shared_quad_state = - frame.render_pass_list.front()->CreateAndAppendSharedQuadState(); - auto* quad = frame.render_pass_list.front() - ->quad_list.AllocateAndConstruct<SolidColorDrawQuad>(); - SharedQuadState* shared_quad_state2 = - frame.render_pass_list.front()->CreateAndAppendSharedQuadState(); - auto* quad2 = frame.render_pass_list.front() - ->quad_list.AllocateAndConstruct<SolidColorDrawQuad>(); - // A small rect is hiding behind the bigger rect (|rect|), same picture for - // the following 3 tests. - // rects structure: show on screen: - // +----+---+ +--------+ - // | | | | | - // |----+ | | | - // | | | | - // +--------+ +--------+ - { - shared_quad_state->SetAll(gfx::Transform(), rect, rect, gfx::RRectF(), rect, - is_clipped, are_contents_opaque, opacity, - SkBlendMode::kSrcOver, 0); - shared_quad_state2->SetAll( - gfx::Transform(), more_then_minimum_size, more_then_minimum_size, - gfx::RRectF(), more_then_minimum_size, is_clipped, are_contents_opaque, - opacity, SkBlendMode::kSrcOver, 0); - quad->SetNew(shared_quad_state, rect, rect, SK_ColorBLACK, false); - quad2->SetNew(shared_quad_state2, more_then_minimum_size, - more_then_minimum_size, SK_ColorBLACK, false); - - EXPECT_EQ(2u, frame.render_pass_list.front()->quad_list.size()); - display_->RemoveOverdrawQuads(&frame); - - // |more_then_minimum_size| rect is not shown on screen. Since its size is - // slightly larger than the skip_rect size, draw occlusion is applied on - // |more_then_minimum_size| and it's removed from the compositor frame. - EXPECT_EQ(1u, frame.render_pass_list.front()->quad_list.size()); - EXPECT_EQ(rect.ToString(), frame.render_pass_list.front() - ->quad_list.ElementAt(0) - ->visible_rect.ToString()); - } - - { - shared_quad_state->SetAll(gfx::Transform(), rect, rect, gfx::RRectF(), rect, - is_clipped, are_contents_opaque, opacity, - SkBlendMode::kSrcOver, 0); - shared_quad_state2->SetAll(gfx::Transform(), minimum_size, minimum_size, - gfx::RRectF(), minimum_size, is_clipped, - are_contents_opaque, opacity, - SkBlendMode::kSrcOver, 0); - quad2 = frame.render_pass_list.front() - ->quad_list.AllocateAndConstruct<SolidColorDrawQuad>(); - quad->SetNew(shared_quad_state, rect, rect, SK_ColorBLACK, false); - quad2->SetNew(shared_quad_state2, minimum_size, minimum_size, SK_ColorBLACK, - false); - - EXPECT_EQ(2u, frame.render_pass_list.front()->quad_list.size()); - display_->RemoveOverdrawQuads(&frame); - - // |minimum_size| rect is not shown on screen. Since its size is the same - // as skip_rect size, draw occlusion is not applied on this rect. So it is - // not removed from compositor frame. - EXPECT_EQ(2u, frame.render_pass_list.front()->quad_list.size()); - EXPECT_EQ(rect.ToString(), frame.render_pass_list.front() - ->quad_list.ElementAt(0) - ->visible_rect.ToString()); - EXPECT_EQ(minimum_size.ToString(), frame.render_pass_list.front() - ->quad_list.ElementAt(1) - ->visible_rect.ToString()); - } - - { - shared_quad_state->SetAll(gfx::Transform(), rect, rect, gfx::RRectF(), rect, - is_clipped, are_contents_opaque, opacity, - SkBlendMode::kSrcOver, 0); - shared_quad_state2->SetAll( - gfx::Transform(), less_than_minimum_size, less_than_minimum_size, - gfx::RRectF(), less_than_minimum_size, is_clipped, are_contents_opaque, - opacity, SkBlendMode::kSrcOver, 0); - quad->SetNew(shared_quad_state, rect, rect, SK_ColorBLACK, false); - quad2->SetNew(shared_quad_state2, less_than_minimum_size, - less_than_minimum_size, SK_ColorBLACK, false); - - EXPECT_EQ(2u, frame.render_pass_list.front()->quad_list.size()); - display_->RemoveOverdrawQuads(&frame); - - // |less_than_minimum_size| rect is not shown on screen. Since its size is - // less than skip_rect size, draw occlusion is not applied on this rect. - // So it is not removed from compositor frame. - EXPECT_EQ(2u, frame.render_pass_list.front()->quad_list.size()); - EXPECT_EQ(rect.ToString(), frame.render_pass_list.front() - ->quad_list.ElementAt(0) - ->visible_rect.ToString()); - EXPECT_EQ(less_than_minimum_size.ToString(), frame.render_pass_list.front() - ->quad_list.ElementAt(1) - ->visible_rect.ToString()); - } - - TearDownDisplay(); -} - -// Check if draw occlusion is not applied on DrawQuads that are smaller than -// skip_rect size, such that DrawQuads that are smaller than the |skip_rect| -// cannot occlude other quads behind it. -TEST_F(DisplayTest, OcclusionIgnoringSkipRect) { - SetUpGpuDisplay(RendererSettings()); - - StubDisplayClient client; - display_->Initialize(&client, manager_.surface_manager()); - - CompositorFrame frame = MakeDefaultCompositorFrame(); - gfx::Rect rect1(0, 0, 50, 50); - gfx::Rect rect2(50, 0, 50, 50); - gfx::Rect rect3(0, 0, 50, 90); - - bool is_clipped = false; - bool are_contents_opaque = true; - float opacity = 1.f; - SharedQuadState* shared_quad_state = - frame.render_pass_list.front()->CreateAndAppendSharedQuadState(); - auto* quad = frame.render_pass_list.front() - ->quad_list.AllocateAndConstruct<SolidColorDrawQuad>(); - SharedQuadState* shared_quad_state2 = - frame.render_pass_list.front()->CreateAndAppendSharedQuadState(); - auto* quad2 = frame.render_pass_list.front() - ->quad_list.AllocateAndConstruct<SolidColorDrawQuad>(); - SharedQuadState* shared_quad_state3 = - frame.render_pass_list.front()->CreateAndAppendSharedQuadState(); - auto* quad3 = frame.render_pass_list.front() - ->quad_list.AllocateAndConstruct<SolidColorDrawQuad>(); - - shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(), - rect1, is_clipped, are_contents_opaque, opacity, - SkBlendMode::kSrcOver, 0); - shared_quad_state2->SetAll(gfx::Transform(), rect2, rect2, gfx::RRectF(), - rect2, is_clipped, are_contents_opaque, opacity, - SkBlendMode::kSrcOver, 0); - shared_quad_state3->SetAll(gfx::Transform(), rect3, rect3, gfx::RRectF(), - rect3, is_clipped, are_contents_opaque, opacity, - SkBlendMode::kSrcOver, 0); - quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false); - quad2->SetNew(shared_quad_state2, rect2, rect2, SK_ColorBLACK, false); - quad3->SetNew(shared_quad_state3, rect3, rect3, SK_ColorBLACK, false); - - EXPECT_EQ(3u, frame.render_pass_list.front()->quad_list.size()); - display_->RemoveOverdrawQuads(&frame); - - // |quad3| is not shown on screen because is hiding behind the occlusion rect - // formed by |quad1| and |quad2|. Since the |visible_rect| in both |quad1| - // and |quad2| are smaller than the skip rect, they cannot be used to occlude - // |quad3|. So no draw quad is removed in compositor frame by draw occlusion. - EXPECT_EQ(3u, frame.render_pass_list.front()->quad_list.size()); - EXPECT_EQ(rect1.ToString(), frame.render_pass_list.front() - ->quad_list.ElementAt(0) - ->visible_rect.ToString()); - EXPECT_EQ(rect2.ToString(), frame.render_pass_list.front() - ->quad_list.ElementAt(1) - ->visible_rect.ToString()); - EXPECT_EQ(rect3.ToString(), frame.render_pass_list.front() - ->quad_list.ElementAt(2) - ->visible_rect.ToString()); - TearDownDisplay(); -} // Check if draw occlusion works well with scale change transformer. TEST_F(DisplayTest, CompositorFrameWithTransformer) { RendererSettings settings; - settings.kMinimumDrawOcclusionSize.set_width(0); SetUpGpuDisplay(settings); StubDisplayClient client; @@ -2153,7 +1961,6 @@ // +-----+ +----+ reduced weight TEST_F(DisplayTest, CompositorFrameWithRotation) { RendererSettings settings; - settings.kMinimumDrawOcclusionSize.set_width(0); SetUpGpuDisplay(settings); StubDisplayClient client; @@ -2282,7 +2089,6 @@ // preserves 2d axis alignment. TEST_F(DisplayTest, CompositorFrameWithPerspective) { RendererSettings settings; - settings.kMinimumDrawOcclusionSize.set_width(0); SetUpGpuDisplay(settings); StubDisplayClient client; @@ -2358,7 +2164,6 @@ // Check if draw occlusion works with transparent DrawQuads. TEST_F(DisplayTest, CompositorFrameWithOpacityChange) { RendererSettings settings; - settings.kMinimumDrawOcclusionSize.set_width(0); SetUpGpuDisplay(settings); StubDisplayClient client; @@ -2425,7 +2230,6 @@ TEST_F(DisplayTest, CompositorFrameWithOpaquenessChange) { RendererSettings settings; - settings.kMinimumDrawOcclusionSize.set_width(0); SetUpGpuDisplay(settings); StubDisplayClient client; @@ -2493,7 +2297,6 @@ // Test if draw occlusion skips 3d objects. https://crbug.com/833748 TEST_F(DisplayTest, CompositorFrameZTranslate) { RendererSettings settings; - settings.kMinimumDrawOcclusionSize.set_width(0); SetUpGpuDisplay(settings); StubDisplayClient client; @@ -2548,7 +2351,6 @@ TEST_F(DisplayTest, CompositorFrameWithTranslateTransformer) { RendererSettings settings; - settings.kMinimumDrawOcclusionSize.set_width(0); SetUpGpuDisplay(settings); StubDisplayClient client; @@ -2669,7 +2471,6 @@ TEST_F(DisplayTest, CompositorFrameWithCombinedSharedQuadState) { RendererSettings settings; - settings.kMinimumDrawOcclusionSize.set_width(0); SetUpGpuDisplay(settings); StubDisplayClient client; @@ -2797,7 +2598,6 @@ TEST_F(DisplayTest, CompositorFrameWithMultipleRenderPass) { RendererSettings settings; - settings.kMinimumDrawOcclusionSize.set_width(0); SetUpGpuDisplay(settings); StubDisplayClient client; @@ -2942,7 +2742,6 @@ TEST_F(DisplayTest, CompositorFrameWithClip) { RendererSettings settings; - settings.kMinimumDrawOcclusionSize.set_width(0); SetUpGpuDisplay(settings); StubDisplayClient client; @@ -3059,7 +2858,6 @@ // Check if draw occlusion works with copy requests in root RenderPass only. TEST_F(DisplayTest, CompositorFrameWithCopyRequest) { RendererSettings settings; - settings.kMinimumDrawOcclusionSize.set_width(0); SetUpGpuDisplay(settings); StubDisplayClient client; @@ -3107,7 +2905,6 @@ TEST_F(DisplayTest, CompositorFrameWithRenderPass) { RendererSettings settings; - settings.kMinimumDrawOcclusionSize.set_width(0); SetUpGpuDisplay(settings); StubDisplayClient client; @@ -3287,7 +3084,6 @@ TEST_F(DisplayTest, CompositorFrameWithMultipleDrawQuadInSharedQuadState) { RendererSettings settings; - settings.kMinimumDrawOcclusionSize.set_width(0); SetUpGpuDisplay(settings); StubDisplayClient client; @@ -3465,7 +3261,6 @@ TEST_F(DisplayTest, CompositorFrameWithNonInvertibleTransform) { RendererSettings settings; - settings.kMinimumDrawOcclusionSize.set_width(0); SetUpGpuDisplay(settings); StubDisplayClient client;
diff --git a/components/viz/service/frame_sinks/video_capture/OWNERS b/components/viz/service/frame_sinks/video_capture/OWNERS index e837b5f..12fd84a 100644 --- a/components/viz/service/frame_sinks/video_capture/OWNERS +++ b/components/viz/service/frame_sinks/video_capture/OWNERS
@@ -1,3 +1,4 @@ miu@chromium.org +mfoltz@chromium.org # COMPONENT: Internals>Media>ScreenCapture
diff --git a/components/viz/service/main/BUILD.gn b/components/viz/service/main/BUILD.gn index 9fa3198..6e0b1a9 100644 --- a/components/viz/service/main/BUILD.gn +++ b/components/viz/service/main/BUILD.gn
@@ -33,6 +33,7 @@ "//services/metrics/public/cpp:metrics_cpp", "//services/metrics/public/mojom", "//services/service_manager/public/cpp", + "//services/tracing/public/cpp", "//services/viz/privileged/mojom", "//ui/gfx:memory_buffer", "//ui/gl/init",
diff --git a/components/viz/service/main/DEPS b/components/viz/service/main/DEPS index ace31d4..0075f301 100644 --- a/components/viz/service/main/DEPS +++ b/components/viz/service/main/DEPS
@@ -16,6 +16,7 @@ "+services/metrics/public", "+services/network/public/mojom", "+services/service_manager/public/cpp", + "+services/tracing/public/cpp", "+services/viz/privileged/mojom", ]
diff --git a/components/viz/service/main/viz_compositor_thread_runner_impl.cc b/components/viz/service/main/viz_compositor_thread_runner_impl.cc index 1d710a7..58a329b 100644 --- a/components/viz/service/main/viz_compositor_thread_runner_impl.cc +++ b/components/viz/service/main/viz_compositor_thread_runner_impl.cc
@@ -27,6 +27,7 @@ #include "gpu/ipc/command_buffer_task_executor.h" #include "gpu/ipc/scheduler_sequence.h" #include "gpu/ipc/service/gpu_memory_buffer_factory.h" +#include "services/tracing/public/cpp/stack_sampling/tracing_sampler_profiler.h" #include "ui/gfx/switches.h" #if BUILDFLAG(USE_VIZ_DEVTOOLS) @@ -74,6 +75,12 @@ #endif // !defined(OS_MACOSX) CHECK(thread->StartWithOptions(thread_options)); + + // Setup tracing sampler profiler as early as possible. + thread->task_runner()->PostTask( + FROM_HERE, + base::BindOnce(&tracing::TracingSamplerProfiler::CreateOnChildThread)); + return thread; #endif // !defined(OS_ANDROID) }
diff --git a/content/browser/accessibility/cross_platform_accessibility_browsertest.cc b/content/browser/accessibility/cross_platform_accessibility_browsertest.cc index 5867f144..454ad740 100644 --- a/content/browser/accessibility/cross_platform_accessibility_browsertest.cc +++ b/content/browser/accessibility/cross_platform_accessibility_browsertest.cc
@@ -1161,5 +1161,59 @@ EXPECT_EQ(text->GetId(), anchor_waiter.event_target_id()); } +IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest, + IFrameContentHadFocus_ThenRootDocumentGainedFocus) { + // Start by loading a document with iframes. + LoadInitialAccessibilityTreeFromHtmlFilePath( + "/accessibility/html/iframe-padding.html"); + WaitForAccessibilityTreeToContainNodeWithName(shell()->web_contents(), + "Second Button"); + + // Get the root BrowserAccessibilityManager and BrowserAccessibility node. + BrowserAccessibilityManager* root_accessibility_manager = GetManager(); + ASSERT_NE(nullptr, root_accessibility_manager); + BrowserAccessibility* root_browser_accessibility = + root_accessibility_manager->GetRoot(); + ASSERT_NE(nullptr, root_browser_accessibility); + ASSERT_EQ(ax::mojom::Role::kRootWebArea, + root_browser_accessibility->GetRole()); + + // Focus the button within the iframe. + { + BrowserAccessibility* leaf_iframe_browser_accessibility = + root_browser_accessibility->InternalDeepestLastChild(); + ASSERT_NE(nullptr, leaf_iframe_browser_accessibility); + ASSERT_EQ(ax::mojom::Role::kIframe, + leaf_iframe_browser_accessibility->GetRole()); + BrowserAccessibility* second_iframe_root_browser_accessibility = + leaf_iframe_browser_accessibility->PlatformGetChild(0); + ASSERT_NE(nullptr, second_iframe_root_browser_accessibility); + ASSERT_EQ(ax::mojom::Role::kRootWebArea, + second_iframe_root_browser_accessibility->GetRole()); + BrowserAccessibility* second_button = FindNodeByRole( + second_iframe_root_browser_accessibility, ax::mojom::Role::kButton); + ASSERT_NE(nullptr, second_button); + + AccessibilityNotificationWaiter waiter( + shell()->web_contents(), ui::kAXModeComplete, ax::mojom::Event::kFocus); + second_iframe_root_browser_accessibility->manager()->SetFocus( + *second_button); + waiter.WaitForNotification(); + ASSERT_EQ(second_button, root_accessibility_manager->GetFocus()); + } + + // Focusing the root Document should cause the iframe content to blur. + // The Document Element becomes implicitly focused when the focus is cleared, + // so there will not be a focus event. + { + AccessibilityNotificationWaiter waiter( + shell()->web_contents(), ui::kAXModeComplete, ax::mojom::Event::kBlur); + root_accessibility_manager->SetFocus(*root_browser_accessibility); + waiter.WaitForNotification(); + ASSERT_EQ(root_browser_accessibility, + root_accessibility_manager->GetFocus()); + } +} + #endif } // namespace content
diff --git a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc index 6094d85..a2866ad 100644 --- a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc +++ b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
@@ -2357,17 +2357,16 @@ } IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest, - DisplayLockingActivatableActivated) { - RunDisplayLockingTest(FILE_PATH_LITERAL("activatable-activated.html")); -} - -IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest, DisplayLockingNonActivatable) { RunDisplayLockingTest(FILE_PATH_LITERAL("non-activatable.html")); } -// crbug.com/1043480: disabled due to flakiness. -IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest, DISABLED_DisplayLockingAll) { +IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest, + DisplayLockingViewportActivation) { + RunDisplayLockingTest(FILE_PATH_LITERAL("viewport-activation.html")); +} + +IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest, DisplayLockingAll) { RunDisplayLockingTest(FILE_PATH_LITERAL("all.html")); }
diff --git a/content/browser/media/OWNERS b/content/browser/media/OWNERS index b0460a9..67e2794 100644 --- a/content/browser/media/OWNERS +++ b/content/browser/media/OWNERS
@@ -1,6 +1,7 @@ file://media/OWNERS olka@chromium.org miu@chromium.org +mfoltz@chromium.org per-file media_devices_*=guidou@chromium.org per-file midi_*=toyoshim@chromium.org
diff --git a/content/browser/media/capture/OWNERS b/content/browser/media/capture/OWNERS index e909a05..8275bb0 100644 --- a/content/browser/media/capture/OWNERS +++ b/content/browser/media/capture/OWNERS
@@ -1,4 +1,5 @@ miu@chromium.org +mfoltz@chromium.org sergeyu@chromium.org wez@chromium.org
diff --git a/content/browser/payments/payment_app_provider_impl.cc b/content/browser/payments/payment_app_provider_impl.cc index 02678e3..3b9a9bfc 100644 --- a/content/browser/payments/payment_app_provider_impl.cc +++ b/content/browser/payments/payment_app_provider_impl.cc
@@ -984,6 +984,12 @@ return true; } +ukm::SourceId PaymentAppProviderImpl::GetSourceIdForPaymentAppFromScope( + const GURL& sw_scope) { + return ukm::UkmRecorder::GetSourceIdForPaymentAppFromScope( + sw_scope.GetOrigin()); +} + PaymentAppProviderImpl::PaymentAppProviderImpl() = default; PaymentAppProviderImpl::~PaymentAppProviderImpl() = default;
diff --git a/content/browser/payments/payment_app_provider_impl.h b/content/browser/payments/payment_app_provider_impl.h index b6d2a44..d1db238 100644 --- a/content/browser/payments/payment_app_provider_impl.h +++ b/content/browser/payments/payment_app_provider_impl.h
@@ -62,6 +62,8 @@ const GURL& sw_js_url, const GURL& sw_scope, std::string* error_message) override; + ukm::SourceId GetSourceIdForPaymentAppFromScope( + const GURL& sw_scope) override; private: PaymentAppProviderImpl();
diff --git a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc index ae198a21..b02b9ed 100644 --- a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc +++ b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
@@ -77,7 +77,6 @@ #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/aura/client/aura_constants.h" -#include "ui/aura/client/screen_position_client.h" #include "ui/aura/client/window_parenting_client.h" #include "ui/aura/env.h" #include "ui/aura/layout_manager.h" @@ -1001,11 +1000,9 @@ // Checks that a popup is positioned correctly relative to its parent using // screen coordinates. TEST_F(RenderWidgetHostViewAuraTest, PositionChildPopup) { - wm::DefaultScreenPositionClient screen_position_client; - aura::Window* window = parent_view_->GetNativeView(); - aura::Window* root = window->GetRootWindow(); - aura::client::SetScreenPositionClient(root, &screen_position_client); + wm::DefaultScreenPositionClient screen_position_client( + window->GetRootWindow()); parent_view_->SetBounds(gfx::Rect(10, 10, 800, 600)); gfx::Rect bounds_in_screen = parent_view_->GetViewBounds(); @@ -1033,8 +1030,6 @@ view_->SetSize(gfx::Size(120, 120)); gfx::Point new_origin = window->bounds().origin(); EXPECT_EQ(original_origin.ToString(), new_origin.ToString()); - - aura::client::SetScreenPositionClient(root, nullptr); } // Checks that moving parent sends new screen bounds. @@ -4843,8 +4838,7 @@ view_->GetNativeView(), parent_view_->GetNativeView()->GetRootWindow(), gfx::Rect()); aura::Window* root_window = parent_view_->GetNativeView()->GetRootWindow(); - wm::DefaultScreenPositionClient screen_position_client; - aura::client::SetScreenPositionClient(root_window, &screen_position_client); + wm::DefaultScreenPositionClient screen_position_client(root_window); const gfx::Rect orig_view_bounds = gfx::Rect(0, 300, 400, 200); const gfx::Rect shifted_view_bounds = gfx::Rect(0, 200, 400, 200); @@ -4872,8 +4866,6 @@ // Window should be restored. EXPECT_EQ(view_->GetNativeView()->bounds(), orig_view_bounds); - - aura::client::SetScreenPositionClient(root_window, nullptr); } #endif // defined(OS_CHROMEOS)
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc index 5be521e..f0ae355b 100644 --- a/content/browser/site_per_process_browsertest.cc +++ b/content/browser/site_per_process_browsertest.cc
@@ -2017,8 +2017,16 @@ DISALLOW_COPY_AND_ASSIGN(ScrollObserver); }; +// crbug.com/825629 +#if defined(OS_ANDROID) +#define MAYBE_ScrollBubblingFromNestedOOPIFTest \ + DISABLED_ScrollBubblingFromNestedOOPIFTest +#else +#define MAYBE_ScrollBubblingFromNestedOOPIFTest \ + ScrollBubblingFromNestedOOPIFTest +#endif IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, - ScrollBubblingFromNestedOOPIFTest) { + MAYBE_ScrollBubblingFromNestedOOPIFTest) { ui::GestureConfiguration::GetInstance()->set_scroll_debounce_interval_in_ms( 0); GURL main_url(embedded_test_server()->GetURL(
diff --git a/content/browser/webauth/authenticator_common.cc b/content/browser/webauth/authenticator_common.cc index 27587d8..5b791c0 100644 --- a/content/browser/webauth/authenticator_common.cc +++ b/content/browser/webauth/authenticator_common.cc
@@ -9,10 +9,8 @@ #include <utility> #include <vector> -#include "base/base64url.h" #include "base/bind.h" #include "base/command_line.h" -#include "base/json/json_writer.h" #include "base/logging.h" #include "base/metrics/histogram_macros.h" #include "base/rand_util.h" @@ -319,6 +317,10 @@ auto common_info = blink::mojom::CommonCredentialInfo::New(); common_info->client_data_json.assign(client_data_json.begin(), client_data_json.end()); + if (response_data.android_client_data_ext()) { + DCHECK(base::FeatureList::IsEnabled(device::kWebAuthPhoneSupport)); + common_info->client_data_json = *response_data.android_client_data_ext(); + } common_info->raw_id = response_data.raw_credential_id(); common_info->id = response_data.GetId(); response->info = std::move(common_info); @@ -381,6 +383,10 @@ auto common_info = blink::mojom::CommonCredentialInfo::New(); common_info->client_data_json.assign(client_data_json.begin(), client_data_json.end()); + if (response_data.android_client_data_ext()) { + DCHECK(base::FeatureList::IsEnabled(device::kWebAuthPhoneSupport)); + common_info->client_data_json = *response_data.android_client_data_ext(); + } common_info->raw_id = response_data.raw_credential_id(); common_info->id = response_data.GetId(); response->info = std::move(common_info); @@ -397,56 +403,6 @@ return response; } -std::string Base64UrlEncode(const base::span<const uint8_t> input) { - std::string ret; - base::Base64UrlEncode( - base::StringPiece(reinterpret_cast<const char*>(input.data()), - input.size()), - base::Base64UrlEncodePolicy::OMIT_PADDING, &ret); - return ret; -} - -// ToJSONString encodes |in| as a JSON string, using the specific escaping rules -// required by https://github.com/w3c/webauthn/pull/1375. -std::string ToJSONString(const std::string& in) { - std::string ret; - ret.reserve(in.size() + 2); - ret.push_back('"'); - - const char* const in_bytes = in.data(); - // ICU uses |int32_t| for lengths. - const int32_t length = base::checked_cast<int32_t>(in.size()); - int32_t offset = 0; - - while (offset < length) { - const int32_t prior_offset = offset; - // Input strings must be valid UTF-8. - uint32_t codepoint; - CHECK(base::ReadUnicodeCharacter(in_bytes, length, &offset, &codepoint)); - // offset is updated by |ReadUnicodeCharacter| to index the last byte of the - // codepoint. Increment it to index the first byte of the next codepoint for - // the subsequent iteration. - offset++; - - if (codepoint == 0x20 || codepoint == 0x21 || - (codepoint >= 0x23 && codepoint <= 0x5b) || codepoint >= 0x5d) { - ret.append(&in_bytes[prior_offset], &in_bytes[offset]); - } else if (codepoint == 0x22) { - ret.append("\\\""); - } else if (codepoint == 0x5c) { - ret.append("\\\\"); - } else { - static const char hextable[17] = "0123456789abcdef"; - ret.append("\\u00"); - ret.push_back(hextable[codepoint >> 4]); - ret.push_back(hextable[codepoint & 15]); - } - } - - ret.push_back('"'); - return ret; -} - bool IsUserVerifyingPlatformAuthenticatorAvailableImpl( AuthenticatorRequestClientDelegate* delegate, device::FidoDiscoveryFactory* discovery_factory, @@ -706,49 +662,6 @@ } // static -std::string AuthenticatorCommon::SerializeCollectedClientDataToJson( - const std::string& type, - const std::string& origin, - base::span<const uint8_t> challenge, - bool is_cross_origin, - bool use_legacy_u2f_type_key /* = false */) { - std::string ret; - ret.reserve(128); - - if (use_legacy_u2f_type_key) { - ret.append(R"({"typ":)"); - } else { - ret.append(R"({"type":)"); - } - ret.append(ToJSONString(type)); - - ret.append(R"(,"challenge":)"); - ret.append(ToJSONString(Base64UrlEncode(challenge))); - - ret.append(R"(,"origin":)"); - ret.append(ToJSONString(origin)); - - if (is_cross_origin) { - ret.append(R"(,"crossOrigin":true)"); - } else { - ret.append(R"(,"crossOrigin":false)"); - } - - if (base::RandDouble() < 0.2) { - // An extra key is sometimes added to ensure that RPs do not make - // unreasonably specific assumptions about the clientData JSON. This is - // done in the fashion of - // https://tools.ietf.org/html/draft-ietf-tls-grease - ret.append(R"(,"extra_keys_may_be_added_here":")"); - ret.append( - "do not compare clientDataJSON against a template. See " - "https://goo.gl/yabPex\""); - } - - ret.append("}"); - return ret; -} - // mojom::Authenticator void AuthenticatorCommon::MakeCredential( url::Origin caller_origin, @@ -903,23 +816,17 @@ WebAuthRequestSecurityChecker::OriginIsCryptoTokenExtension( caller_origin_); - // Save client data to return with the authenticator response. - // TODO(kpaulhamus): Fetch and add the Channel ID/Token Binding ID public key - // used to communicate with the origin. - if (origin_is_crypto_token_extension) { - // As Cryptotoken validates the origin, accept the relying party id as the - // origin from requests originating from Cryptotoken. The origin is provided - // in Cryptotoken requests as the relying party name, which should be used - // as part of client data. - client_data_json_ = SerializeCollectedClientDataToJson( - client_data::kU2fRegisterType, *options->relying_party.name, - std::move(options->challenge), /*is_cross_origin=*/false, - /*use_legacy_u2f_type_key=*/true); - } else { - client_data_json_ = SerializeCollectedClientDataToJson( - client_data::kCreateType, caller_origin_.Serialize(), - std::move(options->challenge), is_cross_origin); - } + // Cryptotoken provides the sender origin for register requests in the + // |relying_party| |name| attribute. (The |id| attribute contains the AppID.) + client_data_json_ = + origin_is_crypto_token_extension + ? device::SerializeCollectedClientDataToJson( + client_data::kU2fRegisterType, *options->relying_party.name, + options->challenge, /*is_cross_origin=*/false, + /*use_legacy_u2f_type_key=*/true) + : device::SerializeCollectedClientDataToJson( + client_data::kCreateType, caller_origin_.Serialize(), + options->challenge, is_cross_origin); // Cryptotoken requests should be proxied without UI. if (origin_is_crypto_token_extension || disable_ui_) @@ -940,6 +847,18 @@ // On dual protocol CTAP2/U2F devices, force credential creation over U2F. ctap_make_credential_request_->is_u2f_only = origin_is_crypto_token_extension; + if (base::FeatureList::IsEnabled(device::kWebAuthPhoneSupport) && + !origin_is_crypto_token_extension && !is_cross_origin) { + // Send the unhashed origin and challenge to caBLEv2 authenticators, because + // the Android API requires them. It does not accept clientDataJSON or its + // hash. + // NOTE: Because Android has no way of building a clientDataJSON for + // cross-origin requests, we don't create the extension for those. This + // problem will go away once we add clientDataHash inputs to Android. + ctap_make_credential_request_->android_client_data_ext.emplace( + client_data::kCreateType, caller_origin_, options->challenge); + } + // Compute the effective attestation conveyance preference and set // |attestation_requested_| for showing the attestation consent prompt later. ::device::AttestationConveyancePreference attestation = options->attestation; @@ -1035,19 +954,17 @@ WebAuthRequestSecurityChecker::OriginIsCryptoTokenExtension( caller_origin_); - // Save client data to return with the authenticator response. - if (origin_is_crypto_token_extension) { - // As Cryptotoken validates the origin, accept the relying party id as the - // origin from requests originating from Cryptotoken. - client_data_json_ = SerializeCollectedClientDataToJson( - client_data::kU2fSignType, options->relying_party_id, - std::move(options->challenge), /*is_cross_origin=*/false, - /*use_legacy_u2f_type_key=*/true); - } else { - client_data_json_ = SerializeCollectedClientDataToJson( - client_data::kGetType, caller_origin_.Serialize(), - std::move(options->challenge), is_cross_origin); - } + // Cryptotoken provides the sender origin for U2F sign requests in the + // |relying_party_id| attribute. + client_data_json_ = + origin_is_crypto_token_extension + ? device::SerializeCollectedClientDataToJson( + client_data::kU2fSignType, options->relying_party_id, + options->challenge, /*is_cross_origin=*/false, + /*use_legacy_u2f_type_key=*/true) + : device::SerializeCollectedClientDataToJson( + client_data::kGetType, caller_origin_.Serialize(), + options->challenge, is_cross_origin); // Cryptotoken requests should be proxied without UI. if (origin_is_crypto_token_extension || disable_ui_) @@ -1087,6 +1004,17 @@ client_data_json_, std::move(options), app_id_, browser_context()->IsOffTheRecord()); ctap_get_assertion_request_->is_u2f_only = origin_is_crypto_token_extension; + if (base::FeatureList::IsEnabled(device::kWebAuthPhoneSupport) && + !origin_is_crypto_token_extension && !is_cross_origin) { + // Send the unhashed origin and challenge to caBLEv2 authenticators, because + // the Android API requires them. It does not accept clientDataJSON or its + // hash. + // NOTE: Because Android has no way of building a clientDataJSON for + // cross-origin requests, we don't create the extension for those. This + // problem will go away once we add clientDataHash inputs to Android. + ctap_get_assertion_request_->android_client_data_ext.emplace( + client_data::kGetType, caller_origin_, options->challenge); + } StartGetAssertionRequest(/*allow_skipping_pin_touch=*/true); } @@ -1273,7 +1201,7 @@ InvokeCallbackAndCleanup( std::move(make_credential_response_callback_), blink::mojom::AuthenticatorStatus::SUCCESS, - CreateMakeCredentialResponse(std::move(client_data_json_), + CreateMakeCredentialResponse(client_data_json_, std::move(*response_data), *attestation_erasure), Focus::kDoCheck); @@ -1337,12 +1265,12 @@ attestation_erasure = AttestationErasureOption::kEraseAttestationAndAaguid; } - InvokeCallbackAndCleanup(std::move(make_credential_response_callback_), - blink::mojom::AuthenticatorStatus::SUCCESS, - CreateMakeCredentialResponse( - std::move(client_data_json_), - std::move(response_data), attestation_erasure), - Focus::kDoCheck); + InvokeCallbackAndCleanup( + std::move(make_credential_response_callback_), + blink::mojom::AuthenticatorStatus::SUCCESS, + CreateMakeCredentialResponse(client_data_json_, std::move(response_data), + attestation_erasure), + Focus::kDoCheck); } void AuthenticatorCommon::OnSignResponse( @@ -1462,8 +1390,8 @@ InvokeCallbackAndCleanup( std::move(get_assertion_response_callback_), blink::mojom::AuthenticatorStatus::SUCCESS, - CreateGetAssertionResponse(std::move(client_data_json_), - std::move(response), echo_appid_extension)); + CreateGetAssertionResponse(client_data_json_, std::move(response), + echo_appid_extension)); return; }
diff --git a/content/browser/webauth/authenticator_common.h b/content/browser/webauth/authenticator_common.h index 2ef69eb..c6f9c05 100644 --- a/content/browser/webauth/authenticator_common.h +++ b/content/browser/webauth/authenticator_common.h
@@ -22,6 +22,7 @@ #include "device/fido/authenticator_get_assertion_response.h" #include "device/fido/authenticator_make_credential_response.h" #include "device/fido/authenticator_selection_criteria.h" +#include "device/fido/client_data.h" #include "device/fido/ctap_get_assertion_request.h" #include "device/fido/ctap_make_credential_request.h" #include "device/fido/fido_constants.h" @@ -114,20 +115,6 @@ bool IsFocused() const; - // Builds the CollectedClientData[1] dictionary with the given values, - // serializes it to JSON, and returns the resulting string. For legacy U2F - // requests coming from the CryptoToken U2F extension, modifies the object key - // 'type' as required[2]. - // [1] https://w3c.github.io/webauthn/#dictdef-collectedclientdata - // [2] - // https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-raw-message-formats-v1.2-ps-20170411.html#client-data - static std::string SerializeCollectedClientDataToJson( - const std::string& type, - const std::string& origin, - base::span<const uint8_t> challenge, - bool is_cross_origin, - bool use_legacy_u2f_type_key = false); - // Callback to handle the async response from a U2fDevice. void OnRegisterResponse( device::MakeCredentialStatus status_code,
diff --git a/content/browser/webauth/authenticator_impl_unittest.cc b/content/browser/webauth/authenticator_impl_unittest.cc index 80977e7..1f201ecf 100644 --- a/content/browser/webauth/authenticator_impl_unittest.cc +++ b/content/browser/webauth/authenticator_impl_unittest.cc
@@ -466,7 +466,7 @@ } std::string GetTestClientDataJSON(std::string type) { - return AuthenticatorCommon::SerializeCollectedClientDataToJson( + return device::SerializeCollectedClientDataToJson( std::move(type), GetTestOrigin().Serialize(), GetTestChallengeBytes(), /*is_cross_origin*/ false); } @@ -475,8 +475,8 @@ const std::string& origin, base::span<const uint8_t> challenge, bool is_cross_origin) { - return AuthenticatorCommon::SerializeCollectedClientDataToJson( - type, origin, challenge, is_cross_origin); + return device::SerializeCollectedClientDataToJson(type, origin, challenge, + is_cross_origin); } AuthenticatorStatus TryAuthenticationWithAppId(const std::string& origin,
diff --git a/content/common/content_navigation_policy.cc b/content/common/content_navigation_policy.cc index da00bec..aa1f35b 100644 --- a/content/common/content_navigation_policy.cc +++ b/content/common/content_navigation_policy.cc
@@ -88,12 +88,7 @@ } std::string GetRenderDocumentLevelName(RenderDocumentLevel level) { - for (size_t i = 0; i < render_document_level.option_count; ++i) { - if (level == render_document_level.options[i].value) - return render_document_level.options[i].name; - } - NOTREACHED(); - return ""; + return render_document_level.GetName(level); } bool CreateNewHostForSameSiteSubframe() {
diff --git a/content/public/browser/payment_app_provider.h b/content/public/browser/payment_app_provider.h index 140ccc587..ef29f48 100644 --- a/content/public/browser/payment_app_provider.h +++ b/content/public/browser/payment_app_provider.h
@@ -13,6 +13,7 @@ #include "base/callback_forward.h" #include "content/common/content_export.h" #include "content/public/browser/stored_payment_app.h" +#include "services/metrics/public/cpp/ukm_recorder.h" #include "third_party/blink/public/mojom/payments/payment_app.mojom.h" class SkBitmap; @@ -103,6 +104,11 @@ const GURL& sw_scope, std::string* error_message) = 0; + // Gets the ukm source id for a payment app with |sw_scope|. + // This must ONLY be called when payment app window has been opened. + virtual ukm::SourceId GetSourceIdForPaymentAppFromScope( + const GURL& sw_scope) = 0; + protected: virtual ~PaymentAppProvider() = default; };
diff --git a/content/public/renderer/render_frame_observer.h b/content/public/renderer/render_frame_observer.h index 156ba73..172b2a2 100644 --- a/content/public/renderer/render_frame_observer.h +++ b/content/public/renderer/render_frame_observer.h
@@ -152,6 +152,9 @@ // Notifications when |PerformanceTiming| data becomes available virtual void DidChangePerformanceTiming() {} + // Notifications When an input delay data becomes available. + virtual void DidObserveInputDelay(base::TimeDelta input_delay) {} + // Notifications when a cpu timing update becomes available, when a frame // has performed at least 100ms of tasks. virtual void DidChangeCpuTiming(base::TimeDelta time) {}
diff --git a/content/renderer/media/OWNERS b/content/renderer/media/OWNERS index cefa19db..43747118 100644 --- a/content/renderer/media/OWNERS +++ b/content/renderer/media/OWNERS
@@ -1,5 +1,6 @@ file://media/OWNERS miu@chromium.org +mfoltz@chromium.org # WebRTC OWNERS. hbos@chromium.org
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc index e964089..1d37c33 100644 --- a/content/renderer/render_frame_impl.cc +++ b/content/renderer/render_frame_impl.cc
@@ -4867,6 +4867,11 @@ observer.DidChangePerformanceTiming(); } +void RenderFrameImpl::DidObserveInputDelay(base::TimeDelta input_delay) { + for (auto& observer : observers_) { + observer.DidObserveInputDelay(input_delay); + } +} void RenderFrameImpl::DidChangeCpuTiming(base::TimeDelta time) { for (auto& observer : observers_) observer.DidChangeCpuTiming(time);
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h index ac3e90f..3b58f29d 100644 --- a/content/renderer/render_frame_impl.h +++ b/content/renderer/render_frame_impl.h
@@ -735,6 +735,7 @@ void DidDisplayContentWithCertificateErrors() override; void DidRunContentWithCertificateErrors() override; void DidChangePerformanceTiming() override; + void DidObserveInputDelay(base::TimeDelta input_delay) override; void DidChangeCpuTiming(base::TimeDelta time) override; void DidObserveLoadingBehavior(blink::LoadingBehaviorFlag behavior) override; void DidObserveNewFeatureUsage(blink::mojom::WebFeature feature) override;
diff --git a/content/renderer/render_frame_impl_browsertest.cc b/content/renderer/render_frame_impl_browsertest.cc index 01fa265..0e5dc9fb9 100644 --- a/content/renderer/render_frame_impl_browsertest.cc +++ b/content/renderer/render_frame_impl_browsertest.cc
@@ -526,8 +526,6 @@ gfx::Point viewport_offset(7, -11); blink::WebRect viewport_intersection(0, 11, 200, 89); - // TODO(crbug/1062006): Change to viewport_offset when blink-side changes are - // relanded with the chromeos-thinlto fix. blink::WebRect mainframe_intersection(0, 0, 200, 140); blink::FrameOcclusionState occlusion_state = blink::FrameOcclusionState::kUnknown; @@ -537,7 +535,8 @@ frame_widget()->OnMessageReceived(set_viewport_intersection_message); // Setting a new frame intersection in a local frame triggers the render frame // observer call. - EXPECT_EQ(observer.last_intersection_rect(), blink::WebRect(0, 0, 200, 140)); + EXPECT_EQ(observer.last_intersection_rect(), + blink::WebRect(7, -11, 200, 140)); } // Used to annotate the source of an interface request.
diff --git a/content/shell/browser/shell_platform_data_aura.cc b/content/shell/browser/shell_platform_data_aura.cc index 71e741c5..9f1d6fa 100644 --- a/content/shell/browser/shell_platform_data_aura.cc +++ b/content/shell/browser/shell_platform_data_aura.cc
@@ -108,8 +108,7 @@ host_->window()->Show(); host_->window()->SetLayoutManager(new FillLayout(host_->window())); - focus_client_.reset(new aura::test::TestFocusClient()); - aura::client::SetFocusClient(host_->window(), focus_client_.get()); + focus_client_.reset(new aura::test::TestFocusClient(host_->window())); new wm::DefaultActivationClient(host_->window()); capture_client_.reset(
diff --git a/content/test/data/accessibility/display-locking/activatable-activated-expected-blink.txt b/content/test/data/accessibility/display-locking/activatable-activated-expected-blink.txt deleted file mode 100644 index 688ea53..0000000 --- a/content/test/data/accessibility/display-locking/activatable-activated-expected-blink.txt +++ /dev/null
@@ -1,11 +0,0 @@ -rootWebArea -++genericContainer ignored -++++genericContainer name='Done' -++++++genericContainer -++++++++genericContainer -++++++++++staticText name='child' -++++++++++++inlineTextBox name='child' -++++++++genericContainer -++++++++++staticText name='nested locked element!' -++++++++++++inlineTextBox name='nested locked element!' -++++++++genericContainer
diff --git a/content/test/data/accessibility/display-locking/activatable-activated.html b/content/test/data/accessibility/display-locking/activatable-activated.html deleted file mode 100644 index 48180f6c..0000000 --- a/content/test/data/accessibility/display-locking/activatable-activated.html +++ /dev/null
@@ -1,25 +0,0 @@ -<!-- -@BLINK-ALLOW:offscreen -@WAIT-FOR:Done ---> -<div id=target aria-label="Working"> - <div id="locked" style="subtree-visibility: auto"> - <div>child</div> - <div id="nested" style="subtree-visibility: auto">nested locked element!</div> - <div id="nonActivatable" style="subtree-visibility: hidden">nested non activatable locked element</div> - </div> -</div> - -<script> -async function runTest() { - // Force layout, then activate. - locked.getBoundingClientRect(); - locked.scrollIntoView(); - // Double-rAF to ensure that both the outer and nested elements have enough - // time to process intersection observations. - requestAnimationFrame( - () => requestAnimationFrame( - () => target.setAttribute("aria-label", "Done"))); -} -onload = () => requestAnimationFrame(runTest); -</script>
diff --git a/content/test/data/accessibility/display-locking/activatable.html b/content/test/data/accessibility/display-locking/activatable.html index 0690f93..f49d116 100644 --- a/content/test/data/accessibility/display-locking/activatable.html +++ b/content/test/data/accessibility/display-locking/activatable.html
@@ -2,9 +2,9 @@ @BLINK-ALLOW:offscreen --> <div> - <div id="locked" style="subtree-visibility: hidden-matchable"> + <div id="locked" style="subtree-visibility: auto"> <div>child</div> - <div id="nested" style="subtree-visibility: hidden-matchable">nested locked element!</div> + <div id="nested" style="subtree-visibility: auto">nested locked element!</div> <div id="nonActivatable" style="subtree-visibility: hidden">nested non activatable locked element</div> </div> </div>
diff --git a/content/test/data/accessibility/display-locking/all-committed-expected-blink.txt b/content/test/data/accessibility/display-locking/all-committed-expected-blink.txt index 2db604e..851b7d1c 100644 --- a/content/test/data/accessibility/display-locking/all-committed-expected-blink.txt +++ b/content/test/data/accessibility/display-locking/all-committed-expected-blink.txt
@@ -2,19 +2,24 @@ ++genericContainer ignored ++++genericContainer ignored ++++++genericContainer -++++++++genericContainer -++++++++++staticText name='child' -++++++++++++inlineTextBox name='child' -++++++++genericContainer -++++++++++staticText name='nested locked element!' -++++++++++++inlineTextBox name='nested locked element!' -++++++++genericContainer -++++++++++staticText name='nested non activatable locked element' -++++++++++++inlineTextBox name='nested non activatable locked element' -++++++++presentational ignored -++++++++++listItem ignored -++++++++++++staticText name='role=presentation item' -++++++++++++++inlineTextBox name='role=presentation item' -++++++++genericContainer ignored invisible name='visibility:hidden text' -++++++++genericContainer ignored invisible -++++++++++staticText ignored invisible name='aria-hidden text' +++++++++staticText name='spacer so that everything below will be offscreen (and won't get viewport-activated)' +++++++++++inlineTextBox name='spacer so that everything below will be offscreen (and won't get viewport-activated)' +++++++genericContainer offscreen +++++++++genericContainer offscreen +++++++++++staticText offscreen name='child text will be in AX tree but without layout' +++++++++++++inlineTextBox offscreen name='child text will be in AX tree but without layout' +++++++++genericContainer offscreen +++++++++++staticText offscreen name='nested activatable locked element will be in AX tree but without layout' +++++++++++++inlineTextBox offscreen name='nested activatable locked element will be in AX tree but without layout' +++++++staticText offscreen name='normal text 1' +++++++++inlineTextBox offscreen name='normal text 1' +++++++genericContainer offscreen +++++++++staticText offscreen name='nested non-viewport-activatable locked element will not be in AX tree' +++++++++++inlineTextBox offscreen name='nested non-viewport-activatable locked element will not be in AX tree' +++++++staticText offscreen name='normal text 2' +++++++++inlineTextBox offscreen name='normal text 2' +++++++genericContainer offscreen +++++++++staticText offscreen name='nested non-activatable locked element will not be in AX tree' +++++++++++inlineTextBox offscreen name='nested non-activatable locked element will not be in AX tree' +++++++staticText offscreen name='normal text 3' +++++++++inlineTextBox offscreen name='normal text 3'
diff --git a/content/test/data/accessibility/display-locking/all-committed.html b/content/test/data/accessibility/display-locking/all-committed.html index 6fce397..85d6337 100644 --- a/content/test/data/accessibility/display-locking/all-committed.html +++ b/content/test/data/accessibility/display-locking/all-committed.html
@@ -2,26 +2,28 @@ @BLINK-ALLOW:offscreen --> <div> - <div id="locked" style="subtree-visibility: hidden-matchable"> - <div>child</div> - <div id="nested" style="subtree-visibility: hidden-matchable">nested locked element!</div> - <div id="nonActivatable" style="subtree-visibility: hidden">nested non activatable locked element</div> - <!-- - TODO(rakina): Make display:none, visibility:hidden, aria-hidden nodes - in locked subtrees get ignored for accessibility/marked invisible. - --> - <div style="display:none;">display:none text</div> - <ul role="presentation"> - <li>role=presentation item</li> - </ul> - <div style="visibility:hidden;">visibility:hidden text</div> - <div aria-hidden="true">aria-hidden text</div> + <div style="height:10000px;">spacer so that everything below will be offscreen (and won't get viewport-activated)</div> + <div id="locked" style="subtree-visibility: auto"> + <div>child text will be in AX tree but without layout</div> + <div id="nested" style="subtree-visibility: auto"> + nested activatable locked element will be in AX tree but without layout + </div> </div> + normal text 1 + <div id="nonViewportActivatable" style="subtree-visibility: hidden-matchable"> + nested non-viewport-activatable locked element will not be in AX tree + </div> + normal text 2 + <div id="nonActivatable" style="subtree-visibility: hidden"> + nested non-activatable locked element will not be in AX tree + </div> + normal text 3 </div> <script> // Force layout, then commit everything. locked.removeAttribute("style"); nested.removeAttribute("style"); + nonViewportActivatable.removeAttribute("style"); nonActivatable.removeAttribute("style"); </script>
diff --git a/content/test/data/accessibility/display-locking/all-expected-blink.txt b/content/test/data/accessibility/display-locking/all-expected-blink.txt index 001cff1..81766c8 100644 --- a/content/test/data/accessibility/display-locking/all-expected-blink.txt +++ b/content/test/data/accessibility/display-locking/all-expected-blink.txt
@@ -2,27 +2,22 @@ ++genericContainer ignored ++++genericContainer ignored ++++++genericContainer -++++++++staticText name='<newline> ' -++++++++genericContainer -++++++++++staticText name='child' -++++++++staticText name='<newline> ' -++++++++genericContainer -++++++++++staticText name='nested locked element!' -++++++++staticText name='<newline> ' -++++++++genericContainer -++++++++staticText name='<newline> ' -++++++++staticText name='<newline> ' -++++++++genericContainer invisible -++++++++++staticText name='display:none text' -++++++++staticText name='<newline> ' -++++++++staticText name='<newline> ' -++++++++genericContainer -++++++++++staticText name='role=presentation item' -++++++++staticText name='<newline> ' -++++++++staticText name='<newline> ' -++++++++genericContainer invisible -++++++++++staticText name='visibility:hidden text' -++++++++staticText name='<newline> ' -++++++++genericContainer invisible -++++++++++staticText invisible name='aria-hidden text' -++++++++staticText name='<newline> ' +++++++++staticText name='spacer so that everything below will be offscreen (and won't get viewport-activated)' +++++++++++inlineTextBox name='spacer so that everything below will be offscreen (and won't get viewport-activated)' +++++++genericContainer offscreen +++++++++staticText offscreen name='<newline> ' +++++++++genericContainer offscreen +++++++++++staticText offscreen name='child text will be in AX tree but without layout' +++++++++staticText offscreen name='<newline> ' +++++++++genericContainer offscreen +++++++++++staticText offscreen name='<newline> nested activatable locked element will be in AX tree but without layout<newline> ' +++++++++staticText offscreen name='<newline> ' +++++++staticText offscreen name='normal text 1' +++++++++inlineTextBox offscreen name='normal text 1' +++++++genericContainer offscreen +++++++staticText offscreen name='normal text 2' +++++++++inlineTextBox offscreen name='normal text 2' +++++++genericContainer offscreen +++++++staticText offscreen name='normal text 3' +++++++++inlineTextBox offscreen name='normal text 3' +
diff --git a/content/test/data/accessibility/display-locking/all.html b/content/test/data/accessibility/display-locking/all.html index ff6d166..1bc37cc 100644 --- a/content/test/data/accessibility/display-locking/all.html +++ b/content/test/data/accessibility/display-locking/all.html
@@ -2,19 +2,20 @@ @BLINK-ALLOW:offscreen --> <div> - <div id="locked" style="subtree-visibility: hidden-matchable"> - <div>child</div> - <div id="nested" style="subtree-visibility: hidden-matchable">nested locked element!</div> - <div id="nonActivatable" style="subtree-visibility: hidden">nested non activatable locked element</div> - <!-- - TODO(rakina): Make display:none, visibility:hidden, aria-hidden nodes - in locked subtrees get ignored for accessibility/marked invisible. - --> - <div style="display:none;">display:none text</div> - <ul role="presentation"> - <li>role=presentation item</li> - </ul> - <div style="visibility:hidden;">visibility:hidden text</div> - <div aria-hidden="true">aria-hidden text</div> + <div style="height:10000px;">spacer so that everything below will be offscreen (and won't get viewport-activated)</div> + <div id="locked" style="subtree-visibility: auto"> + <div>child text will be in AX tree but without layout</div> + <div id="nested" style="subtree-visibility: auto"> + nested activatable locked element will be in AX tree but without layout + </div> </div> + normal text 1 + <div id="nonViewportActivatable" style="subtree-visibility: hidden-matchable"> + nested non-viewport-activatable locked element will not be in AX tree + </div> + normal text 2 + <div id="nonActivatable" style="subtree-visibility: hidden"> + nested non-activatable locked element will not be in AX tree + </div> + normal text 3 </div>
diff --git a/content/test/data/accessibility/display-locking/viewport-activation-expected-blink.txt b/content/test/data/accessibility/display-locking/viewport-activation-expected-blink.txt new file mode 100644 index 0000000..f0d1a10 --- /dev/null +++ b/content/test/data/accessibility/display-locking/viewport-activation-expected-blink.txt
@@ -0,0 +1,21 @@ +rootWebArea +++genericContainer ignored +++++genericContainer ignored +++++++genericContainer +++++++++staticText offscreen name='initial spacer, will initially make everything below this far away from the viewport' +++++++++++inlineTextBox offscreen name='initial spacer, will initially make everything below this far away from the viewport' +++++++genericContainer +++++++++staticText name='This text will get viewport-activated because it's in the viewport, and will be in AX tree with layout.' +++++++++++inlineTextBox name='This text will get viewport-activated because it's in the viewport, and will be in AX tree with layout.' +++++++genericContainer +++++++++staticText name='This text is also in viewport.' +++++++++++inlineTextBox name='This text is also in viewport.' +++++++genericContainer +++++++++staticText name='spacer so that everything below will be offscreen (and won't get viewport-activated)' +++++++++++inlineTextBox name='spacer so that everything below will be offscreen (and won't get viewport-activated)' +++++++genericContainer +++++++++staticText offscreen name='<newline> This text will not get viewport-activated, and will be in AX tree but without layout.<newline> ' +++++++genericContainer offscreen +++++++++staticText offscreen name='doneActivating' +++++++++++inlineTextBox offscreen name='doneActivating' +
diff --git a/content/test/data/accessibility/display-locking/viewport-activation.html b/content/test/data/accessibility/display-locking/viewport-activation.html new file mode 100644 index 0000000..9a385aa1 --- /dev/null +++ b/content/test/data/accessibility/display-locking/viewport-activation.html
@@ -0,0 +1,35 @@ +<!-- +@BLINK-ALLOW:offscreen +@WAIT-FOR:doneActivating +--> +<div> + <div id="initialSpacer" style="height: 10000px;"> + initial spacer, will initially make everything below this far away from the viewport + </div> + <div id="inViewport" style="subtree-visibility: auto"> + This text will get viewport-activated because it's in the viewport, and will be in AX tree with layout. + </div> + <div id="alsoInViewport" style="subtree-visibility: auto"> + This text is also in viewport. + </div> + <div style="height: 10000px;"> + spacer so that everything below will be offscreen (and won't get viewport-activated) + </div> + <div id="wayBelowViewport" style="subtree-visibility: auto"> + This text will not get viewport-activated, and will be in AX tree but without layout. + </div> + <div id="statusDiv"></div> +</div> +<script> + // Viewport activation happens on the next frame, so we'll wait until then before ending. + window.addEventListener("scroll", () => { + window.requestAnimationFrame(() => { + window.requestAnimationFrame(() => { + statusDiv.innerText = "doneActivating"; + }); + }); + }); + // Scroll so that #inViewport will be at the top of the viewport. + window.scrollTo(0, initialSpacer.offsetHeight); +</script> +
diff --git a/content/test/gpu/gpu_tests/skia_gold_integration_test_base.py b/content/test/gpu/gpu_tests/skia_gold_integration_test_base.py index f72e4765..6f7d48c 100644 --- a/content/test/gpu/gpu_tests/skia_gold_integration_test_base.py +++ b/content/test/gpu/gpu_tests/skia_gold_integration_test_base.py
@@ -171,6 +171,12 @@ help='Don\'t use the service account provided by LUCI for authentication ' 'for Skia Gold, instead relying on gsutil to be pre-authenticated. ' 'Meant for testing locally instead of on the bots.') + parser.add_option( + '--bypass-skia-gold-functionality', + action='store_true', default=False, + help='Bypass all interaction with Skia Gold, effectively disabling the ' + 'image comparison portion of any tests that use Gold. Only meant to ' + 'be used in case a Gold outage occurs and cannot be fixed quickly.') @classmethod def ResetGpuInfo(cls): @@ -375,6 +381,10 @@ page: the GPU PixelTestPage object for the test. build_id_args: a list of build-identifying flags and values. """ + if self.GetParsedCommandLineOptions().bypass_skia_gold_functionality: + logging.warning('Not actually comparing with Gold due to ' + '--bypass-skia-gold-functionality being present.') + return if not isinstance(build_id_args, list) or '--commit' not in build_id_args: raise Exception('Requires build args to be specified, including --commit')
diff --git a/content/test/gpu/gpu_tests/test_expectations/context_lost_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/context_lost_expectations.txt index cfc5f2a..a013a9f 100644 --- a/content/test/gpu/gpu_tests/test_expectations/context_lost_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/context_lost_expectations.txt
@@ -34,6 +34,7 @@ crbug.com/965268 [ android qualcomm-adreno-(tm)-418 ] ContextLost_WebGLUnblockedAfterUserInitiatedReload [ Skip ] crbug.com/880078 [ android ] ContextLost_WorkerRAFAfterGPUCrash [ Failure ] crbug.com/880078 [ android ] ContextLost_WorkerRAFAfterGPUCrash_OOPD [ Failure ] +crbug.com/1064853 [ android qualcomm-adreno-(tm)-418 ] ContextLost_WebGLContextLostFromSelectElement [ Skip ] # Nexus 6 # The Nexus 6 times out on these tests while waiting for the JS to complete
diff --git a/device/fido/BUILD.gn b/device/fido/BUILD.gn index 9e9f1a6..3902a8210 100644 --- a/device/fido/BUILD.gn +++ b/device/fido/BUILD.gn
@@ -61,6 +61,8 @@ "cable/noise.h", "cable/v2_handshake.cc", "cable/v2_handshake.h", + "client_data.cc", + "client_data.h", "credential_management.cc", "credential_management.h", "credential_management_handler.cc",
diff --git a/device/fido/authenticator_get_assertion_response.h b/device/fido/authenticator_get_assertion_response.h index 4f60316..d212879 100644 --- a/device/fido/authenticator_get_assertion_response.h +++ b/device/fido/authenticator_get_assertion_response.h
@@ -60,6 +60,13 @@ return num_credentials_; } + const base::Optional<std::vector<uint8_t>>& android_client_data_ext() const { + return android_client_data_ext_; + } + void set_android_client_data_ext(const std::vector<uint8_t>& data) { + android_client_data_ext_ = data; + } + private: base::Optional<PublicKeyCredentialDescriptor> credential_; AuthenticatorData authenticator_data_; @@ -67,6 +74,10 @@ base::Optional<PublicKeyCredentialUserEntity> user_entity_; base::Optional<uint8_t> num_credentials_; + // If not base::nullopt, the content of the googleAndroidClientData extension + // authenticator output. + base::Optional<std::vector<uint8_t>> android_client_data_ext_; + DISALLOW_COPY_AND_ASSIGN(AuthenticatorGetAssertionResponse); };
diff --git a/device/fido/authenticator_make_credential_response.cc b/device/fido/authenticator_make_credential_response.cc index 8022cb3e..35598e58 100644 --- a/device/fido/authenticator_make_credential_response.cc +++ b/device/fido/authenticator_make_credential_response.cc
@@ -11,6 +11,7 @@ #include "device/fido/attestation_statement_formats.h" #include "device/fido/attested_credential_data.h" #include "device/fido/authenticator_data.h" +#include "device/fido/client_data.h" #include "device/fido/ec_public_key.h" #include "device/fido/fido_parsing_utils.h" @@ -107,6 +108,10 @@ map.emplace(1, object.attestation_statement().format_name()); map.emplace(2, object.authenticator_data().SerializeToByteArray()); map.emplace(3, AsCBOR(object.attestation_statement())); + if (response.android_client_data_ext()) { + map.emplace(kAndroidClientDataExtOutputKey, + cbor::Value(*response.android_client_data_ext())); + } auto encoded_bytes = cbor::Writer::Write(cbor::Value(std::move(map))); DCHECK(encoded_bytes); return std::move(*encoded_bytes);
diff --git a/device/fido/authenticator_make_credential_response.h b/device/fido/authenticator_make_credential_response.h index 050f3a4..7f232da 100644 --- a/device/fido/authenticator_make_credential_response.h +++ b/device/fido/authenticator_make_credential_response.h
@@ -71,6 +71,13 @@ return transport_used_; } + const base::Optional<std::vector<uint8_t>>& android_client_data_ext() const { + return android_client_data_ext_; + } + void set_android_client_data_ext(const std::vector<uint8_t>& data) { + android_client_data_ext_ = data; + } + private: AttestationObject attestation_object_; @@ -78,6 +85,10 @@ // nullopt for cases where we cannot determine the transport (Windows). base::Optional<FidoTransportProtocol> transport_used_; + // If not base::nullopt, the content of the googleAndroidClientData extension + // authenticator output. + base::Optional<std::vector<uint8_t>> android_client_data_ext_; + DISALLOW_COPY_AND_ASSIGN(AuthenticatorMakeCredentialResponse); };
diff --git a/device/fido/authenticator_supported_options.h b/device/fido/authenticator_supported_options.h index c0f2938..6396ef8 100644 --- a/device/fido/authenticator_supported_options.h +++ b/device/fido/authenticator_supported_options.h
@@ -85,6 +85,9 @@ // Indicates whether the authenticator is capable of handling built in user // verification based tokens. bool supports_uv_token = false; + // Indicates whether the authenticator supports an extension for passing + // information from the collectedClientData structure with a CTAP request. + bool supports_android_client_data_ext; }; COMPONENT_EXPORT(DEVICE_FIDO)
diff --git a/device/fido/client_data.cc b/device/fido/client_data.cc new file mode 100644 index 0000000..5ee8a6dc --- /dev/null +++ b/device/fido/client_data.cc
@@ -0,0 +1,218 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "device/fido/client_data.h" + +#include "base/base64url.h" +#include "base/json/json_reader.h" +#include "base/logging.h" +#include "base/numerics/safe_conversions.h" +#include "base/rand_util.h" +#include "base/strings/utf_string_conversion_utils.h" +#include "components/device_event_log/device_event_log.h" +#include "url/gurl.h" + +namespace device { + +namespace { + +std::string Base64UrlEncode(const base::span<const uint8_t> input) { + std::string ret; + base::Base64UrlEncode( + base::StringPiece(reinterpret_cast<const char*>(input.data()), + input.size()), + base::Base64UrlEncodePolicy::OMIT_PADDING, &ret); + return ret; +} + +// ToJSONString encodes |in| as a JSON string, using the specific escaping rules +// required by https://github.com/w3c/webauthn/pull/1375. +std::string ToJSONString(base::StringPiece in) { + std::string ret; + ret.reserve(in.size() + 2); + ret.push_back('"'); + + const char* const in_bytes = in.data(); + // ICU uses |int32_t| for lengths. + const int32_t length = base::checked_cast<int32_t>(in.size()); + int32_t offset = 0; + + while (offset < length) { + const int32_t prior_offset = offset; + // Input strings must be valid UTF-8. + uint32_t codepoint; + CHECK(base::ReadUnicodeCharacter(in_bytes, length, &offset, &codepoint)); + // offset is updated by |ReadUnicodeCharacter| to index the last byte of the + // codepoint. Increment it to index the first byte of the next codepoint for + // the subsequent iteration. + offset++; + + if (codepoint == 0x20 || codepoint == 0x21 || + (codepoint >= 0x23 && codepoint <= 0x5b) || codepoint >= 0x5d) { + ret.append(&in_bytes[prior_offset], &in_bytes[offset]); + } else if (codepoint == 0x22) { + ret.append("\\\""); + } else if (codepoint == 0x5c) { + ret.append("\\\\"); + } else { + static const char hextable[17] = "0123456789abcdef"; + ret.append("\\u00"); + ret.push_back(hextable[codepoint >> 4]); + ret.push_back(hextable[codepoint & 15]); + } + } + + ret.push_back('"'); + return ret; +} + +} // namespace + +std::string SerializeCollectedClientDataToJson( + const std::string& type, + const std::string& origin, + base::span<const uint8_t> challenge, + bool is_cross_origin, + bool use_legacy_u2f_type_key /* = false */) { + std::string ret; + ret.reserve(128); + + if (use_legacy_u2f_type_key) { + ret.append(R"({"typ":)"); + } else { + ret.append(R"({"type":)"); + } + ret.append(ToJSONString(type)); + + ret.append(R"(,"challenge":)"); + ret.append(ToJSONString(Base64UrlEncode(challenge))); + + ret.append(R"(,"origin":)"); + ret.append(ToJSONString(origin)); + + if (is_cross_origin) { + ret.append(R"(,"crossOrigin":true)"); + } else { + ret.append(R"(,"crossOrigin":false)"); + } + + if (base::RandDouble() < 0.2) { + // An extra key is sometimes added to ensure that RPs do not make + // unreasonably specific assumptions about the clientData JSON. This is + // done in the fashion of + // https://tools.ietf.org/html/draft-ietf-tls-grease + ret.append(R"(,"extra_keys_may_be_added_here":")"); + ret.append( + "do not compare clientDataJSON against a template. See " + "https://goo.gl/yabPex\""); + } + + ret.append("}"); + return ret; +} + +// static +base::Optional<AndroidClientDataExtensionInput> +AndroidClientDataExtensionInput::Parse(const cbor::Value& value) { + if (!value.is_map()) { + return base::nullopt; + } + const cbor::Value::MapValue& map = value.GetMap(); + if (map.size() != 3) { + return base::nullopt; + } + AndroidClientDataExtensionInput ext; + for (const auto& pair : map) { + if (!pair.first.is_integer()) { + return base::nullopt; + } + switch (pair.first.GetInteger()) { + case 1: + if (!pair.second.is_string()) { + return base::nullopt; + } + ext.type = pair.second.GetString(); + break; + case 2: + if (!pair.second.is_string()) { + return base::nullopt; + } + ext.origin = url::Origin::Create(GURL(pair.second.GetString())); + if (ext.origin.opaque() || + ext.origin.Serialize() != pair.second.GetString()) { + return base::nullopt; + } + break; + case 3: + if (!pair.second.is_bytestring()) { + return base::nullopt; + } + ext.challenge = pair.second.GetBytestring(); + break; + default: + return base::nullopt; + } + } + return ext; +} + +AndroidClientDataExtensionInput::AndroidClientDataExtensionInput() = default; +AndroidClientDataExtensionInput::AndroidClientDataExtensionInput( + std::string type_, + url::Origin origin_, + std::vector<uint8_t> challenge_) + : type(type_), origin(origin_), challenge(challenge_) {} +AndroidClientDataExtensionInput::AndroidClientDataExtensionInput( + const AndroidClientDataExtensionInput&) = default; +AndroidClientDataExtensionInput::AndroidClientDataExtensionInput( + AndroidClientDataExtensionInput&&) = default; + +AndroidClientDataExtensionInput& AndroidClientDataExtensionInput::operator=( + const AndroidClientDataExtensionInput&) = default; +AndroidClientDataExtensionInput& AndroidClientDataExtensionInput::operator=( + AndroidClientDataExtensionInput&&) = default; + +AndroidClientDataExtensionInput::~AndroidClientDataExtensionInput() = default; + +cbor::Value AsCBOR(const AndroidClientDataExtensionInput& ext) { + cbor::Value::MapValue map; + map[cbor::Value(1)] = cbor::Value(ext.type); + map[cbor::Value(2)] = cbor::Value(ext.origin.Serialize()); + map[cbor::Value(3)] = cbor::Value(ext.challenge); + return cbor::Value(map); +} + +bool IsValidAndroidClientDataJSON( + const device::AndroidClientDataExtensionInput& extension_input, + base::StringPiece android_client_data_json) { + base::Optional<base::Value> client_data = + base::JSONReader::Read(android_client_data_json); + if (!client_data || !client_data->is_dict()) { + FIDO_LOG(ERROR) << "Invalid androidClientData extension: " + << android_client_data_json; + return false; + } + const base::DictionaryValue& client_data_dict = + base::Value::AsDictionaryValue(*client_data); + std::string type; + std::string challenge; + std::string origin; + std::string android_package_name; + if (client_data_dict.size() != 4 || + !client_data_dict.GetString("type", &type) || + type != extension_input.type || + !client_data_dict.GetString("challenge", &challenge) || + challenge != Base64UrlEncode(extension_input.challenge) || + !client_data_dict.GetString("origin", &origin) || + origin != extension_input.origin.Serialize() || + !client_data_dict.GetString("androidPackageName", + &android_package_name)) { + FIDO_LOG(ERROR) << "Invalid androidClientData extension: " + << android_client_data_json; + return false; + } + return true; +} + +} // namespace device
diff --git a/device/fido/client_data.h b/device/fido/client_data.h new file mode 100644 index 0000000..f8651733 --- /dev/null +++ b/device/fido/client_data.h
@@ -0,0 +1,72 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef DEVICE_FIDO_CLIENT_DATA_H_ +#define DEVICE_FIDO_CLIENT_DATA_H_ + +#include <stdint.h> + +#include <string> +#include <vector> + +#include "base/containers/span.h" +#include "base/strings/string_piece.h" +#include "components/cbor/values.h" +#include "url/origin.h" + +namespace device { + +// The map key for inserting the googleAndroidClientDataExtension output into a +// CTAP2 makeCredential or getAssertion response. +constexpr int kAndroidClientDataExtOutputKey = 0xf0; + +// Builds the CollectedClientData[1] dictionary with the given values, +// serializes it to JSON, and returns the resulting string. For legacy U2F +// requests coming from the CryptoToken U2F extension, modifies the object key +// 'type' as required[2]. +// [1] https://w3c.github.io/webauthn/#dictdef-collectedclientdata +// [2] +// https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-raw-message-formats-v1.2-ps-20170411.html#client-data +COMPONENT_EXPORT(DEVICE_FIDO) +std::string SerializeCollectedClientDataToJson( + const std::string& type, + const std::string& origin, + base::span<const uint8_t> challenge, + bool is_cross_origin, + bool use_legacy_u2f_type_key = false); + +// AndroidClientDataExtensionInput contains data for an extension sent to the +// Clank caBLEv2 authenticator that are required due to the Android FIDO API not +// supporting the CTAP2 clientDataHash input parameter. +struct COMPONENT_EXPORT(DEVICE_FIDO) AndroidClientDataExtensionInput { + static base::Optional<AndroidClientDataExtensionInput> Parse( + const cbor::Value& value); + + AndroidClientDataExtensionInput(); + AndroidClientDataExtensionInput(std::string type, + url::Origin origin, + std::vector<uint8_t> challenge); + AndroidClientDataExtensionInput(const AndroidClientDataExtensionInput&); + AndroidClientDataExtensionInput(AndroidClientDataExtensionInput&&); + + AndroidClientDataExtensionInput& operator=( + const AndroidClientDataExtensionInput&); + AndroidClientDataExtensionInput& operator=(AndroidClientDataExtensionInput&&); + + ~AndroidClientDataExtensionInput(); + + std::string type; + url::Origin origin; + std::vector<uint8_t> challenge; +}; + +cbor::Value AsCBOR(const AndroidClientDataExtensionInput& ext); + +bool IsValidAndroidClientDataJSON( + const device::AndroidClientDataExtensionInput& extension_input, + base::StringPiece android_client_data_json); + +} // namespace device + +#endif // DEVICE_FIDO_CLIENT_DATA_H_
diff --git a/device/fido/ctap_get_assertion_request.cc b/device/fido/ctap_get_assertion_request.cc index f34010f..7224951 100644 --- a/device/fido/ctap_get_assertion_request.cc +++ b/device/fido/ctap_get_assertion_request.cc
@@ -84,6 +84,27 @@ request.allow_list = std::move(allow_list); } + const auto extensions_it = request_map.find(cbor::Value(4)); + if (extensions_it != request_map.end()) { + if (!extensions_it->second.is_map()) { + return base::nullopt; + } + + const cbor::Value::MapValue& extensions = extensions_it->second.GetMap(); + + const auto android_client_data_ext_it = + extensions.find(cbor::Value(device::kExtensionAndroidClientData)); + if (android_client_data_ext_it != extensions.end()) { + base::Optional<AndroidClientDataExtensionInput> android_client_data_ext = + AndroidClientDataExtensionInput::Parse( + android_client_data_ext_it->second); + if (!android_client_data_ext) { + return base::nullopt; + } + request.android_client_data_ext = std::move(*android_client_data_ext); + } + } + const auto option_it = request_map.find(cbor::Value(5)); if (option_it != request_map.end()) { if (!option_it->second.is_map()) @@ -166,6 +187,13 @@ cbor_map[cbor::Value(3)] = cbor::Value(std::move(allow_list_array)); } + if (request.android_client_data_ext) { + cbor::Value::MapValue extensions; + extensions.emplace(kExtensionAndroidClientData, + AsCBOR(*request.android_client_data_ext)); + cbor_map[cbor::Value(4)] = cbor::Value(std::move(extensions)); + } + if (request.pin_auth) { cbor_map[cbor::Value(6)] = cbor::Value(*request.pin_auth); }
diff --git a/device/fido/ctap_get_assertion_request.h b/device/fido/ctap_get_assertion_request.h index 94c1f5d1..1226606 100644 --- a/device/fido/ctap_get_assertion_request.h +++ b/device/fido/ctap_get_assertion_request.h
@@ -17,6 +17,7 @@ #include "base/optional.h" #include "crypto/sha2.h" #include "device/fido/cable/cable_discovery_data.h" +#include "device/fido/client_data.h" #include "device/fido/fido_constants.h" #include "device/fido/public_key_credential_descriptor.h" @@ -64,6 +65,8 @@ bool is_incognito_mode = false; bool is_u2f_only = false; + + base::Optional<AndroidClientDataExtensionInput> android_client_data_ext; }; struct CtapGetNextAssertionRequest {};
diff --git a/device/fido/ctap_make_credential_request.cc b/device/fido/ctap_make_credential_request.cc index 4fb4832c..8c92c10 100644 --- a/device/fido/ctap_make_credential_request.cc +++ b/device/fido/ctap_make_credential_request.cc
@@ -112,7 +112,7 @@ return base::nullopt; } - const auto& extensions = extensions_it->second.GetMap(); + const cbor::Value::MapValue& extensions = extensions_it->second.GetMap(); const auto hmac_secret_it = extensions.find(cbor::Value(kExtensionHmacSecret)); if (hmac_secret_it != extensions.end()) { @@ -144,6 +144,18 @@ return base::nullopt; } } + + const auto android_client_data_ext_it = + extensions.find(cbor::Value(device::kExtensionAndroidClientData)); + if (android_client_data_ext_it != extensions.end()) { + base::Optional<AndroidClientDataExtensionInput> android_client_data_ext = + AndroidClientDataExtensionInput::Parse( + android_client_data_ext_it->second); + if (!android_client_data_ext) { + return base::nullopt; + } + request.android_client_data_ext = std::move(*android_client_data_ext); + } } const auto option_it = request_map.find(cbor::Value(7)); @@ -244,6 +256,11 @@ static_cast<uint8_t>(request.cred_protect->first)); } + if (request.android_client_data_ext) { + extensions.emplace(kExtensionAndroidClientData, + AsCBOR(*request.android_client_data_ext)); + } + if (!extensions.empty()) { cbor_map[cbor::Value(6)] = cbor::Value(std::move(extensions)); }
diff --git a/device/fido/ctap_make_credential_request.h b/device/fido/ctap_make_credential_request.h index c4416e3..0dd6c28 100644 --- a/device/fido/ctap_make_credential_request.h +++ b/device/fido/ctap_make_credential_request.h
@@ -15,6 +15,7 @@ #include "base/containers/span.h" #include "base/macros.h" #include "base/optional.h" +#include "device/fido/client_data.h" #include "device/fido/fido_constants.h" #include "device/fido/public_key_credential_descriptor.h" #include "device/fido/public_key_credential_params.h" @@ -83,6 +84,8 @@ // provided by the target authenticator for the MakeCredential request to be // sent. base::Optional<std::pair<CredProtect, bool>> cred_protect; + + base::Optional<AndroidClientDataExtensionInput> android_client_data_ext; }; // Serializes MakeCredential request parameter into CBOR encoded map with
diff --git a/device/fido/device_response_converter.cc b/device/fido/device_response_converter.cc index 1362b13..2355b0a 100644 --- a/device/fido/device_response_converter.cc +++ b/device/fido/device_response_converter.cc
@@ -20,6 +20,8 @@ #include "components/device_event_log/device_event_log.h" #include "device/fido/authenticator_data.h" #include "device/fido/authenticator_supported_options.h" +#include "device/fido/client_data.h" +#include "device/fido/features.h" #include "device/fido/fido_constants.h" #include "device/fido/opaque_attestation_statement.h" @@ -88,11 +90,20 @@ if (it == decoded_map.end() || !it->second.is_map()) return base::nullopt; - return AuthenticatorMakeCredentialResponse( + AuthenticatorMakeCredentialResponse response( transport_used, AttestationObject(std::move(*authenticator_data), std::make_unique<OpaqueAttestationStatement>( format, it->second.Clone()))); + + if (base::FeatureList::IsEnabled(kWebAuthPhoneSupport)) { + it = decoded_map.find(CBOR(kAndroidClientDataExtOutputKey)); + if (it != decoded_map.end() && it->second.is_bytestring()) { + response.set_android_client_data_ext(it->second.GetBytestring()); + } + } + + return response; } base::Optional<AuthenticatorGetAssertionResponse> ReadCTAPGetAssertionResponse( @@ -144,7 +155,14 @@ response.SetNumCredentials(it->second.GetUnsigned()); } - return base::Optional<AuthenticatorGetAssertionResponse>(std::move(response)); + if (base::FeatureList::IsEnabled(kWebAuthPhoneSupport)) { + it = response_map.find(CBOR(kAndroidClientDataExtOutputKey)); + if (it != response_map.end() && it->second.is_bytestring()) { + response.set_android_client_data_ext(it->second.GetBytestring()); + } + } + + return response; } base::Optional<AuthenticatorGetInfoResponse> ReadCTAPGetInfoResponse( @@ -229,6 +247,8 @@ const std::string& extension_str = extension.GetString(); if (extension_str == kExtensionCredProtect) { options.supports_cred_protect = true; + } else if (extension_str == kExtensionAndroidClientData) { + options.supports_android_client_data_ext = true; } extensions.push_back(extension_str); }
diff --git a/device/fido/fido_constants.cc b/device/fido/fido_constants.cc index cd002f50..04c5af25 100644 --- a/device/fido/fido_constants.cc +++ b/device/fido/fido_constants.cc
@@ -65,6 +65,7 @@ const char kExtensionHmacSecret[] = "hmac-secret"; const char kExtensionCredProtect[] = "credProtect"; +const char kExtensionAndroidClientData[] = "googleAndroidClientData"; const base::TimeDelta kBleDevicePairingModeWaitingInterval = base::TimeDelta::FromSeconds(2);
diff --git a/device/fido/fido_constants.h b/device/fido/fido_constants.h index 78c0c3f1..c64f740 100644 --- a/device/fido/fido_constants.h +++ b/device/fido/fido_constants.h
@@ -350,6 +350,8 @@ COMPONENT_EXPORT(DEVICE_FIDO) extern const char kExtensionHmacSecret[]; COMPONENT_EXPORT(DEVICE_FIDO) extern const char kExtensionCredProtect[]; +COMPONENT_EXPORT(DEVICE_FIDO) +extern const char kExtensionAndroidClientData[]; // Maximum number of seconds the browser waits for Bluetooth authenticator to // send packets that advertises that the device is in pairing mode before
diff --git a/device/fido/get_assertion_request_handler.cc b/device/fido/get_assertion_request_handler.cc index 924942406..c1067e88 100644 --- a/device/fido/get_assertion_request_handler.cc +++ b/device/fido/get_assertion_request_handler.cc
@@ -81,7 +81,9 @@ bool ResponseValid(const FidoAuthenticator& authenticator, const CtapGetAssertionRequest& request, - const AuthenticatorGetAssertionResponse& response) { + const AuthenticatorGetAssertionResponse& response, + const base::Optional<AndroidClientDataExtensionInput>& + android_client_data_ext_in) { if (response.GetRpIdHash() != fido_parsing_utils::CreateSHA256Hash(request.rp_id) && (!request.app_id || @@ -164,6 +166,18 @@ return false; } + if (response.android_client_data_ext() && + (!android_client_data_ext_in || !authenticator.Options() || + !authenticator.Options()->supports_android_client_data_ext || + !IsValidAndroidClientDataJSON( + *android_client_data_ext_in, + base::StringPiece(reinterpret_cast<const char*>( + response.android_client_data_ext()->data()), + response.android_client_data_ext()->size())))) { + FIDO_LOG(ERROR) << "Invalid androidClientData extension"; + return false; + } + return true; } @@ -245,6 +259,13 @@ request_.user_verification = UserVerificationRequirement::kRequired; } + // Only send the googleAndroidClientData extension to authenticators that + // support it. + if (request_.android_client_data_ext) { + android_client_data_ext_ = *request_.android_client_data_ext; + request_.android_client_data_ext.reset(); + } + FIDO_LOG(EVENT) << "Starting GetAssertion flow"; Start(); } @@ -310,6 +331,10 @@ } else { request.user_verification = UserVerificationRequirement::kDiscouraged; } + if (android_client_data_ext_ && authenticator->Options() && + authenticator->Options()->supports_android_client_data_ext) { + request.android_client_data_ext = *android_client_data_ext_; + } } ReportGetAssertionRequestTransport(authenticator); @@ -440,7 +465,8 @@ return; } - if (!response || !ResponseValid(*authenticator, request_, *response)) { + if (!response || !ResponseValid(*authenticator, request_, *response, + android_client_data_ext_)) { FIDO_LOG(ERROR) << "Failing assertion request due to bad response from " << authenticator->GetDisplayName(); std::move(completion_callback_) @@ -496,7 +522,8 @@ return; } - if (!ResponseValid(*authenticator, request_, *response)) { + if (!ResponseValid(*authenticator, request_, *response, + android_client_data_ext_)) { FIDO_LOG(ERROR) << "Failing assertion request due to bad response from " << authenticator->GetDisplayName(); std::move(completion_callback_) @@ -734,6 +761,11 @@ // Do not do internal UV again. request.user_verification = UserVerificationRequirement::kDiscouraged; + if (android_client_data_ext_ && authenticator_->Options() && + authenticator_->Options()->supports_android_client_data_ext) { + request.android_client_data_ext = *android_client_data_ext_; + } + ReportGetAssertionRequestTransport(authenticator_); authenticator_->GetAssertion(
diff --git a/device/fido/get_assertion_request_handler.h b/device/fido/get_assertion_request_handler.h index 417fee5..2235627 100644 --- a/device/fido/get_assertion_request_handler.h +++ b/device/fido/get_assertion_request_handler.h
@@ -106,6 +106,7 @@ CompletionCallback completion_callback_; State state_ = State::kWaitingForTouch; CtapGetAssertionRequest request_; + base::Optional<AndroidClientDataExtensionInput> android_client_data_ext_; // If true, and if at the time the request is dispatched to the first // authenticator no other authenticators are available, the request handler // will skip the initial touch that is usually required to select a PIN
diff --git a/device/fido/make_credential_request_handler.cc b/device/fido/make_credential_request_handler.cc index c8e2d09..5d4d347d 100644 --- a/device/fido/make_credential_request_handler.cc +++ b/device/fido/make_credential_request_handler.cc
@@ -242,6 +242,13 @@ transport_availability_info().request_type = FidoRequestHandlerBase::RequestType::kMakeCredential; + // Only send the googleAndroidClientData extension to authenticators that + // support it. + if (request_.android_client_data_ext) { + android_client_data_ext_ = *request_.android_client_data_ext; + request_.android_client_data_ext.reset(); + } + // Set the rk, uv and attachment fields, which were only initialized to // default values up to here. TODO(martinkr): Initialize these fields earlier // (in AuthenticatorImpl) and get rid of the separate @@ -363,6 +370,10 @@ !authenticator->Options()->supports_cred_protect) { request.cred_protect.reset(); } + if (android_client_data_ext_ && authenticator->Options() && + authenticator->Options()->supports_android_client_data_ext) { + request.android_client_data_ext = *android_client_data_ext_; + } } ReportMakeCredentialRequestTransport(authenticator); @@ -488,6 +499,21 @@ return; } + if (response->android_client_data_ext() && + (!android_client_data_ext_ || !authenticator->Options() || + !authenticator->Options()->supports_android_client_data_ext || + !IsValidAndroidClientDataJSON( + *android_client_data_ext_, + base::StringPiece(reinterpret_cast<const char*>( + response->android_client_data_ext()->data()), + response->android_client_data_ext()->size())))) { + FIDO_LOG(ERROR) << "Invalid androidClientData extension"; + std::move(completion_callback_) + .Run(MakeCredentialStatus::kAuthenticatorResponseInvalid, base::nullopt, + authenticator); + return; + } + if (authenticator->AuthenticatorTransport()) { base::UmaHistogramEnumeration( "WebAuthentication.MakeCredentialResponseTransport", @@ -762,6 +788,10 @@ !authenticator_->Options()->supports_cred_protect) { request.cred_protect.reset(); } + if (android_client_data_ext_ && authenticator_->Options() && + authenticator_->Options()->supports_android_client_data_ext) { + request.android_client_data_ext = *android_client_data_ext_; + } ReportMakeCredentialRequestTransport(authenticator_);
diff --git a/device/fido/make_credential_request_handler.h b/device/fido/make_credential_request_handler.h index 4cdf5b2..459a4c0c 100644 --- a/device/fido/make_credential_request_handler.h +++ b/device/fido/make_credential_request_handler.h
@@ -16,6 +16,7 @@ #include "base/sequence_checker.h" #include "device/fido/authenticator_make_credential_response.h" #include "device/fido/authenticator_selection_criteria.h" +#include "device/fido/client_data.h" #include "device/fido/ctap_make_credential_request.h" #include "device/fido/fido_constants.h" #include "device/fido/fido_request_handler_base.h" @@ -113,6 +114,8 @@ State state_ = State::kWaitingForTouch; CtapMakeCredentialRequest request_; AuthenticatorSelectionCriteria authenticator_selection_criteria_; + base::Optional<AndroidClientDataExtensionInput> android_client_data_ext_; + // If true, the request handler may skip the first touch to select a device // that will require a PIN. bool allow_skipping_pin_touch_;
diff --git a/docs/linux/development.md b/docs/linux/development.md index 8a837d7..a9507c8 100644 --- a/docs/linux/development.md +++ b/docs/linux/development.md
@@ -33,7 +33,7 @@ ## Contributing code -See [Contributing code](contributing.md). +See [Contributing code](../contributing.md). ## Debugging
diff --git a/docs/security/faq.md b/docs/security/faq.md index 5689f15..23b3daff 100644 --- a/docs/security/faq.md +++ b/docs/security/faq.md
@@ -649,6 +649,34 @@ * [This document](https://www.chromium.org/developers/design-documents/idn-in-google-chrome) describes Chrome's IDN policy in detail. +<a name="TOC-Chrome-silently-syncs-extensions-across-devices.-Is-this-a-security-vulnerability-"></a> +## Chrome silently syncs extensions across devices. Is this a security vulnerability? + +If an attacker has access to one of a victim's devices, the attacker can install +an extension which will be synced to the victim's other sync-enabled +devices. Similarly, an attacker who phishes a victim's Google credentials can +sign in to Chrome as the victim and install an extension, which will be synced +to the victim's other sync-enabled devices. Sync thereby enables an attacker to +elevate phished credentials or physical access to persistent access on all of a +victim's sync-enabled devices. + +To mitigate this issue, Chrome only syncs extensions that have been installed +from the Chrome Web Store. Extensions in the Chrome Web Store are monitored for +abusive behavior. + +In the future, we may pursue further mitigations. However, because an attacker +must already have the victim's Google credentials and/or [physical access to a +device](#TOC-Why-aren-t-physically-local-attacks-in-Chrome-s-threat-model), we +don't consider this attack a security vulnerability. + +We **do** consider it a vulnerability if an attacker can get an extension to +sync to a victim's device without either of the above preconditions. For +example, we consider it a vulnerability if an attacker could craft a request to +Google's sync servers that causes an extension to be installed to a user's +device, or if an attacker could entice a victim to visit a webpage that causes +an extension to be installed on their device(s). Please report such bugs via +https://bugs.chromium.org/p/chromium/issues/entry?template=Security+Bug. + ## TODO * https://dev.chromium.org/Home/chromium-security/client-identification-mechanisms
diff --git a/extensions/browser/api/crash_report_private/crash_report_private_api.cc b/extensions/browser/api/crash_report_private/crash_report_private_api.cc index 973f6e6c..ed996bc1 100644 --- a/extensions/browser/api/crash_report_private/crash_report_private_api.cc +++ b/extensions/browser/api/crash_report_private/crash_report_private_api.cc
@@ -8,13 +8,14 @@ #include "base/strings/stringprintf.h" #include "base/system/sys_info.h" #include "base/task/post_task.h" +#include "base/task/task_traits.h" +#include "base/task/thread_pool.h" #include "base/time/default_clock.h" #include "components/crash/core/app/client_upload_info.h" #include "components/feedback/anonymizer_tool.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/storage_partition.h" -#include "extensions/common/api/crash_report_private.h" #include "net/base/escape.h" #include "services/network/public/cpp/resource_request.h" #include "services/network/public/cpp/simple_url_loader.h" @@ -203,10 +204,6 @@ ~CrashReportPrivateReportErrorFunction() = default; ExtensionFunction::ResponseAction CrashReportPrivateReportErrorFunction::Run() { - // Do not report errors if the user did not give consent for crash reporting. - if (!crash_reporter::GetClientCollectStatsConsent()) - return RespondNow(NoArguments()); - // Ensure we don't send too many crash reports. Limit to one report per hour. if (!g_last_called_time.is_null() && g_clock->Now() - g_last_called_time < base::TimeDelta::FromHours(1)) { @@ -217,21 +214,40 @@ const auto params = crash_report_private::ReportError::Params::Create(*args_); EXTENSION_FUNCTION_VALIDATE(params.get()); + // Consent checking may be blocking, so do it on a separate thread to avoid + // blocking the UI thread. + PostTaskAndReplyWithResult( + FROM_HERE, {base::ThreadPool(), base::MayBlock()}, + base::BindOnce(&crash_reporter::GetClientCollectStatsConsent), + base::BindOnce( + &CrashReportPrivateReportErrorFunction::OnConsentCheckCompleted, this, + std::move(params->info))); + + return RespondLater(); +} + +void CrashReportPrivateReportErrorFunction::OnConsentCheckCompleted( + crash_report_private::ErrorInfo info, + bool consented) { + // Do not report errors if the user did not give consent for crash reporting. + if (!consented) { + Respond(NoArguments()); + return; + } + scoped_refptr<network::SharedURLLoaderFactory> loader_factory = content::BrowserContext::GetDefaultStoragePartition(browser_context()) ->GetURLLoaderFactoryForBrowserProcess(); // Don't anonymize the report on the UI thread as it can take some time. PostTaskAndReplyWithResult( - FROM_HERE, base::BindOnce(&AnonymizeErrorMessage, params->info.message), + FROM_HERE, base::BindOnce(&AnonymizeErrorMessage, info.message), base::BindOnce( - &ReportJavaScriptError, std::move(loader_factory), - std::move(params->info), + &ReportJavaScriptError, std::move(loader_factory), std::move(info), base::BindOnce( &CrashReportPrivateReportErrorFunction::OnReportComplete, this))); - g_last_called_time = base::Time::Now(); - return RespondLater(); + g_last_called_time = base::Time::Now(); } void CrashReportPrivateReportErrorFunction::OnReportComplete() {
diff --git a/extensions/browser/api/crash_report_private/crash_report_private_api.h b/extensions/browser/api/crash_report_private/crash_report_private_api.h index f91819f4..0a7c7af 100644 --- a/extensions/browser/api/crash_report_private/crash_report_private_api.h +++ b/extensions/browser/api/crash_report_private/crash_report_private_api.h
@@ -9,6 +9,7 @@ #include "extensions/browser/extension_function.h" #include "extensions/browser/extension_function_histogram_value.h" +#include "extensions/common/api/crash_report_private.h" namespace base { class Clock; @@ -28,6 +29,8 @@ ResponseAction Run() override; private: + void OnConsentCheckCompleted(crash_report_private::ErrorInfo info, + bool consented); void OnReportComplete(); DISALLOW_COPY_AND_ASSIGN(CrashReportPrivateReportErrorFunction);
diff --git a/extensions/browser/api/crash_report_private/crash_report_private_apitest.cc b/extensions/browser/api/crash_report_private/crash_report_private_apitest.cc index d53409f..ceeecd4 100644 --- a/extensions/browser/api/crash_report_private/crash_report_private_apitest.cc +++ b/extensions/browser/api/crash_report_private/crash_report_private_apitest.cc
@@ -4,6 +4,7 @@ #include "base/system/sys_info.h" #include "base/test/simple_test_clock.h" +#include "base/threading/scoped_blocking_call.h" #include "components/crash/core/app/crash_reporter_client.h" #include "content/public/test/browser_task_environment.h" #include "extensions/browser/api/crash_report_private/crash_report_private_api.h" @@ -26,7 +27,17 @@ constexpr const char* kTestCrashEndpoint = "/crash"; class MockCrashReporterClient : public crash_reporter::CrashReporterClient { - bool GetCollectStatsConsent() override { return true; } + public: + void set_consented(bool consented) { consented_ = consented; } + + private: + bool GetCollectStatsConsent() override { + // In production, GetCollectStatsConsent may be blocking due to file reads. + // Simulate this in our tests as well. + base::ScopedBlockingCall scoped_blocking_call( + FROM_HERE, base::BlockingType::MAY_BLOCK); + return consented_; + } void GetProductNameAndVersion(std::string* product_name, std::string* version, std::string* channel) override { @@ -34,6 +45,8 @@ *version = "1.2.3.4"; *channel = "Stable"; } + + bool consented_ = true; }; std::string GetOsVersion() { @@ -102,6 +115,7 @@ }; const Extension* extension_; + MockCrashReporterClient client_; Report last_report_; private: @@ -121,7 +135,6 @@ return http_response; } - MockCrashReporterClient client_; DISALLOW_COPY_AND_ASSIGN(CrashReportPrivateApiTest); }; @@ -259,4 +272,26 @@ extension_->id(), kTestScript)); } +// Ensures that reportError checks user consent for data collection on the +// correct thread and correctly handles the case where consent is not given. +IN_PROC_BROWSER_TEST_F(CrashReportPrivateApiTest, NoConsent) { + constexpr char kTestScript[] = R"( + chrome.crashReportPrivate.reportError({ + message: "hi", + url: "http://www.test.com", + }, + () => { + window.domAutomationController.send(chrome.runtime.lastError ? + chrome.runtime.lastError.message : "") + }); + )"; + + client_.set_consented(false); + EXPECT_EQ("", ExecuteScriptInBackgroundPage(browser_context(), + extension_->id(), kTestScript)); + // The server should not receive any reports. + EXPECT_EQ(last_report_.query, ""); + EXPECT_EQ(last_report_.content, ""); +} + } // namespace extensions
diff --git a/extensions/common/url_pattern_unittest.cc b/extensions/common/url_pattern_unittest.cc index f699d03..12b9bdf9 100644 --- a/extensions/common/url_pattern_unittest.cc +++ b/extensions/common/url_pattern_unittest.cc
@@ -202,7 +202,9 @@ EXPECT_FALSE(pattern.match_all_urls()); EXPECT_EQ("/foo*bar", pattern.path()); EXPECT_TRUE(pattern.MatchesURL(GURL("http://google.com/foobar"))); + EXPECT_TRUE(pattern.MatchesURL(GURL("http://www.google.com/foobar"))); EXPECT_TRUE(pattern.MatchesURL(GURL("http://www.google.com/foo?bar"))); + EXPECT_FALSE(pattern.MatchesURL(GURL("http://wwwgoogle.com/foobar"))); EXPECT_TRUE(pattern.MatchesURL( GURL("http://monkey.images.google.com/foooobar"))); EXPECT_FALSE(pattern.MatchesURL(GURL("http://yahoo.com/foobar")));
diff --git a/extensions/shell/browser/root_window_controller.cc b/extensions/shell/browser/root_window_controller.cc index 3da1e72b..1743e2f 100644 --- a/extensions/shell/browser/root_window_controller.cc +++ b/extensions/shell/browser/root_window_controller.cc
@@ -7,7 +7,6 @@ #include "extensions/browser/app_window/app_window.h" #include "extensions/browser/app_window/native_app_window.h" #include "extensions/shell/browser/shell_app_delegate.h" -#include "ui/aura/client/screen_position_client.h" #include "ui/aura/layout_manager.h" #include "ui/aura/window.h" #include "ui/aura/window_tracker.h" @@ -68,7 +67,7 @@ // coordinates using the offset of the root window in screen coordinates. class ScreenPositionClient : public wm::DefaultScreenPositionClient { public: - ScreenPositionClient() = default; + using DefaultScreenPositionClient::DefaultScreenPositionClient; ~ScreenPositionClient() override = default; // wm::DefaultScreenPositionClient: @@ -98,9 +97,7 @@ DesktopDelegate* desktop_delegate, const gfx::Rect& bounds, content::BrowserContext* browser_context) - : desktop_delegate_(desktop_delegate), - browser_context_(browser_context), - screen_position_client_(std::make_unique<ScreenPositionClient>()) { + : desktop_delegate_(desktop_delegate), browser_context_(browser_context) { DCHECK(desktop_delegate_); DCHECK(browser_context_); @@ -110,8 +107,8 @@ host_->window()->Show(); aura::client::SetWindowParentingClient(host_->window(), this); - aura::client::SetScreenPositionClient(host_->window(), - screen_position_client_.get()); + screen_position_client_ = + std::make_unique<ScreenPositionClient>(host_->window()); // Ensure the window fills the display. host_->window()->SetLayoutManager(new FillLayout(host_->window())); @@ -122,6 +119,9 @@ RootWindowController::~RootWindowController() { CloseAppWindows(); + // The screen position client holds a pointer to the root window, so free it + // before destroying the window tree host. + screen_position_client_.reset(); DestroyWindowTreeHost(); }
diff --git a/fuchsia/engine/browser/web_engine_permission_delegate.cc b/fuchsia/engine/browser/web_engine_permission_delegate.cc index ae20cb9..e57a7b0 100644 --- a/fuchsia/engine/browser/web_engine_permission_delegate.cc +++ b/fuchsia/engine/browser/web_engine_permission_delegate.cc
@@ -54,8 +54,8 @@ content::PermissionType permission, const GURL& requesting_origin, const GURL& embedding_origin) { - // TODO(crbug.com/922833): Update PermissionControllerDelegate to pass - // RenderFrameHost. + // TODO(crbug.com/1063094): Implement when the PermissionManager protocol is + // defined and implemented. NOTIMPLEMENTED() << ": " << static_cast<int>(permission); } @@ -63,9 +63,11 @@ content::PermissionType permission, const GURL& requesting_origin, const GURL& embedding_origin) { - // GetPermissionStatus() is deprecated and it's not expected to be called in - // WebEngine. - NOTREACHED(); + // Although GetPermissionStatusForFrame() should be used for most permissions, + // some use cases (e.g., BACKGROUND_SYNC) do not have a frame. + // + // TODO(crbug.com/1063094): Handle frame-less permission status checks in the + // PermissionManager API. Until then, reject such requests. return blink::mojom::PermissionStatus::DENIED; } @@ -85,7 +87,7 @@ content::RenderFrameHost* render_frame_host, const GURL& requesting_origin, base::RepeatingCallback<void(blink::mojom::PermissionStatus)> callback) { - // TODO(crbug.com/922833): Implement permission status subscription. It's + // TODO(crbug.com/1063094): Implement permission status subscription. It's // used in blink to emit PermissionStatus.onchange notifications. NOTIMPLEMENTED() << ": " << static_cast<int>(permission); return content::PermissionController::kNoPendingOperation; @@ -93,5 +95,7 @@ void WebEnginePermissionDelegate::UnsubscribePermissionStatusChange( int subscription_id) { + // TODO(crbug.com/1063094): Implement permission status subscription. It's + // used in blink to emit PermissionStatus.onchange notifications. NOTREACHED(); }
diff --git a/gpu/command_buffer/service/external_vk_image_backing.cc b/gpu/command_buffer/service/external_vk_image_backing.cc index 91dca6e..6cea0c6 100644 --- a/gpu/command_buffer/service/external_vk_image_backing.cc +++ b/gpu/command_buffer/service/external_vk_image_backing.cc
@@ -84,23 +84,6 @@ static_assert(base::size(kFormatTable) == (viz::RESOURCE_FORMAT_MAX + 1), "kFormatTable does not handle all cases."); -GrVkImageInfo CreateGrVkImageInfo(SharedContextState* context_state, - VulkanImage* image, - bool use_protected_memory) { - VkPhysicalDevice physical_device = context_state->vk_context_provider() - ->GetDeviceQueue() - ->GetVulkanPhysicalDevice(); - GrVkYcbcrConversionInfo gr_ycbcr_info = CreateGrVkYcbcrConversionInfo( - physical_device, image->image_tiling(), image->ycbcr_info()); - GrVkAlloc alloc(image->device_memory(), 0 /* offset */, image->device_size(), - 0 /* flags */); - return GrVkImageInfo( - image->image(), alloc, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_LAYOUT_UNDEFINED, - image->format(), 1 /* levelCount */, VK_QUEUE_FAMILY_IGNORED, - use_protected_memory ? GrProtected::kYes : GrProtected::kNo, - gr_ycbcr_info); -} - uint32_t FindMemoryTypeIndex(SharedContextState* context_state, const VkMemoryRequirements& requirements, VkMemoryPropertyFlags flags) { @@ -350,12 +333,9 @@ false /* is_thread_safe */), context_state_(context_state), image_(std::move(image)), - backend_texture_( - size.width(), - size.height(), - CreateGrVkImageInfo(context_state_, - image_.get(), - usage & SHARED_IMAGE_USAGE_PROTECTED)), + backend_texture_(size.width(), + size.height(), + CreateGrVkImageInfo(image_.get())), command_pool_(command_pool) {} ExternalVkImageBacking::~ExternalVkImageBacking() {
diff --git a/gpu/command_buffer/service/raster_decoder.cc b/gpu/command_buffer/service/raster_decoder.cc index 94d390a..9b3bf4b 100644 --- a/gpu/command_buffer/service/raster_decoder.cc +++ b/gpu/command_buffer/service/raster_decoder.cc
@@ -2514,10 +2514,13 @@ raster_canvas_ = nullptr; + // The DDL pins memory for the recorded ops so it must be kept alive until its + // flushed. + std::unique_ptr<SkDeferredDisplayList> ddl; if (use_ddl_) { TRACE_EVENT0("gpu", "RasterDecoderImpl::DoEndRasterCHROMIUM::DetachAndDrawDDL"); - auto ddl = recorder_->detach(); + ddl = recorder_->detach(); recorder_ = nullptr; sk_surface_->draw(ddl.get()); } @@ -2540,6 +2543,7 @@ flush_info); DCHECK(result == GrSemaphoresSubmitted::kYes || end_semaphores_.empty()); end_semaphores_.clear(); + ddl.reset(); } shared_context_state_->UpdateSkiaOwnedMemorySize();
diff --git a/gpu/command_buffer/service/shared_image_backing_factory_ahardwarebuffer.cc b/gpu/command_buffer/service/shared_image_backing_factory_ahardwarebuffer.cc index a28fa0d..1c1ad3b5 100644 --- a/gpu/command_buffer/service/shared_image_backing_factory_ahardwarebuffer.cc +++ b/gpu/command_buffer/service/shared_image_backing_factory_ahardwarebuffer.cc
@@ -277,18 +277,11 @@ DCHECK(vulkan_image_); DCHECK(context_state_); DCHECK(context_state_->vk_context_provider()); - // Create backend texture from the VkImage. - GrVkAlloc alloc(vulkan_image_->device_memory(), 0 /* offset */, - vulkan_image_->device_size(), 0 /* flags */); - GrVkImageInfo vk_info(vulkan_image_->image(), alloc, - vulkan_image_->image_tiling(), - VK_IMAGE_LAYOUT_UNDEFINED, vulkan_image_->format(), - 1 /* levelCount */, VK_QUEUE_FAMILY_EXTERNAL); - // TODO(bsalomon): Determine whether it makes sense to attempt to reuse this // if the vk_info stays the same on subsequent calls. promise_texture_ = SkPromiseImageTexture::Make( - GrBackendTexture(size().width(), size().height(), vk_info)); + GrBackendTexture(size().width(), size().height(), + CreateGrVkImageInfo(vulkan_image_.get()))); DCHECK(promise_texture_); }
diff --git a/gpu/command_buffer/service/shared_image_representation.cc b/gpu/command_buffer/service/shared_image_representation.cc index 93133a1..e17f9f5 100644 --- a/gpu/command_buffer/service/shared_image_representation.cc +++ b/gpu/command_buffer/service/shared_image_representation.cc
@@ -31,7 +31,7 @@ GLenum mode, AllowUnclearedAccess allow_uncleared) { if (allow_uncleared != AllowUnclearedAccess::kYes && !IsCleared()) { - LOG(ERROR) << "Attempt to access an uninitialized ShardImage"; + LOG(ERROR) << "Attempt to access an uninitialized SharedImage"; return nullptr; } @@ -108,7 +108,7 @@ std::vector<GrBackendSemaphore>* end_semaphores, AllowUnclearedAccess allow_uncleared) { if (allow_uncleared != AllowUnclearedAccess::kYes && !IsCleared()) { - LOG(ERROR) << "Attempt to write to an uninitialized ShardImage"; + LOG(ERROR) << "Attempt to write to an uninitialized SharedImage"; return nullptr; } @@ -148,7 +148,7 @@ std::vector<GrBackendSemaphore>* begin_semaphores, std::vector<GrBackendSemaphore>* end_semaphores) { if (!IsCleared()) { - LOG(ERROR) << "Attempt to read from an uninitialized ShardImage"; + LOG(ERROR) << "Attempt to read from an uninitialized SharedImage"; return nullptr; } @@ -171,7 +171,7 @@ std::unique_ptr<SharedImageRepresentationOverlay::ScopedReadAccess> SharedImageRepresentationOverlay::BeginScopedReadAccess(bool needs_gl_image) { if (!IsCleared()) { - LOG(ERROR) << "Attempt to read from an uninitialized ShardImage"; + LOG(ERROR) << "Attempt to read from an uninitialized SharedImage"; return nullptr; } @@ -198,7 +198,7 @@ WGPUTextureUsage usage, AllowUnclearedAccess allow_uncleared) { if (allow_uncleared != AllowUnclearedAccess::kYes && !IsCleared()) { - LOG(ERROR) << "Attempt to access an uninitialized ShardImage"; + LOG(ERROR) << "Attempt to access an uninitialized SharedImage"; return nullptr; }
diff --git a/gpu/command_buffer/service/shared_image_video.cc b/gpu/command_buffer/service/shared_image_video.cc index 9e683e2..ba043e3 100644 --- a/gpu/command_buffer/service/shared_image_video.cc +++ b/gpu/command_buffer/service/shared_image_video.cc
@@ -287,22 +287,11 @@ DCHECK_EQ(static_cast<int32_t>(vulkan_image_->image_tiling()), static_cast<int32_t>(VK_IMAGE_TILING_OPTIMAL)); - GrVkYcbcrConversionInfo gr_ycbcr_info = CreateGrVkYcbcrConversionInfo( - device_queue->GetVulkanPhysicalDevice(), VK_IMAGE_TILING_OPTIMAL, - vulkan_image_->ycbcr_info()); - // Create backend texture from the VkImage. - GrVkAlloc alloc(vulkan_image_->device_memory(), 0 /* offset */, - vulkan_image_->device_size(), 0 /* flags */); - GrVkImageInfo vk_info(vulkan_image_->image(), alloc, - vulkan_image_->image_tiling(), - VK_IMAGE_LAYOUT_UNDEFINED, vulkan_image_->format(), - 1 /* levelCount */, VK_QUEUE_FAMILY_EXTERNAL, - GrProtected::kNo, gr_ycbcr_info); - // TODO(bsalomon): Determine whether it makes sense to attempt to reuse // this if the vk_info stays the same on subsequent calls. promise_texture_ = SkPromiseImageTexture::Make( - GrBackendTexture(size().width(), size().height(), vk_info)); + GrBackendTexture(size().width(), size().height(), + CreateGrVkImageInfo(vulkan_image_.get()))); DCHECK(promise_texture_); } return promise_texture_;
diff --git a/gpu/command_buffer/service/skia_utils.cc b/gpu/command_buffer/service/skia_utils.cc index e4e4ad4..b79adbb 100644 --- a/gpu/command_buffer/service/skia_utils.cc +++ b/gpu/command_buffer/service/skia_utils.cc
@@ -20,6 +20,7 @@ #include "gpu/vulkan/vulkan_device_queue.h" #include "gpu/vulkan/vulkan_fence_helper.h" #include "gpu/vulkan/vulkan_function_pointers.h" +#include "gpu/vulkan/vulkan_image.h" #endif namespace gpu { @@ -167,6 +168,20 @@ } #if BUILDFLAG(ENABLE_VULKAN) +GrVkImageInfo CreateGrVkImageInfo(VulkanImage* image) { + DCHECK(image); + VkPhysicalDevice physical_device = + image->device_queue()->GetVulkanPhysicalDevice(); + GrVkYcbcrConversionInfo gr_ycbcr_info = CreateGrVkYcbcrConversionInfo( + physical_device, image->image_tiling(), image->ycbcr_info()); + GrVkAlloc alloc(image->device_memory(), /*offset=*/0, image->device_size(), + /*flags=*/0); + bool is_protected = image->flags() & VK_IMAGE_CREATE_PROTECTED_BIT; + return GrVkImageInfo( + image->image(), alloc, image->image_tiling(), image->image_layout(), + image->format(), /*levelCount=*/1, image->queue_family_index(), + is_protected ? GrProtected::kYes : GrProtected::kNo, gr_ycbcr_info); +} GrVkYcbcrConversionInfo CreateGrVkYcbcrConversionInfo( VkPhysicalDevice physical_device,
diff --git a/gpu/command_buffer/service/skia_utils.h b/gpu/command_buffer/service/skia_utils.h index a383163..0208f72b 100644 --- a/gpu/command_buffer/service/skia_utils.h +++ b/gpu/command_buffer/service/skia_utils.h
@@ -32,6 +32,10 @@ namespace gpu { +#if BUILDFLAG(ENABLE_VULKAN) +class VulkanImage; +#endif + namespace gles2 { class FeatureInfo; } // namespace gles2 @@ -74,6 +78,8 @@ sk_sp<SkSurface> sk_surface); #if BUILDFLAG(ENABLE_VULKAN) +GPU_GLES2_EXPORT GrVkImageInfo CreateGrVkImageInfo(VulkanImage* image); + GPU_GLES2_EXPORT GrVkYcbcrConversionInfo CreateGrVkYcbcrConversionInfo( VkPhysicalDevice physical_device, VkImageTiling tiling,
diff --git a/gpu/vulkan/vulkan_image.cc b/gpu/vulkan/vulkan_image.cc index 2fcbed2..be991ca 100644 --- a/gpu/vulkan/vulkan_image.cc +++ b/gpu/vulkan/vulkan_image.cc
@@ -209,12 +209,13 @@ device_queue_ = device_queue; size_ = size; format_ = format; + flags_ = flags; image_tiling_ = image_tiling; VkImageCreateInfo create_info = { .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, .pNext = vk_image_create_info_next, - .flags = flags, + .flags = flags_, .imageType = VK_IMAGE_TYPE_2D, .format = format_, .extent = {size.width(), size.height(), 1}, @@ -226,7 +227,7 @@ .sharingMode = VK_SHARING_MODE_EXCLUSIVE, .queueFamilyIndexCount = 0, .pQueueFamilyIndices = nullptr, - .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, + .initialLayout = image_layout_, }; VkDevice vk_device = device_queue->GetVulkanDevice(); VkResult result = @@ -486,6 +487,9 @@ return false; } + // VkImage is imported from external. + queue_family_index_ = VK_QUEUE_FAMILY_EXTERNAL; + if (ahb_format_props.format == VK_FORMAT_UNDEFINED) { ycbcr_info_.emplace(VK_FORMAT_UNDEFINED, ahb_format_props.externalFormat, ahb_format_props.suggestedYcbcrModel, @@ -494,6 +498,7 @@ ahb_format_props.suggestedYChromaOffset, ahb_format_props.formatFeatures); } + return true; #endif // defined(OS_ANDROID) }
diff --git a/gpu/vulkan/vulkan_image.h b/gpu/vulkan/vulkan_image.h index d386563..2c24fb5 100644 --- a/gpu/vulkan/vulkan_image.h +++ b/gpu/vulkan/vulkan_image.h
@@ -83,11 +83,17 @@ zx::vmo GetMemoryZirconHandle(); #endif + VulkanDeviceQueue* device_queue() const { return device_queue_; } const gfx::Size& size() const { return size_; } VkFormat format() const { return format_; } + VkImageCreateFlags flags() const { return flags_; } VkDeviceSize device_size() const { return device_size_; } uint32_t memory_type_index() const { return memory_type_index_; } VkImageTiling image_tiling() const { return image_tiling_; } + VkImageLayout image_layout() const { return image_layout_; } + void set_image_layout(VkImageLayout layout) { image_layout_ = layout; } + uint32_t queue_family_index() const { return queue_family_index_; } + void set_queue_family_index(uint32_t index) { queue_family_index_ = index; } const base::Optional<VulkanYCbCrInfo>& ycbcr_info() const { return ycbcr_info_; } @@ -123,9 +129,12 @@ VulkanDeviceQueue* device_queue_ = nullptr; gfx::Size size_; VkFormat format_ = VK_FORMAT_UNDEFINED; + VkImageCreateFlags flags_ = 0; VkDeviceSize device_size_ = 0; uint32_t memory_type_index_ = 0; VkImageTiling image_tiling_ = VK_IMAGE_TILING_OPTIMAL; + VkImageLayout image_layout_ = VK_IMAGE_LAYOUT_UNDEFINED; + uint32_t queue_family_index_ = VK_QUEUE_FAMILY_IGNORED; base::Optional<VulkanYCbCrInfo> ycbcr_info_; VkImage image_ = VK_NULL_HANDLE; VkDeviceMemory device_memory_ = VK_NULL_HANDLE;
diff --git a/ios/chrome/browser/policy/BUILD.gn b/ios/chrome/browser/policy/BUILD.gn index a6f4f730..e3433a77 100644 --- a/ios/chrome/browser/policy/BUILD.gn +++ b/ios/chrome/browser/policy/BUILD.gn
@@ -20,6 +20,7 @@ deps = [ "//base", + "//components/password_manager/core/common", "//components/policy:generated", "//components/policy/core/common", "//ios/chrome/browser", @@ -74,6 +75,7 @@ ":test_support", "//base", "//base/test:test_support", + "//components/password_manager/core/common", "//components/pref_registry", "//components/prefs", "//components/sync_preferences",
diff --git a/ios/chrome/browser/policy/configuration_policy_handler_list_factory.mm b/ios/chrome/browser/policy/configuration_policy_handler_list_factory.mm index 1e6572e..7fed64e 100644 --- a/ios/chrome/browser/policy/configuration_policy_handler_list_factory.mm +++ b/ios/chrome/browser/policy/configuration_policy_handler_list_factory.mm
@@ -6,6 +6,7 @@ #include "base/bind.h" #include "base/logging.h" +#include "components/password_manager/core/common/password_manager_pref_names.h" #include "components/policy/core/browser/configuration_policy_handler.h" #include "components/policy/core/browser/configuration_policy_handler_list.h" #include "components/policy/core/browser/configuration_policy_handler_parameters.h" @@ -23,8 +24,12 @@ namespace { const PolicyToPreferenceMapEntry kSimplePolicyMap[] = { + {policy::key::kPasswordManagerEnabled, + password_manager::prefs::kCredentialsEnableService, + base::Value::Type::BOOLEAN}, {policy::key::kSearchSuggestEnabled, prefs::kSearchSuggestEnabled, - base::Value::Type::BOOLEAN}}; + base::Value::Type::BOOLEAN}, +}; void PopulatePolicyHandlerParameters( policy::PolicyHandlerParameters* parameters) {}
diff --git a/ios/chrome/browser/policy/policy_unittest.mm b/ios/chrome/browser/policy/policy_unittest.mm index db926ec8..752e744 100644 --- a/ios/chrome/browser/policy/policy_unittest.mm +++ b/ios/chrome/browser/policy/policy_unittest.mm
@@ -10,6 +10,7 @@ #include "base/run_loop.h" #include "base/test/task_environment.h" #include "base/threading/thread_task_runner_handle.h" +#include "components/password_manager/core/common/password_manager_pref_names.h" #include "components/policy/core/common/mock_configuration_policy_provider.h" #include "components/policy/core/common/policy_map.h" #include "components/policy/core/common/policy_types.h" @@ -131,3 +132,33 @@ EXPECT_TRUE(pref_service_->IsManagedPreference(prefs::kSearchSuggestEnabled)); EXPECT_FALSE(pref_service_->GetBoolean(prefs::kSearchSuggestEnabled)); } + +// Tests that the PasswordManagerEnabled preference is correctly managed by +// policy. +TEST_F(PolicyTest, TestPasswordManagerEnabled) { + EXPECT_FALSE(pref_service_->IsManagedPreference( + password_manager::prefs::kCredentialsEnableService)); + + policy::PolicyMap values; + // Setting the policy to true should set the pref to true. + values.Set(policy::key::kPasswordManagerEnabled, + policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_MACHINE, + policy::POLICY_SOURCE_PLATFORM, + std::make_unique<base::Value>(true), nullptr); + policy_provider_.UpdateChromePolicy(values); + EXPECT_TRUE(pref_service_->IsManagedPreference( + password_manager::prefs::kCredentialsEnableService)); + EXPECT_TRUE(pref_service_->GetBoolean( + password_manager::prefs::kCredentialsEnableService)); + + // Setting the policy to false should set the pref to false. + values.Set(policy::key::kPasswordManagerEnabled, + policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_MACHINE, + policy::POLICY_SOURCE_PLATFORM, + std::make_unique<base::Value>(false), nullptr); + policy_provider_.UpdateChromePolicy(values); + EXPECT_TRUE(pref_service_->IsManagedPreference( + password_manager::prefs::kCredentialsEnableService)); + EXPECT_FALSE(pref_service_->GetBoolean( + password_manager::prefs::kCredentialsEnableService)); +}
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/BUILD.gn b/ios/chrome/browser/ui/autofill/manual_fill/BUILD.gn index 799cebb..de8ee5e8 100644 --- a/ios/chrome/browser/ui/autofill/manual_fill/BUILD.gn +++ b/ios/chrome/browser/ui/autofill/manual_fill/BUILD.gn
@@ -266,6 +266,7 @@ deps = [ "//base", "//base/test:test_support", + "//components/autofill/core/browser:test_support", "//ios/chrome/app/strings:ios_strings_grit", "//ios/chrome/browser/ui/autofill:eg_test_support+eg2", "//ios/chrome/browser/ui/settings/autofill:feature_flags",
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/card_view_controller_egtest.mm b/ios/chrome/browser/ui/autofill/manual_fill/card_view_controller_egtest.mm index b949c6d..95e895a 100644 --- a/ios/chrome/browser/ui/autofill/manual_fill/card_view_controller_egtest.mm +++ b/ios/chrome/browser/ui/autofill/manual_fill/card_view_controller_egtest.mm
@@ -5,6 +5,7 @@ #include "base/ios/ios_util.h" #include "base/strings/sys_string_conversions.h" #import "base/test/ios/wait_util.h" +#include "components/autofill/core/browser/autofill_test_utils.h" #import "ios/chrome/browser/ui/autofill/autofill_app_interface.h" #import "ios/chrome/browser/ui/settings/autofill/features.h" #include "ios/chrome/grit/ios_strings.h" @@ -44,8 +45,12 @@ NSString* kLocalCardNumber = @"4111111111111111"; NSString* kLocalCardHolder = @"Test User"; -NSString* kLocalCardExpirationMonth = @"11"; -NSString* kLocalCardExpirationYear = @"22"; +// The local card's expiration month and year (only the last two digits) are set +// with next month and next year. +NSString* kLocalCardExpirationMonth = + base::SysUTF8ToNSString(autofill::test::NextMonth()); +NSString* kLocalCardExpirationYear = + base::SysUTF8ToNSString(autofill::test::NextYear().substr(2, 2)); // Unicode characters used in card number: // - 0x0020 - Space.
diff --git a/ios/chrome/browser/ui/settings/autofill/BUILD.gn b/ios/chrome/browser/ui/settings/autofill/BUILD.gn index 3318029..ed05c75 100644 --- a/ios/chrome/browser/ui/settings/autofill/BUILD.gn +++ b/ios/chrome/browser/ui/settings/autofill/BUILD.gn
@@ -149,6 +149,7 @@ ":constants", ":feature_flags", "//base", + "//components/autofill/core/browser:test_support", "//components/strings:components_strings_grit", "//ios/chrome/app/strings", "//ios/chrome/browser/ui/autofill:eg_test_support+eg2",
diff --git a/ios/chrome/browser/ui/settings/autofill/autofill_credit_card_settings_egtest.mm b/ios/chrome/browser/ui/settings/autofill/autofill_credit_card_settings_egtest.mm index 8ab228c..13c394e2 100644 --- a/ios/chrome/browser/ui/settings/autofill/autofill_credit_card_settings_egtest.mm +++ b/ios/chrome/browser/ui/settings/autofill/autofill_credit_card_settings_egtest.mm
@@ -6,6 +6,7 @@ #include "base/strings/sys_string_conversions.h" #import "base/test/ios/wait_util.h" +#include "components/autofill/core/browser/autofill_test_utils.h" #include "components/strings/grit/components_strings.h" #import "ios/chrome/browser/ui/autofill/autofill_app_interface.h" #import "ios/chrome/browser/ui/settings/autofill/autofill_constants.h" @@ -43,8 +44,10 @@ const DisplayStringIDToExpectedResult kExpectedFields[] = { {IDS_IOS_AUTOFILL_CARDHOLDER, @"Test User"}, {IDS_IOS_AUTOFILL_CARD_NUMBER, @"4111111111111111"}, - {IDS_IOS_AUTOFILL_EXP_MONTH, @"11"}, - {IDS_IOS_AUTOFILL_EXP_YEAR, @"2022"}}; + {IDS_IOS_AUTOFILL_EXP_MONTH, + base::SysUTF8ToNSString(autofill::test::NextMonth())}, + {IDS_IOS_AUTOFILL_EXP_YEAR, + base::SysUTF8ToNSString(autofill::test::NextYear())}}; NSString* const kCreditCardLabelTemplate = @"Test User, %@";
diff --git a/ios/chrome/common/credential_provider/OWNERS b/ios/chrome/common/credential_provider/OWNERS new file mode 100644 index 0000000..b2af2796 --- /dev/null +++ b/ios/chrome/common/credential_provider/OWNERS
@@ -0,0 +1,5 @@ +javierrobles@chromium.org +djean@chromium.org + +# TEAM: ios-directory-owners@chromium.org +# OS: iOS
diff --git a/media/audio/OWNERS b/media/audio/OWNERS index c13e013..db515cd 100644 --- a/media/audio/OWNERS +++ b/media/audio/OWNERS
@@ -6,5 +6,6 @@ # Mirroring (and related glue) OWNERS. miu@chromium.org +mfoltz@chromium.org # COMPONENT: Blink>Media>Audio
diff --git a/media/base/mock_filters.h b/media/base/mock_filters.h index e788fec..86c77b3 100644 --- a/media/base/mock_filters.h +++ b/media/base/mock_filters.h
@@ -324,6 +324,8 @@ MOCK_METHOD1(StartPlayingFrom, void(base::TimeDelta)); MOCK_METHOD0(OnTimeProgressing, void()); MOCK_METHOD0(OnTimeStopped, void()); + MOCK_METHOD1(SetLatencyHint, + void(base::Optional<base::TimeDelta> latency_hint)); private: DISALLOW_COPY_AND_ASSIGN(MockVideoRenderer);
diff --git a/media/base/video_renderer.h b/media/base/video_renderer.h index 7a7fc29..bfbc676c 100644 --- a/media/base/video_renderer.h +++ b/media/base/video_renderer.h
@@ -7,6 +7,7 @@ #include "base/callback_forward.h" #include "base/macros.h" +#include "base/optional.h" #include "media/base/media_export.h" #include "media/base/pipeline_status.h" #include "media/base/time_source.h" @@ -63,6 +64,12 @@ virtual void OnTimeProgressing() = 0; virtual void OnTimeStopped() = 0; + // Sets a hint indicating target latency. See comment in header for + // media::Renderer::SetLatencyHint(). + // |latency_hint| may be nullopt to indicate the hint has been cleared + // (restore UA default). + virtual void SetLatencyHint(base::Optional<base::TimeDelta> latency_hint) = 0; + private: DISALLOW_COPY_AND_ASSIGN(VideoRenderer); };
diff --git a/media/capture/content/OWNERS b/media/capture/content/OWNERS index e837b5f..12fd84a 100644 --- a/media/capture/content/OWNERS +++ b/media/capture/content/OWNERS
@@ -1,3 +1,4 @@ miu@chromium.org +mfoltz@chromium.org # COMPONENT: Internals>Media>ScreenCapture
diff --git a/media/renderers/renderer_impl.cc b/media/renderers/renderer_impl.cc index 2a0dcaca..98b8c80 100644 --- a/media/renderers/renderer_impl.cc +++ b/media/renderers/renderer_impl.cc
@@ -199,7 +199,8 @@ DCHECK(!latency_hint || (*latency_hint >= base::TimeDelta())); DCHECK(task_runner_->BelongsToCurrentThread()); - // TODO(chcunningham): Plumb to video renderer in a follow up CL. + if (video_renderer_) + video_renderer_->SetLatencyHint(latency_hint); if (audio_renderer_) audio_renderer_->SetLatencyHint(latency_hint);
diff --git a/media/renderers/video_renderer_impl.cc b/media/renderers/video_renderer_impl.cc index e703824..b89509ce 100644 --- a/media/renderers/video_renderer_impl.cc +++ b/media/renderers/video_renderer_impl.cc
@@ -29,6 +29,16 @@ namespace { +// Maximum number of frames we will buffer, regardless of their "effectiveness". +// See HaveReachedBufferingCap(). The value was historically described in terms +// of |min_buffered_frames_| as follows: +// = 3 * high_water_mark(min_buffered_frames_), +// = 3 * (2 * limits::kMaxVideoFrames) +// = 3 * 2 * 4 +// Today, |min_buffered_frames_| can go down (as low as 1) and up in response to +// SetLatencyHint(), so we needed to peg this with a constant. +constexpr int kAbsoluteMaxFrames = 24; + // Used for UMA stats, only add numbers to end! enum VideoFrameColorSpaceUMA { Unknown = 0, @@ -130,7 +140,8 @@ have_renderered_frames_(false), last_frame_opaque_(false), painted_first_frame_(false), - min_buffered_frames_(limits::kMaxVideoFrames) { + min_buffered_frames_(limits::kMaxVideoFrames), + max_buffered_frames_(limits::kMaxVideoFrames) { DCHECK(create_video_decoders_cb_); } @@ -186,8 +197,10 @@ algorithm_->Reset(); painted_first_frame_ = false; - // Reset preroll capacity so seek time is not penalized. - min_buffered_frames_ = limits::kMaxVideoFrames; + // Reset preroll capacity so seek time is not penalized. |latency_hint_| + // and |low_delay_| mode disable automatic preroll adjustments. + if (!latency_hint_.has_value() && !low_delay_) + min_buffered_frames_ = max_buffered_frames_ = limits::kMaxVideoFrames; } void VideoRendererImpl::StartPlayingFrom(base::TimeDelta timestamp) { @@ -239,11 +252,15 @@ } low_delay_ = ShouldUseLowDelayMode(demuxer_stream_); - UMA_HISTOGRAM_BOOLEAN("Media.VideoRenderer.LowDelay", low_delay_); - if (low_delay_) + if (low_delay_) { MEDIA_LOG(DEBUG, media_log_) << "Video rendering in low delay mode."; + // "Low delay mode" means only one frame must be buffered to transition to + // BUFFERING_HAVE_ENOUGH. + min_buffered_frames_ = 1; + } + // Always post |init_cb_| because |this| could be destroyed if initialization // failed. init_cb_ = BindToCurrentLoop(std::move(init_cb)); @@ -478,12 +495,116 @@ // If we've underflowed, increase the number of frames required to reach // BUFFERING_HAVE_ENOUGH upon resume; this will help prevent us from - // repeatedly underflowing. - const size_t kMaxBufferedFrames = 2 * limits::kMaxVideoFrames; - if (min_buffered_frames_ < kMaxBufferedFrames) { - ++min_buffered_frames_; - DVLOG(2) << "Increased min buffered frames to " << min_buffered_frames_; + // repeatedly underflowing. Providing a |latency_hint_| or enabling + // |low_delay_| mode disables automatic increases. In these cases the site + // is expressing a desire to manually control/minimize the buffering + // threshold for HAVE_ENOUGH. + const size_t kMaxUnderflowGrowth = 2 * limits::kMaxVideoFrames; + if (!latency_hint_.has_value() && !low_delay_) { + DCHECK_EQ(min_buffered_frames_, max_buffered_frames_); + + if (min_buffered_frames_ < kMaxUnderflowGrowth) { + min_buffered_frames_++; + DVLOG(2) << __func__ << " Underflow! Increased min_buffered_frames_: " + << min_buffered_frames_; + } } + + // Increase |max_buffered_frames_| irrespective of |latency_hint_| and + // |low_delay_| mode. Unlike |min_buffered_frames_|, this does not affect + // the buffering threshold for HAVE_ENOUGH. When max > min, the renderer can + // buffer frames _beyond_ the HAVE_ENOUGH threshold (assuming decoder is + // fast enough), which still helps reduce the likelihood of repeat + // underflow. + if (max_buffered_frames_ < kMaxUnderflowGrowth) { + max_buffered_frames_++; + DVLOG(2) << __func__ << " Underflow! Increased max_buffered_frames_: " + << max_buffered_frames_; + } + } +} + +void VideoRendererImpl::SetLatencyHint( + base::Optional<base::TimeDelta> latency_hint) { + base::AutoLock auto_lock(lock_); + + latency_hint_ = latency_hint; + + // Permanently disable implicit |low_delay_| mode. Apps using latencyHint + // are taking manual control of how buffering works. Unsetting the hint + // will make rendering behave as if |low_delay_| were never set. + low_delay_ = false; + + if (!latency_hint_.has_value()) { + // Restore default values. + // NOTE kMaxVideoFrames the default max, not the max overall. + min_buffered_frames_ = max_buffered_frames_ = limits::kMaxVideoFrames; + MEDIA_LOG(DEBUG, media_log_) + << "Video latency hint cleared. Default buffer size (" + << min_buffered_frames_ << " frames) restored"; + } else if (latency_hint_->is_zero()) { + // Zero is a special case implying the bare minimum buffering (1 frame). + // We apply the hint here outside of UpdateLatencyHintBufferingCaps_Locked() + // to avoid needless churn since the "bare minimum" buffering doesn't + // fluctuate with changes to FPS. + min_buffered_frames_ = 1; + max_buffered_frames_ = limits::kMaxVideoFrames; + MEDIA_LOG(DEBUG, media_log_) + << "Video latency hint set:" << *latency_hint << ". " + << "Effective buffering latency: 1 frame"; + } else { + // Non-zero latency hints are set here. This method will also be called + // for each frame in case |average_frame_druation| changes, facilitating + // re-computation of how many frames we should buffer to achieve the target + // latency. |is_latency_hint_media_logged_| ensures that we only MEDIA_LOG + // on the first application of this hint. + is_latency_hint_media_logged_ = false; + UpdateLatencyHintBufferingCaps_Locked(algorithm_->average_frame_duration()); + } +} + +void VideoRendererImpl::UpdateLatencyHintBufferingCaps_Locked( + base::TimeDelta average_frame_duration) { + lock_.AssertAcquired(); + + // NOTE: this method may be called for every frame. Only perform trivial + // tasks. + + // This method should only be called for non-zero latency hints. Zero is hard + // coded to 1 frame inside SetLatencyHint(). + DCHECK(latency_hint_.has_value() && !latency_hint_->is_zero()); + + // For hints > 0, we need |average_frame_duration| to determine how many + // frames would yield the specified target latency. This method will be called + // again as |average_frame_duration| changes. + if (average_frame_duration.is_zero()) + return; + + int latency_hint_frames = + std::round(latency_hint_->InMicrosecondsF() / + average_frame_duration.InMicrosecondsF()); + + std::string clamp_string; + if (latency_hint_frames > kAbsoluteMaxFrames) { + min_buffered_frames_ = kAbsoluteMaxFrames; + clamp_string = " (clamped to max)"; + } else if (latency_hint_frames < 1) { + min_buffered_frames_ = 1; + clamp_string = " (clamped to min)"; + } else { + min_buffered_frames_ = latency_hint_frames; + } + + // Use initial capacity limit if possible. Increase if needed. + max_buffered_frames_ = std::max(min_buffered_frames_, + static_cast<size_t>(limits::kMaxVideoFrames)); + + if (!is_latency_hint_media_logged_) { + is_latency_hint_media_logged_ = true; + MEDIA_LOG(DEBUG, media_log_) + << "Video latency hint set:" << *latency_hint_ << ". " + << "Effective buffering latency:" + << (min_buffered_frames_ * average_frame_duration) << clamp_string; } } @@ -525,7 +646,7 @@ received_end_of_stream_ = true; fps_estimator_.Reset(); ReportFrameRateIfNeeded_Locked(); - } else if ((low_delay_ || cant_read) && is_before_start_time) { + } else if ((min_buffered_frames_ == 1 || cant_read) && is_before_start_time) { // Don't accumulate frames that are earlier than the start time if we // won't have a chance for a better frame, otherwise we could declare // HAVE_ENOUGH_DATA and start playback prematurely. @@ -556,6 +677,34 @@ AddReadyFrame_Locked(std::move(frame)); } + // Attempt to purge bad frames in case of underflow or backgrounding. + RemoveFramesForUnderflowOrBackgroundRendering(); + + // Paint the first frame if possible and necessary. Paint ahead of + // HAVE_ENOUGH_DATA to ensure the user sees the frame as early as possible. + // Paint before calling algorithm_->average_frame_duration(), as the call to + // Render() will trigger internal duration updates. + // + // We want to paint the first frame under two conditions: Either (1) we have + // enough frames to know it's definitely the first frame or (2) there may be + // no more frames coming (sometimes unless we paint one of them). + // + // We have to check both effective_frames_queued() and |is_before_start_time| + // since prior to the clock starting effective_frames_queued() is a guess. + // + // NOTE: Do this before using algorithm_->average_frame_duration(). This + // initial render will update the duration to be non-zero when provided by + // frame metadata. + if (!sink_started_ && !painted_first_frame_ && algorithm_->frames_queued() && + (received_end_of_stream_ || cant_read || + (algorithm_->effective_frames_queued() && !is_before_start_time))) { + scoped_refptr<VideoFrame> first_frame = + algorithm_->Render(base::TimeTicks(), base::TimeTicks(), nullptr); + CheckForMetadataChanges(first_frame->format(), first_frame->natural_size()); + sink_->PaintSingleFrame(first_frame); + painted_first_frame_ = true; + } + // Update average frame duration. base::TimeDelta frame_duration = algorithm_->average_frame_duration(); if (frame_duration != kNoTimestamp && @@ -566,30 +715,16 @@ } ReportFrameRateIfNeeded_Locked(); - // Attempt to purge bad frames in case of underflow or backgrounding. - RemoveFramesForUnderflowOrBackgroundRendering(); - // Update any statistics since the last call. UpdateStats_Locked(); - // Paint the first frame if possible and necessary. Paint ahead of - // HAVE_ENOUGH_DATA to ensure the user sees the frame as early as possible. - // - // We want to paint the first frame under two conditions: Either (1) we have - // enough frames to know it's definitely the first frame or (2) there may be - // no more frames coming (sometimes unless we paint one of them). - // - // We have to check both effective_frames_queued() and |is_before_start_time| - // since prior to the clock starting effective_frames_queued() is a guess. - if (!sink_started_ && !painted_first_frame_ && algorithm_->frames_queued() && - (received_end_of_stream_ || cant_read || - (algorithm_->effective_frames_queued() && !is_before_start_time))) { - scoped_refptr<VideoFrame> first_frame = - algorithm_->Render(base::TimeTicks(), base::TimeTicks(), nullptr); - CheckForMetadataChanges(first_frame->format(), first_frame->natural_size()); - sink_->PaintSingleFrame(first_frame); - painted_first_frame_ = true; - } + // Update hint-driven buffering caps to use the latest average frame duration. + // NOTE: Do this before updating the buffering state below, as it may affect + // the outcome of HaveEnoughData_Locked(). + // TODO(chcunningham): Duration from |algorithm_| is affected by playback + // rate. Consider using wall clock frame duration instead. + if (latency_hint_.has_value() && !latency_hint_->is_zero()) + UpdateLatencyHintBufferingCaps_Locked(frame_duration); // Signal buffering state if we've met our conditions. if (buffering_state_ == BUFFERING_HAVE_NOTHING && HaveEnoughData_Locked()) @@ -610,7 +745,7 @@ if (received_end_of_stream_) return true; - if (HaveReachedBufferingCap()) + if (HaveReachedBufferingCap(min_buffered_frames_)) return true; // If we've decoded any frames since the last render, signal have enough to @@ -618,8 +753,10 @@ if (was_background_rendering_ && last_frame_ready_time_ >= last_render_time_) return true; - if (!low_delay_ && video_decoder_stream_->CanReadWithoutStalling()) + if (min_buffered_frames_ > 1 && + video_decoder_stream_->CanReadWithoutStalling()) { return false; + } // Note: We still require an effective frame in the stalling case since this // method is also used to inform TransitionToHaveNothing_Locked() and thus @@ -685,7 +822,7 @@ if (pending_read_ || received_end_of_stream_) return; - if (HaveReachedBufferingCap()) + if (HaveReachedBufferingCap(max_buffered_frames_)) return; switch (state_) { @@ -764,14 +901,14 @@ client_->OnVideoFrameRateChange(current_fps); } -bool VideoRendererImpl::HaveReachedBufferingCap() const { +bool VideoRendererImpl::HaveReachedBufferingCap(size_t buffering_cap) const { DCHECK(task_runner_->BelongsToCurrentThread()); // When the display rate is less than the frame rate, the effective frames // queued may be much smaller than the actual number of frames queued. Here // we ensure that frames_queued() doesn't get excessive. - return algorithm_->effective_frames_queued() >= min_buffered_frames_ || - algorithm_->frames_queued() >= 3 * min_buffered_frames_; + return algorithm_->effective_frames_queued() >= buffering_cap || + algorithm_->frames_queued() >= kAbsoluteMaxFrames; } void VideoRendererImpl::StartSink() {
diff --git a/media/renderers/video_renderer_impl.h b/media/renderers/video_renderer_impl.h index bfb3d5e..de528fc 100644 --- a/media/renderers/video_renderer_impl.h +++ b/media/renderers/video_renderer_impl.h
@@ -71,6 +71,7 @@ void StartPlayingFrom(base::TimeDelta timestamp) override; void OnTimeProgressing() override; void OnTimeStopped() override; + void SetLatencyHint(base::Optional<base::TimeDelta> latency_hint) override; void SetTickClockForTesting(const base::TickClock* tick_clock); size_t frames_queued_for_testing() const { @@ -79,6 +80,8 @@ size_t effective_frames_queued_for_testing() const { return algorithm_->effective_frames_queued(); } + int min_buffered_frames_for_testing() const { return min_buffered_frames_; } + int max_buffered_frames_for_testing() const { return max_buffered_frames_; } // VideoRendererSink::RenderCallback implementation. scoped_refptr<VideoFrame> Render(base::TimeTicks deadline_min, @@ -137,8 +140,14 @@ // reported, and tracks what the most recently reported frame rate was. void ReportFrameRateIfNeeded_Locked(); - // Returns true if there is no more room for additional buffered frames. - bool HaveReachedBufferingCap() const; + // Update |min_buffered_frames_| and |max_buffered_frames_| using the latest + // |average_frame_duration|. Should only be called when |latency_hint_| > 0. + void UpdateLatencyHintBufferingCaps_Locked( + base::TimeDelta average_frame_duration); + + // Returns true if algorithm_->effective_frames_queued() >= |buffering_cap|, + // or when the number of ineffective frames >= kAbsoluteMaxFrames. + bool HaveReachedBufferingCap(size_t buffering_cap) const; // Starts or stops |sink_| respectively. Do not call while |lock_| is held. void StartSink(); @@ -303,22 +312,35 @@ // Indicates if we've painted the first valid frame after StartPlayingFrom(). bool painted_first_frame_; - // Current minimum and maximum for buffered frames. |min_buffered_frames_| is - // the number of frames required to transition from BUFFERING_HAVE_NOTHING to + // The number of frames required to transition from BUFFERING_HAVE_NOTHING to // BUFFERING_HAVE_ENOUGH. size_t min_buffered_frames_; + // The maximum number of frames to buffer. Always >= |min_buffered_frames_|. + // May be greater-than when |latency_hint_| set that decreases the minimum + // buffering limit. + size_t max_buffered_frames_; + // Last Render() and last FrameReady() times respectively. Used to avoid // triggering underflow when background rendering. base::TimeTicks last_render_time_; base::TimeTicks last_frame_ready_time_; - // Running average of frame durations, without changes due to playback rate. + // Running average of frame durations. FrameRateEstimator fps_estimator_; // Last FPS, if any, reported to the client. base::Optional<int> last_reported_fps_; + // Value saved from last call to SetLatencyHint(). Used to recompute buffering + // limits as framerate fluctuates. + base::Optional<base::TimeDelta> latency_hint_; + + // When latency_hint_ > 0, we make regular adjustments to buffering caps as + // |algorithm_->average_frame_duration()| fluctuates, but we only want to emit + // one MEDIA_LOG. + bool is_latency_hint_media_logged_ = false; + // NOTE: Weak pointers must be invalidated before all other member variables. base::WeakPtrFactory<VideoRendererImpl> weak_factory_{this};
diff --git a/media/renderers/video_renderer_impl_unittest.cc b/media/renderers/video_renderer_impl_unittest.cc index 8eeb090..093dccb 100644 --- a/media/renderers/video_renderer_impl_unittest.cc +++ b/media/renderers/video_renderer_impl_unittest.cc
@@ -106,11 +106,25 @@ demuxer_stream_.set_video_decoder_config(TestVideoConfig::Normal()); - // We expect these to be called but we don't care how/when. - EXPECT_CALL(demuxer_stream_, OnRead(_)) - .WillRepeatedly(RunOnceCallback<0>( - DemuxerStream::kOk, - scoped_refptr<DecoderBuffer>(new DecoderBuffer(0)))); + // We expect these to be called but we don't care how/when. Tests can + // customize the provided buffer returned via MakeDecoderBuffer(). + ON_CALL(demuxer_stream_, OnRead(_)) + .WillByDefault(Invoke(this, &VideoRendererImplTest::MakeDecoderBuffer)); + } + + void MakeDecoderBuffer(DemuxerStream::ReadCB& read_cb) { + scoped_refptr<DecoderBuffer> decoder_buffer(new DecoderBuffer(0)); + + // Set |decoder_buffer| timestamp such that it won't match any of the + // times provided to QueueFrames(). Otherwise the default timestamp of 0 may + // match some frames and not others, which causes non-uniform handling in + // DecoderStreamTraits. + decoder_buffer->set_timestamp(kNoTimestamp); + + // Test hook for to specify a custom buffer duration. + decoder_buffer->set_duration(buffer_duration_); + + std::move(read_cb).Run(DemuxerStream::kOk, decoder_buffer); } ~VideoRendererImplTest() override = default; @@ -337,6 +351,9 @@ WallClockTimeSource time_source_; + // Duration set on DecoderBuffers. See MakeDecoderBuffer(). + base::TimeDelta buffer_duration_; + private: void DecodeRequested(scoped_refptr<DecoderBuffer> buffer, VideoDecoder::DecodeCB& decode_cb) { @@ -600,6 +617,7 @@ EXPECT_CALL(mock_cb_, OnStatisticsUpdate(_)).Times(AnyNumber()); EXPECT_CALL(mock_cb_, OnVideoNaturalSizeChange(_)).Times(1); EXPECT_CALL(mock_cb_, OnVideoOpacityChange(_)).Times(1); + EXPECT_CALL(mock_cb_, OnVideoFrameRateChange(base::Optional<int>(100))); StartPlayingFrom(59); Destroy(); } @@ -613,6 +631,7 @@ EXPECT_CALL(mock_cb_, OnStatisticsUpdate(_)).Times(AnyNumber()); EXPECT_CALL(mock_cb_, OnVideoNaturalSizeChange(_)).Times(1); EXPECT_CALL(mock_cb_, OnVideoOpacityChange(_)).Times(1); + EXPECT_CALL(mock_cb_, OnVideoFrameRateChange(base::Optional<int>(100))); StartPlayingFrom(61); Destroy(); } @@ -1185,7 +1204,13 @@ Destroy(); } -enum class UnderflowTestType { NORMAL, LOW_DELAY, CANT_READ_WITHOUT_STALLING }; +enum class UnderflowTestType { + // Renderer will require a default amount of buffering to reach HAVE_ENOUGH. + NORMAL, + // Both of these require only a single frame to reach HAVE_ENOUGH. + LOW_DELAY, + CANT_READ_WITHOUT_STALLING +}; class UnderflowTest : public VideoRendererImplTest, @@ -1194,13 +1219,13 @@ protected: void SetUp() override { std::tie(test_type, underflow_type) = GetParam(); } - void BasicUnderflowTest(UnderflowTestType type, - BufferingStateChangeReason underflow_type) { - InitializeWithLowDelay(type == UnderflowTestType::LOW_DELAY); - if (type == UnderflowTestType::CANT_READ_WITHOUT_STALLING) + void TestBufferToHaveEnoughThenUnderflow() { + InitializeWithLowDelay(test_type == UnderflowTestType::LOW_DELAY); + + if (test_type == UnderflowTestType::CANT_READ_WITHOUT_STALLING) ON_CALL(*decoder_, CanReadWithoutStalling()).WillByDefault(Return(false)); - QueueFrames("0 30 60 90"); + QueueFrames("0 20 40 60"); { WaitableMessageLoopEvent event; @@ -1217,6 +1242,8 @@ Mock::VerifyAndClearExpectations(&mock_cb_); } + // Start playing. + time_source_.StartTicking(); renderer_->OnTimeProgressing(); // Advance time slightly, but enough to exceed the duration of the last @@ -1225,18 +1252,13 @@ { SCOPED_TRACE("Waiting for frame drops"); WaitableMessageLoopEvent event; + EXPECT_CALL(mock_cb_, FrameReceived(HasTimestampMatcher(20))).Times(0); - // Note: Starting the TimeSource will cause the old VideoRendererImpl to - // start rendering frames on its own thread, so the first frame may be - // received. - time_source_.StartTicking(); - EXPECT_CALL(mock_cb_, FrameReceived(HasTimestampMatcher(30))).Times(0); - - EXPECT_CALL(mock_cb_, FrameReceived(HasTimestampMatcher(60))).Times(0); - EXPECT_CALL(mock_cb_, FrameReceived(HasTimestampMatcher(90))) + EXPECT_CALL(mock_cb_, FrameReceived(HasTimestampMatcher(40))).Times(0); + EXPECT_CALL(mock_cb_, FrameReceived(HasTimestampMatcher(60))) .WillOnce(RunOnceClosure(event.GetClosure())); EXPECT_CALL(mock_cb_, OnStatisticsUpdate(_)).Times(AnyNumber()); - AdvanceTimeInMs(91); + AdvanceTimeInMs(61); event.RunAndWait(); Mock::VerifyAndClearExpectations(&mock_cb_); @@ -1252,69 +1274,7 @@ EXPECT_CALL(mock_cb_, OnBufferingStateChange(BUFFERING_HAVE_NOTHING, underflow_type)) .WillOnce(RunOnceClosure(event.GetClosure())); - AdvanceTimeInMs(30); - event.RunAndWait(); - Mock::VerifyAndClearExpectations(&mock_cb_); - } - - // Simulate delayed buffering state callbacks. - renderer_->OnTimeStopped(); - renderer_->OnTimeProgressing(); - - // Receiving end of stream should signal having enough. - { - SCOPED_TRACE("Waiting for BUFFERING_HAVE_ENOUGH"); - WaitableMessageLoopEvent event; - EXPECT_CALL(mock_cb_, OnStatisticsUpdate(_)).Times(AnyNumber()); - EXPECT_CALL(mock_cb_, - OnBufferingStateChange(BUFFERING_HAVE_ENOUGH, - BUFFERING_CHANGE_REASON_UNKNOWN)) - .WillOnce(RunOnceClosure(event.GetClosure())); - EXPECT_CALL(mock_cb_, OnEnded()); - SatisfyPendingDecodeWithEndOfStream(); - event.RunAndWait(); - } - - Destroy(); - } - - void UnderflowRecoveryTest(UnderflowTestType type, - BufferingStateChangeReason underflow_type) { - InitializeWithLowDelay(type == UnderflowTestType::LOW_DELAY); - if (type == UnderflowTestType::CANT_READ_WITHOUT_STALLING) - ON_CALL(*decoder_, CanReadWithoutStalling()).WillByDefault(Return(false)); - - QueueFrames("0 20 40 60"); - { - WaitableMessageLoopEvent event; - EXPECT_CALL(mock_cb_, FrameReceived(HasTimestampMatcher(0))); - EXPECT_CALL(mock_cb_, - OnBufferingStateChange(BUFFERING_HAVE_ENOUGH, - BUFFERING_CHANGE_REASON_UNKNOWN)) - .WillOnce(RunOnceClosure(event.GetClosure())); - EXPECT_CALL(mock_cb_, OnStatisticsUpdate(_)).Times(AnyNumber()); - EXPECT_CALL(mock_cb_, OnVideoNaturalSizeChange(_)).Times(1); - EXPECT_CALL(mock_cb_, OnVideoOpacityChange(_)).Times(1); - StartPlayingFrom(0); - event.RunAndWait(); - Mock::VerifyAndClearExpectations(&mock_cb_); - } - - renderer_->OnTimeProgressing(); - time_source_.StartTicking(); - - // Advance time, this should cause have nothing to be signaled. - { - SCOPED_TRACE("Waiting for BUFFERING_HAVE_NOTHING"); - WaitableMessageLoopEvent event; - EXPECT_CALL(demuxer_stream_, IsReadPending()) - .WillOnce(Return(underflow_type == DEMUXER_UNDERFLOW)); - EXPECT_CALL(mock_cb_, OnBufferingStateChange(BUFFERING_HAVE_NOTHING, - underflow_type)) - .WillOnce(RunOnceClosure(event.GetClosure())); - EXPECT_CALL(mock_cb_, FrameReceived(HasTimestampMatcher(60))).Times(1); - EXPECT_CALL(mock_cb_, OnStatisticsUpdate(_)).Times(AnyNumber()); - AdvanceTimeInMs(79); + AdvanceTimeInMs(18); event.RunAndWait(); Mock::VerifyAndClearExpectations(&mock_cb_); } @@ -1325,43 +1285,86 @@ EXPECT_EQ(0u, renderer_->frames_queued_for_testing()); ASSERT_TRUE(IsReadPending()); - // Queue some frames, satisfy reads, and make sure expired frames are gone - // when the renderer paints the first frame. - { - SCOPED_TRACE("Waiting for BUFFERING_HAVE_ENOUGH"); - WaitableMessageLoopEvent event; - EXPECT_CALL(mock_cb_, FrameReceived(HasTimestampMatcher(80))).Times(1); - EXPECT_CALL(mock_cb_, OnStatisticsUpdate(_)).Times(AnyNumber()); - EXPECT_CALL(mock_cb_, - OnBufferingStateChange(BUFFERING_HAVE_ENOUGH, - BUFFERING_CHANGE_REASON_UNKNOWN)) - .WillOnce(RunOnceClosure(event.GetClosure())); - EXPECT_CALL(mock_cb_, OnVideoFrameRateChange(base::Optional<int>(50))); - - // Note: In the normal underflow case we queue 5 frames here instead of - // four since the underflow increases the number of required frames to - // reach the have enough state. - if (type == UnderflowTestType::NORMAL) - QueueFrames("80 100 120 140 160"); - else - QueueFrames("40 60 80 90 100"); - SatisfyPendingDecode(); - event.RunAndWait(); + // Stopping time signals a confirmed underflow to VRI. Verify updates to + // buffering limits. + switch (test_type) { + // In the normal and cant_read modes, min and max buffered frames should + // always be equal, and both should increase upon underflow. + case UnderflowTestType::NORMAL: + case UnderflowTestType::CANT_READ_WITHOUT_STALLING: + EXPECT_EQ(renderer_->min_buffered_frames_for_testing(), + limits::kMaxVideoFrames + 1); + EXPECT_EQ(renderer_->max_buffered_frames_for_testing(), + limits::kMaxVideoFrames + 1); + break; + // In low_delay mode only the max should increase while min remains 1. + case UnderflowTestType::LOW_DELAY: + EXPECT_EQ(renderer_->min_buffered_frames_for_testing(), 1); + EXPECT_EQ(renderer_->max_buffered_frames_for_testing(), + limits::kMaxVideoFrames + 1); + break; } - - Destroy(); } UnderflowTestType test_type; BufferingStateChangeReason underflow_type; }; -TEST_P(UnderflowTest, BasicUnderflowTest) { - BasicUnderflowTest(test_type, underflow_type); +TEST_P(UnderflowTest, UnderflowAndEosTest) { + TestBufferToHaveEnoughThenUnderflow(); + + // Receiving end of stream should signal having enough. + { + SCOPED_TRACE("Waiting for BUFFERING_HAVE_ENOUGH"); + WaitableMessageLoopEvent event; + EXPECT_CALL(mock_cb_, OnStatisticsUpdate(_)).Times(AnyNumber()); + EXPECT_CALL(mock_cb_, + OnBufferingStateChange(BUFFERING_HAVE_ENOUGH, + BUFFERING_CHANGE_REASON_UNKNOWN)) + .WillOnce(RunOnceClosure(event.GetClosure())); + EXPECT_CALL(mock_cb_, OnEnded()); + SatisfyPendingDecodeWithEndOfStream(); + event.RunAndWait(); + } + + Destroy(); } -TEST_P(UnderflowTest, UnderflowRecoveryTest) { - UnderflowRecoveryTest(test_type, underflow_type); +TEST_P(UnderflowTest, UnderflowAndRecoverTest) { + TestBufferToHaveEnoughThenUnderflow(); + + // Queue some frames, satisfy reads, and make sure expired frames are gone + // when the renderer paints the first frame. + { + SCOPED_TRACE("Waiting for BUFFERING_HAVE_ENOUGH"); + WaitableMessageLoopEvent event; + EXPECT_CALL(mock_cb_, FrameReceived(HasTimestampMatcher(80))).Times(1); + EXPECT_CALL(mock_cb_, OnStatisticsUpdate(_)).Times(AnyNumber()); + EXPECT_CALL(mock_cb_, + OnBufferingStateChange(BUFFERING_HAVE_ENOUGH, + BUFFERING_CHANGE_REASON_UNKNOWN)) + .WillOnce(RunOnceClosure(event.GetClosure())); + + switch (test_type) { + // In the normal underflow case we queue 5 frames here instead of four + // since the underflow increases the number of required frames to reach + // the have enough state. + case UnderflowTestType::NORMAL: + QueueFrames("80 100 120 140 160"); + EXPECT_CALL(mock_cb_, OnVideoFrameRateChange(base::Optional<int>(50))); + break; + // In either of these modes the HAVE_ENOUGH transition should still + // occur with a single frame. + case UnderflowTestType::LOW_DELAY: + case UnderflowTestType::CANT_READ_WITHOUT_STALLING: + QueueFrames("80"); + break; + } + SatisfyPendingDecode(); + event.RunAndWait(); + } + + Destroy(); } INSTANTIATE_TEST_SUITE_P( @@ -1372,4 +1375,333 @@ UnderflowTestType::CANT_READ_WITHOUT_STALLING), Values(DEMUXER_UNDERFLOW, DECODER_UNDERFLOW))); +class VideoRendererLatencyHintTest : public VideoRendererImplTest { + public: + void VerifyDefaultRebufferingBehavior(int start_playing_from) { + // Keep it simple. Only call this if you're starting from empty. + DCHECK_EQ(renderer_->effective_frames_queued_for_testing(), 0u); + + // Initial frames should trigger various callbacks. + EXPECT_CALL(mock_cb_, + FrameReceived(HasTimestampMatcher(start_playing_from))); + EXPECT_CALL(mock_cb_, OnStatisticsUpdate(_)).Times(AnyNumber()); + EXPECT_CALL(mock_cb_, OnVideoNaturalSizeChange(_)).Times(AnyNumber()); + EXPECT_CALL(mock_cb_, OnVideoOpacityChange(_)).Times(AnyNumber()); + EXPECT_CALL(mock_cb_, OnVideoFrameRateChange(_)).Times(AnyNumber()); + + // Queue 3 frames, 20 msec apart. Stop 1 shy of min_buffered_frames_. + ASSERT_EQ(renderer_->min_buffered_frames_for_testing(), 4); + int frame_time = start_playing_from; + for (int i = 0; i < 3; i++) { + QueueFrames(base::NumberToString(frame_time)); + frame_time += 20; + } + + // Verify no transition to HAVE_ENOUGH since 3 < |min_buffered_frames_| + EXPECT_CALL(mock_cb_, OnBufferingStateChange(BUFFERING_HAVE_ENOUGH, _)) + .Times(0); + + StartPlayingFrom(start_playing_from); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(renderer_->effective_frames_queued_for_testing(), 3u); + Mock::VerifyAndClearExpectations(&mock_cb_); + + // Queuing one extra frame should trigger the transition. + QueueFrames(base::NumberToString(frame_time)); + SatisfyPendingDecode(); + EXPECT_CALL(mock_cb_, OnStatisticsUpdate(_)).Times(AnyNumber()); + EXPECT_CALL(mock_cb_, OnVideoFrameRateChange(_)).Times(AnyNumber()); + EXPECT_CALL(mock_cb_, OnBufferingStateChange(BUFFERING_HAVE_ENOUGH, _)); + base::RunLoop().RunUntilIdle(); + Mock::VerifyAndClearExpectations(&mock_cb_); + } +}; + +// Test default HaveEnough transition when no latency hint is set. +TEST_F(VideoRendererLatencyHintTest, HaveEnough_NoLatencyHint) { + Initialize(); + VerifyDefaultRebufferingBehavior(0); + Destroy(); +} + +// Test early HaveEnough transition when low latency hint is set. +TEST_F(VideoRendererLatencyHintTest, HaveEnough_LowLatencyHint) { + Initialize(); + + // Set latencyHint to bare minimum. + renderer_->SetLatencyHint(base::TimeDelta()); + + // Initial frames should trigger various callbacks. + EXPECT_CALL(mock_cb_, FrameReceived(HasTimestampMatcher(0))); + EXPECT_CALL(mock_cb_, OnStatisticsUpdate(_)).Times(1); + EXPECT_CALL(mock_cb_, OnVideoNaturalSizeChange(_)).Times(1); + EXPECT_CALL(mock_cb_, OnVideoOpacityChange(_)).Times(1); + EXPECT_CALL(mock_cb_, OnBufferingStateChange(BUFFERING_HAVE_ENOUGH, _)); + + // Only 1 frame should be needed to trigger have enough. + ASSERT_EQ(renderer_->min_buffered_frames_for_testing(), 1); + QueueFrames("0"); + + StartPlayingFrom(0); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(renderer_->effective_frames_queued_for_testing(), 1u); + Mock::VerifyAndClearExpectations(&mock_cb_); + + // Verify latency hint doesn't reduce our ability to buffer beyond the + // 1-frame HAVE_ENOUGH (i.e. don't throttle decoding in the name of latency). + EXPECT_EQ(renderer_->max_buffered_frames_for_testing(), 4); + EXPECT_CALL(mock_cb_, OnStatisticsUpdate(_)).Times(3); + QueueFrames("10 20 30"); + WaitForPendingDecode(); + SatisfyPendingDecode(); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(renderer_->frames_queued_for_testing(), 4u); + + // Unset latencyHint, to verify default behavior. + renderer_->SetLatencyHint(base::nullopt); + + // Flush to return to clean slate. + EXPECT_CALL(mock_cb_, OnBufferingStateChange(BUFFERING_HAVE_NOTHING, _)); + Flush(); + + VerifyDefaultRebufferingBehavior(1000); + + Destroy(); +} + +// Test late HaveEnough transition when high latency hint is set. +TEST_F(VideoRendererLatencyHintTest, HaveEnough_HighLatencyHint) { + Initialize(); + + // We must provide a |buffer_duration_| for the latencyHint to take effect + // immediately. The VideoRendererAlgorithm will eventually provide a PTS-delta + // duration, but not until after we've started rendering. + buffer_duration_ = base::TimeDelta::FromMilliseconds(30); + + // Set latencyHint to a large value. + renderer_->SetLatencyHint(base::TimeDelta::FromMilliseconds(400)); + + // Initial frames should trigger various callbacks. + EXPECT_CALL(mock_cb_, FrameReceived(HasTimestampMatcher(0))); + EXPECT_CALL(mock_cb_, OnVideoNaturalSizeChange(_)).Times(1); + EXPECT_CALL(mock_cb_, OnVideoOpacityChange(_)).Times(1); + EXPECT_CALL(mock_cb_, OnStatisticsUpdate(_)).Times(AnyNumber()); + + // Queue 12 frames, each 30 ms apart. At this framerate, 400ms rounds to 13 + // frames, so 12 frames should be 1 shy of the HaveEnough threshold. + EXPECT_CALL(mock_cb_, OnVideoFrameRateChange(base::Optional<int>(33))); + EXPECT_CALL(mock_cb_, OnBufferingStateChange(BUFFERING_HAVE_ENOUGH, _)) + .Times(0); + QueueFrames("0 30 60 90 120 150 180 210 240 270 300 330"); + + StartPlayingFrom(0); + base::RunLoop().RunUntilIdle(); + ASSERT_EQ(renderer_->min_buffered_frames_for_testing(), 13); + EXPECT_EQ(renderer_->effective_frames_queued_for_testing(), 12u); + Mock::VerifyAndClearExpectations(&mock_cb_); + + // Queue 1 additional frame and verify HaveEnough threshold is reached. + EXPECT_CALL(mock_cb_, OnStatisticsUpdate(_)).Times(AnyNumber()); + EXPECT_CALL(mock_cb_, OnBufferingStateChange(BUFFERING_HAVE_ENOUGH, _)); + QueueFrames("360"); + SatisfyPendingDecode(); + base::RunLoop().RunUntilIdle(); + Mock::VerifyAndClearExpectations(&mock_cb_); + + // Unset latencyHint, to verify default behavior. + renderer_->SetLatencyHint(base::nullopt); + + // Flush to return to clean slate. + EXPECT_CALL(mock_cb_, OnBufferingStateChange(BUFFERING_HAVE_NOTHING, _)); + Flush(); + Mock::VerifyAndClearExpectations(&mock_cb_); + + VerifyDefaultRebufferingBehavior(1000); + + Destroy(); +} + +// Test updates to buffering limits upon underflow when latency hint set. +TEST_F(VideoRendererLatencyHintTest, + LatencyHintUnderflowUpdatesMaxBufferingLimit) { + // Enable low delay mode. Low delay mode is tested separately. + InitializeWithLowDelay(true); + EXPECT_EQ(renderer_->min_buffered_frames_for_testing(), 1); + + // We must provide a |buffer_duration_| for the latencyHint to take effect + // immediately. The VideoRendererAlgorithm will eventually provide a PTS-delta + // duration, but not until after we've started rendering. + buffer_duration_ = base::TimeDelta::FromMilliseconds(30); + + // Set latency hint to a medium value. + renderer_->SetLatencyHint(base::TimeDelta::FromMilliseconds(200)); + + // Queue up enough frames to trigger HAVE_ENOUGH. Each frame is 30 ms apart. + // At this spacing, 200ms rounds to 7 frames. + EXPECT_CALL(mock_cb_, FrameReceived(HasTimestampMatcher(0))); + EXPECT_CALL(mock_cb_, OnVideoNaturalSizeChange(_)).Times(1); + EXPECT_CALL(mock_cb_, OnVideoOpacityChange(_)).Times(1); + EXPECT_CALL(mock_cb_, OnStatisticsUpdate(_)).Times(AnyNumber()); + EXPECT_CALL(mock_cb_, OnVideoFrameRateChange(base::Optional<int>(33))); + EXPECT_CALL(mock_cb_, OnBufferingStateChange(BUFFERING_HAVE_ENOUGH, _)); + QueueFrames("0 30 60 90 120 150 180"); + StartPlayingFrom(0); + base::RunLoop().RunUntilIdle(); + ASSERT_EQ(renderer_->min_buffered_frames_for_testing(), 7); + EXPECT_EQ(renderer_->effective_frames_queued_for_testing(), 7u); + Mock::VerifyAndClearExpectations(&mock_cb_); + + // Advance time to trigger HAVE_NOTHING (underflow). + { + SCOPED_TRACE("Waiting for BUFFERING_HAVE_NOTHING"); + WaitableMessageLoopEvent event; + EXPECT_CALL(mock_cb_, FrameReceived(HasTimestampMatcher(180))); + EXPECT_CALL(demuxer_stream_, IsReadPending()).WillOnce(Return(true)); + EXPECT_CALL(mock_cb_, OnBufferingStateChange(BUFFERING_HAVE_NOTHING, + DEMUXER_UNDERFLOW)) + .WillOnce(RunOnceClosure(event.GetClosure())); + renderer_->OnTimeProgressing(); + time_source_.StartTicking(); + AdvanceTimeInMs(300); + event.RunAndWait(); + Mock::VerifyAndClearExpectations(&mock_cb_); + } + + // Simulate delayed buffering state callbacks. + time_source_.StopTicking(); + renderer_->OnTimeStopped(); + + // When latency hint set the max should increase while min remains steady + // (user controls the min via hint). + EXPECT_EQ(renderer_->min_buffered_frames_for_testing(), 7); + EXPECT_EQ(renderer_->max_buffered_frames_for_testing(), 7 + 1); + + Destroy(); +} + +// Test that latency hint overrides low delay mode. +TEST_F(VideoRendererLatencyHintTest, LatencyHintOverridesLowDelay) { + // Enable low delay mode. Low delay mode is tested separately. + InitializeWithLowDelay(true); + EXPECT_EQ(renderer_->min_buffered_frames_for_testing(), 1); + + // We must provide a |buffer_duration_| for the latencyHint to take effect + // immediately. The VideoRendererAlgorithm will eventually provide a PTS-delta + // duration, but not until after we've started rendering. + buffer_duration_ = base::TimeDelta::FromMilliseconds(30); + + // Set latency hint to a medium value. + renderer_->SetLatencyHint(base::TimeDelta::FromMilliseconds(200)); + + // Initial frames should trigger various callbacks. + EXPECT_CALL(mock_cb_, FrameReceived(HasTimestampMatcher(0))); + EXPECT_CALL(mock_cb_, OnVideoNaturalSizeChange(_)).Times(1); + EXPECT_CALL(mock_cb_, OnVideoOpacityChange(_)).Times(1); + EXPECT_CALL(mock_cb_, OnStatisticsUpdate(_)).Times(AnyNumber()); + + // Queue 6 frames, each 30 ms apart. At this spacing, 200ms rounds to + // 7 frames, so 6 frames should be 1 shy of the HaveEnough threshold. Verify + // that HAVE_ENOUGH is not triggered in spite of being initialized with low + // delay mode. + EXPECT_CALL(mock_cb_, OnVideoFrameRateChange(base::Optional<int>(33))); + EXPECT_CALL(mock_cb_, OnBufferingStateChange(BUFFERING_HAVE_ENOUGH, _)) + .Times(0); + QueueFrames("0 30 60 90 120 150"); + StartPlayingFrom(0); + base::RunLoop().RunUntilIdle(); + ASSERT_EQ(renderer_->min_buffered_frames_for_testing(), 7); + EXPECT_EQ(renderer_->effective_frames_queued_for_testing(), 6u); + Mock::VerifyAndClearExpectations(&mock_cb_); + + // Queue 1 additional frame and verify HaveEnough threshold is reached. + EXPECT_CALL(mock_cb_, OnStatisticsUpdate(_)).Times(AnyNumber()); + EXPECT_CALL(mock_cb_, OnBufferingStateChange(BUFFERING_HAVE_ENOUGH, _)); + QueueFrames("180"); + SatisfyPendingDecode(); + base::RunLoop().RunUntilIdle(); + Mock::VerifyAndClearExpectations(&mock_cb_); + + // Unset latencyHint, to verify default behavior. NOTE: low delay mode is not + // restored when latency hint unset. + renderer_->SetLatencyHint(base::nullopt); + + // Flush to return to clean slate. + EXPECT_CALL(mock_cb_, OnBufferingStateChange(BUFFERING_HAVE_NOTHING, _)); + Flush(); + Mock::VerifyAndClearExpectations(&mock_cb_); + + VerifyDefaultRebufferingBehavior(1000); + + Destroy(); +} + +// Test that !CanReadWithoutStalling() overrides latency hint. +TEST_F(VideoRendererLatencyHintTest, + CantReadWithoutStallingOverridesLatencyHint) { + Initialize(); + + // Let decoder indicate that it CANT read without stalling, meaning we should + // enter HAVE_ENOUGH with just one effective frame (waiting for more frames + // will stall the decoder). + ON_CALL(*decoder_, CanReadWithoutStalling()).WillByDefault(Return(false)); + + // We must provide a |buffer_duration_| for the latencyHint to take effect + // immediately. The VideoRendererAlgorithm will eventually provide a PTS-delta + // duration, but not until after we've started rendering. + buffer_duration_ = base::TimeDelta::FromMilliseconds(30); + + // Set latency hint to a medium value. At a spacing of 30ms this would set + // the HAVE_ENOUGH threshold to 4 frames. + renderer_->SetLatencyHint(base::TimeDelta::FromMilliseconds(200)); + + // Initial frames should trigger various callbacks. + EXPECT_CALL(mock_cb_, FrameReceived(HasTimestampMatcher(0))); + EXPECT_CALL(mock_cb_, OnVideoNaturalSizeChange(_)).Times(1); + EXPECT_CALL(mock_cb_, OnVideoOpacityChange(_)).Times(1); + EXPECT_CALL(mock_cb_, OnStatisticsUpdate(_)).Times(AnyNumber()); + + // Queue 1 frame. This is well short of what the latency hint would require, + // but we CANT READ WITHOUT STALLING, so expect a transition to HAVE_ENOUGH + // after just 1 frame. + EXPECT_CALL(mock_cb_, OnBufferingStateChange(BUFFERING_HAVE_ENOUGH, _)); + QueueFrames("0"); + StartPlayingFrom(0); + base::RunLoop().RunUntilIdle(); + ASSERT_EQ(renderer_->min_buffered_frames_for_testing(), 7); + EXPECT_EQ(renderer_->effective_frames_queued_for_testing(), 1u); + Mock::VerifyAndClearExpectations(&mock_cb_); + + // Queue some additional frames, verify buffering state holds at HAVE_ENOUGH. + QueueFrames("30 60 90 120"); + EXPECT_CALL(mock_cb_, OnStatisticsUpdate(_)).Times(AnyNumber()); + EXPECT_CALL(mock_cb_, OnBufferingStateChange(_, _)).Times(0); + // SatisfyPendingDecode(); + base::RunLoop().RunUntilIdle(); + Mock::VerifyAndClearExpectations(&mock_cb_); + + // Unset latency hint to verify 1-frame HAVE_ENOUGH threshold is maintained. + renderer_->SetLatencyHint(base::nullopt); + + // Flush to return to clean slate. + EXPECT_CALL(mock_cb_, OnBufferingStateChange(BUFFERING_HAVE_NOTHING, _)); + Flush(); + Mock::VerifyAndClearExpectations(&mock_cb_); + + // Expect HAVE_ENOUGH (and various other callbacks) again. + EXPECT_CALL(mock_cb_, OnBufferingStateChange(BUFFERING_HAVE_ENOUGH, _)); + EXPECT_CALL(mock_cb_, FrameReceived(HasTimestampMatcher(1000))); + EXPECT_CALL(mock_cb_, OnStatisticsUpdate(_)).Times(AnyNumber()); + EXPECT_CALL(mock_cb_, OnVideoFrameRateChange(_)).Times(AnyNumber()); + + // Queue 1 frame. + QueueFrames("1000"); + StartPlayingFrom(1000); + base::RunLoop().RunUntilIdle(); + ASSERT_EQ(renderer_->min_buffered_frames_for_testing(), 4); + EXPECT_EQ(renderer_->effective_frames_queued_for_testing(), 1u); + Mock::VerifyAndClearExpectations(&mock_cb_); + + Destroy(); +} + } // namespace media
diff --git a/mojo/public/tools/bindings/chromium_bindings_configuration.gni b/mojo/public/tools/bindings/chromium_bindings_configuration.gni index 98c78e5..2eb03f7 100644 --- a/mojo/public/tools/bindings/chromium_bindings_configuration.gni +++ b/mojo/public/tools/bindings/chromium_bindings_configuration.gni
@@ -34,10 +34,7 @@ "//services/resource_coordinator/public/cpp/typemaps.gni", "//services/service_manager/public/cpp/typemaps.gni", "//services/tracing/public/mojom/typemaps.gni", - "//services/viz/privileged/cpp/typemaps.gni", - "//services/viz/privileged/mojom/compositing/typemaps.gni", "//services/viz/public/cpp/compositing/typemaps.gni", - "//services/viz/public/cpp/hit_test/typemaps.gni", "//skia/public/mojom/typemaps.gni", "//third_party/blink/common/typemaps.gni", "//third_party/blink/public/public_typemaps.gni",
diff --git a/net/BUILD.gn b/net/BUILD.gn index d64896d..b135b51b 100644 --- a/net/BUILD.gn +++ b/net/BUILD.gn
@@ -611,8 +611,6 @@ "disk_cache/blockfile/storage_block-inl.h", "disk_cache/blockfile/storage_block.h", "disk_cache/blockfile/stress_support.h", - "disk_cache/blockfile/trace.cc", - "disk_cache/blockfile/trace.h", "disk_cache/cache_util.cc", "disk_cache/cache_util.h", "disk_cache/disk_cache.cc",
diff --git a/net/base/features.cc b/net/base/features.cc index 2e41e84..169f251 100644 --- a/net/base/features.cc +++ b/net/base/features.cc
@@ -57,11 +57,11 @@ const base::FeatureParam<int> kEsniDnsMaxRelativeAdditionalWaitPercent{ &kRequestEsniDnsRecords, "EsniDnsMaxRelativeAdditionalWaitPercent", 5}; -const base::Feature kSameSiteByDefaultCookies{ - "SameSiteByDefaultCookies", base::FEATURE_DISABLED_BY_DEFAULT}; +const base::Feature kSameSiteByDefaultCookies{"SameSiteByDefaultCookies", + base::FEATURE_ENABLED_BY_DEFAULT}; const base::Feature kCookiesWithoutSameSiteMustBeSecure{ - "CookiesWithoutSameSiteMustBeSecure", base::FEATURE_DISABLED_BY_DEFAULT}; + "CookiesWithoutSameSiteMustBeSecure", base::FEATURE_ENABLED_BY_DEFAULT}; const base::Feature kShortLaxAllowUnsafeThreshold{ "ShortLaxAllowUnsafeThreshold", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/net/disk_cache/blockfile/backend_impl.cc b/net/disk_cache/blockfile/backend_impl.cc index 342795d3..f845fa78 100644 --- a/net/disk_cache/blockfile/backend_impl.cc +++ b/net/disk_cache/blockfile/backend_impl.cc
@@ -31,6 +31,7 @@ #include "base/time/time.h" #include "base/timer/timer.h" #include "base/trace_event/process_memory_dump.h" +#include "base/trace_event/trace_event.h" #include "net/base/net_errors.h" #include "net/disk_cache/backend_cleanup_tracker.h" #include "net/disk_cache/blockfile/disk_format.h" @@ -172,7 +173,9 @@ consider_evicting_at_op_end_(false), net_log_(net_log), done_(base::WaitableEvent::ResetPolicy::MANUAL, - base::WaitableEvent::InitialState::NOT_SIGNALED) {} + base::WaitableEvent::InitialState::NOT_SIGNALED) { + TRACE_EVENT0("disk_cache", "BackendImpl::BackendImpl"); +} BackendImpl::BackendImpl( const base::FilePath& path, @@ -200,9 +203,12 @@ consider_evicting_at_op_end_(false), net_log_(net_log), done_(base::WaitableEvent::ResetPolicy::MANUAL, - base::WaitableEvent::InitialState::NOT_SIGNALED) {} + base::WaitableEvent::InitialState::NOT_SIGNALED) { + TRACE_EVENT0("disk_cache", "BackendImpl::BackendImpl"); +} BackendImpl::~BackendImpl() { + TRACE_EVENT0("disk_cache", "BackendImpl::~BackendImpl"); if (user_flags_ & kNoRandom) { // This is a unit test, so we want to be strict about not leaking entries // and completing all the work. @@ -232,6 +238,8 @@ } int BackendImpl::SyncInit() { + TRACE_EVENT0("disk_cache", "BackendImpl::SyncInit"); + #if defined(NET_BUILD_STRESS_CACHE) // Start evictions right away. up_ticks_ = kTrimDelay * 2; @@ -252,12 +260,10 @@ bool should_create_timer = false; if (!restarted_) { buffer_bytes_ = 0; - trace_object_ = TraceObject::GetTraceObject(); should_create_timer = true; } init_ = true; - Trace("Init"); if (data_->header.experiment != NO_EXPERIMENT && GetCacheType() != net::DISK_CACHE) { @@ -344,7 +350,8 @@ void BackendImpl::CleanupCache() { DCHECK(background_queue_.BackgroundIsCurrentSequence()); - Trace("Backend Cleanup"); + TRACE_EVENT0("disk_cache", "BackendImpl::CleanupCache"); + eviction_.Stop(); timer_.reset(); @@ -417,6 +424,8 @@ int BackendImpl::SyncDoomEntriesBetween(const base::Time initial_time, const base::Time end_time) { + TRACE_EVENT0("disk_cache", "BackendImpl::SyncDoomEntriesBetween"); + DCHECK_NE(net::APP_CACHE, GetCacheType()); if (end_time.is_null()) return SyncDoomEntriesSince(initial_time); @@ -449,6 +458,8 @@ } int BackendImpl::SyncCalculateSizeOfAllEntries() { + TRACE_EVENT0("disk_cache", "BackendImpl::SyncCalculateSizeOfAllEntries"); + DCHECK_NE(net::APP_CACHE, GetCacheType()); if (disabled_) return net::ERR_FAILED; @@ -459,6 +470,8 @@ // We use OpenNextEntryImpl to retrieve elements from the cache, until we get // entries that are too old. int BackendImpl::SyncDoomEntriesSince(const base::Time initial_time) { + TRACE_EVENT0("disk_cache", "BackendImpl::SyncDoomEntriesSince"); + DCHECK_NE(net::APP_CACHE, GetCacheType()); if (disabled_) return net::ERR_FAILED; @@ -485,6 +498,8 @@ int BackendImpl::SyncOpenNextEntry(Rankings::Iterator* iterator, scoped_refptr<EntryImpl>* next_entry) { + TRACE_EVENT0("disk_cache", "BackendImpl::SyncOpenNextEntry"); + *next_entry = OpenNextEntryImpl(iterator); return (*next_entry) ? net::OK : net::ERR_FAILED; } @@ -507,12 +522,13 @@ } scoped_refptr<EntryImpl> BackendImpl::OpenEntryImpl(const std::string& key) { + TRACE_EVENT0("disk_cache", "BackendImpl::OpenEntryImpl"); + if (disabled_) return nullptr; TimeTicks start = TimeTicks::Now(); uint32_t hash = base::PersistentHash(key); - Trace("Open hash 0x%x", hash); bool error; scoped_refptr<EntryImpl> cache_entry = @@ -535,8 +551,6 @@ eviction_.OnOpenEntry(cache_entry.get()); entry_count_++; - Trace("Open hash 0x%x end: 0x%x", hash, - cache_entry->entry()->address().value()); CACHE_UMA(AGE_MS, "OpenTime", 0, start); CACHE_UMA(COUNTS_10000, "AllOpenBySize.Hit", 0, current_size); CACHE_UMA(HOURS, "AllOpenByTotalHours.Hit", 0, @@ -548,12 +562,13 @@ } scoped_refptr<EntryImpl> BackendImpl::CreateEntryImpl(const std::string& key) { + TRACE_EVENT0("disk_cache", "BackendImpl::CreateEntryImpl"); + if (disabled_ || key.empty()) return nullptr; TimeTicks start = TimeTicks::Now(); uint32_t hash = base::PersistentHash(key); - Trace("Create hash 0x%x", hash); scoped_refptr<EntryImpl> parent; Addr entry_address(data_->table[hash & mask_]); @@ -638,7 +653,6 @@ CACHE_UMA(AGE_MS, "CreateTime", 0, start); stats_.OnEvent(Stats::CREATE_HIT); - Trace("create entry hit "); FlushIndex(); return cache_entry; } @@ -746,6 +760,7 @@ } bool BackendImpl::CreateExternalFile(Addr* address) { + TRACE_EVENT0("disk_cache", "BackendImpl::CreateExternalFile"); int file_number = data_->header.last_file + 1; Addr file_address(0); bool success = false; @@ -827,8 +842,6 @@ MatchEntry(key, hash, true, entry_addr, &error); CacheAddr child(entry->GetNextAddress()); - Trace("Doom entry 0x%p", entry); - if (!entry->doomed()) { // We may have doomed this entry from within MatchEntry. eviction_.OnDoomEntry(entry); @@ -892,7 +905,6 @@ DCHECK_NE(ENTRY_NORMAL, entry->entry()->Data()->state); - Trace("Remove entry 0x%p", entry); eviction_.OnDestroyEntry(entry); DecreaseNumEntries(); } @@ -1524,6 +1536,8 @@ } void BackendImpl::RestartCache(bool failure) { + TRACE_EVENT0("disk_cache", "BackendImpl::RestartCache"); + int64_t errors = stats_.GetCounter(Stats::FATAL_ERROR); int64_t full_dooms = stats_.GetCounter(Stats::DOOM_CACHE); int64_t partial_dooms = stats_.GetCounter(Stats::DOOM_RECENT); @@ -1632,11 +1646,6 @@ // Prevent overwriting the dirty flag on the destructor. cache_entry->SetDirtyFlag(GetCurrentEntryId()); - if (cache_entry->dirty()) { - Trace("Dirty entry 0x%p 0x%x", reinterpret_cast<void*>(cache_entry.get()), - address.value()); - } - open_entries_[address.value()] = cache_entry.get(); cache_entry->BeginLogging(net_log_, false); @@ -1649,6 +1658,8 @@ bool find_parent, Addr entry_addr, bool* match_error) { + TRACE_EVENT0("disk_cache", "BackendImpl::MatchEntry"); + Addr address(data_->table[hash & mask_]); scoped_refptr<EntryImpl> cache_entry, parent_entry; bool found = false; @@ -1662,7 +1673,6 @@ if (visited.find(address.value()) != visited.end()) { // It's possible for a buggy version of the code to write a loop. Just // break it. - Trace("Hash collision loop 0x%x", address.value()); address.set_value(0); parent_entry->SetNextAddress(address); } @@ -1689,16 +1699,11 @@ data_->table[hash & mask_] = child.value(); } - Trace("MatchEntry dirty %d 0x%x 0x%x", find_parent, entry_addr.value(), - address.value()); - if (!error) { // It is important to call DestroyInvalidEntry after removing this // entry from the table. DestroyInvalidEntry(cache_entry.get()); cache_entry = nullptr; - } else { - Trace("NewEntry failed on MatchEntry 0x%x", address.value()); } // Restart the search. @@ -1713,7 +1718,6 @@ cache_entry = nullptr; found = true; if (find_parent && entry_addr.value() != address.value()) { - Trace("Entry not on the index 0x%x", address.value()); *match_error = true; parent_entry = nullptr; } @@ -1816,7 +1820,6 @@ if (ENTRY_NORMAL == deleted_entry->entry()->Data()->state) { deleted_entry = nullptr; stats_.OnEvent(Stats::CREATE_MISS); - Trace("create entry miss "); return nullptr; } @@ -1827,13 +1830,11 @@ entry_count_++; stats_.OnEvent(Stats::RESURRECT_HIT); - Trace("Resurrect entry hit "); return deleted_entry; } void BackendImpl::DestroyInvalidEntry(EntryImpl* entry) { LOG(WARNING) << "Destroying invalid entry."; - Trace("Destroying invalid entry 0x%p", entry); entry->SetPointerForInvalidEntry(GetCurrentEntryId()); @@ -2098,7 +2099,6 @@ } } - Trace("CheckAllEntries End"); if (num_entries + num_dirty != data_->header.num_entries) { LOG(ERROR) << "Number of entries " << num_entries << " " << num_dirty << " " << data_->header.num_entries;
diff --git a/net/disk_cache/blockfile/backend_impl.h b/net/disk_cache/blockfile/backend_impl.h index a48da439e..3a7e77a 100644 --- a/net/disk_cache/blockfile/backend_impl.h +++ b/net/disk_cache/blockfile/backend_impl.h
@@ -22,7 +22,6 @@ #include "net/disk_cache/blockfile/rankings.h" #include "net/disk_cache/blockfile/stats.h" #include "net/disk_cache/blockfile/stress_support.h" -#include "net/disk_cache/blockfile/trace.h" #include "net/disk_cache/disk_cache.h" namespace base { @@ -426,7 +425,6 @@ Stats stats_; // Usage statistics. std::unique_ptr<base::RepeatingTimer> timer_; // Usage timer. base::WaitableEvent done_; // Signals the end of background work. - scoped_refptr<TraceObject> trace_object_; // Initializes internal tracing. base::WeakPtrFactory<BackendImpl> ptr_factory_{this}; DISALLOW_COPY_AND_ASSIGN(BackendImpl);
diff --git a/net/disk_cache/blockfile/block_files.cc b/net/disk_cache/blockfile/block_files.cc index e4df9dcd..ebce45c 100644 --- a/net/disk_cache/blockfile/block_files.cc +++ b/net/disk_cache/blockfile/block_files.cc
@@ -15,7 +15,6 @@ #include "base/time/time.h" #include "net/disk_cache/blockfile/file_lock.h" #include "net/disk_cache/blockfile/stress_support.h" -#include "net/disk_cache/blockfile/trace.h" #include "net/disk_cache/cache_util.h" using base::TimeTicks; @@ -339,7 +338,6 @@ Addr address(block_type, block_count, file_header.FileId(), index); block_address->set_value(address.value()); - Trace("CreateBlock 0x%x", address.value()); return true; } @@ -356,8 +354,6 @@ if (!file) return; - Trace("DeleteBlock 0x%x", address.value()); - size_t size = address.BlockSize() * address.num_blocks(); size_t offset = address.start_block() * address.BlockSize() + kBlockHeaderSize;
diff --git a/net/disk_cache/blockfile/entry_impl.cc b/net/disk_cache/blockfile/entry_impl.cc index a55ed15..668101ca 100644 --- a/net/disk_cache/blockfile/entry_impl.cc +++ b/net/disk_cache/blockfile/entry_impl.cc
@@ -431,7 +431,6 @@ bool EntryImpl::CreateEntry(Addr node_address, const std::string& key, uint32_t hash) { - Trace("Create entry In"); EntryStore* entry_store = entry_.Data(); RankingsNode* node = node_.Data(); memset(entry_store, 0, sizeof(EntryStore) * entry_.address().num_blocks()); @@ -472,7 +471,6 @@ backend_->ModifyStorageSize(0, static_cast<int32_t>(key.size())); CACHE_UMA(COUNTS, "KeySize", 0, static_cast<int32_t>(key.size())); node->dirty = backend_->GetCurrentEntryId(); - Log("Create Entry "); return true; } @@ -976,7 +974,6 @@ node_.clear_modified(); return; } - Log("~EntryImpl in"); // Save the sparse info to disk. This will generate IO for this entry and // maybe for a child entry, so it is important to do it before deleting this @@ -1018,7 +1015,6 @@ } } - Trace("~EntryImpl out 0x%p", reinterpret_cast<void*>(this)); net_log_.EndEvent(net::NetLogEventType::DISK_CACHE_ENTRY_IMPL); backend_->OnEntryDestroyEnd(); } @@ -1151,11 +1147,9 @@ int entry_size = entry_.Data()->data_size[index]; bool extending = entry_size < offset + buf_len; truncate = truncate && entry_size > offset + buf_len; - Trace("To PrepareTarget 0x%x", entry_.address().value()); if (!PrepareTarget(index, offset, buf_len, truncate)) return net::ERR_FAILED; - Trace("From PrepareTarget 0x%x", entry_.address().value()); if (extending || truncate) UpdateSize(index, entry_size, offset + buf_len); @@ -1614,21 +1608,6 @@ } } -void EntryImpl::Log(const char* msg) { - int dirty = 0; - if (node_.HasData()) { - dirty = node_.Data()->dirty; - } - - Trace("%s 0x%p 0x%x 0x%x", msg, reinterpret_cast<void*>(this), - entry_.address().value(), node_.address().value()); - - Trace(" data: 0x%x 0x%x 0x%x", entry_.Data()->data_addr[0], - entry_.Data()->data_addr[1], entry_.Data()->long_key); - - Trace(" doomed: %d 0x%x", doomed_, dirty); -} - } // namespace disk_cache #undef CACHE_UMA_BACKEND_IMPL_OBJ // undef for jumbo builds
diff --git a/net/disk_cache/blockfile/entry_impl.h b/net/disk_cache/blockfile/entry_impl.h index 616673e..24da1f9 100644 --- a/net/disk_cache/blockfile/entry_impl.h +++ b/net/disk_cache/blockfile/entry_impl.h
@@ -292,9 +292,6 @@ // actual cleanup. void GetData(int index, char** buffer, Addr* address); - // Logs this entry to the internal trace buffer. - void Log(const char* msg); - // |net_log_| should be early since some field destructors (at least // ~SparseControl) can touch it. net::NetLogWithSource net_log_;
diff --git a/net/disk_cache/blockfile/eviction.cc b/net/disk_cache/blockfile/eviction.cc index fdc2169..1ff15ab5 100644 --- a/net/disk_cache/blockfile/eviction.cc +++ b/net/disk_cache/blockfile/eviction.cc
@@ -41,12 +41,12 @@ #include "base/strings/string_util.h" #include "base/threading/thread_task_runner_handle.h" #include "base/time/time.h" +#include "base/trace_event/trace_event.h" #include "net/disk_cache/blockfile/backend_impl.h" #include "net/disk_cache/blockfile/disk_format.h" #include "net/disk_cache/blockfile/entry_impl.h" #include "net/disk_cache/blockfile/experiments.h" #include "net/disk_cache/blockfile/histogram_macros.h" -#include "net/disk_cache/blockfile/trace.h" // Provide a BackendImpl object to macros from histogram_macros.h. #define CACHE_UMA_BACKEND_IMPL_OBJ backend_ @@ -113,6 +113,7 @@ } void Eviction::TrimCache(bool empty) { + TRACE_EVENT0("disk_cache", "Eviction::TrimCache"); if (backend_->disabled_ || trimming_) return; @@ -122,7 +123,6 @@ if (new_eviction_) return TrimCacheV2(empty); - Trace("*** Trim Cache ***"); trimming_ = true; TimeTicks start = TimeTicks::Now(); Rankings::ScopedRankingsBlock node(rankings_); @@ -163,7 +163,6 @@ CACHE_UMA(COUNTS, "TrimItemsV1", 0, deleted_entries); trimming_ = false; - Trace("*** Trim Cache end ***"); return; } @@ -206,6 +205,8 @@ } void Eviction::TrimDeletedList(bool empty) { + TRACE_EVENT0("disk_cache", "Eviction::TrimDeletedList"); + DCHECK(test_mode_ && new_eviction_); TrimDeleted(empty); } @@ -284,10 +285,8 @@ bool Eviction::EvictEntry(CacheRankingsBlock* node, bool empty, Rankings::List list) { scoped_refptr<EntryImpl> entry = backend_->GetEnumeratedEntry(node, list); - if (!entry) { - Trace("NewEntry failed on Trim 0x%x", node->address().value()); + if (!entry) return false; - } ReportTrimTimes(entry.get()); if (empty || !new_eviction_) { @@ -311,7 +310,8 @@ // ----------------------------------------------------------------------- void Eviction::TrimCacheV2(bool empty) { - Trace("*** Trim Cache ***"); + TRACE_EVENT0("disk_cache", "Eviction::TrimCacheV2"); + trimming_ = true; TimeTicks start = TimeTicks::Now(); @@ -389,7 +389,6 @@ } CACHE_UMA(COUNTS, "TrimItemsV2", 0, deleted_entries); - Trace("*** Trim Cache end ***"); trimming_ = false; return; } @@ -489,7 +488,8 @@ // This is a minimal implementation that just discards the oldest nodes. // TODO(rvargas): Do something better here. void Eviction::TrimDeleted(bool empty) { - Trace("*** Trim Deleted ***"); + TRACE_EVENT0("disk_cache", "Eviction::TrimDeleted"); + if (backend_->disabled_) return; @@ -517,17 +517,14 @@ CACHE_UMA(AGE_MS, "TotalTrimDeletedTime", 0, start); CACHE_UMA(COUNTS, "TrimDeletedItems", 0, deleted_entries); - Trace("*** Trim Deleted end ***"); return; } bool Eviction::RemoveDeletedNode(CacheRankingsBlock* node) { scoped_refptr<EntryImpl> entry = backend_->GetEnumeratedEntry(node, Rankings::DELETED); - if (!entry) { - Trace("NewEntry failed on Trim 0x%x", node->address().value()); + if (!entry) return false; - } bool doomed = (entry->entry()->Data()->state == ENTRY_DOOMED); entry->entry()->Data()->state = ENTRY_DOOMED;
diff --git a/net/disk_cache/blockfile/rankings.cc b/net/disk_cache/blockfile/rankings.cc index 2a3344a..7c6bbbc 100644 --- a/net/disk_cache/blockfile/rankings.cc +++ b/net/disk_cache/blockfile/rankings.cc
@@ -246,7 +246,6 @@ } void Rankings::Insert(CacheRankingsBlock* node, bool modified, List list) { - Trace("Insert 0x%x l %d", node->address().value(), list); DCHECK(node->HasData()); Addr& my_head = heads_[list]; Addr& my_tail = tails_[list]; @@ -317,8 +316,6 @@ // 3. a(x, a), r(a, r), head(x), tail(a) prev.Store() // 4. a(x, a), r(0, 0), head(x), tail(a) next.Store() void Rankings::Remove(CacheRankingsBlock* node, List list, bool strict) { - Trace("Remove 0x%x (0x%x 0x%x) l %d", node->address().value(), - node->Data()->next, node->Data()->prev, list); DCHECK(node->HasData()); Addr next_addr(node->Data()->next); @@ -642,25 +639,18 @@ return; } - Trace("CompleteTransaction 0x%x", node_addr.value()); - CacheRankingsBlock node(backend_->File(node_addr), node_addr); if (!node.Load()) return; node.Store(); - Addr& my_head = heads_[control_data_->operation_list]; - Addr& my_tail = tails_[control_data_->operation_list]; - // We want to leave the node inside the list. The entry must me marked as // dirty, and will be removed later. Otherwise, we'll get assertions when // attempting to remove the dirty entry. if (INSERT == control_data_->operation) { - Trace("FinishInsert h:0x%x t:0x%x", my_head.value(), my_tail.value()); FinishInsert(&node); } else if (REMOVE == control_data_->operation) { - Trace("RevertRemove h:0x%x t:0x%x", my_head.value(), my_tail.value()); RevertRemove(&node); } else { NOTREACHED(); @@ -753,15 +743,11 @@ return true; } - Trace("CheckLinks 0x%x (0x%x 0x%x)", node_addr, - prev->Data()->next, next->Data()->prev); - if (node_addr != prev->address().value() && node_addr != next->address().value() && prev->Data()->next == next->address().value() && next->Data()->prev == prev->address().value()) { // The list is actually ok, node is wrong. - Trace("node 0x%x out of list %d", node_addr, list); node->Data()->next = 0; node->Data()->prev = 0; node->Store(); @@ -860,8 +846,6 @@ bool Rankings::IsHead(CacheAddr addr, List* list) const { for (int i = 0; i < LAST_ELEMENT; i++) { if (addr == heads_[i].value()) { - if (*list != i) - Trace("Changing list %d to %d", *list, i); *list = static_cast<List>(i); return true; } @@ -872,8 +856,6 @@ bool Rankings::IsTail(CacheAddr addr, List* list) const { for (int i = 0; i < LAST_ELEMENT; i++) { if (addr == tails_[i].value()) { - if (*list != i) - Trace("Changing list %d to %d", *list, i); *list = static_cast<List>(i); return true; }
diff --git a/net/disk_cache/blockfile/storage_block-inl.h b/net/disk_cache/blockfile/storage_block-inl.h index 903d65c..d976443 100644 --- a/net/disk_cache/blockfile/storage_block-inl.h +++ b/net/disk_cache/blockfile/storage_block-inl.h
@@ -12,7 +12,6 @@ #include "base/hash/hash.h" #include "base/logging.h" -#include "net/disk_cache/blockfile/trace.h" namespace disk_cache { @@ -145,7 +144,6 @@ } } LOG(WARNING) << "Failed data load."; - Trace("Failed data load."); return false; } @@ -158,7 +156,6 @@ } } LOG(ERROR) << "Failed data store."; - Trace("Failed data store."); return false; } @@ -174,7 +171,6 @@ } } LOG(WARNING) << "Failed data load."; - Trace("Failed data load."); return false; } @@ -188,7 +184,6 @@ } } LOG(ERROR) << "Failed data store."; - Trace("Failed data store."); return false; }
diff --git a/net/disk_cache/blockfile/stress_support.h b/net/disk_cache/blockfile/stress_support.h index 5383c5d..2f07de8 100644 --- a/net/disk_cache/blockfile/stress_support.h +++ b/net/disk_cache/blockfile/stress_support.h
@@ -13,11 +13,6 @@ // to ensure that we are not producing corrupt entries. // #define NET_BUILD_STRESS_CACHE 1 -// Uncomment this line to direct the in-memory disk cache tracing to the base -// logging system. On Windows this option will enable ETW (Event Tracing for -// Windows) so logs across multiple runs can be collected. -// #define DISK_CACHE_TRACE_TO_LOG 1 - // Uncomment this line to perform extended integrity checks during init. It is // not recommended to enable this option unless some corruption is being tracked // down.
diff --git a/net/disk_cache/blockfile/trace.cc b/net/disk_cache/blockfile/trace.cc deleted file mode 100644 index 0b451be0..0000000 --- a/net/disk_cache/blockfile/trace.cc +++ /dev/null
@@ -1,193 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/disk_cache/blockfile/trace.h" - -#include <stdarg.h> -#include <stdio.h> -#if defined(OS_WIN) -#include <windows.h> -#endif - -#include "base/lazy_instance.h" -#include "base/logging.h" -#include "base/synchronization/lock.h" -#include "net/disk_cache/blockfile/stress_support.h" - -// Change this value to 1 to enable tracing on a release build. By default, -// tracing is enabled only on debug builds. -#define ENABLE_TRACING 0 - -#ifndef NDEBUG -#undef ENABLE_TRACING -#define ENABLE_TRACING 1 -#endif - -namespace { - -const int kEntrySize = 12 * sizeof(size_t); -#if defined(NET_BUILD_STRESS_CACHE) -const int kNumberOfEntries = 500000; -#else -const int kNumberOfEntries = 5000; // 240 KB on 32bit, 480 KB on 64bit -#endif - -bool s_trace_enabled = false; -base::LazyInstance<base::Lock>::Leaky s_lock = LAZY_INSTANCE_INITIALIZER; - -struct TraceBuffer { - int num_traces; - int current; - char buffer[kNumberOfEntries][kEntrySize]; -}; - -#if ENABLE_TRACING -void DebugOutput(const char* msg) { -#if defined(OS_WIN) - OutputDebugStringA(msg); -#else - NOTIMPLEMENTED(); -#endif -} -#endif // ENABLE_TRACING - -} // namespace - -namespace disk_cache { - -// s_trace_buffer and s_trace_object are not singletons because I want the -// buffer to be destroyed and re-created when the last user goes away, and it -// must be straightforward to access the buffer from the debugger. -static TraceObject* s_trace_object = nullptr; - -// Static. -TraceObject* TraceObject::GetTraceObject() { - base::AutoLock lock(s_lock.Get()); - - if (s_trace_object) - return s_trace_object; - - s_trace_object = new TraceObject(); - return s_trace_object; -} - -TraceObject::TraceObject() { - InitTrace(); -} - -TraceObject::~TraceObject() { - DestroyTrace(); -} - -void TraceObject::EnableTracing(bool enable) { - base::AutoLock lock(s_lock.Get()); - s_trace_enabled = enable; -} - -#if ENABLE_TRACING - -static TraceBuffer* s_trace_buffer = nullptr; - -void InitTrace(void) { - s_trace_enabled = true; - if (s_trace_buffer) - return; - - s_trace_buffer = new TraceBuffer; - memset(s_trace_buffer, 0, sizeof(*s_trace_buffer)); -} - -void DestroyTrace(void) { - base::AutoLock lock(s_lock.Get()); - - delete s_trace_buffer; - s_trace_buffer = nullptr; - s_trace_object = nullptr; -} - -void Trace(const char* format, ...) { - if (!s_trace_buffer || !s_trace_enabled) - return; - - va_list ap; - va_start(ap, format); - char line[kEntrySize + 2]; - -#if defined(OS_WIN) - vsprintf_s(line, format, ap); -#else - vsnprintf(line, kEntrySize, format, ap); -#endif - -#if defined(DISK_CACHE_TRACE_TO_LOG) - line[kEntrySize] = '\0'; - LOG(INFO) << line; -#endif - - va_end(ap); - - { - base::AutoLock lock(s_lock.Get()); - if (!s_trace_buffer || !s_trace_enabled) - return; - - memcpy(s_trace_buffer->buffer[s_trace_buffer->current], line, kEntrySize); - - s_trace_buffer->num_traces++; - s_trace_buffer->current++; - if (s_trace_buffer->current == kNumberOfEntries) - s_trace_buffer->current = 0; - } -} - -// Writes the last num_traces to the debugger output. -void DumpTrace(int num_traces) { - DCHECK(s_trace_buffer); - DebugOutput("Last traces:\n"); - - if (num_traces > kNumberOfEntries || num_traces < 0) - num_traces = kNumberOfEntries; - - if (s_trace_buffer->num_traces) { - char line[kEntrySize + 2]; - - int current = s_trace_buffer->current - num_traces; - if (current < 0) - current += kNumberOfEntries; - - for (int i = 0; i < num_traces; i++) { - memcpy(line, s_trace_buffer->buffer[current], kEntrySize); - line[kEntrySize] = '\0'; - size_t length = strlen(line); - if (length) { - line[length] = '\n'; - line[length + 1] = '\0'; - DebugOutput(line); - } - - current++; - if (current == kNumberOfEntries) - current = 0; - } - } - - DebugOutput("End of Traces\n"); -} - -#else // ENABLE_TRACING - -void InitTrace(void) { - return; -} - -void DestroyTrace(void) { - s_trace_object = NULL; -} - -void Trace(const char* format, ...) { -} - -#endif // ENABLE_TRACING - -} // namespace disk_cache
diff --git a/net/disk_cache/blockfile/trace.h b/net/disk_cache/blockfile/trace.h deleted file mode 100644 index 2cc2fa1..0000000 --- a/net/disk_cache/blockfile/trace.h +++ /dev/null
@@ -1,42 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This file provides support for basic in-memory tracing of short events. We -// keep a static circular buffer where we store the last traced events, so we -// can review the cache recent behavior should we need it. - -#ifndef NET_DISK_CACHE_BLOCKFILE_TRACE_H_ -#define NET_DISK_CACHE_BLOCKFILE_TRACE_H_ - -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "net/base/net_export.h" - -namespace disk_cache { - -// Create and destroy the tracing buffer. -void InitTrace(void); -void DestroyTrace(void); - -// Simple class to handle the trace buffer lifetime. Any object interested in -// tracing should keep a reference to the object returned by GetTraceObject(). -class TraceObject : public base::RefCountedThreadSafe<TraceObject> { - friend class base::RefCountedThreadSafe<TraceObject>; - - public: - static TraceObject* GetTraceObject(); - void EnableTracing(bool enable); - - private: - TraceObject(); - ~TraceObject(); - DISALLOW_COPY_AND_ASSIGN(TraceObject); -}; - -// Traces to the internal buffer. -NET_EXPORT_PRIVATE void Trace(const char* format, ...); - -} // namespace disk_cache - -#endif // NET_DISK_CACHE_BLOCKFILE_TRACE_H_
diff --git a/net/quic/quic_flags_list.h b/net/quic/quic_flags_list.h index 0e9f5036..5c2bc6ef 100644 --- a/net/quic/quic_flags_list.h +++ b/net/quic/quic_flags_list.h
@@ -396,3 +396,9 @@ // If true, use blackhole detector in QuicConnection to detect path degrading // and network blackhole. QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_use_blackhole_detector, false) + +// If true, use idle network detector to detect handshake timeout and idle +// network timeout. +QUIC_FLAG(bool, + FLAGS_quic_reloadable_flag_quic_use_idle_network_detector, + false)
diff --git a/net/quic/quic_stream_factory.cc b/net/quic/quic_stream_factory.cc index 60f1e486..f076703 100644 --- a/net/quic/quic_stream_factory.cc +++ b/net/quic/quic_stream_factory.cc
@@ -45,6 +45,7 @@ #include "net/quic/quic_chromium_connection_helper.h" #include "net/quic/quic_chromium_packet_reader.h" #include "net/quic/quic_chromium_packet_writer.h" +#include "net/quic/quic_client_session_cache.h" #include "net/quic/quic_context.h" #include "net/quic/quic_crypto_client_stream_factory.h" #include "net/quic/quic_http_stream.h" @@ -324,8 +325,9 @@ public: QuicCryptoClientConfigOwner( std::unique_ptr<quic::ProofVerifier> proof_verifier, + std::unique_ptr<QuicClientSessionCache> session_cache, QuicStreamFactory* quic_stream_factory) - : config_(std::move(proof_verifier)), + : config_(std::move(proof_verifier), std::move(session_cache)), quic_stream_factory_(quic_stream_factory) { DCHECK(quic_stream_factory_); } @@ -2277,7 +2279,7 @@ cert_verifier_, ct_policy_enforcer_, transport_security_state_, cert_transparency_verifier_, HostsFromOrigins(params_.origins_to_force_quic_on)), - this); + std::make_unique<QuicClientSessionCache>(), this); quic::QuicCryptoClientConfig* crypto_config = crypto_config_owner->config(); crypto_config->set_user_agent_id(params_.user_agent_id);
diff --git a/net/third_party/quiche/BUILD.gn b/net/third_party/quiche/BUILD.gn index 3370121..5585047 100644 --- a/net/third_party/quiche/BUILD.gn +++ b/net/third_party/quiche/BUILD.gn
@@ -428,6 +428,8 @@ "src/quic/core/quic_flow_controller.h", "src/quic/core/quic_framer.cc", "src/quic/core/quic_framer.h", + "src/quic/core/quic_idle_network_detector.cc", + "src/quic/core/quic_idle_network_detector.h", "src/quic/core/quic_interval.h", "src/quic/core/quic_interval_deque.h", "src/quic/core/quic_interval_set.h", @@ -1315,6 +1317,7 @@ "src/quic/core/quic_error_codes_test.cc", "src/quic/core/quic_flow_controller_test.cc", "src/quic/core/quic_framer_test.cc", + "src/quic/core/quic_idle_network_detector_test.cc", "src/quic/core/quic_interval_deque_test.cc", "src/quic/core/quic_interval_set_test.cc", "src/quic/core/quic_interval_test.cc",
diff --git a/net/tools/stress_cache/stress_cache.cc b/net/tools/stress_cache/stress_cache.cc index 0603c1c..3e6aaa1b 100644 --- a/net/tools/stress_cache/stress_cache.cc +++ b/net/tools/stress_cache/stress_cache.cc
@@ -43,7 +43,6 @@ #include "net/base/test_completion_callback.h" #include "net/disk_cache/blockfile/backend_impl.h" #include "net/disk_cache/blockfile/stress_support.h" -#include "net/disk_cache/blockfile/trace.h" #include "net/disk_cache/disk_cache.h" #include "net/disk_cache/disk_cache_test_util.h" @@ -386,20 +385,6 @@ base::debug::BreakDebugger(); } -bool MessageHandler(int severity, const char* file, int line, - size_t message_start, const std::string& str) { - const size_t kMaxMessageLen = 48; - char message[kMaxMessageLen]; - size_t len = std::min(str.length() - message_start, kMaxMessageLen - 1); - - memcpy(message, str.c_str() + message_start, len); - message[len] = '\0'; -#if !defined(DISK_CACHE_TRACE_TO_LOG) - disk_cache::Trace("%s", message); -#endif - return false; -} - // ----------------------------------------------------------------------- #if defined(OS_WIN) @@ -418,7 +403,6 @@ logging::ScopedLogAssertHandler scoped_assert_handler( base::Bind(CrashHandler)); - logging::SetLogMessageHandler(MessageHandler); #if defined(OS_WIN) logging::LogEventProvider::Initialize(kStressCacheTraceProviderName);
diff --git a/services/device/generic_sensor/platform_sensor_provider.cc b/services/device/generic_sensor/platform_sensor_provider.cc index 8b8c6916..f1f7159 100644 --- a/services/device/generic_sensor/platform_sensor_provider.cc +++ b/services/device/generic_sensor/platform_sensor_provider.cc
@@ -48,8 +48,13 @@ // this Windows version has yet to be released, Win10 is being // provisionally used for testing. This also means sensors will // stream if this implementation path is enabled. + + // Note the fork occurs specifically on the 19H1 build of Win10 + // because a previous version (RS5) contains an access violation + // issue in the WinRT APIs which causes the client code to crash. + // See http://crbug.com/1063124 return base::FeatureList::IsEnabled(features::kWinrtSensorsImplementation) && - base::win::GetVersion() >= base::win::Version::WIN10; + base::win::GetVersion() >= base::win::Version::WIN10_19H1; } #endif
diff --git a/services/device/public/cpp/device_features.cc b/services/device/public/cpp/device_features.cc index 4f05b0c..07072a57 100644 --- a/services/device/public/cpp/device_features.cc +++ b/services/device/public/cpp/device_features.cc
@@ -13,7 +13,7 @@ // Enables usage of the Windows.Devices.Sensors WinRT API for the sensor // backend instead of the ISensor API on Windows. const base::Feature kWinrtSensorsImplementation{ - "WinrtSensorsImplementation", base::FEATURE_DISABLED_BY_DEFAULT}; + "WinrtSensorsImplementation", base::FEATURE_ENABLED_BY_DEFAULT}; // Enables usage of the Windows.Devices.Geolocation WinRT API for the // LocationProvider instead of the NetworkLocationProvider on Windows. const base::Feature kWinrtGeolocationImplementation{
diff --git a/services/metrics/public/cpp/ukm_recorder.cc b/services/metrics/public/cpp/ukm_recorder.cc index b38376ea..7424a3c7 100644 --- a/services/metrics/public/cpp/ukm_recorder.cc +++ b/services/metrics/public/cpp/ukm_recorder.cc
@@ -32,6 +32,16 @@ } // static +ukm::SourceId UkmRecorder::GetSourceIdForPaymentAppFromScope( + const GURL& service_worker_scope) { + ukm::SourceId source_id = base::UkmSourceId::FromOtherId( + GetNewSourceID(), SourceIdType::PAYMENT_APP_ID) + .ToInt64(); + ukm::UkmRecorder::Get()->UpdateSourceURL(source_id, service_worker_scope); + return source_id; +} + +// static ukm::SourceId UkmRecorder::GetSourceIdForWebApkManifestUrl( const GURL& manifest_url) { ukm::SourceId source_id =
diff --git a/services/metrics/public/cpp/ukm_recorder.h b/services/metrics/public/cpp/ukm_recorder.h index 107f9b0..132072b 100644 --- a/services/metrics/public/cpp/ukm_recorder.h +++ b/services/metrics/public/cpp/ukm_recorder.h
@@ -28,6 +28,10 @@ class UkmRecorderInterface; } // namespace metrics +namespace content { +class PaymentAppProviderImpl; +} // namespace content + namespace ukm { class DelegatingUkmRecorder; @@ -72,6 +76,12 @@ // method should only be called by WebApkUkmRecorder class. static SourceId GetSourceIdForWebApkManifestUrl(const GURL& manifest_url); + // Gets new source Id for PAYMENT_APP_ID type and updates the source url to + // the scope of the app. This method should only be called by + // PaymentAppProviderImpl class when the payment app window is opened. + static SourceId GetSourceIdForPaymentAppFromScope( + const GURL& service_worker_scope); + private: friend DelegatingUkmRecorder; friend TestRecordingHelper; @@ -79,6 +89,7 @@ friend blink::Document; friend metrics::UkmRecorderInterface; friend PermissionUmaUtil; + friend content::PaymentAppProviderImpl; // WebApkUkmRecorder records metrics about installed Webapps. Instead of using // the current main frame URL, we want to record the URL of the Webapp
diff --git a/services/metrics/public/cpp/ukm_source_id.cc b/services/metrics/public/cpp/ukm_source_id.cc index d1c20bc..fdba55e 100644 --- a/services/metrics/public/cpp/ukm_source_id.cc +++ b/services/metrics/public/cpp/ukm_source_id.cc
@@ -15,11 +15,13 @@ } SourceId ConvertToSourceId(int64_t other_id, SourceIdType id_type) { - // DCHECK is to restrict the usage of WEBAPK_ID, WebApk should use - // |UkmRecorder::GetSourceIdForWebApkManifestUrl()| instead. + // DCHECK is to restrict the usage of WEBAPK_ID and PAYMENT_APP_ID. WebApk and + // Payment apps should use |UkmRecorder::GetSourceIdForWebApkManifestUrl()| + // and |UkmRecorder::GetSourceIdForPaymentAppFromScope()| instead. // TODO(crbug.com/1046964): Ideally we should restrict // UkmSourceId::FromOtherId() as well. DCHECK(id_type != SourceIdType::WEBAPK_ID); + DCHECK(id_type != SourceIdType::PAYMENT_APP_ID); return base::UkmSourceId::FromOtherId(other_id, id_type).ToInt64(); }
diff --git a/services/viz/privileged/cpp/OWNERS b/services/viz/privileged/cpp/OWNERS index c4f73a0..d5fefd8 100644 --- a/services/viz/privileged/cpp/OWNERS +++ b/services/viz/privileged/cpp/OWNERS
@@ -1,4 +1,2 @@ -per-file *.typemap=set noparent -per-file *.typemap=file://ipc/SECURITY_OWNERS per-file *_mojom_traits*.*=set noparent per-file *_mojom_traits*.*=file://ipc/SECURITY_OWNERS
diff --git a/services/viz/privileged/cpp/context_lost_reason.typemap b/services/viz/privileged/cpp/context_lost_reason.typemap deleted file mode 100644 index 55ffcdbb..0000000 --- a/services/viz/privileged/cpp/context_lost_reason.typemap +++ /dev/null
@@ -1,14 +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. - -mojom = "//services/viz/privileged/mojom/gl/context_lost_reason.mojom" -public_headers = [ "//gpu/command_buffer/common/constants.h" ] -traits_headers = - [ "//services/viz/privileged/cpp/context_lost_reason_traits.h" ] -public_deps = [ - "//gpu/command_buffer/common", -] - -type_mappings = - [ "viz.mojom.ContextLostReason=::gpu::error::ContextLostReason" ]
diff --git a/services/viz/privileged/cpp/context_lost_reason_traits.h b/services/viz/privileged/cpp/context_lost_reason_traits.h index 7be0c33..761b20b1 100644 --- a/services/viz/privileged/cpp/context_lost_reason_traits.h +++ b/services/viz/privileged/cpp/context_lost_reason_traits.h
@@ -6,7 +6,7 @@ #define SERVICES_VIZ_PRIVILEGED_CPP_CONTEXT_LOST_REASON_TRAITS_H_ #include "gpu/command_buffer/common/constants.h" -#include "services/viz/privileged/mojom/gl/context_lost_reason.mojom.h" +#include "services/viz/privileged/mojom/gl/context_lost_reason.mojom-shared.h" namespace mojo {
diff --git a/services/viz/privileged/cpp/overlay_strategy.typemap b/services/viz/privileged/cpp/overlay_strategy.typemap deleted file mode 100644 index 8ee3d48a..0000000 --- a/services/viz/privileged/cpp/overlay_strategy.typemap +++ /dev/null
@@ -1,14 +0,0 @@ -# Copyright 2019 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -mojom = "//services/viz/privileged/mojom/compositing/overlay_strategy.mojom" -public_headers = [ "//components/viz/common/display/overlay_strategy.h" ] -traits_headers = - [ "//services/viz/privileged/cpp/overlay_strategy_mojom_traits.h" ] -public_deps = [ - "//components/viz/common", - #"//services/viz/privileged/mojom/compositing" -] - -type_mappings = [ "viz.mojom.OverlayStrategy=::viz::OverlayStrategy" ]
diff --git a/services/viz/privileged/cpp/overlay_strategy_mojom_traits.h b/services/viz/privileged/cpp/overlay_strategy_mojom_traits.h index dbd6a4ab..9b381e6 100644 --- a/services/viz/privileged/cpp/overlay_strategy_mojom_traits.h +++ b/services/viz/privileged/cpp/overlay_strategy_mojom_traits.h
@@ -6,7 +6,7 @@ #define SERVICES_VIZ_PRIVILEGED_CPP_OVERLAY_STRATEGY_MOJOM_TRAITS_H_ #include "components/viz/common/display/overlay_strategy.h" -#include "services/viz/privileged/mojom/compositing/overlay_strategy.mojom.h" +#include "services/viz/privileged/mojom/compositing/overlay_strategy.mojom-shared.h" namespace mojo {
diff --git a/services/viz/privileged/cpp/typemaps.gni b/services/viz/privileged/cpp/typemaps.gni deleted file mode 100644 index fed7dfa..0000000 --- a/services/viz/privileged/cpp/typemaps.gni +++ /dev/null
@@ -1,4 +0,0 @@ -typemaps = [ - "//services/viz/privileged/cpp/context_lost_reason.typemap", - "//services/viz/privileged/cpp/overlay_strategy.typemap", -]
diff --git a/services/viz/privileged/mojom/compositing/BUILD.gn b/services/viz/privileged/mojom/compositing/BUILD.gn index 75e2ff88..53af38d0 100644 --- a/services/viz/privileged/mojom/compositing/BUILD.gn +++ b/services/viz/privileged/mojom/compositing/BUILD.gn
@@ -36,4 +36,21 @@ if (use_x11) { enabled_features += [ "use_x11" ] } + + cpp_typemaps = [ + { + types = [ + { + mojom = "viz.mojom.RendererSettings" + cpp = "::viz::RendererSettings" + }, + ] + traits_headers = [ "//services/viz/privileged/mojom/compositing/renderer_settings_mojom_traits.h" ] + traits_sources = [ "//services/viz/privileged/mojom/compositing/renderer_settings_mojom_traits.cc" ] + traits_public_deps = [ + "//cc", + "//ui/gfx/geometry/mojom", + ] + }, + ] }
diff --git a/services/viz/privileged/mojom/compositing/OWNERS b/services/viz/privileged/mojom/compositing/OWNERS index ae29a36aa..1feb514 100644 --- a/services/viz/privileged/mojom/compositing/OWNERS +++ b/services/viz/privileged/mojom/compositing/OWNERS
@@ -2,5 +2,3 @@ per-file *.mojom=file://ipc/SECURITY_OWNERS per-file *_mojom_traits*.*=set noparent per-file *_mojom_traits*.*=file://ipc/SECURITY_OWNERS -per-file *.typemap=set noparent -per-file *.typemap=file://ipc/SECURITY_OWNERS
diff --git a/services/viz/privileged/mojom/compositing/renderer_settings.typemap b/services/viz/privileged/mojom/compositing/renderer_settings.typemap deleted file mode 100644 index 4993e50..0000000 --- a/services/viz/privileged/mojom/compositing/renderer_settings.typemap +++ /dev/null
@@ -1,17 +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. - -mojom = "//services/viz/privileged/mojom/compositing/renderer_settings.mojom" -public_headers = [ "//components/viz/common/display/renderer_settings.h" ] -traits_headers = [ "//services/viz/privileged/mojom/compositing/renderer_settings_mojom_traits.h" ] -deps = [ - "//cc", -] -public_deps = [ - "//ui/gfx/geometry/mojom", -] -sources = [ - "renderer_settings_mojom_traits.cc", -] -type_mappings = [ "viz.mojom.RendererSettings=::viz::RendererSettings" ]
diff --git a/services/viz/privileged/mojom/compositing/renderer_settings_mojom_traits.h b/services/viz/privileged/mojom/compositing/renderer_settings_mojom_traits.h index a22d21f..5cb17bd 100644 --- a/services/viz/privileged/mojom/compositing/renderer_settings_mojom_traits.h +++ b/services/viz/privileged/mojom/compositing/renderer_settings_mojom_traits.h
@@ -9,7 +9,7 @@ #include "build/build_config.h" #include "components/viz/common/display/renderer_settings.h" #include "services/viz/privileged/cpp/overlay_strategy_mojom_traits.h" -#include "services/viz/privileged/mojom/compositing/renderer_settings.mojom.h" +#include "services/viz/privileged/mojom/compositing/renderer_settings.mojom-shared.h" #include "ui/gfx/geometry/mojom/geometry_mojom_traits.h" #if defined(USE_OZONE)
diff --git a/services/viz/privileged/mojom/compositing/typemaps.gni b/services/viz/privileged/mojom/compositing/typemaps.gni deleted file mode 100644 index f9e68e3c2..0000000 --- a/services/viz/privileged/mojom/compositing/typemaps.gni +++ /dev/null
@@ -1,6 +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. - -typemaps = - [ "//services/viz/privileged/mojom/compositing/renderer_settings.typemap" ]
diff --git a/services/viz/privileged/mojom/gl/BUILD.gn b/services/viz/privileged/mojom/gl/BUILD.gn index e0a4a98..3ee4a5a 100644 --- a/services/viz/privileged/mojom/gl/BUILD.gn +++ b/services/viz/privileged/mojom/gl/BUILD.gn
@@ -30,4 +30,29 @@ if (!is_android) { enabled_features += [ "is_not_android" ] } + + cpp_typemaps = [ + { + types = [ + { + mojom = "viz.mojom.ContextLostReason" + cpp = "::gpu::error::ContextLostReason" + }, + ] + traits_headers = + [ "//services/viz/privileged/cpp/context_lost_reason_traits.h" ] + traits_public_deps = [ "//gpu/command_buffer/common" ] + }, + { + types = [ + { + mojom = "viz.mojom.OverlayStrategy" + cpp = "::viz::OverlayStrategy" + }, + ] + traits_headers = + [ "//services/viz/privileged/cpp/overlay_strategy_mojom_traits.h" ] + traits_public_deps = [ "//components/viz/common" ] + }, + ] }
diff --git a/services/viz/privileged/mojom/mojom_traits_unittest.cc b/services/viz/privileged/mojom/mojom_traits_unittest.cc index bffe4fc..d1625920 100644 --- a/services/viz/privileged/mojom/mojom_traits_unittest.cc +++ b/services/viz/privileged/mojom/mojom_traits_unittest.cc
@@ -5,7 +5,7 @@ #include <utility> #include "components/viz/common/display/renderer_settings.h" -#include "services/viz/privileged/mojom/compositing/renderer_settings_mojom_traits.h" +#include "services/viz/privileged/mojom/compositing/renderer_settings.mojom.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/gfx/mojom/color_space_mojom_traits.h"
diff --git a/services/viz/public/cpp/hit_test/OWNERS b/services/viz/public/cpp/hit_test/OWNERS index 7aebc8abb..d5fefd8 100644 --- a/services/viz/public/cpp/hit_test/OWNERS +++ b/services/viz/public/cpp/hit_test/OWNERS
@@ -1,4 +1,2 @@ per-file *_mojom_traits*.*=set noparent per-file *_mojom_traits*.*=file://ipc/SECURITY_OWNERS -per-file *.typemap=set noparent -per-file *.typemap=file://ipc/SECURITY_OWNERS
diff --git a/services/viz/public/cpp/hit_test/aggregated_hit_test_region.typemap b/services/viz/public/cpp/hit_test/aggregated_hit_test_region.typemap deleted file mode 100644 index 24fa0173..0000000 --- a/services/viz/public/cpp/hit_test/aggregated_hit_test_region.typemap +++ /dev/null
@@ -1,16 +0,0 @@ -# Copyright 2018 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -mojom = "//services/viz/public/mojom/hit_test/aggregated_hit_test_region.mojom" -public_headers = - [ "//components/viz/common/hit_test/aggregated_hit_test_region.h" ] -deps = [ - "//components/viz/common", -] -traits_headers = [ "//services/viz/public/cpp/hit_test/aggregated_hit_test_region_mojom_traits.h" ] -sources = [ - "//services/viz/public/cpp/hit_test/aggregated_hit_test_region_mojom_traits.cc", -] -type_mappings = - [ "viz.mojom.AggregatedHitTestRegion=::viz::AggregatedHitTestRegion" ]
diff --git a/services/viz/public/cpp/hit_test/hit_test_region_list.typemap b/services/viz/public/cpp/hit_test/hit_test_region_list.typemap deleted file mode 100644 index 55961fc..0000000 --- a/services/viz/public/cpp/hit_test/hit_test_region_list.typemap +++ /dev/null
@@ -1,18 +0,0 @@ -# Copyright 2018 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -mojom = "//services/viz/public/mojom/hit_test/hit_test_region_list.mojom" -public_headers = [ "//components/viz/common/hit_test/hit_test_region_list.h" ] -deps = [ - "//components/viz/common", -] -traits_headers = - [ "//services/viz/public/cpp/hit_test/hit_test_region_list_mojom_traits.h" ] -sources = [ - "//services/viz/public/cpp/hit_test/hit_test_region_list_mojom_traits.cc", -] -type_mappings = [ - "viz.mojom.HitTestRegion=::viz::HitTestRegion", - "viz.mojom.HitTestRegionList=::viz::HitTestRegionList[move_only]", -]
diff --git a/services/viz/public/cpp/hit_test/typemaps.gni b/services/viz/public/cpp/hit_test/typemaps.gni deleted file mode 100644 index 94af9c8..0000000 --- a/services/viz/public/cpp/hit_test/typemaps.gni +++ /dev/null
@@ -1,8 +0,0 @@ -# Copyright 2018 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -typemaps = [ - "//services/viz/public/cpp/hit_test/aggregated_hit_test_region.typemap", - "//services/viz/public/cpp/hit_test/hit_test_region_list.typemap", -]
diff --git a/services/viz/public/mojom/BUILD.gn b/services/viz/public/mojom/BUILD.gn index a08d025..0f3d732a 100644 --- a/services/viz/public/mojom/BUILD.gn +++ b/services/viz/public/mojom/BUILD.gn
@@ -58,4 +58,40 @@ export_class_attribute_blink = "BLINK_PLATFORM_EXPORT" export_define_blink = "BLINK_PLATFORM_IMPLEMENTATION=1" export_header_blink = "third_party/blink/public/platform/web_common.h" + + cpp_typemaps = [ + { + types = [ + { + mojom = "viz.mojom.AggregatedHitTestRegion" + cpp = "::viz::AggregatedHitTestRegion" + }, + ] + traits_headers = [ "//services/viz/public/cpp/hit_test/aggregated_hit_test_region_mojom_traits.h" ] + traits_sources = [ "//services/viz/public/cpp/hit_test/aggregated_hit_test_region_mojom_traits.cc" ] + traits_public_deps = [ + "//components/viz/common", + "//ui/gfx/geometry/mojom", + ] + }, + { + types = [ + { + mojom = "viz.mojom.HitTestRegion" + cpp = "::viz::HitTestRegion" + }, + { + mojom = "viz.mojom.HitTestRegionList" + cpp = "::viz::HitTestRegionList" + move_only = true + }, + ] + traits_headers = [ "//services/viz/public/cpp/hit_test/hit_test_region_list_mojom_traits.h" ] + traits_sources = [ "//services/viz/public/cpp/hit_test/hit_test_region_list_mojom_traits.cc" ] + traits_public_deps = [ + "//components/viz/common", + "//ui/gfx/geometry/mojom", + ] + }, + ] }
diff --git a/skia/config/SkUserConfig.h b/skia/config/SkUserConfig.h index f5ccdaaa..66b4b03c 100644 --- a/skia/config/SkUserConfig.h +++ b/skia/config/SkUserConfig.h
@@ -218,10 +218,6 @@ #define SK_SUPPORT_LEGACY_AAA_CHOICE #endif -#ifndef SK_USE_LEGACY_SRGB_COLOR_FILTER -#define SK_USE_LEGACY_SRGB_COLOR_FILTER -#endif - // We're turning this off indefinitely, // until we can figure out some fundamental problems with its approach. //
diff --git a/testing/buildbot/filters/android.emulator.content_browsertests.filter b/testing/buildbot/filters/android.emulator.content_browsertests.filter index 7ed82ec..c2f3b49 100644 --- a/testing/buildbot/filters/android.emulator.content_browsertests.filter +++ b/testing/buildbot/filters/android.emulator.content_browsertests.filter
@@ -15,3 +15,6 @@ # crbug.com/1058570 -WebRtcGetUserMediaBrowserTest.ApplyConstraintsNonDevice + +# crbug.com/1065184 +-RenderFrameHostImplBrowserTest.CheckIsCurrentBeforeAndAfterUnload
diff --git a/third_party/android_deps/BUILD.gn b/third_party/android_deps/BUILD.gn index 44d2ffd..5a365d5 100644 --- a/third_party/android_deps/BUILD.gn +++ b/third_party/android_deps/BUILD.gn
@@ -381,7 +381,14 @@ ] skip_jetify = true ignore_aidl = true + + # Manifest and proguard config have just one entry: Adding (and -keep'ing) + # android:appComponentFactory="androidx.core.app.CoreComponentFactory" + # Chrome doesn't use this feature and it causes a scary stack trace to be + # shown when incremental_install=true. + ignore_manifest = true ignore_proguard_configs = true + custom_package = "androidx.core" } # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
diff --git a/third_party/android_deps/buildSrc/src/main/groovy/BuildConfigGenerator.groovy b/third_party/android_deps/buildSrc/src/main/groovy/BuildConfigGenerator.groovy index 94ee9f9..813395b 100644 --- a/third_party/android_deps/buildSrc/src/main/groovy/BuildConfigGenerator.groovy +++ b/third_party/android_deps/buildSrc/src/main/groovy/BuildConfigGenerator.groovy
@@ -263,20 +263,29 @@ sb.append(' jar_excluded_patterns = ["META-INF/proguard/*"]\n') break case 'androidx_core_core': - sb.append(' ignore_proguard_configs = true\n') - // Target has AIDL, but we don't support it yet: http://crbug.com/644439 + sb.append('\n') + sb.append(' # Target has AIDL, but we do not support it yet: http://crbug.com/644439\n') sb.append(' ignore_aidl = true\n') + sb.append('\n') + sb.append(' # Manifest and proguard config have just one entry: Adding (and -keep\'ing\n') + sb.append(' # android:appComponentFactory="androidx.core.app.CoreComponentFactory"\n') + sb.append(' # Chrome does not use this feature and it causes a scary stack trace to be\n') + sb.append(' # shown when incremental_install=true.\n') + sb.append(' ignore_manifest = true\n') + sb.append(' ignore_proguard_configs = true\n') + sb.append(' custom_package = "androidx.core"\n') break case 'androidx_media_media': case 'androidx_versionedparcelable_versionedparcelable': case 'com_android_support_support_compat': case 'com_android_support_support_media_compat': case 'com_android_support_versionedparcelable': - // Target has AIDL, but we don't support it yet: http://crbug.com/644439 + sb.append('\n') + sb.append(' # Target has AIDL, but we do not support it yet: http://crbug.com/644439\n') sb.append(' ignore_aidl = true\n') break case 'androidx_test_uiautomator_uiautomator': - sb.append(' deps = [":androidx_test_runner_java"]\n') + sb.append(' deps = [":androidx_test_runner_java"]\n') break case 'com_android_support_mediarouter_v7': sb.append(' # https://crbug.com/1000382\n') @@ -300,17 +309,20 @@ case 'android_arch_lifecycle_viewmodel': case 'androidx_lifecycle_lifecycle_runtime': case 'androidx_lifecycle_lifecycle_viewmodel': + sb.append('\n') sb.append(' # https://crbug.com/887942#c1\n') sb.append(' ignore_proguard_configs = true\n') break case 'com_android_support_coordinatorlayout': case 'androidx_coordinatorlayout_coordinatorlayout': + sb.append('\n') sb.append(' # https:crbug.com/954584\n') sb.append(' ignore_proguard_configs = true\n') break case 'com_android_support_design': case 'com_google_android_material_material': - // Reduce binary size. https:crbug.com/954584 + sb.append('\n') + sb.append(' # Reduce binary size. https:crbug.com/954584\n') sb.append(' ignore_proguard_configs = true\n') break case 'com_android_support_support_annotations': @@ -332,15 +344,17 @@ sb.append(' extract_native_libraries = true\n') break case 'com_google_guava_guava': - // Need to exclude class and replace it with class library as - // com_google_guava_listenablefuture has support_androids=true. + sb.append('\n') + sb.append(' # Need to exclude class and replace it with class library as\n') + sb.append(' # com_google_guava_listenablefuture has support_androids=true.\n') sb.append(' deps += [":com_google_guava_listenablefuture_java"]\n') sb.append(' jar_excluded_patterns = ["*/ListenableFuture.class"]\n') break case 'com_google_code_findbugs_jsr305': case 'com_google_guava_listenablefuture': case 'com_googlecode_java_diff_utils_diffutils': - // Needed to break dependency cycle for errorprone_plugin_java. + sb.append('\n') + sb.append(' # Needed to break dependency cycle for errorprone_plugin_java.\n') sb.append(' no_build_hooks = true\n') break case 'androidx_test_rules':
diff --git a/third_party/blink/public/web/web_local_frame_client.h b/third_party/blink/public/web/web_local_frame_client.h index d821def..8a2f1ab 100644 --- a/third_party/blink/public/web/web_local_frame_client.h +++ b/third_party/blink/public/web/web_local_frame_client.h
@@ -497,6 +497,9 @@ // A performance timing event (e.g. first paint) occurred virtual void DidChangePerformanceTiming() {} + // An Input Event observed. + virtual void DidObserveInputDelay(base::TimeDelta input_delay) {} + // A cpu task or tasks completed. Triggered when at least 100ms of wall time // was spent in tasks on the frame. virtual void DidChangeCpuTiming(base::TimeDelta time) {}
diff --git a/third_party/blink/public/web/web_performance.h b/third_party/blink/public/web/web_performance.h index 730f436..ab7c1b2 100644 --- a/third_party/blink/public/web/web_performance.h +++ b/third_party/blink/public/web/web_performance.h
@@ -102,9 +102,6 @@ BLINK_EXPORT base::Optional<base::TimeDelta> FirstInputTimestamp() const; BLINK_EXPORT base::Optional<base::TimeDelta> LongestInputDelay() const; BLINK_EXPORT base::Optional<base::TimeDelta> LongestInputTimestamp() const; - BLINK_EXPORT double TotalInputDelay() const; - BLINK_EXPORT double TotalAdjustedInputDelay() const; - BLINK_EXPORT uint64_t NumInputEvents() const; BLINK_EXPORT double ParseStart() const; BLINK_EXPORT double ParseStop() const; BLINK_EXPORT double ParseBlockedOnScriptLoadDuration() const;
diff --git a/third_party/blink/renderer/core/css/css_properties.json5 b/third_party/blink/renderer/core/css/css_properties.json5 index fea7ee0..787e2b5a 100644 --- a/third_party/blink/renderer/core/css/css_properties.json5 +++ b/third_party/blink/renderer/core/css/css_properties.json5
@@ -466,6 +466,7 @@ priority: "Animation", typedom_types: ["Time"], separator: ",", + valid_for_marker: true, }, { name: "animation-direction", @@ -479,6 +480,7 @@ }, priority: "Animation", separator: ",", + valid_for_marker: true, }, { name: "animation-duration", @@ -491,6 +493,7 @@ priority: "Animation", typedom_types: ["Time"], separator: ",", + valid_for_marker: true, }, { name: "animation-fill-mode", @@ -503,6 +506,7 @@ keywords: ["none", "forwards", "backwards", "both"], typedom_types: ["Keyword"], separator: ",", + valid_for_marker: true, }, { name: "animation-iteration-count", @@ -517,6 +521,7 @@ keywords: ["infinite"], typedom_types: ["Keyword", "Number"], separator: ",", + valid_for_marker: true, }, { name: "animation-name", @@ -528,7 +533,8 @@ priority: "Animation", keywords: ["none"], typedom_types: ["Keyword"], - separator: "," + separator: ",", + valid_for_marker: true, }, { name: "animation-play-state", @@ -541,6 +547,7 @@ keywords: ["running", "paused"], typedom_types: ["Keyword"], separator: ",", + valid_for_marker: true, }, { name: "animation-timing-function", @@ -565,6 +572,7 @@ ], typedom_types: ["Keyword"], separator: ",", + valid_for_marker: true, }, { name: "transition-delay", @@ -576,6 +584,7 @@ priority: "Animation", typedom_types: ["Time"], separator: ",", + valid_for_marker: true, }, { name: "transition-duration", @@ -587,6 +596,7 @@ attribute: "Duration", }, priority: "Animation", + valid_for_marker: true, }, { name: "transition-property", @@ -597,7 +607,8 @@ }, priority: "Animation", keywords: ["none"], - typedom_types: ["Keyword"] + typedom_types: ["Keyword"], + valid_for_marker: true, }, { name: "transition-timing-function", @@ -621,6 +632,7 @@ "step-end"], typedom_types: ["Keyword"], separator: ",", + valid_for_marker: true, }, // High Priority and all other font properties.
diff --git a/third_party/blink/renderer/core/css/resolver/style_adjuster.cc b/third_party/blink/renderer/core/css/resolver/style_adjuster.cc index 84d7bfa..49f61af 100644 --- a/third_party/blink/renderer/core/css/resolver/style_adjuster.cc +++ b/third_party/blink/renderer/core/css/resolver/style_adjuster.cc
@@ -222,7 +222,6 @@ style.SetMarginEnd(Length::Fixed(margins.second)); } else { // Outside list markers should generate a block container. - DCHECK_EQ(style.Display(), EDisplay::kInline); style.SetDisplay(EDisplay::kInlineBlock); // Do not break inside the marker, and honor the trailing spaces.
diff --git a/third_party/blink/renderer/core/css/resolver/style_resolver.cc b/third_party/blink/renderer/core/css/resolver/style_resolver.cc index de7a32a..ac4742a 100644 --- a/third_party/blink/renderer/core/css/resolver/style_resolver.cc +++ b/third_party/blink/renderer/core/css/resolver/style_resolver.cc
@@ -1399,6 +1399,8 @@ }); if (IsForcedColorsModeEnabled(state)) filter = filter.Add(CSSProperty::kIsAffectedByForcedColors, true); + if (state.Style()->StyleType() == kPseudoIdMarker) + filter = filter.Add(CSSProperty::kValidForMarker, false); filter = filter.Add(CSSProperty::kAnimation, true); cascade->Analyze(interpolations, filter); cascade->Apply(&match_result, &interpolations, filter); @@ -1449,6 +1451,23 @@ return nullptr; } +static bool PassesPropertyFilter(ValidPropertyFilter valid_property_filter, + CSSPropertyID property, + const Document& document) { + switch (valid_property_filter) { + case ValidPropertyFilter::kNoFilter: + return true; + case ValidPropertyFilter::kFirstLetter: + return CSSProperty::Get(property).IsValidForFirstLetter(); + case ValidPropertyFilter::kCue: + return CSSProperty::Get(property).IsValidForCue(); + case ValidPropertyFilter::kMarker: + return CSSProperty::Get(property).IsValidForMarker(); + } + NOTREACHED(); + return true; +} + template <CSSPropertyPriority priority> void StyleResolver::ApplyAnimatedStandardProperties( StyleResolverState& state, @@ -1469,6 +1488,10 @@ entry.key.GetCSSProperty().IsAffectedByForcedColors() && state.Style()->ForcedColorAdjust() != EForcedColorAdjust::kNone) continue; + if (state.Style()->StyleType() == kPseudoIdMarker && + !PassesPropertyFilter(ValidPropertyFilter::kMarker, property, + state.GetDocument())) + continue; const Interpolation& interpolation = *entry.value.front(); if (IsA<InvalidatableInterpolation>(interpolation)) { CSSInterpolationTypesMap map(state.GetDocument().GetPropertyRegistry(), @@ -1481,23 +1504,6 @@ } } -static bool PassesPropertyFilter(ValidPropertyFilter valid_property_filter, - CSSPropertyID property, - const Document& document) { - switch (valid_property_filter) { - case ValidPropertyFilter::kNoFilter: - return true; - case ValidPropertyFilter::kFirstLetter: - return CSSProperty::Get(property).IsValidForFirstLetter(); - case ValidPropertyFilter::kCue: - return CSSProperty::Get(property).IsValidForCue(); - case ValidPropertyFilter::kMarker: - return CSSProperty::Get(property).IsValidForMarker(); - } - NOTREACHED(); - return true; -} - static inline void ApplyProperty(const CSSProperty& property, StyleResolverState& state, const CSSValue& value,
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_context.h b/third_party/blink/renderer/core/display_lock/display_lock_context.h index 667567c..ad076b8 100644 --- a/third_party/blink/renderer/core/display_lock/display_lock_context.h +++ b/third_party/blink/renderer/core/display_lock/display_lock_context.h
@@ -40,7 +40,8 @@ // Shorthands kViewport = static_cast<uint16_t>(kSelection) | static_cast<uint16_t>(kUserFocus) | - static_cast<uint16_t>(kViewportIntersection), + static_cast<uint16_t>(kViewportIntersection) | + static_cast<uint16_t>(kAccessibility), kAny = static_cast<uint16_t>(kAccessibility) | static_cast<uint16_t>(kFindInPage) | static_cast<uint16_t>(kFragmentNavigation) |
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_utilities.cc b/third_party/blink/renderer/core/display_lock/display_lock_utilities.cc index 7289620e..5944de5 100644 --- a/third_party/blink/renderer/core/display_lock/display_lock_utilities.cc +++ b/third_party/blink/renderer/core/display_lock/display_lock_utilities.cc
@@ -296,22 +296,24 @@ return nullptr; } -bool DisplayLockUtilities::IsInNonActivatableLockedSubtree(const Node& node) { - if (!RuntimeEnabledFeatures::CSSSubtreeVisibilityEnabled() || +bool DisplayLockUtilities::IsInUnlockedOrActivatableSubtree( + const Node& node, + DisplayLockActivationReason activation_reason) { + if (!RuntimeEnabledFeatures::CSSSubtreeVisibilityEnabled( + node.GetExecutionContext()) || node.GetDocument().LockedDisplayLockCount() == 0 || node.GetDocument().DisplayLockBlockingAllActivationCount() == 0 || !node.CanParticipateInFlatTree()) { - return false; + return true; } for (auto* element = NearestLockedExclusiveAncestor(node); element; element = NearestLockedExclusiveAncestor(*element)) { - if (!element->GetDisplayLockContext()->IsActivatable( - DisplayLockActivationReason::kAny)) { - return true; + if (!element->GetDisplayLockContext()->IsActivatable(activation_reason)) { + return false; } } - return false; + return true; } bool DisplayLockUtilities::IsInLockedSubtreeCrossingFrames(
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_utilities.h b/third_party/blink/renderer/core/display_lock/display_lock_utilities.h index 89300d4..3eb26666 100644 --- a/third_party/blink/renderer/core/display_lock/display_lock_utilities.h +++ b/third_party/blink/renderer/core/display_lock/display_lock_utilities.h
@@ -70,8 +70,22 @@ static Element* NearestLockedInclusiveAncestor(const LayoutObject& object); static Element* NearestLockedExclusiveAncestor(const LayoutObject& object); - // Whether this node has non-activatable locked exclusive ancestors or not. - static bool IsInNonActivatableLockedSubtree(const Node& node); + // Returns true if |node| is not in a locked subtree, or if it's possible to + // activate all of the locked ancestors for |activation_reason|. + static bool IsInUnlockedOrActivatableSubtree( + const Node& node, + DisplayLockActivationReason activation_reason = + DisplayLockActivationReason::kAny); + + // Returns true if |node| is in a locked subtree, and at least one of its + // locked ancestors can't be activated with |activation_reason|. In other + // words, this node should be treated as if it's not in the tree for + // |activation_reason|. + static bool ShouldIgnoreNodeDueToDisplayLock( + const Node& node, + DisplayLockActivationReason activation_reason) { + return !IsInUnlockedOrActivatableSubtree(node, activation_reason); + } // Returns true if the element is in a locked subtree (or is self-locked with // no self-updates). This crosses frames while navigating the ancestor chain.
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc index acca70bd1..9801e9a 100644 --- a/third_party/blink/renderer/core/dom/element.cc +++ b/third_party/blink/renderer/core/dom/element.cc
@@ -5201,6 +5201,7 @@ element->SetComputedStyle(std::move(pseudo_style)); else GetElementRareData()->SetPseudoElement(kPseudoIdFirstLetter, nullptr); + element->ClearNeedsStyleRecalc(); return; }
diff --git a/third_party/blink/renderer/core/exported/local_frame_client_impl.cc b/third_party/blink/renderer/core/exported/local_frame_client_impl.cc index a06e5240..22919e8 100644 --- a/third_party/blink/renderer/core/exported/local_frame_client_impl.cc +++ b/third_party/blink/renderer/core/exported/local_frame_client_impl.cc
@@ -724,6 +724,12 @@ web_frame_->Client()->DidChangePerformanceTiming(); } +void LocalFrameClientImpl::DidObserveInputDelay(base::TimeDelta input_delay) { + if (web_frame_->Client()) { + web_frame_->Client()->DidObserveInputDelay(input_delay); + } +} + void LocalFrameClientImpl::DidChangeCpuTiming(base::TimeDelta time) { if (web_frame_->Client()) web_frame_->Client()->DidChangeCpuTiming(time);
diff --git a/third_party/blink/renderer/core/exported/local_frame_client_impl.h b/third_party/blink/renderer/core/exported/local_frame_client_impl.h index 8ff5c7ff..77194e8e 100644 --- a/third_party/blink/renderer/core/exported/local_frame_client_impl.h +++ b/third_party/blink/renderer/core/exported/local_frame_client_impl.h
@@ -140,6 +140,7 @@ void DidDisplayContentWithCertificateErrors() override; void DidRunContentWithCertificateErrors() override; void DidChangePerformanceTiming() override; + void DidObserveInputDelay(base::TimeDelta) override; void DidChangeCpuTiming(base::TimeDelta) override; void DidObserveLoadingBehavior(LoadingBehaviorFlag) override; void DidObserveNewFeatureUsage(mojom::WebFeature) override;
diff --git a/third_party/blink/renderer/core/exported/web_frame_test.cc b/third_party/blink/renderer/core/exported/web_frame_test.cc index 1c0ccb7..c8d7b26 100644 --- a/third_party/blink/renderer/core/exported/web_frame_test.cc +++ b/third_party/blink/renderer/core/exported/web_frame_test.cc
@@ -13127,7 +13127,7 @@ ASSERT_TRUE(widget); gfx::Point viewport_offset(7, -11); WebRect viewport_intersection(0, 11, 200, 89); - WebRect mainframe_intersection(0, 0, 200, 140); + WebRect mainframe_intersection(7, -11, 200, 140); FrameOcclusionState occlusion_state = FrameOcclusionState::kUnknown; widget->SetRemoteViewportIntersection( {viewport_offset, viewport_intersection, mainframe_intersection,
diff --git a/third_party/blink/renderer/core/exported/web_performance.cc b/third_party/blink/renderer/core/exported/web_performance.cc index f927ef9..e29242e 100644 --- a/third_party/blink/renderer/core/exported/web_performance.cc +++ b/third_party/blink/renderer/core/exported/web_performance.cc
@@ -212,17 +212,6 @@ return private_->timing()->LongestInputTimestamp(); } -double WebPerformance::TotalInputDelay() const { - return MillisecondsToSeconds(private_->timing()->TotalInputDelay()); -} - -double WebPerformance::TotalAdjustedInputDelay() const { - return MillisecondsToSeconds(private_->timing()->TotalAdjustedInputDelay()); -} -uint64_t WebPerformance::NumInputEvents() const { - return private_->timing()->NumInputEvents(); -} - double WebPerformance::ParseStart() const { return MillisecondsToSeconds(private_->timing()->ParseStart()); }
diff --git a/third_party/blink/renderer/core/frame/frame_view.cc b/third_party/blink/renderer/core/frame/frame_view.cc index 1855e03..0591058 100644 --- a/third_party/blink/renderer/core/frame/frame_view.cc +++ b/third_party/blink/renderer/core/frame/frame_view.cc
@@ -159,20 +159,8 @@ } } - PhysicalRect mainframe_intersection_rect; - if (!geometry.UnclippedIntersectionRect().IsEmpty()) { - mainframe_intersection_rect = PhysicalRect::EnclosingRect( - matrix.ProjectQuad(FloatRect(geometry.UnclippedIntersectionRect())) - .BoundingBox()); - - if (mainframe_intersection_rect.IsEmpty()) { - mainframe_document_intersection = IntRect( - FlooredIntPoint(mainframe_intersection_rect.offset), IntSize()); - } else { - mainframe_document_intersection = - EnclosingIntRect(mainframe_intersection_rect); - } - } + mainframe_document_intersection = + EnclosingIntRect(geometry.UnclippedIntersectionRect()); } else if (occlusion_state == FrameOcclusionState::kGuaranteedNotOccluded) { // If the parent LocalFrameView is throttled and out-of-date, then we can't // get any useful information. @@ -186,6 +174,11 @@ UpdateFrameVisibility(!viewport_intersection.IsEmpty()); + if (ShouldReportMainFrameIntersection()) { + GetFrame().Client()->OnMainFrameDocumentIntersectionChanged( + mainframe_document_intersection); + } + // We don't throttle 0x0 or display:none iframes, because in practice they are // sometimes used to drive UI logic. bool hidden_for_throttling = viewport_intersection.IsEmpty() &&
diff --git a/third_party/blink/renderer/core/frame/frame_view.h b/third_party/blink/renderer/core/frame/frame_view.h index 73d183d22..aa5e42a 100644 --- a/third_party/blink/renderer/core/frame/frame_view.h +++ b/third_party/blink/renderer/core/frame/frame_view.h
@@ -17,7 +17,11 @@ class Frame; struct IntrinsicSizingInfo; -class CORE_EXPORT FrameView : public EmbeddedContentView { +// clang::lto_visibility_public is necessary to prevent the compiler from +// performing a vtable optimization that crashes the renderer. See +// crbug.com/1062006. +class CORE_EXPORT [[clang::lto_visibility_public]] FrameView + : public EmbeddedContentView { public: FrameView(const IntRect& frame_rect) : EmbeddedContentView(frame_rect) {} ~FrameView() override = default; @@ -40,6 +44,7 @@ bool CanThrottleRenderingForPropagation() const; bool IsFrameView() const override { return true; } + virtual bool ShouldReportMainFrameIntersection() const { return false; } Frame& GetFrame() const; blink::mojom::FrameVisibility GetFrameVisibility() const {
diff --git a/third_party/blink/renderer/core/frame/local_frame.cc b/third_party/blink/renderer/core/frame/local_frame.cc index 2fdd3d5..038e421 100644 --- a/third_party/blink/renderer/core/frame/local_frame.cc +++ b/third_party/blink/renderer/core/frame/local_frame.cc
@@ -1491,8 +1491,14 @@ // Notify the render frame observers when the main frame intersection changes. if (intersection_state_.main_frame_document_intersection != intersection_state.main_frame_document_intersection) { + // Put the main frame document intersection in the coordinate system of the + // viewport. + IntRect offset_main_frame_intersection = + intersection_state.main_frame_document_intersection; + offset_main_frame_intersection.MoveBy( + IntPoint(intersection_state.viewport_offset)); Client()->OnMainFrameDocumentIntersectionChanged( - intersection_state.main_frame_document_intersection); + offset_main_frame_intersection); } bool can_skip_sticky_frame_tracking =
diff --git a/third_party/blink/renderer/core/frame/local_frame_client.h b/third_party/blink/renderer/core/frame/local_frame_client.h index 7843fbbf..5cd03293 100644 --- a/third_party/blink/renderer/core/frame/local_frame_client.h +++ b/third_party/blink/renderer/core/frame/local_frame_client.h
@@ -181,6 +181,8 @@ // Will be called when |PerformanceTiming| events are updated virtual void DidChangePerformanceTiming() {} + // Will be called when an |InputEvent| is observed. + virtual void DidObserveInputDelay(base::TimeDelta input_delay) {} // Will be called when |CpuTiming| events are updated virtual void DidChangeCpuTiming(base::TimeDelta time) {}
diff --git a/third_party/blink/renderer/core/frame/local_frame_view.cc b/third_party/blink/renderer/core/frame/local_frame_view.cc index 38b4190..ded89456 100644 --- a/third_party/blink/renderer/core/frame/local_frame_view.cc +++ b/third_party/blink/renderer/core/frame/local_frame_view.cc
@@ -3703,12 +3703,6 @@ } } -void LocalFrameView::SetViewportIntersection( - const ViewportIntersectionState& intersection_state) { - GetFrame().Client()->OnMainFrameDocumentIntersectionChanged( - intersection_state.main_frame_document_intersection); -} - PhysicalOffset LocalFrameView::ViewportToFrame( const PhysicalOffset& point_in_viewport) const { PhysicalOffset point_in_root_frame = PhysicalOffset::FromFloatPointRound( @@ -4419,11 +4413,22 @@ // This is the top-level frame, so no mapping necessary. if (frame_->IsMainFrame()) return true; - bool result = rect.InclusiveIntersect(PhysicalRect( - apply_overflow_clip ? frame_->RemoteViewportIntersection() - : frame_->RemoteMainFrameDocumentIntersection())); - if (result) + bool result; + if (apply_overflow_clip) { + result = rect.InclusiveIntersect( + PhysicalRect(frame_->RemoteViewportIntersection())); + if (result) + rect.Move(PhysicalOffset(GetFrame().RemoteViewportOffset())); + } else { + // If we are not applying the overflow clip, the mapping should be in the + // remote viewport's coordinate system. Map rect to the remote viewport's + // coordinate system prior to intersecting. + // RemoteMainFrameDocumentIntersection is in the remote viewport's + // coordinate system. rect.Move(PhysicalOffset(GetFrame().RemoteViewportOffset())); + result = rect.InclusiveIntersect( + PhysicalRect(frame_->RemoteMainFrameDocumentIntersection())); + } return result; }
diff --git a/third_party/blink/renderer/core/frame/local_frame_view.h b/third_party/blink/renderer/core/frame/local_frame_view.h index fe91ce4..e4362082 100644 --- a/third_party/blink/renderer/core/frame/local_frame_view.h +++ b/third_party/blink/renderer/core/frame/local_frame_view.h
@@ -552,6 +552,7 @@ void Hide() override; bool IsLocalFrameView() const override { return true; } + bool ShouldReportMainFrameIntersection() const override { return true; } void Trace(Visitor*) override; void NotifyPageThatContentAreaWillPaint() const; @@ -702,7 +703,7 @@ void ParentVisibleChanged() override; void NotifyFrameRectsChangedIfNeeded(); void SetViewportIntersection( - const ViewportIntersectionState& intersection_state) override; + const ViewportIntersectionState& intersection_state) override {} void VisibilityForThrottlingChanged() override; bool LifecycleUpdatesThrottled() const override { return lifecycle_updates_throttled_;
diff --git a/third_party/blink/renderer/core/intersection_observer/intersection_geometry.cc b/third_party/blink/renderer/core/intersection_observer/intersection_geometry.cc index 586abe8f..7527e93 100644 --- a/third_party/blink/renderer/core/intersection_observer/intersection_geometry.cc +++ b/third_party/blink/renderer/core/intersection_observer/intersection_geometry.cc
@@ -335,9 +335,6 @@ .Inverse(); intersection_rect_ = PhysicalRect::EnclosingRect( matrix.ProjectQuad(FloatRect(intersection_rect_)).BoundingBox()); - unclipped_intersection_rect_ = PhysicalRect::EnclosingRect( - matrix.ProjectQuad(FloatRect(unclipped_intersection_rect_)) - .BoundingBox()); // intersection_rect_ is in the coordinate system of the implicit root; // map it down the to absolute coordinates for the target's document. } else { @@ -348,10 +345,6 @@ root_geometry.root_to_document_transform .MapQuad(FloatQuad(FloatRect(intersection_rect_))) .BoundingBox()); - unclipped_intersection_rect_ = PhysicalRect::EnclosingRect( - root_geometry.root_to_document_transform - .MapQuad(FloatQuad(FloatRect(unclipped_intersection_rect_))) - .BoundingBox()); } } else { intersection_rect_ = PhysicalRect();
diff --git a/third_party/blink/renderer/core/intersection_observer/intersection_geometry.h b/third_party/blink/renderer/core/intersection_observer/intersection_geometry.h index 35e33f4..854c98c 100644 --- a/third_party/blink/renderer/core/intersection_observer/intersection_geometry.h +++ b/third_party/blink/renderer/core/intersection_observer/intersection_geometry.h
@@ -100,6 +100,9 @@ PhysicalRect TargetRect() const { return target_rect_; } PhysicalRect IntersectionRect() const { return intersection_rect_; } + + // The intersection rect without applying viewport clipping in the coordinate + // system of the root's viewport. PhysicalRect UnclippedIntersectionRect() const { return unclipped_intersection_rect_; }
diff --git a/third_party/blink/renderer/core/loader/document_loader.cc b/third_party/blink/renderer/core/loader/document_loader.cc index 0989d16..237ac7bc 100644 --- a/third_party/blink/renderer/core/loader/document_loader.cc +++ b/third_party/blink/renderer/core/loader/document_loader.cc
@@ -389,6 +389,11 @@ } } +void DocumentLoader::DidObserveInputDelay(base::TimeDelta input_delay) { + if (frame_ && state_ >= kCommitted) { + GetLocalFrameClient().DidObserveInputDelay(input_delay); + } +} void DocumentLoader::DidObserveLoadingBehavior(LoadingBehaviorFlag behavior) { if (frame_) { DCHECK_GE(state_, kCommitted);
diff --git a/third_party/blink/renderer/core/loader/document_loader.h b/third_party/blink/renderer/core/loader/document_loader.h index 0deff31..31fc575 100644 --- a/third_party/blink/renderer/core/loader/document_loader.h +++ b/third_party/blink/renderer/core/loader/document_loader.h
@@ -154,6 +154,7 @@ const; void DidChangePerformanceTiming(); + void DidObserveInputDelay(base::TimeDelta input_delay); void DidObserveLoadingBehavior(LoadingBehaviorFlag); void UpdateForSameDocumentNavigation(const KURL&, SameDocumentNavigationSource,
diff --git a/third_party/blink/renderer/core/loader/interactive_detector.cc b/third_party/blink/renderer/core/loader/interactive_detector.cc index 52d98d6..8ce504fc 100644 --- a/third_party/blink/renderer/core/loader/interactive_detector.cc +++ b/third_party/blink/renderer/core/loader/interactive_detector.cc
@@ -153,18 +153,6 @@ return page_event_times_.longest_input_timestamp; } -uint64_t InteractiveDetector::GetNumInputEvents() const { - return page_event_times_.num_input_events; -} - -base::TimeDelta InteractiveDetector::GetTotalInputDelay() const { - return page_event_times_.total_input_delay; -} - -base::TimeDelta InteractiveDetector::GetTotalAdjustedInputDelay() const { - return page_event_times_.total_adjusted_input_delay; -} - bool InteractiveDetector::PageWasBackgroundedSinceEvent( base::TimeTicks event_time) { DCHECK(GetSupplementable()); @@ -235,17 +223,14 @@ event_timestamp = event_platform_timestamp; } - page_event_times_.num_input_events++; - page_event_times_.total_input_delay += delay; - page_event_times_.total_adjusted_input_delay += - base::TimeDelta::FromMilliseconds( - std::max(delay.InMilliseconds() - 50, int64_t(0))); pending_pointerdown_delay_ = base::TimeDelta(); pending_pointerdown_timestamp_ = base::TimeTicks(); + bool interactive_timing_metrics_changed = false; if (!page_event_times_.first_input_delay.has_value()) { page_event_times_.first_input_delay = delay; page_event_times_.first_input_timestamp = event_timestamp; + interactive_timing_metrics_changed = true; if (delay > kFirstInputDelayTraceEventThreshold) { // Emit a trace event to highlight long first input delays. @@ -275,6 +260,9 @@ ukm::builders::InputEvent(source_id) .SetInteractiveTiming_InputDelay(delay.InMilliseconds()) .Record(GetUkmRecorder()); + if (GetSupplementable()->Loader()) { + GetSupplementable()->Loader()->DidObserveInputDelay(delay); + } UMA_HISTOGRAM_CUSTOM_TIMES(kHistogramInputDelay, delay, base::TimeDelta::FromMilliseconds(1), @@ -291,10 +279,12 @@ !PageWasBackgroundedSinceEvent(event_timestamp)) { page_event_times_.longest_input_delay = delay; page_event_times_.longest_input_timestamp = event_timestamp; + interactive_timing_metrics_changed = true; } - if (GetSupplementable()->Loader()) + if (GetSupplementable()->Loader() && interactive_timing_metrics_changed) { GetSupplementable()->Loader()->DidChangePerformanceTiming(); + } } void InteractiveDetector::BeginNetworkQuietPeriod(
diff --git a/third_party/blink/renderer/core/loader/interactive_detector.h b/third_party/blink/renderer/core/loader/interactive_detector.h index 3b504a2..09e8622e 100644 --- a/third_party/blink/renderer/core/loader/interactive_detector.h +++ b/third_party/blink/renderer/core/loader/interactive_detector.h
@@ -100,15 +100,6 @@ // GetLongestInputDelay(). base::Optional<base::TimeTicks> GetLongestInputTimestamp() const; - // The number of user interactions. - uint64_t GetNumInputEvents() const; - - // The sum of all input delay. - base::TimeDelta GetTotalInputDelay() const; - - // The sum of all adjusted input delay. - base::TimeDelta GetTotalAdjustedInputDelay() const; - // Process an input event, updating first_input_delay and // first_input_timestamp if needed. void HandleForInputDelay(const Event&, @@ -151,9 +142,6 @@ base::Optional<base::TimeDelta> longest_input_delay; base::Optional<base::TimeTicks> first_input_timestamp; base::Optional<base::TimeTicks> longest_input_timestamp; - base::TimeDelta total_input_delay; - base::TimeDelta total_adjusted_input_delay; - uint64_t num_input_events; } page_event_times_; struct VisibilityChangeEvent {
diff --git a/third_party/blink/renderer/core/loader/interactive_detector_test.cc b/third_party/blink/renderer/core/loader/interactive_detector_test.cc index 19ac39d..ecd729b 100644 --- a/third_party/blink/renderer/core/loader/interactive_detector_test.cc +++ b/third_party/blink/renderer/core/loader/interactive_detector_test.cc
@@ -584,30 +584,6 @@ delay.InMilliseconds()); } -TEST_F(InteractiveDetectorTest, TotalInputDelay) { - Event event_1; - event_1.SetTrusted(true); - event_1.SetType(event_type_names::kClick); - base::TimeDelta delay_1 = base::TimeDelta::FromMilliseconds(10); - base::TimeTicks processing_start_1 = Now() + delay_1; - base::TimeTicks event_platform_timestamp_1 = Now(); - GetDetector()->HandleForInputDelay(event_1, event_platform_timestamp_1, - processing_start_1); - Event event_2; - event_2.SetTrusted(true); - event_2.SetType(event_type_names::kClick); - base::TimeDelta delay_2 = base::TimeDelta::FromMilliseconds(60); - base::TimeTicks processing_start_2 = Now() + delay_2; - base::TimeTicks event_platform_timestamp_2 = Now(); - GetDetector()->HandleForInputDelay(event_2, event_platform_timestamp_2, - processing_start_2); - - EXPECT_EQ(uint64_t(2), GetDetector()->GetNumInputEvents()); - EXPECT_EQ(int64_t(70), GetDetector()->GetTotalInputDelay().InMilliseconds()); - EXPECT_EQ(int64_t(10), - GetDetector()->GetTotalAdjustedInputDelay().InMilliseconds()); -} - // In tests for Total Blocking Time (TBT) we call SetTimeToInteractive() instead // of allowing TimeToInteractive to occur because the computation is gated // behind tracing being enabled, which means that they won't run by default. In
diff --git a/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.cc b/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.cc index 1581092c..ce7d9b18 100644 --- a/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.cc +++ b/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.cc
@@ -138,7 +138,12 @@ if (auto* scrollable_area = layer->GetScrollableArea()) { if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) { bool force_prefer_compositing_to_lcd_text = - reasons != CompositingReason::kNone; + reasons != CompositingReason::kNone || + // In CompositeAfterPaint though we don't treat hidden backface as + // a direct compositing reason, it's very likely that the object will + // be composited, and it also indicates preference of compositing, + // so we prefer composited scrolling here. + style.BackfaceVisibility() == EBackfaceVisibility::kHidden; if (!force_prefer_compositing_to_lcd_text && object.IsLayoutView()) { if (auto* owner_object = object.GetFrame()->OwnerLayoutObject()) {
diff --git a/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc b/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc index b8b50fdf..cf5d358 100644 --- a/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc +++ b/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
@@ -422,6 +422,12 @@ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) { if (direct_compositing_reasons != CompositingReason::kNone) return true; + // In CompositeAfterPaint though we don't treat hidden backface as + // a direct compositing reason, it's very likely that the object will + // be composited, so a paint offset translation will be beneficial. + if (box_model.StyleRef().BackfaceVisibility() == + EBackfaceVisibility::kHidden) + return true; } else if (box_model.GetCompositingState() == kPaintsIntoOwnBacking) { return true; }
diff --git a/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc b/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc index 8402f5b7..1805b3d 100644 --- a/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc +++ b/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc
@@ -5158,16 +5158,10 @@ ASSERT_NE(nullptr, target_properties); const auto* paint_offset_translation = target_properties->PaintOffsetTranslation(); - if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) { - EXPECT_EQ(nullptr, paint_offset_translation); - EXPECT_EQ(PhysicalOffset(60, 50), target->FirstFragment().PaintOffset()); - } else { - // For SPv1, |target| is composited so we created PaintOffsetTranslation. - ASSERT_NE(nullptr, paint_offset_translation); - EXPECT_EQ(FloatSize(60, 50), paint_offset_translation->Translation2D()); - EXPECT_EQ(TransformPaintPropertyNode::BackfaceVisibility::kInherited, - paint_offset_translation->GetBackfaceVisibilityForTesting()); - } + ASSERT_NE(nullptr, paint_offset_translation); + EXPECT_EQ(FloatSize(60, 50), paint_offset_translation->Translation2D()); + EXPECT_EQ(TransformPaintPropertyNode::BackfaceVisibility::kInherited, + paint_offset_translation->GetBackfaceVisibilityForTesting()); const auto* transform = target_properties->Transform(); ASSERT_NE(nullptr, transform);
diff --git a/third_party/blink/renderer/core/timing/performance_timing.cc b/third_party/blink/renderer/core/timing/performance_timing.cc index 902bb05a..a661f3f 100644 --- a/third_party/blink/renderer/core/timing/performance_timing.cc +++ b/third_party/blink/renderer/core/timing/performance_timing.cc
@@ -448,29 +448,6 @@ interactive_detector->GetLongestInputTimestamp()); } -uint64_t PerformanceTiming::TotalInputDelay() const { - const InteractiveDetector* interactive_detector = GetInteractiveDetector(); - if (!interactive_detector) - return 0; - - return ToIntegerMilliseconds(interactive_detector->GetTotalInputDelay()); -} - -uint64_t PerformanceTiming::TotalAdjustedInputDelay() const { - const InteractiveDetector* interactive_detector = GetInteractiveDetector(); - if (!interactive_detector) - return 0; - - return ToIntegerMilliseconds( - interactive_detector->GetTotalAdjustedInputDelay()); -} -uint64_t PerformanceTiming::NumInputEvents() const { - const InteractiveDetector* interactive_detector = GetInteractiveDetector(); - if (!interactive_detector) - return 0; - - return interactive_detector->GetNumInputEvents(); -} uint64_t PerformanceTiming::ParseStart() const { const DocumentParserTiming* timing = GetDocumentParserTiming(); if (!timing)
diff --git a/third_party/blink/renderer/core/timing/performance_timing.h b/third_party/blink/renderer/core/timing/performance_timing.h index 32e5068..29ce0e4d 100644 --- a/third_party/blink/renderer/core/timing/performance_timing.h +++ b/third_party/blink/renderer/core/timing/performance_timing.h
@@ -139,12 +139,6 @@ base::Optional<base::TimeDelta> LongestInputDelay() const; // The timestamp of the event whose delay is reported by LongestInputDelay(). base::Optional<base::TimeDelta> LongestInputTimestamp() const; - // The sum of all input delay. - uint64_t TotalInputDelay() const; - // The sum of all adjusted input delay. - uint64_t TotalAdjustedInputDelay() const; - // The number of user interactions. - uint64_t NumInputEvents() const; uint64_t ParseStart() const; uint64_t ParseStop() const;
diff --git a/third_party/blink/renderer/core/workers/worker_thread_test.cc b/third_party/blink/renderer/core/workers/worker_thread_test.cc index 7a1eddc..a0da94e 100644 --- a/third_party/blink/renderer/core/workers/worker_thread_test.cc +++ b/third_party/blink/renderer/core/workers/worker_thread_test.cc
@@ -492,8 +492,7 @@ EXPECT_EQ(ExitCode::kGracefullyTerminated, GetExitCode()); } -// Disabled due to flakiness: https://crbug.com/935231 -TEST_F(WorkerThreadTest, DISABLED_TerminateWorkerWhileChildIsLoading) { +TEST_F(WorkerThreadTest, TerminateWorkerWhileChildIsLoading) { ExpectReportingCalls(); Start(); worker_thread_->WaitForInit();
diff --git a/third_party/blink/renderer/modules/accessibility/ax_node_object.cc b/third_party/blink/renderer/modules/accessibility/ax_node_object.cc index e5a5570..b6fdfb64 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_node_object.cc +++ b/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
@@ -79,6 +79,7 @@ #include "third_party/blink/renderer/core/layout/layout_object.h" #include "third_party/blink/renderer/core/layout/layout_table.h" #include "third_party/blink/renderer/core/layout/layout_view.h" +#include "third_party/blink/renderer/core/page/focus_controller.h" #include "third_party/blink/renderer/core/page/page.h" #include "third_party/blink/renderer/core/svg/svg_element.h" #include "third_party/blink/renderer/core/svg/svg_svg_element.h" @@ -372,7 +373,8 @@ } if (DisplayLockUtilities::NearestLockedExclusiveAncestor(*GetNode())) { - if (DisplayLockUtilities::IsInNonActivatableLockedSubtree(*GetNode())) { + if (DisplayLockUtilities::ShouldIgnoreNodeDueToDisplayLock( + *GetNode(), DisplayLockActivationReason::kAccessibility)) { if (ignored_reasons) ignored_reasons->push_back(IgnoredReason(kAXNotRendered)); return true; @@ -3139,7 +3141,21 @@ Document* document = GetDocument(); if (IsWebArea()) { - document->ClearFocusedElement(); + // If another Frame has focused content (e.g. nested iframe), then we + // need to clear focus for the other Document Frame. + // Here we set the focused element via the FocusController so that the + // other Frame loses focus, and the target Document Element gains focus. + // This fixes a scenario with Narrator Item Navigation when the user + // navigates from the outer UI to the document when the last focused + // element was within a nested iframe before leaving the document frame. + Page* page = document->GetPage(); + // Elements inside a portal should not be focusable. + if (page && !page->InsidePortal()) { + page->GetFocusController().SetFocusedElement(document->documentElement(), + document->GetFrame()); + } else { + document->ClearFocusedElement(); + } return true; }
diff --git a/third_party/blink/renderer/platform/graphics/paint/drawing_display_item.h b/third_party/blink/renderer/platform/graphics/paint/drawing_display_item.h index 636a26c..a6fa2cd 100644 --- a/third_party/blink/renderer/platform/graphics/paint/drawing_display_item.h +++ b/third_party/blink/renderer/platform/graphics/paint/drawing_display_item.h
@@ -37,6 +37,8 @@ bool Equals(const DisplayItem& other) const final; bool KnownToBeOpaque() const { + if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) + return false; if (!known_to_be_opaque_.has_value()) known_to_be_opaque_.emplace(CalculateKnownToBeOpaque(record_.get())); return *known_to_be_opaque_;
diff --git a/third_party/blink/web_tests/FlagExpectations/composite-after-paint b/third_party/blink/web_tests/FlagExpectations/composite-after-paint index d59e2037..dd4f1bec 100644 --- a/third_party/blink/web_tests/FlagExpectations/composite-after-paint +++ b/third_party/blink/web_tests/FlagExpectations/composite-after-paint
@@ -75,23 +75,14 @@ # Raster invalidation doesn't work for huge layers. paint/invalidation/raster-under-invalidation-checking.html [ Failure ] -# backface-visibility:hidden doesn't trigger composited scrolling. +# No composited scrolling for overflow:hidden (on marquee). compositing/overflow/do-not-repaint-if-scrolling-composited-layers.html [ Failure ] -paint/invalidation/compositing/scrolling-neg-z-index-descendants.html [ Failure ] -paint/invalidation/scroll/overflow-hidden-yet-scrolled-with-custom-scrollbar.html [ Failure ] -paint/invalidation/scroll/overflow-hidden-yet-scrolled.html [ Failure ] # We paint the iframe's content background in the scrolling layer, causing invalidation on scroll. paint/invalidation/scroll/iframe-scroll-repaint.html [ Failure ] # will-transform on descendant doesn't trigger compositing of iframe. paint/invalidation/scroll/composited-iframe-scroll-repaint.html [ Failure ] -# backface-visiblity:hidden is not a direct compositing reason. -# Extra raster invalidation caused by offset change, etc. -paint/invalidation/compositing/should-not-repaint-move-backface-hidden.html [ Failure ] -paint/invalidation/position/relative-positioned-movement-repaint.html [ Failure ] -paint/invalidation/compositing/should-not-repaint-composited-descendants.html [ Failure ] - # Extra layers for non-fast scrolling areas. compositing/overflow/textarea-scroll-touch.html [ Failure ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index 836f970..838be19 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -1784,8 +1784,6 @@ crbug.com/995106 external/wpt/css/css-pseudo/first-letter-exclude-inline-marker.html [ Failure ] crbug.com/995106 external/wpt/css/css-pseudo/first-letter-exclude-inline-child-marker.html [ Failure ] -crbug.com/1054509 external/wpt/css/css-transitions/non-rendered-element-004.tentative.html [ Skip ] - crbug.com/1058822 virtual/dark-color-scheme/external/wpt/css/css-color-adjust/rendering/dark-color-scheme/color-scheme-iframe-background-mismatch-alpha.html [ Failure ] crbug.com/1058822 virtual/dark-color-scheme/external/wpt/css/css-color-adjust/rendering/dark-color-scheme/color-scheme-iframe-background-mismatch-opaque.html [ Failure ] @@ -3200,8 +3198,6 @@ crbug.com/626703 [ Mac ] external/wpt/css/css-sizing/clone-intrinsic-size.html [ Failure ] crbug.com/626703 [ Win ] external/wpt/css/css-sizing/clone-intrinsic-size.html [ Failure ] crbug.com/626703 [ Retina ] external/wpt/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-screenx-screeny.html [ Timeout ] -crbug.com/626703 [ Mac10.12 ] external/wpt/media-source/mediasource-config-change-webm-av-framesize.html [ Timeout ] -crbug.com/626703 [ Mac10.12 ] external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-cue-negative-duration.html [ Timeout ] crbug.com/626703 [ Mac10.12 ] external/wpt/preload/download-resources.html [ Failure Timeout ] crbug.com/626703 [ Mac10.13 ] external/wpt/preload/download-resources.html [ Failure Timeout ] crbug.com/626703 [ Retina ] external/wpt/preload/download-resources.html [ Failure Timeout ] @@ -3285,7 +3281,6 @@ crbug.com/626703 external/wpt/css/css-lists/li-list-item-counter.html [ Failure ] crbug.com/626703 external/wpt/css/css-sizing/image-min-max-content-intrinsic-size-change-006.html [ Failure ] crbug.com/626703 external/wpt/css/css-sizing/image-min-max-content-intrinsic-size-change-004.html [ Failure ] -crbug.com/626703 virtual/threaded/external/wpt/css/css-animations/animationevent-marker-pseudoelement.html [ Timeout ] crbug.com/626703 external/wpt/css/css-sizing/image-min-max-content-intrinsic-size-change-007.html [ Failure ] crbug.com/626703 external/wpt/css/css-lists/counter-set-001.html [ Failure ] crbug.com/626703 external/wpt/css/css-text/text-transform/text-transform-multiple-001.html [ Failure ] @@ -3296,7 +3291,6 @@ crbug.com/626703 external/wpt/css/css-sizing/image-min-max-content-intrinsic-size-change-008.html [ Failure ] crbug.com/626703 external/wpt/css/css-animations/animationevent-marker-pseudoelement.html [ Timeout ] crbug.com/626703 external/wpt/css/css-text/overflow-wrap/overflow-wrap-normal-keep-all-001.html [ Failure ] -crbug.com/626703 [ Mac10.12 ] external/wpt/media-source/mediasource-config-change-webm-a-bitrate.html [ Timeout ] crbug.com/626703 external/wpt/html/semantics/embedded-content/media-elements/src_object_blob.html [ Timeout ] crbug.com/626703 external/wpt/css/css-lists/list-item-definition.html [ Failure ] crbug.com/626703 [ Win7 ] external/wpt/webrtc/RTCPeerConnection-ondatachannel.html [ Failure Timeout ] @@ -4755,9 +4749,6 @@ # Sheriff failures 2017-07-03 crbug.com/708994 http/tests/security/cross-frame-mouse-source-capabilities.html [ Timeout Pass ] - -crbug.com/746128 [ Win7 Debug ] media/controls/video-enter-exit-fullscreen-without-hovering-doesnt-show-controls.html [ Failure ] -crbug.com/746128 [ Win7 Debug ] virtual/audio-service/media/controls/video-enter-exit-fullscreen-without-hovering-doesnt-show-controls.html [ Failure ] crbug.com/746128 [ Mac ] media/controls/video-enter-exit-fullscreen-without-hovering-doesnt-show-controls.html [ Failure Pass ] crbug.com/746128 [ Mac ] virtual/audio-service/media/controls/video-enter-exit-fullscreen-without-hovering-doesnt-show-controls.html [ Failure Pass ] @@ -6022,7 +6013,6 @@ crbug.com/1003055 virtual/threaded/external/wpt/css/css-scroll-snap/scroll-target-snap-002.html [ Failure ] # Sheriff 2019-09-12 -crbug.com/1011515 [ Win7 ] fast/harness/internals-observe-gc.html [ Failure ] crbug.com/731018 [ Mac ] external/wpt/accelerometer/Accelerometer.https.html [ Pass Failure ] crbug.com/731018 [ Mac ] external/wpt/gyroscope/Gyroscope.https.html [ Pass Failure ] crbug.com/731018 [ Mac ] external/wpt/orientation-sensor/AbsoluteOrientationSensor.https.html [ Pass Failure ]
diff --git a/third_party/blink/web_tests/WPTOverrideExpectations b/third_party/blink/web_tests/WPTOverrideExpectations index 969bede..985f340 100644 --- a/third_party/blink/web_tests/WPTOverrideExpectations +++ b/third_party/blink/web_tests/WPTOverrideExpectations
@@ -216,7 +216,6 @@ external/wpt/css/css-animations/CSSAnimation-ready.tentative.html [ Failure Pass ] external/wpt/css/css-animations/CSSPseudoElement-getAnimations.tentative.html [ Failure ] external/wpt/css/css-animations/Element-getAnimations-dynamic-changes.tentative.html [ Failure Pass ] # wpt_subtest_failure -external/wpt/css/css-animations/animationevent-marker-pseudoelement.html [ Timeout ] # wpt_subtest_failure external/wpt/css/css-animations/event-dispatch.tentative.html [ Pass Timeout ] # wpt_subtest_failure external/wpt/css/css-backgrounds/background-size/vector/background-size-vector-024.html [ Pass Failure ] external/wpt/css/css-box/parsing/min-height-invalid.html [ Failure ]
diff --git a/third_party/blink/web_tests/android/ClankWPTOverrideExpectations b/third_party/blink/web_tests/android/ClankWPTOverrideExpectations index 7bbf814a..91136c4e 100644 --- a/third_party/blink/web_tests/android/ClankWPTOverrideExpectations +++ b/third_party/blink/web_tests/android/ClankWPTOverrideExpectations
@@ -475,7 +475,6 @@ crbug.com/1050754 external/wpt/css/css-animations/animation-before-initial-box-construction-001.html [ Failure ] crbug.com/1050754 external/wpt/css/css-animations/AnimationEffect-getComputedTiming.tentative.html [ Failure ] crbug.com/1050754 external/wpt/css/css-animations/AnimationEffect-updateTiming.tentative.html [ Failure ] -crbug.com/1050754 external/wpt/css/css-animations/animationevent-marker-pseudoelement.html [ Timeout ] crbug.com/1050754 external/wpt/css/css-animations/CSSAnimation-animationName.tentative.html [ Failure ] crbug.com/1050754 external/wpt/css/css-animations/CSSAnimation-canceling.tentative.html [ Failure ] crbug.com/1050754 external/wpt/css/css-animations/CSSAnimation-compositeOrder.tentative.html [ Failure ]
diff --git a/third_party/blink/web_tests/android/WeblayerWPTOverrideExpectations b/third_party/blink/web_tests/android/WeblayerWPTOverrideExpectations index f0835e6..f1b1054b 100644 --- a/third_party/blink/web_tests/android/WeblayerWPTOverrideExpectations +++ b/third_party/blink/web_tests/android/WeblayerWPTOverrideExpectations
@@ -371,7 +371,6 @@ crbug.com/1050754 external/wpt/css/compositing/mix-blend-mode/mix-blend-mode-creates-stacking-context.html [ Failure ] crbug.com/1050754 external/wpt/css/compositing/parsing/background-blend-mode-computed.html [ Failure ] crbug.com/1050754 external/wpt/css/css-animations/AnimationEffect-updateTiming.tentative.html [ Failure ] -crbug.com/1050754 external/wpt/css/css-animations/animationevent-marker-pseudoelement.html [ Timeout ] crbug.com/1050754 external/wpt/css/css-animations/CSSAnimation-compositeOrder.tentative.html [ Failure ] crbug.com/1050754 external/wpt/css/css-animations/CSSAnimation-effect.tentative.html [ Timeout ] crbug.com/1050754 external/wpt/css/css-animations/CSSAnimation-ready.tentative.html [ Failure ]
diff --git a/third_party/blink/web_tests/android/WebviewWPTOverrideExpectations b/third_party/blink/web_tests/android/WebviewWPTOverrideExpectations index 925a258..cd196940 100644 --- a/third_party/blink/web_tests/android/WebviewWPTOverrideExpectations +++ b/third_party/blink/web_tests/android/WebviewWPTOverrideExpectations
@@ -507,7 +507,6 @@ external/wpt/css/css-animations/animation-before-initial-box-construction-001.html [ Failure ] external/wpt/css/css-animations/AnimationEffect-getComputedTiming.tentative.html [ Failure ] external/wpt/css/css-animations/AnimationEffect-updateTiming.tentative.html [ Failure ] -external/wpt/css/css-animations/animationevent-marker-pseudoelement.html [ Timeout ] external/wpt/css/css-animations/CSSAnimation-animationName.tentative.html [ Failure ] external/wpt/css/css-animations/CSSAnimation-canceling.tentative.html [ Failure ] external/wpt/css/css-animations/CSSAnimation-compositeOrder.tentative.html [ Failure ]
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_7.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_7.json index 28b7f94..a04bea44 100644 --- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_7.json +++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_7.json
@@ -44637,6 +44637,18 @@ {} ] ], + "css/css-flexbox/cross-axis-scrollbar.html": [ + [ + "css/css-flexbox/cross-axis-scrollbar.html", + [ + [ + "/css/css-flexbox/reference/cross-axis-scrollbar-ref.html", + "==" + ] + ], + {} + ] + ], "css/css-flexbox/css-box-justify-content.html": [ [ "css/css-flexbox/css-box-justify-content.html", @@ -49118,7 +49130,7 @@ "css/css-flexbox/gap-009-ltr.html", [ [ - "/css/css-flexbox/gap-008-ltr-ref.html", + "/css/css-flexbox/gap-009-ltr-ref.html", "==" ] ], @@ -49130,7 +49142,7 @@ "css/css-flexbox/gap-010-ltr.html", [ [ - "/css/css-flexbox/gap-008-ltr-ref.html", + "/css/css-flexbox/gap-010-ltr-ref.html", "==" ] ], @@ -139664,9 +139676,6 @@ "css/css-animations/CSSAnimation-compositeOrder.tentative-expected.txt": [ [] ], - "css/css-animations/CSSAnimation-effect.tentative-expected.txt": [ - [] - ], "css/css-animations/CSSAnimation-ready.tentative-expected.txt": [ [] ], @@ -142163,6 +142172,9 @@ "css/css-flexbox/reference/content-height-with-scrollbars-ref.html": [ [] ], + "css/css-flexbox/reference/cross-axis-scrollbar-ref.html": [ + [] + ], "css/css-flexbox/reference/css-box-justify-content-ref.html": [ [] ], @@ -150602,6 +150614,9 @@ "css/css-pseudo/parsing/marker-supported-properties-expected.txt": [ [] ], + "css/css-pseudo/parsing/marker-supported-properties-in-animation-expected.txt": [ + [] + ], "css/css-pseudo/placeholder-input-number-notref.html": [ [] ], @@ -154862,9 +154877,6 @@ "css/css-transitions/CSSTransition-effect.tentative-expected.txt": [ [] ], - "css/css-transitions/Document-getAnimations.tentative-expected.txt": [ - [] - ], "css/css-transitions/KeyframeEffect-getKeyframes.tentative-expected.txt": [ [] ], @@ -219134,12 +219146,24 @@ {} ] ], + "css/css-flexbox/inline-flex.html": [ + [ + "css/css-flexbox/inline-flex.html", + {} + ] + ], "css/css-flexbox/inline-flexbox-wrap-vertically-width-calculation.html": [ [ "css/css-flexbox/inline-flexbox-wrap-vertically-width-calculation.html", {} ] ], + "css/css-flexbox/intrinsic-min-width-applies-with-fixed-width.html": [ + [ + "css/css-flexbox/intrinsic-min-width-applies-with-fixed-width.html", + {} + ] + ], "css/css-flexbox/order_value.html": [ [ "css/css-flexbox/order_value.html", @@ -224492,6 +224516,12 @@ {} ] ], + "css/css-pseudo/parsing/marker-supported-properties-in-animation.html": [ + [ + "css/css-pseudo/parsing/marker-supported-properties-in-animation.html", + {} + ] + ], "css/css-pseudo/parsing/marker-supported-properties.html": [ [ "css/css-pseudo/parsing/marker-supported-properties.html", @@ -339014,9 +339044,9 @@ {} ] ], - "css/css-flexbox/justify-content_space-between.html": [ + "css/css-flexbox/justify-content_space-between-001.html": [ [ - "css/css-flexbox/justify-content_space-between.html", + "css/css-flexbox/justify-content_space-between-001.html", {} ] ], @@ -373091,10 +373121,6 @@ "d55db9a2d117f54cebd447d9bf5ef9f44ab7309a", "testharness" ], - "css/css-animations/CSSAnimation-effect.tentative-expected.txt": [ - "194b7bce92958bcf4232bed45f87096f2e8a465b", - "support" - ], "css/css-animations/CSSAnimation-effect.tentative.html": [ "fadcaa129ab2c4da612add9951bf99b447fe948d", "testharness" @@ -373132,7 +373158,7 @@ "testharness" ], "css/css-animations/Document-getAnimations.tentative-expected.txt": [ - "5d923ba5cb4d02c2316c0189b520293795e37081", + "5337475efa989cee768211e37c44e5542f33e9ea", "support" ], "css/css-animations/Document-getAnimations.tentative.html": [ @@ -373536,7 +373562,7 @@ "testharness" ], "css/css-animations/event-dispatch.tentative-expected.txt": [ - "0906f8b2f77356ef7eea18dc3b728b8afcfba3b9", + "a4512f67d28b1cdd814fa152b6d8fef4fe153e82", "support" ], "css/css-animations/event-dispatch.tentative.html": [ @@ -373544,7 +373570,7 @@ "testharness" ], "css/css-animations/event-order.tentative-expected.txt": [ - "69df99e5e7f3358362bea8451af5a75dede55d4e", + "a1bc0ba1d25d22cf0cbc8ad41723921843c0ec78", "support" ], "css/css-animations/event-order.tentative.html": [ @@ -381579,6 +381605,10 @@ "5a63322da7dbeb007aaace719cdc652e30338b9c", "reftest" ], + "css/css-flexbox/cross-axis-scrollbar.html": [ + "6bb325175562a231af8177e8d12f0bc35ac187a6", + "reftest" + ], "css/css-flexbox/css-box-justify-content.html": [ "d5c7244f08dcad0b0955290804ec5959754a963d", "reftest" @@ -383964,7 +383994,7 @@ "support" ], "css/css-flexbox/gap-009-ltr.html": [ - "43a4cefc72e80fc594793cfc115f1f7bc8bbb2e8", + "462b5b69c66a8f28c7c066152f1a24954a485f80", "reftest" ], "css/css-flexbox/gap-010-ltr-ref.html": [ @@ -383972,7 +384002,7 @@ "support" ], "css/css-flexbox/gap-010-ltr.html": [ - "f57a167e16df0e55f1edc6625d9550e9e8e326fd", + "85dba78db5a90ec124f2179adedf2e7f357fa5fd", "reftest" ], "css/css-flexbox/getcomputedstyle/flexbox_computedstyle_align-content-center.html": [ @@ -384299,6 +384329,10 @@ "b84b9afc0b67b83d3d3e2abb73c9b7e22aeb3cbe", "reftest" ], + "css/css-flexbox/inline-flex.html": [ + "1f21ae35a898b0fee9bda8fd1c14cbc4c2c205ef", + "testharness" + ], "css/css-flexbox/inline-flexbox-wrap-vertically-width-calculation.html": [ "e9010cf96cff8d131e0319168d7570285331dd2a", "testharness" @@ -384383,6 +384417,10 @@ "684233223b82c7105a9550e4957597acc0153e75", "manual" ], + "css/css-flexbox/intrinsic-min-width-applies-with-fixed-width.html": [ + "080169b52d7fdf39cbf6ff970c3100480e46d2a3", + "testharness" + ], "css/css-flexbox/item-with-max-height-and-scrollbar.html": [ "167417a2563eaf54650f8347584e7e5b53d13903", "reftest" @@ -384427,7 +384465,7 @@ "c0dba54e50c09f66ea90aae7778f7b201de8d5d8", "visual" ], - "css/css-flexbox/justify-content_space-between.html": [ + "css/css-flexbox/justify-content_space-between-001.html": [ "7abfd4a6c3c3e9d80b2cea059ac7e2a5463523fe", "visual" ], @@ -384727,6 +384765,10 @@ "8a1484f6934dc3e30aae299380c82308cd1fec42", "support" ], + "css/css-flexbox/reference/cross-axis-scrollbar-ref.html": [ + "f0a3225502e3da036ab28d89fb03c0441b6c3862", + "support" + ], "css/css-flexbox/reference/css-box-justify-content-ref.html": [ "e8377473fdef6f93bdf0e1e0e78fd33f01c93e82", "support" @@ -405868,11 +405910,19 @@ "reftest" ], "css/css-pseudo/parsing/marker-supported-properties-expected.txt": [ - "ae332b152bd19f6a05a2b972a74f762c6cf5f337", + "79c4baa4684c3468a52cc0659ea82b2dbcf8d525", "support" ], + "css/css-pseudo/parsing/marker-supported-properties-in-animation-expected.txt": [ + "ccc3ee3b5cda07fae2766ab7f7bd233f784b4f04", + "support" + ], + "css/css-pseudo/parsing/marker-supported-properties-in-animation.html": [ + "faf7c904fb04460ad08cc7b8a0e9d3504bbfe158", + "testharness" + ], "css/css-pseudo/parsing/marker-supported-properties.html": [ - "7f8eacbc2ce4874392f1e1651ae2f60894563215", + "e27decc133424ba01b96ff7960ecbe62d5033077", "testharness" ], "css/css-pseudo/parsing/tree-abiding-pseudo-elements.html": [ @@ -423715,10 +423765,6 @@ "8eb284107d350fb2a5da1b176aa213f807cd212f", "testharness" ], - "css/css-transitions/Document-getAnimations.tentative-expected.txt": [ - "50c89edbdd431cb895687f9c77f5e0e4fd0f907e", - "support" - ], "css/css-transitions/Document-getAnimations.tentative.html": [ "cd97acfd5ec76c7585d5356c86b3832bb0b7bd37", "testharness" @@ -524756,7 +524802,7 @@ "wdspec" ], "webdriver/tests/perform_actions/pointer.py": [ - "49468a73aed9e6e1da341e47c16968b0d204fa43", + "a752203587bed5ebcfa50599f0548feb69ca4c98", "wdspec" ], "webdriver/tests/perform_actions/pointer_contextmenu.py": [ @@ -524800,7 +524846,7 @@ "support" ], "webdriver/tests/perform_actions/support/test_actions_wdspec.html": [ - "6f844cd255a075d31caf1c19957af3d6ac833778", + "39a8876e54ad183b900acbb552a5930b5b4b83fd", "support" ], "webdriver/tests/perform_actions/user_prompts.py": [
diff --git a/third_party/blink/web_tests/external/wpt/css/css-animations/Document-getAnimations.tentative-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-animations/Document-getAnimations.tentative-expected.txt index 5d923ba5..5337475 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-animations/Document-getAnimations.tentative-expected.txt +++ b/third_party/blink/web_tests/external/wpt/css/css-animations/Document-getAnimations.tentative-expected.txt
@@ -14,6 +14,6 @@ PASS CSS Animations canceled via the API are not returned PASS CSS Animations canceled and restarted via the API are returned PASS CSS Animations targetting (pseudo-)elements should have correct order after sorting -FAIL CSS Animations targetting (pseudo-)elements should have correct order after sorting (::marker) assert_equals: CSS animations on both pseudo-elements and elements are returned expected 5 but got 4 +PASS CSS Animations targetting (pseudo-)elements should have correct order after sorting (::marker) Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/css/css-animations/event-order.tentative-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-animations/event-order.tentative-expected.txt index 69df99e..a1bc0ba 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-animations/event-order.tentative-expected.txt +++ b/third_party/blink/web_tests/external/wpt/css/css-animations/event-order.tentative-expected.txt
@@ -1,7 +1,7 @@ This is a testharness.js-based test. PASS Same events are ordered by elements PASS Same events on pseudo-elements follow the prescribed order -FAIL Same events on pseudo-elements follow the prescribed order (::marker) assert_equals: Number of events received (4) should match expected number (5) (expected: animationstart, animationstart, animationstart, animationstart, animationstart, actual: animationstart, animationstart, animationstart, animationstart) expected 5 but got 4 +PASS Same events on pseudo-elements follow the prescribed order (::marker) FAIL Start and iteration events are ordered by time assert_equals: Event #1 types should match (expected: animationiteration, animationstart, actual: animationstart, animationiteration) expected "animationiteration" but got "animationstart" FAIL Iteration and end events are ordered by time assert_equals: Event #1 types should match (expected: animationiteration, animationend, actual: animationend, animationiteration) expected "animationiteration" but got "animationend" FAIL Start and end events are sorted correctly when fired simultaneously assert_equals: Event #1 targets should match expected Element node <div style="animation: anim 100s 2"></div> but got Element node <div style="animation: anim 100s 100s"></div>
diff --git a/third_party/blink/web_tests/css3/flexbox/inline-flex.html b/third_party/blink/web_tests/external/wpt/css/css-flexbox/inline-flex.html similarity index 62% rename from third_party/blink/web_tests/css3/flexbox/inline-flex.html rename to third_party/blink/web_tests/external/wpt/css/css-flexbox/inline-flex.html index 23f6f50..1f21ae3 100644 --- a/third_party/blink/web_tests/css3/flexbox/inline-flex.html +++ b/third_party/blink/web_tests/external/wpt/css/css-flexbox/inline-flex.html
@@ -1,5 +1,9 @@ <!DOCTYPE html> <html> +<title>CSS Flexbox: Ensure proper formatting with display: inline-flex</title> +<link rel="help" href="https://www.w3.org/TR/css-flexbox-1/#flex-containers"> +<link rel="help" href="https://www.w3.org/TR/css-flexbox-1/#flex-property"> +<meta name="assert" content="This test checks that inline-flex generates a flex container box that is inline-level when placed in flow layout."> <style> #testcase > div { height: 50px; @@ -11,9 +15,9 @@ flex: 1; } </style> -<script src="../../resources/testharness.js"></script> -<script src="../../resources/testharnessreport.js"></script> -<script src="../../resources/check-layout-th.js"></script> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/check-layout-th.js"></script> <body onload="checkLayout('#testcase')"> <div id=log></div> <p>This test passes if the three green boxes are on the same horizontal line.</p>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-pseudo/first-letter-text-and-display-change.html b/third_party/blink/web_tests/external/wpt/css/css-pseudo/first-letter-text-and-display-change.html new file mode 100644 index 0000000..d50da5f --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-pseudo/first-letter-text-and-display-change.html
@@ -0,0 +1,18 @@ +<!doctype html> +<title>CSS Test: Change display for the ::first-letter container while replacing text node</title> +<link rel="help" href="https://drafts.csswg.org/css-pseudo/#first-letter-pseudo"> +<link rel="match" href="../reference/pass_if_letter_uppercase.html"> +<style> + #container::first-letter { text-transform: uppercase } + #container.ib { display: inline-block } +</style> +<body> + <p>Test passes if the letter "F" in the words "Filler Text" below is in upper-case.</p> + <div id="container">Test not run</div> +</body> +<script> + container.offsetTop; + container.className = "ib"; + container.appendChild(document.createTextNode("filler Text")); + container.firstChild.remove(); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-pseudo/parsing/marker-supported-properties-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-pseudo/parsing/marker-supported-properties-expected.txt index ae332b1..79c4baa4 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-pseudo/parsing/marker-supported-properties-expected.txt +++ b/third_party/blink/web_tests/external/wpt/css/css-pseudo/parsing/marker-supported-properties-expected.txt
@@ -21,6 +21,20 @@ PASS Property unicode-bidi value 'plaintext' in ::marker PASS Property direction value 'rtl' in ::marker PASS Property content value '"foo"' in ::marker +PASS Property animation value '1s linear 2s infinite alternate forwards paused anim' in ::marker +PASS Property animation-delay value '1s' in ::marker +PASS Property animation-direction value 'alternate' in ::marker +PASS Property animation-duration value '2s' in ::marker +PASS Property animation-fill-mode value 'forwards' in ::marker +PASS Property animation-iteration-count value 'infinite' in ::marker +PASS Property animation-name value 'anim' in ::marker +PASS Property animation-play-state value 'paused' in ::marker +PASS Property animation-timing-function value 'linear' in ::marker +PASS Property transition value 'display 1s linear 2s' in ::marker +PASS Property transition-delay value '1s' in ::marker +PASS Property transition-duration value '2s' in ::marker +PASS Property transition-property value 'display' in ::marker +PASS Property transition-timing-function value 'linear' in ::marker PASS Property display value 'none' in ::marker PASS Property position value 'absolute' in ::marker PASS Property float value 'right' in ::marker
diff --git a/third_party/blink/web_tests/external/wpt/css/css-pseudo/parsing/marker-supported-properties-in-animation-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-pseudo/parsing/marker-supported-properties-in-animation-expected.txt new file mode 100644 index 0000000..ccc3ee3 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-pseudo/parsing/marker-supported-properties-in-animation-expected.txt
@@ -0,0 +1,64 @@ +This is a testharness.js-based test. +Found 60 tests; 49 PASS, 11 FAIL, 0 TIMEOUT, 0 NOTRUN. +FAIL Animation of font in ::marker assert_in_array: value "italic small-caps 500 ultra-expanded 15px Ahem" not in array ["italic small-caps 500 expanded 15px Ahem", "italic small-caps 500 expanded 15px/normal Ahem"] +PASS Animation of font-family in ::marker +PASS Animation of font-feature-settings in ::marker +PASS Animation of font-kerning in ::marker +PASS Animation of font-size in ::marker +PASS Animation of font-size-adjust in ::marker +FAIL Animation of font-stretch in ::marker assert_in_array: value "200%" not in array ["expanded", "125%"] +PASS Animation of font-style in ::marker +FAIL Animation of font-synthesis in ::marker assert_true: font-synthesis doesn't seem to be supported in the computed style expected true got false +PASS Animation of font-variant in ::marker +PASS Animation of font-variant-caps in ::marker +PASS Animation of font-variant-east-asian in ::marker +PASS Animation of font-variant-ligatures in ::marker +PASS Animation of font-variant-numeric in ::marker +FAIL Animation of font-variant-position in ::marker assert_true: font-variant-position doesn't seem to be supported in the computed style expected true got false +PASS Animation of font-weight in ::marker +FAIL Animation of white-space in ::marker assert_equals: expected "nowrap" but got "pre" +PASS Animation of color in ::marker +FAIL Animation of text-combine-upright in ::marker assert_equals: expected "none" but got "all" +PASS Animation of unicode-bidi in ::marker +PASS Animation of direction in ::marker +PASS Animation of content in ::marker +PASS Animation of display in ::marker +PASS Animation of position in ::marker +PASS Animation of float in ::marker +PASS Animation of list-style in ::marker +PASS Animation of list-style-image in ::marker +PASS Animation of list-style-position in ::marker +PASS Animation of list-style-type in ::marker +PASS Animation of line-height in ::marker +FAIL Transition of font in ::marker assert_in_array: value "italic small-caps 500 ultra-expanded 15px Ahem" not in array ["italic small-caps 500 expanded 15px Ahem", "italic small-caps 500 expanded 15px/normal Ahem"] +PASS Transition of font-family in ::marker +PASS Transition of font-feature-settings in ::marker +PASS Transition of font-kerning in ::marker +PASS Transition of font-size in ::marker +PASS Transition of font-size-adjust in ::marker +FAIL Transition of font-stretch in ::marker assert_in_array: value "200%" not in array ["expanded", "125%"] +PASS Transition of font-style in ::marker +FAIL Transition of font-synthesis in ::marker assert_true: font-synthesis doesn't seem to be supported in the computed style expected true got false +PASS Transition of font-variant in ::marker +PASS Transition of font-variant-caps in ::marker +PASS Transition of font-variant-east-asian in ::marker +PASS Transition of font-variant-ligatures in ::marker +PASS Transition of font-variant-numeric in ::marker +FAIL Transition of font-variant-position in ::marker assert_true: font-variant-position doesn't seem to be supported in the computed style expected true got false +PASS Transition of font-weight in ::marker +FAIL Transition of white-space in ::marker assert_equals: expected "nowrap" but got "pre" +PASS Transition of color in ::marker +PASS Transition of text-combine-upright in ::marker +PASS Transition of unicode-bidi in ::marker +PASS Transition of direction in ::marker +PASS Transition of content in ::marker +PASS Transition of display in ::marker +PASS Transition of position in ::marker +PASS Transition of float in ::marker +PASS Transition of list-style in ::marker +PASS Transition of list-style-image in ::marker +PASS Transition of list-style-position in ::marker +PASS Transition of list-style-type in ::marker +PASS Transition of line-height in ::marker +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/css/css-pseudo/parsing/marker-supported-properties-in-animation.html b/third_party/blink/web_tests/external/wpt/css/css-pseudo/parsing/marker-supported-properties-in-animation.html new file mode 100644 index 0000000..faf7c90 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-pseudo/parsing/marker-supported-properties-in-animation.html
@@ -0,0 +1,292 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>CSS Pseudo-Elements Test: Supported properties in ::marker animations</title> +<link rel="help" href="https://drafts.csswg.org/css-pseudo-4/#marker-pseudo"> +<link rel="help" href="https://drafts.csswg.org/css-animations-1/#keyframes"> +<link rel="help" href="https://drafts.csswg.org/css-transitions-1/#transitions"> +<link rel="author" title="Oriol Brufau" href="mailto:obrufau@igalia.com"> +<meta name="assert" content="This test checks ::marker supports animations and transitions, but only for the properties that apply to ::marker." /> +<style id="style"></style> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<ul> + <li id="target">target</li> +</ul> +<script> +const interpolationTests = [ + // ::marker supports all font properties. + { + property: "font", + from: "oblique normal 100 ultra-condensed 5px / 20px serif", + to: "italic small-caps 900 ultra-expanded 25px / 50px Ahem", + midPoint: ["italic small-caps 500 expanded 15px Ahem", "italic small-caps 500 expanded 15px/normal Ahem"], + }, + { + property: "font-family", + from: "serif", + to: "Ahem", + midPoint: "Ahem", + }, + { + property: "font-feature-settings", + from: "'c2sc'", + to: "'smcp'", + midPoint: "\"smcp\"", + }, + { + property: "font-kerning", + from: "normal", + to: "none", + midPoint: "none", + }, + { + property: "font-size", + from: "5px", + to: "25px", + midPoint: "15px", + }, + { + property: "font-size-adjust", + from: "1", + to: "3", + midPoint: "2", + }, + { + property: "font-stretch", + from: "ultra-condensed", + to: "ultra-expanded", + midPoint: ["expanded", "125%"], + }, + { + property: "font-style", + from: "oblique", + to: "italic", + midPoint: "italic", + }, + { + property: "font-synthesis", + from: "weight", + to: "none", + midPoint: "none", + }, + { + property: "font-variant", + from: "unicase", + to: "small-caps", + midPoint: "small-caps", + }, + { + property: "font-variant-caps", + from: "unicase", + to: "small-caps", + midPoint: "small-caps", + }, + { + property: "font-variant-east-asian", + from: "proportional-width", + to: "full-width", + midPoint: "full-width", + }, + { + property: "font-variant-ligatures", + from: "no-historical-ligatures", + to: "historical-ligatures", + midPoint: "historical-ligatures", + }, + { + property: "font-variant-numeric", + from: "ordinal", + to: "slashed-zero", + midPoint: "slashed-zero", + }, + { + property: "font-variant-position", + from: "super", + to: "sub", + midPoint: "sub", + }, + { + property: "font-weight", + from: "100", + to: "900", + midPoint: "500", + }, + + // ::marker supports `white-space` + { + property: "white-space", + from: "pre-line", + to: "nowrap", + midPoint: "nowrap", + }, + + // ::marker supports `color` + { + property: "color", + from: "rgb(0, 100, 200)", + to: "rgb(100, 200, 0)", + midPoint: "rgb(50, 150, 100)", + }, + + // ::marker supports `text-combine-upright`, `unicode-bidi` and `direction`, + // but they are not animatable. + { + property: "text-combine-upright", + from: "all", + to: "all", + midPoint: null, + }, + { + property: "unicode-bidi", + from: "embed", + to: "plaintext", + midPoint: null, + }, + { + property: "direction", + from: "rtl", + to: "rtl", + midPoint: null, + }, + + // ::marker supports `content` + { + property: "content", + from: "'foo'", + to: "'bar'", + midPoint: "\"bar\"", + }, + + // ::marker does NOT support layout properties + { + property: "display", + from: "flex", + to: "none", + midPoint: ["block", "inline", "inline-block"], + }, + { + property: "position", + from: "fixed", + to: "absolute", + midPoint: "static", + }, + { + property: "float", + from: "left", + to: "right", + midPoint: "none", + }, + + // ::marker does NOT support list properties despite being affected by them, + // they apply to the list item instead. + { + property: "list-style", + from: "inside url('foo') square", + to: "inside url('bar') decimal", + midPoint: "outside none disc", + }, + { + property: "list-style-image", + from: "url('foo')", + to: "url('bar')", + midPoint: "none", + }, + { + property: "list-style-position", + from: "inside", + to: "inside", + midPoint: "outside", + }, + { + property: "list-style-type", + from: "square", + to: "decimal", + midPoint: "disc", + }, + + // ::marker does NOT support `line-height` because, despite being a + // longhand of `font`, it's not a font property. + { + property: "line-height", + from: "20px", + to: "50px", + midPoint: "normal", + }, +]; + +const target = document.getElementById("target"); +const styleElement = document.getElementById("style"); +const markerStyle = getComputedStyle(target, "::marker"); + +function check({property, from, to, midPoint}) { + assert_true(property in markerStyle, property + " doesn't seem to be supported in the computed style"); + assert_true(CSS.supports(property, from), `'${from}' is a supported value for ${property}.`); + assert_true(CSS.supports(property, to), `'${to}' is a supported value for ${property}.`); + const computed = markerStyle.getPropertyValue(property); + if (Array.isArray(midPoint)) { + assert_in_array(computed, midPoint); + } else { + assert_equals(computed, midPoint); + } +} + +function testAnimations(interpolationTests) { + styleElement.textContent = ` + ::marker { + animation: anim 2s -1s paused linear; + } + @keyframes anim { + from {} + to {} + } + `; + const keyframes = styleElement.sheet.cssRules[1]; + const fromStyle = keyframes.cssRules[0].style; + const toStyle = keyframes.cssRules[1].style; + for (let {property, from, to, midPoint} of interpolationTests) { + fromStyle.cssText = ""; + toStyle.cssText = ""; + if (midPoint == null) { + midPoint = markerStyle.getPropertyValue(property); + } + fromStyle.setProperty(property, from); + toStyle.setProperty(property, to); + test(() => { + check({property, from, to, midPoint}); + }, `Animation of ${property} in ::marker`); + } +} + +function testTransitions(interpolationTests) { + styleElement.textContent = ` + .transition::marker { + transition: all 2s -1s linear; + } + .from::marker {} + .to::marker {} + `; + const fromStyle = styleElement.sheet.cssRules[1].style; + const toStyle = styleElement.sheet.cssRules[2].style; + for (let {property, from, to, midPoint} of interpolationTests) { + fromStyle.cssText = ""; + toStyle.cssText = ""; + if (midPoint == null) { + midPoint = to; + } + fromStyle.setProperty(property, from); + toStyle.setProperty(property, to); + target.className = "from"; + markerStyle.width; + target.classList.add("transition"); + markerStyle.width; + target.classList.add("to"); + test(() => { + check({property, from, to, midPoint}); + }, `Transition of ${property} in ::marker`); + } +} + +testAnimations(interpolationTests); +testTransitions(interpolationTests); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-pseudo/parsing/marker-supported-properties.html b/third_party/blink/web_tests/external/wpt/css/css-pseudo/parsing/marker-supported-properties.html index 7f8eacb..e27decc 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-pseudo/parsing/marker-supported-properties.html +++ b/third_party/blink/web_tests/external/wpt/css/css-pseudo/parsing/marker-supported-properties.html
@@ -45,6 +45,24 @@ // ::marker supports `content` test_pseudo_computed_value("::marker", "content", "\"foo\""); +// ::marker supports animation properties. +test_pseudo_computed_value("::marker", "animation", "1s linear 2s infinite alternate forwards paused anim"); +test_pseudo_computed_value("::marker", "animation-delay", "1s"); +test_pseudo_computed_value("::marker", "animation-direction", "alternate"); +test_pseudo_computed_value("::marker", "animation-duration", "2s"); +test_pseudo_computed_value("::marker", "animation-fill-mode", "forwards"); +test_pseudo_computed_value("::marker", "animation-iteration-count", "infinite"); +test_pseudo_computed_value("::marker", "animation-name", "anim"); +test_pseudo_computed_value("::marker", "animation-play-state", "paused"); +test_pseudo_computed_value("::marker", "animation-timing-function", "linear"); + +// ::marker supports transition properties. +test_pseudo_computed_value("::marker", "transition", "display 1s linear 2s"); +test_pseudo_computed_value("::marker", "transition-delay", "1s"); +test_pseudo_computed_value("::marker", "transition-duration", "2s"); +test_pseudo_computed_value("::marker", "transition-property", "display"); +test_pseudo_computed_value("::marker", "transition-timing-function", "linear"); + // ::marker does NOT support layout properties test_pseudo_computed_value("::marker", "display", "none", ["block", "inline", "inline-block"]); test_pseudo_computed_value("::marker", "position", "absolute", "static");
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transitions/Document-getAnimations.tentative-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-transitions/Document-getAnimations.tentative-expected.txt deleted file mode 100644 index 50c89ed..0000000 --- a/third_party/blink/web_tests/external/wpt/css/css-transitions/Document-getAnimations.tentative-expected.txt +++ /dev/null
@@ -1,8 +0,0 @@ -This is a testharness.js-based test. -PASS getAnimations for non-animated content -PASS getAnimations for CSS Transitions -PASS CSS Transitions targetting (pseudo-)elements should have correct order after sorting -FAIL CSS Transitions targetting (pseudo-)elements should have correct order after sorting (::marker) assert_equals: CSS transition on both pseudo-elements and elements are returned expected 5 but got 4 -PASS Transitions are not returned after they have finished -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/perform_actions/pointer.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/perform_actions/pointer.py index 49468a73..a752203 100644 --- a/third_party/blink/web_tests/external/wpt/webdriver/tests/perform_actions/pointer.py +++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/perform_actions/pointer.py
@@ -141,3 +141,34 @@ final_rect = drag_target.rect assert initial_rect["x"] + dx == final_rect["x"] assert initial_rect["y"] + dy == final_rect["y"] + + +@pytest.mark.parametrize("drag_duration", [0, 300, 800]) +def test_drag_and_drop_with_draggable_element(session, + test_actions_page, + mouse_chain, + drag_duration): + drag_target = session.find.css("#draggable", all=False) + drop_target = session.find.css("#droppable", all=False) + # Conclude chain with extra move to allow time for last queued + # coordinate-update of drag_target and to test that drag_target is "dropped". + mouse_chain \ + .pointer_move(0, 0, origin=drag_target) \ + .pointer_down() \ + .pointer_move(50, + 25, + duration=drag_duration, + origin=drop_target) \ + .pointer_up() \ + .pointer_move(80, 50, duration=100, origin="pointer") \ + .perform() + # mouseup that ends the drag is at the expected destination + e = get_events(session) + assert e[1]["type"] == "dragstart", "Events captured were {}".format(e) + assert e[2]["type"] == "dragover", "Events captured were {}".format(e) + drag_events_captured = [ev["type"] for ev in e if ev["type"].startswith("drag") or ev["type"].startswith("drop")] + assert "dragend" in drag_events_captured + assert "dragenter" in drag_events_captured + assert "dragexit" in drag_events_captured + assert "dragleave" in drag_events_captured + assert "drop" in drag_events_captured \ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/perform_actions/support/test_actions_wdspec.html b/third_party/blink/web_tests/external/wpt/webdriver/tests/perform_actions/support/test_actions_wdspec.html index 6f844cd..39a8876 100644 --- a/third_party/blink/web_tests/external/wpt/webdriver/tests/perform_actions/support/test_actions_wdspec.html +++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/perform_actions/support/test_actions_wdspec.html
@@ -9,6 +9,7 @@ #resultContainer { width: 600px; height: 60px; } .area { width: 100px; height: 50px; background-color: #ccc; } .block { width: 5px; height: 5px; border: solid 1px red; } + .box { display: flex;} #dragArea { position: relative; } #dragTarget { position: absolute; top:22px; left:47px;} </style> @@ -167,8 +168,20 @@ window.addEventListener("mousemove", move(pointer, 15, 15, 30)); // drag and drop els.dragArea = document.getElementById("dragArea"); + els.dragArea.addEventListener("dragstart", recordPointerEvent); els.dragTarget = document.getElementById("dragTarget"); els.dragTarget.addEventListener("mousedown", grabOnce); + + var draggable = document.getElementById("draggable"); + draggable.addEventListener("dragstart", recordPointerEvent); + draggable.addEventListener("dragenter", recordPointerEvent); + draggable.addEventListener("dragend", recordPointerEvent); + draggable.addEventListener("dragleave", recordPointerEvent); + draggable.addEventListener("dragover", recordPointerEvent); + draggable.addEventListener("dragexit", recordPointerEvent); + + var droppable = document.getElementById("droppable"); + droppable.addEventListener("drop", recordPointerEvent); }); </script> </head> @@ -189,6 +202,13 @@ <div id="dragTarget" class="block"></div> </div> </div> + <div> + <h2>draggable</h2> + <div class=box> + <div id=draggable draggable="true" class="area"></div> + <div id=droppable dropzone="true" class="area"></div> + </div> + </div> <div id="resultContainer"> <h2>Events</h2> <div id="events"></div>
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/compositing/overflow/scroll-parent-with-non-stacking-context-composited-ancestor-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/compositing/overflow/scroll-parent-with-non-stacking-context-composited-ancestor-expected.txt index 2342f3a..17f8b82 100644 --- a/third_party/blink/web_tests/flag-specific/composite-after-paint/compositing/overflow/scroll-parent-with-non-stacking-context-composited-ancestor-expected.txt +++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/compositing/overflow/scroll-parent-with-non-stacking-context-composited-ancestor-expected.txt
@@ -8,11 +8,11 @@ }, { "name": "LayoutNGBlockFlow DIV id='intervening'", - "position": [98, 90], "bounds": [300, 300], "contentsOpaque": true, "backfaceVisibility": "hidden", - "backgroundColor": "#FFEFD5" + "backgroundColor": "#FFEFD5", + "transform": 1 }, { "name": "LayoutNGBlockFlow DIV id='scroller'",
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/background/background-resize-height-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/background/background-resize-height-expected.txt index 44c7e3d3..2ed0523 100644 --- a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/background/background-resize-height-expected.txt +++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/background/background-resize-height-expected.txt
@@ -53,12 +53,12 @@ }, { "name": "LayoutNGBlockFlow (positioned) DIV class='test image repeat-round'", - "position": [508, 8], "bounds": [60, 44], "backfaceVisibility": "hidden", "invalidations": [ [0, 0, 60, 44] - ] + ], + "transform": 1 }, { "name": "LayoutNGBlockFlow (positioned) DIV class='test generated'", @@ -108,6 +108,17 @@ [0, 0, 60, 44] ] } + ], + "transforms": [ + { + "id": 1, + "transform": [ + [1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, 1, 0], + [508, 8, 0, 1] + ] + } ] }
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/compositing/fixed-scroll-in-empty-root-layer-expected.png b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/compositing/fixed-scroll-in-empty-root-layer-expected.png deleted file mode 100644 index 355f16ad..0000000 --- a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/compositing/fixed-scroll-in-empty-root-layer-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/compositing/fixed-scroll-in-empty-root-layer-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/compositing/fixed-scroll-in-empty-root-layer-expected.txt index 4e21c7e..1be6e4b3 100644 --- a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/compositing/fixed-scroll-in-empty-root-layer-expected.txt +++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/compositing/fixed-scroll-in-empty-root-layer-expected.txt
@@ -14,12 +14,11 @@ }, { "name": "LayoutNGBlockFlow (positioned) DIV", - "position": [0, 250], "bounds": [100, 100], "contentsOpaque": true, "backfaceVisibility": "hidden", "backgroundColor": "#FF0000", - "transform": 1 + "transform": 2 }, { "name": "LayoutNGBlockFlow HTML", @@ -31,7 +30,7 @@ "name": "LayoutNGBlockFlow (positioned) DIV", "bounds": [100, 100], "backgroundColor": "#008000", - "transform": 2 + "transform": 3 } ], "transforms": [ @@ -46,6 +45,16 @@ }, { "id": 2, + "parent": 1, + "transform": [ + [1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, 1, 0], + [0, 250, 0, 1] + ] + }, + { + "id": 3, "transform": [ [1, 0, 0, 0], [0, 1, 0, 0],
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/compositing/scrolling-neg-z-index-descendants-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/compositing/scrolling-neg-z-index-descendants-expected.txt new file mode 100644 index 0000000..c05afda4 --- /dev/null +++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/compositing/scrolling-neg-z-index-descendants-expected.txt
@@ -0,0 +1,60 @@ +{ + "layers": [ + { + "name": "Scrolling background of LayoutView #document", + "bounds": [800, 600], + "contentsOpaque": true, + "backgroundColor": "#FFFFFF" + }, + { + "name": "LayoutNGBlockFlow (relative positioned) DIV id='neg-z'", + "position": [1, 11], + "bounds": [100, 410], + "backfaceVisibility": "hidden", + "backgroundColor": "#008000", + "transform": 2 + }, + { + "name": "LayoutNGBlockFlow HTML", + "position": [8, 8], + "bounds": [784, 302], + "drawsContent": false + }, + { + "name": "LayoutNGBlockFlow (relative positioned) DIV id='container'", + "bounds": [102, 302], + "backfaceVisibility": "hidden", + "transform": 1 + }, + { + "name": "LayoutNGBlockFlow (relative positioned) DIV id='container'", + "position": [1, 1], + "bounds": [100, 300], + "drawsContent": false, + "backfaceVisibility": "hidden", + "transform": 1 + } + ], + "transforms": [ + { + "id": 1, + "transform": [ + [1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, 1, 0], + [8, 8, 0, 1] + ] + }, + { + "id": 2, + "parent": 1, + "transform": [ + [1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, 1, 0], + [0, -100, 0, 1] + ] + } + ] +} +
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/compositing/should-not-repaint-composited-descendants-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/compositing/should-not-repaint-composited-descendants-expected.txt new file mode 100644 index 0000000..b7df2895 --- /dev/null +++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/compositing/should-not-repaint-composited-descendants-expected.txt
@@ -0,0 +1,50 @@ +{ + "layers": [ + { + "name": "Scrolling background of LayoutView #document", + "bounds": [800, 600], + "contentsOpaque": true, + "backgroundColor": "#FFFFFF" + }, + { + "name": "LayoutNGBlockFlow (positioned) DIV id='composited-box'", + "position": [30, 30], + "bounds": [20, 70], + "contentsOpaque": true, + "backgroundColor": "#008000", + "invalidations": [ + [0, 0, 20, 70] + ], + "transform": 1 + }, + { + "name": "LayoutNGBlockFlow DIV class='composited child'", + "bounds": [50, 50], + "contentsOpaque": true, + "backgroundColor": "#008000", + "transform": 2 + } + ], + "transforms": [ + { + "id": 1, + "transform": [ + [1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, 1, 0], + [8, 8, 0, 1] + ] + }, + { + "id": 2, + "parent": 1, + "transform": [ + [1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, 1, 0], + [0, 50, 0, 1] + ] + } + ] +} +
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/compositing/should-not-repaint-composited-z-index-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/compositing/should-not-repaint-composited-z-index-expected.txt index 9da69a76..1f91c5a 100644 --- a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/compositing/should-not-repaint-composited-z-index-expected.txt +++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/compositing/should-not-repaint-composited-z-index-expected.txt
@@ -8,11 +8,22 @@ }, { "name": "LayoutNGBlockFlow DIV id='composited-box'", - "position": [8, 8], "bounds": [100, 100], "contentsOpaque": true, "backfaceVisibility": "hidden", - "backgroundColor": "#008000" + "backgroundColor": "#008000", + "transform": 1 + } + ], + "transforms": [ + { + "id": 1, + "transform": [ + [1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, 1, 0], + [8, 8, 0, 1] + ] } ] }
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/compositing/should-not-repaint-move-backface-hidden-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/compositing/should-not-repaint-move-backface-hidden-expected.txt new file mode 100644 index 0000000..2781d1de --- /dev/null +++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/compositing/should-not-repaint-move-backface-hidden-expected.txt
@@ -0,0 +1,30 @@ +{ + "layers": [ + { + "name": "Scrolling background of LayoutView #document", + "bounds": [800, 600], + "contentsOpaque": true, + "backgroundColor": "#FFFFFF" + }, + { + "name": "LayoutNGBlockFlow (positioned) DIV id='target'", + "bounds": [100, 100], + "contentsOpaque": true, + "backfaceVisibility": "hidden", + "backgroundColor": "#008000", + "transform": 1 + } + ], + "transforms": [ + { + "id": 1, + "transform": [ + [1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, 1, 0], + [100, 200, 0, 1] + ] + } + ] +} +
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/multicol/multicol-as-paint-container-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/multicol/multicol-as-paint-container-expected.txt index f3f1125..df27eb02 100644 --- a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/multicol/multicol-as-paint-container-expected.txt +++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/multicol/multicol-as-paint-container-expected.txt
@@ -8,12 +8,24 @@ }, { "name": "LayoutBlockFlow DIV id='target'", - "position": [8, -172], + "position": [0, -180], "bounds": [630, 520], "backfaceVisibility": "hidden", "invalidations": [ [0, 0, 625, 360], [0, 180, 625, 340] + ], + "transform": 1 + } + ], + "transforms": [ + { + "id": 1, + "transform": [ + [1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, 1, 0], + [8, 8, 0, 1] ] } ]
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/position/relative-positioned-movement-repaint-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/position/relative-positioned-movement-repaint-expected.txt new file mode 100644 index 0000000..00f92ad --- /dev/null +++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/position/relative-positioned-movement-repaint-expected.txt
@@ -0,0 +1,28 @@ +{ + "layers": [ + { + "name": "Scrolling background of LayoutView #document", + "bounds": [800, 600], + "contentsOpaque": true, + "backgroundColor": "#FFFFFF" + }, + { + "name": "LayoutNGBlockFlow (relative positioned) DIV id='block'", + "bounds": [402, 62], + "backfaceVisibility": "hidden", + "transform": 1 + } + ], + "transforms": [ + { + "id": 1, + "transform": [ + [1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, 1, 0], + [68, 10, 0, 1] + ] + } + ] +} +
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/scroll/fixed-under-composited-absolute-scrolled-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/scroll/fixed-under-composited-absolute-scrolled-expected.txt index d2a6a3a..7241421 100644 --- a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/scroll/fixed-under-composited-absolute-scrolled-expected.txt +++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/scroll/fixed-under-composited-absolute-scrolled-expected.txt
@@ -14,12 +14,11 @@ }, { "name": "LayoutNGBlockFlow (positioned) DIV id='absolute'", - "position": [8, 2000], "bounds": [1, 1], "contentsOpaque": true, "backfaceVisibility": "hidden", "backgroundColor": "#FF0000", - "transform": 1 + "transform": 2 }, { "name": "LayoutNGBlockFlow (positioned) DIV id='fixed'", @@ -39,6 +38,16 @@ [0, 0, 1, 0], [0, -400, 0, 1] ] + }, + { + "id": 2, + "parent": 1, + "transform": [ + [1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, 1, 0], + [8, 2000, 0, 1] + ] } ] }
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/scroll/fixed-with-border-under-composited-absolute-scrolled-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/scroll/fixed-with-border-under-composited-absolute-scrolled-expected.txt index 462914a..e812ba3 100644 --- a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/scroll/fixed-with-border-under-composited-absolute-scrolled-expected.txt +++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/scroll/fixed-with-border-under-composited-absolute-scrolled-expected.txt
@@ -14,12 +14,11 @@ }, { "name": "LayoutNGBlockFlow (positioned) DIV id='absolute'", - "position": [8, 2000], "bounds": [1, 1], "contentsOpaque": true, "backfaceVisibility": "hidden", "backgroundColor": "#FF0000", - "transform": 1 + "transform": 2 }, { "name": "LayoutNGBlockFlow (positioned) DIV id='fixed'", @@ -39,6 +38,16 @@ [0, 0, 1, 0], [0, -400, 0, 1] ] + }, + { + "id": 2, + "parent": 1, + "transform": [ + [1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, 1, 0], + [8, 2000, 0, 1] + ] } ] }
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/scroll/overflow-hidden-yet-scrolled-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/scroll/overflow-hidden-yet-scrolled-expected.txt new file mode 100644 index 0000000..c9019e0 --- /dev/null +++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/scroll/overflow-hidden-yet-scrolled-expected.txt
@@ -0,0 +1,31 @@ +{ + "layers": [ + { + "name": "Scrolling background of LayoutView #document", + "bounds": [800, 600], + "contentsOpaque": true, + "backgroundColor": "#FFFFFF" + }, + { + "name": "LayoutNGBlockFlow DIV id='scroller'", + "bounds": [302, 302], + "backfaceVisibility": "hidden", + "invalidations": [ + [1, 201, 100, 100] + ], + "transform": 1 + } + ], + "transforms": [ + { + "id": 1, + "transform": [ + [1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, 1, 0], + [8, 8, 0, 1] + ] + } + ] +} +
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/scroll/overflow-hidden-yet-scrolled-with-custom-scrollbar-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/scroll/overflow-hidden-yet-scrolled-with-custom-scrollbar-expected.txt new file mode 100644 index 0000000..c9019e0 --- /dev/null +++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/scroll/overflow-hidden-yet-scrolled-with-custom-scrollbar-expected.txt
@@ -0,0 +1,31 @@ +{ + "layers": [ + { + "name": "Scrolling background of LayoutView #document", + "bounds": [800, 600], + "contentsOpaque": true, + "backgroundColor": "#FFFFFF" + }, + { + "name": "LayoutNGBlockFlow DIV id='scroller'", + "bounds": [302, 302], + "backfaceVisibility": "hidden", + "invalidations": [ + [1, 201, 100, 100] + ], + "transform": 1 + } + ], + "transforms": [ + { + "id": 1, + "transform": [ + [1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, 1, 0], + [8, 8, 0, 1] + ] + } + ] +} +
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/scroll/scroll-stacking-context-backface-visiblity-leaves-traces-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/scroll/scroll-stacking-context-backface-visiblity-leaves-traces-expected.txt index e2af358..54eaed1 100644 --- a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/scroll/scroll-stacking-context-backface-visiblity-leaves-traces-expected.txt +++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/scroll/scroll-stacking-context-backface-visiblity-leaves-traces-expected.txt
@@ -14,18 +14,17 @@ }, { "name": "LayoutNGBlockFlow (relative positioned) HEADER", - "position": [8, 28], "bounds": [769, 20], "drawsContent": false, "backfaceVisibility": "hidden", - "transform": 1 + "transform": 2 }, { "name": "LayoutNGBlockFlow (positioned) DIV id='searchbar'", "bounds": [150, 150], "contentsOpaque": true, "backgroundColor": "#800080", - "transform": 2 + "transform": 3 } ], "transforms": [ @@ -40,6 +39,16 @@ }, { "id": 2, + "parent": 1, + "transform": [ + [1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, 1, 0], + [8, 28, 0, 1] + ] + }, + { + "id": 3, "transform": [ [1, 0, 0, 0], [0, 1, 0, 0],
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/stacking-context-lost-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/stacking-context-lost-expected.txt index 96447ca..8c0be2d 100644 --- a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/stacking-context-lost-expected.txt +++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/stacking-context-lost-expected.txt
@@ -8,13 +8,24 @@ }, { "name": "LayoutNGBlockFlow (relative positioned) DIV id='outer'", - "position": [278, 278], "bounds": [100, 100], "contentsOpaque": true, "backfaceVisibility": "hidden", "backgroundColor": "#008000", "invalidations": [ [0, 0, 100, 100] + ], + "transform": 1 + } + ], + "transforms": [ + { + "id": 1, + "transform": [ + [1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, 1, 0], + [278, 278, 0, 1] ] } ]
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/svg/transform-focus-ring-repaint-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/svg/transform-focus-ring-repaint-expected.txt index 8954e2b..9016fdc8 100644 --- a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/svg/transform-focus-ring-repaint-expected.txt +++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/svg/transform-focus-ring-repaint-expected.txt
@@ -8,19 +8,20 @@ }, { "name": "LayoutNGBlockFlow (positioned) DIV id='target'", - "position": [6, 56], + "position": [-2, -2], "bounds": [204, 204], "backfaceVisibility": "hidden", "backgroundColor": "#FFFF00", "invalidations": [ [0, 0, 204, 204] - ] + ], + "transform": 1 }, { "name": "LayoutNGBlockFlow (positioned) DIV", "bounds": [440, 300], "backgroundColor": "#0000FF", - "transform": 2 + "transform": 3 } ], "transforms": [ @@ -30,13 +31,23 @@ [1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], - [108, 158, 0, 1] + [8, 58, 0, 1] ] }, { "id": 2, "parent": 1, "transform": [ + [1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, 1, 0], + [100, 100, 0, 1] + ] + }, + { + "id": 3, + "parent": 2, + "transform": [ [0, 1, 0, 0], [-1, 0, 0, 0], [0, 0, 1, 0],
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/vertical-rl-as-paint-container-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/vertical-rl-as-paint-container-expected.txt index 590c932..1adb49e 100644 --- a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/vertical-rl-as-paint-container-expected.txt +++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/vertical-rl-as-paint-container-expected.txt
@@ -8,11 +8,22 @@ }, { "name": "LayoutNGBlockFlow DIV id='target'", - "position": [8, 8], "bounds": [600, 400], "backfaceVisibility": "hidden", "invalidations": [ [520, 0, 80, 340] + ], + "transform": 1 + } + ], + "transforms": [ + { + "id": 1, + "transform": [ + [1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, 1, 0], + [8, 8, 0, 1] ] } ]
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/compositing/should-not-repaint-composited-descendants-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/compositing/should-not-repaint-composited-descendants-expected.txt index f8dd35e..b155170 100644 --- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/compositing/should-not-repaint-composited-descendants-expected.txt +++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/compositing/should-not-repaint-composited-descendants-expected.txt
@@ -11,7 +11,6 @@ "position": [30, 30], "bounds": [20, 70], "contentsOpaque": true, - "backfaceVisibility": "hidden", "backgroundColor": "#008000", "invalidations": [ [0, 0, 20, 70] @@ -20,12 +19,10 @@ }, { "name": "LayoutBlockFlow DIV class='composited child'", - "position": [0, 50], "bounds": [50, 50], "contentsOpaque": true, - "backfaceVisibility": "hidden", "backgroundColor": "#008000", - "transform": 1 + "transform": 2 } ], "transforms": [ @@ -37,6 +34,16 @@ [0, 0, 1, 0], [8, 8, 0, 1] ] + }, + { + "id": 2, + "parent": 1, + "transform": [ + [1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, 1, 0], + [0, 50, 0, 1] + ] } ] }
diff --git a/third_party/blink/web_tests/inspector-protocol/accessibility/accessibility-getFullAXTree-display-locked-expected.txt b/third_party/blink/web_tests/inspector-protocol/accessibility/accessibility-getFullAXTree-display-locked-expected.txt index 38282be..355c8010 100644 --- a/third_party/blink/web_tests/inspector-protocol/accessibility/accessibility-getFullAXTree-display-locked-expected.txt +++ b/third_party/blink/web_tests/inspector-protocol/accessibility/accessibility-getFullAXTree-display-locked-expected.txt
@@ -3,6 +3,9 @@ WebArea generic generic + text "spacer" + InlineTextBox + generic text "locked" generic text "child" @@ -18,6 +21,7 @@ text "text" generic generic + generic text "normal text" InlineTextBox
diff --git a/third_party/blink/web_tests/inspector-protocol/accessibility/accessibility-getFullAXTree-display-locked.js b/third_party/blink/web_tests/inspector-protocol/accessibility/accessibility-getFullAXTree-display-locked.js index a970ca07..0fa2e1b 100644 --- a/third_party/blink/web_tests/inspector-protocol/accessibility/accessibility-getFullAXTree-display-locked.js +++ b/third_party/blink/web_tests/inspector-protocol/accessibility/accessibility-getFullAXTree-display-locked.js
@@ -1,15 +1,17 @@ (async function(testRunner) { var {page, session, dp} = await testRunner.startHTML(` - <div id='activatable' style='subtree-visibility: hidden-matchable'> + <div style='height: 10000px;'>spacer</div> + <div id='activatable' style='subtree-visibility: auto'> locked <div id='child'> child <div id='grandChild'>grandChild</div> </div> <div id='invisible' style='display:none'>invisible</div> - <div id='nested' style='subtree-visibility: hidden-matchable'>nested</div> + <div id='nested' style='subtree-visibility: auto'>nested</div> text </div> + <div id='nonViewportActivatable' style='subtree-visibility: hidden-matchable'>nonViewportActivatable text</div> <div id='nonActivatable' style='subtree-visibility: hidden'>nonActivatable text</div> <div id='normal'>normal text</div> `, 'Tests accessibility values of display locked nodes');
diff --git a/third_party/blink/web_tests/paint/invalidation/compositing/should-not-repaint-composited-descendants-expected.txt b/third_party/blink/web_tests/paint/invalidation/compositing/should-not-repaint-composited-descendants-expected.txt index 0514dff..cbf9fd3 100644 --- a/third_party/blink/web_tests/paint/invalidation/compositing/should-not-repaint-composited-descendants-expected.txt +++ b/third_party/blink/web_tests/paint/invalidation/compositing/should-not-repaint-composited-descendants-expected.txt
@@ -11,7 +11,6 @@ "position": [30, 30], "bounds": [20, 70], "contentsOpaque": true, - "backfaceVisibility": "hidden", "backgroundColor": "#008000", "invalidations": [ [0, 0, 20, 70] @@ -20,12 +19,10 @@ }, { "name": "LayoutNGBlockFlow DIV class='composited child'", - "position": [0, 50], "bounds": [50, 50], "contentsOpaque": true, - "backfaceVisibility": "hidden", "backgroundColor": "#008000", - "transform": 1 + "transform": 2 } ], "transforms": [ @@ -37,6 +34,16 @@ [0, 0, 1, 0], [8, 8, 0, 1] ] + }, + { + "id": 2, + "parent": 1, + "transform": [ + [1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, 1, 0], + [0, 50, 0, 1] + ] } ] }
diff --git a/third_party/blink/web_tests/paint/invalidation/compositing/should-not-repaint-composited-descendants.html b/third_party/blink/web_tests/paint/invalidation/compositing/should-not-repaint-composited-descendants.html index aded658..798a0f86 100644 --- a/third_party/blink/web_tests/paint/invalidation/compositing/should-not-repaint-composited-descendants.html +++ b/third_party/blink/web_tests/paint/invalidation/compositing/should-not-repaint-composited-descendants.html
@@ -1,7 +1,7 @@ <!DOCTYPE html> <style> #composited-box { - backface-visibility: hidden; + will-change: transform; position: absolute; background-color: green; clip: rect(40px, 110px, 110px, 40px); @@ -12,7 +12,7 @@ background-color: green; } .composited { - backface-visibility: hidden; + will-change: transform; } </style> <script src="../resources/text-based-repaint.js"></script>
diff --git a/third_party/blink/web_tests/platform/linux/virtual/scalefactor200/css3/filters/effect-reference-colorspace-hw-expected.png b/third_party/blink/web_tests/platform/linux/virtual/scalefactor200/css3/filters/effect-reference-colorspace-hw-expected.png index 1b59c37..7d45612f 100644 --- a/third_party/blink/web_tests/platform/linux/virtual/scalefactor200/css3/filters/effect-reference-colorspace-hw-expected.png +++ b/third_party/blink/web_tests/platform/linux/virtual/scalefactor200/css3/filters/effect-reference-colorspace-hw-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/css3/filters/effect-reference-colorspace-hw-expected.png b/third_party/blink/web_tests/platform/mac/css3/filters/effect-reference-colorspace-hw-expected.png index 8f619dc..7accaf9 100644 --- a/third_party/blink/web_tests/platform/mac/css3/filters/effect-reference-colorspace-hw-expected.png +++ b/third_party/blink/web_tests/platform/mac/css3/filters/effect-reference-colorspace-hw-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/scalefactor200/css3/filters/effect-reference-colorspace-hw-expected.png b/third_party/blink/web_tests/platform/mac/virtual/scalefactor200/css3/filters/effect-reference-colorspace-hw-expected.png index af640be..43a89000 100644 --- a/third_party/blink/web_tests/platform/mac/virtual/scalefactor200/css3/filters/effect-reference-colorspace-hw-expected.png +++ b/third_party/blink/web_tests/platform/mac/virtual/scalefactor200/css3/filters/effect-reference-colorspace-hw-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/css3/filters/effect-reference-colorspace-hw-expected.png b/third_party/blink/web_tests/platform/win/css3/filters/effect-reference-colorspace-hw-expected.png index 91333a6..5b04ab45 100644 --- a/third_party/blink/web_tests/platform/win/css3/filters/effect-reference-colorspace-hw-expected.png +++ b/third_party/blink/web_tests/platform/win/css3/filters/effect-reference-colorspace-hw-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/scalefactor200/css3/filters/effect-reference-colorspace-hw-expected.png b/third_party/blink/web_tests/platform/win/virtual/scalefactor200/css3/filters/effect-reference-colorspace-hw-expected.png index 55cdb79..3950b50 100644 --- a/third_party/blink/web_tests/platform/win/virtual/scalefactor200/css3/filters/effect-reference-colorspace-hw-expected.png +++ b/third_party/blink/web_tests/platform/win/virtual/scalefactor200/css3/filters/effect-reference-colorspace-hw-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/serial/serialPort_readable_gc.html b/third_party/blink/web_tests/serial/serialPort_readable_gc.html index 1a485f64..3c270ad 100644 --- a/third_party/blink/web_tests/serial/serialPort_readable_gc.html +++ b/third_party/blink/web_tests/serial/serialPort_readable_gc.html
@@ -29,10 +29,7 @@ port.readable.pipeTo(writable); })(); - for (let i = 0; i < 50; ++i) { - GCController.collect(); - await new Promise(resolve => setTimeout(resolve, 0)); - } + GCController.collectAll(); const data = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]); fakePort.write(data);
diff --git a/tools/mb/mb.py b/tools/mb/mb.py index 094e171..0782960 100755 --- a/tools/mb/mb.py +++ b/tools/mb/mb.py
@@ -659,8 +659,11 @@ # # TODO(dpranke): Also, add support for sharding and merging results. dimensions = [] + swarming_pool = '' for k, v in self._DefaultDimensions() + self.args.dimensions: dimensions += ['-d', k, v] + if k == 'pool': + swarming_pool = v archive_json_path = self.ToSrcRelPath( '%s/%s.archive.json' % (build_dir, target)) @@ -724,7 +727,10 @@ '-S', swarming_server, '--tags=purpose:user-debug-mb', ] + dimensions - self._AddBaseSoftware(cmd) + # TODO(crbug.com/812428): Remove this once all pools have migrated to task + # templates. + if not swarming_pool.endswith('.template'): + self._AddBaseSoftware(cmd) if self.args.extra_args: cmd += ['--'] + self.args.extra_args self.Print('')
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 416e182a..298b882 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -14941,6 +14941,9 @@ <int value="33" label="Network panel film strip started recording"/> <int value="34" label="Coverage report was filtered"/> <int value="35" label="Coverage started (per block)"/> + <int value="36" label="Settings opened via gear icon"/> + <int value="37" label="Settings opened via menu"/> + <int value="38" label="Settings opened via command menu"/> </enum> <enum name="DevToolsBackgroundService"> @@ -15008,6 +15011,14 @@ <int value="26" label="Drawer - Live Heap Profile"/> <int value="27" label="Drawer - Quick source"/> <int value="28" label="Drawer - Request blocking"/> + <int value="29" label="Settings - Preferences"/> + <int value="30" label="Settings - Workspace"/> + <int value="31" label="Settings - Experiments"/> + <int value="32" label="Settings - Blackbox"/> + <int value="33" label="Settings - Devices"/> + <int value="34" label="Settings - Throttling Conditions"/> + <int value="35" label="Settings - Emulation Geolocations"/> + <int value="36" label="Settings - Shortcuts"/> </enum> <enum name="DevToolsSetting"> @@ -39540,6 +39551,7 @@ <int value="414114078" label="LitePageServerPreviews:disabled"/> <int value="415154056" label="enable-physical-keyboard-autocorrect"/> <int value="415395210" label="TrimOnMemoryPressure:enabled"/> + <int value="416691040" label="SendTabToSelfOmniboxSendingAnimation:disabled"/> <int value="416887895" label="enable-password-change-support"/> <int value="417709910" label="AutofillSendExperimentIdsInPaymentsRPCs:disabled"/> @@ -40178,6 +40190,7 @@ <int value="1203795051" label="PassiveMixedContentWarning:enabled"/> <int value="1203821857" label="Vulkan:disabled"/> <int value="1205849612" label="enable-sync-synced-notifications"/> + <int value="1205929554" label="SendTabToSelfOmniboxSendingAnimation:enabled"/> <int value="1210343926" label="enable-drop-sync-credential"/> <int value="1211284676" label="V8NoTurbo:enabled"/> <int value="1211756417"
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 0f1bb94..63130b30 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -25605,8 +25605,9 @@ </histogram> <histogram name="Compositing.Display.Draw.Occlusion.Calculation.Time" - units="microseconds" expires_after="M82"> + units="microseconds" expires_after="2020-08-23"> <owner>yiyix@chromium.org</owner> + <owner>chromeos-gfx@chromium.org</owner> <summary> Time spent to remove invisible quads from the quad_list in CompositorFrame. @@ -140512,7 +140513,7 @@ </histogram> <histogram name="Scheduler.CancelableTaskTracker.TaskDuration2" units="ms" - expires_after="2020-05-01"> + expires_after="2020-08-01"> <!-- Name completed by histogram_suffixes name="CancelableTaskTrackerDurationTypes" --> <owner>wez@chromium.org</owner> @@ -140524,7 +140525,7 @@ </histogram> <histogram name="Scheduler.CancelableTaskTracker.TaskStatus" - enum="CancelableTaskStatus" expires_after="2020-05-01"> + enum="CancelableTaskStatus" expires_after="2020-08-01"> <owner>wez@chromium.org</owner> <owner>scheduler-dev@chromium.org</owner> <summary>
diff --git a/tools/metrics/ukm/ukm.xml b/tools/metrics/ukm/ukm.xml index ff77ed1e..3696af9c 100644 --- a/tools/metrics/ukm/ukm.xml +++ b/tools/metrics/ukm/ukm.xml
@@ -8367,6 +8367,31 @@ </metric> </event> +<event name="PaymentApp.CheckoutEvents"> + <owner>sahel@chromium.org</owner> + <owner>web-payments-team@google.com</owner> + <summary> + Records checkout events as well as completion status for the invoked payment + app when its origin is shown inside the payment handler modal window. This + metric uses the specific PAYMENT_APP_ID ukm_source_id which is generated + from the app's origin. + </summary> + <metric name="CompletionStatus" enum="PaymentRequestFlowCompletionStatus"> + <summary> + How the Payment Request ended. This metric will only get recorded if a + non-autofill payment app gets invoked to handle the request. + </summary> + </metric> + <metric name="Events"> + <summary> + Bitfield representing the events that occurred during the Payment Request. + This metric will only get recorded if a non-autofill payment app gets + invoked to handle the request. Values defined in the Event enum of + components/payments/core/journey_logger.h. + </summary> + </metric> +</event> + <event name="PaymentRequest.CheckoutEvents"> <owner>sebsg@chromium.org</owner> <metric name="CompletionStatus">
diff --git a/ui/aura/demo/demo_main.cc b/ui/aura/demo/demo_main.cc index 2baf62a2..fe5050a 100644 --- a/ui/aura/demo/demo_main.cc +++ b/ui/aura/demo/demo_main.cc
@@ -197,8 +197,7 @@ test_screen->CreateHostForPrimaryDisplay()); std::unique_ptr<DemoWindowParentingClient> window_parenting_client( new DemoWindowParentingClient(host->window())); - aura::test::TestFocusClient focus_client; - aura::client::SetFocusClient(host->window(), &focus_client); + aura::test::TestFocusClient focus_client(host->window()); // Create a hierarchy of test windows. gfx::Rect window1_bounds(100, 100, 400, 400);
diff --git a/ui/aura/test/aura_test_helper.cc b/ui/aura/test/aura_test_helper.cc index 87d6170..e9894c8a 100644 --- a/ui/aura/test/aura_test_helper.cc +++ b/ui/aura/test/aura_test_helper.cc
@@ -83,8 +83,6 @@ setup_called_ = true; wm_state_ = std::make_unique<wm::WMState>(); - // Needs to be before creating WindowTreeClient. - focus_client_ = std::make_unique<TestFocusClient>(); if (!env) { // Some tests suites create Env globally rather than per test. @@ -125,7 +123,7 @@ Window* root_window = GetContext(); new wm::DefaultActivationClient(root_window); // Manages own lifetime. - client::SetFocusClient(root_window, focus_client_.get()); + focus_client_ = std::make_unique<TestFocusClient>(root_window); capture_client_ = std::make_unique<client::DefaultCaptureClient>(root_window); parenting_client_ = std::make_unique<TestWindowParentingClient>(root_window); @@ -140,16 +138,14 @@ g_instance = nullptr; teardown_called_ = true; parenting_client_.reset(); - client::SetFocusClient(GetContext(), nullptr); capture_client_.reset(); + focus_client_.reset(); host_.reset(); if (display::Screen::GetScreen() == test_screen_.get()) display::Screen::SetScreenInstance(nullptr); test_screen_.reset(); - focus_client_.reset(); - ui::ShutdownInputMethodForTesting(); context_factories_.reset();
diff --git a/ui/aura/test/test_focus_client.cc b/ui/aura/test/test_focus_client.cc index b32122f..afcf4dc 100644 --- a/ui/aura/test/test_focus_client.cc +++ b/ui/aura/test/test_focus_client.cc
@@ -13,12 +13,16 @@ //////////////////////////////////////////////////////////////////////////////// // TestFocusClient, public: -TestFocusClient::TestFocusClient() - : focused_window_(NULL), +TestFocusClient::TestFocusClient(Window* root_window) + : root_window_(root_window), + focused_window_(nullptr), observer_manager_(this) { + DCHECK(root_window_); + client::SetFocusClient(root_window_, this); } TestFocusClient::~TestFocusClient() { + client::SetFocusClient(root_window_, nullptr); } ////////////////////////////////////////////////////////////////////////////////
diff --git a/ui/aura/test/test_focus_client.h b/ui/aura/test/test_focus_client.h index 1cca6ed8..aa1435b 100644 --- a/ui/aura/test/test_focus_client.h +++ b/ui/aura/test/test_focus_client.h
@@ -18,7 +18,7 @@ class TestFocusClient : public client::FocusClient, public WindowObserver { public: - TestFocusClient(); + explicit TestFocusClient(Window* root_window); ~TestFocusClient() override; private: @@ -32,6 +32,7 @@ // Overridden from WindowObserver: void OnWindowDestroying(Window* window) override; + Window* root_window_; Window* focused_window_; ScopedObserver<Window, WindowObserver> observer_manager_; base::ObserverList<aura::client::FocusChangeObserver>::Unchecked
diff --git a/ui/file_manager/file_manager/foreground/elements/files_quick_view.css b/ui/file_manager/file_manager/foreground/elements/files_quick_view.css index a2a1ea32..8cd0ad89 100644 --- a/ui/file_manager/file_manager/foreground/elements/files_quick_view.css +++ b/ui/file_manager/file_manager/foreground/elements/files_quick_view.css
@@ -185,8 +185,7 @@ width: 36px; } -/* TODO(files-ng): files-ng rule that gets applied to non-files-ng */ -:host-context(html.pointer-active) cr-button:not(:active):hover { +:host-context(html.pointer-active.files-ng) cr-button:not(:active):hover { --hover-bg-color: none; cursor: unset; } @@ -255,7 +254,7 @@ display: none; } -:host([files-ng]) #info-button[toogle] { +:host([files-ng]) #info-button[aria-pressed=true] { background-color: rgba(255, 255, 255, 12%); } @@ -268,8 +267,7 @@ font-weight: bold; } -/* TODO(files-ng): files-ng rule that gets applied to non-files-ng */ -:host-context(html.focus-outline-visible) cr-button:not(:active):focus { +:host-context(html.focus-outline-visible.files-ng) cr-button:not(:active):focus { border: 2px solid var(--google-blue-300); }
diff --git a/ui/file_manager/file_manager/foreground/elements/files_quick_view.html b/ui/file_manager/file_manager/foreground/elements/files_quick_view.html index 2c60d50b..b18d616 100644 --- a/ui/file_manager/file_manager/foreground/elements/files_quick_view.html +++ b/ui/file_manager/file_manager/foreground/elements/files_quick_view.html
@@ -34,7 +34,7 @@ </cr-button> <files-icon-button toggles id="metadata-button" on-tap="onMetadataButtonTap_" active="{{metadataBoxActive}}" aria-label="$i18n{QUICK_VIEW_TOGGLE_METADATA_BOX_BUTTON_LABEL}" tabindex="0" has-tooltip> </files-icon-button> - <cr-button id="info-button" on-click="onMetadataButtonTap_" aria-label="$i18n{QUICK_VIEW_TOGGLE_METADATA_BOX_BUTTON_LABEL}" has-tooltip toogle> + <cr-button id="info-button" on-click="onMetadataButtonTap_" aria-pressed="{{metadataBoxActive}}" aria-label="$i18n{QUICK_VIEW_TOGGLE_METADATA_BOX_BUTTON_LABEL}" has-tooltip> <span class="icon"></span> </cr-button> </div>
diff --git a/ui/file_manager/file_manager/foreground/elements/files_quick_view.js b/ui/file_manager/file_manager/foreground/elements/files_quick_view.js index edc2561..3a01b27d 100644 --- a/ui/file_manager/file_manager/foreground/elements/files_quick_view.js +++ b/ui/file_manager/file_manager/foreground/elements/files_quick_view.js
@@ -182,21 +182,20 @@ }, /** - * TODO(992824): investigate the this.$.innerContentPanel.focus() since the - * has no tabindex it seems, and so the focus() call is ignored. + * See the changes on crbug.com/641587, but crbug.com/779044#c11 later undid + * that work. So the focus remains on the metadata button when clicked after + * the crbug.com/779044 "ghost focus" fix. + * + * crbug.com/641587 mentions a different UI behavior, that was wanted to fix + * that bug. TODO(files-ng): UX to resolve the correct behavior needed here. * * @param {!Event} event tap event. * * @private */ onMetadataButtonTap_: function(event) { - // Set focus back to innerContent panel so that pressing space key next - // closes Quick View. - this.$.innerContentPanel.focus(); - if (this.hasAttribute('files-ng')) { this.metadataBoxActive = !this.metadataBoxActive; - event.target.toggleAttribute('toogle', this.metadataBoxActive); } },
diff --git a/ui/gfx/color_space_win.cc b/ui/gfx/color_space_win.cc index 262bb4a..5d316af5 100644 --- a/ui/gfx/color_space_win.cc +++ b/ui/gfx/color_space_win.cc
@@ -138,6 +138,10 @@ DXGI_COLOR_SPACE_TYPE ColorSpaceWin::GetDXGIColorSpace( const ColorSpace& color_space, bool force_yuv) { + // Treat invalid color space as sRGB. + if (!color_space.IsValid()) + return DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709; + if (color_space.GetMatrixID() == gfx::ColorSpace::MatrixID::RGB && !force_yuv) { // For RGB, we default to FULL @@ -223,16 +227,10 @@ } } -DXGI_FORMAT ColorSpaceWin::GetDXGIFormat(const gfx::ColorSpace& color_space, - bool needs_alpha) { - // The PQ transfer function needs 10 bits. If we need an alpha channel, then - // we will need to bump to 16 bits. - if (color_space.GetTransferID() == gfx::ColorSpace::TransferID::SMPTEST2084) { - if (needs_alpha) - return DXGI_FORMAT_R16G16B16A16_UNORM; - else - return DXGI_FORMAT_R10G10B10A2_UNORM; - } +DXGI_FORMAT ColorSpaceWin::GetDXGIFormat(const gfx::ColorSpace& color_space) { + // The PQ transfer function needs 10 bits. + if (color_space.GetTransferID() == gfx::ColorSpace::TransferID::SMPTEST2084) + return DXGI_FORMAT_R10G10B10A2_UNORM; // Non-PQ HDR color spaces use half-float. if (color_space.IsHDR())
diff --git a/ui/gfx/color_space_win.h b/ui/gfx/color_space_win.h index cce9d2b..734ab3d 100644 --- a/ui/gfx/color_space_win.h +++ b/ui/gfx/color_space_win.h
@@ -37,8 +37,7 @@ // Get DXGI format for swap chain. This will default to 8-bit, but will use // 10-bit or half-float for HDR color spaces. - static DXGI_FORMAT GetDXGIFormat(const gfx::ColorSpace& color_space, - bool needs_alpha); + static DXGI_FORMAT GetDXGIFormat(const gfx::ColorSpace& color_space); static D3D11_VIDEO_PROCESSOR_COLOR_SPACE GetD3D11ColorSpace( const ColorSpace& color_space);
diff --git a/ui/gl/android/android_surface_control_compat.cc b/ui/gl/android/android_surface_control_compat.cc index 765a79f..c0a2e48 100644 --- a/ui/gl/android/android_surface_control_compat.cc +++ b/ui/gl/android/android_surface_control_compat.cc
@@ -14,6 +14,7 @@ #include "base/memory/ptr_util.h" #include "base/no_destructor.h" #include "base/strings/string_number_conversions.h" +#include "base/system/sys_info.h" #include "base/trace_event/trace_event.h" #include "ui/gfx/color_space.h" @@ -287,6 +288,12 @@ bool SurfaceControl::IsSupported() { if (!base::android::BuildInfo::GetInstance()->is_at_least_q()) return false; + + // GLFence cannot be created successfully on emulator, and it is needed by + // Android surface control. + if (base::SysInfo::GetAndroidHardwareEGL() == "emulation") + return false; + CHECK(SurfaceControlMethods::Get().supported); return true; }
diff --git a/ui/gl/direct_composition_child_surface_win.cc b/ui/gl/direct_composition_child_surface_win.cc index 93a85f27..f132887 100644 --- a/ui/gl/direct_composition_child_surface_win.cc +++ b/ui/gl/direct_composition_child_surface_win.cc
@@ -267,8 +267,7 @@ return false; } - DXGI_FORMAT dxgi_format = - gfx::ColorSpaceWin::GetDXGIFormat(color_space_, has_alpha_); + DXGI_FORMAT dxgi_format = gfx::ColorSpaceWin::GetDXGIFormat(color_space_); if (!dcomp_surface_ && enable_dc_layers_) { TRACE_EVENT2("gpu", "DirectCompositionChildSurfaceWin::CreateSurface", @@ -308,9 +307,8 @@ desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; desc.Scaling = DXGI_SCALING_STRETCH; desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; - desc.AlphaMode = (has_alpha_ || enable_dc_layers_) - ? DXGI_ALPHA_MODE_PREMULTIPLIED - : DXGI_ALPHA_MODE_IGNORE; + desc.AlphaMode = + has_alpha_ ? DXGI_ALPHA_MODE_PREMULTIPLIED : DXGI_ALPHA_MODE_IGNORE; desc.Flags = DirectCompositionSurfaceWin::AllowTearing() ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0; @@ -331,8 +329,10 @@ } Microsoft::WRL::ComPtr<IDXGISwapChain3> swap_chain; if (SUCCEEDED(swap_chain_.As(&swap_chain))) { - swap_chain->SetColorSpace1( + hr = swap_chain->SetColorSpace1( gfx::ColorSpaceWin::GetDXGIColorSpace(color_space_)); + DCHECK(SUCCEEDED(hr)) + << "SetColorSpace1 failed with error " << std::hex << hr; } } @@ -418,8 +418,7 @@ // ResizeBuffers can't change alpha blending mode. if (swap_chain_ && resize_only) { - DXGI_FORMAT format = - gfx::ColorSpaceWin::GetDXGIFormat(color_space_, has_alpha_); + DXGI_FORMAT format = gfx::ColorSpaceWin::GetDXGIFormat(color_space_); UINT flags = DirectCompositionSurfaceWin::AllowTearing() ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0;
diff --git a/ui/gl/gl_surface_egl.cc b/ui/gl/gl_surface_egl.cc index 17a6259..65d0cc4 100644 --- a/ui/gl/gl_surface_egl.cc +++ b/ui/gl/gl_surface_egl.cc
@@ -961,16 +961,19 @@ // The native fence sync extension is a bit complicated. It's reported as // present for ChromeOS, but Android currently doesn't report this extension - // even when it's present, and older devices may export a useless wrapper - // function. See crbug.com/775707 for details. In short, if the symbol is - // present and we're on Android N or newer, assume that it's usable even if - // the extension wasn't reported. + // even when it's present, and older devices and Android emulator may export + // a useless wrapper function. See crbug.com/775707 for details. In short, if + // the symbol is present and we're on Android N or newer and we are not on + // Android emulator, assume that it's usable even if the extension wasn't + // reported. g_egl_android_native_fence_sync_supported = HasEGLExtension("EGL_ANDROID_native_fence_sync"); #if defined(OS_ANDROID) - if (base::android::BuildInfo::GetInstance()->sdk_int() >= + if (!g_egl_android_native_fence_sync_supported && + base::android::BuildInfo::GetInstance()->sdk_int() >= base::android::SDK_VERSION_NOUGAT && - g_driver_egl.fn.eglDupNativeFenceFDANDROIDFn) { + g_driver_egl.fn.eglDupNativeFenceFDANDROIDFn && + base::SysInfo::GetAndroidHardwareEGL() != "emulation") { g_egl_android_native_fence_sync_supported = true; } #endif
diff --git a/ui/native_theme/common_theme.cc b/ui/native_theme/common_theme.cc index e0c2d90..3173a71 100644 --- a/ui/native_theme/common_theme.cc +++ b/ui/native_theme/common_theme.cc
@@ -395,7 +395,10 @@ case NativeTheme::kColorId_TextfieldReadOnlyColor: { const SkColor bg = base_theme->GetSystemColor( NativeTheme::kColorId_TextfieldReadOnlyBackground, color_scheme); - return color_utils::BlendForMinContrast(gfx::kGoogleGrey600, bg).color; + const SkColor fg = base_theme->GetSystemColor( + NativeTheme::kColorId_TextfieldDefaultColor, color_scheme); + return color_utils::BlendForMinContrast(gfx::kGoogleGrey600, bg, fg) + .color; } case NativeTheme::kColorId_TextfieldSelectionBackgroundFocused: return gfx::kGoogleBlue200;
diff --git a/ui/native_theme/native_theme.cc b/ui/native_theme/native_theme.cc index fbfc8ade..370c3ab 100644 --- a/ui/native_theme/native_theme.cc +++ b/ui/native_theme/native_theme.cc
@@ -165,19 +165,17 @@ // TODO(http://crbug.com/1057754): Remove the below restrictions. if (base::FeatureList::IsEnabled(features::kColorProviderRedirection) && - color_scheme == NativeTheme::ColorScheme::kLight) { - if (!color_provider_) { - // Lazy init the color provider as it makes USER32 calls underneath on - // Windows, which isn't permitted on renderers. - // TODO(http://crbug.com/1057754): Handle dark and high contrast modes. - color_provider_ = ColorProviderManager::Get().GetColorProviderFor( - ColorProviderManager::ColorMode::kLight, - ColorProviderManager::ContrastMode::kNormal); - } + color_scheme != NativeTheme::ColorScheme::kPlatformHighContrast) { + auto color_mode = (color_scheme == NativeTheme::ColorScheme::kDark) + ? ColorProviderManager::ColorMode::kDark + : ColorProviderManager::ColorMode::kLight; + // TODO(http://crbug.com/1057754): Handle high contrast modes. + auto* color_provider = ColorProviderManager::Get().GetColorProviderFor( + color_mode, ColorProviderManager::ContrastMode::kNormal); auto color_id_map = NativeThemeColorIdToColorIdMap(); auto result = color_id_map.find(color_id); if (result != color_id_map.cend()) - return color_provider_->GetColor(result->second); + return color_provider->GetColor(result->second); } return GetAuraColor(color_id, this, color_scheme); }
diff --git a/ui/native_theme/native_theme.h b/ui/native_theme/native_theme.h index 380a8e7..45757a9 100644 --- a/ui/native_theme/native_theme.h +++ b/ui/native_theme/native_theme.h
@@ -29,8 +29,6 @@ namespace ui { -class ColorProvider; - // This class supports drawing UI controls (like buttons, text fields, lists, // comboboxes, etc) that look like the native UI controls of the underlying // platform, such as Windows or Linux. It also supplies default colors for @@ -480,7 +478,6 @@ bool is_high_contrast_ = false; PreferredColorScheme preferred_color_scheme_ = PreferredColorScheme::kNoPreference; - mutable ColorProvider* color_provider_ = nullptr; DISALLOW_COPY_AND_ASSIGN(NativeTheme); };
diff --git a/ui/views/controls/webview/OWNERS b/ui/views/controls/webview/OWNERS index db57a47..d2e5686 100644 --- a/ui/views/controls/webview/OWNERS +++ b/ui/views/controls/webview/OWNERS
@@ -1,3 +1,6 @@ -miu@chromium.org sadrul@chromium.org sky@chromium.org + +# For "EmbedFullscreenWidgetMode" changes. (Component: UI>Browser>TabCapture) +miu@chromium.org +mfoltz@chromium.org
diff --git a/ui/views/corewm/tooltip_controller_unittest.cc b/ui/views/corewm/tooltip_controller_unittest.cc index 712e3fc..9ac9d77 100644 --- a/ui/views/corewm/tooltip_controller_unittest.cc +++ b/ui/views/corewm/tooltip_controller_unittest.cc
@@ -11,7 +11,6 @@ #include "ui/accessibility/ax_enums.mojom.h" #include "ui/accessibility/ax_node_data.h" #include "ui/aura/client/cursor_client.h" -#include "ui/aura/client/screen_position_client.h" #include "ui/aura/client/window_types.h" #include "ui/aura/env.h" #include "ui/aura/test/aura_test_base.h" @@ -485,17 +484,17 @@ void SetUp() override { TooltipControllerTest::SetUp(); - aura::client::SetScreenPositionClient(GetRootWindow(), - &screen_position_client_); + screen_position_client_ = + std::make_unique<wm::DefaultScreenPositionClient>(GetRootWindow()); } void TearDown() override { - aura::client::SetScreenPositionClient(GetRootWindow(), nullptr); + screen_position_client_.reset(); TooltipControllerTest::TearDown(); } private: - wm::DefaultScreenPositionClient screen_position_client_; + std::unique_ptr<wm::DefaultScreenPositionClient> screen_position_client_; std::unique_ptr<display::Screen> desktop_screen_; DISALLOW_COPY_AND_ASSIGN(TooltipControllerCaptureTest);
diff --git a/ui/views/test/views_test_helper_aura.cc b/ui/views/test/views_test_helper_aura.cc index 8621b3e1..73c202a7 100644 --- a/ui/views/test/views_test_helper_aura.cc +++ b/ui/views/test/views_test_helper_aura.cc
@@ -21,9 +21,7 @@ gfx::NativeWindow root_window = GetContext(); if (root_window && !aura::client::GetScreenPositionClient(root_window)) { screen_position_client_ = - std::make_unique<wm::DefaultScreenPositionClient>(); - aura::client::SetScreenPositionClient(root_window, - screen_position_client_.get()); + std::make_unique<wm::DefaultScreenPositionClient>(root_window); } } @@ -37,12 +35,9 @@ // So, although it's optional, check the root window to detect failures // before they hit the CQ on other platforms. DCHECK(root_window->children().empty()) << "Not all windows were closed."; - - if (screen_position_client_.get() == - aura::client::GetScreenPositionClient(root_window)) - aura::client::SetScreenPositionClient(root_window, nullptr); } + screen_position_client_.reset(); aura_test_helper_.TearDown(); const wm::CaptureController* const controller = wm::CaptureController::Get();
diff --git a/ui/views/widget/desktop_aura/desktop_screen_position_client.cc b/ui/views/widget/desktop_aura/desktop_screen_position_client.cc index b889969e..2406d29 100644 --- a/ui/views/widget/desktop_aura/desktop_screen_position_client.cc +++ b/ui/views/widget/desktop_aura/desktop_screen_position_client.cc
@@ -22,15 +22,7 @@ } // namespace -DesktopScreenPositionClient::DesktopScreenPositionClient( - aura::Window* root_window) - : root_window_(root_window) { - aura::client::SetScreenPositionClient(root_window_, this); -} - -DesktopScreenPositionClient::~DesktopScreenPositionClient() { - aura::client::SetScreenPositionClient(root_window_, nullptr); -} +DesktopScreenPositionClient::~DesktopScreenPositionClient() = default; void DesktopScreenPositionClient::SetBounds(aura::Window* window, const gfx::Rect& bounds,
diff --git a/ui/views/widget/desktop_aura/desktop_screen_position_client.h b/ui/views/widget/desktop_aura/desktop_screen_position_client.h index 33fbdc2..586ac07 100644 --- a/ui/views/widget/desktop_aura/desktop_screen_position_client.h +++ b/ui/views/widget/desktop_aura/desktop_screen_position_client.h
@@ -16,7 +16,7 @@ class VIEWS_EXPORT DesktopScreenPositionClient : public wm::DefaultScreenPositionClient { public: - explicit DesktopScreenPositionClient(aura::Window* root_window); + using DefaultScreenPositionClient::DefaultScreenPositionClient; ~DesktopScreenPositionClient() override; // aura::client::DefaultScreenPositionClient: @@ -25,8 +25,6 @@ const display::Display& display) override; private: - aura::Window* root_window_; - DISALLOW_COPY_AND_ASSIGN(DesktopScreenPositionClient); };
diff --git a/ui/wm/core/coordinate_conversion_unittest.cc b/ui/wm/core/coordinate_conversion_unittest.cc index 13d077a..871eb195 100644 --- a/ui/wm/core/coordinate_conversion_unittest.cc +++ b/ui/wm/core/coordinate_conversion_unittest.cc
@@ -5,7 +5,6 @@ #include "ui/wm/core/coordinate_conversion.h" #include "testing/gtest/include/gtest/gtest.h" -#include "ui/aura/client/screen_position_client.h" #include "ui/aura/test/aura_test_base.h" #include "ui/aura/test/test_windows.h" #include "ui/wm/core/default_screen_position_client.h" @@ -15,8 +14,7 @@ typedef aura::test::AuraTestBase CoordinateConversionTest; TEST_F(CoordinateConversionTest, ConvertRect) { - DefaultScreenPositionClient screen_position_client; - aura::client::SetScreenPositionClient(root_window(), &screen_position_client); + DefaultScreenPositionClient screen_position_client(root_window()); aura::Window* w = aura::test::CreateTestWindowWithBounds( gfx::Rect(10, 20, 100, 200), root_window()); @@ -35,8 +33,6 @@ gfx::Rect r4(-10, -20, 100, 200); ConvertRectToScreen(w, &r4); EXPECT_EQ("0,0 100x200", r4.ToString()); - - aura::client::SetScreenPositionClient(root_window(), nullptr); } } // namespace wm
diff --git a/ui/wm/core/default_screen_position_client.cc b/ui/wm/core/default_screen_position_client.cc index 36f8ea7..1c532c27 100644 --- a/ui/wm/core/default_screen_position_client.cc +++ b/ui/wm/core/default_screen_position_client.cc
@@ -11,10 +11,15 @@ namespace wm { -DefaultScreenPositionClient::DefaultScreenPositionClient() { +DefaultScreenPositionClient::DefaultScreenPositionClient( + aura::Window* root_window) + : root_window_(root_window) { + DCHECK(root_window_); + aura::client::SetScreenPositionClient(root_window_, this); } DefaultScreenPositionClient::~DefaultScreenPositionClient() { + aura::client::SetScreenPositionClient(root_window_, nullptr); } void DefaultScreenPositionClient::ConvertPointToScreen(
diff --git a/ui/wm/core/default_screen_position_client.h b/ui/wm/core/default_screen_position_client.h index d1bf747..2e70ce2 100644 --- a/ui/wm/core/default_screen_position_client.h +++ b/ui/wm/core/default_screen_position_client.h
@@ -16,7 +16,7 @@ class WM_CORE_EXPORT DefaultScreenPositionClient : public aura::client::ScreenPositionClient { public: - DefaultScreenPositionClient(); + explicit DefaultScreenPositionClient(aura::Window* root_window); ~DefaultScreenPositionClient() override; // aura::client::ScreenPositionClient overrides: @@ -35,6 +35,8 @@ virtual gfx::Point GetOriginInScreen(const aura::Window* root_window); private: + aura::Window* root_window_; + DISALLOW_COPY_AND_ASSIGN(DefaultScreenPositionClient); };
diff --git a/ui/wm/core/ime_util_chromeos_unittest.cc b/ui/wm/core/ime_util_chromeos_unittest.cc index 24fbb50..b4510da 100644 --- a/ui/wm/core/ime_util_chromeos_unittest.cc +++ b/ui/wm/core/ime_util_chromeos_unittest.cc
@@ -23,13 +23,12 @@ void SetUp() override { AuraTestBase::SetUp(); - screen_position_client_ = std::make_unique<DefaultScreenPositionClient>(); - aura::client::SetScreenPositionClient(root_window(), - screen_position_client_.get()); + screen_position_client_ = + std::make_unique<DefaultScreenPositionClient>(root_window()); } void TearDown() override { - aura::client::SetScreenPositionClient(root_window(), nullptr); + screen_position_client_.reset(); AuraTestBase::TearDown(); }
diff --git a/ui/wm/test/wm_test_helper.cc b/ui/wm/test/wm_test_helper.cc index 844c4d37..a0c43c6 100644 --- a/ui/wm/test/wm_test_helper.cc +++ b/ui/wm/test/wm_test_helper.cc
@@ -32,8 +32,8 @@ aura::client::SetWindowParentingClient(host_->window(), this); - focus_client_ = std::make_unique<aura::test::TestFocusClient>(); - aura::client::SetFocusClient(host_->window(), focus_client_.get()); + focus_client_ = + std::make_unique<aura::test::TestFocusClient>(host_->window()); root_window_event_filter_ = std::make_unique<wm::CompoundEventFilter>(); host_->window()->AddPreTargetHandler(root_window_event_filter_.get());
diff --git a/weblayer/browser/safe_browsing/url_checker_delegate_impl.cc b/weblayer/browser/safe_browsing/url_checker_delegate_impl.cc index e7f3fb2..cf88f33 100644 --- a/weblayer/browser/safe_browsing/url_checker_delegate_impl.cc +++ b/weblayer/browser/safe_browsing/url_checker_delegate_impl.cc
@@ -43,6 +43,13 @@ base::Unretained(this), resource)); } +void UrlCheckerDelegateImpl:: + StartObservingInteractionsForDelayedBlockingPageHelper( + const security_interstitials::UnsafeResource& resource, + bool is_main_frame) { + NOTREACHED() << "Delayed warnings aren't implemented for WebLayer"; +} + void UrlCheckerDelegateImpl::StartDisplayingDefaultBlockingPage( const security_interstitials::UnsafeResource& resource) { content::WebContents* web_contents = resource.web_contents_getter.Run();
diff --git a/weblayer/browser/safe_browsing/url_checker_delegate_impl.h b/weblayer/browser/safe_browsing/url_checker_delegate_impl.h index fc5fa47..55814185 100644 --- a/weblayer/browser/safe_browsing/url_checker_delegate_impl.h +++ b/weblayer/browser/safe_browsing/url_checker_delegate_impl.h
@@ -37,6 +37,9 @@ const net::HttpRequestHeaders& headers, bool is_main_frame, bool has_user_gesture) override; + void StartObservingInteractionsForDelayedBlockingPageHelper( + const security_interstitials::UnsafeResource& resource, + bool is_main_frame) override; bool IsUrlWhitelisted(const GURL& url) override; bool ShouldSkipRequestCheck(const GURL& original_url, int frame_tree_node_id,