diff --git a/DEPS b/DEPS index b006624..8fef72a3 100644 --- a/DEPS +++ b/DEPS
@@ -297,7 +297,7 @@ # 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': '5d0618b59df269774607d703e977d4e671c125e5', + 'skia_revision': '3fbcfbbd908e05e6511003355df6b593205641bf', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. @@ -305,11 +305,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': '4330a827bac71d1928b02a93984a1b996bcfa0a7', + 'angle_revision': '9a25828113d57cf95b0c9f583e904af151a2edde', # 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': '1c3dfde53353d5e13ca25eb52aa208d450b5e980', + 'swiftshader_revision': 'c21aa26e0256a3efed81740d6215acb393b61d9e', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. @@ -324,7 +324,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Fuchsia sdk # and whatever else without interference from each other. - 'fuchsia_version': 'version:9.20220819.1.1', + 'fuchsia_version': 'version:9.20220819.2.1', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling google-toolbox-for-mac # and whatever else without interference from each other. @@ -368,7 +368,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': '72946313ec4f9773088a8258f7509fbeaf47465e', + 'catapult_revision': '9bfc1aede5c2b3c736e89ae1af93660807a16654', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other. @@ -376,7 +376,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': '39530caaf4faf099e939a27a574a1e6a837d138e', + 'devtools_frontend_revision': '34b7dd793876ff02ee2dda54161a529a60ec5dfc', # 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. @@ -440,7 +440,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling nearby # and whatever else without interference from each other. - 'nearby_revision': 'd92f1d47573427e6417e29a3e82ea7d4c34fe0b5', + 'nearby_revision': '5b7bb37d41f45635fcb848841524cb18664336dd', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling securemessage # and whatever else without interference from each other. @@ -480,7 +480,7 @@ # If you change this, also update the libc++ revision in # //buildtools/deps_revisions.gni. - 'libcxx_revision': 'db722166934ebc79a6e65e5fef9a6eae21eacb77', + 'libcxx_revision': '8b1c50618df7677fb1bd4bdf40d15a55b1733293', # GN CIPD package version. 'gn_version': 'git_revision:0bcd37bd2b83f1a9ee17088037ebdfe6eab6d31a', @@ -873,7 +873,7 @@ 'packages': [ { 'package': 'chromium/rts/model/mac-amd64', - 'version': 'sGVhzaqwgT697qIGKjfghO3mclJdO4I-L5nQoJqYb3sC', + 'version': 'AD0RPrNJPAmLU42D6TRmyl_oyaX9DwtzHkISlAWK7u8C', }, ], 'dep_type': 'cipd', @@ -1338,7 +1338,7 @@ Var('chromium_git') + '/chromium/deps/hunspell_dictionaries.git' + '@' + '41cdffd71c9948f63c7ad36e1fb0ff519aa7a37e', 'src/third_party/icu': - Var('chromium_git') + '/chromium/deps/icu.git' + '@' + 'b3070c52557323463e6b9827e2343e60e1b91f85', + Var('chromium_git') + '/chromium/deps/icu.git' + '@' + '31c77cbfff890d173237f51b3c5930416b3d5b24', 'src/third_party/icu4j': { 'packages': [ @@ -1613,7 +1613,7 @@ 'packages': [ { 'package': 'chromium/third_party/r8', - 'version': 'qvL35O3yU1ZbOWHVZBedmVtdaav1qKquii4RJyUh-PgC', + 'version': '2P7CTTsDUzoP3f8LtGNRdtwC48KAMmV-hPoNhGAwiKMC', }, ], 'condition': 'checkout_android', @@ -1693,7 +1693,7 @@ 'dep_type': 'cipd', }, - 'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@41bdd557a6ae1523a6c5a4067942ad59fe62210f', + 'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@691fb8dbe91e834e87f0e1dbe23ffbe22bfd4fa2', 'src/third_party/vulkan_memory_allocator': Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git' + '@' + 'ebe84bec02c041d28f902da0214bf442743fc907', @@ -1732,7 +1732,7 @@ Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + 'fef5f14679a5ec7185835be9142220bd8b79db6c', 'src/third_party/webrtc': - Var('webrtc_git') + '/src.git' + '@' + '79c96ded88372967b3ca89c415e4b34d4ba391bd', + Var('webrtc_git') + '/src.git' + '@' + 'f7f9791cc740ecf855261e28090651db98bb3d37', 'src/third_party/libgifcodec': Var('skia_git') + '/libgifcodec' + '@'+ Var('libgifcodec_revision'), @@ -1805,7 +1805,7 @@ Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'), 'src-internal': { - 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@f20197a770e5f1e30545d4bc852a5f05beaad445', + 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@31585af7148cabee01eef21c8ef70c46f6fbab21', 'condition': 'checkout_src_internal', }, @@ -1846,7 +1846,7 @@ 'packages': [ { 'package': 'chromeos_internal/apps/media_app/app', - 'version': 'zCrKLiPCz5bh2lVC4vnvgOsqADfZs68OXYymyBpbb-0C', + 'version': 'p6yXpwzNA-pohu1ZVgaTtuoVemyUR6Nyj0zEPx-EDuEC', }, ], 'condition': 'checkout_chromeos and checkout_src_internal',
diff --git a/WATCHLISTS b/WATCHLISTS index 72507f5..c10e86a 100644 --- a/WATCHLISTS +++ b/WATCHLISTS
@@ -2555,12 +2555,14 @@ 'diagnostics_mojo': ['ashleydp+watch-diagnostics_mojo@google.com', 'gavindodd+watch-diagnostics_mojo@google.com', 'michaelcheco+watch-diagnostics_mojo@google.com', - 'zentaro+watch-diagnostics_mojo@chromium.org'], + 'zentaro+watch-diagnostics_mojo@chromium.org', + 'dpad+watch-diagnostics_mojo@google.com'], 'diagnostics_ui': ['gavinwill+diagnostics-watch@chromium.org', 'michaelcheco+diagnostics-watch@google.com', 'zentaro+diagnostics-watch@chromium.org', 'gavindodd+diagnostics-watch@google.com', - 'ashleydp+diagnostics-watch@google.com'], + 'ashleydp+diagnostics-watch@google.com', + 'dpad+diagnostics-watch@google.com'], 'discardable_memory': ['thiabaud+watch-discardable-memory@google.com'], 'disk_cache': ['gavinp+disk@chromium.org'], 'dom_storage': ['dmurph+watchingdomstorage@chromium.org'], @@ -2817,7 +2819,8 @@ 'remoting': ['chromoting-reviews@chromium.org'], 'rgb_kbd': ['michaelcheco+watch-rgb-kbd@google.com', 'jimmyxgong+watch-rgb-kbd@chromium.org', - 'zentaro+watch-rgb-kbd@chromium.org'], + 'zentaro+watch-rgb-kbd@chromium.org', + 'dpad+watch-rgb-kbd@google.com'], 'rlz_id': ['gab+watch@chromium.org', 'robertshield+watch@chromium.org'], 'runtime_enabled_features': ['jmedley+watch@chromium.org'],
diff --git a/ash/BUILD.gn b/ash/BUILD.gn index 173d150..32a0d5f 100644 --- a/ash/BUILD.gn +++ b/ash/BUILD.gn
@@ -2658,11 +2658,7 @@ "frame/caption_buttons/frame_size_button_unittest.cc", "frame/default_frame_header_unittest.cc", "frame/non_client_frame_view_ash_unittest.cc", - "glanceables/glanceables_controller_unittest.cc", "glanceables/glanceables_unittests.cc", - "glanceables/glanceables_up_next_view_unittest.cc", - "glanceables/glanceables_view_unittest.cc", - "glanceables/glanceables_weather_view_unittest.cc", "glanceables/glanceables_welcome_label_unittest.cc", "highlighter/highlighter_controller_unittest.cc", "highlighter/highlighter_gesture_util_unittest.cc",
diff --git a/ash/components/phonehub/util/histogram_util.cc b/ash/components/phonehub/util/histogram_util.cc index 35d747e3..e55b0005 100644 --- a/ash/components/phonehub/util/histogram_util.cc +++ b/ash/components/phonehub/util/histogram_util.cc
@@ -61,9 +61,14 @@ case proto::MessageType::INITIATE_CAMERA_ROLL_ITEM_TRANSFER_REQUEST: return "PhoneHub.TaskCompletion.InitiateCameraRollItemTransfer.Result"; + case proto::MessageType::FEATURE_SETUP_REQUEST: + [[fallthrough]]; + case proto::MessageType::FEATURE_SETUP_RESPONSE: + return "PhoneHub.TaskCompletion.FeatureSetup.Result"; + default: // Note that PROVIDE_CROS_STATE, PHONE_STATUS_SNAPSHOT and - // PHONE_STATUS_UPDATE message types are not logged as part of this + // PHONE_STATUS_UPDATE message types are not logged as part of these // metrics. return std::string(); }
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc index ede7c22..5ced17f 100644 --- a/ash/constants/ash_features.cc +++ b/ash/constants/ash_features.cc
@@ -897,6 +897,11 @@ "HoldingSpaceInProgressNotificationSuppression", base::FEATURE_DISABLED_BY_DEFAULT}; +// Enables holding space icon to be permanently displayed with extended file +// expiration to increase predictability of the feature. +const base::Feature kHoldingSpacePredictability{ + "HoldingSpacePredictability", base::FEATURE_DISABLED_BY_DEFAULT}; + // Enables rebranding of holding space to convey the relationship with // Files to simplify feature comprehension. const base::Feature kHoldingSpaceRebrand{"HoldingSpaceRebrand", @@ -2060,6 +2065,10 @@ kHoldingSpaceInProgressDownloadsNotificationSuppression); } +bool IsHoldingSpacePredictabilityEnabled() { + return base::FeatureList::IsEnabled(kHoldingSpacePredictability); +} + bool IsHoldingSpaceRebrandEnabled() { return base::FeatureList::IsEnabled(kHoldingSpaceRebrand); }
diff --git a/ash/constants/ash_features.h b/ash/constants/ash_features.h index 48b030ce..e25a669b 100644 --- a/ash/constants/ash_features.h +++ b/ash/constants/ash_features.h
@@ -372,6 +372,8 @@ extern const base::Feature kHoldingSpaceInProgressDownloadsNotificationSuppression; COMPONENT_EXPORT(ASH_CONSTANTS) +extern const base::Feature kHoldingSpacePredictability; +COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kHoldingSpaceRebrand; COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kHoldingSpaceSuggestions; @@ -771,6 +773,7 @@ COMPONENT_EXPORT(ASH_CONSTANTS) bool IsHideShelfControlsInTabletModeEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsHoldingSpaceInProgressDownloadsNotificationSuppressionEnabled(); +COMPONENT_EXPORT(ASH_CONSTANTS) bool IsHoldingSpacePredictabilityEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsHoldingSpaceRebrandEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsHoldingSpaceSuggestionsEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsHostnameSettingEnabled();
diff --git a/ash/frame/non_client_frame_view_ash.cc b/ash/frame/non_client_frame_view_ash.cc index 6ea4e70..2746a09 100644 --- a/ash/frame/non_client_frame_view_ash.cc +++ b/ash/frame/non_client_frame_view_ash.cc
@@ -470,6 +470,12 @@ if (!chromeos::features::IsDarkLightModeEnabled()) return; + if (highlight_border_overlay_ || + !GetWidget()->GetNativeWindow()->GetProperty( + chromeos::kShouldHaveHighlightBorderOverlay)) { + return; + } + highlight_border_overlay_ = std::make_unique<HighlightBorderOverlay>(GetWidget()); }
diff --git a/ash/glanceables/glanceables_controller.h b/ash/glanceables/glanceables_controller.h index 2fb9b05c..030cada 100644 --- a/ash/glanceables/glanceables_controller.h +++ b/ash/glanceables/glanceables_controller.h
@@ -39,9 +39,6 @@ // Triggers a session restore. void RestoreSession(); - views::Widget* widget_for_test() { return widget_.get(); } - GlanceablesView* view_for_test() { return view_; } - private: friend class GlanceablesTest;
diff --git a/ash/glanceables/glanceables_controller_unittest.cc b/ash/glanceables/glanceables_controller_unittest.cc deleted file mode 100644 index fd415c9..0000000 --- a/ash/glanceables/glanceables_controller_unittest.cc +++ /dev/null
@@ -1,54 +0,0 @@ -// Copyright 2022 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/glanceables/glanceables_controller.h" - -#include "ash/constants/ash_features.h" -#include "ash/glanceables/glanceables_view.h" -#include "ash/shell.h" -#include "ash/test/ash_test_base.h" -#include "base/test/scoped_feature_list.h" - -namespace ash { -namespace { - -// Use a "no session" test so the glanceables widget is not automatically -// created at the start of the test. -// TODO(crbug.com/1353119): Once glanceables are shown by code in the -// chrome/browser/ash layer, switch this to AshTestBase. -class GlanceablesControllerTest : public NoSessionAshTestBase { - protected: - base::test::ScopedFeatureList feature_list_{features::kGlanceables}; -}; - -TEST_F(GlanceablesControllerTest, CreateUi) { - GlanceablesController* controller = Shell::Get()->glanceables_controller(); - ASSERT_TRUE(controller); - - controller->CreateUi(); - - // A fullscreen widget was created. - views::Widget* widget = controller->widget_for_test(); - ASSERT_TRUE(widget); - EXPECT_TRUE(widget->IsFullscreen()); - - // The controller's view is the widget's contents view. - views::View* view = controller->view_for_test(); - EXPECT_TRUE(view); - EXPECT_EQ(view, widget->GetContentsView()); -} - -TEST_F(GlanceablesControllerTest, DestroyUi) { - auto* controller = Shell::Get()->glanceables_controller(); - ASSERT_TRUE(controller); - - controller->CreateUi(); - controller->DestroyUi(); - - EXPECT_FALSE(controller->widget_for_test()); - EXPECT_FALSE(controller->view_for_test()); -} - -} // namespace -} // namespace ash
diff --git a/ash/glanceables/glanceables_unittests.cc b/ash/glanceables/glanceables_unittests.cc index 4ffbb03..bede21ea 100644 --- a/ash/glanceables/glanceables_unittests.cc +++ b/ash/glanceables/glanceables_unittests.cc
@@ -2,18 +2,33 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "ash/ambient/ambient_controller.h" +#include "ash/ambient/model/ambient_weather_model.h" #include "ash/constants/ash_features.h" #include "ash/glanceables/glanceables_controller.h" #include "ash/glanceables/glanceables_restore_view.h" +#include "ash/glanceables/glanceables_up_next_view.h" #include "ash/glanceables/glanceables_view.h" +#include "ash/glanceables/glanceables_weather_view.h" +#include "ash/glanceables/glanceables_welcome_label.h" #include "ash/glanceables/test_glanceables_delegate.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" #include "base/test/scoped_feature_list.h" #include "ui/events/test/test_event.h" +#include "ui/gfx/image/image_unittest_util.h" +#include "ui/views/controls/image_view.h" +#include "ui/views/controls/label.h" #include "ui/views/test/button_test_api.h" namespace ash { +namespace { + +AmbientWeatherModel* GetWeatherModel() { + return Shell::Get()->ambient_controller()->GetAmbientWeatherModel(); +} + +} // namespace // Unified test suite for the glanceables controller, views, etc. // @@ -30,12 +45,33 @@ void SetUp() override { NoSessionAshTestBase::SetUp(); controller_ = Shell::Get()->glanceables_controller(); + DCHECK(controller_); } TestGlanceablesDelegate* GetTestDelegate() { return static_cast<TestGlanceablesDelegate*>(controller_->delegate_.get()); } + views::Widget* GetWidget() { return controller_->widget_.get(); } + + GlanceablesView* GetGlanceablesView() { return controller_->view_; } + + GlanceablesWelcomeLabel* GetWelcomeLabel() { + return controller_->view_->welcome_label_; + } + + views::ImageView* GetWeatherIcon() { + return controller_->view_->weather_view_->icon_; + } + + views::Label* GetWeatherTemperature() { + return controller_->view_->weather_view_->temperature_; + } + + GlanceablesUpNextView* GetUpNextView() { + return controller_->view_->up_next_view_; + } + GlanceablesRestoreView* GetRestoreView() { return controller_->view_->restore_view_; } @@ -45,6 +81,71 @@ base::test::ScopedFeatureList feature_list_{features::kGlanceables}; }; +TEST_F(GlanceablesTest, CreateAndDestroyUi) { + controller_->CreateUi(); + + // A fullscreen widget was created. + views::Widget* widget = GetWidget(); + ASSERT_TRUE(widget); + EXPECT_TRUE(widget->IsFullscreen()); + + // The controller's view is the widget's contents view. + views::View* view = GetGlanceablesView(); + EXPECT_TRUE(view); + EXPECT_EQ(view, widget->GetContentsView()); + + controller_->DestroyUi(); + + // Widget and glanceables view are destroyed. + EXPECT_FALSE(GetWidget()); + EXPECT_FALSE(GetGlanceablesView()); +} + +TEST_F(GlanceablesTest, GlanceablesViewCreatesChildViews) { + controller_->CreateUi(); + + GlanceablesView* view = GetGlanceablesView(); + ASSERT_TRUE(view); + EXPECT_TRUE(GetWelcomeLabel()); + EXPECT_TRUE(GetWeatherIcon()); + EXPECT_TRUE(GetWeatherTemperature()); + EXPECT_TRUE(GetUpNextView()); + EXPECT_TRUE(GetRestoreView()); +} + +TEST_F(GlanceablesTest, WeatherViewShowsWeather) { + controller_->CreateUi(); + + // Icon starts blank. + views::ImageView* icon = GetWeatherIcon(); + EXPECT_TRUE(icon->GetImage().isNull()); + + // Trigger a weather update. Use an image the same size as the icon view's + // image so the image won't be resized and we can compare backing objects. + gfx::Rect image_bounds = icon->GetImageBounds(); + gfx::ImageSkia weather_image = + gfx::test::CreateImageSkia(image_bounds.width(), image_bounds.height()); + GetWeatherModel()->UpdateWeatherInfo(weather_image, 72.0f, + /*show_celsius=*/false); + + // The view reflects the new weather. + EXPECT_EQ(weather_image.GetBackingObject(), + icon->GetImage().GetBackingObject()); + EXPECT_EQ(u"72° F", GetWeatherTemperature()->GetText()); +} + +TEST_F(GlanceablesTest, UpNextViewRendersCorrectly) { + controller_->CreateUi(); + + // Events list contains rendered event items inside. + const auto& items = GetUpNextView()->events_list_items_views_for_test(); + EXPECT_EQ(items.size(), 5u); + for (const auto& item : items) { + EXPECT_EQ(std::get<0>(item)->GetText(), u"James / Artsiom"); + EXPECT_EQ(std::get<1>(item)->GetText(), u"2:00 – 2:30pm"); + } +} + TEST_F(GlanceablesTest, ClickOnSessionRestore) { controller_->CreateUi();
diff --git a/ash/glanceables/glanceables_up_next_view_unittest.cc b/ash/glanceables/glanceables_up_next_view_unittest.cc deleted file mode 100644 index 7bbb2ab..0000000 --- a/ash/glanceables/glanceables_up_next_view_unittest.cc +++ /dev/null
@@ -1,35 +0,0 @@ -// Copyright 2022 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/glanceables/glanceables_up_next_view.h" - -#include "ash/test/ash_test_base.h" -#include "ui/views/controls/label.h" - -namespace ash { -namespace { - -class GlanceablesUpNextViewTest : public NoSessionAshTestBase { - public: - void SetUp() override { - NoSessionAshTestBase::SetUp(); - up_next_view_ = std::make_unique<GlanceablesUpNextView>(); - } - - protected: - std::unique_ptr<GlanceablesUpNextView> up_next_view_; -}; - -TEST_F(GlanceablesUpNextViewTest, RendersCorrectly) { - // Events list contains rendered event items inside. - const auto& items = up_next_view_->events_list_items_views_for_test(); - EXPECT_EQ(items.size(), 5u); - for (const auto& item : items) { - EXPECT_EQ(std::get<0>(item)->GetText(), u"James / Artsiom"); - EXPECT_EQ(std::get<1>(item)->GetText(), u"2:00 – 2:30pm"); - } -} - -} // namespace -} // namespace ash
diff --git a/ash/glanceables/glanceables_view.h b/ash/glanceables/glanceables_view.h index f149d1e..9ea58a1 100644 --- a/ash/glanceables/glanceables_view.h +++ b/ash/glanceables/glanceables_view.h
@@ -32,10 +32,6 @@ void OnBoundsChanged(const gfx::Rect& previous_bounds) override; void OnThemeChanged() override; - GlanceablesWelcomeLabel* welcome_label_for_test() { return welcome_label_; } - GlanceablesWeatherView* weather_view_for_test() { return weather_view_; } - GlanceablesUpNextView* up_next_view_for_test() { return up_next_view_; } - private: friend class GlanceablesTest;
diff --git a/ash/glanceables/glanceables_view_unittest.cc b/ash/glanceables/glanceables_view_unittest.cc deleted file mode 100644 index d865f70..0000000 --- a/ash/glanceables/glanceables_view_unittest.cc +++ /dev/null
@@ -1,44 +0,0 @@ -// Copyright 2022 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/glanceables/glanceables_view.h" - -#include "ash/constants/ash_features.h" -#include "ash/glanceables/glanceables_controller.h" -#include "ash/glanceables/glanceables_welcome_label.h" -#include "ash/shell.h" -#include "ash/test/ash_test_base.h" -#include "base/test/scoped_feature_list.h" - -namespace ash { -namespace { - -// Use a "no session" test so the glanceables widget is not automatically -// created at the start of the test. -// TODO(crbug.com/1353119): Once glanceables are shown by code in the -// chrome/browser/ash layer, switch this to AshTestBase. -class GlanceablesViewTest : public NoSessionAshTestBase { - protected: - base::test::ScopedFeatureList feature_list_{features::kGlanceables}; -}; - -TEST_F(GlanceablesViewTest, Basics) { - GlanceablesController* controller = Shell::Get()->glanceables_controller(); - ASSERT_TRUE(controller); - controller->CreateUi(); - - GlanceablesView* view = controller->view_for_test(); - ASSERT_TRUE(view); - - // Welcome label was created. - GlanceablesWelcomeLabel* welcome_label = view->welcome_label_for_test(); - ASSERT_TRUE(welcome_label); - EXPECT_FALSE(welcome_label->GetText().empty()); - - // "Up next" widget was created. - EXPECT_TRUE(view->up_next_view_for_test()); -} - -} // namespace -} // namespace ash
diff --git a/ash/glanceables/glanceables_weather_view.h b/ash/glanceables/glanceables_weather_view.h index 9853543..3630ee53 100644 --- a/ash/glanceables/glanceables_weather_view.h +++ b/ash/glanceables/glanceables_weather_view.h
@@ -29,10 +29,9 @@ // AmbientWeatherModelObserver: void OnWeatherInfoUpdated() override; - views::ImageView* icon_for_test() { return icon_; } - views::Label* temperature_for_test() { return temperature_; } - private: + friend class GlanceablesTest; + views::ImageView* icon_ = nullptr; views::Label* temperature_ = nullptr; };
diff --git a/ash/glanceables/glanceables_weather_view_unittest.cc b/ash/glanceables/glanceables_weather_view_unittest.cc deleted file mode 100644 index e07e12b..0000000 --- a/ash/glanceables/glanceables_weather_view_unittest.cc +++ /dev/null
@@ -1,63 +0,0 @@ -// Copyright 2022 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/glanceables/glanceables_weather_view.h" - -#include "ash/ambient/ambient_controller.h" -#include "ash/ambient/model/ambient_weather_model.h" -#include "ash/constants/ash_features.h" -#include "ash/glanceables/glanceables_controller.h" -#include "ash/glanceables/glanceables_view.h" -#include "ash/shell.h" -#include "ash/test/ash_test_base.h" -#include "base/test/scoped_feature_list.h" -#include "ui/gfx/image/image_unittest_util.h" -#include "ui/views/controls/image_view.h" -#include "ui/views/controls/label.h" - -namespace ash { -namespace { - -AmbientWeatherModel* GetWeatherModel() { - return Shell::Get()->ambient_controller()->GetAmbientWeatherModel(); -} - -// Use a "no session" test so the glanceables widget is not automatically -// created at the start of the test. -// TODO(crbug.com/1353119): Once glanceables are shown by code in the -// chrome/browser/ash layer, switch this to AshTestBase. -class GlanceablesWeatherViewTest : public NoSessionAshTestBase { - protected: - base::test::ScopedFeatureList feature_list_{features::kGlanceables}; -}; - -TEST_F(GlanceablesWeatherViewTest, Basics) { - GlanceablesController* controller = Shell::Get()->glanceables_controller(); - ASSERT_TRUE(controller); - controller->CreateUi(); - - GlanceablesWeatherView* view = - controller->view_for_test()->weather_view_for_test(); - ASSERT_TRUE(view); - - // Icon starts blank. - views::ImageView* icon = view->icon_for_test(); - EXPECT_TRUE(icon->GetImage().isNull()); - - // Trigger a weather update. Use an image the same size as the icon view's - // image so the image won't be resized and we can compare backing objects. - gfx::Rect image_bounds = icon->GetImageBounds(); - gfx::ImageSkia weather_image = - gfx::test::CreateImageSkia(image_bounds.width(), image_bounds.height()); - GetWeatherModel()->UpdateWeatherInfo(weather_image, 72.0f, - /*show_celsius=*/false); - - // The view reflects the new weather. - EXPECT_EQ(weather_image.GetBackingObject(), - icon->GetImage().GetBackingObject()); - EXPECT_EQ(u"72° F", view->temperature_for_test()->GetText()); -} - -} // namespace -} // namespace ash
diff --git a/ash/glanceables/glanceables_welcome_label.cc b/ash/glanceables/glanceables_welcome_label.cc index 0b9387d1..2ffcf7f 100644 --- a/ash/glanceables/glanceables_welcome_label.cc +++ b/ash/glanceables/glanceables_welcome_label.cc
@@ -47,8 +47,7 @@ const auto account_id = session_controller->GetActiveAccountId(); if (account_id.empty()) { - // Prevents failures in `GlanceablesViewTest` and - // `GlanceablesControllerTest`. + // Prevents failures in `GlanceablesTest`. // TODO(crbug.com/1353119): Remove this after switching to `AshTestBase`. return u""; }
diff --git a/ash/glanceables/glanceables_welcome_label_unittest.cc b/ash/glanceables/glanceables_welcome_label_unittest.cc index 6fb0cae..c44efa5 100644 --- a/ash/glanceables/glanceables_welcome_label_unittest.cc +++ b/ash/glanceables/glanceables_welcome_label_unittest.cc
@@ -13,6 +13,10 @@ namespace ash { namespace { +// TODO(crbug.com/crbug.com/1353119): Move this to the GlanceablesTest suite +// after that suite switches to AshTestBase. These tests only pass because this +// suite is not enabling the Glanceables feature flag. When the flag is enabled +// the simulated login causes a weather fetch, which crashes. class GlanceablesWelcomeLabelTest : public NoSessionAshTestBase { public: void SetUp() override {
diff --git a/ash/quick_pair/repository/fast_pair/device_id_map.cc b/ash/quick_pair/repository/fast_pair/device_id_map.cc index dcbc116..717057c5 100644 --- a/ash/quick_pair/repository/fast_pair/device_id_map.cc +++ b/ash/quick_pair/repository/fast_pair/device_id_map.cc
@@ -24,10 +24,8 @@ registry->RegisterDictionaryPref(kDeviceIdMapPref); } -DeviceIdMap::DeviceIdMap() { - device::BluetoothAdapterFactory::Get()->GetAdapter(base::BindOnce( - &DeviceIdMap::OnGetAdapter, weak_ptr_factory_.GetWeakPtr())); -} +DeviceIdMap::DeviceIdMap(scoped_refptr<device::BluetoothAdapter> adapter) + : bluetooth_adapter_(adapter) {} DeviceIdMap::~DeviceIdMap() = default; @@ -182,11 +180,6 @@ } } -void DeviceIdMap::OnGetAdapter( - scoped_refptr<device::BluetoothAdapter> adapter) { - bluetooth_adapter_ = adapter; -} - absl::optional<const std::string> DeviceIdMap::GetDeviceIdForAddress( const std::string& address) { if (!bluetooth_adapter_) {
diff --git a/ash/quick_pair/repository/fast_pair/device_id_map.h b/ash/quick_pair/repository/fast_pair/device_id_map.h index 8a53ff9..595a9cf 100644 --- a/ash/quick_pair/repository/fast_pair/device_id_map.h +++ b/ash/quick_pair/repository/fast_pair/device_id_map.h
@@ -32,7 +32,7 @@ // Registers preferences used by this class in the provided |registry|. static void RegisterLocalStatePrefs(PrefRegistrySimple* registry); - DeviceIdMap(); + explicit DeviceIdMap(scoped_refptr<device::BluetoothAdapter> adapter); DeviceIdMap(const DeviceIdMap&) = delete; DeviceIdMap& operator=(const DeviceIdMap&) = delete; ~DeviceIdMap(); @@ -74,7 +74,6 @@ // Loads device ID -> model ID records persisted in prefs to // device_id_to_model_id_. void LoadPersistedRecordsFromPrefs(); - void OnGetAdapter(scoped_refptr<device::BluetoothAdapter> adapter); // Used to lazily load saved records from prefs. bool loaded_records_from_prefs_ = false;
diff --git a/ash/quick_pair/repository/fast_pair/device_id_map_unittest.cc b/ash/quick_pair/repository/fast_pair/device_id_map_unittest.cc index f20d7fb..c49a2d7b 100644 --- a/ash/quick_pair/repository/fast_pair/device_id_map_unittest.cc +++ b/ash/quick_pair/repository/fast_pair/device_id_map_unittest.cc
@@ -64,7 +64,7 @@ device_ = base::MakeRefCounted<Device>(kTestModelId, kTestBLEAddress, Protocol::kFastPairInitial); device_->set_classic_address(kTestClassicAddress); - device_id_map_ = std::make_unique<DeviceIdMap>(); + device_id_map_ = std::make_unique<DeviceIdMap>(adapter_); } protected: @@ -286,7 +286,7 @@ // A new/restarted DeviceIdMap instance should load persisted ID records // from prefs. - DeviceIdMap new_device_id_map; + DeviceIdMap new_device_id_map(adapter_); absl::optional<const std::string> model_id = new_device_id_map.GetModelIdForDeviceId(kTestBLEDeviceId); EXPECT_TRUE(model_id);
diff --git a/ash/quick_pair/repository/fast_pair/saved_device_registry.cc b/ash/quick_pair/repository/fast_pair/saved_device_registry.cc index 45d9c4c..31e62e2 100644 --- a/ash/quick_pair/repository/fast_pair/saved_device_registry.cc +++ b/ash/quick_pair/repository/fast_pair/saved_device_registry.cc
@@ -7,9 +7,12 @@ #include "ash/quick_pair/common/logging.h" #include "ash/quick_pair/common/quick_pair_browser_delegate.h" #include "base/base64.h" +#include "base/containers/contains.h" #include "components/prefs/pref_registry_simple.h" #include "components/prefs/pref_service.h" #include "components/prefs/scoped_user_pref_update.h" +#include "device/bluetooth//bluetooth_adapter.h" +#include "device/bluetooth/bluetooth_device.h" namespace { @@ -20,7 +23,10 @@ namespace ash { namespace quick_pair { -SavedDeviceRegistry::SavedDeviceRegistry() = default; +SavedDeviceRegistry::SavedDeviceRegistry( + scoped_refptr<device::BluetoothAdapter> adapter) + : adapter_(adapter) {} + SavedDeviceRegistry::~SavedDeviceRegistry() = default; void SavedDeviceRegistry::RegisterProfilePrefs(PrefRegistrySimple* registry) { @@ -120,9 +126,15 @@ return false; } + if (!has_updated_saved_devices_registry_) { + QP_LOG(INFO) << __func__ + << ": checking for changes to the registry by cross checking " + "the adapter before continuing"; + RemoveDevicesIfRemovedFromDifferentUser(pref_service); + } + const base::Value::Dict& saved_devices = pref_service->GetValueDict(kFastPairSavedDevicesPref); - std::string encoded_key = base::Base64Encode(account_key); for (const auto it : saved_devices) { const std::string* value = it.second.GetIfString(); @@ -134,5 +146,36 @@ return false; } +void SavedDeviceRegistry::RemoveDevicesIfRemovedFromDifferentUser( + PrefService* pref_service) { + DCHECK(pref_service); + + // Set of currently paired devices, stored by Bluetooth address, used to + // cross reference the registry for any devices that need to be removed. + std::set<std::string> paired_devices; + for (device::BluetoothDevice* device : adapter_->GetDevices()) { + if (device->IsPaired()) + paired_devices.insert(device->GetAddress()); + } + + // Iterate over the list of devices in the registry, and if there are any in + // the registry that are no longer paired to the adapter (determined by mac + // address), remove them from the registry. + const base::Value::Dict& saved_devices = + pref_service->GetValueDict(kFastPairSavedDevicesPref); + for (const auto it : saved_devices) { + const std::string& mac_address = it.first; + if (!base::Contains(paired_devices, mac_address)) { + DictionaryPrefUpdate update(pref_service, kFastPairSavedDevicesPref); + update->RemoveKey(it.first); + QP_LOG(VERBOSE) << __func__ + << ": removed device from registry at address= " + << mac_address; + } + } + + has_updated_saved_devices_registry_ = true; +} + } // namespace quick_pair } // namespace ash
diff --git a/ash/quick_pair/repository/fast_pair/saved_device_registry.h b/ash/quick_pair/repository/fast_pair/saved_device_registry.h index 7a2c438..4bcf287 100644 --- a/ash/quick_pair/repository/fast_pair/saved_device_registry.h +++ b/ash/quick_pair/repository/fast_pair/saved_device_registry.h
@@ -9,10 +9,16 @@ #include <string> #include <vector> +#include "base/memory/scoped_refptr.h" #include "base/values.h" #include "third_party/abseil-cpp/absl/types/optional.h" class PrefRegistrySimple; +class PrefService; + +namespace device { +class BluetoothAdapter; +} // namespace device namespace ash { namespace quick_pair { @@ -22,7 +28,7 @@ // as a lookup key, and user prefs for storage. class SavedDeviceRegistry { public: - SavedDeviceRegistry(); + explicit SavedDeviceRegistry(scoped_refptr<device::BluetoothAdapter> adapter); SavedDeviceRegistry(const SavedDeviceRegistry&) = delete; SavedDeviceRegistry& operator=(const SavedDeviceRegistry&) = delete; ~SavedDeviceRegistry(); @@ -49,6 +55,25 @@ // Checks if the account key is in the registry. bool IsAccountKeySavedToRegistry(const std::vector<uint8_t>& account_key); + + private: + // Cross check the list of devices in the registry with the devices paired + // to the BluetoothAdapter to see if any devices need to be removed from the + // registry if they are no longer paired to the adapter. This can happen if + // a primary user pairs and saves a device to their account, logs out, then a + // secondary user logs in, forgets the device from the Bluetooth pairing + // menu. When the primary user logs back in, we need to reflect the device is + // no longer paired locally in the registry. + void RemoveDevicesIfRemovedFromDifferentUser(PrefService* pref_service); + + // Flags cross checking the registry with the devices paired to the adapter + // to see if any devices need to be removed from the registry (see + // |RemoveDevicesIfRemovedFromDifferentUser|). This only needs to happen once + // per session, which is why it is flagged. Everything else following during + // the user session will be immediately reflected here. + bool has_updated_saved_devices_registry_ = false; + + scoped_refptr<device::BluetoothAdapter> adapter_; }; } // namespace quick_pair
diff --git a/ash/quick_pair/repository/fast_pair/saved_device_registry_unittest.cc b/ash/quick_pair/repository/fast_pair/saved_device_registry_unittest.cc index 07729761..237fa76 100644 --- a/ash/quick_pair/repository/fast_pair/saved_device_registry_unittest.cc +++ b/ash/quick_pair/repository/fast_pair/saved_device_registry_unittest.cc
@@ -9,6 +9,8 @@ #include "components/prefs/pref_service.h" #include "components/prefs/scoped_user_pref_update.h" #include "components/prefs/testing_pref_service.h" +#include "device/bluetooth/bluetooth_adapter_factory.h" +#include "device/bluetooth/test/mock_bluetooth_adapter.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -31,6 +33,26 @@ class SavedDeviceRegistryTest : public testing::Test { public: + SavedDeviceRegistryTest() + : adapter_(base::MakeRefCounted< + testing::NiceMock<device::MockBluetoothAdapter>>()), + bluetooth_device1_(/*adapter=*/adapter_.get(), + /*bluetooth_class=*/0, + /*name=*/"Test name 1", + /*address=*/kFirstSavedMacAddress, + /*initially_paired=*/true, + /*connected=*/true), + bluetooth_device2_(/*adapter=*/adapter_.get(), + /*bluetooth_class=*/0, + /*name=*/"Test name 1", + /*address=*/kSecondSavedMacAddress, + /*initially_paired=*/true, + /*connected=*/true) { + ON_CALL(bluetooth_device1_, IsPaired).WillByDefault(testing::Return(true)); + ON_CALL(bluetooth_device2_, IsPaired).WillByDefault(testing::Return(true)); + ON_CALL(*adapter_, GetDevices).WillByDefault(testing::Return(device_list_)); + } + void SetUp() override { pref_service_ = std::make_unique<TestingPrefServiceSimple>(); SavedDeviceRegistry::RegisterProfilePrefs(pref_service_->registry()); @@ -39,10 +61,17 @@ ON_CALL(*browser_delegate_, GetActivePrefService()) .WillByDefault(testing::Return(pref_service_.get())); - saved_device_registry_ = std::make_unique<SavedDeviceRegistry>(); + saved_device_registry_ = + std::make_unique<SavedDeviceRegistry>(adapter_); + device::BluetoothAdapterFactory::SetAdapterForTesting(adapter_); } protected: + scoped_refptr<testing::NiceMock<device::MockBluetoothAdapter>> adapter_; + testing::NiceMock<device::MockBluetoothDevice> bluetooth_device1_; + testing::NiceMock<device::MockBluetoothDevice> bluetooth_device2_; + device::BluetoothAdapter::ConstDeviceList device_list_{&bluetooth_device1_, + &bluetooth_device2_}; std::unique_ptr<MockQuickPairBrowserDelegate> browser_delegate_; std::unique_ptr<TestingPrefServiceSimple> pref_service_; std::unique_ptr<SavedDeviceRegistry> saved_device_registry_; @@ -165,5 +194,30 @@ EXPECT_FALSE(saved_device_registry_->DeleteAccountKey(kAccountKey1)); } +TEST_F(SavedDeviceRegistryTest, IsAccountKeySavedToRegistry_DeviceRemoved) { + // Simulate a user saving devices to their account. + saved_device_registry_->SaveAccountKey(kFirstSavedMacAddress, kAccountKey1); + saved_device_registry_->SaveAccountKey(kSecondSavedMacAddress, kAccountKey2); + + // Destroy the object to simulate a user's session ending. + saved_device_registry_.reset(); + + // Simulate a device being removed from the bluetooth adapter. This is meant + // to replicate the circumstances of a second user forgetting a device. + device::BluetoothAdapter::ConstDeviceList device_list{&bluetooth_device2_}; + ON_CALL(*adapter_, GetDevices()).WillByDefault(testing::Return(device_list)); + + // Create a new object to simulate a new user session. + saved_device_registry_ = + std::make_unique<SavedDeviceRegistry>(adapter_.get()); + + // We expect |kAccountKey1| to be removed from the registry since it is no + // longer paired. + EXPECT_FALSE( + saved_device_registry_->IsAccountKeySavedToRegistry(kAccountKey1)); + EXPECT_TRUE( + saved_device_registry_->IsAccountKeySavedToRegistry(kAccountKey2)); +} + } // namespace quick_pair } // namespace ash
diff --git a/ash/quick_pair/repository/fast_pair_repository_impl.cc b/ash/quick_pair/repository/fast_pair_repository_impl.cc index 2adf196..f7dd2d6 100644 --- a/ash/quick_pair/repository/fast_pair_repository_impl.cc +++ b/ash/quick_pair/repository/fast_pair_repository_impl.cc
@@ -22,21 +22,30 @@ #include "base/strings/string_number_conversions.h" #include "base/strings/stringprintf.h" #include "chromeos/services/bluetooth_config/public/cpp/device_image_info.h" +#include "device/bluetooth/bluetooth_adapter.h" +#include "device/bluetooth/bluetooth_adapter_factory.h" #include "device/bluetooth/bluetooth_device.h" namespace ash { namespace quick_pair { FastPairRepositoryImpl::FastPairRepositoryImpl() - : FastPairRepository(), - device_metadata_fetcher_(std::make_unique<DeviceMetadataFetcher>()), + : device_metadata_fetcher_(std::make_unique<DeviceMetadataFetcher>()), footprints_fetcher_(std::make_unique<FootprintsFetcherImpl>()), image_decoder_(std::make_unique<FastPairImageDecoderImpl>()), - device_id_map_(std::make_unique<DeviceIdMap>()), device_image_store_( std::make_unique<DeviceImageStore>(image_decoder_.get())), - saved_device_registry_(std::make_unique<SavedDeviceRegistry>()), - footprints_last_updated_(base::Time::UnixEpoch()) {} + footprints_last_updated_(base::Time::UnixEpoch()) { + device::BluetoothAdapterFactory::Get()->GetAdapter(base::BindOnce( + &FastPairRepositoryImpl::OnGetAdapter, weak_ptr_factory_.GetWeakPtr())); +} + +void FastPairRepositoryImpl::OnGetAdapter( + scoped_refptr<device::BluetoothAdapter> adapter) { + adapter_ = adapter; + device_id_map_ = std::make_unique<DeviceIdMap>(adapter_); + saved_device_registry_ = std::make_unique<SavedDeviceRegistry>(adapter_); +} FastPairRepositoryImpl::FastPairRepositoryImpl( std::unique_ptr<DeviceMetadataFetcher> device_metadata_fetcher,
diff --git a/ash/quick_pair/repository/fast_pair_repository_impl.h b/ash/quick_pair/repository/fast_pair_repository_impl.h index 3e7235a3..da52944 100644 --- a/ash/quick_pair/repository/fast_pair_repository_impl.h +++ b/ash/quick_pair/repository/fast_pair_repository_impl.h
@@ -10,6 +10,7 @@ #include "ash/quick_pair/repository/fast_pair_repository.h" #include "base/callback.h" #include "base/containers/flat_map.h" +#include "base/memory/scoped_refptr.h" #include "base/time/time.h" #include "third_party/abseil-cpp/absl/types/optional.h" @@ -20,6 +21,7 @@ } // namespace chromeos namespace device { +class BluetoothAdapter; class BluetoothDevice; } // namespace device @@ -132,6 +134,12 @@ GetSavedDevicesCallback callback, absl::optional<nearby::fastpair::UserReadDevicesResponse> user_devices); + // Internal method called by BluetoothAdapterFactory to provide the adapter + // object. + void OnGetAdapter(scoped_refptr<device::BluetoothAdapter> adapter); + + scoped_refptr<device::BluetoothAdapter> adapter_; + std::unique_ptr<DeviceMetadataFetcher> device_metadata_fetcher_; std::unique_ptr<FootprintsFetcher> footprints_fetcher_; std::unique_ptr<FastPairImageDecoder> image_decoder_;
diff --git a/ash/quick_pair/repository/fast_pair_repository_impl_unittest.cc b/ash/quick_pair/repository/fast_pair_repository_impl_unittest.cc index fd61a2e0..4b3da373 100644 --- a/ash/quick_pair/repository/fast_pair_repository_impl_unittest.cc +++ b/ash/quick_pair/repository/fast_pair_repository_impl_unittest.cc
@@ -41,9 +41,8 @@ constexpr char kInvalidModelId[] = "666"; constexpr char kTestModelId[] = "test_model_id"; constexpr char kTestDeviceId[] = "test_ble_device_id"; -constexpr char kTestBLEAddress[] = "test_ble_address"; -constexpr char kTestClassicAddress[] = "test_classic_address"; -constexpr char kFirstSavedMacAddress[] = "00:11:22:33:44"; +constexpr char kTestBLEAddress[] = "00:11:22:33:45"; +constexpr char kTestClassicAddress[] = "00:11:22:33:44"; const std::vector<uint8_t> kAccountKey1{0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}; @@ -85,6 +84,11 @@ .WillByDefault(Return(kTestDeviceId)); ON_CALL(classic_bluetooth_device_, GetIdentifier) .WillByDefault(Return(kTestDeviceId)); + ON_CALL(ble_bluetooth_device_, IsPaired) + .WillByDefault(testing::Return(true)); + ON_CALL(classic_bluetooth_device_, IsPaired) + .WillByDefault(testing::Return(true)); + ON_CALL(*adapter_, GetDevices).WillByDefault(testing::Return(device_list_)); ON_CALL(*adapter_, GetDevice(kTestBLEAddress)) .WillByDefault(Return(&ble_bluetooth_device_)); ON_CALL(*adapter_, GetDevice(kTestClassicAddress)) @@ -114,14 +118,15 @@ ON_CALL(*image_decoder_, DecodeImage(_, _, _)) .WillByDefault(RunOnceCallback<2>(test_image_)); - auto device_id_map = std::make_unique<DeviceIdMap>(); + auto device_id_map = std::make_unique<DeviceIdMap>(adapter_.get()); device_id_map_ = device_id_map.get(); auto device_image_store = std::make_unique<DeviceImageStore>(image_decoder_); device_image_store_ = device_image_store.get(); - auto saved_device_registry = std::make_unique<SavedDeviceRegistry>(); + auto saved_device_registry = + std::make_unique<SavedDeviceRegistry>(adapter_.get()); saved_device_registry_ = saved_device_registry.get(); fast_pair_repository_ = std::make_unique<FastPairRepositoryImpl>( @@ -180,6 +185,8 @@ scoped_refptr<testing::NiceMock<device::MockBluetoothAdapter>> adapter_; testing::NiceMock<device::MockBluetoothDevice> ble_bluetooth_device_; testing::NiceMock<device::MockBluetoothDevice> classic_bluetooth_device_; + device::BluetoothAdapter::ConstDeviceList device_list_{ + &ble_bluetooth_device_, &classic_bluetooth_device_}; scoped_refptr<Device> device_; gfx::Image test_image_; std::unique_ptr<TestingPrefServiceSimple> pref_service_; @@ -594,7 +601,7 @@ } TEST_F(FastPairRepositoryImplTest, IsAccountKeyPairedLocally) { - saved_device_registry_->SaveAccountKey(kFirstSavedMacAddress, kAccountKey1); + saved_device_registry_->SaveAccountKey(kTestClassicAddress, kAccountKey1); EXPECT_TRUE(fast_pair_repository_->IsAccountKeyPairedLocally(kAccountKey1)); EXPECT_FALSE(fast_pair_repository_->IsAccountKeyPairedLocally(kAccountKey2)); }
diff --git a/ash/webui/shortcut_customization_ui/resources/BUILD.gn b/ash/webui/shortcut_customization_ui/resources/BUILD.gn index 40e3af2..6123054 100644 --- a/ash/webui/shortcut_customization_ui/resources/BUILD.gn +++ b/ash/webui/shortcut_customization_ui/resources/BUILD.gn
@@ -23,12 +23,12 @@ ] web_component_files = [ - "accelerator_edit_dialog.js", + "accelerator_edit_dialog.ts", "accelerator_edit_view.js", "accelerator_row.js", "accelerator_subsection.js", "accelerator_view.js", - "input_key.js", + "input_key.ts", "shortcut_customization_app.js", "shortcut_input.js", "shortcuts_page.js", @@ -36,7 +36,11 @@ html_files = [] foreach(f, web_component_files) { - html_files += [ string_replace(f, ".js", ".html") ] + if (get_path_info(f, "extension") == "ts") { + html_files += [ string_replace(f, ".ts", ".html") ] + } else { + html_files += [ string_replace(f, ".js", ".html") ] + } } icons_html_files = [ "icons.html" ]
diff --git a/ash/webui/shortcut_customization_ui/resources/accelerator_edit_dialog.js b/ash/webui/shortcut_customization_ui/resources/accelerator_edit_dialog.js deleted file mode 100644 index 59cdcc9..0000000 --- a/ash/webui/shortcut_customization_ui/resources/accelerator_edit_dialog.js +++ /dev/null
@@ -1,158 +0,0 @@ -// Copyright 2021 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import './accelerator_edit_view.js'; -import './shortcut_customization_shared.css.js'; -import 'chrome://resources/cr_elements/cr_button/cr_button.js'; -import 'chrome://resources/cr_elements/cr_dialog/cr_dialog.js'; -import 'chrome://resources/cr_elements/cr_input/cr_input.js'; - -import {flush, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; - -import {getTemplate} from './accelerator_edit_dialog.html.js'; -import {ViewState} from './accelerator_view.js'; -import {AcceleratorInfo, AcceleratorSource} from './shortcut_types.js'; - -/** - * @fileoverview - * 'accelerator-edit-dialog' is a dialog that displays the accelerators for - * a given shortcut. Allows users to edit the accelerators. - * TODO(jimmyxgong): Implement editing accelerators. - */ -export class AcceleratorEditDialogElement extends PolymerElement { - static get is() { - return 'accelerator-edit-dialog'; - } - - static get properties() { - return { - description: { - type: String, - value: '', - }, - - /** @type {!Array<!AcceleratorInfo>} */ - acceleratorInfos: { - type: Array, - value: () => {}, - }, - - /** @private */ - pendingNewAcceleratorState_: { - type: Number, - value: ViewState.VIEW, - }, - - action: { - type: Number, - value: 0, - }, - - /** @type {!AcceleratorSource} */ - source: { - type: Number, - value: 0, - }, - - /** @protected */ - isAcceleratorCapturing_: { - type: Boolean, - value: false, - }, - }; - } - - /** @override */ - constructor() { - super(); - - /** - * Event callback for 'accelerator-capturing-started'. - * @private {!Function} - */ - this.onAcceleratorCapturingStarted_ = () => { - this.isAcceleratorCapturing_ = true; - }; - - /** - * Event callback for 'accelerator-capturing-ended'. - * @private {!Function} - */ - this.onAcceleratorCapturingEnded_ = () => { - this.isAcceleratorCapturing_ = false; - }; - } - - /** @override */ - connectedCallback() { - super.connectedCallback(); - this.$.editDialog.showModal(); - - window.addEventListener( - 'accelerator-capturing-started', this.onAcceleratorCapturingStarted_); - window.addEventListener( - 'accelerator-capturing-ended', this.onAcceleratorCapturingEnded_); - } - - /** @override */ - disconnectedCallback() { - super.disconnectedCallback(); - window.removeEventListener( - 'accelerator-capturing-started', this.onAcceleratorCapturingStarted_); - window.removeEventListener( - 'accelerator-capturing-ended', this.onAcceleratorCapturingEnded_); - } - - /** - * @param {!Array<AcceleratorInfo>} updatedAccels - */ - updateDialogAccelerators(updatedAccels) { - this.set('acceleratorInfos', []); - this.shadowRoot.querySelector('#viewList').render(); - this.acceleratorInfos = updatedAccels; - } - - /** @protected */ - onDoneButtonClicked_() { - this.$.editDialog.close(); - } - - /** @protected */ - onDialogClose_() { - this.dispatchEvent(new CustomEvent('edit-dialog-closed', - {bubbles: true, composed: true})); - } - - /** @protected */ - onAddAcceleratorClicked_() { - this.pendingNewAcceleratorState_ = ViewState.ADD; - - // Flush the dom so that the AcceleratorEditView is ready to be focused. - flush(); - const editView = this.$.editDialog.querySelector('#pendingAccelerator'); - const accelItem = editView.shadowRoot.querySelector('#acceleratorItem'); - accelItem.shadowRoot.querySelector('#container').focus(); - } - - /** - * @return {boolean} - * @protected - */ - showAddButton_() { - // If the state is VIEW, no new pending accelerators are being added. - return this.pendingNewAcceleratorState_ === ViewState.VIEW; - } - - /** @protected */ - onRestoreDefaultButtonClicked_() { - // TODO(jimmyxgong): Implement this function. - } - - static get template() { - return getTemplate(); - } -} - -customElements.define(AcceleratorEditDialogElement.is, - AcceleratorEditDialogElement);
diff --git a/ash/webui/shortcut_customization_ui/resources/accelerator_edit_dialog.ts b/ash/webui/shortcut_customization_ui/resources/accelerator_edit_dialog.ts new file mode 100644 index 0000000..891e82e3 --- /dev/null +++ b/ash/webui/shortcut_customization_ui/resources/accelerator_edit_dialog.ts
@@ -0,0 +1,177 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import './accelerator_edit_view.js'; +import './shortcut_customization_shared.css.js'; +import 'chrome://resources/cr_elements/cr_button/cr_button.js'; +import 'chrome://resources/cr_elements/cr_dialog/cr_dialog.js'; +import 'chrome://resources/cr_elements/cr_input/cr_input.js'; + +import {CrDialogElement} from 'chrome://resources/cr_elements/cr_dialog/cr_dialog.js'; +import {assert} from 'chrome://resources/js/assert_ts.js'; +import {DomRepeat, flush, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; + +import {getTemplate} from './accelerator_edit_dialog.html.js'; +import {ViewState} from './accelerator_view.js'; +import {AcceleratorInfo, AcceleratorSource} from './shortcut_types.js'; + +export interface AcceleratorEditDialogElement { + $: { + editDialog: CrDialogElement, + }; +} + +declare global { + interface HTMLElementEventMap { + 'accelerator-capturing-started': CustomEvent<void>; + 'accelerator-capturing-ended': CustomEvent<void>; + } +} + +/** + * @fileoverview + * 'accelerator-edit-dialog' is a dialog that displays the accelerators for + * a given shortcut. Allows users to edit the accelerators. + * TODO(jimmyxgong): Implement editing accelerators. + */ +export class AcceleratorEditDialogElement extends PolymerElement { + static get is() { + return 'accelerator-edit-dialog'; + } + + static get template() { + return getTemplate(); + } + + static get properties() { + return { + description: { + type: String, + value: '', + }, + + acceleratorInfos: { + type: Array, + value: () => {}, + }, + + pendingNewAcceleratorState_: { + type: Number, + value: ViewState.VIEW, + }, + + action: { + type: Number, + value: 0, + }, + + source: { + type: Number, + value: 0, + }, + + isAcceleratorCapturing_: { + type: Boolean, + value: false, + }, + }; + } + + description: string; + acceleratorInfos: AcceleratorInfo[]; + action: number; + source: AcceleratorSource; + protected isAcceleratorCapturing_: boolean; + private pendingNewAcceleratorState_: number; + private acceleratorCapturingStartedListener_ = () => + this.onAcceleratorCapturingStarted_(); + private acceleratorCapturingEndedListener_ = () => + this.onAcceleratorCapturingEnded_(); + + override connectedCallback() { + super.connectedCallback(); + this.$.editDialog.showModal(); + + window.addEventListener( + 'accelerator-capturing-started', + this.acceleratorCapturingStartedListener_); + window.addEventListener( + 'accelerator-capturing-ended', this.acceleratorCapturingEndedListener_); + } + + override disconnectedCallback() { + super.disconnectedCallback(); + window.removeEventListener( + 'accelerator-capturing-started', + this.acceleratorCapturingStartedListener_); + window.removeEventListener( + 'accelerator-capturing-ended', this.acceleratorCapturingEndedListener_); + } + + private getViewList_(): DomRepeat { + const viewList = this.shadowRoot!.querySelector('#viewList') as DomRepeat; + assert(viewList); + return viewList; + } + + updateDialogAccelerators(updatedAccels: AcceleratorInfo[]) { + this.set('acceleratorInfos', []); + this.getViewList_().render(); + this.acceleratorInfos = updatedAccels; + } + + protected onDoneButtonClicked_() { + this.$.editDialog.close(); + } + + protected onDialogClose_() { + this.dispatchEvent( + new CustomEvent('edit-dialog-closed', {bubbles: true, composed: true})); + } + + private onAcceleratorCapturingStarted_() { + this.isAcceleratorCapturing_ = true; + } + + private onAcceleratorCapturingEnded_() { + this.isAcceleratorCapturing_ = false; + } + + private focusAcceleratorItemContainer_() { + const editView = this.$.editDialog.querySelector('#pendingAccelerator'); + assert(editView); + const accelItem = editView.shadowRoot!.querySelector('#acceleratorItem'); + assert(accelItem); + const container = + accelItem.shadowRoot!.querySelector<HTMLElement>('#container'); + assert(container); + container!.focus(); + } + + protected onAddAcceleratorClicked_() { + this.pendingNewAcceleratorState_ = ViewState.ADD; + + // Flush the dom so that the AcceleratorEditView is ready to be focused. + flush(); + this.focusAcceleratorItemContainer_(); + } + + protected showAddButton_(): boolean { + // If the state is VIEW, no new pending accelerators are being added. + return this.pendingNewAcceleratorState_ === ViewState.VIEW; + } + + protected onRestoreDefaultButtonClicked_() { + // TODO(jimmyxgong): Implement this function. + } +} + +declare global { + interface HTMLElementTagNameMap { + 'accelerator-edit-dialog': AcceleratorEditDialogElement; + } +} + +customElements.define( + AcceleratorEditDialogElement.is, AcceleratorEditDialogElement);
diff --git a/ash/webui/shortcut_customization_ui/resources/input_key.js b/ash/webui/shortcut_customization_ui/resources/input_key.ts similarity index 84% rename from ash/webui/shortcut_customization_ui/resources/input_key.js rename to ash/webui/shortcut_customization_ui/resources/input_key.ts index f5aa434..11a0874 100644 --- a/ash/webui/shortcut_customization_ui/resources/input_key.js +++ b/ash/webui/shortcut_customization_ui/resources/input_key.ts
@@ -11,13 +11,12 @@ /** * Refers to the state of an 'input-key' item. - * @enum {string} */ -export const KeyInputState = { - NOT_SELECTED: 'not-selected', - MODIFIER_SELECTED: 'modifier-selected', - ALPHANUMERIC_SELECTED: 'alpha-numeric-selected', -}; +export enum KeyInputState { + NOT_SELECTED = 'not-selected', + MODIFIER_SELECTED = 'modifier-selected', + ALPHANUMERIC_SELECTED = 'alpha-numeric-selected', +} /** * @fileoverview @@ -44,6 +43,9 @@ }; } + key: string; + keyState: KeyInputState; + static get template() { return getTemplate(); }
diff --git a/ash/wm/desks/templates/saved_desk_grid_view.cc b/ash/wm/desks/templates/saved_desk_grid_view.cc index 4cd8e80..f75d991 100644 --- a/ash/wm/desks/templates/saved_desk_grid_view.cc +++ b/ash/wm/desks/templates/saved_desk_grid_view.cc
@@ -181,7 +181,7 @@ AnimateGridItems(new_grid_items); } -void SavedDeskGridView::DeleteTemplates(const std::vector<std::string>& uuids, +void SavedDeskGridView::DeleteTemplates(const std::vector<base::GUID>& uuids, bool delete_animation) { OverviewHighlightController* highlight_controller = Shell::Get() @@ -190,12 +190,11 @@ ->highlight_controller(); DCHECK(highlight_controller); - for (const std::string& uuid : uuids) { - auto iter = - std::find_if(grid_items_.begin(), grid_items_.end(), - [uuid](SavedDeskItemView* grid_item) { - return uuid == grid_item->uuid().AsLowercaseString(); - }); + for (const base::GUID& uuid : uuids) { + auto iter = std::find_if(grid_items_.begin(), grid_items_.end(), + [&uuid](SavedDeskItemView* grid_item) { + return uuid == grid_item->uuid(); + }); if (iter == grid_items_.end()) continue;
diff --git a/ash/wm/desks/templates/saved_desk_grid_view.h b/ash/wm/desks/templates/saved_desk_grid_view.h index c3f0abc..1bab0965 100644 --- a/ash/wm/desks/templates/saved_desk_grid_view.h +++ b/ash/wm/desks/templates/saved_desk_grid_view.h
@@ -61,7 +61,7 @@ // shuffle `grid_items_` to their final positions. If `delete_animation` is // false, then deleted items will simply disappear (shuffled items will still // animate). - void DeleteTemplates(const std::vector<std::string>& uuids, + void DeleteTemplates(const std::vector<base::GUID>& uuids, bool delete_animation); // Returns true if a template name is being modified using an item view's
diff --git a/ash/wm/desks/templates/saved_desk_item_view.cc b/ash/wm/desks/templates/saved_desk_item_view.cc index d1361a5..c0a13da 100644 --- a/ash/wm/desks/templates/saved_desk_item_view.cc +++ b/ash/wm/desks/templates/saved_desk_item_view.cc
@@ -339,12 +339,12 @@ saved_desk_util::GetSavedDeskDialogController()->ShowReplaceDialog( root_window, name_view_->GetText(), type, base::BindOnce(&SavedDeskItemView::ReplaceTemplate, - weak_ptr_factory_.GetWeakPtr(), uuid.AsLowercaseString()), + weak_ptr_factory_.GetWeakPtr(), uuid), base::BindOnce(&SavedDeskItemView::RevertTemplateName, weak_ptr_factory_.GetWeakPtr())); } -void SavedDeskItemView::ReplaceTemplate(const std::string& uuid) { +void SavedDeskItemView::ReplaceTemplate(const base::GUID& uuid) { // Make sure we delete the template we are replacing first, so that we don't // get template name collisions. Passing `nullopt` as `record_for_type` since // we only record the delete operation when the user specifically deletes an @@ -707,8 +707,8 @@ } void SavedDeskItemView::OnDeleteTemplate() { - saved_desk_util::GetSavedDeskPresenter()->DeleteEntry( - desk_template_->uuid().AsLowercaseString(), desk_template_->type()); + saved_desk_util::GetSavedDeskPresenter()->DeleteEntry(desk_template_->uuid(), + desk_template_->type()); } void SavedDeskItemView::OnDeleteButtonPressed() {
diff --git a/ash/wm/desks/templates/saved_desk_item_view.h b/ash/wm/desks/templates/saved_desk_item_view.h index b62d701..53fe80b 100644 --- a/ash/wm/desks/templates/saved_desk_item_view.h +++ b/ash/wm/desks/templates/saved_desk_item_view.h
@@ -98,7 +98,7 @@ const base::GUID& uuid); // Rename current saved desk with new name, delete old saved desk with same // name by uuid. Used for callback functions for Replace Dialog. - void ReplaceTemplate(const std::string& uuid); + void ReplaceTemplate(const base::GUID& uuid); void RevertTemplateName(); // This allows us to update an existing template view. Currently, this
diff --git a/ash/wm/desks/templates/saved_desk_library_view.cc b/ash/wm/desks/templates/saved_desk_library_view.cc index 97c545e..5c420e4a 100644 --- a/ash/wm/desks/templates/saved_desk_library_view.cc +++ b/ash/wm/desks/templates/saved_desk_library_view.cc
@@ -374,9 +374,8 @@ Layout(); } -void SavedDeskLibraryView::DeleteTemplates( - const std::vector<std::string>& uuids, - bool delete_animation) { +void SavedDeskLibraryView::DeleteTemplates(const std::vector<base::GUID>& uuids, + bool delete_animation) { if (desk_template_grid_view_) desk_template_grid_view_->DeleteTemplates(uuids, delete_animation); if (save_and_recall_grid_view_) @@ -432,7 +431,7 @@ .SetOpacity(item_layer, 0.0f); // Delete the existing saved desk item without animation. - DeleteTemplates({uuid.AsLowercaseString()}, /*delete_animation=*/false); + DeleteTemplates({uuid}, /*delete_animation=*/false); } void SavedDeskLibraryView::OnFeedbackButtonPressed() {
diff --git a/ash/wm/desks/templates/saved_desk_library_view.h b/ash/wm/desks/templates/saved_desk_library_view.h index e1c3f37..16b8d376 100644 --- a/ash/wm/desks/templates/saved_desk_library_view.h +++ b/ash/wm/desks/templates/saved_desk_library_view.h
@@ -64,7 +64,7 @@ // Delete all templates identified by `uuids`. If `delete_animation` is false, // then the respective item views will just disappear instead of fading out. - void DeleteTemplates(const std::vector<std::string>& uuids, + void DeleteTemplates(const std::vector<base::GUID>& uuids, bool delete_animation); // This performs the launch animation for Save & Recall. The `DeskItemView`
diff --git a/ash/wm/desks/templates/saved_desk_presenter.cc b/ash/wm/desks/templates/saved_desk_presenter.cc index cebb30f..920533f 100644 --- a/ash/wm/desks/templates/saved_desk_presenter.cc +++ b/ash/wm/desks/templates/saved_desk_presenter.cc
@@ -346,7 +346,7 @@ } void SavedDeskPresenter::DeleteEntry( - const std::string& uuid, + const base::GUID& uuid, absl::optional<DeskTemplateType> record_for_type) { weak_ptr_factory_.InvalidateWeakPtrs(); GetDeskModel()->DeleteEntry( @@ -450,7 +450,16 @@ void SavedDeskPresenter::EntriesRemovedRemotely( const std::vector<std::string>& uuids) { - RemoveUIEntries(uuids); + // TODO(crbug.com/1352667): We want the backend to provide this as + // vector<base::GUID>. Until it does, we'll convert manually here. + std::vector<base::GUID> typed_uuids; + for (const std::string& uuid_str : uuids) { + base::GUID uuid = base::GUID::ParseCaseInsensitive(uuid_str); + if (uuid.is_valid()) + typed_uuids.push_back(uuid); + } + + RemoveUIEntries(typed_uuids); } void SavedDeskPresenter::GetAllEntries(const base::GUID& item_to_focus, @@ -489,7 +498,7 @@ } void SavedDeskPresenter::OnDeleteEntry( - const std::string& uuid, + const base::GUID& uuid, absl::optional<DeskTemplateType> record_for_type, desks_storage::DeskModel::DeleteEntryStatus status) { if (status != desks_storage::DeskModel::DeleteEntryStatus::kOk) @@ -518,7 +527,7 @@ // store the template ID here since we're about to move the desk template. const auto saved_desk_type = saved_desk->type(); const auto saved_desk_creation_time = saved_desk->created_time(); - const std::string uuid = saved_desk->uuid().AsLowercaseString(); + const base::GUID uuid = saved_desk->uuid(); auto* overview_controller = Shell::Get()->overview_controller(); if (saved_desk_type == DeskTemplateType::kSaveAndRecall) { @@ -533,7 +542,7 @@ DCHECK(mini_view); SavedDeskLibraryView* library = overview_grid->GetSavedDeskLibraryView(); - library->AnimateDeskLaunch(saved_desk->uuid(), mini_view); + library->AnimateDeskLaunch(uuid, mini_view); } } @@ -696,8 +705,7 @@ std::move(on_update_ui_closure_for_testing_).Run(); } -void SavedDeskPresenter::RemoveUIEntries( - const std::vector<std::string>& uuids) { +void SavedDeskPresenter::RemoveUIEntries(const std::vector<base::GUID>& uuids) { if (uuids.empty()) return;
diff --git a/ash/wm/desks/templates/saved_desk_presenter.h b/ash/wm/desks/templates/saved_desk_presenter.h index 7c7e3f0c..c4e7070 100644 --- a/ash/wm/desks/templates/saved_desk_presenter.h +++ b/ash/wm/desks/templates/saved_desk_presenter.h
@@ -62,7 +62,7 @@ // Calls the DeskModel to delete the saved desk with the provided `uuid`. Will // record histogram if `record_for_type` is specified. - void DeleteEntry(const std::string& uuid, + void DeleteEntry(const base::GUID& uuid, absl::optional<DeskTemplateType> record_for_type); // Launches `saved_desk` into a new desk. `delay` is the time between each app @@ -104,7 +104,7 @@ // Callback after deleting an entry. Will then call `RemoveUIEntries` to // update the UI by removing the deleted saved desk. - void OnDeleteEntry(const std::string& uuid, + void OnDeleteEntry(const base::GUID& uuid, absl::optional<DeskTemplateType> record_for_type, desks_storage::DeskModel::DeleteEntryStatus status); @@ -120,7 +120,7 @@ // Helper functions for updating the UI. void AddOrUpdateUIEntries( const std::vector<const DeskTemplate*>& new_entries); - void RemoveUIEntries(const std::vector<std::string>& uuids); + void RemoveUIEntries(const std::vector<base::GUID>& uuids); // Returns a copy of a duplicated name to be stored. This function works by // taking the name to be duplicated and adding a "(1)" to it. If the name
diff --git a/ash/wm/desks/templates/saved_desk_unittest.cc b/ash/wm/desks/templates/saved_desk_unittest.cc index 67ee450..0a6ecf5 100644 --- a/ash/wm/desks/templates/saved_desk_unittest.cc +++ b/ash/wm/desks/templates/saved_desk_unittest.cc
@@ -177,11 +177,10 @@ void DeleteEntry(const base::GUID& uuid) { base::RunLoop loop; desk_model()->DeleteEntry( - uuid.AsLowercaseString(), - base::BindLambdaForTesting( - [&](desks_storage::DeskModel::DeleteEntryStatus status) { - loop.Quit(); - })); + uuid, base::BindLambdaForTesting( + [&](desks_storage::DeskModel::DeleteEntryStatus status) { + loop.Quit(); + })); loop.Run(); } @@ -3217,7 +3216,7 @@ auto* dialog_controller = saved_desk_util::GetSavedDeskDialogController(); auto callback = base::BindLambdaForTesting([&]() { item_view->name_view()->SetText(base::UTF8ToUTF16(name_1)); - item_view->ReplaceTemplate(uuid_1.AsLowercaseString()); + item_view->ReplaceTemplate(uuid_1); }); dialog_controller->ShowReplaceDialog(
diff --git a/ash/wm/tablet_mode/tablet_mode_multitask_menu.cc b/ash/wm/tablet_mode/tablet_mode_multitask_menu.cc index 05d3589..2c0a988 100644 --- a/ash/wm/tablet_mode/tablet_mode_multitask_menu.cc +++ b/ash/wm/tablet_mode/tablet_mode_multitask_menu.cc
@@ -8,6 +8,7 @@ #include "base/callback_forward.h" #include "chromeos/ui/frame/multitask_menu/multitask_menu_view.h" #include "ui/aura/window.h" +#include "ui/base/metadata/metadata_impl_macros.h" #include "ui/views/background.h" #include "ui/views/layout/box_layout.h" @@ -25,6 +26,8 @@ // The contents view of the multitask menu. class TabletModeMultitaskMenuView : public views::View { public: + METADATA_HEADER(TabletModeMultitaskMenuView); + TabletModeMultitaskMenuView(aura::Window* window, base::RepeatingClosure hide_menu) { SetBackground(views::CreateSolidBackground(SK_ColorWHITE)); @@ -50,6 +53,9 @@ ~TabletModeMultitaskMenuView() override = default; }; +BEGIN_METADATA(TabletModeMultitaskMenuView, View) +END_METADATA + TabletModeMultitaskMenu::TabletModeMultitaskMenu(aura::Window* window) : window_(window) { DCHECK(window_);
diff --git a/ash/wm/tablet_mode/tablet_mode_multitask_menu_event_handler.cc b/ash/wm/tablet_mode/tablet_mode_multitask_menu_event_handler.cc index 28307ba..39e6bab 100644 --- a/ash/wm/tablet_mode/tablet_mode_multitask_menu_event_handler.cc +++ b/ash/wm/tablet_mode/tablet_mode_multitask_menu_event_handler.cc
@@ -49,7 +49,8 @@ void TabletModeMultitaskMenuEventHandler::OnGestureEvent( ui::GestureEvent* event) { aura::Window* active_window = window_util::GetActiveWindow(); - if (!active_window || active_window != event->target() || + if (!active_window || + !active_window->Contains(static_cast<aura::Window*>(event->target())) || !WindowState::Get(active_window)->CanResize()) { return; }
diff --git a/build/android/pylib/local/emulator/avd.py b/build/android/pylib/local/emulator/avd.py index 76078fc..ae69c591 100644 --- a/build/android/pylib/local/emulator/avd.py +++ b/build/android/pylib/local/emulator/avd.py
@@ -16,6 +16,7 @@ from google.protobuf import text_format # pylint: disable=import-error +from devil.android import apk_helper from devil.android import device_utils from devil.android import settings from devil.android.sdk import adb_wrapper @@ -120,9 +121,13 @@ curr_min_sdk_version = entry['min_sdk'] if not min_sdk_found: - logging.error('No suitable apk file found that suits the minimum sdk.') + logging.error('No suitable apk file found that suits the minimum sdk %d.', + min_sdk) return None + logging.info('Found apk file for mininum sdk %d: %r with version %r', + min_sdk, min_sdk_found['file_name'], + min_sdk_found['version_name']) return os.path.join(apk_dir, min_sdk_found['file_name']) @@ -378,11 +383,14 @@ if not additional_apks: additional_apks = [] - for apk_package in self._config.additional_apk: - apk_dir = os.path.join(COMMON_CIPD_ROOT, apk_package.dest_path) - for f in os.listdir(apk_dir): - if os.path.isfile(f) and f.endswith('.apk'): - additional_apks.append(os.path.join(apk_dir, f)) + for pkg in self._config.additional_apk: + apk_dir = os.path.join(COMMON_CIPD_ROOT, pkg.dest_path) + apk_file = _FindMinSdkFile(apk_dir, self._config.min_sdk) + # Some of these files come from chrome internal, so may not be + # available to non-internal permissioned users. + if os.path.exists(apk_file): + logging.info('Adding additional apk for install: %s', apk_file) + additional_apks.append(apk_file) if not privileged_apk_tuples: privileged_apk_tuples = [] @@ -422,9 +430,18 @@ if additional_apks: for apk in additional_apks: instance.device.Install(apk, allow_downgrade=True, reinstall=True) + package_name = apk_helper.GetPackageName(apk) + package_version = instance.device.GetApplicationVersion(package_name) + logging.info('The version for package %r on the device is %r', + package_name, package_version) if privileged_apk_tuples: system_app.InstallPrivilegedApps(instance.device, privileged_apk_tuples) + for apk, _ in privileged_apk_tuples: + package_name = apk_helper.GetPackageName(apk) + package_version = instance.device.GetApplicationVersion(package_name) + logging.info('The version for package %r on the device is %r', + package_name, package_version) # Always disable the network to prevent built-in system apps from # updating themselves, which could take over package manager and
diff --git a/buildtools/deps_revisions.gni b/buildtools/deps_revisions.gni index a6bd91c..8181a9d 100644 --- a/buildtools/deps_revisions.gni +++ b/buildtools/deps_revisions.gni
@@ -5,5 +5,5 @@ declare_args() { # Used to cause full rebuilds on libc++ rolls. This should be kept in sync # with the libcxx_revision vars in //DEPS. - libcxx_revision = "db722166934ebc79a6e65e5fef9a6eae21eacb77" + libcxx_revision = "8b1c50618df7677fb1bd4bdf40d15a55b1733293" }
diff --git a/cc/trees/layer_tree_host_pixeltest_filters.cc b/cc/trees/layer_tree_host_pixeltest_filters.cc index 4bd1a34..6331433 100644 --- a/cc/trees/layer_tree_host_pixeltest_filters.cc +++ b/cc/trees/layer_tree_host_pixeltest_filters.cc
@@ -597,7 +597,7 @@ if (renderer_type() == viz::RendererType::kSkiaVk) { pixel_comparator_ = std::make_unique<FuzzyPixelOffByOneComparator>(false); } -#elif BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_CHROMEOS_ASH) || \ +#elif BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_CHROMEOS) || \ defined(_MIPS_ARCH_LOONGSON) || defined(ARCH_CPU_ARM64) #if BUILDFLAG(IS_WIN) // Windows has 153 pixels off by at most 2: crbug.com/225027 @@ -608,7 +608,7 @@ percentage_pixels_large_error = 0.415f; // 166px / (200*200) large_error_allowed = 1; } -#elif BUILDFLAG(IS_MAC) || BUILDFLAG(IS_CHROMEOS_ASH) +#elif BUILDFLAG(IS_MAC) || BUILDFLAG(IS_CHROMEOS) // There's a 1 pixel error on MacOS and ChromeOS float percentage_pixels_large_error = 0.0025f; // 1px / (200*200) int large_error_allowed = 1;
diff --git a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceConfiguration.java b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceConfiguration.java index fd79a9d..5c1a267 100644 --- a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceConfiguration.java +++ b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceConfiguration.java
@@ -29,27 +29,27 @@ private static final String TAG = "StartSurfaceConfig"; public static final StringCachedFieldTrialParameter START_SURFACE_VARIATION = new StringCachedFieldTrialParameter( - ChromeFeatureList.START_SURFACE_ANDROID, "start_surface_variation", ""); + ChromeFeatureList.START_SURFACE_ANDROID, "start_surface_variation", "single"); public static final BooleanCachedFieldTrialParameter START_SURFACE_EXCLUDE_MV_TILES = new BooleanCachedFieldTrialParameter( ChromeFeatureList.START_SURFACE_ANDROID, "exclude_mv_tiles", false); public static final BooleanCachedFieldTrialParameter START_SURFACE_HIDE_INCOGNITO_SWITCH_NO_TAB = new BooleanCachedFieldTrialParameter(ChromeFeatureList.START_SURFACE_ANDROID, - "hide_switch_when_no_incognito_tabs", false); + "hide_switch_when_no_incognito_tabs", true); public static final BooleanCachedFieldTrialParameter START_SURFACE_LAST_ACTIVE_TAB_ONLY = new BooleanCachedFieldTrialParameter( - ChromeFeatureList.START_SURFACE_ANDROID, "show_last_active_tab_only", false); + ChromeFeatureList.START_SURFACE_ANDROID, "show_last_active_tab_only", true); public static final BooleanCachedFieldTrialParameter START_SURFACE_OPEN_NTP_INSTEAD_OF_START = new BooleanCachedFieldTrialParameter( - ChromeFeatureList.START_SURFACE_ANDROID, "open_ntp_instead_of_start", false); + ChromeFeatureList.START_SURFACE_ANDROID, "open_ntp_instead_of_start", true); private static final String TAB_COUNT_BUTTON_ON_START_SURFACE_PARAM = "tab_count_button_on_start_surface"; public static final BooleanCachedFieldTrialParameter TAB_COUNT_BUTTON_ON_START_SURFACE = new BooleanCachedFieldTrialParameter(ChromeFeatureList.START_SURFACE_ANDROID, - TAB_COUNT_BUTTON_ON_START_SURFACE_PARAM, false); + TAB_COUNT_BUTTON_ON_START_SURFACE_PARAM, true); private static final String SHOW_TABS_IN_MRU_ORDER_PARAM = "show_tabs_in_mru_order"; public static final BooleanCachedFieldTrialParameter SHOW_TABS_IN_MRU_ORDER = @@ -101,21 +101,21 @@ private static final String SIGNIN_PROMO_NTP_COUNT_LIMIT_PARAM = "signin_promo_NTP_count_limit"; public static final IntCachedFieldTrialParameter SIGNIN_PROMO_NTP_COUNT_LIMIT = - new IntCachedFieldTrialParameter(ChromeFeatureList.START_SURFACE_ANDROID, - SIGNIN_PROMO_NTP_COUNT_LIMIT_PARAM, Integer.MAX_VALUE); + new IntCachedFieldTrialParameter( + ChromeFeatureList.START_SURFACE_ANDROID, SIGNIN_PROMO_NTP_COUNT_LIMIT_PARAM, 5); private static final String SIGNIN_PROMO_NTP_SINCE_FIRST_TIME_SHOWN_LIMIT_HOURS_PARAM = "signin_promo_NTP_since_first_time_shown_limit_hours"; public static final IntCachedFieldTrialParameter SIGNIN_PROMO_NTP_SINCE_FIRST_TIME_SHOWN_LIMIT_HOURS = new IntCachedFieldTrialParameter(ChromeFeatureList.START_SURFACE_ANDROID, - SIGNIN_PROMO_NTP_SINCE_FIRST_TIME_SHOWN_LIMIT_HOURS_PARAM, -1); + SIGNIN_PROMO_NTP_SINCE_FIRST_TIME_SHOWN_LIMIT_HOURS_PARAM, 336); private static final String SIGNIN_PROMO_NTP_RESET_AFTER_HOURS_PARAM = "signin_promo_NTP_reset_after_hours"; public static final IntCachedFieldTrialParameter SIGNIN_PROMO_NTP_RESET_AFTER_HOURS = new IntCachedFieldTrialParameter(ChromeFeatureList.START_SURFACE_ANDROID, - SIGNIN_PROMO_NTP_RESET_AFTER_HOURS_PARAM, -1); + SIGNIN_PROMO_NTP_RESET_AFTER_HOURS_PARAM, 672); private static final String IS_DOODLE_SUPPORTED_PARAM = "is_doodle_supported"; public static final BooleanCachedFieldTrialParameter IS_DOODLE_SUPPORTED =
diff --git a/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/InstantStartTabSwitcherTest.java b/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/InstantStartTabSwitcherTest.java index b846efa..dcb8aaf 100644 --- a/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/InstantStartTabSwitcherTest.java +++ b/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/InstantStartTabSwitcherTest.java
@@ -57,6 +57,7 @@ import org.chromium.base.test.util.CriteriaHelper; import org.chromium.base.test.util.DisableIf; import org.chromium.base.test.util.DisabledTest; +import org.chromium.base.test.util.DoNotBatch; import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.Restriction; import org.chromium.chrome.R; @@ -103,6 +104,7 @@ ChromeFeatureList.START_SURFACE_ANDROID + "<Study", ChromeFeatureList.INSTANT_START}) @Restriction({Restriction.RESTRICTION_TYPE_NON_LOW_END_DEVICE, UiRestriction.RESTRICTION_TYPE_PHONE}) +@DoNotBatch(reason = "This test suite tests startup behaviours and thus can't be batched.") public class InstantStartTabSwitcherTest { // clang-format on private static final String SHADOW_VIEW_TAG = "TabListViewShadow"; @@ -212,7 +214,7 @@ // clang-format off @EnableFeatures({ChromeFeatureList.TAB_GROUPS_ANDROID}) @CommandLineFlags.Add({ChromeSwitches.DISABLE_NATIVE_INITIALIZATION, - INSTANT_START_TEST_BASE_PARAMS}) + INSTANT_START_TEST_BASE_PARAMS + "/show_last_active_tab_only/false"}) @DisableIf.Build(message = "Flaky. See https://crbug.com/1091311", sdk_is_greater_than = Build.VERSION_CODES.O) public void renderTabGroups() throws IOException { @@ -264,7 +266,7 @@ // clang-format off @EnableFeatures({ChromeFeatureList.TAB_GROUPS_ANDROID}) @CommandLineFlags.Add({ChromeSwitches.DISABLE_NATIVE_INITIALIZATION, - INSTANT_START_TEST_BASE_PARAMS}) + INSTANT_START_TEST_BASE_PARAMS + "/show_last_active_tab_only/false"}) @DisableIf.Build(message = "Flaky. See https://crbug.com/1091311", sdk_is_greater_than = Build.VERSION_CODES.O) public void renderTabGroups_ThemeRefactor() throws IOException { @@ -303,7 +305,7 @@ @MediumTest // clang-format off @CommandLineFlags.Add({ChromeSwitches.DISABLE_NATIVE_INITIALIZATION, - INSTANT_START_TEST_BASE_PARAMS}) + INSTANT_START_TEST_BASE_PARAMS + "/show_last_active_tab_only/false"}) public void testSingleAsHomepage_CloseTabInCarouselTabSwitcher() throws IOException, ExecutionException { // clang-format on @@ -381,9 +383,10 @@ @Test @MediumTest - // clang-format off @CommandLineFlags.Add({ChromeSwitches.DISABLE_NATIVE_INITIALIZATION, - INSTANT_START_TEST_BASE_PARAMS}) + INSTANT_START_TEST_BASE_PARAMS + + "/show_last_active_tab_only/false/open_ntp_instead_of_start/false"}) + // clang-format off public void testSingleAsHomepage_Landscape_TabSize() { // clang-format on StartSurfaceTestUtils.startMainActivityFromLauncher(mActivityTestRule);
diff --git a/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/InstantStartTest.java b/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/InstantStartTest.java index 0278aa6..1dfadd5 100644 --- a/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/InstantStartTest.java +++ b/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/InstantStartTest.java
@@ -45,6 +45,7 @@ import org.chromium.base.test.util.Criteria; import org.chromium.base.test.util.CriteriaHelper; import org.chromium.base.test.util.DisabledTest; +import org.chromium.base.test.util.DoNotBatch; import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.Restriction; import org.chromium.build.BuildConfig; @@ -103,6 +104,7 @@ ChromeFeatureList.START_SURFACE_ANDROID, ChromeFeatureList.INSTANT_START}) @Restriction({Restriction.RESTRICTION_TYPE_NON_LOW_END_DEVICE, UiRestriction.RESTRICTION_TYPE_PHONE}) +@DoNotBatch(reason = "InstantStartTest tests startup behaviours and thus can't be batched.") public class InstantStartTest { // clang-format on private static final String IMMEDIATE_RETURN_PARAMS = "force-fieldtrial-params=Study.Group:" @@ -486,7 +488,8 @@ public void testShowLastTabWhenHomepageDisabledNoImmediateReturn() throws IOException { // clang-format on Assert.assertTrue(ChromeFeatureList.sInstantStart.isEnabled()); - Assert.assertEquals(-1, ReturnToChromeUtil.TAB_SWITCHER_ON_RETURN_MS.getValue()); + Assert.assertEquals(ReturnToChromeUtil.TAB_SWITCHER_ON_RETURN_MS.getDefaultValue(), + ReturnToChromeUtil.TAB_SWITCHER_ON_RETURN_MS.getValue()); TestThreadUtils.runOnUiThreadBlocking( () -> HomepageManager.getInstance().setPrefHomepageEnabled(false)); @@ -506,7 +509,8 @@ throws IOException { // clang-format on Assert.assertFalse(ChromeFeatureList.sInstantStart.isEnabled()); - Assert.assertEquals(-1, ReturnToChromeUtil.TAB_SWITCHER_ON_RETURN_MS.getValue()); + Assert.assertEquals(ReturnToChromeUtil.TAB_SWITCHER_ON_RETURN_MS.getDefaultValue(), + ReturnToChromeUtil.TAB_SWITCHER_ON_RETURN_MS.getValue()); TestThreadUtils.runOnUiThreadBlocking( () -> HomepageManager.getInstance().setPrefHomepageEnabled(false));
diff --git a/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceBackButtonTest.java b/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceBackButtonTest.java index 085c7e5a..fc7a63f 100644 --- a/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceBackButtonTest.java +++ b/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceBackButtonTest.java
@@ -13,6 +13,7 @@ import static org.hamcrest.CoreMatchers.allOf; import static org.chromium.chrome.features.start_surface.StartSurfaceTestUtils.START_SURFACE_TEST_BASE_PARAMS; +import static org.chromium.chrome.features.start_surface.StartSurfaceTestUtils.START_SURFACE_TEST_SINGLE_ENABLED_PARAMS; import static org.chromium.chrome.features.start_surface.StartSurfaceTestUtils.sClassParamsForStartSurfaceTest; import static org.chromium.ui.test.util.ViewUtils.onViewWaiting; import static org.chromium.ui.test.util.ViewUtils.waitForView; @@ -155,7 +156,7 @@ @Test @MediumTest @Feature({"StartSurface"}) - @CommandLineFlags.Add({START_SURFACE_TEST_BASE_PARAMS}) + @CommandLineFlags.Add({START_SURFACE_TEST_SINGLE_ENABLED_PARAMS}) public void testShow_SingleAsHomepage_BackButton() { if (!mImmediateReturn) { StartSurfaceTestUtils.pressHomePageButton(mActivityTestRule.getActivity()); @@ -197,7 +198,7 @@ @MediumTest @Feature({"StartSurface"}) // clang-format off - @CommandLineFlags.Add({START_SURFACE_TEST_BASE_PARAMS}) + @CommandLineFlags.Add({START_SURFACE_TEST_SINGLE_ENABLED_PARAMS}) @DisableIf. Build(sdk_is_less_than = Build.VERSION_CODES.N, message = "Flaky, see crbug.com/1246457") public void testShow_SingleAsHomepage_BackButtonWithTabSwitcher() { @@ -209,7 +210,7 @@ @MediumTest @Feature({"StartSurface"}) // clang-format off - @CommandLineFlags.Add({START_SURFACE_TEST_BASE_PARAMS + "/show_last_active_tab_only/true"}) + @CommandLineFlags.Add({START_SURFACE_TEST_BASE_PARAMS + "open_ntp_instead_of_start/false"}) @DisableIf. Build(sdk_is_less_than = Build.VERSION_CODES.N, message = "Flaky, see crbug.com/1246457") public void testShow_SingleAsHomepageV2_BackButtonWithTabSwitcher() { @@ -280,7 +281,7 @@ @Test @MediumTest @Feature({"StartSurface"}) - @CommandLineFlags.Add({START_SURFACE_TEST_BASE_PARAMS}) + @CommandLineFlags.Add({START_SURFACE_TEST_SINGLE_ENABLED_PARAMS}) public void testOpenRecentTabOnStartAndTapBackButtonReturnToStartSurface() throws ExecutionException { ChromeTabbedActivity cta = mActivityTestRule.getActivity(); @@ -310,9 +311,8 @@ @Test @MediumTest @Feature({"StartSurface"}) + @CommandLineFlags.Add({START_SURFACE_TEST_BASE_PARAMS + "open_ntp_instead_of_start/false"}) // clang-format off - @CommandLineFlags.Add({START_SURFACE_TEST_BASE_PARAMS - + "/show_last_active_tab_only/true/tab_count_button_on_start_surface/true"}) public void testUserActionLoggedWhenBackToStartSurfaceHomePage() throws ExecutionException { // clang-format on ChromeTabbedActivity cta = mActivityTestRule.getActivity(); @@ -339,7 +339,7 @@ @MediumTest @Feature({"StartSurface"}) // clang-format off - @CommandLineFlags.Add({START_SURFACE_TEST_BASE_PARAMS}) + @CommandLineFlags.Add({START_SURFACE_TEST_SINGLE_ENABLED_PARAMS}) @DisabledTest(message = "https://crbug.com/1246457") @DisableFeatures({ChromeFeatureList.BACK_GESTURE_REFACTOR}) public void testSwipeBackOnStartSurfaceHomePage() throws ExecutionException { @@ -350,7 +350,7 @@ @Test @MediumTest @Feature({"StartSurface"}) - @CommandLineFlags.Add({START_SURFACE_TEST_BASE_PARAMS}) + @CommandLineFlags.Add({START_SURFACE_TEST_SINGLE_ENABLED_PARAMS}) @DisabledTest(message = "https://crbug.com/1246457") @EnableFeatures({ChromeFeatureList.BACK_GESTURE_REFACTOR}) public void testSwipeBackOnStartSurfaceHomePage_BackGestureRefactor() @@ -361,7 +361,7 @@ @Test @MediumTest @Feature({"StartSurface"}) - @CommandLineFlags.Add({START_SURFACE_TEST_BASE_PARAMS}) + @CommandLineFlags.Add({START_SURFACE_TEST_SINGLE_ENABLED_PARAMS}) @DisabledTest(message = "https://crbug.com/1246457") public void testSwipeBackOnTabOfLaunchTypeStartSurface() throws ExecutionException { ChromeTabbedActivity cta = mActivityTestRule.getActivity(); @@ -384,7 +384,7 @@ @Test @MediumTest @Feature({"StartSurface"}) - @CommandLineFlags.Add({START_SURFACE_TEST_BASE_PARAMS}) + @CommandLineFlags.Add({START_SURFACE_TEST_SINGLE_ENABLED_PARAMS}) public void testBackButtonOnIncognitoTabOpenedFromStart() throws ExecutionException { // This is a test for crbug.com/1315915 to make sure when clicking back button on the // incognito tab opened from Start, the non-incognito homepage should show.
diff --git a/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceMVTilesTest.java b/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceMVTilesTest.java index 15fe2ef..871d8cd1 100644 --- a/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceMVTilesTest.java +++ b/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceMVTilesTest.java
@@ -11,7 +11,7 @@ import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.MatcherAssert.assertThat; -import static org.chromium.chrome.features.start_surface.StartSurfaceTestUtils.START_SURFACE_TEST_BASE_PARAMS; +import static org.chromium.chrome.features.start_surface.StartSurfaceTestUtils.START_SURFACE_TEST_SINGLE_ENABLED_PARAMS; import static org.chromium.chrome.features.start_surface.StartSurfaceTestUtils.sClassParamsForStartSurfaceTest; import static org.chromium.ui.test.util.ViewUtils.onViewWaiting; @@ -150,7 +150,7 @@ @Test @MediumTest @Feature({"StartSurface"}) - @CommandLineFlags.Add({START_SURFACE_TEST_BASE_PARAMS}) + @CommandLineFlags.Add({START_SURFACE_TEST_SINGLE_ENABLED_PARAMS}) public void testTapMVTilesInSingleSurface() { if (!mImmediateReturn) { StartSurfaceTestUtils.pressHomePageButton(mActivityTestRule.getActivity()); @@ -176,7 +176,7 @@ @Feature({"StartSurface"}) // Disable feed placeholder animation because it causes waitForSnackbar() to time out. @CommandLineFlags. - Add({START_SURFACE_TEST_BASE_PARAMS, FeedPlaceholderLayout.DISABLE_ANIMATION_SWITCH}) + Add({START_SURFACE_TEST_SINGLE_ENABLED_PARAMS, FeedPlaceholderLayout.DISABLE_ANIMATION_SWITCH}) public void testDismissTileWithContextMenuAndUndo() throws Exception { if (!mImmediateReturn) { StartSurfaceTestUtils.pressHomePageButton(mActivityTestRule.getActivity()); @@ -208,7 +208,7 @@ @Test @MediumTest @Feature({"StartSurface"}) - @CommandLineFlags.Add({START_SURFACE_TEST_BASE_PARAMS}) + @CommandLineFlags.Add({START_SURFACE_TEST_SINGLE_ENABLED_PARAMS}) public void testOpenTileInNewTabWithContextMenu() throws ExecutionException { if (!mImmediateReturn) { StartSurfaceTestUtils.pressHomePageButton(mActivityTestRule.getActivity()); @@ -232,7 +232,7 @@ @Test @MediumTest @Feature({"StartSurface"}) - @CommandLineFlags.Add({START_SURFACE_TEST_BASE_PARAMS}) + @CommandLineFlags.Add({START_SURFACE_TEST_SINGLE_ENABLED_PARAMS}) public void testOpenTileInIncognitoTabWithContextMenu() throws ExecutionException { Assume.assumeFalse("https://crbug.com/1210554", mUseInstantStart && mImmediateReturn); if (!mImmediateReturn) {
diff --git a/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceNoTabsTest.java b/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceNoTabsTest.java index e01cfa46..cc835071 100644 --- a/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceNoTabsTest.java +++ b/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceNoTabsTest.java
@@ -81,8 +81,7 @@ new ParameterSet().value(false, true).name("NoInstant_Return"), new ParameterSet().value(true, true).name("Instant_Return")); - private static final String BASE_PARAMS = - "force-fieldtrial-params=Study.Group:start_surface_variation"; + private static final String BASE_PARAMS = "force-fieldtrial-params=Study.Group:"; @Rule public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule(); @@ -124,7 +123,7 @@ @LargeTest @Feature({"StartSurface"}) // clang-format off - @CommandLineFlags.Add({BASE_PARAMS + "/single/tab_count_button_on_start_surface/true"}) + @CommandLineFlags.Add({BASE_PARAMS + "tab_count_button_on_start_surface/true"}) @DisabledTest(message = "https://crbug.com/1263910") public void testShow_SingleAsHomepage_NoTabs() throws TimeoutException { // clang-format on @@ -156,8 +155,7 @@ @MediumTest @Feature({"StartSurface"}) // clang-format off - @CommandLineFlags.Add({BASE_PARAMS + "/single/exclude_mv_tiles/true" + - "/show_last_active_tab_only/true/open_ntp_instead_of_start/true"}) + @CommandLineFlags.Add({BASE_PARAMS + "exclude_mv_tiles/true"}) @DisabledTest(message = "https://crbug.com/1263910") public void testShow_SingleAsHomepage_SingleTabSwitcher_NoTabs() { // clang-format on
diff --git a/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTabSwitcherTest.java b/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTabSwitcherTest.java index 6a60a3d..8dd9dca 100644 --- a/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTabSwitcherTest.java +++ b/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTabSwitcherTest.java
@@ -20,6 +20,7 @@ import static org.chromium.chrome.browser.feed.FeedPlaceholderLayout.DISABLE_ANIMATION_SWITCH; import static org.chromium.chrome.features.start_surface.StartSurfaceTestUtils.START_SURFACE_TEST_BASE_PARAMS; +import static org.chromium.chrome.features.start_surface.StartSurfaceTestUtils.START_SURFACE_TEST_SINGLE_ENABLED_PARAMS; import static org.chromium.chrome.features.start_surface.StartSurfaceTestUtils.sClassParamsForStartSurfaceTest; import static org.chromium.ui.test.util.ViewUtils.onViewWaiting; import static org.chromium.ui.test.util.ViewUtils.waitForView; @@ -145,7 +146,7 @@ @Test @MediumTest @Feature({"StartSurface"}) - @CommandLineFlags.Add({START_SURFACE_TEST_BASE_PARAMS}) + @CommandLineFlags.Add({START_SURFACE_TEST_SINGLE_ENABLED_PARAMS}) public void testShow_SingleAsTabSwitcher() { if (mImmediateReturn) { StartSurfaceTestUtils.waitForOverviewVisible(mLayoutChangedCallbackHelper, @@ -174,7 +175,7 @@ @Test @MediumTest @Feature({"StartSurface"}) - @CommandLineFlags.Add({START_SURFACE_TEST_BASE_PARAMS}) + @CommandLineFlags.Add({START_SURFACE_TEST_SINGLE_ENABLED_PARAMS}) public void testShow_SingleAsHomepage_CloseAllTabsShouldHideTabSwitcher() { if (!mImmediateReturn) { StartSurfaceTestUtils.pressHomePageButton(mActivityTestRule.getActivity()); @@ -195,7 +196,7 @@ @Test @MediumTest @Feature({"StartSurface", "TabGroup"}) - @CommandLineFlags.Add({START_SURFACE_TEST_BASE_PARAMS}) + @CommandLineFlags.Add({START_SURFACE_TEST_SINGLE_ENABLED_PARAMS}) @EnableFeatures({ChromeFeatureList.TAB_GROUPS_ANDROID}) @FlakyTest(message = "https://crbug.com/1232695") public void testCreateTabWithinTabGroup() throws Exception { @@ -263,7 +264,8 @@ @LargeTest @Feature({"StartSurface"}) @FlakyTest(message = "https://crbug.com/1295839") - @CommandLineFlags.Add({START_SURFACE_TEST_BASE_PARAMS + "/show_tabs_in_mru_order/true"}) + @CommandLineFlags. + Add({START_SURFACE_TEST_SINGLE_ENABLED_PARAMS + "/show_tabs_in_mru_order/true"}) public void test_CarouselTabSwitcherShowTabsInMRUOrder() { if (!mImmediateReturn) { StartSurfaceTestUtils.pressHomePageButton(mActivityTestRule.getActivity()); @@ -307,7 +309,8 @@ @Test @LargeTest @Feature({"StartSurface"}) - @CommandLineFlags.Add({START_SURFACE_TEST_BASE_PARAMS + "/show_tabs_in_mru_order/true"}) + @CommandLineFlags. + Add({START_SURFACE_TEST_SINGLE_ENABLED_PARAMS + "/show_tabs_in_mru_order/true"}) public void testShow_GridTabSwitcher_AlwaysShowTabsInCreationOrder() { tabSwitcher_AlwaysShowTabsInGridTabSwitcherInCreationOrderImpl(); } @@ -317,8 +320,8 @@ @Feature({"StartSurface"}) @EnableFeatures(ChromeFeatureList.TAB_GROUPS_ANDROID) // clang-format off - @CommandLineFlags.Add({START_SURFACE_TEST_BASE_PARAMS + - "/show_tabs_in_mru_order/true/show_last_active_tab_only/true", + @CommandLineFlags.Add({START_SURFACE_TEST_BASE_PARAMS + + "show_tabs_in_mru_order/true/open_ntp_instead_of_start/false", DISABLE_ANIMATION_SWITCH}) public void testShowV2_GridTabSwitcher_AlwaysShowTabsInCreationOrder() { // clang-format on
diff --git a/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTest.java b/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTest.java index bd9bed3..e6026393 100644 --- a/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTest.java +++ b/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTest.java
@@ -28,6 +28,7 @@ import static org.chromium.chrome.features.start_surface.StartSurfaceMediator.FEED_VISIBILITY_CONSISTENCY; import static org.chromium.chrome.features.start_surface.StartSurfaceTestUtils.START_SURFACE_TEST_BASE_PARAMS; +import static org.chromium.chrome.features.start_surface.StartSurfaceTestUtils.START_SURFACE_TEST_SINGLE_ENABLED_PARAMS; import static org.chromium.chrome.features.start_surface.StartSurfaceTestUtils.sClassParamsForStartSurfaceTest; import static org.chromium.ui.test.util.ViewUtils.onViewWaiting; import static org.chromium.ui.test.util.ViewUtils.waitForStableView; @@ -179,7 +180,7 @@ @Test @MediumTest @Feature({"StartSurface"}) - @CommandLineFlags.Add({START_SURFACE_TEST_BASE_PARAMS}) + @CommandLineFlags.Add({START_SURFACE_TEST_SINGLE_ENABLED_PARAMS}) public void testShow_SingleAsHomepage() { if (!mImmediateReturn) { StartSurfaceTestUtils.pressHomePageButton(mActivityTestRule.getActivity()); @@ -210,7 +211,8 @@ @Test @MediumTest @Feature({"StartSurface"}) - @CommandLineFlags.Add({START_SURFACE_TEST_BASE_PARAMS}) + @CommandLineFlags. + Add({START_SURFACE_TEST_SINGLE_ENABLED_PARAMS + "/hide_switch_when_no_incognito_tabs/false"}) public void testShow_SingleAsHomepage_NoIncognitoSwitch() { if (!mImmediateReturn) { StartSurfaceTestUtils.pressHomePageButton(mActivityTestRule.getActivity()); @@ -256,9 +258,10 @@ @Test @LargeTest @Feature({"StartSurface"}) + @CommandLineFlags. + Add({START_SURFACE_TEST_BASE_PARAMS + "exclude_mv_tiles/true/show_last_active_tab_only/false" + + "/open_ntp_instead_of_start/false/tab_count_button_on_start_surface/false"}) // clang-format off - @CommandLineFlags.Add({START_SURFACE_TEST_BASE_PARAMS + - "/exclude_mv_tiles/true/hide_switch_when_no_incognito_tabs/true"}) public void testShow_SingleAsHomepage_NoMVTiles() { // clang-format on if (!mImmediateReturn) { @@ -302,9 +305,9 @@ @Test @LargeTest @Feature({"StartSurface"}) + @CommandLineFlags. + Add({START_SURFACE_TEST_BASE_PARAMS + "exclude_mv_tiles/true/open_ntp_instead_of_start/false"}) // clang-format off - @CommandLineFlags.Add({START_SURFACE_TEST_BASE_PARAMS + "/exclude_mv_tiles/true" + - "/hide_switch_when_no_incognito_tabs/true/show_last_active_tab_only/true"}) public void testShow_SingleAsHomepage_SingleTabNoMVTiles() { // clang-format on Assume.assumeFalse("https://crbug.com/1205642, https://crbug.com/1214303", @@ -350,7 +353,7 @@ @MediumTest @Feature({"StartSurface"}) // clang-format off - @CommandLineFlags.Add({START_SURFACE_TEST_BASE_PARAMS}) + @CommandLineFlags.Add({START_SURFACE_TEST_SINGLE_ENABLED_PARAMS}) @DisableIf. Build(sdk_is_less_than = Build.VERSION_CODES.N, message = "Flaky, see crbug.com/1246457") public void testShow_SingleAsHomepage_FromResumeShowStart() throws Exception { @@ -395,7 +398,7 @@ @Test @MediumTest @Feature({"StartSurface"}) - @CommandLineFlags.Add({START_SURFACE_TEST_BASE_PARAMS}) + @CommandLineFlags.Add({START_SURFACE_TEST_SINGLE_ENABLED_PARAMS}) @DisabledTest(message = "crbug.com/1170673 - NoInstant_NoReturn version is flaky") public void testSearchInSingleSurface() { if (!mImmediateReturn) { @@ -429,7 +432,8 @@ @Test @MediumTest @Feature({"StartSurface"}) - @CommandLineFlags.Add({START_SURFACE_TEST_BASE_PARAMS + "/open_ntp_instead_of_start/true"}) + @CommandLineFlags. + Add({START_SURFACE_TEST_BASE_PARAMS + "hide_switch_when_no_incognito_tabs/false"}) public void testCreateNewTab_OpenNTPInsteadOfStart() { ChromeTabbedActivity cta = mActivityTestRule.getActivity(); StartSurfaceTestUtils.waitForTabModel(cta); @@ -458,7 +462,6 @@ @Test @MediumTest @Feature({"StartSurface"}) - @CommandLineFlags.Add({START_SURFACE_TEST_BASE_PARAMS + "/open_ntp_instead_of_start/true"}) public void testHomeButton_OpenNTPInsteadOfStart() { ChromeTabbedActivity cta = mActivityTestRule.getActivity(); StartSurfaceTestUtils.waitForTabModel(cta); @@ -493,15 +496,15 @@ @Test @MediumTest @Restriction({UiRestriction.RESTRICTION_TYPE_PHONE}) - // clang-format off + @EnableFeatures({ChromeFeatureList.TAB_SWITCHER_ON_RETURN + "<Study", ChromeFeatureList.TAB_GRID_LAYOUT_ANDROID, ChromeFeatureList.START_SURFACE_ANDROID + "<Study"}) - @CommandLineFlags.Add({ - START_SURFACE_TEST_BASE_PARAMS + "/show_last_active_tab_only/true", + @CommandLineFlags.Add({START_SURFACE_TEST_BASE_PARAMS + "open_ntp_instead_of_start/false", // Disable feed placeholder animation because it causes waitForDeferredStartup() to time // out. FeedPlaceholderLayout.DISABLE_ANIMATION_SWITCH}) + // clang-format off public void startSurfaceRecordHistogramsTest_SingleTab() { // clang-format on startSurfaceRecordHistogramsTest(true); @@ -514,7 +517,7 @@ @EnableFeatures({ChromeFeatureList.TAB_SWITCHER_ON_RETURN + "<Study", ChromeFeatureList.TAB_GRID_LAYOUT_ANDROID, ChromeFeatureList.START_SURFACE_ANDROID + "<Study"}) - @CommandLineFlags.Add({START_SURFACE_TEST_BASE_PARAMS, + @CommandLineFlags.Add({START_SURFACE_TEST_SINGLE_ENABLED_PARAMS, // Disable feed placeholder animation because it causes waitForDeferredStartup() to time // out. FeedPlaceholderLayout.DISABLE_ANIMATION_SWITCH}) @@ -592,7 +595,7 @@ @Test @MediumTest @Feature({"StartSurface"}) - @CommandLineFlags.Add({START_SURFACE_TEST_BASE_PARAMS}) + @CommandLineFlags.Add({START_SURFACE_TEST_SINGLE_ENABLED_PARAMS}) public void testShow_SingleAsHomepage_VoiceSearchButtonShown() { if (!mImmediateReturn) { StartSurfaceTestUtils.pressHomePageButton(mActivityTestRule.getActivity()); @@ -609,7 +612,7 @@ @Test @MediumTest @Feature({"StartSurface"}) - @CommandLineFlags.Add({START_SURFACE_TEST_BASE_PARAMS}) + @CommandLineFlags.Add({START_SURFACE_TEST_SINGLE_ENABLED_PARAMS}) public void testShow_SingleAsHomepage_BottomSheet() { if (!mImmediateReturn) { StartSurfaceTestUtils.pressHomePageButton(mActivityTestRule.getActivity()); @@ -657,7 +660,7 @@ @Test @MediumTest @Feature({"StartSurface"}) - @CommandLineFlags.Add({START_SURFACE_TEST_BASE_PARAMS}) + @CommandLineFlags.Add({START_SURFACE_TEST_SINGLE_ENABLED_PARAMS}) public void testShow_SingleAsHomepage_ResetScrollPosition() { if (!mImmediateReturn) { StartSurfaceTestUtils.pressHomePageButton(mActivityTestRule.getActivity()); @@ -689,7 +692,7 @@ @Test @MediumTest @Feature({"StartSurface"}) - @CommandLineFlags.Add({START_SURFACE_TEST_BASE_PARAMS}) + @CommandLineFlags.Add({START_SURFACE_TEST_SINGLE_ENABLED_PARAMS}) public void singleAsHomepage_PressHomeButtonWillKeepTab() { if (!mImmediateReturn) { StartSurfaceTestUtils.pressHomePageButton(mActivityTestRule.getActivity()); @@ -725,7 +728,7 @@ @MediumTest @Feature({"StartSurface"}) // clang-format off - @CommandLineFlags.Add({START_SURFACE_TEST_BASE_PARAMS}) + @CommandLineFlags.Add({START_SURFACE_TEST_SINGLE_ENABLED_PARAMS}) @DisableIf.Build(sdk_is_greater_than = VERSION_CODES.O_MR1, supported_abis_includes = "x86", message = "Flaky, see crbug.com/1258154") public void testNotShowIncognitoHomepage() { @@ -761,7 +764,7 @@ @MediumTest @Feature({"StartSurface"}) // clang-format off - @CommandLineFlags.Add({START_SURFACE_TEST_BASE_PARAMS}) + @CommandLineFlags.Add({START_SURFACE_TEST_SINGLE_ENABLED_PARAMS}) public void test_DoNotLoadLastSelectedTabOnStartup() { // clang-format on doTestNotLoadLastSelectedTabOnStartupImpl(); @@ -771,7 +774,6 @@ @MediumTest @Feature({"StartSurface"}) // clang-format off - @CommandLineFlags.Add({START_SURFACE_TEST_BASE_PARAMS + "/show_last_active_tab_only/true"}) public void test_DoNotLoadLastSelectedTabOnStartupV2() { // clang-format on doTestNotLoadLastSelectedTabOnStartupImpl();
diff --git a/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTestUtils.java b/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTestUtils.java index eff6aecd..48b824c 100644 --- a/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTestUtils.java +++ b/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTestUtils.java
@@ -98,10 +98,12 @@ public class StartSurfaceTestUtils { public static final String INSTANT_START_TEST_BASE_PARAMS = "force-fieldtrial-params=Study.Group:" - + ReturnToChromeUtil.TAB_SWITCHER_ON_RETURN_MS_PARAM + "/0" - + "/start_surface_variation/single"; + + ReturnToChromeUtil.TAB_SWITCHER_ON_RETURN_MS_PARAM + "/0"; + public static final String START_SURFACE_TEST_SINGLE_ENABLED_PARAMS = + "force-fieldtrial-params=Study.Group:" + + "show_last_active_tab_only/false/open_ntp_instead_of_start/false"; public static final String START_SURFACE_TEST_BASE_PARAMS = - "force-fieldtrial-params=Study.Group:start_surface_variation/single"; + "force-fieldtrial-params=Study.Group:"; public static List<ParameterSet> sClassParamsForStartSurfaceTest = Arrays.asList(new ParameterSet().value(false, false).name("NoInstant_NoReturn"), new ParameterSet().value(true, false).name("Instant_NoReturn"),
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 7f08a96..2b46e4c2 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
@@ -52,6 +52,7 @@ import static org.chromium.chrome.browser.tasks.tab_management.TabUiTestHelper.verifyAllTabsHaveThumbnail; import static org.chromium.chrome.browser.tasks.tab_management.TabUiTestHelper.verifyTabStripFaviconCount; import static org.chromium.chrome.browser.tasks.tab_management.TabUiTestHelper.verifyTabSwitcherCardCount; +import static org.chromium.chrome.features.start_surface.StartSurfaceTestUtils.START_SURFACE_TEST_SINGLE_ENABLED_PARAMS; import static org.chromium.chrome.features.start_surface.StartSurfaceTestUtils.createTabStateFile; import static org.chromium.chrome.features.start_surface.StartSurfaceTestUtils.createThumbnailBitmapAndWriteToFile; import static org.chromium.ui.test.util.ViewUtils.onViewWaiting; @@ -131,8 +132,6 @@ // clang-format on private static final String CUSTOMIZED_TITLE1 = "wfh tips"; private static final String CUSTOMIZED_TITLE2 = "wfh funs"; - private static final String START_SURFACE_BASE_PARAMS = - "force-fieldtrial-params=Study.Group:start_surface_variation"; private static final String TAB_GROUP_LAUNCH_POLISH_PARAMS = "force-fieldtrial-params=Study.Group:enable_launch_polish/true"; @@ -928,7 +927,8 @@ @MediumTest @DisableIf.Device(type = UiDisableIf.TABLET) @Features.EnableFeatures({ChromeFeatureList.START_SURFACE_ANDROID + "<Study"}) - @CommandLineFlags.Add({"force-fieldtrials=Study/Group", START_SURFACE_BASE_PARAMS + "/single"}) + @CommandLineFlags. + Add({"force-fieldtrials=Study/Group", START_SURFACE_TEST_SINGLE_ENABLED_PARAMS}) public void testDialogSetup_WithStartSurface() throws Exception { // Create a tab group with 2 tabs. finishActivity(mActivityTestRule.getActivity()); @@ -966,11 +966,14 @@ @Test @MediumTest @Features.EnableFeatures({ChromeFeatureList.START_SURFACE_ANDROID + "<Study"}) - @CommandLineFlags.Add({"force-fieldtrials=Study/Group", START_SURFACE_BASE_PARAMS + "/single"}) + @CommandLineFlags.Add({"force-fieldtrials=Study/Group", + START_SURFACE_TEST_SINGLE_ENABLED_PARAMS + "/hide_switch_when_no_incognito_tabs/false"}) @DisableIf. Build(sdk_is_greater_than = VERSION_CODES.M, message = "crbug.com/1119899, crbug.com/1131545") @DisableIf.Device(type = UiDisableIf.TABLET) + // clang-format off public void testUndoClosureInDialog_WithStartSurface() throws Exception { + // clang-format on // Create a tab group with 2 tabs. finishActivity(mActivityTestRule.getActivity()); createThumbnailBitmapAndWriteToFile(0);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/flags/ChromeCachedFlags.java b/chrome/android/java/src/org/chromium/chrome/browser/app/flags/ChromeCachedFlags.java index 99a01b1..7a1bf2d 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/app/flags/ChromeCachedFlags.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/app/flags/ChromeCachedFlags.java
@@ -85,6 +85,7 @@ add(ChromeFeatureList.sCctResizableAllowResizeByUserGesture); add(ChromeFeatureList.sCctResizableForFirstParties); add(ChromeFeatureList.sCctResizableForThirdParties); + add(ChromeFeatureList.sCctResizableWindowAboveNavbar); add(ChromeFeatureList.sCctToolbarCustomizations); add(ChromeFeatureList.sCloseTabSuggestions); add(ChromeFeatureList.sCommandLineOnNonRooted);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabRootUiCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabRootUiCoordinator.java index e783539..af4b81724 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabRootUiCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabRootUiCoordinator.java
@@ -285,6 +285,16 @@ } @Override + protected Supplier<Integer> getBaseHeightProvider() { + if (mIntentDataProvider.get().isPartialHeightCustomTab() + && !ChromeFeatureList.sCctResizableWindowAboveNavbar.isEnabled()) { + return () -> mActivity.findViewById(R.id.coordinator).getHeight(); + } else { + return null; + } + } + + @Override protected boolean canDrawOutsideScreen() { return mCustomTabHeightStrategy.canDrawOutsideScreen(); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/PartialCustomTabHeightStrategy.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/PartialCustomTabHeightStrategy.java index c554151..9dbc1a1 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/PartialCustomTabHeightStrategy.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/PartialCustomTabHeightStrategy.java
@@ -23,11 +23,13 @@ import android.util.DisplayMetrics; import android.view.Display; import android.view.GestureDetector; +import android.view.Gravity; import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.View; import android.view.ViewGroup; import android.view.ViewStub; +import android.view.Window; import android.view.WindowInsets; import android.view.WindowManager; import android.view.animation.AccelerateInterpolator; @@ -44,6 +46,7 @@ import androidx.core.view.WindowInsetsControllerCompat; import androidx.swiperefreshlayout.widget.CircularProgressDrawable; +import org.chromium.base.Consumer; import org.chromium.base.MathUtils; import org.chromium.base.SysUtils; import org.chromium.base.ThreadUtils; @@ -99,6 +102,7 @@ private final OnResizedCallback mOnResizedCallback; private final AnimatorListener mSpinnerFadeoutAnimatorListener; private final int mCachedHandleHeight; + private boolean mWindowAboveNavbar; private @Px int mInitialHeight; private ValueAnimator mAnimator; private int mShadowOffset; @@ -108,6 +112,7 @@ // ContentFrame + CoordinatorLayout - CompositorViewHolder // + NavigationBar // + Spinner + // When CCT_RESIZABLE_WINDOW_ABOVE_NAVBAR is disabled, We resize inner contents view. // Not just CompositorViewHolder but also CoordinatorLayout is resized because many UI // components such as BottomSheet, InfoBar, Snackbar are child views of CoordinatorLayout, // which makes them appear correctly at the bottom. @@ -122,6 +127,7 @@ private @Px int mNavbarHeight; private int mOrientation; private boolean mIsInMultiWindowMode; + private int mHeight; private ImageView mSpinnerView; private LinearLayout mNavbar; @@ -139,6 +145,10 @@ // Y offset when a dragging gesture starts. private int mDraggingStartY; + // Method to invoke to animate the tab. Animates by altering top y position by default, + // but using height for the close animation. + private Consumer<Integer> mTabAnimator = this::updateWindowPos; + /** A callback to be called once the Custom Tab has been resized. */ interface OnResizedCallback { /** The Custom Tab has been resized. */ @@ -202,7 +212,8 @@ mSeenFirstMoveOrDown = true; mVelocityTracker.clear(); onMoveStart(); - mOffsetY = mActivity.getWindow().getAttributes().y - y; + mDraggingStartY = mActivity.getWindow().getAttributes().y; + mOffsetY = mDraggingStartY - y; mLastPosY = y; mStopShowingSpinner = false; } else { @@ -298,6 +309,7 @@ public PartialCustomTabHeightStrategy(Activity activity, @Px int initialHeight, Integer navigationBarColor, Integer navigationBarDividerColor, OnResizedCallback onResizedCallback, ActivityLifecycleDispatcher lifecycleDispatcher) { + mWindowAboveNavbar = ChromeFeatureList.sCctResizableWindowAboveNavbar.isEnabled(); mActivity = activity; mMaxHeight = getMaximumPossibleHeight(); mInitialHeight = MathUtils.clamp( @@ -333,10 +345,8 @@ mSpinnerFadeoutAnimatorListener = new AnimatorListener() { @Override public void onAnimationStart(Animator animator) {} - @Override public void onAnimationRepeat(Animator animator) {} - @Override public void onAnimationEnd(Animator animator) { mSpinner.stop(); @@ -395,9 +405,12 @@ initializeHeight(); updateShadowOffset(); - - setContentsHeight(); - updateNavbarVisibility(true); + if (mWindowAboveNavbar) { + maybeInvokeResizeCallback(); + } else { + setContentsHeight(); + updateNavbarVisibility(true); + } } private int initialY() { @@ -475,8 +488,8 @@ // ValueAnimator.AnimatorUpdateListener implementation. @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { - int ypos = (int) valueAnimator.getAnimatedValue(); - updateWindowPos(ypos); + int value = (int) valueAnimator.getAnimatedValue(); + mTabAnimator.accept(value); } private void roundCorners( @@ -540,8 +553,9 @@ } private void initializeHeight() { - mActivity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL); - mActivity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND); + Window window = mActivity.getWindow(); + window.addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL); + window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND); mNavbarHeight = getNavbarHeight(); int maxExpandedY = getFullyExpandedYCoordinate(); @@ -551,32 +565,53 @@ // Resizing by user dragging is not supported in landscape mode; no need to set // the status here. height = mDisplayHeight - maxExpandedY; - mActivity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS); + if (!mWindowAboveNavbar) { + mActivity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS); + } } else { height = mInitialHeight; mStatus = HeightStatus.INITIAL_HEIGHT; - mActivity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS); + if (!mWindowAboveNavbar) { + mActivity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS); + } } - WindowManager.LayoutParams attributes = mActivity.getWindow().getAttributes(); - // TODO(jinsukkim): Handle multi-window mode. - if (attributes.height == height) return; + WindowManager.LayoutParams attrs = window.getAttributes(); + if (attrs.height == height) return; - // We do not resize Window but just translate its vertical offset, and resize Coordinator- - // LayoutForPointer instead. This helps us work around the round-corner bug in Android S. - // See b/223536648. - attributes.y = Math.max(maxExpandedY, mDisplayHeight - height); - mActivity.getWindow().setAttributes(attributes); - + if (mWindowAboveNavbar) { + // To avoid the bottom navigation bar area flickering when starting dragging, position + // web contents area right above the navigation bar so the two won't overlap. The + // navigation area now just shows whatever is underneath: 1) loading view/web contents + // while dragging 2) host app's navigation bar when at rest. + positionAtHeight(height); + mHeight = attrs.height; + } else { + // We do not resize Window but just translate its vertical offset, and resize + // CoordinatorLayoutForPointer instead. This helps us work around the round-corner bug + // in Android S. See b/223536648. + attrs.y = Math.max(maxExpandedY, mDisplayHeight - height); + window.setAttributes(attrs); + } updateDragBarVisibility(); } + private void positionAtHeight(int height) { + WindowManager.LayoutParams attrs = mActivity.getWindow().getAttributes(); + attrs.height = height - mNavbarHeight; + attrs.y = mNavbarHeight; + attrs.gravity = Gravity.BOTTOM; + mActivity.getWindow().setAttributes(attrs); + } + private void updateDragBarVisibility() { View dragBar = mActivity.findViewById(R.id.drag_bar); if (dragBar != null) dragBar.setVisibility(isFullHeight() ? View.GONE : View.VISIBLE); } private void updateShadowOffset() { + // TODO(jinsukkim): Remove the shadow when in full-height so there won't be a gap + // beneath the status bar. if (isFullHeight() || mDrawOutlineShadow) { mShadowOffset = 0; } else { @@ -608,11 +643,13 @@ // bar and (optionally) the 90%-height adjustment. int topY = getFullyExpandedYCoordinateWithAdjustment(); y = MathUtils.clamp(y, topY, mMaxHeight); - WindowManager.LayoutParams attributes = mActivity.getWindow().getAttributes(); - if (attributes.y == y) return; + Window window = mActivity.getWindow(); + WindowManager.LayoutParams attrs = window.getAttributes(); + if (attrs.y == y) return; - attributes.y = y; - mActivity.getWindow().setAttributes(attributes); + attrs.y = y; + window.setAttributes(attrs); + if (mFinishRunnable != null) return; // Starting dragging from INITIAL_HEIGHT state, we can hide the spinner if the tab: @@ -639,13 +676,30 @@ } } + private void updateWindowHeight(int height) { + Window window = mActivity.getWindow(); + WindowManager.LayoutParams attrs = window.getAttributes(); + attrs.height = height; + window.setAttributes(attrs); + } + private boolean isSpinnerVisible() { return mSpinnerView != null && mSpinnerView.getVisibility() == View.VISIBLE; } private void onMoveStart() { - mDraggingStartY = mActivity.getWindow().getAttributes().y; - updateNavbarVisibility(false); + if (mWindowAboveNavbar) { + Window window = mActivity.getWindow(); + window.addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS); + WindowManager.LayoutParams attrs = window.getAttributes(); + attrs.y = mMaxHeight - attrs.height - mNavbarHeight; + attrs.height = mMaxHeight; + attrs.gravity = Gravity.NO_GRAVITY; + window.setAttributes(attrs); + showNavbarButtons(false); + } else { + updateNavbarVisibility(false); + } } private void onMoveEnd() { @@ -654,11 +708,19 @@ return; } hideSpinnerView(); - updateNavbarVisibility(true); + if (mWindowAboveNavbar) { + Window window = mActivity.getWindow(); + window.clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS); + positionAtHeight(mMaxHeight - window.getAttributes().y); + showNavbarButtons(true); + maybeInvokeResizeCallback(); + } else { + updateNavbarVisibility(true); + } } private void hideSpinnerView() { - setContentsHeight(); + if (!mWindowAboveNavbar) setContentsHeight(); // TODO(crbug.com/1328555): Look into observing a view resize event to ensure the fade // animation can always cover the transition artifact. @@ -681,7 +743,11 @@ // Toolbar should not be hidden by spinner screen. ViewGroup.MarginLayoutParams lp = new ViewGroup.MarginLayoutParams(MATCH_PARENT, 0); - lp.setMargins(0, mToolbarView.getHeight() + getHandleHeight() + mShadowOffset, 0, 0); + int topMargin = mToolbarView.getHeight() + mShadowOffset; + // See the comment below for why we add handle height. + if (!mWindowAboveNavbar) topMargin += getHandleHeight(); + lp.setMargins(0, topMargin, 0, 0); + mSpinner = new CircularProgressDrawable(mActivity); mSpinner.setStyle(CircularProgressDrawable.LARGE); mSpinnerView.setImageDrawable(mSpinner); @@ -691,9 +757,14 @@ mSpinner.setColorSchemeColors(colorList); centerSpinnerVertically(lp); } - // Spinner view is added to ContentFrameLayout to hide both WebContents and navigation bar. - if (mSpinnerView.getParent() == null) mContentFrame.addView(mSpinnerView); + // For window-above-navbar, it should be added to CoordinatorLayoutForPointer to obscure + // the flickering at the beginning of dragging action. Their top positions differ by + // |getHandleHeight()| which is a top margin of CoordinatorLayoutForPointer. + if (mSpinnerView.getParent() == null) { + ViewGroup parent = mWindowAboveNavbar ? mCoordinatorLayout : mContentFrame; + parent.addView(mSpinnerView); + } mSpinnerView.clearAnimation(); mSpinnerView.setAlpha(0.f); mSpinnerView.setVisibility(View.VISIBLE); @@ -808,6 +879,14 @@ } } + private void maybeInvokeResizeCallback() { + WindowManager.LayoutParams attrs = mActivity.getWindow().getAttributes(); + if (mHeight != attrs.height && attrs.height > 0) { + mOnResizedCallback.onResized(attrs.height); + mHeight = attrs.height; + } + } + private void showNavbarButtons(boolean show) { View decorView = mActivity.getWindow().getDecorView(); WindowInsetsControllerCompat controller = @@ -901,23 +980,25 @@ if (mFinishRunnable != null) return; mFinishRunnable = finishRunnable; - - int start = mActivity.getWindow().getAttributes().y; - int end = mDisplayHeight - mNavbarHeight; - - if (isFullHeight()) { + WindowManager.LayoutParams attrs = mActivity.getWindow().getAttributes(); + if (attrs.gravity == Gravity.BOTTOM) { + mTabAnimator = this::updateWindowHeight; + mAnimator.setIntValues(attrs.height, 0); + } else { + mAnimator.setIntValues(attrs.y, mDisplayHeight - mNavbarHeight); + } + if (!mWindowAboveNavbar && isFullHeight()) { mActivity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS); } mAnimator.setDuration( mActivity.getResources().getInteger(android.R.integer.config_mediumAnimTime)); - mAnimator.setIntValues(start, end); mAnimator.setInterpolator(new AccelerateInterpolator()); mAnimator.start(); } @Override public boolean canDrawOutsideScreen() { - return !isFullHeight(); + return !mWindowAboveNavbar && !isFullHeight(); } @VisibleForTesting @@ -937,4 +1018,9 @@ int getNavbarHeightForTesting() { return mNavbarHeight; } + + @VisibleForTesting + void setWindowAboveNavbarForTesting(boolean windowAboveNavbar) { + mWindowAboveNavbar = windowAboveNavbar; + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunSignInProcessor.java b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunSignInProcessor.java index 46c55fc..7b8e0ad 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunSignInProcessor.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunSignInProcessor.java
@@ -11,6 +11,7 @@ import androidx.annotation.NonNull; import org.chromium.chrome.browser.SyncFirstSetupCompleteSource; +import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.preferences.ChromePreferenceKeys; import org.chromium.chrome.browser.preferences.SharedPreferencesManager; import org.chromium.chrome.browser.profiles.Profile; @@ -68,7 +69,7 @@ final String accountName = getFirstRunFlowSignInAccountName(); if (TextUtils.isEmpty(accountName) && getFirstRunFlowSignInSetup()) { - assert SyncConsentFirstRunFragment.shouldEnableImmediately(); + assert ChromeFeatureList.isEnabled(ChromeFeatureList.ENABLE_SYNC_IMMEDIATELY_IN_FRE); openAdvancedSyncSettings(activity); setFirstRunFlowSignInComplete(true); return;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/SyncConsentFirstRunFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/SyncConsentFirstRunFragment.java index 3eddafe..3d199df 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/SyncConsentFirstRunFragment.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/SyncConsentFirstRunFragment.java
@@ -11,11 +11,15 @@ import org.chromium.chrome.R; import org.chromium.chrome.browser.flags.ChromeFeatureList; +import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.signin.services.FREMobileIdentityConsistencyFieldTrial; +import org.chromium.chrome.browser.signin.services.IdentityServicesProvider; import org.chromium.chrome.browser.signin.services.SigninPreferencesManager; import org.chromium.chrome.browser.ui.signin.SyncConsentFragmentBase; import org.chromium.components.signin.AccountManagerFacadeProvider; import org.chromium.components.signin.AccountUtils; +import org.chromium.components.signin.base.CoreAccountInfo; +import org.chromium.components.signin.identitymanager.ConsentLevel; import org.chromium.components.signin.metrics.SigninAccessPoint; import java.util.List; @@ -33,15 +37,6 @@ // saved state bundle. See crbug.com/1225102 public SyncConsentFirstRunFragment() {} - /** - * Returns true if sync will be enabled as soon as the user clicks the "Yes, I'm in" button, - * and false if this will be deferred until the main activity starts. - */ - public static boolean shouldEnableImmediately() { - return ChromeFeatureList.isEnabled(ChromeFeatureList.ENABLE_SYNC_IMMEDIATELY_IN_FRE) - && ChromeFeatureList.isEnabled(ChromeFeatureList.ALLOW_SYNC_OFF_FOR_CHILD_ACCOUNTS); - } - @Override public void onAttach(Context context) { super.onAttach(context); @@ -84,25 +79,52 @@ MobileFreProgress.SYNC_CONSENT_SETTINGS_LINK_CLICK); } - if (shouldEnableImmediately()) { - // Enable sync now. Leave the account pref empty in FirstRunSignInProcessor, so start() - // doesn't try to do it a second time. Only set the advanced setup pref later in - // closeAndMaybeOpenSyncSettings(), because settings shouldn't open if - // signinAndEnableSync() fails. - FirstRunSignInProcessor.setFirstRunFlowSignInAccountName(null); - signinAndEnableSync(accountName, settingsClicked, callback); - } else { + if (!ChromeFeatureList.isEnabled(ChromeFeatureList.ENABLE_SYNC_IMMEDIATELY_IN_FRE)) { // Enabling sync is deferred to FirstRunSignInProcessor.start(). FirstRunSignInProcessor.setFirstRunFlowSignInAccountName(accountName); FirstRunSignInProcessor.setFirstRunFlowSignInSetup(settingsClicked); getPageDelegate().advanceToNextPage(); callback.run(); + return; } + + // Enable sync now. Leave the account pref empty in FirstRunSignInProcessor, so start() + // doesn't try to do it a second time. Only set the advanced setup pref later in + // closeAndMaybeOpenSyncSettings(), because settings shouldn't open if + // signinAndEnableSync() fails. + FirstRunSignInProcessor.setFirstRunFlowSignInAccountName(null); + if (!getPageDelegate().getProperties().getBoolean(IS_CHILD_ACCOUNT, false)) { + signinAndEnableSync(accountName, settingsClicked, callback); + return; + } + + // Special case for child accounts. In rare cases, e.g. if Terms & Conditions is clicked, + // SigninChecker might have been triggered before the FRE ends and started sign-in (the + // ConsentLevel depends on AllowSyncOffForChildAccounts). In doubt, wait. + Profile profile = Profile.getLastUsedRegularProfile(); + IdentityServicesProvider.get().getSigninManager(profile).runAfterOperationInProgress(() -> { + CoreAccountInfo syncingAccount = IdentityServicesProvider.get() + .getIdentityManager(profile) + .getPrimaryAccountInfo(ConsentLevel.SYNC); + if (syncingAccount == null) { + signinAndEnableSync(accountName, settingsClicked, callback); + return; + } + + if (!accountName.equals(syncingAccount.getEmail())) { + throw new IllegalStateException( + "Child accounts should only be allowed to sync with a single account"); + } + + // SigninChecker enabled sync already. Just open settings if needed. + closeAndMaybeOpenSyncSettings(settingsClicked); + callback.run(); + }); } @Override protected void closeAndMaybeOpenSyncSettings(boolean settingsClicked) { - assert shouldEnableImmediately(); + assert ChromeFeatureList.isEnabled(ChromeFeatureList.ENABLE_SYNC_IMMEDIATELY_IN_FRE); // Now that signinAndEnableSync() succeeded, signal whether FirstRunSignInProcessor.start() // should open settings. FirstRunSignInProcessor.setFirstRunFlowSignInSetup(settingsClicked);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/TranslateCompactInfoBar.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/TranslateCompactInfoBar.java index 3ea0817..f6d96f5 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/TranslateCompactInfoBar.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/TranslateCompactInfoBar.java
@@ -23,6 +23,7 @@ import org.chromium.base.metrics.RecordHistogram; import org.chromium.base.supplier.Supplier; import org.chromium.chrome.R; +import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.preferences.Pref; import org.chromium.chrome.browser.preferences.PrefChangeRegistrar; import org.chromium.chrome.browser.preferences.PrefChangeRegistrar.PrefObserver; @@ -319,6 +320,8 @@ // is set to allow the app to be drawn outside the screen. Returns {@code null} if not // necessary. private Rect getAppRectInWindow() { + if (ChromeFeatureList.sCctResizableWindowAboveNavbar.isEnabled()) return null; + View view = getView().getRootView().findViewById(R.id.coordinator); if (!view.isAttachedToWindow()) return null; WindowManager.LayoutParams attrs = ((Activity) getContext()).getWindow().getAttributes();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/share/ShareDelegateImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/share/ShareDelegateImpl.java index a27ef4f..8775720 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/share/ShareDelegateImpl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/share/ShareDelegateImpl.java
@@ -260,15 +260,16 @@ Supplier<Profile> profileSupplier, Callback<Tab> printCallback, @ShareOrigin int shareOrigin, long shareStartTime, boolean sharingHubEnabled) { Profile profile = profileSupplier.get(); - // In some cases, ProfileSupplier.get() will return null or will not be initialized in - // Native. See https://crbug.com/1346710 and https://crbug.com/1353138 for context. - if (profile == null || !profile.isNativeInitialized()) { + // In some cases, ProfileSupplier.get() will return null. See https://crbug.com/1346710 + // and https://crbug.com/1353138 for context. + if (profile == null) { profile = Profile.getLastUsedRegularProfile(); } if (chromeShareExtras.shareDirectly()) { ShareHelper.shareWithLastUsedComponent(params); } else if (sharingHubEnabled && !chromeShareExtras.sharingTabGroup() && profile != null) { + profile.ensureNativeInitialized(); // TODO(crbug.com/1085078): Sharing hub is suppressed for tab group sharing. // Re-enable it when tab group sharing is supported by sharing hub. RecordHistogram.recordEnumeratedHistogram(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tasks/ReturnToChromeUtil.java b/chrome/android/java/src/org/chromium/chrome/browser/tasks/ReturnToChromeUtil.java index c7e036c..590c1c65 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tasks/ReturnToChromeUtil.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tasks/ReturnToChromeUtil.java
@@ -87,8 +87,8 @@ @VisibleForTesting public static final String TAB_SWITCHER_ON_RETURN_MS_PARAM = "tab_switcher_on_return_time_ms"; public static final IntCachedFieldTrialParameter TAB_SWITCHER_ON_RETURN_MS = - new IntCachedFieldTrialParameter( - ChromeFeatureList.TAB_SWITCHER_ON_RETURN, TAB_SWITCHER_ON_RETURN_MS_PARAM, -1); + new IntCachedFieldTrialParameter(ChromeFeatureList.TAB_SWITCHER_ON_RETURN, + TAB_SWITCHER_ON_RETURN_MS_PARAM, 28800000); // 8 hours @VisibleForTesting static final String UMA_TIME_TO_GTS_FIRST_MEANINGFUL_PAINT =
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ui/RootUiCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/ui/RootUiCoordinator.java index 7d22e27..459a9fba 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ui/RootUiCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ui/RootUiCoordinator.java
@@ -1311,6 +1311,18 @@ } /** + * Provides the height of the base app area on which bottom sheet client is drawn. This is + * not necessary for most embedders of BottomSheet, unless they have non-zero vertical Window + * offset that would push down a part of app area out of the screen. BottomSheet then uses + * this height to resize the sheet content so all of it is visible. + * @return Supplier of the height of the base app area. {@code null} if not necessary. + */ + @Nullable + protected Supplier<Integer> getBaseHeightProvider() { + return null; + } + + /** * Whether UI like popup can be drawn outside the screen. {@code false} by default. */ protected boolean canDrawOutsideScreen() { @@ -1401,8 +1413,7 @@ -> mScrimCoordinator, sheetInitializedCallback, mActivity.getWindow(), mWindowAndroid.getKeyboardDelegate(), - () -> mActivity.findViewById(R.id.sheet_container), - () -> mActivity.findViewById(R.id.coordinator).getHeight()); + () -> mActivity.findViewById(R.id.sheet_container), getBaseHeightProvider()); BottomSheetControllerFactory.setExceptionReporter( (throwable) -> ChromePureJavaExceptionReporter.reportJavaException(
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java index 8b23dd9..f1a540b 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
@@ -1792,7 +1792,19 @@ @Test @SmallTest @Features.EnableFeatures({ChromeFeatureList.CCT_RESIZABLE_FOR_THIRD_PARTIES}) - public void testLaunchPartialCustomTabActivity() throws Exception { + @Features.DisableFeatures({ChromeFeatureList.CCT_RESIZABLE_WINDOW_ABOVE_NAVBAR}) + public void testLaunchPartialCustomTabActivity_fixedWindow() throws Exception { + testLaunchPartialCustomTabActivity(); + } + + @Test + @SmallTest + @Features.EnableFeatures({ChromeFeatureList.CCT_RESIZABLE_FOR_THIRD_PARTIES}) + public void testLaunchPartialCustomTabActivity_dynamicWindow() throws Exception { + testLaunchPartialCustomTabActivity(); + } + + private void testLaunchPartialCustomTabActivity() throws Exception { Intent intent = createMinimalCustomTabIntent(); CustomTabsSessionToken token = CustomTabsSessionToken.getSessionTokenFromIntent(intent); CustomTabsConnection connection = CustomTabsConnection.getInstance(); @@ -1801,8 +1813,13 @@ intent.putExtra(CustomTabIntentDataProvider.EXTRA_INITIAL_ACTIVITY_HEIGHT_IN_PIXEL, 50); mCustomTabActivityTestRule.startCustomTabActivityWithIntent(intent); - WindowManager.LayoutParams attributes = getActivity().getWindow().getAttributes(); - assertNotEquals("The window should have non-zero y offset", 0, attributes.y); + if (ChromeFeatureList.sCctResizableWindowAboveNavbar.isEnabled()) { + // A Normal CCT height is set to MATCH_PARENT while Partial CCT has non-zero value. + int fullHeight = ViewGroup.LayoutParams.MATCH_PARENT; + WindowManager.LayoutParams attrs = getActivity().getWindow().getAttributes(); + assertNotEquals("The window should have non-full height", fullHeight, attrs.height); + return; + } // Verify the hierarchy of the enclosing layouts that PCCT relies on for its operation. CallbackHelper eventHelper = new CallbackHelper(); @@ -1814,6 +1831,8 @@ cvh.getParent() instanceof CoordinatorLayoutForPointer); assertTrue("ContentFrameLayout should be the parent of CoodinatorLayoutForPointer", cvh.getParent().getParent() instanceof ContentFrameLayout); + WindowManager.LayoutParams attrs = getActivity().getWindow().getAttributes(); + assertNotEquals("The window should have non-zero y", 0, attrs.y); eventHelper.notifyCalled(); }); });
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/firstrun/FirstRunActivitySigninAndSyncTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/firstrun/FirstRunActivitySigninAndSyncTest.java index 8467f4e..a3790ac 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/firstrun/FirstRunActivitySigninAndSyncTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/firstrun/FirstRunActivitySigninAndSyncTest.java
@@ -281,10 +281,8 @@ @Test @MediumTest - @EnableFeatures({ChromeFeatureList.ALLOW_SYNC_OFF_FOR_CHILD_ACCOUNTS, - ChromeFeatureList.ENABLE_SYNC_IMMEDIATELY_IN_FRE}) - public void - acceptingSyncEndsFreAndEnablesSyncIfEnableSyncImmediatelyFeatureEnabled() { + @EnableFeatures({ChromeFeatureList.ENABLE_SYNC_IMMEDIATELY_IN_FRE}) + public void acceptingSyncEndsFreAndEnablesSyncIfEnableSyncImmediatelyFeatureEnabled() { when(mExternalAuthUtilsMock.canUseGooglePlayServices(any())).thenReturn(true); mAccountManagerTestRule.addAccount(TEST_EMAIL); launchFirstRunActivityAndWaitForNativeInitialization(); @@ -317,10 +315,8 @@ @Test @MediumTest - @EnableFeatures({ChromeFeatureList.ALLOW_SYNC_OFF_FOR_CHILD_ACCOUNTS, - ChromeFeatureList.ENABLE_SYNC_IMMEDIATELY_IN_FRE}) - public void - refusingSyncEndsFreAndDoesNotEnableSyncIfEnableSyncImmediatelyFeatureEnabled() { + @EnableFeatures({ChromeFeatureList.ENABLE_SYNC_IMMEDIATELY_IN_FRE}) + public void refusingSyncEndsFreAndDoesNotEnableSyncIfEnableSyncImmediatelyFeatureEnabled() { mAccountManagerTestRule.addAccount(TEST_EMAIL); launchFirstRunActivityAndWaitForNativeInitialization(); waitUntilCurrentPageIs(SigninFirstRunFragment.class); @@ -353,8 +349,7 @@ @Test @MediumTest - @EnableFeatures({ChromeFeatureList.ALLOW_SYNC_OFF_FOR_CHILD_ACCOUNTS, - ChromeFeatureList.ENABLE_SYNC_IMMEDIATELY_IN_FRE}) + @EnableFeatures({ChromeFeatureList.ENABLE_SYNC_IMMEDIATELY_IN_FRE}) @DisabledTest(message = "https://crbug.com/1335094") public void clickingSettingsEndsFreAndStartsEnablingSyncIfEnableSyncImmediatelyFeatureEnabled() {
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/PartialCustomTabHeightStrategyTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/PartialCustomTabHeightStrategyTest.java index 126b81e..37f5a91 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/PartialCustomTabHeightStrategyTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/PartialCustomTabHeightStrategyTest.java
@@ -21,6 +21,7 @@ import android.animation.Animator.AnimatorListener; import android.app.Activity; +import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; import android.os.Looper; @@ -39,6 +40,7 @@ import android.widget.LinearLayout; import androidx.swiperefreshlayout.widget.CircularProgressDrawable; +import androidx.test.core.app.ApplicationProvider; import org.junit.After; import org.junit.Before; @@ -48,13 +50,17 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.ParameterizedRobolectricTestRunner; +import org.robolectric.ParameterizedRobolectricTestRunner.Parameter; +import org.robolectric.ParameterizedRobolectricTestRunner.Parameters; import org.robolectric.annotation.Config; import org.robolectric.annotation.LooperMode; import org.robolectric.annotation.LooperMode.Mode; import org.robolectric.shadows.ShadowLog; import org.chromium.base.Callback; -import org.chromium.base.test.BaseRobolectricTestRunner; +import org.chromium.base.CommandLine; +import org.chromium.base.ContextUtils; import org.chromium.chrome.R; import org.chromium.chrome.browser.customtabs.PartialCustomTabHeightStrategy.PartialCustomTabHandleStrategy; import org.chromium.chrome.browser.flags.ChromeFeatureList; @@ -63,10 +69,12 @@ import org.chromium.chrome.test.util.browser.Features; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; import java.util.List; /** Tests for {@link PartialCustomTabHandleStrategy}. */ -@RunWith(BaseRobolectricTestRunner.class) +@RunWith(ParameterizedRobolectricTestRunner.class) @Config(manifest = Config.NONE) @Features.EnableFeatures({ChromeFeatureList.CCT_RESIZABLE_FOR_THIRD_PARTIES, ChromeFeatureList.CCT_RESIZABLE_ALLOW_RESIZE_BY_USER_GESTURE}) @@ -81,6 +89,18 @@ private static final int NAVBAR_HEIGHT = 160; private static final int MAX_INIT_POS = DEVICE_HEIGHT / 2; + private static final int INITIAL_HEIGHT = DEVICE_HEIGHT / 2 - NAVBAR_HEIGHT; + private static final int FULL_HEIGHT = DEVICE_HEIGHT - NAVBAR_HEIGHT; + + @Parameters + public static Collection<Object[]> data() { + return Arrays.asList(new Object[][] {{true}, {false}}); + } + + // Parameterize the internal implementation. 'Fixed window' type does not resize the Window + // but the WebContents, while 'Window above navbar' type dynamically resizes the Window. + @Parameter(0) + public boolean mWindowAboveNavbar; @Mock private Activity mActivity; @@ -125,7 +145,10 @@ private ViewGroup mCoordinatorLayout; @Mock private View mDragBar; + @Mock + private CommandLine mCommandLine; + private Context mContext; private List<WindowManager.LayoutParams> mAttributeResults; private DisplayMetrics mRealMetrics; private Callback<Integer> mBottomInsetCallback = inset -> {}; @@ -187,6 +210,9 @@ }) .when(mDisplay) .getRealMetrics(any(DisplayMetrics.class)); + mContext = ApplicationProvider.getApplicationContext(); + ContextUtils.initApplicationContextForTests(mContext); + CommandLine.setInstanceForTesting(mCommandLine); } @After @@ -198,6 +224,7 @@ private PartialCustomTabHeightStrategy createPcctAtHeight(int heightPx) { PartialCustomTabHeightStrategy pcct = new PartialCustomTabHeightStrategy( mActivity, heightPx, null, null, mOnResizedCallback, mActivityLifecycleDispatcher); + pcct.setWindowAboveNavbarForTesting(mWindowAboveNavbar); pcct.setMockViewForTesting( mNavbar, mSpinnerView, mSpinner, mToolbarView, mToolbarCoordinator); return pcct; @@ -209,7 +236,7 @@ verifyWindowFlagsSet(); assertEquals(1, mAttributeResults.size()); - assertEquals(MAX_INIT_POS, mAttributeResults.get(0).y); + assertTabIsAtInitialPos(mAttributeResults.get(0)); } @Test @@ -218,7 +245,7 @@ verifyWindowFlagsSet(); assertEquals(1, mAttributeResults.size()); - assertEquals(0, mAttributeResults.get(0).y); + assertTabIsFullHeight(mAttributeResults.get(0)); } @Test @@ -227,7 +254,7 @@ verifyWindowFlagsSet(); assertEquals(1, mAttributeResults.size()); - assertEquals(0, mAttributeResults.get(0).y); + assertTabIsFullHeight(mAttributeResults.get(0)); } @Test @@ -264,9 +291,10 @@ * Simulate dragging the tab and lifting the finger at the end. * @param handleStrategy {@link PartialCustomTabHandleStrategy} object. * @param ypos Series of y positions simulating the events. - * @return Y position of the tab after the dragging finishes. + * @return Window attributes after the dragging finishes. */ - private int dragTab(PartialCustomTabHandleStrategy handleStrategy, int... ypos) { + private WindowManager.LayoutParams dragTab( + PartialCustomTabHandleStrategy handleStrategy, int... ypos) { int npos = ypos.length; assert npos >= 2; long timestamp = SystemClock.uptimeMillis(); @@ -281,7 +309,7 @@ int length = mAttributeResults.size(); assertTrue(length > 1); - return mAttributeResults.get(length - 1).y; + return mAttributeResults.get(length - 1); } private void assertMotionEventIgnored(PartialCustomTabHandleStrategy handleStrategy) { @@ -289,6 +317,22 @@ event(SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN, 1500))); } + private void assertTabIsAtInitialPos(WindowManager.LayoutParams attrs) { + if (mWindowAboveNavbar) { + assertEquals(INITIAL_HEIGHT, attrs.height); + } else { + assertEquals(MAX_INIT_POS, attrs.y); + } + } + + private void assertTabIsFullHeight(WindowManager.LayoutParams attrs) { + if (mWindowAboveNavbar) { + assertEquals(FULL_HEIGHT, attrs.height); + } else { + assertEquals(0, attrs.y); + } + } + private void disableSpinnerAnimation() { // Disable animation for the mock spinner view. doAnswer(invocation -> { @@ -307,7 +351,7 @@ verifyWindowFlagsSet(); assertEquals(1, mAttributeResults.size()); - assertEquals(MAX_INIT_POS, mAttributeResults.get(0).y); + assertTabIsAtInitialPos(mAttributeResults.get(0)); // Pass null because we have a mock Activity and we don't depend on the GestureDetector // inside as we test MotionEvents directly. @@ -315,13 +359,13 @@ strategy.new PartialCustomTabHandleStrategy(null); // Drag to the top. - assertEquals(0, dragTab(handleStrategy, 1500, 1000, 500)); + assertTabIsFullHeight(dragTab(handleStrategy, 1500, 1000, 500)); // Drag down a little -> slide back to the top. - assertEquals(0, dragTab(handleStrategy, 50, 100, 150)); + assertTabIsFullHeight(dragTab(handleStrategy, 50, 100, 150)); // Drag down enough -> slide to the initial position. - assertEquals(MAX_INIT_POS, dragTab(handleStrategy, 50, 650, 1300)); + assertTabIsAtInitialPos(dragTab(handleStrategy, 50, 650, 1300)); } @Test @@ -330,16 +374,17 @@ verifyWindowFlagsSet(); assertEquals(1, mAttributeResults.size()); - assertEquals(MAX_INIT_POS, mAttributeResults.get(0).y); + + assertTabIsAtInitialPos(mAttributeResults.get(0)); PartialCustomTabHandleStrategy handleStrategy = strategy.new PartialCustomTabHandleStrategy(null); // Drag up slightly -> slide back to the initial height. - assertEquals(MAX_INIT_POS, dragTab(handleStrategy, 1500, 1450, 1400)); + assertTabIsAtInitialPos(dragTab(handleStrategy, 1500, 1450, 1400)); // Drag down slightly -> slide back to the initial height. - assertEquals(MAX_INIT_POS, dragTab(handleStrategy, 1500, 1550, 1600)); + assertTabIsAtInitialPos(dragTab(handleStrategy, 1500, 1550, 1600)); } @Test @@ -350,13 +395,13 @@ verify(mWindow).clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND); assertEquals(1, mAttributeResults.size()); - assertEquals(MAX_INIT_POS, mAttributeResults.get(0).y); + assertTabIsAtInitialPos(mAttributeResults.get(0)); PartialCustomTabHandleStrategy handleStrategy = strategy.new PartialCustomTabHandleStrategy(null); // Shake the tab from the initial position slightly -> back to the initial height. - assertEquals(MAX_INIT_POS, dragTab(handleStrategy, 1500, 1450, 1600)); + assertTabIsAtInitialPos(dragTab(handleStrategy, 1500, 1450, 1600)); } @Test @@ -395,6 +440,9 @@ @Test public void rotateToLandescapeHideCustomNavbar() { + // Custom navigation bar is drawn only on 'Fixed Window'-type implementation. + if (mWindowAboveNavbar) return; + PartialCustomTabHeightStrategy strategy = createPcctAtHeight(800); mConfiguration.orientation = Configuration.ORIENTATION_LANDSCAPE; @@ -447,14 +495,14 @@ verifyWindowFlagsSet(); assertEquals(1, mAttributeResults.size()); - assertEquals(MAX_INIT_POS, mAttributeResults.get(0).y); + assertTabIsAtInitialPos(mAttributeResults.get(0)); PartialCustomTabHandleStrategy handleStrategy = strategy.new PartialCustomTabHandleStrategy(null); final boolean[] closed = {false}; handleStrategy.setCloseClickHandler(() -> closed[0] = true); - dragTab(handleStrategy, MAX_INIT_POS, DEVICE_HEIGHT - 400); + dragTab(handleStrategy, INITIAL_HEIGHT, DEVICE_HEIGHT - 400); assertTrue("Close click handler should be called.", closed[0]); } @@ -466,7 +514,7 @@ verify(mWindow).clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND); assertEquals(1, mAttributeResults.size()); - assertEquals(MAX_INIT_POS, mAttributeResults.get(0).y); + assertTabIsAtInitialPos(mAttributeResults.get(0)); when(mSpinnerView.getVisibility()).thenReturn(View.GONE); @@ -505,7 +553,7 @@ verify(mWindow).clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND); assertEquals(1, mAttributeResults.size()); - assertEquals(MAX_INIT_POS, mAttributeResults.get(0).y); + assertTabIsAtInitialPos(mAttributeResults.get(0)); when(mSpinnerView.getVisibility()).thenReturn(View.GONE); @@ -540,7 +588,7 @@ verify(mWindow).clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND); assertEquals(1, mAttributeResults.size()); - assertEquals(MAX_INIT_POS, mAttributeResults.get(0).y); + assertTabIsAtInitialPos(mAttributeResults.get(0)); when(mSpinnerView.getVisibility()).thenReturn(View.GONE); @@ -548,8 +596,8 @@ strategy.new PartialCustomTabHandleStrategy(null); long timestamp = SystemClock.uptimeMillis(); - actionDown(handleStrategy, timestamp, 1500); - actionMove(handleStrategy, timestamp, 1450); + actionDown(handleStrategy, timestamp, INITIAL_HEIGHT - 100); + actionMove(handleStrategy, timestamp, INITIAL_HEIGHT - 150); // Verify the spinner is visible. verify(mSpinnerView).setVisibility(View.VISIBLE); @@ -557,7 +605,7 @@ clearInvocations(mSpinnerView); // Drag below the initial height. - actionMove(handleStrategy, timestamp, MAX_INIT_POS + 100); + actionMove(handleStrategy, timestamp, INITIAL_HEIGHT + 100); // Verify the spinner goes invisible. verify(mSpinnerView).setVisibility(View.GONE); @@ -567,7 +615,7 @@ public void expandToFullHeightOnShowingKeyboard() { PartialCustomTabHeightStrategy strategy = createPcctAtHeight(500); assertEquals(1, mAttributeResults.size()); - assertEquals(MAX_INIT_POS, mAttributeResults.get(0).y); + assertTabIsAtInitialPos(mAttributeResults.get(0)); strategy.onShowSoftInput(); shadowOf(Looper.getMainLooper()).idle(); @@ -576,7 +624,7 @@ assertTrue(length > 1); // Verify that the tab expands to full height. - assertEquals(0, mAttributeResults.get(length - 1).y); + assertTabIsFullHeight(mAttributeResults.get(length - 1)); } private void verifyWindowFlagsSet() {
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 02b93e9dc..17cf8d0 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -1557,15 +1557,6 @@ {" - tabs don't shrink", kMinimumTabWidthSettingFull, std::size(kMinimumTabWidthSettingFull), nullptr}}; -const FeatureEntry::FeatureParam kAlsoShowMediaTabsinOpenTabsSection[] = { - {features::kTabSearchAlsoShowMediaTabsinOpenTabsSectionParameterName, - "true"}}; - -const FeatureEntry::FeatureVariation kTabSearchMediaTabsVariations[] = { - {" - media tabs also shown in open tabs section", - kAlsoShowMediaTabsinOpenTabsSection, - std::size(kAlsoShowMediaTabsinOpenTabsSection), nullptr}}; - const FeatureEntry::FeatureParam kTabSearchSearchThresholdSmall[] = { {features::kTabSearchSearchThresholdName, "0.3"}}; const FeatureEntry::FeatureParam kTabSearchSearchThresholdMedium[] = { @@ -2063,54 +2054,28 @@ }; const FeatureEntry::FeatureParam kStartSurfaceAndroid_SingleSurface[] = { - {"start_surface_variation", "single"}, + {"open_ntp_instead_of_start", "false"}, + {"show_last_active_tab_only", "false"}, {"show_tabs_in_mru_order", "true"}}; -const FeatureEntry::FeatureParam kStartSurfaceAndroid_SingleSurface_V2[] = { - {"start_surface_variation", "single"}, - {"show_last_active_tab_only", "true"}, - {"open_ntp_instead_of_start", "true"}}; - -const FeatureEntry::FeatureParam kStartSurfaceAndroid_SingleSurfaceSingleTab[] = - {{"start_surface_variation", "single"}, - {"show_last_active_tab_only", "true"}, - {"hide_switch_when_no_incognito_tabs", "true"}}; - const FeatureEntry::FeatureParam kStartSurfaceAndroid_CandidateA[] = { - {"start_surface_variation", "single"}, - {"show_last_active_tab_only", "true"}, - {"hide_switch_when_no_incognito_tabs", "true"}, - {"tab_count_button_on_start_surface", "true"}}; + {"open_ntp_instead_of_start", "false"}}; const FeatureEntry::FeatureParam kStartSurfaceAndroid_CandidateA_SyncCheck[] = { - {"start_surface_variation", "single"}, - {"show_last_active_tab_only", "true"}, - {"hide_switch_when_no_incognito_tabs", "true"}, - {"tab_count_button_on_start_surface", "true"}, + {"open_ntp_instead_of_start", "false"}, {"check_sync_before_show_start_at_startup", "true"}}; const FeatureEntry::FeatureParam kStartSurfaceAndroid_CandidateA_SigninPromoTimeLimit[] = { - {"start_surface_variation", "single"}, - {"show_last_active_tab_only", "true"}, - {"hide_switch_when_no_incognito_tabs", "true"}, - {"tab_count_button_on_start_surface", "true"}, + {"open_ntp_instead_of_start", "false"}, {"sign_in_promo_show_since_last_background_limit_ms", "30000"}}; const FeatureEntry::FeatureParam kStartSurfaceAndroid_CandidateB[] = { - {"start_surface_variation", "single"}, - {"show_last_active_tab_only", "true"}, - {"hide_switch_when_no_incognito_tabs", "true"}, - {"tab_count_button_on_start_surface", "true"}, {"open_ntp_instead_of_start", "true"}}; const FeatureEntry::FeatureParam kStartSurfaceAndroid_CandidateB_AlwaysShowIncognito[] = { - {"start_surface_variation", "single"}, - {"show_last_active_tab_only", "true"}, - {"hide_switch_when_no_incognito_tabs", "false"}, - {"tab_count_button_on_start_surface", "true"}, - {"open_ntp_instead_of_start", "true"}}; + {"hide_switch_when_no_incognito_tabs", "false"}}; const FeatureEntry::FeatureVariation kStartSurfaceAndroidVariations[] = { {"Candidate A", kStartSurfaceAndroid_CandidateA, @@ -2127,10 +2092,6 @@ std::size(kStartSurfaceAndroid_CandidateB_AlwaysShowIncognito), nullptr}, {"Single Surface", kStartSurfaceAndroid_SingleSurface, std::size(kStartSurfaceAndroid_SingleSurface), nullptr}, - {"Single Surface V2", kStartSurfaceAndroid_SingleSurface_V2, - std::size(kStartSurfaceAndroid_SingleSurface_V2), nullptr}, - {"Single Surface + Single Tab", kStartSurfaceAndroid_SingleSurfaceSingleTab, - std::size(kStartSurfaceAndroid_SingleSurfaceSingleTab), nullptr}, }; const FeatureEntry::FeatureParam kFeedPositionAndroid_push_down_feed_small[] = { @@ -6205,6 +6166,10 @@ chrome::android::kCCTResizableForThirdParties, kCCTResizableThirdPartiesDefaultPolicyVariations, "CCTResizableThirdPartiesDefaultPolicy")}, + {"cct-resizable-window-above-navbar", + flag_descriptions::kCCTResizableWindowAboveNavbarName, + flag_descriptions::kCCTResizableWindowAboveNavbarDescription, kOsAndroid, + FEATURE_VALUE_TYPE(chrome::android::kCCTResizableWindowAboveNavbar)}, #endif #if BUILDFLAG(IS_ANDROID) @@ -8018,13 +7983,6 @@ kDrawPredictedPointVariations, "DrawPredictedInkPoint")}, - {flag_descriptions::kTabSearchMediaTabsId, - flag_descriptions::kTabSearchMediaTabsName, - flag_descriptions::kTabSearchMediaTabsDescription, kOsDesktop, - FEATURE_WITH_PARAMS_VALUE_TYPE(features::kTabSearchMediaTabs, - kTabSearchMediaTabsVariations, - "TabSearchMediaTabs")}, - #if BUILDFLAG(IS_ANDROID) {"optimization-guide-push-notifications", flag_descriptions::kOptimizationGuidePushNotificationName,
diff --git a/chrome/browser/android/history_report/data_observer.cc b/chrome/browser/android/history_report/data_observer.cc index 9da2cbc..c39e286 100644 --- a/chrome/browser/android/history_report/data_observer.cc +++ b/chrome/browser/android/history_report/data_observer.cc
@@ -52,7 +52,8 @@ void DataObserver::BookmarkNodeAdded(BookmarkModel* model, const BookmarkNode* parent, - size_t index) { + size_t index, + bool added_by_user) { delta_file_service_->PageAdded(parent->children()[index]->url()); data_changed_callback_.Run(); }
diff --git a/chrome/browser/android/history_report/data_observer.h b/chrome/browser/android/history_report/data_observer.h index 1483daff..dce37315 100644 --- a/chrome/browser/android/history_report/data_observer.h +++ b/chrome/browser/android/history_report/data_observer.h
@@ -54,7 +54,8 @@ size_t new_index) override; void BookmarkNodeAdded(bookmarks::BookmarkModel* model, const bookmarks::BookmarkNode* parent, - size_t index) override; + size_t index, + bool added_by_user) override; void BookmarkNodeRemoved(bookmarks::BookmarkModel* model, const bookmarks::BookmarkNode* parent, size_t old_index,
diff --git a/chrome/browser/ash/floating_workspace/floating_workspace_service.h b/chrome/browser/ash/floating_workspace/floating_workspace_service.h index 3ff776b..3aa0f14 100644 --- a/chrome/browser/ash/floating_workspace/floating_workspace_service.h +++ b/chrome/browser/ash/floating_workspace/floating_workspace_service.h
@@ -38,12 +38,9 @@ void TryRestoreMostRecentlyUsedSession(); private: - // Virtual for testing. - virtual const sync_sessions::SyncedSession* - GetMostRecentlyUsedRemoteSession(); + const sync_sessions::SyncedSession* GetMostRecentlyUsedRemoteSession(); - // Virtual for testing. - virtual const sync_sessions::SyncedSession* GetLocalSession(); + const sync_sessions::SyncedSession* GetLocalSession(); // Virtual for testing. virtual void RestoreForeignSessionWindows( @@ -52,7 +49,8 @@ // Virtual for testing. virtual void RestoreLocalSessionWindows(); - sync_sessions::OpenTabsUIDelegate* GetOpenTabsUIDelegate(); + // Virtual for testing. + virtual sync_sessions::OpenTabsUIDelegate* GetOpenTabsUIDelegate(); Profile* const profile_;
diff --git a/chrome/browser/ash/floating_workspace/floating_workspace_service_unittest.cc b/chrome/browser/ash/floating_workspace/floating_workspace_service_unittest.cc index 64bc034..c2b388b 100644 --- a/chrome/browser/ash/floating_workspace/floating_workspace_service_unittest.cc +++ b/chrome/browser/ash/floating_workspace/floating_workspace_service_unittest.cc
@@ -3,17 +3,22 @@ // found in the LICENSE file. #include "chrome/browser/ash/floating_workspace/floating_workspace_service.h" #include "base/files/scoped_temp_dir.h" +#include "base/ranges/algorithm.h" #include "base/time/time.h" #include "chrome/test/base/testing_profile.h" +#include "components/sync_sessions/open_tabs_ui_delegate.h" #include "components/sync_sessions/synced_session.h" #include "content/public/test/browser_task_environment.h" +#include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" namespace { constexpr char local_session_name[] = "local_session"; -constexpr char remote_session_name[] = "remote_session"; +constexpr char remote_session_1_name[] = "remote_session_1"; +constexpr char remote_session_2_name[] = "remote_session_2"; +const base::Time most_recent_time = base::Time::FromDoubleT(15); const base::Time more_recent_time = base::Time::FromDoubleT(10); -const base::Time less_recent_time = base::Time::FromDoubleT(5); +const base::Time least_recent_time = base::Time::FromDoubleT(5); std::unique_ptr<sync_sessions::SyncedSession> CreateNewSession( const std::string& session_name, const base::Time& session_time) { @@ -22,51 +27,107 @@ session->modified_time = session_time; return session; } + +class MockOpenTabsUIDelegate : public sync_sessions::OpenTabsUIDelegate { + public: + MockOpenTabsUIDelegate() = default; + + bool GetAllForeignSessions( + std::vector<const sync_sessions::SyncedSession*>* sessions) override { + *sessions = foreign_sessions_; + base::ranges::sort(*sessions, std::greater(), + [](const sync_sessions::SyncedSession* session) { + return session->modified_time; + }); + + return !sessions->empty(); + } + + bool GetLocalSession( + const sync_sessions::SyncedSession** local_session) override { + *local_session = local_session_; + return *local_session != nullptr; + } + + void SetForeignSessionsForTesting( + std::vector<const sync_sessions::SyncedSession*> foreign_sessions) { + foreign_sessions_ = foreign_sessions; + } + + void SetLocalSessionForTesting(sync_sessions::SyncedSession* local_session) { + local_session_ = local_session; + } + + MOCK_METHOD3(GetForeignTab, + bool(const std::string& tag, + const SessionID tab_id, + const sessions::SessionTab** tab)); + + MOCK_METHOD1(DeleteForeignSession, void(const std::string& tag)); + + MOCK_METHOD2(GetForeignSession, + bool(const std::string& tag, + std::vector<const sessions::SessionWindow*>* windows)); + + MOCK_METHOD2(GetForeignSessionTabs, + bool(const std::string& tag, + std::vector<const sessions::SessionTab*>* tabs)); + + private: + std::vector<const sync_sessions::SyncedSession*> foreign_sessions_; + sync_sessions::SyncedSession* local_session_ = nullptr; +}; + } // namespace namespace ash { class TestFloatingWorkSpaceService : public ash::FloatingWorkspaceService { public: explicit TestFloatingWorkSpaceService(TestingProfile* profile) - : ash::FloatingWorkspaceService(profile) {} - void RestoreLocalSessionWindows() override { - restored_session_ = GetLocalSession(); + : ash::FloatingWorkspaceService(profile) { + mock_open_tabs_ = std::make_unique<MockOpenTabsUIDelegate>(); } + + void RestoreLocalSessionWindows() override { + mock_open_tabs_->GetLocalSession(&restored_session_); + } + void RestoreForeignSessionWindows( const sync_sessions::SyncedSession* session) override { restored_session_ = session; } - const sync_sessions::SyncedSession* GetLocalSession() override { - return local_session_; - } - const sync_sessions::SyncedSession* GetMostRecentlyUsedRemoteSession() - override { - return most_recently_used_remote_session_; - } + const sync_sessions::SyncedSession* GetRestoredSession() { return restored_session_; } - void SetLocalSessionForTesting(const sync_sessions::SyncedSession* session) { - local_session_ = session; + + void SetLocalSessionForTesting(sync_sessions::SyncedSession* session) { + mock_open_tabs_->SetLocalSessionForTesting(session); } - void SetMostRecentlyUsedRemoteSession( - const sync_sessions::SyncedSession* session) { - most_recently_used_remote_session_ = session; + + void SetForeignSessionForTesting( + std::vector<const sync_sessions::SyncedSession*> foreign_sessions) { + mock_open_tabs_->SetForeignSessionsForTesting(foreign_sessions); } private: + sync_sessions::OpenTabsUIDelegate* GetOpenTabsUIDelegate() override { + return mock_open_tabs_.get(); + } const sync_sessions::SyncedSession* restored_session_ = nullptr; - const sync_sessions::SyncedSession* local_session_ = nullptr; - const sync_sessions::SyncedSession* most_recently_used_remote_session_ = - nullptr; + std::unique_ptr<MockOpenTabsUIDelegate> mock_open_tabs_; }; class FloatingWorkspaceServiceTest : public testing::Test { public: FloatingWorkspaceServiceTest() = default; + ~FloatingWorkspaceServiceTest() override = default; + TestingProfile* profile() const { return profile_.get(); } + const base::TimeDelta GetMaxRestoreTime() { return max_restore_time_; } + void SetUp() override { TestingProfile::Builder profile_builder; base::ScopedTempDir temp_dir; @@ -85,15 +146,22 @@ TEST_F(FloatingWorkspaceServiceTest, RestoreRemoteSession) { TestFloatingWorkSpaceService test_floating_workspace_service(profile()); - // Remote session is more recent at the beginning. std::unique_ptr<sync_sessions::SyncedSession> local_session = - CreateNewSession(local_session_name, less_recent_time); - std::unique_ptr<sync_sessions::SyncedSession> remote_session = - CreateNewSession(remote_session_name, more_recent_time); + CreateNewSession(local_session_name, more_recent_time); + std::vector<const sync_sessions::SyncedSession*> foreign_sessions; + // This remote session has most recent timestamp and should be restored. + const std::unique_ptr<sync_sessions::SyncedSession> + most_recent_remote_session = + CreateNewSession(remote_session_1_name, most_recent_time); + const std::unique_ptr<sync_sessions::SyncedSession> + less_recent_remote_session = + CreateNewSession(remote_session_2_name, least_recent_time); + foreign_sessions.push_back(less_recent_remote_session.get()); + foreign_sessions.push_back(most_recent_remote_session.get()); + test_floating_workspace_service.SetLocalSessionForTesting( local_session.get()); - test_floating_workspace_service.SetMostRecentlyUsedRemoteSession( - remote_session.get()); + test_floating_workspace_service.SetForeignSessionForTesting(foreign_sessions); test_floating_workspace_service .RestoreBrowserWindowsFromMostRecentlyUsedDevice(); // Wait for 3 seconds which is kMaxTimeAvailableForRestoreAfterLogin @@ -102,24 +170,31 @@ FROM_HERE, run_loop.QuitClosure(), GetMaxRestoreTime()); run_loop.Run(); EXPECT_TRUE(test_floating_workspace_service.GetRestoredSession()); - EXPECT_EQ(remote_session_name, + EXPECT_EQ(remote_session_1_name, test_floating_workspace_service.GetRestoredSession()->session_name); } TEST_F(FloatingWorkspaceServiceTest, RestoreLocalSession) { TestFloatingWorkSpaceService test_floating_workspace_service(profile()); - // Local session is more recent. + // Local session has most recent timestamp and should be restored. std::unique_ptr<sync_sessions::SyncedSession> local_session = - CreateNewSession(local_session_name, more_recent_time); - std::unique_ptr<sync_sessions::SyncedSession> remote_session = - CreateNewSession(remote_session_name, less_recent_time); + CreateNewSession(local_session_name, most_recent_time); + std::vector<const sync_sessions::SyncedSession*> foreign_sessions; + const std::unique_ptr<sync_sessions::SyncedSession> + most_recent_remote_session = + CreateNewSession(remote_session_1_name, more_recent_time); + const std::unique_ptr<sync_sessions::SyncedSession> + less_recent_remote_session = + CreateNewSession(remote_session_2_name, least_recent_time); + foreign_sessions.push_back(less_recent_remote_session.get()); + foreign_sessions.push_back(most_recent_remote_session.get()); + test_floating_workspace_service.SetLocalSessionForTesting( local_session.get()); - test_floating_workspace_service.SetMostRecentlyUsedRemoteSession( - remote_session.get()); + test_floating_workspace_service.SetForeignSessionForTesting(foreign_sessions); test_floating_workspace_service .RestoreBrowserWindowsFromMostRecentlyUsedDevice(); - // Wait for 3 seconds which is kMaxTimeAvailableForRestoreAfterLogin. + // Wait for 3 seconds which is kMaxTimeAvailableForRestoreAfterLogin base::RunLoop run_loop; base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( FROM_HERE, run_loop.QuitClosure(), GetMaxRestoreTime()); @@ -131,16 +206,22 @@ TEST_F(FloatingWorkspaceServiceTest, RestoreRemoteSessionAfterUpdated) { TestFloatingWorkSpaceService test_floating_workspace_service(profile()); - // Local session is more recent at the beginning - // but updated remote session within 3 seconds is more recent. + // Local session has most recent timestamp and should be restored. std::unique_ptr<sync_sessions::SyncedSession> local_session = - CreateNewSession(local_session_name, more_recent_time); - std::unique_ptr<sync_sessions::SyncedSession> remote_session = - CreateNewSession(remote_session_name, less_recent_time); + CreateNewSession(local_session_name, most_recent_time); + std::vector<const sync_sessions::SyncedSession*> foreign_sessions; + const std::unique_ptr<sync_sessions::SyncedSession> + most_recent_remote_session = + CreateNewSession(remote_session_1_name, more_recent_time); + const std::unique_ptr<sync_sessions::SyncedSession> + less_recent_remote_session = + CreateNewSession(remote_session_2_name, least_recent_time); + foreign_sessions.push_back(less_recent_remote_session.get()); + foreign_sessions.push_back(most_recent_remote_session.get()); + test_floating_workspace_service.SetLocalSessionForTesting( local_session.get()); - test_floating_workspace_service.SetMostRecentlyUsedRemoteSession( - remote_session.get()); + test_floating_workspace_service.SetForeignSessionForTesting(foreign_sessions); test_floating_workspace_service .RestoreBrowserWindowsFromMostRecentlyUsedDevice(); // Wait for 3 seconds which is kMaxTimeAvailableForRestoreAfterLogin @@ -151,28 +232,34 @@ first_run_loop.Run(); // Remote session got updated during the 3 second delay of dispatching task // and updated remote session is most recent. - base::Time remote_session_updated_time = more_recent_time + base::Seconds(5); - remote_session = - CreateNewSession(remote_session_name, remote_session_updated_time); - test_floating_workspace_service.SetMostRecentlyUsedRemoteSession( - remote_session.get()); + base::Time remote_session_updated_time = most_recent_time + base::Seconds(5); + std::vector<const sync_sessions::SyncedSession*> updated_foreign_sessions; + // Now previously less recent remote session becomes most recent + // and should be restored. + less_recent_remote_session->modified_time = remote_session_updated_time; base::RunLoop second_run_loop; base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( FROM_HERE, second_run_loop.QuitClosure(), GetMaxRestoreTime() - first_run_loop_delay_time); second_run_loop.Run(); EXPECT_TRUE(test_floating_workspace_service.GetRestoredSession()); - EXPECT_EQ(remote_session_name, + EXPECT_EQ(less_recent_remote_session->session_name, test_floating_workspace_service.GetRestoredSession()->session_name); } TEST_F(FloatingWorkspaceServiceTest, NoLocalSession) { TestFloatingWorkSpaceService test_floating_workspace_service(profile()); - std::unique_ptr<sync_sessions::SyncedSession> remote_session = - CreateNewSession(remote_session_name, less_recent_time); - test_floating_workspace_service.SetLocalSessionForTesting(nullptr); - test_floating_workspace_service.SetMostRecentlyUsedRemoteSession( - remote_session.get()); + std::vector<const sync_sessions::SyncedSession*> foreign_sessions; + const std::unique_ptr<sync_sessions::SyncedSession> + most_recent_remote_session = + CreateNewSession(remote_session_1_name, more_recent_time); + const std::unique_ptr<sync_sessions::SyncedSession> + less_recent_remote_session = + CreateNewSession(remote_session_2_name, least_recent_time); + foreign_sessions.push_back(less_recent_remote_session.get()); + foreign_sessions.push_back(most_recent_remote_session.get()); + test_floating_workspace_service.SetForeignSessionForTesting(foreign_sessions); + test_floating_workspace_service .RestoreBrowserWindowsFromMostRecentlyUsedDevice(); // Wait for 3 seconds which is kMaxTimeAvailableForRestoreAfterLogin @@ -181,16 +268,16 @@ FROM_HERE, run_loop.QuitClosure(), GetMaxRestoreTime()); run_loop.Run(); EXPECT_TRUE(test_floating_workspace_service.GetRestoredSession()); - EXPECT_EQ(remote_session_name, + EXPECT_EQ(most_recent_remote_session->session_name, test_floating_workspace_service.GetRestoredSession()->session_name); } + TEST_F(FloatingWorkspaceServiceTest, NoRemoteSession) { TestFloatingWorkSpaceService test_floating_workspace_service(profile()); std::unique_ptr<sync_sessions::SyncedSession> local_session = - CreateNewSession(local_session_name, less_recent_time); + CreateNewSession(local_session_name, least_recent_time); test_floating_workspace_service.SetLocalSessionForTesting( local_session.get()); - test_floating_workspace_service.SetMostRecentlyUsedRemoteSession(nullptr); test_floating_workspace_service .RestoreBrowserWindowsFromMostRecentlyUsedDevice(); // Wait for 3 seconds which is kMaxTimeAvailableForRestoreAfterLogin @@ -205,8 +292,6 @@ TEST_F(FloatingWorkspaceServiceTest, NoSession) { TestFloatingWorkSpaceService test_floating_workspace_service(profile()); - test_floating_workspace_service.SetLocalSessionForTesting(nullptr); - test_floating_workspace_service.SetMostRecentlyUsedRemoteSession(nullptr); test_floating_workspace_service .RestoreBrowserWindowsFromMostRecentlyUsedDevice(); // Wait for 3 seconds which is kMaxTimeAvailableForRestoreAfterLogin.
diff --git a/chrome/browser/ash/policy/reporting/metrics_reporting/metric_browsertest_utils.cc b/chrome/browser/ash/policy/reporting/metrics_reporting/metric_browsertest_utils.cc new file mode 100644 index 0000000..8696b9a --- /dev/null +++ b/chrome/browser/ash/policy/reporting/metrics_reporting/metric_browsertest_utils.cc
@@ -0,0 +1,47 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ash/policy/reporting/metrics_reporting/metric_browsertest_utils.h" + +#include "chrome/browser/ash/policy/core/browser_policy_connector_ash.h" +#include "chrome/browser/chromeos/reporting/metric_default_utils.h" +#include "components/policy/core/common/cloud/cloud_policy_core.h" + +namespace ash::reporting { + +MetricBrowserTestBase::MetricBrowserTestBase() { + device_state_.set_skip_initial_policy_setup(true); +} + +MetricBrowserTestBase::~MetricBrowserTestBase() = default; + +void MetricBrowserTestBase::OnCoreConnected(policy::CloudPolicyCore* core) { + run_loop_->Quit(); + mock_task_runner_ = + std::make_unique<base::ScopedMockTimeMessageLoopTaskRunner>(); +} + +void MetricBrowserTestBase::OnRefreshSchedulerStarted( + policy::CloudPolicyCore* core) {} + +void MetricBrowserTestBase::OnCoreDisconnecting(policy::CloudPolicyCore* core) { +} + +void MetricBrowserTestBase::SetUpDelayedInitialization() { + auto* browser_policy_manager = g_browser_process->platform_part() + ->browser_policy_connector_ash() + ->GetDeviceCloudPolicyManager(); + run_loop_ = std::make_unique<base::RunLoop>(); + browser_policy_manager->core()->AddObserver(this); + device_state_.RequestDevicePolicyUpdate(); + run_loop_->Run(); + mock_task_runner_->task_runner()->FastForwardBy( + ::reporting::metrics::kInitDelay); + browser_policy_manager->core()->RemoveObserver(this); + // Destroy the mock task runner. The test can create its own + // ScopedMockTimeMessageLoopTaskRunner if it requires further time control. + mock_task_runner_.reset(); +} + +} // namespace ash::reporting
diff --git a/chrome/browser/ash/policy/reporting/metrics_reporting/metric_browsertest_utils.h b/chrome/browser/ash/policy/reporting/metrics_reporting/metric_browsertest_utils.h new file mode 100644 index 0000000..5b53425 --- /dev/null +++ b/chrome/browser/ash/policy/reporting/metrics_reporting/metric_browsertest_utils.h
@@ -0,0 +1,55 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_ASH_POLICY_REPORTING_METRICS_REPORTING_METRIC_BROWSERTEST_UTILS_H_ +#define CHROME_BROWSER_ASH_POLICY_REPORTING_METRICS_REPORTING_METRIC_BROWSERTEST_UTILS_H_ + +#include "base/test/scoped_mock_time_message_loop_task_runner.h" +#include "chrome/browser/ash/policy/core/device_policy_cros_browser_test.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/browser_process_platform_part.h" +#include "components/policy/core/common/cloud/cloud_policy_core.h" +#include "content/public/test/browser_test.h" + +namespace ash::reporting { + +// The base class of metric browser tests. + +// One main challenge of the metric browser tests is the delayed initialization +// (which enqueues info metric) by |MetricReportingManager|: It must be called +// after |MissiveClientTestObserver| has been set up (so setting delayed +// initialization time to zero won't work) but before the rest of the test body. +// Therefore, some mock time manipulation is required. Due to the complexity of +// mocking time in browser tests, this class addresses the issue as follows: +// +// - In its constructor, initial policy setup is skipped. This prevents delayed +// initialization task from being posted. +// - A method |SetUpDelayedInitialization| is provided. This should be called +// after |MissiveClientTestObserver| has been initialized and device settings +// have been set. +// +// Check out network/network_info_sampler_browsertest.cc for an example. +class MetricBrowserTestBase : public policy::DevicePolicyCrosBrowserTest, + public policy::CloudPolicyCore::Observer { + protected: + MetricBrowserTestBase(); + ~MetricBrowserTestBase() override; + + // Called after the core is connected. + void OnCoreConnected(policy::CloudPolicyCore* core) override; + // Called after the refresh scheduler is started. + void OnRefreshSchedulerStarted(policy::CloudPolicyCore* core) override; + // Called before the core is disconnected. + void OnCoreDisconnecting(policy::CloudPolicyCore* core) override; + + // Run |MetricReportingManager::DelayedInit| by advancing the mock clock. + void SetUpDelayedInitialization(); + + private: + std::unique_ptr<base::ScopedMockTimeMessageLoopTaskRunner> mock_task_runner_; + std::unique_ptr<base::RunLoop> run_loop_; +}; +} // namespace ash::reporting + +#endif // CHROME_BROWSER_ASH_POLICY_REPORTING_METRICS_REPORTING_METRIC_BROWSERTEST_UTILS_H_
diff --git a/chrome/browser/ash/policy/reporting/metrics_reporting/network/network_info_sampler_browsertest.cc b/chrome/browser/ash/policy/reporting/metrics_reporting/network/network_info_sampler_browsertest.cc new file mode 100644 index 0000000..4749309 --- /dev/null +++ b/chrome/browser/ash/policy/reporting/metrics_reporting/network/network_info_sampler_browsertest.cc
@@ -0,0 +1,72 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/components/settings/cros_settings_names.h" +#include "chrome/browser/ash/login/test/session_manager_state_waiter.h" +#include "chrome/browser/ash/policy/core/device_policy_cros_browser_test.h" +#include "chrome/browser/ash/policy/reporting/metrics_reporting/metric_browsertest_utils.h" +#include "chrome/browser/ash/settings/scoped_testing_cros_settings.h" +#include "chrome/browser/ash/settings/stub_cros_settings_provider.h" +#include "chromeos/dbus/missive/missive_client_test_observer.h" +#include "components/policy/core/common/cloud/cloud_policy_core.h" +#include "components/reporting/proto/synced/metric_data.pb.h" +#include "components/reporting/proto/synced/record.pb.h" +#include "components/reporting/proto/synced/record_constants.pb.h" +#include "content/public/test/browser_test.h" + +namespace ash::reporting { + +namespace { + +using ::chromeos::MissiveClientTestObserver; +using ::reporting::Destination; +using ::reporting::MetricData; +using ::reporting::Priority; +using ::testing::Eq; +using ::testing::NotNull; + +class NetworkInfoSamplerBrowserTest : public MetricBrowserTestBase { + protected: + NetworkInfoSamplerBrowserTest() = default; + ~NetworkInfoSamplerBrowserTest() override = default; + ScopedTestingCrosSettings scoped_testing_cros_settings_; +}; + +IN_PROC_BROWSER_TEST_F(NetworkInfoSamplerBrowserTest, + ReportNetworkInfoDefaultDevices) { + // Default network devices + scoped_testing_cros_settings_.device_settings()->SetBoolean( + kReportDeviceNetworkInterfaces, true); + MissiveClientTestObserver observer(Destination::INFO_METRIC); + // Start initialization after the observer is initialized. + SetUpDelayedInitialization(); + + // Indicates at least one network interface is available. + bool has_network_interfaces = false; + do { + // At least one record, otherwise this line would time out when the loop is + // entered for the first time. + auto [priority, record] = observer.GetNextEnqueuedRecord(); + EXPECT_THAT(priority, Eq(Priority::SLOW_BATCH)); + EXPECT_THAT(record.destination(), Eq(Destination::INFO_METRIC)); + ::reporting::MetricData record_data; + ASSERT_TRUE(record_data.ParseFromString(record.data())); + EXPECT_TRUE(record_data.has_timestamp_ms()); + EXPECT_TRUE(record_data.has_info_data()); + EXPECT_FALSE(record_data.has_telemetry_data()); + + const auto& info_data = record_data.info_data(); + if (info_data.has_networks_info()) { + const auto& networks_info = info_data.networks_info(); + has_network_interfaces |= (networks_info.network_interfaces_size() > 0); + } + } while (!has_network_interfaces); + + ASSERT_TRUE(has_network_interfaces) + << "No network interface is in any records."; +} + +} // namespace + +} // namespace ash::reporting
diff --git a/chrome/browser/bookmarks/android/bookmark_bridge.cc b/chrome/browser/bookmarks/android/bookmark_bridge.cc index cc7cbad..4bc99d06 100644 --- a/chrome/browser/bookmarks/android/bookmark_bridge.cc +++ b/chrome/browser/bookmarks/android/bookmark_bridge.cc
@@ -1257,7 +1257,8 @@ void BookmarkBridge::BookmarkNodeAdded(BookmarkModel* model, const BookmarkNode* parent, - size_t index) { + size_t index, + bool added_by_user) { if (!IsLoaded()) return;
diff --git a/chrome/browser/bookmarks/android/bookmark_bridge.h b/chrome/browser/bookmarks/android/bookmark_bridge.h index bdacd62..aea7945 100644 --- a/chrome/browser/bookmarks/android/bookmark_bridge.h +++ b/chrome/browser/bookmarks/android/bookmark_bridge.h
@@ -342,7 +342,8 @@ size_t new_index) override; void BookmarkNodeAdded(bookmarks::BookmarkModel* model, const bookmarks::BookmarkNode* parent, - size_t index) override; + size_t index, + bool added_by_user) override; void BookmarkNodeRemoved(bookmarks::BookmarkModel* model, const bookmarks::BookmarkNode* parent, size_t old_index,
diff --git a/chrome/browser/bookmarks/managed_bookmark_service_unittest.cc b/chrome/browser/bookmarks/managed_bookmark_service_unittest.cc index d3f327c..2295f0e 100644 --- a/chrome/browser/bookmarks/managed_bookmark_service_unittest.cc +++ b/chrome/browser/bookmarks/managed_bookmark_service_unittest.cc
@@ -233,7 +233,7 @@ base::Value::List updated; updated.Append(CreateFolder("Container", CreateTestTree())); - EXPECT_CALL(observer_, BookmarkNodeAdded(model_.get(), _, _)).Times(5); + EXPECT_CALL(observer_, BookmarkNodeAdded(model_.get(), _, _, _)).Times(5); // The remaining nodes have been pushed to positions 1 and 2; they'll both be // removed when at position 1. const BookmarkNode* parent = managed_->managed_node(); @@ -291,10 +291,10 @@ TEST_F(ManagedBookmarkServiceTest, RemoveAllDoesntRemoveManaged) { EXPECT_EQ(2u, managed_->managed_node()->children().size()); - EXPECT_CALL(observer_, - BookmarkNodeAdded(model_.get(), model_->bookmark_bar_node(), 0)); - EXPECT_CALL(observer_, - BookmarkNodeAdded(model_.get(), model_->bookmark_bar_node(), 1)); + EXPECT_CALL(observer_, BookmarkNodeAdded(model_.get(), + model_->bookmark_bar_node(), 0, _)); + EXPECT_CALL(observer_, BookmarkNodeAdded(model_.get(), + model_->bookmark_bar_node(), 1, _)); model_->AddURL(model_->bookmark_bar_node(), 0, u"Test", GURL("http://google.com/")); model_->AddFolder(model_->bookmark_bar_node(), 1, u"Test Folder");
diff --git a/chrome/browser/browsing_data/browsing_data_remover_browsertest.cc b/chrome/browser/browsing_data/browsing_data_remover_browsertest.cc index cfa6a3f..bbaf393 100644 --- a/chrome/browser/browsing_data/browsing_data_remover_browsertest.cc +++ b/chrome/browser/browsing_data/browsing_data_remover_browsertest.cc
@@ -78,7 +78,6 @@ #include "chromeos/startup/browser_init_params.h" #include "components/account_manager_core/account.h" #include "components/account_manager_core/account_manager_util.h" -#include "components/signin/public/identity_manager/identity_test_utils.h" #endif using content::BrowserThread;
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc index fb7da1181..aa29c8a 100644 --- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc +++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
@@ -147,7 +147,6 @@ #include "chrome/browser/offline_pages/offline_page_model_factory.h" #include "chrome/browser/profiles/profile_android.h" #include "components/cdm/browser/media_drm_storage_impl.h" // nogncheck crbug.com/1125897 -#include "components/feed/buildflags.h" #include "components/feed/core/v2/public/feed_service.h" #include "components/feed/feed_feature_list.h" #include "components/installedapp/android/jni_headers/PackageHash_jni.h" @@ -170,7 +169,6 @@ #if BUILDFLAG(IS_CHROMEOS_ASH) #include "chrome/browser/ash/net/system_proxy_manager.h" #include "chrome/browser/ash/profiles/profile_helper.h" -#include "chrome/browser/browser_process.h" #include "chrome/browser/browser_process_platform_part.h" #include "chromeos/ash/components/cryptohome/cryptohome_parameters.h" #include "chromeos/ash/components/dbus/attestation/attestation_client.h"
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc index c2992590..0c2dfbca 100644 --- a/chrome/browser/chrome_browser_main.cc +++ b/chrome/browser/chrome_browser_main.cc
@@ -251,16 +251,16 @@ #if BUILDFLAG(IS_MAC) #include <Security/Security.h> +#if defined(ARCH_CPU_X86_64) +#include "base/mac/mac_util.h" +#include "base/threading/platform_thread.h" +#endif // defined(ARCH_CPU_X86_64) + #include "chrome/browser/app_controller_mac.h" #include "chrome/browser/mac/keystone_glue.h" #include "chrome/browser/ui/ui_features.h" #endif // BUILDFLAG(IS_MAC) -// TODO(port): several win-only methods have been pulled out of this, but -// BrowserMain() as a whole needs to be broken apart so that it's usable by -// other platforms. For now, it's just a stub. This is a serious work in -// progress and should not be taken as an indication of a real refactoring. - #if BUILDFLAG(IS_WIN) #include "base/trace_event/trace_event_etw_export_win.h" #include "base/win/win_util.h" @@ -1048,6 +1048,20 @@ // BUILDFLAG(IS_OPENBSD) #if BUILDFLAG(IS_MAC) +#if defined(ARCH_CPU_X86_64) + // The use of Rosetta to run the x64 version of Chromium on Arm is neither + // tested nor maintained, and there are reports of it crashing in weird ways + // (e.g. https://crbug.com/1305353). Warn the user if this is the case, as + // it's almost certainly accidental on their part. + if (base::mac::GetCPUType() == base::mac::CPUType::kTranslatedIntel) { + LOG(ERROR) << "The use of Rosetta to run the x64 version of Chromium on " + "Arm is neither tested nor maintained, and unexpected " + "behavior will likely result. Please check that all tools " + "that spawn Chromium are Arm-native."; + base::PlatformThread::Sleep(base::Seconds(3)); + } +#endif // defined(ARCH_CPU_X86_64) + // Get the Keychain API to register for distributed notifications on the main // thread, which has a proper CFRunloop, instead of later on the I/O thread, // which doesn't. This ensures those notifications will get delivered
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc index 0fbdf34..164c1191 100644 --- a/chrome/browser/chrome_content_browser_client.cc +++ b/chrome/browser/chrome_content_browser_client.cc
@@ -3034,6 +3034,19 @@ accessing_origin); } +bool ChromeContentBrowserClient::IsPrivateAggregationAllowed( + content::BrowserContext* browser_context, + const url::Origin& top_frame_origin, + const url::Origin& reporting_origin) { + Profile* profile = Profile::FromBrowserContext(browser_context); + auto* privacy_sandbox_settings = + PrivacySandboxSettingsFactory::GetForProfile(profile); + DCHECK(privacy_sandbox_settings); + + return privacy_sandbox_settings->IsPrivateAggregationAllowed( + top_frame_origin, reporting_origin); +} + #if BUILDFLAG(IS_CHROMEOS) void ChromeContentBrowserClient::OnTrustAnchorUsed( content::BrowserContext* browser_context) { @@ -3463,7 +3476,8 @@ frame_name, disposition, features, user_gesture, opener_suppressed); NavigateParams nav_params = blocked_params.CreateNavigateParams(opener->GetProcess(), web_contents); - return blocked_content::MaybeBlockPopup( + return !blocked_content::ConsiderForPopupBlocking(disposition) || + blocked_content::MaybeBlockPopup( web_contents, &opener_top_level_frame_url, std::make_unique<ChromePopupNavigationDelegate>( std::move(nav_params)),
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h index 268836f..edaf7a0 100644 --- a/chrome/browser/chrome_content_browser_client.h +++ b/chrome/browser/chrome_content_browser_client.h
@@ -313,6 +313,10 @@ bool IsSharedStorageAllowed(content::BrowserContext* browser_context, const url::Origin& top_frame_origin, const url::Origin& accessing_origin) override; + bool IsPrivateAggregationAllowed( + content::BrowserContext* browser_context, + const url::Origin& top_frame_origin, + const url::Origin& reporting_origin) override; #if BUILDFLAG(IS_CHROMEOS) void OnTrustAnchorUsed(content::BrowserContext* browser_context) override; #endif
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn index c65af2f..f9d320b 100644 --- a/chrome/browser/chromeos/BUILD.gn +++ b/chrome/browser/chromeos/BUILD.gn
@@ -3560,7 +3560,6 @@ "../ui/webui/settings/ash/search/search_handler_unittest.cc", "../ui/webui/settings/ash/search/search_tag_registry_unittest.cc", "../ui/webui/settings/chromeos/bluetooth_handler_unittest.cc", - "../ui/webui/settings/chromeos/change_picture_handler_unittest.cc", "../ui/webui/settings/chromeos/device_keyboard_handler_unittest.cc", "../ui/webui/settings/chromeos/device_name_handler_unittest.cc", "../ui/webui/settings/chromeos/device_storage_handler_unittest.cc",
diff --git a/chrome/browser/component_updater/recovery_improved_component_installer.cc b/chrome/browser/component_updater/recovery_improved_component_installer.cc index 454d3e1c..963f7ce4 100644 --- a/chrome/browser/component_updater/recovery_improved_component_installer.cc +++ b/chrome/browser/component_updater/recovery_improved_component_installer.cc
@@ -28,7 +28,6 @@ #include "base/strings/utf_string_conversions.h" #include "base/task/thread_pool.h" #include "base/time/time.h" -#include "build/build_config.h" #include "chrome/browser/component_updater/component_updater_utils.h" #include "components/services/unzip/content/unzip_service.h" #include "components/update_client/patcher.h"
diff --git a/chrome/browser/content_settings/sound_content_setting_observer_browsertest.cc b/chrome/browser/content_settings/sound_content_setting_observer_browsertest.cc index 100a404..6d9386ce 100644 --- a/chrome/browser/content_settings/sound_content_setting_observer_browsertest.cc +++ b/chrome/browser/content_settings/sound_content_setting_observer_browsertest.cc
@@ -8,7 +8,6 @@ #include "base/test/bind.h" #include "base/test/scoped_feature_list.h" #include "chrome/browser/content_settings/host_content_settings_map_factory.h" -#include "chrome/browser/content_settings/sound_content_setting_observer.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" #include "chrome/test/base/in_process_browser_test.h"
diff --git a/chrome/browser/dev_ui/android/dev_ui_loader_throttle.cc b/chrome/browser/dev_ui/android/dev_ui_loader_throttle.cc index c366c1b1..4b65863 100644 --- a/chrome/browser/dev_ui/android/dev_ui_loader_throttle.cc +++ b/chrome/browser/dev_ui/android/dev_ui_loader_throttle.cc
@@ -62,6 +62,7 @@ host == chrome::kChromeUIUserActionsHost || host == chrome::kChromeUIWebApksHost || host == chrome::kChromeUIWebRtcLogsHost || + host == content::kChromeUIPrivateAggregationInternalsHost || host == content::kChromeUIAttributionInternalsHost || host == content::kChromeUIBlobInternalsHost || host == content::kChromeUIGpuHost ||
diff --git a/chrome/browser/device_identity/chromeos/device_oauth2_token_store_chromeos_unittest.cc b/chrome/browser/device_identity/chromeos/device_oauth2_token_store_chromeos_unittest.cc index 389387f..1310450 100644 --- a/chrome/browser/device_identity/chromeos/device_oauth2_token_store_chromeos_unittest.cc +++ b/chrome/browser/device_identity/chromeos/device_oauth2_token_store_chromeos_unittest.cc
@@ -11,7 +11,6 @@ #include "chrome/browser/ash/policy/core/device_policy_builder.h" #include "chrome/browser/ash/settings/cros_settings.h" #include "chrome/browser/ash/settings/device_settings_service.h" -#include "chrome/browser/device_identity/chromeos/device_oauth2_token_store_chromeos.h" #include "chrome/common/pref_names.h" #include "chrome/test/base/scoped_testing_local_state.h" #include "chrome/test/base/testing_browser_process.h"
diff --git a/chrome/browser/extensions/api/bookmarks/bookmarks_api.cc b/chrome/browser/extensions/api/bookmarks/bookmarks_api.cc index 33287dd0..1ef29a9 100644 --- a/chrome/browser/extensions/api/bookmarks/bookmarks_api.cc +++ b/chrome/browser/extensions/api/bookmarks/bookmarks_api.cc
@@ -284,7 +284,8 @@ void BookmarkEventRouter::BookmarkNodeAdded(BookmarkModel* model, const BookmarkNode* parent, - size_t index) { + size_t index, + bool added_by_user) { const BookmarkNode* node = parent->children()[index].get(); BookmarkTreeNode tree_node = bookmark_api_helpers::GetBookmarkTreeNode(managed_, node, false, false);
diff --git a/chrome/browser/extensions/api/bookmarks/bookmarks_api.h b/chrome/browser/extensions/api/bookmarks/bookmarks_api.h index 9912ca1..fddfba66 100644 --- a/chrome/browser/extensions/api/bookmarks/bookmarks_api.h +++ b/chrome/browser/extensions/api/bookmarks/bookmarks_api.h
@@ -65,7 +65,8 @@ size_t new_index) override; void BookmarkNodeAdded(bookmarks::BookmarkModel* model, const bookmarks::BookmarkNode* parent, - size_t index) override; + size_t index, + bool added_by_user) override; void BookmarkNodeRemoved(bookmarks::BookmarkModel* model, const bookmarks::BookmarkNode* parent, size_t old_index,
diff --git a/chrome/browser/extensions/api/commands/command_service.cc b/chrome/browser/extensions/api/commands/command_service.cc index 0dd3a1d..a3065da 100644 --- a/chrome/browser/extensions/api/commands/command_service.cc +++ b/chrome/browser/extensions/api/commands/command_service.cc
@@ -74,23 +74,20 @@ // Merge |suggested_key_prefs| into the saved preferences for the extension. We // merge rather than overwrite to preserve existing was_assigned preferences. -void MergeSuggestedKeyPrefs( - const std::string& extension_id, - ExtensionPrefs* extension_prefs, - std::unique_ptr<base::DictionaryValue> suggested_key_prefs) { - const base::DictionaryValue* current_prefs; - if (extension_prefs->ReadPrefAsDictionary(extension_id, - kCommands, - ¤t_prefs)) { - std::unique_ptr<base::DictionaryValue> new_prefs = - base::DictionaryValue::From( - base::Value::ToUniquePtrValue(current_prefs->Clone())); - new_prefs->MergeDictionary(suggested_key_prefs.get()); +void MergeSuggestedKeyPrefs(const std::string& extension_id, + ExtensionPrefs* extension_prefs, + base::Value::Dict suggested_key_prefs) { + const base::Value::Dict* current_prefs = + extension_prefs->ReadPrefAsDict(extension_id, kCommands); + if (current_prefs) { + base::Value::Dict new_prefs = current_prefs->Clone(); + new_prefs.Merge(std::move(suggested_key_prefs)); suggested_key_prefs = std::move(new_prefs); } - extension_prefs->UpdateExtensionPref(extension_id, kCommands, - std::move(suggested_key_prefs)); + extension_prefs->UpdateExtensionPref( + extension_id, kCommands, + std::make_unique<base::Value>(std::move(suggested_key_prefs))); } } // namespace @@ -223,12 +220,10 @@ bindings->SetKey(key, std::move(keybinding)); // Set the was_assigned pref for the suggested key. - std::unique_ptr<base::DictionaryValue> command_keys( - new base::DictionaryValue); - command_keys->SetBoolKey(kSuggestedKeyWasAssigned, true); - std::unique_ptr<base::DictionaryValue> suggested_key_prefs( - new base::DictionaryValue); - suggested_key_prefs->Set(command_name, std::move(command_keys)); + base::Value::Dict command_keys; + command_keys.Set(kSuggestedKeyWasAssigned, true); + base::Value::Dict suggested_key_prefs; + suggested_key_prefs.Set(command_name, base::Value(std::move(command_keys))); MergeSuggestedKeyPrefs(extension_id, ExtensionPrefs::Get(profile_), std::move(suggested_key_prefs)); @@ -503,18 +498,16 @@ void CommandService::UpdateExtensionSuggestedCommandPrefs( const Extension* extension) { - std::unique_ptr<base::DictionaryValue> suggested_key_prefs( - new base::DictionaryValue); + base::Value::Dict suggested_key_prefs; const CommandMap* commands = CommandsInfo::GetNamedCommands(extension); if (commands) { for (auto iter = commands->cbegin(); iter != commands->cend(); ++iter) { const Command command = iter->second; - std::unique_ptr<base::DictionaryValue> command_keys( - new base::DictionaryValue); - command_keys->SetStringKey( - kSuggestedKey, Command::AcceleratorToString(command.accelerator())); - suggested_key_prefs->Set(command.command_name(), std::move(command_keys)); + base::Value::Dict command_keys; + command_keys.Set(kSuggestedKey, + Command::AcceleratorToString(command.accelerator())); + suggested_key_prefs.Set(command.command_name(), std::move(command_keys)); } } @@ -525,25 +518,21 @@ // declared. See CommandsHandler::MaybeSetBrowserActionDefault. if (browser_action_command && browser_action_command->accelerator().key_code() != ui::VKEY_UNKNOWN) { - std::unique_ptr<base::DictionaryValue> command_keys( - new base::DictionaryValue); - command_keys->SetStringKey( - kSuggestedKey, - Command::AcceleratorToString(browser_action_command->accelerator())); - suggested_key_prefs->Set(browser_action_command->command_name(), - std::move(command_keys)); + base::Value::Dict command_keys; + command_keys.Set(kSuggestedKey, Command::AcceleratorToString( + browser_action_command->accelerator())); + suggested_key_prefs.Set(browser_action_command->command_name(), + std::move(command_keys)); } const Command* page_action_command = CommandsInfo::GetPageActionCommand(extension); if (page_action_command) { - std::unique_ptr<base::DictionaryValue> command_keys( - new base::DictionaryValue); - command_keys->SetStringKey( - kSuggestedKey, - Command::AcceleratorToString(page_action_command->accelerator())); - suggested_key_prefs->Set(page_action_command->command_name(), - std::move(command_keys)); + base::Value::Dict command_keys; + command_keys.Set(kSuggestedKey, Command::AcceleratorToString( + page_action_command->accelerator())); + suggested_key_prefs.Set(page_action_command->command_name(), + std::move(command_keys)); } // Merge into current prefs, if present.
diff --git a/chrome/browser/extensions/api/declarative_content/declarative_content_is_bookmarked_condition_tracker.cc b/chrome/browser/extensions/api/declarative_content/declarative_content_is_bookmarked_condition_tracker.cc index d1b23b9d..4c549e6e 100644 --- a/chrome/browser/extensions/api/declarative_content/declarative_content_is_bookmarked_condition_tracker.cc +++ b/chrome/browser/extensions/api/declarative_content/declarative_content_is_bookmarked_condition_tracker.cc
@@ -219,7 +219,8 @@ void DeclarativeContentIsBookmarkedConditionTracker::BookmarkNodeAdded( bookmarks::BookmarkModel* model, const bookmarks::BookmarkNode* parent, - size_t index) { + size_t index, + bool added_by_user) { if (!extensive_bookmark_changes_in_progress_) { for (const auto& web_contents_tracker_pair : per_web_contents_tracker_) { web_contents_tracker_pair.second->BookmarkAddedForUrl(
diff --git a/chrome/browser/extensions/api/declarative_content/declarative_content_is_bookmarked_condition_tracker.h b/chrome/browser/extensions/api/declarative_content/declarative_content_is_bookmarked_condition_tracker.h index 64f45305..d757f7b6 100644 --- a/chrome/browser/extensions/api/declarative_content/declarative_content_is_bookmarked_condition_tracker.h +++ b/chrome/browser/extensions/api/declarative_content/declarative_content_is_bookmarked_condition_tracker.h
@@ -138,7 +138,8 @@ void BookmarkModelChanged() override; void BookmarkNodeAdded(bookmarks::BookmarkModel* model, const bookmarks::BookmarkNode* parent, - size_t index) override; + size_t index, + bool added_by_user) override; void BookmarkNodeRemoved(bookmarks::BookmarkModel* model, const bookmarks::BookmarkNode* parent, size_t old_index,
diff --git a/chrome/browser/extensions/api/settings_private/prefs_util.cc b/chrome/browser/extensions/api/settings_private/prefs_util.cc index 45c3d7b..9f6a5218 100644 --- a/chrome/browser/extensions/api/settings_private/prefs_util.cc +++ b/chrome/browser/extensions/api/settings_private/prefs_util.cc
@@ -348,6 +348,8 @@ settings_api::PrefType::PREF_TYPE_BOOLEAN; (*s_allowlist)[translate::prefs::kBlockedLanguages] = settings_api::PrefType::PREF_TYPE_LIST; + (*s_allowlist)[translate::prefs::kPrefNeverPromptSitesWithTime] = + settings_api::PrefType::PREF_TYPE_LIST; (*s_allowlist)[language::prefs::kSelectedLanguages] = settings_api::PrefType::PREF_TYPE_STRING; (*s_allowlist)[language::prefs::kForcedLanguages] =
diff --git a/chrome/browser/extensions/api/web_request/web_request_apitest.cc b/chrome/browser/extensions/api/web_request/web_request_apitest.cc index 361206df..a2beb699 100644 --- a/chrome/browser/extensions/api/web_request/web_request_apitest.cc +++ b/chrome/browser/extensions/api/web_request/web_request_apitest.cc
@@ -333,8 +333,6 @@ } // namespace -using ContextType = ExtensionBrowserTest::ContextType; - class ExtensionWebRequestApiTest : public ExtensionApiTest { public: explicit ExtensionWebRequestApiTest( @@ -401,6 +399,29 @@ std::unique_ptr<NavigateTabMessageHandler> navigationHandler_; }; +using ContextType = ExtensionBrowserTest::ContextType; + +class ExtensionWebRequestApiTestWithContextType + : public ExtensionWebRequestApiTest, + public testing::WithParamInterface<ContextType> { + public: + ExtensionWebRequestApiTestWithContextType() + : ExtensionWebRequestApiTest(GetParam()) {} + ExtensionWebRequestApiTestWithContextType( + const ExtensionWebRequestApiTestWithContextType&) = delete; + ExtensionWebRequestApiTestWithContextType& operator=( + const ExtensionWebRequestApiTestWithContextType&) = delete; + ~ExtensionWebRequestApiTestWithContextType() override = default; +}; + +INSTANTIATE_TEST_SUITE_P(PersistentBackground, + ExtensionWebRequestApiTestWithContextType, + ::testing::Values(ContextType::kPersistentBackground)); + +INSTANTIATE_TEST_SUITE_P(ServiceWorker, + ExtensionWebRequestApiTestWithContextType, + ::testing::Values(ContextType::kServiceWorker)); + class DevToolsFrontendInWebRequestApiTest : public ExtensionApiTest { public: void SetUpOnMainThread() override { @@ -895,7 +916,7 @@ } // Flaky on all platforms: https://crbug.com/1003661 -IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, +IN_PROC_BROWSER_TEST_P(ExtensionWebRequestApiTestWithContextType, DISABLED_WebRequestExtraHeaders_Auth) { CancelLoginDialog login_dialog_helper; @@ -904,24 +925,26 @@ << message_; } -IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, WebRequestChangeCSPHeaders) { +IN_PROC_BROWSER_TEST_P(ExtensionWebRequestApiTestWithContextType, + WebRequestChangeCSPHeaders) { ASSERT_TRUE(StartEmbeddedTestServer()); ASSERT_TRUE(RunExtensionTest("webrequest/test_change_csp_headers")) << message_; } -IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, +IN_PROC_BROWSER_TEST_P(ExtensionWebRequestApiTestWithContextType, WebRequestCORSWithExtraHeaders) { ASSERT_TRUE(StartEmbeddedTestServer()); ASSERT_TRUE(RunExtensionTest("webrequest/test_cors")) << message_; } -IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, WebRequestRedirects) { +IN_PROC_BROWSER_TEST_P(ExtensionWebRequestApiTestWithContextType, + WebRequestRedirects) { ASSERT_TRUE(StartEmbeddedTestServer()); ASSERT_TRUE(RunExtensionTest("webrequest/test_redirects")) << message_; } -IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, +IN_PROC_BROWSER_TEST_P(ExtensionWebRequestApiTestWithContextType, WebRequestRedirectsWithExtraHeaders) { ASSERT_TRUE(StartEmbeddedTestServer()); ASSERT_TRUE(RunExtensionTest("webrequest/test_redirects", @@ -930,7 +953,7 @@ } // Tests that redirects from secure to insecure don't send the referrer header. -IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, +IN_PROC_BROWSER_TEST_P(ExtensionWebRequestApiTestWithContextType, WebRequestRedirectsToInsecure) { ASSERT_TRUE(StartEmbeddedTestServer()); GURL insecure_destination = @@ -953,6 +976,9 @@ << message_; } +// TODO(crbug.com/1093066): The JS file for this test uses XmlHttpRequest, +// which needs to be migrated to use fetch() to be compatible with +// service workers. IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, WebRequestSubresourceRedirects) { ASSERT_TRUE(StartEmbeddedTestServer()); @@ -960,6 +986,9 @@ << message_; } +// TODO(crbug.com/1093066): The JS file for this test uses XmlHttpRequest, +// which needs to be migrated to use fetch() to be compatible with +// service workers. IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, WebRequestSubresourceRedirectsWithExtraHeaders) { ASSERT_TRUE(StartEmbeddedTestServer()); @@ -968,7 +997,8 @@ << message_; } -IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, WebRequestNewTab) { +IN_PROC_BROWSER_TEST_P(ExtensionWebRequestApiTestWithContextType, + WebRequestNewTab) { ASSERT_TRUE(StartEmbeddedTestServer()); // Wait for the extension to set itself up and return control to us. ASSERT_TRUE(RunExtensionTest("webrequest/test_new_tab")) << message_; @@ -1094,27 +1124,6 @@ EXPECT_EQ(exptected_content_incognito_window, body); } -class ExtensionWebRequestApiTestWithContextType - : public ExtensionWebRequestApiTest, - public testing::WithParamInterface<ContextType> { - public: - ExtensionWebRequestApiTestWithContextType() - : ExtensionWebRequestApiTest(GetParam()) {} - ExtensionWebRequestApiTestWithContextType( - const ExtensionWebRequestApiTestWithContextType&) = delete; - ExtensionWebRequestApiTestWithContextType& operator=( - const ExtensionWebRequestApiTestWithContextType&) = delete; - ~ExtensionWebRequestApiTestWithContextType() override = default; -}; - -INSTANTIATE_TEST_SUITE_P(PersistentBackground, - ExtensionWebRequestApiTestWithContextType, - ::testing::Values(ContextType::kPersistentBackground)); - -INSTANTIATE_TEST_SUITE_P(ServiceWorker, - ExtensionWebRequestApiTestWithContextType, - ::testing::Values(ContextType::kServiceWorker)); - IN_PROC_BROWSER_TEST_P(ExtensionWebRequestApiTestWithContextType, WebRequestDeclarativePermissionSpanning1) { // Test spanning with incognito permission. @@ -5200,8 +5209,6 @@ << message_; } -using ContextType = ExtensionBrowserTest::ContextType; - class WebRequestApiTestWithContextType : public ExtensionWebRequestApiTest, public testing::WithParamInterface<ContextType> {
diff --git a/chrome/browser/feature_engagement/java/src/org/chromium/chrome/browser/feature_engagement/TrackerFactory.java b/chrome/browser/feature_engagement/java/src/org/chromium/chrome/browser/feature_engagement/TrackerFactory.java index 16e2902..8c37be5 100644 --- a/chrome/browser/feature_engagement/java/src/org/chromium/chrome/browser/feature_engagement/TrackerFactory.java +++ b/chrome/browser/feature_engagement/java/src/org/chromium/chrome/browser/feature_engagement/TrackerFactory.java
@@ -32,11 +32,7 @@ if (profile == null) { throw new IllegalArgumentException("Profile is required for retrieving tracker."); } - if (!profile.isNativeInitialized()) { - // Temporary to debug https://crbug.com/1346710. - throw new IllegalArgumentException("Profile must have a valid native pointer."); - } - + profile.ensureNativeInitialized(); return TrackerFactoryJni.get().getTrackerForProfile(profile); }
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index 4e38600..975ded25 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -854,6 +854,11 @@ "expiry_milestone": 110 }, { + "name": "cct-resizable-window-above-navbar", + "owners": ["jinsukkim", "twellington"], + "expiry_milestone": 110 + }, + { "name": "cellular-bypass-esim-installation-connectivity-check", "owners": [ "azeemarshad", "khorimoto", "jiajunz", "cros-connectivity@google.com" ], // This flag does not expire because it allows some test cases that host a local SM-DP+ server @@ -2439,6 +2444,21 @@ "expiry_milestone": 107 }, { + "name": "enable-lens-in-home-screen-widget", + "owners": [ "schechter", "hujasonx" ], + "expiry_milestone": 120 + }, + { + "name": "enable-lens-in-keyboard", + "owners": [ "schechter", "hujasonx" ], + "expiry_milestone": 120 + }, + { + "name": "enable-lens-in-ntp", + "owners": [ "schechter", "hujasonx" ], + "expiry_milestone": 120 + }, + { "name": "enable-lens-standalone", "owners": [ "stanfield@google.com", "benwgold@google.com", "juanmojica@google.com" ], "expiry_milestone": 107 @@ -6148,11 +6168,6 @@ "expiry_milestone": 110 }, { - "name": "tab-search-media-tabs", - "owners": ["elainechien", "romanarora"], - "expiry_milestone": 110 - }, - { "name": "tangible-sync", "owners": [ "aliceywang", "chrome-signin-team" ], "expiry_milestone":120
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index f59187b0..e4c3c7e3 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -1611,11 +1611,6 @@ "When enabled, the audio indicators in the tab strip double as tab audio " "mute controls."; -const char kTabSearchMediaTabsId[] = "tab-search-media-tabs"; -const char kTabSearchMediaTabsName[] = "Tab Search Media Tabs"; -const char kTabSearchMediaTabsDescription[] = - "Enable indicators on media tabs in Tab Search."; - const char kTabSwitcherOnReturnName[] = "Tab switcher on return"; const char kTabSwitcherOnReturnDescription[] = "Enable tab switcher on return after specified time has elapsed"; @@ -3330,6 +3325,12 @@ "Bottom sheet Custom Tabs (third party)"; const char kCCTResizableForThirdPartiesDescription[] = "Enable bottom sheet Custom Tabs for third party apps."; +const char kCCTResizableWindowAboveNavbarName[] = + "Bottom sheet Custom Tabs placed above the NavBar"; +const char kCCTResizableWindowAboveNavbarDescription[] = + "Avoid various UI glitches/misbehavior by always keeping bottom sheet " + "custom tab above the navigation bar. The navigation bar color is not " + "customizable - it is up to the host app to ensure the bar looks okay."; const char kCCTRealTimeEngagementSignalsName[] = "Enable CCT real-time engagement signals.";
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index fdad6f1..2130dc7 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -894,10 +894,6 @@ extern const char kTabAudioMutingName[]; extern const char kTabAudioMutingDescription[]; -extern const char kTabSearchMediaTabsId[]; -extern const char kTabSearchMediaTabsName[]; -extern const char kTabSearchMediaTabsDescription[]; - extern const char kTabSwitcherOnReturnName[]; extern const char kTabSwitcherOnReturnDescription[]; @@ -1875,6 +1871,8 @@ extern const char kCCTResizableForFirstPartiesDescription[]; extern const char kCCTResizableForThirdPartiesName[]; extern const char kCCTResizableForThirdPartiesDescription[]; +extern const char kCCTResizableWindowAboveNavbarName[]; +extern const char kCCTResizableWindowAboveNavbarDescription[]; extern const char kCCTRealTimeEngagementSignalsName[]; extern const char kCCTRealTimeEngagementSignalsDescription[];
diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc index d105345..cf4f1e8 100644 --- a/chrome/browser/flags/android/chrome_feature_list.cc +++ b/chrome/browser/flags/android/chrome_feature_list.cc
@@ -201,6 +201,7 @@ &kCCTResizableAllowResizeByUserGesture, &kCCTResizableForFirstParties, &kCCTResizableForThirdParties, + &kCCTResizableWindowAboveNavbar, &kCCTRetainingState, &kCCTResourcePrefetch, &kCCTToolbarCustomizations, @@ -563,6 +564,9 @@ const base::Feature kCCTResizableForThirdParties{ "CCTResizableForThirdParties", base::FEATURE_DISABLED_BY_DEFAULT}; +const base::Feature kCCTResizableWindowAboveNavbar{ + "CCTResizableWindowAboveNavbar", base::FEATURE_ENABLED_BY_DEFAULT}; + const base::Feature kCCTResourcePrefetch{"CCTResourcePrefetch", base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/chrome/browser/flags/android/chrome_feature_list.h b/chrome/browser/flags/android/chrome_feature_list.h index b0e7936..2b360ec 100644 --- a/chrome/browser/flags/android/chrome_feature_list.h +++ b/chrome/browser/flags/android/chrome_feature_list.h
@@ -52,6 +52,7 @@ extern const base::Feature kCCTResizableAllowResizeByUserGesture; extern const base::Feature kCCTResizableForFirstParties; extern const base::Feature kCCTResizableForThirdParties; +extern const base::Feature kCCTResizableWindowAboveNavbar; extern const base::Feature kCCTResourcePrefetch; extern const base::Feature kCCTRetainingState; extern const base::Feature kCCTToolbarCustomizations;
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/CachedFeatureFlags.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/CachedFeatureFlags.java index b700fc8..a6f50ef1 100644 --- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/CachedFeatureFlags.java +++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/CachedFeatureFlags.java
@@ -61,6 +61,7 @@ .put(ChromeFeatureList.COMMERCE_COUPONS, false) .put(ChromeFeatureList.CCT_RESIZABLE_FOR_THIRD_PARTIES, false) .put(ChromeFeatureList.CCT_TOOLBAR_CUSTOMIZATIONS, true) + .put(ChromeFeatureList.CCT_RESIZABLE_WINDOW_ABOVE_NAVBAR, true) .put(ChromeFeatureList.CLOSE_TAB_SUGGESTIONS, false) .put(ChromeFeatureList.COMMAND_LINE_ON_NON_ROOTED, false) .put(ChromeFeatureList.CONDITIONAL_TAB_STRIP_ANDROID, false)
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java index 34fb846..ddf10c0 100644 --- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java +++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
@@ -264,6 +264,7 @@ "CCTResizableAllowResizeByUserGesture"; public static final String CCT_RESIZABLE_FOR_FIRST_PARTIES = "CCTResizableForFirstParties"; public static final String CCT_RESIZABLE_FOR_THIRD_PARTIES = "CCTResizableForThirdParties"; + public static final String CCT_RESIZABLE_WINDOW_ABOVE_NAVBAR = "CCTResizableWindowAboveNavbar"; public static final String CCT_RESOURCE_PREFETCH = "CCTResourcePrefetch"; public static final String CCT_RETAINING_STATE = "CCTRetainingState"; public static final String CCT_REPORT_PARALLEL_REQUEST_STATUS = @@ -630,6 +631,8 @@ new CachedFlag(CCT_RESIZABLE_FOR_FIRST_PARTIES, true); public static final CachedFlag sCctResizableForThirdParties = new CachedFlag(CCT_RESIZABLE_FOR_THIRD_PARTIES, false); + public static final CachedFlag sCctResizableWindowAboveNavbar = + new CachedFlag(CCT_RESIZABLE_WINDOW_ABOVE_NAVBAR, true); public static final CachedFlag sCctToolbarCustomizations = new CachedFlag(CCT_TOOLBAR_CUSTOMIZATIONS, true); public static final CachedFlag sCloseTabSuggestions =
diff --git a/chrome/browser/media/webrtc/display_media_access_handler.cc b/chrome/browser/media/webrtc/display_media_access_handler.cc index eec2cb4..df63803 100644 --- a/chrome/browser/media/webrtc/display_media_access_handler.cc +++ b/chrome/browser/media/webrtc/display_media_access_handler.cc
@@ -313,9 +313,23 @@ base::Erase(media_types, DesktopMediaList::Type::kWindow); } - auto includable_web_contents_filter = + auto includable_web_contents_filter = base::BindRepeating( + [](DesktopMediaList::WebContentsFilter capture_policy_filter, + bool exclude_self_browser_surface, + base::WeakPtr<content::WebContents> capturing_web_contents, + content::WebContents* captured_web_contents) { + if (!capturing_web_contents) + return false; + if (!capture_policy_filter.Run(captured_web_contents)) + return false; + if (!exclude_self_browser_surface) + return true; + return capturing_web_contents.get() != captured_web_contents; + }, capture_policy::GetIncludableWebContentsFilter(request_origin, - capture_level); + capture_level), + pending_request.request.exclude_self_browser_surface, + web_contents->GetWeakPtr()); auto source_lists = picker_factory_->CreateMediaList( media_types, web_contents, includable_web_contents_filter);
diff --git a/chrome/browser/media/webrtc/display_media_access_handler_unittest.cc b/chrome/browser/media/webrtc/display_media_access_handler_unittest.cc index e7fa044..242894a 100644 --- a/chrome/browser/media/webrtc/display_media_access_handler_unittest.cc +++ b/chrome/browser/media/webrtc/display_media_access_handler_unittest.cc
@@ -90,6 +90,13 @@ return request; } + content::MediaStreamRequest MakeExcludeSelfBrowserSurfaceRequest( + bool exclude_self_browser_surface) { + content::MediaStreamRequest request = MakeRequest(/*request_audio=*/false); + request.exclude_self_browser_surface = exclude_self_browser_surface; + return request; + } + content::MediaResponseCallback MakeCallback( base::RunLoop* wait_loop, blink::mojom::MediaStreamRequestResult* request_result, @@ -172,6 +179,10 @@ access_handler_->WebContentsDestroyed(web_contents()); } + bool IsWebContentsExcluded() const { + return picker_factory_->IsWebContentsExcluded(); + } + DesktopMediaPicker::Params GetParams() { return picker_factory_->picker()->GetParams(); } @@ -741,3 +752,35 @@ EXPECT_EQ(blink::mojom::MediaStreamRequestResult::OK, results[2]); access_handler_.reset(); } + +class DisplayMediaAccessHandlerTestWithSelfBrowserSurface + : public DisplayMediaAccessHandlerTest, + public testing::WithParamInterface<bool> { + public: + DisplayMediaAccessHandlerTestWithSelfBrowserSurface() + : exclude_self_browser_surface_(GetParam()) {} + + ~DisplayMediaAccessHandlerTestWithSelfBrowserSurface() override = default; + + protected: + const bool exclude_self_browser_surface_; +}; + +INSTANTIATE_TEST_SUITE_P(_, + DisplayMediaAccessHandlerTestWithSelfBrowserSurface, + ::testing::Bool()); + +TEST_P(DisplayMediaAccessHandlerTestWithSelfBrowserSurface, + CheckIsWebContentsExcluded) { + SetTestFlags({{MakePickerTestFlags(/*request_audio=*/false)}}); + blink::mojom::MediaStreamRequestResult result; + blink::mojom::StreamDevices devices; + base::RunLoop wait_loop; + + HandleRequest( + MakeExcludeSelfBrowserSurfaceRequest(exclude_self_browser_surface_), + &wait_loop, &result, devices); + wait_loop.Run(); + EXPECT_EQ(exclude_self_browser_surface_, IsWebContentsExcluded()); + access_handler_.reset(); +}
diff --git a/chrome/browser/media/webrtc/fake_desktop_media_picker_factory.cc b/chrome/browser/media/webrtc/fake_desktop_media_picker_factory.cc index fc12d70..c69b34f 100644 --- a/chrome/browser/media/webrtc/fake_desktop_media_picker_factory.cc +++ b/chrome/browser/media/webrtc/fake_desktop_media_picker_factory.cc
@@ -105,6 +105,7 @@ content::WebContents* web_contents, DesktopMediaList::WebContentsFilter includable_web_contents_filter) { EXPECT_LE(current_test_, tests_count_); + is_web_contents_excluded_ = !includable_web_contents_filter.Run(web_contents); std::vector<std::unique_ptr<DesktopMediaList>> media_lists; for (auto source_type : types) media_lists.emplace_back(new FakeDesktopMediaList(source_type));
diff --git a/chrome/browser/media/webrtc/fake_desktop_media_picker_factory.h b/chrome/browser/media/webrtc/fake_desktop_media_picker_factory.h index 3c1af8a..eeb0c2a 100644 --- a/chrome/browser/media/webrtc/fake_desktop_media_picker_factory.h +++ b/chrome/browser/media/webrtc/fake_desktop_media_picker_factory.h
@@ -46,6 +46,7 @@ // |test_flags| are expected to outlive the factory. void SetTestFlags(TestFlags* test_flags, int tests_count); FakeDesktopMediaPicker* picker() const { return picker_; } + bool IsWebContentsExcluded() const { return is_web_contents_excluded_; } // DesktopMediaPickerFactory implementation std::unique_ptr<DesktopMediaPicker> CreatePicker() override; std::vector<std::unique_ptr<DesktopMediaList>> CreateMediaList( @@ -59,6 +60,7 @@ raw_ptr<TestFlags> test_flags_; int tests_count_; int current_test_; + bool is_web_contents_excluded_ = false; }; class FakeDesktopMediaPicker : public DesktopMediaPicker {
diff --git a/chrome/browser/media/webrtc/webrtc_getdisplaymedia_browsertest.cc b/chrome/browser/media/webrtc/webrtc_getdisplaymedia_browsertest.cc index 9cebac001..f129b50 100644 --- a/chrome/browser/media/webrtc/webrtc_getdisplaymedia_browsertest.cc +++ b/chrome/browser/media/webrtc/webrtc_getdisplaymedia_browsertest.cc
@@ -51,6 +51,7 @@ static const char kSameOriginRenamedTitle[] = "Renamed Same Origin Tab"; // TODO(https://crbug.com/1215089): Enable on Lacros. #if !BUILDFLAG(IS_CHROMEOS_LACROS) +static const char kMainHtmlTitle[] = "WebRTC Automated Test"; // The captured tab is identified by its title. static const char kCapturedTabTitle[] = "totally-unique-captured-page-title"; static const char kCapturedPageMain[] = "/webrtc/captured_page_main.html"; @@ -464,7 +465,7 @@ command_line->AppendSwitch( switches::kEnableExperimentalWebPlatformFeatures); command_line->AppendSwitchASCII( - switches::kAutoSelectTabCaptureSourceByTitle, "WebRTC Automated Test"); + switches::kAutoSelectTabCaptureSourceByTitle, kMainHtmlTitle); } bool PreferCurrentTab() const override { @@ -1040,6 +1041,53 @@ #endif +// TODO(https://crbug.com/1215089): Enable this test suite on Lacros. +#if !BUILDFLAG(IS_CHROMEOS_LACROS) +class GetDisplayMediaSelfBrowserSurfaceBrowserTest + : public WebRtcTestBase, + public testing::WithParamInterface<bool> { + public: + void SetUpInProcessBrowserTestFixture() override { + WebRtcTestBase::SetUpInProcessBrowserTestFixture(); + + DetectErrorsInJavaScript(); + + base::FilePath test_dir; + ASSERT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &test_dir)); + } + + void SetUpCommandLine(base::CommandLine* command_line) override { + command_line->AppendSwitch( + switches::kEnableExperimentalWebPlatformFeatures); + command_line->AppendSwitchASCII( + switches::kAutoSelectTabCaptureSourceByTitle, kMainHtmlTitle); + } + + bool IsSelfBrowserSurfaceInclude() { return GetParam(); } +}; + +INSTANTIATE_TEST_SUITE_P(All, + GetDisplayMediaSelfBrowserSurfaceBrowserTest, + testing::Bool()); + +IN_PROC_BROWSER_TEST_P(GetDisplayMediaSelfBrowserSurfaceBrowserTest, + SelfBrowserSurfaceChangesCapturedTab) { + ASSERT_TRUE(embedded_test_server()->Start()); + content::WebContents* other_tab = OpenTestPageInNewTab(kMainHtmlPage); + content::WebContents* capturing_tab = OpenTestPageInNewTab(kMainHtmlPage); + + const std::string constraints = + base::StringPrintf("{video: true, selfBrowserSurface: \"%s\"}", + IsSelfBrowserSurfaceInclude() ? "include" : "exclude"); + RunGetDisplayMedia(capturing_tab, constraints, /*is_fake_ui=*/false, + /*expect_success=*/true, /*is_tab_capture=*/true); + + EXPECT_EQ(IsSelfBrowserSurfaceInclude(), capturing_tab->IsBeingCaptured()); + EXPECT_EQ(!IsSelfBrowserSurfaceInclude(), other_tab->IsBeingCaptured()); +} + +#endif + #if BUILDFLAG(IS_CHROMEOS_LACROS) || BUILDFLAG(IS_CHROMEOS_ASH) class WebRtcScreenCaptureSelectAllScreensTest
diff --git a/chrome/browser/nearby_sharing/common/nearby_share_features.cc b/chrome/browser/nearby_sharing/common/nearby_share_features.cc index b7e35cc..763093d 100644 --- a/chrome/browser/nearby_sharing/common/nearby_share_features.cc +++ b/chrome/browser/nearby_sharing/common/nearby_share_features.cc
@@ -32,10 +32,6 @@ const base::Feature kNearbySharingOnePageOnboarding{ "NearbySharingOnePageOnboarding", base::FEATURE_ENABLED_BY_DEFAULT}; -// Enables receiving WiFi networks using Nearby Share. -const base::Feature kNearbySharingReceiveWifiCredentials{ - "NearbySharingReceiveWifiCredentials", base::FEATURE_ENABLED_BY_DEFAULT}; - // Enables auto-accept functionality when sharing between a user's own devices. const base::Feature kNearbySharingSelfShareAutoAccept{ "NearbySharingSelfShareAutoAccept", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/chrome/browser/nearby_sharing/common/nearby_share_features.h b/chrome/browser/nearby_sharing/common/nearby_share_features.h index f622c24..37818b5 100644 --- a/chrome/browser/nearby_sharing/common/nearby_share_features.h +++ b/chrome/browser/nearby_sharing/common/nearby_share_features.h
@@ -14,7 +14,6 @@ extern const base::Feature kNearbySharingChildAccounts; extern const base::Feature kNearbySharingDeviceContacts; extern const base::Feature kNearbySharingOnePageOnboarding; -extern const base::Feature kNearbySharingReceiveWifiCredentials; extern const base::Feature kNearbySharingSelfShareAutoAccept; extern const base::Feature kNearbySharingSelfShareUI; extern const base::Feature kNearbySharingVisibilityReminder;
diff --git a/chrome/browser/nearby_sharing/nearby_notification_manager.cc b/chrome/browser/nearby_sharing/nearby_notification_manager.cc index 30d3427..feeaeb0c 100644 --- a/chrome/browser/nearby_sharing/nearby_notification_manager.cc +++ b/chrome/browser/nearby_sharing/nearby_notification_manager.cc
@@ -222,9 +222,7 @@ size_t attachment_count = share_target.file_attachments.size() + share_target.text_attachments.size(); - if (!share_target.wifi_credentials_attachments.empty() && - base::FeatureList::IsEnabled( - features::kNearbySharingReceiveWifiCredentials)) { + if (!share_target.wifi_credentials_attachments.empty()) { std::u16string network_name = base::UTF8ToUTF16(share_target.wifi_credentials_attachments[0].ssid()); return base::ReplaceStringPlaceholders( @@ -238,9 +236,7 @@ } std::u16string GetProgressNotificationTitle(const ShareTarget& share_target) { - if (!share_target.wifi_credentials_attachments.empty() && - base::FeatureList::IsEnabled( - features::kNearbySharingReceiveWifiCredentials)) { + if (!share_target.wifi_credentials_attachments.empty()) { return FormatNotificationTitle( share_target, IDS_NEARBY_NOTIFICATION_RECEIVE_PROGRESS_TITLE_WIFI_CREDENTIALS, @@ -256,9 +252,7 @@ } std::u16string GetSuccessNotificationTitle(const ShareTarget& share_target) { - if (!share_target.wifi_credentials_attachments.empty() && - base::FeatureList::IsEnabled( - features::kNearbySharingReceiveWifiCredentials)) { + if (!share_target.wifi_credentials_attachments.empty()) { return FormatNotificationTitle( share_target, IDS_NEARBY_NOTIFICATION_RECEIVE_SUCCESS_TITLE_WIFI_CREDENTIALS, @@ -273,9 +267,7 @@ } std::u16string GetFailureNotificationTitle(const ShareTarget& share_target) { - if (!share_target.wifi_credentials_attachments.empty() && - base::FeatureList::IsEnabled( - features::kNearbySharingReceiveWifiCredentials)) { + if (!share_target.wifi_credentials_attachments.empty()) { return FormatNotificationTitle( share_target, IDS_NEARBY_NOTIFICATION_RECEIVE_FAILURE_TITLE_WIFI_CREDENTIALS, @@ -313,9 +305,7 @@ size_t attachment_count = share_target.file_attachments.size() + share_target.text_attachments.size(); std::u16string message; - if (!share_target.wifi_credentials_attachments.empty() && - base::FeatureList::IsEnabled( - features::kNearbySharingReceiveWifiCredentials)) { + if (!share_target.wifi_credentials_attachments.empty()) { message = base::ReplaceStringPlaceholders( l10n_util::GetStringUTF16( IDS_NEARBY_NOTIFICATION_CONNECTION_REQUEST_MESSAGE_WIFI_CREDENTIALS),
diff --git a/chrome/browser/nearby_sharing/nearby_notification_manager_unittest.cc b/chrome/browser/nearby_sharing/nearby_notification_manager_unittest.cc index ae7dfee..2824253 100644 --- a/chrome/browser/nearby_sharing/nearby_notification_manager_unittest.cc +++ b/chrome/browser/nearby_sharing/nearby_notification_manager_unittest.cc
@@ -152,24 +152,16 @@ class NearbyNotificationManagerTestBase : public testing::Test { public: explicit NearbyNotificationManagerTestBase( - std::tuple<bool, bool, bool> feature_list) { + std::tuple<bool, bool> feature_list) { std::vector<base::Feature> enabled_features; std::vector<base::Feature> disabled_features; is_self_share_enabled_ = std::get<0>(feature_list); - is_receive_wifi_credentials_enabled_ = std::get<1>(feature_list); - is_self_share_auto_accept_enabled_ = std::get<2>(feature_list); + is_self_share_auto_accept_enabled_ = std::get<1>(feature_list); if (is_self_share_enabled_) { enabled_features.push_back(features::kNearbySharingSelfShareUI); } else { disabled_features.push_back(features::kNearbySharingSelfShareUI); } - if (is_receive_wifi_credentials_enabled_) { - enabled_features.push_back( - features::kNearbySharingReceiveWifiCredentials); - } else { - disabled_features.push_back( - features::kNearbySharingReceiveWifiCredentials); - } if (is_self_share_auto_accept_enabled_) { enabled_features.push_back(features::kNearbySharingSelfShareAutoAccept); } else { @@ -271,7 +263,7 @@ CreateFileAttachment(FileAttachment::Type::kVideo)); } - if (wifi_credentials_attachments && is_receive_wifi_credentials_enabled_) { + if (wifi_credentials_attachments) { share_target.wifi_credentials_attachments.push_back( CreateWifiCredentialsAttachment( WifiCredentialsAttachment::SecurityType::kWpaPsk)); @@ -294,7 +286,6 @@ data_decoder::test::InProcessDataDecoder in_process_data_decoder_; MockSettingsOpener* settings_opener_; bool is_self_share_enabled_ = false; - bool is_receive_wifi_credentials_enabled_ = false; bool is_self_share_auto_accept_enabled_ = false; }; @@ -302,7 +293,7 @@ // Visibility Reminder enabled and disabled. class NearbyNotificationManagerTest : public NearbyNotificationManagerTestBase, - public testing::WithParamInterface<std::tuple<bool, bool, bool>> { + public testing::WithParamInterface<std::tuple<bool, bool>> { public: NearbyNotificationManagerTest() : NearbyNotificationManagerTestBase(/*feature_list=*/GetParam()) {} @@ -407,10 +398,9 @@ }; // Boolean parameter is |is_incoming| and the tuple parameter is a feature list -// containing |is_self_share_enabled|, |is_receive_wifi_credentials_enabled|, -// and |is_self_share_auto_accept_enabled|. -using AttachmentsTestParam = std:: - tuple<AttachmentsTestParamInternal, bool, std::tuple<bool, bool, bool>>; +// containing |is_self_share_enabled| and |is_self_share_auto_accept_enabled|. +using AttachmentsTestParam = + std::tuple<AttachmentsTestParamInternal, bool, std::tuple<bool, bool>>; class NearbyNotificationManagerAttachmentsTest : public NearbyNotificationManagerTestBase, @@ -422,10 +412,8 @@ }; // Boolean parameter is |with_token| and the tuple parameter is featuree list -// contains |is_self_share_enabled|, |is_receive_wifi_credentials_enabled|, -// and |is_self_share_auto_accept_enabled|. -using ConnectionRequestTestParam = - std::tuple<bool, std::tuple<bool, bool, bool>>; +// contains |is_self_share_enabled| and |is_self_share_auto_accept_enabled|. +using ConnectionRequestTestParam = std::tuple<bool, std::tuple<bool, bool>>; class NearbyNotificationManagerConnectionRequestTest : public NearbyNotificationManagerTestBase, @@ -442,9 +430,7 @@ const std::string& device_name, const std::string& network_name, bool use_capitalized_resource) { - if (!param.wifi_credentials_attachments.empty() && - base::FeatureList::IsEnabled( - features::kNearbySharingReceiveWifiCredentials)) { + if (!param.wifi_credentials_attachments.empty()) { return base::ReplaceStringPlaceholders( l10n_util::GetStringUTF16(resource_id), {base::ASCIIToUTF16(network_name), base::ASCIIToUTF16(device_name)}, @@ -595,7 +581,7 @@ for (FileAttachment::Type type : param.file_attachments) share_target.file_attachments.push_back(CreateFileAttachment(type)); - if (is_incoming && is_receive_wifi_credentials_enabled_) { + if (is_incoming) { for (WifiCredentialsAttachment::SecurityType securityType : param.wifi_credentials_attachments) { share_target.wifi_credentials_attachments.push_back( @@ -607,8 +593,7 @@ manager()->ShowProgress(share_target, transfer_metadata); std::u16string expected; - if (!param.wifi_credentials_attachments.empty() && - is_receive_wifi_credentials_enabled_ && is_incoming) { + if (!param.wifi_credentials_attachments.empty() && is_incoming) { expected = FormatNotificationTitle( IDS_NEARBY_NOTIFICATION_RECEIVE_PROGRESS_TITLE_WIFI_CREDENTIALS, param, device_name, share_target.wifi_credentials_attachments[0].ssid(), @@ -648,7 +633,7 @@ for (FileAttachment::Type type : param.file_attachments) share_target.file_attachments.push_back(CreateFileAttachment(type)); - if (is_incoming && is_receive_wifi_credentials_enabled_) { + if (is_incoming) { for (WifiCredentialsAttachment::SecurityType securityType : param.wifi_credentials_attachments) { share_target.wifi_credentials_attachments.push_back( @@ -659,8 +644,7 @@ manager()->ShowSuccess(share_target); std::u16string expected; - if (!param.wifi_credentials_attachments.empty() && - is_receive_wifi_credentials_enabled_ && is_incoming) { + if (!param.wifi_credentials_attachments.empty() && is_incoming) { expected = FormatNotificationTitle( IDS_NEARBY_NOTIFICATION_RECEIVE_SUCCESS_TITLE_WIFI_CREDENTIALS, param, device_name, share_target.wifi_credentials_attachments[0].ssid(), @@ -700,7 +684,7 @@ for (FileAttachment::Type type : param.file_attachments) share_target.file_attachments.push_back(CreateFileAttachment(type)); - if (is_incoming && is_receive_wifi_credentials_enabled_) { + if (is_incoming) { for (WifiCredentialsAttachment::SecurityType securityType : param.wifi_credentials_attachments) { share_target.wifi_credentials_attachments.push_back( @@ -732,8 +716,7 @@ } std::u16string expected_title; - if (!param.wifi_credentials_attachments.empty() && - is_receive_wifi_credentials_enabled_ && is_incoming) { + if (!param.wifi_credentials_attachments.empty() && is_incoming) { expected_title = FormatNotificationTitle( IDS_NEARBY_NOTIFICATION_RECEIVE_FAILURE_TITLE_WIFI_CREDENTIALS, param, device_name, share_target.wifi_credentials_attachments[0].ssid(), @@ -767,10 +750,9 @@ INSTANTIATE_TEST_SUITE_P( NearbyNotificationManagerAttachmentsTest, NearbyNotificationManagerAttachmentsTest, - testing::Combine( - testing::ValuesIn(kAttachmentsTestParams), - testing::Bool(), - testing::Combine(testing::Bool(), testing::Bool(), testing::Bool()))); + testing::Combine(testing::ValuesIn(kAttachmentsTestParams), + testing::Bool(), + testing::Combine(testing::Bool(), testing::Bool()))); TEST_P(NearbyNotificationManagerConnectionRequestTest, ShowConnectionRequest_ShowsNotification) { @@ -847,7 +829,6 @@ NearbyNotificationManagerConnectionRequestTest, testing::Combine(testing::Bool(), testing::Combine(testing::Bool(), - testing::Bool(), testing::Bool()))); TEST_P(NearbyNotificationManagerTest, @@ -1636,9 +1617,6 @@ TEST_P(NearbyNotificationManagerTest, SuccessNotificationClicked_WifiCredentialsReceived) { - if (!is_receive_wifi_credentials_enabled_) - return; - base::RunLoop run_loop; manager()->SetOnSuccessClickedForTesting(base::BindLambdaForTesting( [&](NearbyNotificationManager::SuccessNotificationAction action) { @@ -1952,6 +1930,4 @@ INSTANTIATE_TEST_SUITE_P(NearbyNotificationManagerTest, NearbyNotificationManagerTest, - testing::Combine(testing::Bool(), - testing::Bool(), - testing::Bool())); + testing::Combine(testing::Bool(), testing::Bool()));
diff --git a/chrome/browser/nearby_sharing/nearby_sharing_service_impl.cc b/chrome/browser/nearby_sharing/nearby_sharing_service_impl.cc index 5d67521..308554c 100644 --- a/chrome/browser/nearby_sharing/nearby_sharing_service_impl.cc +++ b/chrome/browser/nearby_sharing/nearby_sharing_service_impl.cc
@@ -3416,30 +3416,25 @@ share_target.text_attachments.push_back(std::move(attachment)); } - if (base::FeatureList::IsEnabled( - features::kNearbySharingReceiveWifiCredentials)) { - for (const auto& wifi_credentials : - introduction_frame->wifi_credentials_metadata) { - if (wifi_credentials->ssid.empty()) { - Fail(share_target, - TransferMetadata::Status::kUnsupportedAttachmentType); - NS_LOG(WARNING) << __func__ - << ": Ignore introduction, due to invalid Wi-Fi SSID"; - return; - } - - NS_LOG(VERBOSE) << __func__ << ": Found Wi-Fi Credentials: id=" - << wifi_credentials->id - << ", payload_id=" << wifi_credentials->payload_id - << ", security_type=" << wifi_credentials->security_type; - - WifiCredentialsAttachment attachment(wifi_credentials->id, - wifi_credentials->security_type, - wifi_credentials->ssid); - SetAttachmentPayloadId(attachment, wifi_credentials->payload_id); - share_target.wifi_credentials_attachments.push_back( - std::move(attachment)); + for (const auto& wifi_credentials : + introduction_frame->wifi_credentials_metadata) { + if (wifi_credentials->ssid.empty()) { + Fail(share_target, TransferMetadata::Status::kUnsupportedAttachmentType); + NS_LOG(WARNING) << __func__ + << ": Ignore introduction, due to invalid Wi-Fi SSID"; + return; } + + NS_LOG(VERBOSE) << __func__ + << ": Found Wi-Fi Credentials: id=" << wifi_credentials->id + << ", payload_id=" << wifi_credentials->payload_id + << ", security_type=" << wifi_credentials->security_type; + + WifiCredentialsAttachment attachment(wifi_credentials->id, + wifi_credentials->security_type, + wifi_credentials->ssid); + SetAttachmentPayloadId(attachment, wifi_credentials->payload_id); + share_target.wifi_credentials_attachments.push_back(std::move(attachment)); } if (!share_target.has_attachments()) { @@ -3955,64 +3950,61 @@ attachment_info.text_body = std::move(text_body); } - if (base::FeatureList::IsEnabled( - features::kNearbySharingReceiveWifiCredentials)) { - for (auto& wifi_credentials : share_target.wifi_credentials_attachments) { - AttachmentInfo& attachment_info = - attachment_info_map_[wifi_credentials.id()]; - absl::optional<int64_t> payload_id = attachment_info.payload_id; - if (!payload_id) { - NS_LOG(WARNING) << __func__ - << ": No payload id found for wifi credentials - " - << wifi_credentials.id(); - return false; - } - - location::nearby::connections::mojom::Payload* incoming_payload = - nearby_connections_manager_->GetIncomingPayload(*payload_id); - if (!incoming_payload || !incoming_payload->content || - !incoming_payload->content->is_bytes()) { - NS_LOG(WARNING) << __func__ - << ": No payload found for Wi-Fi credentials - " - << wifi_credentials.id(); - return false; - } - - const std::vector<uint8_t>& bytes = - incoming_payload->content->get_bytes()->bytes; - if (bytes.empty()) { - NS_LOG(WARNING) - << __func__ - << ": Incoming bytes is empty for Wi-Fi password with payload_id - " - << *payload_id; - return false; - } - - sharing::nearby::WifiCredentials credentials_proto; - if (!credentials_proto.ParseFromArray(bytes.data(), bytes.size())) { - NS_LOG(WARNING) << __func__ - << ": Failed to parse Wi-Fi credentials proto"; - return false; - } - - if (credentials_proto.password().empty()) { - NS_LOG(WARNING) << __func__ << ": No Wi-Fi password found"; - return false; - } - - if (credentials_proto.has_hidden_ssid() && - credentials_proto.hidden_ssid()) { - NS_LOG(WARNING) << __func__ << ": Network is hidden"; - return false; - } - - std::string wifi_password(credentials_proto.password()); - wifi_credentials.set_wifi_password(wifi_password); - - // Automatically set up the Wi-Fi network for the user. - wifi_network_handler_->ConfigureWifiNetwork(wifi_credentials, - base::DoNothing()); + for (auto& wifi_credentials : share_target.wifi_credentials_attachments) { + AttachmentInfo& attachment_info = + attachment_info_map_[wifi_credentials.id()]; + absl::optional<int64_t> payload_id = attachment_info.payload_id; + if (!payload_id) { + NS_LOG(WARNING) << __func__ + << ": No payload id found for wifi credentials - " + << wifi_credentials.id(); + return false; } + + location::nearby::connections::mojom::Payload* incoming_payload = + nearby_connections_manager_->GetIncomingPayload(*payload_id); + if (!incoming_payload || !incoming_payload->content || + !incoming_payload->content->is_bytes()) { + NS_LOG(WARNING) << __func__ + << ": No payload found for Wi-Fi credentials - " + << wifi_credentials.id(); + return false; + } + + const std::vector<uint8_t>& bytes = + incoming_payload->content->get_bytes()->bytes; + if (bytes.empty()) { + NS_LOG(WARNING) + << __func__ + << ": Incoming bytes is empty for Wi-Fi password with payload_id - " + << *payload_id; + return false; + } + + sharing::nearby::WifiCredentials credentials_proto; + if (!credentials_proto.ParseFromArray(bytes.data(), bytes.size())) { + NS_LOG(WARNING) << __func__ + << ": Failed to parse Wi-Fi credentials proto"; + return false; + } + + if (credentials_proto.password().empty()) { + NS_LOG(WARNING) << __func__ << ": No Wi-Fi password found"; + return false; + } + + if (credentials_proto.has_hidden_ssid() && + credentials_proto.hidden_ssid()) { + NS_LOG(WARNING) << __func__ << ": Network is hidden"; + return false; + } + + std::string wifi_password(credentials_proto.password()); + wifi_credentials.set_wifi_password(wifi_password); + + // Automatically set up the Wi-Fi network for the user. + wifi_network_handler_->ConfigureWifiNetwork(wifi_credentials, + base::DoNothing()); } return true; }
diff --git a/chrome/browser/nearby_sharing/nearby_sharing_service_impl_unittest.cc b/chrome/browser/nearby_sharing/nearby_sharing_service_impl_unittest.cc index ca890e5..6e7c19b 100644 --- a/chrome/browser/nearby_sharing/nearby_sharing_service_impl_unittest.cc +++ b/chrome/browser/nearby_sharing/nearby_sharing_service_impl_unittest.cc
@@ -349,8 +349,7 @@ const std::vector<base::Feature> kTestFeatures = { features::kNearbySharingBackgroundScanning, features::kNearbySharingSelfShareAutoAccept, - features::kNearbySharingSelfShareUI, - features::kNearbySharingReceiveWifiCredentials}; + features::kNearbySharingSelfShareUI}; bool FileExists(const base::FilePath& file_path) { base::ScopedAllowBlockingForTesting allow_blocking; @@ -413,13 +412,10 @@ std::vector<sharing::mojom::WifiCredentialsMetadataPtr> mojo_wifi_credentials_metadatas; - if (base::FeatureList::IsEnabled( - features::kNearbySharingReceiveWifiCredentials)) { - mojo_wifi_credentials_metadatas.push_back( - sharing::mojom::WifiCredentialsMetadata::New(kSsid, kWifiSecurityType, - kWifiCredentialsPayloadId, - kWifiCredentialsId)); - } + mojo_wifi_credentials_metadatas.push_back( + sharing::mojom::WifiCredentialsMetadata::New(kSsid, kWifiSecurityType, + kWifiCredentialsPayloadId, + kWifiCredentialsId)); sharing::mojom::V1FramePtr mojo_v1frame = sharing::mojom::V1Frame::NewIntroduction( @@ -1220,13 +1216,8 @@ } if (id == kWifiCredentialsPayloadId) { - if (base::FeatureList::IsEnabled( - features::kNearbySharingReceiveWifiCredentials)) { - fake_nearby_connections_manager_->SetIncomingPayload( - id, GetWifiPayloadPtr(id, kWifiPassword)); - } else { - continue; - } + fake_nearby_connections_manager_->SetIncomingPayload( + id, GetWifiPayloadPtr(id, kWifiPassword)); } base::WeakPtr<NearbyConnectionsManager::PayloadStatusListener> listener = @@ -1275,25 +1266,21 @@ EXPECT_EQ(kTextPayload, text.text_body()); } - if (base::FeatureList::IsEnabled( - features::kNearbySharingReceiveWifiCredentials)) { - EXPECT_EQ(1u, share_target.wifi_credentials_attachments.size()); - for (const WifiCredentialsAttachment& wifi_credentials : - share_target.wifi_credentials_attachments) { - EXPECT_EQ(kSsid, wifi_credentials.ssid()); - EXPECT_EQ(kWifiPassword, wifi_credentials.wifi_password()); - EXPECT_EQ(kWifiSecurityType, wifi_credentials.security_type()); - } - EXPECT_EQ(1u, wifi_network_handler_->num_configure_network_calls()); - EXPECT_EQ(kSsid, wifi_network_handler_->last_attachment().ssid()); - EXPECT_EQ(kWifiPassword, - wifi_network_handler_->last_attachment().wifi_password()); - EXPECT_EQ(kWifiSecurityType, - wifi_network_handler_->last_attachment().security_type()); - } else { - EXPECT_EQ(0u, share_target.wifi_credentials_attachments.size()); - EXPECT_EQ(0u, wifi_network_handler_->num_configure_network_calls()); + EXPECT_EQ(1u, share_target.wifi_credentials_attachments.size()); + for (const WifiCredentialsAttachment& wifi_credentials : + share_target.wifi_credentials_attachments) { + EXPECT_EQ(kSsid, wifi_credentials.ssid()); + EXPECT_EQ(kWifiPassword, wifi_credentials.wifi_password()); + EXPECT_EQ(kWifiSecurityType, wifi_credentials.security_type()); } + + EXPECT_EQ(1u, wifi_network_handler_->num_configure_network_calls()); + EXPECT_EQ(kSsid, wifi_network_handler_->last_attachment().ssid()); + EXPECT_EQ(kWifiPassword, + wifi_network_handler_->last_attachment().wifi_password()); + EXPECT_EQ(kWifiSecurityType, + wifi_network_handler_->last_attachment().security_type()); + run_loop_success.Quit(); })); @@ -1331,116 +1318,111 @@ void ReceiveBadWifiPayload( location::nearby::connections::mojom::PayloadPtr wifi_payload) { - if (base::FeatureList::IsEnabled( - features::kNearbySharingReceiveWifiCredentials)) { - for (int64_t payload_id : kValidIntroductionFramePayloadIds) { - fake_nearby_connections_manager_->SetPayloadPathStatus( - payload_id, location::nearby::connections::mojom::Status::kSuccess); - } + for (int64_t payload_id : kValidIntroductionFramePayloadIds) { + fake_nearby_connections_manager_->SetPayloadPathStatus( + payload_id, location::nearby::connections::mojom::Status::kSuccess); + } - NiceMock<MockTransferUpdateCallback> callback; - ShareTarget share_target = SetUpIncomingConnection(callback); + NiceMock<MockTransferUpdateCallback> callback; + ShareTarget share_target = SetUpIncomingConnection(callback); - base::RunLoop run_loop_accept; - EXPECT_CALL(callback, OnTransferUpdate(testing::_, testing::_)) - .WillOnce(testing::Invoke( - [](const ShareTarget& share_target, TransferMetadata metadata) { - EXPECT_FALSE(metadata.is_final_status()); - EXPECT_EQ(TransferMetadata::Status::kAwaitingRemoteAcceptance, - metadata.status()); - })); - - service_->Accept( - share_target, - base::BindLambdaForTesting( - [&](NearbySharingServiceImpl::StatusCodes status_code) { - EXPECT_EQ(NearbySharingServiceImpl::StatusCodes::kOk, - status_code); - run_loop_accept.Quit(); - })); - - run_loop_accept.Run(); - - fake_nearby_connections_manager_->SetIncomingPayload( - kFilePayloadId, GetFilePayloadPtr(kFilePayloadId)); - - for (int64_t id : kValidIntroductionFramePayloadIds) { - if (id == kFilePayloadId) - continue; - - if (id != kWifiCredentialsPayloadId) { - fake_nearby_connections_manager_->SetIncomingPayload( - id, GetTextPayloadPtr(id, kTextPayload)); - } else { - fake_nearby_connections_manager_->SetIncomingPayload( - id, std::move(wifi_payload)); - } - - base::WeakPtr<NearbyConnectionsManager::PayloadStatusListener> - listener = fake_nearby_connections_manager_ - ->GetRegisteredPayloadStatusListener(id); - ASSERT_TRUE(listener); - - base::RunLoop run_loop_progress; - EXPECT_CALL(callback, OnTransferUpdate(testing::_, testing::_)) - .WillOnce(testing::Invoke([&](const ShareTarget& share_target, - TransferMetadata metadata) { + base::RunLoop run_loop_accept; + EXPECT_CALL(callback, OnTransferUpdate(testing::_, testing::_)) + .WillOnce(testing::Invoke( + [](const ShareTarget& share_target, TransferMetadata metadata) { EXPECT_FALSE(metadata.is_final_status()); - EXPECT_EQ(TransferMetadata::Status::kInProgress, + EXPECT_EQ(TransferMetadata::Status::kAwaitingRemoteAcceptance, metadata.status()); - run_loop_progress.Quit(); })); - location::nearby::connections::mojom::PayloadTransferUpdatePtr payload = - location::nearby::connections::mojom::PayloadTransferUpdate::New( - id, - location::nearby::connections::mojom::PayloadStatus::kSuccess, - /*total_bytes=*/kPayloadSize, - /*bytes_transferred=*/kPayloadSize); - listener->OnStatusUpdate(std::move(payload), - /*upgraded_medium=*/absl::nullopt); - run_loop_progress.Run(); + service_->Accept( + share_target, + base::BindLambdaForTesting( + [&](NearbySharingServiceImpl::StatusCodes status_code) { + EXPECT_EQ(NearbySharingServiceImpl::StatusCodes::kOk, + status_code); + run_loop_accept.Quit(); + })); - task_environment_.FastForwardBy(kMinProgressUpdateFrequency); + run_loop_accept.Run(); + + fake_nearby_connections_manager_->SetIncomingPayload( + kFilePayloadId, GetFilePayloadPtr(kFilePayloadId)); + + for (int64_t id : kValidIntroductionFramePayloadIds) { + if (id == kFilePayloadId) + continue; + + if (id != kWifiCredentialsPayloadId) { + fake_nearby_connections_manager_->SetIncomingPayload( + id, GetTextPayloadPtr(id, kTextPayload)); + } else { + fake_nearby_connections_manager_->SetIncomingPayload( + id, std::move(wifi_payload)); } - base::RunLoop run_loop_success; - EXPECT_CALL(callback, OnTransferUpdate(testing::_, testing::_)) - .WillOnce(testing::Invoke([&](const ShareTarget& share_target, - TransferMetadata metadata) { - EXPECT_TRUE(metadata.is_final_status()); - EXPECT_EQ(TransferMetadata::Status::kIncompletePayloads, - metadata.status()); - - ASSERT_TRUE(share_target.has_attachments()); - EXPECT_EQ(0u, wifi_network_handler_->num_configure_network_calls()); - - run_loop_success.Quit(); - })); - base::WeakPtr<NearbyConnectionsManager::PayloadStatusListener> listener = fake_nearby_connections_manager_->GetRegisteredPayloadStatusListener( - kFilePayloadId); + id); ASSERT_TRUE(listener); + base::RunLoop run_loop_progress; + EXPECT_CALL(callback, OnTransferUpdate(testing::_, testing::_)) + .WillOnce(testing::Invoke([&](const ShareTarget& share_target, + TransferMetadata metadata) { + EXPECT_FALSE(metadata.is_final_status()); + EXPECT_EQ(TransferMetadata::Status::kInProgress, metadata.status()); + run_loop_progress.Quit(); + })); + location::nearby::connections::mojom::PayloadTransferUpdatePtr payload = location::nearby::connections::mojom::PayloadTransferUpdate::New( - kFilePayloadId, - location::nearby::connections::mojom::PayloadStatus::kSuccess, + id, location::nearby::connections::mojom::PayloadStatus::kSuccess, /*total_bytes=*/kPayloadSize, /*bytes_transferred=*/kPayloadSize); listener->OnStatusUpdate(std::move(payload), /*upgraded_medium=*/absl::nullopt); + run_loop_progress.Run(); - run_loop_success.Run(); - - EXPECT_FALSE(fake_nearby_connections_manager_->connection_endpoint_info( - kEndpointId)); - EXPECT_FALSE(fake_nearby_connections_manager_->has_incoming_payloads()); - - // To avoid UAF in OnIncomingTransferUpdate(). - service_->UnregisterReceiveSurface(&callback); + task_environment_.FastForwardBy(kMinProgressUpdateFrequency); } + + base::RunLoop run_loop_success; + EXPECT_CALL(callback, OnTransferUpdate(testing::_, testing::_)) + .WillOnce(testing::Invoke([&](const ShareTarget& share_target, + TransferMetadata metadata) { + EXPECT_TRUE(metadata.is_final_status()); + EXPECT_EQ(TransferMetadata::Status::kIncompletePayloads, + metadata.status()); + + ASSERT_TRUE(share_target.has_attachments()); + EXPECT_EQ(0u, wifi_network_handler_->num_configure_network_calls()); + + run_loop_success.Quit(); + })); + + base::WeakPtr<NearbyConnectionsManager::PayloadStatusListener> listener = + fake_nearby_connections_manager_->GetRegisteredPayloadStatusListener( + kFilePayloadId); + ASSERT_TRUE(listener); + + location::nearby::connections::mojom::PayloadTransferUpdatePtr payload = + location::nearby::connections::mojom::PayloadTransferUpdate::New( + kFilePayloadId, + location::nearby::connections::mojom::PayloadStatus::kSuccess, + /*total_bytes=*/kPayloadSize, + /*bytes_transferred=*/kPayloadSize); + listener->OnStatusUpdate(std::move(payload), + /*upgraded_medium=*/absl::nullopt); + + run_loop_success.Run(); + + EXPECT_FALSE(fake_nearby_connections_manager_->connection_endpoint_info( + kEndpointId)); + EXPECT_FALSE(fake_nearby_connections_manager_->has_incoming_payloads()); + + // To avoid UAF in OnIncomingTransferUpdate(). + service_->UnregisterReceiveSurface(&callback); } protected: @@ -3116,12 +3098,7 @@ EXPECT_TRUE(share_target.has_attachments()); EXPECT_EQ(3u, share_target.text_attachments.size()); EXPECT_EQ(1u, share_target.file_attachments.size()); - if (base::FeatureList::IsEnabled( - features::kNearbySharingReceiveWifiCredentials)) { - EXPECT_EQ(1u, share_target.wifi_credentials_attachments.size()); - } else { - EXPECT_EQ(0u, share_target.wifi_credentials_attachments.size()); - } + EXPECT_EQ(1u, share_target.wifi_credentials_attachments.size()); EXPECT_EQ(kDeviceName, share_target.device_name); EXPECT_EQ(GURL(kTestMetadataIconUrl), share_target.image_url); EXPECT_EQ(kDeviceType, share_target.type); @@ -3436,13 +3413,8 @@ // for failure condition. if (id == kWifiCredentialsPayloadId) { - if (base::FeatureList::IsEnabled( - features::kNearbySharingReceiveWifiCredentials)) { - fake_nearby_connections_manager_->SetIncomingPayload( - id, GetWifiPayloadPtr(kWifiCredentialsPayloadId, kWifiPassword)); - } else { - continue; - } + fake_nearby_connections_manager_->SetIncomingPayload( + id, GetWifiPayloadPtr(kWifiCredentialsPayloadId, kWifiPassword)); } base::WeakPtr<NearbyConnectionsManager::PayloadStatusListener> listener = @@ -3741,12 +3713,7 @@ EXPECT_TRUE(share_target.has_attachments()); EXPECT_EQ(3u, share_target.text_attachments.size()); EXPECT_EQ(1u, share_target.file_attachments.size()); - if (base::FeatureList::IsEnabled( - features::kNearbySharingReceiveWifiCredentials)) { - EXPECT_EQ(1u, share_target.wifi_credentials_attachments.size()); - } else { - EXPECT_EQ(0u, share_target.wifi_credentials_attachments.size()); - } + EXPECT_EQ(1u, share_target.wifi_credentials_attachments.size()); EXPECT_EQ(kDeviceName, share_target.device_name); EXPECT_EQ(GURL(kTestMetadataIconUrl), share_target.image_url); EXPECT_EQ(kDeviceType, share_target.type); @@ -3802,12 +3769,7 @@ EXPECT_TRUE(share_target.has_attachments()); EXPECT_EQ(3u, share_target.text_attachments.size()); EXPECT_EQ(1u, share_target.file_attachments.size()); - if (base::FeatureList::IsEnabled( - features::kNearbySharingReceiveWifiCredentials)) { - EXPECT_EQ(1u, share_target.wifi_credentials_attachments.size()); - } else { - EXPECT_EQ(0u, share_target.wifi_credentials_attachments.size()); - } + EXPECT_EQ(1u, share_target.wifi_credentials_attachments.size()); EXPECT_EQ(kDeviceName, share_target.device_name); EXPECT_EQ(GURL(kTestMetadataIconUrl), share_target.image_url); EXPECT_EQ(kDeviceType, share_target.type);
diff --git a/chrome/browser/nearby_sharing/payload_tracker.cc b/chrome/browser/nearby_sharing/payload_tracker.cc index 8d754d1..6672c38d 100644 --- a/chrome/browser/nearby_sharing/payload_tracker.cc +++ b/chrome/browser/nearby_sharing/payload_tracker.cc
@@ -53,8 +53,6 @@ for (const auto& wifi_credentials : share_target.wifi_credentials_attachments) { - DCHECK(base::FeatureList::IsEnabled( - features::kNearbySharingReceiveWifiCredentials)); auto it = attachment_info_map.find(wifi_credentials.id()); if (it == attachment_info_map.end() || !it->second.payload_id) { NS_LOG(WARNING) << __func__
diff --git a/chrome/browser/nearby_sharing/payload_tracker_unittest.cc b/chrome/browser/nearby_sharing/payload_tracker_unittest.cc index 6b79c20..9d91049 100644 --- a/chrome/browser/nearby_sharing/payload_tracker_unittest.cc +++ b/chrome/browser/nearby_sharing/payload_tracker_unittest.cc
@@ -8,8 +8,6 @@ #include "base/files/file_path.h" #include "base/test/mock_callback.h" -#include "base/test/scoped_feature_list.h" -#include "chrome/browser/nearby_sharing/common/nearby_share_features.h" #include "chrome/browser/nearby_sharing/constants.h" #include "chrome/browser/nearby_sharing/transfer_metadata_builder.h" #include "content/public/test/browser_task_environment.h" @@ -68,10 +66,6 @@ share_target_.text_attachments.push_back(std::move(text)); } - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndEnableFeature( - features::kNearbySharingReceiveWifiCredentials); - WifiCredentialsAttachment wifi_credentials_ok( kWifiCredentialsIdOk, kWifiSecurityType, kWifiSsidOk);
diff --git a/chrome/browser/net/storage_test_utils.cc b/chrome/browser/net/storage_test_utils.cc index a9b53553..30cf0be 100644 --- a/chrome/browser/net/storage_test_utils.cc +++ b/chrome/browser/net/storage_test_utils.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/net/storage_test_utils.h" +#include "base/strings/stringprintf.h" #include "content/public/test/browser_test_utils.h" namespace storage::test { @@ -30,6 +31,12 @@ " () => { window.domAutomationController.send(false); }," ");"; +constexpr char kRequestStorageAccessForSite[] = + "document.requestStorageAccessForSite('%s').then(" + " () => { window.domAutomationController.send(true); }," + " () => { window.domAutomationController.send(false); }," + ");"; + constexpr char kHasStorageAccess[] = "document.hasStorageAccess().then(" " (result) => { window.domAutomationController.send(result); }," @@ -150,6 +157,15 @@ .ExtractBool(); } +bool RequestStorageAccessForSite(content::RenderFrameHost* frame, + const std::string& site) { + return content::EvalJs( + frame, + base::StringPrintf(kRequestStorageAccessForSite, site.c_str()), + content::EXECUTE_SCRIPT_USE_MANUAL_REPLY) + .ExtractBool(); +} + bool HasStorageAccessForFrame(content::RenderFrameHost* frame) { return content::EvalJs(frame, kHasStorageAccess, content::EXECUTE_SCRIPT_USE_MANUAL_REPLY)
diff --git a/chrome/browser/net/storage_test_utils.h b/chrome/browser/net/storage_test_utils.h index bfabd381..5c8db81 100644 --- a/chrome/browser/net/storage_test_utils.h +++ b/chrome/browser/net/storage_test_utils.h
@@ -35,6 +35,11 @@ // document.requestStorageAccess(). Returns true if the promise resolves; false // if it rejects. bool RequestStorageAccessForFrame(content::RenderFrameHost* frame); +// Helper to request storage access with a site override for a frame using +// document.requestStorageAccessForSite(site). Returns true if the promise +// resolves; false if it rejects. +bool RequestStorageAccessForSite(content::RenderFrameHost* frame, + const std::string& site); // Helper to see if a frame currently has storage access using // document.hasStorageAccess(). Returns true if the promise resolves with a // value of true; false otherwise.
diff --git a/chrome/browser/notifications/notification_interactive_uitest_mac.mm b/chrome/browser/notifications/notification_interactive_uitest_mac.mm index 4131d89..9b0aa058 100644 --- a/chrome/browser/notifications/notification_interactive_uitest_mac.mm +++ b/chrome/browser/notifications/notification_interactive_uitest_mac.mm
@@ -27,12 +27,17 @@ { base::scoped_nsobject<WindowedNSNotificationObserver> observer( [[WindowedNSNotificationObserver alloc] - initForNotification:NSApplicationDidResignActiveNotification + initForNotification:NSApplicationDidHideNotification object:NSApp]); [NSApp hide:nil]; [observer wait]; } - EXPECT_FALSE([NSApp isActive]); + EXPECT_TRUE([NSApp isHidden]); + + base::scoped_nsobject<WindowedNSNotificationObserver> observer( + [[WindowedNSNotificationObserver alloc] + initForNotification:NSApplicationDidUnhideNotification + object:NSApp]); std::string result = CreateNotification( browser(), true, "", "", "", "", @@ -43,13 +48,8 @@ message_center::Notification* notification = *message_center->GetVisibleNotifications().begin(); - { - base::scoped_nsobject<WindowedNSNotificationObserver> observer( - [[WindowedNSNotificationObserver alloc] - initForNotification:NSApplicationDidBecomeActiveNotification - object:NSApp]); - message_center->ClickOnNotification(notification->id()); - [observer wait]; - } - EXPECT_TRUE([NSApp isActive]); + message_center->ClickOnNotification(notification->id()); + [observer wait]; + + EXPECT_FALSE([NSApp isHidden]); }
diff --git a/chrome/browser/password_manager/chrome_password_manager_client.cc b/chrome/browser/password_manager/chrome_password_manager_client.cc index bfff557..817210a 100644 --- a/chrome/browser/password_manager/chrome_password_manager_client.cc +++ b/chrome/browser/password_manager/chrome_password_manager_client.cc
@@ -461,7 +461,9 @@ TouchToFillWebAuthnCredential::DisplayName( suggestion.main_text.value), TouchToFillWebAuthnCredential::BackendId( - suggestion.template GetPayload<std::string>())); + (suggestion + .template GetPayload<autofill::Suggestion::BackendId>()) + .value())); }); }
diff --git a/chrome/browser/password_manager/chrome_webauthn_credentials_delegate.cc b/chrome/browser/password_manager/chrome_webauthn_credentials_delegate.cc index 6d4b81e..c792857e 100644 --- a/chrome/browser/password_manager/chrome_webauthn_credentials_delegate.cc +++ b/chrome/browser/password_manager/chrome_webauthn_credentials_delegate.cc
@@ -125,7 +125,8 @@ password_manager::GetPlatformAuthenticatorLabel()); suggestion.icon = "globeIcon"; suggestion.frontend_id = autofill::POPUP_ITEM_ID_WEBAUTHN_CREDENTIAL; - suggestion.payload = base::Base64Encode(credential.cred_id); + suggestion.payload = + autofill::Suggestion::BackendId(base::Base64Encode(credential.cred_id)); suggestions.push_back(std::move(suggestion)); } suggestions_ = std::move(suggestions);
diff --git a/chrome/browser/pdf/pdf_find_request_manager_browsertest.cc b/chrome/browser/pdf/pdf_find_request_manager_browsertest.cc index e1edc7a..44706f5 100644 --- a/chrome/browser/pdf/pdf_find_request_manager_browsertest.cc +++ b/chrome/browser/pdf/pdf_find_request_manager_browsertest.cc
@@ -350,4 +350,26 @@ EXPECT_EQ(1, results.number_of_matches); } +// Regression test for crbug.com/1352097. +IN_PROC_BROWSER_TEST_F(PdfFindRequestManagerTest, SingleResultFindNext) { + ASSERT_TRUE(embedded_test_server()->Start()); + LoadAndWait("/find_in_pdf_page.pdf"); + ASSERT_TRUE(pdf_extension_test_util::EnsurePDFHasLoaded(contents())); + + auto options = blink::mojom::FindOptions::New(); + Find("pdf", options.Clone()); + delegate()->MarkNextReply(); + delegate()->WaitForNextReply(); + + options->new_session = false; + Find("pdf", options.Clone()); + delegate()->MarkNextReply(); + delegate()->WaitForNextReply(); + + FindResults results = delegate()->GetFindResults(); + EXPECT_EQ(last_request_id(), results.request_id); + EXPECT_EQ(1, results.number_of_matches); + EXPECT_EQ(1, results.active_match_ordinal); +} + } // namespace content
diff --git a/chrome/browser/profiles/android/java/src/org/chromium/chrome/browser/profiles/Profile.java b/chrome/browser/profiles/android/java/src/org/chromium/chrome/browser/profiles/Profile.java index a8a5b1b7..0ed3fdf 100644 --- a/chrome/browser/profiles/android/java/src/org/chromium/chrome/browser/profiles/Profile.java +++ b/chrome/browser/profiles/android/java/src/org/chromium/chrome/browser/profiles/Profile.java
@@ -184,11 +184,21 @@ /** * @return Whether or not the native side profile exists. */ - // @VisibleForTesting (Temporarily allow calling this to debug https://crbug.com/1346710). + @VisibleForTesting public boolean isNativeInitialized() { return mNativeProfileAndroid != 0; } + /** + * When called, raises an exception if the native pointer is not initialized. This is useful to + * get a more debuggable stacktrace than failing on native-side when dereferencing. + */ + public void ensureNativeInitialized() { + if (mNativeProfileAndroid == 0) { + throw new RuntimeException("Native profile pointer not initialized."); + } + } + @Override public long getNativeBrowserContextPointer() { return ProfileJni.get().getBrowserContextPointer(mNativeProfileAndroid);
diff --git a/chrome/browser/renderer_preferences_util.cc b/chrome/browser/renderer_preferences_util.cc index cc8ea097..ed6ffbb 100644 --- a/chrome/browser/renderer_preferences_util.cc +++ b/chrome/browser/renderer_preferences_util.cc
@@ -83,13 +83,10 @@ // Extracts the string representation of URLs allowed for local IP exposure. std::vector<std::string> GetLocalIpsAllowedUrls( - const base::Value* allowed_urls) { + const base::Value::List& allowed_urls) { std::vector<std::string> ret; - if (allowed_urls) { - const auto& urls = allowed_urls->GetListDeprecated(); - for (const auto& url : urls) - ret.push_back(url.GetString()); - } + for (const auto& url : allowed_urls) + ret.push_back(url.GetString()); return ret; } @@ -139,8 +136,8 @@ ParsePortRange(webrtc_udp_port_range, &prefs->webrtc_udp_min_port, &prefs->webrtc_udp_max_port); - const base::Value* allowed_urls = - pref_service->GetList(prefs::kWebRtcLocalIpsAllowedUrls); + const base::Value::List& allowed_urls = + pref_service->GetValueList(prefs::kWebRtcLocalIpsAllowedUrls); prefs->webrtc_local_ips_allowed_urls = GetLocalIpsAllowedUrls(allowed_urls); prefs->webrtc_allow_legacy_tls_protocols = pref_service->GetBoolean(prefs::kWebRTCAllowLegacyTLSProtocols);
diff --git a/chrome/browser/resources/chromeos/internet_detail_dialog/internet_detail_dialog.js b/chrome/browser/resources/chromeos/internet_detail_dialog/internet_detail_dialog.js index a8828ab5..4b99f5f 100644 --- a/chrome/browser/resources/chromeos/internet_detail_dialog/internet_detail_dialog.js +++ b/chrome/browser/resources/chromeos/internet_detail_dialog/internet_detail_dialog.js
@@ -124,6 +124,10 @@ created() { this.networkConfig_ = MojoInterfaceProviderImpl.getInstance().getMojoServiceRemote(); + window.CrPolicyStrings = { + controlledSettingPolicy: + loadTimeData.getString('controlledSettingPolicy'), + }; }, /** @override */
diff --git a/chrome/browser/resources/settings/autofill_page/passwords_import_dialog.ts b/chrome/browser/resources/settings/autofill_page/passwords_import_dialog.ts index c6110437..bb34b32c 100644 --- a/chrome/browser/resources/settings/autofill_page/passwords_import_dialog.ts +++ b/chrome/browser/resources/settings/autofill_page/passwords_import_dialog.ts
@@ -166,6 +166,7 @@ this.handleSuccess_(); break; case chrome.passwordsPrivate.ImportResultsStatus.IO_ERROR: + case chrome.passwordsPrivate.ImportResultsStatus.UNKNOWN_ERROR: this.descriptionText_ = this.i18n('importPasswordsUnknownError'); this.dialogState = ImportDialogState.ERROR; break; @@ -230,12 +231,16 @@ private getFailedEntryError_( status: chrome.passwordsPrivate.ImportEntryStatus): string { + // TODO(crbug/1325290): return appropriate strings for LONG_URL, + // NON_ASCII_URL, UNKNOWN_ERROR. switch (status) { case chrome.passwordsPrivate.ImportEntryStatus.MISSING_PASSWORD: return this.i18n('importPasswordsMissingPassword'); case chrome.passwordsPrivate.ImportEntryStatus.MISSING_URL: return this.i18n('importPasswordsMissingURL'); case chrome.passwordsPrivate.ImportEntryStatus.INVALID_URL: + case chrome.passwordsPrivate.ImportEntryStatus.LONG_URL: + case chrome.passwordsPrivate.ImportEntryStatus.NON_ASCII_URL: return this.i18n('importPasswordsInvalidURL'); case chrome.passwordsPrivate.ImportEntryStatus.LONG_PASSWORD: return this.i18n('importPasswordsLongPassword'); @@ -248,8 +253,11 @@ return this.i18n('importPasswordsConflictDevice'); case chrome.passwordsPrivate.ImportEntryStatus.CONFLICT_ACCOUNT: return this.i18n('importPasswordsConflictAccount', this.accountEmail); + case chrome.passwordsPrivate.ImportEntryStatus.UNKNOWN_ERROR: + return ''; + default: + assertNotReached(); } - assertNotReached(); } private onCancelClick_() {
diff --git a/chrome/browser/resources/settings/chromeos/os_route.js b/chrome/browser/resources/settings/chromeos/os_route.js index 4d6e1d83..fac2101 100644 --- a/chrome/browser/resources/settings/chromeos/os_route.js +++ b/chrome/browser/resources/settings/chromeos/os_route.js
@@ -158,14 +158,6 @@ r.PERSONALIZATION = createSection( r.BASIC, routesMojomWebui.PERSONALIZATION_SECTION_PATH, Section.kPersonalization); - // Top level PERSONALIZATION section only contains a link to personalization - // hub if hub is enabled. The subpages should only be accessible if hub is - // off. - if (!loadTimeData.getBoolean('isPersonalizationHubEnabled')) { - r.CHANGE_PICTURE = createSubpage( - r.PERSONALIZATION, routesMojomWebui.CHANGE_PICTURE_SUBPAGE_PATH, - Subpage.kChangePicture); - } } // Search and Assistant section.
diff --git a/chrome/browser/resources/settings/chromeos/os_settings.gni b/chrome/browser/resources/settings/chromeos/os_settings.gni index b054eee..5b43c8b 100644 --- a/chrome/browser/resources/settings/chromeos/os_settings.gni +++ b/chrome/browser/resources/settings/chromeos/os_settings.gni
@@ -117,7 +117,6 @@ "chromeos/os_settings_page/main_page_behavior.js", "chromeos/os_settings_routes.js", "chromeos/parental_controls_page/parental_controls_browser_proxy.js", - "chromeos/personalization_page/change_picture_browser_proxy.js", "chromeos/personalization_page/personalization_hub_browser_proxy.js", "chromeos/personalization_search_handler.js", "chromeos/pref_to_setting_metric_converter.js", @@ -327,7 +326,6 @@ "chromeos/os_settings_search_box/os_search_result_row.js", "chromeos/os_settings_search_box/os_settings_search_box.js", "chromeos/parental_controls_page/parental_controls_page.js", - "chromeos/personalization_page/change_picture.js", "chromeos/personalization_page/personalization_page.js", "chromeos/settings_scheduler_slider/settings_scheduler_slider.js", ]
diff --git a/chrome/browser/resources/settings/chromeos/os_settings.js b/chrome/browser/resources/settings/chromeos/os_settings.js index a97f69e..e00d775 100644 --- a/chrome/browser/resources/settings/chromeos/os_settings.js +++ b/chrome/browser/resources/settings/chromeos/os_settings.js
@@ -39,7 +39,6 @@ import './multidevice_page/multidevice_page.js'; import './nearby_share_page/nearby_share_receive_dialog.js'; import './nearby_share_page/nearby_share_subpage.js'; -import './personalization_page/change_picture.js'; import './personalization_page/personalization_page.js'; import './os_a11y_page/change_dictation_locale_dialog.js'; import './os_about_page/channel_switcher_dialog.js'; @@ -170,7 +169,6 @@ export {routes} from './os_route.js'; export {SearchEngine, SearchEnginesBrowserProxy, SearchEnginesBrowserProxyImpl, SearchEnginesInfo} from './os_search_page/search_engines_browser_proxy.js'; export {ParentalControlsBrowserProxy, ParentalControlsBrowserProxyImpl} from './parental_controls_page/parental_controls_browser_proxy.js'; -export {ChangePictureBrowserProxy, ChangePictureBrowserProxyImpl} from './personalization_page/change_picture_browser_proxy.js'; export {PersonalizationHubBrowserProxy, PersonalizationHubBrowserProxyImpl} from './personalization_page/personalization_hub_browser_proxy.js'; export {getPersonalizationSearchHandler, setPersonalizationSearchHandlerForTesting} from './personalization_search_handler.js'; export {getSettingsSearchHandler, setSettingsSearchHandlerForTesting} from './settings_search_handler.js';
diff --git a/chrome/browser/resources/settings/chromeos/personalization_page/BUILD.gn b/chrome/browser/resources/settings/chromeos/personalization_page/BUILD.gn index 80ecbe5..9d8ab26 100644 --- a/chrome/browser/resources/settings/chromeos/personalization_page/BUILD.gn +++ b/chrome/browser/resources/settings/chromeos/personalization_page/BUILD.gn
@@ -10,40 +10,11 @@ closure_flags = os_settings_closure_flags is_polymer3 = true deps = [ - ":change_picture", - ":change_picture_browser_proxy", ":personalization_hub_browser_proxy", ":personalization_page", ] } -js_library("change_picture") { - deps = [ - ":change_picture_browser_proxy", - "..:deep_linking_behavior", - "..:metrics_recorder", - "..:os_route", - "..:route_observer_behavior", - "../..:router", - "//ash/webui/common/resources/cr_picture:cr_picture_list", - "//ash/webui/common/resources/cr_picture:cr_picture_pane", - "//ash/webui/common/resources/cr_picture:cr_picture_types", - "//ash/webui/common/resources/cr_picture:png", - "//third_party/polymer/v3_0/components-chromium/iron-selector:iron-selector", - "//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:load_time_data.m", - "//ui/webui/resources/js:util.m", - "//ui/webui/resources/js:web_ui_listener_behavior.m", - ] - externs_list = [ "//ui/webui/resources/cr_elements/cr_a11y_announcer/cr_a11y_announcer_externs.js" ] -} - -js_library("change_picture_browser_proxy") { - deps = [ "//ui/webui/resources/js:cr.m" ] -} - js_library("personalization_page") { deps = [ ":personalization_hub_browser_proxy", @@ -63,8 +34,5 @@ } html_to_js("web_components") { - js_files = [ - "change_picture.js", - "personalization_page.js", - ] + js_files = [ "personalization_page.js" ] }
diff --git a/chrome/browser/resources/settings/chromeos/personalization_page/change_picture.html b/chrome/browser/resources/settings/chromeos/personalization_page/change_picture.html deleted file mode 100644 index 3c2d96b..0000000 --- a/chrome/browser/resources/settings/chromeos/personalization_page/change_picture.html +++ /dev/null
@@ -1,98 +0,0 @@ -<style include="settings-shared"> - :host { - /* #headerLine height + padding */ - --cr-settings-header-height: calc(62px + 1.34em); - --title-height: 2em; - --title-padding: 16px; - display: block; - min-height: 328px; - } - - #title { - height: var(--title-height); - margin-inline-start: 20px; - padding-top: var(--title-padding); - } - - #container { - align-items: flex-start; - display: flex; - margin-inline-start: 20px; - position: absolute; - top: calc(var(--cr-settings-header-height) + - var(--title-padding) + - var(--title-height)); - user-select: none; - } - - #picturePane { - --cr-picture-image-size: 192px; - flex-shrink: 0; - height: 288px; - margin-inline-end: 24px; - margin-top: 6px; - position: relative; - width: 288px; - } - - #sourceInfo { - color: var(--cros-text-color-disabled); - display: flex; - flex-direction: column; - margin-top: 20px; - } - - #pictureList { - /* TODO(reveman): Find a way to have height align to viewport - without using fixed position. */ - height: calc(100vh - - var(--cr-toolbar-height) - - var(--cr-toolbar-padding-top) - - var(--cr-settings-header-height) - - var(--title-padding) - - var(--title-height)); - margin-inline-end: 16px; - margin-top: 0; - min-height: 332px; - overflow-x: hidden; - overflow-y: auto; - position: relative; - } - -</style> -<div id="title">$i18n{changePicturePageDescription}</div> -<div id="container"> - <div> - <cr-picture-pane id="picturePane" - camera-present="[[cameraPresent_]]", - image-src="[[getImageSrc_(selectedItem_)]]" - image-type="[[getImageType_(selectedItem_)]]" - discard-image-label="$i18n{discardPhoto}" - preview-alt-text="$i18n{previewAltText}" - take-photo-label="$i18n{takePhoto}" - capture-video-label="$i18n{captureVideo}" - switch-mode-to-camera-label="$i18n{switchModeToCamera}" - switch-mode-to-video-label="$i18n{switchModeToVideo}" - camera-video-mode-enabled="[[cameraVideoModeEnabled_]]" - on-keys-pressed="onCameraPaneKeysPressed_"> - </cr-picture-pane> - <div id="sourceInfo" - hidden="[[!shouldShowSourceInfo_(selectedItem_, authorInfo_, websiteInfo_)]]"> - [[authorInfo_]] - <a href="[[websiteInfo_]]" target="_blank"> - [[websiteInfo_]] - </a> - </div> - </div> - <cr-picture-list id="pictureList" - hidden="[[!currentDefaultImages_]]" - camera-present="[[cameraPresent_]]" - default-images="[[currentDefaultImages_]]" - selected-item="{{selectedItem_}}" - choose-file-label="$i18n{chooseFile}" - old-image-label="[[oldImageLabel_]]" - profile-image-label="$i18n{profilePhoto}" - take-photo-label="$i18n{takePhoto}" - capture-video-label="$i18n{captureVideo}"> - </cr-picture-list> -</div>
diff --git a/chrome/browser/resources/settings/chromeos/personalization_page/change_picture.js b/chrome/browser/resources/settings/chromeos/personalization_page/change_picture.js deleted file mode 100644 index 24c6463..0000000 --- a/chrome/browser/resources/settings/chromeos/personalization_page/change_picture.js +++ /dev/null
@@ -1,405 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -/** - * @fileoverview - * 'settings-change-picture' is the settings subpage containing controls to - * edit a ChromeOS user's picture. - */ -import 'chrome://resources/ash/common/cr_picture/cr_picture_list.js'; -import 'chrome://resources/ash/common/cr_picture/cr_picture_pane.js'; -import '../../settings_shared.css.js'; - -import {CrPicture} from 'chrome://resources/ash/common/cr_picture/cr_picture_types.js'; -import {isEncodedPngDataUrlAnimated} from 'chrome://resources/ash/common/cr_picture/png.js'; -import {getInstance as getAnnouncerInstance} from 'chrome://resources/cr_elements/cr_a11y_announcer/cr_a11y_announcer.js'; -import {assert, assertNotReached} from 'chrome://resources/js/assert.m.js'; -import {I18nBehavior, I18nBehaviorInterface} from 'chrome://resources/js/i18n_behavior.m.js'; -import {WebUIListenerBehavior, WebUIListenerBehaviorInterface} from 'chrome://resources/js/web_ui_listener_behavior.m.js'; -import {html, mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; - -import {loadTimeData} from '../../i18n_setup.js'; -import {Setting} from '../../mojom-webui/setting.mojom-webui.js'; -import {DeepLinkingBehavior, DeepLinkingBehaviorInterface} from '../deep_linking_behavior.js'; -import {recordSettingChange} from '../metrics_recorder.js'; -import {routes} from '../os_route.js'; -import {RouteObserverBehavior, RouteObserverBehaviorInterface} from '../route_observer_behavior.js'; - -import {ChangePictureBrowserProxy, ChangePictureBrowserProxyImpl, DefaultImage} from './change_picture_browser_proxy.js'; - -/** - * @constructor - * @extends {PolymerElement} - * @implements {DeepLinkingBehaviorInterface} - * @implements {RouteObserverBehaviorInterface} - * @implements {I18nBehaviorInterface} - * @implements {WebUIListenerBehaviorInterface} - */ -const SettingsChangePictureElementBase = mixinBehaviors( - [ - DeepLinkingBehavior, - RouteObserverBehavior, - I18nBehavior, - WebUIListenerBehavior, - ], - PolymerElement); - -/** @polymer */ -class SettingsChangePictureElement extends SettingsChangePictureElementBase { - static get is() { - return 'settings-change-picture'; - } - - static get template() { - return html`{__html_template__}`; - } - - static get properties() { - return { - /** - * True if the user has a plugged-in webcam. - * @private {boolean} - */ - cameraPresent_: { - type: Boolean, - value: false, - }, - - /** - * The currently selected item. This property is bound to the - * iron-selector and never directly assigned. This may be undefined - * momentarily as the selection changes due to iron-selector - * implementation details. - * @private {?CrPicture.ImageElement} - */ - selectedItem_: { - type: Object, - value: null, - }, - - /** - * The current set of the default user images. - * @private {?Array<!DefaultImage>} - */ - currentDefaultImages_: { - type: Object, - value: null, - }, - - /** - * True when camera video mode is enabled. - * @private {boolean} - */ - cameraVideoModeEnabled_: { - type: Boolean, - value() { - return loadTimeData.getBoolean('changePictureVideoModeEnabled'); - }, - readOnly: true, - }, - - /** - * Author info of the default image. - * @private {string} - */ - authorInfo_: String, - - /** - * Website info of the default image. - * @private {string} - */ - websiteInfo_: String, - - /** @private */ - oldImageLabel_: String, - - /** - * Used by DeepLinkingBehavior to focus this page's deep links. - * @type {!Set<!Setting>} - */ - supportedSettingIds: { - type: Object, - value: () => new Set([Setting.kChangeDeviceAccountImage]), - }, - }; - } - - constructor() { - super(); - - /** @private {!ChangePictureBrowserProxy} */ - this.browserProxy_ = ChangePictureBrowserProxyImpl.getInstance(); - - /** @private {?CrPictureListElement} */ - this.pictureList_ = null; - - /** @private {boolean} */ - this.oldImagePending_ = false; - } - - /** @override */ - ready() { - super.ready(); - - this.pictureList_ = - /** @type {CrPictureListElement} */ (this.$.pictureList); - - this.addEventListener('discard-image', this.onDiscardImage_); - this.addEventListener('image-activate', (e) => { - this.onImageActivate_( - /** @type {!CustomEvent<!CrPicture.ImageElement>} */ (e)); - }); - this.addEventListener('focus-action', this.onFocusAction_); - this.addEventListener('photo-taken', (e) => { - this.onPhotoTaken_( - /** @type {!CustomEvent<{photoDataUrl: string}>} */ (e)); - }); - this.addEventListener('switch-mode', (e) => { - this.onSwitchMode_(/** @type {!CustomEvent<boolean>} */ (e)); - }); - } - - /** @override */ - connectedCallback() { - super.connectedCallback(); - - this.addWebUIListener( - 'default-images-changed', this.receiveDefaultImages_.bind(this)); - this.addWebUIListener( - 'selected-image-changed', this.receiveSelectedImage_.bind(this)); - this.addWebUIListener( - 'old-image-changed', this.receiveOldImage_.bind(this)); - this.addWebUIListener( - 'preview-deprecated-image', - this.receivePreviewDeprecatedImage_.bind(this)); - this.addWebUIListener( - 'profile-image-changed', this.receiveProfileImage_.bind(this)); - this.addWebUIListener( - 'camera-presence-changed', this.receiveCameraPresence_.bind(this)); - } - - /** - * Overridden from DeepLinkingBehavior. - * @param {!Setting} settingId - * @return {boolean} - */ - beforeDeepLinkAttempt(settingId) { - assert(settingId === Setting.kChangeDeviceAccountImage); - - this.pictureList_.setFocus(); - return false; - } - - - /** @protected */ - currentRouteChanged(newRoute) { - if (newRoute === routes.CHANGE_PICTURE) { - this.browserProxy_.initialize(); - this.browserProxy_.requestSelectedImage(); - this.pictureList_.setFocus(); - this.attemptDeepLink(); - } else { - // Ensure we deactivate the camera when we navigate away. - this.selectedItem_ = null; - } - } - - /** - * Handler for the 'default-images-changed' event. - * @param {{current_default_images: !Array<!DefaultImage>}} info - * @private - */ - receiveDefaultImages_(info) { - this.currentDefaultImages_ = info.current_default_images; - } - - /** - * Handler for the 'selected-image-changed' event. Is only called with - * default images. - * @param {string} imageUrl - * @private - */ - receiveSelectedImage_(imageUrl) { - this.pictureList_.setSelectedImageUrl(imageUrl); - } - - /** - * Handler for the 'old-image-changed' event. The Old image is any selected - * non-profile and non-default image. It can be from the camera or a file. - * When this method is called, the Old image becomes the selected image. - * @param {string} imageUrl - * @private - */ - receiveOldImage_(imageUrl) { - this.oldImageLabel_ = this.i18n( - isEncodedPngDataUrlAnimated(imageUrl) ? 'oldVideo' : 'oldPhoto'); - this.oldImagePending_ = false; - this.pictureList_.setOldImageUrl(imageUrl); - } - - /** - * Handler for the 'preview-deprecated-image' event. - * When this method is called, preview the deprecated default image in - * picturePane while do not show in the pictureList. - * Also set the source info for the deprecated image. - * @param {!{url: string, author: string, website: string}} imageInfo - * @private - */ - receivePreviewDeprecatedImage_(imageInfo) { - this.$.picturePane.previewDeprecatedImage(imageInfo.url); - this.authorInfo_ = - imageInfo.author ? this.i18n('authorCreditText', imageInfo.author) : ''; - this.websiteInfo_ = imageInfo.website; - this.selectedItem_ = null; - } - - /** - * Whether the source info should be shown. - * @param {CrPicture.ImageElement} selectedItem - * @param {string} authorInfo - * @param {string} websiteInfo - * @private - */ - shouldShowSourceInfo_(selectedItem, authorInfo, websiteInfo) { - return !selectedItem && (authorInfo || websiteInfo); - } - - /** - * Handler for the 'profile-image-changed' event. - * @param {string} imageUrl - * @param {boolean} selected - * @private - */ - receiveProfileImage_(imageUrl, selected) { - this.pictureList_.setProfileImageUrl(imageUrl, selected); - } - - /** - * Handler for the 'camera-presence-changed' event. - * @param {boolean} cameraPresent - * @private - */ - receiveCameraPresence_(cameraPresent) { - this.cameraPresent_ = cameraPresent; - } - - /** - * Selects an image element. - * @param {!CrPicture.ImageElement} image - * @private - */ - selectImage_(image) { - switch (image.dataset.type) { - case CrPicture.SelectionTypes.CAMERA: - /** CrPicturePaneElement */ (this.$.picturePane).takePhoto(); - break; - case CrPicture.SelectionTypes.FILE: - this.browserProxy_.chooseFile(); - recordSettingChange(); - break; - case CrPicture.SelectionTypes.PROFILE: - this.browserProxy_.selectProfileImage(); - recordSettingChange(); - break; - case CrPicture.SelectionTypes.OLD: - this.browserProxy_.selectOldImage(); - recordSettingChange(); - break; - case CrPicture.SelectionTypes.DEFAULT: - this.browserProxy_.selectDefaultImage(image.dataset.url); - recordSettingChange(); - break; - default: - assertNotReached('Selected unknown image type'); - } - } - - /** - * Handler for when an image is activated. - * @param {!CustomEvent<!CrPicture.ImageElement>} event - * @private - */ - onImageActivate_(event) { - this.selectImage_(event.detail); - } - - /** Focus the action button in the picture pane. */ - onFocusAction_() { - /** CrPicturePaneElement */ (this.$.picturePane).focusActionButton(); - } - - /** - * @param {!CustomEvent<{photoDataUrl: string}>} event - * @private - */ - onPhotoTaken_(event) { - this.oldImagePending_ = true; - this.browserProxy_.photoTaken(event.detail.photoDataUrl); - this.pictureList_.setOldImageUrl(event.detail.photoDataUrl); - this.pictureList_.setFocus(); - getAnnouncerInstance().announce( - loadTimeData.getString('photoCaptureAccessibleText')); - } - - /** - * @param {!CustomEvent<boolean>} event - * @private - */ - onSwitchMode_(event) { - const videomode = event.detail; - getAnnouncerInstance().announce(this.i18n( - videomode ? 'videoModeAccessibleText' : 'photoModeAccessibleText')); - } - - /** - * Callback the iron-a11y-keys "keys-pressed" event bubbles up from the - * cr-camera-pane. - * @param {!CustomEvent<!{key: string, keyboardEvent: Object}>} event - * @private - */ - onCameraPaneKeysPressed_(event) { - this.$.pictureList.focus(); - this.$.pictureList.onKeysPressed(event); - } - - /** @private */ - onDiscardImage_() { - // Prevent image from being discarded if old image is pending. - if (this.oldImagePending_) { - return; - } - this.pictureList_.setOldImageUrl(CrPicture.kDefaultImageUrl); - // Revert to profile image as we don't know what last used default image is. - this.browserProxy_.selectProfileImage(); - - const event = new CustomEvent('iron-announce', { - bubbles: true, - composed: true, - detail: {text: this.i18n('photoDiscardAccessibleText')}, - }); - this.dispatchEvent(event); - } - - /** - * @param {CrPicture.ImageElement} selectedItem - * @return {string} - * @private - */ - getImageSrc_(selectedItem) { - return (selectedItem && selectedItem.dataset.url) || ''; - } - - /** - * @param {CrPicture.ImageElement} selectedItem - * @return {string} - * @private - */ - getImageType_(selectedItem) { - return (selectedItem && selectedItem.dataset.type) || - CrPicture.SelectionTypes.NONE; - } -} - -customElements.define( - SettingsChangePictureElement.is, SettingsChangePictureElement);
diff --git a/chrome/browser/resources/settings/chromeos/personalization_page/change_picture_browser_proxy.js b/chrome/browser/resources/settings/chromeos/personalization_page/change_picture_browser_proxy.js deleted file mode 100644 index c6cff981..0000000 --- a/chrome/browser/resources/settings/chromeos/personalization_page/change_picture_browser_proxy.js +++ /dev/null
@@ -1,115 +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. - -/** - * An object describing a default image. - * @typedef {{ - * author: (string|undefined), - * index: number, - * title: (string|undefined), - * url: string, - * website: (string|undefined) - * }} - */ -export let DefaultImage; - -/** @interface */ -export class ChangePictureBrowserProxy { - /** - * Retrieves the initial set of default images, profile image, etc. As a - * response, the C++ sends these WebUIListener events: - * 'default-images-changed', 'profile-image-changed', 'old-image-changed', - * and 'selected-image-changed' - */ - initialize() {} - - /** - * Sets the user image to one of the default images. As a response, the C++ - * sends the 'default-images-changed' WebUIListener event. - * @param {string} imageUrl - */ - selectDefaultImage(imageUrl) {} - - /** - * Sets the user image to the 'old' image. As a response, the C++ sends the - * 'old-image-changed' WebUIListener event. - */ - selectOldImage() {} - - /** - * Sets the user image to the profile image. As a response, the C++ sends - * the 'profile-image-changed' WebUIListener event. - */ - selectProfileImage() {} - - /** - * Provides the taken photo as a data URL to the C++ and sets the user - * image to the 'old' image. As a response, the C++ sends the - * 'old-image-changed' WebUIListener event. - * @param {string} photoDataUrl - */ - photoTaken(photoDataUrl) {} - - /** - * Requests a file chooser to select a new user image. No response is - * expected. - */ - chooseFile() {} - - /** Requests the currently selected image. */ - requestSelectedImage() {} -} - -/** @type {?ChangePictureBrowserProxy} */ -let instance = null; - -/** - * @implements {ChangePictureBrowserProxy} - */ -export class ChangePictureBrowserProxyImpl { - /** @return {!ChangePictureBrowserProxy} */ - static getInstance() { - return instance || (instance = new ChangePictureBrowserProxyImpl()); - } - - /** @param {!ChangePictureBrowserProxy} obj */ - static setInstanceForTesting(obj) { - instance = obj; - } - - /** @override */ - initialize() { - chrome.send('onChangePicturePageInitialized'); - } - - /** @override */ - selectDefaultImage(imageUrl) { - chrome.send('selectImage', [imageUrl, 'default']); - } - - /** @override */ - selectOldImage() { - chrome.send('selectImage', ['', 'old']); - } - - /** @override */ - selectProfileImage() { - chrome.send('selectImage', ['', 'profile']); - } - - /** @override */ - photoTaken(photoDataUrl) { - chrome.send('photoTaken', [photoDataUrl]); - } - - /** @override */ - chooseFile() { - chrome.send('chooseFile'); - } - - /** @override */ - requestSelectedImage() { - chrome.send('requestSelectedImage'); - } -}
diff --git a/chrome/browser/resources/settings/chromeos/personalization_page/personalization_page.html b/chrome/browser/resources/settings/chromeos/personalization_page/personalization_page.html index 23731f2..ffb20436 100644 --- a/chrome/browser/resources/settings/chromeos/personalization_page/personalization_page.html +++ b/chrome/browser/resources/settings/chromeos/personalization_page/personalization_page.html
@@ -9,19 +9,6 @@ on-click="openPersonalizationHub_"> </cr-link-row> </template> - - <template is="dom-if" if="[[!isPersonalizationHubEnabled_]]"> - <cr-link-row id="changePictureRow" - label="$i18n{changePictureTitle}" - on-click="navigateToChangePicture_" - role-description="$i18n{subpageArrowRoleDescription}"> - </cr-link-row> - </template> </div> - <template is="dom-if" route-path="/changePicture"> - <settings-subpage page-title="$i18n{changePictureTitle}"> - <settings-change-picture></settings-change-picture> - </settings-subpage> - </template> </settings-animated-pages>
diff --git a/chrome/browser/resources/settings/chromeos/personalization_page/personalization_page.js b/chrome/browser/resources/settings/chromeos/personalization_page/personalization_page.js index 06f039f6..c515f74e 100644 --- a/chrome/browser/resources/settings/chromeos/personalization_page/personalization_page.js +++ b/chrome/browser/resources/settings/chromeos/personalization_page/personalization_page.js
@@ -7,12 +7,10 @@ * personalization settings. */ import 'chrome://resources/cr_elements/cr_link_row/cr_link_row.js'; -import './change_picture.js'; import '../../settings_page/settings_animated_pages.js'; import '../../settings_page/settings_subpage.js'; import '../../settings_shared.css.js'; -import {I18nBehavior, I18nBehaviorInterface} from 'chrome://resources/js/i18n_behavior.m.js'; import {html, mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {loadTimeData} from '../../i18n_setup.js'; @@ -28,11 +26,10 @@ * @constructor * @extends {PolymerElement} * @implements {DeepLinkingBehaviorInterface} - * @implements {I18nBehaviorInterface} * @implements {RouteObserverBehaviorInterface} */ const SettingsPersonalizationPageElementBase = mixinBehaviors( - [DeepLinkingBehavior, I18nBehavior, RouteObserverBehavior], PolymerElement); + [DeepLinkingBehavior, RouteObserverBehavior], PolymerElement); /** @polymer */ class SettingsPersonalizationPageElement extends @@ -66,10 +63,6 @@ type: Object, value() { const map = new Map(); - if (routes.CHANGE_PICTURE) { - map.set(routes.CHANGE_PICTURE.path, '#changePictureRow'); - } - return map; }, }, @@ -111,11 +104,6 @@ openPersonalizationHub_() { this.personalizationHubBrowserProxy_.openPersonalizationHub(); } - - /** @private */ - navigateToChangePicture_() { - Router.getInstance().navigateTo(routes.CHANGE_PICTURE); - } } customElements.define(
diff --git a/chrome/browser/resources/settings/languages_page/languages.ts b/chrome/browser/resources/settings/languages_page/languages.ts index cf03ac7..022ac91 100644 --- a/chrome/browser/resources/settings/languages_page/languages.ts +++ b/chrome/browser/resources/settings/languages_page/languages.ts
@@ -56,6 +56,7 @@ translateTarget: string; alwaysTranslateCodes: string[]; neverTranslateCodes: string[]; + neverTranslateSites: string[]; startingUILanguage: string; supportedInputMethods?: chrome.languageSettingsPrivate.InputMethod[]; currentInputMethodId?: string; @@ -132,6 +133,8 @@ 'prefs.translate_allowlists.value.*, languages)', 'neverTranslateLanguagesPrefChanged_(' + 'prefs.translate_blocked_languages.value.*, languages)', + 'neverTranslateSitesPrefChanged_(' + + 'prefs.translate_site_blocklist_with_time.value.*, languages)', // <if expr="is_win"> 'prospectiveUILanguageChanged_(prefs.intl.app_locale.value, languages)', // </if> @@ -196,6 +199,7 @@ translateTarget: '', alwaysTranslateCodes: [], neverTranslateCodes: [], + neverTranslateSites: [], startingUILanguage: '', // Only used by ChromeOS @@ -469,6 +473,18 @@ this.set('languages.neverTranslate', neverTranslateLanguages); } + /** + * Updates the list of never translate sites from translate prefs. + */ + private neverTranslateSitesPrefChanged_() { + if (this.prefs === undefined || this.languages === undefined) { + return; + } + const neverTranslateSites = + Object.keys(this.getPref('translate_site_blocklist_with_time').value); + this.set('languages.neverTranslateSites', neverTranslateSites); + } + private translateLanguagesPrefChanged_() { if (this.prefs === undefined || this.languages === undefined) { return; @@ -543,6 +559,7 @@ translateTarget: args.translateTarget, alwaysTranslate: alwaysTranslateLanguages, neverTranslate: neverTranslateLangauges, + neverTranslateSites: args.neverTranslateSites, spellCheckOnLanguages, spellCheckOffLanguages, // <if expr="is_win">
diff --git a/chrome/browser/resources/settings/languages_page/languages_types.ts b/chrome/browser/resources/settings/languages_page/languages_types.ts index 76dee02..0f4777a 100644 --- a/chrome/browser/resources/settings/languages_page/languages_types.ts +++ b/chrome/browser/resources/settings/languages_page/languages_types.ts
@@ -56,6 +56,7 @@ translateTarget: string; alwaysTranslate: chrome.languageSettingsPrivate.Language[]; neverTranslate: chrome.languageSettingsPrivate.Language[]; + neverTranslateSites: string[]; spellCheckOnLanguages: SpellCheckLanguageState[]; spellCheckOffLanguages: SpellCheckLanguageState[]; // TODO(dpapad): Wrap prospectiveUILanguage with if expr "is_win" block.
diff --git a/chrome/browser/resources/tab_search/app.ts b/chrome/browser/resources/tab_search/app.ts index 5964c7c..6295dd8 100644 --- a/chrome/browser/resources/tab_search/app.ts +++ b/chrome/browser/resources/tab_search/app.ts
@@ -401,10 +401,7 @@ this.tabItemAction_(tabItem, e.model.index); } - private recordMetricsForAction( - action: string, isMediaTab: boolean, tabIndex: number, - indexRelativeToSection: number, - distanceFromInitiallySelectedIndex: number) { + private recordMetricsForAction(action: string, tabIndex: number) { const withSearch = !!this.searchText_; if (action === 'SwitchTab') { chrome.metricsPrivate.recordEnumerationValue( @@ -417,21 +414,6 @@ withSearch ? `Tabs.TabSearch.WebUI.IndexOf${action}InFilteredList` : `Tabs.TabSearch.WebUI.IndexOf${action}InUnfilteredList`, tabIndex); - chrome.metricsPrivate.recordSmallCount( - withSearch ? `Tabs.TabSearch.DistanceOf${ - action}FromInitiallySelectedTabInFilteredList` : - `Tabs.TabSearch.DistanceOf${ - action}FromInitiallySelectedTabInUnfilteredList`, - distanceFromInitiallySelectedIndex); - if (isMediaTab) { - chrome.metricsPrivate.recordBoolean( - `Tabs.TabSearch.WebUI.MediaTab${action}Action`, withSearch); - } else if (!withSearch) { - chrome.metricsPrivate.recordSmallCount( - `Tabs.TabSearch.WebUI.IndexRelativeToOpenTabsSectionOf${ - action}InUnfilteredList`, - indexRelativeToSection); - } } /** @@ -452,12 +434,7 @@ } } - const isMediaTab = tabHasMediaAlerts((itemData as TabData).tab as Tab); - const tabIndexRelativeToSection = - isMediaTab ? tabIndex : tabIndex - this.filteredMediaTabsCount_; - this.recordMetricsForAction( - 'SwitchTab', isMediaTab, tabIndex, tabIndexRelativeToSection, - Math.abs(this.initiallySelectedTabIndex_ - tabIndex)); + this.recordMetricsForAction('SwitchTab', tabIndex); this.apiProxy_.switchToTab({tabId: (itemData as TabData).tab.tabId}); action = 'SwitchTab'; break; @@ -486,12 +463,7 @@ performance.mark('tab_search:close_tab:metric_begin'); const tabId = e.model.item.tab.tabId; const tabIndex = e.model.index; - const isMediaTab = tabHasMediaAlerts(e.model.item.tab as Tab); - const tabIndexRelativeToSection = - isMediaTab ? tabIndex : tabIndex - this.filteredMediaTabsCount_; - this.recordMetricsForAction( - 'CloseTab', isMediaTab, tabIndex, tabIndexRelativeToSection, - Math.abs(this.initiallySelectedTabIndex_ - tabIndex)); + this.recordMetricsForAction('CloseTab', tabIndex); this.apiProxy_.closeTab(tabId); this.announceA11y_(loadTimeData.getString('a11yTabClosed')); listenOnce(this.$.tabsList, 'iron-items-changed', () => { @@ -697,8 +669,7 @@ filteredMediaTabs.length; } - if (!loadTimeData.getBoolean('alsoShowMediaTabsinOpenTabsSection') && - this.searchText_.length === 0) { + if (this.searchText_.length === 0) { filteredOpenTabs = filteredOpenTabs.filter( tabData => !tabHasMediaAlerts(tabData.tab as Tab)); }
diff --git a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/link_to_text/LinkToTextIPHController.java b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/link_to_text/LinkToTextIPHController.java index b85e041..a488832 100644 --- a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/link_to_text/LinkToTextIPHController.java +++ b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/link_to_text/LinkToTextIPHController.java
@@ -59,9 +59,9 @@ if (!LinkToTextHelper.hasTextFragment(url)) return; Profile profile = profileSupplier.get(); - // In some cases, ProfileSupplier.get() will return null or will not be initialized - // in Native. See https://crbug.com/1346710 and https://crbug.com/1353138. - if (profile == null || !profile.isNativeInitialized()) { + // In some cases, ProfileSupplier.get() will return null. See + // https://crbug.com/1346710 and https://crbug.com/1353138. + if (profile == null) { profile = Profile.getLastUsedRegularProfile(); } if (profile == null) {
diff --git a/chrome/browser/speech/tts_crosapi_util.cc b/chrome/browser/speech/tts_crosapi_util.cc index 415565d4..b54ee9d2 100644 --- a/chrome/browser/speech/tts_crosapi_util.cc +++ b/chrome/browser/speech/tts_crosapi_util.cc
@@ -5,7 +5,9 @@ #include "chrome/browser/speech/tts_crosapi_util.h" #include "base/feature_list.h" +#include "base/values.h" #include "build/chromeos_buildflags.h" +#include "chrome/browser/profiles/profile_manager.h" #if BUILDFLAG(IS_CHROMEOS_ASH) #include "ash/constants/ash_features.h" @@ -103,6 +105,71 @@ return mojo_voice; } +crosapi::mojom::TtsUtterancePtr ToMojo(content::TtsUtterance* utterance) { + auto mojo_utterance = crosapi::mojom::TtsUtterance::New(); + mojo_utterance->utterance_id = utterance->GetId(); + mojo_utterance->text = utterance->GetText(); + mojo_utterance->lang = utterance->GetLang(); + mojo_utterance->voice_name = utterance->GetVoiceName(); + mojo_utterance->volume = utterance->GetContinuousParameters().volume; + mojo_utterance->rate = utterance->GetContinuousParameters().rate; + mojo_utterance->pitch = utterance->GetContinuousParameters().pitch; + mojo_utterance->engine_id = utterance->GetEngineId(); + mojo_utterance->should_clear_queue = utterance->GetShouldClearQueue(); + mojo_utterance->src_id = utterance->GetSrcId(); + mojo_utterance->src_url = utterance->GetSrcUrl(); + + for (const auto& event : utterance->GetDesiredEventTypes()) + mojo_utterance->desired_event_types.push_back( + tts_crosapi_util::ToMojo(event)); + + for (const auto& event : utterance->GetRequiredEventTypes()) + mojo_utterance->required_event_types.push_back( + tts_crosapi_util::ToMojo(event)); + + content::WebContents* web_contents = utterance->GetWebContents(); + mojo_utterance->was_created_with_web_contents = web_contents != nullptr; + + base::Value::Dict options = utterance->GetOptions()->Clone(); + mojo_utterance->options = std::move(options); + + return mojo_utterance; +} + +std::unique_ptr<content::TtsUtterance> FromMojo( + crosapi::mojom::TtsUtterancePtr& mojo_utterance) { + // Construct TtsUtterance object. + content::BrowserContext* browser_context = + ProfileManager::GetPrimaryUserProfile(); + std::unique_ptr<content::TtsUtterance> utterance = + content::TtsUtterance::Create(browser_context, + /*should_always_be_spoken=*/true); + + utterance->SetText(mojo_utterance->text); + utterance->SetLang(mojo_utterance->lang); + utterance->SetVoiceName(mojo_utterance->voice_name); + utterance->SetContinuousParameters( + mojo_utterance->rate, mojo_utterance->pitch, mojo_utterance->volume); + utterance->SetEngineId(mojo_utterance->engine_id); + utterance->SetShouldClearQueue(mojo_utterance->should_clear_queue); + utterance->SetSrcUrl(mojo_utterance->src_url); + utterance->SetSrcId(mojo_utterance->src_id); + + std::set<content::TtsEventType> desired_events; + for (const auto& mojo_event : mojo_utterance->desired_event_types) + desired_events.insert(tts_crosapi_util::FromMojo(mojo_event)); + utterance->SetDesiredEventTypes(std::move(desired_events)); + + std::set<content::TtsEventType> required_events; + for (const auto& mojo_event : mojo_utterance->required_event_types) + required_events.insert(tts_crosapi_util::FromMojo(mojo_event)); + utterance->SetRequiredEventTypes(std::move(required_events)); + + base::Value::Dict options = mojo_utterance->options.Clone(); + utterance->SetOptions(std::move(options)); + return utterance; +} + bool ShouldEnableLacrosTtsSupport() { #if BUILDFLAG(IS_CHROMEOS_ASH) bool lacros_tts_support_enabled =
diff --git a/chrome/browser/speech/tts_crosapi_util.h b/chrome/browser/speech/tts_crosapi_util.h index b33cef0..832c739c 100644 --- a/chrome/browser/speech/tts_crosapi_util.h +++ b/chrome/browser/speech/tts_crosapi_util.h
@@ -15,6 +15,9 @@ crosapi::mojom::TtsEventType ToMojo(content::TtsEventType event_type); content::VoiceData FromMojo(const crosapi::mojom::TtsVoicePtr& mojo_voice); crosapi::mojom::TtsVoicePtr ToMojo(const content::VoiceData& voice); +crosapi::mojom::TtsUtterancePtr ToMojo(content::TtsUtterance* utterance); +std::unique_ptr<content::TtsUtterance> FromMojo( + crosapi::mojom::TtsUtterancePtr& mojo_utterance); bool ShouldEnableLacrosTtsSupport();
diff --git a/chrome/browser/speech/tts_crosapi_util_unittest.cc b/chrome/browser/speech/tts_crosapi_util_unittest.cc new file mode 100644 index 0000000..f930301a --- /dev/null +++ b/chrome/browser/speech/tts_crosapi_util_unittest.cc
@@ -0,0 +1,189 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <set> + +#include "base/unguessable_token.h" +#include "base/values.h" +#include "chrome/browser/speech/extension_api/tts_extension_api_constants.h" +#include "chrome/browser/speech/tts_crosapi_util.h" +#include "chrome/test/base/testing_profile.h" +#include "chromeos/crosapi/mojom/tts.mojom.h" +#include "content/public/browser/browser_context.h" +#include "content/public/browser/tts_controller.h" +#include "content/public/browser/tts_utterance.h" +#include "content/public/browser/web_contents.h" +#include "content/public/test/browser_task_environment.h" +#include "content/public/test/test_renderer_host.h" +#include "content/public/test/web_contents_tester.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +const char kText[] = "hello, world"; +const char kVoiceName[] = "Alice"; +const char kLang[] = "en-GB"; +const int kSrcId = 12345; +const char kSrcUrl[] = "http://test.com"; +const char kEngineId[] = "test_engine_id"; +const double kRate = 1.0f; +const double kPitch = 0.5f; +const double kVolume = 0.9f; +const base::UnguessableToken kBrowerContextId = + base::UnguessableToken::Create(); + +bool EventTypesMatches( + const std::set<content::TtsEventType>& tts_event_types_in, + const std::set<content::TtsEventType>& tts_event_types_out) { + if (tts_event_types_in.size() != tts_event_types_out.size()) + return false; + + for (const auto& event_type : tts_event_types_in) { + if (tts_event_types_out.find(event_type) == tts_event_types_out.end()) + return false; + } + + return true; +} + +} // namespace + +class TtsUtteranceMojomTest : public testing::Test { + public: + TtsUtteranceMojomTest() + : task_environment_(content::BrowserTaskEnvironment::IO_MAINLOOP), + rvh_test_enabler_(new content::RenderViewHostTestEnabler()) {} + + TtsUtteranceMojomTest(const TtsUtteranceMojomTest&) = delete; + TtsUtteranceMojomTest& operator=(const TtsUtteranceMojomTest&) = delete; + + void SetUp() override { + testing::Test::SetUp(); + + testing_profile_ = TestingProfile::Builder().Build(); + web_contents_ = CreateTestWebContents(); + } + + protected: + content::BrowserContext* browser_context() { return testing_profile_.get(); } + content::WebContents* GetWebContents() { return web_contents_.get(); } + + private: + std::unique_ptr<content::WebContents> CreateTestWebContents() { + auto site_instance = content::SiteInstance::Create(browser_context()); + return content::WebContentsTester::CreateTestWebContents( + browser_context(), std::move(site_instance)); + } + + content::BrowserTaskEnvironment task_environment_; + std::unique_ptr<content::RenderViewHostTestEnabler> rvh_test_enabler_; + std::unique_ptr<TestingProfile> testing_profile_; + std::unique_ptr<content::WebContents> web_contents_; +}; + +// Test that every field in content::TtsUtterance in correctly converted +// with a round trip conversion to and from crosapi::mojom::TtsUtterance. +TEST_F(TtsUtteranceMojomTest, RoundTripWithoutOptions) { + std::unique_ptr<content::TtsUtterance> in_utterance = + content::TtsUtterance::Create(); + in_utterance->SetText(kText); + in_utterance->SetVoiceName(kVoiceName); + in_utterance->SetLang(kLang); + in_utterance->SetSrcId(kSrcId); + in_utterance->SetSrcUrl(GURL(kSrcUrl)); + in_utterance->SetEngineId(kEngineId); + in_utterance->SetContinuousParameters(kRate, kPitch, kVolume); + in_utterance->SetShouldClearQueue(true); + + std::set<content::TtsEventType> required_event_types; + required_event_types.insert(content::TTS_EVENT_START); + required_event_types.insert(content::TTS_EVENT_WORD); + required_event_types.insert(content::TTS_EVENT_END); + in_utterance->SetRequiredEventTypes(required_event_types); + + std::set<content::TtsEventType> desired_event_types; + desired_event_types.insert(content::TTS_EVENT_CANCELLED); + desired_event_types.insert(content::TTS_EVENT_RESUME); + desired_event_types.insert(content::TTS_EVENT_PAUSE); + in_utterance->SetDesiredEventTypes(desired_event_types); + + // Round trip conversion to and from mojom utterance. + auto mojo_utterance = tts_crosapi_util::ToMojo(in_utterance.get()); + mojo_utterance->browser_context_id = kBrowerContextId; + std::unique_ptr<content::TtsUtterance> out_utterance = + tts_crosapi_util::FromMojo(mojo_utterance); + + ASSERT_EQ(out_utterance->GetText(), kText); + ASSERT_EQ(out_utterance->GetVoiceName(), kVoiceName); + ASSERT_EQ(out_utterance->GetLang(), kLang); + ASSERT_EQ(out_utterance->GetSrcId(), kSrcId); + ASSERT_EQ(out_utterance->GetSrcUrl(), GURL(kSrcUrl)); + ASSERT_EQ(out_utterance->GetEngineId(), kEngineId); + auto continuouse_params = out_utterance->GetContinuousParameters(); + ASSERT_EQ(continuouse_params.rate, kRate); + ASSERT_EQ(continuouse_params.pitch, kPitch); + ASSERT_EQ(continuouse_params.volume, kVolume); + ASSERT_TRUE(out_utterance->GetShouldClearQueue()); + + ASSERT_TRUE(EventTypesMatches(in_utterance->GetRequiredEventTypes(), + out_utterance->GetRequiredEventTypes())); + ASSERT_TRUE(EventTypesMatches(in_utterance->GetDesiredEventTypes(), + out_utterance->GetDesiredEventTypes())); + + ASSERT_TRUE(out_utterance->ShouldAlwaysBeSpoken()); +} + +TEST_F(TtsUtteranceMojomTest, RoundTripWithOptions) { + std::unique_ptr<content::TtsUtterance> in_utterance = + content::TtsUtterance::Create(); + base::Value::Dict in_options; + in_options.Set(tts_extension_api_constants::kVoiceNameKey, kVoiceName); + in_options.Set(tts_extension_api_constants::kRateKey, kRate); + in_options.Set(tts_extension_api_constants::kEnqueueKey, true); + in_utterance->SetOptions(std::move(in_options)); + + auto mojo_utterance = tts_crosapi_util::ToMojo(in_utterance.get()); + std::unique_ptr<content::TtsUtterance> out_utterance = + tts_crosapi_util::FromMojo(mojo_utterance); + + auto* out_options = out_utterance->GetOptions(); + + const base::Value* voice_value = + out_options->Find(tts_extension_api_constants::kVoiceNameKey); + ASSERT_TRUE(voice_value); + ASSERT_TRUE(voice_value->is_string()); + ASSERT_EQ(voice_value->GetString(), kVoiceName); + + const base::Value* rate_value = + out_options->Find(tts_extension_api_constants::kRateKey); + ASSERT_TRUE(rate_value); + ASSERT_TRUE(rate_value->is_double()); + ASSERT_EQ(rate_value->GetDouble(), kRate); + + const base::Value* enqueue_value = + out_options->Find(tts_extension_api_constants::kEnqueueKey); + ASSERT_TRUE(enqueue_value); + ASSERT_TRUE(enqueue_value->is_bool()); + ASSERT_TRUE(enqueue_value->GetBool()); +} + +TEST_F(TtsUtteranceMojomTest, WasCreatedWithNoWebContents) { + std::unique_ptr<content::TtsUtterance> in_utterance = + content::TtsUtterance::Create(); + ASSERT_FALSE(in_utterance->GetWebContents()); + auto mojo_utterance = tts_crosapi_util::ToMojo(in_utterance.get()); + ASSERT_FALSE(mojo_utterance->was_created_with_web_contents); +} + +TEST_F(TtsUtteranceMojomTest, WasCreatedWithWebContents) { + content::WebContents* web_contents = GetWebContents(); + std::unique_ptr<content::TtsUtterance> in_utterance = + content::TtsUtterance::Create(web_contents); + auto mojo_utterance = tts_crosapi_util::ToMojo(in_utterance.get()); + ASSERT_TRUE(mojo_utterance->was_created_with_web_contents); + + // Finish |in_utterance| so that it can be destructed without DCHECK + // failure. + in_utterance->Finish(); +}
diff --git a/chrome/browser/ssl/ssl_config_service_manager.cc b/chrome/browser/ssl/ssl_config_service_manager.cc index 8845f3c..f921565 100644 --- a/chrome/browser/ssl/ssl_config_service_manager.cc +++ b/chrome/browser/ssl/ssl_config_service_manager.cc
@@ -49,10 +49,11 @@ // Converts a ListValue of StringValues into a vector of strings. Any Values // which cannot be converted will be skipped. -std::vector<std::string> ListValueToStringVector(const base::ListValue* value) { +std::vector<std::string> ValueListToStringVector( + const base::Value::List& list) { std::vector<std::string> results; - results.reserve(value->GetListDeprecated().size()); - for (const auto& entry : value->GetListDeprecated()) { + results.reserve(list.size()); + for (const auto& entry : list) { const std::string* s = entry.GetIfString(); if (s) results.push_back(*s); @@ -246,9 +247,9 @@ void SSLConfigServiceManager::OnDisabledCipherSuitesChange( PrefService* local_state) { - const base::ListValue* value = &base::Value::AsListValue( - *local_state->GetList(prefs::kCipherSuiteBlacklist)); - disabled_cipher_suites_ = ParseCipherSuites(ListValueToStringVector(value)); + const base::Value::List& list = + local_state->GetValueList(prefs::kCipherSuiteBlacklist); + disabled_cipher_suites_ = ParseCipherSuites(ValueListToStringVector(list)); } void SSLConfigServiceManager::CacheVariationsPolicy(PrefService* local_state) {
diff --git a/chrome/browser/storage_access_api/api_browsertest.cc b/chrome/browser/storage_access_api/api_browsertest.cc index 1a0e540..2ae771b 100644 --- a/chrome/browser/storage_access_api/api_browsertest.cc +++ b/chrome/browser/storage_access_api/api_browsertest.cc
@@ -60,21 +60,33 @@ : https_server_(net::EmbeddedTestServer::TYPE_HTTPS), permission_grants_unpartitioned_storage_( permission_grants_unpartitioned_storage), - is_storage_partitioned_(is_storage_partitioned) { + is_storage_partitioned_(is_storage_partitioned) {} + + void SetUp() override { + features_.InitWithFeaturesAndParameters(GetEnabledFeatures(), + GetDisabledFeatures()); + InProcessBrowserTest::SetUp(); + } + + virtual std::vector<base::test::ScopedFeatureList::FeatureAndParams> + GetEnabledFeatures() { std::vector<base::test::ScopedFeatureList::FeatureAndParams> enabled({ {net::features::kStorageAccessAPI, {{"storage-access-api-grants-unpartitioned-storage", - BoolToString(permission_grants_unpartitioned_storage)}}}, + BoolToString(permission_grants_unpartitioned_storage_)}}}, }); - std::vector<base::Feature> disabled; - - if (is_storage_partitioned) { + if (is_storage_partitioned_) { enabled.push_back({net::features::kThirdPartyStoragePartitioning, {}}); - } else { + } + return enabled; + } + + virtual std::vector<base::Feature> GetDisabledFeatures() { + std::vector<base::Feature> disabled; + if (!is_storage_partitioned_) { disabled.push_back(net::features::kThirdPartyStoragePartitioning); } - - features_.InitWithFeaturesAndParameters(enabled, disabled); + return disabled; } void SetUpOnMainThread() override { @@ -505,6 +517,16 @@ EXPECT_EQ(ReadCookiesViaJS(GetNestedFrame()), "thirdparty=c"); } +IN_PROC_BROWSER_TEST_P(StorageAccessAPIBrowserTest, + RsaForSiteDisabledByDefault) { + NavigateToPageWithFrame("a.com"); + // Ensure that the proposed extension is not available unless explicitly + // enabled. + EXPECT_TRUE(EvalJs(GetPrimaryMainFrame(), + "\"requestStorageAccessForSite\" in document === false") + .ExtractBool()); +} + INSTANTIATE_TEST_CASE_P(/* no prefix */, StorageAccessAPIBrowserTest, testing::Combine(testing::Bool(), testing::Bool())); @@ -649,4 +671,96 @@ testing::Bool(), testing::Bool())); +class StorageAccessAPIForSiteExtensionBrowserTest + : public StorageAccessAPIBaseBrowserTest, + public testing::WithParamInterface<std::tuple<bool, bool>> { + public: + StorageAccessAPIForSiteExtensionBrowserTest() + : StorageAccessAPIBaseBrowserTest(std::get<0>(GetParam()), + std::get<1>(GetParam())) {} + + protected: + std::vector<base::test::ScopedFeatureList::FeatureAndParams> + GetEnabledFeatures() override { + std::vector<base::test::ScopedFeatureList::FeatureAndParams> enabled = + StorageAccessAPIBaseBrowserTest::GetEnabledFeatures(); + enabled.push_back({blink::features::kStorageAccessAPIForSiteExtension, {}}); + return enabled; + } +}; + +IN_PROC_BROWSER_TEST_P(StorageAccessAPIForSiteExtensionBrowserTest, + OnlySameOriginGrantedByDefault) { + SetBlockThirdPartyCookies(true); + base::HistogramTester histogram_tester; + + NavigateToPageWithFrame("a.com"); + + // Asserting very basic behavior while the extension is being implemented. + EXPECT_FALSE(storage::test::RequestStorageAccessForSite( + GetFrame(), "https://asdf.example")); + EXPECT_FALSE( + storage::test::RequestStorageAccessForSite(GetFrame(), "mattwashere")); + EXPECT_TRUE(storage::test::RequestStorageAccessForSite(GetPrimaryMainFrame(), + "https://a.com")); + EXPECT_FALSE( + storage::test::RequestStorageAccessForSite(GetFrame(), "https://a.com")); +} + +INSTANTIATE_TEST_CASE_P(/* no prefix */, + StorageAccessAPIForSiteExtensionBrowserTest, + testing::Combine(testing::Bool(), testing::Bool())); + +// Tests to validate that, when the rsaForSite extension is explicitly disabled, +// or if the larger Storage Access API is disabled, it does not leak onto the +// document object. +class StorageAccessAPIForSiteExtensionExplicitlyDisabledBrowserTest + : public StorageAccessAPIBaseBrowserTest, + public testing::WithParamInterface<bool> { + public: + StorageAccessAPIForSiteExtensionExplicitlyDisabledBrowserTest() + : StorageAccessAPIBaseBrowserTest(true, true), + enable_standard_storage_access_api_(GetParam()) {} + + protected: + std::vector<base::Feature> GetDisabledFeatures() override { + // The test should validate that either flag alone disables the API. + // Note that enabling the extension and not the standard API means both are + // disabled. + if (enable_standard_storage_access_api_) { + return {blink::features::kStorageAccessAPIForSiteExtension}; + } + return {net::features::kStorageAccessAPI}; + } + std::vector<base::test::ScopedFeatureList::FeatureAndParams> + GetEnabledFeatures() override { + // When the standard API is enabled, return the parent class's enabled + // feature list. Otherwise, enable only the extension; this should not take + // effect. + if (enable_standard_storage_access_api_) { + return StorageAccessAPIBaseBrowserTest::GetEnabledFeatures(); + } + return {{blink::features::kStorageAccessAPIForSiteExtension, {}}}; + } + + private: + bool enable_standard_storage_access_api_; +}; + +IN_PROC_BROWSER_TEST_P( + StorageAccessAPIForSiteExtensionExplicitlyDisabledBrowserTest, + RsaForSiteNotPresentOnDocumentWhenExplicitlyDisabled) { + NavigateToPageWithFrame("a.com"); + // Ensure that the proposed extension is not available unless explicitly + // enabled. + EXPECT_TRUE(EvalJs(GetPrimaryMainFrame(), + "\"requestStorageAccessForSite\" in document === false") + .ExtractBool()); +} + +INSTANTIATE_TEST_CASE_P( + /* no prefix */, + StorageAccessAPIForSiteExtensionExplicitlyDisabledBrowserTest, + testing::Bool()); + } // namespace
diff --git a/chrome/browser/sync/test/integration/bookmarks_helper.cc b/chrome/browser/sync/test/integration/bookmarks_helper.cc index ca38c7bf..a0b6f07 100644 --- a/chrome/browser/sync/test/integration/bookmarks_helper.cc +++ b/chrome/browser/sync/test/integration/bookmarks_helper.cc
@@ -152,7 +152,8 @@ size_t new_index) override {} void BookmarkNodeAdded(BookmarkModel* model, const BookmarkNode* parent, - size_t index) override {} + size_t index, + bool added_by_user) override {} void BookmarkNodeRemoved(BookmarkModel* model, const BookmarkNode* parent, size_t old_index, @@ -923,7 +924,8 @@ void AnyBookmarkChangeObserver::BookmarkNodeAdded(BookmarkModel* model, const BookmarkNode* parent, - size_t index) { + size_t index, + bool added_by_user) { cb_.Run(); }
diff --git a/chrome/browser/sync/test/integration/bookmarks_helper.h b/chrome/browser/sync/test/integration/bookmarks_helper.h index 75bbc78..81a34235 100644 --- a/chrome/browser/sync/test/integration/bookmarks_helper.h +++ b/chrome/browser/sync/test/integration/bookmarks_helper.h
@@ -321,7 +321,8 @@ size_t new_index) override; void BookmarkNodeAdded(bookmarks::BookmarkModel* model, const bookmarks::BookmarkNode* parent, - size_t index) override; + size_t index, + bool added_by_user) override; void OnWillRemoveBookmarks(bookmarks::BookmarkModel* model, const bookmarks::BookmarkNode* parent, size_t old_index,
diff --git a/chrome/browser/sync/test/integration/single_client_workspace_desk_sync_test.cc b/chrome/browser/sync/test/integration/single_client_workspace_desk_sync_test.cc index 3f6652d..a3959ce 100644 --- a/chrome/browser/sync/test/integration/single_client_workspace_desk_sync_test.cc +++ b/chrome/browser/sync/test/integration/single_client_workspace_desk_sync_test.cc
@@ -140,7 +140,7 @@ // Delete template 1. base::RunLoop loop; model->DeleteEntry( - kTestUuid1_.AsLowercaseString(), + kTestUuid1_, base::BindLambdaForTesting([&](DeskModel::DeleteEntryStatus status) { EXPECT_EQ(DeskModel::DeleteEntryStatus::kOk, status); loop.Quit();
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index 716a69e7..c111d066 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -1413,6 +1413,7 @@ "toolbar/media_router_contextual_menu.h", "toolbar/recent_tabs_sub_menu_model.cc", "toolbar/recent_tabs_sub_menu_model.h", + "toolbar/toolbar_action_hover_card_types.h", "toolbar/toolbar_action_view_controller.h", "toolbar/toolbar_action_view_delegate.cc", "toolbar/toolbar_action_view_delegate.h", @@ -2913,8 +2914,6 @@ "webui/settings/chromeos/bluetooth_handler.h", "webui/settings/chromeos/bluetooth_section.cc", "webui/settings/chromeos/bluetooth_section.h", - "webui/settings/chromeos/change_picture_handler.cc", - "webui/settings/chromeos/change_picture_handler.h", "webui/settings/chromeos/constants/constants_util.cc", "webui/settings/chromeos/constants/constants_util.h", "webui/settings/chromeos/constants/routes_util.cc", @@ -5054,6 +5053,10 @@ "views/toolbar/side_panel_toolbar_button.h", "views/toolbar/toolbar_account_icon_container_view.cc", "views/toolbar/toolbar_account_icon_container_view.h", + "views/toolbar/toolbar_action_hover_card_bubble_view.cc", + "views/toolbar/toolbar_action_hover_card_bubble_view.h", + "views/toolbar/toolbar_action_hover_card_controller.cc", + "views/toolbar/toolbar_action_hover_card_controller.h", "views/toolbar/toolbar_action_view.cc", "views/toolbar/toolbar_action_view.h", "views/toolbar/toolbar_action_view_delegate_views.h",
diff --git a/chrome/browser/ui/android/appmenu/internal/java/src/org/chromium/chrome/browser/ui/appmenu/AppMenu.java b/chrome/browser/ui/android/appmenu/internal/java/src/org/chromium/chrome/browser/ui/appmenu/AppMenu.java index b42c2c36..e991c9be 100644 --- a/chrome/browser/ui/android/appmenu/internal/java/src/org/chromium/chrome/browser/ui/appmenu/AppMenu.java +++ b/chrome/browser/ui/android/appmenu/internal/java/src/org/chromium/chrome/browser/ui/appmenu/AppMenu.java
@@ -42,6 +42,7 @@ import org.chromium.base.metrics.RecordHistogram; import org.chromium.base.task.PostTask; import org.chromium.base.task.TaskTraits; +import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.ui.appmenu.internal.R; import org.chromium.components.browser_ui.styles.ChromeColors; import org.chromium.components.browser_ui.widget.chips.ChipView; @@ -299,7 +300,8 @@ popupHeight, anchorView.getRootView().getLayoutDirection()); mPopup.setContentView(contentView); - if (popupHeight + popupPosition[1] > visibleDisplayFrame.bottom) { + if (!ChromeFeatureList.sCctResizableWindowAboveNavbar.isEnabled() + && popupHeight + popupPosition[1] > visibleDisplayFrame.bottom) { mPopup.setHeight(visibleDisplayFrame.height()); }
diff --git a/chrome/browser/ui/android/appmenu/internal/java/src/org/chromium/chrome/browser/ui/appmenu/AppMenuHandlerImpl.java b/chrome/browser/ui/android/appmenu/internal/java/src/org/chromium/chrome/browser/ui/appmenu/AppMenuHandlerImpl.java index 965d17e..0fb91a7 100644 --- a/chrome/browser/ui/android/appmenu/internal/java/src/org/chromium/chrome/browser/ui/appmenu/AppMenuHandlerImpl.java +++ b/chrome/browser/ui/android/appmenu/internal/java/src/org/chromium/chrome/browser/ui/appmenu/AppMenuHandlerImpl.java
@@ -20,6 +20,7 @@ import org.chromium.base.Callback; import org.chromium.base.metrics.RecordUserAction; import org.chromium.base.supplier.Supplier; +import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher; import org.chromium.chrome.browser.lifecycle.ConfigurationChangedObserver; import org.chromium.chrome.browser.lifecycle.StartStopWithNativeObserver; @@ -199,7 +200,14 @@ registerViewBinders(customViewBinders, customViewTypeOffsetMap, adapter, mDelegate.shouldShowIconBeforeItem()); - Rect appRect = mAppRect.get(); + Rect appRect; + if (ChromeFeatureList.sCctResizableWindowAboveNavbar.isEnabled()) { + // Get the height and width of the display. + appRect = new Rect(); + mDecorView.getWindowVisibleDisplayFrame(appRect); + } else { + appRect = mAppRect.get(); + } // Use full size of window for abnormal appRect. if (appRect.left < 0 && appRect.top < 0) { @@ -208,7 +216,6 @@ appRect.right = mDecorView.getWidth(); appRect.bottom = mDecorView.getHeight(); } - Point pt = new Point(); display.getSize(pt);
diff --git a/chrome/browser/ui/ash/arc_open_url_delegate_impl.cc b/chrome/browser/ui/ash/arc_open_url_delegate_impl.cc index bd07d94..72a4237 100644 --- a/chrome/browser/ui/ash/arc_open_url_delegate_impl.cc +++ b/chrome/browser/ui/ash/arc_open_url_delegate_impl.cc
@@ -78,8 +78,6 @@ chromeos::settings::mojom::kBluetoothDevicesSubpagePath}, {ChromePage::BLUETOOTHDEVICES, chromeos::settings::mojom::kBluetoothDevicesSubpagePath}, - {ChromePage::CHANGEPICTURE, - chromeos::settings::mojom::kChangePictureSubpagePath}, {ChromePage::CUPSPRINTERS, chromeos::settings::mojom::kPrintingDetailsSubpagePath}, {ChromePage::DATETIME, chromeos::settings::mojom::kDateAndTimeSectionPath},
diff --git a/chrome/browser/ui/ash/arc_open_url_delegate_impl_browsertest.cc b/chrome/browser/ui/ash/arc_open_url_delegate_impl_browsertest.cc index ad31eceb..d40e563 100644 --- a/chrome/browser/ui/ash/arc_open_url_delegate_impl_browsertest.cc +++ b/chrome/browser/ui/ash/arc_open_url_delegate_impl_browsertest.cc
@@ -306,9 +306,6 @@ base_url.Resolve( chromeos::settings::mojom::kBluetoothDevicesSubpagePath)); TestOpenOSSettingsChromePage( - ChromePage::CHANGEPICTURE, - base_url.Resolve(chromeos::settings::mojom::kChangePictureSubpagePath)); - TestOpenOSSettingsChromePage( ChromePage::CUPSPRINTERS, base_url.Resolve(chromeos::settings::mojom::kPrintingDetailsSubpagePath)); TestOpenOSSettingsChromePage(
diff --git a/chrome/browser/ui/ash/desks/desks_client.cc b/chrome/browser/ui/ash/desks/desks_client.cc index 021c382b..f773520 100644 --- a/chrome/browser/ui/ash/desks/desks_client.cc +++ b/chrome/browser/ui/ash/desks/desks_client.cc
@@ -258,7 +258,7 @@ template_name, std::move(callback))); } -void DesksClient::DeleteDeskTemplate(const std::string& template_uuid, +void DesksClient::DeleteDeskTemplate(const base::GUID& template_uuid, DeleteDeskTemplateCallback callback) { if (!active_profile_) { std::move(callback).Run(std::string(kNoCurrentUserError));
diff --git a/chrome/browser/ui/ash/desks/desks_client.h b/chrome/browser/ui/ash/desks/desks_client.h index 818238e..765c336f 100644 --- a/chrome/browser/ui/ash/desks/desks_client.h +++ b/chrome/browser/ui/ash/desks/desks_client.h
@@ -88,7 +88,7 @@ // to be removed,|callback| will be invoked with an empty error string. // TODO(crbug.com/1286515): This will be removed with the extension. Avoid // further uses of this method. - void DeleteDeskTemplate(const std::string& template_uuid, + void DeleteDeskTemplate(const base::GUID& template_uuid, DeleteDeskTemplateCallback callback); using GetDeskTemplatesCallback =
diff --git a/chrome/browser/ui/ash/desks/desks_client_browsertest.cc b/chrome/browser/ui/ash/desks/desks_client_browsertest.cc index f10c730..b8eae77b 100644 --- a/chrome/browser/ui/ash/desks/desks_client_browsertest.cc +++ b/chrome/browser/ui/ash/desks/desks_client_browsertest.cc
@@ -229,9 +229,8 @@ void DeleteDeskTemplate(const base::GUID uuid) { base::RunLoop run_loop; DesksClient::Get()->DeleteDeskTemplate( - uuid.AsLowercaseString(), - base::BindLambdaForTesting( - [&](std::string error_string) { run_loop.Quit(); })); + uuid, base::BindLambdaForTesting( + [&](std::string error_string) { run_loop.Quit(); })); run_loop.Run(); }
diff --git a/chrome/browser/ui/ash/shelf/app_service/exo_app_type_resolver.cc b/chrome/browser/ui/ash/shelf/app_service/exo_app_type_resolver.cc index 49ef60f..f8a534b 100644 --- a/chrome/browser/ui/ash/shelf/app_service/exo_app_type_resolver.cc +++ b/chrome/browser/ui/ash/shelf/app_service/exo_app_type_resolver.cc
@@ -90,6 +90,9 @@ reinterpret_cast<exo::ProtectedNativePixmapQueryDelegate*>( &protected_native_pixmap_query_client_)); + out_properties_container.SetProperty( + chromeos::kShouldHaveHighlightBorderOverlay, true); + if (task_id.has_value()) out_properties_container.SetProperty(app_restore::kWindowIdKey, *task_id);
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc b/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc index 0424a9d..8be3f75 100644 --- a/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc +++ b/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc
@@ -451,9 +451,9 @@ if (selected_line_) { const Suggestion& suggestion = suggestions_[*selected_line_]; - delegate_->DidSelectSuggestion(suggestion.main_text.value, - suggestion.frontend_id, - suggestion.GetPayload<std::string>()); + delegate_->DidSelectSuggestion( + suggestion.main_text.value, suggestion.frontend_id, + suggestion.GetPayload<Suggestion::BackendId>()); } else { delegate_->ClearPreviewedForm(); }
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_unittest.cc b/chrome/browser/ui/autofill/autofill_popup_controller_unittest.cc index d8a36c6..ba110c6b 100644 --- a/chrome/browser/ui/autofill/autofill_popup_controller_unittest.cc +++ b/chrome/browser/ui/autofill/autofill_popup_controller_unittest.cc
@@ -111,7 +111,7 @@ void DidSelectSuggestion(const std::u16string& value, int frontend_id, - const std::string& backend_id) override {} + const Suggestion::BackendId& backend_id) override {} bool RemoveSuggestion(const std::u16string& value, int frontend_id) override { return true; } @@ -188,7 +188,7 @@ ~MockAxTreeManager() = default; MOCK_CONST_METHOD2(GetNodeFromTree, - ui::AXNode*(const ui::AXTreeID tree_id, + ui::AXNode*(const ui::AXTreeID& tree_id, const int32_t node_id)); MOCK_CONST_METHOD2(GetDelegate, ui::AXPlatformNodeDelegate*(const ui::AXTreeID tree_id,
diff --git a/chrome/browser/ui/blocked_content/popup_blocker_browsertest.cc b/chrome/browser/ui/blocked_content/popup_blocker_browsertest.cc index 21d4a9a5..67ada726 100644 --- a/chrome/browser/ui/blocked_content/popup_blocker_browsertest.cc +++ b/chrome/browser/ui/blocked_content/popup_blocker_browsertest.cc
@@ -894,6 +894,12 @@ ->IsContentBlocked(ContentSettingsType::POPUPS)); } +IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest, + DocumentPictureInPictureIsNotConsideredForBlocking) { + EXPECT_FALSE(blocked_content::ConsiderForPopupBlocking( + WindowOpenDisposition::NEW_PICTURE_IN_PICTURE)); +} + class PopupBlockerFencedFrameTest : public PopupBlockerBrowserTest { public: PopupBlockerFencedFrameTest() = default;
diff --git a/chrome/browser/ui/bookmarks/bookmark_tab_helper.cc b/chrome/browser/ui/bookmarks/bookmark_tab_helper.cc index 22478d6..511dff85 100644 --- a/chrome/browser/ui/bookmarks/bookmark_tab_helper.cc +++ b/chrome/browser/ui/bookmarks/bookmark_tab_helper.cc
@@ -123,7 +123,8 @@ void BookmarkTabHelper::BookmarkNodeAdded(BookmarkModel* model, const BookmarkNode* parent, - size_t index) { + size_t index, + bool added_by_user) { UpdateStarredStateForCurrentURL(); }
diff --git a/chrome/browser/ui/bookmarks/bookmark_tab_helper.h b/chrome/browser/ui/bookmarks/bookmark_tab_helper.h index 60e76b1b..f1ff121 100644 --- a/chrome/browser/ui/bookmarks/bookmark_tab_helper.h +++ b/chrome/browser/ui/bookmarks/bookmark_tab_helper.h
@@ -76,7 +76,8 @@ bool ids_reassigned) override; void BookmarkNodeAdded(bookmarks::BookmarkModel* model, const bookmarks::BookmarkNode* parent, - size_t index) override; + size_t index, + bool added_by_user) override; void BookmarkNodeRemoved(bookmarks::BookmarkModel* model, const bookmarks::BookmarkNode* parent, size_t old_index,
diff --git a/chrome/browser/ui/bookmarks/recently_used_folders_combo_model.cc b/chrome/browser/ui/bookmarks/recently_used_folders_combo_model.cc index 55773ca..4af66b30 100644 --- a/chrome/browser/ui/bookmarks/recently_used_folders_combo_model.cc +++ b/chrome/browser/ui/bookmarks/recently_used_folders_combo_model.cc
@@ -147,7 +147,8 @@ void RecentlyUsedFoldersComboModel::BookmarkNodeAdded( BookmarkModel* model, const BookmarkNode* parent, - size_t index) {} + size_t index, + bool added_by_user) {} void RecentlyUsedFoldersComboModel::OnWillRemoveBookmarks( BookmarkModel* model,
diff --git a/chrome/browser/ui/bookmarks/recently_used_folders_combo_model.h b/chrome/browser/ui/bookmarks/recently_used_folders_combo_model.h index 5eb3a1a..69047af 100644 --- a/chrome/browser/ui/bookmarks/recently_used_folders_combo_model.h +++ b/chrome/browser/ui/bookmarks/recently_used_folders_combo_model.h
@@ -50,7 +50,8 @@ size_t new_index) override; void BookmarkNodeAdded(bookmarks::BookmarkModel* model, const bookmarks::BookmarkNode* parent, - size_t index) override; + size_t index, + bool added_by_user) override; void OnWillRemoveBookmarks(bookmarks::BookmarkModel* model, const bookmarks::BookmarkNode* parent, size_t old_index,
diff --git a/chrome/browser/ui/cocoa/apps/native_app_window_cocoa_browsertest.mm b/chrome/browser/ui/cocoa/apps/native_app_window_cocoa_browsertest.mm index dc922914..b1695e58 100644 --- a/chrome/browser/ui/cocoa/apps/native_app_window_cocoa_browsertest.mm +++ b/chrome/browser/ui/cocoa/apps/native_app_window_cocoa_browsertest.mm
@@ -589,20 +589,28 @@ // Test that the colored frames have the correct color when active and inactive. // Disabled; https://crbug.com/1322741. -IN_PROC_BROWSER_TEST_F(NativeAppWindowCocoaBrowserTest, DISABLED_FrameColor) { +IN_PROC_BROWSER_TEST_F(NativeAppWindowCocoaBrowserTest, FrameColor) { + EXPECT_EQ(NSApp.activationPolicy, NSApplicationActivationPolicyAccessory); + // The hex values indicate an RGB color. When we get the NSColor later, the // components are CGFloats in the range [0, 1]. extensions::AppWindow* app_window = CreateTestAppWindow( "{\"frame\": {\"color\": \"#FF0000\", \"inactiveColor\": \"#0000FF\"}}"); NSWindow* ns_window = app_window->GetNativeWindow().GetNativeNSWindow(); + // No color correction in the default case. [ns_window setColorSpace:[NSColorSpace sRGBColorSpace]]; - int half_width = NSWidth([ns_window frame]) / 2; + // Make sure the window is inactive before color sampling. + ui::test::ScopedFakeNSWindowFocus fake_focus; + [ns_window resignMainWindow]; + [ns_window resignKeyWindow]; NSBitmapImageRep* bitmap = ScreenshotNSWindow(ns_window); - // The window is currently inactive so it should be blue (#0000FF). + // The window is currently inactive so it should be blue (#0000FF). We are + // assuming the Light appearance is being used. NSColor* expected_color = ColorInBitmapColorSpace(0xFF0000FF, bitmap); + int half_width = NSWidth([ns_window frame]) / 2; NSColor* color = [bitmap colorAtX:half_width y:5]; CGFloat expected_components[4], color_components[4]; [expected_color getComponents:expected_components]; @@ -611,11 +619,12 @@ EXPECT_NEAR(expected_components[1], color_components[1], 0.01); EXPECT_NEAR(expected_components[2], color_components[2], 0.01); - ui::test::ScopedFakeNSWindowFocus fake_focus; + // Activate the window. [ns_window makeMainWindow]; bitmap = ScreenshotNSWindow(ns_window); - // The window is now active so it should be red (#FF0000). + // The window is now active so it should be red (#FF0000). Again, this is + // assuming the Light appearance is being used. expected_color = ColorInBitmapColorSpace(0xFFFF0000, bitmap); color = [bitmap colorAtX:half_width y:5]; [expected_color getComponents:expected_components];
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_bridge.h b/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_bridge.h index bc5047b..f3306d3 100644 --- a/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_bridge.h +++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_bridge.h
@@ -60,7 +60,8 @@ size_t new_index) override; void BookmarkNodeAdded(bookmarks::BookmarkModel* model, const bookmarks::BookmarkNode* parent, - size_t index) override; + size_t index, + bool added_by_user) override; void BookmarkNodeRemoved(bookmarks::BookmarkModel* model, const bookmarks::BookmarkNode* parent, size_t old_index,
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_bridge.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_bridge.mm index eed94ff..85b9b1cb 100644 --- a/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_bridge.mm +++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_bridge.mm
@@ -159,7 +159,8 @@ void BookmarkMenuBridge::BookmarkNodeAdded(BookmarkModel* model, const BookmarkNode* parent, - size_t index) { + size_t index, + bool added_by_user) { InvalidateMenu(); }
diff --git a/chrome/browser/ui/color/chrome_color_mixer.cc b/chrome/browser/ui/color/chrome_color_mixer.cc index 1c64aa44..31ccadd 100644 --- a/chrome/browser/ui/color/chrome_color_mixer.cc +++ b/chrome/browser/ui/color/chrome_color_mixer.cc
@@ -241,7 +241,9 @@ kColorToolbarButtonIcon, kColorDownloadShelfBackground, 0x3A); mixer[kColorDownloadShelfForeground] = {kColorToolbarText}; mixer[kColorDownloadStartedAnimationForeground] = {ui::kColorAccent}; - mixer[kColorDownloadToolbarButtonActive] = {ui::kColorThrobber}; + mixer[kColorDownloadToolbarButtonActive] = + ui::PickGoogleColor(ui::kColorThrobber, kColorToolbar, + color_utils::kMinimumVisibleContrastRatio); mixer[kColorDownloadToolbarButtonInactive] = {kColorToolbarButtonIcon}; mixer[kColorDownloadToolbarButtonRingBackground] = { SkColorSetA(kColorDownloadToolbarButtonInactive, 0x33)};
diff --git a/chrome/browser/ui/extensions/extension_action_view_controller.cc b/chrome/browser/ui/extensions/extension_action_view_controller.cc index 39aaa20..f531aa84 100644 --- a/chrome/browser/ui/extensions/extension_action_view_controller.cc +++ b/chrome/browser/ui/extensions/extension_action_view_controller.cc
@@ -319,6 +319,15 @@ view_delegate_->UpdateState(); } +void ExtensionActionViewController::UpdateHoverCard( + ToolbarActionView* action_view, + ToolbarActionHoverCardUpdateType update_type) { + if (!ExtensionIsValid()) + return; + + extensions_container_->UpdateToolbarActionHoverCard(action_view, update_type); +} + void ExtensionActionViewController::RegisterCommand() { if (!ExtensionIsValid()) return;
diff --git a/chrome/browser/ui/extensions/extension_action_view_controller.h b/chrome/browser/ui/extensions/extension_action_view_controller.h index 00aec3db..6b2f040 100644 --- a/chrome/browser/ui/extensions/extension_action_view_controller.h +++ b/chrome/browser/ui/extensions/extension_action_view_controller.h
@@ -11,6 +11,7 @@ #include "chrome/browser/extensions/extension_action_icon_factory.h" #include "chrome/browser/extensions/extension_context_menu_model.h" #include "chrome/browser/extensions/site_permissions_helper.h" +#include "chrome/browser/ui/toolbar/toolbar_action_hover_card_types.h" #include "chrome/browser/ui/toolbar/toolbar_action_view_controller.h" #include "extensions/browser/extension_host.h" #include "extensions/browser/extension_host_observer.h" @@ -85,6 +86,8 @@ void ExecuteUserAction(InvocationSource source) override; void TriggerPopupForAPI(ShowPopupCallback callback) override; void UpdateState() override; + void UpdateHoverCard(ToolbarActionView* action_view, + ToolbarActionHoverCardUpdateType update_type) override; void RegisterCommand() override; void UnregisterCommand() override;
diff --git a/chrome/browser/ui/extensions/extensions_container.h b/chrome/browser/ui/extensions/extensions_container.h index bc1c909..b6e606d 100644 --- a/chrome/browser/ui/extensions/extensions_container.h +++ b/chrome/browser/ui/extensions/extensions_container.h
@@ -10,9 +10,11 @@ #include "base/callback_forward.h" #include "chrome/browser/extensions/extension_context_menu_model.h" #include "chrome/browser/ui/extensions/extension_popup_types.h" +#include "chrome/browser/ui/toolbar/toolbar_action_hover_card_types.h" class ToolbarActionViewController; class ToolbarActionsBarBubbleDelegate; +class ToolbarActionView; // An interface for containers in the toolbar that host extensions. class ExtensionsContainer { @@ -75,6 +77,11 @@ // Whether there are any Extensions registered with the ExtensionsContainer. virtual bool HasAnyExtensions() const = 0; + + // Updates the hover card for `action_view` based on `update_type`. + virtual void UpdateToolbarActionHoverCard( + ToolbarActionView* action_view, + ToolbarActionHoverCardUpdateType update_type) = 0; }; #endif // CHROME_BROWSER_UI_EXTENSIONS_EXTENSIONS_CONTAINER_H_
diff --git a/chrome/browser/ui/toolbar/toolbar_action_hover_card_types.h b/chrome/browser/ui/toolbar/toolbar_action_hover_card_types.h new file mode 100644 index 0000000..deaf217 --- /dev/null +++ b/chrome/browser/ui/toolbar/toolbar_action_hover_card_types.h
@@ -0,0 +1,16 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_TOOLBAR_TOOLBAR_ACTION_HOVER_CARD_TYPES_H_ +#define CHROME_BROWSER_UI_TOOLBAR_TOOLBAR_ACTION_HOVER_CARD_TYPES_H_ + +// TODO(crbug.com/1351778): Mergue with `TabSlotController::HoverCardUpdateType` +// once the base hover card controller class once it's implemented. +enum class ToolbarActionHoverCardUpdateType { + kHover, + kToolbarActionRemoved, + kEvent +}; + +#endif // CHROME_BROWSER_UI_TOOLBAR_TOOLBAR_ACTION_HOVER_CARD_TYPES_H_
diff --git a/chrome/browser/ui/toolbar/toolbar_action_view_controller.h b/chrome/browser/ui/toolbar/toolbar_action_view_controller.h index 2391124..4865821 100644 --- a/chrome/browser/ui/toolbar/toolbar_action_view_controller.h +++ b/chrome/browser/ui/toolbar/toolbar_action_view_controller.h
@@ -10,6 +10,7 @@ #include "chrome/browser/extensions/extension_context_menu_model.h" #include "chrome/browser/extensions/site_permissions_helper.h" #include "chrome/browser/ui/extensions/extension_popup_types.h" +#include "chrome/browser/ui/toolbar/toolbar_action_hover_card_types.h" #include "ui/gfx/image/image.h" namespace content { @@ -25,6 +26,7 @@ } class ToolbarActionViewDelegate; +class ToolbarActionView; // The basic controller class for an action that is shown on the toolbar - // an extension action (like browser actions) or a component action (like @@ -128,6 +130,10 @@ // Updates the current state of the action. virtual void UpdateState() = 0; + // Updates the hover card for `action_view` based on `update_type`. + virtual void UpdateHoverCard(ToolbarActionView* action_view, + ToolbarActionHoverCardUpdateType update_type) {} + // Registers an accelerator. Called when the view is added to a widget. virtual void RegisterCommand() {}
diff --git a/chrome/browser/ui/ui_features.cc b/chrome/browser/ui/ui_features.cc index 4f453aaa..18763ff5 100644 --- a/chrome/browser/ui/ui_features.cc +++ b/chrome/browser/ui/ui_features.cc
@@ -216,9 +216,6 @@ const base::FeatureParam<bool> kTabSearchSearchIgnoreLocation{ &kTabSearchFuzzySearch, "TabSearchSearchIgnoreLocation", false}; -const base::Feature kTabSearchMediaTabs{"TabSearchMediaTabs", - base::FEATURE_ENABLED_BY_DEFAULT}; - // If this feature parameter is enabled, show media tabs in both "Audio & Video" // section and "Open Tabs" section. const char kTabSearchAlsoShowMediaTabsinOpenTabsSectionParameterName[] =
diff --git a/chrome/browser/ui/ui_features.h b/chrome/browser/ui/ui_features.h index 8dfea86..3d7ec60 100644 --- a/chrome/browser/ui/ui_features.h +++ b/chrome/browser/ui/ui_features.h
@@ -133,8 +133,6 @@ // This means that it will not matter where in the string the pattern occurs. extern const base::FeatureParam<bool> kTabSearchSearchIgnoreLocation; -extern const base::Feature kTabSearchMediaTabs; - extern const char kTabSearchAlsoShowMediaTabsinOpenTabsSectionParameterName[]; // Determines how close the match must be to the beginning of the string. Eg a
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc b/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc index 11eac50..a7a12bb 100644 --- a/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc +++ b/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc
@@ -1189,7 +1189,8 @@ void BookmarkBarView::BookmarkNodeAdded(BookmarkModel* model, const BookmarkNode* parent, - size_t index) { + size_t index, + bool added_by_user) { // See comment in BookmarkNodeMoved() for details on this. InvalidateDrop(); if (BookmarkNodeAddedImpl(model, parent, index))
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bar_view.h b/chrome/browser/ui/views/bookmarks/bookmark_bar_view.h index cf0cc603..de4eb76 100644 --- a/chrome/browser/ui/views/bookmarks/bookmark_bar_view.h +++ b/chrome/browser/ui/views/bookmarks/bookmark_bar_view.h
@@ -201,7 +201,8 @@ size_t new_index) override; void BookmarkNodeAdded(bookmarks::BookmarkModel* model, const bookmarks::BookmarkNode* parent, - size_t index) override; + size_t index, + bool added_by_user) override; void BookmarkNodeRemoved(bookmarks::BookmarkModel* model, const bookmarks::BookmarkNode* parent, size_t old_index,
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_editor_view.cc b/chrome/browser/ui/views/bookmarks/bookmark_editor_view.cc index 1adadfc..d2624268 100644 --- a/chrome/browser/ui/views/bookmarks/bookmark_editor_view.cc +++ b/chrome/browser/ui/views/bookmarks/bookmark_editor_view.cc
@@ -215,7 +215,8 @@ void BookmarkEditorView::BookmarkNodeAdded(BookmarkModel* model, const BookmarkNode* parent, - size_t index) { + size_t index, + bool added_by_user) { Reset(); }
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_editor_view.h b/chrome/browser/ui/views/bookmarks/bookmark_editor_view.h index 249acff..8525c335 100644 --- a/chrome/browser/ui/views/bookmarks/bookmark_editor_view.h +++ b/chrome/browser/ui/views/bookmarks/bookmark_editor_view.h
@@ -128,7 +128,8 @@ size_t new_index) override; void BookmarkNodeAdded(bookmarks::BookmarkModel* model, const bookmarks::BookmarkNode* parent, - size_t index) override; + size_t index, + bool added_by_user) override; void BookmarkNodeRemoved(bookmarks::BookmarkModel* model, const bookmarks::BookmarkNode* parent, size_t index,
diff --git a/chrome/browser/ui/views/download/bubble/download_toolbar_button_view.cc b/chrome/browser/ui/views/download/bubble/download_toolbar_button_view.cc index bc057699..44e1bd1 100644 --- a/chrome/browser/ui/views/download/bubble/download_toolbar_button_view.cc +++ b/chrome/browser/ui/views/download/bubble/download_toolbar_button_view.cc
@@ -287,6 +287,11 @@ controller_->OnButtonPressed(); } +void DownloadToolbarButtonView::OnThemeChanged() { + ToolbarButton::OnThemeChanged(); + UpdateIcon(); +} + std::unique_ptr<views::View> DownloadToolbarButtonView::CreateRowListView( std::vector<DownloadUIModel::DownloadUIModelPtr> model_list) { // Do not create empty partial view.
diff --git a/chrome/browser/ui/views/download/bubble/download_toolbar_button_view.h b/chrome/browser/ui/views/download/bubble/download_toolbar_button_view.h index 69bdbb4..86591e5 100644 --- a/chrome/browser/ui/views/download/bubble/download_toolbar_button_view.h +++ b/chrome/browser/ui/views/download/bubble/download_toolbar_button_view.h
@@ -57,6 +57,7 @@ // ToolbarButton: void UpdateIcon() override; + void OnThemeChanged() override; // DownloadBubbleNavigationHandler: void OpenPrimaryDialog() override;
diff --git a/chrome/browser/ui/views/extensions/extensions_toolbar_container.cc b/chrome/browser/ui/views/extensions/extensions_toolbar_container.cc index 1e0f606..0b9580d3 100644 --- a/chrome/browser/ui/views/extensions/extensions_toolbar_container.cc +++ b/chrome/browser/ui/views/extensions/extensions_toolbar_container.cc
@@ -22,9 +22,9 @@ #include "chrome/browser/ui/views/extensions/extensions_menu_view.h" #include "chrome/browser/ui/views/extensions/extensions_request_access_button.h" #include "chrome/browser/ui/views/extensions/extensions_tabbed_menu_coordinator.h" -#include "chrome/browser/ui/views/extensions/extensions_tabbed_menu_view.h" #include "chrome/browser/ui/views/extensions/extensions_toolbar_button.h" #include "chrome/browser/ui/views/frame/browser_view.h" +#include "chrome/browser/ui/views/toolbar/toolbar_action_hover_card_controller.h" #include "chrome/browser/ui/views/toolbar/toolbar_actions_bar_bubble_views.h" #include "chrome/browser/ui/views/web_apps/frame_toolbar/web_app_frame_toolbar_view.h" #include "extensions/common/extension_features.h" @@ -106,10 +106,17 @@ extensions_tabbed_menu_coordinator_.get()), std::make_unique<ExtensionsRequestAccessButton>(browser_)) : nullptr), - display_mode_(display_mode) { + display_mode_(display_mode), + action_hover_card_controller_( + std::make_unique<ToolbarActionHoverCardController>(this)) { // The container shouldn't show unless / until we have extensions available. SetVisible(false); + // So we only get enter/exit messages when the mouse enters/exits the whole + // container, even if it is entering/exiting a specific toolbar action view, + // too. + SetNotifyEnterExitOnChild(true); + model_observation_.Observe(model_.get()); permissions_manager_observation_.Observe( extensions::PermissionsManager::Get(browser_->profile())); @@ -158,6 +165,10 @@ } ExtensionsToolbarContainer::~ExtensionsToolbarContainer() { + // Eliminate the hover card first to avoid order-of-operation issues (e.g. + // avoid events during teardown). + action_hover_card_controller_.reset(); + // The child views hold pointers to the |actions_|, and thus need to be // destroyed before them. RemoveAllChildViews(); @@ -887,5 +898,28 @@ extensions_controls_->UpdateControls(actions_, site_setting, web_contents); } +void ExtensionsToolbarContainer::UpdateToolbarActionHoverCard( + ToolbarActionView* action_view, + ToolbarActionHoverCardUpdateType update_type) { + action_hover_card_controller_->UpdateHoverCard(action_view, update_type); +} + +void ExtensionsToolbarContainer::OnMouseExited(const ui::MouseEvent& event) { + UpdateToolbarActionHoverCard(nullptr, + ToolbarActionHoverCardUpdateType::kHover); +} + +void ExtensionsToolbarContainer::OnMouseMoved(const ui::MouseEvent& event) { + // Since we set the container's "notify enter exit on child" to true, we can + // get notified when the mouse enters a child view only if it originates from + // outside the container. This means that we a) can know when the mouse enters + // a toolbar action view (which is handled in such class) and b) cannot + // know when the mouse leaves a toolbar action view and enters a toolbar + // control. Therefore, listening for on mouse moved in the container reflects + // moving the mouse from toolbar action view to toolbar controls. + UpdateToolbarActionHoverCard(nullptr, + ToolbarActionHoverCardUpdateType::kHover); +} + BEGIN_METADATA(ExtensionsToolbarContainer, ToolbarIconContainerView) END_METADATA
diff --git a/chrome/browser/ui/views/extensions/extensions_toolbar_container.h b/chrome/browser/ui/views/extensions/extensions_toolbar_container.h index 810487c..8adfac90 100644 --- a/chrome/browser/ui/views/extensions/extensions_toolbar_container.h +++ b/chrome/browser/ui/views/extensions/extensions_toolbar_container.h
@@ -132,6 +132,8 @@ void OnDragExited() override; views::View::DropCallback GetDropCallback( const ui::DropTargetEvent& event) override; + void OnMouseExited(const ui::MouseEvent& event) override; + void OnMouseMoved(const ui::MouseEvent& event) override; // ExtensionsContainer: ToolbarActionViewController* GetActionForId( @@ -155,6 +157,9 @@ std::unique_ptr<ToolbarActionsBarBubbleDelegate> bubble) override; void ToggleExtensionsMenu() override; bool HasAnyExtensions() const override; + void UpdateToolbarActionHoverCard( + ToolbarActionView* action_view, + ToolbarActionHoverCardUpdateType update_type) override; // ToolbarActionView::Delegate: content::WebContents* GetCurrentWebContents() override; @@ -170,6 +175,8 @@ const gfx::Point& p) override; private: + friend class ToolbarActionHoverCardBubbleViewUITest; + // A struct representing the position and action being dragged. struct DropInfo; @@ -299,6 +306,10 @@ const raw_ptr<ExtensionsToolbarControls> extensions_controls_; DisplayMode display_mode_; + // Controller for showing the toolbar action hover card. + std::unique_ptr<ToolbarActionHoverCardController> + action_hover_card_controller_; + // TODO(pbos): Create actions and icons only for pinned pinned / popped out // actions (lazily). Currently code expects GetActionForId() to return // actions for extensions that aren't visible.
diff --git a/chrome/browser/ui/views/frame/browser_frame_ash.cc b/chrome/browser/ui/views/frame/browser_frame_ash.cc index 2a4540c..9a19240 100644 --- a/chrome/browser/ui/views/frame/browser_frame_ash.cc +++ b/chrome/browser/ui/views/frame/browser_frame_ash.cc
@@ -20,6 +20,7 @@ #include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/views/frame/browser_frame.h" #include "chrome/browser/ui/views/frame/browser_view.h" +#include "chromeos/ui/base/window_properties.h" #include "chromeos/ui/base/window_state_type.h" #include "components/app_restore/app_restore_info.h" #include "components/app_restore/app_restore_utils.h" @@ -191,6 +192,8 @@ params.init_properties_container.SetProperty(app_restore::kBrowserAppNameKey, browser->app_name()); + params.init_properties_container.SetProperty( + chromeos::kShouldHaveHighlightBorderOverlay, true); // This is only needed for ash. For lacros, Exo tags the associated // ShellSurface as being of AppType::LACROS.
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos.cc index 74d748a..a75d64e 100644 --- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos.cc +++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos.cc
@@ -812,6 +812,12 @@ if (!chromeos::features::IsDarkLightModeEnabled()) return; + if (highlight_border_overlay_ || + !GetWidget()->GetNativeWindow()->GetProperty( + chromeos::kShouldHaveHighlightBorderOverlay)) { + return; + } + highlight_border_overlay_ = std::make_unique<HighlightBorderOverlay>(GetWidget()); }
diff --git a/chrome/browser/ui/views/frame/desktop_browser_frame_lacros.cc b/chrome/browser/ui/views/frame/desktop_browser_frame_lacros.cc index 10d0f53..c2597f9 100644 --- a/chrome/browser/ui/views/frame/desktop_browser_frame_lacros.cc +++ b/chrome/browser/ui/views/frame/desktop_browser_frame_lacros.cc
@@ -8,6 +8,7 @@ #include "chrome/browser/ui/views/frame/browser_frame.h" #include "chrome/browser/ui/views/frame/browser_view.h" #include "chrome/browser/ui/views/frame/native_browser_frame_factory.h" +#include "chromeos/ui/base/window_properties.h" DesktopBrowserFrameLacros::DesktopBrowserFrameLacros( BrowserFrame* browser_frame, @@ -24,6 +25,8 @@ Browser* browser = browser_view()->browser(); params.restore_session_id = browser->session_id().id(); params.restore_window_id = browser->create_params().restore_id; + params.init_properties_container.SetProperty( + chromeos::kShouldHaveHighlightBorderOverlay, true); return params; }
diff --git a/chrome/browser/ui/views/side_panel/lens/lens_side_panel_coordinator_browsertest.cc b/chrome/browser/ui/views/side_panel/lens/lens_side_panel_coordinator_browsertest.cc index 6b39dac..d0223e6 100644 --- a/chrome/browser/ui/views/side_panel/lens/lens_side_panel_coordinator_browsertest.cc +++ b/chrome/browser/ui/views/side_panel/lens/lens_side_panel_coordinator_browsertest.cc
@@ -170,8 +170,15 @@ base::UserActionTester user_action_tester; }; +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) +#define MAYBE_ImageSearchWithValidImageOpensUnifiedSidePanel \ + DISABLED_ImageSearchWithValidImageOpensUnifiedSidePanel +#else +#define MAYBE_ImageSearchWithValidImageOpensUnifiedSidePanel \ + ImageSearchWithValidImageOpensUnifiedSidePanel +#endif IN_PROC_BROWSER_TEST_F(SearchImageWithUnifiedSidePanel, - ImageSearchWithValidImageOpensUnifiedSidePanel) { + MAYBE_ImageSearchWithValidImageOpensUnifiedSidePanel) { SetupUnifiedSidePanel(); EXPECT_TRUE(GetRightAlignedSidePanel()->GetVisible()); @@ -256,8 +263,15 @@ } }; +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) +#define MAYBE_ImageSearchWithValidImageOpensUnifiedSidePanel \ + DISABLED_ImageSearchWithValidImageOpensUnifiedSidePanel +#else +#define MAYBE_ImageSearchWithValidImageOpensUnifiedSidePanel \ + ImageSearchWithValidImageOpensUnifiedSidePanel +#endif IN_PROC_BROWSER_TEST_F(SearchImageWithUnifiedSidePanelFooterDisabled, - ImageSearchWithValidImageOpensUnifiedSidePanel) { + MAYBE_ImageSearchWithValidImageOpensUnifiedSidePanel) { SetupUnifiedSidePanel(); EXPECT_TRUE(GetRightAlignedSidePanel()->GetVisible());
diff --git a/chrome/browser/ui/views/side_panel/side_panel_coordinator.cc b/chrome/browser/ui/views/side_panel/side_panel_coordinator.cc index d987aa8..b7d49bc 100644 --- a/chrome/browser/ui/views/side_panel/side_panel_coordinator.cc +++ b/chrome/browser/ui/views/side_panel/side_panel_coordinator.cc
@@ -476,7 +476,7 @@ header_combobox_ = header->AddChildView(CreateCombobox()); - header->AddChildView(CreateControlButton( + auto* header_close_button = header->AddChildView(CreateControlButton( header.get(), base::BindRepeating(&SidePanelCoordinator::Close, base::Unretained(this)), views::kIcCloseIcon, gfx::Insets(), @@ -485,6 +485,9 @@ ChromeLayoutProvider::Get()->GetDistanceMetric( ChromeDistanceMetric::DISTANCE_SIDE_PANEL_HEADER_VECTOR_ICON_SIZE))); + header_combobox_->SetFocusBehavior(views::View::FocusBehavior::ALWAYS); + header_close_button->SetFocusBehavior(views::View::FocusBehavior::ALWAYS); + return header; }
diff --git a/chrome/browser/ui/views/side_panel/side_panel_resize_area.cc b/chrome/browser/ui/views/side_panel/side_panel_resize_area.cc index c409c74..fcd8b0e 100644 --- a/chrome/browser/ui/views/side_panel/side_panel_resize_area.cc +++ b/chrome/browser/ui/views/side_panel/side_panel_resize_area.cc
@@ -24,7 +24,7 @@ const gfx::Size preferred_resize_handle_size = gfx::Size(16, 24); SetPreferredSize(preferred_resize_handle_size); SetCanProcessEventsWithinSubtree(false); - SetFocusBehavior(FocusBehavior::ACCESSIBLE_ONLY); + SetFocusBehavior(FocusBehavior::ALWAYS); FocusRing::Install(this); }
diff --git a/chrome/browser/ui/views/toolbar/chrome_labs_bubble_view_model.cc b/chrome/browser/ui/views/toolbar/chrome_labs_bubble_view_model.cc index 240161f43..0d6fad81 100644 --- a/chrome/browser/ui/views/toolbar/chrome_labs_bubble_view_model.cc +++ b/chrome/browser/ui/views/toolbar/chrome_labs_bubble_view_model.cc
@@ -38,19 +38,6 @@ static const base::NoDestructor<std::vector<LabInfo>> lab_info_([]() { std::vector<LabInfo> lab_info; - // Tab Search Media Tabs - std::vector<std::u16string> tab_search_media_tabs_variation_description = { - l10n_util::GetStringUTF16( - IDS_MEDIA_TABS_ALSO_SHOWN_IN_OPEN_TABS_SECTION)}; - - lab_info.emplace_back(LabInfo( - flag_descriptions::kTabSearchMediaTabsId, - l10n_util::GetStringUTF16(IDS_TAB_SEARCH_MEDIA_TABS_EXPERIMENT_NAME), - l10n_util::GetStringUTF16( - IDS_TAB_SEARCH_MEDIA_TABS_EXPERIMENT_DESCRIPTION), - "chrome-labs-tab-search-media-tabs", version_info::Channel::BETA, - tab_search_media_tabs_variation_description)); - // Tab Scrolling. std::vector<std::u16string> tab_scrolling_variation_descriptions = { l10n_util::GetStringUTF16(IDS_TABS_SHRINK_TO_PINNED_TAB_WIDTH),
diff --git a/chrome/browser/ui/views/toolbar/chrome_labs_view_controller.cc b/chrome/browser/ui/views/toolbar/chrome_labs_view_controller.cc index 876d77ec..bd476bd 100644 --- a/chrome/browser/ui/views/toolbar/chrome_labs_view_controller.cc +++ b/chrome/browser/ui/views/toolbar/chrome_labs_view_controller.cc
@@ -52,8 +52,8 @@ // kSidePanelSelected = 4, // kLensRegionSearchSelected = 5, kWebUITabStripSelected = 6, - kTabSearchMediaTabsSelected = 7, - kMaxValue = kTabSearchMediaTabsSelected, + // kTabSearchMediaTabsSelected = 7, + kMaxValue = kWebUITabStripSelected, }; void EmitToHistogram(const std::u16string& selected_lab_state, @@ -82,8 +82,6 @@ if (internal_name == flag_descriptions::kWebUITabStripFlagId) return ChromeLabsSelectedLab::kWebUITabStripSelected; #endif - if (internal_name == flag_descriptions::kTabSearchMediaTabsId) - return ChromeLabsSelectedLab::kTabSearchMediaTabsSelected; return ChromeLabsSelectedLab::kUnspecifiedSelected; };
diff --git a/chrome/browser/ui/views/toolbar/toolbar_action_hover_card_bubble_view.cc b/chrome/browser/ui/views/toolbar/toolbar_action_hover_card_bubble_view.cc new file mode 100644 index 0000000..18548fb --- /dev/null +++ b/chrome/browser/ui/views/toolbar/toolbar_action_hover_card_bubble_view.cc
@@ -0,0 +1,265 @@ +// Copyright (c) 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/views/toolbar/toolbar_action_hover_card_bubble_view.h" + +#include "base/feature_list.h" +#include "chrome/browser/ui/views/chrome_layout_provider.h" +#include "chrome/browser/ui/views/chrome_typography.h" +#include "extensions/common/extension_features.h" +#include "ui/base/metadata/metadata_impl_macros.h" +#include "ui/gfx/canvas.h" +#include "ui/views/accessibility/view_accessibility.h" +#include "ui/views/layout/fill_layout.h" +#include "ui/views/layout/flex_layout.h" + +#if BUILDFLAG(IS_WIN) +#include "ui/base/win/shell.h" +#endif + +namespace { + +// Maximum number of lines that labels can occupy. +constexpr int kHoverCardTitleMaxLines = 2; + +// Hover card margins. +// TODO(crbug.com/1351778): Move to a base hover card class. +constexpr int kHorizontalMargin = 18; +constexpr int kVerticalMargin = 10; +constexpr auto kTitleMargins = + gfx::Insets::VH(kVerticalMargin, kHorizontalMargin); + +bool CustomShadowsSupported() { +#if BUILDFLAG(IS_WIN) + return ui::win::IsAeroGlassEnabled(); +#else + return true; +#endif +} + +// Label that renders its background in a solid color. Placed in front of a +// normal label either by being later in the draw order or on a layer, it can +// be used to animate a fade-out. +class SolidLabel : public views::Label { + public: + METADATA_HEADER(SolidLabel); + using Label::Label; + SolidLabel() = default; + ~SolidLabel() override = default; + + protected: + // views::Label: + void OnPaintBackground(gfx::Canvas* canvas) override { + canvas->DrawColor(GetBackgroundColor()); + } +}; + +BEGIN_METADATA(SolidLabel, views::Label) +END_METADATA + +// Label that exposes the CreateRenderText() method, so that we can use +// ToolbarActionHoverCardView::FilenameElider to do a two-line elision of +// filenames. +class RenderTextFactoryLabel : public views::Label { + public: + using Label::CreateRenderText; + using Label::Label; +}; + +} // namespace + +// ToolbarActionHoverCardBubbleView::FadeLabel: +// ---------------------------------------------------------- + +// This view overlays and fades out an old version of the text of a label, +// while displaying the new text underneath. It is used to fade out the old +// value of the title and domain labels on the hover card when the tab switches +// or the tab title changes. +// TODO(crbug.com/1354321): ToolbarActionHoverCarBubbleView has the same +// FadeLabel. Move it to its own shared file. +class ToolbarActionHoverCardBubbleView::FadeLabel : public views::View { + public: + FadeLabel(int context, int num_lines) { + primary_label_ = AddChildView(std::make_unique<RenderTextFactoryLabel>( + std::u16string(), context, views::style::STYLE_PRIMARY)); + primary_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT); + primary_label_->SetVerticalAlignment(gfx::ALIGN_TOP); + primary_label_->SetMultiLine(num_lines > 1); + if (num_lines > 1) + primary_label_->SetMaxLines(num_lines); + + label_fading_out_ = AddChildView(std::make_unique<SolidLabel>( + std::u16string(), context, views::style::STYLE_PRIMARY)); + label_fading_out_->SetHorizontalAlignment(gfx::ALIGN_LEFT); + label_fading_out_->SetVerticalAlignment(gfx::ALIGN_TOP); + label_fading_out_->SetMultiLine(num_lines > 1); + if (num_lines > 1) + label_fading_out_->SetMaxLines(num_lines); + label_fading_out_->GetViewAccessibility().OverrideIsIgnored(true); + + SetLayoutManager(std::make_unique<views::FillLayout>()); + } + + ~FadeLabel() override = default; + + void SetText(std::u16string text, absl::optional<bool> is_filename) { + if (was_filename_.has_value()) + SetMultilineParams(label_fading_out_, was_filename_.value()); + label_fading_out_->SetText(primary_label_->GetText()); + if (is_filename.has_value()) + SetMultilineParams(primary_label_, is_filename.value()); + was_filename_ = is_filename; + primary_label_->SetText(text); + } + + // Sets the fade-out of the label as |percent| in the range [0, 1]. Since + // FadeLabel is designed to mask new text with the old and then fade away, the + // higher the percentage the less opaque the label. + void SetFade(double percent) { + percent_ = std::min(1.0, percent); + if (percent_ == 1.0) + label_fading_out_->SetText(std::u16string()); + const SkAlpha alpha = base::saturated_cast<SkAlpha>( + std::numeric_limits<SkAlpha>::max() * (1.0 - percent_)); + label_fading_out_->SetBackgroundColor( + SkColorSetA(label_fading_out_->GetBackgroundColor(), alpha)); + label_fading_out_->SetEnabledColor( + SkColorSetA(label_fading_out_->GetEnabledColor(), alpha)); + } + + std::u16string GetText() const { return primary_label_->GetText(); } + + protected: + // views::View: + gfx::Size GetMaximumSize() const override { + return gfx::Tween::SizeValueBetween(percent_, + label_fading_out_->GetPreferredSize(), + primary_label_->GetPreferredSize()); + } + + gfx::Size CalculatePreferredSize() const override { + return primary_label_->GetPreferredSize(); + } + + gfx::Size GetMinimumSize() const override { + return primary_label_->GetMinimumSize(); + } + + int GetHeightForWidth(int width) const override { + return primary_label_->GetHeightForWidth(width); + } + + private: + static void SetMultilineParams(views::Label* label, bool is_filename) { + label->SetElideBehavior(is_filename ? gfx::NO_ELIDE : gfx::ELIDE_TAIL); + } + + raw_ptr<RenderTextFactoryLabel> primary_label_; + raw_ptr<SolidLabel> label_fading_out_; + absl::optional<bool> was_filename_; + double percent_ = 1.0; +}; + +// ToolbarActionHoverCardBubbleView: +// ---------------------------------------------------------- + +// TODO(crbug.com/1351778): Add content based on `action_view`. +ToolbarActionHoverCardBubbleView::ToolbarActionHoverCardBubbleView( + ToolbarActionView* action_view) + : BubbleDialogDelegateView(action_view, + views::BubbleBorder::TOP_LEFT, + views::BubbleBorder::STANDARD_SHADOW) { + DCHECK(base::FeatureList::IsEnabled( + extensions_features::kExtensionsMenuAccessControl)); + + // Remove dialog's default buttons. + SetButtons(ui::DIALOG_BUTTON_NONE); + + // Remove the accessible role so that hover cards are not read when they + // appear because tabs handle accessibility text. + SetAccessibleRole(ax::mojom::Role::kNone); + + // We'll do all of our own layout inside the bubble, so no need to inset this + // view inside the client view. + set_margins(gfx::Insets()); + + // Set so that when hovering over a toolbar action in a inactive window that + // window will not become active. Setting this to false creates the need to + // explicitly hide the hovercard on press, touch, and keyboard events. + SetCanActivate(false); +#if BUILDFLAG(IS_MAC) + set_accept_events(false); +#endif + + // Set so that the toolbar action hover card is not focus traversable when + // keyboard navigating through the tab strip. + set_focus_traversable_from_anchor_view(false); + + // Set up content. + title_label_ = AddChildView(std::make_unique<FadeLabel>( + CONTEXT_TAB_HOVER_CARD_TITLE, kHoverCardTitleMaxLines)); + // TODO(crbug.com/1351778): Use 'alert_label' for extension's site access + // information. + UpdateCardContent(); + + // Set up layout. + views::FlexLayout* const layout = + SetLayoutManager(std::make_unique<views::FlexLayout>()); + layout->SetOrientation(views::LayoutOrientation::kVertical); + layout->SetMainAxisAlignment(views::LayoutAlignment::kStart); + layout->SetCrossAxisAlignment(views::LayoutAlignment::kStretch); + layout->SetCollapseMargins(true); + + title_label_->SetProperty(views::kMarginsKey, kTitleMargins); + title_label_->SetProperty( + views::kFlexBehaviorKey, + views::FlexSpecification(views::MinimumFlexSizeRule::kScaleToMinimum, + views::MaximumFlexSizeRule::kScaleToMaximum) + .WithOrder(2)); + + if (CustomShadowsSupported()) { + corner_radius_ = ChromeLayoutProvider::Get()->GetCornerRadiusMetric( + views::Emphasis::kHigh); + } + + // Set up widget. + views::BubbleDialogDelegateView::CreateBubble(this); + set_adjust_if_offscreen(true); + + GetBubbleFrameView()->SetPreferredArrowAdjustment( + views::BubbleFrameView::PreferredArrowAdjustment::kOffset); + GetBubbleFrameView()->set_hit_test_transparent(true); + + if (using_rounded_corners()) + GetBubbleFrameView()->SetCornerRadius(corner_radius_.value()); + + // Start in the fully "faded-in" position so that whatever text we initially + // display is visible. + SetTextFade(1.0); +} + +void ToolbarActionHoverCardBubbleView::UpdateCardContent() { + title_label_->SetText(u"Extension name", absl::nullopt); +} + +void ToolbarActionHoverCardBubbleView::SetTextFade(double percent) { + title_label_->SetFade(percent); +} + +void ToolbarActionHoverCardBubbleView::OnThemeChanged() { + BubbleDialogDelegateView::OnThemeChanged(); + + // Bubble closes if the theme changes to the point where the border has to be + // regenerated. See crbug.com/1140256 + if (using_rounded_corners() != CustomShadowsSupported()) { + GetWidget()->Close(); + return; + } +} + +ToolbarActionHoverCardBubbleView::~ToolbarActionHoverCardBubbleView() = default; + +BEGIN_METADATA(ToolbarActionHoverCardBubbleView, + views::BubbleDialogDelegateView) +END_METADATA
diff --git a/chrome/browser/ui/views/toolbar/toolbar_action_hover_card_bubble_view.h b/chrome/browser/ui/views/toolbar/toolbar_action_hover_card_bubble_view.h new file mode 100644 index 0000000..5cbb84e --- /dev/null +++ b/chrome/browser/ui/views/toolbar/toolbar_action_hover_card_bubble_view.h
@@ -0,0 +1,46 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_VIEWS_TOOLBAR_TOOLBAR_ACTION_HOVER_CARD_BUBBLE_VIEW_H_ +#define CHROME_BROWSER_UI_VIEWS_TOOLBAR_TOOLBAR_ACTION_HOVER_CARD_BUBBLE_VIEW_H_ + +#include "chrome/browser/ui/views/toolbar/toolbar_action_view.h" +#include "ui/base/metadata/metadata_header_macros.h" +#include "ui/views/bubble/bubble_dialog_delegate_view.h" + +class ToolbarActionView; + +// Dialog that displays a hover card with extensions information. +class ToolbarActionHoverCardBubbleView + : public views::BubbleDialogDelegateView { + public: + METADATA_HEADER(ToolbarActionHoverCardBubbleView); + explicit ToolbarActionHoverCardBubbleView(ToolbarActionView* action_view); + ToolbarActionHoverCardBubbleView(const ToolbarActionHoverCardBubbleView&) = + delete; + ToolbarActionHoverCardBubbleView& operator=( + const ToolbarActionHoverCardBubbleView&) = delete; + ~ToolbarActionHoverCardBubbleView() override; + + // Updates the hover card content. + // TODO(crbug.com/1351778): Update content based on a given `action_view`. + void UpdateCardContent(); + + // Update the text fade to the given percent, which should be between 0 and 1. + void SetTextFade(double percent); + + private: + class FadeLabel; + + bool using_rounded_corners() const { return corner_radius_.has_value(); } + + // views::BubbleDialogDelegateView: + void OnThemeChanged() override; + + raw_ptr<FadeLabel> title_label_ = nullptr; + + absl::optional<int> corner_radius_; +}; + +#endif // CHROME_BROWSER_UI_VIEWS_TOOLBAR_TOOLBAR_ACTION_HOVER_CARD_BUBBLE_VIEW_H_
diff --git a/chrome/browser/ui/views/toolbar/toolbar_action_hover_card_bubble_view_interactive_uitest.cc b/chrome/browser/ui/views/toolbar/toolbar_action_hover_card_bubble_view_interactive_uitest.cc new file mode 100644 index 0000000..1a323bd --- /dev/null +++ b/chrome/browser/ui/views/toolbar/toolbar_action_hover_card_bubble_view_interactive_uitest.cc
@@ -0,0 +1,259 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/views/toolbar/toolbar_action_hover_card_bubble_view.h" + +#include "chrome/browser/ui/test/test_browser_dialog.h" +#include "chrome/browser/ui/views/extensions/extensions_toolbar_container.h" +#include "chrome/browser/ui/views/extensions/extensions_toolbar_interactive_uitest.h" +#include "chrome/browser/ui/views/toolbar/toolbar_action_hover_card_bubble_view.h" +#include "chrome/browser/ui/views/toolbar/toolbar_action_hover_card_controller.h" +#include "chrome/test/base/interactive_test_utils.h" +#include "content/public/test/browser_test.h" +#include "extensions/common/extension_features.h" +#include "ui/events/types/event_type.h" +#include "ui/gfx/animation/animation_test_api.h" +#include "ui/views/test/widget_test.h" + +namespace { + +// Similar to views::test::WidgetDestroyedWaiter but waiting after the widget +// has been closed is a no-op rather than an error. +// TODO(crbug.com/1354661): Move SafeWidgetDestroyedWaiter to a shared file +// since it's used by multiple tests. +class SafeWidgetDestroyedWaiter : public views::WidgetObserver { + public: + explicit SafeWidgetDestroyedWaiter(views::Widget* widget) { + observation_.Observe(widget); + } + + // views::WidgetObserver: + void OnWidgetDestroyed(views::Widget* widget) override { + observation_.Reset(); + if (!quit_closure_.is_null()) + std::move(quit_closure_).Run(); + } + + void Wait() { + if (!observation_.IsObserving()) + return; + DCHECK(quit_closure_.is_null()); + quit_closure_ = run_loop_.QuitClosure(); + run_loop_.Run(); + } + + private: + base::RunLoop run_loop_; + base::OnceClosure quit_closure_; + base::ScopedObservation<views::Widget, views::WidgetObserver> observation_{ + this}; +}; + +} // namespace + +class ToolbarActionHoverCardBubbleViewUITest : public ExtensionsToolbarUITest { + public: + ToolbarActionHoverCardBubbleViewUITest() + : animation_mode_reset_(gfx::AnimationTestApi::SetRichAnimationRenderMode( + gfx::Animation::RichAnimationRenderMode::FORCE_DISABLED)) { + ToolbarActionHoverCardController::disable_animations_for_testing_ = true; + scoped_feature_list_.InitAndEnableFeature( + extensions_features::kExtensionsMenuAccessControl); + } + ToolbarActionHoverCardBubbleViewUITest( + const ToolbarActionHoverCardBubbleViewUITest&) = delete; + ToolbarActionHoverCardBubbleViewUITest& operator=( + const ToolbarActionHoverCardBubbleViewUITest&) = delete; + ~ToolbarActionHoverCardBubbleViewUITest() override = default; + + ToolbarActionHoverCardBubbleView* hover_card() { + return GetExtensionsToolbarContainer() + ->action_hover_card_controller_->hover_card_; + } + + void HoverMouseOverActionView(ToolbarActionView* action_view) { + // We don't use ToolbarActionView::OnMouseEntered here to invoke the hover + // card because that path is disabled in browser tests. If we enabled it, + // the real mouse might interfere with the test. + GetExtensionsToolbarContainer()->UpdateToolbarActionHoverCard( + action_view, ToolbarActionHoverCardUpdateType::kHover); + } + + void ClickMouseOnActionView(ToolbarActionView* action_view) { + ui::MouseEvent mouse_event(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), + base::TimeTicks(), ui::EF_NONE, 0); + action_view->OnMousePressed(mouse_event); + } + + void MouseExitsFromExtensionsContainer() { + ui::MouseEvent mouse_event(ui::ET_MOUSE_EXITED, gfx::Point(), gfx::Point(), + base::TimeTicks(), ui::EF_NONE, 0); + GetExtensionsToolbarContainer()->OnMouseExited(mouse_event); + } + + void MouseMovesInExtensionsContainer() { + ui::MouseEvent mouse_event(ui::ET_MOUSE_MOVED, gfx::Point(), gfx::Point(), + base::TimeTicks(), ui::EF_NONE, 0); + GetExtensionsToolbarContainer()->OnMouseMoved(mouse_event); + } + + scoped_refptr<const extensions::Extension> LoadExtensionAndPinIt( + const std::string& path) { + scoped_refptr<const extensions::Extension> extension = + LoadTestExtension(path); + + ToolbarActionsModel* const toolbar_model = + ToolbarActionsModel::Get(browser()->profile()); + toolbar_model->SetActionVisibility(extension->id(), true); + GetExtensionsToolbarContainer()->GetWidget()->LayoutRootViewIfNecessary(); + return extension; + } + + // DialogBrowserTest: + void ShowUi(const std::string& name) override { + LoadExtensionAndPinIt("extensions/simple_with_popup"); + auto action_views = GetVisibleToolbarActionViews(); + ASSERT_EQ(action_views.size(), 1u); + + HoverMouseOverActionView(action_views[0]); + views::test::WidgetVisibleWaiter(hover_card()->GetWidget()).Wait(); + } + + protected: + base::test::ScopedFeatureList scoped_feature_list_; + + private: + std::unique_ptr<base::AutoReset<gfx::Animation::RichAnimationRenderMode>> + animation_mode_reset_; +}; + +IN_PROC_BROWSER_TEST_F(ToolbarActionHoverCardBubbleViewUITest, InvokeUi) { + ShowAndVerifyUi(); +} + +// Verify hover card is visible while hovering and not visible outside of the +// extensions container. +IN_PROC_BROWSER_TEST_F(ToolbarActionHoverCardBubbleViewUITest, + WidgetVisibleOnHover) { + ShowUi(""); + views::Widget* const widget = hover_card()->GetWidget(); + ASSERT_TRUE(widget); + EXPECT_TRUE(widget->IsVisible()); + + MouseExitsFromExtensionsContainer(); + EXPECT_FALSE(widget->IsVisible()); +} + +// Verify anchor is correctly updated when moving hover from one action view to +// another. +// TODO(crbug.com/1351778): Once implemented, verify hover card content +// matches corresponding action view. +IN_PROC_BROWSER_TEST_F(ToolbarActionHoverCardBubbleViewUITest, + WidgetAnchoredToCorrectActionView) { + LoadExtensionAndPinIt("extensions/simple_with_popup"); + LoadExtensionAndPinIt("extensions/simple_with_icon"); + auto action_views = GetVisibleToolbarActionViews(); + ASSERT_EQ(action_views.size(), 2u); + + HoverMouseOverActionView(action_views[0]); + views::Widget* const widget = hover_card()->GetWidget(); + views::test::WidgetVisibleWaiter(widget).Wait(); + ASSERT_TRUE(widget); + EXPECT_TRUE(widget->IsVisible()); + EXPECT_EQ(hover_card()->GetAnchorView(), + static_cast<views::View*>(action_views[0])); + + // Note that the widget is the same because it transitions from one action + // view to the other. + HoverMouseOverActionView(action_views[1]); + views::test::WidgetVisibleWaiter(widget).Wait(); + ASSERT_TRUE(widget); + EXPECT_TRUE(widget->IsVisible()); + EXPECT_EQ(hover_card()->GetAnchorView(), + static_cast<views::View*>(action_views[1])); +} + +// Verify hover card is not visible when mouse moves inside the extensions +// container to a button that is not a toolbar icon view (which has its own 'on +// mouse moved' event listener). +IN_PROC_BROWSER_TEST_F(ToolbarActionHoverCardBubbleViewUITest, + WidgetNotVisibleOnExtensionsControl) { + ShowUi(""); + views::Widget* const widget = hover_card()->GetWidget(); + ASSERT_TRUE(widget); + EXPECT_TRUE(widget->IsVisible()); + + MouseMovesInExtensionsContainer(); + EXPECT_FALSE(widget->IsVisible()); +} + +// Verify hover card is not visible after clicking on a toolbar action view. +IN_PROC_BROWSER_TEST_F(ToolbarActionHoverCardBubbleViewUITest, + WidgetNotVisibleOnToolbarActionViewClick) { + ShowUi(""); + views::Widget* const widget = hover_card()->GetWidget(); + ASSERT_TRUE(widget); + EXPECT_TRUE(widget->IsVisible()); + + auto action_views = GetVisibleToolbarActionViews(); + ASSERT_EQ(action_views.size(), 1u); + + ClickMouseOnActionView(action_views[0]); + EXPECT_FALSE(widget->IsVisible()); +} + +// Verify hover card is not visible on focus, similar to tooltip behavior. +IN_PROC_BROWSER_TEST_F(ToolbarActionHoverCardBubbleViewUITest, + WidgetNotVisibleOnFocus) { + LoadExtensionAndPinIt("extensions/simple_with_popup"); + auto action_views = GetVisibleToolbarActionViews(); + ASSERT_EQ(action_views.size(), 1u); + + GetExtensionsToolbarContainer()->GetFocusManager()->SetFocusedView( + action_views[0]); + EXPECT_EQ(hover_card(), nullptr); +} + +// Verify that the hover card is not visible when any key is pressed. +IN_PROC_BROWSER_TEST_F(ToolbarActionHoverCardBubbleViewUITest, + WidgetNotVisibleOnAnyKeyPressInSameWindow) { + ShowUi(""); + views::Widget* const widget = hover_card()->GetWidget(); + ASSERT_TRUE(widget); + EXPECT_TRUE(widget->IsVisible()); + + // Verify that the hover card widget is destroyed sometime between now and + // when we check afterwards. Depending on platform, the destruction could be + // synchronous or asynchronous. + SafeWidgetDestroyedWaiter widget_destroyed_waiter(widget); + EXPECT_TRUE(ui_test_utils::SendKeyPressSync(browser(), ui::VKEY_DOWN, false, + false, false, false)); + + // Note, fade in/out animations are disabled for testing so this should be + // relatively quick. + widget_destroyed_waiter.Wait(); + EXPECT_EQ(hover_card(), nullptr); +} + +class ToolbarActionHoverCardBubbleViewDisabledFeatureUITest + : public ToolbarActionHoverCardBubbleViewUITest { + public: + ToolbarActionHoverCardBubbleViewDisabledFeatureUITest() { + scoped_feature_list_.Reset(); + scoped_feature_list_.InitAndDisableFeature( + extensions_features::kExtensionsMenuAccessControl); + } +}; + +// Verify hover card is not visible on toolbar action view hover when the +// feature is disabled. +IN_PROC_BROWSER_TEST_F(ToolbarActionHoverCardBubbleViewDisabledFeatureUITest, + WidgetNotVisibleWhenDisabledFeature) { + LoadExtensionAndPinIt("extensions/simple_with_popup"); + auto action_views = GetVisibleToolbarActionViews(); + ASSERT_EQ(action_views.size(), 1u); + + HoverMouseOverActionView(action_views[0]); + EXPECT_EQ(hover_card(), nullptr); +}
diff --git a/chrome/browser/ui/views/toolbar/toolbar_action_hover_card_controller.cc b/chrome/browser/ui/views/toolbar/toolbar_action_hover_card_controller.cc new file mode 100644 index 0000000..ecf9d24e --- /dev/null +++ b/chrome/browser/ui/views/toolbar/toolbar_action_hover_card_controller.cc
@@ -0,0 +1,349 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/views/toolbar/toolbar_action_hover_card_controller.h" + +#include "base/bind.h" +#include "base/callback_list.h" +#include "base/feature_list.h" +#include "base/memory/raw_ptr.h" +#include "base/time/time.h" +#include "build/build_config.h" +#include "chrome/browser/ui/views/extensions/extensions_toolbar_container.h" +#include "chrome/browser/ui/views/toolbar/toolbar_action_hover_card_bubble_view.h" +#include "chrome/browser/ui/views/toolbar/toolbar_action_view.h" +#include "extensions/common/extension_features.h" +#include "ui/events/event_observer.h" +#include "ui/views/event_monitor.h" +#include "ui/views/view.h" +#include "ui/views/widget/widget.h" + +namespace { + +constexpr base::TimeDelta kTriggerDelay = base::Milliseconds(300); +constexpr base::TimeDelta kHoverCardSlideDuration = base::Milliseconds(200); + +} // namespace + +// static +bool ToolbarActionHoverCardController::disable_animations_for_testing_ = false; + +//------------------------------------------------------------------- +// ToolbarActionHoverCardController::EventSniffer + +// Listens in on the browser event stream and hides an associated hover card +// on any keypress, mouse click, or gesture. +class ToolbarActionHoverCardController::EventSniffer + : public ui::EventObserver { + public: + explicit EventSniffer(ToolbarActionHoverCardController* controller) + : controller_(controller) { + // Note that null is a valid value for the second parameter here; if for + // some reason there is no native window it simply falls back to + // application-wide event-sniffing, which for this case is better than not + // watching events at all. + event_monitor_ = views::EventMonitor::CreateWindowMonitor( + this, + controller_->extensions_container_->GetWidget()->GetNativeWindow(), + {ui::ET_KEY_PRESSED, ui::ET_KEY_RELEASED, ui::ET_MOUSE_PRESSED, + ui::ET_MOUSE_RELEASED, ui::ET_GESTURE_BEGIN, ui::ET_GESTURE_END}); + } + + ~EventSniffer() override = default; + + protected: + // ui::EventObserver: + void OnEvent(const ui::Event& event) override { + controller_->UpdateHoverCard(nullptr, + ToolbarActionHoverCardUpdateType::kEvent); + } + + private: + const raw_ptr<ToolbarActionHoverCardController> controller_; + std::unique_ptr<views::EventMonitor> event_monitor_; +}; + +//------------------------------------------------------------------- +// ToolbarActionHoverCardController + +ToolbarActionHoverCardController::ToolbarActionHoverCardController( + ExtensionsToolbarContainer* extensions_container) + : extensions_container_(extensions_container) {} + +ToolbarActionHoverCardController::~ToolbarActionHoverCardController() = default; + +// static +bool ToolbarActionHoverCardController::UseAnimations() { + return gfx::Animation::ShouldRenderRichAnimation(); +} + +bool ToolbarActionHoverCardController::IsHoverCardVisible() const { + return hover_card_ != nullptr && hover_card_->GetWidget() && + !hover_card_->GetWidget()->IsClosed(); +} + +bool ToolbarActionHoverCardController::IsHoverCardShowingForAction( + ToolbarActionView* action_view) const { + return IsHoverCardVisible() && !fade_animator_->IsFadingOut() && + GetTargetAnchorView() == action_view; +} + +void ToolbarActionHoverCardController::UpdateHoverCard( + ToolbarActionView* action_view, + ToolbarActionHoverCardUpdateType update_type) { + if (!base::FeatureList::IsEnabled( + extensions_features::kExtensionsMenuAccessControl)) { + return; + } + + // TODO(crbug.com/1351778): Check if we need to handle never displaying a + // hover card for a toolbar action that is closing (pin was removed). + + // Update this ASAP so that if we try to fade-in and we have the wrong target + // then when the fade timer elapses we won't incorrectly try to fade in on the + // wrong action view. + if (target_action_view_ != action_view) { + delayed_show_timer_.Stop(); + target_action_view_observation_.Reset(); + if (action_view) + target_action_view_observation_.Observe(action_view); + target_action_view_ = action_view; + } + + // If there's nothing to attach to then there's no point in creating a card. + if (!hover_card_ && (!action_view || !extensions_container_->GetWidget())) + return; + + switch (update_type) { + case ToolbarActionHoverCardUpdateType::kHover: + if (!action_view) + last_mouse_exit_timestamp_ = base::TimeTicks::Now(); + break; + case ToolbarActionHoverCardUpdateType::kToolbarActionRemoved: + // Should not have an action view associated. + DCHECK(!action_view); + break; + case ToolbarActionHoverCardUpdateType::kEvent: + // No special action taken for this type of event. + break; + } + + if (action_view) + UpdateOrShowHoverCard(action_view, update_type); + else + HideHoverCard(); +} + +// TODO(crbug.com/1351778): Fix inkdrop when hovering over `action_view`. +void ToolbarActionHoverCardController::UpdateOrShowHoverCard( + ToolbarActionView* action_view, + ToolbarActionHoverCardUpdateType update_type) { + // Close is asynchronous, so make sure that if we're closing we clear out all + // of our data *now* rather than waiting for the deletion message. + if (hover_card_ && hover_card_->GetWidget()->IsClosed()) + OnViewIsDeleting(hover_card_); + + // Cancel any pending fades. + if (hover_card_ && fade_animator_->IsFadingOut()) { + fade_animator_->CancelFadeOut(); + } + + if (hover_card_) { + // Card should never exist without an anchor. + DCHECK(hover_card_->GetAnchorView()); + // TODO(crbug.com/1351778): Update card contents for `action_view` since the + // card was visible. + + // If widget is already visible and anchored to the correct action view we + // should not try to reset the anchor view or reshow. + if (!UseAnimations() || (hover_card_->GetAnchorView() == action_view && + !slide_animator_->is_animating())) { + slide_animator_->SnapToAnchorView(action_view); + } else { + slide_animator_->AnimateToAnchorView(action_view); + } + return; + } + + // Maybe make hover card visible. Disabling animations for testing also + // eliminates the show timer, lest the tests have to be significantly more + // complex and time-consuming. + const bool is_initial = !ShouldShowImmediately(action_view); + if (is_initial && !disable_animations_for_testing_) { + delayed_show_timer_.Start( + FROM_HERE, kTriggerDelay, + base::BindOnce(&ToolbarActionHoverCardController::ShowHoverCard, + weak_ptr_factory_.GetWeakPtr(), true, action_view)); + } else { + // Just in case, cancel the timer. This shouldn't cancel a delayed capture + // since delayed capture only happens when the hover card already exists, + // and this code is only invoked if there is no hover card yet. + delayed_show_timer_.Stop(); + DCHECK_EQ(target_action_view_, action_view); + ShowHoverCard(is_initial, action_view); + } +} + +void ToolbarActionHoverCardController::CreateHoverCard( + ToolbarActionView* action_view) { + hover_card_ = new ToolbarActionHoverCardBubbleView(action_view); + hover_card_observation_.Observe(hover_card_.get()); + event_sniffer_ = std::make_unique<EventSniffer>(this); + + slide_animator_ = std::make_unique<views::BubbleSlideAnimator>(hover_card_); + slide_animator_->SetSlideDuration(kHoverCardSlideDuration); + slide_progressed_subscription_ = + slide_animator_->AddSlideProgressedCallback(base::BindRepeating( + &ToolbarActionHoverCardController::OnSlideAnimationProgressed, + weak_ptr_factory_.GetWeakPtr())); + slide_complete_subscription_ = + slide_animator_->AddSlideCompleteCallback(base::BindRepeating( + &ToolbarActionHoverCardController::OnSlideAnimationComplete, + weak_ptr_factory_.GetWeakPtr())); + + fade_animator_ = + std::make_unique<views::WidgetFadeAnimator>(hover_card_->GetWidget()); + fade_complete_subscription_ = + fade_animator_->AddFadeCompleteCallback(base::BindRepeating( + &ToolbarActionHoverCardController::OnFadeAnimationEnded, + weak_ptr_factory_.GetWeakPtr())); +} + +void ToolbarActionHoverCardController::ShowHoverCard( + bool is_initial, + const ToolbarActionView* intended_action_view) { + // Make sure the hover card isn't accidentally shown if it's already visible + // or if the anchor is gone or changed. + if (hover_card_ || target_action_view_ != intended_action_view || + !TargetActionViewIsValid()) + return; + + CreateHoverCard(target_action_view_); + // TODO(crbug.com/1351778): Update card contents for `target_action_view`. + slide_animator_->UpdateTargetBounds(); + // TODO(crbug.com/1351778): Do we need to fix widget stack order? Revisit + // this, specially after adding IPH. + + if (!is_initial || !UseAnimations()) { + hover_card_->GetWidget()->Show(); + return; + } + + fade_animator_->FadeIn(); +} + +void ToolbarActionHoverCardController::HideHoverCard() { + if (!hover_card_ || hover_card_->GetWidget()->IsClosed()) + return; + + // Cancel any pending fade-in. + if (fade_animator_->IsFadingIn()) { + fade_animator_->CancelFadeIn(); + } + + // This needs to be called whether we're doing a fade or a pop out. + slide_animator_->StopAnimation(); + if (!UseAnimations()) { + hover_card_->GetWidget()->Close(); + return; + } + if (fade_animator_->IsFadingOut()) + return; + + fade_animator_->FadeOut(); +} + +bool ToolbarActionHoverCardController::ShouldShowImmediately( + const ToolbarActionView* action_view) const { + // If less than `kShowWithoutDelayTimeBuffer` time has passed since the hover + // card was last visible then it is shown immediately. This is to account for + // if hover unintentionally leaves the extensions container. + constexpr base::TimeDelta kShowWithoutDelayTimeBuffer = + base::Milliseconds(300); + base::TimeDelta elapsed_time = + base::TimeTicks::Now() - last_mouse_exit_timestamp_; + + bool within_delay_time_buffer = !last_mouse_exit_timestamp_.is_null() && + elapsed_time <= kShowWithoutDelayTimeBuffer; + // Hover cards should be shown without delay if triggered within the time + // buffer. + // TODO(crbug.com/1351778): Should hover cards be shown if the action view + // is keyboard focused? + return within_delay_time_buffer; +} + +const views::View* ToolbarActionHoverCardController::GetTargetAnchorView() + const { + if (!hover_card_) + return nullptr; + if (slide_animator_->is_animating()) + return slide_animator_->desired_anchor_view(); + return hover_card_->GetAnchorView(); +} + +bool ToolbarActionHoverCardController::TargetActionViewIsValid() const { + // TODO(crbug.com/1351778): Explore more conditions where an action view is no + // longer valid. + return target_action_view_ && target_action_view_->GetVisible(); +} + +void ToolbarActionHoverCardController::OnFadeAnimationEnded( + views::WidgetFadeAnimator* animator, + views::WidgetFadeAnimator::FadeType fade_type) { + if (fade_type == views::WidgetFadeAnimator::FadeType::kFadeOut) + hover_card_->GetWidget()->Close(); +} + +void ToolbarActionHoverCardController::OnSlideAnimationProgressed( + views::BubbleSlideAnimator* animator, + double value) { + // TODO(crbug.com/1351778): Set text fade for hover card once content is + // updated based on the toolbar action. +} + +void ToolbarActionHoverCardController::OnSlideAnimationComplete( + views::BubbleSlideAnimator* animator) { + // TODO(crbug.com/1351778): Set text fade for hover card once content is + // updated based on the toolbar action. +} + +void ToolbarActionHoverCardController::OnViewIsDeleting( + views::View* observed_view) { + if (hover_card_ == observed_view) { + delayed_show_timer_.Stop(); + hover_card_observation_.Reset(); + event_sniffer_.reset(); + slide_progressed_subscription_ = base::CallbackListSubscription(); + slide_complete_subscription_ = base::CallbackListSubscription(); + fade_complete_subscription_ = base::CallbackListSubscription(); + slide_animator_.reset(); + fade_animator_.reset(); + hover_card_ = nullptr; + } else if (target_action_view_ == observed_view) { + UpdateHoverCard(nullptr, + ToolbarActionHoverCardUpdateType::kToolbarActionRemoved); + // These postconditions should always be met after calling + // UpdateHoverCard(nullptr, ...) + DCHECK(!target_action_view_); + DCHECK(!target_action_view_observation_.IsObserving()); + } +} + +void ToolbarActionHoverCardController::OnViewVisibilityChanged( + views::View* observed_view, + views::View* starting_view) { + // Only care about target action view becoming invisible. + if (observed_view != target_action_view_) + return; + // Visibility comes from `starting_view` or the widget, if no starting view; + // see documentation for ViewObserver::OnViewVisibilityChanged(). + const bool visible = starting_view + ? starting_view->GetVisible() + : (observed_view->GetWidget() && + observed_view->GetWidget()->IsVisible()); + // If visibility changed to false, treat it as if the target action view had + // gone away. + if (!visible) + OnViewIsDeleting(observed_view); +}
diff --git a/chrome/browser/ui/views/toolbar/toolbar_action_hover_card_controller.h b/chrome/browser/ui/views/toolbar/toolbar_action_hover_card_controller.h new file mode 100644 index 0000000..a30de7e8 --- /dev/null +++ b/chrome/browser/ui/views/toolbar/toolbar_action_hover_card_controller.h
@@ -0,0 +1,108 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_VIEWS_TOOLBAR_TOOLBAR_ACTION_HOVER_CARD_CONTROLLER_H_ +#define CHROME_BROWSER_UI_VIEWS_TOOLBAR_TOOLBAR_ACTION_HOVER_CARD_CONTROLLER_H_ + +#include <memory> + +#include "base/callback_list.h" +#include "base/gtest_prod_util.h" +#include "base/memory/memory_pressure_listener.h" +#include "base/memory/raw_ptr.h" +#include "base/memory/weak_ptr.h" +#include "base/scoped_observation.h" +#include "base/time/time.h" +#include "base/timer/timer.h" +#include "chrome/browser/ui/toolbar/toolbar_action_hover_card_types.h" +#include "ui/views/animation/bubble_slide_animator.h" +#include "ui/views/animation/widget_fade_animator.h" +#include "ui/views/view.h" +#include "ui/views/view_observer.h" + +class ToolbarActionHoverCardBubbleView; +class ExtensionsToolbarContainer; +class ToolbarActionView; + +// Controls how hover cards are shown and hidden for toolbar actions. +class ToolbarActionHoverCardController : public views::ViewObserver { + public: + explicit ToolbarActionHoverCardController( + ExtensionsToolbarContainer* extensions_container); + ~ToolbarActionHoverCardController() override; + + // Returns whether hover card animations should be shown on the current + // device. + static bool UseAnimations(); + + bool IsHoverCardVisible() const; + bool IsHoverCardShowingForAction(ToolbarActionView* action_view) const; + void UpdateHoverCard(ToolbarActionView* action_view, + ToolbarActionHoverCardUpdateType update_type); + + private: + friend class ToolbarActionHoverCardBubbleViewUITest; + + class EventSniffer; + + void UpdateOrShowHoverCard(ToolbarActionView* action_view, + ToolbarActionHoverCardUpdateType update_type); + void CreateHoverCard(ToolbarActionView* action_view); + void ShowHoverCard(bool is_initial, const ToolbarActionView* action_view); + void HideHoverCard(); + + bool ShouldShowImmediately(const ToolbarActionView* action_view) const; + + const views::View* GetTargetAnchorView() const; + + // Determines if `target_action_view` is still valid. Call this when entering + // ToolbarActionHoverCardController from an asynchronous callback. + bool TargetActionViewIsValid() const; + + // Animator events: + void OnFadeAnimationEnded(views::WidgetFadeAnimator* animator, + views::WidgetFadeAnimator::FadeType fade_type); + void OnSlideAnimationProgressed(views::BubbleSlideAnimator* animator, + double value); + void OnSlideAnimationComplete(views::BubbleSlideAnimator* animator); + + // views::ViewObserver: + void OnViewIsDeleting(views::View* observed_view) override; + void OnViewVisibilityChanged(views::View* observed_view, + views::View* starting_view) override; + + // Timestamp of the last time the hover card is hidden by the mouse leaving + // the tab strip. This is used for reshowing the hover card without delay if + // the mouse reenters within a given amount of time. + base::TimeTicks last_mouse_exit_timestamp_; + + raw_ptr<ToolbarActionView> target_action_view_ = nullptr; + const raw_ptr<ExtensionsToolbarContainer> extensions_container_; + raw_ptr<ToolbarActionHoverCardBubbleView> hover_card_ = nullptr; + + base::ScopedObservation<views::View, views::ViewObserver> + hover_card_observation_{this}; + base::ScopedObservation<views::View, views::ViewObserver> + target_action_view_observation_{this}; + std::unique_ptr<EventSniffer> event_sniffer_; + + // Used to animate the tab hover card's opacity when visible or not. + std::unique_ptr<views::WidgetFadeAnimator> fade_animator_; + // Fade animations interfere with browser tests so we disable them in tests. + static bool disable_animations_for_testing_; + + // Used to animate the tab hover card's movement between tabs. + std::unique_ptr<views::BubbleSlideAnimator> slide_animator_; + + base::CallbackListSubscription fade_complete_subscription_; + base::CallbackListSubscription slide_progressed_subscription_; + base::CallbackListSubscription slide_complete_subscription_; + + // Ensure that this timer is destroyed before anything else is cleaned up. + base::OneShotTimer delayed_show_timer_; + base::WeakPtrFactory<ToolbarActionHoverCardController> weak_ptr_factory_{ + this}; +}; + +#endif // CHROME_BROWSER_UI_VIEWS_TOOLBAR_TOOLBAR_ACTION_HOVER_CARD_CONTROLLER_H_
diff --git a/chrome/browser/ui/views/toolbar/toolbar_action_view.cc b/chrome/browser/ui/views/toolbar/toolbar_action_view.cc index 2885304c..a3189860 100644 --- a/chrome/browser/ui/views/toolbar/toolbar_action_view.cc +++ b/chrome/browser/ui/views/toolbar/toolbar_action_view.cc
@@ -8,6 +8,7 @@ #include "base/auto_reset.h" #include "base/bind.h" +#include "base/feature_list.h" #include "base/metrics/user_metrics.h" #include "base/metrics/user_metrics_action.h" #include "chrome/browser/chrome_notification_types.h" @@ -19,10 +20,12 @@ #include "chrome/browser/ui/views/chrome_layout_provider.h" #include "chrome/browser/ui/views/extensions/extension_context_menu_controller.h" #include "chrome/browser/ui/views/toolbar/toolbar_button.h" +#include "chrome/browser/ui/views/toolbar/toolbar_icon_container_view.h" #include "chrome/browser/ui/views/toolbar/toolbar_ink_drop_util.h" #include "components/sessions/content/session_tab_helper.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/notification_source.h" +#include "extensions/common/extension_features.h" #include "ui/accessibility/ax_node_data.h" #include "ui/base/metadata/metadata_impl_macros.h" #include "ui/base/resource/resource_bundle.h" @@ -126,6 +129,26 @@ return MenuButton::OnKeyPressed(event); } +// Linux enter/leave events are sometimes flaky, so we don't want to "miss" +// an enter event and fail to hover the button. This is effectively a no-op if +// the button is already showing the hover card (crbug.com/1326272). +void ToolbarActionView::OnMouseMoved(const ui::MouseEvent& event) { + MaybeUpdateHoverCardStatus(event); +} + +void ToolbarActionView::OnMouseEntered(const ui::MouseEvent& event) { + MaybeUpdateHoverCardStatus(event); +} + +void ToolbarActionView::MaybeUpdateHoverCardStatus( + const ui::MouseEvent& event) { + if (!GetWidget()->IsMouseEventsEnabled()) + return; + + view_controller_->UpdateHoverCard(this, + ToolbarActionHoverCardUpdateType::kHover); +} + content::WebContents* ToolbarActionView::GetCurrentWebContents() const { return delegate_->GetCurrentWebContents(); } @@ -144,7 +167,10 @@ SetImageModel(views::Button::STATE_NORMAL, ui::ImageModel::FromImageSkia(icon)); - SetTooltipText(view_controller_->GetTooltip(web_contents)); + if (!base::FeatureList::IsEnabled( + extensions_features::kExtensionsMenuAccessControl)) { + SetTooltipText(view_controller_->GetTooltip(web_contents)); + } Layout(); // We need to layout since we may have added an icon as a result. SchedulePaint(); @@ -163,6 +189,8 @@ } bool ToolbarActionView::OnMousePressed(const ui::MouseEvent& event) { + view_controller_->UpdateHoverCard(nullptr, + ToolbarActionHoverCardUpdateType::kEvent); if (event.IsOnlyLeftMouseButton()) { if (view_controller()->IsShowingPopup()) { // Left-clicking the button should always hide the popup. In most cases,
diff --git a/chrome/browser/ui/views/toolbar/toolbar_action_view.h b/chrome/browser/ui/views/toolbar/toolbar_action_view.h index 708ba85..0df01a5 100644 --- a/chrome/browser/ui/views/toolbar/toolbar_action_view.h +++ b/chrome/browser/ui/views/toolbar/toolbar_action_view.h
@@ -7,6 +7,7 @@ #include "base/callback.h" #include "base/memory/raw_ptr.h" +#include "chrome/browser/ui/views/toolbar/toolbar_action_hover_card_controller.h" #include "chrome/browser/ui/views/toolbar/toolbar_action_view_delegate_views.h" #include "ui/base/metadata/metadata_header_macros.h" #include "ui/views/context_menu_controller.h" @@ -54,12 +55,16 @@ ToolbarActionView& operator=(const ToolbarActionView&) = delete; ~ToolbarActionView() override; + void MaybeUpdateHoverCardStatus(const ui::MouseEvent& event); + // views::MenuButton: gfx::Rect GetAnchorBoundsInScreen() const override; std::unique_ptr<views::LabelButtonBorder> CreateDefaultBorder() const override; bool IsTriggerableEvent(const ui::Event& event) override; bool OnKeyPressed(const ui::KeyEvent& event) override; + void OnMouseMoved(const ui::MouseEvent& event) override; + void OnMouseEntered(const ui::MouseEvent& event) override; // ToolbarActionViewDelegateViews: content::WebContents* GetCurrentWebContents() const override; @@ -76,6 +81,8 @@ int GetDragOperationsForTest(const gfx::Point& point); private: + friend class ToolbarActionHoverCardBubbleViewUITest; + // views::MenuButton: gfx::Size CalculatePreferredSize() const override; bool OnMousePressed(const ui::MouseEvent& event) override; @@ -110,7 +117,6 @@ // doesn't hide on mouse press and immediately reshow on mouse release. bool suppress_next_release_ = false; - // This controller is responsible for showing the context menu for an // extension. std::unique_ptr<ExtensionContextMenuController> context_menu_controller_;
diff --git a/chrome/browser/ui/webui/settings/chromeos/change_picture_handler.cc b/chrome/browser/ui/webui/settings/chromeos/change_picture_handler.cc deleted file mode 100644 index 3837a29..0000000 --- a/chrome/browser/ui/webui/settings/chromeos/change_picture_handler.cc +++ /dev/null
@@ -1,417 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/ui/webui/settings/chromeos/change_picture_handler.h" - -#include <memory> -#include <utility> - -#include "base/base64.h" -#include "base/bind.h" -#include "base/callback_helpers.h" -#include "base/command_line.h" -#include "base/metrics/histogram_functions.h" -#include "base/metrics/histogram_macros.h" -#include "base/no_destructor.h" -#include "base/path_service.h" -#include "base/strings/string_util.h" -#include "base/strings/utf_string_conversions.h" -#include "base/task/thread_pool.h" -#include "base/values.h" -#include "chrome/browser/ash/accessibility/accessibility_manager.h" -#include "chrome/browser/ash/camera_presence_notifier.h" -#include "chrome/browser/ash/login/users/avatar/user_image_manager.h" -#include "chrome/browser/ash/login/users/chrome_user_manager.h" -#include "chrome/browser/ash/login/users/default_user_image/default_user_images.h" -#include "chrome/browser/ash/profiles/profile_helper.h" -#include "chrome/browser/ash/web_applications/personalization_app/personalization_app_manager.h" -#include "chrome/browser/ash/web_applications/personalization_app/personalization_app_manager_factory.h" -#include "chrome/browser/ui/browser_finder.h" -#include "chrome/browser/ui/browser_window.h" -#include "chrome/browser/ui/chrome_select_file_policy.h" -#include "chrome/common/chrome_paths.h" -#include "chrome/common/chrome_switches.h" -#include "chrome/common/url_constants.h" -#include "chrome/grit/browser_resources.h" -#include "chrome/grit/generated_resources.h" -#include "chromeos/ash/components/audio/sounds.h" -#include "components/user_manager/user.h" -#include "components/user_manager/user_image/user_image.h" -#include "components/user_manager/user_manager.h" -#include "content/public/browser/browser_context.h" -#include "content/public/browser/browser_thread.h" -#include "content/public/browser/web_contents.h" -#include "content/public/browser/web_ui.h" -#include "content/public/common/url_constants.h" -#include "net/base/data_url.h" -#include "services/audio/public/cpp/sounds/sounds_manager.h" -#include "third_party/skia/include/core/SkBitmap.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/base/webui/web_ui_util.h" -#include "ui/views/widget/widget.h" -#include "url/gurl.h" - -namespace chromeos { -namespace settings { -namespace { - -using ::ash::AccessibilityManager; -using ::ash::PlaySoundOption; -using ::content::BrowserThread; - -} // namespace - -ChangePictureHandler::ChangePictureHandler() - : previous_image_index_(user_manager::User::USER_IMAGE_INVALID), - camera_presence_notifier_( - base::BindRepeating(&ChangePictureHandler::SetCameraPresent, - base::Unretained(this))) { - ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); - audio::SoundsManager* manager = audio::SoundsManager::Get(); - manager->Initialize(static_cast<int>(Sound::kObjectDelete), - bundle.GetRawDataResource(IDR_SOUND_OBJECT_DELETE_WAV)); - manager->Initialize(static_cast<int>(Sound::kCameraSnap), - bundle.GetRawDataResource(IDR_SOUND_CAMERA_SNAP_WAV)); -} - -ChangePictureHandler::~ChangePictureHandler() { - if (IsJavascriptAllowed()) { - ::ash::personalization_app::PersonalizationAppManagerFactory:: - GetForBrowserContext(web_ui()->GetWebContents()->GetBrowserContext()) - ->MaybeStartHatsTimer( - ::ash::personalization_app::HatsSurveyType::kAvatar); - } -} - -void ChangePictureHandler::RegisterMessages() { - web_ui()->RegisterMessageCallback( - "chooseFile", base::BindRepeating(&ChangePictureHandler::HandleChooseFile, - base::Unretained(this))); - web_ui()->RegisterMessageCallback( - "photoTaken", base::BindRepeating(&ChangePictureHandler::HandlePhotoTaken, - base::Unretained(this))); - web_ui()->RegisterMessageCallback( - "discardPhoto", - base::BindRepeating(&ChangePictureHandler::HandleDiscardPhoto, - base::Unretained(this))); - web_ui()->RegisterMessageCallback( - "onChangePicturePageInitialized", - base::BindRepeating(&ChangePictureHandler::HandlePageInitialized, - base::Unretained(this))); - web_ui()->RegisterMessageCallback( - "selectImage", - base::BindRepeating(&ChangePictureHandler::HandleSelectImage, - base::Unretained(this))); - web_ui()->RegisterMessageCallback( - "requestSelectedImage", - base::BindRepeating(&ChangePictureHandler::HandleRequestSelectedImage, - base::Unretained(this))); -} - -void ChangePictureHandler::OnJavascriptAllowed() { - user_manager_observation_.Observe(user_manager::UserManager::Get()); - camera_presence_notifier_.Start(); -} - -void ChangePictureHandler::OnJavascriptDisallowed() { - DCHECK(user_manager_observation_.IsObservingSource( - user_manager::UserManager::Get())); - user_manager_observation_.Reset(); - - camera_presence_notifier_.Stop(); - - user_image_file_selector_.reset(); -} - -void ChangePictureHandler::SendDefaultImages() { - base::Value::Dict result; - result.Set("current_default_images", - default_user_image::GetCurrentImageSetAsListValue()); - FireWebUIListener("default-images-changed", result); -} - -void ChangePictureHandler::HandleChooseFile(const base::Value::List& args) { - DCHECK(args.empty()); - user_image_file_selector_ = - std::make_unique<ash::UserImageFileSelector>(web_ui()); - user_image_file_selector_->SelectFile( - base::BindOnce(&ChangePictureHandler::FileSelected, - weak_ptr_factory_.GetWeakPtr()), - base::BindOnce(&ChangePictureHandler::FileSelectionCanceled, - weak_ptr_factory_.GetWeakPtr())); -} - -void ChangePictureHandler::HandleDiscardPhoto(const base::Value::List& args) { - DCHECK(args.empty()); - AccessibilityManager::Get()->PlayEarcon( - Sound::kObjectDelete, PlaySoundOption::kOnlyIfSpokenFeedbackEnabled); -} - -void ChangePictureHandler::HandlePhotoTaken(const base::Value::List& args) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - AccessibilityManager::Get()->PlayEarcon( - Sound::kCameraSnap, PlaySoundOption::kOnlyIfSpokenFeedbackEnabled); - - if (args.size() != 1 || !args[0].is_string()) - NOTREACHED(); - const std::string& image_url = args[0].GetString(); - DCHECK(!image_url.empty()); - - std::string raw_data; - base::StringPiece url(image_url); - const char kDataUrlPrefix[] = "data:image/png;base64,"; - const size_t kDataUrlPrefixLength = std::size(kDataUrlPrefix) - 1; - if (!base::StartsWith(url, kDataUrlPrefix) || - !base::Base64Decode(url.substr(kDataUrlPrefixLength), &raw_data)) { - LOG(WARNING) << "Invalid image URL"; - return; - } - - // Use |raw_data| as image but first verify that it can be decoded. - user_photo_ = gfx::ImageSkia(); - std::vector<unsigned char> photo_data(raw_data.begin(), raw_data.end()); - user_photo_data_ = base::RefCountedBytes::TakeVector(&photo_data); - - ImageDecoder::Cancel(this); - ImageDecoder::Start(this, std::move(raw_data)); -} - -void ChangePictureHandler::HandlePageInitialized( - const base::Value::List& args) { - DCHECK(args.empty()); - - AllowJavascript(); - - SendDefaultImages(); - SendSelectedImage(); - UpdateProfileImage(); -} - -void ChangePictureHandler::SendSelectedImage() { - const user_manager::User* user = GetUser(); - DCHECK(user->GetAccountId().is_valid()); - - previous_image_index_ = user->image_index(); - switch (previous_image_index_) { - case user_manager::User::USER_IMAGE_EXTERNAL: { - // User has image from camera/file, record it and add to the image list. - previous_image_ = user->GetImage(); - previous_image_format_ = user->image_format(); - if (previous_image_format_ == user_manager::UserImage::FORMAT_PNG && - user->has_image_bytes()) { - previous_image_bytes_ = user->image_bytes(); - SendOldImage(webui::GetPngDataUrl(previous_image_bytes_->front(), - previous_image_bytes_->size())); - } else { - previous_image_bytes_ = nullptr; - DCHECK(previous_image_.IsThreadSafe()); - // Post a task because GetBitmapDataUrl does PNG encoding, which is - // slow for large images. - base::ThreadPool::PostTaskAndReplyWithResult( - FROM_HERE, {base::TaskPriority::USER_BLOCKING}, - base::BindOnce(&webui::GetBitmapDataUrl, *previous_image_.bitmap()), - base::BindOnce(&ChangePictureHandler::SendOldImage, - weak_ptr_factory_.GetWeakPtr())); - } - break; - } - case user_manager::User::USER_IMAGE_PROFILE: { - // User has their Profile image as the current image. - SendProfileImage(user->GetImage(), true); - break; - } - default: { - if (default_user_image::IsInCurrentImageSet(previous_image_index_)) { - // User has image from the current set of default images. - base::Value image_url( - default_user_image::GetDefaultImageUrl(previous_image_index_) - .spec()); - FireWebUIListener("selected-image-changed", image_url); - } else { - // User has a deprecated default image, send it for preview. - previous_image_ = user->GetImage(); - previous_image_bytes_ = nullptr; - previous_image_format_ = user_manager::UserImage::FORMAT_UNKNOWN; - - base::Value::Dict result; - result.Set("url", - default_user_image::GetDefaultImageUrl(previous_image_index_) - .spec()); - auto source_info = - default_user_image::GetDeprecatedDefaultImageSourceInfo( - previous_image_index_); - if (source_info.has_value()) { - result.Set("author", std::move(source_info.value().author)); - result.Set("website", source_info.value().website.spec()); - } - FireWebUIListener("preview-deprecated-image", result); - } - } - } -} - -void ChangePictureHandler::SendProfileImage(const gfx::ImageSkia& image, - bool should_select) { - base::Value data_url(webui::GetBitmapDataUrl(*image.bitmap())); - base::Value select(should_select); - FireWebUIListener("profile-image-changed", data_url, select); -} - -void ChangePictureHandler::UpdateProfileImage() { - auto* user_image_manager = - ChromeUserManager::Get()->GetUserImageManager(GetUser()->GetAccountId()); - // If we have a downloaded profile image and haven't sent it in - // |SendSelectedImage|, send it now (without selecting). - if (previous_image_index_ != user_manager::User::USER_IMAGE_PROFILE && - !user_image_manager->DownloadedProfileImage().isNull()) { - SendProfileImage(user_image_manager->DownloadedProfileImage(), false); - } - user_image_manager->DownloadProfileImage(); -} - -void ChangePictureHandler::SendOldImage(std::string&& image_url) { - FireWebUIListener("old-image-changed", base::Value(image_url)); -} - -void ChangePictureHandler::HandleSelectImage(const base::Value::List& args) { - if (args.size() != 2 || !args[0].is_string() || !args[1].is_string()) { - NOTREACHED(); - return; - } - const std::string& image_url = args[0].GetString(); - const std::string& image_type = args[1].GetString(); - // |image_url| may be empty unless |image_type| is "default". - DCHECK(!image_type.empty()); - - auto* user_image_manager = - ChromeUserManager::Get()->GetUserImageManager(GetUser()->GetAccountId()); - bool waiting_for_camera_photo = false; - - // Track the index of previous selected message to be compared with the index - // of the new image. - int previous_image_index = GetUser()->image_index(); - - if (image_type == "old") { - // Previous image (from camera or manually uploaded) re-selected. - DCHECK(!previous_image_.isNull()); - std::unique_ptr<user_manager::UserImage> user_image; - if (previous_image_format_ == user_manager::UserImage::FORMAT_PNG && - previous_image_bytes_) { - user_image = std::make_unique<user_manager::UserImage>( - previous_image_, previous_image_bytes_, previous_image_format_); - user_image->MarkAsSafe(); - } else { - user_image = user_manager::UserImage::CreateAndEncode( - previous_image_, user_manager::UserImage::FORMAT_JPEG); - } - user_image_manager->SaveUserImage(std::move(user_image)); - - VLOG(1) << "Selected old user image"; - } else if (image_type == "default") { - int image_index = user_manager::User::USER_IMAGE_INVALID; - if (default_user_image::IsDefaultImageUrl(image_url, &image_index)) { - // One of the default user images. - user_image_manager->SaveUserDefaultImageIndex(image_index); - - VLOG(1) << "Selected default user image: " << image_index; - } else { - LOG(WARNING) << "Invalid image_url for default image type: " << image_url; - } - } else if (image_type == "profile") { - // Profile image selected. Could be previous (old) user image. - user_image_manager->SaveUserImageFromProfileImage(); - } else { - NOTREACHED() << "Unexpected image type: " << image_type; - } - - int image_index = GetUser()->image_index(); - // `previous_image_index` is used instead of `previous_image_index_` as the - // latter has the same value of `image_index` after new image is selected. - if (previous_image_index != image_index) { - ash::UserImageManager::RecordUserImageChanged( - ash::UserImageManager::ImageIndexToHistogramIndex(image_index)); - } - - // Ignore the result of the previous decoding if it's no longer needed. - if (!waiting_for_camera_photo) - ImageDecoder::Cancel(this); -} - -void ChangePictureHandler::HandleRequestSelectedImage( - const base::Value::List& args) { - SendSelectedImage(); -} - -void ChangePictureHandler::FileSelected(const base::FilePath& path) { - auto* user_image_manager = - ChromeUserManager::Get()->GetUserImageManager(GetUser()->GetAccountId()); - - // Log an impression if image is selected from a file. - ash::UserImageManager::RecordUserImageChanged( - default_user_image::kHistogramImageExternal); - - user_image_manager->SaveUserImageFromFile(path); - VLOG(1) << "Selected image from file"; -} - -void ChangePictureHandler::FileSelectionCanceled() { - SendSelectedImage(); -} - -void ChangePictureHandler::SetImageFromCamera( - const gfx::ImageSkia& photo, - base::RefCountedBytes* photo_bytes) { - std::unique_ptr<user_manager::UserImage> user_image = - std::make_unique<user_manager::UserImage>( - photo, photo_bytes, user_manager::UserImage::FORMAT_PNG); - user_image->MarkAsSafe(); - ChromeUserManager::Get() - ->GetUserImageManager(GetUser()->GetAccountId()) - ->SaveUserImage(std::move(user_image)); - - // Log an impression if image is taken from photo. - ash::UserImageManager::RecordUserImageChanged( - default_user_image::kHistogramImageFromCamera); - VLOG(1) << "Selected camera photo"; -} - -void ChangePictureHandler::SetCameraPresent(bool present) { - FireWebUIListener("camera-presence-changed", base::Value(present)); -} - -void ChangePictureHandler::OnUserImageChanged(const user_manager::User& user) { - // Not initialized yet. - if (previous_image_index_ == user_manager::User::USER_IMAGE_INVALID) - return; - SendSelectedImage(); -} - -void ChangePictureHandler::OnUserProfileImageUpdated( - const user_manager::User& user, - const gfx::ImageSkia& profile_image) { - // User profile image has been updated. - SendProfileImage(profile_image, false); -} - -void ChangePictureHandler::OnImageDecoded(const SkBitmap& decoded_image) { - user_photo_ = gfx::ImageSkia::CreateFrom1xBitmap(decoded_image); - SetImageFromCamera(user_photo_, user_photo_data_.get()); -} - -void ChangePictureHandler::OnDecodeImageFailed() { - NOTREACHED() << "Failed to decode PNG image from WebUI"; -} - -const user_manager::User* ChangePictureHandler::GetUser() { - Profile* profile = Profile::FromWebUI(web_ui()); - const user_manager::User* user = - ProfileHelper::Get()->GetUserByProfile(profile); - if (!user) - return user_manager::UserManager::Get()->GetActiveUser(); - return user; -} - -} // namespace settings -} // namespace chromeos
diff --git a/chrome/browser/ui/webui/settings/chromeos/change_picture_handler.h b/chrome/browser/ui/webui/settings/chromeos/change_picture_handler.h deleted file mode 100644 index 275a877..0000000 --- a/chrome/browser/ui/webui/settings/chromeos/change_picture_handler.h +++ /dev/null
@@ -1,136 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_CHANGE_PICTURE_HANDLER_H_ -#define CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_CHANGE_PICTURE_HANDLER_H_ - -#include "base/memory/weak_ptr.h" -#include "base/scoped_observation.h" -#include "chrome/browser/ash/camera_presence_notifier.h" -#include "chrome/browser/ash/login/users/avatar/user_image_file_selector.h" -#include "chrome/browser/image_decoder/image_decoder.h" -#include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h" -#include "components/user_manager/user_manager.h" -#include "ui/gfx/image/image_skia.h" - -namespace user_manager { -class User; -} - -namespace chromeos { - -namespace settings { - -// ChromeOS user image settings page UI handler. -class ChangePictureHandler : public ::settings::SettingsPageUIHandler, - public user_manager::UserManager::Observer, - public ImageDecoder::ImageRequest { - public: - ChangePictureHandler(); - - ChangePictureHandler(const ChangePictureHandler&) = delete; - ChangePictureHandler& operator=(const ChangePictureHandler&) = delete; - - ~ChangePictureHandler() override; - - // WebUIMessageHandler implementation. - void RegisterMessages() override; - void OnJavascriptAllowed() override; - void OnJavascriptDisallowed() override; - - private: - friend class ChangePictureHandlerTest; - - // Sends list of available default images to the page. - void SendDefaultImages(); - - // Sends current selection to the page. - void SendSelectedImage(); - - // Sends the profile image to the page. If |should_select| is true then - // the profile image element is selected. - void SendProfileImage(const gfx::ImageSkia& image, bool should_select); - - // Starts profile image update and shows the last downloaded profile image, - // if any, on the page. Shouldn't be called before |SendProfileImage|. - void UpdateProfileImage(); - - // Sends the previous user image from camera or file to the page. - void SendOldImage(std::string&& image_url); - - // Updates UI with camera presence state. - void SetCameraPresent(bool present); - - // Opens a file selection dialog to choose user image from file. - void HandleChooseFile(const base::Value::List& args); - - // Handles photo taken with WebRTC UI. - void HandlePhotoTaken(const base::Value::List& args); - - // Handles 'discard-photo' button click. - void HandleDiscardPhoto(const base::Value::List& args); - - // Gets the list of available user images and sends it to the page. - void HandleGetAvailableImages(const base::Value::List& args); - - // Handles page initialized event. - void HandlePageInitialized(const base::Value::List& args); - - // Selects one of the available images as user's. - void HandleSelectImage(const base::Value::List& args); - - // Requests the currently selected image. - void HandleRequestSelectedImage(const base::Value::List& args); - - void FileSelected(const base::FilePath& path); - - void FileSelectionCanceled(); - - // user_manager::UserManager::Observer implementation. - void OnUserImageChanged(const user_manager::User& user) override; - void OnUserProfileImageUpdated(const user_manager::User& user, - const gfx::ImageSkia& profile_image) override; - - // Sets user image to photo taken from camera. - void SetImageFromCamera(const gfx::ImageSkia& photo, - base::RefCountedBytes* image_bytes); - - // Overriden from ImageDecoder::ImageRequest: - void OnImageDecoded(const SkBitmap& decoded_image) override; - void OnDecodeImageFailed() override; - - // Returns user related to current WebUI. If this user doesn't exist, - // returns active user. - const user_manager::User* GetUser(); - - // Previous user image from camera/file and its data URL. - gfx::ImageSkia previous_image_; - scoped_refptr<base::RefCountedBytes> previous_image_bytes_; - user_manager::UserImage::ImageFormat previous_image_format_ = - user_manager::UserImage::FORMAT_UNKNOWN; - - // Index of the previous user image. - int previous_image_index_; - - // Last user photo, if taken. - gfx::ImageSkia user_photo_; - - // Data for |user_photo_|. - scoped_refptr<base::RefCountedBytes> user_photo_data_; - - base::ScopedObservation<user_manager::UserManager, - user_manager::UserManager::Observer> - user_manager_observation_{this}; - - ash::CameraPresenceNotifier camera_presence_notifier_; - - std::unique_ptr<ash::UserImageFileSelector> user_image_file_selector_; - - base::WeakPtrFactory<ChangePictureHandler> weak_ptr_factory_{this}; -}; - -} // namespace settings -} // namespace chromeos - -#endif // CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_CHANGE_PICTURE_HANDLER_H_
diff --git a/chrome/browser/ui/webui/settings/chromeos/change_picture_handler_unittest.cc b/chrome/browser/ui/webui/settings/chromeos/change_picture_handler_unittest.cc deleted file mode 100644 index bc0832c..0000000 --- a/chrome/browser/ui/webui/settings/chromeos/change_picture_handler_unittest.cc +++ /dev/null
@@ -1,301 +0,0 @@ -// Copyright 2021 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/ui/webui/settings/chromeos/change_picture_handler.h" - -#include <memory> - -#include "base/files/file_path.h" -#include "base/test/metrics/histogram_tester.h" -#include "base/values.h" -#include "chrome/browser/ash/login/users/avatar/user_image_manager.h" -#include "chrome/browser/ash/login/users/default_user_image/default_user_images.h" -#include "chrome/browser/ash/login/users/fake_chrome_user_manager.h" -#include "chrome/browser/ash/profiles/profile_helper.h" -#include "chrome/browser/ash/web_applications/personalization_app/mock_personalization_app_manager.h" -#include "chrome/browser/ash/web_applications/personalization_app/personalization_app_manager.h" -#include "chrome/browser/ash/web_applications/personalization_app/personalization_app_manager_factory.h" -#include "chrome/test/base/testing_browser_process.h" -#include "chrome/test/base/testing_profile_manager.h" -#include "components/user_manager/scoped_user_manager.h" -#include "components/user_manager/user_manager.h" -#include "content/public/browser/audio_service.h" -#include "content/public/browser/browser_context.h" -#include "content/public/browser/web_contents.h" -#include "content/public/test/browser_task_environment.h" -#include "content/public/test/test_web_ui.h" -#include "services/audio/public/cpp/sounds/sounds_manager.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "third_party/skia/include/core/SkBitmap.h" - -namespace chromeos { -namespace settings { - -namespace { - -std::unique_ptr<KeyedService> MakeMockPersonalizationAppManager( - content::BrowserContext* context) { - return std::make_unique<::testing::NiceMock< - ::ash::personalization_app::MockPersonalizationAppManager>>(); -} - -} // namespace - -class ChangePictureHandlerTest : public testing::Test { - public: - ChangePictureHandlerTest() - : profile_manager_(TestingBrowserProcess::GetGlobal()), - user_manager_enabler_(std::make_unique<ash::FakeChromeUserManager>()) {} - ~ChangePictureHandlerTest() override = default; - - void SetUp() override { - audio::SoundsManager::Create(content::GetAudioServiceStreamFactoryBinder()); - - ASSERT_TRUE(profile_manager_.SetUp()); - account_id_ = AccountId::FromUserEmail("lala@example.com"); - - user_manager::User* user = GetFakeUserManager()->AddUser(account_id_); - - testing_profile_ = profile_manager_.CreateTestingProfile( - account_id_.GetUserEmail(), - {{ash::personalization_app::PersonalizationAppManagerFactory:: - GetInstance(), - base::BindRepeating(&MakeMockPersonalizationAppManager)}}); - - ProfileHelper::Get()->SetUserToProfileMappingForTesting(user, - testing_profile_); - - // Note that user profiles are created after user login in reality. - GetFakeUserManager()->LoginUser(account_id_); - GetFakeUserManager()->UserLoggedIn(account_id_, user->username_hash(), - /*browser_restart=*/false, - /*is_child=*/false); - - web_ui_ = std::make_unique<content::TestWebUI>(); - web_contents_ = content::WebContents::Create( - content::WebContents::CreateParams(testing_profile_)); - web_ui_->set_web_contents(web_contents_.get()); - - handler_ = std::make_unique<ChangePictureHandler>(); - handler_->set_web_ui(web_ui_.get()); - handler_->AllowJavascript(); - handler_->RegisterMessages(); - - request_ = handler_.get(); - } - - void TearDown() override { - request_ = nullptr; - handler_.reset(); - web_contents_.reset(); - web_ui_.reset(); - GetFakeUserManager()->Shutdown(); - testing_profile_ = nullptr; - profile_manager_.DeleteAllTestingProfiles(); - audio::SoundsManager::Shutdown(); - } - - content::TestWebUI* web_ui() { return web_ui_.get(); } - - ash::FakeChromeUserManager* GetFakeUserManager() const { - return static_cast<ash::FakeChromeUserManager*>( - user_manager::UserManager::Get()); - } - - const base::HistogramTester& histogram_tester() const { - return histogram_tester_; - } - - void SelectNewDefaultImage(int default_image_index) { - base::Value::List args; - args.Append( - default_user_image::GetDefaultImageUrl(default_image_index).spec()); - args.Append("default"); - - web_ui_->HandleReceivedMessage("selectImage", args); - } - - void SelectProfileImage() { - base::Value::List args; - args.Append("empty url"); - args.Append("profile"); - - web_ui_->HandleReceivedMessage("selectImage", args); - } - - void SelectImageFromFile(const base::FilePath& path) { - handler_->FileSelected(path); - } - - void CancelFileSelection() { handler_->FileSelectionCanceled(); } - - void OnCameraImageDecoded() { - SkBitmap bitmap; - bitmap.allocN32Pixels(1, 1); - - std::vector<unsigned char> data; - data.push_back('a'); - handler_->user_photo_data_ = base::RefCountedBytes::TakeVector(&data); - - request_->OnImageDecoded(bitmap); - } - - ash::UserImageManager* GetUserImageManager() { - return GetFakeUserManager()->GetUserImageManager(account_id_); - } - - void ResetHandler() { handler_.reset(); } - - ChangePictureHandler* handler() { return handler_.get(); } - - ::testing::NiceMock< - ::ash::personalization_app::MockPersonalizationAppManager>* - MockPersonalizationAppManager() { - return static_cast<::testing::NiceMock< - ::ash::personalization_app::MockPersonalizationAppManager>*>( - ::ash::personalization_app::PersonalizationAppManagerFactory:: - GetForBrowserContext( - web_ui()->GetWebContents()->GetBrowserContext())); - } - - private: - content::BrowserTaskEnvironment task_environment_{ - content::BrowserTaskEnvironment::REAL_IO_THREAD}; - std::unique_ptr<content::TestWebUI> web_ui_; - std::unique_ptr<content::WebContents> web_contents_; - std::unique_ptr<ChangePictureHandler> handler_; - base::HistogramTester histogram_tester_; - AccountId account_id_; - TestingProfile* testing_profile_; - TestingProfileManager profile_manager_; - user_manager::ScopedUserManager user_manager_enabler_; - ImageDecoder::ImageRequest* request_; -}; - -TEST_F(ChangePictureHandlerTest, - ShouldSendUmaMetricWhenNewDefaultImageIsSelected) { - const int default_image_index = - default_user_image::GetRandomDefaultImageIndex(); - SelectNewDefaultImage(default_image_index); - - auto* user_image_manager = GetUserImageManager(); - - histogram_tester().ExpectBucketCount( - ash::UserImageManager::kUserImageChangedHistogramName, - user_image_manager->ImageIndexToHistogramIndex(default_image_index), 1); -} - -TEST_F(ChangePictureHandlerTest, - ShouldNotSendUmaMetricWhenDefaultImageIsReselected) { - const int default_image_index = - default_user_image::GetRandomDefaultImageIndex(); - auto* user_image_manager = GetUserImageManager(); - - SelectNewDefaultImage(default_image_index); - histogram_tester().ExpectBucketCount( - ash::UserImageManager::kUserImageChangedHistogramName, - user_image_manager->ImageIndexToHistogramIndex(default_image_index), 1); - - // Selecting the same default image should not log another impression. - SelectNewDefaultImage(default_image_index); - histogram_tester().ExpectBucketCount( - ash::UserImageManager::kUserImageChangedHistogramName, - user_image_manager->ImageIndexToHistogramIndex(default_image_index), 1); -} - -TEST_F(ChangePictureHandlerTest, ShoulSendUmaMetricWhenProfileImageIsSelected) { - const int default_image_index = - default_user_image::GetRandomDefaultImageIndex(); - auto* user_image_manager = GetUserImageManager(); - - // User selects a new default image. - SelectNewDefaultImage(default_image_index); - histogram_tester().ExpectBucketCount( - ash::UserImageManager::kUserImageChangedHistogramName, - user_image_manager->ImageIndexToHistogramIndex(default_image_index), 1); - - // User selects the profile image. - SelectProfileImage(); - histogram_tester().ExpectBucketCount( - ash::UserImageManager::kUserImageChangedHistogramName, - user_image_manager->ImageIndexToHistogramIndex( - user_manager::User::USER_IMAGE_PROFILE), - 1); -} - -TEST_F(ChangePictureHandlerTest, - ShoulNotSendUmaMetricWhenProfileImageIsReselected) { - auto* user_image_manager = GetUserImageManager(); - // User has profile image by default, thus reselecting profile does not log an - // impression - SelectProfileImage(); - histogram_tester().ExpectBucketCount( - ash::UserImageManager::kUserImageChangedHistogramName, - user_image_manager->ImageIndexToHistogramIndex( - user_manager::User::USER_IMAGE_PROFILE), - 0); -} - -TEST_F(ChangePictureHandlerTest, - ShouldSendUmaMetricWhenImageIsSelectedFromFile) { - auto* user_image_manager = GetUserImageManager(); - - const base::FilePath base_file_path("/this/is/a/test/directory/Base Name"); - const base::FilePath dir_path = base_file_path.AppendASCII("dir1"); - const base::FilePath file_path = dir_path.AppendASCII("file1.txt"); - SelectImageFromFile(file_path); - - histogram_tester().ExpectBucketCount( - ash::UserImageManager::kUserImageChangedHistogramName, - user_image_manager->ImageIndexToHistogramIndex( - user_manager::User::USER_IMAGE_EXTERNAL), - 1); -} - -TEST_F(ChangePictureHandlerTest, ShouldSendUmaMetricWhenCameraImageIsDecoded) { - // Camera image is decoded - OnCameraImageDecoded(); - histogram_tester().ExpectBucketCount( - ash::UserImageManager::kUserImageChangedHistogramName, - default_user_image::kHistogramImageFromCamera, 1); -} - -TEST_F(ChangePictureHandlerTest, - ShouldSelectTheCurrentUserImageIfFileSelectionIsCanceled) { - // keep the current call size so we can check what happened after our test - // method call. - auto number_of_calls_before_cancel = web_ui()->call_data().size(); - CancelFileSelection(); - // reset back to previous profile image. - EXPECT_EQ(web_ui() - ->call_data() - .at(number_of_calls_before_cancel) - ->arg1() - ->GetString(), - "profile-image-changed"); -} - -TEST_F(ChangePictureHandlerTest, CallsMaybeStartHatsTimerOnDestruction) { - EXPECT_CALL( - *MockPersonalizationAppManager(), - MaybeStartHatsTimer(::ash::personalization_app::HatsSurveyType::kAvatar)) - .Times(1); - - ResetHandler(); -} - -TEST_F(ChangePictureHandlerTest, - DoesNotCallMaybeStartHatsTimerOnDestructionIfJavascriptDisallowed) { - handler()->DisallowJavascript(); - - EXPECT_CALL( - *MockPersonalizationAppManager(), - MaybeStartHatsTimer(::ash::personalization_app::HatsSurveyType::kAvatar)) - .Times(0); - - ResetHandler(); -} - -} // namespace settings -} // namespace chromeos
diff --git a/chrome/browser/ui/webui/settings/chromeos/constants/routes.mojom b/chrome/browser/ui/webui/settings/chromeos/constants/routes.mojom index 3fe3d92..7e2c220 100644 --- a/chrome/browser/ui/webui/settings/chromeos/constants/routes.mojom +++ b/chrome/browser/ui/webui/settings/chromeos/constants/routes.mojom
@@ -79,7 +79,7 @@ kAudio = 408, // Personalization section. - kChangePicture = 500, + // 500 was used for kChangePicture. Do not reuse. // 501 was used for kAmbientMode. Do not reuse. // Note: Value 502 was for deprecated kAmbientModePhotos. Do not reuse. // 503 was used for kAmbientModeGooglePhotosAlbum. Do not reuse. @@ -205,7 +205,6 @@ // Personalization section. const string kPersonalizationSectionPath = "personalization"; -const string kChangePictureSubpagePath = "changePicture"; // Search and Assistant section. const string kSearchAndAssistantSectionPath = "osSearch";
diff --git a/chrome/browser/ui/webui/settings/chromeos/constants/routes_util.cc b/chrome/browser/ui/webui/settings/chromeos/constants/routes_util.cc index 26201d1..4f61db7a 100644 --- a/chrome/browser/ui/webui/settings/chromeos/constants/routes_util.cc +++ b/chrome/browser/ui/webui/settings/chromeos/constants/routes_util.cc
@@ -60,7 +60,6 @@ // Personalization section. chromeos::settings::mojom::kPersonalizationSectionPath, - chromeos::settings::mojom::kChangePictureSubpagePath, // Search and Assistant section. chromeos::settings::mojom::kSearchAndAssistantSectionPath,
diff --git a/chrome/browser/ui/webui/settings/chromeos/constants/setting.mojom b/chrome/browser/ui/webui/settings/chromeos/constants/setting.mojom index e5b6a1c..756a56b 100644 --- a/chrome/browser/ui/webui/settings/chromeos/constants/setting.mojom +++ b/chrome/browser/ui/webui/settings/chromeos/constants/setting.mojom
@@ -144,7 +144,7 @@ kOpenWallpaper = 500, // 501 was used for kAmbientModeOnOff. Do not reuse. // 502 was used for kAmbientModeSource. Do not reuse. - kChangeDeviceAccountImage = 503, + // 503 was used for kChangeDeviceAccountImage. Do not reuse. // Note: Values 504, 505, and 506 were for deprecated // kAmbientModeUpdatePhotosContainers, kDarkModeOnOff and // kDarkModeThemed respectively.
diff --git a/chrome/browser/ui/webui/settings/chromeos/personalization_section.cc b/chrome/browser/ui/webui/settings/chromeos/personalization_section.cc index d4669efa..91bf454 100644 --- a/chrome/browser/ui/webui/settings/chromeos/personalization_section.cc +++ b/chrome/browser/ui/webui/settings/chromeos/personalization_section.cc
@@ -8,7 +8,6 @@ #include "base/no_destructor.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/webui/settings/ash/search/search_tag_registry.h" -#include "chrome/browser/ui/webui/settings/chromeos/change_picture_handler.h" #include "chrome/browser/ui/webui/settings/chromeos/os_settings_features_util.h" #include "chrome/browser/ui/webui/settings/chromeos/personalization_hub_handler.h" #include "chrome/common/chrome_features.h" @@ -40,17 +39,6 @@ {.setting = mojom::Setting::kOpenWallpaper}, {IDS_OS_SETTINGS_TAG_CHANGE_WALLPAPER_ALT1, IDS_OS_SETTINGS_TAG_CHANGE_WALLPAPER_ALT2, SearchConcept::kAltTagEnd}}, - {IDS_OS_SETTINGS_TAG_CHANGE_DEVICE_ACCOUNT_IMAGE, - mojom::kChangePictureSubpagePath, - mojom::SearchResultIcon::kAvatar, - mojom::SearchResultDefaultRank::kMedium, - mojom::SearchResultType::kSetting, - {.setting = mojom::Setting::kChangeDeviceAccountImage}, - {IDS_OS_SETTINGS_TAG_CHANGE_DEVICE_ACCOUNT_IMAGE_ALT1, - IDS_OS_SETTINGS_TAG_CHANGE_DEVICE_ACCOUNT_IMAGE_ALT2, - IDS_OS_SETTINGS_TAG_CHANGE_DEVICE_ACCOUNT_IMAGE_ALT3, - IDS_OS_SETTINGS_TAG_CHANGE_DEVICE_ACCOUNT_IMAGE_ALT4, - SearchConcept::kAltTagEnd}}, }); return *tags; } @@ -115,8 +103,6 @@ } void PersonalizationSection::AddHandlers(content::WebUI* web_ui) { - web_ui->AddMessageHandler( - std::make_unique<chromeos::settings::ChangePictureHandler>()); if (ash::features::IsPersonalizationHubEnabled()) { web_ui->AddMessageHandler( std::make_unique<chromeos::settings::PersonalizationHubHandler>()); @@ -148,14 +134,6 @@ void PersonalizationSection::RegisterHierarchy( HierarchyGenerator* generator) const { generator->RegisterTopLevelSetting(mojom::Setting::kOpenWallpaper); - - // Change picture. - generator->RegisterTopLevelSubpage( - IDS_OS_SETTINGS_CHANGE_PICTURE_TITLE, mojom::Subpage::kChangePicture, - mojom::SearchResultIcon::kAvatar, mojom::SearchResultDefaultRank::kMedium, - mojom::kChangePictureSubpagePath); - generator->RegisterNestedSetting(mojom::Setting::kChangeDeviceAccountImage, - mojom::Subpage::kChangePicture); } } // namespace settings
diff --git a/chrome/browser/ui/webui/signin/dice_web_signin_intercept_handler.cc b/chrome/browser/ui/webui/signin/dice_web_signin_intercept_handler.cc index 5c7e1c0..c488ae68 100644 --- a/chrome/browser/ui/webui/signin/dice_web_signin_intercept_handler.cc +++ b/chrome/browser/ui/webui/signin/dice_web_signin_intercept_handler.cc
@@ -166,46 +166,44 @@ ResolveJavascriptCallback(callback_id, GetInterceptionParametersValue()); } -base::Value DiceWebSigninInterceptHandler::GetAccountInfoValue( +base::Value::Dict DiceWebSigninInterceptHandler::GetAccountInfoValue( const AccountInfo& info) { std::string picture_url_to_load = info.account_image.IsEmpty() ? profiles::GetPlaceholderAvatarIconUrl() : webui::GetBitmapDataUrl(info.account_image.AsBitmap()); - base::Value account_info_value(base::Value::Type::DICTIONARY); - account_info_value.SetBoolKey("isManaged", IsManaged(info)); - account_info_value.SetStringKey("pictureUrl", picture_url_to_load); + base::Value::Dict account_info_value; + account_info_value.Set("isManaged", IsManaged(info)); + account_info_value.Set("pictureUrl", picture_url_to_load); return account_info_value; } -base::Value DiceWebSigninInterceptHandler::GetInterceptionParametersValue() { - base::Value parameters(base::Value::Type::DICTIONARY); - parameters.SetStringKey("headerText", GetHeaderText()); - parameters.SetStringKey("bodyTitle", GetBodyTitle()); - parameters.SetStringKey("bodyText", GetBodyText()); - parameters.SetStringKey("confirmButtonLabel", GetConfirmButtonLabel()); - parameters.SetStringKey("cancelButtonLabel", GetCancelButtonLabel()); - parameters.SetStringKey("managedDisclaimerText", GetManagedDisclaimerText()); - parameters.SetBoolKey("showGuestOption", - bubble_parameters_.show_guest_option); - parameters.SetKey("interceptedAccount", - GetAccountInfoValue(intercepted_account())); - parameters.SetKey("primaryAccount", GetAccountInfoValue(primary_account())); - parameters.SetStringKey("interceptedProfileColor", - color_utils::SkColorToRgbaString( - bubble_parameters_.profile_highlight_color)); - parameters.SetStringKey( - "primaryProfileColor", - color_utils::SkColorToRgbaString( - GetProfileHighlightColor(Profile::FromWebUI(web_ui())))); - parameters.SetBoolKey("useV2Design", GetShouldUseV2Design()); - parameters.SetBoolKey("showManagedDisclaimer", - bubble_parameters_.show_managed_disclaimer); +base::Value::Dict +DiceWebSigninInterceptHandler::GetInterceptionParametersValue() { + base::Value::Dict parameters; + parameters.Set("headerText", GetHeaderText()); + parameters.Set("bodyTitle", GetBodyTitle()); + parameters.Set("bodyText", GetBodyText()); + parameters.Set("confirmButtonLabel", GetConfirmButtonLabel()); + parameters.Set("cancelButtonLabel", GetCancelButtonLabel()); + parameters.Set("managedDisclaimerText", GetManagedDisclaimerText()); + parameters.Set("showGuestOption", bubble_parameters_.show_guest_option); + parameters.Set("interceptedAccount", + GetAccountInfoValue(intercepted_account())); + parameters.Set("primaryAccount", GetAccountInfoValue(primary_account())); + parameters.Set("interceptedProfileColor", + color_utils::SkColorToRgbaString( + bubble_parameters_.profile_highlight_color)); + parameters.Set("primaryProfileColor", + color_utils::SkColorToRgbaString( + GetProfileHighlightColor(Profile::FromWebUI(web_ui())))); + parameters.Set("useV2Design", GetShouldUseV2Design()); + parameters.Set("showManagedDisclaimer", + bubble_parameters_.show_managed_disclaimer); - parameters.SetStringKey( - "headerTextColor", - color_utils::SkColorToRgbaString(GetProfileForegroundTextColor( - bubble_parameters_.profile_highlight_color))); + parameters.Set("headerTextColor", + color_utils::SkColorToRgbaString(GetProfileForegroundTextColor( + bubble_parameters_.profile_highlight_color))); return parameters; }
diff --git a/chrome/browser/ui/webui/signin/dice_web_signin_intercept_handler.h b/chrome/browser/ui/webui/signin/dice_web_signin_intercept_handler.h index f9526a3..e6c807b 100644 --- a/chrome/browser/ui/webui/signin/dice_web_signin_intercept_handler.h +++ b/chrome/browser/ui/webui/signin/dice_web_signin_intercept_handler.h
@@ -52,8 +52,8 @@ void HandlePageLoaded(const base::Value::List& args); // Gets the values sent to javascript. - base::Value GetAccountInfoValue(const AccountInfo& info); - base::Value GetInterceptionParametersValue(); + base::Value::Dict GetAccountInfoValue(const AccountInfo& info); + base::Value::Dict GetInterceptionParametersValue(); // The dialog string is different when the device is managed. This function // returns whether the version for managed devices should be used.
diff --git a/chrome/browser/ui/webui/signin/dice_web_signin_intercept_handler_unittest.cc b/chrome/browser/ui/webui/signin/dice_web_signin_intercept_handler_unittest.cc index 682ac73..fbd2959 100644 --- a/chrome/browser/ui/webui/signin/dice_web_signin_intercept_handler_unittest.cc +++ b/chrome/browser/ui/webui/signin/dice_web_signin_intercept_handler_unittest.cc
@@ -204,7 +204,7 @@ DiceWebSigninInterceptHandlerTest() : profile_manager_(TestingBrowserProcess::GetGlobal()) {} - base::Value GetInterceptionParameters() { + base::Value::Dict GetInterceptionParameters() { Profile* profile = profile_manager_.CreateTestingProfile("Primary Profile"); // Resetting the platform authority to NONE, as not all platforms have the // same value in browser tests. See https://crbug.com/1324377. @@ -230,17 +230,15 @@ void SetUp() override { ASSERT_TRUE(profile_manager_.SetUp()); } protected: - void ExpectStringsMatch(const base::Value& parameters, + void ExpectStringsMatch(const base::Value::Dict& parameters, const BubbleStrings& expected_strings) { - EXPECT_EQ(*parameters.FindStringKey("headerText"), + EXPECT_EQ(*parameters.FindString("headerText"), expected_strings.header_text); - EXPECT_EQ(*parameters.FindStringKey("bodyTitle"), - expected_strings.body_title); - EXPECT_EQ(*parameters.FindStringKey("bodyText"), - expected_strings.body_text); - EXPECT_EQ(*parameters.FindStringKey("confirmButtonLabel"), + EXPECT_EQ(*parameters.FindString("bodyTitle"), expected_strings.body_title); + EXPECT_EQ(*parameters.FindString("bodyText"), expected_strings.body_text); + EXPECT_EQ(*parameters.FindString("confirmButtonLabel"), expected_strings.confirm_button_label); - EXPECT_EQ(*parameters.FindStringKey("cancelButtonLabel"), + EXPECT_EQ(*parameters.FindString("cancelButtonLabel"), expected_strings.cancel_button_label); } @@ -252,17 +250,17 @@ }; TEST_P(DiceWebSigninInterceptHandlerTest, CheckStrings) { - base::Value parameters = GetInterceptionParameters(); + base::Value::Dict parameters = GetInterceptionParameters(); - EXPECT_FALSE(*parameters.FindBoolKey("useV2Design")); + EXPECT_FALSE(*parameters.FindBool("useV2Design")); ExpectStringsMatch(parameters, GetParam().expected_strings.Run()); } TEST_P(DiceWebSigninInterceptHandlerTest, CheckStrings_V2) { base::test::ScopedFeatureList feature_list{kSigninInterceptBubbleV2}; - base::Value parameters = GetInterceptionParameters(); + base::Value::Dict parameters = GetInterceptionParameters(); - EXPECT_TRUE(*parameters.FindBoolKey("useV2Design")); + EXPECT_TRUE(*parameters.FindBool("useV2Design")); ExpectStringsMatch(parameters, GetParam().expected_strings_v2.Run()); }
diff --git a/chrome/browser/ui/webui/signin/enterprise_profile_welcome_handler.cc b/chrome/browser/ui/webui/signin/enterprise_profile_welcome_handler.cc index 6bc3be0..8dcdf55 100644 --- a/chrome/browser/ui/webui/signin/enterprise_profile_welcome_handler.cc +++ b/chrome/browser/ui/webui/signin/enterprise_profile_welcome_handler.cc
@@ -256,11 +256,11 @@ FireWebUIListener("on-profile-info-changed", GetProfileInfoValue()); } -base::Value EnterpriseProfileWelcomeHandler::GetProfileInfoValue() { - base::Value dict(base::Value::Type::DICTIONARY); - dict.SetStringKey("backgroundColor", color_utils::SkColorToRgbaString( - GetHighlightColor(profile_color_))); - dict.SetStringKey("pictureUrl", GetPictureUrl()); +base::Value::Dict EnterpriseProfileWelcomeHandler::GetProfileInfoValue() { + base::Value::Dict dict; + dict.Set("backgroundColor", + color_utils::SkColorToRgbaString(GetHighlightColor(profile_color_))); + dict.Set("pictureUrl", GetPictureUrl()); std::string title = l10n_util::GetStringUTF8(IDS_ENTERPRISE_PROFILE_WELCOME_TITLE); @@ -271,54 +271,51 @@ switch (type_) { case EnterpriseProfileWelcomeUI::ScreenType::kEntepriseAccountSyncEnabled: - dict.SetBoolKey("showEnterpriseBadge", true); + dict.Set("showEnterpriseBadge", true); subtitle = GetManagedAccountTitle(entry, domain_name_); enterprise_info = l10n_util::GetStringUTF8( IDS_ENTERPRISE_PROFILE_WELCOME_MANAGED_DESCRIPTION_WITH_SYNC); - dict.SetStringKey( - "proceedLabel", - l10n_util::GetStringUTF8(IDS_PROFILE_PICKER_IPH_NEXT_BUTTON_LABEL)); + dict.Set("proceedLabel", l10n_util::GetStringUTF8( + IDS_PROFILE_PICKER_IPH_NEXT_BUTTON_LABEL)); break; case EnterpriseProfileWelcomeUI::ScreenType::kEntepriseAccountSyncDisabled: - dict.SetBoolKey("showEnterpriseBadge", true); + dict.Set("showEnterpriseBadge", true); subtitle = GetManagedAccountTitle(entry, domain_name_); enterprise_info = l10n_util ::GetStringUTF8( IDS_ENTERPRISE_PROFILE_WELCOME_MANAGED_DESCRIPTION_WITHOUT_SYNC); - dict.SetStringKey("proceedLabel", l10n_util::GetStringUTF8(IDS_DONE)); + dict.Set("proceedLabel", l10n_util::GetStringUTF8(IDS_DONE)); break; case EnterpriseProfileWelcomeUI::ScreenType::kConsumerAccountSyncDisabled: - dict.SetBoolKey("showEnterpriseBadge", false); + dict.Set("showEnterpriseBadge", false); subtitle = GetManagedDeviceTitle(); enterprise_info = l10n_util::GetStringUTF8(IDS_SYNC_DISABLED_CONFIRMATION_DETAILS); - dict.SetStringKey("proceedLabel", l10n_util::GetStringUTF8(IDS_DONE)); + dict.Set("proceedLabel", l10n_util::GetStringUTF8(IDS_DONE)); break; case EnterpriseProfileWelcomeUI::ScreenType::kEnterpriseAccountCreation: title = l10n_util::GetStringUTF8( profile_creation_required_by_policy_ ? IDS_ENTERPRISE_WELCOME_PROFILE_REQUIRED_TITLE : IDS_ENTERPRISE_WELCOME_PROFILE_WILL_BE_MANAGED_TITLE); - dict.SetBoolKey("showEnterpriseBadge", false); + dict.Set("showEnterpriseBadge", false); subtitle = GetManagedAccountTitleWithEmail(entry, domain_name_, email_); enterprise_info = l10n_util::GetStringUTF8( IDS_ENTERPRISE_PROFILE_WELCOME_MANAGED_DESCRIPTION_WITH_SYNC); - dict.SetStringKey( - "proceedLabel", - l10n_util::GetStringUTF8( - profile_creation_required_by_policy_ - ? IDS_ENTERPRISE_PROFILE_WELCOME_CREATE_PROFILE_BUTTON - : IDS_WELCOME_SIGNIN_VIEW_SIGNIN)); + dict.Set("proceedLabel", + l10n_util::GetStringUTF8( + profile_creation_required_by_policy_ + ? IDS_ENTERPRISE_PROFILE_WELCOME_CREATE_PROFILE_BUTTON + : IDS_WELCOME_SIGNIN_VIEW_SIGNIN)); #if !BUILDFLAG(IS_CHROMEOS) - dict.SetBoolKey( - "checkLinkDataCheckboxByDefault", - show_link_data_option_ && - g_browser_process->local_state()->GetBoolean( - prefs::kEnterpriseProfileCreationKeepBrowsingData)); + dict.Set("checkLinkDataCheckboxByDefault", + show_link_data_option_ && + g_browser_process->local_state()->GetBoolean( + prefs::kEnterpriseProfileCreationKeepBrowsingData)); #endif break; #if BUILDFLAG(IS_CHROMEOS_LACROS) case EnterpriseProfileWelcomeUI::ScreenType::kLacrosEnterpriseWelcome: - dict.SetBoolKey("showEnterpriseBadge", true); + dict.Set("showEnterpriseBadge", true); enterprise_info = GetLacrosFirstRunManagedAccountInfo(entry, domain_name_); [[fallthrough]]; @@ -326,18 +323,18 @@ title = GetLacrosWelcomeTitle(); subtitle = l10n_util::GetStringFUTF8( IDS_PRIMARY_PROFILE_FIRST_RUN_SUBTITLE, email_); - dict.SetStringKey("proceedLabel", - l10n_util::GetStringUTF8( - IDS_PRIMARY_PROFILE_FIRST_RUN_NEXT_BUTTON_LABEL)); + dict.Set("proceedLabel", + l10n_util::GetStringUTF8( + IDS_PRIMARY_PROFILE_FIRST_RUN_NEXT_BUTTON_LABEL)); show_cancel_button = false; break; #endif } - dict.SetStringKey("title", title); - dict.SetStringKey("subtitle", subtitle); - dict.SetStringKey("enterpriseInfo", enterprise_info); - dict.SetBoolKey("showCancelButton", show_cancel_button); + dict.Set("title", title); + dict.Set("subtitle", subtitle); + dict.Set("enterpriseInfo", enterprise_info); + dict.Set("showCancelButton", show_cancel_button); return dict; }
diff --git a/chrome/browser/ui/webui/signin/enterprise_profile_welcome_handler.h b/chrome/browser/ui/webui/signin/enterprise_profile_welcome_handler.h index 6517ea4..af82826a 100644 --- a/chrome/browser/ui/webui/signin/enterprise_profile_welcome_handler.h +++ b/chrome/browser/ui/webui/signin/enterprise_profile_welcome_handler.h
@@ -92,7 +92,7 @@ void UpdateProfileInfo(const base::FilePath& profile_path); // Computes the profile info (avatar and colors) to be sent to the WebUI. - base::Value GetProfileInfoValue(); + base::Value::Dict GetProfileInfoValue(); // Returns the ProfilesAttributesEntry associated with the current profile. ProfileAttributesEntry* GetProfileEntry() const;
diff --git a/chrome/browser/ui/webui/signin/inline_login_handler.cc b/chrome/browser/ui/webui/signin/inline_login_handler.cc index 8a7d4e0..f15d418 100644 --- a/chrome/browser/ui/webui/signin/inline_login_handler.cc +++ b/chrome/browser/ui/webui/signin/inline_login_handler.cc
@@ -158,7 +158,7 @@ params.Set("readOnlyEmail", !read_only_email.empty()); SetExtraInitParams(params); - FireWebUIListener("load-auth-extension", base::Value(std::move(params))); + FireWebUIListener("load-auth-extension", params); } void InlineLoginHandler::HandleCompleteLoginMessage(
diff --git a/chrome/browser/ui/webui/signin/inline_login_handler_chromeos.cc b/chrome/browser/ui/webui/signin/inline_login_handler_chromeos.cc index 413d672..ef3f0de 100644 --- a/chrome/browser/ui/webui/signin/inline_login_handler_chromeos.cc +++ b/chrome/browser/ui/webui/signin/inline_login_handler_chromeos.cc
@@ -105,20 +105,19 @@ return default_icon.GetRepresentation(1.0f).GetBitmap(); } -base::Value GaiaAccountToValue(const ::account_manager::Account& account, - const AccountInfo& account_info) { +base::Value::Dict GaiaAccountToValue(const ::account_manager::Account& account, + const AccountInfo& account_info) { DCHECK_EQ(account.key.account_type(), account_manager::AccountType::kGaia); DCHECK(!account_info.IsEmpty()); - base::Value dict(base::Value::Type::DICTIONARY); - dict.SetKey(kAccountKeyId, base::Value(account.key.id())); - dict.SetKey(kAccountKeyEmail, base::Value(account.raw_email)); - dict.SetKey(kAccountKeyFullName, base::Value(account_info.full_name)); - dict.SetKey(kAccountKeyImage, - base::Value(webui::GetBitmapDataUrl( - account_info.account_image.IsEmpty() - ? GetDefaultAccountIcon() - : account_info.account_image.AsBitmap()))); + base::Value::Dict dict; + dict.Set(kAccountKeyId, account.key.id()); + dict.Set(kAccountKeyEmail, account.raw_email); + dict.Set(kAccountKeyFullName, account_info.full_name); + dict.Set(kAccountKeyImage, webui::GetBitmapDataUrl( + account_info.account_image.IsEmpty() + ? GetDefaultAccountIcon() + : account_info.account_image.AsBitmap())); return dict; } @@ -270,18 +269,16 @@ void InlineLoginHandlerChromeOS::SetExtraInitParams(base::Value::Dict& params) { const GaiaUrls* const gaia_urls = GaiaUrls::GetInstance(); - params.Set("clientId", base::Value(gaia_urls->oauth2_chrome_client_id())); + params.Set("clientId", gaia_urls->oauth2_chrome_client_id()); const GURL& url = gaia_urls->embedded_setup_chromeos_url(2U); - params.Set("gaiaPath", base::Value(url.path().substr(1))); + params.Set("gaiaPath", url.path().substr(1)); - params.Set( - "platformVersion", - base::Value(version_loader::GetVersion(version_loader::VERSION_SHORT))); - params.Set("constrained", base::Value("1")); - params.Set("flow", - base::Value(GetInlineLoginFlowName(Profile::FromWebUI(web_ui()), - params.FindString("email")))); + params.Set("platformVersion", + version_loader::GetVersion(version_loader::VERSION_SHORT)); + params.Set("constrained", "1"); + params.Set("flow", GetInlineLoginFlowName(Profile::FromWebUI(web_ui()), + params.FindString("email"))); params.Set("dontResizeNonEmbeddedPages", true); params.Set("enableGaiaActionButtons", true); @@ -385,7 +382,7 @@ params.Set("deviceType", ui::GetChromeOSDeviceName()); params.Set("signinBlockedByPolicy", !hosted_domain.empty() ? true : false); - FireWebUIListener("show-signin-error-page", base::Value(std::move(params))); + FireWebUIListener("show-signin-error-page", params); } void InlineLoginHandlerChromeOS::ShowIncognitoAndCloseDialog( @@ -406,7 +403,7 @@ void InlineLoginHandlerChromeOS::OnGetAccounts( const std::string& callback_id, const std::vector<::account_manager::Account>& accounts) { - base::ListValue account_emails; + base::Value::List account_emails; for (const auto& account : accounts) { if (account.key.account_type() == ::account_manager::AccountType::kActiveDirectory) { @@ -417,8 +414,7 @@ } } - ResolveJavascriptCallback(base::Value(callback_id), - std::move(account_emails)); + ResolveJavascriptCallback(base::Value(callback_id), account_emails); } void InlineLoginHandlerChromeOS::GetAccountsNotAvailableInArc( @@ -446,7 +442,7 @@ const std::string& callback_id, const std::vector<::account_manager::Account>& accounts, const base::flat_set<account_manager::Account>& arc_accounts) { - base::Value result(base::Value::Type::LIST); + base::Value::List result; auto* identity_manager = IdentityManagerFactory::GetForProfile(Profile::FromWebUI(web_ui())); for (const auto& account : accounts) { @@ -462,7 +458,7 @@ result.Append(GaiaAccountToValue(account, maybe_account_info)); } } - ResolveJavascriptCallback(base::Value(callback_id), std::move(result)); + ResolveJavascriptCallback(base::Value(callback_id), result); } void InlineLoginHandlerChromeOS::MakeAvailableInArcAndCloseDialog(
diff --git a/chrome/browser/ui/webui/signin/profile_customization_handler.cc b/chrome/browser/ui/webui/signin/profile_customization_handler.cc index bc0ec9cb..00e5937 100644 --- a/chrome/browser/ui/webui/signin/profile_customization_handler.cc +++ b/chrome/browser/ui/webui/signin/profile_customization_handler.cc
@@ -123,27 +123,24 @@ FireWebUIListener("on-profile-info-changed", GetProfileInfoValue()); } -base::Value ProfileCustomizationHandler::GetProfileInfoValue() { +base::Value::Dict ProfileCustomizationHandler::GetProfileInfoValue() { ProfileAttributesEntry* entry = GetProfileEntry(); - base::Value dict(base::Value::Type::DICTIONARY); - dict.SetStringKey( - "backgroundColor", - color_utils::SkColorToRgbaString( - entry->GetProfileThemeColors().profile_highlight_color)); + base::Value::Dict dict; + dict.Set("backgroundColor", + color_utils::SkColorToRgbaString( + entry->GetProfileThemeColors().profile_highlight_color)); const int avatar_icon_size = kAvatarSize * web_ui()->GetDeviceScaleFactor(); gfx::Image icon = profiles::GetSizedAvatarIcon(entry->GetAvatarIcon(avatar_icon_size), avatar_icon_size, avatar_icon_size); - dict.SetStringKey("pictureUrl", webui::GetBitmapDataUrl(icon.AsBitmap())); - dict.SetBoolKey("isManaged", - AccountInfo::IsManaged(entry->GetHostedDomain())); + dict.Set("pictureUrl", webui::GetBitmapDataUrl(icon.AsBitmap())); + dict.Set("isManaged", AccountInfo::IsManaged(entry->GetHostedDomain())); std::u16string gaia_name = entry->GetGAIANameToDisplay(); if (gaia_name.empty()) gaia_name = entry->GetLocalProfileName(); - dict.SetStringKey( - "welcomeTitle", - l10n_util::GetStringFUTF8(IDS_PROFILE_CUSTOMIZATION_WELCOME, gaia_name)); + dict.Set("welcomeTitle", l10n_util::GetStringFUTF8( + IDS_PROFILE_CUSTOMIZATION_WELCOME, gaia_name)); return dict; }
diff --git a/chrome/browser/ui/webui/signin/profile_customization_handler.h b/chrome/browser/ui/webui/signin/profile_customization_handler.h index 82b30da..4af8192 100644 --- a/chrome/browser/ui/webui/signin/profile_customization_handler.h +++ b/chrome/browser/ui/webui/signin/profile_customization_handler.h
@@ -60,7 +60,7 @@ void UpdateProfileInfo(const base::FilePath& profile_path); // Computes the profile info (avatar and colors) to be sent to the WebUI. - base::Value GetProfileInfoValue(); + base::Value::Dict GetProfileInfoValue(); // Returns the ProfilesAttributesEntry associated with the current profile. ProfileAttributesEntry* GetProfileEntry() const;
diff --git a/chrome/browser/ui/webui/signin/profile_picker_handler.cc b/chrome/browser/ui/webui/signin/profile_picker_handler.cc index ac46ead..d2bbbd2 100644 --- a/chrome/browser/ui/webui/signin/profile_picker_handler.cc +++ b/chrome/browser/ui/webui/signin/profile_picker_handler.cc
@@ -121,7 +121,7 @@ } } -base::Value GetAutogeneratedProfileThemeInfoValue( +base::Value::Dict GetAutogeneratedProfileThemeInfoValue( int color_id, absl::optional<SkColor> color, const ui::ColorProvider& color_provider, @@ -129,26 +129,24 @@ SkColor active_tab_color, SkColor frame_text_color, float scale_factor) { - base::Value dict(base::Value::Type::DICTIONARY); - dict.SetIntKey("colorId", color_id); + base::Value::Dict dict; + dict.Set("colorId", color_id); if (color.has_value()) - dict.SetIntKey("color", *color); - dict.SetStringKey("themeFrameColor", - color_utils::SkColorToRgbaString(frame_color)); - dict.SetStringKey("themeShapeColor", - color_utils::SkColorToRgbaString(active_tab_color)); - dict.SetStringKey("themeFrameTextColor", - color_utils::SkColorToRgbaString(frame_text_color)); + dict.Set("color", static_cast<int>(*color)); + dict.Set("themeFrameColor", color_utils::SkColorToRgbaString(frame_color)); + dict.Set("themeShapeColor", + color_utils::SkColorToRgbaString(active_tab_color)); + dict.Set("themeFrameTextColor", + color_utils::SkColorToRgbaString(frame_text_color)); gfx::Image icon = profiles::GetPlaceholderAvatarIconWithColors( /*fill_color=*/frame_color, /*stroke_color=*/GetAvatarStrokeColor(color_provider, frame_color), kProfileCreationAvatarSize * scale_factor); - dict.SetStringKey("themeGenericAvatar", - webui::GetBitmapDataUrl(icon.AsBitmap())); + dict.Set("themeGenericAvatar", webui::GetBitmapDataUrl(icon.AsBitmap())); return dict; } -base::Value CreateDefaultProfileThemeInfo( +base::Value::Dict CreateDefaultProfileThemeInfo( const ui::ColorProvider& color_provider, float scale_factor) { SkColor frame_color = color_provider.GetColor(ui::kColorFrameActive); @@ -160,7 +158,7 @@ active_tab_color, frame_text_color, scale_factor); } -base::Value CreateAutogeneratedProfileThemeInfo( +base::Value::Dict CreateAutogeneratedProfileThemeInfo( int color_id, SkColor color, const ui::ColorProvider& color_provider, @@ -193,31 +191,31 @@ } } -base::Value CreateProfileEntry(const ProfileAttributesEntry* entry, - int avatar_icon_size) { - base::Value profile_entry(base::Value::Type::DICTIONARY); - profile_entry.SetKey("profilePath", base::FilePathToValue(entry->GetPath())); - profile_entry.SetStringKey("localProfileName", entry->GetLocalProfileName()); - profile_entry.SetBoolKey( - "isSyncing", entry->GetSigninState() == - SigninState::kSignedInWithConsentedPrimaryAccount); - profile_entry.SetBoolKey("needsSignin", entry->IsSigninRequired()); +base::Value::Dict CreateProfileEntry(const ProfileAttributesEntry* entry, + int avatar_icon_size) { + base::Value::Dict profile_entry; + profile_entry.Set("profilePath", base::FilePathToValue(entry->GetPath())); + profile_entry.Set("localProfileName", entry->GetLocalProfileName()); + profile_entry.Set("isSyncing", + entry->GetSigninState() == + SigninState::kSignedInWithConsentedPrimaryAccount); + profile_entry.Set("needsSignin", entry->IsSigninRequired()); // GAIA full name/user name can be empty, if the profile is not signed in to // chrome. - profile_entry.SetStringKey("gaiaName", entry->GetGAIAName()); - profile_entry.SetStringKey("userName", entry->GetUserName()); - profile_entry.SetBoolKey("isManaged", - AccountInfo::IsManaged(entry->GetHostedDomain())); + profile_entry.Set("gaiaName", entry->GetGAIAName()); + profile_entry.Set("userName", entry->GetUserName()); + profile_entry.Set("isManaged", + AccountInfo::IsManaged(entry->GetHostedDomain())); gfx::Image icon = profiles::GetSizedAvatarIcon(entry->GetAvatarIcon(avatar_icon_size), avatar_icon_size, avatar_icon_size); std::string icon_url = webui::GetBitmapDataUrl(icon.AsBitmap()); - profile_entry.SetStringKey("avatarIcon", icon_url); + profile_entry.Set("avatarIcon", icon_url); #if BUILDFLAG(IS_CHROMEOS_LACROS) - profile_entry.SetBoolKey("isPrimaryLacrosProfile", - Profile::IsMainProfilePath(entry->GetPath())); + profile_entry.Set("isPrimaryLacrosProfile", + Profile::IsMainProfilePath(entry->GetPath())); #else - profile_entry.SetBoolKey("isPrimaryLacrosProfile", false); + profile_entry.Set("isPrimaryLacrosProfile", false); #endif // BUILDFLAG(IS_CHROMEOS_LACROS) return profile_entry; } @@ -598,7 +596,7 @@ ThemeService* theme_service = ThemeServiceFactory::GetForProfile(Profile::FromBrowserContext( web_ui()->GetWebContents()->GetBrowserContext())); - base::Value profile_dict; + base::Value::Dict profile_dict; if (theme_service->UsingAutogeneratedTheme()) { // We'll never use `profile_dict` for showing the color picker so we can // pass in kManuallyPickedColorId to simplify the code. @@ -611,16 +609,16 @@ web_ui()->GetWebContents()->GetColorProvider(), web_ui()->GetDeviceScaleFactor()); } - ResolveJavascriptCallback(callback_id, std::move(profile_dict)); + ResolveJavascriptCallback(callback_id, profile_dict); return; } #endif chrome_colors::ColorInfo color_info = GenerateNewProfileColor(); - base::Value dict = CreateAutogeneratedProfileThemeInfo( + base::Value::Dict dict = CreateAutogeneratedProfileThemeInfo( color_info.id, color_info.color, web_ui()->GetWebContents()->GetColorProvider(), web_ui()->GetDeviceScaleFactor()); - ResolveJavascriptCallback(callback_id, std::move(dict)); + ResolveJavascriptCallback(callback_id, dict); } void ProfilePickerHandler::HandleGetProfileThemeInfo( @@ -631,7 +629,7 @@ const base::Value::Dict& user_theme_choice = args[1].GetDict(); int color_id = user_theme_choice.FindInt("colorId").value(); absl::optional<SkColor> color = user_theme_choice.FindDouble("color"); - base::Value dict; + base::Value::Dict dict; switch (color_id) { case kDefaultThemeColorId: dict = CreateDefaultProfileThemeInfo( @@ -650,7 +648,7 @@ web_ui()->GetDeviceScaleFactor()); break; } - ResolveJavascriptCallback(callback_id, std::move(dict)); + ResolveJavascriptCallback(callback_id, dict); } void ProfilePickerHandler::HandleGetAvailableIcons( @@ -658,9 +656,8 @@ AllowJavascript(); CHECK_EQ(1U, args.size()); const base::Value& callback_id = args[0]; - ResolveJavascriptCallback( - callback_id, - base::Value(profiles::GetCustomProfileAvatarIconsAndLabels())); + ResolveJavascriptCallback(callback_id, + profiles::GetCustomProfileAvatarIconsAndLabels()); } void ProfilePickerHandler::HandleCreateProfile(const base::Value::List& args) { @@ -701,8 +698,8 @@ ->GetProfileAttributesStorage() .GetProfileAttributesWithPath(profile_path); CHECK(entry); - base::Value dict = CreateProfileEntry(entry, avatar_icon_size); - ResolveJavascriptCallback(callback_id, std::move(dict)); + base::Value::Dict dict = CreateProfileEntry(entry, avatar_icon_size); + ResolveJavascriptCallback(callback_id, dict); } void ProfilePickerHandler::HandleConfirmProfileSwitch( @@ -877,16 +874,16 @@ void ProfilePickerHandler::OnProfileStatisticsReceived( const base::FilePath& profile_path, profiles::ProfileCategoryStats result) { - base::Value dict(base::Value::Type::DICTIONARY); - dict.SetKey("profilePath", base::FilePathToValue(profile_path)); - base::Value stats(base::Value::Type::DICTIONARY); + base::Value::Dict dict; + dict.Set("profilePath", base::FilePathToValue(profile_path)); + base::Value::Dict stats; // Categories are defined in |kProfileStatisticsCategories| // {"BrowsingHistory", "Passwords", "Bookmarks", "Autofill"}. for (const auto& item : result) { - stats.SetIntKey(item.category, item.count); + stats.Set(item.category, item.count); } - dict.SetKey("statistics", std::move(stats)); - FireWebUIListener("profile-statistics-received", std::move(dict)); + dict.Set("statistics", std::move(stats)); + FireWebUIListener("profile-statistics-received", dict); } void ProfilePickerHandler::HandleSelectAccountLacros( @@ -1051,8 +1048,8 @@ return entries; } -base::Value ProfilePickerHandler::GetProfilesList() { - base::Value profiles_list(base::Value::Type::LIST); +base::Value::List ProfilePickerHandler::GetProfilesList() { + base::Value::List profiles_list; std::vector<ProfileAttributesEntry*> entries = GetProfileAttributes(); const int avatar_icon_size = kProfileCardAvatarSize * web_ui()->GetDeviceScaleFactor(); @@ -1218,23 +1215,23 @@ void ProfilePickerHandler::SendAvailableAccounts( std::vector<GetAccountInformationHelper::GetAccountInformationResult> accounts) { - base::Value accounts_list(base::Value::Type::LIST); + base::Value::List accounts_list; for (const GetAccountInformationHelper::GetAccountInformationResult& account : accounts) { // TODO(https://crbug/1226050): Filter out items with no email as items // without an email are impossible to use. The email should be always // available, unless the mojo connection fails. This requires more robust // unit-tests. - base::Value account_dict(base::Value::Type::DICTIONARY); - account_dict.SetStringKey("gaiaId", account.gaia); - account_dict.SetStringKey("email", account.email); - account_dict.SetStringKey("name", account.full_name); + base::Value::Dict account_dict; + account_dict.Set("gaiaId", account.gaia); + account_dict.Set("email", account.email); + account_dict.Set("name", account.full_name); SkBitmap account_bitmap = GetAvailableAccountBitmap(account.account_image); - account_dict.SetStringKey("accountImageUrl", - webui::GetBitmapDataUrl(account_bitmap)); + account_dict.Set("accountImageUrl", + webui::GetBitmapDataUrl(account_bitmap)); accounts_list.Append(std::move(account_dict)); } - FireWebUIListener("available-accounts-changed", std::move(accounts_list)); + FireWebUIListener("available-accounts-changed", accounts_list); } void ProfilePickerHandler::OnLacrosSignedInProfileCreated(
diff --git a/chrome/browser/ui/webui/signin/profile_picker_handler.h b/chrome/browser/ui/webui/signin/profile_picker_handler.h index eeeae9e..6e2c6408 100644 --- a/chrome/browser/ui/webui/signin/profile_picker_handler.h +++ b/chrome/browser/ui/webui/signin/profile_picker_handler.h
@@ -112,7 +112,7 @@ bool create_shortcut, Profile* profile); void PushProfilesList(); - base::Value GetProfilesList(); + base::Value::List GetProfilesList(); // Adds a profile with `profile_path` to `profiles_order_`. void AddProfileToList(const base::FilePath& profile_path); // Removes a profile with `profile_path` from `profiles_order_`. Returns
diff --git a/chrome/browser/ui/webui/signin/sync_confirmation_handler.cc b/chrome/browser/ui/webui/signin/sync_confirmation_handler.cc index 26c21da..7f55ab4 100644 --- a/chrome/browser/ui/webui/signin/sync_confirmation_handler.cc +++ b/chrome/browser/ui/webui/signin/sync_confirmation_handler.cc
@@ -168,9 +168,9 @@ GURL picture_gurl_with_options = signin::GetAvatarImageURLWithOptions( picture_gurl, kProfileImageSize, false /* no_silhouette */); - base::Value value(base::Value::Type::DICTIONARY); - value.SetKey("src", base::Value(picture_gurl_with_options.spec())); - value.SetKey("showEnterpriseBadge", base::Value(info.IsManaged())); + base::Value::Dict value; + value.Set("src", picture_gurl_with_options.spec()); + value.Set("showEnterpriseBadge", info.IsManaged()); AllowJavascript(); FireWebUIListener("account-info-changed", value);
diff --git a/chrome/browser/ui/webui/tab_search/tab_search_page_handler.cc b/chrome/browser/ui/webui/tab_search/tab_search_page_handler.cc index 99914ea..4582b55 100644 --- a/chrome/browser/ui/webui/tab_search/tab_search_page_handler.cc +++ b/chrome/browser/ui/webui/tab_search/tab_search_page_handler.cc
@@ -152,13 +152,6 @@ if (!sent_initial_payload_) { sent_initial_payload_ = true; int tab_count = 0; - int media_tab_count = 0; - for (const auto& window : profile_tabs->windows) { - tab_count += window->tabs.size(); - media_tab_count += base::ranges::count_if( - window->tabs.begin(), window->tabs.end(), - [](const auto& tab) { return tab->alert_states.size() > 0; }); - } base::UmaHistogramCounts100("Tabs.TabSearch.NumWindowsOnOpen", profile_tabs->windows.size()); base::UmaHistogramCounts10000("Tabs.TabSearch.NumTabsOnOpen", tab_count); @@ -170,8 +163,6 @@ "Tabs.TabSearch.RecentlyClosedSectionToggleStateOnOpen", expand_preference ? TabSearchRecentlyClosedToggleAction::kExpand : TabSearchRecentlyClosedToggleAction::kCollapse); - base::UmaHistogramCounts10000("Tabs.TabSearch.NumMediaTabsOnOpen", - media_tab_count); } std::move(callback).Run(std::move(profile_tabs)); @@ -478,7 +469,6 @@ tab_data->last_active_elapsed_text = GetLastActiveElapsedText(last_active_time_ticks); - if (base::FeatureList::IsEnabled(features::kTabSearchMediaTabs)) { std::vector<TabAlertState> alert_states = chrome::GetTabAlertStatesForContents(contents); // Currently, we only report media alert states. @@ -489,9 +479,8 @@ alert == TabAlertState::AUDIO_PLAYING || alert == TabAlertState::AUDIO_MUTING; }); - } - return tab_data; + return tab_data; } tab_search::mojom::RecentlyClosedTabPtr
diff --git a/chrome/browser/ui/webui/tab_search/tab_search_page_handler_unittest.cc b/chrome/browser/ui/webui/tab_search/tab_search_page_handler_unittest.cc index 9b876467..9267d70 100644 --- a/chrome/browser/ui/webui/tab_search/tab_search_page_handler_unittest.cc +++ b/chrome/browser/ui/webui/tab_search/tab_search_page_handler_unittest.cc
@@ -6,7 +6,6 @@ #include "base/memory/raw_ptr.h" #include "base/test/bind.h" -#include "base/test/scoped_feature_list.h" #include "base/timer/mock_timer.h" #include "build/build_config.h" #include "build/chromeos_buildflags.h" @@ -381,8 +380,6 @@ } TEST_F(TabSearchPageHandlerTest, MediaTabsTest) { - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndEnableFeature(features::kTabSearchMediaTabs); std::unique_ptr<content::WebContents> test_web_contents( content::WebContentsTester::CreateTestWebContents( content::WebContents::CreateParams(profile())));
diff --git a/chrome/browser/ui/webui/tab_search/tab_search_ui.cc b/chrome/browser/ui/webui/tab_search/tab_search_ui.cc index 97f1637..fe21dcc 100644 --- a/chrome/browser/ui/webui/tab_search/tab_search_ui.cc +++ b/chrome/browser/ui/webui/tab_search/tab_search_ui.cc
@@ -72,12 +72,6 @@ "useMetricsReporter", base::FeatureList::IsEnabled(features::kTabSearchUseMetricsReporter)); - source->AddBoolean( - "alsoShowMediaTabsinOpenTabsSection", - GetFieldTrialParamByFeatureAsBool( - features::kTabSearchMediaTabs, - features::kTabSearchAlsoShowMediaTabsinOpenTabsSectionParameterName, - false)); source->AddBoolean("searchIgnoreLocation", features::kTabSearchSearchIgnoreLocation.Get()); source->AddInteger("searchDistance",
diff --git a/chrome/browser/ui/webui/whats_new/whats_new_util.cc b/chrome/browser/ui/webui/whats_new/whats_new_util.cc index cea48abb..dc39ea1 100644 --- a/chrome/browser/ui/webui/whats_new/whats_new_util.cc +++ b/chrome/browser/ui/webui/whats_new/whats_new_util.cc
@@ -103,12 +103,14 @@ } GURL GetServerURL(bool may_redirect) { - return may_redirect - ? net::AppendQueryParameter( - GURL(kChromeWhatsNewURL), "version", - base::NumberToString(CHROME_VERSION_MAJOR)) - : GURL(kChromeWhatsNewURL) - .Resolve(base::StringPrintf("m%d", CHROME_VERSION_MAJOR)); + const GURL url = + may_redirect + ? net::AppendQueryParameter( + GURL(kChromeWhatsNewURL), "version", + base::NumberToString(CHROME_VERSION_MAJOR)) + : GURL(kChromeWhatsNewURL) + .Resolve(base::StringPrintf("m%d", CHROME_VERSION_MAJOR)); + return net::AppendQueryParameter(url, "internal", "true"); } GURL GetWebUIStartupURL() {
diff --git a/chrome/browser/ui/webui/whats_new/whats_new_util_unittest.cc b/chrome/browser/ui/webui/whats_new/whats_new_util_unittest.cc new file mode 100644 index 0000000..53a46bd --- /dev/null +++ b/chrome/browser/ui/webui/whats_new/whats_new_util_unittest.cc
@@ -0,0 +1,26 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/webui/whats_new/whats_new_util.h" + +#include <stddef.h> + +#include "base/strings/stringprintf.h" +#include "build/build_config.h" +#include "chrome/common/chrome_version.h" +#include "testing/gtest/include/gtest/gtest.h" + +TEST(WhatsNewUtil, GetServerURL) { + const std::string expected_no_redirect = base::StringPrintf( + "https://www.google.com/chrome/whats-new/m%d?internal=true", + CHROME_VERSION_MAJOR); + const std::string expected_redirect = base::StringPrintf( + "https://www.google.com/chrome/whats-new/?version=%d&internal=true", + CHROME_VERSION_MAJOR); + + EXPECT_EQ(expected_no_redirect, + whats_new::GetServerURL(false).possibly_invalid_spec()); + EXPECT_EQ(expected_redirect, + whats_new::GetServerURL(true).possibly_invalid_spec()); +}
diff --git a/chrome/browser/webid/federated_identity_active_session_permission_context.cc b/chrome/browser/webid/federated_identity_active_session_permission_context.cc index 78ca5c9c90..99f386a 100644 --- a/chrome/browser/webid/federated_identity_active_session_permission_context.cc +++ b/chrome/browser/webid/federated_identity_active_session_permission_context.cc
@@ -28,25 +28,25 @@ ~FederatedIdentityActiveSessionPermissionContext() = default; bool FederatedIdentityActiveSessionPermissionContext::HasActiveSession( - const url::Origin& relying_party, + const url::Origin& relying_party_requester, const url::Origin& identity_provider, const std::string& account_identifier) { - return HasPermission(relying_party, relying_party, identity_provider, - account_identifier); + return HasPermission(relying_party_requester, relying_party_requester, + identity_provider, account_identifier); } void FederatedIdentityActiveSessionPermissionContext::GrantActiveSession( - const url::Origin& relying_party, + const url::Origin& relying_party_requester, const url::Origin& identity_provider, const std::string& account_identifier) { - GrantPermission(relying_party, relying_party, identity_provider, - account_identifier); + GrantPermission(relying_party_requester, relying_party_requester, + identity_provider, account_identifier); } void FederatedIdentityActiveSessionPermissionContext::RevokeActiveSession( - const url::Origin& relying_party, + const url::Origin& relying_party_requester, const url::Origin& identity_provider, const std::string& account_identifier) { - RevokePermission(relying_party, relying_party, identity_provider, - account_identifier); + RevokePermission(relying_party_requester, relying_party_requester, + identity_provider, account_identifier); }
diff --git a/chrome/browser/webid/federated_identity_active_session_permission_context.h b/chrome/browser/webid/federated_identity_active_session_permission_context.h index 2a78f546..85e6531b 100644 --- a/chrome/browser/webid/federated_identity_active_session_permission_context.h +++ b/chrome/browser/webid/federated_identity_active_session_permission_context.h
@@ -32,13 +32,13 @@ const FederatedIdentityActiveSessionPermissionContext&) = delete; // content::FederatedIdentityActiveSessionPermissionContextDelegate: - bool HasActiveSession(const url::Origin& relying_party, + bool HasActiveSession(const url::Origin& relying_party_requester, const url::Origin& identity_provider, const std::string& account_identifier) override; - void GrantActiveSession(const url::Origin& relying_party, + void GrantActiveSession(const url::Origin& relying_party_requester, const url::Origin& identity_provider, const std::string& account_identifier) override; - void RevokeActiveSession(const url::Origin& relying_party, + void RevokeActiveSession(const url::Origin& relying_party_requester, const url::Origin& identity_provider, const std::string& account_identifier) override; };
diff --git a/chrome/browser/webid/federated_identity_api_permission_context.cc b/chrome/browser/webid/federated_identity_api_permission_context.cc index 23976fa..bc452944 100644 --- a/chrome/browser/webid/federated_identity_api_permission_context.cc +++ b/chrome/browser/webid/federated_identity_api_permission_context.cc
@@ -32,7 +32,7 @@ content::FederatedIdentityApiPermissionContextDelegate::PermissionStatus FederatedIdentityApiPermissionContext::GetApiPermissionStatus( - const url::Origin& rp_origin) { + const url::Origin& relying_party_embedder) { if (!base::FeatureList::IsEnabled(features::kFedCm)) return PermissionStatus::BLOCKED_VARIATIONS; @@ -42,9 +42,10 @@ if (cookie_settings_->ShouldBlockThirdPartyCookies()) return PermissionStatus::BLOCKED_THIRD_PARTY_COOKIES_BLOCKED; - const GURL rp_url = rp_origin.GetURL(); + const GURL rp_embedder_url = relying_party_embedder.GetURL(); const ContentSetting setting = host_content_settings_map_->GetContentSetting( - rp_url, rp_url, ContentSettingsType::FEDERATED_IDENTITY_API); + rp_embedder_url, rp_embedder_url, + ContentSettingsType::FEDERATED_IDENTITY_API); switch (setting) { case CONTENT_SETTING_ALLOW: break; @@ -56,32 +57,34 @@ } if (permission_autoblocker_->IsEmbargoed( - rp_url, ContentSettingsType::FEDERATED_IDENTITY_API)) { + rp_embedder_url, ContentSettingsType::FEDERATED_IDENTITY_API)) { return PermissionStatus::BLOCKED_EMBARGO; } return PermissionStatus::GRANTED; } void FederatedIdentityApiPermissionContext::RecordDismissAndEmbargo( - const url::Origin& rp_origin) { - const GURL rp_url = rp_origin.GetURL(); - // If content setting is allowed for `rp_url`, reset it. + const url::Origin& relying_party_embedder) { + const GURL rp_embedder_url = relying_party_embedder.GetURL(); + // If content setting is allowed for `rp_embedder_url`, reset it. // See crbug.com/1340127 for why the resetting is not conditional on the // default content setting state. const ContentSetting setting = host_content_settings_map_->GetContentSetting( - rp_url, rp_url, ContentSettingsType::FEDERATED_IDENTITY_API); + rp_embedder_url, rp_embedder_url, + ContentSettingsType::FEDERATED_IDENTITY_API); if (setting == CONTENT_SETTING_ALLOW) { host_content_settings_map_->SetContentSettingDefaultScope( - rp_url, rp_url, ContentSettingsType::FEDERATED_IDENTITY_API, - CONTENT_SETTING_DEFAULT); + rp_embedder_url, rp_embedder_url, + ContentSettingsType::FEDERATED_IDENTITY_API, CONTENT_SETTING_DEFAULT); } permission_autoblocker_->RecordDismissAndEmbargo( - rp_url, ContentSettingsType::FEDERATED_IDENTITY_API, + rp_embedder_url, ContentSettingsType::FEDERATED_IDENTITY_API, false /* dismissed_prompt_was_quiet */); } void FederatedIdentityApiPermissionContext::RemoveEmbargoAndResetCounts( - const url::Origin& rp_origin) { + const url::Origin& relying_party_embedder) { permission_autoblocker_->RemoveEmbargoAndResetCounts( - rp_origin.GetURL(), ContentSettingsType::FEDERATED_IDENTITY_API); + relying_party_embedder.GetURL(), + ContentSettingsType::FEDERATED_IDENTITY_API); }
diff --git a/chrome/browser/webid/federated_identity_api_permission_context.h b/chrome/browser/webid/federated_identity_api_permission_context.h index 18d427f..8339c41 100644 --- a/chrome/browser/webid/federated_identity_api_permission_context.h +++ b/chrome/browser/webid/federated_identity_api_permission_context.h
@@ -39,9 +39,11 @@ // content::FederatedIdentityApiPermissionContextDelegate: content::FederatedIdentityApiPermissionContextDelegate::PermissionStatus - GetApiPermissionStatus(const url::Origin& rp_origin) override; - void RecordDismissAndEmbargo(const url::Origin& rp_origin) override; - void RemoveEmbargoAndResetCounts(const url::Origin& rp_origin) override; + GetApiPermissionStatus(const url::Origin& relying_party_embedder) override; + void RecordDismissAndEmbargo( + const url::Origin& relying_party_embedder) override; + void RemoveEmbargoAndResetCounts( + const url::Origin& relying_party_embedder) override; private: const raw_ptr<HostContentSettingsMap> host_content_settings_map_;
diff --git a/chrome/browser/webid/federated_identity_sharing_permission_context.cc b/chrome/browser/webid/federated_identity_sharing_permission_context.cc index 4754788a..e6bdfdb 100644 --- a/chrome/browser/webid/federated_identity_sharing_permission_context.cc +++ b/chrome/browser/webid/federated_identity_sharing_permission_context.cc
@@ -28,16 +28,19 @@ ~FederatedIdentitySharingPermissionContext() = default; bool FederatedIdentitySharingPermissionContext::HasSharingPermission( - const url::Origin& relying_party, + const url::Origin& relying_party_requester, + const url::Origin& relying_party_embedder, const url::Origin& identity_provider, const std::string& account_id) { - return HasPermission(relying_party, relying_party, identity_provider, - account_id); + return HasPermission(relying_party_requester, relying_party_embedder, + identity_provider, account_id); } void FederatedIdentitySharingPermissionContext::GrantSharingPermission( - const url::Origin& relying_party, + const url::Origin& relying_party_requester, + const url::Origin& relying_party_embedder, const url::Origin& identity_provider, const std::string& account_id) { - GrantPermission(relying_party, relying_party, identity_provider, account_id); + GrantPermission(relying_party_requester, relying_party_embedder, + identity_provider, account_id); }
diff --git a/chrome/browser/webid/federated_identity_sharing_permission_context.h b/chrome/browser/webid/federated_identity_sharing_permission_context.h index 747e88b8..5c7a296 100644 --- a/chrome/browser/webid/federated_identity_sharing_permission_context.h +++ b/chrome/browser/webid/federated_identity_sharing_permission_context.h
@@ -32,10 +32,12 @@ const FederatedIdentitySharingPermissionContext&) = delete; // content::FederatedIdentitySharingPermissionContextDelegate: - bool HasSharingPermission(const url::Origin& relying_party, + bool HasSharingPermission(const url::Origin& relying_party_requester, + const url::Origin& relying_party_embedder, const url::Origin& identity_provider, const std::string& account_id) override; - void GrantSharingPermission(const url::Origin& relying_party, + void GrantSharingPermission(const url::Origin& relying_party_requester, + const url::Origin& relying_party_embedder, const url::Origin& identity_provider, const std::string& account_id) override; };
diff --git a/chrome/browser/webshare/share_service_browsertest.cc b/chrome/browser/webshare/share_service_browsertest.cc index 4e18f25..7fd02a1 100644 --- a/chrome/browser/webshare/share_service_browsertest.cc +++ b/chrome/browser/webshare/share_service_browsertest.cc
@@ -15,8 +15,10 @@ #include "chrome/test/base/ui_test_utils.h" #include "components/safe_browsing/core/browser/db/fake_database_manager.h" #include "content/public/browser/browser_task_traits.h" +#include "content/public/browser/render_frame_host.h" #include "content/public/test/browser_test.h" #include "content/public/test/browser_test_utils.h" +#include "content/public/test/prerender_test_util.h" #include "net/test/embedded_test_server/embedded_test_server.h" #if BUILDFLAG(IS_CHROMEOS) @@ -165,3 +167,61 @@ EXPECT_EQ("share failed: NotAllowedError: Permission denied", content::EvalJs(contents, "share_pdf_file()")); } + +class ShareServicePrerenderBrowserTest : public ShareServiceBrowserTest { + public: + ShareServicePrerenderBrowserTest() + : prerender_helper_( + base::BindRepeating(&ShareServicePrerenderBrowserTest::web_contents, + base::Unretained(this))) {} + ~ShareServicePrerenderBrowserTest() override = default; + + protected: + content::WebContents* web_contents() { + return browser()->tab_strip_model()->GetActiveWebContents(); + } + + content::test::PrerenderTestHelper prerender_helper_; +}; + +IN_PROC_BROWSER_TEST_F(ShareServicePrerenderBrowserTest, Text) { + base::HistogramTester histogram_tester; + ASSERT_TRUE(embedded_test_server()->Start()); + ASSERT_TRUE(ui_test_utils::NavigateToURL( + browser(), embedded_test_server()->GetURL("/empty.html"))); + + content::WebContents* const contents = + browser()->tab_strip_model()->GetActiveWebContents(); + + // Start a prerender. + const GURL kPrerenderUrl = + embedded_test_server()->GetURL("/webshare/index.html"); + const int kPrerenderHostId = prerender_helper_.AddPrerender((kPrerenderUrl)); + ASSERT_EQ(prerender_helper_.GetHostForUrl(kPrerenderUrl), kPrerenderHostId); + + content::RenderFrameHost* prerender_rfh = + prerender_helper_.GetPrerenderedMainFrameHost(kPrerenderHostId); + EXPECT_EQ(prerender_rfh->GetLifecycleState(), + content::RenderFrameHost::LifecycleState::kPrerendering); + const std::string script = "share_text('hello')"; + const content::EvalJsResult prerendered_result = + content::EvalJs(prerender_rfh, script); + EXPECT_EQ( + "share failed: NotAllowedError: Failed to execute 'share' on " + "'Navigator': Must be handling a user gesture to perform a share " + "request.", + prerendered_result); + histogram_tester.ExpectBucketCount(kWebShareApiCountMetric, + WebShareMethod::kShare, 0); + + // Activate the prerendered page. + prerender_helper_.NavigatePrimaryPage(kPrerenderUrl); + EXPECT_EQ(prerender_rfh->GetLifecycleState(), + content::RenderFrameHost::LifecycleState::kActive); + ASSERT_EQ(kPrerenderUrl, contents->GetLastCommittedURL()); + const content::EvalJsResult activated_result = + content::EvalJs(prerender_rfh, script); + EXPECT_EQ("share succeeded", activated_result); + histogram_tester.ExpectBucketCount(kWebShareApiCountMetric, + WebShareMethod::kShare, 1); +}
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt index c8b5704..f500e22 100644 --- a/chrome/build/linux.pgo.txt +++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@ -chrome-linux-main-1660910358-3979b2240422bff46d6633737995e90099e11c4e.profdata +chrome-linux-main-1660931915-e3d237b7ef4f5e5f5b092bf2ee5dbef7471660b5.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt index d40fe43c..7bbe3785 100644 --- a/chrome/build/mac-arm.pgo.txt +++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@ -chrome-mac-arm-main-1660910358-dbbb692954d2f6c5c460d1e18b608df67d4b7bba.profdata +chrome-mac-arm-main-1660931915-434ee39902a2a49541bf1e885174b731ed5873e1.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt index 701188a..fd8c346 100644 --- a/chrome/build/mac.pgo.txt +++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@ -chrome-mac-main-1660910358-c6646bdc2ee417472d5c644bb06a3e2f1932d24b.profdata +chrome-mac-main-1660931915-01748db33f1d1293e8643b2d0242151ac08d534c.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt index 7e38ab6..06ebaeb6 100644 --- a/chrome/build/win32.pgo.txt +++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@ -chrome-win32-main-1660921165-2821267ae30bb34326dd7cb61af0ee5f5916fa36.profdata +chrome-win32-main-1660931915-829fed840eefe53900738c1b6b18a780456e26b4.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt index be7f096b..8aa54861 100644 --- a/chrome/build/win64.pgo.txt +++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@ -chrome-win64-main-1660910358-f8f0ae66331a69857533cab712c957eb33416a16.profdata +chrome-win64-main-1660931915-c3a2098161c9e48dacfae89eda246a32068f0f1e.profdata
diff --git a/chrome/common/webui_url_constants.cc b/chrome/common/webui_url_constants.cc index 29c0e6b..44b10b24 100644 --- a/chrome/common/webui_url_constants.cc +++ b/chrome/common/webui_url_constants.cc
@@ -682,6 +682,7 @@ #if !BUILDFLAG(IS_ANDROID) kChromeUIWebAppInternalsHost, #endif + content::kChromeUIPrivateAggregationInternalsHost, content::kChromeUIAttributionInternalsHost, content::kChromeUIBlobInternalsHost, content::kChromeUIDinoHost,
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 6841235..f0997bf1 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -3847,6 +3847,9 @@ "../browser/ash/policy/login/signin_profile_extensions_policy_browsertest.cc", "../browser/ash/policy/networking/network_policy_application_browsertest.cc", "../browser/ash/policy/networking/policy_certs_browsertest.cc", + "../browser/ash/policy/reporting/metrics_reporting/metric_browsertest_utils.cc", + "../browser/ash/policy/reporting/metrics_reporting/metric_browsertest_utils.h", + "../browser/ash/policy/reporting/metrics_reporting/network/network_info_sampler_browsertest.cc", "../browser/ash/policy/reporting/metrics_reporting/usb/usb_events_browsertest.cc", "../browser/ash/policy/reporting/user_added_removed/user_added_removed_reporter_browsertest.cc", "../browser/ash/policy/status_collector/child_status_collector_browsertest.cc", @@ -7059,6 +7062,7 @@ "../browser/extensions/api/document_scan/document_scan_api_unittest.cc", "../browser/media/platform_verification_chromeos_unittest.cc", "../browser/policy/system_features_disable_list_policy_handler_unittest.cc", + "../browser/speech/tts_crosapi_util_unittest.cc", "../browser/ui/webui/certificate_provisioning_ui_handler_unittest.cc", "chromeos/printing/fake_local_printer_chromeos.cc", "chromeos/printing/fake_local_printer_chromeos.h", @@ -8359,6 +8363,7 @@ "../browser/ui/webui/app_home/mock_app_home_page.cc", "../browser/ui/webui/app_home/mock_app_home_page.h", "../browser/ui/webui/ntp/app_launcher_handler_unittest.cc", + "../browser/ui/webui/whats_new/whats_new_util_unittest.cc", ] deps += [ @@ -9521,6 +9526,7 @@ "../browser/ui/views/test/view_event_test_base.cc", "../browser/ui/views/test/view_event_test_base.h", "../browser/ui/views/toolbar/reload_button_browsertest.cc", + "../browser/ui/views/toolbar/toolbar_action_hover_card_bubble_view_interactive_uitest.cc", "../browser/ui/views/toolbar/toolbar_view_interactive_uitest.cc", "../browser/ui/views/translate/translate_bubble_test_utils_views.cc", "../browser/ui/views/translate/translate_bubble_view_interactive_uitest.cc",
diff --git a/chrome/test/base/chromeos/ash_browser_test_starter.cc b/chrome/test/base/chromeos/ash_browser_test_starter.cc index 1095c18..2ba1420d 100644 --- a/chrome/test/base/chromeos/ash_browser_test_starter.cc +++ b/chrome/test/base/chromeos/ash_browser_test_starter.cc
@@ -41,7 +41,8 @@ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); scoped_feature_list_.InitWithFeatures( - {chromeos::features::kLacrosSupport, chromeos::features::kLacrosPrimary}, + {chromeos::features::kLacrosSupport, chromeos::features::kLacrosPrimary, + chromeos::features::kLacrosOnly}, {}); command_line->AppendSwitch("enable-wayland-server"); command_line->AppendSwitch("no-startup-window");
diff --git a/chrome/test/data/safe_browsing/visual_model_android.tflite b/chrome/test/data/safe_browsing/visual_model_android.tflite index 8478ec7..922c0d8d 100644 --- a/chrome/test/data/safe_browsing/visual_model_android.tflite +++ b/chrome/test/data/safe_browsing/visual_model_android.tflite Binary files differ
diff --git a/chrome/test/data/webui/cr_components/help_bubble_mixin_test.ts b/chrome/test/data/webui/cr_components/help_bubble_mixin_test.ts index ce99e3bf..4d27d000 100644 --- a/chrome/test/data/webui/cr_components/help_bubble_mixin_test.ts +++ b/chrome/test/data/webui/cr_components/help_bubble_mixin_test.ts
@@ -6,7 +6,7 @@ import 'chrome://resources/cr_components/help_bubble/help_bubble.js'; import {HelpBubbleElement} from 'chrome://resources/cr_components/help_bubble/help_bubble.js'; -import {HelpBubbleClientCallbackRouter, HelpBubbleClientRemote, HelpBubbleHandlerInterface, HelpBubbleParams, HelpBubblePosition} from 'chrome://resources/cr_components/help_bubble/help_bubble.mojom-webui.js'; +import {HelpBubbleArrowPosition, HelpBubbleClientCallbackRouter, HelpBubbleClientRemote, HelpBubbleHandlerInterface, HelpBubbleParams} from 'chrome://resources/cr_components/help_bubble/help_bubble.mojom-webui.js'; import {HelpBubbleMixin, HelpBubbleMixinInterface} from 'chrome://resources/cr_components/help_bubble/help_bubble_mixin.js'; import {HelpBubbleProxy, HelpBubbleProxyImpl} from 'chrome://resources/cr_components/help_bubble/help_bubble_proxy.js'; import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; @@ -158,7 +158,7 @@ const defaultParams: HelpBubbleParams = new HelpBubbleParams(); defaultParams.nativeIdentifier = PARAGRAPH_NATIVE_ID; defaultParams.closeButtonAltText = CLOSE_BUTTON_ALT_TEXT; - defaultParams.position = HelpBubblePosition.ABOVE; + defaultParams.position = HelpBubbleArrowPosition.BOTTOM_CENTER; defaultParams.bodyText = 'This is a help bubble.'; defaultParams.buttons = []; @@ -258,7 +258,7 @@ const params: HelpBubbleParams = new HelpBubbleParams(); params.nativeIdentifier = 'This is an unregistered identifier'; params.closeButtonAltText = CLOSE_BUTTON_ALT_TEXT; - params.position = HelpBubblePosition.ABOVE; + params.position = HelpBubbleArrowPosition.BOTTOM_CENTER; params.bodyText = 'This is a help bubble.'; params.buttons = []; @@ -372,7 +372,7 @@ const paramsWithTitle: HelpBubbleParams = new HelpBubbleParams(); paramsWithTitle.nativeIdentifier = TITLE_NATIVE_ID; paramsWithTitle.closeButtonAltText = CLOSE_BUTTON_ALT_TEXT; - paramsWithTitle.position = HelpBubblePosition.BELOW; + paramsWithTitle.position = HelpBubbleArrowPosition.TOP_CENTER; paramsWithTitle.bodyText = 'This is another help bubble.'; paramsWithTitle.titleText = 'This is a title'; paramsWithTitle.buttons = []; @@ -411,7 +411,7 @@ const paramsWithProgress: HelpBubbleParams = new HelpBubbleParams(); paramsWithProgress.nativeIdentifier = LIST_NATIVE_ID; paramsWithProgress.closeButtonAltText = CLOSE_BUTTON_ALT_TEXT; - paramsWithProgress.position = HelpBubblePosition.BELOW; + paramsWithProgress.position = HelpBubbleArrowPosition.TOP_CENTER; paramsWithProgress.bodyText = 'This is another help bubble.'; paramsWithProgress.progress = {current: 1, total: 3}; paramsWithProgress.buttons = []; @@ -471,7 +471,7 @@ const buttonParams: HelpBubbleParams = new HelpBubbleParams(); buttonParams.nativeIdentifier = PARAGRAPH_NATIVE_ID; buttonParams.closeButtonAltText = CLOSE_BUTTON_ALT_TEXT; - buttonParams.position = HelpBubblePosition.BELOW; + buttonParams.position = HelpBubbleArrowPosition.TOP_CENTER; buttonParams.bodyText = 'This is another help bubble.'; buttonParams.titleText = 'This is a title'; buttonParams.buttons = [
diff --git a/chrome/test/data/webui/cr_components/help_bubble_test.ts b/chrome/test/data/webui/cr_components/help_bubble_test.ts index 61ecd124..70e3138 100644 --- a/chrome/test/data/webui/cr_components/help_bubble_test.ts +++ b/chrome/test/data/webui/cr_components/help_bubble_test.ts
@@ -7,7 +7,7 @@ import {CrButtonElement} from '//resources/cr_elements/cr_button/cr_button.js'; import {HELP_BUBBLE_DISMISSED_EVENT, HelpBubbleDismissedEvent, HelpBubbleElement} from 'chrome://resources/cr_components/help_bubble/help_bubble.js'; -import {HelpBubbleButtonParams, HelpBubblePosition} from 'chrome://resources/cr_components/help_bubble/help_bubble.mojom-webui.js'; +import {HelpBubbleArrowPosition, HelpBubbleButtonParams} from 'chrome://resources/cr_components/help_bubble/help_bubble.mojom-webui.js'; import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js'; import {isVisible, waitAfterNextRender} from 'chrome://webui-test/test_util.js'; @@ -80,7 +80,7 @@ test('help bubble shows and anchors correctly', () => { helpBubble.anchorId = 'p1'; - helpBubble.position = HelpBubblePosition.BELOW; + helpBubble.position = HelpBubbleArrowPosition.TOP_CENTER; helpBubble.bodyText = HELP_BUBBLE_BODY; helpBubble.show(); @@ -98,7 +98,7 @@ test('help bubble titles shows', () => { helpBubble.anchorId = 'p1'; - helpBubble.position = HelpBubblePosition.BELOW; + helpBubble.position = HelpBubbleArrowPosition.TOP_CENTER; helpBubble.bodyText = HELP_BUBBLE_BODY; helpBubble.titleText = HELP_BUBBLE_TITLE; helpBubble.show(); @@ -116,7 +116,7 @@ test('help bubble titles hides when no title set', () => { helpBubble.anchorId = 'p1'; - helpBubble.position = HelpBubblePosition.BELOW; + helpBubble.position = HelpBubbleArrowPosition.TOP_CENTER; helpBubble.bodyText = HELP_BUBBLE_BODY; helpBubble.show(); @@ -129,7 +129,7 @@ test('help bubble closes', () => { helpBubble.anchorId = 'title'; - helpBubble.position = HelpBubblePosition.BELOW; + helpBubble.position = HelpBubbleArrowPosition.TOP_CENTER; helpBubble.bodyText = HELP_BUBBLE_BODY; helpBubble.show(); @@ -147,7 +147,7 @@ test('help bubble open close open', () => { helpBubble.anchorId = 'title'; - helpBubble.position = HelpBubblePosition.BELOW; + helpBubble.position = HelpBubbleArrowPosition.TOP_CENTER; helpBubble.bodyText = HELP_BUBBLE_BODY; helpBubble.show(); helpBubble.hide(); @@ -184,7 +184,7 @@ }; helpBubble.addEventListener(HELP_BUBBLE_DISMISSED_EVENT, callback); helpBubble.anchorId = 'title'; - helpBubble.position = HelpBubblePosition.BELOW; + helpBubble.position = HelpBubbleArrowPosition.TOP_CENTER; helpBubble.bodyText = HELP_BUBBLE_BODY; helpBubble.show(); await waitAfterNextRender(helpBubble); @@ -196,7 +196,7 @@ test('help bubble adds one button', async () => { helpBubble.anchorId = 'title'; - helpBubble.position = HelpBubblePosition.BELOW; + helpBubble.position = HelpBubbleArrowPosition.TOP_CENTER; helpBubble.bodyText = HELP_BUBBLE_BODY; helpBubble.buttons = [{text: 'button1', isDefault: false}]; helpBubble.show(); @@ -214,7 +214,7 @@ test('help bubble adds several buttons', async () => { helpBubble.anchorId = 'title'; - helpBubble.position = HelpBubblePosition.BELOW; + helpBubble.position = HelpBubbleArrowPosition.TOP_CENTER; helpBubble.bodyText = HELP_BUBBLE_BODY; helpBubble.buttons = [ {text: 'button1', isDefault: false}, @@ -238,7 +238,7 @@ test('help bubble adds default button', async () => { helpBubble.anchorId = 'title'; - helpBubble.position = HelpBubblePosition.BELOW; + helpBubble.position = HelpBubbleArrowPosition.TOP_CENTER; helpBubble.bodyText = HELP_BUBBLE_BODY; helpBubble.buttons = [{text: 'button1', isDefault: true}]; helpBubble.show(); @@ -258,7 +258,7 @@ test('help bubble adds default button among several', async () => { helpBubble.anchorId = 'title'; - helpBubble.position = HelpBubblePosition.BELOW; + helpBubble.position = HelpBubbleArrowPosition.TOP_CENTER; helpBubble.bodyText = HELP_BUBBLE_BODY; helpBubble.buttons = THREE_BUTTONS_MIDDLE_DEFAULT; helpBubble.show(); @@ -303,7 +303,7 @@ }; helpBubble.addEventListener(HELP_BUBBLE_DISMISSED_EVENT, callback); helpBubble.anchorId = 'title'; - helpBubble.position = HelpBubblePosition.BELOW; + helpBubble.position = HelpBubbleArrowPosition.TOP_CENTER; helpBubble.bodyText = HELP_BUBBLE_BODY; helpBubble.buttons = THREE_BUTTONS_MIDDLE_DEFAULT; @@ -323,7 +323,7 @@ test('help bubble with no progress doesn\'t show progress', async () => { helpBubble.anchorId = 'title'; - helpBubble.position = HelpBubblePosition.BELOW; + helpBubble.position = HelpBubbleArrowPosition.TOP_CENTER; helpBubble.bodyText = HELP_BUBBLE_BODY; helpBubble.buttons = THREE_BUTTONS_MIDDLE_DEFAULT; @@ -341,7 +341,7 @@ 'help bubble with no progress and title doesn\'t show progress', async () => { helpBubble.anchorId = 'title'; - helpBubble.position = HelpBubblePosition.BELOW; + helpBubble.position = HelpBubbleArrowPosition.TOP_CENTER; helpBubble.bodyText = HELP_BUBBLE_BODY; helpBubble.titleText = HELP_BUBBLE_TITLE; helpBubble.buttons = THREE_BUTTONS_MIDDLE_DEFAULT; @@ -363,7 +363,7 @@ test('help bubble with progress shows progress', async () => { helpBubble.anchorId = 'title'; - helpBubble.position = HelpBubblePosition.BELOW; + helpBubble.position = HelpBubbleArrowPosition.TOP_CENTER; helpBubble.bodyText = HELP_BUBBLE_BODY; helpBubble.progress = {current: 1, total: 3}; helpBubble.buttons = THREE_BUTTONS_MIDDLE_DEFAULT; @@ -387,7 +387,7 @@ test('help bubble with progress and title shows progress', async () => { helpBubble.anchorId = 'title'; - helpBubble.position = HelpBubblePosition.BELOW; + helpBubble.position = HelpBubbleArrowPosition.TOP_CENTER; helpBubble.bodyText = HELP_BUBBLE_BODY; helpBubble.titleText = HELP_BUBBLE_TITLE; helpBubble.progress = {current: 1, total: 2}; @@ -416,7 +416,7 @@ test('help bubble with full progress', async () => { helpBubble.anchorId = 'title'; - helpBubble.position = HelpBubblePosition.BELOW; + helpBubble.position = HelpBubbleArrowPosition.TOP_CENTER; helpBubble.bodyText = HELP_BUBBLE_BODY; helpBubble.progress = {current: 2, total: 2}; @@ -435,7 +435,7 @@ test('help bubble with empty progress', async () => { helpBubble.anchorId = 'title'; - helpBubble.position = HelpBubblePosition.BELOW; + helpBubble.position = HelpBubbleArrowPosition.TOP_CENTER; helpBubble.bodyText = HELP_BUBBLE_BODY; helpBubble.progress = {current: 0, total: 2};
diff --git a/chrome/test/data/webui/settings/chromeos/os_settings_v3_browsertest.js b/chrome/test/data/webui/settings/chromeos/os_settings_v3_browsertest.js index e7ef248e..399a967 100644 --- a/chrome/test/data/webui/settings/chromeos/os_settings_v3_browsertest.js +++ b/chrome/test/data/webui/settings/chromeos/os_settings_v3_browsertest.js
@@ -420,7 +420,6 @@ ['OSSettingsMenu', 'os_settings_menu_test.js'], ['ParentalControlsPage', 'parental_controls_page_test.js'], ['PeoplePage', 'os_people_page_test.js'], - ['PeoplePageChangePicture', 'people_page_change_picture_test.js'], ['PeoplePageQuickUnlock', 'quick_unlock_authenticate_browsertest_chromeos.js'], [ 'PersonalizationPage',
diff --git a/chrome/test/data/webui/settings/chromeos/people_page_change_picture_test.js b/chrome/test/data/webui/settings/chromeos/people_page_change_picture_test.js deleted file mode 100644 index 467016c..0000000 --- a/chrome/test/data/webui/settings/chromeos/people_page_change_picture_test.js +++ /dev/null
@@ -1,403 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import {ChangePictureBrowserProxyImpl, routes} from 'chrome://os-settings/chromeos/os_settings.js'; -import {CrPicture} from 'chrome://resources/ash/common/cr_picture/cr_picture_types.js'; -import {webUIListenerCallback} from 'chrome://resources/js/cr.m.js'; -import {pressAndReleaseKeyOn} from 'chrome://resources/polymer/v3_0/iron-test-helpers/mock-interactions.js'; -import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; - -import {assertEquals, assertFalse, assertTrue} from '../../chai_assert.js'; -import {TestBrowserProxy} from '../../test_browser_proxy.js'; - -/** @implements {ChangePictureBrowserProxy} */ -class TestChangePictureBrowserProxy extends TestBrowserProxy { - constructor() { - super([ - 'initialize', - 'selectDefaultImage', - 'selectOldImage', - 'selectProfileImage', - 'photoTaken', - 'chooseFile', - 'requestSelectedImage', - ]); - } - - /** @override */ - initialize() { - webUIListenerCallback( - 'profile-image-changed', 'fake-profile-image-url', - false /* selected */); - - const fakeCurrentDefaultImages = [ - { - index: 2, - title: 'Title2', - url: 'chrome://foo/2.png', - }, - { - index: 3, - title: 'Title3', - url: 'chrome://foo/3.png', - }, - ]; - webUIListenerCallback('default-images-changed', { - current_default_images: fakeCurrentDefaultImages, - }); - - this.methodCalled('initialize'); - } - - /** @override */ - selectDefaultImage(imageUrl) { - webUIListenerCallback('selected-image-changed', imageUrl); - this.methodCalled('selectDefaultImage', imageUrl); - } - - /** @override */ - selectOldImage() { - webUIListenerCallback('old-image-changed', { - url: 'fake-old-image.jpg', - index: 1, - }); - this.methodCalled('selectOldImage'); - } - - /** @override */ - selectProfileImage() { - webUIListenerCallback( - 'profile-image-changed', 'fake-profile-image-url', true /* selected */); - this.methodCalled('selectProfileImage'); - } - - /** @override */ - photoTaken() { - this.methodCalled('photoTaken'); - } - - /** @override */ - chooseFile() { - this.methodCalled('chooseFile'); - } - - /** @override */ - requestSelectedImage() { - this.methodCalled('requestSelectedImage'); - } -} - -suite('ChangePictureTests', function() { - let changePicture = null; - let browserProxy = null; - let crPicturePane = null; - let crPictureList = null; - - const LEFT_KEY_CODE = 37; - const RIGHT_KEY_CODE = 39; - - /** - * @return {Array<HTMLElement>} Traverses the DOM tree to find the lowest - * level active element and returns an array of the node path down the - * tree, skipping shadow roots. - */ - function getActiveElementPath() { - let node = document.activeElement; - const path = []; - while (node) { - path.push(node); - node = (node.shadowRoot || node).activeElement; - } - return path; - } - - - suiteSetup(function() { - loadTimeData.overrideValues({ - profilePhoto: 'Fake Profile Photo description', - }); - }); - - setup(async function() { - browserProxy = new TestChangePictureBrowserProxy(); - ChangePictureBrowserProxyImpl.setInstanceForTesting(browserProxy); - PolymerTest.clearBody(); - changePicture = document.createElement('settings-change-picture'); - document.body.appendChild(changePicture); - - crPicturePane = changePicture.shadowRoot.querySelector('cr-picture-pane'); - assertTrue(!!crPicturePane); - - crPictureList = changePicture.shadowRoot.querySelector('cr-picture-list'); - assertTrue(!!crPictureList); - - changePicture.currentRouteChanged(routes.CHANGE_PICTURE); - - await browserProxy.whenCalled('initialize'); - flush(); - }); - - teardown(function() { - changePicture.remove(); - }); - - test('TraverseCameraIconUsingArrows', function() { - // Force the camera to be present. - webUIListenerCallback('camera-presence-changed', true); - flush(); - assertTrue(crPictureList.cameraPresent); - - // Click camera icon. - const cameraImage = crPictureList.$.cameraImage; - cameraImage.click(); - flush(); - - assertTrue(crPictureList.cameraSelected_); - const crCamera = crPicturePane.shadowRoot.querySelector('#camera'); - assertTrue(!!crCamera); - - // Mock camera's video stream beginning to play. - crCamera.$.cameraVideo.dispatchEvent(new Event('canplay')); - flush(); - - // "Take photo" button should be active. - let activeElementPath = getActiveElementPath(); - assertTrue(activeElementPath.includes(crPicturePane)); - assertFalse(activeElementPath.includes(crPictureList)); - - // Press 'Right' key on active element. - pressAndReleaseKeyOn(activeElementPath.pop(), RIGHT_KEY_CODE); - flush(); - - // A profile picture open should be active. - activeElementPath = getActiveElementPath(); - assertFalse(crPictureList.cameraSelected_); - assertFalse(activeElementPath.includes(crPicturePane)); - assertTrue(activeElementPath.includes(crPictureList)); - - // Press 'Left' key on active element. - pressAndReleaseKeyOn(activeElementPath.pop(), LEFT_KEY_CODE); - flush(); - - // Mock camera's video stream beginning to play. - crCamera.$.cameraVideo.dispatchEvent(new Event('canplay')); - flush(); - - // "Take photo" button should be active again. - activeElementPath = getActiveElementPath(); - assertTrue(crPictureList.cameraSelected_); - assertTrue(activeElementPath.includes(crPicturePane)); - assertFalse(activeElementPath.includes(crPictureList)); - }); - - test('ChangePictureSelectCamera', async function() { - // Force the camera to be absent, even if it's actually present. - webUIListenerCallback('camera-presence-changed', false); - flush(); - - await new Promise(function(resolve) { - changePicture.async(resolve); - }); - let camera = crPicturePane.shadowRoot.querySelector('#camera'); - assertFalse(crPicturePane.cameraPresent); - assertFalse(crPicturePane.cameraActive_); - assertFalse(!!camera && camera.hidden); - - webUIListenerCallback('camera-presence-changed', true); - flush(); - await new Promise(function(resolve) { - changePicture.async(resolve); - }); - camera = crPicturePane.shadowRoot.querySelector('#camera'); - assertTrue(crPicturePane.cameraPresent); - assertFalse(crPicturePane.cameraActive_); - assertFalse(!!camera && camera.hidden); - - const cameraImage = crPictureList.$.cameraImage; - cameraImage.click(); - flush(); - await new Promise(function(resolve) { - changePicture.async(resolve); - }); - camera = crPicturePane.shadowRoot.querySelector('#camera'); - assertTrue(crPicturePane.cameraActive_); - assertTrue(!!camera && !camera.hidden); - assertEquals( - CrPicture.SelectionTypes.CAMERA, - changePicture.selectedItem_.dataset.type); - const discard = crPicturePane.shadowRoot.querySelector('#discard'); - assertTrue(!discard || discard.hidden); - - // Ensure that the camera is deactivated if user navigates away. - changePicture.currentRouteChanged(routes.BASIC); - await new Promise(function(resolve) { - changePicture.async(resolve); - }); - assertFalse(crPicturePane.cameraActive_); - }); - - test('ChangePictureProfileImage', async function() { - const profileImage = crPictureList.$.profileImage; - assertTrue(!!profileImage); - - assertEquals(null, changePicture.selectedItem_); - profileImage.click(); - - await browserProxy.whenCalled('selectProfileImage'); - flush(); - - assertEquals( - CrPicture.SelectionTypes.PROFILE, - changePicture.selectedItem_.dataset.type); - assertFalse(crPicturePane.cameraActive_); - const discard = crPicturePane.shadowRoot.querySelector('#discard'); - assertTrue(!discard || discard.hidden); - - // Ensure that the selection is restored after navigating away and - // then back to the subpage. - changePicture.currentRouteChanged(routes.BASIC); - changePicture.currentRouteChanged(routes.CHANGE_PICTURE); - assertEquals(null, changePicture.selectedItem_); - }); - - test('ChangePictureDeprecatedImage', async function() { - webUIListenerCallback( - 'preview-deprecated-image', {url: 'fake-old-image.jpg'}); - flush(); - - // Expect the deprecated image is presented in picture pane. - assertEquals(CrPicture.SelectionTypes.DEPRECATED, crPicturePane.imageType); - const image = crPicturePane.shadowRoot.querySelector('#image'); - assertTrue(!!image); - assertFalse(image.hidden); - const discard = crPicturePane.shadowRoot.querySelector('#discard'); - assertTrue(!!discard); - assertTrue(discard.hidden); - }); - - test('ChangePictureDeprecatedImageWithSourceInfo', async function() { - const fakeAuthor = 'FakeAuthor'; - const fakeWebsite = 'http://foo1.com'; - webUIListenerCallback('preview-deprecated-image', { - url: 'fake-old-image.jpg', - author: fakeAuthor, - website: fakeWebsite, - }); - flush(); - - // Expect the deprecated image is presented in picture pane. - assertEquals(CrPicture.SelectionTypes.DEPRECATED, crPicturePane.imageType); - const image = crPicturePane.shadowRoot.querySelector('#image'); - assertTrue(!!image); - assertFalse(image.hidden); - const discard = crPicturePane.shadowRoot.querySelector('#discard'); - assertTrue(!!discard); - assertTrue(discard.hidden); - const sourceInfo = changePicture.shadowRoot.querySelector('#sourceInfo'); - assertTrue(!!sourceInfo); - assertFalse(sourceInfo.hidden); - assertEquals(changePicture.authorInfo_, 'Photo by ' + fakeAuthor); - assertEquals(changePicture.websiteInfo_, fakeWebsite); - }); - - test('ChangePictureFileImage', async function() { - assertFalse(!!changePicture.selectedItem_); - - // By default there is no old image and the element is hidden. - const oldImage = crPictureList.$.oldImage; - assertTrue(!!oldImage); - assertTrue(oldImage.hidden); - - webUIListenerCallback('old-image-changed', 'file-image.jpg'); - flush(); - - await new Promise(function(resolve) { - changePicture.async(resolve); - }); - assertTrue(!!changePicture.selectedItem_); - // Expect the old image to be selected once an old image is sent via - // the native interface. - assertEquals( - CrPicture.SelectionTypes.OLD, changePicture.selectedItem_.dataset.type); - assertFalse(oldImage.hidden); - assertFalse(crPicturePane.cameraActive_); - const discard = crPicturePane.shadowRoot.querySelector('#discard'); - assertTrue(!!discard); - assertFalse(discard.hidden); - // Ensure the file image does not show the source info. - const sourceInfo = changePicture.shadowRoot.querySelector('#sourceInfo'); - assertTrue(!sourceInfo || sourceInfo.hidden); - }); - - test('ChangePictureSelectFirstDefaultImage', async function() { - const firstDefaultImage = - crPictureList.shadowRoot.querySelector('img[data-type="default"]'); - assertTrue(!!firstDefaultImage); - - firstDefaultImage.click(); - - let imageUrl = await browserProxy.whenCalled('selectDefaultImage'); - assertEquals('chrome://foo/2.png', imageUrl); - - flush(); - assertEquals( - CrPicture.SelectionTypes.DEFAULT, - changePicture.selectedItem_.dataset.type); - assertEquals(firstDefaultImage, changePicture.selectedItem_); - assertFalse(crPicturePane.cameraActive_); - const discard = crPicturePane.shadowRoot.querySelector('#discard'); - assertTrue(!discard || discard.hidden); - - // Now verify that arrow keys actually select the new image. - browserProxy.resetResolver('selectDefaultImage'); - pressAndReleaseKeyOn(changePicture.selectedItem_, RIGHT_KEY_CODE); - imageUrl = await browserProxy.whenCalled('selectDefaultImage'); - assertEquals('chrome://foo/3.png', imageUrl); - }); - - test('ChangePictureRestoreImageAfterDiscard', async function() { - const firstDefaultImage = - crPictureList.shadowRoot.querySelector('img[data-type="default"]'); - assertTrue(!!firstDefaultImage); - - firstDefaultImage.click(); - - await browserProxy.whenCalled('selectDefaultImage'); - flush(); - assertEquals(firstDefaultImage, changePicture.selectedItem_); - - webUIListenerCallback('old-image-changed', 'fake-old-image.jpg'); - - flush(); - assertEquals( - CrPicture.SelectionTypes.OLD, changePicture.selectedItem_.dataset.type); - - const discardButton = - crPicturePane.shadowRoot.querySelector('#discard cr-icon-button'); - assertTrue(!!discardButton); - discardButton.click(); - - flush(); - const profileImage = crPictureList.$.profileImage; - assertTrue(!!profileImage); - assertEquals(profileImage, changePicture.selectedItem_); - }); - - test('ChangePictureImagePendingStateCheck', async function() { - // oldImagePending_ should be false when no camera photo pending. - assertFalse(changePicture.oldImagePending_); - assertEquals(crPictureList.oldImageUrl_, ''); - // Simulate photo taken event. - crPicturePane.fire('photo-taken', {photoDataUrl: 'camera-image.jpg'}); - flush(); - // oldImagePending_ should be true due to pending camera image. - assertTrue(changePicture.oldImagePending_); - - webUIListenerCallback('old-image-changed', 'camera-image.jpg'); - flush(); - // oldImagePending_ should be false after the image has been received. - assertFalse(changePicture.oldImagePending_); - assertEquals(crPictureList.oldImageUrl_, 'camera-image.jpg'); - }); -});
diff --git a/chrome/test/data/webui/settings/chromeos/personalization_page_test.js b/chrome/test/data/webui/settings/chromeos/personalization_page_test.js index 9f3074e..5b33db4 100644 --- a/chrome/test/data/webui/settings/chromeos/personalization_page_test.js +++ b/chrome/test/data/webui/settings/chromeos/personalization_page_test.js
@@ -52,34 +52,4 @@ personalizationPage.remove(); Router.getInstance().resetRouteForTesting(); }); - - test('changePicture', function() { - const row = - personalizationPage.shadowRoot.getElementById('changePictureRow'); - assertTrue(!!row); - row.click(); - assertEquals(routes.CHANGE_PICTURE, Router.getInstance().getCurrentRoute()); - }); - - test('Deep link to change account picture', async () => { - const params = new URLSearchParams(); - params.append('settingId', '503'); - Router.getInstance().navigateTo(routes.CHANGE_PICTURE, params); - - flush(); - - await waitAfterNextRender(personalizationPage); - - const changePicturePage = - personalizationPage.shadowRoot.querySelector('settings-change-picture'); - assertTrue(!!changePicturePage); - const deepLinkElement = - changePicturePage.shadowRoot.querySelector('#pictureList') - .shadowRoot.querySelector('#selector') - .$$('[class="iron-selected"]'); - await waitAfterNextRender(deepLinkElement); - assertEquals( - deepLinkElement, getDeepActiveElement(), - 'Account picture elem should be focused for settingId=503.'); - }); });
diff --git a/chrome/test/data/webui/settings/fake_language_settings_private.ts b/chrome/test/data/webui/settings/fake_language_settings_private.ts index 1080eb4c..b3ce8f4 100644 --- a/chrome/test/data/webui/settings/fake_language_settings_private.ts +++ b/chrome/test/data/webui/settings/fake_language_settings_private.ts
@@ -457,6 +457,14 @@ type: chrome.settingsPrivate.PrefType.LIST, value: ['en-US'], }, + { + key: 'translate_site_blocklist_with_time', + type: chrome.settingsPrivate.PrefType.LIST, + value: { + 'ru.wikipedia.org': '13305315102292953', + 'de.wikipedia.org': '13305315083099649', + }, + }, // Note: The real implementation of this pref is actually a dictionary // of {always translate: target}, however only the keys are needed for // testing.
diff --git a/chrome/test/data/webui/tab_search/tab_search_media_tabs_test.ts b/chrome/test/data/webui/tab_search/tab_search_media_tabs_test.ts index 558177a..7d1148e 100644 --- a/chrome/test/data/webui/tab_search/tab_search_media_tabs_test.ts +++ b/chrome/test/data/webui/tab_search/tab_search_media_tabs_test.ts
@@ -151,37 +151,17 @@ test('Show media tab in Audio & Video section', async () => { await setupTest( - createProfileData({ - windows: SAMPLE_WINDOW_DATA_WITH_MEDIA_TAB, - }), - {alsoShowMediaTabsinOpenTabsSection: false}); + createProfileData({windows: SAMPLE_WINDOW_DATA_WITH_MEDIA_TAB})); // One media tab and two non-media tabs. assertEquals(3, queryRows().length); // "Audio and Video" and "Open Tabs" section should both exist. assertEquals(2, queryListTitle().length); }); - test( - 'Show media tab in Audio & Video section and Open Tabs section', - async () => { - await setupTest( - createProfileData({ - windows: SAMPLE_WINDOW_DATA_WITH_MEDIA_TAB, - }), - {alsoShowMediaTabsinOpenTabsSection: true}); - // Only the two media tabs should be duplicated. - assertEquals(4, queryRows().length); - // "Audio and Video" and "Open Tabs" section should both exist. - assertEquals(2, queryListTitle().length); - }); test('Tab is no longer media tab', async () => { await setupTest( - createProfileData({ - windows: SAMPLE_WINDOW_DATA_WITH_MEDIA_TAB, - }), - {alsoShowMediaTabsinOpenTabsSection: false}); - + createProfileData({windows: SAMPLE_WINDOW_DATA_WITH_MEDIA_TAB})); const updatedTab: Tab = createTab({ alertStates: [], tabId: 1, @@ -200,40 +180,11 @@ assertEquals(1, queryListTitle().length); }); - test( - 'Tab is no longer media tab with media tabs also shown in Open Tabs section ', - async () => { - await setupTest( - createProfileData({ - windows: SAMPLE_WINDOW_DATA_WITH_MEDIA_TAB, - }), - {alsoShowMediaTabsinOpenTabsSection: true}); - - const updatedTab: Tab = createTab({ - alertStates: [], - tabId: 1, - lastActiveTimeTicks: {internalValue: BigInt(1)}, - }); - - const tabUpdateInfo = { - inActiveWindow: true, - tab: updatedTab, - }; - testProxy.getCallbackRouterRemote().tabUpdated(tabUpdateInfo); - await flushTasks(); - // Three non-media tabs. - assertEquals(3, queryRows().length); - // Only "Open Tabs" section should exist. - assertEquals(1, queryListTitle().length); - }); test('Non-media tab becomes media tab', async () => { await setupTest( - createProfileData({ - windows: SAMPLE_WINDOW_DATA, - }), - {alsoShowMediaTabsinOpenTabsSection: false}); - + createProfileData({windows: SAMPLE_WINDOW_DATA}), + ); assertEquals(1, queryListTitle().length); const updatedTab: Tab = createTab({ @@ -254,43 +205,10 @@ assertEquals(2, queryListTitle().length); }); - test( - 'Non-media tab becomes media tab with media tabs also shown in Open Tabs section ', - async () => { - await setupTest( - createProfileData({ - windows: SAMPLE_WINDOW_DATA, - }), - {alsoShowMediaTabsinOpenTabsSection: true}); - - assertEquals(1, queryListTitle().length); - - const updatedTab: Tab = createTab({ - alertStates: [TabAlertState.kAudioPlaying], - tabId: 5, - lastActiveTimeTicks: {internalValue: BigInt(1)}, - }); - - const tabUpdateInfo = { - inActiveWindow: true, - tab: updatedTab, - }; - - testProxy.getCallbackRouterRemote().tabUpdated(tabUpdateInfo); - await flushTasks(); - // One media tab is duplicated, the rest are non-media tabs. - assertEquals(7, queryRows().length); - // "Audio and Video" and "Open Tabs" section should both exist. - assertEquals(2, queryListTitle().length); - }); test('Search for media tab', async () => { await setupTest( - createProfileData({ - windows: SAMPLE_WINDOW_DATA_WITH_MEDIA_TAB, - }), - {alsoShowMediaTabsinOpenTabsSection: false}); - + createProfileData({windows: SAMPLE_WINDOW_DATA_WITH_MEDIA_TAB})); const searchField = tabSearchApp.$.searchField; searchField.setValue('google'); await flushTasks(); @@ -298,21 +216,4 @@ assertEquals(1, queryListTitle().length); assertEquals(2, queryRows().length); }); - - test( - 'Search for media tab with media tabs also shown in Open Tabs section', - async () => { - await setupTest( - createProfileData({ - windows: SAMPLE_WINDOW_DATA_WITH_MEDIA_TAB, - }), - {alsoShowMediaTabsinOpenTabsSection: true}); - - const searchField = tabSearchApp.$.searchField; - searchField.setValue('google'); - await flushTasks(); - // No media tabs section when there is a search query. - assertEquals(1, queryListTitle().length); - assertEquals(2, queryRows().length); - }); });
diff --git a/chrome/updater/test/integration_tests.cc b/chrome/updater/test/integration_tests.cc index 597ed7aa..f7dd358 100644 --- a/chrome/updater/test/integration_tests.cc +++ b/chrome/updater/test/integration_tests.cc
@@ -713,13 +713,7 @@ #if BUILDFLAG(CHROMIUM_BRANDING) || BUILDFLAG(GOOGLE_CHROME_BRANDING) #if !defined(COMPONENT_BUILD) -// Disabled on Windows due to high flake rate; see https://crbug.com/1341471. -#if BUILDFLAG(IS_WIN) -#define MAYBE_SelfUpdateFromOldReal DISABLED_SelfUpdateFromOldReal -#else -#define MAYBE_SelfUpdateFromOldReal SelfUpdateFromOldReal -#endif -TEST_F(IntegrationTest, MAYBE_SelfUpdateFromOldReal) { +TEST_F(IntegrationTest, SelfUpdateFromOldReal) { ScopedServer test_server(test_commands_); SetupRealUpdaterLowerVersion(); @@ -745,14 +739,7 @@ #endif #endif -// TODO(crbug.com/1336591) - enable test after investigating crbug.com/1336591 -// or open a new crbug for debugging this test if it is the culprit. -#if BUILDFLAG(IS_WIN) -#define MAYBE_UpdateServiceStress DISABLED_UpdateServiceStress -#else -#define MAYBE_UpdateServiceStress UpdateServiceStress -#endif -TEST_F(IntegrationTest, MAYBE_UpdateServiceStress) { +TEST_F(IntegrationTest, UpdateServiceStress) { Install(); ExpectInstalled(); StressUpdateService();
diff --git a/chrome/updater/update_service_impl.cc b/chrome/updater/update_service_impl.cc index 164fa85e..f40867b 100644 --- a/chrome/updater/update_service_impl.cc +++ b/chrome/updater/update_service_impl.cc
@@ -395,11 +395,32 @@ priority, UpdateService::PolicySameVersionUpdate::kNotAllowed)); } +void UpdateServiceImpl::GetDMPolicies(base::OnceClosure callback) { + VLOG(1) << __func__; + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + base::MakeRefCounted<DeviceManagementTask>(config_, main_task_runner_) + ->RunRegisterDevice( + base::BindOnce(&DeviceManagementTask::RunFetchPolicy, + base::MakeRefCounted<DeviceManagementTask>( + config_, main_task_runner_), + std::move(callback))); +} + void UpdateServiceImpl::UpdateAll(StateChangeCallback state_update, Callback callback) { VLOG(1) << __func__; DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + GetDMPolicies(base::BindOnce(&UpdateServiceImpl::UpdateAllInternal, this, + state_update, std::move(callback))); +} + +void UpdateServiceImpl::UpdateAllInternal(StateChangeCallback state_update, + Callback callback) { + VLOG(1) << __func__; + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + const auto app_ids = persisted_data_->GetAppIds(); DCHECK(base::Contains(app_ids, kUpdaterAppId)); @@ -436,6 +457,21 @@ VLOG(1) << __func__; DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + GetDMPolicies(base::BindOnce( + &UpdateServiceImpl::UpdateInternal, this, app_id, install_data_index, + priority, policy_same_version_update, state_update, std::move(callback))); +} + +void UpdateServiceImpl::UpdateInternal( + const std::string& app_id, + const std::string& install_data_index, + Priority priority, + PolicySameVersionUpdate policy_same_version_update, + StateChangeCallback state_update, + Callback callback) { + VLOG(1) << __func__; + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + int policy = kPolicyEnabled; if (IsUpdateDisabledByPolicy(app_id, priority, false, policy)) { HandleUpdateDisabledByPolicy(app_id, policy, false, state_update, @@ -457,6 +493,19 @@ Priority priority, StateChangeCallback state_update, Callback callback) { + VLOG(1) << __func__; + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + GetDMPolicies(base::BindOnce(&UpdateServiceImpl::InstallInternal, this, + registration, install_data_index, priority, + state_update, std::move(callback))); +} + +void UpdateServiceImpl::InstallInternal(const RegistrationRequest& registration, + const std::string& install_data_index, + Priority priority, + StateChangeCallback state_update, + Callback callback) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); VLOG(1) << __func__; int policy = kPolicyEnabled; @@ -510,6 +559,23 @@ VLOG(1) << __func__; DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + GetDMPolicies(base::BindOnce(&UpdateServiceImpl::RunInstallerInternal, this, + app_id, installer_path, install_args, + install_data, install_settings, state_update, + std::move(callback))); +} + +void UpdateServiceImpl::RunInstallerInternal( + const std::string& app_id, + const base::FilePath& installer_path, + const std::string& install_args, + const std::string& install_data, + const std::string& install_settings, + StateChangeCallback state_update, + Callback callback) { + VLOG(1) << __func__; + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + int policy = kPolicyEnabled; if (IsUpdateDisabledByPolicy(app_id, Priority::kForeground, true, policy)) { HandleUpdateDisabledByPolicy(app_id, policy, true, state_update,
diff --git a/chrome/updater/update_service_impl.h b/chrome/updater/update_service_impl.h index f6c159b..8ea194f 100644 --- a/chrome/updater/update_service_impl.h +++ b/chrome/updater/update_service_impl.h
@@ -19,6 +19,7 @@ #include "third_party/abseil-cpp/absl/types/optional.h" namespace base { +class FilePath; class SequencedTaskRunner; class Version; } // namespace base @@ -84,6 +85,32 @@ // Installs applications in the wake task based on the ForceInstalls policy. void ForceInstall(StateChangeCallback state_update, Callback callback); + // `GetDMPolicies` refreshes the DM registration and policies, and is called + // before all installs and updates. + void GetDMPolicies(base::OnceClosure callback); + + // After `GetDMPolicies` completes, it calls on these `Internal` method to do + // the actual install or update. + void UpdateAllInternal(StateChangeCallback state_update, Callback callback); + void UpdateInternal(const std::string& app_id, + const std::string& install_data_index, + Priority priority, + PolicySameVersionUpdate policy_same_version_update, + StateChangeCallback state_update, + Callback callback); + void InstallInternal(const RegistrationRequest& registration, + const std::string& install_data_index, + Priority priority, + StateChangeCallback state_update, + Callback callback); + void RunInstallerInternal(const std::string& app_id, + const base::FilePath& installer_path, + const std::string& install_args, + const std::string& install_data, + const std::string& install_settings, + StateChangeCallback state_update, + Callback callback); + bool IsUpdateDisabledByPolicy(const std::string& app_id, Priority priority, bool is_install,
diff --git a/chromeos/ash/components/network/OWNERS b/chromeos/ash/components/network/OWNERS index 1cc59240..d1e3b95 100644 --- a/chromeos/ash/components/network/OWNERS +++ b/chromeos/ash/components/network/OWNERS
@@ -1,5 +1,6 @@ azeemarshad@chromium.org +chadduffin@chromium.org +jiajunz@google.com khorimoto@chromium.org stevenjb@chromium.org tbarzic@chromium.org -jiajunz@google.com
diff --git a/chromeos/ash/components/network/network_state.cc b/chromeos/ash/components/network/network_state.cc index 2b0204a..96837da 100644 --- a/chromeos/ash/components/network/network_state.cc +++ b/chromeos/ash/components/network/network_state.cc
@@ -34,10 +34,6 @@ // TODO(tbarzic): Add payment portal method values to shill/dbus-constants. constexpr char kPaymentPortalMethodPost[] = "POST"; -// TODO(b/169939319): Use shill constant once it lands. -const char kPortalDetectionFailedStatusCodeProperty[] = - "PortalDetectionFailedStatusCode"; - // |dict| may be an empty value, in which case return an empty string. std::string GetStringFromDictionary(const base::Value& dict, const char* key) { const std::string* stringp = @@ -646,7 +642,7 @@ void NetworkState::UpdateCaptivePortalState(const base::Value& properties) { int status_code = - properties.FindIntKey(kPortalDetectionFailedStatusCodeProperty) + properties.FindIntKey(shill::kPortalDetectionFailedStatusCodeProperty) .value_or(0); if (connection_state_ == shill::kStateNoConnectivity) { shill_portal_state_ = PortalState::kNoInternet;
diff --git a/chromeos/ash/components/network/network_state_handler.cc b/chromeos/ash/components/network/network_state_handler.cc index 57e4114..4225ace0 100644 --- a/chromeos/ash/components/network/network_state_handler.cc +++ b/chromeos/ash/components/network/network_state_handler.cc
@@ -18,7 +18,7 @@ #include "base/guid.h" #include "base/location.h" #include "base/memory/ptr_util.h" -#include "base/metrics/histogram_macros.h" +#include "base/metrics/histogram_functions.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" @@ -1772,9 +1772,9 @@ ++shared; } } - UMA_HISTOGRAM_COUNTS_100("Networks.Visible", visible); - UMA_HISTOGRAM_COUNTS_100("Networks.RememberedShared", shared); - UMA_HISTOGRAM_COUNTS_100("Networks.RememberedUnshared", unshared); + base::UmaHistogramCounts100("Networks.Visible", visible); + base::UmaHistogramCounts100("Networks.RememberedShared", shared); + base::UmaHistogramCounts100("Networks.RememberedUnshared", unshared); } void NetworkStateHandler::DefaultNetworkServiceChanged( @@ -2073,28 +2073,92 @@ notifying_network_observers_ = true; for (auto& observer : observers_) observer.DefaultNetworkChanged(default_network); + notifying_network_observers_ = false; + UpdatePortalStateAndNotify(default_network); +} + +void NetworkStateHandler::UpdatePortalStateAndNotify( + const NetworkState* default_network) { + NetworkState::PortalState new_portal_state; + std::string new_default_network_path; if (default_network && (default_network->shill_portal_state() != default_network_portal_state_ || default_network->proxy_config() != default_network_proxy_config_)) { - default_network_portal_state_ = default_network->shill_portal_state(); + new_portal_state = default_network->shill_portal_state(); + new_default_network_path = default_network->path(); default_network_proxy_config_ = default_network->proxy_config().Clone(); - NET_LOG(EVENT) << "NOTIFY: PortalStateChanged: " - << default_network_portal_state_; - for (auto& observer : observers_) { - observer.PortalStateChanged(default_network, - default_network_portal_state_); - } } else if (!default_network && (default_network_portal_state_ != NetworkState::PortalState::kUnknown || !default_network_proxy_config_.is_none())) { - default_network_portal_state_ = NetworkState::PortalState::kUnknown; + new_portal_state = NetworkState::PortalState::kUnknown; default_network_proxy_config_ = base::Value(); - NET_LOG(EVENT) << "NOTIFY: PortalStateChanged: Unknown (no network)"; - for (auto& observer : observers_) - observer.PortalStateChanged(nullptr, NetworkState::PortalState::kUnknown); + } else { + // No portal state changes. + return; } - notifying_network_observers_ = false; + + // Update metrics. + if (new_default_network_path != default_network_path_) { + // When the default network changes, update time histograms with a 0 result + // to indicate a failure to transition to online. + if (time_in_portal_) { + SendPortalHistogramTimes(base::TimeDelta()); + time_in_portal_.reset(); + } + } else { + switch (new_portal_state) { + case NetworkState::PortalState::kUnknown: + // If we transition to an unknown state, update time histograms with a 0 + // result to indicate a failure to transition to online. + if (time_in_portal_) { + SendPortalHistogramTimes(base::TimeDelta()); + time_in_portal_.reset(); + } + break; + case NetworkState::PortalState::kOnline: + if (time_in_portal_) { + SendPortalHistogramTimes(time_in_portal_->Elapsed()); + time_in_portal_.reset(); + } + break; + case NetworkState::PortalState::kPortalSuspected: + [[fallthrough]]; + case NetworkState::PortalState::kPortal: + time_in_portal_ = base::ElapsedTimer(); + break; + case NetworkState::PortalState::kProxyAuthRequired: + [[fallthrough]]; + case NetworkState::PortalState::kNoInternet: + // We don't track these states, reset the timer. + time_in_portal_.reset(); + break; + } + } + + // Update the portal state after sending histograms. + default_network_portal_state_ = new_portal_state; + + // Notify observers. + NET_LOG(EVENT) << "NOTIFY: PortalStateChanged: " + << GetLogName(default_network) << ": " + << default_network_portal_state_; + for (auto& observer : observers_) + observer.PortalStateChanged(default_network, default_network_portal_state_); +} + +void NetworkStateHandler::SendPortalHistogramTimes(base::TimeDelta elapsed) { + switch (default_network_portal_state_) { + case NetworkState::PortalState::kPortal: + base::UmaHistogramTimes("Network.RedirectFoundToOnlineTime", elapsed); + break; + case NetworkState::PortalState::kPortalSuspected: + base::UmaHistogramTimes("Network.PortalSuspectedToOnlineTime", elapsed); + break; + default: + // Previous state was not portalled, no times to report. + break; + } } bool NetworkStateHandler::ActiveNetworksChanged( @@ -2239,6 +2303,9 @@ void NetworkStateHandler::SetDefaultNetworkValues(const std::string& path, bool metered) { + // If the default network changes, ensure that the portal state is updated. + if (!path.empty()) + UpdatePortalStateAndNotify(GetNetworkState(path)); default_network_path_ = path; default_network_is_metered_ = metered; }
diff --git a/chromeos/ash/components/network/network_state_handler.h b/chromeos/ash/components/network/network_state_handler.h index d98b2cf..10c1f2a 100644 --- a/chromeos/ash/components/network/network_state_handler.h +++ b/chromeos/ash/components/network/network_state_handler.h
@@ -15,12 +15,14 @@ #include "base/gtest_prod_util.h" #include "base/observer_list.h" #include "base/sequence_checker.h" +#include "base/timer/elapsed_timer.h" #include "chromeos/ash/components/network/managed_state.h" #include "chromeos/ash/components/network/network_handler.h" #include "chromeos/ash/components/network/network_handler_callbacks.h" #include "chromeos/ash/components/network/network_state.h" #include "chromeos/ash/components/network/network_type_pattern.h" #include "chromeos/ash/components/network/shill_property_handler.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace base { class Location; @@ -616,6 +618,15 @@ // NotifyDefaultNetworkChanged. void OnNetworkConnectionStateChanged(NetworkState* network); + // Updates the cached portal state for the default network, sends portal + // timer metrics, and notifies observers of portal state changes. + void UpdatePortalStateAndNotify(const NetworkState* default_network); + + // Send metrics for elapsed time from a redirect-found or portal-suspected + // to an online or non portal state. If the new state is not online then + // |elapsed| should be 0 to indicate a failure to transition to online. + void SendPortalHistogramTimes(base::TimeDelta elapsed); + // Verifies the connection state of the default network. Returns false // if the connection state change should be ignored. bool VerifyDefaultNetworkConnectionStateChange(NetworkState* network); @@ -751,6 +762,9 @@ NetworkState::PortalState default_network_portal_state_ = NetworkState::PortalState::kUnknown; + // Tracks the time spent in a Portal or PortalSuspected state. + absl::optional<base::ElapsedTimer> time_in_portal_; + // Tracks the default network proxy config for triggering PortalStateChanged. base::Value default_network_proxy_config_;
diff --git a/chromeos/ash/components/network/network_state_handler_unittest.cc b/chromeos/ash/components/network/network_state_handler_unittest.cc index fb9de76f..c8fca8f 100644 --- a/chromeos/ash/components/network/network_state_handler_unittest.cc +++ b/chromeos/ash/components/network/network_state_handler_unittest.cc
@@ -19,6 +19,7 @@ #include "base/logging.h" #include "base/run_loop.h" #include "base/strings/string_number_conversions.h" +#include "base/test/metrics/histogram_tester.h" #include "base/test/task_environment.h" #include "base/values.h" #include "chromeos/ash/components/dbus/shill/shill_clients.h" @@ -40,6 +41,8 @@ #include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/cros_system_api/dbus/service_constants.h" +using testing::ElementsAre; + namespace ash { namespace { @@ -1963,9 +1966,13 @@ TEST_F(NetworkStateHandlerTest, SetNetworkChromePortalState) { RemoveEthernet(); + base::HistogramTester histogram_tester; service_test_->SetServiceProperty(kShillManagerClientStubDefaultWifi, shill::kStateProperty, base::Value(shill::kStatePortalSuspected)); + service_test_->SetServiceProperty( + kShillManagerClientStubDefaultWifi, + shill::kPortalDetectionFailedStatusCodeProperty, base::Value(300)); base::RunLoop().RunUntilIdle(); const NetworkState* network = network_state_handler_->GetNetworkState( @@ -1989,10 +1996,17 @@ kShillManagerClientStubDefaultWifi); EXPECT_EQ(NetworkState::PortalState::kPortalSuspected, network->GetPortalState()); + + EXPECT_THAT(histogram_tester.GetAllSamples("Network.CaptivePortalResult"), + ElementsAre(base::Bucket( + NetworkState::PortalState::kPortalSuspected, 1))); + EXPECT_THAT(histogram_tester.GetAllSamples("Network.CaptivePortalStatusCode"), + ElementsAre(base::Bucket(300, 1))); } TEST_F(NetworkStateHandlerTest, PortalStateChanged) { RemoveEthernet(); + test_observer_->reset_change_counts(); // Set wifi1 to portal-suspected and ensure observer is triggered. service_test_->SetServiceProperty(kShillManagerClientStubDefaultWifi, @@ -2030,6 +2044,62 @@ EXPECT_EQ(test_observer_->portal_state_change_count(), 4u); } +TEST_F(NetworkStateHandlerTest, PortalToOnline) { + RemoveEthernet(); + test_observer_->reset_change_counts(); + base::HistogramTester histogram_tester; + + // Set wifi1 to redirect-found and ensure observer is triggered. + service_test_->SetServiceProperty(kShillManagerClientStubDefaultWifi, + shill::kStateProperty, + base::Value(shill::kStateRedirectFound)); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(test_observer_->default_network_portal_state(), + NetworkState::PortalState::kPortal); + EXPECT_EQ(test_observer_->portal_state_change_count(), 1u); + + // Set wifi1 to online and ensure observer is triggered. + service_test_->SetServiceProperty(kShillManagerClientStubDefaultWifi, + shill::kStateProperty, + base::Value(shill::kStateOnline)); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(test_observer_->default_network_portal_state(), + NetworkState::PortalState::kOnline); + EXPECT_EQ(test_observer_->portal_state_change_count(), 2u); + + // redirect-found -> online should update RedirectFoundToOnlineTime. + histogram_tester.ExpectTotalCount("Network.RedirectFoundToOnlineTime", 1); + histogram_tester.ExpectTotalCount("Network.PortalSuspectedToOnlineTime", 0); +} + +TEST_F(NetworkStateHandlerTest, PortalSuspectedToOnline) { + RemoveEthernet(); + test_observer_->reset_change_counts(); + base::HistogramTester histogram_tester; + + // Set wifi1 to portal-suspected and ensure observer is triggered. + service_test_->SetServiceProperty(kShillManagerClientStubDefaultWifi, + shill::kStateProperty, + base::Value(shill::kStatePortalSuspected)); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(test_observer_->default_network_portal_state(), + NetworkState::PortalState::kPortalSuspected); + EXPECT_EQ(test_observer_->portal_state_change_count(), 1u); + + // Set wifi1 to online and ensure observer is triggered. + service_test_->SetServiceProperty(kShillManagerClientStubDefaultWifi, + shill::kStateProperty, + base::Value(shill::kStateOnline)); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(test_observer_->default_network_portal_state(), + NetworkState::PortalState::kOnline); + EXPECT_EQ(test_observer_->portal_state_change_count(), 2u); + + // portal-suspected -> online should update PortalSuspectedToOnlineTime. + histogram_tester.ExpectTotalCount("Network.RedirectFoundToOnlineTime", 0); + histogram_tester.ExpectTotalCount("Network.PortalSuspectedToOnlineTime", 1); +} + TEST_F(NetworkStateHandlerTest, RequestUpdate) { // Request an update for kShillManagerClientStubDefaultWifi. EXPECT_EQ(1, test_observer_->PropertyUpdatesForService(
diff --git a/chromeos/ash/components/oobe_quick_start/connectivity/fake_target_device_connection_broker.cc b/chromeos/ash/components/oobe_quick_start/connectivity/fake_target_device_connection_broker.cc index a2e85f74..a6f861d 100644 --- a/chromeos/ash/components/oobe_quick_start/connectivity/fake_target_device_connection_broker.cc +++ b/chromeos/ash/components/oobe_quick_start/connectivity/fake_target_device_connection_broker.cc
@@ -4,6 +4,8 @@ #include "chromeos/ash/components/oobe_quick_start/connectivity/fake_target_device_connection_broker.h" +#include "chromeos/ash/components/oobe_quick_start/connectivity/random_session_id.h" + namespace ash::quick_start { FakeTargetDeviceConnectionBroker::Factory::Factory() = default; @@ -11,7 +13,8 @@ FakeTargetDeviceConnectionBroker::Factory::~Factory() = default; std::unique_ptr<TargetDeviceConnectionBroker> -FakeTargetDeviceConnectionBroker::Factory::CreateInstance() { +FakeTargetDeviceConnectionBroker::Factory::CreateInstance( + RandomSessionId session_id) { auto connection_broker = std::make_unique<FakeTargetDeviceConnectionBroker>(); instances_.push_back(connection_broker.get()); return std::move(connection_broker);
diff --git a/chromeos/ash/components/oobe_quick_start/connectivity/fake_target_device_connection_broker.h b/chromeos/ash/components/oobe_quick_start/connectivity/fake_target_device_connection_broker.h index cae26106..0ce928f3 100644 --- a/chromeos/ash/components/oobe_quick_start/connectivity/fake_target_device_connection_broker.h +++ b/chromeos/ash/components/oobe_quick_start/connectivity/fake_target_device_connection_broker.h
@@ -13,6 +13,8 @@ namespace ash::quick_start { +class RandomSessionId; + class FakeTargetDeviceConnectionBroker : public TargetDeviceConnectionBroker { public: class Factory : public TargetDeviceConnectionBrokerFactory { @@ -29,7 +31,8 @@ } private: - std::unique_ptr<TargetDeviceConnectionBroker> CreateInstance() override; + std::unique_ptr<TargetDeviceConnectionBroker> CreateInstance( + RandomSessionId session_id) override; std::vector<FakeTargetDeviceConnectionBroker*> instances_; };
diff --git a/chromeos/ash/components/oobe_quick_start/connectivity/random_session_id.cc b/chromeos/ash/components/oobe_quick_start/connectivity/random_session_id.cc index 7c20277..0c60893 100644 --- a/chromeos/ash/components/oobe_quick_start/connectivity/random_session_id.cc +++ b/chromeos/ash/components/oobe_quick_start/connectivity/random_session_id.cc
@@ -15,6 +15,10 @@ crypto::RandBytes(bytes_); } +RandomSessionId::RandomSessionId(base::span<const uint8_t, kLength> bytes) { + std::copy(bytes.begin(), bytes.end(), bytes_.begin()); +} + std::string RandomSessionId::ToString() const { return base::HexEncode(bytes_); }
diff --git a/chromeos/ash/components/oobe_quick_start/connectivity/random_session_id.h b/chromeos/ash/components/oobe_quick_start/connectivity/random_session_id.h index fc3e3de..b06a08ab 100644 --- a/chromeos/ash/components/oobe_quick_start/connectivity/random_session_id.h +++ b/chromeos/ash/components/oobe_quick_start/connectivity/random_session_id.h
@@ -20,11 +20,12 @@ static constexpr size_t kLength = 10; RandomSessionId(); + explicit RandomSessionId(base::span<const uint8_t, kLength> bytes); RandomSessionId(RandomSessionId&) = default; RandomSessionId& operator=(RandomSessionId&) = default; ~RandomSessionId() = default; - base::span<const uint8_t, kLength> AsBytes() const { return bytes_; }; + base::span<const uint8_t, kLength> AsBytes() const { return bytes_; } // Convert to hexadecimal. std::string ToString() const;
diff --git a/chromeos/ash/components/oobe_quick_start/connectivity/target_device_connection_broker_factory.cc b/chromeos/ash/components/oobe_quick_start/connectivity/target_device_connection_broker_factory.cc index 331d132e..18a6653c 100644 --- a/chromeos/ash/components/oobe_quick_start/connectivity/target_device_connection_broker_factory.cc +++ b/chromeos/ash/components/oobe_quick_start/connectivity/target_device_connection_broker_factory.cc
@@ -4,6 +4,7 @@ #include "chromeos/ash/components/oobe_quick_start/connectivity/target_device_connection_broker_factory.h" +#include "chromeos/ash/components/oobe_quick_start/connectivity/random_session_id.h" #include "chromeos/ash/components/oobe_quick_start/connectivity/target_device_connection_broker_impl.h" namespace ash::quick_start { @@ -11,11 +12,17 @@ // static std::unique_ptr<TargetDeviceConnectionBroker> TargetDeviceConnectionBrokerFactory::Create() { + return Create(RandomSessionId()); +} + +// static +std::unique_ptr<TargetDeviceConnectionBroker> +TargetDeviceConnectionBrokerFactory::Create(RandomSessionId session_id) { if (test_factory_) { - return test_factory_->CreateInstance(); + return test_factory_->CreateInstance(session_id); } - return std::make_unique<TargetDeviceConnectionBrokerImpl>(); + return std::make_unique<TargetDeviceConnectionBrokerImpl>(session_id); } // static
diff --git a/chromeos/ash/components/oobe_quick_start/connectivity/target_device_connection_broker_factory.h b/chromeos/ash/components/oobe_quick_start/connectivity/target_device_connection_broker_factory.h index 94f45cf..e006f6d 100644 --- a/chromeos/ash/components/oobe_quick_start/connectivity/target_device_connection_broker_factory.h +++ b/chromeos/ash/components/oobe_quick_start/connectivity/target_device_connection_broker_factory.h
@@ -11,12 +11,18 @@ namespace ash::quick_start { +class RandomSessionId; + // A factory class for creating instances of TargetDeviceConnectionBroker. // Calling code should use the static Create() method. class TargetDeviceConnectionBrokerFactory { public: static std::unique_ptr<TargetDeviceConnectionBroker> Create(); + // A RandomSessionId may be provided in order to resume a connection. + static std::unique_ptr<TargetDeviceConnectionBroker> Create( + RandomSessionId session_id); + static void SetFactoryForTesting( TargetDeviceConnectionBrokerFactory* test_factory); @@ -28,7 +34,8 @@ virtual ~TargetDeviceConnectionBrokerFactory(); protected: - virtual std::unique_ptr<TargetDeviceConnectionBroker> CreateInstance() = 0; + virtual std::unique_ptr<TargetDeviceConnectionBroker> CreateInstance( + RandomSessionId session_id) = 0; private: static TargetDeviceConnectionBrokerFactory* test_factory_;
diff --git a/chromeos/ash/components/oobe_quick_start/connectivity/target_device_connection_broker_impl.cc b/chromeos/ash/components/oobe_quick_start/connectivity/target_device_connection_broker_impl.cc index 980696c..9b2aec1 100644 --- a/chromeos/ash/components/oobe_quick_start/connectivity/target_device_connection_broker_impl.cc +++ b/chromeos/ash/components/oobe_quick_start/connectivity/target_device_connection_broker_impl.cc
@@ -10,6 +10,7 @@ #include "base/bind.h" #include "base/callback.h" #include "base/logging.h" +#include "base/strings/string_number_conversions.h" #include "base/threading/sequenced_task_runner_handle.h" #include "chromeos/ash/components/oobe_quick_start/connectivity/fast_pair_advertiser.h" #include "chromeos/ash/components/oobe_quick_start/connectivity/random_session_id.h" @@ -40,15 +41,29 @@ constexpr char kEndpointInfoDefaultDisplayName[] = "Chromebook"; +// Derive three decimal digits from the RandomSessionId. +std::string GetDisplayNameSessionIdDigits(const RandomSessionId& session_id) { + base::span<const uint8_t, RandomSessionId::kLength> session_id_bytes = + session_id.AsBytes(); + uint32_t high = session_id_bytes[0]; + uint32_t low = session_id_bytes[1]; + uint32_t x = (high << 8) + low; + return base::NumberToString(x % 1000); +} + // The display name must: // - Be a variable-length string of utf-8 bytes // - Be at most 18 bytes // - If less than 18 bytes, must be null-terminated std::vector<uint8_t> GetEndpointInfoDisplayNameBytes( - RandomSessionId session_id) { - // TODO(b/234655072): Append session id to display name, vary name based on - // device type, e.g. Chromebook, Chromebox, Chromebase, Chromebit, etc. + const RandomSessionId& session_id) { std::string display_name = kEndpointInfoDefaultDisplayName; + std::string suffix = " (" + GetDisplayNameSessionIdDigits(session_id) + ")"; + + // TODO(b/234655072): Before appending suffix, vary |display_name| based on + // device type, e.g. Chromebook, Chromebox, Chromebase, etc. + display_name += suffix; + std::vector<uint8_t> display_name_bytes(display_name.begin(), display_name.end()); display_name_bytes.push_back(0); @@ -79,7 +94,9 @@ TargetDeviceConnectionBrokerImpl::BluetoothAdapterFactoryWrapper:: bluetooth_adapter_factory_wrapper_for_testing_ = nullptr; -TargetDeviceConnectionBrokerImpl::TargetDeviceConnectionBrokerImpl() { +TargetDeviceConnectionBrokerImpl::TargetDeviceConnectionBrokerImpl( + RandomSessionId session_id) + : random_session_id_(session_id) { GetBluetoothAdapter(); } @@ -149,7 +166,8 @@ return; } - VLOG(1) << "Starting advertising with session id " << random_session_id_; + VLOG(1) << "Starting advertising with session id " << random_session_id_ + << " (" << GetDisplayNameSessionIdDigits(random_session_id_) << ")"; fast_pair_advertiser_ = FastPairAdvertiser::Factory::Create(bluetooth_adapter_);
diff --git a/chromeos/ash/components/oobe_quick_start/connectivity/target_device_connection_broker_impl.h b/chromeos/ash/components/oobe_quick_start/connectivity/target_device_connection_broker_impl.h index bf869182..69bba0c3 100644 --- a/chromeos/ash/components/oobe_quick_start/connectivity/target_device_connection_broker_impl.h +++ b/chromeos/ash/components/oobe_quick_start/connectivity/target_device_connection_broker_impl.h
@@ -40,7 +40,7 @@ bluetooth_adapter_factory_wrapper_for_testing_; }; - TargetDeviceConnectionBrokerImpl(); + explicit TargetDeviceConnectionBrokerImpl(RandomSessionId session_id); TargetDeviceConnectionBrokerImpl(TargetDeviceConnectionBrokerImpl&) = delete; TargetDeviceConnectionBrokerImpl& operator=( TargetDeviceConnectionBrokerImpl&) = delete;
diff --git a/chromeos/ash/components/oobe_quick_start/connectivity/target_device_connection_broker_impl_unittest.cc b/chromeos/ash/components/oobe_quick_start/connectivity/target_device_connection_broker_impl_unittest.cc index b1b3116..35d1f42 100644 --- a/chromeos/ash/components/oobe_quick_start/connectivity/target_device_connection_broker_impl_unittest.cc +++ b/chromeos/ash/components/oobe_quick_start/connectivity/target_device_connection_broker_impl_unittest.cc
@@ -4,6 +4,8 @@ #include "chromeos/ash/components/oobe_quick_start/connectivity/target_device_connection_broker_impl.h" +#include <array> + #include "base/bind.h" #include "base/test/task_environment.h" #include "chromeos/ash/components/oobe_quick_start/connectivity/fast_pair_advertiser.h" @@ -20,6 +22,12 @@ constexpr size_t kMaxEndpointInfoDisplayNameLength = 18; +// 10 random bytes to use as the RandomSessionId. The corresponding display name +// code is (0x135e % 1000) = 958. +constexpr std::array<uint8_t, 10> kRandomSessionId = { + 0x13, 0x5e, 0xfb, 0x0f, 0x3a, 0x20, 0x06, 0xbd, 0xbf, 0x95}; +constexpr char kExpectedEndpointInfoDisplayName[] = "Chromebook (958)"; + using testing::NiceMock; // Allows us to delay returning a Bluetooth adapter until after ReturnAdapter() @@ -167,8 +175,10 @@ } void CreateConnectionBroker() { + RandomSessionId session_id(kRandomSessionId); connection_broker_ = - ash::quick_start::TargetDeviceConnectionBrokerFactory::Create(); + ash::quick_start::TargetDeviceConnectionBrokerFactory::Create( + session_id); } void FinishFetchingBluetoothAdapter() { @@ -412,7 +422,7 @@ } std::string display_name = std::string(display_name_bytes.begin(), display_name_bytes.end()); - EXPECT_EQ("Chromebook", display_name); + EXPECT_EQ(kExpectedEndpointInfoDisplayName, display_name); i += j; ASSERT_GT(endpoint_info.size(), i);
diff --git a/chromeos/crosapi/mojom/tts.mojom b/chromeos/crosapi/mojom/tts.mojom index d85d017b..515b2e8 100644 --- a/chromeos/crosapi/mojom/tts.mojom +++ b/chromeos/crosapi/mojom/tts.mojom
@@ -5,6 +5,8 @@ module crosapi.mojom; import "mojo/public/mojom/base/unguessable_token.mojom"; +import "mojo/public/mojom/base/values.mojom"; +import "url/mojom/url.mojom"; // Events sent back from the TTS engine indicating the progress. [Stable, Extensible] @@ -47,6 +49,68 @@ string native_voice_identifier; }; +// Represents a Tts utterance. +[Stable] +struct TtsUtterance { + // Unique id of utterance that helps route a Tts event back to the client. + // This is needed when speaking an Ash utterance with a Lacros voice. + // |utterance_id| is created by TtsController (in Ash) and passed to TtsEngine + // extension API (in Lacros) onSpeak event, ttsEngine extension (in Lacros) + // will pass it back in sendTtsEvent, which will eventually pass it to + // TtsController::OnTtsEvent (in Ash), so that TtsController (in Ash) can + // track and process the async TtsEvent for the utterances. + int32 utterance_id; + + // Text to speak. + string text; + + // Language to use for synthesis. + string lang; + + // Name of the voice to use for synthesis. + string voice_name; + + // Speaking volume. + double volume; + + // Speaking rate. + double rate; + + // Speaking pitch. + double pitch; + + // Extension id of the speech engine to use. + string engine_id; + + // If false, enqueues this utterance if TTS is already in progress. Otherwise, + // interrupts any current speech and flushes the speech queue before speaking + // this new utterance. + bool should_clear_queue; + + // TTS event types that the client is interested in listening to. + array<TtsEventType> desired_event_types; + + // The TTS event types the voice must support. + array<TtsEventType> required_event_types; + + // The source engine's ID of this utterance, so that it can route the events + // back to the correct tts.speak call. + uint32 src_id; + + // The URL of the page from which the speech request is called. + url.mojom.Url src_url; + + // Options passed from tts.speak argument, which will be passed to ttsEngine + // onSpeak event with sanitizing process. + mojo_base.mojom.DictionaryValue options; + + // True if the utterance is associated with a WebContents. + bool was_created_with_web_contents; + + // Unique id of the browser context of the utterance. + mojo_base.mojom.UnguessableToken browser_context_id; +}; + // Interface for Tts, implemented in ash-chrome. Used by lacros-chrome to // communicate with ash TtsController to send the voice data and // speech requests to ash.
diff --git a/chromeos/profiles/orderfile.newest.txt b/chromeos/profiles/orderfile.newest.txt index 1e98dd1..da20873e 100644 --- a/chromeos/profiles/orderfile.newest.txt +++ b/chromeos/profiles/orderfile.newest.txt
@@ -1 +1 @@ -chromeos-chrome-orderfile-field-106-5195.19-1659952549-benchmark-106.0.5237.0-r1.orderfile.xz +chromeos-chrome-orderfile-field-106-5226.0-1660558034-benchmark-106.0.5241.0-r1.orderfile.xz
diff --git a/chromeos/ui/base/window_properties.cc b/chromeos/ui/base/window_properties.cc index 2217222..432b3c6b 100644 --- a/chromeos/ui/base/window_properties.cc +++ b/chromeos/ui/base/window_properties.cc
@@ -45,6 +45,8 @@ DEFINE_UI_CLASS_PROPERTY_KEY(bool, kIsShowingInOverviewKey, false) +DEFINE_UI_CLASS_PROPERTY_KEY(bool, kShouldHaveHighlightBorderOverlay, false) + DEFINE_UI_CLASS_PROPERTY_KEY(bool, kWindowManagerManagesOpacityKey, false) DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(std::u16string,
diff --git a/chromeos/ui/base/window_properties.h b/chromeos/ui/base/window_properties.h index 2ad44ea..c8b4bf3 100644 --- a/chromeos/ui/base/window_properties.h +++ b/chromeos/ui/base/window_properties.h
@@ -108,6 +108,10 @@ COMPONENT_EXPORT(CHROMEOS_UI_BASE) extern const ui::ClassProperty<bool>* const kIsShowingInOverviewKey; +// A property to indicate if a window should have a highlight border overlay. +COMPONENT_EXPORT(CHROMEOS_UI_BASE) +extern const ui::ClassProperty<bool>* const kShouldHaveHighlightBorderOverlay; + // A property key to tell if the window's opacity should be managed by WM. COMPONENT_EXPORT(CHROMEOS_UI_BASE) extern const ui::ClassProperty<bool>* const kWindowManagerManagesOpacityKey;
diff --git a/chromeos/ui/frame/multitask_menu/multitask_button.cc b/chromeos/ui/frame/multitask_menu/multitask_button.cc index 231eba1..1b7c0742 100644 --- a/chromeos/ui/frame/multitask_menu/multitask_button.cc +++ b/chromeos/ui/frame/multitask_menu/multitask_button.cc
@@ -5,6 +5,7 @@ #include "chromeos/ui/frame/multitask_menu/multitask_button.h" #include "chromeos/ui/frame/multitask_menu/multitask_menu_constants.h" +#include "ui/base/metadata/metadata_impl_macros.h" #include "ui/gfx/canvas.h" #include "ui/views/animation/ink_drop.h" #include "ui/views/controls/focus_ring.h" @@ -82,4 +83,7 @@ views::Button::OnThemeChanged(); } +BEGIN_METADATA(MultitaskBaseButton, views::Button) +END_METADATA + } // namespace chromeos
diff --git a/chromeos/ui/frame/multitask_menu/multitask_button.h b/chromeos/ui/frame/multitask_menu/multitask_button.h index 148326c..fdbb78e 100644 --- a/chromeos/ui/frame/multitask_menu/multitask_button.h +++ b/chromeos/ui/frame/multitask_menu/multitask_button.h
@@ -5,6 +5,7 @@ #ifndef CHROMEOS_UI_FRAME_MULTITASK_MENU_MULTITASK_BUTTON_H_ #define CHROMEOS_UI_FRAME_MULTITASK_MENU_MULTITASK_BUTTON_H_ +#include "ui/base/metadata/metadata_header_macros.h" #include "ui/views/controls/button/button.h" namespace chromeos { @@ -12,6 +13,8 @@ // The base button for multitask menu to create Full Screen and Float buttons. class MultitaskBaseButton : public views::Button { public: + METADATA_HEADER(MultitaskBaseButton); + // The types of single operated multitask button. enum class Type { kFull, // The button that turn the window to full screen mode.
diff --git a/chromeos/ui/frame/multitask_menu/multitask_menu.cc b/chromeos/ui/frame/multitask_menu/multitask_menu.cc index 5be13c966..c69634d0 100644 --- a/chromeos/ui/frame/multitask_menu/multitask_menu.cc +++ b/chromeos/ui/frame/multitask_menu/multitask_menu.cc
@@ -9,6 +9,7 @@ #include "base/check.h" #include "chromeos/ui/frame/multitask_menu/float_controller_base.h" #include "chromeos/ui/frame/multitask_menu/multitask_menu_view.h" +#include "ui/base/metadata/metadata_impl_macros.h" #include "ui/views/layout/table_layout.h" namespace chromeos { @@ -34,8 +35,6 @@ set_close_on_deactivate(true); SetPreferredSize(gfx::Size(KMultitaskMenuWidth, kMultitaskMenuHeight)); SetUseDefaultFillLayout(true); - // TODO(sammiequon/sophiewen): Check that `CalculatePreferredSize` gets the - // size based on the child button sizes. // Must be initialized after setting bounds. multitask_menu_view_ = AddChildView(std::make_unique<MultitaskMenuView>( @@ -93,4 +92,8 @@ if (bubble_widget_ && !bubble_widget_->IsClosed()) bubble_widget_->CloseNow(); } + +BEGIN_METADATA(MultitaskMenu, views::BubbleDialogDelegateView) +END_METADATA + } // namespace chromeos
diff --git a/chromeos/ui/frame/multitask_menu/multitask_menu.h b/chromeos/ui/frame/multitask_menu/multitask_menu.h index c59b6c47d..89860f2 100644 --- a/chromeos/ui/frame/multitask_menu/multitask_menu.h +++ b/chromeos/ui/frame/multitask_menu/multitask_menu.h
@@ -8,6 +8,7 @@ #include "base/memory/raw_ptr.h" #include "chromeos/ui/frame/caption_buttons/snap_controller.h" #include "chromeos/ui/frame/multitask_menu/multitask_menu_view.h" +#include "ui/base/metadata/metadata_header_macros.h" #include "ui/views/bubble/bubble_dialog_delegate_view.h" namespace views { @@ -23,6 +24,8 @@ : public views::BubbleDialogDelegateView, public views::WidgetObserver { public: + METADATA_HEADER(MultitaskMenu); + MultitaskMenu(views::View* anchor, aura::Window* parent_window); MultitaskMenu(const MultitaskMenu&) = delete;
diff --git a/chromeos/ui/frame/multitask_menu/multitask_menu_view.cc b/chromeos/ui/frame/multitask_menu/multitask_menu_view.cc index ca4afe45..d70a5c5f 100644 --- a/chromeos/ui/frame/multitask_menu/multitask_menu_view.cc +++ b/chromeos/ui/frame/multitask_menu/multitask_menu_view.cc
@@ -13,6 +13,7 @@ #include "ui/aura/window.h" #include "ui/base/default_style.h" #include "ui/base/l10n/l10n_util.h" +#include "ui/base/metadata/metadata_impl_macros.h" #include "ui/strings/grit/ui_strings.h" #include "ui/views/background.h" #include "ui/views/controls/label.h" @@ -128,4 +129,7 @@ on_any_button_pressed_.Run(); } +BEGIN_METADATA(MultitaskMenuView, View) +END_METADATA + } // namespace chromeos \ No newline at end of file
diff --git a/chromeos/ui/frame/multitask_menu/multitask_menu_view.h b/chromeos/ui/frame/multitask_menu/multitask_menu_view.h index 9db4eb5..6d5e989 100644 --- a/chromeos/ui/frame/multitask_menu/multitask_menu_view.h +++ b/chromeos/ui/frame/multitask_menu/multitask_menu_view.h
@@ -8,6 +8,7 @@ #include "base/memory/raw_ptr.h" #include "chromeos/ui/frame/multitask_menu/multitask_button.h" #include "chromeos/ui/frame/multitask_menu/split_button.h" +#include "ui/base/metadata/metadata_header_macros.h" namespace views { class View; @@ -22,6 +23,8 @@ class COMPONENT_EXPORT(CHROMEOS_UI_FRAME) MultitaskMenuView : public views::View { public: + METADATA_HEADER(MultitaskMenuView); + MultitaskMenuView(aura::Window* window, base::RepeatingClosure on_any_button_pressed);
diff --git a/chromeos/ui/frame/multitask_menu/split_button.cc b/chromeos/ui/frame/multitask_menu/split_button.cc index f66fab9e..a9e7092 100644 --- a/chromeos/ui/frame/multitask_menu/split_button.cc +++ b/chromeos/ui/frame/multitask_menu/split_button.cc
@@ -6,6 +6,7 @@ #include <memory> +#include "ui/base/metadata/metadata_impl_macros.h" #include "ui/gfx/canvas.h" #include "ui/gfx/color_palette.h" #include "ui/gfx/geometry/point_f.h" @@ -61,6 +62,9 @@ canvas->DrawRoundRect(pattern_bounds, kButtonCornerRadius, pattern_flags); } +BEGIN_METADATA(SplitButton, views::Button) +END_METADATA + SplitButtonView::SplitButtonView( SplitButton::SplitButtonType type, views::Button::PressedCallback primary_callback, @@ -135,4 +139,7 @@ views::View::OnThemeChanged(); } +BEGIN_METADATA(SplitButtonView, View) +END_METADATA + } // namespace chromeos
diff --git a/chromeos/ui/frame/multitask_menu/split_button.h b/chromeos/ui/frame/multitask_menu/split_button.h index 6518295..b5979820 100644 --- a/chromeos/ui/frame/multitask_menu/split_button.h +++ b/chromeos/ui/frame/multitask_menu/split_button.h
@@ -7,6 +7,7 @@ #include "chromeos/ui/frame/multitask_menu/multitask_menu_constants.h" +#include "ui/base/metadata/metadata_header_macros.h" #include "ui/views/controls/button/button.h" #include "ui/views/layout/box_layout_view.h" #include "ui/views/view.h" @@ -16,6 +17,7 @@ // A button used for SplitButtonView to trigger primary/secondary split. class SplitButton : public views::Button { public: + METADATA_HEADER(SplitButton); enum class SplitButtonType { kHalfButtons, kPartialButtons, @@ -49,6 +51,8 @@ // A button view with 2 divided buttons, primary and secondary. class SplitButtonView : public views::BoxLayoutView { public: + METADATA_HEADER(SplitButtonView); + SplitButtonView(SplitButton::SplitButtonType type, views::Button::PressedCallback primary_callback, views::Button::PressedCallback secondary_callback);
diff --git a/components/autofill/core/browser/autofill_external_delegate.cc b/components/autofill/core/browser/autofill_external_delegate.cc index d86f018..f6168116 100644 --- a/components/autofill/core/browser/autofill_external_delegate.cc +++ b/components/autofill/core/browser/autofill_external_delegate.cc
@@ -213,7 +213,7 @@ void AutofillExternalDelegate::DidSelectSuggestion( const std::u16string& value, int frontend_id, - const std::string& backend_id) { + const Suggestion::BackendId& backend_id) { ClearPreviewedForm(); // Only preview the data if it is a profile or a virtual card. @@ -225,7 +225,7 @@ value); } else if (frontend_id == POPUP_ITEM_ID_VIRTUAL_CREDIT_CARD_ENTRY) { manager_->FillOrPreviewVirtualCardInformation( - mojom::RendererFormDataAction::kPreview, backend_id, query_id_, + mojom::RendererFormDataAction::kPreview, backend_id.value(), query_id_, query_form_, query_field_); } } @@ -278,10 +278,11 @@ // POPUP_ITEM_ID_VIRTUAL_CREDIT_CARD_ENTRY as a frontend_id. In this case, // the payload contains the backend id, which is a GUID that identifies the // actually chosen credit card. - DCHECK(absl::holds_alternative<std::string>(payload)); + DCHECK(absl::holds_alternative<Suggestion::BackendId>(payload)); manager_->FillOrPreviewVirtualCardInformation( - mojom::RendererFormDataAction::kFill, absl::get<std::string>(payload), - query_id_, query_form_, query_field_); + mojom::RendererFormDataAction::kFill, + absl::get<Suggestion::BackendId>(payload).value(), query_id_, + query_form_, query_field_); } else if (frontend_id == POPUP_ITEM_ID_SEE_PROMO_CODE_DETAILS) { DCHECK(absl::holds_alternative<GURL>(payload)); manager_->OnSeePromoCodeOfferDetailsSelected(absl::get<GURL>(payload),
diff --git a/components/autofill/core/browser/autofill_external_delegate.h b/components/autofill/core/browser/autofill_external_delegate.h index 40dce87..7999bcd 100644 --- a/components/autofill/core/browser/autofill_external_delegate.h +++ b/components/autofill/core/browser/autofill_external_delegate.h
@@ -48,7 +48,7 @@ void OnPopupSuppressed() override; void DidSelectSuggestion(const std::u16string& value, int frontend_id, - const std::string& backend_id) override; + const Suggestion::BackendId& backend_id) override; void DidAcceptSuggestion(const std::u16string& value, int frontend_id, const Suggestion::Payload& payload,
diff --git a/components/autofill/core/browser/autofill_external_delegate_unittest.cc b/components/autofill/core/browser/autofill_external_delegate_unittest.cc index 45cdd7a..24133ca 100644 --- a/components/autofill/core/browser/autofill_external_delegate_unittest.cc +++ b/components/autofill/core/browser/autofill_external_delegate_unittest.cc
@@ -609,7 +609,8 @@ EXPECT_CALL(*browser_autofill_manager_, FillOrPreviewForm(_, _, _, _, _)) .Times(0); EXPECT_CALL(*autofill_driver_, RendererShouldClearPreviewedForm()).Times(1); - external_delegate_->DidSelectSuggestion(std::u16string(), -1, std::string()); + external_delegate_->DidSelectSuggestion(std::u16string(), -1, + Suggestion::BackendId()); // Ensure it doesn't try to fill the form in with the negative id. EXPECT_CALL(autofill_client_, @@ -649,7 +650,8 @@ EXPECT_CALL(*autofill_driver_, RendererShouldPreviewFieldWithValue(field_id_, promo_code_value)); external_delegate_->DidSelectSuggestion( - promo_code_value, POPUP_ITEM_ID_MERCHANT_PROMO_CODE_ENTRY, ""); + promo_code_value, POPUP_ITEM_ID_MERCHANT_PROMO_CODE_ENTRY, + Suggestion::BackendId()); EXPECT_CALL(autofill_client_, HideAutofillPopup(PopupHidingReason::kAcceptSuggestion)); EXPECT_CALL(*autofill_driver_, @@ -664,7 +666,8 @@ TEST_F(AutofillExternalDelegateUnitTest, ExternalDelegateMerchantPromoCodeSuggestionsFooter) { const GURL gurl{"https://example.com/"}; - absl::variant<std::string, GURL> payload(absl::in_place_type<GURL>, gurl); + absl::variant<Suggestion::BackendId, GURL> payload(absl::in_place_type<GURL>, + gurl); EXPECT_CALL(autofill_client_, OpenPromoCodeOfferDetailsURL(gurl)); external_delegate_->DidAcceptSuggestion( u"baz foo", POPUP_ITEM_ID_SEE_PROMO_CODE_DETAILS, payload, 0); @@ -678,12 +681,13 @@ IssueOnQuery(123); EXPECT_CALL(*autofill_driver_, RendererShouldClearPreviewedForm()).Times(1); external_delegate_->DidSelectSuggestion( - u"baz foo", POPUP_ITEM_ID_PASSWORD_ENTRY, std::string()); + u"baz foo", POPUP_ITEM_ID_PASSWORD_ENTRY, Suggestion::BackendId()); EXPECT_CALL(*autofill_driver_, RendererShouldClearPreviewedForm()).Times(1); EXPECT_CALL( *browser_autofill_manager_, FillOrPreviewForm(mojom::RendererFormDataAction::kPreview, _, _, _, _)); - external_delegate_->DidSelectSuggestion(u"baz foo", 1, std::string()); + external_delegate_->DidSelectSuggestion(u"baz foo", 1, + Suggestion::BackendId()); // Ensure selecting an autocomplete entry will cause any previews to // get cleared. @@ -691,7 +695,7 @@ EXPECT_CALL(*autofill_driver_, RendererShouldPreviewFieldWithValue( field_id_, std::u16string(u"baz foo"))); external_delegate_->DidSelectSuggestion( - u"baz foo", POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY, std::string()); + u"baz foo", POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY, Suggestion::BackendId()); // Ensure selecting a virtual card entry will cause any previews to // get cleared. @@ -700,7 +704,8 @@ FillOrPreviewVirtualCardInformation( mojom::RendererFormDataAction::kPreview, _, _, _, _)); external_delegate_->DidSelectSuggestion( - std::u16string(), POPUP_ITEM_ID_VIRTUAL_CREDIT_CARD_ENTRY, std::string()); + std::u16string(), POPUP_ITEM_ID_VIRTUAL_CREDIT_CARD_ENTRY, + Suggestion::BackendId()); } // Test that the popup is hidden once we are done editing the autofill field. @@ -885,8 +890,9 @@ POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY)) .Times(1); base::HistogramTester histogram_tester; - external_delegate_->DidAcceptSuggestion( - dummy_string, POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY, std::string(), 0); + external_delegate_->DidAcceptSuggestion(dummy_string, + POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY, + Suggestion::BackendId(), 0); histogram_tester.ExpectUniqueSample( "Autofill.SuggestionAcceptedIndex.Autocomplete", 0, 1); @@ -899,7 +905,7 @@ .Times(1); external_delegate_->DidAcceptSuggestion( dummy_string, POPUP_ITEM_ID_MERCHANT_PROMO_CODE_ENTRY, - absl::variant<std::string, GURL>(), 0); + absl::variant<Suggestion::BackendId, GURL>(), 0); } TEST_F(AutofillExternalDelegateUnitTest, ShouldShowGooglePayIcon) { @@ -997,7 +1003,8 @@ FillOrPreviewVirtualCardInformation( mojom::RendererFormDataAction::kPreview, _, _, _, _)); external_delegate_->DidSelectSuggestion( - std::u16string(), POPUP_ITEM_ID_VIRTUAL_CREDIT_CARD_ENTRY, std::string()); + std::u16string(), POPUP_ITEM_ID_VIRTUAL_CREDIT_CARD_ENTRY, + Suggestion::BackendId()); } // Tests that the prompt to show account cards shows up when the corresponding
diff --git a/components/autofill/core/browser/autofill_suggestion_generator.cc b/components/autofill/core/browser/autofill_suggestion_generator.cc index 20c60866..83fe4c8d 100644 --- a/components/autofill/core/browser/autofill_suggestion_generator.cc +++ b/components/autofill/core/browser/autofill_suggestion_generator.cc
@@ -20,7 +20,6 @@ #include "components/autofill/core/browser/metrics/autofill_metrics.h" #include "components/autofill/core/browser/payments/autofill_offer_manager.h" #include "components/autofill/core/browser/personal_data_manager.h" -#include "components/autofill/core/browser/ui/suggestion.h" #include "components/autofill/core/browser/ui/suggestion_selection.h" #include "components/autofill/core/common/autofill_clock.h" #include "components/autofill/core/common/autofill_constants.h" @@ -77,7 +76,7 @@ if (autofill_field.Type().group() == FieldTypeGroup::kPhoneHome) { for (auto& suggestion : suggestions) { const AutofillProfile* profile = personal_data_->GetProfileByGUID( - suggestion.GetPayload<std::string>()); + suggestion.GetPayload<Suggestion::BackendId>().value()); if (profile) { const std::u16string phone_home_city_and_number = profile->GetInfo(PHONE_HOME_CITY_AND_NUMBER, app_locale); @@ -92,7 +91,8 @@ for (auto& suggestion : suggestions) { suggestion.frontend_id = - MakeFrontendId(std::string(), suggestion.GetPayload<std::string>()); + MakeFrontendId(Suggestion::BackendId(), + suggestion.GetPayload<Suggestion::BackendId>()); } return suggestions; @@ -173,7 +173,8 @@ for (Suggestion& suggestion : suggestions) { if (suggestion.frontend_id == 0) { suggestion.frontend_id = - MakeFrontendId(suggestion.GetPayload<std::string>(), std::string()); + MakeFrontendId(suggestion.GetPayload<Suggestion::BackendId>(), + Suggestion::BackendId()); } } @@ -187,7 +188,7 @@ for (const IBAN* iban : ibans) { Suggestion& suggestion = suggestions.emplace_back(iban->value()); suggestion.frontend_id = POPUP_ITEM_ID_IBAN_ENTRY; - suggestion.payload = iban->guid(); + suggestion.payload = Suggestion::BackendId(iban->guid()); suggestion.main_text.value = iban->GetIdentifierStringForAutofillDisplay(); if (!iban->nickname().empty()) suggestion.label = iban->nickname(); @@ -208,7 +209,8 @@ Suggestion& suggestion = suggestions.back(); suggestion.label = base::ASCIIToUTF16( promo_code_offer->GetDisplayStrings().value_prop_text); - suggestion.payload = base::NumberToString(promo_code_offer->GetOfferId()); + suggestion.payload = Suggestion::BackendId( + base::NumberToString(promo_code_offer->GetOfferId())); suggestion.frontend_id = POPUP_ITEM_ID_MERCHANT_PROMO_CODE_ENTRY; // Every offer for a given merchant leads to the same GURL, so we grab the @@ -294,8 +296,8 @@ // profile IDs into a single integer. Credit card IDs are sent in the high // word and profile IDs are sent in the low word. int AutofillSuggestionGenerator::MakeFrontendId( - const std::string& cc_backend_id, - const std::string& profile_backend_id) const { + const Suggestion::BackendId& cc_backend_id, + const Suggestion::BackendId& profile_backend_id) const { InternalId cc_int_id = BackendIdToInternalId(cc_backend_id); InternalId profile_int_id = BackendIdToInternalId(profile_backend_id); @@ -315,16 +317,17 @@ // the high word and profile IDs are stored in the low word. void AutofillSuggestionGenerator::SplitFrontendId( int frontend_id, - std::string* cc_backend_id, - std::string* profile_backend_id) const { + Suggestion::BackendId* cc_backend_id, + Suggestion::BackendId* profile_backend_id) const { InternalId cc_int_id = InternalId((frontend_id >> std::numeric_limits<uint16_t>::digits) & std::numeric_limits<uint16_t>::max()); InternalId profile_int_id = InternalId(frontend_id & std::numeric_limits<uint16_t>::max()); - *cc_backend_id = InternalIdToBackendId(cc_int_id); - *profile_backend_id = InternalIdToBackendId(profile_int_id); + *cc_backend_id = Suggestion::BackendId(InternalIdToBackendId(cc_int_id)); + *profile_backend_id = + Suggestion::BackendId(InternalIdToBackendId(profile_int_id)); } Suggestion AutofillSuggestionGenerator::CreateCreditCardSuggestion( @@ -338,7 +341,7 @@ suggestion.main_text = Suggestion::Text(credit_card.GetInfo(type, app_locale), Suggestion::Text::IsPrimary(true)); suggestion.icon = credit_card.CardIconStringForAutofillSuggestion(); - suggestion.payload = credit_card.guid(); + suggestion.payload = Suggestion::BackendId(credit_card.guid()); suggestion.match = prefix_matched_suggestion ? Suggestion::PREFIX_MATCH : Suggestion::SUBSTRING_MATCH; @@ -410,7 +413,7 @@ DCHECK(server_duplicate_card); card_art_url_for_virtual_card_option = server_duplicate_card->card_art_url(); - suggestion.payload = server_duplicate_card->guid(); + suggestion.payload = Suggestion::BackendId(server_duplicate_card->guid()); } suggestion.frontend_id = POPUP_ITEM_ID_VIRTUAL_CREDIT_CARD_ENTRY; @@ -493,16 +496,16 @@ } InternalId AutofillSuggestionGenerator::BackendIdToInternalId( - const std::string& backend_id) const { - if (!base::IsValidGUID(backend_id)) + const Suggestion::BackendId& backend_id) const { + if (!base::IsValidGUID(backend_id.value())) return InternalId(0); - const auto found = backend_to_int_map_.find(backend_id); + const auto found = backend_to_int_map_.find(backend_id.value()); if (found == backend_to_int_map_.end()) { // Unknown one, make a new entry. InternalId int_id = InternalId(backend_to_int_map_.size() + 1); - backend_to_int_map_[backend_id] = int_id; - int_to_backend_map_[int_id] = backend_id; + backend_to_int_map_[backend_id.value()] = int_id; + int_to_backend_map_[int_id] = backend_id.value(); return int_id; } return InternalId(found->second);
diff --git a/components/autofill/core/browser/autofill_suggestion_generator.h b/components/autofill/core/browser/autofill_suggestion_generator.h index 94a39c653..914f689 100644 --- a/components/autofill/core/browser/autofill_suggestion_generator.h +++ b/components/autofill/core/browser/autofill_suggestion_generator.h
@@ -12,6 +12,7 @@ #include "base/gtest_prod_util.h" #include "base/memory/raw_ptr.h" #include "base/types/strong_alias.h" +#include "components/autofill/core/browser/ui/suggestion.h" namespace base { class Time; @@ -28,7 +29,6 @@ class FormStructure; class IBAN; class PersonalDataManager; -struct Suggestion; using InternalId = base::StrongAlias<class InternalIdTag, int>; @@ -83,11 +83,11 @@ // Methods for packing and unpacking credit card and profile IDs for sending // and receiving to and from the renderer process. - int MakeFrontendId(const std::string& cc_backend_id, - const std::string& profile_backend_id) const; + int MakeFrontendId(const Suggestion::BackendId& cc_backend_id, + const Suggestion::BackendId& profile_backend_id) const; void SplitFrontendId(int frontend_id, - std::string* cc_backend_id, - std::string* profile_backend_id) const; + Suggestion::BackendId* cc_backend_id, + Suggestion::BackendId* profile_backend_id) const; private: FRIEND_TEST_ALL_PREFIXES(AutofillSuggestionGeneratorTest, @@ -136,7 +136,8 @@ // Maps suggestion backend ID to and from an integer identifying it. Two of // these intermediate integers are packed by MakeFrontendID to make the IDs // that this class generates for the UI and for IPC. - InternalId BackendIdToInternalId(const std::string& backend_id) const; + InternalId BackendIdToInternalId( + const Suggestion::BackendId& backend_id) const; std::string InternalIdToBackendId(InternalId int_id) const; // autofill_client_ and the generator are both one per tab, and have the same
diff --git a/components/autofill/core/browser/autofill_suggestion_generator_unittest.cc b/components/autofill/core/browser/autofill_suggestion_generator_unittest.cc index 4ca6cadb..4c7ffa1 100644 --- a/components/autofill/core/browser/autofill_suggestion_generator_unittest.cc +++ b/components/autofill/core/browser/autofill_suggestion_generator_unittest.cc
@@ -291,8 +291,8 @@ EXPECT_EQ(virtual_card_suggestion.frontend_id, POPUP_ITEM_ID_VIRTUAL_CREDIT_CARD_ENTRY); - EXPECT_EQ(absl::get<std::string>(virtual_card_suggestion.payload), - "00000000-0000-0000-0000-000000000001"); + EXPECT_EQ(virtual_card_suggestion.GetPayload<Suggestion::BackendId>(), + Suggestion::BackendId("00000000-0000-0000-0000-000000000001")); Suggestion real_card_suggestion = suggestion_generator()->CreateCreditCardSuggestion( @@ -301,8 +301,8 @@ ""); EXPECT_EQ(real_card_suggestion.frontend_id, 0); - EXPECT_EQ(absl::get<std::string>(real_card_suggestion.payload), - "00000000-0000-0000-0000-000000000001"); + EXPECT_EQ(real_card_suggestion.GetPayload<Suggestion::BackendId>(), + Suggestion::BackendId("00000000-0000-0000-0000-000000000001")); } TEST_F(AutofillSuggestionGeneratorTest, CreateCreditCardSuggestion_LocalCard) { @@ -330,8 +330,8 @@ EXPECT_EQ(virtual_card_suggestion.frontend_id, POPUP_ITEM_ID_VIRTUAL_CREDIT_CARD_ENTRY); - EXPECT_EQ(absl::get<std::string>(virtual_card_suggestion.payload), - "00000000-0000-0000-0000-000000000001"); + EXPECT_EQ(virtual_card_suggestion.GetPayload<Suggestion::BackendId>(), + Suggestion::BackendId("00000000-0000-0000-0000-000000000001")); Suggestion real_card_suggestion = suggestion_generator()->CreateCreditCardSuggestion( @@ -340,8 +340,8 @@ ""); EXPECT_EQ(real_card_suggestion.frontend_id, 0); - EXPECT_EQ(absl::get<std::string>(real_card_suggestion.payload), - "00000000-0000-0000-0000-000000000002"); + EXPECT_EQ(real_card_suggestion.GetPayload<Suggestion::BackendId>(), + Suggestion::BackendId("00000000-0000-0000-0000-000000000002")); EXPECT_TRUE(real_card_suggestion.custom_icon.IsEmpty()); } @@ -645,13 +645,15 @@ EXPECT_EQ(promo_code_suggestions[0].main_text.value, u"test_promo_code_1"); EXPECT_EQ(promo_code_suggestions[0].label, u"test_value_prop_text_1"); - EXPECT_EQ(promo_code_suggestions[0].GetPayload<std::string>(), "1"); + EXPECT_EQ(promo_code_suggestions[0].GetPayload<Suggestion::BackendId>(), + Suggestion::BackendId("1")); EXPECT_EQ(promo_code_suggestions[0].frontend_id, POPUP_ITEM_ID_MERCHANT_PROMO_CODE_ENTRY); EXPECT_EQ(promo_code_suggestions[1].main_text.value, u"test_promo_code_2"); EXPECT_EQ(promo_code_suggestions[1].label, u"test_value_prop_text_2"); - EXPECT_EQ(promo_code_suggestions[1].GetPayload<std::string>(), "2"); + EXPECT_EQ(promo_code_suggestions[1].GetPayload<Suggestion::BackendId>(), + Suggestion::BackendId("2")); EXPECT_EQ(promo_code_suggestions[1].frontend_id, POPUP_ITEM_ID_MERCHANT_PROMO_CODE_ENTRY);
diff --git a/components/autofill/core/browser/browser_autofill_manager.cc b/components/autofill/core/browser/browser_autofill_manager.cc index 33d9fd9..5a8d48e 100644 --- a/components/autofill/core/browser/browser_autofill_manager.cc +++ b/components/autofill/core/browser/browser_autofill_manager.cc
@@ -1842,22 +1842,23 @@ CreditCard* BrowserAutofillManager::GetCreditCard(int unique_id) { // Unpack the |unique_id| into component parts. - std::string credit_card_id; - std::string profile_id; + Suggestion::BackendId credit_card_id; + Suggestion::BackendId profile_id; suggestion_generator_->SplitFrontendId(unique_id, &credit_card_id, &profile_id); - return personal_data_->GetCreditCardByGUID(credit_card_id); + return personal_data_->GetCreditCardByGUID(credit_card_id.value()); } AutofillProfile* BrowserAutofillManager::GetProfile(int unique_id) { // Unpack the |unique_id| into component parts. - std::string credit_card_id; - std::string profile_id; + Suggestion::BackendId credit_card_id; + Suggestion::BackendId profile_id; suggestion_generator_->SplitFrontendId(unique_id, &credit_card_id, &profile_id); - if (base::IsValidGUID(profile_id)) - return personal_data_->GetProfileByGUID(profile_id); + std::string guid = profile_id.value(); + if (base::IsValidGUID(guid)) + return personal_data_->GetProfileByGUID(guid); return nullptr; }
diff --git a/components/autofill/core/browser/browser_autofill_manager_unittest.cc b/components/autofill/core/browser/browser_autofill_manager_unittest.cc index 2bc0c2d9..7493f1cd 100644 --- a/components/autofill/core/browser/browser_autofill_manager_unittest.cc +++ b/components/autofill/core/browser/browser_autofill_manager_unittest.cc
@@ -602,7 +602,7 @@ int MakeFrontendId(const std::string& cc_sid, const std::string& profile_sid) const { return browser_autofill_manager_->suggestion_generator()->MakeFrontendId( - cc_sid, profile_sid); + Suggestion::BackendId(cc_sid), Suggestion::BackendId(profile_sid)); } bool WillFillCreditCardNumber(const FormData& form,
diff --git a/components/autofill/core/browser/metrics/autofill_metrics_unittest.cc b/components/autofill/core/browser/metrics/autofill_metrics_unittest.cc index dc84f884..b3bce3c 100644 --- a/components/autofill/core/browser/metrics/autofill_metrics_unittest.cc +++ b/components/autofill/core/browser/metrics/autofill_metrics_unittest.cc
@@ -54,6 +54,7 @@ #include "components/autofill/core/browser/test_personal_data_manager.h" #include "components/autofill/core/browser/ui/popup_item_ids.h" #include "components/autofill/core/browser/ui/popup_types.h" +#include "components/autofill/core/browser/ui/suggestion.h" #include "components/autofill/core/browser/webdata/autofill_webdata_service.h" #include "components/autofill/core/common/autofill_clock.h" #include "components/autofill/core/common/autofill_features.h" @@ -793,8 +794,8 @@ std::string guid(kTestGuid); autofill_manager().FillOrPreviewForm( mojom::RendererFormDataAction::kFill, 0, form, form.fields.front(), - autofill_manager().suggestion_generator()->MakeFrontendId(std::string(), - guid)); + autofill_manager().suggestion_generator()->MakeFrontendId( + Suggestion::BackendId(), Suggestion::BackendId(guid))); // Simulate form submission. base::HistogramTester histogram_tester; @@ -840,8 +841,8 @@ std::string guid(kTestGuid); autofill_manager().FillOrPreviewForm( mojom::RendererFormDataAction::kFill, 0, form, form.fields.front(), - autofill_manager().suggestion_generator()->MakeFrontendId(std::string(), - guid)); + autofill_manager().suggestion_generator()->MakeFrontendId( + Suggestion::BackendId(), Suggestion::BackendId(guid))); // Simulate form submission. base::HistogramTester histogram_tester; @@ -899,8 +900,8 @@ std::string guid(kTestGuid); autofill_manager().FillOrPreviewForm( mojom::RendererFormDataAction::kFill, 0, form, form.fields.front(), - autofill_manager().suggestion_generator()->MakeFrontendId(std::string(), - guid)); + autofill_manager().suggestion_generator()->MakeFrontendId( + Suggestion::BackendId(), Suggestion::BackendId(guid))); base::HistogramTester histogram_tester; @@ -947,8 +948,8 @@ std::string guid(kTestGuid); autofill_manager().FillOrPreviewForm( mojom::RendererFormDataAction::kFill, 0, form, form.fields.front(), - autofill_manager().suggestion_generator()->MakeFrontendId(std::string(), - guid)); + autofill_manager().suggestion_generator()->MakeFrontendId( + Suggestion::BackendId(), Suggestion::BackendId(guid))); // Simulate form submission. base::HistogramTester histogram_tester; @@ -1027,8 +1028,8 @@ std::string guid(kTestGuid); autofill_manager().FillOrPreviewForm( mojom::RendererFormDataAction::kFill, 0, form, form.fields.front(), - autofill_manager().suggestion_generator()->MakeFrontendId(std::string(), - guid)); + autofill_manager().suggestion_generator()->MakeFrontendId( + Suggestion::BackendId(), Suggestion::BackendId(guid))); // Simulate form submission. base::HistogramTester histogram_tester; @@ -1111,8 +1112,8 @@ std::string guid(kTestGuid); autofill_manager().FillOrPreviewForm( mojom::RendererFormDataAction::kFill, 0, form, form.fields.front(), - autofill_manager().suggestion_generator()->MakeFrontendId(std::string(), - guid)); + autofill_manager().suggestion_generator()->MakeFrontendId( + Suggestion::BackendId(), Suggestion::BackendId(guid))); // Simulate form submission. base::HistogramTester histogram_tester; @@ -1201,8 +1202,8 @@ std::string guid(kTestGuid); autofill_manager().FillOrPreviewForm( mojom::RendererFormDataAction::kFill, 0, form, form.fields.front(), - autofill_manager().suggestion_generator()->MakeFrontendId(std::string(), - guid)); + autofill_manager().suggestion_generator()->MakeFrontendId( + Suggestion::BackendId(), Suggestion::BackendId(guid))); // Simulate form submission. base::HistogramTester histogram_tester; @@ -1294,8 +1295,8 @@ std::string guid(kTestGuid); autofill_manager().FillOrPreviewForm( mojom::RendererFormDataAction::kFill, 0, form, form.fields.front(), - autofill_manager().suggestion_generator()->MakeFrontendId(std::string(), - guid)); + autofill_manager().suggestion_generator()->MakeFrontendId( + Suggestion::BackendId(), Suggestion::BackendId(guid))); // Simulate form submission. base::HistogramTester histogram_tester; @@ -1375,8 +1376,8 @@ std::string guid(kTestGuid); autofill_manager().FillOrPreviewForm( mojom::RendererFormDataAction::kFill, 0, form, form.fields.front(), - autofill_manager().suggestion_generator()->MakeFrontendId(std::string(), - guid)); + autofill_manager().suggestion_generator()->MakeFrontendId( + Suggestion::BackendId(), Suggestion::BackendId(guid))); // Simulate form submission. base::HistogramTester histogram_tester; @@ -1486,8 +1487,8 @@ // Trigger phone number rationalization at filling time. autofill_manager().FillOrPreviewForm( mojom::RendererFormDataAction::kFill, 0, form, form.fields.front(), - autofill_manager().suggestion_generator()->MakeFrontendId(std::string(), - guid)); + autofill_manager().suggestion_generator()->MakeFrontendId( + Suggestion::BackendId(), Suggestion::BackendId(guid))); EXPECT_EQ( 1, user_action_tester.GetActionCount("Autofill_FilledProfileSuggestion")); @@ -1553,8 +1554,8 @@ // Trigger phone number rationalization at filling time. autofill_manager().FillOrPreviewForm( mojom::RendererFormDataAction::kFill, 0, form, form.fields.front(), - autofill_manager().suggestion_generator()->MakeFrontendId(std::string(), - guid)); + autofill_manager().suggestion_generator()->MakeFrontendId( + Suggestion::BackendId(), Suggestion::BackendId(guid))); EXPECT_EQ( 1, user_action_tester.GetActionCount("Autofill_FilledProfileSuggestion")); @@ -1636,8 +1637,8 @@ std::string guid(kTestGuid); // local profile. autofill_manager().FillOrPreviewForm( mojom::RendererFormDataAction::kFill, 0, form, form.fields.front(), - autofill_manager().suggestion_generator()->MakeFrontendId(std::string(), - guid)); + autofill_manager().suggestion_generator()->MakeFrontendId( + Suggestion::BackendId(), Suggestion::BackendId(guid))); } VerifyUkm( @@ -2027,8 +2028,8 @@ // Trigger phone number rationalization at filling time. autofill_manager().FillOrPreviewForm( mojom::RendererFormDataAction::kFill, 0, form, form.fields.front(), - autofill_manager().suggestion_generator()->MakeFrontendId(std::string(), - guid)); + autofill_manager().suggestion_generator()->MakeFrontendId( + Suggestion::BackendId(), Suggestion::BackendId(guid))); EXPECT_EQ( 1, user_action_tester.GetActionCount("Autofill_FilledProfileSuggestion")); @@ -2110,8 +2111,8 @@ // Trigger phone number rationalization at filling time. autofill_manager().FillOrPreviewForm( mojom::RendererFormDataAction::kFill, 0, form, form.fields.front(), - autofill_manager().suggestion_generator()->MakeFrontendId(std::string(), - guid)); + autofill_manager().suggestion_generator()->MakeFrontendId( + Suggestion::BackendId(), Suggestion::BackendId(guid))); EXPECT_EQ( 1, user_action_tester.GetActionCount("Autofill_FilledProfileSuggestion")); @@ -3878,11 +3879,12 @@ base::UserActionTester user_action_tester; std::string guid("10000000-0000-0000-0000-000000000001"); // local card external_delegate_->OnQuery(0, form, form.fields.front(), gfx::RectF()); + Suggestion::BackendId backend_id = Suggestion::BackendId(guid); external_delegate_->DidAcceptSuggestion( u"Test", autofill_manager().suggestion_generator()->MakeFrontendId( - guid, std::string()), - guid, 0); + backend_id, Suggestion::BackendId()), + backend_id, 0); EXPECT_EQ(1, user_action_tester.GetActionCount("Autofill_SelectedSuggestion")); } @@ -3903,7 +3905,7 @@ std::string guid("10000000-0000-0000-0000-000000000001"); // local card external_delegate_->OnQuery(0, form, form.fields.front(), gfx::RectF()); external_delegate_->DidAcceptSuggestion( - std::u16string(), POPUP_ITEM_ID_CLEAR_FORM, std::string(), 0); + std::u16string(), POPUP_ITEM_ID_CLEAR_FORM, Suggestion::BackendId(), 0); EXPECT_EQ(1, user_action_tester.GetActionCount("Autofill_ClearedForm")); } @@ -3922,11 +3924,12 @@ base::UserActionTester user_action_tester; std::string guid("10000000-0000-0000-0000-000000000001"); // local card external_delegate_->OnQuery(0, form, form.fields.front(), gfx::RectF()); + Suggestion::BackendId backend_id = Suggestion::BackendId(guid); external_delegate_->DidAcceptSuggestion( u"Test", autofill_manager().suggestion_generator()->MakeFrontendId( - guid, std::string()), - guid, 0); + backend_id, Suggestion::BackendId()), + backend_id, 0); EXPECT_EQ(1, user_action_tester.GetActionCount("Autofill_SelectedSuggestion")); } @@ -3938,7 +3941,7 @@ autofill_manager().FillOrPreviewForm( mojom::RendererFormDataAction::kFill, 0, form, form.fields.front(), autofill_manager().suggestion_generator()->MakeFrontendId( - guid, std::string())); + Suggestion::BackendId(guid), Suggestion::BackendId())); EXPECT_EQ(1, user_action_tester.GetActionCount( "Autofill_FilledCreditCardSuggestion")); } @@ -4097,11 +4100,12 @@ base::UserActionTester user_action_tester; std::string guid(kTestGuid); // local profile. external_delegate_->OnQuery(0, form, form.fields.front(), gfx::RectF()); + Suggestion::BackendId backend_id = Suggestion::BackendId(guid); external_delegate_->DidAcceptSuggestion( u"Test", - autofill_manager().suggestion_generator()->MakeFrontendId(std::string(), - guid), - guid, 0); + autofill_manager().suggestion_generator()->MakeFrontendId( + Suggestion::BackendId(), backend_id), + backend_id, 0); EXPECT_EQ(1, user_action_tester.GetActionCount("Autofill_SelectedSuggestion")); } @@ -4112,8 +4116,8 @@ std::string guid(kTestGuid); // local profile. autofill_manager().FillOrPreviewForm( mojom::RendererFormDataAction::kFill, 0, form, form.fields.front(), - autofill_manager().suggestion_generator()->MakeFrontendId(std::string(), - guid)); + autofill_manager().suggestion_generator()->MakeFrontendId( + Suggestion::BackendId(), Suggestion::BackendId(guid))); EXPECT_EQ(1, user_action_tester.GetActionCount( "Autofill_FilledProfileSuggestion")); } @@ -4794,7 +4798,7 @@ autofill_manager().FillOrPreviewForm( mojom::RendererFormDataAction::kFill, 0, form, form.fields[2], autofill_manager().suggestion_generator()->MakeFrontendId( - guid, std::string())); + Suggestion::BackendId(guid), Suggestion::BackendId())); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.CreditCard", FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_SELECTED, 1); @@ -4821,11 +4825,11 @@ autofill_manager().FillOrPreviewForm( mojom::RendererFormDataAction::kFill, 0, form, form.fields[2], autofill_manager().suggestion_generator()->MakeFrontendId( - guid, std::string())); + Suggestion::BackendId(guid), Suggestion::BackendId())); autofill_manager().FillOrPreviewForm( mojom::RendererFormDataAction::kFill, 0, form, form.fields[2], autofill_manager().suggestion_generator()->MakeFrontendId( - guid, std::string())); + Suggestion::BackendId(guid), Suggestion::BackendId())); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.CreditCard", FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_SELECTED, 2); @@ -4940,7 +4944,7 @@ autofill_manager().FillOrPreviewForm( mojom::RendererFormDataAction::kFill, 0, form, form.fields.front(), autofill_manager().suggestion_generator()->MakeFrontendId( - guid, std::string())); + Suggestion::BackendId(guid), Suggestion::BackendId())); histogram_tester.ExpectBucketCount("Autofill.FormEvents.CreditCard", FORM_EVENT_LOCAL_SUGGESTION_FILLED, 1); histogram_tester.ExpectBucketCount(credit_card_form_events_frame_histogram_, @@ -4993,7 +4997,7 @@ autofill_manager().FillOrPreviewForm( mojom::RendererFormDataAction::kFill, 0, form, form.fields.back(), autofill_manager().suggestion_generator()->MakeFrontendId( - guid, std::string())); + Suggestion::BackendId(guid), Suggestion::BackendId())); OnCreditCardFetchingSuccessful(u"6011000990139424"); SubmitForm(form); histogram_tester.ExpectBucketCount( @@ -5029,7 +5033,7 @@ autofill_manager().FillOrPreviewForm( mojom::RendererFormDataAction::kFill, 0, form, form.fields.front(), autofill_manager().suggestion_generator()->MakeFrontendId( - guid, std::string())); + Suggestion::BackendId(guid), Suggestion::BackendId())); histogram_tester.ExpectBucketCount("Autofill.FormEvents.CreditCard", FORM_EVENT_SERVER_SUGGESTION_FILLED, 1); histogram_tester.ExpectBucketCount(credit_card_form_events_frame_histogram_, @@ -5053,11 +5057,11 @@ autofill_manager().FillOrPreviewForm( mojom::RendererFormDataAction::kFill, 0, form, form.fields.front(), autofill_manager().suggestion_generator()->MakeFrontendId( - guid, std::string())); + Suggestion::BackendId(guid), Suggestion::BackendId())); autofill_manager().FillOrPreviewForm( mojom::RendererFormDataAction::kFill, 0, form, form.fields.front(), autofill_manager().suggestion_generator()->MakeFrontendId( - guid, std::string())); + Suggestion::BackendId(guid), Suggestion::BackendId())); histogram_tester.ExpectBucketCount("Autofill.FormEvents.CreditCard", FORM_EVENT_LOCAL_SUGGESTION_FILLED, 2); histogram_tester.ExpectBucketCount(credit_card_form_events_frame_histogram_, @@ -5096,8 +5100,8 @@ base::HistogramTester histogram_tester; autofill_manager().FillOrPreviewForm( mojom::RendererFormDataAction::kFill, 0, form, form.fields.front(), - autofill_manager().suggestion_generator()->MakeFrontendId(local_guid, - std::string())); + autofill_manager().suggestion_generator()->MakeFrontendId( + Suggestion::BackendId(local_guid), Suggestion::BackendId())); EXPECT_THAT( histogram_tester.GetAllSamples("Autofill.FormEvents.CreditCard"), @@ -5142,8 +5146,8 @@ std::string local_guid(local_and_duplicate_server_card_guids.at(0)); autofill_manager().FillOrPreviewForm( mojom::RendererFormDataAction::kFill, 0, form, form.fields.front(), - autofill_manager().suggestion_generator()->MakeFrontendId(local_guid, - std::string())); + autofill_manager().suggestion_generator()->MakeFrontendId( + Suggestion::BackendId(local_guid), Suggestion::BackendId())); EXPECT_THAT( histogram_tester.GetAllSamples("Autofill.FormEvents.CreditCard"), @@ -5247,7 +5251,7 @@ autofill_manager().FillOrPreviewForm( mojom::RendererFormDataAction::kFill, 0, form, form.fields.back(), autofill_manager().suggestion_generator()->MakeFrontendId( - guid, std::string())); + Suggestion::BackendId(guid), Suggestion::BackendId())); // Preflight call is made only if a masked server card is available and the // user is eligible for FIDO authentication (except iOS). #if BUILDFLAG(IS_IOS) @@ -5275,7 +5279,7 @@ autofill_manager().FillOrPreviewForm( mojom::RendererFormDataAction::kFill, 0, form, form.fields.back(), autofill_manager().suggestion_generator()->MakeFrontendId( - guid, std::string())); + Suggestion::BackendId(guid), Suggestion::BackendId())); // Preflight call is made only if a masked server card is available and the // user is eligible for FIDO authentication (except iOS). #if BUILDFLAG(IS_IOS) @@ -5328,7 +5332,7 @@ autofill_manager().FillOrPreviewForm( mojom::RendererFormDataAction::kFill, 0, form, form.fields.back(), autofill_manager().suggestion_generator()->MakeFrontendId( - guid, std::string())); + Suggestion::BackendId(guid), Suggestion::BackendId())); OnDidGetRealPan(AutofillClient::PaymentsRpcResult::kSuccess, "6011000990139424"); histogram_tester.ExpectTotalCount( @@ -5354,7 +5358,7 @@ autofill_manager().FillOrPreviewForm( mojom::RendererFormDataAction::kFill, 0, form, form.fields.back(), autofill_manager().suggestion_generator()->MakeFrontendId( - guid, std::string())); + Suggestion::BackendId(guid), Suggestion::BackendId())); OnDidGetRealPan(AutofillClient::PaymentsRpcResult::kPermanentFailure, std::string()); histogram_tester.ExpectTotalCount( @@ -5395,7 +5399,7 @@ autofill_manager().FillOrPreviewForm( mojom::RendererFormDataAction::kFill, 0, form, form.fields.back(), autofill_manager().suggestion_generator()->MakeFrontendId( - guid, std::string())); + Suggestion::BackendId(guid), Suggestion::BackendId())); OnDidGetRealPanWithNonHttpOkResponse(); histogram_tester.ExpectTotalCount( "Autofill.UnmaskPrompt.GetRealPanDuration", 1); @@ -5760,8 +5764,8 @@ std::string guid("10000000-0000-0000-0000-000000000001"); autofill_manager().FillOrPreviewForm( mojom::RendererFormDataAction::kFill, 0, form, form.fields.back(), - autofill_manager().suggestion_generator()->MakeFrontendId(guid, - std::string())); + autofill_manager().suggestion_generator()->MakeFrontendId( + Suggestion::BackendId(guid), Suggestion::BackendId())); SubmitForm(form); histogram_tester.ExpectBucketCount( @@ -5981,7 +5985,7 @@ autofill_manager().FillOrPreviewForm( mojom::RendererFormDataAction::kFill, 0, form, form.fields.front(), autofill_manager().suggestion_generator()->MakeFrontendId( - guid, std::string())); + Suggestion::BackendId(guid), Suggestion::BackendId())); SubmitForm(form); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.CreditCard", @@ -6074,8 +6078,9 @@ autofill_manager().FillOrPreviewForm( mojom::RendererFormDataAction::kFill, 0, form, form.fields.front(), autofill_manager().suggestion_generator()->MakeFrontendId( - guid, std::string())); + Suggestion::BackendId(guid), Suggestion::BackendId())); SubmitForm(form); + histogram_tester.ExpectBucketCount( "Autofill.FormEvents.CreditCard", FORM_EVENT_SERVER_SUGGESTION_WILL_SUBMIT_ONCE, 1); @@ -6119,7 +6124,7 @@ autofill_manager().FillOrPreviewForm( mojom::RendererFormDataAction::kFill, 0, form, form.fields.back(), autofill_manager().suggestion_generator()->MakeFrontendId( - guid, std::string())); + Suggestion::BackendId(guid), Suggestion::BackendId())); OnCreditCardFetchingSuccessful(u"6011000990139424"); SubmitForm(form); histogram_tester.ExpectBucketCount( @@ -6448,7 +6453,7 @@ autofill_manager().FillOrPreviewForm( mojom::RendererFormDataAction::kFill, 0, form, form.fields.front(), autofill_manager().suggestion_generator()->MakeFrontendId( - guid, std::string())); + Suggestion::BackendId(guid), Suggestion::BackendId())); SubmitForm(form); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.CreditCard", @@ -6507,7 +6512,7 @@ autofill_manager().FillOrPreviewForm( mojom::RendererFormDataAction::kFill, 0, form, form.fields.front(), autofill_manager().suggestion_generator()->MakeFrontendId( - guid, std::string())); + Suggestion::BackendId(guid), Suggestion::BackendId())); SubmitForm(form); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.CreditCard", @@ -6535,7 +6540,7 @@ autofill_manager().FillOrPreviewForm( mojom::RendererFormDataAction::kFill, 0, form, form.fields.back(), autofill_manager().suggestion_generator()->MakeFrontendId( - guid, std::string())); + Suggestion::BackendId(guid), Suggestion::BackendId())); OnCreditCardFetchingSuccessful(u"6011000990139424"); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.CreditCard", @@ -6743,7 +6748,7 @@ autofill_manager().FillOrPreviewForm( mojom::RendererFormDataAction::kFill, 0, form, form.fields.front(), autofill_manager().suggestion_generator()->MakeFrontendId( - guid, std::string())); + Suggestion::BackendId(guid), Suggestion::BackendId())); histogram_tester.ExpectBucketCount("Autofill.FormEvents.CreditCard", FORM_EVENT_SUGGESTIONS_SHOWN, 1); histogram_tester.ExpectBucketCount("Autofill.FormEvents.CreditCard", @@ -6792,7 +6797,7 @@ autofill_manager().FillOrPreviewForm( mojom::RendererFormDataAction::kFill, 0, form, form.fields.back(), autofill_manager().suggestion_generator()->MakeFrontendId( - guid, std::string())); + Suggestion::BackendId(guid), Suggestion::BackendId())); OnDidGetRealPan(AutofillClient::PaymentsRpcResult::kSuccess, "6011000990139424"); SubmitForm(form); @@ -6840,7 +6845,7 @@ autofill_manager().FillOrPreviewForm( mojom::RendererFormDataAction::kFill, 0, form, form.fields.back(), autofill_manager().suggestion_generator()->MakeFrontendId( - guid, std::string())); + Suggestion::BackendId(guid), Suggestion::BackendId())); OnDidGetRealPan(AutofillClient::PaymentsRpcResult::kSuccess, "6011000990139424"); SubmitForm(form); @@ -6903,7 +6908,7 @@ autofill_manager().FillOrPreviewForm( mojom::RendererFormDataAction::kFill, 0, form, form.fields.back(), autofill_manager().suggestion_generator()->MakeFrontendId( - guid, std::string())); + Suggestion::BackendId(guid), Suggestion::BackendId())); OnDidGetRealPan(AutofillClient::PaymentsRpcResult::kSuccess, "6011000990139424"); SubmitForm(form); @@ -6977,7 +6982,7 @@ autofill_manager().FillOrPreviewForm( mojom::RendererFormDataAction::kFill, 0, form, form.fields.back(), autofill_manager().suggestion_generator()->MakeFrontendId( - guid, std::string())); + Suggestion::BackendId(guid), Suggestion::BackendId())); OnDidGetRealPan(AutofillClient::PaymentsRpcResult::kSuccess, "6011000990139424"); @@ -7038,7 +7043,7 @@ autofill_manager().FillOrPreviewForm( mojom::RendererFormDataAction::kFill, 0, form, form.fields.back(), autofill_manager().suggestion_generator()->MakeFrontendId( - guid, std::string())); + Suggestion::BackendId(guid), Suggestion::BackendId())); OnDidGetRealPan(AutofillClient::PaymentsRpcResult::kPermanentFailure, std::string()); @@ -7096,7 +7101,7 @@ autofill_manager().FillOrPreviewForm( mojom::RendererFormDataAction::kFill, 0, form, form.fields.back(), autofill_manager().suggestion_generator()->MakeFrontendId( - guid, std::string())); + Suggestion::BackendId(guid), Suggestion::BackendId())); OnDidGetRealPan(AutofillClient::PaymentsRpcResult::kSuccess, "6011000990139424"); @@ -7107,7 +7112,7 @@ autofill_manager().FillOrPreviewForm( mojom::RendererFormDataAction::kFill, 0, form, form.fields.back(), autofill_manager().suggestion_generator()->MakeFrontendId( - guid, std::string())); + Suggestion::BackendId(guid), Suggestion::BackendId())); SubmitForm(form); EXPECT_THAT( histogram_tester.GetAllSamples( @@ -7535,8 +7540,8 @@ std::string guid(kTestGuid); // local profile autofill_manager().FillOrPreviewForm( mojom::RendererFormDataAction::kFill, 0, form, form.fields.front(), - autofill_manager().suggestion_generator()->MakeFrontendId(std::string(), - guid)); + autofill_manager().suggestion_generator()->MakeFrontendId( + Suggestion::BackendId(), Suggestion::BackendId(guid))); histogram_tester.ExpectBucketCount("Autofill.FormEvents.Address", FORM_EVENT_LOCAL_SUGGESTION_FILLED, 1); histogram_tester.ExpectBucketCount("Autofill.FormEvents.Address", @@ -7571,12 +7576,12 @@ std::string guid(kTestGuid); // local profile autofill_manager().FillOrPreviewForm( mojom::RendererFormDataAction::kFill, 0, form, form.fields.front(), - autofill_manager().suggestion_generator()->MakeFrontendId(std::string(), - guid)); + autofill_manager().suggestion_generator()->MakeFrontendId( + Suggestion::BackendId(), Suggestion::BackendId(guid))); autofill_manager().FillOrPreviewForm( mojom::RendererFormDataAction::kFill, 0, form, form.fields.front(), - autofill_manager().suggestion_generator()->MakeFrontendId(std::string(), - guid)); + autofill_manager().suggestion_generator()->MakeFrontendId( + Suggestion::BackendId(), Suggestion::BackendId(guid))); histogram_tester.ExpectBucketCount("Autofill.FormEvents.Address", FORM_EVENT_LOCAL_SUGGESTION_FILLED, 2); histogram_tester.ExpectBucketCount("Autofill.FormEvents.Address", @@ -7595,8 +7600,8 @@ std::string guid(kTestGuid); // server profile autofill_manager().FillOrPreviewForm( mojom::RendererFormDataAction::kFill, 0, form, form.fields.front(), - autofill_manager().suggestion_generator()->MakeFrontendId(std::string(), - guid)); + autofill_manager().suggestion_generator()->MakeFrontendId( + Suggestion::BackendId(), Suggestion::BackendId(guid))); histogram_tester.ExpectBucketCount("Autofill.FormEvents.Address", FORM_EVENT_SERVER_SUGGESTION_FILLED, 1); histogram_tester.ExpectBucketCount("Autofill.FormEvents.Address", @@ -7613,12 +7618,12 @@ std::string guid(kTestGuid); // server profile autofill_manager().FillOrPreviewForm( mojom::RendererFormDataAction::kFill, 0, form, form.fields.front(), - autofill_manager().suggestion_generator()->MakeFrontendId(std::string(), - guid)); + autofill_manager().suggestion_generator()->MakeFrontendId( + Suggestion::BackendId(), Suggestion::BackendId(guid))); autofill_manager().FillOrPreviewForm( mojom::RendererFormDataAction::kFill, 0, form, form.fields.front(), - autofill_manager().suggestion_generator()->MakeFrontendId(std::string(), - guid)); + autofill_manager().suggestion_generator()->MakeFrontendId( + Suggestion::BackendId(), Suggestion::BackendId(guid))); histogram_tester.ExpectBucketCount("Autofill.FormEvents.Address", FORM_EVENT_SERVER_SUGGESTION_FILLED, 2); histogram_tester.ExpectBucketCount("Autofill.FormEvents.Address", @@ -7732,8 +7737,8 @@ std::string guid(kTestGuid); // local profile autofill_manager().FillOrPreviewForm( mojom::RendererFormDataAction::kFill, 0, form, form.fields.front(), - autofill_manager().suggestion_generator()->MakeFrontendId(std::string(), - guid)); + autofill_manager().suggestion_generator()->MakeFrontendId( + Suggestion::BackendId(), Suggestion::BackendId(guid))); SubmitForm(form); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.Address", @@ -7874,8 +7879,8 @@ std::string guid(kTestGuid); // local profile autofill_manager().FillOrPreviewForm( mojom::RendererFormDataAction::kFill, 0, form, form.fields.front(), - autofill_manager().suggestion_generator()->MakeFrontendId(std::string(), - guid)); + autofill_manager().suggestion_generator()->MakeFrontendId( + Suggestion::BackendId(), Suggestion::BackendId(guid))); SubmitForm(form); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.Address", @@ -8839,7 +8844,7 @@ autofill_manager().FillOrPreviewForm( mojom::RendererFormDataAction::kFill, 0, form, form.fields.front(), autofill_manager().suggestion_generator()->MakeFrontendId( - guid, std::string())); + Suggestion::BackendId(guid), Suggestion::BackendId())); ChangeTextField(form, form.fields.front()); // Simulate a second keystroke; make sure we don't log the metric twice. ChangeTextField(form, form.fields.front()); @@ -8988,8 +8993,8 @@ std::string guid(kTestGuid); autofill_manager().FillOrPreviewForm( mojom::RendererFormDataAction::kFill, 0, form, form.fields.front(), - autofill_manager().suggestion_generator()->MakeFrontendId(std::string(), - guid)); + autofill_manager().suggestion_generator()->MakeFrontendId( + Suggestion::BackendId(), Suggestion::BackendId(guid))); ChangeTextField(form, form.fields.front()); // Simulate a second keystroke; make sure we don't log the metric twice. ChangeTextField(form, form.fields.front()); @@ -10082,8 +10087,8 @@ // Simulate filling the form. autofill_manager().FillOrPreviewForm( mojom::RendererFormDataAction::kFill, 0, form, form.fields.front(), - autofill_manager().suggestion_generator()->MakeFrontendId(std::string(), - guid)); + autofill_manager().suggestion_generator()->MakeFrontendId( + Suggestion::BackendId(), Suggestion::BackendId(guid))); // Simulate checking whether to fill a dynamic form after the form was filled // initially. @@ -11044,8 +11049,8 @@ autofill_manager().FillOrPreviewForm( mojom::RendererFormDataAction::kFill, /*query_id=*/0, form, form.fields.front(), - autofill_manager().suggestion_generator()->MakeFrontendId(std::string(), - kTestGuid)); + autofill_manager().suggestion_generator()->MakeFrontendId( + Suggestion::BackendId(), Suggestion::BackendId(kTestGuid))); } // Simulate form submission. @@ -11363,8 +11368,8 @@ /*has_autofill_suggestions=*/true, form_, form_.fields[0]); autofill_manager().FillOrPreviewForm( mojom::RendererFormDataAction::kFill, 0, form_, form_.fields.front(), - autofill_manager().suggestion_generator()->MakeFrontendId(std::string(), - kTestGuid)); + autofill_manager().suggestion_generator()->MakeFrontendId( + Suggestion::BackendId(), Suggestion::BackendId(kTestGuid))); // Simulate user fixing the address. ChangeTextField(form_, form_.fields[1]); @@ -11405,8 +11410,8 @@ /*has_autofill_suggestions=*/true, form_, form_.fields[0]); autofill_manager().FillOrPreviewForm( mojom::RendererFormDataAction::kFill, 0, form_, form_.fields.front(), - autofill_manager().suggestion_generator()->MakeFrontendId(std::string(), - kTestGuid)); + autofill_manager().suggestion_generator()->MakeFrontendId( + Suggestion::BackendId(), Suggestion::BackendId(kTestGuid))); // Simulate user fixing the address. ChangeTextField(form_, form_.fields[1]); @@ -11602,8 +11607,8 @@ std::string guid(kTestGuid); autofill_manager().FillOrPreviewForm( mojom::RendererFormDataAction::kFill, 0, form, form.fields.front(), - autofill_manager().suggestion_generator()->MakeFrontendId(std::string(), - guid)); + autofill_manager().suggestion_generator()->MakeFrontendId( + Suggestion::BackendId(), Suggestion::BackendId(guid))); // Case #1: Change submitted value to expected autofilled value for the field. // The histogram should emit true for this. @@ -11649,8 +11654,8 @@ std::string guid(kTestGuid); autofill_manager().FillOrPreviewForm( mojom::RendererFormDataAction::kFill, 0, form, form.fields.front(), - autofill_manager().suggestion_generator()->MakeFrontendId(std::string(), - guid)); + autofill_manager().suggestion_generator()->MakeFrontendId( + Suggestion::BackendId(), Suggestion::BackendId(guid))); // Simulate form submission. SubmitForm(form);
diff --git a/components/autofill/core/browser/metrics/form_events/credit_card_form_event_logger.cc b/components/autofill/core/browser/metrics/form_events/credit_card_form_event_logger.cc index b1858523..f98bfff 100644 --- a/components/autofill/core/browser/metrics/form_events/credit_card_form_event_logger.cc +++ b/components/autofill/core/browser/metrics/form_events/credit_card_form_event_logger.cc
@@ -362,7 +362,8 @@ bool CreditCardFormEventLogger::DoesCardHaveOffer( const CreditCard& credit_card) { for (auto& suggestion : suggestions_) { - if (suggestion.GetPayload<std::string>() == credit_card.guid()) { + if (suggestion.GetPayload<Suggestion::BackendId>().value() == + credit_card.guid()) { return !suggestion.offer_label.empty(); } }
diff --git a/components/autofill/core/browser/payments/autofill_offer_manager.cc b/components/autofill/core/browser/payments/autofill_offer_manager.cc index c94e756..1201488 100644 --- a/components/autofill/core/browser/payments/autofill_offer_manager.cc +++ b/components/autofill/core/browser/payments/autofill_offer_manager.cc
@@ -53,8 +53,8 @@ // Update |offer_label| for each suggestion. for (auto& suggestion : suggestions) { - std::string id = suggestion.GetPayload<std::string>(); - if (eligible_offers_map.count(id)) { + if (eligible_offers_map.count( + suggestion.GetPayload<Suggestion::BackendId>().value())) { suggestion.offer_label = l10n_util::GetStringUTF16(IDS_AUTOFILL_OFFERS_CASHBACK); }
diff --git a/components/autofill/core/browser/payments/autofill_offer_manager_unittest.cc b/components/autofill/core/browser/payments/autofill_offer_manager_unittest.cc index 609a825..3e3adb1 100644 --- a/components/autofill/core/browser/payments/autofill_offer_manager_unittest.cc +++ b/components/autofill/core/browser/payments/autofill_offer_manager_unittest.cc
@@ -14,6 +14,7 @@ #include "components/autofill/core/browser/payments/autofill_offer_manager.h" #include "components/autofill/core/browser/test_autofill_client.h" #include "components/autofill/core/browser/test_personal_data_manager.h" +#include "components/autofill/core/browser/ui/suggestion.h" #include "components/autofill/core/browser/webdata/autofill_webdata_service.h" #include "components/autofill/core/common/autofill_clock.h" #include "components/autofill/core/common/autofill_payments_features.h" @@ -27,8 +28,10 @@ namespace autofill { namespace { -const char kTestGuid[] = "00000000-0000-0000-0000-000000000001"; -const char kTestGuid2[] = "00000000-0000-0000-0000-000000000002"; +const Suggestion::Suggestion::BackendId kTestGuid = + Suggestion::Suggestion::BackendId("00000000-0000-0000-0000-000000000001"); +const Suggestion::Suggestion::BackendId kTestGuid2 = + Suggestion::Suggestion::BackendId("00000000-0000-0000-0000-000000000002"); const char kTestNumber[] = "4234567890123456"; // Visa const char kTestUrl[] = "http://www.example.com/"; const char kTestUrlWithParam[] = @@ -133,7 +136,7 @@ }; TEST_F(AutofillOfferManagerTest, UpdateSuggestionsWithOffers_EligibleCashback) { - CreditCard card = CreateCreditCard(kTestGuid); + CreditCard card = CreateCreditCard(kTestGuid.value()); personal_data_manager_.AddAutofillOfferData( CreateCreditCardOfferForCard(card, "5%")); @@ -147,7 +150,7 @@ } TEST_F(AutofillOfferManagerTest, UpdateSuggestionsWithOffers_ExpiredOffer) { - CreditCard card = CreateCreditCard(kTestGuid); + CreditCard card = CreateCreditCard(kTestGuid.value()); personal_data_manager_.AddAutofillOfferData( CreateCreditCardOfferForCard(card, "5%", /*expired=*/true)); @@ -160,7 +163,7 @@ } TEST_F(AutofillOfferManagerTest, UpdateSuggestionsWithOffers_WrongUrl) { - CreditCard card = CreateCreditCard(kTestGuid); + CreditCard card = CreateCreditCard(kTestGuid.value()); personal_data_manager_.AddAutofillOfferData( CreateCreditCardOfferForCard(card, "5%")); @@ -174,9 +177,9 @@ TEST_F(AutofillOfferManagerTest, UpdateSuggestionsWithOffer_SuggestionsSortedByOfferPresence) { - CreditCard cardWithoutOffer = CreateCreditCard(kTestGuid); + CreditCard cardWithoutOffer = CreateCreditCard(kTestGuid.value()); CreditCard cardWithOffer = - CreateCreditCard(kTestGuid2, "4111111111111111", 100); + CreateCreditCard(kTestGuid2.value(), "4111111111111111", 100); personal_data_manager_.AddAutofillOfferData( CreateCreditCardOfferForCard(cardWithOffer, "5%")); @@ -190,14 +193,15 @@ // suggestion[0] EXPECT_TRUE(!suggestions[0].offer_label.empty()); EXPECT_TRUE(suggestions[1].offer_label.empty()); - EXPECT_EQ(absl::get<std::string>(suggestions[0].payload), kTestGuid2); - EXPECT_EQ(absl::get<std::string>(suggestions[1].payload), kTestGuid); + EXPECT_EQ(suggestions[0].GetPayload<Suggestion::BackendId>(), kTestGuid2); + EXPECT_EQ(suggestions[1].GetPayload<Suggestion::BackendId>(), kTestGuid); } TEST_F(AutofillOfferManagerTest, UpdateSuggestionsWithOffer_SuggestionsNotSortedIfAllCardsHaveOffers) { - CreditCard card1 = CreateCreditCard(kTestGuid, kTestNumber, 100); - CreditCard card2 = CreateCreditCard(kTestGuid2, "4111111111111111", 101); + CreditCard card1 = CreateCreditCard(kTestGuid.value(), kTestNumber, 100); + CreditCard card2 = + CreateCreditCard(kTestGuid2.value(), "4111111111111111", 101); personal_data_manager_.AddAutofillOfferData( CreateCreditCardOfferForCard(card1, "5%")); personal_data_manager_.AddAutofillOfferData( @@ -209,13 +213,14 @@ autofill_offer_manager_->UpdateSuggestionsWithOffers(GURL(kTestUrlWithParam), suggestions); - EXPECT_EQ(absl::get<std::string>(suggestions[0].payload), kTestGuid); - EXPECT_EQ(absl::get<std::string>(suggestions[1].payload), kTestGuid2); + EXPECT_EQ(suggestions[0].GetPayload<Suggestion::BackendId>(), kTestGuid); + EXPECT_EQ(suggestions[1].GetPayload<Suggestion::BackendId>(), kTestGuid2); } TEST_F(AutofillOfferManagerTest, IsUrlEligible) { - CreditCard card1 = CreateCreditCard(kTestGuid, kTestNumber, 100); - CreditCard card2 = CreateCreditCard(kTestGuid2, "4111111111111111", 101); + CreditCard card1 = CreateCreditCard(kTestGuid.value(), kTestNumber, 100); + CreditCard card2 = + CreateCreditCard(kTestGuid2.value(), "4111111111111111", 101); personal_data_manager_.AddAutofillOfferData(CreateCreditCardOfferForCard( card1, "5%", /*expired=*/false, {GURL("http://www.google.com"), GURL("http://www.youtube.com")})); @@ -232,7 +237,7 @@ } TEST_F(AutofillOfferManagerTest, GetOfferForUrl_ReturnNothingWhenFindNoMatch) { - CreditCard card1 = CreateCreditCard(kTestGuid, kTestNumber, 100); + CreditCard card1 = CreateCreditCard(kTestGuid.value(), kTestNumber, 100); personal_data_manager_.AddAutofillOfferData(CreateCreditCardOfferForCard( card1, "5%", /*expired=*/false, {GURL("http://www.google.com"), GURL("http://www.youtube.com")})); @@ -244,8 +249,9 @@ TEST_F(AutofillOfferManagerTest, GetOfferForUrl_ReturnCorrectOfferWhenFindMatch) { - CreditCard card1 = CreateCreditCard(kTestGuid, kTestNumber, 100); - CreditCard card2 = CreateCreditCard(kTestGuid2, "4111111111111111", 101); + CreditCard card1 = CreateCreditCard(kTestGuid.value(), kTestNumber, 100); + CreditCard card2 = + CreateCreditCard(kTestGuid2.value(), "4111111111111111", 101); AutofillOfferData offer1 = CreateCreditCardOfferForCard( card1, "5%", /*expired=*/false, @@ -266,7 +272,7 @@ TEST_F(AutofillOfferManagerTest, GetOfferForUrl_ReturnOfferFromCouponDelegate) { const GURL example_url("http://www.example.com"); // Add card-linked offer to PersonalDataManager. - CreditCard card = CreateCreditCard(kTestGuid, kTestNumber, 100); + CreditCard card = CreateCreditCard(kTestGuid.value(), kTestNumber, 100); AutofillOfferData offer1 = CreateCreditCardOfferForCard( card, "5%", /*expired=*/false, /*merchant_origins=*/ @@ -303,8 +309,9 @@ TEST_F(AutofillOfferManagerTest, CreateCardLinkedOffersMap_ReturnsOnlyCardLinkedOffers) { - CreditCard card1 = CreateCreditCard(kTestGuid, kTestNumber, 100); - CreditCard card2 = CreateCreditCard(kTestGuid2, "4111111111111111", 101); + CreditCard card1 = CreateCreditCard(kTestGuid.value(), kTestNumber, 100); + CreditCard card2 = + CreateCreditCard(kTestGuid2.value(), "4111111111111111", 101); AutofillOfferData offer1 = CreateCreditCardOfferForCard( card1, "5%", /*expired=*/false,
diff --git a/components/autofill/core/browser/test_browser_autofill_manager.cc b/components/autofill/core/browser/test_browser_autofill_manager.cc index 414bbcca..3517633 100644 --- a/components/autofill/core/browser/test_browser_autofill_manager.cc +++ b/components/autofill/core/browser/test_browser_autofill_manager.cc
@@ -15,6 +15,7 @@ #include "components/autofill/core/browser/test_autofill_driver.h" #include "components/autofill/core/browser/test_autofill_manager_waiter.h" #include "components/autofill/core/browser/test_personal_data_manager.h" +#include "components/autofill/core/browser/ui/suggestion.h" #include "form_structure_test_api.h" #include "services/network/public/cpp/shared_url_loader_factory.h" #include "testing/gtest/include/gtest/gtest.h" @@ -173,8 +174,8 @@ std::string credit_card_guid = base::StringPrintf("00000000-0000-0000-0000-%012d", credit_card_id); - return suggestion_generator()->MakeFrontendId(credit_card_guid, - std::string()); + return suggestion_generator()->MakeFrontendId( + Suggestion::BackendId(credit_card_guid), Suggestion::BackendId()); } void TestBrowserAutofillManager::AddSeenForm(
diff --git a/components/autofill/core/browser/ui/autofill_popup_delegate.h b/components/autofill/core/browser/ui/autofill_popup_delegate.h index d884117..409d19df 100644 --- a/components/autofill/core/browser/ui/autofill_popup_delegate.h +++ b/components/autofill/core/browser/ui/autofill_popup_delegate.h
@@ -39,7 +39,7 @@ // the guid of the backend data model. virtual void DidSelectSuggestion(const std::u16string& value, int frontend_id, - const std::string& backend_id) = 0; + const Suggestion::BackendId& backend_id) = 0; // Inform the delegate that a row in the popup has been chosen. |value| is the // suggestion's value, and is usually the main text to be shown. |frontend_id|
diff --git a/components/autofill/core/browser/ui/suggestion.h b/components/autofill/core/browser/ui/suggestion.h index 1368f10a..a220a027 100644 --- a/components/autofill/core/browser/ui/suggestion.h +++ b/components/autofill/core/browser/ui/suggestion.h
@@ -20,7 +20,8 @@ struct Suggestion { using IsLoading = base::StrongAlias<class IsLoadingTag, bool>; - using Payload = absl::variant<std::string, GURL>; + using BackendId = base::StrongAlias<struct BackendIdTag, std::string>; + using Payload = absl::variant<BackendId, GURL>; enum MatchMode { PREFIX_MATCH, // for prefix matched suggestions; @@ -87,7 +88,7 @@ case PopupItemId::POPUP_ITEM_ID_SEE_PROMO_CODE_DETAILS: return absl::holds_alternative<GURL>(payload); default: - return absl::holds_alternative<std::string>(payload); + return absl::holds_alternative<BackendId>(payload); } } #endif
diff --git a/components/autofill/core/browser/ui/suggestion_selection.cc b/components/autofill/core/browser/ui/suggestion_selection.cc index 64a56eb..755e5510 100644 --- a/components/autofill/core/browser/ui/suggestion_selection.cc +++ b/components/autofill/core/browser/ui/suggestion_selection.cc
@@ -126,7 +126,7 @@ } suggestions.emplace_back(value); - suggestions.back().payload = profile->guid(); + suggestions.back().payload = Suggestion::BackendId(profile->guid()); suggestions.back().match = prefix_matched_suggestion ? Suggestion::PREFIX_MATCH : Suggestion::SUBSTRING_MATCH;
diff --git a/components/autofill/ios/browser/autofill_agent.mm b/components/autofill/ios/browser/autofill_agent.mm index aeb0f6c..a90b5bf 100644 --- a/components/autofill/ios/browser/autofill_agent.mm +++ b/components/autofill/ios/browser/autofill_agent.mm
@@ -29,6 +29,7 @@ #include "components/autofill/core/browser/keyboard_accessory_metrics_logger.h" #include "components/autofill/core/browser/metrics/autofill_metrics.h" #include "components/autofill/core/browser/ui/popup_item_ids.h" +#include "components/autofill/core/browser/ui/suggestion.h" #include "components/autofill/core/common/autofill_constants.h" #include "components/autofill/core/common/autofill_features.h" #include "components/autofill/core/common/autofill_prefs.h" @@ -424,8 +425,8 @@ if (_popupDelegate) { // TODO(966411): Replace 0 with the index of the selected suggestion. _popupDelegate->DidAcceptSuggestion(SysNSStringToUTF16(suggestion.value), - suggestion.identifier, std::string(), - 0); + suggestion.identifier, + autofill::Suggestion::BackendId(), 0); } return; }
diff --git a/components/bookmarks/browser/base_bookmark_model_observer.cc b/components/bookmarks/browser/base_bookmark_model_observer.cc index 657a3c9..f7bd690 100644 --- a/components/bookmarks/browser/base_bookmark_model_observer.cc +++ b/components/bookmarks/browser/base_bookmark_model_observer.cc
@@ -25,7 +25,8 @@ void BaseBookmarkModelObserver::BookmarkNodeAdded(BookmarkModel* model, const BookmarkNode* parent, - size_t index) { + size_t index, + bool added_by_user) { BookmarkModelChanged(); }
diff --git a/components/bookmarks/browser/base_bookmark_model_observer.h b/components/bookmarks/browser/base_bookmark_model_observer.h index abe84cf6..7ac72712 100644 --- a/components/bookmarks/browser/base_bookmark_model_observer.h +++ b/components/bookmarks/browser/base_bookmark_model_observer.h
@@ -31,7 +31,8 @@ size_t new_index) override; void BookmarkNodeAdded(BookmarkModel* model, const BookmarkNode* parent, - size_t index) override; + size_t index, + bool added_by_user) override; void BookmarkNodeRemoved(BookmarkModel* model, const BookmarkNode* parent, size_t old_index,
diff --git a/components/bookmarks/browser/bookmark_model.cc b/components/bookmarks/browser/bookmark_model.cc index dd662f64..2d91c6d 100644 --- a/components/bookmarks/browser/bookmark_model.cc +++ b/components/bookmarks/browser/bookmark_model.cc
@@ -671,7 +671,7 @@ const BookmarkNode::MetaInfoMap* meta_info) { metrics::RecordBookmarkAdded(); return AddURL(parent, index, title, url, meta_info, absl::nullopt, - absl::nullopt); + absl::nullopt, true); } const BookmarkNode* BookmarkModel::AddURL( @@ -681,7 +681,8 @@ const GURL& url, const BookmarkNode::MetaInfoMap* meta_info, absl::optional<base::Time> creation_time, - absl::optional<base::GUID> guid) { + absl::optional<base::GUID> guid, + bool added_by_user) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(loaded_); DCHECK(url.is_valid()); @@ -706,7 +707,7 @@ if (meta_info) new_node->SetMetaInfoMap(*meta_info); - return AddNode(AsMutable(parent), index, std::move(new_node)); + return AddNode(AsMutable(parent), index, std::move(new_node), added_by_user); } void BookmarkModel::SortChildren(const BookmarkNode* parent) { @@ -824,7 +825,7 @@ for (size_t i = 0; i < node->children().size(); ++i) { for (BookmarkModelObserver& observer : observers_) - observer.BookmarkNodeAdded(this, node, i); + observer.BookmarkNodeAdded(this, node, i, false); NotifyNodeAddedForAllDescendants(node->children()[i].get()); } } @@ -898,7 +899,8 @@ BookmarkNode* BookmarkModel::AddNode(BookmarkNode* parent, size_t index, - std::unique_ptr<BookmarkNode> node) { + std::unique_ptr<BookmarkNode> node, + bool added_by_user) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); BookmarkNode* node_ptr = node.get(); @@ -910,7 +912,7 @@ AddNodeToIndexRecursive(node_ptr); for (BookmarkModelObserver& observer : observers_) - observer.BookmarkNodeAdded(this, parent, index); + observer.BookmarkNodeAdded(this, parent, index, added_by_user); return node_ptr; }
diff --git a/components/bookmarks/browser/bookmark_model.h b/components/bookmarks/browser/bookmark_model.h index 6347e4e..c74d4ee 100644 --- a/components/bookmarks/browser/bookmark_model.h +++ b/components/bookmarks/browser/bookmark_model.h
@@ -235,7 +235,8 @@ // (i.e. nullopt), then a random one will be generated. If a GUID is // provided, it must be valid. Used for bookmarks not being added from // direct user actions (e.g. created via sync, locally modified bookmark - // or pre-existing bookmark). + // or pre-existing bookmark). `added_by_user` is true when a new bookmark was + // added by the user and false when a node is added by sync or duplicated. const BookmarkNode* AddURL( const BookmarkNode* parent, size_t index, @@ -243,7 +244,8 @@ const GURL& url, const BookmarkNode::MetaInfoMap* meta_info = nullptr, absl::optional<base::Time> creation_time = absl::nullopt, - absl::optional<base::GUID> guid = absl::nullopt); + absl::optional<base::GUID> guid = absl::nullopt, + bool added_by_user = false); // Sorts the children of |parent|, notifying observers by way of the // BookmarkNodeChildrenReordered method. @@ -356,11 +358,13 @@ // Called when done loading. Updates internal state and notifies observers. void DoneLoading(std::unique_ptr<BookmarkLoadDetails> details); - // Adds the |node| at |parent| in the specified |index| and notifies its - // observers. + // Adds the `node` at `parent` in the specified `index` and notifies its + // observers. `added_by_user` is true when a new bookmark was added by the + // user and false when a node is added by sync or duplicated. BookmarkNode* AddNode(BookmarkNode* parent, size_t index, - std::unique_ptr<BookmarkNode> node); + std::unique_ptr<BookmarkNode> node, + bool added_by_user = false); // Adds |node| to |index_| and recursively invokes this for all children. void AddNodeToIndexRecursive(const BookmarkNode* node);
diff --git a/components/bookmarks/browser/bookmark_model_observer.h b/components/bookmarks/browser/bookmark_model_observer.h index 0e5eb96..42cd99a 100644 --- a/components/bookmarks/browser/bookmark_model_observer.h +++ b/components/bookmarks/browser/bookmark_model_observer.h
@@ -37,10 +37,13 @@ const BookmarkNode* new_parent, size_t new_index) = 0; - // Invoked when a node has been added. + // Invoked when a node has been added. `added_by_user` is true when a new + // bookmark was added by the user and false when a node is added by sync + // or duplicated. virtual void BookmarkNodeAdded(BookmarkModel* model, const BookmarkNode* parent, - size_t index) = 0; + size_t index, + bool added_by_user) = 0; // Invoked prior to removing a node from the model. When a node is removed // it's descendants are implicitly removed from the model as
diff --git a/components/bookmarks/browser/bookmark_model_unittest.cc b/components/bookmarks/browser/bookmark_model_unittest.cc index ef3d30e..83a491a 100644 --- a/components/bookmarks/browser/bookmark_model_unittest.cc +++ b/components/bookmarks/browser/bookmark_model_unittest.cc
@@ -268,27 +268,32 @@ public: struct ObserverDetails { ObserverDetails() { - Set(nullptr, nullptr, static_cast<size_t>(-1), static_cast<size_t>(-1)); + Set(nullptr, nullptr, static_cast<size_t>(-1), static_cast<size_t>(-1), + false); } void Set(const BookmarkNode* node1, const BookmarkNode* node2, size_t index1, - size_t index2) { + size_t index2, + bool added_by_user) { node1_ = node1; node2_ = node2; index1_ = index1; index2_ = index2; + added_by_user_ = added_by_user; } void ExpectEquals(const BookmarkNode* node1, const BookmarkNode* node2, size_t index1, - size_t index2) { + size_t index2, + bool added_by_user) { EXPECT_EQ(node1_, node1); EXPECT_EQ(node2_, node2); EXPECT_EQ(index1_, index1); EXPECT_EQ(index2_, index2); + EXPECT_EQ(added_by_user_, added_by_user); } private: @@ -296,6 +301,7 @@ raw_ptr<const BookmarkNode> node2_; size_t index1_; size_t index2_; + bool added_by_user_; }; struct NodeRemovalDetail { @@ -334,14 +340,16 @@ const BookmarkNode* new_parent, size_t new_index) override { ++moved_count_; - observer_details_.Set(old_parent, new_parent, old_index, new_index); + observer_details_.Set(old_parent, new_parent, old_index, new_index, false); } void BookmarkNodeAdded(BookmarkModel* model, const BookmarkNode* parent, - size_t index) override { + size_t index, + bool added_by_user) override { ++added_count_; - observer_details_.Set(parent, nullptr, index, static_cast<size_t>(-1)); + observer_details_.Set(parent, nullptr, index, static_cast<size_t>(-1), + added_by_user); } void OnWillRemoveBookmarks(BookmarkModel* model, @@ -359,14 +367,15 @@ const BookmarkNode* node, const std::set<GURL>& removed_urls) override { ++removed_count_; - observer_details_.Set(parent, nullptr, old_index, static_cast<size_t>(-1)); + observer_details_.Set(parent, nullptr, old_index, static_cast<size_t>(-1), + false); } void BookmarkNodeChanged(BookmarkModel* model, const BookmarkNode* node) override { ++changed_count_; observer_details_.Set(node, nullptr, static_cast<size_t>(-1), - static_cast<size_t>(-1)); + static_cast<size_t>(-1), false); } void OnWillChangeBookmarkNode(BookmarkModel* model, @@ -537,7 +546,30 @@ const BookmarkNode* new_node = model_->AddURL(root, 0, title, url); AssertObserverCount(1, 0, 0, 0, 0, 0, 0, 0, 0); - observer_details_.ExpectEquals(root, nullptr, 0, static_cast<size_t>(-1)); + observer_details_.ExpectEquals(root, nullptr, 0, static_cast<size_t>(-1), + false); + + ASSERT_EQ(1u, root->children().size()); + ASSERT_EQ(title, new_node->GetTitle()); + ASSERT_TRUE(url == new_node->url()); + ASSERT_TRUE(new_node->guid().is_valid()); + ASSERT_EQ(BookmarkNode::URL, new_node->type()); + ASSERT_EQ(new_node, model_->GetMostRecentlyAddedUserNodeForURL(url)); + + EXPECT_TRUE(new_node->id() != root->id() && + new_node->id() != model_->other_node()->id() && + new_node->id() != model_->mobile_node()->id()); +} + +TEST_F(BookmarkModelTest, AddNewURL) { + const BookmarkNode* root = model_->bookmark_bar_node(); + const std::u16string title(u"foo"); + const GURL url("http://foo.com"); + + const BookmarkNode* new_node = model_->AddNewURL(root, 0, title, url); + AssertObserverCount(1, 0, 0, 0, 0, 0, 0, 0, 0); + observer_details_.ExpectEquals(root, nullptr, 0, static_cast<size_t>(-1), + true); ASSERT_EQ(1u, root->children().size()); ASSERT_EQ(title, new_node->GetTitle()); @@ -559,7 +591,8 @@ const BookmarkNode* new_node = model_->AddURL(root, 0, title, url); AssertObserverCount(1, 0, 0, 0, 0, 0, 0, 0, 0); - observer_details_.ExpectEquals(root, nullptr, 0, static_cast<size_t>(-1)); + observer_details_.ExpectEquals(root, nullptr, 0, static_cast<size_t>(-1), + false); ASSERT_EQ(1u, root->children().size()); ASSERT_EQ(title, new_node->GetTitle()); @@ -599,7 +632,8 @@ const BookmarkNode* new_node = model_->AddURL(root, 0, title, url, &meta_info, time); AssertObserverCount(1, 0, 0, 0, 0, 0, 0, 0, 0); - observer_details_.ExpectEquals(root, nullptr, 0, static_cast<size_t>(-1)); + observer_details_.ExpectEquals(root, nullptr, 0, static_cast<size_t>(-1), + false); ASSERT_EQ(1u, root->children().size()); ASSERT_EQ(title, new_node->GetTitle()); @@ -637,7 +671,8 @@ const BookmarkNode* new_node = model_->AddURL(root, 0, title, url); AssertObserverCount(1, 0, 0, 0, 0, 0, 0, 0, 0); - observer_details_.ExpectEquals(root, nullptr, 0, static_cast<size_t>(-1)); + observer_details_.ExpectEquals(root, nullptr, 0, static_cast<size_t>(-1), + false); ASSERT_EQ(1u, root->children().size()); ASSERT_EQ(title, new_node->GetTitle()); @@ -656,7 +691,8 @@ const BookmarkNode* new_node = model_->AddFolder(root, 0, title); AssertObserverCount(1, 0, 0, 0, 0, 0, 0, 0, 0); - observer_details_.ExpectEquals(root, nullptr, 0, static_cast<size_t>(-1)); + observer_details_.ExpectEquals(root, nullptr, 0, static_cast<size_t>(-1), + false); ASSERT_EQ(1u, root->children().size()); ASSERT_EQ(title, new_node->GetTitle()); @@ -671,7 +707,8 @@ ClearCounts(); model_->AddFolder(root, 0, title); AssertObserverCount(1, 0, 0, 0, 0, 0, 0, 0, 0); - observer_details_.ExpectEquals(root, nullptr, 0, static_cast<size_t>(-1)); + observer_details_.ExpectEquals(root, nullptr, 0, static_cast<size_t>(-1), + false); } TEST_F(BookmarkModelTest, AddFolderWithCreationTime) { @@ -724,7 +761,8 @@ model_->Remove(root->children().front().get()); ASSERT_EQ(0u, root->children().size()); AssertObserverCount(0, 0, 1, 0, 0, 1, 0, 0, 0); - observer_details_.ExpectEquals(root, nullptr, 0, static_cast<size_t>(-1)); + observer_details_.ExpectEquals(root, nullptr, 0, static_cast<size_t>(-1), + false); // Make sure there is no mapping for the URL. ASSERT_TRUE(model_->GetMostRecentlyAddedUserNodeForURL(url) == nullptr); @@ -747,7 +785,8 @@ model_->Remove(root->children().front().get()); ASSERT_EQ(0u, root->children().size()); AssertObserverCount(0, 0, 1, 0, 0, 1, 0, 0, 0); - observer_details_.ExpectEquals(root, nullptr, 0, static_cast<size_t>(-1)); + observer_details_.ExpectEquals(root, nullptr, 0, static_cast<size_t>(-1), + false); // Make sure there is no mapping for the URL. ASSERT_TRUE(model_->GetMostRecentlyAddedUserNodeForURL(url) == nullptr); @@ -861,7 +900,7 @@ model_->SetTitle(node, title); AssertObserverCount(0, 0, 0, 1, 0, 0, 1, 0, 0); observer_details_.ExpectEquals(node, nullptr, static_cast<size_t>(-1), - static_cast<size_t>(-1)); + static_cast<size_t>(-1), false); EXPECT_EQ(title, node->GetTitle()); // Should update the index. @@ -930,7 +969,7 @@ model_->SetURL(node, url); AssertObserverCount(0, 0, 0, 1, 0, 0, 1, 0, 0); observer_details_.ExpectEquals(node, nullptr, static_cast<size_t>(-1), - static_cast<size_t>(-1)); + static_cast<size_t>(-1), false); EXPECT_EQ(url, node->url()); } @@ -960,7 +999,7 @@ model_->Move(node, folder1, 0); AssertObserverCount(0, 1, 0, 0, 0, 0, 0, 0, 0); - observer_details_.ExpectEquals(root, folder1, 1, 0); + observer_details_.ExpectEquals(root, folder1, 1, 0, false); EXPECT_TRUE(folder1 == node->parent()); EXPECT_EQ(1u, root->children().size()); EXPECT_EQ(folder1, root->children().front().get()); @@ -976,7 +1015,8 @@ ClearCounts(); model_->Remove(root->children().front().get()); AssertObserverCount(0, 0, 1, 0, 0, 1, 0, 0, 0); - observer_details_.ExpectEquals(root, nullptr, 0, static_cast<size_t>(-1)); + observer_details_.ExpectEquals(root, nullptr, 0, static_cast<size_t>(-1), + false); EXPECT_TRUE(model_->GetMostRecentlyAddedUserNodeForURL(url) == nullptr); EXPECT_EQ(0u, root->children().size()); @@ -1014,7 +1054,7 @@ // Should update the hierarchy. AssertObserverCount(0, 1, 0, 0, 0, 0, 0, 0, 0); - observer_details_.ExpectEquals(folder1, folder2, 0, 0); + observer_details_.ExpectEquals(folder1, folder2, 0, 0, false); EXPECT_EQ(root->children().size(), 2u); EXPECT_EQ(folder1->children().size(), 0u); EXPECT_EQ(folder2->children().size(), 1u); @@ -1036,7 +1076,7 @@ // Should update the hierarchy. AssertObserverCount(0, 1, 0, 0, 0, 0, 0, 0, 0); - observer_details_.ExpectEquals(folder2, folder1, 0, 0); + observer_details_.ExpectEquals(folder2, folder1, 0, 0, false); EXPECT_EQ(root->children().size(), 2u); EXPECT_EQ(folder1->children().size(), 1u); EXPECT_EQ(folder2->children().size(), 0u); @@ -1067,7 +1107,7 @@ // Should update the hierarchy. AssertObserverCount(0, 1, 0, 0, 0, 0, 0, 0, 0); - observer_details_.ExpectEquals(folder1, folder2, 0, 0); + observer_details_.ExpectEquals(folder1, folder2, 0, 0, false); EXPECT_EQ(root->children().size(), 2u); EXPECT_EQ(root->children()[0].get(), folder1); EXPECT_EQ(root->children()[1].get(), folder2); @@ -1734,7 +1774,8 @@ void BookmarkNodeAdded(BookmarkModel* model, const BookmarkNode* parent, - size_t index) override {} + size_t index, + bool added_by_user) override {} void BookmarkNodeRemoved(BookmarkModel* model, const BookmarkNode* parent,
diff --git a/components/bookmarks/managed/managed_bookmarks_tracker_unittest.cc b/components/bookmarks/managed/managed_bookmarks_tracker_unittest.cc index 8f4d50a..444f1c9 100644 --- a/components/bookmarks/managed/managed_bookmarks_tracker_unittest.cc +++ b/components/bookmarks/managed/managed_bookmarks_tracker_unittest.cc
@@ -251,7 +251,7 @@ base::Value::List updated; updated.Append(CreateFolder("Container", CreateTestTree())); - EXPECT_CALL(observer_, BookmarkNodeAdded(model_.get(), _, _)).Times(5); + EXPECT_CALL(observer_, BookmarkNodeAdded(model_.get(), _, _, _)).Times(5); // The remaining nodes have been pushed to positions 1 and 2; they'll both be // removed when at position 1. const BookmarkNode* parent = managed_node(); @@ -308,10 +308,10 @@ CreateModel(); EXPECT_EQ(2u, managed_node()->children().size()); - EXPECT_CALL(observer_, - BookmarkNodeAdded(model_.get(), model_->bookmark_bar_node(), 0)); - EXPECT_CALL(observer_, - BookmarkNodeAdded(model_.get(), model_->bookmark_bar_node(), 1)); + EXPECT_CALL(observer_, BookmarkNodeAdded(model_.get(), + model_->bookmark_bar_node(), 0, _)); + EXPECT_CALL(observer_, BookmarkNodeAdded(model_.get(), + model_->bookmark_bar_node(), 1, _)); model_->AddURL(model_->bookmark_bar_node(), 0, u"Test", GURL("http://google.com/")); model_->AddFolder(model_->bookmark_bar_node(), 1, u"Test Folder");
diff --git a/components/bookmarks/test/mock_bookmark_model_observer.h b/components/bookmarks/test/mock_bookmark_model_observer.h index 7391c92..8d835848 100644 --- a/components/bookmarks/test/mock_bookmark_model_observer.h +++ b/components/bookmarks/test/mock_bookmark_model_observer.h
@@ -25,8 +25,8 @@ const BookmarkNode*, size_t)); - MOCK_METHOD3(BookmarkNodeAdded, - void(BookmarkModel*, const BookmarkNode*, size_t)); + MOCK_METHOD4(BookmarkNodeAdded, + void(BookmarkModel*, const BookmarkNode*, size_t, bool)); MOCK_METHOD5(BookmarkNodeRemoved, void(BookmarkModel*,
diff --git a/components/browser_ui/bottomsheet/android/internal/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheet.java b/components/browser_ui/bottomsheet/android/internal/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheet.java index 8b99f79b..640dfb93 100644 --- a/components/browser_ui/bottomsheet/android/internal/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheet.java +++ b/components/browser_ui/bottomsheet/android/internal/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheet.java
@@ -1097,7 +1097,7 @@ // Resizing is necessary if we have non-zero translation on Window Y, which can change // throughout the lifecycle. Ensure sheet content's bottom is aligned with the base layout. - if (mWindow.getAttributes().y != 0 + if (mBaseHeightProvider != null && mWindow.getAttributes().y != 0 && (mCurrentState == SheetState.PEEK || mCurrentState == SheetState.HALF || mCurrentState == SheetState.FULL)) { BottomSheetContent content = mSheetContent;
diff --git a/components/desks_storage/core/desk_model.h b/components/desks_storage/core/desk_model.h index e911ee7..c60257a 100644 --- a/components/desks_storage/core/desk_model.h +++ b/components/desks_storage/core/desk_model.h
@@ -135,7 +135,7 @@ base::OnceCallback<void(DeleteEntryStatus status)>; // Remove entry with `uuid` from entries. If the entry with `uuid` does not // exist, then the deletion is considered a success. - virtual void DeleteEntry(const std::string& uuid, + virtual void DeleteEntry(const base::GUID& uuid, DeleteEntryCallback callback) = 0; // Delete all entries.
diff --git a/components/desks_storage/core/desk_model_wrapper.cc b/components/desks_storage/core/desk_model_wrapper.cc index aa826d86..5c633674 100644 --- a/components/desks_storage/core/desk_model_wrapper.cc +++ b/components/desks_storage/core/desk_model_wrapper.cc
@@ -81,13 +81,13 @@ } } -void DeskModelWrapper::DeleteEntry(const std::string& uuid_str, +void DeskModelWrapper::DeleteEntry(const base::GUID& uuid, DeskModel::DeleteEntryCallback callback) { auto status = std::make_unique<DeskModel::DeleteEntryStatus>(); - if (GetDeskTemplateModel()->HasUuid(uuid_str)) { - GetDeskTemplateModel()->DeleteEntry(uuid_str, std::move(callback)); + if (GetDeskTemplateModel()->HasUuid(uuid.AsLowercaseString())) { + GetDeskTemplateModel()->DeleteEntry(uuid, std::move(callback)); } else { - save_and_recall_desks_model_->DeleteEntry(uuid_str, std::move(callback)); + save_and_recall_desks_model_->DeleteEntry(uuid, std::move(callback)); } }
diff --git a/components/desks_storage/core/desk_model_wrapper.h b/components/desks_storage/core/desk_model_wrapper.h index 0c969f5..ed7cd1a 100644 --- a/components/desks_storage/core/desk_model_wrapper.h +++ b/components/desks_storage/core/desk_model_wrapper.h
@@ -39,7 +39,7 @@ GetEntryByUuidCallback callback) override; void AddOrUpdateEntry(std::unique_ptr<ash::DeskTemplate> new_entry, AddOrUpdateEntryCallback callback) override; - void DeleteEntry(const std::string& uuid, + void DeleteEntry(const base::GUID& uuid, DeleteEntryCallback callback) override; void DeleteAllEntries(DeleteEntryCallback callback) override; std::size_t GetEntryCount() const override;
diff --git a/components/desks_storage/core/desk_model_wrapper_unittests.cc b/components/desks_storage/core/desk_model_wrapper_unittests.cc index ca86bb0aa..e1fa2498 100644 --- a/components/desks_storage/core/desk_model_wrapper_unittests.cc +++ b/components/desks_storage/core/desk_model_wrapper_unittests.cc
@@ -622,7 +622,7 @@ base::BindOnce(&VerifyEntryAddedCorrectly)); model_wrapper_->DeleteEntry( - kTestUuid1, + base::GUID::ParseCaseInsensitive(kTestUuid1), base::BindLambdaForTesting([&](DeskModel::DeleteEntryStatus status) { EXPECT_EQ(status, DeskModel::DeleteEntryStatus::kOk); })); @@ -637,7 +637,7 @@ base::BindOnce(&VerifyEntryAddedCorrectly)); model_wrapper_->DeleteEntry( - kTestUuid3, + base::GUID::ParseCaseInsensitive(kTestUuid3), base::BindLambdaForTesting([&](DeskModel::DeleteEntryStatus status) { EXPECT_EQ(status, DeskModel::DeleteEntryStatus::kOk); }));
diff --git a/components/desks_storage/core/desk_sync_bridge.cc b/components/desks_storage/core/desk_sync_bridge.cc index f282150..9d4334c74 100644 --- a/components/desks_storage/core/desk_sync_bridge.cc +++ b/components/desks_storage/core/desk_sync_bridge.cc
@@ -1155,7 +1155,7 @@ std::move(callback).Run(AddOrUpdateEntryStatus::kOk); } -void DeskSyncBridge::DeleteEntry(const std::string& uuid_str, +void DeskSyncBridge::DeleteEntry(const base::GUID& uuid, DeleteEntryCallback callback) { if (!IsReady()) { // This sync bridge has not finished initializing. @@ -1164,8 +1164,6 @@ return; } - const base::GUID uuid = base::GUID::ParseCaseInsensitive(uuid_str); - if (GetUserEntryByUUID(uuid) == nullptr) { // Consider the deletion successful if the entry does not exist. std::move(callback).Run(DeleteEntryStatus::kOk);
diff --git a/components/desks_storage/core/desk_sync_bridge.h b/components/desks_storage/core/desk_sync_bridge.h index 7efcbdd..88c838a 100644 --- a/components/desks_storage/core/desk_sync_bridge.h +++ b/components/desks_storage/core/desk_sync_bridge.h
@@ -69,7 +69,7 @@ GetEntryByUuidCallback callback) override; void AddOrUpdateEntry(std::unique_ptr<ash::DeskTemplate> new_entry, AddOrUpdateEntryCallback callback) override; - void DeleteEntry(const std::string& uuid, + void DeleteEntry(const base::GUID& uuid, DeleteEntryCallback callback) override; void DeleteAllEntries(DeleteEntryCallback callback) override; std::size_t GetEntryCount() const override;
diff --git a/components/desks_storage/core/desk_sync_bridge_unittest.cc b/components/desks_storage/core/desk_sync_bridge_unittest.cc index 055ae44f..b2c31ac9 100644 --- a/components/desks_storage/core/desk_sync_bridge_unittest.cc +++ b/components/desks_storage/core/desk_sync_bridge_unittest.cc
@@ -1456,7 +1456,7 @@ // Delete template 1. base::RunLoop loop; bridge()->DeleteEntry( - kTestUuid1.AsLowercaseString(), + kTestUuid1, base::BindLambdaForTesting([&](DeskModel::DeleteEntryStatus status) { EXPECT_EQ(status, DeskModel::DeleteEntryStatus::kOk); loop.Quit();
diff --git a/components/desks_storage/core/local_desk_data_manager.cc b/components/desks_storage/core/local_desk_data_manager.cc index fe45d60f..687c45f 100644 --- a/components/desks_storage/core/local_desk_data_manager.cc +++ b/components/desks_storage/core/local_desk_data_manager.cc
@@ -122,8 +122,8 @@ // file given the `file_path` to the desk template or save and recall desk // directory and the entry's `uuid`. base::FilePath GetFullyQualifiedPath(base::FilePath file_path, - const std::string& uuid) { - std::string filename(uuid); + const base::GUID& uuid) { + std::string filename = uuid.AsLowercaseString(); filename.append(kFileExtension); return base::FilePath(file_path.Append(base::FilePath(filename))); @@ -287,7 +287,7 @@ } void LocalDeskDataManager::DeleteEntry( - const std::string& uuid_str, + const base::GUID& uuid, DeskModel::DeleteEntryCallback callback) { auto status = std::make_unique<DeskModel::DeleteEntryStatus>(); if (cache_status_ != CacheStatus::kOk) { @@ -296,7 +296,6 @@ return; } - const base::GUID uuid = base::GUID::ParseCaseInsensitive(uuid_str); if (!uuid.is_valid()) { // There does not exist an entry with invalid UUID. // Therefore the deletion request is vicariously successful. @@ -314,7 +313,7 @@ task_runner_->PostTaskAndReply( FROM_HERE, base::BindOnce(&LocalDeskDataManager::DeleteEntryTask, - base::Unretained(this), uuid_str, status.get()), + base::Unretained(this), uuid, status.get()), base::BindOnce(&LocalDeskDataManager::OnDeleteEntry, weak_ptr_factory_.GetWeakPtr(), std::move(status), std::move(entry), std::move(callback))); @@ -509,7 +508,7 @@ DeskModel::AddOrUpdateEntryStatus* out_status_ptr, base::Value entry_base_value) { const base::FilePath fully_qualified_path = - GetFullyQualifiedPath(local_saved_desk_path_, uuid.AsLowercaseString()); + GetFullyQualifiedPath(local_saved_desk_path_, uuid); if (WriteTemplateFile(fully_qualified_path, std::move(entry_base_value))) { *out_status_ptr = DeskModel::AddOrUpdateEntryStatus::kOk; } else { @@ -536,10 +535,10 @@ } void LocalDeskDataManager::DeleteEntryTask( - const std::string& uuid_str, + const base::GUID& uuid, DeskModel::DeleteEntryStatus* out_status_ptr) { const base::FilePath fully_qualified_path = - GetFullyQualifiedPath(local_saved_desk_path_, uuid_str); + GetFullyQualifiedPath(local_saved_desk_path_, uuid); base::ScopedBlockingCall scoped_blocking_call(FROM_HERE, base::BlockingType::MAY_BLOCK); if (base::DeleteFile(fully_qualified_path)) {
diff --git a/components/desks_storage/core/local_desk_data_manager.h b/components/desks_storage/core/local_desk_data_manager.h index 9230aeb..686ed0c9 100644 --- a/components/desks_storage/core/local_desk_data_manager.h +++ b/components/desks_storage/core/local_desk_data_manager.h
@@ -60,7 +60,7 @@ GetEntryByUuidCallback callback) override; void AddOrUpdateEntry(std::unique_ptr<ash::DeskTemplate> new_entry, AddOrUpdateEntryCallback callback) override; - void DeleteEntry(const std::string& uuid, + void DeleteEntry(const base::GUID& uuid, DeleteEntryCallback callback) override; void DeleteAllEntries(DeleteEntryCallback callback) override; std::size_t GetEntryCount() const override; @@ -117,9 +117,9 @@ const base::GUID uuid, std::unique_ptr<ash::DeskTemplate> entry); - // Remove entry with `uuid_str`. If the entry with `uuid_str` does not - // exist, then the deletion is considered a success. - void DeleteEntryTask(const std::string& uuid_str, + // Remove entry with `uuid`. If the entry with `uuid` does not exist, then the + // deletion is considered a success. + void DeleteEntryTask(const base::GUID& uuid, DeskModel::DeleteEntryStatus* status_ptr); // Delete all entries.
diff --git a/components/desks_storage/core/local_desk_data_manager_unittests.cc b/components/desks_storage/core/local_desk_data_manager_unittests.cc index 7fe09f4..756817f 100644 --- a/components/desks_storage/core/local_desk_data_manager_unittests.cc +++ b/components/desks_storage/core/local_desk_data_manager_unittests.cc
@@ -565,7 +565,7 @@ base::BindOnce(&VerifyEntryAddedCorrectly)); data_manager_->DeleteEntry( - kTestUuid1, + base::GUID::ParseCaseInsensitive(kTestUuid1), base::BindLambdaForTesting([&](DeskModel::DeleteEntryStatus status) { EXPECT_EQ(status, DeskModel::DeleteEntryStatus::kOk); })); @@ -680,7 +680,7 @@ VerifyAllEntries(1ul, "Added one save and recall desk"); EXPECT_EQ(data_manager_->GetSaveAndRecallDeskEntryCount(), 1ul); data_manager_->DeleteEntry( - kTestSaveAndRecallDeskUuid1, + base::GUID::ParseCaseInsensitive(kTestSaveAndRecallDeskUuid1), base::BindLambdaForTesting([&](DeskModel::DeleteEntryStatus status) { EXPECT_EQ(status, DeskModel::DeleteEntryStatus::kOk); })); @@ -838,7 +838,7 @@ base::SetPosixFilePermissions(temp_dir_.GetPath(), base::FILE_PERMISSION_READ_BY_USER); data_manager_->DeleteEntry( - kTestUuid1, + base::GUID::ParseCaseInsensitive(kTestUuid1), base::BindLambdaForTesting([&](DeskModel::DeleteEntryStatus status) { EXPECT_EQ(status, DeskModel::DeleteEntryStatus::kFailure); }));
diff --git a/components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/ColorPickerSimple.java b/components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/ColorPickerSimple.java index 0b03e8c2..36bb934 100644 --- a/components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/ColorPickerSimple.java +++ b/components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/ColorPickerSimple.java
@@ -29,6 +29,8 @@ R.string.color_picker_button_yellow, R.string.color_picker_button_black, R.string.color_picker_button_white}; + private ColorSuggestionListAdapter mAdapter; + public ColorPickerSimple(Context context) { super(context); } @@ -60,10 +62,9 @@ } } - ColorSuggestionListAdapter adapter = - new ColorSuggestionListAdapter(getContext(), suggestions); - adapter.setOnColorSuggestionClickListener(this); - setAdapter(adapter); + mAdapter = new ColorSuggestionListAdapter(getContext(), suggestions); + mAdapter.setOnColorSuggestionClickListener(this); + setAdapter(mAdapter); setAccessibilityDelegate(new View.AccessibilityDelegate() { @Override public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) { @@ -77,5 +78,8 @@ @Override public void onColorSuggestionClick(ColorSuggestion suggestion) { mOnColorChangedListener.onColorChanged(suggestion.mColor); + + assert mAdapter != null; + mAdapter.setSelectedColor(suggestion.mColor); } }
diff --git a/components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/ColorSuggestionListAdapter.java b/components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/ColorSuggestionListAdapter.java index 0dc02d4..4e51b62 100644 --- a/components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/ColorSuggestionListAdapter.java +++ b/components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/ColorSuggestionListAdapter.java
@@ -25,6 +25,7 @@ private Context mContext; private ColorSuggestion[] mSuggestions; private OnColorSuggestionClickListener mListener; + private int mSelectedColor; /** * The callback used to indicate the user has clicked on a suggestion. @@ -53,6 +54,14 @@ } /** + * Sets the currently selected color so the corresponding list item can be labeled. + * @param selectedColor The newly selected color. + */ + public void setSelectedColor(int selectedColor) { + mSelectedColor = selectedColor; + } + + /** * Sets up the color button to represent a color suggestion. * * @param button The button view to set up. @@ -84,6 +93,7 @@ super.onInitializeAccessibilityNodeInfo(host, info); info.setCollectionItemInfo( AccessibilityNodeInfo.CollectionItemInfo.obtain(index, 1, 1, 1, false)); + info.setSelected(suggestion.mColor == mSelectedColor); } }); }
diff --git a/components/exo/pointer.cc b/components/exo/pointer.cc index 75cd6bb..42989f0 100644 --- a/components/exo/pointer.cc +++ b/components/exo/pointer.cc
@@ -265,7 +265,7 @@ // Permission of Pointer lock is controlled by SecurityDelegate, created per // server instance. Default implementation allows this for ARC and Lacros - // windows which have their own security mechanism and are consiered trusted. + // windows which have their own security mechanism and are considered trusted. aura::Window* toplevel = constrained_surface->window()->GetToplevelWindow(); auto* shell_surface_base = GetShellSurfaceBaseForWindow(toplevel); auto* security_delegate = shell_surface_base->GetSecurityDelegate(); @@ -398,6 +398,7 @@ gfx::Point p = location_when_pointer_capture_enabled_ ? *location_when_pointer_capture_enabled_ : root->bounds().CenterPoint(); + expected_next_mouse_location_ = p; root->MoveCursorTo(p); aura::Window* window = capture_window_; @@ -528,12 +529,28 @@ #endif if (!same_location) { - bool needs_frame = HandleRelativePointerMotion( - event->time_stamp(), location_in_root, ordinal_motion); + bool ignore_motion = false; + if (expected_next_mouse_location_) { + const gfx::Point& expected = *expected_next_mouse_location_; + // Since MoveCursorTo() takes integer coordinates, the resulting move + // could have a conversion error of up to 2 due to fractional scale + // factors. + if (std::abs(location_in_root.x() - expected.x()) <= 2 && + std::abs(location_in_root.y() - expected.y()) <= 2) { + // This was a synthetic move event, so do not forward it and clear the + // expected location. + expected_next_mouse_location_.reset(); + ignore_motion = true; + } + } + bool needs_frame = + !ignore_motion && + HandleRelativePointerMotion(event->time_stamp(), location_in_root, + ordinal_motion); if (capture_window_) { if (ShouldMoveToCenter()) MoveCursorToCenterOfActiveDisplay(); - } else if (event->type() != ui::ET_MOUSE_EXITED) { + } else if (event->type() != ui::ET_MOUSE_EXITED && !ignore_motion) { delegate_->OnPointerMotion(event->time_stamp(), location_in_target); needs_frame = true; } @@ -997,7 +1014,7 @@ return; aura::Window* root = capture_window_->GetRootWindow(); gfx::Point p = root->bounds().CenterPoint(); - location_synthetic_move_ = p; + expected_next_mouse_location_ = p; root->MoveCursorTo(p); } @@ -1008,19 +1025,6 @@ if (!relative_pointer_delegate_) return false; - if (location_synthetic_move_) { - gfx::Point synthetic = *location_synthetic_move_; - // Since MoveCursorTo() takes integer coordinates, the resulting move could - // have a conversion error of up to 2 due to fractional scale factors. - if (std::abs(location_in_root.x() - synthetic.x()) <= 2 && - std::abs(location_in_root.y() - synthetic.y()) <= 2) { - // This was a synthetic move event, so do not forward it and clear the - // synthetic move. - location_synthetic_move_.reset(); - return false; - } - } - gfx::Vector2dF delta = location_in_root - location_; relative_pointer_delegate_->OnPointerRelativeMotion( time_stamp, delta,
diff --git a/components/exo/pointer.h b/components/exo/pointer.h index 187d5f9..8b0b457ee 100644 --- a/components/exo/pointer.h +++ b/components/exo/pointer.h
@@ -233,7 +233,7 @@ // If this is not nullptr, a synthetic move was sent and this points to the // location of a generated move that was sent which should not be forwarded. - absl::optional<gfx::Point> location_synthetic_move_; + absl::optional<gfx::Point> expected_next_mouse_location_; // The window with pointer capture. Pointer capture is enabled if and only if // this is not null.
diff --git a/components/exo/pointer_unittest.cc b/components/exo/pointer_unittest.cc index 3a46589..8cd46a1 100644 --- a/components/exo/pointer_unittest.cc +++ b/components/exo/pointer_unittest.cc
@@ -1815,7 +1815,7 @@ pointer_.reset(); } -TEST_F(PointerConstraintTest, DefaultSecrityDeletegate) { +TEST_F(PointerConstraintTest, DefaultSecurityDeletegate) { auto default_security_delegate = SecurityDelegate::GetDefaultSecurityDelegate(); auto shell_surface = test::ShellSurfaceBuilder({10, 10}) @@ -1860,6 +1860,34 @@ pointer_.reset(); } +TEST_F(PointerConstraintTest, NoPointerMotionEventWhenUnconstrainingPointer) { + testing::MockFunction<void(std::string check_point_name)> check; + { + testing::InSequence s; + + EXPECT_CALL(check, Call("Unconstrain pointer")); + EXPECT_CALL(delegate_, OnPointerMotion(testing::_, testing::_)).Times(0); + } + + generator_->MoveMouseTo( + surface_->window()->GetBoundsInScreen().CenterPoint() + + gfx::Vector2d(4, 4)); + + EXPECT_TRUE(pointer_->ConstrainPointer(&constraint_delegate_)); + + generator_->MoveMouseTo( + surface_->window()->GetBoundsInScreen().CenterPoint() + + gfx::Vector2d(-4, -4)); + + check.Call("Unconstrain pointer"); + + pointer_->UnconstrainPointerByUserAction(); + + // Ensure the posted task for synthesized mouse move event is run. + base::RunLoop().RunUntilIdle(); + + pointer_.reset(); +} #endif TEST_F(PointerTest, PointerStylus) {
diff --git a/components/omnibox/common/omnibox_features.cc b/components/omnibox/common/omnibox_features.cc index 8483d959..9672f91 100644 --- a/components/omnibox/common/omnibox_features.cc +++ b/components/omnibox/common/omnibox_features.cc
@@ -152,7 +152,7 @@ // Enables prefetching of the zero prefix suggestions for eligible users on NTP. const base::Feature kZeroSuggestPrefetching{"ZeroSuggestPrefetching", - enabled_by_default_desktop_only}; + enabled_by_default_desktop_android}; // Enables prefetching of the zero prefix suggestions for eligible users on SRP. const base::Feature kZeroSuggestPrefetchingOnSRP{
diff --git a/components/password_manager/core/browser/password_autofill_manager.cc b/components/password_manager/core/browser/password_autofill_manager.cc index db0186b4..d1f5ec3 100644 --- a/components/password_manager/core/browser/password_autofill_manager.cc +++ b/components/password_manager/core/browser/password_autofill_manager.cc
@@ -390,7 +390,7 @@ void PasswordAutofillManager::DidSelectSuggestion( const std::u16string& value, int frontend_id, - const std::string& backend_id) { + const autofill::Suggestion::BackendId& backend_id) { ClearPreviewedForm(); if (frontend_id == autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY || frontend_id == autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_EMPTY || @@ -479,9 +479,10 @@ PasswordDropdownSelectedOption::kWebAuthn, password_client_->IsIncognito()); password_client_->GetWebAuthnCredentialsDelegate() - ->SelectWebAuthnCredential(absl::holds_alternative<std::string>(payload) - ? absl::get<std::string>(payload) - : std::string()); + ->SelectWebAuthnCredential( + absl::holds_alternative<autofill::Suggestion::BackendId>(payload) + ? absl::get<autofill::Suggestion::BackendId>(payload).value() + : std::string()); } else if (frontend_id == autofill::POPUP_ITEM_ID_WEBAUTHN_SIGN_IN_WITH_ANOTHER_DEVICE) { metrics_util::LogPasswordDropdownItemSelected(
diff --git a/components/password_manager/core/browser/password_autofill_manager.h b/components/password_manager/core/browser/password_autofill_manager.h index 349c6b46..0b4e764 100644 --- a/components/password_manager/core/browser/password_autofill_manager.h +++ b/components/password_manager/core/browser/password_autofill_manager.h
@@ -54,9 +54,10 @@ void OnPopupShown() override; void OnPopupHidden() override; void OnPopupSuppressed() override; - void DidSelectSuggestion(const std::u16string& value, - int frontend_id, - const std::string& backend_id) override; + void DidSelectSuggestion( + const std::u16string& value, + int frontend_id, + const autofill::Suggestion::BackendId& backend_id) override; void DidAcceptSuggestion(const std::u16string& value, int frontend_id, const autofill::Suggestion::Payload& payload,
diff --git a/components/password_manager/core/browser/password_autofill_manager_unittest.cc b/components/password_manager/core/browser/password_autofill_manager_unittest.cc index 17b3081..adb7190 100644 --- a/components/password_manager/core/browser/password_autofill_manager_unittest.cc +++ b/components/password_manager/core/browser/password_autofill_manager_unittest.cc
@@ -23,6 +23,7 @@ #include "components/autofill/core/browser/test_autofill_client.h" #include "components/autofill/core/browser/test_autofill_driver.h" #include "components/autofill/core/browser/ui/popup_item_ids.h" +#include "components/autofill/core/browser/ui/suggestion.h" #include "components/autofill/core/browser/ui/suggestion_test_helpers.h" #include "components/autofill/core/common/autofill_constants.h" #include "components/autofill/core/common/autofill_features.h" @@ -454,7 +455,7 @@ is_suggestion_on_password_field ? autofill::POPUP_ITEM_ID_PASSWORD_ENTRY : autofill::POPUP_ITEM_ID_USERNAME_ENTRY, - std::string(), 1); + autofill::Suggestion::BackendId(), 1); histograms.ExpectUniqueSample( kDropdownSelectedHistogram, metrics_util::PasswordDropdownSelectedOption::kPassword, 1); @@ -524,7 +525,7 @@ is_suggestion_on_password_field ? autofill::POPUP_ITEM_ID_ACCOUNT_STORAGE_PASSWORD_ENTRY : autofill::POPUP_ITEM_ID_ACCOUNT_STORAGE_USERNAME_ENTRY, - std::string(), + autofill::Suggestion::BackendId(), /*position=*/1); } } @@ -624,7 +625,7 @@ /*has_re_signin=*/false))); password_autofill_manager_->DidAcceptSuggestion( test_username_, autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_OPT_IN, - std::string(), 1); + autofill::Suggestion::BackendId(), 1); ASSERT_GE(suggestions.size(), 2u); EXPECT_TRUE(suggestions.back().is_loading); } @@ -659,7 +660,7 @@ password_autofill_manager_->DidAcceptSuggestion( test_username_, autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_OPT_IN_AND_GENERATE, - std::string(), 1); + autofill::Suggestion::BackendId(), 1); ASSERT_GE(suggestions.size(), 2u); EXPECT_TRUE(suggestions.back().is_loading); } @@ -678,8 +679,8 @@ EXPECT_CALL(autofill_client, HideAutofillPopup); password_autofill_manager_->DidAcceptSuggestion( test_username_, - autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_RE_SIGNIN, std::string(), - 1); + autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_RE_SIGNIN, + autofill::Suggestion::BackendId(), 1); } // Test that the popup is updated once "opt in and fill" is clicked and the @@ -726,7 +727,7 @@ password_autofill_manager_->DidAcceptSuggestion( test_username_, autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_OPT_IN, - std::string(), 1); + autofill::Suggestion::BackendId(), 1); ASSERT_GE(suggestions.size(), 2u); EXPECT_FALSE(suggestions.back().is_loading); } @@ -778,7 +779,7 @@ password_autofill_manager_->DidAcceptSuggestion( test_username_, autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_OPT_IN_AND_GENERATE, - std::string(), 1); + autofill::Suggestion::BackendId(), 1); ASSERT_GE(suggestions.size(), 2u); EXPECT_FALSE(suggestions.back().is_loading); } @@ -813,7 +814,7 @@ password_autofill_manager_->DidAcceptSuggestion( test_username_, autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_OPT_IN, - std::string(), 1); + autofill::Suggestion::BackendId(), 1); } // Test that the popup is hidden and password generation is triggered once @@ -853,7 +854,7 @@ password_autofill_manager_->DidAcceptSuggestion( test_username_, autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_OPT_IN_AND_GENERATE, - std::string(), 1); + autofill::Suggestion::BackendId(), 1); } // Test that the popup shows an empty state if opted-into an empty store. @@ -1254,7 +1255,7 @@ EXPECT_CALL(*client.mock_driver(), PreviewSuggestion(std::u16string(), test_password_)); password_autofill_manager_->DidSelectSuggestion( - no_username_string, 0 /*not used*/, std::string() /*not used*/); + no_username_string, 0 /*not used*/, Suggestion::BackendId() /*not used*/); testing::Mock::VerifyAndClearExpectations(client.mock_driver()); // Check that fill of the empty username works. @@ -1264,8 +1265,8 @@ autofill_client, HideAutofillPopup(autofill::PopupHidingReason::kAcceptSuggestion)); password_autofill_manager_->DidAcceptSuggestion( - no_username_string, autofill::POPUP_ITEM_ID_PASSWORD_ENTRY, std::string(), - 1); + no_username_string, autofill::POPUP_ITEM_ID_PASSWORD_ENTRY, + autofill::Suggestion::BackendId(), 1); testing::Mock::VerifyAndClearExpectations(client.mock_driver()); } @@ -1313,7 +1314,7 @@ HideAutofillPopup(autofill::PopupHidingReason::kAcceptSuggestion)); password_autofill_manager_->DidAcceptSuggestion( std::u16string(), autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY, - std::string(), 0); + autofill::Suggestion::BackendId(), 0); histograms.ExpectUniqueSample( kDropdownSelectedHistogram, metrics_util::PasswordDropdownSelectedOption::kShowAll, 1); @@ -1425,7 +1426,7 @@ HideAutofillPopup(autofill::PopupHidingReason::kAcceptSuggestion)); password_autofill_manager_->DidAcceptSuggestion( std::u16string(), autofill::POPUP_ITEM_ID_GENERATE_PASSWORD_ENTRY, - std::string(), 1); + autofill::Suggestion::BackendId(), 1); histograms.ExpectUniqueSample( kDropdownSelectedHistogram, metrics_util::PasswordDropdownSelectedOption::kGenerate, 1); @@ -1576,8 +1577,8 @@ // Accept the suggestion to start the filing process which tries to // reauthenticate the user if possible. password_autofill_manager_->DidAcceptSuggestion( - test_username_, autofill::POPUP_ITEM_ID_PASSWORD_ENTRY, std::string(), - 1); + test_username_, autofill::POPUP_ITEM_ID_PASSWORD_ENTRY, + autofill::Suggestion::BackendId(), 1); } } @@ -1633,8 +1634,8 @@ // Accept the suggestion to start the filing process which tries to // reauthenticate the user if possible. password_autofill_manager_->DidAcceptSuggestion( - test_username_, autofill::POPUP_ITEM_ID_PASSWORD_ENTRY, std::string(), - 1); + test_username_, autofill::POPUP_ITEM_ID_PASSWORD_ENTRY, + autofill::Suggestion::BackendId(), 1); } } @@ -1690,8 +1691,8 @@ // Accept the suggestion to start the filing process which tries to // reauthenticate the user if possible. password_autofill_manager_->DidAcceptSuggestion( - test_username_, autofill::POPUP_ITEM_ID_PASSWORD_ENTRY, std::string(), - 1); + test_username_, autofill::POPUP_ITEM_ID_PASSWORD_ENTRY, + autofill::Suggestion::BackendId(), 1); } } @@ -1733,7 +1734,8 @@ // Accept the suggestion to start the filing process which tries to // reauthenticate the user if possible. password_autofill_manager_->DidAcceptSuggestion( - test_username_, autofill::POPUP_ITEM_ID_PASSWORD_ENTRY, std::string(), 1); + test_username_, autofill::POPUP_ITEM_ID_PASSWORD_ENTRY, + autofill::Suggestion::BackendId(), 1); EXPECT_CALL(*authenticator_.get(), Cancel(BiometricAuthRequester::kAutofillSuggestion)); @@ -1778,7 +1780,8 @@ // Accept the suggestion to start the filing process which tries to // reauthenticate the user if possible. password_autofill_manager_->DidAcceptSuggestion( - test_username_, autofill::POPUP_ITEM_ID_PASSWORD_ENTRY, std::string(), 1); + test_username_, autofill::POPUP_ITEM_ID_PASSWORD_ENTRY, + autofill::Suggestion::BackendId(), 1); EXPECT_CALL(*authenticator_.get(), Cancel(BiometricAuthRequester::kAutofillSuggestion)); @@ -1824,7 +1827,8 @@ // Accept the suggestion to start the filing process which tries to // reauthenticate the user if possible. password_autofill_manager_->DidAcceptSuggestion( - test_username_, autofill::POPUP_ITEM_ID_PASSWORD_ENTRY, std::string(), 1); + test_username_, autofill::POPUP_ITEM_ID_PASSWORD_ENTRY, + autofill::Suggestion::BackendId(), 1); EXPECT_CALL(*authenticator_.get(), Cancel(BiometricAuthRequester::kAutofillSuggestion)); @@ -1843,7 +1847,7 @@ const std::u16string kAuthenticator = u"Use device sign-in"; autofill::Suggestion webauthn_credential(kName); webauthn_credential.frontend_id = autofill::POPUP_ITEM_ID_WEBAUTHN_CREDENTIAL; - webauthn_credential.payload = kId; + webauthn_credential.payload = Suggestion::BackendId(kId); webauthn_credential.label = kAuthenticator; ON_CALL(webauthn_credentials_delegate, IsWebAuthnAutofillEnabled) .WillByDefault(Return(true)); @@ -1871,7 +1875,8 @@ autofill::POPUP_ITEM_ID_WEBAUTHN_SIGN_IN_WITH_ANOTHER_DEVICE, #endif // !BUILDFLAG(IS_ANDROID) autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY))); - EXPECT_EQ(absl::get<std::string>(open_args.suggestions[0].payload), kId); + EXPECT_EQ(open_args.suggestions[0].GetPayload<Suggestion::BackendId>(), + Suggestion::BackendId(kId)); EXPECT_EQ(open_args.suggestions[0].frontend_id, autofill::POPUP_ITEM_ID_WEBAUTHN_CREDENTIAL); EXPECT_EQ(open_args.suggestions[0].main_text.value, kName); @@ -1883,7 +1888,7 @@ PreviewSuggestion(kName, /*password=*/std::u16string(u""))); password_autofill_manager_->DidSelectSuggestion( kName, autofill::POPUP_ITEM_ID_WEBAUTHN_CREDENTIAL, - std::string() /*not used*/); + Suggestion::BackendId() /*not used*/); testing::Mock::VerifyAndClearExpectations(client.mock_driver()); // Check that selecting the credential reports back to the client. @@ -1892,7 +1897,8 @@ autofill_client, HideAutofillPopup(autofill::PopupHidingReason::kAcceptSuggestion)); password_autofill_manager_->DidAcceptSuggestion( - kName, autofill::POPUP_ITEM_ID_WEBAUTHN_CREDENTIAL, kId, /*position=*/1); + kName, autofill::POPUP_ITEM_ID_WEBAUTHN_CREDENTIAL, + autofill::Suggestion::BackendId(kId), /*position=*/1); } #if !BUILDFLAG(IS_ANDROID) @@ -1940,7 +1946,7 @@ password_autofill_manager_->DidAcceptSuggestion( kSignInWithAnotherDeviceText, autofill::POPUP_ITEM_ID_WEBAUTHN_SIGN_IN_WITH_ANOTHER_DEVICE, - /*payload=*/std::string(), /*position=*/1); + /*payload=*/autofill::Suggestion::BackendId(), /*position=*/1); } #endif // !BUILDFLAG(IS_ANDROID)
diff --git a/components/pdf/renderer/pdf_view_web_plugin_client.cc b/components/pdf/renderer/pdf_view_web_plugin_client.cc index 0beee3a..937e0de 100644 --- a/components/pdf/renderer/pdf_view_web_plugin_client.cc +++ b/components/pdf/renderer/pdf_view_web_plugin_client.cc
@@ -115,8 +115,9 @@ } void PdfViewWebPluginClient::ReportFindInPageSelection(int identifier, - int index) { - plugin_container_->ReportFindInPageSelection(identifier, index); + int index, + bool final_update) { + plugin_container_->ReportFindInPageSelection(identifier, index, final_update); } void PdfViewWebPluginClient::ReportFindInPageTickmarks(
diff --git a/components/pdf/renderer/pdf_view_web_plugin_client.h b/components/pdf/renderer/pdf_view_web_plugin_client.h index 1a1bf3c6..9d2cc65 100644 --- a/components/pdf/renderer/pdf_view_web_plugin_client.h +++ b/components/pdf/renderer/pdf_view_web_plugin_client.h
@@ -49,7 +49,9 @@ void ReportFindInPageMatchCount(int identifier, int total, bool final_update) override; - void ReportFindInPageSelection(int identifier, int index) override; + void ReportFindInPageSelection(int identifier, + int index, + bool final_update) override; void ReportFindInPageTickmarks( const std::vector<gfx::Rect>& tickmarks) override; float DeviceScaleFactor() override;
diff --git a/components/privacy_sandbox/privacy_sandbox_settings.cc b/components/privacy_sandbox/privacy_sandbox_settings.cc index 453c304..8458b1a 100644 --- a/components/privacy_sandbox/privacy_sandbox_settings.cc +++ b/components/privacy_sandbox/privacy_sandbox_settings.cc
@@ -328,6 +328,13 @@ top_frame_origin); } +bool PrivacySandboxSettings::IsPrivateAggregationAllowed( + const url::Origin& top_frame_origin, + const url::Origin& reporting_origin) const { + return IsPrivacySandboxEnabledForContext(reporting_origin.GetURL(), + top_frame_origin); +} + bool PrivacySandboxSettings::IsPrivacySandboxEnabled() const { // If the delegate is restricting access the Privacy Sandbox is disabled. if (delegate_->IsPrivacySandboxRestricted())
diff --git a/components/privacy_sandbox/privacy_sandbox_settings.h b/components/privacy_sandbox/privacy_sandbox_settings.h index f75fd48e..44509d1c 100644 --- a/components/privacy_sandbox/privacy_sandbox_settings.h +++ b/components/privacy_sandbox/privacy_sandbox_settings.h
@@ -155,6 +155,12 @@ bool IsSharedStorageAllowed(const url::Origin& top_frame_origin, const url::Origin& accessing_origin) const; + // Determines whether the Private Aggregation API is allowable in a particular + // context. `top_frame_origin` is the associated top-frame origin of the + // calling context. + bool IsPrivateAggregationAllowed(const url::Origin& top_frame_origin, + const url::Origin& reporting_origin) const; + // Returns whether the profile has the Privacy Sandbox enabled. This consults // the main preference, as well as the delegate to check whether the sandbox // is restricted. It does not consider any cookie settings. A return value of
diff --git a/components/privacy_sandbox/privacy_sandbox_settings_unittest.cc b/components/privacy_sandbox/privacy_sandbox_settings_unittest.cc index 18ec624..bd044f7 100644 --- a/components/privacy_sandbox/privacy_sandbox_settings_unittest.cc +++ b/components/privacy_sandbox/privacy_sandbox_settings_unittest.cc
@@ -131,6 +131,10 @@ url::Origin::Create(GURL("https://another-test.com")), url::Origin::Create(GURL("https://embedded.com")))); + EXPECT_FALSE(privacy_sandbox_settings()->IsPrivateAggregationAllowed( + url::Origin::Create(GURL("https://test.com")), + url::Origin::Create(GURL("https://embedded.com")))); + EXPECT_FALSE(privacy_sandbox_settings()->IsFledgeAllowed( url::Origin::Create(GURL("https://test.com")), url::Origin::Create(GURL("https://embedded.com")))); @@ -180,6 +184,10 @@ url::Origin::Create(GURL("https://another-test.com")), url::Origin::Create(GURL("https://embedded.com")))); + EXPECT_FALSE(privacy_sandbox_settings()->IsPrivateAggregationAllowed( + url::Origin::Create(GURL("https://test.com")), + url::Origin::Create(GURL("https://embedded.com")))); + EXPECT_FALSE(privacy_sandbox_settings()->IsFledgeAllowed( url::Origin::Create(GURL("https://test.com")), url::Origin::Create(GURL("https://embedded.com")))); @@ -223,6 +231,10 @@ url::Origin::Create(GURL("https://another-test.com")), url::Origin::Create(GURL("https://embedded.com")))); + EXPECT_FALSE(privacy_sandbox_settings()->IsPrivateAggregationAllowed( + url::Origin::Create(GURL("https://test.com")), + url::Origin::Create(GURL("https://embedded.com")))); + EXPECT_FALSE(privacy_sandbox_settings()->IsFledgeAllowed( url::Origin::Create(GURL("https://test.com")), url::Origin::Create(GURL("https://embedded.com")))); @@ -265,6 +277,10 @@ url::Origin::Create(GURL("https://another-test.com")), url::Origin::Create(GURL("https://embedded.com")))); + EXPECT_FALSE(privacy_sandbox_settings()->IsPrivateAggregationAllowed( + url::Origin::Create(GURL("https://test.com")), + url::Origin::Create(GURL("https://embedded.com")))); + EXPECT_FALSE(privacy_sandbox_settings()->IsFledgeAllowed( url::Origin::Create(GURL("https://test.com")), url::Origin::Create(GURL("https://embedded.com")))); @@ -319,6 +335,13 @@ url::Origin::Create(GURL("https://unrelated-d.com")), url::Origin::Create(GURL("https://unrelated-e.com")))); + EXPECT_FALSE(privacy_sandbox_settings()->IsPrivateAggregationAllowed( + url::Origin::Create(GURL("https://test.com")), + url::Origin::Create(GURL("https://embedded.com")))); + EXPECT_TRUE(privacy_sandbox_settings()->IsPrivateAggregationAllowed( + url::Origin::Create(GURL("https://unrelated-a.com")), + url::Origin::Create(GURL("https://unrelated-b.com")))); + EXPECT_FALSE(privacy_sandbox_settings()->IsFledgeAllowed( url::Origin::Create(GURL("https://test.com")), url::Origin::Create(GURL("https://embedded.com")))); @@ -387,6 +410,10 @@ url::Origin::Create(GURL("https://yet-another-test.com")), url::Origin::Create(GURL("https://embedded.com")))); + EXPECT_TRUE(privacy_sandbox_settings()->IsPrivateAggregationAllowed( + url::Origin::Create(GURL("https://another-test.com")), + url::Origin::Create(GURL("https://embedded.com")))); + EXPECT_TRUE(privacy_sandbox_settings()->IsFledgeAllowed( url::Origin::Create(GURL("https://another-test.com")), url::Origin::Create(GURL("https://embedded.com")))); @@ -427,6 +454,10 @@ url::Origin::Create(GURL("https://another-test.com")), url::Origin::Create(GURL("https://embedded.com")))); + EXPECT_FALSE(privacy_sandbox_settings()->IsPrivateAggregationAllowed( + url::Origin::Create(GURL("https://test.com")), + url::Origin::Create(GURL("https://embedded.com")))); + EXPECT_FALSE(privacy_sandbox_settings()->IsFledgeAllowed( url::Origin::Create(GURL("https://test.com")), url::Origin::Create(GURL("https://embedded.com")))); @@ -465,6 +496,10 @@ url::Origin::Create(GURL("https://another-test.com")), url::Origin::Create(GURL("https://embedded.com")))); + EXPECT_FALSE(privacy_sandbox_settings()->IsPrivateAggregationAllowed( + url::Origin::Create(GURL("https://test.com")), + url::Origin::Create(GURL("https://embedded.com")))); + EXPECT_FALSE(privacy_sandbox_settings()->IsFledgeAllowed( url::Origin::Create(GURL("https://test.com")), url::Origin::Create(GURL("https://embedded.com")))); @@ -501,6 +536,10 @@ url::Origin::Create(GURL("https://another-test.com")), url::Origin::Create(GURL("https://embedded.com")))); + EXPECT_FALSE(privacy_sandbox_settings()->IsPrivateAggregationAllowed( + url::Origin::Create(GURL("https://test.com")), + url::Origin::Create(GURL("https://embedded.com")))); + EXPECT_FALSE(privacy_sandbox_settings()->IsFledgeAllowed( url::Origin::Create(GURL("https://test.com")), url::Origin::Create(GURL("https://embedded.com")))); @@ -542,6 +581,10 @@ url::Origin::Create(GURL("https://another-test.com")), url::Origin::Create(GURL("https://embedded.com")))); + EXPECT_FALSE(privacy_sandbox_settings()->IsPrivateAggregationAllowed( + url::Origin::Create(GURL("https://test.com")), + url::Origin::Create(GURL("https://embedded.com")))); + EXPECT_FALSE(privacy_sandbox_settings()->IsFledgeAllowed( url::Origin::Create(GURL("https://test.com")), url::Origin::Create(GURL("https://embedded.com"))));
diff --git a/components/remote_cocoa/app_shim/native_widget_mac_nswindow.mm b/components/remote_cocoa/app_shim/native_widget_mac_nswindow.mm index 7618054..949fb64 100644 --- a/components/remote_cocoa/app_shim/native_widget_mac_nswindow.mm +++ b/components/remote_cocoa/app_shim/native_widget_mac_nswindow.mm
@@ -19,6 +19,24 @@ namespace { +bool AreWindowShadowsDisabled() { + // When: + // 1) Shadows are being generated by the window server + // 2) The window with the shadow has a layer (all of Chrome's do) + // 3) Software compositing is in use (it is in most test configs, which + // run in VMs) + // 4) There are many windows in use at once (they are when running + // test in parallel) + // The window server seems to crash with distressing frequency. To hopefully + // mitigate that, disable window shadows when running on a bot. + // For context on this see: + // https://crbug.com/899286 + // https://crbug.com/828031 + // https://crbug.com/515627, especially #63 and #67 + static bool is_headless = getenv("CHROME_HEADLESS") != nullptr; + return is_headless; +} + // AppKit quirk: -[NSWindow orderWindow] does not handle reordering for children // windows. Their order is fixed to the attachment order (the last attached // window is on the top). Therefore, work around it by re-parenting in our @@ -218,6 +236,10 @@ // Public methods. +- (void)setHasShadow:(BOOL)flag { + [super setHasShadow:flag && !AreWindowShadowsDisabled()]; +} + - (void)setCommandDispatcherDelegate:(id<CommandDispatcherDelegate>)delegate { [_commandDispatcher setDelegate:delegate]; }
diff --git a/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.mm b/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.mm index 9a7641b..0a2a8ff 100644 --- a/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.mm +++ b/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.mm
@@ -58,24 +58,6 @@ namespace { constexpr auto kUIPaintTimeout = base::Seconds(5); -bool AreWindowShadowsDisabled() { - // When: - // 1) Shadows are being generated by the window server - // 2) The window with the shadow has a layer (all of Chrome's do) - // 3) Software compositing is in use (it is in most test configs, which - // run in VMs) - // 4) There are many windows in use at once (they are when running - // test in parallel) - // The window server seems to crash with distressing frequency. To hopefully - // mitigate that, disable window shadows when running on a bot. - // For context on this see: - // https://crbug.com/899286 - // https://crbug.com/828031 - // https://crbug.com/515627, especially #63 and #67 - static bool is_headless = getenv("CHROME_HEADLESS") != nullptr; - return is_headless; -} - // Returns the display that the specified window is on. display::Display GetDisplayForWindow(NSWindow* window) { return display::Screen::GetScreen()->GetDisplayNearestWindow(window); @@ -477,8 +459,8 @@ NSWindowCollectionBehaviorParticipatesInCycle]; } - [window_ setHasShadow:params->has_window_server_shadow && - !AreWindowShadowsDisabled()]; + [window_ setHasShadow:params->has_window_server_shadow]; + // Don't allow dragging sheets. if (params->modal_type == ui::MODAL_TYPE_WINDOW) [window_ setMovable:NO];
diff --git a/components/safe_search_api/safe_search/safe_search_url_checker_client.cc b/components/safe_search_api/safe_search/safe_search_url_checker_client.cc index c53542b..69ecb34 100644 --- a/components/safe_search_api/safe_search/safe_search_url_checker_client.cc +++ b/components/safe_search_api/safe_search/safe_search_url_checker_client.cc
@@ -42,30 +42,29 @@ // returns true on success. Otherwise, returns false and doesn't set |is_porn|. bool ParseResponse(const std::string& response, bool* is_porn) { absl::optional<base::Value> optional_value = base::JSONReader::Read(response); - const base::DictionaryValue* dict = nullptr; - if (!optional_value || !optional_value.value().GetAsDictionary(&dict)) { + if (!optional_value || !optional_value.value().is_dict()) { DLOG(WARNING) << "ParseResponse failed to parse global dictionary"; return false; } - const base::ListValue* classifications_list = nullptr; - if (!dict->GetList("classifications", &classifications_list)) { + const base::Value::Dict& dict = optional_value.value().GetDict(); + const base::Value::List* classifications_list = + dict.FindList("classifications"); + if (!classifications_list) { DLOG(WARNING) << "ParseResponse failed to parse classifications list"; return false; } - if (classifications_list->GetListDeprecated().size() != 1) { + if (classifications_list->size() != 1u) { DLOG(WARNING) << "ParseResponse expected exactly one result"; return false; } - const base::Value& classification_value = - classifications_list->GetListDeprecated()[0]; + const base::Value& classification_value = (*classifications_list)[0]; if (!classification_value.is_dict()) { DLOG(WARNING) << "ParseResponse failed to parse classification dict"; return false; } - const base::DictionaryValue& classification_dict = - base::Value::AsDictionaryValue(classification_value); + const base::Value::Dict& classification_dict = classification_value.GetDict(); absl::optional<bool> is_porn_opt = - classification_dict.FindBoolKey("pornography"); + classification_dict.FindBool("pornography"); if (is_porn_opt.has_value()) *is_porn = is_porn_opt.value(); return true;
diff --git a/components/segmentation_platform/internal/metadata/metadata_utils.cc b/components/segmentation_platform/internal/metadata/metadata_utils.cc index 4128d5bf..06fd7f5 100644 --- a/components/segmentation_platform/internal/metadata/metadata_utils.cc +++ b/components/segmentation_platform/internal/metadata/metadata_utils.cc
@@ -362,9 +362,19 @@ model_metadata.min_signal_collection_length())); } if (model_metadata.has_result_time_to_live()) { - result.append(base::StringPrintf("result_time_to_live:%" PRId64, + result.append(base::StringPrintf("result_time_to_live:%" PRId64 ", ", model_metadata.result_time_to_live())); } + if (model_metadata.has_output_collection_delay_sec()) { + result.append( + base::StringPrintf("output_collection_delay_sec:%" PRId64 ", ", + model_metadata.output_collection_delay_sec())); + } + if (model_metadata.has_upload_tensors()) { + result.append( + base::StringPrintf("upload_tensors: %s", + model_metadata.upload_tensors() ? "true" : "false")); + } if (base::EndsWith(result, ", ")) result.resize(result.size() - 2);
diff --git a/components/segmentation_platform/public/proto/model_metadata.proto b/components/segmentation_platform/public/proto/model_metadata.proto index 0f94f4c..1dcb45a0 100644 --- a/components/segmentation_platform/public/proto/model_metadata.proto +++ b/components/segmentation_platform/public/proto/model_metadata.proto
@@ -227,7 +227,7 @@ // Metadata about a segmentation model for a given segment. Contains information // on how to use the model such as collecting signals, interpreting results etc. -// Next tag: 12 +// Next tag: 14 message SegmentationModelMetadata { // The version information needed to validate segmentation models. optional VersionInfo version_info = 9; @@ -285,4 +285,13 @@ // The default key to use during the mapping process if no key has been // provided. optional string default_discrete_mapping = 8; + + // The delay, in seconds, to collect output tensors after input tensors are + // collected. For example, output labels can be collected one week after input + // tensors are collected. If not specified, output tensors are collected in + // the same time period as input tensors. + optional int64 output_collection_delay_sec = 12; + + // Whether the client should upload the input and output tensors through UKM. + optional bool upload_tensors = 13; }
diff --git a/components/sync/base/features.h b/components/sync/base/features.h index e273d48..0806302 100644 --- a/components/sync/base/features.h +++ b/components/sync/base/features.h
@@ -24,7 +24,7 @@ "CacheBaseEntitySpecificsInMetadata", base::FEATURE_DISABLED_BY_DEFAULT}; inline constexpr base::Feature kEnableSyncImmediatelyInFRE{ - "EnableSyncImmediatelyInFRE", base::FEATURE_DISABLED_BY_DEFAULT}; + "EnableSyncImmediatelyInFRE", base::FEATURE_ENABLED_BY_DEFAULT}; // Causes Sync to ignore updates encrypted with keys that have been missing for // too long from this client; Sync will proceed normally as if those updates
diff --git a/components/sync_bookmarks/bookmark_model_observer_impl.cc b/components/sync_bookmarks/bookmark_model_observer_impl.cc index 1035d50a..6c0e4e8 100644 --- a/components/sync_bookmarks/bookmark_model_observer_impl.cc +++ b/components/sync_bookmarks/bookmark_model_observer_impl.cc
@@ -148,7 +148,8 @@ void BookmarkModelObserverImpl::BookmarkNodeAdded( bookmarks::BookmarkModel* model, const bookmarks::BookmarkNode* parent, - size_t index) { + size_t index, + bool added_by_user) { const bookmarks::BookmarkNode* node = parent->children()[index].get(); if (!model->client()->CanSyncNode(node)) { return;
diff --git a/components/sync_bookmarks/bookmark_model_observer_impl.h b/components/sync_bookmarks/bookmark_model_observer_impl.h index 52d7bf0..9af25de0 100644 --- a/components/sync_bookmarks/bookmark_model_observer_impl.h +++ b/components/sync_bookmarks/bookmark_model_observer_impl.h
@@ -53,7 +53,8 @@ size_t new_index) override; void BookmarkNodeAdded(bookmarks::BookmarkModel* model, const bookmarks::BookmarkNode* parent, - size_t index) override; + size_t index, + bool added_by_user) override; void OnWillRemoveBookmarks(bookmarks::BookmarkModel* model, const bookmarks::BookmarkNode* parent, size_t old_index,
diff --git a/components/sync_bookmarks/bookmark_model_observer_impl_unittest.cc b/components/sync_bookmarks/bookmark_model_observer_impl_unittest.cc index 190a5440..ad0330f 100644 --- a/components/sync_bookmarks/bookmark_model_observer_impl_unittest.cc +++ b/components/sync_bookmarks/bookmark_model_observer_impl_unittest.cc
@@ -725,11 +725,11 @@ // Now simulate calling the observer as if the nodes are added in that order. // 4,0,2,3,1. - observer.BookmarkNodeAdded(bookmark_model(), bookmark_bar_node, 4); - observer.BookmarkNodeAdded(bookmark_model(), bookmark_bar_node, 0); - observer.BookmarkNodeAdded(bookmark_model(), bookmark_bar_node, 2); - observer.BookmarkNodeAdded(bookmark_model(), bookmark_bar_node, 3); - observer.BookmarkNodeAdded(bookmark_model(), bookmark_bar_node, 1); + observer.BookmarkNodeAdded(bookmark_model(), bookmark_bar_node, 4, false); + observer.BookmarkNodeAdded(bookmark_model(), bookmark_bar_node, 0, false); + observer.BookmarkNodeAdded(bookmark_model(), bookmark_bar_node, 2, false); + observer.BookmarkNodeAdded(bookmark_model(), bookmark_bar_node, 3, false); + observer.BookmarkNodeAdded(bookmark_model(), bookmark_bar_node, 1, false); ASSERT_THAT(bookmark_tracker->TrackedEntitiesCountForTest(), 6U);
diff --git a/components/translate/core/browser/translate_pref_names.cc b/components/translate/core/browser/translate_pref_names.cc index ae72e6c..74228fb7 100644 --- a/components/translate/core/browser/translate_pref_names.cc +++ b/components/translate/core/browser/translate_pref_names.cc
@@ -22,5 +22,9 @@ // Languages that the user marked as "do not translate". const char kBlockedLanguages[] = "translate_blocked_languages"; +// Sites that never prompt to translate. +const char kPrefNeverPromptSitesWithTime[] = + "translate_site_blocklist_with_time"; + } // namespace prefs } // namespace translate
diff --git a/components/translate/core/browser/translate_pref_names.h b/components/translate/core/browser/translate_pref_names.h index 65ac5232..ee02655 100644 --- a/components/translate/core/browser/translate_pref_names.h +++ b/components/translate/core/browser/translate_pref_names.h
@@ -12,6 +12,7 @@ extern const char kPrefAlwaysTranslateList[]; extern const char kPrefTranslateRecentTarget[]; extern const char kBlockedLanguages[]; +extern const char kPrefNeverPromptSitesWithTime[]; } // namespace prefs } // namespace translate
diff --git a/components/translate/core/browser/translate_prefs.cc b/components/translate/core/browser/translate_prefs.cc index 13446c50..f37ee92 100644 --- a/components/translate/core/browser/translate_prefs.cc +++ b/components/translate/core/browser/translate_prefs.cc
@@ -144,8 +144,6 @@ "translate_force_trigger_on_english_count_for_backoff_1"; const char TranslatePrefs::kPrefNeverPromptSitesDeprecated[] = "translate_site_blacklist"; -const char TranslatePrefs::kPrefNeverPromptSitesWithTime[] = - "translate_site_blacklist_with_time"; const char TranslatePrefs::kPrefTranslateDeniedCount[] = "translate_denied_count_for_language"; const char TranslatePrefs::kPrefTranslateIgnoredCount[] = @@ -611,20 +609,20 @@ } bool TranslatePrefs::IsSiteOnNeverPromptList(base::StringPiece site) const { - return prefs_->GetValueDict(kPrefNeverPromptSitesWithTime).Find(site); + return prefs_->GetValueDict(prefs::kPrefNeverPromptSitesWithTime).Find(site); } void TranslatePrefs::AddSiteToNeverPromptList(base::StringPiece site) { DCHECK(!site.empty()); AddValueToNeverPromptList(kPrefNeverPromptSitesDeprecated, site); - DictionaryPrefUpdate update(prefs_, kPrefNeverPromptSitesWithTime); + DictionaryPrefUpdate update(prefs_, prefs::kPrefNeverPromptSitesWithTime); update->GetDict().Set(site, base::TimeToValue(base::Time::Now())); } void TranslatePrefs::RemoveSiteFromNeverPromptList(base::StringPiece site) { DCHECK(!site.empty()); RemoveValueFromNeverPromptList(kPrefNeverPromptSitesDeprecated, site); - DictionaryPrefUpdate update(prefs_, kPrefNeverPromptSitesWithTime); + DictionaryPrefUpdate update(prefs_, prefs::kPrefNeverPromptSitesWithTime); update->GetDict().Remove(site); } @@ -632,13 +630,13 @@ base::Time begin, base::Time end) const { std::vector<std::string> result; - const auto& dict = prefs_->GetValueDict(kPrefNeverPromptSitesWithTime); + const auto& dict = prefs_->GetValueDict(prefs::kPrefNeverPromptSitesWithTime); for (const auto entry : dict) { absl::optional<base::Time> time = base::ValueToTime(entry.second); if (!time) { // Badly formatted preferences may be synced from the server, see // https://crbug.com/1295549 - LOG(ERROR) << "Preference " << kPrefNeverPromptSitesWithTime + LOG(ERROR) << "Preference " << prefs::kPrefNeverPromptSitesWithTime << " has invalid format. Ignoring."; continue; } @@ -723,7 +721,7 @@ void TranslatePrefs::ClearNeverPromptSiteList() { prefs_->ClearPref(kPrefNeverPromptSitesDeprecated); - prefs_->ClearPref(kPrefNeverPromptSitesWithTime); + prefs_->ClearPref(prefs::kPrefNeverPromptSitesWithTime); } bool TranslatePrefs::HasLanguagePairsToAlwaysTranslate() const { @@ -939,7 +937,7 @@ registry->RegisterListPref(kPrefNeverPromptSitesDeprecated, user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); registry->RegisterDictionaryPref( - kPrefNeverPromptSitesWithTime, + prefs::kPrefNeverPromptSitesWithTime, user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); registry->RegisterDictionaryPref( prefs::kPrefAlwaysTranslateList, @@ -990,8 +988,8 @@ // Migration copies any sites on the deprecated never prompt pref to // the new version and clears all references to the old one. This will // make subsequent calls to migrate no-ops. - DictionaryPrefUpdate never_prompt_list_update(prefs_, - kPrefNeverPromptSitesWithTime); + DictionaryPrefUpdate never_prompt_list_update( + prefs_, prefs::kPrefNeverPromptSitesWithTime); base::Value::Dict& never_prompt_list = never_prompt_list_update->GetDict(); ListPrefUpdate deprecated_prompt_list_update(prefs_, kPrefNeverPromptSitesDeprecated);
diff --git a/components/translate/core/browser/translate_prefs.h b/components/translate/core/browser/translate_prefs.h index c19a471..3120555e 100644 --- a/components/translate/core/browser/translate_prefs.h +++ b/components/translate/core/browser/translate_prefs.h
@@ -111,7 +111,6 @@ // TODO(crbug.com/524927): Remove kPrefNeverPromptSites after // 3 milestones (M74). static const char kPrefNeverPromptSitesDeprecated[]; - static const char kPrefNeverPromptSitesWithTime[]; static const char kPrefTranslateDeniedCount[]; static const char kPrefTranslateIgnoredCount[]; static const char kPrefTranslateAcceptedCount[];
diff --git a/components/translate/core/browser/translate_prefs_unittest.cc b/components/translate/core/browser/translate_prefs_unittest.cc index b044fb44..51d4796 100644 --- a/components/translate/core/browser/translate_prefs_unittest.cc +++ b/components/translate/core/browser/translate_prefs_unittest.cc
@@ -943,7 +943,7 @@ 2u); // Also put one of those sites on the new pref but migrated incorrectly. DictionaryPrefUpdate never_prompt_list_update( - &prefs_, TranslatePrefs::kPrefNeverPromptSitesWithTime); + &prefs_, prefs::kPrefNeverPromptSitesWithTime); base::Value::Dict& never_prompt_list = never_prompt_list_update->GetDict(); never_prompt_list.Set("migratedWrong.com", 0); @@ -961,7 +961,7 @@ TEST_F(TranslatePrefsTest, InvalidNeverPromptSites) { // Add sites with invalid times. DictionaryPrefUpdate never_prompt_list_update( - &prefs_, TranslatePrefs::kPrefNeverPromptSitesWithTime); + &prefs_, prefs::kPrefNeverPromptSitesWithTime); base::Value::Dict& never_prompt_list = never_prompt_list_update->GetDict(); never_prompt_list.Set("not-a-string.com", 0); never_prompt_list.Set("not-a-valid-time.com", "foo");
diff --git a/components/translate/translate_internals/translate_internals_handler.cc b/components/translate/translate_internals/translate_internals_handler.cc index b5bca335..2d88f76 100644 --- a/components/translate/translate_internals/translate_internals_handler.cc +++ b/components/translate/translate_internals/translate_internals_handler.cc
@@ -241,7 +241,7 @@ prefs::kPrefAlwaysTranslateList, prefs::kPrefTranslateRecentTarget, translate::TranslatePrefs::kPrefNeverPromptSitesDeprecated, - translate::TranslatePrefs::kPrefNeverPromptSitesWithTime, + prefs::kPrefNeverPromptSitesWithTime, translate::TranslatePrefs::kPrefTranslateDeniedCount, translate::TranslatePrefs::kPrefTranslateIgnoredCount, translate::TranslatePrefs::kPrefTranslateAcceptedCount,
diff --git a/components/undo/bookmark_undo_service.cc b/components/undo/bookmark_undo_service.cc index 6fa3a3b..a4ccc71 100644 --- a/components/undo/bookmark_undo_service.cc +++ b/components/undo/bookmark_undo_service.cc
@@ -378,7 +378,8 @@ void BookmarkUndoService::BookmarkNodeAdded(BookmarkModel* model, const BookmarkNode* parent, - size_t index) { + size_t index, + bool added_by_user) { std::unique_ptr<UndoOperation> op( new BookmarkAddOperation(model, parent, index)); undo_manager()->AddUndoOperation(std::move(op));
diff --git a/components/undo/bookmark_undo_service.h b/components/undo/bookmark_undo_service.h index bdb9687..a3d6d7c 100644 --- a/components/undo/bookmark_undo_service.h +++ b/components/undo/bookmark_undo_service.h
@@ -54,7 +54,8 @@ size_t new_index) override; void BookmarkNodeAdded(bookmarks::BookmarkModel* model, const bookmarks::BookmarkNode* parent, - size_t index) override; + size_t index, + bool added_by_user) override; void OnWillChangeBookmarkNode(bookmarks::BookmarkModel* model, const bookmarks::BookmarkNode* node) override; void OnWillReorderBookmarkNode(bookmarks::BookmarkModel* model,
diff --git a/components/user_education/webui/help_bubble_handler.cc b/components/user_education/webui/help_bubble_handler.cc index 0b03dae2..0510828 100644 --- a/components/user_education/webui/help_bubble_handler.cc +++ b/components/user_education/webui/help_bubble_handler.cc
@@ -29,24 +29,41 @@ // Converts help bubble arrow to WebUI bubble position. This is not a complete // mapping as many HelpBubbleArrow options are not (yet) supported in WebUI. -help_bubble::mojom::HelpBubblePosition HelpBubbleArrowToPosition( +help_bubble::mojom::HelpBubbleArrowPosition HelpBubbleArrowToPosition( HelpBubbleArrow arrow) { switch (arrow) { case HelpBubbleArrow::kBottomLeft: + return help_bubble::mojom::HelpBubbleArrowPosition::BOTTOM_LEFT; case HelpBubbleArrow::kBottomCenter: + return help_bubble::mojom::HelpBubbleArrowPosition::BOTTOM_CENTER; case HelpBubbleArrow::kBottomRight: - return help_bubble::mojom::HelpBubblePosition::ABOVE; + return help_bubble::mojom::HelpBubbleArrowPosition::BOTTOM_RIGHT; + + case HelpBubbleArrow::kTopLeft: + return help_bubble::mojom::HelpBubbleArrowPosition::TOP_LEFT; + case HelpBubbleArrow::kTopCenter: + return help_bubble::mojom::HelpBubbleArrowPosition::TOP_CENTER; + case HelpBubbleArrow::kTopRight: + return help_bubble::mojom::HelpBubbleArrowPosition::TOP_RIGHT; + case HelpBubbleArrow::kLeftTop: + return help_bubble::mojom::HelpBubbleArrowPosition::LEFT_TOP; case HelpBubbleArrow::kLeftCenter: + return help_bubble::mojom::HelpBubbleArrowPosition::LEFT_CENTER; case HelpBubbleArrow::kLeftBottom: - return help_bubble::mojom::HelpBubblePosition::RIGHT; + return help_bubble::mojom::HelpBubbleArrowPosition::LEFT_BOTTOM; + case HelpBubbleArrow::kRightTop: + return help_bubble::mojom::HelpBubbleArrowPosition::RIGHT_TOP; case HelpBubbleArrow::kRightCenter: + return help_bubble::mojom::HelpBubbleArrowPosition::RIGHT_CENTER; case HelpBubbleArrow::kRightBottom: - return help_bubble::mojom::HelpBubblePosition::LEFT; + return help_bubble::mojom::HelpBubbleArrowPosition::RIGHT_BOTTOM; + default: - return help_bubble::mojom::HelpBubblePosition::BELOW; + NOTIMPLEMENTED(); } + return help_bubble::mojom::HelpBubbleArrowPosition::TOP_CENTER; } } // namespace
diff --git a/components/user_education/webui/help_bubble_handler_unittest.cc b/components/user_education/webui/help_bubble_handler_unittest.cc index f3c6a98..0eb0ea6 100644 --- a/components/user_education/webui/help_bubble_handler_unittest.cc +++ b/components/user_education/webui/help_bubble_handler_unittest.cc
@@ -224,7 +224,7 @@ expected->body_text = base::UTF16ToUTF8(params.body_text); expected->close_button_alt_text = base::UTF16ToUTF8(params.close_button_alt_text); - expected->position = help_bubble::mojom::HelpBubblePosition::BELOW; + expected->position = help_bubble::mojom::HelpBubbleArrowPosition::TOP_CENTER; EXPECT_CALL(test_handler_->mock(), ShowHelpBubble(MatchesHelpBubbleParams(expected.get()))); @@ -269,7 +269,7 @@ expected->body_text = base::UTF16ToUTF8(params.body_text); expected->close_button_alt_text = base::UTF16ToUTF8(params.close_button_alt_text); - expected->position = help_bubble::mojom::HelpBubblePosition::BELOW; + expected->position = help_bubble::mojom::HelpBubbleArrowPosition::TOP_CENTER; auto expected_button = help_bubble::mojom::HelpBubbleButtonParams::New(); expected_button->text = "button1";
diff --git a/components/viz/common/DEPS b/components/viz/common/DEPS index adbe40b2..1211a19 100644 --- a/components/viz/common/DEPS +++ b/components/viz/common/DEPS
@@ -6,6 +6,7 @@ "-mojo/public/cpp/bindings", # Exception is struct_traits.h which is used for defining friends only. "+cc/base", + "+cc/paint/filter_operations.h", "+mojo/public/cpp/bindings/struct_traits.h", "+third_party/perfetto/protos/perfetto/trace/track_event", "+third_party/skia",
diff --git a/components/viz/common/viz_utils.cc b/components/viz/common/viz_utils.cc index 6da7dc0..c933c89 100644 --- a/components/viz/common/viz_utils.cc +++ b/components/viz/common/viz_utils.cc
@@ -163,4 +163,18 @@ return gfx::ToEnclosingRect(ClippedQuadRectangleF(quad)); } +gfx::Rect GetExpandedRectWithPixelMovingForegroundFilter( + const DrawQuad& rpdq, + const cc::FilterOperations& filters) { + const SharedQuadState* shared_quad_state = rpdq.shared_quad_state; + float max_pixel_movement = filters.MaximumPixelMovement(); + gfx::RectF rect(rpdq.rect); + rect.Inset(-max_pixel_movement); + gfx::Rect expanded_rect = gfx::ToEnclosingRect(rect); + + // expanded_rect in the target space + return cc::MathUtil::MapEnclosingClippedRect( + shared_quad_state->quad_to_target_transform, expanded_rect); +} + } // namespace viz
diff --git a/components/viz/common/viz_utils.h b/components/viz/common/viz_utils.h index d07ab405..c1821c5 100644 --- a/components/viz/common/viz_utils.h +++ b/components/viz/common/viz_utils.h
@@ -6,6 +6,7 @@ #define COMPONENTS_VIZ_COMMON_VIZ_UTILS_H_ #include "base/timer/elapsed_timer.h" +#include "cc/paint/filter_operations.h" #include "components/viz/common/quads/draw_quad.h" #include "components/viz/common/viz_common_export.h" @@ -52,6 +53,12 @@ // Returns the smallest rectangle in target space that contains the quad. VIZ_COMMON_EXPORT gfx::Rect ClippedQuadRectangle(const DrawQuad* quad); VIZ_COMMON_EXPORT gfx::RectF ClippedQuadRectangleF(const DrawQuad* quad); + +// The expanded area that will be changed by a render pass draw quad with a +// pixel-moving foreground filter. +VIZ_COMMON_EXPORT gfx::Rect GetExpandedRectWithPixelMovingForegroundFilter( + const DrawQuad& rpdq, + const cc::FilterOperations& filters); } // namespace viz #endif // COMPONENTS_VIZ_COMMON_VIZ_UTILS_H_
diff --git a/components/viz/service/display/direct_renderer.cc b/components/viz/service/display/direct_renderer.cc index f86e099..647174a 100644 --- a/components/viz/service/display/direct_renderer.cc +++ b/components/viz/service/display/direct_renderer.cc
@@ -27,6 +27,7 @@ #include "components/viz/common/quads/compositor_render_pass_draw_quad.h" #include "components/viz/common/quads/draw_quad.h" #include "components/viz/common/quads/solid_color_draw_quad.h" +#include "components/viz/common/viz_utils.h" #include "components/viz/service/display/bsp_tree.h" #include "components/viz/service/display/bsp_walk_action.h" #include "components/viz/service/display/output_surface.h" @@ -249,8 +250,11 @@ // RenderPass owns filters, backdrop_filters, etc., and will outlive this // function call. So it is safe to store pointers in these maps. for (const auto& pass : *render_passes_in_draw_order) { - if (!pass->filters.IsEmpty()) + if (!pass->filters.IsEmpty()) { render_pass_filters_[pass->id] = &pass->filters; + if (pass->filters.HasFilterThatMovesPixels()) + has_pixel_moving_foreground_filters_ = true; + } if (!pass->backdrop_filters.IsEmpty()) { render_pass_backdrop_filters_[pass->id] = &pass->backdrop_filters; render_pass_backdrop_filter_bounds_[pass->id] = @@ -406,6 +410,7 @@ render_pass_backdrop_filter_bounds_.clear(); render_pass_bypass_quads_.clear(); backdrop_filter_output_rects_.clear(); + has_pixel_moving_foreground_filters_ = false; current_frame_valid_ = false; } @@ -792,27 +797,43 @@ root_damage_rect.Union(frame_buffer_damage); // If the root damage rect intersects any child render pass that has a - // pixel-moving backdrop-filter, expand the damage to include the entire + // pixel-moving backdrop filter, expand the damage to include the entire // child pass. See crbug.com/986206 for context. - if (!backdrop_filter_output_rects_.empty() && + if ((!backdrop_filter_output_rects_.empty() || + has_pixel_moving_foreground_filters_) && !root_damage_rect.IsEmpty()) { - for (auto* quad : render_pass->quad_list) { + for (auto* quad : root_render_pass->quad_list) { // Sanity check: we should not have a Compositor // CompositorRenderPassDrawQuad here. DCHECK_NE(quad->material, DrawQuad::Material::kCompositorRenderPass); if (quad->material == DrawQuad::Material::kAggregatedRenderPass) { - auto iter = backdrop_filter_output_rects_.find( - AggregatedRenderPassDrawQuad::MaterialCast(quad) - ->render_pass_id); - if (iter != backdrop_filter_output_rects_.end()) { - gfx::Rect this_output_rect = iter->second; - if (root_damage_rect.Intersects(this_output_rect)) - root_damage_rect.Union(this_output_rect); + const auto* rpdq = AggregatedRenderPassDrawQuad::MaterialCast(quad); + + // For render pass with pixel moving backdrop filters. + if (!backdrop_filter_output_rects_.empty()) { + auto iter = + backdrop_filter_output_rects_.find(rpdq->render_pass_id); + if (iter != backdrop_filter_output_rects_.end()) { + gfx::Rect this_output_rect = iter->second; + if (root_damage_rect.Intersects(this_output_rect)) + root_damage_rect.Union(this_output_rect); + } + } + + // For render pass with pixel moving foreground filters. + const cc::FilterOperations* foreground_filters = + FiltersForPass(rpdq->render_pass_id); + if (foreground_filters && + foreground_filters->HasFilterThatMovesPixels()) { + gfx::Rect expanded_rect = + GetExpandedRectWithPixelMovingForegroundFilter( + *rpdq, *foreground_filters); + if (root_damage_rect.Intersects(expanded_rect)) + root_damage_rect.Union(expanded_rect); } } } } - // Total damage after all adjustments. base::CheckedNumeric<int64_t> total_damage_area = root_damage_rect.size().GetCheckedArea();
diff --git a/components/viz/service/display/direct_renderer.h b/components/viz/service/display/direct_renderer.h index 88512df..c97bb8b 100644 --- a/components/viz/service/display/direct_renderer.h +++ b/components/viz/service/display/direct_renderer.h
@@ -331,6 +331,10 @@ base::flat_map<AggregatedRenderPassId, gfx::Rect> backdrop_filter_output_rects_; + // Whether a render pass with foreground filters that move pixels is found in + // this frame. + bool has_pixel_moving_foreground_filters_ = false; + bool visible_ = false; bool disable_color_checks_for_testing_ = false;
diff --git a/components/viz/service/display/display_unittest.cc b/components/viz/service/display/display_unittest.cc index 22e0c7a9..896a3636 100644 --- a/components/viz/service/display/display_unittest.cc +++ b/components/viz/service/display/display_unittest.cc
@@ -59,6 +59,7 @@ #include "components/viz/test/fake_skia_output_surface.h" #include "components/viz/test/mock_compositor_frame_sink_client.h" #include "components/viz/test/test_gles2_interface.h" +#include "components/viz/test/test_surface_id_allocator.h" #include "components/viz/test/viz_test_suite.h" #include "gpu/GLES2/gl2extchromium.h" #include "testing/gmock/include/gmock/gmock.h" @@ -4332,6 +4333,121 @@ } } +TEST_F(DisplayTest, PixelMovingForegroundFilterTest) { + RendererSettings settings; + settings.partial_swap_enabled = true; + id_allocator_.GenerateId(); + const LocalSurfaceId local_surface_id( + id_allocator_.GetCurrentLocalSurfaceId()); + + // Set up first display. + SetUpSoftwareDisplay(settings); + StubDisplayClient client; + display_->Initialize(&client, manager_.surface_manager()); + display_->SetLocalSurfaceId(local_surface_id, 1.f); + + // Create frame sink for a sub surface. + TestSurfaceIdAllocator sub_surface_id1(kAnotherFrameSinkId); + auto sub_support1 = std::make_unique<CompositorFrameSinkSupport>( + nullptr, &manager_, kAnotherFrameSinkId, /*is_root=*/false); + + // Create frame sink for another sub surface. + TestSurfaceIdAllocator sub_surface_id2(kAnotherFrameSinkId2); + auto sub_support2 = std::make_unique<CompositorFrameSinkSupport>( + nullptr, &manager_, kAnotherFrameSinkId2, /*is_root=*/false); + + // Main surface M, damage D, sub-surface B with foreground filter. + // +-----------+ + // | +----+ M| + // | |B +-|-+ | + // | +--|-+ | | + // | | D| | + // | +---+ | + // +-----------+ + const gfx::Size display_size(100, 100); + const gfx::Rect damage_rect(20, 20, 40, 40); + display_->Resize(display_size); + const gfx::Rect sub_surface_rect(5, 5, 25, 25); + const gfx::Rect no_damage; + + CompositorRenderPassId::Generator render_pass_id_generator; + for (size_t frame_num = 1; frame_num <= 2; ++frame_num) { + bool first_frame = frame_num == 1; + ResetDamageForTest(); + { + // Sub-surface with pixel-moving foreground filter - drop shadow filter + CompositorRenderPassList pass_list; + auto bd_pass = CompositorRenderPass::Create(); + cc::FilterOperations foreground_filters; + foreground_filters.Append(cc::FilterOperation::CreateDropShadowFilter( + gfx::Point(5, 10), 2.f, SkColors::kTransparent)); + bd_pass->SetAll( + render_pass_id_generator.GenerateNextId(), sub_surface_rect, + no_damage, gfx::Transform(), foreground_filters, + cc::FilterOperations(), gfx::RRectF(gfx::RectF(sub_surface_rect), 0), + SubtreeCaptureId(), sub_surface_rect.size(), + SharedElementResourceId(), false, false, false, false, false); + pass_list.push_back(std::move(bd_pass)); + + CompositorFrame frame = CompositorFrameBuilder() + .SetRenderPassList(std::move(pass_list)) + .Build(); + sub_support1->SubmitCompositorFrame(sub_surface_id1.local_surface_id(), + std::move(frame)); + } + + { + // Sub-surface with damage. + CompositorRenderPassList pass_list; + auto other_pass = CompositorRenderPass::Create(); + other_pass->output_rect = gfx::Rect(display_size); + other_pass->damage_rect = damage_rect; + other_pass->id = render_pass_id_generator.GenerateNextId(); + pass_list.push_back(std::move(other_pass)); + + CompositorFrame frame = CompositorFrameBuilder() + .SetRenderPassList(std::move(pass_list)) + .Build(); + sub_support2->SubmitCompositorFrame(sub_surface_id2.local_surface_id(), + std::move(frame)); + } + + { + auto frame = CompositorFrameBuilder() + .AddRenderPass( + RenderPassBuilder(display_size) + .AddSurfaceQuad( + sub_surface_rect, + SurfaceRange(absl::nullopt, sub_surface_id1), + {.allow_merge = false}) + .AddSurfaceQuad( + gfx::Rect(display_size), + SurfaceRange(absl::nullopt, sub_surface_id2), + {.allow_merge = false}) + .SetDamageRect(damage_rect)) + .Build(); + support_->SubmitCompositorFrame(local_surface_id, std::move(frame)); + + scheduler_->reset_swapped_for_test(); + display_->DrawAndSwap({base::TimeTicks::Now(), base::TimeTicks::Now()}); + EXPECT_TRUE(scheduler_->swapped()); + EXPECT_EQ(frame_num, output_surface_->num_sent_frames()); + EXPECT_EQ(display_size, software_output_device_->viewport_pixel_size()); + + auto expected_damage = + first_frame ? gfx::Rect(display_size) : damage_rect; + EXPECT_EQ(expected_damage, software_output_device_->damage_rect()); + // The scissor rect is expanded by direct_renderer to include the + // overlapping pixel-moving foreground filter surface. + auto expected_scissor_rect = + first_frame ? gfx::Rect(display_size) : gfx::Rect(0, 0, 60, 60); + EXPECT_EQ( + expected_scissor_rect, + display_->renderer_for_testing()->GetLastRootScissorRectForTesting()); + } + } +} + class SkiaDelegatedInkRendererTest : public DisplayTest { public: void SetUp() override { EnablePrediction(); }
diff --git a/components/viz/service/display/surface_aggregator.cc b/components/viz/service/display/surface_aggregator.cc index 764edcb..c62b4f7e 100644 --- a/components/viz/service/display/surface_aggregator.cc +++ b/components/viz/service/display/surface_aggregator.cc
@@ -128,20 +128,6 @@ return true; } -gfx::Rect GetExpandedRectWithPixelMovingForegroundFilter( - const CompositorRenderPassDrawQuad* rpdq, - const CompositorRenderPass& child_render_pass) { - const SharedQuadState* shared_quad_state = rpdq->shared_quad_state; - float max_pixel_movement = child_render_pass.filters.MaximumPixelMovement(); - gfx::RectF rect(rpdq->rect); - rect.Inset(-max_pixel_movement); - gfx::Rect expanded_rect = gfx::ToEnclosingRect(rect); - - // expanded_rect in the target space - return cc::MathUtil::MapEnclosingClippedRect( - shared_quad_state->quad_to_target_transform, expanded_rect); -} - // Create a clip rect for an aggregated quad from the original clip rect and // the clip rect from the surface it's on. absl::optional<gfx::Rect> CalculateClipRect( @@ -347,8 +333,8 @@ // The size of pixel-moving foreground filter is allowed to expand. // No intersecting shared_quad_state->clip_rect for the expanded rect. damage_rect_in_target_space = - GetExpandedRectWithPixelMovingForegroundFilter(render_pass_quad, - child_render_pass); + GetExpandedRectWithPixelMovingForegroundFilter( + *render_pass_quad, child_render_pass.filters); } else if (child_render_pass.backdrop_filters.HasFilterThatMovesPixels()) { const auto* shared_quad_state = render_pass_quad->shared_quad_state; damage_rect_in_target_space = cc::MathUtil::MapEnclosingClippedRect( @@ -1686,8 +1672,8 @@ // has pixel-moving foreground filter. if (child_render_pass.filters.HasFilterThatMovesPixels()) { gfx::Rect expanded_rect_in_target_space = - GetExpandedRectWithPixelMovingForegroundFilter(render_pass_quad, - child_render_pass); + GetExpandedRectWithPixelMovingForegroundFilter( + *render_pass_quad, child_render_pass.filters); if (expanded_rect_in_target_space.Intersects(damage_rect) || expanded_rect_in_target_space.Intersects(damage_from_parent) ||
diff --git a/content/BUILD.gn b/content/BUILD.gn index dc8fafb..a098bc6 100644 --- a/content/BUILD.gn +++ b/content/BUILD.gn
@@ -114,8 +114,10 @@ "dev_ui_content_resources.pak", ] deps = [ + "//content/browser/aggregation_service:mojo_bindings_webui_js", "//content/browser/attribution_reporting:mojo_bindings_webui_js", "//content/browser/preloading/prerender:mojo_bindings_webui_js", + "//content/browser/resources/aggregation_service:build_ts", "//content/browser/resources/attribution_reporting:build_ts", "//content/browser/resources/gpu:html_wrapper_files", "//content/browser/resources/process:build_ts",
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn index 1a71bab..993ec8ac 100644 --- a/content/browser/BUILD.gn +++ b/content/browser/BUILD.gn
@@ -391,6 +391,8 @@ "aggregation_service/aggregation_service_impl.h", "aggregation_service/aggregation_service_internals_handler_impl.cc", "aggregation_service/aggregation_service_internals_handler_impl.h", + "aggregation_service/aggregation_service_internals_ui.cc", + "aggregation_service/aggregation_service_internals_ui.h", "aggregation_service/aggregation_service_key_fetcher.cc", "aggregation_service/aggregation_service_key_fetcher.h", "aggregation_service/aggregation_service_network_fetcher_impl.cc",
diff --git a/content/browser/accessibility/browser_accessibility_manager.cc b/content/browser/accessibility/browser_accessibility_manager.cc index 2e692f4b..b1c4ad4 100644 --- a/content/browser/accessibility/browser_accessibility_manager.cc +++ b/content/browser/accessibility/browser_accessibility_manager.cc
@@ -1675,7 +1675,7 @@ } ui::AXNode* BrowserAccessibilityManager::GetNodeFromTree( - const ui::AXTreeID tree_id, + const ui::AXTreeID& tree_id, const ui::AXNodeID node_id) const { auto* manager = BrowserAccessibilityManager::FromID(tree_id); CHECK(manager);
diff --git a/content/browser/accessibility/browser_accessibility_manager.h b/content/browser/accessibility/browser_accessibility_manager.h index 4fea19ac..73f2bf1 100644 --- a/content/browser/accessibility/browser_accessibility_manager.h +++ b/content/browser/accessibility/browser_accessibility_manager.h
@@ -483,7 +483,7 @@ const std::vector<ui::AXTreeObserver::Change>& changes) override; // AXTreeManager overrides. - ui::AXNode* GetNodeFromTree(ui::AXTreeID tree_id, + ui::AXNode* GetNodeFromTree(const ui::AXTreeID& tree_id, ui::AXNodeID node_id) const override; ui::AXNode* GetNodeFromTree(ui::AXNodeID node_id) const override; ui::AXPlatformNode* GetPlatformNodeFromTree(
diff --git a/content/browser/aggregation_service/aggregation_service_impl.cc b/content/browser/aggregation_service/aggregation_service_impl.cc index ae68d2f..19d5f779 100644 --- a/content/browser/aggregation_service/aggregation_service_impl.cc +++ b/content/browser/aggregation_service/aggregation_service_impl.cc
@@ -188,6 +188,9 @@ return; } + // TODO(crbug.com/1354220): Consider checking with the browser client if + // reporting is allowed before sending. We don't currently have the top-frame + // origin to perform this check. base::Value value(report->GetAsJson()); SendReport(reporting_url, value, /*callback=*/
diff --git a/content/browser/aggregation_service/aggregation_service_internals_browsertest.cc b/content/browser/aggregation_service/aggregation_service_internals_browsertest.cc new file mode 100644 index 0000000..2764050 --- /dev/null +++ b/content/browser/aggregation_service/aggregation_service_internals_browsertest.cc
@@ -0,0 +1,390 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/aggregation_service/aggregation_service_internals_ui.h" + +#include <memory> +#include <string> +#include <utility> +#include <vector> + +#include "base/callback.h" +#include "base/memory/raw_ptr.h" +#include "base/observer_list.h" +#include "base/test/gmock_callback_support.h" +#include "base/time/time.h" +#include "content/browser/aggregation_service/aggregation_service.h" +#include "content/browser/aggregation_service/aggregation_service_observer.h" +#include "content/browser/aggregation_service/aggregation_service_storage.h" +#include "content/browser/aggregation_service/aggregation_service_test_utils.h" +#include "content/browser/storage_partition_impl.h" +#include "content/public/browser/browser_context.h" +#include "content/public/browser/web_contents.h" +#include "content/public/test/browser_test.h" +#include "content/public/test/content_browser_test.h" +#include "content/public/test/content_browser_test_utils.h" +#include "content/shell/browser/shell.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "third_party/abseil-cpp/absl/types/optional.h" +#include "url/gurl.h" + +namespace content { + +namespace { + +using GetPendingReportsCallback = base::OnceCallback<void( + std::vector<AggregationServiceStorage::RequestAndId>)>; + +constexpr char kPrivateAggregationInternalsUrl[] = + "chrome://private-aggregation-internals/"; + +const std::u16string kCompleteTitle = u"Complete"; + +class AggregationServiceInternalsWebUiBrowserTest : public ContentBrowserTest { + public: + AggregationServiceInternalsWebUiBrowserTest() = default; + + void SetUpOnMainThread() override { + ContentBrowserTest::SetUpOnMainThread(); + + auto aggregation_service = std::make_unique<MockAggregationService>(); + aggregation_service_ = aggregation_service.get(); + + ON_CALL(*aggregation_service_, GetPendingReportRequestsForWebUI) + .WillByDefault([](GetPendingReportsCallback callback) { + std::move(callback).Run( + AggregatableReportRequestsAndIdsBuilder().Build()); + }); + + static_cast<StoragePartitionImpl*>(shell() + ->web_contents() + ->GetBrowserContext() + ->GetDefaultStoragePartition()) + ->OverrideAggregationServiceForTesting(std::move(aggregation_service)); + } + + // Executing javascript in the WebUI requires using an isolated world in which + // to execute the script because WebUI has a default CSP policy denying + // "eval()", which is what EvalJs uses under the hood. + bool ExecJsInWebUI(const std::string& script) { + return ExecJs(shell()->web_contents()->GetPrimaryMainFrame(), script, + EXECUTE_SCRIPT_DEFAULT_OPTIONS, /*world_id=*/1); + } + + // Registers a mutation observer that sets the window title to `title` when + // the report table is empty. + void SetTitleOnReportsTableEmpty(const std::u16string& title) { + static constexpr char kObserveEmptyReportsTableScript[] = R"( + const table = document.querySelector('#reportTable') + .shadowRoot.querySelector('tbody'); + const obs = new MutationObserver((_, obs) => { + if (table.children.length === 1 && + table.children[0].children[0].textContent === 'No sent or pending reports.') { + obs.disconnect(); + document.title = $1; + } + }); + obs.observe(table, {'childList': true});)"; + EXPECT_TRUE( + ExecJsInWebUI(JsReplace(kObserveEmptyReportsTableScript, title))); + } + + void ClickRefreshButton() { + EXPECT_TRUE(ExecJsInWebUI("document.getElementById('refresh').click();")); + } + + protected: + raw_ptr<MockAggregationService> aggregation_service_; +}; + +IN_PROC_BROWSER_TEST_F(AggregationServiceInternalsWebUiBrowserTest, + NavigationUrl_ResolvedToWebUI) { + EXPECT_TRUE(NavigateToURL(shell(), GURL(kPrivateAggregationInternalsUrl))); + + EXPECT_EQ(true, EvalJs(shell()->web_contents()->GetPrimaryMainFrame(), + "document.body.innerHTML.includes('Private " + "Aggregation API Internals');", + EXECUTE_SCRIPT_DEFAULT_OPTIONS, /*world_id=*/1)); +} + +IN_PROC_BROWSER_TEST_F(AggregationServiceInternalsWebUiBrowserTest, + WebUIShownWithNoReports_NoReportsDisplayed) { + EXPECT_TRUE(NavigateToURL(shell(), GURL(kPrivateAggregationInternalsUrl))); + + TitleWatcher title_watcher(shell()->web_contents(), kCompleteTitle); + SetTitleOnReportsTableEmpty(kCompleteTitle); + ClickRefreshButton(); + EXPECT_EQ(kCompleteTitle, title_watcher.WaitAndGetTitle()); +} + +IN_PROC_BROWSER_TEST_F(AggregationServiceInternalsWebUiBrowserTest, + WebUIShownWithReports_ReportsDisplayed) { + EXPECT_TRUE(NavigateToURL(shell(), GURL(kPrivateAggregationInternalsUrl))); + + base::Time now = base::Time::Now(); + + ON_CALL(*aggregation_service_, GetPendingReportRequestsForWebUI) + .WillByDefault([now](GetPendingReportsCallback callback) { + std::move(callback).Run( + AggregatableReportRequestsAndIdsBuilder() + .AddRequestWithID( + aggregation_service::CreateExampleRequestWithReportTime( + now), + AggregationServiceStorage::RequestId(20)) + .Build()); + }); + + aggregation_service::TestHpkeKey hpke_key = + aggregation_service::GenerateKey("id123"); + + AggregatableReportRequest request_1 = + aggregation_service::CreateExampleRequest(); + absl::optional<AggregatableReport> report_1 = + AggregatableReport::Provider().CreateFromRequestAndPublicKeys( + request_1, {hpke_key.public_key}); + + aggregation_service_->NotifyReportHandled( + AggregationServiceStorage::RequestAndId{ + .request = std::move(request_1), + .id = AggregationServiceStorage::RequestId(1)}, + std::move(report_1), /*report_handled_time=*/now + base::Hours(1), + AggregationServiceObserver::ReportStatus::kSent); + + AggregatableReportRequest request_2 = + aggregation_service::CreateExampleRequest(); + aggregation_service_->NotifyReportHandled( + AggregationServiceStorage::RequestAndId{ + .request = std::move(request_2), + .id = AggregationServiceStorage::RequestId(2)}, + /*report=*/absl::nullopt, + /*report_handled_time=*/now + base::Hours(2), + AggregationServiceObserver::ReportStatus::kFailedToAssemble); + + AggregatableReportRequest request_3 = + aggregation_service::CreateExampleRequest(); + absl::optional<AggregatableReport> report_3 = + AggregatableReport::Provider().CreateFromRequestAndPublicKeys( + request_3, {hpke_key.public_key}); + + aggregation_service_->NotifyReportHandled( + AggregationServiceStorage::RequestAndId{ + .request = std::move(request_3), + .id = AggregationServiceStorage::RequestId(3)}, + std::move(report_3), + /*report_handled_time=*/now + base::Hours(3), + AggregationServiceObserver::ReportStatus::kFailedToSend); + + { + static constexpr char wait_script[] = R"( + const table = document.querySelector('#reportTable') + .shadowRoot.querySelector('tbody'); + const cell = (a, b) => table.children[a]?.children[b]?.textContent; + const obs = new MutationObserver((_, obs) => { + if (table.children.length === 4 && + cell(0, 1) === 'Pending' && + cell(0, 2) === 'https://reporting.example/example-path' && + cell(0, 3) === (new Date($2)).toLocaleString() && + cell(0, 4) === 'example-api' && + cell(0, 5) === '' && + cell(0, 6) === '[ { "bucket": { "high": "0", "low": "123" }, "value": 456 }]' && + cell(1, 1) === 'Sent' && + cell(2, 1) === 'Failed to assemble' && + cell(3, 1) === 'Failed to send') { + obs.disconnect(); + document.title = $1; + } + }); + obs.observe(table, {'childList': true});)"; + EXPECT_TRUE(ExecJsInWebUI( + JsReplace(wait_script, kCompleteTitle, (now).ToJsTime()))); + + TitleWatcher title_watcher(shell()->web_contents(), kCompleteTitle); + ClickRefreshButton(); + EXPECT_EQ(kCompleteTitle, title_watcher.WaitAndGetTitle()); + } + + { + static constexpr char wait_script[] = R"( + const table = document.querySelector('#reportTable') + .shadowRoot.querySelector('tbody'); + const cell = (a, b) => table.children[a]?.children[b]?.textContent; + const obs = new MutationObserver((_, obs) => { + if (table.children.length === 4 && + cell(0, 1) === 'Failed to assemble' && + cell(1, 1) === 'Failed to send' && + cell(2, 1) === 'Pending' && + cell(3, 1) === 'Sent') { + obs.disconnect(); + document.title = $1; + } + }); + obs.observe(table, {'childList': true});)"; + + const std::u16string kCompleteTitle2 = u"Complete2"; + EXPECT_TRUE(ExecJsInWebUI(JsReplace(wait_script, kCompleteTitle2))); + + TitleWatcher title_watcher(shell()->web_contents(), kCompleteTitle2); + // Sort by status ascending. + EXPECT_TRUE( + ExecJsInWebUI("document.querySelector('#reportTable')" + ".shadowRoot.querySelectorAll('th')[1].click();")); + EXPECT_EQ(kCompleteTitle2, title_watcher.WaitAndGetTitle()); + } + + { + static constexpr char wait_script[] = R"( + const table = document.querySelector('#reportTable') + .shadowRoot.querySelector('tbody'); + const cell = (a, b) => table.children[a]?.children[b]?.textContent; + const obs = new MutationObserver((_, obs) => { + if (table.children.length === 4 && + cell(0, 1) === 'Sent' && + cell(1, 1) === 'Pending' && + cell(2, 1) === 'Failed to send' && + cell(3, 1) === 'Failed to assemble') { + obs.disconnect(); + document.title = $1; + } + }); + obs.observe(table, {'childList': true});)"; + + const std::u16string kCompleteTitle3 = u"Complete3"; + EXPECT_TRUE(ExecJsInWebUI(JsReplace(wait_script, kCompleteTitle3))); + + TitleWatcher title_watcher(shell()->web_contents(), kCompleteTitle3); + // Sort by status descending. + EXPECT_TRUE( + ExecJsInWebUI("document.querySelector('#reportTable')" + ".shadowRoot.querySelectorAll('th')[1].click();")); + EXPECT_EQ(kCompleteTitle3, title_watcher.WaitAndGetTitle()); + } +} + +IN_PROC_BROWSER_TEST_F(AggregationServiceInternalsWebUiBrowserTest, + WebUISendReports_ReportsRemoved) { + EXPECT_CALL(*aggregation_service_, GetPendingReportRequestsForWebUI) + .WillOnce([](GetPendingReportsCallback callback) { + std::move(callback).Run( + AggregatableReportRequestsAndIdsBuilder().Build()); + }) // on page loaded + .WillOnce([](GetPendingReportsCallback callback) { + std::move(callback).Run( + AggregatableReportRequestsAndIdsBuilder() + .AddRequestWithID(aggregation_service::CreateExampleRequest(), + AggregationServiceStorage::RequestId(5)) + .Build()); + }) // on page refresh + .WillOnce([](GetPendingReportsCallback callback) { + std::move(callback).Run( + AggregatableReportRequestsAndIdsBuilder().Build()); + }); // on page updated + + EXPECT_TRUE(NavigateToURL(shell(), GURL(kPrivateAggregationInternalsUrl))); + + EXPECT_CALL(*aggregation_service_, + SendReportsForWebUI( + testing::ElementsAre(AggregationServiceStorage::RequestId(5)), + testing::_)) + .WillOnce(base::test::RunOnceCallback<1>()); + + static constexpr char wait_script[] = R"( + const table = document.querySelector('#reportTable') + .shadowRoot.querySelector('tbody'); + const obs = new MutationObserver((_, obs) => { + if (table.children.length === 1 && + table.children[0].children[1].textContent === 'Pending') { + obs.disconnect(); + document.title = $1; + } + }); + obs.observe(table, {'childList': true});)"; + EXPECT_TRUE(ExecJsInWebUI(JsReplace(wait_script, kCompleteTitle))); + + TitleWatcher title_watcher(shell()->web_contents(), kCompleteTitle); + ClickRefreshButton(); + EXPECT_EQ(kCompleteTitle, title_watcher.WaitAndGetTitle()); + + // Click the send reports button and expect that the report table is emptied. + const std::u16string kSentTitle = u"Sent"; + TitleWatcher sent_title_watcher(shell()->web_contents(), kSentTitle); + SetTitleOnReportsTableEmpty(kSentTitle); + + EXPECT_TRUE(ExecJsInWebUI( + R"(document.querySelector('#reportTable') + .shadowRoot.querySelector('input[type="checkbox"]').click();)")); + EXPECT_TRUE( + ExecJsInWebUI("document.getElementById('send-reports').click();")); + + // The real aggregation service would do this itself, but the test aggregation + // service requires manual triggering. + aggregation_service_->NotifyRequestStorageModified(); + + EXPECT_EQ(kSentTitle, sent_title_watcher.WaitAndGetTitle()); +} + +IN_PROC_BROWSER_TEST_F(AggregationServiceInternalsWebUiBrowserTest, + WebUIClearStorage_ReportsRemoved) { + EXPECT_TRUE(NavigateToURL(shell(), GURL(kPrivateAggregationInternalsUrl))); + + ON_CALL(*aggregation_service_, GetPendingReportRequestsForWebUI) + .WillByDefault([](GetPendingReportsCallback callback) { + std::move(callback).Run( + AggregatableReportRequestsAndIdsBuilder() + .AddRequestWithID(aggregation_service::CreateExampleRequest(), + AggregationServiceStorage::RequestId(5)) + .Build()); + }); + + aggregation_service::TestHpkeKey hpke_key = + aggregation_service::GenerateKey("id123"); + AggregatableReportRequest request = + aggregation_service::CreateExampleRequest(); + absl::optional<AggregatableReport> report = + AggregatableReport::Provider().CreateFromRequestAndPublicKeys( + request, {hpke_key.public_key}); + + aggregation_service_->NotifyReportHandled( + AggregationServiceStorage::RequestAndId{ + .request = std::move(request), + .id = AggregationServiceStorage::RequestId(10)}, + std::move(report), + /*report_handled_time=*/base::Time::Now() + base::Hours(1), + AggregationServiceObserver::ReportStatus::kSent); + + EXPECT_CALL(*aggregation_service_, ClearData) + .WillOnce(base::test::RunOnceCallback<3>()); + + // Verify both rows get rendered. + static constexpr char wait_script[] = R"( + const table = document.querySelector('#reportTable') + .shadowRoot.querySelector('tbody'); + const obs = new MutationObserver((_, obs) => { + if (table.children.length === 2 && + table.children[0].children[1].textContent === 'Pending' && + table.children[1].children[1].textContent === 'Sent') { + obs.disconnect(); + document.title = $1; + } + }); + obs.observe(table, {'childList': true});)"; + EXPECT_TRUE(ExecJsInWebUI(JsReplace(wait_script, kCompleteTitle))); + + // Wait for the table to be rendered. + TitleWatcher title_watcher(shell()->web_contents(), kCompleteTitle); + ClickRefreshButton(); + EXPECT_EQ(kCompleteTitle, title_watcher.WaitAndGetTitle()); + + // Click the send reports button and expect that the report table is emptied. + const std::u16string kDeleteTitle = u"Delete"; + TitleWatcher delete_title_watcher(shell()->web_contents(), kDeleteTitle); + SetTitleOnReportsTableEmpty(kDeleteTitle); + + EXPECT_TRUE(ExecJsInWebUI("document.getElementById('clear-data').click();")); + + EXPECT_EQ(kDeleteTitle, delete_title_watcher.WaitAndGetTitle()); +} + +} // namespace + +} // namespace content
diff --git a/content/browser/aggregation_service/aggregation_service_internals_ui.cc b/content/browser/aggregation_service/aggregation_service_internals_ui.cc new file mode 100644 index 0000000..9ac842c0 --- /dev/null +++ b/content/browser/aggregation_service/aggregation_service_internals_ui.cc
@@ -0,0 +1,66 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/aggregation_service/aggregation_service_internals_ui.h" + +#include <memory> +#include <utility> + +#include "content/browser/aggregation_service/aggregation_service_internals_handler_impl.h" +#include "content/grit/dev_ui_content_resources.h" +#include "content/public/browser/render_frame_host.h" +#include "content/public/browser/web_contents.h" +#include "content/public/browser/web_ui.h" +#include "content/public/browser/web_ui_data_source.h" +#include "content/public/common/bindings_policy.h" +#include "services/network/public/mojom/content_security_policy.mojom.h" + +namespace content { + +AggregationServiceInternalsUI::AggregationServiceInternalsUI(WebUI* web_ui) + : WebUIController(web_ui) { + // Initialize the UI with no bindings. Mojo bindings will be separately + // granted to frames within this WebContents. + web_ui->SetBindings(BINDINGS_POLICY_NONE); + WebUIDataSource* source = WebUIDataSource::CreateAndAdd( + web_ui->GetWebContents()->GetBrowserContext(), + kChromeUIPrivateAggregationInternalsHost); + + source->AddResourcePath("aggregation_service_internals.mojom-webui.js", + IDR_AGGREGATION_SERVICE_INTERNALS_MOJOM_JS); + source->AddResourcePath("aggregation_service_internals.js", + IDR_AGGREGATION_SERVICE_INTERNALS_JS); + source->AddResourcePath("aggregation_service_internals_table.js", + IDR_AGGREGATION_SERVICE_INTERNALS_TABLE_JS); + source->AddResourcePath("aggregation_service_internals_table.html.js", + IDR_AGGREGATION_SERVICE_INTERNALS_TABLE_HTML_JS); + source->AddResourcePath("table_model.js", + IDR_AGGREGATION_SERVICE_INTERNALS_TABLE_MODEL_JS); + source->AddResourcePath("aggregation_service_internals.css", + IDR_AGGREGATION_SERVICE_INTERNALS_CSS); + source->SetDefaultResource(IDR_AGGREGATION_SERVICE_INTERNALS_HTML); + source->OverrideContentSecurityPolicy( + network::mojom::CSPDirectiveName::TrustedTypes, + "trusted-types static-types;"); +} + +WEB_UI_CONTROLLER_TYPE_IMPL(AggregationServiceInternalsUI) + +AggregationServiceInternalsUI::~AggregationServiceInternalsUI() = default; + +void AggregationServiceInternalsUI::WebUIRenderFrameCreated( + RenderFrameHost* rfh) { + // Enable the JavaScript Mojo bindings in the renderer process, so the JS + // code can call the Mojo APIs exposed by this WebUI. + rfh->EnableMojoJsBindings(nullptr); +} + +void AggregationServiceInternalsUI::BindInterface( + mojo::PendingReceiver<aggregation_service_internals::mojom::Handler> + receiver) { + ui_handler_ = std::make_unique<AggregationServiceInternalsHandlerImpl>( + web_ui(), std::move(receiver)); +} + +} // namespace content
diff --git a/content/browser/aggregation_service/aggregation_service_internals_ui.h b/content/browser/aggregation_service/aggregation_service_internals_ui.h new file mode 100644 index 0000000..539be5ab --- /dev/null +++ b/content/browser/aggregation_service/aggregation_service_internals_ui.h
@@ -0,0 +1,58 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_AGGREGATION_SERVICE_AGGREGATION_SERVICE_INTERNALS_UI_H_ +#define CONTENT_BROWSER_AGGREGATION_SERVICE_AGGREGATION_SERVICE_INTERNALS_UI_H_ + +#include <memory> + +#include "content/browser/aggregation_service/aggregation_service_internals.mojom-forward.h" +#include "content/public/browser/web_ui_controller.h" +#include "content/public/browser/webui_config.h" +#include "content/public/common/url_constants.h" +#include "mojo/public/cpp/bindings/pending_receiver.h" + +namespace content { + +class AggregationServiceInternalsHandlerImpl; +class AggregationServiceInternalsUI; +class WebUI; + +// WebUIConfig for chrome://aggregation-service-internals page +class AggregationServiceInternalsUIConfig + : public DefaultWebUIConfig<AggregationServiceInternalsUI> { + public: + AggregationServiceInternalsUIConfig() + : DefaultWebUIConfig(kChromeUIScheme, + kChromeUIPrivateAggregationInternalsHost) {} +}; + +// WebUI which handles serving the chrome://aggregation-service-internals page. +class AggregationServiceInternalsUI : public WebUIController { + public: + explicit AggregationServiceInternalsUI(WebUI* web_ui); + AggregationServiceInternalsUI(const AggregationServiceInternalsUI&) = delete; + AggregationServiceInternalsUI(AggregationServiceInternalsUI&&) = delete; + AggregationServiceInternalsUI& operator=( + const AggregationServiceInternalsUI&) = delete; + AggregationServiceInternalsUI& operator=(AggregationServiceInternalsUI&&) = + delete; + ~AggregationServiceInternalsUI() override; + + // WebUIController overrides: + void WebUIRenderFrameCreated(RenderFrameHost* render_frame_host) override; + + void BindInterface( + mojo::PendingReceiver<aggregation_service_internals::mojom::Handler> + receiver); + + private: + std::unique_ptr<AggregationServiceInternalsHandlerImpl> ui_handler_; + + WEB_UI_CONTROLLER_TYPE_DECL(); +}; + +} // namespace content + +#endif // CONTENT_BROWSER_AGGREGATION_SERVICE_AGGREGATION_SERVICE_INTERNALS_UI_H_
diff --git a/content/browser/aggregation_service/aggregation_service_test_utils.cc b/content/browser/aggregation_service/aggregation_service_test_utils.cc index fe141c0..0a975be 100644 --- a/content/browser/aggregation_service/aggregation_service_test_utils.cc +++ b/content/browser/aggregation_service/aggregation_service_test_utils.cc
@@ -213,6 +213,13 @@ AggregatableReportRequest CreateExampleRequest( mojom::AggregationServiceMode aggregation_mode) { + return CreateExampleRequestWithReportTime(base::Time::Now(), + aggregation_mode); +} + +AggregatableReportRequest CreateExampleRequestWithReportTime( + base::Time report_time, + mojom::AggregationServiceMode aggregation_mode) { return AggregatableReportRequest::Create( AggregationServicePayloadContents( AggregationServicePayloadContents::Operation::kHistogram, @@ -221,7 +228,7 @@ /*value=*/456)}, aggregation_mode), AggregatableReportSharedInfo( - /*scheduled_report_time=*/base::Time::Now(), + /*scheduled_report_time=*/report_time, /*report_id=*/ base::GUID::GenerateRandomV4(), url::Origin::Create(GURL("https://reporting.example")),
diff --git a/content/browser/aggregation_service/aggregation_service_test_utils.h b/content/browser/aggregation_service/aggregation_service_test_utils.h index 304b7aab..9c6e3d7 100644 --- a/content/browser/aggregation_service/aggregation_service_test_utils.h +++ b/content/browser/aggregation_service/aggregation_service_test_utils.h
@@ -69,6 +69,11 @@ mojom::AggregationServiceMode aggregation_mode = mojom::AggregationServiceMode::kDefault); +AggregatableReportRequest CreateExampleRequestWithReportTime( + base::Time report_time, + mojom::AggregationServiceMode aggregation_mode = + mojom::AggregationServiceMode::kDefault); + AggregatableReportRequest CloneReportRequest( const AggregatableReportRequest& request); AggregatableReport CloneAggregatableReport(const AggregatableReport& report);
diff --git a/content/browser/bad_message.h b/content/browser/bad_message.h index abcc0ca..7ff2810 100644 --- a/content/browser/bad_message.h +++ b/content/browser/bad_message.h
@@ -308,6 +308,7 @@ MSDH_REQUEST_ALL_SCREENS_NOT_ALLOWED_FOR_ORIGIN = 281, RFHI_CREATE_FENCED_FRAME_BAD_FRAME_TOKEN = 282, RFHI_CREATE_FENCED_FRAME_BAD_DEVTOOLS_FRAME_TOKEN = 283, + FF_FROZEN_SANDBOX_FLAGS_CHANGED = 284, // Please add new elements here. The naming convention is abbreviated class // name (e.g. RenderFrameHost becomes RFH) plus a unique description of the
diff --git a/content/browser/browser_interface_binders.cc b/content/browser/browser_interface_binders.cc index 15debe2..8566ac7 100644 --- a/content/browser/browser_interface_binders.cc +++ b/content/browser/browser_interface_binders.cc
@@ -13,6 +13,8 @@ #include "build/branding_buildflags.h" #include "build/build_config.h" #include "cc/base/switches.h" +#include "content/browser/aggregation_service/aggregation_service_internals.mojom.h" +#include "content/browser/aggregation_service/aggregation_service_internals_ui.h" #include "content/browser/attribution_reporting/attribution_internals.mojom.h" #include "content/browser/attribution_reporting/attribution_internals_ui.h" #include "content/browser/background_fetch/background_fetch_service_impl.h" @@ -1044,6 +1046,9 @@ map->Add<device::mojom::VRService>( base::BindRepeating(&EmptyBinderForFrame<device::mojom::VRService>)); #endif + RegisterWebUIControllerInterfaceBinder< + aggregation_service_internals::mojom::Handler, + AggregationServiceInternalsUI>(map); RegisterWebUIControllerInterfaceBinder<attribution_internals::mojom::Handler, AttributionInternalsUI>(map); RegisterWebUIControllerInterfaceBinder<mojom::PrerenderInternalsHandler,
diff --git a/content/browser/first_party_sets/database/first_party_sets_database.cc b/content/browser/first_party_sets/database/first_party_sets_database.cc index fff7688..6a93f5b 100644 --- a/content/browser/first_party_sets/database/first_party_sets_database.cc +++ b/content/browser/first_party_sets/database/first_party_sets_database.cc
@@ -17,6 +17,7 @@ #include "base/metrics/histogram_functions.h" #include "content/browser/first_party_sets/first_party_set_parser.h" #include "net/base/schemeful_site.h" +#include "net/cookies/first_party_set_entry.h" #include "sql/database.h" #include "sql/error_delegate_util.h" #include "sql/meta_table.h" @@ -148,7 +149,8 @@ bool FirstPartySetsDatabase::InsertPolicyModifications( const std::string& browser_context_id, const base::flat_map<net::SchemefulSite, - absl::optional<net::SchemefulSite>>& modificatons) { + absl::optional<net::FirstPartySetEntry>>& + modificatons) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (!LazyInit()) @@ -175,7 +177,7 @@ statement.BindString(0, browser_context_id); statement.BindString(1, site.Serialize()); if (owner.has_value()) { - statement.BindString(2, owner.value().Serialize()); + statement.BindString(2, owner.value().primary().Serialize()); } else { statement.BindNull(2); } @@ -263,7 +265,7 @@ return results; } -base::flat_map<net::SchemefulSite, absl::optional<net::SchemefulSite>> +base::flat_map<net::SchemefulSite, absl::optional<net::FirstPartySetEntry>> FirstPartySetsDatabase::FetchPolicyModifications( const std::string& browser_context_id) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); @@ -271,7 +273,7 @@ if (!LazyInit()) return {}; - base::flat_map<net::SchemefulSite, absl::optional<net::SchemefulSite>> + base::flat_map<net::SchemefulSite, absl::optional<net::FirstPartySetEntry>> results; static constexpr char kSelectSql[] = // clang-format off @@ -294,8 +296,19 @@ // TODO(crbug/1314039): Invalid sites should be rare case but possible. // Consider deleting them from DB. - if (site.has_value()) - results.emplace(std::move(site.value()), maybe_site_owner); + if (site.has_value()) { + results.emplace( + std::move(site.value()), + maybe_site_owner.has_value() + ? absl::make_optional(net::FirstPartySetEntry( + maybe_site_owner.value(), + // TODO(https://crbug.com/1219656): May change to use the + // real site_type and site_index in the future, depending on + // the design details. Use kAssociated as default site type + // and null site index for now. + net::SiteType::kAssociated, absl::nullopt)) + : absl::nullopt); + } } return results; }
diff --git a/content/browser/first_party_sets/database/first_party_sets_database.h b/content/browser/first_party_sets/database/first_party_sets_database.h index ba7d8131..9c1adf3 100644 --- a/content/browser/first_party_sets/database/first_party_sets_database.h +++ b/content/browser/first_party_sets/database/first_party_sets_database.h
@@ -19,6 +19,7 @@ namespace net { class SchemefulSite; +class FirstPartySetEntry; } // namespace net namespace sql { @@ -80,7 +81,8 @@ [[nodiscard]] bool InsertPolicyModifications( const std::string& browser_context_id, const base::flat_map<net::SchemefulSite, - absl::optional<net::SchemefulSite>>& modificatons); + absl::optional<net::FirstPartySetEntry>>& + modificatons); // Gets the list of sites to clear for the `browser_context_id`. [[nodiscard]] std::vector<net::SchemefulSite> FetchSitesToClear( @@ -95,7 +97,7 @@ // Gets the previously-stored policy modifications for the // `browser_context_id`. [[nodiscard]] base::flat_map<net::SchemefulSite, - absl::optional<net::SchemefulSite>> + absl::optional<net::FirstPartySetEntry>> FetchPolicyModifications(const std::string& browser_context_id); private:
diff --git a/content/browser/first_party_sets/database/first_party_sets_database_unittest.cc b/content/browser/first_party_sets/database/first_party_sets_database_unittest.cc index efe00c9..44406dd 100644 --- a/content/browser/first_party_sets/database/first_party_sets_database_unittest.cc +++ b/content/browser/first_party_sets/database/first_party_sets_database_unittest.cc
@@ -11,6 +11,7 @@ #include "base/path_service.h" #include "base/test/metrics/histogram_tester.h" #include "net/base/schemeful_site.h" +#include "net/cookies/first_party_set_entry.h" #include "sql/database.h" #include "sql/statement.h" #include "sql/test/test_helpers.h" @@ -393,10 +394,12 @@ const std::string site_member1 = "https://member1.test"; const std::string site_member2 = "https://member2.test"; - base::flat_map<net::SchemefulSite, absl::optional<net::SchemefulSite>> input = - {{net::SchemefulSite(GURL(site_member1)), - net::SchemefulSite(GURL(site_owner))}, - {net::SchemefulSite(GURL(site_member2)), absl::nullopt}}; + base::flat_map<net::SchemefulSite, absl::optional<net::FirstPartySetEntry>> + input = { + {net::SchemefulSite(GURL(site_member1)), + net::FirstPartySetEntry(net::SchemefulSite(GURL(site_owner)), + net::SiteType::kAssociated, absl::nullopt)}, + {net::SchemefulSite(GURL(site_member2)), absl::nullopt}}; OpenDatabase(); // Trigger the lazy-initialization. @@ -456,10 +459,12 @@ const std::string site_member1 = "https://member3.test"; const std::string site_member2 = "https://member4.test"; - base::flat_map<net::SchemefulSite, absl::optional<net::SchemefulSite>> input = - {{net::SchemefulSite(GURL(site_member1)), - net::SchemefulSite(GURL(site_owner))}, - {net::SchemefulSite(GURL(site_member2)), absl::nullopt}}; + base::flat_map<net::SchemefulSite, absl::optional<net::FirstPartySetEntry>> + input = { + {net::SchemefulSite(GURL(site_member1)), + net::FirstPartySetEntry(net::SchemefulSite(GURL(site_owner)), + net::SiteType::kAssociated, absl::nullopt)}, + {net::SchemefulSite(GURL(site_member2)), absl::nullopt}}; OpenDatabase(); // Trigger the lazy-initialization. @@ -632,11 +637,14 @@ EXPECT_EQ(kTableCount, sql::test::CountSQLTables(&db)); EXPECT_EQ(2u, CountPolicyModificationsEntries(&db)); } - base::flat_map<net::SchemefulSite, absl::optional<net::SchemefulSite>> res = { - {net::SchemefulSite(GURL("https://member1.test")), - {net::SchemefulSite(GURL("https://example.test"))}}, - {net::SchemefulSite(GURL("https://member2.test")), absl::nullopt}, - }; + base::flat_map<net::SchemefulSite, absl::optional<net::FirstPartySetEntry>> + res = { + {net::SchemefulSite(GURL("https://member1.test")), + net::FirstPartySetEntry( + {net::SchemefulSite(GURL("https://example.test"))}, + net::SiteType::kAssociated, absl::nullopt)}, + {net::SchemefulSite(GURL("https://member2.test")), absl::nullopt}, + }; OpenDatabase(); EXPECT_THAT(db()->FetchPolicyModifications("b2"), res); }
diff --git a/content/browser/interest_group/ad_auction_service_impl.cc b/content/browser/interest_group/ad_auction_service_impl.cc index 60015c4..674de83 100644 --- a/content/browser/interest_group/ad_auction_service_impl.cc +++ b/content/browser/interest_group/ad_auction_service_impl.cc
@@ -467,7 +467,8 @@ for (auto& [origin, requests] : private_aggregation_requests) { mojo::Remote<mojom::PrivateAggregationHost> remote; if (!private_aggregation_manager_->BindNewReceiver( - origin, PrivateAggregationBudgetKey::Api::kFledge, + origin, main_frame_origin_, + PrivateAggregationBudgetKey::Api::kFledge, remote.BindNewPipeAndPassReceiver())) { continue; }
diff --git a/content/browser/interest_group/ad_auction_service_impl_unittest.cc b/content/browser/interest_group/ad_auction_service_impl_unittest.cc index 541289d..b24c1be7 100644 --- a/content/browser/interest_group/ad_auction_service_impl_unittest.cc +++ b/content/browser/interest_group/ad_auction_service_impl_unittest.cc
@@ -5638,13 +5638,14 @@ PrivateAggregationBudgetKey)> mock_callback; - static_cast<StoragePartitionImpl*>( - browser_context()->GetDefaultStoragePartition()) - ->OverridePrivateAggregationManagerForTesting( - std::make_unique<TestPrivateAggregationManagerImpl>( - std::make_unique<MockPrivateAggregationBudgeter>(), - std::make_unique<PrivateAggregationHost>( - /*on_report_request_received=*/mock_callback.Get()))); + auto* storage_partition_impl = static_cast<StoragePartitionImpl*>( + browser_context()->GetDefaultStoragePartition()); + storage_partition_impl->OverridePrivateAggregationManagerForTesting( + std::make_unique<TestPrivateAggregationManagerImpl>( + std::make_unique<MockPrivateAggregationBudgeter>(), + std::make_unique<PrivateAggregationHost>( + /*on_report_request_received=*/mock_callback.Get(), + /*browser_context=*/storage_partition_impl->browser_context()))); network_responder_->RegisterScriptResponse(kBiddingUrlPath, kBiddingScript); network_responder_->RegisterScriptResponse(kDecisionUrlPath, kDecisionScript);
diff --git a/content/browser/private_aggregation/private_aggregation_host.cc b/content/browser/private_aggregation/private_aggregation_host.cc index f3d8d83..2f5a1a57 100644 --- a/content/browser/private_aggregation/private_aggregation_host.cc +++ b/content/browser/private_aggregation/private_aggregation_host.cc
@@ -19,6 +19,8 @@ #include "content/browser/private_aggregation/private_aggregation_budget_key.h" #include "content/common/aggregatable_report.mojom.h" #include "content/common/private_aggregation_host.mojom.h" +#include "content/public/browser/content_browser_client.h" +#include "content/public/common/content_client.h" #include "mojo/public/cpp/bindings/message.h" #include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/cpp/bindings/receiver_set.h" @@ -42,19 +44,25 @@ struct PrivateAggregationHost::ReceiverContext { url::Origin worklet_origin; + url::Origin top_frame_origin; PrivateAggregationBudgetKey::Api api_for_budgeting; }; PrivateAggregationHost::PrivateAggregationHost( base::RepeatingCallback<void(AggregatableReportRequest, PrivateAggregationBudgetKey)> - on_report_request_received) - : on_report_request_received_(std::move(on_report_request_received)) {} + on_report_request_received, + BrowserContext* browser_context) + : on_report_request_received_(std::move(on_report_request_received)), + browser_context_(*browser_context) { + DCHECK(!on_report_request_received_.is_null()); +} PrivateAggregationHost::~PrivateAggregationHost() = default; bool PrivateAggregationHost::BindNewReceiver( url::Origin worklet_origin, + url::Origin top_frame_origin, PrivateAggregationBudgetKey::Api api_for_budgeting, mojo::PendingReceiver<mojom::PrivateAggregationHost> pending_receiver) { if (!network::IsOriginPotentiallyTrustworthy(worklet_origin)) { @@ -62,9 +70,11 @@ // its requests are processed. return false; } - receiver_set_.Add(this, std::move(pending_receiver), - ReceiverContext{.worklet_origin = std::move(worklet_origin), - .api_for_budgeting = api_for_budgeting}); + receiver_set_.Add( + this, std::move(pending_receiver), + ReceiverContext{.worklet_origin = std::move(worklet_origin), + .top_frame_origin = std::move(top_frame_origin), + .api_for_budgeting = api_for_budgeting}); return true; } @@ -82,6 +92,12 @@ receiver_set_.current_context().worklet_origin; DCHECK(network::IsOriginPotentiallyTrustworthy(reporting_origin)); + if (!GetContentClient()->browser()->IsPrivateAggregationAllowed( + &*browser_context_, receiver_set_.current_context().top_frame_origin, + reporting_origin)) { + return; + } + // Null pointers should fail mojo validation. DCHECK(base::ranges::none_of( contribution_ptrs,
diff --git a/content/browser/private_aggregation/private_aggregation_host.h b/content/browser/private_aggregation/private_aggregation_host.h index 4157534e..019f273 100644 --- a/content/browser/private_aggregation/private_aggregation_host.h +++ b/content/browser/private_aggregation/private_aggregation_host.h
@@ -8,6 +8,7 @@ #include <vector> #include "base/callback.h" +#include "base/memory/raw_ref.h" #include "content/browser/private_aggregation/private_aggregation_budget_key.h" #include "content/common/content_export.h" #include "content/common/private_aggregation_host.mojom.h" @@ -21,6 +22,7 @@ namespace content { class AggregatableReportRequest; +class BrowserContext; // UI thread class responsible for implementing the mojo interface used by // worklets and renderers to request reports be sent and maintaining the @@ -39,10 +41,12 @@ // Aligns with `blink::kMaxAttributionAggregationKeysPerSourceOrTrigger`. static constexpr int kMaxNumberOfContributions = 50; - explicit PrivateAggregationHost( + // `on_report_request_received` and `browser_context` must be non-null. + PrivateAggregationHost( base::RepeatingCallback<void(AggregatableReportRequest, PrivateAggregationBudgetKey)> - on_report_request_received); + on_report_request_received, + BrowserContext* browser_context); PrivateAggregationHost(const PrivateAggregationHost&) = delete; PrivateAggregationHost& operator=(const PrivateAggregationHost&) = delete; ~PrivateAggregationHost() override; @@ -53,6 +57,7 @@ // receiver was accepted. Virtual for testing. [[nodiscard]] virtual bool BindNewReceiver( url::Origin worklet_origin, + url::Origin top_frame_origin, PrivateAggregationBudgetKey::Api api_for_budgeting, mojo::PendingReceiver<mojom::PrivateAggregationHost> pending_receiver); @@ -71,6 +76,10 @@ mojo::ReceiverSet<mojom::PrivateAggregationHost, ReceiverContext> receiver_set_; + + // `this` is indirectly owned by the StoragePartitionImpl, which itself is + // owned by `browser_context_`. + raw_ref<BrowserContext> browser_context_; }; } // namespace content
diff --git a/content/browser/private_aggregation/private_aggregation_host_unittest.cc b/content/browser/private_aggregation/private_aggregation_host_unittest.cc index aadc799..a16e9a5 100644 --- a/content/browser/private_aggregation/private_aggregation_host_unittest.cc +++ b/content/browser/private_aggregation/private_aggregation_host_unittest.cc
@@ -18,8 +18,12 @@ #include "content/browser/aggregation_service/aggregatable_report.h" #include "content/browser/aggregation_service/aggregation_service_test_utils.h" #include "content/browser/private_aggregation/private_aggregation_budget_key.h" +#include "content/browser/private_aggregation/private_aggregation_test_utils.h" #include "content/common/aggregatable_report.mojom.h" #include "content/common/private_aggregation_host.mojom.h" +#include "content/public/test/browser_task_environment.h" +#include "content/public/test/test_browser_context.h" +#include "content/public/test/test_utils.h" #include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/cpp/bindings/remote.h" #include "testing/gmock/include/gmock/gmock.h" @@ -42,7 +46,8 @@ void SetUp() override { host_ = std::make_unique<PrivateAggregationHost>( - /*on_report_request_received=*/mock_callback_.Get()); + /*on_report_request_received=*/mock_callback_.Get(), + /*browser_context=*/&test_browser_context_); } void TearDown() override { host_.reset(); } @@ -54,8 +59,9 @@ std::unique_ptr<PrivateAggregationHost> host_; private: - base::test::TaskEnvironment task_environment_{ + BrowserTaskEnvironment task_environment_{ base::test::TaskEnvironment::TimeSource::MOCK_TIME}; + TestBrowserContext test_browser_context_; }; } // namespace @@ -64,9 +70,11 @@ SendHistogramReport_ReportRequestHasCorrectMembers) { const url::Origin kExampleOrigin = url::Origin::Create(GURL("https://example.com")); + const url::Origin kMainFrameOrigin = + url::Origin::Create(GURL("https://main_frame.com")); mojo::Remote<mojom::PrivateAggregationHost> remote; - EXPECT_TRUE(host_->BindNewReceiver(kExampleOrigin, + EXPECT_TRUE(host_->BindNewReceiver(kExampleOrigin, kMainFrameOrigin, PrivateAggregationBudgetKey::Api::kFledge, remote.BindNewPipeAndPassReceiver())); @@ -122,6 +130,8 @@ TEST_F(PrivateAggregationHostTest, ReportingPath) { const url::Origin kExampleOrigin = url::Origin::Create(GURL("https://example.com")); + const url::Origin kMainFrameOrigin = + url::Origin::Create(GURL("https://main_frame.com")); const PrivateAggregationBudgetKey::Api apis[] = { PrivateAggregationBudgetKey::Api::kFledge, @@ -132,8 +142,9 @@ /*n=*/2}; for (int i = 0; i < 2; i++) { - EXPECT_TRUE(host_->BindNewReceiver( - kExampleOrigin, apis[i], remotes[i].BindNewPipeAndPassReceiver())); + EXPECT_TRUE( + host_->BindNewReceiver(kExampleOrigin, kMainFrameOrigin, apis[i], + remotes[i].BindNewPipeAndPassReceiver())); EXPECT_CALL(mock_callback_, Run(_, Property(&PrivateAggregationBudgetKey::api, apis[i]))) .WillOnce(MoveArg<0>(&validated_requests[i])); @@ -163,21 +174,25 @@ url::Origin::Create(GURL("https://a.example")); const url::Origin kExampleOriginB = url::Origin::Create(GURL("https://b.example")); + const url::Origin kMainFrameOrigin = + url::Origin::Create(GURL("https://main_frame.com")); std::vector<mojo::Remote<mojom::PrivateAggregationHost>> remotes(/*n=*/4); - EXPECT_TRUE(host_->BindNewReceiver(kExampleOriginA, + EXPECT_TRUE(host_->BindNewReceiver(kExampleOriginA, kMainFrameOrigin, PrivateAggregationBudgetKey::Api::kFledge, remotes[0].BindNewPipeAndPassReceiver())); - EXPECT_TRUE(host_->BindNewReceiver(kExampleOriginB, + EXPECT_TRUE(host_->BindNewReceiver(kExampleOriginB, kMainFrameOrigin, PrivateAggregationBudgetKey::Api::kFledge, remotes[1].BindNewPipeAndPassReceiver())); - EXPECT_TRUE(host_->BindNewReceiver( - kExampleOriginA, PrivateAggregationBudgetKey::Api::kSharedStorage, - remotes[2].BindNewPipeAndPassReceiver())); - EXPECT_TRUE(host_->BindNewReceiver( - kExampleOriginB, PrivateAggregationBudgetKey::Api::kSharedStorage, - remotes[3].BindNewPipeAndPassReceiver())); + EXPECT_TRUE( + host_->BindNewReceiver(kExampleOriginA, kMainFrameOrigin, + PrivateAggregationBudgetKey::Api::kSharedStorage, + remotes[2].BindNewPipeAndPassReceiver())); + EXPECT_TRUE( + host_->BindNewReceiver(kExampleOriginB, kMainFrameOrigin, + PrivateAggregationBudgetKey::Api::kSharedStorage, + remotes[3].BindNewPipeAndPassReceiver())); // Use the bucket as a sentinel to ensure that calls were routed correctly. EXPECT_CALL(mock_callback_, @@ -233,14 +248,16 @@ const url::Origin kInsecureOrigin = url::Origin::Create(GURL("http://example.com")); const url::Origin kOpaqueOrigin; + const url::Origin kMainFrameOrigin = + url::Origin::Create(GURL("https://main_frame.com")); mojo::Remote<mojom::PrivateAggregationHost> remote_1; - EXPECT_FALSE(host_->BindNewReceiver(kInsecureOrigin, + EXPECT_FALSE(host_->BindNewReceiver(kInsecureOrigin, kMainFrameOrigin, PrivateAggregationBudgetKey::Api::kFledge, remote_1.BindNewPipeAndPassReceiver())); mojo::Remote<mojom::PrivateAggregationHost> remote_2; - EXPECT_FALSE(host_->BindNewReceiver(kOpaqueOrigin, + EXPECT_FALSE(host_->BindNewReceiver(kOpaqueOrigin, kMainFrameOrigin, PrivateAggregationBudgetKey::Api::kFledge, remote_2.BindNewPipeAndPassReceiver())); @@ -264,9 +281,11 @@ TEST_F(PrivateAggregationHostTest, InvalidRequest_Rejected) { const url::Origin kExampleOrigin = url::Origin::Create(GURL("https://example.com")); + const url::Origin kMainFrameOrigin = + url::Origin::Create(GURL("https://main_frame.com")); mojo::Remote<mojom::PrivateAggregationHost> remote; - EXPECT_TRUE(host_->BindNewReceiver(kExampleOrigin, + EXPECT_TRUE(host_->BindNewReceiver(kExampleOrigin, kMainFrameOrigin, PrivateAggregationBudgetKey::Api::kFledge, remote.BindNewPipeAndPassReceiver())); @@ -294,4 +313,64 @@ remote.FlushForTesting(); } +TEST_F(PrivateAggregationHostTest, PrivateAggregationAllowed_RequestSucceeds) { + MockPrivateAggregationContentBrowserClient browser_client; + ScopedContentBrowserClientSetting setting(&browser_client); + + const url::Origin kExampleOrigin = + url::Origin::Create(GURL("https://example.com")); + const url::Origin kMainFrameOrigin = + url::Origin::Create(GURL("https://main_frame.com")); + + mojo::Remote<mojom::PrivateAggregationHost> remote; + EXPECT_TRUE(host_->BindNewReceiver(kExampleOrigin, kMainFrameOrigin, + PrivateAggregationBudgetKey::Api::kFledge, + remote.BindNewPipeAndPassReceiver())); + + // If the API is enabled, the call should succeed. + EXPECT_CALL(browser_client, + IsPrivateAggregationAllowed(_, kMainFrameOrigin, kExampleOrigin)) + .WillOnce(testing::Return(true)); + EXPECT_CALL(mock_callback_, Run); + + std::vector<mojom::AggregatableReportHistogramContributionPtr> contributions; + contributions.push_back(mojom::AggregatableReportHistogramContribution::New( + /*bucket=*/123, /*value=*/456)); + remote->SendHistogramReport(std::move(contributions), + mojom::AggregationServiceMode::kDefault); + + remote.FlushForTesting(); + EXPECT_TRUE(remote.is_connected()); +} + +TEST_F(PrivateAggregationHostTest, PrivateAggregationDisallowed_RequestFails) { + MockPrivateAggregationContentBrowserClient browser_client; + ScopedContentBrowserClientSetting setting(&browser_client); + + const url::Origin kExampleOrigin = + url::Origin::Create(GURL("https://example.com")); + const url::Origin kMainFrameOrigin = + url::Origin::Create(GURL("https://main_frame.com")); + + mojo::Remote<mojom::PrivateAggregationHost> remote; + EXPECT_TRUE(host_->BindNewReceiver(kExampleOrigin, kMainFrameOrigin, + PrivateAggregationBudgetKey::Api::kFledge, + remote.BindNewPipeAndPassReceiver())); + + // If the API is enabled, the call should succeed. + EXPECT_CALL(browser_client, + IsPrivateAggregationAllowed(_, kMainFrameOrigin, kExampleOrigin)) + .WillOnce(testing::Return(false)); + EXPECT_CALL(mock_callback_, Run).Times(0); + + std::vector<mojom::AggregatableReportHistogramContributionPtr> contributions; + contributions.push_back(mojom::AggregatableReportHistogramContribution::New( + /*bucket=*/123, /*value=*/456)); + remote->SendHistogramReport(std::move(contributions), + mojom::AggregationServiceMode::kDefault); + + remote.FlushForTesting(); + EXPECT_TRUE(remote.is_connected()); +} + } // namespace content
diff --git a/content/browser/private_aggregation/private_aggregation_manager.h b/content/browser/private_aggregation/private_aggregation_manager.h index d57a75f06..8abe8f9 100644 --- a/content/browser/private_aggregation/private_aggregation_manager.h +++ b/content/browser/private_aggregation/private_aggregation_manager.h
@@ -31,6 +31,7 @@ // receiver was accepted. [[nodiscard]] virtual bool BindNewReceiver( url::Origin worklet_origin, + url::Origin top_frame_origin, PrivateAggregationBudgetKey::Api api_for_budgeting, mojo::PendingReceiver<mojom::PrivateAggregationHost> pending_receiver) = 0;
diff --git a/content/browser/private_aggregation/private_aggregation_manager_impl.cc b/content/browser/private_aggregation/private_aggregation_manager_impl.cc index c6e3eab..5b34908 100644 --- a/content/browser/private_aggregation/private_aggregation_manager_impl.cc +++ b/content/browser/private_aggregation/private_aggregation_manager_impl.cc
@@ -57,7 +57,9 @@ /*on_report_request_received=*/base::BindRepeating( &PrivateAggregationManagerImpl:: OnReportRequestReceivedFromHost, - base::Unretained(this))), + base::Unretained(this)), + storage_partition ? storage_partition->browser_context() + : nullptr), storage_partition) {} PrivateAggregationManagerImpl::PrivateAggregationManagerImpl( @@ -75,9 +77,11 @@ bool PrivateAggregationManagerImpl::BindNewReceiver( url::Origin worklet_origin, + url::Origin top_frame_origin, PrivateAggregationBudgetKey::Api api_for_budgeting, mojo::PendingReceiver<mojom::PrivateAggregationHost> pending_receiver) { - return host_->BindNewReceiver(std::move(worklet_origin), api_for_budgeting, + return host_->BindNewReceiver(std::move(worklet_origin), + std::move(top_frame_origin), api_for_budgeting, std::move(pending_receiver)); }
diff --git a/content/browser/private_aggregation/private_aggregation_manager_impl.h b/content/browser/private_aggregation/private_aggregation_manager_impl.h index 7c45570..127f9f1 100644 --- a/content/browser/private_aggregation/private_aggregation_manager_impl.h +++ b/content/browser/private_aggregation/private_aggregation_manager_impl.h
@@ -48,6 +48,7 @@ // PrivateAggregationManager: [[nodiscard]] bool BindNewReceiver( url::Origin worklet_origin, + url::Origin top_frame_origin, PrivateAggregationBudgetKey::Api api_for_budgeting, mojo::PendingReceiver<mojom::PrivateAggregationHost> pending_receiver) override;
diff --git a/content/browser/private_aggregation/private_aggregation_manager_impl_unittest.cc b/content/browser/private_aggregation/private_aggregation_manager_impl_unittest.cc index 2650f1e5..8808f8a05 100644 --- a/content/browser/private_aggregation/private_aggregation_manager_impl_unittest.cc +++ b/content/browser/private_aggregation/private_aggregation_manager_impl_unittest.cc
@@ -14,7 +14,6 @@ #include "base/memory/ptr_util.h" #include "base/task/sequenced_task_runner.h" #include "base/task/thread_pool.h" -#include "base/test/task_environment.h" #include "base/time/time.h" #include "content/browser/aggregation_service/aggregatable_report.h" #include "content/browser/aggregation_service/aggregation_service.h" @@ -25,6 +24,7 @@ #include "content/browser/private_aggregation/private_aggregation_test_utils.h" #include "content/common/aggregatable_report.mojom.h" #include "content/public/browser/storage_partition.h" +#include "content/public/test/browser_task_environment.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/abseil-cpp/absl/types/optional.h" @@ -45,6 +45,7 @@ const base::Time kExampleTime = base::Time::FromJavaTime(1652984901234); constexpr char kExampleOriginUrl[] = "https://origin.example"; +constexpr char kExampleMainFrameUrl[] = "https://main_frame.example"; class PrivateAggregationManagerImplUnderTest : public PrivateAggregationManagerImpl { @@ -81,15 +82,14 @@ base::WrapUnique(aggregation_service_)) {} protected: + BrowserTaskEnvironment task_environment_; + // Keep pointers around for EXPECT_CALL. MockPrivateAggregationBudgeter* budgeter_; MockPrivateAggregationHost* host_; MockAggregationService* aggregation_service_; testing::StrictMock<PrivateAggregationManagerImplUnderTest> manager_; - - private: - base::test::TaskEnvironment task_environment_; }; TEST_F(PrivateAggregationManagerImplTest, @@ -265,21 +265,25 @@ BindNewReceiver_InvokesHostMethodIdentically) { const url::Origin example_origin = url::Origin::Create(GURL(kExampleOriginUrl)); + const url::Origin example_main_frame_origin = + url::Origin::Create(GURL(kExampleMainFrameUrl)); EXPECT_CALL(*host_, - BindNewReceiver(example_origin, + BindNewReceiver(example_origin, example_main_frame_origin, PrivateAggregationBudgetKey::Api::kFledge, _)) .WillOnce(Return(true)); EXPECT_TRUE(manager_.BindNewReceiver( - example_origin, PrivateAggregationBudgetKey::Api::kFledge, + example_origin, example_main_frame_origin, + PrivateAggregationBudgetKey::Api::kFledge, mojo::PendingReceiver<mojom::PrivateAggregationHost>())); EXPECT_CALL(*host_, BindNewReceiver( - example_origin, + example_origin, example_main_frame_origin, PrivateAggregationBudgetKey::Api::kSharedStorage, _)) .WillOnce(Return(false)); EXPECT_FALSE(manager_.BindNewReceiver( - example_origin, PrivateAggregationBudgetKey::Api::kSharedStorage, + example_origin, example_main_frame_origin, + PrivateAggregationBudgetKey::Api::kSharedStorage, mojo::PendingReceiver<mojom::PrivateAggregationHost>())); }
diff --git a/content/browser/private_aggregation/private_aggregation_test_utils.cc b/content/browser/private_aggregation/private_aggregation_test_utils.cc index a079968..9327e2cb 100644 --- a/content/browser/private_aggregation/private_aggregation_test_utils.cc +++ b/content/browser/private_aggregation/private_aggregation_test_utils.cc
@@ -16,10 +16,17 @@ MockPrivateAggregationHost::MockPrivateAggregationHost() : PrivateAggregationHost( - /*on_report_request_received=*/base::DoNothing()) {} + /*on_report_request_received=*/base::DoNothing(), + &test_browser_context_) {} MockPrivateAggregationHost::~MockPrivateAggregationHost() = default; +MockPrivateAggregationContentBrowserClient:: + MockPrivateAggregationContentBrowserClient() = default; + +MockPrivateAggregationContentBrowserClient:: + ~MockPrivateAggregationContentBrowserClient() = default; + bool operator==(const PrivateAggregationBudgetKey::TimeWindow& a, const PrivateAggregationBudgetKey::TimeWindow& b) { return a.start_time() == b.start_time();
diff --git a/content/browser/private_aggregation/private_aggregation_test_utils.h b/content/browser/private_aggregation/private_aggregation_test_utils.h index 08ae5f1..ac4696f 100644 --- a/content/browser/private_aggregation/private_aggregation_test_utils.h +++ b/content/browser/private_aggregation/private_aggregation_test_utils.h
@@ -13,6 +13,8 @@ #include "content/browser/private_aggregation/private_aggregation_budgeter.h" #include "content/browser/private_aggregation/private_aggregation_host.h" #include "content/common/aggregatable_report.mojom-forward.h" +#include "content/public/test/test_browser_context.h" +#include "content/test/test_content_browser_client.h" #include "mojo/public/cpp/bindings/pending_receiver.h" #include "testing/gmock/include/gmock/gmock.h" @@ -35,6 +37,8 @@ (override)); }; +// Note: the `TestBrowserContext` may require a `BrowserTaskEnvironment` to be +// set up. class MockPrivateAggregationHost : public PrivateAggregationHost { public: MockPrivateAggregationHost(); @@ -43,6 +47,7 @@ MOCK_METHOD(bool, BindNewReceiver, (url::Origin, + url::Origin, PrivateAggregationBudgetKey::Api, mojo::PendingReceiver<mojom::PrivateAggregationHost>), (override)); @@ -52,6 +57,24 @@ (std::vector<mojom::AggregatableReportHistogramContributionPtr>, mojom::AggregationServiceMode aggregation_mode), (override)); + + private: + TestBrowserContext test_browser_context_; +}; + +class MockPrivateAggregationContentBrowserClient + : public TestContentBrowserClient { + public: + MockPrivateAggregationContentBrowserClient(); + ~MockPrivateAggregationContentBrowserClient() override; + + // ContentBrowserClient: + MOCK_METHOD(bool, + IsPrivateAggregationAllowed, + (content::BrowserContext * browser_context, + const url::Origin& top_frame_origin, + const url::Origin& reporting_origin), + (override)); }; bool operator==(const PrivateAggregationBudgetKey::TimeWindow&,
diff --git a/content/browser/renderer_host/frame_tree_node.cc b/content/browser/renderer_host/frame_tree_node.cc index 5640ef2..a90baf0c 100644 --- a/content/browser/renderer_host/frame_tree_node.cc +++ b/content/browser/renderer_host/frame_tree_node.cc
@@ -33,6 +33,7 @@ #include "services/network/public/cpp/web_sandbox_flags.h" #include "services/network/public/mojom/web_sandbox_flags.mojom-shared.h" #include "third_party/blink/public/common/features.h" +#include "third_party/blink/public/common/frame/fenced_frame_sandbox_flags.h" #include "third_party/blink/public/common/loader/loader_constants.h" #include "third_party/blink/public/mojom/frame/user_activation_update_types.mojom.h" #include "third_party/blink/public/mojom/security_context/insecure_request_policy.mojom.h" @@ -492,6 +493,31 @@ return; } + // Inside of a fenced frame, the sandbox flags should not be able to change + // from its initial value. If the flags change, we have to assume the change + // came from a compromised renderer and terminate it. + // We will only do the check if the sandbox flags are already set to + // kFencedFrameForcedSandboxFlags. This is to allow the sandbox flags to + // be set initially (go from kNone -> kFencedFrameForcedSandboxFlags). Once + // it has been set, it cannot change to another value. + // Note: The bad message is only expected to hit for ShadowDOM fenced frames. + // For MPArch, the RFHI will detect that the change is not coming from the + // frame's parent in DidChangeFramePolicy() (an MPArch fenced frame parent + // is null since it's the root frame in its tree) and terminate the + // renderer before we reach this point. + // TODO(crbug.com/1262022) When ShadowDOM is removed, turn this into a DCHECK + // and remove the BadMessage call. + if (IsFencedFrameRoot() && + pending_frame_policy_.sandbox_flags == + blink::kFencedFrameForcedSandboxFlags && + frame_policy.sandbox_flags != blink::kFencedFrameForcedSandboxFlags) { + DCHECK(frame_tree()->IsFencedFramesShadowDOMBased()); + bad_message::ReceivedBadMessage( + current_frame_host()->GetProcess(), + bad_message::FF_FROZEN_SANDBOX_FLAGS_CHANGED); + return; + } + pending_frame_policy_.sandbox_flags = frame_policy.sandbox_flags; if (parent()) {
diff --git a/content/browser/renderer_host/media/media_stream_manager.cc b/content/browser/renderer_host/media/media_stream_manager.cc index 135450e..00915d0 100644 --- a/content/browser/renderer_host/media/media_stream_manager.cc +++ b/content/browser/renderer_host/media/media_stream_manager.cc
@@ -771,6 +771,8 @@ video_type_, controls.disable_local_echo, controls.request_pan_tilt_zoom_permission); ui_request_->exclude_system_audio = controls.exclude_system_audio; + ui_request_->exclude_self_browser_surface = + controls.exclude_self_browser_surface; } // Creates a tab capture specific MediaStreamRequest object that is used by
diff --git a/content/browser/resources/aggregation_service/BUILD.gn b/content/browser/resources/aggregation_service/BUILD.gn new file mode 100644 index 0000000..20effe61 --- /dev/null +++ b/content/browser/resources/aggregation_service/BUILD.gn
@@ -0,0 +1,48 @@ +# Copyright 2022 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//tools/polymer/html_to_wrapper.gni") +import("//tools/typescript/ts_library.gni") + +html_to_wrapper("html_wrapper_files") { + in_files = [ "aggregation_service_internals_table.html" ] + template = "native" +} + +# Copy (via creating sym links) all the other files into the same folder for +# ts_library. +copy("copy_files") { + deps = [ "//content/browser/aggregation_service:mojo_bindings_webui_js" ] + sources = [ + "$root_gen_dir/mojom-webui/content/browser/aggregation_service/aggregation_service_internals.mojom-webui.js", + "aggregation_service_internals.ts", + "aggregation_service_internals_table.ts", + "table_model.ts", + ] + outputs = [ "$target_gen_dir/{{source_file_part}}" ] +} + +ts_library("build_ts") { + root_dir = target_gen_dir + out_dir = "$target_gen_dir/tsc" + tsconfig_base = "tsconfig_base.json" + in_files = [ + "aggregation_service_internals.ts", + "aggregation_service_internals_table.ts", + "aggregation_service_internals_table.html.ts", + "table_model.ts", + ] + + # Generated .js files. + in_files += [ "aggregation_service_internals.mojom-webui.js" ] + deps = [ + "//ui/webui/resources:library", + "//ui/webui/resources/mojo:library", + ] + definitions = [ "//tools/typescript/definitions/chrome_send.d.ts" ] + extra_deps = [ + ":copy_files", + ":html_wrapper_files", + ] +}
diff --git a/content/browser/resources/aggregation_service/DIR_METADATA b/content/browser/resources/aggregation_service/DIR_METADATA new file mode 100644 index 0000000..e5ef722 --- /dev/null +++ b/content/browser/resources/aggregation_service/DIR_METADATA
@@ -0,0 +1 @@ +mixins: "//content/browser/aggregation_service/COMMON_METADATA"
diff --git a/content/browser/resources/aggregation_service/OWNERS b/content/browser/resources/aggregation_service/OWNERS new file mode 100644 index 0000000..76fa9199 --- /dev/null +++ b/content/browser/resources/aggregation_service/OWNERS
@@ -0,0 +1 @@ +file://content/browser/aggregation_service/OWNERS
diff --git a/content/browser/resources/aggregation_service/aggregation_service_internals.css b/content/browser/resources/aggregation_service/aggregation_service_internals.css new file mode 100644 index 0000000..d6fa9dc --- /dev/null +++ b/content/browser/resources/aggregation_service/aggregation_service_internals.css
@@ -0,0 +1,47 @@ +/* Copyright 2022 The Chromium Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. */ + +* { + box-sizing: border-box; +} + +html { + height: 100%; +} + +body { + color: rgb(48, 57, 66); + display: flex; + flex-direction: column; + font-family: Roboto, sans-serif; + font-size: 13px; + height: 100%; + margin: 15px; + overflow: auto; +} + +h1 { + color: rgb(92, 97, 102); + font-size: 1.5rem; + padding-bottom: 10px; +} + +main { + border-top: 1px solid rgb(48, 57, 66); + margin-top: 1rem; + padding-top: 1rem; +} + +.content { + background-color: rgb(251, 251, 251); +} + +button { + font: inherit; + margin-inline-end: 30px; +} + +.sendbutton { + margin-bottom: 16px; +}
diff --git a/content/browser/resources/aggregation_service/aggregation_service_internals.html b/content/browser/resources/aggregation_service/aggregation_service_internals.html new file mode 100644 index 0000000..c7d35ab1 --- /dev/null +++ b/content/browser/resources/aggregation_service/aggregation_service_internals.html
@@ -0,0 +1,32 @@ +<!-- Copyright 2022 The Chromium Authors. All rights reserved. + Use of this source code is governed by a BSD-style license that can be + found in the LICENSE file.--> +<!DOCTYPE html> +<html dir="ltr" lang="en"> +<head> + <meta charset="utf-8"> + <link rel="stylesheet" href="chrome://resources/css/text_defaults.css"> + <link rel="stylesheet" href="chrome://resources/css/roboto.css"> + + <link rel="stylesheet" href="aggregation_service_internals.css"> + <script type="module" src="aggregation_service_internals.js"></script> + <title>Private Aggregation API Internals</title> +</head> +<body> +<header> + <h1>Private Aggregation API Internals</h1> + <button id="refresh">Refresh all page data</button> + <button id="clear-data">Clear all private aggregation data</button> +</header> +<main> +<section> + <h2>Aggregatable reports</h2> + <div class="content"> + <button class = "button sendbutton" id="send-reports" disabled>Send Selected Reports</button> + <aggregation-service-internals-table id="reportTable"> + </aggregation-service-internals-table> + </div> +</section> +</main> +</body> +</html>
diff --git a/content/browser/resources/aggregation_service/aggregation_service_internals.ts b/content/browser/resources/aggregation_service/aggregation_service_internals.ts new file mode 100644 index 0000000..e6ba6f5bf --- /dev/null +++ b/content/browser/resources/aggregation_service/aggregation_service_internals.ts
@@ -0,0 +1,368 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import './aggregation_service_internals_table.js'; + +import {assert} from 'chrome://resources/js/assert_ts.js'; + +import {AggregatableReportRequestID, Handler as AggregationServiceInternalsHandler, HandlerRemote as AggregationServiceInternalsHandlerRemote, ObserverInterface, ObserverReceiver, ReportStatus, WebUIAggregatableReport} from './aggregation_service_internals.mojom-webui.js'; +import {AggregationServiceInternalsTableElement} from './aggregation_service_internals_table.js'; +import {Column, TableModel} from './table_model.js'; + +function compareDefault<T>(a: T, b: T): number { + return (a < b) ? -1 : ((a > b) ? 1 : 0); +} + +function bigintReplacer(_key: string, value: any): any { + return typeof value === 'bigint' ? value.toString() : value; +} + +class ValueColumn<T, V> implements Column<T> { + compare: (a: T, b: T) => number; + header: string; + private minWidth?: string; + protected getValue: (param: T) => V; + + constructor( + header: string, getValue: (param: T) => V, minWidth?: string, + compare?: ((a: T, b: T) => number)) { + this.header = header; + this.getValue = getValue; + this.minWidth = minWidth; + this.compare = + compare ?? ((a: T, b: T) => compareDefault(getValue(a), getValue(b))); + } + + render(td: HTMLElement, row: T) { + if (this.minWidth) { + td.style.minWidth = this.minWidth; + } + td.textContent = `${this.getValue(row)}`; + } + + renderHeader(th: HTMLElement) { + th.textContent = `${this.header}`; + } +} + +/** + * Column that holds date. + */ +class DateColumn<T> extends ValueColumn<T, Date> { + constructor(header: string, getValue: (p: T) => Date) { + super(header, getValue); + } + + override render(td: HTMLElement, row: T) { + td.innerText = this.getValue(row).toLocaleString(); + } +} + +class CodeColumn<T> extends ValueColumn<T, string> { + constructor(header: string, getValue: (p: T) => string) { + super(header, getValue); + } + + override render(td: HTMLElement, row: T) { + const code = td.ownerDocument.createElement('code'); + code.innerText = this.getValue(row); + + const pre = td.ownerDocument.createElement('pre'); + pre.appendChild(code); + + td.appendChild(pre); + } +} + +/** + * Wraps a checkbox. + */ +class Selectable { + selectCheckbox: HTMLInputElement; + + constructor() { + this.selectCheckbox = document.createElement('input'); + this.selectCheckbox.type = 'checkbox'; + } +} + +/** + * Checkbox column for selection. + */ +class SelectionColumn<T extends Selectable> implements Column<T> { + compare: ((a: T, b: T) => number)|null; + private model: TableModel<T>; + private selectAllCheckbox: HTMLInputElement; + selectionChangedListeners: Set<(param: boolean) => void>; + header: string|null; + private rowChangedListener: () => void; + + constructor(model: TableModel<T>) { + // Selection column is not sortable. + this.compare = null; + this.model = model; + this.header = null; + + this.selectAllCheckbox = document.createElement('input'); + this.selectAllCheckbox.type = 'checkbox'; + this.selectAllCheckbox.addEventListener('input', () => { + const checked = this.selectAllCheckbox.checked; + this.model.getRows().forEach((row) => { + if (!row.selectCheckbox.disabled) { + row.selectCheckbox.checked = checked; + } + }); + this.notifySelectionChanged(checked); + }); + + this.rowChangedListener = () => this.onChange(); + this.model.rowsChangedListeners.add(this.rowChangedListener); + this.selectionChangedListeners = new Set(); + } + + render(td: HTMLElement, row: T) { + td.appendChild(row.selectCheckbox); + } + + renderHeader(th: HTMLElement) { + th.appendChild(this.selectAllCheckbox); + } + + onChange() { + let anySelectable = false; + let anySelected = false; + let anyUnselected = false; + + this.model.getRows().forEach((row) => { + // addEventListener deduplicates, so only one event will be fired per + // input. + row.selectCheckbox.addEventListener('input', this.rowChangedListener); + + if (row.selectCheckbox.disabled) { + return; + } + + anySelectable = true; + if (row.selectCheckbox.checked) { + anySelected = true; + } else { + anyUnselected = true; + } + }); + + this.selectAllCheckbox.disabled = !anySelectable; + this.selectAllCheckbox.checked = anySelected && !anyUnselected; + this.selectAllCheckbox.indeterminate = anySelected && anyUnselected; + + this.notifySelectionChanged(anySelected); + } + + notifySelectionChanged(anySelected: boolean) { + this.selectionChangedListeners.forEach((f) => f(anySelected)); + } +} + +function reportStatusToText(status: ReportStatus) { + switch (status) { + case ReportStatus.kPending: + return 'Pending'; + case ReportStatus.kSent: + return 'Sent'; + case ReportStatus.kFailedToAssemble: + return 'Failed to assemble'; + case ReportStatus.kFailedToSend: + return 'Failed to send'; + default: + return status.toString(); + } +} + +class Report extends Selectable { + id: AggregatableReportRequestID; + reportBody: string; + reportUrl: string; + reportTime: Date; + status: string; + apiIdentifier: string; + apiVersion: string; + contributions: string; + + constructor(mojo: WebUIAggregatableReport) { + super(); + + this.id = mojo.id; + this.reportBody = mojo.reportBody; + this.reportUrl = mojo.reportUrl.url; + this.reportTime = new Date(mojo.reportTime); + this.apiIdentifier = mojo.apiIdentifier; + this.apiVersion = mojo.apiVersion; + + // Only pending reports are selectable. + if (mojo.status !== ReportStatus.kPending) { + this.selectCheckbox.disabled = true; + } + + this.status = reportStatusToText(mojo.status); + + this.contributions = + JSON.stringify(mojo.contributions, bigintReplacer, ' '); + } +} + +class ReportTableModel extends TableModel<Report> { + private sendReportsButton: HTMLButtonElement; + private selectionColumn: SelectionColumn<Report>; + private handledReports: Report[] = []; + private storedReports: Report[] = []; + + constructor(sendReportsButton: HTMLButtonElement) { + super(); + + this.sendReportsButton = sendReportsButton; + + this.selectionColumn = new SelectionColumn(this); + + this.cols = [ + this.selectionColumn, + new ValueColumn<Report, string>('Status', (e) => e.status), + new ValueColumn<Report, string>( + 'Report URL', (e) => e.reportUrl, '250px'), + new DateColumn<Report>('Report Time', (e) => e.reportTime), + new ValueColumn<Report, string>( + 'API identifier', (e) => e.apiIdentifier, '90px'), + new ValueColumn<Report, string>('API version', (e) => e.apiVersion), + new CodeColumn<Report>( + 'Contributions', (e) => (e as Report).contributions), + new CodeColumn<Report>('Report Body', (e) => e.reportBody), + ]; + + // Sort by report time by default. + this.sortIdx = 3; + assert(this.cols[this.sortIdx]!.header === 'Report Time'); + + this.emptyRowText = 'No sent or pending reports.'; + + this.sendReportsButton.addEventListener('click', () => this.sendReports_()); + this.selectionColumn.selectionChangedListeners.add( + (anySelected: boolean) => { + this.sendReportsButton.disabled = !anySelected; + }); + } + + override getRows() { + return this.handledReports.concat(this.storedReports); + } + + setStoredReports(storedReports: Report[]) { + this.storedReports = storedReports; + this.notifyRowsChanged(); + } + + addHandledReport(report: Report) { + // Prevent the page from consuming ever more memory if the user leaves the + // page open for a long time. + if (this.handledReports.length >= 1000) { + this.handledReports = []; + } + + this.handledReports.push(report); + + this.notifyRowsChanged(); + } + + clear() { + this.storedReports = []; + this.handledReports = []; + this.notifyRowsChanged(); + } + + /** + * Sends all selected reports. + * Disables the button while the reports are still being sent. + * Observer.onRequestStorageModified will be called automatically as reports + * are deleted, so there's no need to manually refresh the data on completion. + */ + private sendReports_() { + const ids: AggregatableReportRequestID[] = []; + this.storedReports.forEach((report) => { + if (!report.selectCheckbox.disabled && report.selectCheckbox.checked) { + ids.push(report.id); + } + }); + + if (ids.length === 0) { + return; + } + + const previousText = this.sendReportsButton.innerText; + + this.sendReportsButton.disabled = true; + this.sendReportsButton.innerText = 'Sending...'; + + pageHandler!.sendReports(ids).then(() => { + this.sendReportsButton.innerText = previousText; + }); + } +} + +/** + * Reference to the backend providing all the data. + */ +let pageHandler: AggregationServiceInternalsHandlerRemote|null = null; + +let reportTableModel: ReportTableModel|null = null; + +/** + * Fetches all pending reports from the backend and populate the tables. + */ +function updateReports() { + pageHandler!.getReports().then((response) => { + reportTableModel!.setStoredReports( + response.reports.map((mojo) => new Report(mojo))); + }); +} + +/** + * Deletes all data stored by the aggregation service backend. + * Observer.onRequestStorageModified will be called automatically as reports are + * deleted, so there's no need to manually refresh the data on completion. + */ +function clearStorage() { + reportTableModel!.clear(); + pageHandler!.clearStorage(); +} + +class Observer implements ObserverInterface { + onRequestStorageModified() { + updateReports(); + } + + onReportHandled(mojo: WebUIAggregatableReport) { + reportTableModel!.addHandledReport(new Report(mojo)); + } +} + +document.addEventListener('DOMContentLoaded', () => { + // Setup the mojo interface. + pageHandler = AggregationServiceInternalsHandler.getRemote(); + + const sendReports = + document.querySelector<HTMLButtonElement>('#send-reports'); + reportTableModel = new ReportTableModel(sendReports!); + + const refresh = document.querySelector('#refresh'); + refresh!.addEventListener('click', updateReports); + const clearData = document.querySelector('#clear-data'); + clearData!.addEventListener('click', clearStorage); + + const reportTable = + document.querySelector<AggregationServiceInternalsTableElement<Report>>( + '#reportTable'); + reportTable!.setModel(reportTableModel!); + + const receiver = new ObserverReceiver(new Observer()); + pageHandler!.addObserver(receiver.$.bindNewPipeAndPassRemote()); + + updateReports(); +});
diff --git a/content/browser/resources/aggregation_service/aggregation_service_internals_table.html b/content/browser/resources/aggregation_service/aggregation_service_internals_table.html new file mode 100644 index 0000000..f640a65 --- /dev/null +++ b/content/browser/resources/aggregation_service/aggregation_service_internals_table.html
@@ -0,0 +1,58 @@ +<style> + :host { + background-color: #fff; + border-color: rgba(0, 0, 0, .12); + border-radius: 4px; + border-style: solid; + border-width: 1px; + display: block; + overflow-x: scroll; + } + + table { + border: 0; + border-collapse: collapse; + } + + tbody tr { + border-top-color: rgba(0, 0, 0, .12); + border-top-style: solid; + border-top-width: 1px; + } + + thead tr { + border: 0; + } + + table td, + table th { + padding-bottom: 16px; + padding-inline-end: 16px; + padding-inline-start: 16px; + padding-top: 16px; + text-align: start; + vertical-align: top; + } + + th[aria-sort] { + cursor: pointer; + } + + th[aria-sort]::after { + content: '\u2B0D'; /* Up Down Black Arrow */ + } + + th[aria-sort='ascending']::after { + content: '\u2B06'; /* Upwards Black Arrow */ + } + + th[aria-sort='descending']::after { + content: '\u2B07'; /* Downwards Black Arrow */ + } +</style> +<table> + <thead> + <tr></tr> + </thead> + <tbody></tbody> +</table>
diff --git a/content/browser/resources/aggregation_service/aggregation_service_internals_table.ts b/content/browser/resources/aggregation_service/aggregation_service_internals_table.ts new file mode 100644 index 0000000..cee0d72 --- /dev/null +++ b/content/browser/resources/aggregation_service/aggregation_service_internals_table.ts
@@ -0,0 +1,141 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import {assert} from 'chrome://resources/js/assert_ts.js'; +import {CustomElement} from 'chrome://resources/js/custom_element.js'; + +import {getTemplate} from './aggregation_service_internals_table.html.js'; +import {TableModel} from './table_model.js'; + +/** + * Helper function for setting sort attributes on |th|. + */ +function setSortAttrs(th: HTMLElement, sortDesc: boolean|null) { + let nextDir; + if (sortDesc === null) { + th.ariaSort = 'none'; + nextDir = 'ascending'; + } else if (sortDesc) { + th.ariaSort = 'descending'; + nextDir = 'ascending'; + } else { + th.ariaSort = 'ascending'; + nextDir = 'descending'; + } + + th.title = `Sort by ${th.innerText} ${nextDir}`; + th.ariaLabel = th.title; +} + +/** + * Table abstracts the logic for rendering and sorting a table. The table's + * columns are supplied by a TableModel supplied to the decorate function. Each + * Column knows how to render the underlying value of the row type T, and + * optionally sort rows of type T by that value. + */ +export class AggregationServiceInternalsTableElement<T> extends CustomElement { + static override get template() { + return getTemplate(); + } + + private model_: TableModel<T>|null = null; + private sortDesc_: boolean = false; + + setModel(model: TableModel<T>) { + this.model_ = model; + this.sortDesc_ = false; + + const tr = this.$<HTMLElement>('tr'); + assert(tr); + model.cols.forEach((col, idx) => { + const th = document.createElement('th'); + th.scope = 'col'; + col.renderHeader(th); + + if (col.compare) { + th.setAttribute('role', 'button'); + setSortAttrs(th, /*sortDesc=*/ null); + th.addEventListener('click', () => this.changeSortHeader_(idx)); + } + + tr.appendChild(th); + }); + + this.addEmptyStateRow_(); + this.model_.rowsChangedListeners.add(() => this.updateTbody()); + } + + private addEmptyStateRow_() { + const td = document.createElement('td'); + assert(this.model_); + td.textContent = this.model_.emptyRowText; + td.colSpan = this.model_.cols.length; + const tr = document.createElement('tr'); + tr.appendChild(td); + const tbody = this.$<HTMLElement>('tbody'); + assert(tbody); + tbody.appendChild(tr); + } + + private changeSortHeader_(idx: number) { + const ths = this.$all<HTMLElement>('thead th'); + + assert(this.model_); + if (idx === this.model_.sortIdx) { + this.sortDesc_ = !this.sortDesc_; + } else { + this.sortDesc_ = false; + if (this.model_.sortIdx >= 0) { + setSortAttrs(ths[this.model_.sortIdx]!, /*descending=*/ null); + } + } + + this.model_.sortIdx = idx; + setSortAttrs(ths[this.model_.sortIdx]!, this.sortDesc_); + this.updateTbody(); + } + + private sort_(rows: T[]) { + assert(this.model_); + if (this.model_.sortIdx < 0) { + return; + } + + const multiplier = this.sortDesc_ ? -1 : 1; + rows.sort( + (a, b) => this.model_!.cols[this.model_!.sortIdx]!.compare!(a, b) * + multiplier); + } + + updateTbody() { + const tbody = this.$<HTMLElement>('tbody'); + assert(tbody); + tbody.innerText = ''; + + assert(this.model_); + const rows = this.model_.getRows(); + if (rows.length === 0) { + this.addEmptyStateRow_(); + return; + } + + this.sort_(rows); + + rows.forEach((row) => { + const tr = document.createElement('tr'); + assert(this.model_); + this.model_.cols.forEach((col) => { + const td = document.createElement('td'); + col.render(td, row); + tr.appendChild(td); + }); + this.model_.styleRow(tr, row); + tbody.appendChild(tr); + }); + } +} + +customElements.define( + 'aggregation-service-internals-table', + AggregationServiceInternalsTableElement);
diff --git a/content/browser/resources/aggregation_service/table_model.ts b/content/browser/resources/aggregation_service/table_model.ts new file mode 100644 index 0000000..b44e692 --- /dev/null +++ b/content/browser/resources/aggregation_service/table_model.ts
@@ -0,0 +1,34 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +export interface Column<T> { + compare: ((a: T, b: T) => number)|null; + + render(td: HTMLElement, row: T): void; + + renderHeader(th: HTMLElement): void; + + header: string|null; +} + +export class TableModel<T> { + cols: Array<Column<T>> = []; + emptyRowText: string = ''; + sortIdx: number = -1; + rowsChangedListeners: Set<() => void>; + + constructor() { + this.rowsChangedListeners = new Set(); + } + + styleRow(_tr: Element, _data: T) {} + + getRows(): T[] { + return []; + } + + notifyRowsChanged() { + this.rowsChangedListeners.forEach(f => f()); + } +}
diff --git a/content/browser/resources/aggregation_service/tsconfig_base.json b/content/browser/resources/aggregation_service/tsconfig_base.json new file mode 100644 index 0000000..99a81eca --- /dev/null +++ b/content/browser/resources/aggregation_service/tsconfig_base.json
@@ -0,0 +1,6 @@ +{ + "extends": "../../../../tools/typescript/tsconfig_base.json", + "compilerOptions": { + "allowJs": true + } +}
diff --git a/content/browser/security_exploit_browsertest.cc b/content/browser/security_exploit_browsertest.cc index 3c6ef8d..d7155ee9 100644 --- a/content/browser/security_exploit_browsertest.cc +++ b/content/browser/security_exploit_browsertest.cc
@@ -55,6 +55,7 @@ #include "content/public/test/content_browser_test_utils.h" #include "content/public/test/fenced_frame_test_util.h" #include "content/public/test/navigation_handle_observer.h" +#include "content/public/test/test_frame_navigation_observer.h" #include "content/public/test/test_navigation_observer.h" #include "content/public/test/test_renderer_host.h" #include "content/public/test/test_utils.h" @@ -92,6 +93,7 @@ #include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/blink/public/common/blob/blob_utils.h" #include "third_party/blink/public/common/fenced_frame/fenced_frame_utils.h" +#include "third_party/blink/public/common/frame/fenced_frame_sandbox_flags.h" #include "third_party/blink/public/common/navigation/navigation_policy.h" #include "third_party/blink/public/mojom/blob/blob_url_store.mojom-test-utils.h" #include "third_party/blink/public/mojom/choosers/file_chooser.mojom.h" @@ -1962,21 +1964,75 @@ kill_waiter.Wait()); } -class SecurityExploitBrowserTestEnableFencedFrames - : public SecurityExploitBrowserTest { +class SecurityExploitBrowserTestParameterizedFencedFrames + : public SecurityExploitBrowserTest, + public ::testing::WithParamInterface< + blink::features::FencedFramesImplementationType> { public: - SecurityExploitBrowserTestEnableFencedFrames() { + SecurityExploitBrowserTestParameterizedFencedFrames() { scoped_feature_list_.InitAndEnableFeatureWithParameters( - blink::features::kFencedFrames, {{"implementation_type", "mparch"}}); + blink::features::kFencedFrames, + {{"implementation_type", + GetParam() == + blink::features::FencedFramesImplementationType::kShadowDOM + ? "shadow_dom" + : "mparch"}}); } + // Provides meaningful param names instead of /0 and /1. + static std::string DescribeParams( + const ::testing::TestParamInfo<ParamType>& info) { + switch (info.param) { + case blink::features::FencedFramesImplementationType::kShadowDOM: + return "ShadowDOM"; + case blink::features::FencedFramesImplementationType::kMPArch: + return "MPArch"; + } + } + + void SetUpOnMainThread() override { + host_resolver()->AddRule("*", "127.0.0.1"); + https_server()->StartAcceptingConnections(); + } + + void SetUpCommandLine(base::CommandLine* command_line) override { + https_server()->AddDefaultHandlers(GetTestDataFilePath()); + https_server()->ServeFilesFromSourceDirectory(GetTestDataFilePath()); + https_server()->SetSSLConfig(net::EmbeddedTestServer::CERT_TEST_NAMES); + SetupCrossSiteRedirector(https_server()); + + // EmbeddedTestServer::InitializeAndListen() initializes its |base_url_| + // which is required below. This cannot invoke Start() however as that kicks + // off the "EmbeddedTestServer IO Thread" which then races with + // initialization in ContentBrowserTest::SetUp(), http://crbug.com/674545. + ASSERT_TRUE(https_server()->InitializeAndListen()); + } + + test::FencedFrameTestHelper& fenced_frame_test_helper() { + return fenced_frame_test_helper_; + } + + net::EmbeddedTestServer* https_server() { return &https_server_; } + private: + test::FencedFrameTestHelper fenced_frame_test_helper_{ + GetParam() == blink::features::FencedFramesImplementationType::kShadowDOM + ? test::FencedFrameTestHelper::FencedFrameType::kShadowDOM + : test::FencedFrameTestHelper::FencedFrameType::kMPArch}; base::test::ScopedFeatureList scoped_feature_list_; + net::EmbeddedTestServer https_server_{net::EmbeddedTestServer::TYPE_HTTPS}; }; -IN_PROC_BROWSER_TEST_F(SecurityExploitBrowserTestEnableFencedFrames, +IN_PROC_BROWSER_TEST_P(SecurityExploitBrowserTestParameterizedFencedFrames, NavigateFencedFrameToInvalidURL) { - GURL main_frame_url("http://foo.com/simple_page.html"); + // The valid URL browser check only exists for the MPArch implementation of + // fenced frames. So, we have to disable this test for ShadowDOM. + if (GetParam() == + blink::features::FencedFramesImplementationType::kShadowDOM) { + return; + } + + GURL main_frame_url(https_server()->GetURL("a.test", "/simple_page.html")); std::vector<GURL> invalid_urls = { GURL("http://example.com"), GURL("about:srcdoc"), @@ -2026,4 +2082,68 @@ } } +IN_PROC_BROWSER_TEST_P(SecurityExploitBrowserTestParameterizedFencedFrames, + ChangeFencedFrameSandboxFlags) { + GURL main_frame_url(https_server()->GetURL("a.test", "/simple_page.html")); + + EXPECT_TRUE(NavigateToURL(shell(), main_frame_url)); + RenderFrameHostImpl* root_rfh = static_cast<RenderFrameHostImpl*>( + shell()->web_contents()->GetPrimaryMainFrame()); + + const GURL fenced_frame_url = + https_server()->GetURL("a.test", "/fenced_frames/sandbox_flags.html"); + constexpr char kAddFencedFrameScript[] = R"({ + const fenced_frame = document.createElement('fencedframe'); + fenced_frame.src = $1; + document.body.appendChild(fenced_frame); + })"; + EXPECT_TRUE( + ExecJs(root_rfh, JsReplace(kAddFencedFrameScript, fenced_frame_url))); + + RenderFrameHostImpl* fenced_rfh = nullptr; + RenderFrameHostImpl* parent_rfh = nullptr; + + if (GetParam() == + blink::features::FencedFramesImplementationType::kShadowDOM) { + // ShadowDOM + fenced_rfh = root_rfh->child_at(0)->current_frame_host(); + parent_rfh = root_rfh; + } else { + // MPArch + std::vector<FencedFrame*> fenced_frames = root_rfh->GetFencedFrames(); + EXPECT_EQ(fenced_frames.size(), 1u); + FencedFrame* new_fenced_frame = fenced_frames.back(); + fenced_rfh = new_fenced_frame->GetInnerRoot(); + parent_rfh = fenced_rfh; + } + + RenderProcessHostBadIpcMessageWaiter kill_waiter(fenced_rfh->GetProcess()); + + blink::FramePolicy first_policy = + fenced_rfh->frame_tree_node()->pending_frame_policy(); + + first_policy.sandbox_flags = blink::kFencedFrameMandatoryUnsandboxedFlags; + static_cast<blink::mojom::LocalFrameHost*>(parent_rfh) + ->DidChangeFramePolicy(std::move(fenced_rfh->GetFrameToken()), + std::move(first_policy)); + + if (GetParam() == + blink::features::FencedFramesImplementationType::kShadowDOM) { + EXPECT_EQ(bad_message::FF_FROZEN_SANDBOX_FLAGS_CHANGED, kill_waiter.Wait()); + } else { + // MPArch fenced frames are the root node of its frame tree, so a different + // check is expected to trigger. This check makes sure only the parent can + // change a frame's sandbox flags. + EXPECT_EQ(bad_message::RFH_SANDBOX_FLAGS, kill_waiter.Wait()); + } +} + +INSTANTIATE_TEST_SUITE_P( + All, + SecurityExploitBrowserTestParameterizedFencedFrames, + ::testing::Values( + blink::features::FencedFramesImplementationType::kShadowDOM, + blink::features::FencedFramesImplementationType::kMPArch), + &SecurityExploitBrowserTestParameterizedFencedFrames::DescribeParams); + } // namespace content
diff --git a/content/browser/shared_storage/shared_storage_browsertest.cc b/content/browser/shared_storage/shared_storage_browsertest.cc index b50be4b..af2a82c 100644 --- a/content/browser/shared_storage/shared_storage_browsertest.cc +++ b/content/browser/shared_storage/shared_storage_browsertest.cc
@@ -2796,18 +2796,21 @@ a_test_origin_ = https_server()->GetOrigin("a.test"); - private_aggregation_host_ = new PrivateAggregationHost( - /*on_report_request_received=*/mock_callback_.Get()); + auto* storage_partition_impl = + static_cast<StoragePartitionImpl*>(shell() + ->web_contents() + ->GetBrowserContext() + ->GetDefaultStoragePartition()); - static_cast<StoragePartitionImpl*>(shell() - ->web_contents() - ->GetBrowserContext() - ->GetDefaultStoragePartition()) - ->OverridePrivateAggregationManagerForTesting( - std::make_unique<TestPrivateAggregationManagerImpl>( - std::make_unique<MockPrivateAggregationBudgeter>(), - base::WrapUnique<PrivateAggregationHost>( - private_aggregation_host_))); + private_aggregation_host_ = new PrivateAggregationHost( + /*on_report_request_received=*/mock_callback_.Get(), + storage_partition_impl->browser_context()); + + storage_partition_impl->OverridePrivateAggregationManagerForTesting( + std::make_unique<TestPrivateAggregationManagerImpl>( + std::make_unique<MockPrivateAggregationBudgeter>(), + base::WrapUnique<PrivateAggregationHost>( + private_aggregation_host_))); EXPECT_TRUE(NavigateToURL( shell(), https_server()->GetURL("a.test", kSimplePagePath)));
diff --git a/content/browser/shared_storage/shared_storage_worklet_host.cc b/content/browser/shared_storage/shared_storage_worklet_host.cc index b386f91..d4f5351 100644 --- a/content/browser/shared_storage/shared_storage_worklet_host.cc +++ b/content/browser/shared_storage/shared_storage_worklet_host.cc
@@ -687,7 +687,7 @@ mojo::PendingRemote<content::mojom::PrivateAggregationHost> pending_pa_host_remote; if (!private_aggregation_manager->BindNewReceiver( - shared_storage_origin_, + shared_storage_origin_, main_frame_origin_, PrivateAggregationBudgetKey::Api::kSharedStorage, pending_pa_host_remote.InitWithNewPipeAndPassReceiver())) { return mojo::PendingRemote<content::mojom::PrivateAggregationHost>();
diff --git a/content/browser/speech/tts_utterance_impl.cc b/content/browser/speech/tts_utterance_impl.cc index 5c26851..38e661c 100644 --- a/content/browser/speech/tts_utterance_impl.cc +++ b/content/browser/speech/tts_utterance_impl.cc
@@ -48,9 +48,10 @@ // static std::unique_ptr<TtsUtterance> TtsUtterance::Create( - BrowserContext* browser_context) { - DCHECK(browser_context); - return std::make_unique<TtsUtteranceImpl>(browser_context, nullptr); + BrowserContext* browser_context, + bool should_always_be_spoken) { + return std::make_unique<TtsUtteranceImpl>(browser_context, + should_always_be_spoken); } // static @@ -72,6 +73,12 @@ } } +TtsUtteranceImpl::TtsUtteranceImpl(BrowserContext* browser_context, + bool should_always_be_spoken) + : TtsUtteranceImpl(browser_context, nullptr) { + should_always_be_spoken_ = should_always_be_spoken; +} + TtsUtteranceImpl::~TtsUtteranceImpl() { // It's an error if an Utterance is destructed without being finished, // unless |browser_context_| is nullptr because it's a unit test. @@ -222,4 +229,8 @@ return web_contents_.get(); } +bool TtsUtteranceImpl::ShouldAlwaysBeSpoken() { + return should_always_be_spoken_; +} + } // namespace content
diff --git a/content/browser/speech/tts_utterance_impl.h b/content/browser/speech/tts_utterance_impl.h index c458910..5410bf8c 100644 --- a/content/browser/speech/tts_utterance_impl.h +++ b/content/browser/speech/tts_utterance_impl.h
@@ -11,7 +11,9 @@ #include "base/memory/raw_ptr.h" #include "base/memory/weak_ptr.h" +#include "base/unguessable_token.h" #include "base/values.h" +#include "build/chromeos_buildflags.h" #include "content/common/content_export.h" #include "content/public/browser/tts_utterance.h" @@ -27,6 +29,9 @@ class CONTENT_EXPORT TtsUtteranceImpl : public TtsUtterance { public: TtsUtteranceImpl(BrowserContext* browser_context, WebContents* web_contents); + TtsUtteranceImpl(content::BrowserContext* browser_context, + bool should_always_be_spoken); + ~TtsUtteranceImpl() override; bool was_created_with_web_contents() const { @@ -86,7 +91,9 @@ bool IsFinished() override; // Returns the associated WebContents, may be null. - WebContents* GetWebContents(); + WebContents* GetWebContents() override; + + bool ShouldAlwaysBeSpoken() override; private: // The BrowserContext that initiated this utterance. @@ -138,6 +145,9 @@ // True if this utterance received an event indicating it's done. bool finished_; + + // True if this utterance should always be spoken. + bool should_always_be_spoken_ = false; }; } // namespace content
diff --git a/content/browser/webid/federated_auth_request_impl.cc b/content/browser/webid/federated_auth_request_impl.cc index 8c102e3..26e57f0 100644 --- a/content/browser/webid/federated_auth_request_impl.cc +++ b/content/browser/webid/federated_auth_request_impl.cc
@@ -292,9 +292,14 @@ } void FederatedAuthRequestImpl::RequestToken( - IdentityProviderPtr identity_provider_ptr, + std::vector<blink::mojom::IdentityProviderPtr> identity_provider_ptrs, bool prefer_auto_sign_in, RequestTokenCallback callback) { + // TODO(crbug.com/1348262): Temporarily support only the first IDP, extend to + // support multiple IDPs. + blink::mojom::IdentityProviderPtr identity_provider_ptr = + std::move(identity_provider_ptrs[0]); + if (HasPendingRequest()) { fedcm_metrics_->RecordRequestTokenStatus(TokenStatus::kTooManyRequests); std::move(callback).Run(RequestTokenStatus::kErrorTooManyRequests, ""); @@ -327,7 +332,7 @@ network_manager_ = CreateNetworkManager(identity_provider_ptr->config_url); FederatedApiPermissionStatus permission_status = - api_permission_delegate_->GetApiPermissionStatus(origin()); + api_permission_delegate_->GetApiPermissionStatus(GetEmbeddingOrigin()); absl::optional<TokenStatus> error_token_status; FederatedAuthRequestResult request_result = @@ -427,7 +432,7 @@ return; } - if (api_permission_delegate_->GetApiPermissionStatus(origin()) != + if (api_permission_delegate_->GetApiPermissionStatus(GetEmbeddingOrigin()) != FederatedApiPermissionStatus::GRANTED) { CompleteLogoutRequest(LogoutRpsStatus::kError); return; @@ -706,6 +711,7 @@ WebContents* rp_web_contents = WebContents::FromRenderFrameHost(&render_frame_host()); + DCHECK(render_frame_host().GetMainFrame()->IsInPrimaryMainFrame()); ComputeLoginStateAndReorderAccounts(identity_provider, accounts); @@ -748,8 +754,8 @@ bool idp_claimed_sign_in = account.login_state == LoginState::kSignIn; bool browser_observed_sign_in = sharing_permission_delegate_->HasSharingPermission( - origin(), url::Origin::Create(identity_provider.config_url), - account.id); + origin(), GetEmbeddingOrigin(), + url::Origin::Create(identity_provider.config_url), account.id); if (idp_claimed_sign_in == browser_observed_sign_in) { fedcm_metrics_->RecordSignInStateMatchStatus( @@ -796,7 +802,7 @@ // settings are changed while an existing FedCM UI is displayed. Ideally, we // should enforce this check before all requests but users typically won't // have time to disable the FedCM API in other types of requests. - if (api_permission_delegate_->GetApiPermissionStatus(origin()) != + if (api_permission_delegate_->GetApiPermissionStatus(GetEmbeddingOrigin()) != FederatedApiPermissionStatus::GRANTED) { fedcm_metrics_->RecordRequestTokenStatus(TokenStatus::kDisabledInSettings); @@ -807,7 +813,7 @@ RecordIsSignInUser(is_sign_in); - api_permission_delegate_->RemoveEmbargoAndResetCounts(origin()); + api_permission_delegate_->RemoveEmbargoAndResetCounts(GetEmbeddingOrigin()); account_id_ = account_id; select_account_time_ = base::TimeTicks::Now(); @@ -847,7 +853,7 @@ fedcm_metrics_->RecordCancelReason(dismiss_reason); if (should_embargo) { - api_permission_delegate_->RecordDismissAndEmbargo(origin()); + api_permission_delegate_->RecordDismissAndEmbargo(GetEmbeddingOrigin()); } // Reject the promise immediately if the UI is dismissed without selecting @@ -928,8 +934,8 @@ // https://crbug.com/1199088 CHECK(!account_id_.empty()); sharing_permission_delegate_->GrantSharingPermission( - origin(), url::Origin::Create(identity_provider.config_url), - account_id_); + origin(), GetEmbeddingOrigin(), + url::Origin::Create(identity_provider.config_url), account_id_); active_session_permission_delegate_->GrantActiveSession( origin(), url::Origin::Create(identity_provider.config_url), @@ -1060,6 +1066,12 @@ return api_permission_delegate_->ShouldCompleteRequestImmediately(); } +url::Origin FederatedAuthRequestImpl::GetEmbeddingOrigin() const { + RenderFrameHost* main_frame = render_frame_host().GetMainFrame(); + DCHECK(main_frame->IsInPrimaryMainFrame()); + return main_frame->GetLastCommittedOrigin(); +} + void FederatedAuthRequestImpl::CompleteLogoutRequest( blink::mojom::LogoutRpsStatus status) { network_manager_.reset();
diff --git a/content/browser/webid/federated_auth_request_impl.h b/content/browser/webid/federated_auth_request_impl.h index ea80961..31bf3bf3 100644 --- a/content/browser/webid/federated_auth_request_impl.h +++ b/content/browser/webid/federated_auth_request_impl.h
@@ -56,9 +56,10 @@ ~FederatedAuthRequestImpl() override; // blink::mojom::FederatedAuthRequest: - void RequestToken(blink::mojom::IdentityProviderPtr identity_provider_ptr, - bool prefer_auto_sign_in, - RequestTokenCallback) override; + void RequestToken( + std::vector<blink::mojom::IdentityProviderPtr> identity_provider_ptrs, + bool prefer_auto_sign_in, + RequestTokenCallback) override; void CancelTokenRequest() override; void LogoutRps(std::vector<blink::mojom::LogoutRpsRequestPtr> logout_requests, LogoutRpsCallback) override; @@ -165,6 +166,8 @@ const blink::mojom::IdentityProvider& identity_provider, IdpNetworkRequestManager::AccountList& accounts); + url::Origin GetEmbeddingOrigin() const; + std::unique_ptr<IdpNetworkRequestManager> network_manager_; std::unique_ptr<IdentityRequestDialogController> request_dialog_controller_;
diff --git a/content/browser/webid/federated_auth_request_impl_unittest.cc b/content/browser/webid/federated_auth_request_impl_unittest.cc index f064701..48c690a 100644 --- a/content/browser/webid/federated_auth_request_impl_unittest.cc +++ b/content/browser/webid/federated_auth_request_impl_unittest.cc
@@ -700,10 +700,12 @@ const std::string& nonce, bool prefer_auto_sign_in, bool wait_for_callback) { - blink::mojom::IdentityProviderPtr identity_provider = + std::vector<blink::mojom::IdentityProviderPtr> identity_provider_ptrs; + blink::mojom::IdentityProviderPtr identity_provider_ptr = blink::mojom::IdentityProvider::New(provider, client_id, nonce); + identity_provider_ptrs.push_back(std::move(identity_provider_ptr)); - request_remote_->RequestToken(std::move(identity_provider), + request_remote_->RequestToken(std::move(identity_provider_ptrs), prefer_auto_sign_in, auth_helper_.callback()); if (wait_for_callback) @@ -1207,7 +1209,7 @@ // Pretend the sharing permission has been granted for this account. EXPECT_CALL( *mock_sharing_permission_delegate_, - HasSharingPermission(OriginFromString(kRpUrl), + HasSharingPermission(OriginFromString(kRpUrl), OriginFromString(kRpUrl), OriginFromString(kProviderUrlFull), kAccountId)) .WillOnce(Return(true)); RunAuthTest(kDefaultRequestParameters, kExpectationSuccess, @@ -1217,11 +1219,12 @@ TEST_F(FederatedAuthRequestImplTest, LoginStateSuccessfulSignUpGrantsSharingPermission) { - EXPECT_CALL(*mock_sharing_permission_delegate_, HasSharingPermission(_, _, _)) + EXPECT_CALL(*mock_sharing_permission_delegate_, + HasSharingPermission(_, _, _, _)) .WillOnce(Return(false)); EXPECT_CALL( *mock_sharing_permission_delegate_, - GrantSharingPermission(OriginFromString(kRpUrl), + GrantSharingPermission(OriginFromString(kRpUrl), OriginFromString(kRpUrl), OriginFromString(kProviderUrlFull), kAccountId)) .Times(1); RunAuthTest(kDefaultRequestParameters, kExpectationSuccess, @@ -1230,10 +1233,11 @@ TEST_F(FederatedAuthRequestImplTest, LoginStateFailedSignUpNotGrantSharingPermission) { - EXPECT_CALL(*mock_sharing_permission_delegate_, HasSharingPermission(_, _, _)) + EXPECT_CALL(*mock_sharing_permission_delegate_, + HasSharingPermission(_, _, _, _)) .WillOnce(Return(false)); EXPECT_CALL(*mock_sharing_permission_delegate_, - GrantSharingPermission(_, _, _)) + GrantSharingPermission(_, _, _, _)) .Times(0); MockConfiguration configuration = kConfigurationValid; @@ -1256,7 +1260,7 @@ // Pretend the sharing permission has been granted for this account. EXPECT_CALL( *mock_sharing_permission_delegate_, - HasSharingPermission(OriginFromString(kRpUrl), + HasSharingPermission(OriginFromString(kRpUrl), OriginFromString(kRpUrl), OriginFromString(kProviderUrlFull), kAccountId)) .WillOnce(Return(true)); @@ -1330,7 +1334,7 @@ // Pretend the sharing permission has been granted for this account. EXPECT_CALL( *mock_sharing_permission_delegate_, - HasSharingPermission(OriginFromString(kRpUrl), + HasSharingPermission(OriginFromString(kRpUrl), OriginFromString(kRpUrl), OriginFromString(kProviderUrlFull), kAccountId)) .WillOnce(Return(true)); @@ -1362,9 +1366,9 @@ TEST_F(FederatedAuthRequestImplTest, MetricsForSuccessfulSignInCase) { // Pretends that the sharing permission has been granted for this account. - EXPECT_CALL( - *mock_sharing_permission_delegate_, - HasSharingPermission(_, OriginFromString(kProviderUrlFull), kAccountId)) + EXPECT_CALL(*mock_sharing_permission_delegate_, + HasSharingPermission(_, _, OriginFromString(kProviderUrlFull), + kAccountId)) .WillOnce(Return(true)); base::RunLoop ukm_loop; @@ -1516,9 +1520,9 @@ content::PageVisibilityState::kVisible); // Pretends that the sharing permission has been granted for this account. - EXPECT_CALL( - *mock_sharing_permission_delegate_, - HasSharingPermission(_, OriginFromString(kProviderUrlFull), kAccountId)) + EXPECT_CALL(*mock_sharing_permission_delegate_, + HasSharingPermission(_, _, OriginFromString(kProviderUrlFull), + kAccountId)) .WillOnce(Return(true)); RunAuthTest(kDefaultRequestParameters, kExpectationSuccess, @@ -1637,7 +1641,7 @@ // Set browser observes user is signed in. EXPECT_CALL( *mock_sharing_permission_delegate_, - HasSharingPermission(OriginFromString(kRpUrl), + HasSharingPermission(OriginFromString(kRpUrl), OriginFromString(kRpUrl), OriginFromString(kProviderUrlFull), kAccountId)) .WillOnce(Return(true)); @@ -1667,7 +1671,7 @@ // Set browser observes user is not signed in. EXPECT_CALL( *mock_sharing_permission_delegate_, - HasSharingPermission(OriginFromString(kRpUrl), + HasSharingPermission(OriginFromString(kRpUrl), OriginFromString(kRpUrl), OriginFromString(kProviderUrlFull), kAccountId)) .WillOnce(Return(false)); @@ -1693,7 +1697,7 @@ // Set browser observes user is not signed in. EXPECT_CALL( *mock_sharing_permission_delegate_, - HasSharingPermission(OriginFromString(kRpUrl), + HasSharingPermission(OriginFromString(kRpUrl), OriginFromString(kRpUrl), OriginFromString(kProviderUrlFull), kAccountId)) .WillOnce(Return(false)); @@ -1724,7 +1728,7 @@ // Set browser observes user is signed in. EXPECT_CALL( *mock_sharing_permission_delegate_, - HasSharingPermission(OriginFromString(kRpUrl), + HasSharingPermission(OriginFromString(kRpUrl), OriginFromString(kRpUrl), OriginFromString(kProviderUrlFull), kAccountId)) .WillOnce(Return(true)); @@ -1924,7 +1928,7 @@ // Pretend the sharing permission has been granted for this account. EXPECT_CALL( *mock_sharing_permission_delegate_, - HasSharingPermission(OriginFromString(kRpUrl), + HasSharingPermission(OriginFromString(kRpUrl), OriginFromString(kRpUrl), OriginFromString(kProviderUrlFull), kAccountId)) .WillOnce(Return(true));
diff --git a/content/browser/webid/test/mock_sharing_permission_delegate.h b/content/browser/webid/test/mock_sharing_permission_delegate.h index 078a1284..64b79e2 100644 --- a/content/browser/webid/test/mock_sharing_permission_delegate.h +++ b/content/browser/webid/test/mock_sharing_permission_delegate.h
@@ -24,13 +24,15 @@ MOCK_METHOD(bool, HasSharingPermission, - (const url::Origin& relying_party, + (const url::Origin& relying_party_requester, + const url::Origin& relying_party_embedder, const url::Origin& identity_provider, const std::string& account_id), (override)); MOCK_METHOD(void, GrantSharingPermission, - (const url::Origin& relying_party, + (const url::Origin& relying_party_requester, + const url::Origin& relying_party_embedder, const url::Origin& identity_provider, const std::string& account_id), (override));
diff --git a/content/browser/webui/content_web_ui_configs.cc b/content/browser/webui/content_web_ui_configs.cc index 4a20d74a..615d5fa 100644 --- a/content/browser/webui/content_web_ui_configs.cc +++ b/content/browser/webui/content_web_ui_configs.cc
@@ -4,6 +4,9 @@ #include "content/browser/webui/content_web_ui_configs.h" +#include <memory> + +#include "content/browser/aggregation_service/aggregation_service_internals_ui.h" #include "content/browser/attribution_reporting/attribution_internals_ui.h" #include "content/browser/gpu/gpu_internals_ui.h" #include "content/browser/indexed_db/indexed_db_internals_ui.h" @@ -27,6 +30,7 @@ void RegisterContentWebUIConfigs() { auto& map = WebUIConfigMap::GetInstance(); map.AddWebUIConfig(std::make_unique<AttributionInternalsUIConfig>()); + map.AddWebUIConfig(std::make_unique<AggregationServiceInternalsUIConfig>()); map.AddWebUIConfig(std::make_unique<GpuInternalsUIConfig>()); map.AddWebUIConfig(std::make_unique<IndexedDBInternalsUIConfig>()); map.AddWebUIConfig(std::make_unique<MediaInternalsUIConfig>());
diff --git a/content/child/runtime_features.cc b/content/child/runtime_features.cc index 9416bce..495261c 100644 --- a/content/child/runtime_features.cc +++ b/content/child/runtime_features.cc
@@ -390,6 +390,8 @@ {"SecureContextFixForWorkers", blink::features::kSecureContextFixForWorkers}, {"StorageAccessAPI", net::features::kStorageAccessAPI}, + {"StorageAccessAPIForSiteExtension", + blink::features::kStorageAccessAPIForSiteExtension}, {"ThrottleDisplayNoneAndVisibilityHiddenCrossOriginIframes", blink::features:: kThrottleDisplayNoneAndVisibilityHiddenCrossOriginIframes}, @@ -651,6 +653,20 @@ << blink::features::kBrowsingTopics.name << " instead."; WebRuntimeFeatures::EnableTopicsAPI(false); } + + // Storage Access API ForSite cannot be enabled unless the larger Storage + // Access API is also enabled. + if (base::FeatureList::IsEnabled( + blink::features::kStorageAccessAPIForSiteExtension) && + !base::FeatureList::IsEnabled(net::features::kStorageAccessAPI)) { + LOG_IF(WARNING, + WebRuntimeFeatures::IsStorageAccessAPIForSiteExtensionEnabled()) + << "requestStorageAccessForSite cannot be enabled in this " + "configuration. Use --" + << switches::kEnableFeatures << "=" + << net::features::kStorageAccessAPI.name << " in addition."; + WebRuntimeFeatures::EnableStorageAccessAPIForSiteExtension(false); + } } } // namespace
diff --git a/content/dev_ui_content_resources.grd b/content/dev_ui_content_resources.grd index 24817e94..f75bbe67 100644 --- a/content/dev_ui_content_resources.grd +++ b/content/dev_ui_content_resources.grd
@@ -15,6 +15,13 @@ <translations /> <release seq="1"> <includes> + <include name="IDR_AGGREGATION_SERVICE_INTERNALS_HTML" file="browser/resources/aggregation_service/aggregation_service_internals.html" type="BINDATA" /> + <include name="IDR_AGGREGATION_SERVICE_INTERNALS_JS" file="${root_gen_dir}/content/browser/resources/aggregation_service/tsc/aggregation_service_internals.js" use_base_dir="false" type="BINDATA" /> + <include name="IDR_AGGREGATION_SERVICE_INTERNALS_TABLE_MODEL_JS" file="${root_gen_dir}/content/browser/resources/aggregation_service/tsc/table_model.js" use_base_dir="false" type="BINDATA" /> + <include name="IDR_AGGREGATION_SERVICE_INTERNALS_TABLE_JS" file="${root_gen_dir}/content/browser/resources/aggregation_service/tsc/aggregation_service_internals_table.js" use_base_dir="false" type="BINDATA" /> + <include name="IDR_AGGREGATION_SERVICE_INTERNALS_TABLE_HTML_JS" file="${root_gen_dir}/content/browser/resources/aggregation_service/tsc/aggregation_service_internals_table.html.js" use_base_dir="false" type="BINDATA" /> + <include name="IDR_AGGREGATION_SERVICE_INTERNALS_CSS" file="browser/resources/aggregation_service/aggregation_service_internals.css" type="BINDATA" /> + <include name="IDR_AGGREGATION_SERVICE_INTERNALS_MOJOM_JS" file="${root_gen_dir}/mojom-webui/content/browser/aggregation_service/aggregation_service_internals.mojom-webui.js" use_base_dir="false" type="BINDATA" /> <include name="IDR_ATTRIBUTION_INTERNALS_HTML" file="browser/resources/attribution_reporting/attribution_internals.html" type="BINDATA" /> <include name="IDR_ATTRIBUTION_INTERNALS_JS" file="${root_gen_dir}/content/browser/resources/attribution_reporting/tsc/attribution_internals.js" use_base_dir="false" type="BINDATA" /> <include name="IDR_ATTRIBUTION_INTERNALS_TABLE_MODEL_JS" file="${root_gen_dir}/content/browser/resources/attribution_reporting/tsc/table_model.js" use_base_dir="false" type="BINDATA" />
diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc index 6044fe8..2722ee6 100644 --- a/content/public/browser/content_browser_client.cc +++ b/content/public/browser/content_browser_client.cc
@@ -512,6 +512,13 @@ return true; } +bool ContentBrowserClient::IsPrivateAggregationAllowed( + content::BrowserContext* browser_context, + const url::Origin& top_frame_origin, + const url::Origin& reporting_origin) { + return true; +} + bool ContentBrowserClient::CanSendSCTAuditingReport( BrowserContext* browser_context) { return false;
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h index 5853cf2..3f07e771 100644 --- a/content/public/browser/content_browser_client.h +++ b/content/public/browser/content_browser_client.h
@@ -873,6 +873,13 @@ const url::Origin& top_frame_origin, const url::Origin& accessing_origin); + // Allows the embedder to control if Private Aggregation API operations can + // happen in a given context. + virtual bool IsPrivateAggregationAllowed( + content::BrowserContext* browser_context, + const url::Origin& top_frame_origin, + const url::Origin& reporting_origin); + #if BUILDFLAG(IS_CHROMEOS) // Notification that a trust anchor was used by the given user. virtual void OnTrustAnchorUsed(BrowserContext* browser_context) {}
diff --git a/content/public/browser/federated_identity_active_session_permission_context_delegate.h b/content/public/browser/federated_identity_active_session_permission_context_delegate.h index 5aa3036..60711a4 100644 --- a/content/public/browser/federated_identity_active_session_permission_context_delegate.h +++ b/content/public/browser/federated_identity_active_session_permission_context_delegate.h
@@ -19,21 +19,22 @@ FederatedIdentityActiveSessionPermissionContextDelegate() = default; virtual ~FederatedIdentityActiveSessionPermissionContextDelegate() = default; - // Determine whether the relying_party has an existing active session for - // the specified account_identifier with the identity_provider. - virtual bool HasActiveSession(const url::Origin& relying_party, + // Determine whether the `relying_party_requester` has an existing active + // session for the specified `account_identifier` with the + // `identity_provider`. + virtual bool HasActiveSession(const url::Origin& relying_party_requester, const url::Origin& identity_provider, const std::string& account_identifier) = 0; - // Grant active session capabilities between the relying_party and - // identity_provider origins for the specified account. - virtual void GrantActiveSession(const url::Origin& relying_party, + // Grant active session capabilities between the `relying_party_requester` and + // `identity_provider` origins for the specified account. + virtual void GrantActiveSession(const url::Origin& relying_party_requester, const url::Origin& identity_provider, const std::string& account_identifier) = 0; - // Revoke a previously-provided grant from the relying_party to the provider - // for the specified account. - virtual void RevokeActiveSession(const url::Origin& relying_party, + // Revoke a previously-provided grant from the `relying_party_requester` to + // the `identity_provider` for the specified account. + virtual void RevokeActiveSession(const url::Origin& relying_party_requester, const url::Origin& identity_provider, const std::string& account_identifier) = 0; };
diff --git a/content/public/browser/federated_identity_api_permission_context_delegate.h b/content/public/browser/federated_identity_api_permission_context_delegate.h index f209baa..a737288 100644 --- a/content/public/browser/federated_identity_api_permission_context_delegate.h +++ b/content/public/browser/federated_identity_api_permission_context_delegate.h
@@ -28,18 +28,21 @@ FederatedIdentityApiPermissionContextDelegate() = default; virtual ~FederatedIdentityApiPermissionContextDelegate() = default; - // Returns the status of the FedCM API for the passed-in |rp_origin|. + // Returns the status of the FedCM API for the passed-in + // |relying_party_embedder|. virtual PermissionStatus GetApiPermissionStatus( - const url::Origin& rp_origin) = 0; + const url::Origin& relying_party_embedder) = 0; // Records that the FedCM prompt was explicitly dismissed and places the - // permission under embargo for the passed-in |rp_origin|. - virtual void RecordDismissAndEmbargo(const url::Origin& rp_origin) = 0; + // permission under embargo for the passed-in |relying_party_embedder|. + virtual void RecordDismissAndEmbargo( + const url::Origin& relying_party_embedder) = 0; - // Clears any existing embargo status for |url| for the FEDERATED_IDENTITY_API - // permission for the passed-in |rp_origin|. Clears the dismiss and ignore - // counts. - virtual void RemoveEmbargoAndResetCounts(const url::Origin& rp_origin) = 0; + // Clears any existing embargo status for the FEDERATED_IDENTITY_API + // permission for the passed-in |relying_party_embedder|. Clears the dismiss + // and ignore counts. + virtual void RemoveEmbargoAndResetCounts( + const url::Origin& relying_party_embedder) = 0; // This function is so we can avoid the delay in tests. It does not really // belong on this delegate but we don't have a better one and it seems
diff --git a/content/public/browser/federated_identity_sharing_permission_context_delegate.h b/content/public/browser/federated_identity_sharing_permission_context_delegate.h index 0a7abdce..a0e27edb 100644 --- a/content/public/browser/federated_identity_sharing_permission_context_delegate.h +++ b/content/public/browser/federated_identity_sharing_permission_context_delegate.h
@@ -17,17 +17,21 @@ FederatedIdentitySharingPermissionContextDelegate() = default; virtual ~FederatedIdentitySharingPermissionContextDelegate() = default; - // Determine whether the requester has an existing permission grant to share - // identity information for the given account to the relying party. - virtual bool HasSharingPermission(const url::Origin& relying_party, + // Determine whether there is an existing permission grant to share identity + // information for the given account to the `relying_party_requester` when + // embedded in `relying_party_embedder`. + virtual bool HasSharingPermission(const url::Origin& relying_party_requester, + const url::Origin& relying_party_embedder, const url::Origin& identity_provider, const std::string& account_id) = 0; - // Grant permission for the requester to share identity information for the - // given account to the relying party. - virtual void GrantSharingPermission(const url::Origin& relying_party, - const url::Origin& identity_provider, - const std::string& account_id) = 0; + // Grants permission to share identity information for the given account to + // `relying_party_requester` when embedded in `relying_party_embedder`. + virtual void GrantSharingPermission( + const url::Origin& relying_party_requester, + const url::Origin& relying_party_embedder, + const url::Origin& identity_provider, + const std::string& account_id) = 0; }; } // namespace content
diff --git a/content/public/browser/media_stream_request.h b/content/public/browser/media_stream_request.h index 255a3777..89e3275 100644 --- a/content/public/browser/media_stream_request.h +++ b/content/public/browser/media_stream_request.h
@@ -86,6 +86,10 @@ // system-audio should nevertheless not be offered to the user. bool exclude_system_audio = false; + // Flag to indicate that the current tab should be excluded from the list of + // tabs offered to the user. + bool exclude_self_browser_surface = false; + // Flag to indicate whether the request is for PTZ use. bool request_pan_tilt_zoom_permission; };
diff --git a/content/public/browser/tts_utterance.h b/content/public/browser/tts_utterance.h index ea73614..ddf425e9 100644 --- a/content/public/browser/tts_utterance.h +++ b/content/public/browser/tts_utterance.h
@@ -8,6 +8,7 @@ #include <memory> #include <set> +#include "base/unguessable_token.h" #include "base/values.h" #include "content/common/content_export.h" #include "url/gurl.h" @@ -63,7 +64,10 @@ // Before speaking this utterance, its other parameters like text, rate, // pitch, etc. should all be set. static std::unique_ptr<TtsUtterance> Create(WebContents* web_contents); - static std::unique_ptr<TtsUtterance> Create(BrowserContext* browser_context); + // |should_always_be_spoken|: See comment for ShouldAlwaysBeSpoken(). + static std::unique_ptr<TtsUtterance> Create( + BrowserContext* browser_context, + bool should_always_be_spoken = false); static std::unique_ptr<TtsUtterance> Create(); virtual ~TtsUtterance() = default; @@ -126,6 +130,14 @@ virtual void ClearBrowserContext() = 0; virtual int GetId() = 0; virtual bool IsFinished() = 0; + virtual WebContents* GetWebContents() = 0; + + // An utterance could become invalid (for example, its associated WebContents + // has been destroyed) and therefore should not be spoken when it is + // processed by TtsController from the utterance queue. If this function + // returns true, it guarantees that the utterance must be a valid one and + // should be spoken. + virtual bool ShouldAlwaysBeSpoken() = 0; }; } // namespace content
diff --git a/content/public/common/url_constants.cc b/content/public/common/url_constants.cc index a502f88..17904d6 100644 --- a/content/public/common/url_constants.cc +++ b/content/public/common/url_constants.cc
@@ -37,6 +37,8 @@ const char kChromeUINetworkErrorHost[] = "network-error"; const char kChromeUINetworkErrorsListingHost[] = "network-errors"; const char kChromeUIPrerenderInternalsHost[] = "prerender-internals"; +const char kChromeUIPrivateAggregationInternalsHost[] = + "private-aggregation-internals"; const char kChromeUIProcessInternalsHost[] = "process-internals"; const char kChromeUIQuotaInternalsHost[] = "quota-internals"; const char kChromeUIResourcesHost[] = "resources";
diff --git a/content/public/common/url_constants.h b/content/public/common/url_constants.h index ebbb5796..ff7a3081 100644 --- a/content/public/common/url_constants.h +++ b/content/public/common/url_constants.h
@@ -47,6 +47,7 @@ CONTENT_EXPORT extern const char kChromeUINetworkErrorHost[]; CONTENT_EXPORT extern const char kChromeUINetworkErrorsListingHost[]; CONTENT_EXPORT extern const char kChromeUIPrerenderInternalsHost[]; +CONTENT_EXPORT extern const char kChromeUIPrivateAggregationInternalsHost[]; CONTENT_EXPORT extern const char kChromeUIProcessInternalsHost[]; CONTENT_EXPORT extern const char kChromeUIQuotaInternalsHost[]; CONTENT_EXPORT extern const char kChromeUIResourcesHost[];
diff --git a/content/public/test/browser_test_base.cc b/content/public/test/browser_test_base.cc index 0521a8f..bb2781f 100644 --- a/content/public/test/browser_test_base.cc +++ b/content/public/test/browser_test_base.cc
@@ -276,6 +276,7 @@ #elif BUILDFLAG(IS_MAC) ui::test::EventGeneratorDelegate::SetFactoryFunction( base::BindRepeating(&views::test::CreateEventGeneratorDelegateMac)); + EnableNativeWindowActivation(); #endif }
diff --git a/content/public/test/browser_test_utils.h b/content/public/test/browser_test_utils.h index 5c6d2d3..5c7793a1 100644 --- a/content/public/test/browser_test_utils.h +++ b/content/public/test/browser_test_utils.h
@@ -2293,6 +2293,13 @@ [[nodiscard]] bool HistoryGoBack(WebContents* wc); [[nodiscard]] bool HistoryGoForward(WebContents* wc); +#if BUILDFLAG(IS_MAC) +// Grant native windows the ability to activate, allowing them to become key +// and/or main. This can be useful to enable when the process hosting the window +// is a standalone executable without an Info.plist. +bool EnableNativeWindowActivation(); +#endif // BUILDFLAG(IS_MAC) + } // namespace content #endif // CONTENT_PUBLIC_TEST_BROWSER_TEST_UTILS_H_
diff --git a/content/public/test/browser_test_utils_mac.mm b/content/public/test/browser_test_utils_mac.mm new file mode 100644 index 0000000..fabd386 --- /dev/null +++ b/content/public/test/browser_test_utils_mac.mm
@@ -0,0 +1,24 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/public/test/browser_test_utils.h" + +#import <AppKit/AppKit.h> + +namespace content { + +bool EnableNativeWindowActivation() { + // Do not downgrade the activation policy. + if (NSApp.activationPolicy > NSApplicationActivationPolicyProhibited) { + return true; + } + + // NSApplicationActivationPolicyAccessory is the least permissive policy that + // still allows for programmatic activation. + return [NSApp setActivationPolicy:NSApplicationActivationPolicyAccessory] + ? true + : false; +} + +} // namespace content
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc index 0531a26..5a70dc2 100644 --- a/content/renderer/render_frame_impl.cc +++ b/content/renderer/render_frame_impl.cc
@@ -1164,8 +1164,9 @@ case blink::kWebNavigationPolicyNewWindow: return WindowOpenDisposition::NEW_WINDOW; case blink::kWebNavigationPolicyNewPopup: - case blink::kWebNavigationPolicyPictureInPicture: return WindowOpenDisposition::NEW_POPUP; + case blink::kWebNavigationPolicyPictureInPicture: + return WindowOpenDisposition::NEW_PICTURE_IN_PICTURE; } NOTREACHED() << "Unexpected WebNavigationPolicy"; return WindowOpenDisposition::IGNORE_ACTION;
diff --git a/content/shell/browser/shell_federated_permission_context.cc b/content/shell/browser/shell_federated_permission_context.cc index 45cb0bc..10422fe 100644 --- a/content/shell/browser/shell_federated_permission_context.cc +++ b/content/shell/browser/shell_federated_permission_context.cc
@@ -16,59 +16,63 @@ content::FederatedIdentityApiPermissionContextDelegate::PermissionStatus ShellFederatedPermissionContext::GetApiPermissionStatus( - const url::Origin& rp_origin) { + const url::Origin& relying_party_embedder) { return base::FeatureList::IsEnabled(features::kFedCm) ? PermissionStatus::GRANTED : PermissionStatus::BLOCKED_VARIATIONS; } void ShellFederatedPermissionContext::RecordDismissAndEmbargo( - const url::Origin& rp_origin) {} + const url::Origin& relying_party_embedder) {} void ShellFederatedPermissionContext::RemoveEmbargoAndResetCounts( - const url::Origin& rp_origin) {} + const url::Origin& relying_party_embedder) {} bool ShellFederatedPermissionContext::HasSharingPermission( - const url::Origin& relying_party, + const url::Origin& relying_party_requester, + const url::Origin& relying_party_embedder, const url::Origin& identity_provider, const std::string& account_id) { return sharing_permissions_.find(std::tuple( - relying_party.Serialize(), identity_provider.Serialize(), + relying_party_requester.Serialize(), + relying_party_embedder.Serialize(), identity_provider.Serialize(), account_id)) != sharing_permissions_.end(); } void ShellFederatedPermissionContext::GrantSharingPermission( - const url::Origin& relying_party, + const url::Origin& relying_party_requester, + const url::Origin& relying_party_embedder, const url::Origin& identity_provider, const std::string& account_id) { sharing_permissions_.insert(std::tuple( - relying_party.Serialize(), identity_provider.Serialize(), account_id)); + relying_party_requester.Serialize(), relying_party_embedder.Serialize(), + identity_provider.Serialize(), account_id)); } // FederatedIdentityActiveSessionPermissionContextDelegate bool ShellFederatedPermissionContext::HasActiveSession( - const url::Origin& relying_party, + const url::Origin& relying_party_requester, const url::Origin& identity_provider, const std::string& account_identifier) { return active_sessions_.find(std::tuple( - relying_party.Serialize(), identity_provider.Serialize(), + relying_party_requester.Serialize(), identity_provider.Serialize(), account_identifier)) != active_sessions_.end(); } void ShellFederatedPermissionContext::GrantActiveSession( - const url::Origin& relying_party, + const url::Origin& relying_party_requester, const url::Origin& identity_provider, const std::string& account_identifier) { - active_sessions_.insert(std::tuple(relying_party.Serialize(), + active_sessions_.insert(std::tuple(relying_party_requester.Serialize(), identity_provider.Serialize(), account_identifier)); } void ShellFederatedPermissionContext::RevokeActiveSession( - const url::Origin& relying_party, + const url::Origin& relying_party_requester, const url::Origin& identity_provider, const std::string& account_identifier) { - active_sessions_.erase(std::tuple(relying_party.Serialize(), + active_sessions_.erase(std::tuple(relying_party_requester.Serialize(), identity_provider.Serialize(), account_identifier)); }
diff --git a/content/shell/browser/shell_federated_permission_context.h b/content/shell/browser/shell_federated_permission_context.h index 91eb23c..c6f5e54 100644 --- a/content/shell/browser/shell_federated_permission_context.h +++ b/content/shell/browser/shell_federated_permission_context.h
@@ -28,38 +28,42 @@ // FederatedIdentityApiPermissionContextDelegate content::FederatedIdentityApiPermissionContextDelegate::PermissionStatus - GetApiPermissionStatus(const url::Origin& rp_origin) override; - void RecordDismissAndEmbargo(const url::Origin& rp_origin) override; - void RemoveEmbargoAndResetCounts(const url::Origin& rp_origin) override; + GetApiPermissionStatus(const url::Origin& relying_party_embedder) override; + void RecordDismissAndEmbargo( + const url::Origin& relying_party_embedder) override; + void RemoveEmbargoAndResetCounts( + const url::Origin& relying_party_embedder) override; // FederatedIdentitySharingPermissionContextDelegate - bool HasSharingPermission(const url::Origin& relying_party, + bool HasSharingPermission(const url::Origin& relying_party_requester, + const url::Origin& relying_party_embedder, const url::Origin& identity_provider, const std::string& account_id) override; - void GrantSharingPermission(const url::Origin& relying_party, + void GrantSharingPermission(const url::Origin& relying_party_requester, + const url::Origin& relying_party_embedder, const url::Origin& identity_provider, const std::string& account_id) override; // FederatedIdentityActiveSessionPermissionContextDelegate - bool HasActiveSession(const url::Origin& relying_party, + bool HasActiveSession(const url::Origin& relying_party_requester, const url::Origin& identity_provider, const std::string& account_identifier) override; - void GrantActiveSession(const url::Origin& relying_party, + void GrantActiveSession(const url::Origin& relying_party_requester, const url::Origin& identity_provider, const std::string& account_identifier) override; - void RevokeActiveSession(const url::Origin& relying_party, + void RevokeActiveSession(const url::Origin& relying_party_requester, const url::Origin& identity_provider, const std::string& account_identifier) override; bool ShouldCompleteRequestImmediately() const override; private: - // Pairs of <RP, IDP> + // Pairs of <RP embedder, IDP> std::set<std::pair<std::string, std::string>> request_permissions_; - // Tuples of <RP, IDP, Account> - std::set<std::tuple<std::string, std::string, std::string>> + // Tuples of <RP requester, RP embedder, IDP, Account> + std::set<std::tuple<std::string, std::string, std::string, std::string>> sharing_permissions_; - // Tuples of <RP, IDP, Account> + // Tuples of <RP requester, IDP, Account> std::set<std::tuple<std::string, std::string, std::string>> active_sessions_; };
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn index e20dd32..4330e25 100644 --- a/content/test/BUILD.gn +++ b/content/test/BUILD.gn
@@ -695,6 +695,7 @@ sources += [ "../browser/renderer_host/test_render_widget_host_view_mac_factory.h", "../browser/renderer_host/test_render_widget_host_view_mac_factory.mm", + "../public/test/browser_test_utils_mac.mm", "../public/test/text_input_test_utils_mac.mm", ] deps += [ @@ -1212,6 +1213,7 @@ "../browser/accessibility/site_per_process_accessibility_browsertest.cc", "../browser/accessibility/snapshot_ax_tree_browsertest.cc", "../browser/accessibility/touch_accessibility_aura_browsertest.cc", + "../browser/aggregation_service/aggregation_service_internals_browsertest.cc", "../browser/attribution_reporting/attribution_internals_browsertest.cc", "../browser/attribution_reporting/attribution_src_browsertest.cc", "../browser/attribution_reporting/attributions_browsertest.cc",
diff --git a/device/bluetooth/floss/floss_dbus_client.cc b/device/bluetooth/floss/floss_dbus_client.cc index 7c4dbb9..db2d90e 100644 --- a/device/bluetooth/floss/floss_dbus_client.cc +++ b/device/bluetooth/floss/floss_dbus_client.cc
@@ -423,39 +423,12 @@ template <> bool FlossDBusClient::ReadDBusParam(dbus::MessageReader* reader, FlossDeviceId* device) { - // Parse a FlossDeviceId from a message. - // - // The format: - // array ( - // dict_entry ( - // key "name" - // variant string("") - // ) - // dict entry ( - // key "address" - // variant string("") - // ) - // ) + static StructReader<FlossDeviceId> struct_reader({ + {"address", CreateFieldReader(&FlossDeviceId::address)}, + {"name", CreateFieldReader(&FlossDeviceId::name)}, + }); - dbus::MessageReader array(nullptr); - dbus::MessageReader dict(nullptr); - bool found_name = false; - bool found_address = false; - - if (reader->PopArray(&array)) { - while (array.PopDictEntry(&dict)) { - std::string key; - dict.PopString(&key); - - if (key == kDeviceIdNameKey) { - found_name = dict.PopVariantOfString(&device->name); - } else if (key == kDeviceIdAddressKey) { - found_address = dict.PopVariantOfString(&device->address); - } - } - } - - return found_name && found_address; + return struct_reader.ReadDBusParam(reader, device); } template <>
diff --git a/device/bluetooth/floss/floss_dbus_client.h b/device/bluetooth/floss/floss_dbus_client.h index de8a1ad..edaeb0da 100644 --- a/device/bluetooth/floss/floss_dbus_client.h +++ b/device/bluetooth/floss/floss_dbus_client.h
@@ -9,6 +9,7 @@ #include <string> #include "base/callback.h" +#include "base/containers/contains.h" #include "base/logging.h" #include "base/types/expected.h" #include "dbus/bus.h" @@ -374,6 +375,84 @@ return ReadDBusParam(reader, first) && ReadAllDBusParams(reader, args...); } + template <typename T> + using FieldReader = std::function<bool(dbus::MessageReader*, T* data)>; + + // Useful to generate D-Bus reader of a struct. Example usage: + // + // template <> + // bool FlossDBusClient::ReadDBusParam(dbus::MessageReader* reader, + // ScanResult* scan_result) { + // static StructReader<ScanResult> struct_reader({ + // {"address", CreateFieldReader(&ScanResult::address)}, + // {"addr_type", CreateFieldReader(&ScanResult::addr_type)}, + // <just define more fields here> + // }); + // return struct_reader.ReadDBusParam(reader, scan_result); + // } + template <typename T> + class StructReader { + private: + std::unordered_map<std::string, FieldReader<T>> fields_; + + public: + explicit StructReader( + std::vector<std::pair<std::string, FieldReader<T>>> fields) { + for (auto const& kv : fields) { + fields_.insert(kv); + } + }; + + bool ReadDBusParam(dbus::MessageReader* reader, T* data) { + // Keep track of parsed fields to detect missing and duplicate fields. + std::unordered_set<std::string> parsed_fields; + + dbus::MessageReader array_reader(nullptr); + if (!reader->PopArray(&array_reader)) + return false; + + // For each dictionary entry + while (array_reader.HasMoreData()) { + dbus::MessageReader entry_reader(nullptr); + if (!array_reader.PopDictEntry(&entry_reader)) + return false; + + std::string key; + if (!entry_reader.PopString(&key)) + return false; + + if (base::Contains(fields_, key)) { + dbus::MessageReader variant_reader(nullptr); + entry_reader.PopVariant(&variant_reader); + + if (!fields_[key](&variant_reader, data)) + return false; + + if (base::Contains(parsed_fields, key)) + return false; + + parsed_fields.insert(key); + } else { + DBusTypeInfo type_info = GetDBusTypeInfo<T>(); + VLOG(3) << "Does not know how to read field " << type_info.type_name + << "." << key; + } + } + + // All defined fields are required. + return parsed_fields.size() == fields_.size(); + } + }; + + // S is the type of the container struct. + // T is the type of the field. + template <typename S, typename T> + static FieldReader<S> CreateFieldReader(T S::*field) { + return [field](dbus::MessageReader* reader, S* container) -> bool { + return FlossDBusClient::ReadDBusParam(reader, &(container->*field)); + }; + } + template <typename R, typename... Args> void CallMethod(ResponseCallback<R> callback, dbus::Bus* bus,
diff --git a/extensions/browser/extension_prefs.cc b/extensions/browser/extension_prefs.cc index cfa38f1..7168afc8 100644 --- a/extensions/browser/extension_prefs.cc +++ b/extensions/browser/extension_prefs.cc
@@ -433,30 +433,28 @@ } void ExtensionPrefs::MakePathsRelative() { - const base::DictionaryValue* dict = &base::Value::AsDictionaryValue( - *prefs_->GetDictionary(pref_names::kExtensions)); - if (!dict || dict->DictEmpty()) + const base::Value::Dict& dict = prefs_->GetValueDict(pref_names::kExtensions); + if (dict.empty()) return; // Collect all extensions ids with absolute paths in |absolute_keys|. std::set<std::string> absolute_keys; - for (base::DictionaryValue::Iterator i(*dict); !i.IsAtEnd(); i.Advance()) { - const base::DictionaryValue* extension_dict = NULL; - if (!i.value().GetAsDictionary(&extension_dict)) + for (const auto [extension_id, extension_item] : dict) { + if (!extension_item.is_dict()) continue; - absl::optional<int> location_value = - extension_dict->FindIntKey(kPrefLocation); + const base::Value::Dict& extension_dict = extension_item.GetDict(); + absl::optional<int> location_value = extension_dict.FindInt(kPrefLocation); if (location_value && Manifest::IsUnpackedLocation( static_cast<ManifestLocation>(*location_value))) { // Unpacked extensions can have absolute paths. continue; } - std::string path_string; - if (!extension_dict->GetString(kPrefPath, &path_string)) + const std::string* path_string = extension_dict.FindString(kPrefPath); + if (!path_string) continue; - base::FilePath path = base::FilePath::FromUTF8Unsafe(path_string); + base::FilePath path = base::FilePath::FromUTF8Unsafe(*path_string); if (path.IsAbsolute()) - absolute_keys.insert(i.key()); + absolute_keys.insert(extension_id); } if (absolute_keys.empty()) return; @@ -487,11 +485,13 @@ if (extension_id.empty()) { return nullptr; } - const base::Value* extensions = - prefs_->GetDictionary(pref_names::kExtensions); - if (!extensions) + // TODO (https://crbug.com/1342019) This should call + // `PrefService::GetValueDict`, which will in turn require the return type to + // be `base::Value::Dict`. + const base::Value& extensions = prefs_->GetValue(pref_names::kExtensions); + if (!extensions.is_dict()) return nullptr; - const base::Value* extension_dict = extensions->FindDictPath(extension_id); + const base::Value* extension_dict = extensions.FindDictPath(extension_id); return extension_dict ? &base::Value::AsDictionaryValue(*extension_dict) : nullptr; } @@ -1163,8 +1163,11 @@ } base::Time ExtensionPrefs::BlocklistLastPingDay() const { + // TODO (https://crbug.com/1342019) This should call + // `PrefService::GetValueDict`, which will in turn require the return type to + // be `base::Value::Dict`. return ReadTime(&base::Value::AsDictionaryValue( - *prefs_->GetDictionary(kExtensionsBlocklistUpdate)), + prefs_->GetValue(kExtensionsBlocklistUpdate)), kLastPingDay); } @@ -1492,9 +1495,9 @@ std::unique_ptr<ExtensionInfo> ExtensionPrefs::GetInstalledInfoHelper( const std::string& extension_id, - const base::Value* extension, + const base::Value::Dict& extension, bool include_component_extensions) const { - absl::optional<int> location_value = extension->FindIntKey(kPrefLocation); + absl::optional<int> location_value = extension.FindInt(kPrefLocation); if (!location_value) return nullptr; @@ -1518,13 +1521,14 @@ return nullptr; } - const base::Value* manifest = extension->FindDictKey(kPrefManifest); - if (!Manifest::IsUnpackedLocation(location) && !manifest) { + const base::Value* manifest = extension.Find(kPrefManifest); + if (!Manifest::IsUnpackedLocation(location) && + !(manifest && manifest->is_dict())) { LOG(WARNING) << "Missing manifest for extension " << extension_id; // Just a warning for now. } - const std::string* path = extension->FindStringPath(kPrefPath); + const std::string* path = extension.FindString(kPrefPath); if (!path) return nullptr; base::FilePath file_path = base::FilePath::FromUTF8Unsafe(*path); @@ -1533,7 +1537,9 @@ if (!file_path.IsAbsolute()) file_path = install_directory_.Append(file_path); const base::DictionaryValue* manifest_dict = - manifest ? &base::Value::AsDictionaryValue(*manifest) : nullptr; + (manifest && manifest->is_dict()) + ? &base::Value::AsDictionaryValue(*manifest) + : nullptr; return std::make_unique<ExtensionInfo>(manifest_dict, extension_id, file_path, location); } @@ -1541,21 +1547,19 @@ std::unique_ptr<ExtensionInfo> ExtensionPrefs::GetInstalledExtensionInfo( const std::string& extension_id, bool include_component_extensions) const { - const base::Value* extensions = - prefs_->GetDictionary(pref_names::kExtensions); - if (!extensions) - return nullptr; - const base::Value* ext = extensions->FindDictKey(extension_id); + const base::Value::Dict& extensions = + prefs_->GetValueDict(pref_names::kExtensions); + const base::Value::Dict* ext = extensions.FindDict(extension_id); if (!ext) return nullptr; - absl::optional<int> state_value = ext->FindIntKey(kPrefState); + absl::optional<int> state_value = ext->FindInt(kPrefState); // TODO(devlin): Remove this once all clients are updated with // MigrateToNewExternalUninstallPref(). if (state_value == Extension::DEPRECATED_EXTERNAL_EXTENSION_UNINSTALLED) return nullptr; - return GetInstalledInfoHelper(extension_id, ext, + return GetInstalledInfoHelper(extension_id, *ext, include_component_extensions); } @@ -1564,9 +1568,9 @@ bool include_component_extensions) const { std::unique_ptr<ExtensionsInfo> extensions_info(new ExtensionsInfo); - const base::Value* extensions = - prefs_->GetDictionary(pref_names::kExtensions); - for (const auto extension_id : extensions->DictItems()) { + const base::Value::Dict& extensions = + prefs_->GetValueDict(pref_names::kExtensions); + for (const auto extension_id : extensions) { if (!crx_file::id_util::IdIsValid(extension_id.first)) continue; @@ -1663,7 +1667,7 @@ if (!ext) return nullptr; - return GetInstalledInfoHelper(extension_id, ext, + return GetInstalledInfoHelper(extension_id, ext->GetDict(), /*include_component_extensions = */ false); } @@ -1689,14 +1693,13 @@ ExtensionPrefs::GetAllDelayedInstallInfo() const { std::unique_ptr<ExtensionsInfo> extensions_info(new ExtensionsInfo); - const base::Value* extensions = - prefs_->GetDictionary(pref_names::kExtensions); - for (const auto extension_id : extensions->DictItems()) { - if (!crx_file::id_util::IdIsValid(extension_id.first)) + const base::Value::Dict& extensions = + prefs_->GetValueDict(pref_names::kExtensions); + for (const auto [extension_id, _] : extensions) { + if (!crx_file::id_util::IdIsValid(extension_id)) continue; - std::unique_ptr<ExtensionInfo> info = - GetDelayedInstallInfo(extension_id.first); + std::unique_ptr<ExtensionInfo> info = GetDelayedInstallInfo(extension_id); if (info) extensions_info->push_back(std::move(info)); } @@ -1805,8 +1808,8 @@ } void ExtensionPrefs::ClearLastLaunchTimes() { - const base::Value* dict = prefs_->GetDictionary(pref_names::kExtensions); - if (!dict || dict->DictEmpty()) + const base::Value::Dict& dict = prefs_->GetValueDict(pref_names::kExtensions); + if (dict.empty()) return; // Collect all the keys to remove the last launched preference from. @@ -1906,7 +1909,10 @@ const PrefMap& pref) const { DCHECK_EQ(PrefScope::kProfile, pref.scope); DCHECK_EQ(PrefType::kDictionary, pref.type); - return &base::Value::AsDictionaryValue(*prefs_->GetDictionary(pref.name)); + // TODO (https://crbug.com/1342019) This should call + // `PrefService::GetValueDict`, which will in turn require the return type to + // be `base::Value::Dict`. + return &base::Value::AsDictionaryValue(prefs_->GetValue(pref.name)); } std::unique_ptr<prefs::ScopedDictionaryPrefUpdate> @@ -2021,8 +2027,10 @@ } const base::DictionaryValue* ExtensionPrefs::GetInstallSignature() const { - return &base::Value::AsDictionaryValue( - *prefs_->GetDictionary(kInstallSignature)); + // TODO (https://crbug.com/1342019) This should call + // `PrefService::GetValueDict`, which will in turn require the return type to + // be `base::Value::Dict`. + return &base::Value::AsDictionaryValue(prefs_->GetValue(kInstallSignature)); } void ExtensionPrefs::SetInstallSignature( @@ -2454,14 +2462,14 @@ return; std::string key = extension_id + "." + scope_string; - const base::Value* source_dict = - pref_service()->GetDictionary(pref_names::kExtensions); + const base::Value::Dict& source_dict = + pref_service()->GetValueDict(pref_names::kExtensions); - const base::Value* preferences = source_dict->FindDictPath(key); + const base::Value::Dict* preferences = source_dict.FindDictByDottedPath(key); if (!preferences) return; - for (auto pair : preferences->DictItems()) { + for (auto pair : *preferences) { extension_pref_value_map_->SetExtensionPref(extension_id, pair.first, scope, pair.second.Clone()); } @@ -2549,16 +2557,15 @@ } void ExtensionPrefs::MigrateYoutubeOffBookmarkApps() { - const base::Value* extensions_dictionary = - prefs_->GetDictionary(pref_names::kExtensions); - DCHECK(extensions_dictionary->is_dict()); - const base::Value* youtube_dictionary = - extensions_dictionary->FindDictPath(extension_misc::kYoutubeAppId); + const base::Value::Dict& extensions_dictionary = + prefs_->GetValueDict(pref_names::kExtensions); + const base::Value::Dict* youtube_dictionary = + extensions_dictionary.FindDict(extension_misc::kYoutubeAppId); if (!youtube_dictionary) { return; } int creation_flags = - youtube_dictionary->FindIntKey(kPrefCreationFlags).value_or(0); + youtube_dictionary->FindInt(kPrefCreationFlags).value_or(0); if ((creation_flags & Extension::FROM_BOOKMARK) == 0) return; ScopedExtensionPrefUpdate update(prefs_, extension_misc::kYoutubeAppId); @@ -2567,9 +2574,8 @@ } void ExtensionPrefs::MigrateObsoleteExtensionPrefs() { - const base::Value* extensions_dictionary = - prefs_->GetDictionary(pref_names::kExtensions); - DCHECK(extensions_dictionary->is_dict()); + const base::Value::Dict& extensions_dictionary = + prefs_->GetValueDict(pref_names::kExtensions); // Please clean this list up periodically, removing any entries added more // than a year ago (with the exception of the testing key). @@ -2580,7 +2586,7 @@ // TODO(crbug.com/1015619): Remove 2023-05. Incorrect spelling from 2013. "id_mapping_dictioanry"}; - for (auto key_value : extensions_dictionary->DictItems()) { + for (auto key_value : extensions_dictionary) { if (!crx_file::id_util::IdIsValid(key_value.first)) continue; ScopedExtensionPrefUpdate update(prefs_, key_value.first); @@ -2635,13 +2641,11 @@ } void ExtensionPrefs::MigrateToNewExternalUninstallPref() { - const base::Value* extensions = - prefs_->GetDictionary(pref_names::kExtensions); - if (!extensions) - return; + const base::Value::Dict& extensions = + prefs_->GetValueDict(pref_names::kExtensions); std::vector<std::string> uninstalled_ids; - for (auto item : extensions->DictItems()) { + for (auto item : extensions) { if (!crx_file::id_util::IdIsValid(item.first) || !item.second.is_dict()) { continue; }
diff --git a/extensions/browser/extension_prefs.h b/extensions/browser/extension_prefs.h index e98d4e5..01e889ff1 100644 --- a/extensions/browser/extension_prefs.h +++ b/extensions/browser/extension_prefs.h
@@ -818,7 +818,7 @@ // |extension| dictionary. std::unique_ptr<ExtensionInfo> GetInstalledInfoHelper( const std::string& extension_id, - const base::Value* extension, + const base::Value::Dict& extension, bool include_component_extensions) const; // Read the boolean preference entry and return true if the preference exists
diff --git a/extensions/renderer/api/automation/automation_ax_tree_wrapper.cc b/extensions/renderer/api/automation/automation_ax_tree_wrapper.cc index 4b663c1..16ec6ec 100644 --- a/extensions/renderer/api/automation/automation_ax_tree_wrapper.cc +++ b/extensions/renderer/api/automation/automation_ax_tree_wrapper.cc
@@ -549,7 +549,7 @@ } ui::AXNode* AutomationAXTreeWrapper::GetNodeFromTree( - const ui::AXTreeID tree_id, + const ui::AXTreeID& tree_id, const ui::AXNodeID node_id) const { AutomationAXTreeWrapper* tree_wrapper = owner_->GetAutomationAXTreeWrapperFromTreeID(tree_id);
diff --git a/extensions/renderer/api/automation/automation_ax_tree_wrapper.h b/extensions/renderer/api/automation/automation_ax_tree_wrapper.h index a790d761..c2239817 100644 --- a/extensions/renderer/api/automation/automation_ax_tree_wrapper.h +++ b/extensions/renderer/api/automation/automation_ax_tree_wrapper.h
@@ -107,7 +107,7 @@ bool IsTreeIgnored(); // AXTreeManager overrides. - ui::AXNode* GetNodeFromTree(const ui::AXTreeID tree_id, + ui::AXNode* GetNodeFromTree(const ui::AXTreeID& tree_id, const ui::AXNodeID node_id) const override; ui::AXNode* GetNodeFromTree(const ui::AXNodeID node_id) const override; ui::AXTreeID GetParentTreeID() const override;
diff --git a/extensions/renderer/script_injection.cc b/extensions/renderer/script_injection.cc index 5fc0aba..4e98e861 100644 --- a/extensions/renderer/script_injection.cc +++ b/extensions/renderer/script_injection.cc
@@ -312,6 +312,17 @@ should_execute_asynchronously ? blink::mojom::EvaluationTiming::kAsynchronous : blink::mojom::EvaluationTiming::kSynchronous; + // Historically, when `kSynchronous` is used, we did not block the load + // event. We preserve this here for now to ensure we don't break anything. + // However, this is probably wrong, since the execution context could be + // paused, triggering an asynchronous execution of the script even when + // `kSynchronous` is used. + // TODO(crbug.com/1354639): Change this to block the load event, even with + // `kSynchronous`. + blink::mojom::LoadEventBlockingOption blocking_option = + should_execute_asynchronously + ? blink::mojom::LoadEventBlockingOption::kBlock + : blink::mojom::LoadEventBlockingOption::kDoNotBlock; int32_t world_id = blink::kMainDOMWorldId; switch (injector_->GetExecutionWorld()) { @@ -328,7 +339,7 @@ } render_frame_->GetWebFrame()->RequestExecuteScript( world_id, sources, injector_->IsUserGesture(), execution_option, - blink::mojom::LoadEventBlockingOption::kBlock, + blocking_option, base::BindOnce(&ScriptInjection::OnJsInjectionCompleted, weak_ptr_factory_.GetWeakPtr()), blink::BackForwardCacheAware::kPossiblyDisallow,
diff --git a/fuchsia_web/webengine/browser/web_engine_browser_main_parts.cc b/fuchsia_web/webengine/browser/web_engine_browser_main_parts.cc index 4d43477..e6cfe6aa 100644 --- a/fuchsia_web/webengine/browser/web_engine_browser_main_parts.cc +++ b/fuchsia_web/webengine/browser/web_engine_browser_main_parts.cc
@@ -303,6 +303,10 @@ // Main loop should quit only after all Context instances have been destroyed. DCHECK_EQ(context_bindings_.size(), 0u); + // FrameHost channels may still be active and contain live Frames. Close them + // here so that they are torn-down before their dependent resources. + frame_host_bindings_.CloseAll(); + // These resources must be freed while a MessageLoop is still available, so // that they may post cleanup tasks during teardown. // NOTE: Objects are destroyed in the reverse order of their creation.
diff --git a/gpu/config/gpu_finch_features.cc b/gpu/config/gpu_finch_features.cc index caf3a0d3..4d4f6433 100644 --- a/gpu/config/gpu_finch_features.cc +++ b/gpu/config/gpu_finch_features.cc
@@ -56,7 +56,7 @@ // Used to limit GL version to 2.0 for skia raster and compositing. const base::Feature kUseGles2ForOopR { "UseGles2ForOopR", -#if BUILDFLAG(IS_ANDROID) +#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS) base::FEATURE_DISABLED_BY_DEFAULT #else base::FEATURE_ENABLED_BY_DEFAULT
diff --git a/infra/config/generated/luci/commit-queue.cfg b/infra/config/generated/luci/commit-queue.cfg index 6c7be3e..7d63690 100644 --- a/infra/config/generated/luci/commit-queue.cfg +++ b/infra/config/generated/luci/commit-queue.cfg
@@ -4343,6 +4343,7 @@ ref_regexp_exclude: "refs/branch-heads/5060" ref_regexp_exclude: "refs/branch-heads/5112" ref_regexp_exclude: "refs/branch-heads/5195" + ref_regexp_exclude: "refs/branch-heads/5249" } } verifiers {
diff --git a/infra/config/generated/luci/cr-buildbucket.cfg b/infra/config/generated/luci/cr-buildbucket.cfg index ecbbd08..70562568 100644 --- a/infra/config/generated/luci/cr-buildbucket.cfg +++ b/infra/config/generated/luci/cr-buildbucket.cfg
@@ -50042,7 +50042,6 @@ builders { name: "runner" swarming_host: "chromium-swarm.appspot.com" - dimensions: "builder:runner" dimensions: "pool:luci.chromium.ci" exe { cipd_package: "infra/chromium/bootstrapper/${platform}" @@ -50072,7 +50071,7 @@ ' "led_builder_is_bootstrapped": true,' ' "recipe": "reviver/chromium/runner"' '}' - service_account: "reviver-builder@chops-service-accounts.iam.gserviceaccount.com" + service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com" experiments { key: "luci.recipes.use_python3" value: 100
diff --git a/infra/config/generated/luci/luci-milo.cfg b/infra/config/generated/luci/luci-milo.cfg index 741c122b..2f501fa 100644 --- a/infra/config/generated/luci/luci-milo.cfg +++ b/infra/config/generated/luci/luci-milo.cfg
@@ -873,6 +873,10 @@ url: "/p/chromium-m105/g/main/console" } links { + text: "m106" + url: "/p/chromium-m106/g/main/console" + } + links { text: "trunk" url: "/p/chromium/g/main/console" alt: "Trunk (ToT) console" @@ -1633,6 +1637,10 @@ url: "/p/chromium-m105/g/main/console" } links { + text: "m106" + url: "/p/chromium-m106/g/main/console" + } + links { text: "trunk" url: "/p/chromium/g/main/console" alt: "Trunk (ToT) console" @@ -2117,6 +2125,10 @@ url: "/p/chromium-m105/g/main/console" } links { + text: "m106" + url: "/p/chromium-m106/g/main/console" + } + links { text: "trunk" url: "/p/chromium/g/main/console" alt: "Trunk (ToT) console" @@ -2476,6 +2488,10 @@ url: "/p/chromium-m105/g/main/console" } links { + text: "m106" + url: "/p/chromium-m106/g/main/console" + } + links { text: "trunk" url: "/p/chromium/g/main/console" alt: "Trunk (ToT) console" @@ -3173,6 +3189,10 @@ url: "/p/chromium-m105/g/main/console" } links { + text: "m106" + url: "/p/chromium-m106/g/main/console" + } + links { text: "trunk" url: "/p/chromium/g/main/console" alt: "Trunk (ToT) console" @@ -3513,6 +3533,10 @@ url: "/p/chromium-m105/g/main/console" } links { + text: "m106" + url: "/p/chromium-m106/g/main/console" + } + links { text: "trunk" url: "/p/chromium/g/main/console" alt: "Trunk (ToT) console" @@ -4116,6 +4140,10 @@ url: "/p/chromium-m105/g/main/console" } links { + text: "m106" + url: "/p/chromium-m106/g/main/console" + } + links { text: "trunk" url: "/p/chromium/g/main/console" alt: "Trunk (ToT) console" @@ -4539,6 +4567,10 @@ url: "/p/chromium-m105/g/main/console" } links { + text: "m106" + url: "/p/chromium-m106/g/main/console" + } + links { text: "trunk" url: "/p/chromium/g/main/console" alt: "Trunk (ToT) console" @@ -4948,6 +4980,10 @@ url: "/p/chromium-m105/g/main/console" } links { + text: "m106" + url: "/p/chromium-m106/g/main/console" + } + links { text: "trunk" url: "/p/chromium/g/main/console" alt: "Trunk (ToT) console" @@ -5395,6 +5431,10 @@ url: "/p/chromium-m105/g/main/console" } links { + text: "m106" + url: "/p/chromium-m106/g/main/console" + } + links { text: "trunk" url: "/p/chromium/g/main/console" alt: "Trunk (ToT) console" @@ -5959,6 +5999,10 @@ url: "/p/chromium-m105/g/main/console" } links { + text: "m106" + url: "/p/chromium-m106/g/main/console" + } + links { text: "trunk" url: "/p/chromium/g/main/console" alt: "Trunk (ToT) console" @@ -6428,6 +6472,10 @@ url: "/p/chromium-m105/g/main/console" } links { + text: "m106" + url: "/p/chromium-m106/g/main/console" + } + links { text: "trunk" url: "/p/chromium/g/main/console" alt: "Trunk (ToT) console" @@ -6809,6 +6857,10 @@ url: "/p/chromium-m105/g/main/console" } links { + text: "m106" + url: "/p/chromium-m106/g/main/console" + } + links { text: "trunk" url: "/p/chromium/g/main/console" alt: "Trunk (ToT) console" @@ -7178,6 +7230,10 @@ url: "/p/chromium-m105/g/main/console" } links { + text: "m106" + url: "/p/chromium-m106/g/main/console" + } + links { text: "trunk" url: "/p/chromium/g/main/console" alt: "Trunk (ToT) console" @@ -7671,6 +7727,10 @@ url: "/p/chromium-m105/g/main/console" } links { + text: "m106" + url: "/p/chromium-m106/g/main/console" + } + links { text: "trunk" url: "/p/chromium/g/main/console" alt: "Trunk (ToT) console" @@ -8563,6 +8623,10 @@ url: "/p/chromium-m105/g/main/console" } links { + text: "m106" + url: "/p/chromium-m106/g/main/console" + } + links { text: "trunk" url: "/p/chromium/g/main/console" alt: "Trunk (ToT) console" @@ -8994,6 +9058,10 @@ url: "/p/chromium-m105/g/main/console" } links { + text: "m106" + url: "/p/chromium-m106/g/main/console" + } + links { text: "trunk" url: "/p/chromium/g/main/console" alt: "Trunk (ToT) console" @@ -9399,6 +9467,10 @@ url: "/p/chromium-m105/g/main/console" } links { + text: "m106" + url: "/p/chromium-m106/g/main/console" + } + links { text: "trunk" url: "/p/chromium/g/main/console" alt: "Trunk (ToT) console" @@ -9799,6 +9871,10 @@ url: "/p/chromium-m105/g/main/console" } links { + text: "m106" + url: "/p/chromium-m106/g/main/console" + } + links { text: "trunk" url: "/p/chromium/g/main/console" alt: "Trunk (ToT) console" @@ -10436,6 +10512,10 @@ url: "/p/chromium-m105/g/main/console" } links { + text: "m106" + url: "/p/chromium-m106/g/main/console" + } + links { text: "trunk" url: "/p/chromium/g/main/console" alt: "Trunk (ToT) console" @@ -10850,6 +10930,10 @@ url: "/p/chromium-m105/g/main/console" } links { + text: "m106" + url: "/p/chromium-m106/g/main/console" + } + links { text: "trunk" url: "/p/chromium/g/main/console" alt: "Trunk (ToT) console" @@ -11279,6 +11363,10 @@ url: "/p/chromium-m105/g/main/console" } links { + text: "m106" + url: "/p/chromium-m106/g/main/console" + } + links { text: "trunk" url: "/p/chromium/g/main/console" alt: "Trunk (ToT) console" @@ -11733,6 +11821,10 @@ url: "/p/chromium-m105/g/main/console" } links { + text: "m106" + url: "/p/chromium-m106/g/main/console" + } + links { text: "trunk" url: "/p/chromium/g/main/console" alt: "Trunk (ToT) console" @@ -12097,6 +12189,10 @@ url: "/p/chromium-m105/g/main/console" } links { + text: "m106" + url: "/p/chromium-m106/g/main/console" + } + links { text: "trunk" url: "/p/chromium/g/main/console" alt: "Trunk (ToT) console" @@ -12551,6 +12647,10 @@ url: "/p/chromium-m105/g/main/console" } links { + text: "m106" + url: "/p/chromium-m106/g/main/console" + } + links { text: "trunk" url: "/p/chromium/g/main/console" alt: "Trunk (ToT) console" @@ -12906,6 +13006,10 @@ url: "/p/chromium-m105/g/main/console" } links { + text: "m106" + url: "/p/chromium-m106/g/main/console" + } + links { text: "trunk" url: "/p/chromium/g/main/console" alt: "Trunk (ToT) console" @@ -13285,6 +13389,10 @@ url: "/p/chromium-m105/g/main/console" } links { + text: "m106" + url: "/p/chromium-m106/g/main/console" + } + links { text: "trunk" url: "/p/chromium/g/main/console" alt: "Trunk (ToT) console" @@ -13764,6 +13872,10 @@ url: "/p/chromium-m105/g/main/console" } links { + text: "m106" + url: "/p/chromium-m106/g/main/console" + } + links { text: "trunk" url: "/p/chromium/g/main/console" alt: "Trunk (ToT) console" @@ -14138,6 +14250,10 @@ url: "/p/chromium-m105/g/main/console" } links { + text: "m106" + url: "/p/chromium-m106/g/main/console" + } + links { text: "trunk" url: "/p/chromium/g/main/console" alt: "Trunk (ToT) console" @@ -14553,6 +14669,10 @@ url: "/p/chromium-m105/g/main/console" } links { + text: "m106" + url: "/p/chromium-m106/g/main/console" + } + links { text: "trunk" url: "/p/chromium/g/main/console" alt: "Trunk (ToT) console" @@ -14947,6 +15067,10 @@ url: "/p/chromium-m105/g/main/console" } links { + text: "m106" + url: "/p/chromium-m106/g/main/console" + } + links { text: "trunk" url: "/p/chromium/g/main/console" alt: "Trunk (ToT) console" @@ -15352,6 +15476,10 @@ url: "/p/chromium-m105/g/main/console" } links { + text: "m106" + url: "/p/chromium-m106/g/main/console" + } + links { text: "trunk" url: "/p/chromium/g/main/console" alt: "Trunk (ToT) console" @@ -15690,6 +15818,10 @@ url: "/p/chromium-m105/g/main/console" } links { + text: "m106" + url: "/p/chromium-m106/g/main/console" + } + links { text: "trunk" url: "/p/chromium/g/main/console" alt: "Trunk (ToT) console" @@ -16042,6 +16174,10 @@ url: "/p/chromium-m105/g/main/console" } links { + text: "m106" + url: "/p/chromium-m106/g/main/console" + } + links { text: "trunk" url: "/p/chromium/g/main/console" alt: "Trunk (ToT) console"
diff --git a/infra/config/generated/luci/realms.cfg b/infra/config/generated/luci/realms.cfg index d6ba620..7c2ce5cc 100644 --- a/infra/config/generated/luci/realms.cfg +++ b/infra/config/generated/luci/realms.cfg
@@ -388,6 +388,7 @@ principals: "project:chromium-m103" principals: "project:chromium-m104" principals: "project:chromium-m105" + principals: "project:chromium-m106" principals: "project:chromium-m96" principals: "project:chromium-m97" principals: "user:chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com" @@ -441,6 +442,7 @@ principals: "project:chromium-m103" principals: "project:chromium-m104" principals: "project:chromium-m105" + principals: "project:chromium-m106" principals: "project:chromium-m96" principals: "project:chromium-m97" principals: "user:chromium-orchestrator@chops-service-accounts.iam.gserviceaccount.com" @@ -490,6 +492,7 @@ name: "reviver" bindings { role: "role/buildbucket.builderServiceAccount" + principals: "user:chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com" principals: "user:reviver-builder@chops-service-accounts.iam.gserviceaccount.com" } bindings {
diff --git a/infra/config/milestones.json b/infra/config/milestones.json index 4c77587..9cd9d5e 100644 --- a/infra/config/milestones.json +++ b/infra/config/milestones.json
@@ -33,5 +33,10 @@ "name": "m105", "project": "chromium-m105", "ref": "refs/branch-heads/5195" + }, + "106": { + "name": "m106", + "project": "chromium-m106", + "ref": "refs/branch-heads/5249" } }
diff --git a/infra/config/subprojects/reviver/reviver.star b/infra/config/subprojects/reviver/reviver.star index 4c6126f..fe97b8b 100644 --- a/infra/config/subprojects/reviver/reviver.star +++ b/infra/config/subprojects/reviver/reviver.star
@@ -83,6 +83,10 @@ builder( name = "runner", executable = "recipe:reviver/chromium/runner", + auto_builder_dimension = False, # TODO(crbug/1346396) Figure out what machines the runnner should run on pool = ci.DEFAULT_POOL, + # TODO(crbug/1346396) Remove this once the reviver service account has + # necessary permissions + service_account = ci.DEFAULT_SERVICE_ACCOUNT, )
diff --git a/ios/chrome/app/spotlight/bookmarks_spotlight_manager.mm b/ios/chrome/app/spotlight/bookmarks_spotlight_manager.mm index 279c8ec3..b59eadf 100644 --- a/ios/chrome/app/spotlight/bookmarks_spotlight_manager.mm +++ b/ios/chrome/app/spotlight/bookmarks_spotlight_manager.mm
@@ -105,7 +105,8 @@ void BookmarkNodeAdded(bookmarks::BookmarkModel* model, const bookmarks::BookmarkNode* parent, - size_t index) override { + size_t index, + bool added_by_user) override { [owner_ refreshNodeInIndex:parent->children()[index].get() initial:NO]; }
diff --git a/ios/chrome/browser/flags/about_flags.mm b/ios/chrome/browser/flags/about_flags.mm index 025eea4..9cfd85b 100644 --- a/ios/chrome/browser/flags/about_flags.mm +++ b/ios/chrome/browser/flags/about_flags.mm
@@ -843,6 +843,16 @@ flag_descriptions::kUseLensToSearchForImageName, flag_descriptions::kUseLensToSearchForImageDescription, flags_ui::kOsIos, FEATURE_VALUE_TYPE(kUseLensToSearchForImage)}, + {"enable-lens-in-home-screen-widget", + flag_descriptions::kEnableLensInHomeScreenWidgetName, + flag_descriptions::kEnableLensInHomeScreenWidgetDescription, + flags_ui::kOsIos, FEATURE_VALUE_TYPE(kEnableLensInHomeScreenWidget)}, + {"enable-lens-in-keyboard", flag_descriptions::kEnableLensInKeyboardName, + flag_descriptions::kEnableLensInKeyboardDescription, flags_ui::kOsIos, + FEATURE_VALUE_TYPE(kEnableLensInKeyboard)}, + {"enable-lens-in-ntp", flag_descriptions::kEnableLensInNTPName, + flag_descriptions::kEnableLensInNTPDescription, flags_ui::kOsIos, + FEATURE_VALUE_TYPE(kEnableLensInNTP)}, {"use-load-simulated-request-for-error-page-navigation", flag_descriptions::kUseLoadSimulatedRequestForOfflinePageName, flag_descriptions::kUseLoadSimulatedRequestForOfflinePageDescription,
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc index c4dbe6fd..581c63a3 100644 --- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc +++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
@@ -714,6 +714,26 @@ "When enabled, use Lens to search for images from the long press context " "menu when Google is the selected search engine."; +const char kEnableLensInHomeScreenWidgetName[] = + "Enable Google Lens in the Home Screen Widget"; +const char kEnableLensInHomeScreenWidgetDescription[] = + "When enabled, use Lens to search for images from your device camera " + "menu when Google is the selected search engine, accessible from the" + "home screen widget."; + +const char kEnableLensInKeyboardName[] = + "Enable Google Lens in the Omnibox Keyboard"; +const char kEnableLensInKeyboardDescription[] = + "When enabled, use Lens to search for images from your device camera " + "menu when Google is the selected search engine, accessible from the" + "omnibox keyboard."; + +const char kEnableLensInNTPName[] = "Enable Google Lens in the NTP"; +const char kEnableLensInNTPDescription[] = + "When enabled, use Lens to search for images from your device camera " + "menu when Google is the selected search engine, accessible from the" + "new tab page."; + const char kUseLoadSimulatedRequestForOfflinePageName[] = "Use loadSimulatedRequest:responseHTMLString: when displaying offline " "pages";
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h index a1a916b..7ff68c87 100644 --- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h +++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
@@ -646,6 +646,21 @@ extern const char kUseLensToSearchForImageName[]; extern const char kUseLensToSearchForImageDescription[]; +// Title and description for the flag to enable using Lens to search using +// the device camera from the home screen widget. +extern const char kEnableLensInHomeScreenWidgetName[]; +extern const char kEnableLensInHomeScreenWidgetDescription[]; + +// Title and description for the flag to enable using Lens to search using +// the device camera from the keyboard. +extern const char kEnableLensInKeyboardName[]; +extern const char kEnableLensInKeyboardDescription[]; + +// Title and description for the flag to enable using Lens to search using +// the device camera from the ntp. +extern const char kEnableLensInNTPName[]; +extern const char kEnableLensInNTPDescription[]; + // Title and description for the flag to enable using the // loadSimulatedRequest:responseHTMLString: API for displaying error pages in // CRWWKNavigationHandler.
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/infobar_overlay_browser_agent.h b/ios/chrome/browser/infobars/overlays/browser_agent/infobar_overlay_browser_agent.h index e6ec3f7..e8a867c8 100644 --- a/ios/chrome/browser/infobars/overlays/browser_agent/infobar_overlay_browser_agent.h +++ b/ios/chrome/browser/infobars/overlays/browser_agent/infobar_overlay_browser_agent.h
@@ -26,7 +26,7 @@ // Adds an InfobarInteractionHandler to make model-layer updates for // interactions with infobars. An OverlayCallbackInstaller will be created - // from each added handler for each InfobarOverlayType. |interaction_handler| + // from each added handler for each InfobarOverlayType. `interaction_handler` // must not be null. Only one interaction handler for a given InfobarType // can be added. void AddInfobarInteractionHandler( @@ -40,7 +40,7 @@ explicit InfobarOverlayBrowserAgent(Browser* browser); // Returns the interaction handler for the InfobarType of the infobar used to - // configure |request|, or nullptr if |request| is not supported. + // configure `request`, or nullptr if `request` is not supported. InfobarInteractionHandler* GetInteractionHandler(OverlayRequest* request); // Helper object that notifies interaction handler of changes in infobar UI @@ -53,7 +53,7 @@ private: // Notifies the BrowserAgent's interaction handler that the visibility of - // |request|'s UI has changed. + // `request`'s UI has changed. void OverlayVisibilityChanged(OverlayRequest* request, bool visible); // OverlayPresenterObserver:
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/infobar_overlay_browser_agent_unittest.mm b/ios/chrome/browser/infobars/overlays/browser_agent/infobar_overlay_browser_agent_unittest.mm index b61d71c..f7fae38a 100644 --- a/ios/chrome/browser/infobars/overlays/browser_agent/infobar_overlay_browser_agent_unittest.mm +++ b/ios/chrome/browser/infobars/overlays/browser_agent/infobar_overlay_browser_agent_unittest.mm
@@ -101,9 +101,9 @@ } // Creates the OverlayRequestCallbackInstaller to return from - // CreateInstaller() for the mock interaction handler for |overlay_type|. + // CreateInstaller() for the mock interaction handler for `overlay_type`. // Returned installers forwards callbacks to the receivers in - // |mock_callback_receivers_|. + // `mock_callback_receivers_`. std::unique_ptr<FakeOverlayRequestCallbackInstaller> CreateInstaller( InfobarOverlayType overlay_type) { std::unique_ptr<FakeOverlayRequestCallbackInstaller> installer = @@ -168,7 +168,7 @@ EXPECT_CALL(*mock_handler(), InfobarVisibilityChanged(&infobar_, /*visible=*/true)); queue()->AddRequest(std::move(added_request)); - // Verify that dispatched responses sent through |request|'s callback manager + // Verify that dispatched responses sent through `request`'s callback manager // are received by the expected receiver. EXPECT_CALL(*mock_callback_receiver(), DispatchCallback(request, DispatchInfo::ResponseSupport()));
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/infobar_overlay_browser_agent_util.h b/ios/chrome/browser/infobars/overlays/browser_agent/infobar_overlay_browser_agent_util.h index 2587034..9eab5d2 100644 --- a/ios/chrome/browser/infobars/overlays/browser_agent/infobar_overlay_browser_agent_util.h +++ b/ios/chrome/browser/infobars/overlays/browser_agent/infobar_overlay_browser_agent_util.h
@@ -7,7 +7,7 @@ class Browser; -// Attaches browser agents to |browser| that manage the model changes for +// Attaches browser agents to `browser` that manage the model changes for // infobar UI presented via OverlayPresenter. void AttachInfobarOverlayBrowserAgent(Browser* browser);
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_banner_interaction_handler.h b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_banner_interaction_handler.h index 5db5bc40..5dbbfb8e 100644 --- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_banner_interaction_handler.h +++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_banner_interaction_handler.h
@@ -26,7 +26,7 @@ void BannerDismissedByUser(InfoBarIOS* infobar) override; private: - // Returns the SaveAddressProfile delegate from |infobar|. + // Returns the SaveAddressProfile delegate from `infobar`. autofill::AutofillSaveUpdateAddressProfileDelegateIOS* GetInfobarDelegate( InfoBarIOS* infobar); };
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_modal_interaction_handler.h b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_modal_interaction_handler.h index ace6325f..e2c2773 100644 --- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_modal_interaction_handler.h +++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_modal_interaction_handler.h
@@ -41,7 +41,7 @@ std::unique_ptr<InfobarModalOverlayRequestCallbackInstaller> CreateModalInstaller() override; - // Returns the SaveAddressProfile delegate from |infobar|. + // Returns the SaveAddressProfile delegate from `infobar`. autofill::AutofillSaveUpdateAddressProfileDelegateIOS* GetInfoBarDelegate( InfoBarIOS* infobar); };
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_modal_overlay_request_callback_installer.h b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_modal_overlay_request_callback_installer.h index c9fd884..7185081 100644 --- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_modal_overlay_request_callback_installer.h +++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_modal_overlay_request_callback_installer.h
@@ -16,22 +16,22 @@ : public InfobarModalOverlayRequestCallbackInstaller { public: // Constructor for an instance that installs callbacks that forward - // interaction events to |interaction_handler|. + // interaction events to `interaction_handler`. explicit SaveAddressProfileInfobarModalOverlayRequestCallbackInstaller( SaveAddressProfileInfobarModalInteractionHandler* interaction_handler); ~SaveAddressProfileInfobarModalOverlayRequestCallbackInstaller() override; private: - // Used as a callback for OverlayResponses dispatched through |request|'s + // Used as a callback for OverlayResponses dispatched through `request`'s // callback manager. The OverlayDispatchCallback is created with an - // OverlayResponseSupport that guarantees that |response| is created with a + // OverlayResponseSupport that guarantees that `response` is created with a // save_address_profile_infobar_modal_responses::EditedProfileSaveAction. void SaveEditedProfileDetailsCallback(OverlayRequest* request, OverlayResponse* response); - // Used as a callback for OverlayResponses dispatched through |request|'s + // Used as a callback for OverlayResponses dispatched through `request`'s // callback manager. The OverlayDispatchCallback is created with an - // OverlayResponseSupport that guarantees that |response| is created with a + // OverlayResponseSupport that guarantees that `response` is created with a // save_address_profile_infobar_modal_responses::CancelViewAction. void CancelModalCallback(OverlayRequest* request, OverlayResponse* response);
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/common/infobar_banner_interaction_handler.h b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/common/infobar_banner_interaction_handler.h index 468603f..18ae5ff 100644 --- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/common/infobar_banner_interaction_handler.h +++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/common/infobar_banner_interaction_handler.h
@@ -22,17 +22,17 @@ : public InfobarInteractionHandler::Handler { public: // Constructor for a banner interaction handler that creates callback - // installers with |request_support|. + // installers with `request_support`. explicit InfobarBannerInteractionHandler( const OverlayRequestSupport* request_support); ~InfobarBannerInteractionHandler() override; - // Updates the model when the visibility of |infobar|'s banner is changed. + // Updates the model when the visibility of `infobar`'s banner is changed. virtual void BannerVisibilityChanged(InfoBarIOS* infobar, bool visible) {} - // Updates the model when the main button is tapped for |infobar|'s banner. + // Updates the model when the main button is tapped for `infobar`'s banner. virtual void MainButtonTapped(InfoBarIOS* infobar) {} - // Shows the modal when the modal button is tapped for |infobar|'s banner. - // |web_state| is the WebState associated with |infobar|'s InfoBarManager. + // Shows the modal when the modal button is tapped for `infobar`'s banner. + // `web_state` is the WebState associated with `infobar`'s InfoBarManager. virtual void ShowModalButtonTapped(InfoBarIOS* infobar, web::WebState* web_state); // Notifies the model that the upcoming dismissal is user-initiated (i.e.
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/common/infobar_banner_overlay_request_callback_installer.h b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/common/infobar_banner_overlay_request_callback_installer.h index 30f6d9e..ea515da 100644 --- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/common/infobar_banner_overlay_request_callback_installer.h +++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/common/infobar_banner_overlay_request_callback_installer.h
@@ -16,8 +16,8 @@ : public OverlayRequestCallbackInstaller { public: // Constructor for an instance that installs callbacks for OverlayRequests - // supported by |request_support| that forward interaction events to - // |interaction_handler|. + // supported by `request_support` that forward interaction events to + // `interaction_handler`. InfobarBannerOverlayRequestCallbackInstaller( const OverlayRequestSupport* request_support, InfobarBannerInteractionHandler* interaction_handler); @@ -28,34 +28,34 @@ void InstallCallbacksInternal(OverlayRequest* request) override; private: - // Used as a callback for OverlayResponses dispatched through |request|'s + // Used as a callback for OverlayResponses dispatched through `request`'s // callback manager. The OverlayDispatchCallback is created with an - // OverlayResponseSupport that guarantees that |response| is created with an + // OverlayResponseSupport that guarantees that `response` is created with an // InfobarBannerMainActionResponse. void MainActionButtonTapped(OverlayRequest* request, OverlayResponse* response); - // Used as a callback for OverlayResponses dispatched through |request|'s + // Used as a callback for OverlayResponses dispatched through `request`'s // callback manager. The OverlayDispatchCallback is created with an - // OverlayResponseSupport that guarantees that |response| is created with an + // OverlayResponseSupport that guarantees that `response` is created with an // InfobarBannerShowModalResponse. void ShowModalButtonTapped(OverlayRequest* request, OverlayResponse* response); - // Used as a callback for OverlayResponses dispatched through |request|'s + // Used as a callback for OverlayResponses dispatched through `request`'s // callback manager. The OverlayDispatchCallback is created with an - // OverlayResponseSupport that guarantees that |response| is created with an + // OverlayResponseSupport that guarantees that `response` is created with an // InfobarBannerUserInitiatedDismissalResponse. void BannerDismissedByUser(OverlayRequest* request, OverlayResponse* response); - // Used as a callback for OverlayResponses dispatched through |request|'s + // Used as a callback for OverlayResponses dispatched through `request`'s // callback manager. The OverlayDispatchCallback is created with an - // OverlayResponseSupport that guarantees that |response| is created with an + // OverlayResponseSupport that guarantees that `response` is created with an // InfobarBannerRemoveInfobarResponse. void RemoveInfobar(OverlayRequest* request, OverlayResponse* response); // OverlayRequestCallbackInstaller: const OverlayRequestSupport* GetRequestSupport() const override; - // The request support for |interaction_handler_|. + // The request support for `interaction_handler_`. const OverlayRequestSupport* request_support_ = nullptr; // The handler for received responses. InfobarBannerInteractionHandler* interaction_handler_ = nullptr;
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/common/infobar_modal_interaction_handler.h b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/common/infobar_modal_interaction_handler.h index 5910e7a..81ccd805 100644 --- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/common/infobar_modal_interaction_handler.h +++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/common/infobar_modal_interaction_handler.h
@@ -16,7 +16,7 @@ public: ~InfobarModalInteractionHandler() override; - // Updates the model to perform the main action for |infobar|. + // Updates the model to perform the main action for `infobar`. virtual void PerformMainAction(InfoBarIOS* infobar) = 0; protected:
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/common/infobar_modal_overlay_request_callback_installer.h b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/common/infobar_modal_overlay_request_callback_installer.h index 0a536d1..22c4623 100644 --- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/common/infobar_modal_overlay_request_callback_installer.h +++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/common/infobar_modal_overlay_request_callback_installer.h
@@ -19,8 +19,8 @@ protected: // Constructor for an instance that installs callbacks for OverlayRequests - // supported by |request_support| that forward interaction events to - // |interaction_handler|. + // supported by `request_support` that forward interaction events to + // `interaction_handler`. InfobarModalOverlayRequestCallbackInstaller( const OverlayRequestSupport* request_support, InfobarModalInteractionHandler* interaction_handler); @@ -31,16 +31,16 @@ void InstallCallbacksInternal(OverlayRequest* request) override; private: - // Used as a callback for OverlayResponses dispatched through |request|'s + // Used as a callback for OverlayResponses dispatched through `request`'s // callback manager. The OverlayDispatchCallback is created with an - // OverlayResponseSupport that guarantees that |response| is created with an + // OverlayResponseSupport that guarantees that `response` is created with an // InfobarModalMainActionResponse. void MainActionCallback(OverlayRequest* request, OverlayResponse* response); // OverlayRequestCallbackInstaller: const OverlayRequestSupport* GetRequestSupport() const override; - // The request support for |interaction_handler_|. + // The request support for `interaction_handler_`. const OverlayRequestSupport* request_support_ = nullptr; // The handler for received responses. InfobarModalInteractionHandler* interaction_handler_ = nullptr;
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/confirm/confirm_infobar_banner_interaction_handler.h b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/confirm/confirm_infobar_banner_interaction_handler.h index f5b744a4..bbaf059 100644 --- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/confirm/confirm_infobar_banner_interaction_handler.h +++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/confirm/confirm_infobar_banner_interaction_handler.h
@@ -22,7 +22,7 @@ void BannerVisibilityChanged(InfoBarIOS* infobar, bool visible) override; private: - // Returns the password delegate from |infobar|. + // Returns the password delegate from `infobar`. ConfirmInfoBarDelegate* GetInfobarDelegate(InfoBarIOS* infobar); };
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/infobar_interaction_handler.h b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/infobar_interaction_handler.h index 827a0aa..d0d20c2 100644 --- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/infobar_interaction_handler.h +++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/infobar_interaction_handler.h
@@ -30,15 +30,15 @@ // handler's InfobarOverlayType. virtual std::unique_ptr<OverlayRequestCallbackInstaller> CreateInstaller() = 0; - // Notifies the handler that |infobar|'s UI with the handler's InfobarType + // Notifies the handler that `infobar`'s UI with the handler's InfobarType virtual void InfobarVisibilityChanged(InfoBarIOS* infobar, bool visible) = 0; }; // Constructor for an InfobarInteractionHandler that uses the provided - // handlers for each InfobarOverlayType. |banner_handler| must be non-null. - // |modal_handler| may be null if its corresponding InfobarOverlayType is not - // supported for |infobar_type|. + // handlers for each InfobarOverlayType. `banner_handler` must be non-null. + // `modal_handler` may be null if its corresponding InfobarOverlayType is not + // supported for `infobar_type`. InfobarInteractionHandler(InfobarType infobar_type, std::unique_ptr<Handler> banner_handler, std::unique_ptr<Handler> modal_handler); @@ -58,8 +58,8 @@ std::unique_ptr<OverlayRequestCallbackInstaller> CreateModalCallbackInstaller(); - // Called to notify the interaction handler that |infobar|'s overlay UI with - // |overlay_type|'s visibility has changed. + // Called to notify the interaction handler that `infobar`'s overlay UI with + // `overlay_type`'s visibility has changed. void InfobarVisibilityChanged(InfoBarIOS* infobar, InfobarOverlayType overlay_type, bool visible);
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/passwords/password_infobar_banner_interaction_handler.h b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/passwords/password_infobar_banner_interaction_handler.h index 7e355ce2..8d9e8f69 100644 --- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/passwords/password_infobar_banner_interaction_handler.h +++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/passwords/password_infobar_banner_interaction_handler.h
@@ -23,7 +23,7 @@ void MainButtonTapped(InfoBarIOS* infobar) override; private: - // Returns the password delegate from |infobar|. + // Returns the password delegate from `infobar`. IOSChromeSavePasswordInfoBarDelegate* GetInfobarDelegate(InfoBarIOS* infobar); };
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/passwords/password_infobar_modal_interaction_handler.h b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/passwords/password_infobar_modal_interaction_handler.h index c5fb1975..4abcca9 100644 --- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/passwords/password_infobar_modal_interaction_handler.h +++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/passwords/password_infobar_modal_interaction_handler.h
@@ -20,23 +20,23 @@ password_modal::PasswordAction action_type); ~PasswordInfobarModalInteractionHandler() override; - // Instructs the handler to update the credentials with |username| and - // |password| for interaction with |infobar|'s modal UI. + // Instructs the handler to update the credentials with `username` and + // `password` for interaction with `infobar`'s modal UI. // TODO(crbug.com/1040653): This function is only virtual so it can be mocked // for testing purposes. It should become non-virtual once the password // infobar delegate is refactored for testability. virtual void UpdateCredentials(InfoBarIOS* infobar, NSString* username, NSString* password); - // Instructs the handler that the user has used |infobar|'s modal UI to + // Instructs the handler that the user has used `infobar`'s modal UI to // request that credentials are never saved for the current site. // TODO(crbug.com/1040653): This function is only virtual so it can be mocked // for testing purposes. It should become non-virtual once the password // infobar delegate is refactored for testability. virtual void NeverSaveCredentials(InfoBarIOS* infobar); // Instructs the handler that the user has requested the passwords settings - // page through |infobar|'s modal UI. The settings will be presented after - // the dismissal of |infobar|'s modal UI. + // page through `infobar`'s modal UI. The settings will be presented after + // the dismissal of `infobar`'s modal UI. // TODO(crbug.com/1040653): This function is only virtual so it can be mocked // for testing purposes. It should become non-virtual once the password // infobar delegate is refactored for testability. @@ -59,7 +59,7 @@ std::unique_ptr<InfobarModalOverlayRequestCallbackInstaller> CreateModalInstaller() override; - // Returns the password delegate from |infobar|. + // Returns the password delegate from `infobar`. IOSChromeSavePasswordInfoBarDelegate* GetDelegate(InfoBarIOS* infobar); // The Browser passed on initialization.
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/passwords/password_infobar_modal_overlay_request_callback_installer.h b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/passwords/password_infobar_modal_overlay_request_callback_installer.h index 77478f3..97e18d6 100644 --- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/passwords/password_infobar_modal_overlay_request_callback_installer.h +++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/passwords/password_infobar_modal_overlay_request_callback_installer.h
@@ -18,38 +18,38 @@ : public InfobarModalOverlayRequestCallbackInstaller { public: // Constructor for an instance that installs callbacks that forward - // interaction events to |interaction_handler| for an Password Infobar Overlay - // of type |action_type|. + // interaction events to `interaction_handler` for an Password Infobar Overlay + // of type `action_type`. explicit PasswordInfobarModalOverlayRequestCallbackInstaller( PasswordInfobarModalInteractionHandler* interaction_handler, password_modal::PasswordAction action_type); ~PasswordInfobarModalOverlayRequestCallbackInstaller() override; private: - // Used as a callback for OverlayResponses dispatched through |request|'s + // Used as a callback for OverlayResponses dispatched through `request`'s // callback manager. The OverlayDispatchCallback is created with an - // OverlayResponseSupport that guarantees that |response| is created with an + // OverlayResponseSupport that guarantees that `response` is created with an // password_infobar_modal_responses::UpdateCredentialsInfo. void UpdateCredentialsCallback(OverlayRequest* request, OverlayResponse* response); - // Used as a callback for OverlayResponses dispatched through |request|'s + // Used as a callback for OverlayResponses dispatched through `request`'s // callback manager. The OverlayDispatchCallback is created with an - // OverlayResponseSupport that guarantees that |response| is created with a + // OverlayResponseSupport that guarantees that `response` is created with a // password_infobar_modal_responses::NeverSaveCredentials. void NeverSaveCredentialsCallback(OverlayRequest* request, OverlayResponse* response); - // Used as a callback for OverlayResponses dispatched through |request|'s + // Used as a callback for OverlayResponses dispatched through `request`'s // callback manager. The OverlayDispatchCallback is created with an - // OverlayResponseSupport that guarantees that |response| is created with a + // OverlayResponseSupport that guarantees that `response` is created with a // password_infobar_modal_responses::PresentPasswordSettings. void PresentPasswordsSettingsCallback(OverlayRequest* request, OverlayResponse* response); - // Used as an optional completion callback for |request|. Removes the + // Used as an optional completion callback for `request`. Removes the // request's infobar from its manager upon completion. void RemoveInfobarCompletionCallback(OverlayRequest* request, OverlayResponse* response); - // Used as an optional completion callback for |request|. Presents the + // Used as an optional completion callback for `request`. Presents the // password settings. void PresentPasswordSettingsCompletionCallback(OverlayRequest* request, OverlayResponse* response);
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/save_card/save_card_infobar_banner_interaction_handler.h b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/save_card/save_card_infobar_banner_interaction_handler.h index 779f2a0..15150ad 100644 --- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/save_card/save_card_infobar_banner_interaction_handler.h +++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/save_card/save_card_infobar_banner_interaction_handler.h
@@ -23,8 +23,8 @@ SaveCardInfobarBannerInteractionHandler(); ~SaveCardInfobarBannerInteractionHandler() override; - // Instructs the handler to update the credentials with |cardholder_name|, - // |expiration_date_month|, and |expiration_date_year|. This replaces + // Instructs the handler to update the credentials with `cardholder_name`, + // `expiration_date_month`, and `expiration_date_year`. This replaces // MainButtonTapped. virtual void SaveCredentials(InfoBarIOS* infobar, std::u16string cardholder_name, @@ -40,7 +40,7 @@ std::unique_ptr<InfobarBannerOverlayRequestCallbackInstaller> CreateBannerInstaller() override; - // Returns the SaveCard delegate from |infobar|. + // Returns the SaveCard delegate from `infobar`. autofill::AutofillSaveCardInfoBarDelegateMobile* GetInfobarDelegate( InfoBarIOS* infobar); };
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/save_card/save_card_infobar_banner_overlay_request_callback_installer.h b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/save_card/save_card_infobar_banner_overlay_request_callback_installer.h index fb6e5bb..c365547 100644 --- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/save_card/save_card_infobar_banner_overlay_request_callback_installer.h +++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/save_card/save_card_infobar_banner_overlay_request_callback_installer.h
@@ -14,15 +14,15 @@ : public InfobarBannerOverlayRequestCallbackInstaller { public: // Constructor for an instance that installs callbacks that forward - // interaction events to |interaction_handler|. + // interaction events to `interaction_handler`. explicit SaveCardInfobarBannerOverlayRequestCallbackInstaller( SaveCardInfobarBannerInteractionHandler* interaction_handler); ~SaveCardInfobarBannerOverlayRequestCallbackInstaller() override; private: - // Used as a callback for OverlayResponses dispatched through |request|'s + // Used as a callback for OverlayResponses dispatched through `request`'s // callback manager. The OverlayDispatchCallback is created with an - // OverlayResponseSupport that guarantees that |response| is created with an + // OverlayResponseSupport that guarantees that `response` is created with an // save_card_infobar_modal_responses::SaveCardMainAction. void SaveCredentialsCallback(OverlayRequest* request, OverlayResponse* response);
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/save_card/save_card_infobar_modal_interaction_handler.h b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/save_card/save_card_infobar_modal_interaction_handler.h index fb3ac8ad..1664eb3 100644 --- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/save_card/save_card_infobar_modal_interaction_handler.h +++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/save_card/save_card_infobar_modal_interaction_handler.h
@@ -22,15 +22,15 @@ SaveCardInfobarModalInteractionHandler(); ~SaveCardInfobarModalInteractionHandler() override; - // Instructs the handler to update the credentials with |cardholder_name|, - // |expiration_date_month|, and |expiration_date_year|. Replaces + // Instructs the handler to update the credentials with `cardholder_name`, + // `expiration_date_month`, and `expiration_date_year`. Replaces // MainButtonTapped. virtual void UpdateCredentials(InfoBarIOS* infobar, std::u16string cardholder_name, std::u16string expiration_date_month, std::u16string expiration_date_year); - // Instructs the handler to load |url| through the delegate. + // Instructs the handler to load `url` through the delegate. virtual void LoadURL(InfoBarIOS* infobar, GURL url); // InfobarModalInteractionHandler: @@ -42,7 +42,7 @@ std::unique_ptr<InfobarModalOverlayRequestCallbackInstaller> CreateModalInstaller() override; - // Returns the SaveCard delegate from |infobar|. + // Returns the SaveCard delegate from `infobar`. autofill::AutofillSaveCardInfoBarDelegateMobile* GetInfoBarDelegate( InfoBarIOS* infobar); };
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/save_card/save_card_infobar_modal_overlay_request_callback_installer.h b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/save_card/save_card_infobar_modal_overlay_request_callback_installer.h index b1ea213a..1cde498 100644 --- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/save_card/save_card_infobar_modal_overlay_request_callback_installer.h +++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/save_card/save_card_infobar_modal_overlay_request_callback_installer.h
@@ -16,21 +16,21 @@ : public InfobarModalOverlayRequestCallbackInstaller { public: // Constructor for an instance that installs callbacks that forward - // interaction events to |interaction_handler|. + // interaction events to `interaction_handler`. explicit SaveCardInfobarModalOverlayRequestCallbackInstaller( SaveCardInfobarModalInteractionHandler* interaction_handler); ~SaveCardInfobarModalOverlayRequestCallbackInstaller() override; private: - // Used as a callback for OverlayResponses dispatched through |request|'s + // Used as a callback for OverlayResponses dispatched through `request`'s // callback manager. The OverlayDispatchCallback is created with an - // OverlayResponseSupport that guarantees that |response| is created with an + // OverlayResponseSupport that guarantees that `response` is created with an // save_card_infobar_modal_responses::SaveCardMainAction. void SaveCardCredentialsCallback(OverlayRequest* request, OverlayResponse* response); - // Used as a callback for OverlayResponses dispatched through |request|'s + // Used as a callback for OverlayResponses dispatched through `request`'s // callback manager. The OverlayDispatchCallback is created with an - // OverlayResponseSupport that guarantees that |response| is created with a + // OverlayResponseSupport that guarantees that `response` is created with a // save_card_infobar_modal_responses::SaveCardLoadURL. void LoadURLCallback(OverlayRequest* request, OverlayResponse* response);
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/mock_infobar_interaction_handler.h b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/mock_infobar_interaction_handler.h index bb5eb4b..10f0c5ab 100644 --- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/mock_infobar_interaction_handler.h +++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/mock_infobar_interaction_handler.h
@@ -34,11 +34,11 @@ ~Builder(); // Constructs an InfobarInteractionHandler using mock handlers. Calling - // this function also populates |mock_handlers_|. Must only be called once + // this function also populates `mock_handlers_`. Must only be called once // per Builder. std::unique_ptr<InfobarInteractionHandler> Build(); - // Returns the mock handler for |overlay_type| used to build the + // Returns the mock handler for `overlay_type` used to build the // InfobarInteractionHandler. Returns null before Build() is called. Handler* mock_handler(InfobarOverlayType overlay_type) { return mock_handlers_[overlay_type];
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/translate_infobar_banner_interaction_handler.h b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/translate_infobar_banner_interaction_handler.h index d002252..19c31e0 100644 --- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/translate_infobar_banner_interaction_handler.h +++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/translate_infobar_banner_interaction_handler.h
@@ -21,7 +21,7 @@ void MainButtonTapped(InfoBarIOS* infobar) override; private: - // Returns the password delegate from |infobar|. + // Returns the password delegate from `infobar`. translate::TranslateInfoBarDelegate* GetInfobarDelegate(InfoBarIOS* infobar); };
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/translate_infobar_modal_interaction_handler.h b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/translate_infobar_modal_interaction_handler.h index 2cad065..81efa255 100644 --- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/translate_infobar_modal_interaction_handler.h +++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/translate_infobar_modal_interaction_handler.h
@@ -19,22 +19,22 @@ TranslateInfobarModalInteractionHandler(); ~TranslateInfobarModalInteractionHandler() override; - // Instructs the handler that the user has used |infobar|'s modal UI to + // Instructs the handler that the user has used `infobar`'s modal UI to // request that the always translate preference be toggled. virtual void ToggleAlwaysTranslate(InfoBarIOS* infobar); - // Instructs the handler that the user has used |infobar|'s modal UI to + // Instructs the handler that the user has used `infobar`'s modal UI to // request that the never translate source language preference be toggled. virtual void ToggleNeverTranslateLanguage(InfoBarIOS* infobar); - // Instructs the handler that the user has used |infobar|'s modal UI to + // Instructs the handler that the user has used `infobar`'s modal UI to // request that the never translate site preference be toggled. virtual void ToggleNeverTranslateSite(InfoBarIOS* infobar); - // Instructs the handler that the user has used |infobar|'s modal UI to + // Instructs the handler that the user has used `infobar`'s modal UI to // request that the translation be reverted. virtual void RevertTranslation(InfoBarIOS* infobar); - // Instructs the handler that the user has used |infobar|'s modal UI to + // Instructs the handler that the user has used `infobar`'s modal UI to // request that the source language change to the language at - // |source_language_index| and/or the target language change to the language - // at |target_language_index|. If either do not need to be updated, then the + // `source_language_index` and/or the target language change to the language + // at `target_language_index`. If either do not need to be updated, then the // index passed should be -1. virtual void UpdateLanguages(InfoBarIOS* infobar, int source_language_index, @@ -47,14 +47,14 @@ void InfobarVisibilityChanged(InfoBarIOS* infobar, bool visible) override; private: - // Initiates a translate for |infobar|. + // Initiates a translate for `infobar`. void StartTranslation(InfoBarIOS* infobar); // InfobarModalInteractionHandler: std::unique_ptr<InfobarModalOverlayRequestCallbackInstaller> CreateModalInstaller() override; - // Returns the translate delegate from |infobar|. + // Returns the translate delegate from `infobar`. translate::TranslateInfoBarDelegate* GetDelegate(InfoBarIOS* infobar); };
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/translate_infobar_modal_interaction_handler.mm b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/translate_infobar_modal_interaction_handler.mm index c53e63af..1b9dc1e 100644 --- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/translate_infobar_modal_interaction_handler.mm +++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/translate_infobar_modal_interaction_handler.mm
@@ -29,7 +29,7 @@ using translate_infobar_overlay::ModalRequestCallbackInstaller; namespace { -// Records a histogram of |histogram| for |langCode|. This is used to log the +// Records a histogram of `histogram` for `langCode`. This is used to log the // language distribution of certain Translate events. void RecordLanguageDataHistogram(const std::string& histogram_name, const std::string& lang_code) {
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/translate_infobar_modal_overlay_request_callback_installer.h b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/translate_infobar_modal_overlay_request_callback_installer.h index f8c52b2..9fff441 100644 --- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/translate_infobar_modal_overlay_request_callback_installer.h +++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/translate_infobar_modal_overlay_request_callback_installer.h
@@ -19,41 +19,41 @@ : public InfobarModalOverlayRequestCallbackInstaller { public: // Constructor for an instance that installs callbacks that forward - // interaction events to |interaction_handler|. + // interaction events to `interaction_handler`. explicit ModalRequestCallbackInstaller( TranslateInfobarModalInteractionHandler* interaction_handler); ~ModalRequestCallbackInstaller() override; private: - // Used as a callback for OverlayResponses dispatched through |request|'s + // Used as a callback for OverlayResponses dispatched through `request`'s // callback manager. The OverlayDispatchCallback is created with an - // OverlayResponseSupport that guarantees that |response| is created with an + // OverlayResponseSupport that guarantees that `response` is created with an // translate_infobar_modal_responses::RevertMainAction. void RevertTranslationCallback(OverlayRequest* request, OverlayResponse* response); - // Used as a callback for OverlayResponses dispatched through |request|'s + // Used as a callback for OverlayResponses dispatched through `request`'s // callback manager. The OverlayDispatchCallback is created with an - // OverlayResponseSupport that guarantees that |response| is created with an + // OverlayResponseSupport that guarantees that `response` is created with an // translate_infobar_modal_responses::ToggleAlwaysTranslate. void ToggleAlwaysTranslateCallback(OverlayRequest* request, OverlayResponse* response); - // Used as a callback for OverlayResponses dispatched through |request|'s + // Used as a callback for OverlayResponses dispatched through `request`'s // callback manager. The OverlayDispatchCallback is created with an - // OverlayResponseSupport that guarantees that |response| is created with a + // OverlayResponseSupport that guarantees that `response` is created with a // translate_infobar_modal_responses::ToggleNeverTranslateSourceLanguage. void ToggleNeverTranslateSourceLanguageCallback(OverlayRequest* request, OverlayResponse* response); - // Used as a callback for OverlayResponses dispatched through |request|'s + // Used as a callback for OverlayResponses dispatched through `request`'s // callback manager. The OverlayDispatchCallback is created with an - // OverlayResponseSupport that guarantees that |response| is created with a + // OverlayResponseSupport that guarantees that `response` is created with a // translate_infobar_modal_responses::ToggleNeverPromptSite. void ToggleNeverTranslateSiteCallback(OverlayRequest* request, OverlayResponse* response); - // Used as a callback for OverlayResponses dispatched through |request|'s + // Used as a callback for OverlayResponses dispatched through `request`'s // callback manager. The OverlayDispatchCallback is created with an - // OverlayResponseSupport that guarantees that |response| is created with a + // OverlayResponseSupport that guarantees that `response` is created with a // translate_infobar_modal_responses::UpdateLanguageInfo. void UpdateLanguageCallback(OverlayRequest* request, OverlayResponse* response);
diff --git a/ios/chrome/browser/infobars/overlays/infobar_banner_overlay_request_cancel_handler.h b/ios/chrome/browser/infobars/overlays/infobar_banner_overlay_request_cancel_handler.h index 000c37c..5dedd744 100644 --- a/ios/chrome/browser/infobars/overlays/infobar_banner_overlay_request_cancel_handler.h +++ b/ios/chrome/browser/infobars/overlays/infobar_banner_overlay_request_cancel_handler.h
@@ -15,9 +15,9 @@ class InfobarBannerOverlayRequestCancelHandler : public InfobarOverlayRequestCancelHandler { public: - // Constructor for a handler that cancels |request| from |queue|. |inserter| + // Constructor for a handler that cancels `request` from `queue`. `inserter` // is used to insert replacement requests when an infobar is replaced. - // |modal_completion_notifier| is used to detect the completion of any modal + // `modal_completion_notifier` is used to detect the completion of any modal // UI that was presented from the banner. InfobarBannerOverlayRequestCancelHandler( OverlayRequest* request, @@ -80,7 +80,7 @@ void ModalPresentedFromBanner() { presenting_modal_ = true; } // Indicates that a modal completed. Only called for modal completions of - // infobars that match the one used to configure |request|. + // infobars that match the one used to configure `request`. void ModalCompleted(); // InfobarOverlayRequestCancelHandler:
diff --git a/ios/chrome/browser/infobars/overlays/infobar_modal_completion_notifier.h b/ios/chrome/browser/infobars/overlays/infobar_modal_completion_notifier.h index 9c8a4d6..832b66f 100644 --- a/ios/chrome/browser/infobars/overlays/infobar_modal_completion_notifier.h +++ b/ios/chrome/browser/infobars/overlays/infobar_modal_completion_notifier.h
@@ -29,20 +29,20 @@ Observer() = default; ~Observer() override = default; - // Called to notify observers of |notifier| that the modal requests for - // |infobar| have completed. Banners should remain visible until all + // Called to notify observers of `notifier` that the modal requests for + // `infobar` have completed. Banners should remain visible until all // requests for modal UI originating from the banner's infobar is completed. virtual void InfobarModalsCompleted( InfobarModalCompletionNotifier* notifier, InfoBarIOS* infobar) {} - // Called when |notifier| is being destroyed. + // Called when `notifier` is being destroyed. virtual void InfobarModalCompletionNotifierDestroyed( InfobarModalCompletionNotifier* notifier) {} }; // Constructs a notifier that observes the completion of modal requests in - // |web_state|'s queue. + // `web_state`'s queue. explicit InfobarModalCompletionNotifier(web::WebState* web_state); ~InfobarModalCompletionNotifier(); @@ -60,7 +60,7 @@ private: // Used as a completion callback for the modal OverlayRequests for - // |infobar|. + // `infobar`. void ModalCompleted(InfoBarIOS* infobar, OverlayResponse* response); // OverlayRequestCallbackInstaller: @@ -72,11 +72,11 @@ base::WeakPtrFactory<ModalCompletionInstaller> weak_factory_; }; - // Called when a completion callback for a modal request for |infobar| has + // Called when a completion callback for a modal request for `infobar` has // been installed. void ModalCompletionInstalled(InfoBarIOS* infobar); - // Called when a modal request for |infobar| has been completed. + // Called when a modal request for `infobar` has been completed. void ModalRequestCompleted(InfoBarIOS* infobar); // Map storing the number of active modal OverlayRequests for a given
diff --git a/ios/chrome/browser/infobars/overlays/infobar_modal_completion_notifier_unittest.mm b/ios/chrome/browser/infobars/overlays/infobar_modal_completion_notifier_unittest.mm index 5ed47ea1..1084bc8 100644 --- a/ios/chrome/browser/infobars/overlays/infobar_modal_completion_notifier_unittest.mm +++ b/ios/chrome/browser/infobars/overlays/infobar_modal_completion_notifier_unittest.mm
@@ -53,10 +53,10 @@ scoped_observation_{&observer_}; }; -// Tests that the observer is notified when all modal requests for |infobar_| +// Tests that the observer is notified when all modal requests for `infobar_` // have been removed. TEST_F(InfobarModalCompletionNotifierTest, ModalCompletion) { - // Add a modal request for |infobar_|. + // Add a modal request for `infobar_`. std::unique_ptr<OverlayRequest> modal_request = OverlayRequest::CreateWithConfig<InfobarOverlayRequestConfig>( &infobar_, InfobarOverlayType::kModal, false);
diff --git a/ios/chrome/browser/infobars/overlays/infobar_modal_overlay_request_cancel_handler.h b/ios/chrome/browser/infobars/overlays/infobar_modal_overlay_request_cancel_handler.h index 49a514f2..43f69f8f 100644 --- a/ios/chrome/browser/infobars/overlays/infobar_modal_overlay_request_cancel_handler.h +++ b/ios/chrome/browser/infobars/overlays/infobar_modal_overlay_request_cancel_handler.h
@@ -14,8 +14,8 @@ class InfobarModalOverlayRequestCancelHandler : public InfobarOverlayRequestCancelHandler { public: - // Constructor for a handler that cancels |request| from |queue|. - // |modal_completion_notifier| is used to detect the completion of any modal + // Constructor for a handler that cancels `request` from `queue`. + // `modal_completion_notifier` is used to detect the completion of any modal // UI that was presented from the banner. InfobarModalOverlayRequestCancelHandler( OverlayRequest* request,
diff --git a/ios/chrome/browser/infobars/overlays/infobar_overlay_request_cancel_handler.h b/ios/chrome/browser/infobars/overlays/infobar_overlay_request_cancel_handler.h index 2628532..1833a646 100644 --- a/ios/chrome/browser/infobars/overlays/infobar_overlay_request_cancel_handler.h +++ b/ios/chrome/browser/infobars/overlays/infobar_overlay_request_cancel_handler.h
@@ -24,7 +24,7 @@ // Returns the InfoBar that the corresponding request was configured with. InfoBarIOS* infobar() const { return infobar_; } - // Called when the infobar triggering |request| was replaced in its manager. + // Called when the infobar triggering `request` was replaced in its manager. // Default implementation does nothing. virtual void HandleReplacement(InfoBarIOS* replacement);
diff --git a/ios/chrome/browser/infobars/overlays/infobar_overlay_request_inserter.h b/ios/chrome/browser/infobars/overlays/infobar_overlay_request_inserter.h index a81af8b..e0e3d35a 100644 --- a/ios/chrome/browser/infobars/overlays/infobar_overlay_request_inserter.h +++ b/ios/chrome/browser/infobars/overlays/infobar_overlay_request_inserter.h
@@ -49,7 +49,7 @@ class InfobarOverlayRequestInserter : public web::WebStateUserData<InfobarOverlayRequestInserter> { public: - // Creates an inserter for |web_state| that uses |request_factory| to create + // Creates an inserter for `web_state` that uses `request_factory` to create // inserted requests. static void CreateForWebState( web::WebState* web_state, @@ -57,7 +57,7 @@ ~InfobarOverlayRequestInserter() override; - // Creates an OverlayRequest with |params| configurations. + // Creates an OverlayRequest with `params` configurations. void InsertOverlayRequest(const InsertParams& params); // Notifies observers of Infobar request insertions @@ -67,12 +67,12 @@ ~Observer() override = default; // Called to notify observers that an Infobar request has been inserted - // with |params| configurations. - // |params.insertion_index| must be less than or equal to the size of the + // with `params` configurations. + // `params.insertion_index` must be less than or equal to the size of the // queue. virtual void InfobarRequestInserted(InfobarOverlayRequestInserter* inserter, const InsertParams& params) = 0; - // Called to notify observers that the |inserter| is about to be destroyed; + // Called to notify observers that the `inserter` is about to be destroyed; virtual void InserterDestroyed(InfobarOverlayRequestInserter* inserter) = 0; }; @@ -84,9 +84,9 @@ friend class web::WebStateUserData<InfobarOverlayRequestInserter>; WEB_STATE_USER_DATA_KEY_DECL(); - // Constructor for an inserter that uses |factory| to construct - // OverlayRequests to insert into |web_state|'s OverlayRequestQueues. Both - // |web_state| and |factory| must be non-null. + // Constructor for an inserter that uses `factory` to construct + // OverlayRequests to insert into `web_state`'s OverlayRequestQueues. Both + // `web_state` and `factory` must be non-null. InfobarOverlayRequestInserter(web::WebState* web_state, InfobarOverlayRequestFactory factory);
diff --git a/ios/chrome/browser/infobars/overlays/infobar_overlay_request_inserter.mm b/ios/chrome/browser/infobars/overlays/infobar_overlay_request_inserter.mm index 23d8e5e..3bfa5c14 100644 --- a/ios/chrome/browser/infobars/overlays/infobar_overlay_request_inserter.mm +++ b/ios/chrome/browser/infobars/overlays/infobar_overlay_request_inserter.mm
@@ -51,7 +51,7 @@ request_factory_(factory) { DCHECK(web_state_); DCHECK(request_factory_); - // Populate |queues_| with the request queues at the appropriate modalities. + // Populate `queues_` with the request queues at the appropriate modalities. queues_[InfobarOverlayType::kBanner] = OverlayRequestQueue::FromWebState( web_state_, OverlayModality::kInfobarBanner); queues_[InfobarOverlayType::kModal] = OverlayRequestQueue::FromWebState(
diff --git a/ios/chrome/browser/infobars/overlays/infobar_overlay_request_inserter_unittest.mm b/ios/chrome/browser/infobars/overlays/infobar_overlay_request_inserter_unittest.mm index 29a7556..453a1e8 100644 --- a/ios/chrome/browser/infobars/overlays/infobar_overlay_request_inserter_unittest.mm +++ b/ios/chrome/browser/infobars/overlays/infobar_overlay_request_inserter_unittest.mm
@@ -57,7 +57,7 @@ } // Adds an InfoBar created with a test delegate to the manager. Returns a - // pointer to the added InfoBar. If |message_text| matches an infobar already + // pointer to the added InfoBar. If `message_text` matches an infobar already // added, then it the new one will be ignored. InfoBar* CreateInfobar(std::u16string message_text) { std::unique_ptr<InfoBar> added_infobar = std::make_unique<FakeInfobarIOS>( @@ -75,7 +75,7 @@ TEST_F(InfobarOverlayRequestInserterTest, InsertBanner) { OverlayRequestQueue* queue = GetQueue(InfobarOverlayType::kBanner); ASSERT_EQ(0U, queue->size()); - // Insert |infobar| at front of queue and check that the queue is updated + // Insert `infobar` at front of queue and check that the queue is updated // correctly. InfoBar* infobar = CreateInfobar(kFirstInfobarMessageText); InsertParams params(static_cast<InfoBarIOS*>(infobar)); @@ -87,7 +87,7 @@ EXPECT_EQ(infobar, queue->front_request() ->GetConfig<InfobarOverlayRequestConfig>() ->infobar()); - // Insert |inserted_infobar| in front of |infobar| and check that it is now + // Insert `inserted_infobar` in front of `infobar` and check that it is now // the front request. InfoBar* inserted_infobar = CreateInfobar(kSecondInfobarMessageText); params.infobar = static_cast<InfoBarIOS*>(inserted_infobar); @@ -102,7 +102,7 @@ TEST_F(InfobarOverlayRequestInserterTest, AddBanner) { OverlayRequestQueue* queue = GetQueue(InfobarOverlayType::kBanner); ASSERT_EQ(0U, queue->size()); - // Add |infobar| to the back of the queue and check that the it is updated + // Add `infobar` to the back of the queue and check that the it is updated // correctly. InfoBar* infobar = CreateInfobar(kFirstInfobarMessageText); InsertParams params(static_cast<InfoBarIOS*>(infobar)); @@ -114,7 +114,7 @@ EXPECT_EQ(infobar, queue->front_request() ->GetConfig<InfobarOverlayRequestConfig>() ->infobar()); - // Add |second_infobar| in to the queue and check that it is second in the + // Add `second_infobar` in to the queue and check that it is second in the // queue. InfoBar* second_infobar = CreateInfobar(kSecondInfobarMessageText); params.infobar = static_cast<InfoBarIOS*>(second_infobar);
diff --git a/ios/chrome/browser/infobars/overlays/infobar_overlay_tab_helper_unittest.mm b/ios/chrome/browser/infobars/overlays/infobar_overlay_tab_helper_unittest.mm index 7f60061b..a9db153 100644 --- a/ios/chrome/browser/infobars/overlays/infobar_overlay_tab_helper_unittest.mm +++ b/ios/chrome/browser/infobars/overlays/infobar_overlay_tab_helper_unittest.mm
@@ -42,7 +42,7 @@ InfobarOverlayTabHelper::CreateForWebState(&web_state_); } - // Returns the front request of |web_state_|'s OverlayRequestQueue. + // Returns the front request of `web_state_`'s OverlayRequestQueue. OverlayRequest* front_request() { return OverlayRequestQueue::FromWebState(&web_state_, OverlayModality::kInfobarBanner)
diff --git a/ios/chrome/browser/infobars/overlays/infobar_overlay_util.h b/ios/chrome/browser/infobars/overlays/infobar_overlay_util.h index 6a67c0e9..749e0360 100644 --- a/ios/chrome/browser/infobars/overlays/infobar_overlay_util.h +++ b/ios/chrome/browser/infobars/overlays/infobar_overlay_util.h
@@ -14,24 +14,24 @@ class OverlayRequest; class OverlayRequestQueue; -// Returns the InfoBarIOS used to configure |request|, or null if the InfoBarIOS -// was already destroyed or if |request| was not created with an infobar config. +// Returns the InfoBarIOS used to configure `request`, or null if the InfoBarIOS +// was already destroyed or if `request` was not created with an infobar config. InfoBarIOS* GetOverlayRequestInfobar(OverlayRequest* request); -// Returns the InfobarType of the InfoBar used to configure |request|. -// |request| must be non-null and configured with an +// Returns the InfobarType of the InfoBar used to configure `request`. +// `request` must be non-null and configured with an // InfobarOverlayRequestConfig. -// TODO(crbug.com/1038933): Remove requirements on |request| and return +// TODO(crbug.com/1038933): Remove requirements on `request` and return // InfobarType::kNone once added. InfobarType GetOverlayRequestInfobarType(OverlayRequest* request); -// Returns the InfobarOverlayType for |request|. |request| must be non-null and +// Returns the InfobarOverlayType for `request`. `request` must be non-null and // configured with an InfobarOverlayRequestConfig. InfobarOverlayType GetOverlayRequestInfobarOverlayType(OverlayRequest* request); -// Searches through |queue| for an OverlayRequest configured with |infobar|. If -// found, returns true and populates |index| with the index of the first request -// configured with |infobar|. If no matching request was found, returns false. +// Searches through `queue` for an OverlayRequest configured with `infobar`. If +// found, returns true and populates `index` with the index of the first request +// configured with `infobar`. If no matching request was found, returns false. // All arguments must be non-null. bool GetInfobarOverlayRequestIndex(OverlayRequestQueue* queue, InfoBarIOS* infobar,
diff --git a/ios/chrome/browser/infobars/overlays/permissions_overlay_tab_helper_unittest.mm b/ios/chrome/browser/infobars/overlays/permissions_overlay_tab_helper_unittest.mm index eae50eb..037c758 100644 --- a/ios/chrome/browser/infobars/overlays/permissions_overlay_tab_helper_unittest.mm +++ b/ios/chrome/browser/infobars/overlays/permissions_overlay_tab_helper_unittest.mm
@@ -45,13 +45,13 @@ ~PermissionsOverlayTabHelperTest() override { InfoBarManagerImpl::FromWebState(&web_state_)->ShutDown(); - // Observer should be removed before |scoped_feature_list_| is reset. + // Observer should be removed before `scoped_feature_list_` is reset. web_state_.RemoveObserver( PermissionsOverlayTabHelper::FromWebState(&web_state_)); } protected: - // Returns InfoBarManager attached to |web_state()|. + // Returns InfoBarManager attached to `web_state()`. infobars::InfoBarManager* infobar_manager() { return InfoBarManagerImpl::FromWebState(&web_state_); }
diff --git a/ios/chrome/browser/infobars/overlays/translate_infobar_placeholder_overlay_request_cancel_handler.h b/ios/chrome/browser/infobars/overlays/translate_infobar_placeholder_overlay_request_cancel_handler.h index 77c5f28..08433b3 100644 --- a/ios/chrome/browser/infobars/overlays/translate_infobar_placeholder_overlay_request_cancel_handler.h +++ b/ios/chrome/browser/infobars/overlays/translate_infobar_placeholder_overlay_request_cancel_handler.h
@@ -22,7 +22,7 @@ class PlaceholderRequestCancelHandler : public InfobarOverlayRequestCancelHandler { public: - // Constructor for a handler that cancels |request| of |translate_infobar|. + // Constructor for a handler that cancels `request` of `translate_infobar`. PlaceholderRequestCancelHandler(OverlayRequest* request, OverlayRequestQueue* queue, TranslateOverlayTabHelper* tab_helper,
diff --git a/ios/chrome/browser/infobars/overlays/translate_overlay_tab_helper.h b/ios/chrome/browser/infobars/overlays/translate_overlay_tab_helper.h index 76d8d9bd..9166a75 100644 --- a/ios/chrome/browser/infobars/overlays/translate_overlay_tab_helper.h +++ b/ios/chrome/browser/infobars/overlays/translate_overlay_tab_helper.h
@@ -58,7 +58,7 @@ TranslateStepObserver(TranslateOverlayTabHelper* tab_helper); ~TranslateStepObserver() override; - // Starts observing |infobar|'s delegate, stores |infobar| for + // Starts observing `infobar`'s delegate, stores `infobar` for // TranslateDid[Start/Finish] void SetTranslateInfoBar(InfoBarIOS* infobar);
diff --git a/ios/chrome/browser/infobars/overlays/translate_overlay_tab_helper_unittest.mm b/ios/chrome/browser/infobars/overlays/translate_overlay_tab_helper_unittest.mm index 9ff1597..34385b4 100644 --- a/ios/chrome/browser/infobars/overlays/translate_overlay_tab_helper_unittest.mm +++ b/ios/chrome/browser/infobars/overlays/translate_overlay_tab_helper_unittest.mm
@@ -67,7 +67,7 @@ InfoBarManagerImpl::FromWebState(&web_state_)->ShutDown(); } - // Returns the front request of |web_state_|'s OverlayRequestQueue. + // Returns the front request of `web_state_`'s OverlayRequestQueue. OverlayRequest* front_request() { return OverlayRequestQueue::FromWebState(&web_state_, OverlayModality::kInfobarBanner)
diff --git a/ios/chrome/browser/promos_manager/constants.cc b/ios/chrome/browser/promos_manager/constants.cc index 3c7b3b5..5f23e703 100644 --- a/ios/chrome/browser/promos_manager/constants.cc +++ b/ios/chrome/browser/promos_manager/constants.cc
@@ -8,6 +8,8 @@ namespace promos_manager { +const int kLastSeenDayPromoNotFound = -1; + // WARNING - PLEASE READ: Sadly, we cannot switch over strings in C++, so be // very careful when updating this method to ensure all enums are accounted for. Promo PromoForName(std::string promo) {
diff --git a/ios/chrome/browser/promos_manager/constants.h b/ios/chrome/browser/promos_manager/constants.h index 3f30b3d..e2720bc 100644 --- a/ios/chrome/browser/promos_manager/constants.h +++ b/ios/chrome/browser/promos_manager/constants.h
@@ -9,10 +9,23 @@ namespace promos_manager { +// Sentinel value returned from PromosManager::LastSeenDay() if the +// promos_manager::Promo `promo` isn't found in the impressions list. +extern const int kLastSeenDayPromoNotFound; + enum class Promo { Test = 0, // Test promo used for testing purposes (e.g. unit tests) }; +typedef struct Impression { + Promo promo; + // A day (int) is represented as the number of days since the Unix epoch + // (running from UTC midnight to UTC midnight). + int day; + + Impression(Promo promo, int day) : promo(promo), day(day) {} +} Impression; + // Returns string representation of promos_manager::Promo `promo`. std::string NameForPromo(Promo promo);
diff --git a/ios/chrome/browser/promos_manager/promos_manager.h b/ios/chrome/browser/promos_manager/promos_manager.h index 97fce47..bda2f2f 100644 --- a/ios/chrome/browser/promos_manager/promos_manager.h +++ b/ios/chrome/browser/promos_manager/promos_manager.h
@@ -6,9 +6,11 @@ #define IOS_CHROME_BROWSER_PROMOS_MANAGER_PROMOS_MANAGER_H_ #import <Foundation/Foundation.h> +#import <vector> #import "base/values.h" #import "components/prefs/pref_service.h" +#import "ios/chrome/browser/promos_manager/constants.h" #import "ios/chrome/browser/promos_manager/impression_limit.h" // Centralized promos manager for coordinating and scheduling the display of @@ -38,6 +40,20 @@ // Impression limits that count against any given promo. NSArray<ImpressionLimit*>* GlobalPerPromoImpressionLimits(); + + // Returns the most recent day (int) that `promo` was seen by the user. + // + // A day (int) is represented as the number of days since the Unix epoch + // (running from UTC midnight to UTC midnight). + // + // Assumes that `sorted_impressions` is sorted by day (most recent -> least + // recent). + // + // Returns promos_manager::kLastSeenDayPromoNotFound if `promo` isn't + // found in the impressions list. + int LastSeenDay( + promos_manager::Promo promo, + std::vector<promos_manager::Impression>& sorted_impressions) const; }; #endif // IOS_CHROME_BROWSER_PROMOS_MANAGER_PROMOS_MANAGER_H_
diff --git a/ios/chrome/browser/promos_manager/promos_manager.mm b/ios/chrome/browser/promos_manager/promos_manager.mm index 3825229..8ad40235c 100644 --- a/ios/chrome/browser/promos_manager/promos_manager.mm +++ b/ios/chrome/browser/promos_manager/promos_manager.mm
@@ -5,10 +5,12 @@ #import "ios/chrome/browser/promos_manager/promos_manager.h" #import <Foundation/Foundation.h> +#import <vector> #import "base/values.h" #import "components/prefs/pref_service.h" #import "ios/chrome/browser/pref_names.h" +#import "ios/chrome/browser/promos_manager/constants.h" #import "ios/chrome/browser/promos_manager/features.h" #import "ios/chrome/browser/promos_manager/impression_limit.h" @@ -16,6 +18,15 @@ #error "This file requires ARC support." #endif +namespace { + +// Comparator for descending sort evaluation using std::is_sorted. +bool Compare(promos_manager::Impression a, promos_manager::Impression b) { + return a.day > b.day; +} + +} // namespace + #pragma mark - PromosManager #pragma mark - Constructor/Destructor @@ -73,3 +84,22 @@ return limits; } + +int PromosManager::LastSeenDay( + promos_manager::Promo promo, + std::vector<promos_manager::Impression>& sorted_impressions) const { + if (sorted_impressions.empty()) + return promos_manager::kLastSeenDayPromoNotFound; + + DCHECK(std::is_sorted(sorted_impressions.begin(), sorted_impressions.end(), + Compare)); + + // Find first occurrence of `promo` in list (i.e. find the most recent + // occurrence of `promo`). + for (size_t j = 0; j < sorted_impressions.size(); ++j) { + if (sorted_impressions[j].promo == promo) + return sorted_impressions[j].day; + } + + return promos_manager::kLastSeenDayPromoNotFound; +}
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_model_bridge_observer.h b/ios/chrome/browser/ui/bookmarks/bookmark_model_bridge_observer.h index 8f8c348a..3f7a05be 100644 --- a/ios/chrome/browser/ui/bookmarks/bookmark_model_bridge_observer.h +++ b/ios/chrome/browser/ui/bookmarks/bookmark_model_bridge_observer.h
@@ -54,7 +54,8 @@ size_t new_index) override; void BookmarkNodeAdded(BookmarkModel* model, const BookmarkNode* parent, - size_t index) override; + size_t index, + bool added_by_user) override; void BookmarkNodeRemoved(BookmarkModel* model, const BookmarkNode* parent, size_t old_index,
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_model_bridge_observer.mm b/ios/chrome/browser/ui/bookmarks/bookmark_model_bridge_observer.mm index d22d442..4f5ff51 100644 --- a/ios/chrome/browser/ui/bookmarks/bookmark_model_bridge_observer.mm +++ b/ios/chrome/browser/ui/bookmarks/bookmark_model_bridge_observer.mm
@@ -53,7 +53,8 @@ void BookmarkModelBridge::BookmarkNodeAdded(BookmarkModel* model, const BookmarkNode* parent, - size_t index) { + size_t index, + bool added_by_user) { [observer_ bookmarkNodeChildrenChanged:parent]; }
diff --git a/ios/chrome/browser/ui/first_run/trending_queries_field_trial.cc b/ios/chrome/browser/ui/first_run/trending_queries_field_trial.cc index e9e5644586..12cd30b 100644 --- a/ios/chrome/browser/ui/first_run/trending_queries_field_trial.cc +++ b/ios/chrome/browser/ui/first_run/trending_queries_field_trial.cc
@@ -53,6 +53,12 @@ weight_by_id[kTrendingQueriesControlID] = 10; break; case version_info::Channel::STABLE: + weight_by_id[kTrendingQueriesEnabledAllUsersID] = 1; + weight_by_id[kTrendingQueriesEnabledAllUsersHideShortcutsID] = 1; + weight_by_id[kTrendingQueriesEnabledDisabledFeedID] = 1; + weight_by_id[kTrendingQueriesEnabledSignedOutID] = 1; + weight_by_id[kTrendingQueriesEnabledNeverShowModuleID] = 1; + weight_by_id[kTrendingQueriesControlID] = 1; break; } return weight_by_id;
diff --git a/ios/chrome/browser/ui/lens/BUILD.gn b/ios/chrome/browser/ui/lens/BUILD.gn index 412b1ec..872fd90 100644 --- a/ios/chrome/browser/ui/lens/BUILD.gn +++ b/ios/chrome/browser/ui/lens/BUILD.gn
@@ -26,3 +26,12 @@ ] deps = [] } + +source_set("lens_entrypoint") { + configs += [ "//build/config/compiler:enable_arc" ] + sources = [ + "lens_entrypoint.h", + "lens_entrypoint.mm", + ] + deps = [] +}
diff --git a/ios/chrome/browser/ui/lens/lens_entrypoint.h b/ios/chrome/browser/ui/lens/lens_entrypoint.h new file mode 100644 index 0000000..5f19b62 --- /dev/null +++ b/ios/chrome/browser/ui/lens/lens_entrypoint.h
@@ -0,0 +1,21 @@ +// Copyright 2022 The Chromium Authors. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_BROWSER_UI_LENS_LENS_ENTRYPOINT_H_ +#define IOS_CHROME_BROWSER_UI_LENS_LENS_ENTRYPOINT_H_ + +// Enum representing the possible Lens entrypoints on iOS. +// Current values should not be renumbered. Please keep in sync with +// "IOSLensEntrypoint" in src/tools/metrics/histograms/enums.xml. +enum class LensEntrypoint { + ContextMenu = 0, + HomeScreenWidget = 1, + NewTabPage = 2, + Keyboard = 3, + kMaxValue = Keyboard, +}; + +extern const char kIOSLensEntrypoint[]; + +#endif // IOS_CHROME_BROWSER_UI_LENS_LENS_ENTRYPOINT_H_
diff --git a/ios/chrome/browser/ui/lens/lens_entrypoint.mm b/ios/chrome/browser/ui/lens/lens_entrypoint.mm new file mode 100644 index 0000000..412218b --- /dev/null +++ b/ios/chrome/browser/ui/lens/lens_entrypoint.mm
@@ -0,0 +1,11 @@ +// Copyright 2022 The Chromium Authors. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/chrome/browser/ui/lens/lens_entrypoint.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +const char kIOSLensEntrypoint[] = "ContextMenu.iOS.LensEntrypoint";
diff --git a/ios/chrome/browser/ui/ui_feature_flags.cc b/ios/chrome/browser/ui/ui_feature_flags.cc index 9bbc68ca..fbcbb1ca 100644 --- a/ios/chrome/browser/ui/ui_feature_flags.cc +++ b/ios/chrome/browser/ui/ui_feature_flags.cc
@@ -61,6 +61,15 @@ const base::Feature kUseLensToSearchForImage{"UseLensToSearchForImage", base::FEATURE_DISABLED_BY_DEFAULT}; +const base::Feature kEnableLensInHomeScreenWidget{ + "EnableLensInHomeScreenWidget", base::FEATURE_DISABLED_BY_DEFAULT}; + +const base::Feature kEnableLensInKeyboard{"EnableLensInKeyboard", + base::FEATURE_DISABLED_BY_DEFAULT}; + +const base::Feature kEnableLensInNTP{"EnableLensInNTP", + base::FEATURE_DISABLED_BY_DEFAULT}; + const base::Feature kRemoveExcessNTPs{"RemoveExcessNTPs", base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/ios/chrome/browser/ui/ui_feature_flags.h b/ios/chrome/browser/ui/ui_feature_flags.h index a55461b..c852c53 100644 --- a/ios/chrome/browser/ui/ui_feature_flags.h +++ b/ios/chrome/browser/ui/ui_feature_flags.h
@@ -77,6 +77,15 @@ // Feature flag to enable using Lens to search for images. extern const base::Feature kUseLensToSearchForImage; +// Feature flag to enable the Lens entrypoint in the home screen widget. +extern const base::Feature kEnableLensInHomeScreenWidget; + +// Feature flag to enable the Lens entrypoint in the keyboard. +extern const base::Feature kEnableLensInKeyboard; + +// Feature flag to enable the Lens entrypoint in the new tab page. +extern const base::Feature kEnableLensInNTP; + // Feature flag to enable duplicate NTP cleanup. extern const base::Feature kRemoveExcessNTPs;
diff --git a/ios/chrome/browser/web/web_share_egtest.mm b/ios/chrome/browser/web/web_share_egtest.mm index 90d354f..65129448 100644 --- a/ios/chrome/browser/web/web_share_egtest.mm +++ b/ios/chrome/browser/web/web_share_egtest.mm
@@ -28,6 +28,7 @@ const char kWebShareFileUrl[] = "/share_file.html"; const char kWebShareRelativeLinkUrl[] = "/share_relative_link.html"; const char kWebShareRelativeFilenameFileUrl[] = "/share_filename_file.html"; +const char kWebShareUrlObjectUrl[] = "/share_url_object.html"; const char kWebSharePageContents[] = "<html>" @@ -36,8 +37,8 @@ "async function tryUrl() {" " document.getElementById(\"result\").innerHTML = '';" " try {" - " var opts = {url: \"%s\"};" - " navigator.share(opts);" + " var opts = {url: %s};" + " await navigator.share(opts);" " document.getElementById(\"result\").innerHTML = 'success';" " } catch {" " document.getElementById(\"result\").innerHTML = 'failure';" @@ -57,19 +58,23 @@ if (request.relative_url == kWebShareValidLinkUrl) { std::string content = - base::StringPrintf(kWebSharePageContents, "https://example.com"); + base::StringPrintf(kWebSharePageContents, "\"https://example.com\""); http_response->set_content(content); } else if (request.relative_url == kWebShareFileUrl) { std::string content = - base::StringPrintf(kWebSharePageContents, "file:///Users/u/data"); + base::StringPrintf(kWebSharePageContents, "\"file:///Users/u/data\""); http_response->set_content(content); } else if (request.relative_url == kWebShareRelativeLinkUrl) { std::string content = - base::StringPrintf(kWebSharePageContents, "/something.png"); + base::StringPrintf(kWebSharePageContents, "\"/something.png\""); http_response->set_content(content); } else if (request.relative_url == kWebShareRelativeFilenameFileUrl) { std::string content = - base::StringPrintf(kWebSharePageContents, "filename.zip"); + base::StringPrintf(kWebSharePageContents, "\"filename.zip\""); + http_response->set_content(content); + } else if (request.relative_url == kWebShareUrlObjectUrl) { + std::string content = + base::StringPrintf(kWebSharePageContents, "window.location"); http_response->set_content(content); } else { return nullptr; @@ -145,4 +150,17 @@ assertWithMatcher:grey_nil()]; } +// Tests that an url object can be shared. +- (void)testShareUrlObject { + const GURL pageURL = self.testServer->GetURL(kWebShareUrlObjectUrl); + [ChromeEarlGrey loadURL:pageURL]; + [[EarlGrey selectElementWithMatcher:chrome_test_util::WebViewMatcher()] + performAction:chrome_test_util::TapWebElementWithId(kWebShareButtonId)]; + + [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(@"Copy")] + performAction:grey_tap()]; + + [ChromeEarlGrey waitForWebStateContainingText:kWebShareStatusSuccess]; +} + @end
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 index 3c622a05..223b23f 100644 --- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -efa0c0eebae6942a02964c7cf482a4ed4a7e3b2a \ No newline at end of file +7bd464603dd765c23feb18aceefeb1c1dc671a9d \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 index 969f22af..42607c9 100644 --- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -1ccd5df11f4570bfce8bb8217891712a02f6294b \ No newline at end of file +2e5d4633d6328ea13da22410b382e19b8c38274e \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 index c53fc9e..41f2afd9 100644 --- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -0bffa95c454c08afa4a4f45ce9a02d002b2bd179 \ No newline at end of file +b2298131b8e0a9c26bdbd9b1d6eb2702bd3d6dcf \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 index 5f89b49..cc1b00f 100644 --- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -3af08f4429cd4d43f1dde3f91e25eba6cd8e8147 \ No newline at end of file +258ea725c0b9400e9f176196a9035086e47de93a \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1 index b178199..c83351e1 100644 --- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -e468aa4f006ab935bc9bd3edd71336d7c9d55bf6 \ No newline at end of file +5460a5f2851583d0fca4f5588e8322abd26b2cf2 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1 index 7739934..6b2990e 100644 --- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -1110f7e96e1aff6a555c1a1c6b7a2127996ff918 \ No newline at end of file +a87805c062b890080eafef65eb487691264721c8 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 index cd73652..fc7d2dd 100644 --- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -05758d525e85d31d3a5a9d552dad8e991bb321f1 \ No newline at end of file +0a342e12b6a97d90ee850575677cd2f284fc7eb3 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 index 2fe603b..0ee8ba1b 100644 --- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -97ee4087024faa1aa3c8820d3a6113f23e09c9bd \ No newline at end of file +1ee4b7151fe65989fa458a6c5d94a7758f09ded9 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 index de6d59e..d930628 100644 --- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -5344966552648b2a67fa401de7e3b90ee602587f \ No newline at end of file +602ec65e2727f7d5bcddc9f1a7fae3c47f325098 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 index 3e5d4d76..af37ded 100644 --- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -78008e6ccb24cfa6ede586ec69f76985fc66ab16 \ No newline at end of file +79e9f77b88ef9336b96d049aa5c7752d97c6ce29 \ No newline at end of file
diff --git a/ios/web/web_state/js/resources/share_workaround.js b/ios/web/web_state/js/resources/share_workaround.js index e8c0da05..704f598 100644 --- a/ios/web/web_state/js/resources/share_workaround.js +++ b/ios/web/web_state/js/resources/share_workaround.js
@@ -48,13 +48,13 @@ let url = undefined; if (data.hasOwnProperty('url')) { - url = data['url']; + url = data['url']?.toString(); let proceed = false; if (url === undefined) { // Allow url key to be set without value. proceed = true; - } else if (typeof url === "string") { + } else { // file: URLs are not allowed. if (url.length >= 5 && (url[0] == 'f' || url[0] == 'F') &&
diff --git a/ios/web_view/internal/translate/cwv_translation_controller_unittest.mm b/ios/web_view/internal/translate/cwv_translation_controller_unittest.mm index 0af34aa..79b2399 100644 --- a/ios/web_view/internal/translate/cwv_translation_controller_unittest.mm +++ b/ios/web_view/internal/translate/cwv_translation_controller_unittest.mm
@@ -96,7 +96,7 @@ pref_service_.registry()->RegisterListPref( translate::TranslatePrefs::kPrefNeverPromptSitesDeprecated); pref_service_.registry()->RegisterDictionaryPref( - translate::TranslatePrefs::kPrefNeverPromptSitesWithTime); + translate::prefs::kPrefNeverPromptSitesWithTime); pref_service_.registry()->RegisterDictionaryPref( translate::prefs::kPrefAlwaysTranslateList); pref_service_.registry()->RegisterDictionaryPref(
diff --git a/ipc/DEPS b/ipc/DEPS index d58fa4c1..9a8d5bd 100644 --- a/ipc/DEPS +++ b/ipc/DEPS
@@ -22,7 +22,7 @@ "+third_party/protobuf/src/google/protobuf/repeated_field.h", ], "run_all_unittests\.cc": [ + "+third_party/ipcz/src/test", "+third_party/ipcz/src/test_buildflags.h", - "+third_party/ipcz/src/test/test_child_launcher.h", ], }
diff --git a/ipc/run_all_unittests.cc b/ipc/run_all_unittests.cc index bfd91e2..913cb5e 100644 --- a/ipc/run_all_unittests.cc +++ b/ipc/run_all_unittests.cc
@@ -9,6 +9,7 @@ #include "base/test/test_suite.h" #include "mojo/core/embedder/embedder.h" #include "mojo/core/embedder/scoped_ipc_support.h" +#include "third_party/ipcz/src/test/multinode_test.h" #include "third_party/ipcz/src/test_buildflags.h" #if BUILDFLAG(ENABLE_IPCZ_MULTIPROCESS_TESTS) @@ -21,6 +22,7 @@ #endif base::TestSuite test_suite(argc, argv); + ipcz::test::RegisterMultinodeTests(); mojo::core::Init(); base::TestIOThread test_io_thread(base::TestIOThread::kAutoStart); mojo::core::ScopedIPCSupport ipc_support(
diff --git a/media/cast/encoding/external_video_encoder.cc b/media/cast/encoding/external_video_encoder.cc index d0de515..fdc5980e 100644 --- a/media/cast/encoding/external_video_encoder.cc +++ b/media/cast/encoding/external_video_encoder.cc
@@ -89,7 +89,7 @@ } #endif -#if BUILDFLAG(IS_CHROMEOS) && ARCH_CPU_64_BITS +#if BUILDFLAG(IS_CHROMEOS) && ARCH_CPU_X86_64 // The encoder also doesn't work well with some first party Chromecast // devices. See https://crbug.com/1342276 for more information. if (base::StartsWith(receiver_model_name, "Chromecast")) {
diff --git a/media/cast/encoding/external_video_encoder_unittest.cc b/media/cast/encoding/external_video_encoder_unittest.cc index 752f8d9..275118c 100644 --- a/media/cast/encoding/external_video_encoder_unittest.cc +++ b/media/cast/encoding/external_video_encoder_unittest.cc
@@ -114,7 +114,7 @@ } TEST(ExternalVideoEncoderTest, RecommendsExternalVp8EncoderForChromecast) { -#if BUILDFLAG(IS_CHROMEOS) && ARCH_CPU_64_BITS +#if BUILDFLAG(IS_CHROMEOS) && ARCH_CPU_X86_64 EXPECT_TRUE(ExternalVideoEncoder::IsRecommended( CODEC_VIDEO_VP8, "Eureka Dongle", kValidVeaProfiles)); EXPECT_FALSE(ExternalVideoEncoder::IsRecommended(
diff --git a/media/gpu/chromeos/oop_video_decoder.cc b/media/gpu/chromeos/oop_video_decoder.cc index 471e077..277c7d89 100644 --- a/media/gpu/chromeos/oop_video_decoder.cc +++ b/media/gpu/chromeos/oop_video_decoder.cc
@@ -164,7 +164,7 @@ InitCB init_cb, const OutputCB& output_cb, const WaitingCB& waiting_cb) { - VLOGF(2); + DVLOGF(2) << config.AsHumanReadableString(); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); CHECK(!init_cb_); @@ -235,7 +235,7 @@ void OOPVideoDecoder::Decode(scoped_refptr<DecoderBuffer> buffer, DecodeCB decode_cb) { - VLOGF(2); + DVLOGF(4); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); CHECK(!init_cb_); @@ -279,6 +279,7 @@ void OOPVideoDecoder::OnDecodeDone(uint64_t decode_id, bool is_flushing, const DecoderStatus& status) { + DVLOGF(4); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); CHECK(!has_error_); @@ -306,7 +307,7 @@ } void OOPVideoDecoder::Reset(base::OnceClosure reset_cb) { - VLOGF(2); + DVLOGF(2); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); CHECK(!init_cb_); @@ -427,7 +428,7 @@ const scoped_refptr<VideoFrame>& frame, bool can_read_without_stalling, const base::UnguessableToken& release_token) { - VLOGF(2); + DVLOGF(4); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); CHECK(!has_error_); @@ -451,7 +452,7 @@ } void OOPVideoDecoder::OnWaiting(WaitingReason reason) { - VLOGF(2); + DVLOGF(4); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); CHECK(!has_error_);
diff --git a/media/mojo/clients/win/media_foundation_renderer_client.cc b/media/mojo/clients/win/media_foundation_renderer_client.cc index dbf3a7b4..1cc5230 100644 --- a/media/mojo/clients/win/media_foundation_renderer_client.cc +++ b/media/mojo/clients/win/media_foundation_renderer_client.cc
@@ -545,7 +545,9 @@ } dcomp_video_frame_ = video_frame; - sink_->PaintSingleFrame(dcomp_video_frame_, true); + if (!IsFrameServerMode()) { + sink_->PaintSingleFrame(dcomp_video_frame_, true); + } } void MediaFoundationRendererClient::OnCdmAttached(bool success) {
diff --git a/mojo/core/ipcz_driver/transport.cc b/mojo/core/ipcz_driver/transport.cc index 831f9a8..98ea0f2d 100644 --- a/mojo/core/ipcz_driver/transport.cc +++ b/mojo/core/ipcz_driver/transport.cc
@@ -50,6 +50,10 @@ // Indicates what type of destination the other end of this serialized // transport is connected to. Transport::Destination destination; + + // Indicates whether the remote process on the other end of this transport + // is the same process sending this object. + bool is_same_remote_process; }; #if BUILDFLAG(IS_WIN) @@ -338,7 +342,7 @@ auto object_handles = base::make_span(platform_handles.container()); switch (header.type) { case ObjectBase::kTransport: - object = Transport::Deserialize(object_data, object_handles); + object = Deserialize(*this, object_data, object_handles); break; case ObjectBase::kSharedBuffer: @@ -377,7 +381,11 @@ size_t& num_bytes, size_t& num_handles) { num_bytes = sizeof(TransportHeader); +#if BUILDFLAG(IS_WIN) + num_handles = ShouldSerializeProcessHandle(transmitter) ? 2 : 1; +#else num_handles = 1; +#endif return true; } @@ -387,25 +395,50 @@ DCHECK_EQ(sizeof(TransportHeader), data.size()); auto& header = *reinterpret_cast<TransportHeader*>(data.data()); header.destination = destination_; + header.is_same_remote_process = remote_process_.is_current(); - DCHECK_EQ(1u, handles.size()); +#if BUILDFLAG(IS_WIN) + if (ShouldSerializeProcessHandle(transmitter)) { + DCHECK_EQ(handles.size(), 2u); + DCHECK(remote_process_.IsValid()); + DCHECK(!remote_process_.is_current()); + handles[1] = PlatformHandle( + base::win::ScopedHandle(remote_process_.Duplicate().Release())); + } else { + DCHECK_EQ(handles.size(), 1u); + } +#else + DCHECK_EQ(handles.size(), 1u); +#endif + DCHECK(inactive_endpoint_.is_valid()); handles[0] = inactive_endpoint_.TakePlatformHandle(); - return true; } // static scoped_refptr<Transport> Transport::Deserialize( + Transport& from_transport, base::span<const uint8_t> data, base::span<PlatformHandle> handles) { if (data.size() < sizeof(TransportHeader) || handles.size() < 1) { return nullptr; } + base::Process process; const auto& header = *reinterpret_cast<const TransportHeader*>(data.data()); +#if BUILDFLAG(IS_WIN) + if (handles.size() >= 2 && from_transport.remote_process().IsValid()) { + process = base::Process(handles[1].ReleaseHandle()); + } +#endif + if (header.is_same_remote_process && + from_transport.remote_process().IsValid()) { + process = from_transport.remote_process().Duplicate(); + } return base::MakeRefCounted<Transport>( - header.destination, PlatformChannelEndpoint(std::move(handles[0]))); + header.destination, PlatformChannelEndpoint(std::move(handles[0])), + std::move(process)); } bool Transport::IsIpczTransport() const { @@ -455,6 +488,16 @@ #endif } +bool Transport::ShouldSerializeProcessHandle(Transport& transmitter) const { +#if BUILDFLAG(IS_WIN) + return remote_process_.IsValid() && !remote_process_.is_current() && + destination_ == kToBroker; +#else + // We have no need for the process handle on other platforms. + return false; +#endif +} + Transport::PendingTransmission::PendingTransmission() = default; Transport::PendingTransmission::PendingTransmission(PendingTransmission&&) =
diff --git a/mojo/core/ipcz_driver/transport.h b/mojo/core/ipcz_driver/transport.h index c9d224a..eae0922 100644 --- a/mojo/core/ipcz_driver/transport.h +++ b/mojo/core/ipcz_driver/transport.h
@@ -88,6 +88,7 @@ base::span<PlatformHandle> handles) override; static scoped_refptr<Transport> Deserialize( + Transport& from_transport, base::span<const uint8_t> data, base::span<PlatformHandle> handles); @@ -114,6 +115,13 @@ bool CanTransmitHandles() const; + // Indicates whether this transport should serialize its remote process handle + // along with its endpoint handle being serialized for transmission over + // `transmitter`. This must only be true if we have a valid remote process + // handle and `transmitter` goes to a broker. Always false on non-Windows + // platforms. + bool ShouldSerializeProcessHandle(Transport& transmitter) const; + const Destination destination_; const base::Process remote_process_;
diff --git a/mojo/public/js/mojo_bindings_resources.grd b/mojo/public/js/mojo_bindings_resources.grd index 8af1efb..6fea1f7 100644 --- a/mojo/public/js/mojo_bindings_resources.grd +++ b/mojo/public/js/mojo_bindings_resources.grd
@@ -64,6 +64,11 @@ use_base_dir="false" resource_path="mojo/mojo/public/mojom/base/file_path.mojom-webui.js" type="BINDATA" /> + <include name="IDR_MOJO_INT128_MOJOM_WEBUI_JS" + file="${root_gen_dir}/mojom-webui/mojo/public/mojom/base/int128.mojom-webui.js" + use_base_dir="false" + resource_path="mojo/mojo/public/mojom/base/int128.mojom-webui.js" + type="BINDATA" /> <include name="IDR_MOJO_READ_ONLY_BUFFER_MOJOM_WEBUI_JS" file="${root_gen_dir}/mojom-webui/mojo/public/mojom/base/read_only_buffer.mojom-webui.js" use_base_dir="false"
diff --git a/pdf/pdf_engine.h b/pdf/pdf_engine.h index e13d8bb..7d2469f 100644 --- a/pdf/pdf_engine.h +++ b/pdf/pdf_engine.h
@@ -171,13 +171,16 @@ // Updates the number of find results for the current search term. If // there are no matches 0 should be passed in. Only when the plugin has - // finished searching should it pass in the final count with final_result + // finished searching should it pass in the final count with `final_result` // set to true. virtual void NotifyNumberOfFindResultsChanged(int total, bool final_result) {} - // Updates the index of the currently selected search item. - virtual void NotifySelectedFindResultChanged(int current_find_index) {} + // Updates the index of the currently selected search item. Set + // `final_result` to true only when there is no subsequent + // `NotifyNumberOfFindResultsChanged()` call. + virtual void NotifySelectedFindResultChanged(int current_find_index, + bool final_result) {} virtual void NotifyTouchSelectionOccurred() {}
diff --git a/pdf/pdf_view_web_plugin.cc b/pdf/pdf_view_web_plugin.cc index 30f2214..92daa54a 100644 --- a/pdf/pdf_view_web_plugin.cc +++ b/pdf/pdf_view_web_plugin.cc
@@ -841,12 +841,14 @@ kFindResultCooldown); } -void PdfViewWebPlugin::NotifySelectedFindResultChanged(int current_find_index) { +void PdfViewWebPlugin::NotifySelectedFindResultChanged(int current_find_index, + bool final_result) { if (find_identifier_ == -1 || !client_->PluginContainer()) return; DCHECK_GE(current_find_index, -1); - client_->ReportFindInPageSelection(find_identifier_, current_find_index + 1); + client_->ReportFindInPageSelection(find_identifier_, current_find_index + 1, + final_result); } void PdfViewWebPlugin::CaretChanged(const gfx::Rect& caret_rect) {
diff --git a/pdf/pdf_view_web_plugin.h b/pdf/pdf_view_web_plugin.h index 4fc0ce8..5771ba23 100644 --- a/pdf/pdf_view_web_plugin.h +++ b/pdf/pdf_view_web_plugin.h
@@ -133,7 +133,9 @@ bool final_update) = 0; // Notify the web plugin container about the selected find result in plugin. - virtual void ReportFindInPageSelection(int identifier, int index) = 0; + virtual void ReportFindInPageSelection(int identifier, + int index, + bool final_update) = 0; // Notify the web plugin container about find result tickmarks. virtual void ReportFindInPageTickmarks( @@ -278,7 +280,8 @@ void UpdateCursor(ui::mojom::CursorType new_cursor_type) override; void UpdateTickMarks(const std::vector<gfx::Rect>& tickmarks) override; void NotifyNumberOfFindResultsChanged(int total, bool final_result) override; - void NotifySelectedFindResultChanged(int current_find_index) override; + void NotifySelectedFindResultChanged(int current_find_index, + bool final_result) override; void GetDocumentPassword( base::OnceCallback<void(const std::string&)> callback) override; void Beep() override;
diff --git a/pdf/pdf_view_web_plugin_unittest.cc b/pdf/pdf_view_web_plugin_unittest.cc index d7f149b..32ce138 100644 --- a/pdf/pdf_view_web_plugin_unittest.cc +++ b/pdf/pdf_view_web_plugin_unittest.cc
@@ -254,7 +254,7 @@ MOCK_METHOD(void, ReportFindInPageMatchCount, (int, int, bool), (override)); - MOCK_METHOD(void, ReportFindInPageSelection, (int, int), (override)); + MOCK_METHOD(void, ReportFindInPageSelection, (int, int, bool), (override)); MOCK_METHOD(void, ReportFindInPageTickmarks,
diff --git a/pdf/pdfium/findtext_unittest.cc b/pdf/pdfium/findtext_unittest.cc index 242b1d58..3aa922e 100644 --- a/pdf/pdfium/findtext_unittest.cc +++ b/pdf/pdfium/findtext_unittest.cc
@@ -28,7 +28,7 @@ // PDFEngine::Client: MOCK_METHOD(void, NotifyNumberOfFindResultsChanged, (int, bool), (override)); - MOCK_METHOD(void, NotifySelectedFindResultChanged, (int), (override)); + MOCK_METHOD(void, NotifySelectedFindResultChanged, (int, bool), (override)); std::vector<SearchStringResult> SearchString(const char16_t* string, const char16_t* term, @@ -73,7 +73,8 @@ EXPECT_CALL(client, NotifyNumberOfFindResultsChanged(1, /*final_result=*/false)); - EXPECT_CALL(client, NotifySelectedFindResultChanged(0)); + EXPECT_CALL(client, + NotifySelectedFindResultChanged(0, /*final_result=*/false)); for (int i = 2; i < count + 1; ++i) { EXPECT_CALL(client, NotifyNumberOfFindResultsChanged(i, /*final_result=*/false)); @@ -185,14 +186,17 @@ engine->StartFind("world", /*case_sensitive=*/true); EXPECT_CALL(client, NotifyNumberOfFindResultsChanged(_, _)).Times(0); - EXPECT_CALL(client, NotifySelectedFindResultChanged(1)); + EXPECT_CALL(client, + NotifySelectedFindResultChanged(1, /*final_result=*/true)); ASSERT_TRUE(engine->SelectFindResult(/*forward=*/true)); - EXPECT_CALL(client, NotifySelectedFindResultChanged(2)); + EXPECT_CALL(client, + NotifySelectedFindResultChanged(2, /*final_result=*/true)); ASSERT_TRUE(engine->SelectFindResult(/*forward=*/true)); - EXPECT_CALL(client, NotifySelectedFindResultChanged(1)); + EXPECT_CALL(client, + NotifySelectedFindResultChanged(1, /*final_result=*/true)); ASSERT_TRUE(engine->SelectFindResult(/*forward=*/false)); } @@ -208,8 +212,10 @@ { InSequence sequence; - EXPECT_CALL(client, NotifySelectedFindResultChanged(1)); - EXPECT_CALL(client, NotifySelectedFindResultChanged(2)); + EXPECT_CALL(client, + NotifySelectedFindResultChanged(1, /*final_result=*/true)); + EXPECT_CALL(client, + NotifySelectedFindResultChanged(2, /*final_result=*/true)); } ASSERT_TRUE(engine->SelectFindResult(/*forward=*/true)); ASSERT_TRUE(engine->SelectFindResult(/*forward=*/true)); @@ -229,7 +235,8 @@ { InSequence sequence; - EXPECT_CALL(client, NotifySelectedFindResultChanged(2)); + EXPECT_CALL(client, + NotifySelectedFindResultChanged(2, /*final_result=*/true)); } ASSERT_TRUE(engine->SelectFindResult(/*forward=*/true)); }
diff --git a/pdf/pdfium/pdfium_engine.cc b/pdf/pdfium/pdfium_engine.cc index ddb8d4a5..38d9d82 100644 --- a/pdf/pdfium/pdfium_engine.cc +++ b/pdf/pdfium/pdfium_engine.cc
@@ -1761,6 +1761,7 @@ character_to_start_searching_from = old_selection[0].char_index(); last_page_to_search_ = next_page_to_search_; } + search_in_progress_ = true; } int current_page = next_page_to_search_; @@ -1801,6 +1802,8 @@ (pages_.size() > 1 && current_page == next_page_to_search_)); if (end_of_search) { + search_in_progress_ = false; + // Send the final notification. client_->NotifyNumberOfFindResultsChanged(find_results_.size(), true); return; @@ -2023,8 +2026,9 @@ if ((forward && current_index >= last_index) || (!forward && current_index == 0)) { current_find_index_.reset(); - client_->NotifySelectedFindResultChanged(-1); - client_->NotifyNumberOfFindResultsChanged(find_results_.size(), true); + client_->NotifySelectedFindResultChanged(-1, /*final_result=*/false); + client_->NotifyNumberOfFindResultsChanged(find_results_.size(), + /*final_result=*/true); return true; } int increment = forward ? 1 : -1; @@ -2070,7 +2074,8 @@ } } - client_->NotifySelectedFindResultChanged(current_find_index_.value()); + client_->NotifySelectedFindResultChanged( + current_find_index_.value(), /*final_result=*/!search_in_progress_); return true; }
diff --git a/pdf/pdfium/pdfium_engine.h b/pdf/pdfium/pdfium_engine.h index c0f83d9..998071c 100644 --- a/pdf/pdfium/pdfium_engine.h +++ b/pdf/pdfium/pdfium_engine.h
@@ -726,6 +726,8 @@ std::string current_find_text_; // The results found. std::vector<PDFiumRange> find_results_; + // Whether a search is in progress. + bool search_in_progress_ = false; // Which page to search next. int next_page_to_search_ = -1; // Where to stop searching.
diff --git a/pdf/preview_mode_client.cc b/pdf/preview_mode_client.cc index 28ffbe41..2c9fcaa 100644 --- a/pdf/preview_mode_client.cc +++ b/pdf/preview_mode_client.cc
@@ -72,8 +72,8 @@ NOTREACHED(); } -void PreviewModeClient::NotifySelectedFindResultChanged( - int current_find_index) { +void PreviewModeClient::NotifySelectedFindResultChanged(int current_find_index, + bool final_result) { NOTREACHED(); }
diff --git a/pdf/preview_mode_client.h b/pdf/preview_mode_client.h index 43514fd..c96bbfc 100644 --- a/pdf/preview_mode_client.h +++ b/pdf/preview_mode_client.h
@@ -41,7 +41,8 @@ void UpdateCursor(ui::mojom::CursorType cursor_type) override; void UpdateTickMarks(const std::vector<gfx::Rect>& tickmarks) override; void NotifyNumberOfFindResultsChanged(int total, bool final_result) override; - void NotifySelectedFindResultChanged(int current_find_index) override; + void NotifySelectedFindResultChanged(int current_find_index, + bool final_result) override; void GetDocumentPassword( base::OnceCallback<void(const std::string&)> callback) override; void Alert(const std::string& message) override;
diff --git a/remoting/host/BUILD.gn b/remoting/host/BUILD.gn index 9b4b488..aa398af 100644 --- a/remoting/host/BUILD.gn +++ b/remoting/host/BUILD.gn
@@ -101,6 +101,7 @@ "input_injector.h", "input_injector_metadata.h", "sas_injector.h", + "usage_stats_consent.h", "worker_process_ipc_delegate.h", ] if (!is_chromeos_ash) { @@ -368,7 +369,6 @@ "token_validator_base.h", "token_validator_factory_impl.cc", "token_validator_factory_impl.h", - "usage_stats_consent.h", "xmpp_register_support_host_request.cc", "xmpp_register_support_host_request.h", "xsession_chooser_ui.inc",
diff --git a/remoting/host/remote_open_url/BUILD.gn b/remoting/host/remote_open_url/BUILD.gn index 10cc4e32..f3fa656 100644 --- a/remoting/host/remote_open_url/BUILD.gn +++ b/remoting/host/remote_open_url/BUILD.gn
@@ -79,6 +79,7 @@ "//base", "//base:i18n", "//mojo/core/embedder", + "//remoting/base:breakpad", "//remoting/host", "//remoting/host:chromoting_host_services_client", "//remoting/host:resources",
diff --git a/remoting/host/remote_open_url/remote_open_url_main.cc b/remoting/host/remote_open_url/remote_open_url_main.cc index 1bce849..5e2bd8e 100644 --- a/remoting/host/remote_open_url/remote_open_url_main.cc +++ b/remoting/host/remote_open_url/remote_open_url_main.cc
@@ -13,12 +13,14 @@ #include "base/threading/thread_task_runner_handle.h" #include "mojo/core/embedder/embedder.h" #include "mojo/core/embedder/scoped_ipc_support.h" +#include "remoting/base/breakpad.h" #include "remoting/base/host_settings.h" #include "remoting/base/logging.h" #include "remoting/host/base/host_exit_codes.h" #include "remoting/host/chromoting_host_services_client.h" #include "remoting/host/remote_open_url/remote_open_url_client.h" #include "remoting/host/resources.h" +#include "remoting/host/usage_stats_consent.h" #include "ui/base/l10n/l10n_util.h" namespace remoting { @@ -35,6 +37,12 @@ base::CommandLine::Init(argc, argv); InitHostLogging(); +#if defined(REMOTING_ENABLE_BREAKPAD) + if (IsUsageStatsAllowed()) { + InitializeCrashReporting(); + } +#endif // defined(REMOTING_ENABLE_BREAKPAD) + if (!ChromotingHostServicesClient::Initialize()) { return kInitializationFailed; }
diff --git a/remoting/host/security_key/BUILD.gn b/remoting/host/security_key/BUILD.gn index 8423fdf3..d843abf 100644 --- a/remoting/host/security_key/BUILD.gn +++ b/remoting/host/security_key/BUILD.gn
@@ -66,6 +66,7 @@ ":security_key", "//base:debugging_buildflags", "//mojo/core/embedder", + "//remoting/base:breakpad", "//remoting/host:common", "//remoting/host/base", ]
diff --git a/remoting/host/security_key/remote_security_key_main.cc b/remoting/host/security_key/remote_security_key_main.cc index a46c6ac5..293afeb 100644 --- a/remoting/host/security_key/remote_security_key_main.cc +++ b/remoting/host/security_key/remote_security_key_main.cc
@@ -17,10 +17,12 @@ #include "build/build_config.h" #include "mojo/core/embedder/embedder.h" #include "mojo/core/embedder/scoped_ipc_support.h" +#include "remoting/base/breakpad.h" #include "remoting/base/logging.h" #include "remoting/host/base/host_exit_codes.h" #include "remoting/host/security_key/security_key_ipc_client.h" #include "remoting/host/security_key/security_key_message_handler.h" +#include "remoting/host/usage_stats_consent.h" #if BUILDFLAG(IS_WIN) #include <windows.h> @@ -88,6 +90,12 @@ base::CommandLine::Init(argc, argv); remoting::InitHostLogging(); +#if defined(REMOTING_ENABLE_BREAKPAD) + if (IsUsageStatsAllowed()) { + InitializeCrashReporting(); + } +#endif // defined(REMOTING_ENABLE_BREAKPAD) + return StartRemoteSecurityKey(); }
diff --git a/remoting/host/setup/BUILD.gn b/remoting/host/setup/BUILD.gn index 14da0a2..170bf6f 100644 --- a/remoting/host/setup/BUILD.gn +++ b/remoting/host/setup/BUILD.gn
@@ -103,6 +103,7 @@ "//mojo/core/embedder", "//net", "//remoting/base:base", + "//remoting/base:breakpad", "//remoting/host:common", "//remoting/host/setup", "//remoting/host/setup:start_host_main_headers",
diff --git a/remoting/host/setup/start_host_main.cc b/remoting/host/setup/start_host_main.cc index d5b2490..4080b55 100644 --- a/remoting/host/setup/start_host_main.cc +++ b/remoting/host/setup/start_host_main.cc
@@ -19,10 +19,12 @@ #include "build/build_config.h" #include "mojo/core/embedder/embedder.h" #include "net/url_request/url_request_context_getter.h" +#include "remoting/base/breakpad.h" #include "remoting/base/logging.h" #include "remoting/base/url_request_context_getter.h" #include "remoting/host/setup/host_starter.h" #include "remoting/host/setup/pin_validator.h" +#include "remoting/host/usage_stats_consent.h" #include "services/network/public/cpp/shared_url_loader_factory.h" #include "services/network/transitional_url_loader_factory_owner.h" @@ -146,6 +148,12 @@ logging::LOG_TO_SYSTEM_DEBUG_LOG | logging::LOG_TO_STDERR; logging::InitLogging(settings); +#if defined(REMOTING_ENABLE_BREAKPAD) + if (IsUsageStatsAllowed()) { + InitializeCrashReporting(); + } +#endif // defined(REMOTING_ENABLE_BREAKPAD) + base::ThreadPoolInstance::CreateAndStartWithDefaultParams( "RemotingHostSetup");
diff --git a/remoting/host/webauthn/BUILD.gn b/remoting/host/webauthn/BUILD.gn index 523fef2..5a34b48b 100644 --- a/remoting/host/webauthn/BUILD.gn +++ b/remoting/host/webauthn/BUILD.gn
@@ -52,7 +52,9 @@ "//base", "//mojo/core/embedder:embedder", "//remoting/base", + "//remoting/base:breakpad", "//remoting/host:chromoting_host_services_client", + "//remoting/host:common_headers", "//remoting/host/base", "//remoting/host/native_messaging", ]
diff --git a/remoting/host/webauthn/remote_webauthn_main.cc b/remoting/host/webauthn/remote_webauthn_main.cc index 734d98e..21ffeb49 100644 --- a/remoting/host/webauthn/remote_webauthn_main.cc +++ b/remoting/host/webauthn/remote_webauthn_main.cc
@@ -18,11 +18,13 @@ #include "mojo/core/embedder/embedder.h" #include "mojo/core/embedder/scoped_ipc_support.h" #include "remoting/base/auto_thread_task_runner.h" +#include "remoting/base/breakpad.h" #include "remoting/base/logging.h" #include "remoting/host/base/host_exit_codes.h" #include "remoting/host/chromoting_host_services_client.h" #include "remoting/host/native_messaging/native_messaging_pipe.h" #include "remoting/host/native_messaging/pipe_messaging_channel.h" +#include "remoting/host/usage_stats_consent.h" #include "remoting/host/webauthn/remote_webauthn_caller_security_utils.h" #include "remoting/host/webauthn/remote_webauthn_native_messaging_host.h" @@ -41,6 +43,12 @@ base::CommandLine::Init(argc, argv); InitHostLogging(); +#if defined(REMOTING_ENABLE_BREAKPAD) + if (IsUsageStatsAllowed()) { + InitializeCrashReporting(); + } +#endif // defined(REMOTING_ENABLE_BREAKPAD) + if (!IsLaunchedByTrustedProcess()) { LOG(ERROR) << "Current process is not launched by a trusted process."; return kNoPermissionExitCode;
diff --git a/skia/BUILD.gn b/skia/BUILD.gn index 7a096b9..14e5c776 100644 --- a/skia/BUILD.gn +++ b/skia/BUILD.gn
@@ -429,13 +429,11 @@ "//third_party/skia/src/ports/SkOSFile_win.cpp", "//third_party/skia/src/ports/SkRemotableFontMgr_win_dw.cpp", "//third_party/skia/src/ports/SkScalerContext_win_dw.cpp", - "//third_party/skia/src/ports/SkTLS_win.cpp", "//third_party/skia/src/ports/SkTypeface_win_dw.cpp", ] } else { sources += [ "//third_party/skia/src/ports/SkOSFile_posix.cpp", - "//third_party/skia/src/ports/SkTLS_pthread.cpp", ] }
diff --git a/skia/OWNERS b/skia/OWNERS index ef55d67b..2d792d9 100644 --- a/skia/OWNERS +++ b/skia/OWNERS
@@ -3,9 +3,9 @@ brianosman@google.com bsalomon@google.com bungeman@google.com +egdaniel@google.com fmalita@chromium.org michaelludwig@google.com -reed@google.com robertphillips@google.com scroggo@google.com senorblanco@chromium.org
diff --git a/skia/config/SkUserConfig.h b/skia/config/SkUserConfig.h index 289671a1..a42fc44 100644 --- a/skia/config/SkUserConfig.h +++ b/skia/config/SkUserConfig.h
@@ -197,6 +197,8 @@ // // Remove these as we update our sites. +#define SK_LEGACY_LAYER_BOUNDS_EXPANSION // skbug.com/12083, skbug.com/12303 + // Workaround for poor anisotropic mipmap quality, // pending Skia ripmap support. // (https://bugs.chromium.org/p/skia/issues/detail?id=4863)
diff --git a/testing/buildbot/chrome.json b/testing/buildbot/chrome.json index 48c090f..23f5fb5 100644 --- a/testing/buildbot/chrome.json +++ b/testing/buildbot/chrome.json
@@ -2393,6 +2393,26 @@ "test_id_prefix": "ninja://ash/components:ash_components_unittests/" }, { + "ci_only": true, + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "os": "Ubuntu-18.04", + "pool": "chrome.tests", + "ssd": "0" + } + ], + "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "ash_crosapi_browsertests", + "test_id_prefix": "ninja://chrome/test:ash_crosapi_browsertests/" + }, + { "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py"
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json index b940a40..a2abdd9 100644 --- a/testing/buildbot/chromium.chromiumos.json +++ b/testing/buildbot/chromium.chromiumos.json
@@ -1598,6 +1598,24 @@ "test_id_prefix": "ninja://ash/components:ash_components_unittests/" }, { + "ci_only": true, + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "os": "Ubuntu-18.04" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "ash_crosapi_browsertests", + "test_id_prefix": "ninja://chrome/test:ash_crosapi_browsertests/" + }, + { "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -3198,6 +3216,25 @@ "test_id_prefix": "ninja://ash/components:ash_components_unittests/" }, { + "ci_only": true, + "isolate_profile_data": true, + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "os": "Ubuntu-18.04" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "ash_crosapi_browsertests", + "test_id_prefix": "ninja://chrome/test:ash_crosapi_browsertests/" + }, + { "args": [ "--enable-pixel-output-in-tests", "--git-revision=${got_revision}"
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json index 6e088688..e73e4f3d 100644 --- a/testing/buildbot/chromium.fyi.json +++ b/testing/buildbot/chromium.fyi.json
@@ -1686,6 +1686,30 @@ "args": [ "--test-launcher-print-test-stdio=always" ], + "ci_only": true, + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-20.04" + } + ], + "expiration": 10800, + "hard_timeout": 7200, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "ash_crosapi_browsertests", + "test_id_prefix": "ninja://chrome/test:ash_crosapi_browsertests/" + }, + { + "args": [ + "--test-launcher-print-test-stdio=always" + ], "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -94464,6 +94488,25 @@ "test_id_prefix": "ninja://ash/components:ash_components_unittests/" }, { + "ci_only": true, + "isolate_profile_data": true, + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "os": "Ubuntu-18.04" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "ash_crosapi_browsertests", + "test_id_prefix": "ninja://chrome/test:ash_crosapi_browsertests/" + }, + { "isolate_profile_data": true, "merge": { "args": [],
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json index 1fc0456c..aca138f 100644 --- a/testing/buildbot/chromium.memory.json +++ b/testing/buildbot/chromium.memory.json
@@ -5289,6 +5289,27 @@ "args": [ "--test-launcher-print-test-stdio=always" ], + "ci_only": true, + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "os": "Ubuntu-18.04" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "ash_crosapi_browsertests", + "test_id_prefix": "ninja://chrome/test:ash_crosapi_browsertests/" + }, + { + "args": [ + "--test-launcher-print-test-stdio=always" + ], "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -7131,6 +7152,28 @@ "args": [ "--test-launcher-print-test-stdio=always" ], + "ci_only": true, + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Ubuntu-16.04" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "ash_crosapi_browsertests", + "test_id_prefix": "ninja://chrome/test:ash_crosapi_browsertests/" + }, + { + "args": [ + "--test-launcher-print-test-stdio=always" + ], "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py"
diff --git a/testing/buildbot/filters/linux-chromeos.browser_tests.require_lacros.filter b/testing/buildbot/filters/linux-chromeos.browser_tests.require_lacros.filter index b193ab92..6f2f5e9e 100644 --- a/testing/buildbot/filters/linux-chromeos.browser_tests.require_lacros.filter +++ b/testing/buildbot/filters/linux-chromeos.browser_tests.require_lacros.filter
@@ -45,3 +45,5 @@ -ChromeVoxLiveRegionsTest.LiveRegionAddElement -ChromeVoxLiveRegionsTest.LiveRegionRemoveElement -ChromeVoxUserActionMonitorTest.Gestures +# TODO(crbug.com/1339456) Disabled when switch to LacrosOnly. +-DesksTemplatesClientLacrosTest.SystemUILaunchBrowser
diff --git a/testing/buildbot/gn_isolate_map.pyl b/testing/buildbot/gn_isolate_map.pyl index a0a1724d..0745fcd 100644 --- a/testing/buildbot/gn_isolate_map.pyl +++ b/testing/buildbot/gn_isolate_map.pyl
@@ -180,6 +180,10 @@ "label": "//ash/components:ash_components_unittests", "type": "windowed_test_launcher", }, + "ash_crosapi_browsertests": { + "label": "//chrome/test:ash_crosapi_browsertests", + "type": "windowed_test_launcher", + }, "ash_webui_unittests": { "label": "//ash/webui:ash_webui_unittests", "type": "windowed_test_launcher",
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl index cc34d90..c99ff03 100644 --- a/testing/buildbot/test_suites.pyl +++ b/testing/buildbot/test_suites.pyl
@@ -3779,6 +3779,10 @@ 'linux_chromeos_specific_gtests': { # Chrome OS only. 'ash_components_unittests': {}, + # TODO(crbug.com/1351793) Enable on CQ when stable. + 'ash_crosapi_browsertests': { + 'ci_only': True, + }, 'ash_unittests': { 'swarming': { 'shards': 5,
diff --git a/testing/multiprocess_func_list.cc b/testing/multiprocess_func_list.cc index f96c2b5..740bbe7 100644 --- a/testing/multiprocess_func_list.cc +++ b/testing/multiprocess_func_list.cc
@@ -12,6 +12,8 @@ namespace { +ChildProcessTestRunner g_test_runner = nullptr; + struct ProcessFunctions { ProcessFunctions() : main(NULL), setup(NULL) {} ProcessFunctions(TestMainFunctionPtr main, SetupFunctionPtr setup) @@ -40,7 +42,18 @@ ProcessFunctions(main_func_ptr, setup_func_ptr); } +void SetChildProcessTestRunner(ChildProcessTestRunner runner) { + g_test_runner = runner; +} + int InvokeChildProcessTest(const std::string& test_name) { + if (g_test_runner) { + return g_test_runner(test_name); + } + return InvokeChildProcessTestMain(test_name); +} + +int InvokeChildProcessTestMain(const std::string& test_name) { MultiProcessTestMap& func_lookup_table = GetMultiprocessFuncMap(); MultiProcessTestMap::iterator it = func_lookup_table.find(test_name); if (it != func_lookup_table.end()) {
diff --git a/testing/multiprocess_func_list.h b/testing/multiprocess_func_list.h index c3d2f1f7..5b2caef7 100644 --- a/testing/multiprocess_func_list.h +++ b/testing/multiprocess_func_list.h
@@ -45,10 +45,18 @@ SetupFunctionPtr setup_func_ptr); }; -// Invoke the main function of a test previously registered with -// MULTIPROCESS_TEST_MAIN() +using ChildProcessTestRunner = int (*)(const std::string&); +void SetChildProcessTestRunner(ChildProcessTestRunner runner); + +// Invokes the ChildProcessTestRunner callback with `test_name` if the callback +// is not null. Otherwise invokes test associated main function previously +// registered with MULTIPROCESS_TEST_MAIN(). int InvokeChildProcessTest(const std::string& test_name); +// Invokes a the main function of a test previously registered with +// MULTIPROCESS_TEST_MAIN(). +int InvokeChildProcessTestMain(const std::string& test_name); + // This macro creates a global MultiProcessTest::AppendMultiProcessTest object // whose constructor does the work of adding the global mapping. #define MULTIPROCESS_TEST_MAIN(test_main) \
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index 5329bbe..099b7603 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -6717,8 +6717,7 @@ "OmniboxLocalZeroSuggestAgeThreshold", "OmniboxMaxURLMatches", "OmniboxRetainSuggestionsWithHeaders", - "OmniboxUIExperimentMaxAutocompleteMatches", - "ZeroSuggestPrefetching" + "OmniboxUIExperimentMaxAutocompleteMatches" ], "disable_features": [ "UseSharedInstanceForZeroSuggestPrefetching" @@ -7852,7 +7851,8 @@ "InterestGroupStorage", "NoncedPartitionedCookies", "PrivacySandboxAdsAPIs", - "PrivacySandboxSettings3" + "PrivacySandboxSettings3", + "SharedStorageAPI" ] } ]
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc index 02aa250c..db91a892 100644 --- a/third_party/blink/common/features.cc +++ b/third_party/blink/common/features.cc
@@ -503,6 +503,11 @@ #endif }; +// Enable an experimental extension to the StorageAccessAPI. +// https://crbug.com/1351540 +const base::Feature kStorageAccessAPIForSiteExtension{ + "StorageAccessAPIForSiteExtension", base::FEATURE_DISABLED_BY_DEFAULT}; + // Enable text snippets in URL fragments. https://crbug.com/919204. const base::Feature kTextFragmentAnchor{"TextFragmentAnchor", base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/third_party/blink/common/mediastream/media_stream_mojom_traits.cc b/third_party/blink/common/mediastream/media_stream_mojom_traits.cc index bcfbb773..85871e025 100644 --- a/third_party/blink/common/mediastream/media_stream_mojom_traits.cc +++ b/third_party/blink/common/mediastream/media_stream_mojom_traits.cc
@@ -69,6 +69,7 @@ out->hotword_enabled = input.hotword_enabled(); out->disable_local_echo = input.disable_local_echo(); out->exclude_system_audio = input.exclude_system_audio(); + out->exclude_self_browser_surface = input.exclude_self_browser_surface(); out->request_pan_tilt_zoom_permission = input.request_pan_tilt_zoom_permission(); out->request_all_screens = input.request_all_screens();
diff --git a/third_party/blink/public/common/features.h b/third_party/blink/public/common/features.h index 2c14e34a..7010377 100644 --- a/third_party/blink/public/common/features.h +++ b/third_party/blink/public/common/features.h
@@ -214,6 +214,8 @@ BLINK_COMMON_EXPORT extern const base::Feature kServiceWorkerUpdateDelay; BLINK_COMMON_EXPORT extern const base::Feature kSpeculationRulesPrefetchProxy; BLINK_COMMON_EXPORT extern const base::Feature kStopInBackground; +BLINK_COMMON_EXPORT extern const base::Feature + kStorageAccessAPIForSiteExtension; BLINK_COMMON_EXPORT extern const base::Feature kTextFragmentAnchor; BLINK_COMMON_EXPORT extern const base::Feature kCssSelectorFragmentAnchor; BLINK_COMMON_EXPORT extern const base::Feature kDropInputEventsBeforeFirstPaint;
diff --git a/third_party/blink/public/common/mediastream/media_stream_controls.h b/third_party/blink/public/common/mediastream/media_stream_controls.h index 6323af93..f86f91c 100644 --- a/third_party/blink/public/common/mediastream/media_stream_controls.h +++ b/third_party/blink/public/common/mediastream/media_stream_controls.h
@@ -55,6 +55,7 @@ bool hotword_enabled = false; bool disable_local_echo = false; bool exclude_system_audio = false; + bool exclude_self_browser_surface = false; bool request_pan_tilt_zoom_permission = false; bool request_all_screens = false; };
diff --git a/third_party/blink/public/common/mediastream/media_stream_mojom_traits.h b/third_party/blink/public/common/mediastream/media_stream_mojom_traits.h index f8cb97cf..5501d94b 100644 --- a/third_party/blink/public/common/mediastream/media_stream_mojom_traits.h +++ b/third_party/blink/public/common/mediastream/media_stream_mojom_traits.h
@@ -108,6 +108,11 @@ return controls.exclude_system_audio; } + static bool exclude_self_browser_surface( + const blink::StreamControls& controls) { + return controls.exclude_self_browser_surface; + } + static bool request_pan_tilt_zoom_permission( const blink::StreamControls& controls) { return controls.request_pan_tilt_zoom_permission;
diff --git a/third_party/blink/public/mojom/mediastream/media_stream.mojom b/third_party/blink/public/mojom/mediastream/media_stream.mojom index 5cf1603..08e7eb53 100644 --- a/third_party/blink/public/mojom/mediastream/media_stream.mojom +++ b/third_party/blink/public/mojom/mediastream/media_stream.mojom
@@ -123,6 +123,7 @@ bool hotword_enabled; bool disable_local_echo; bool exclude_system_audio; + bool exclude_self_browser_surface; bool request_pan_tilt_zoom_permission; bool request_all_screens; };
diff --git a/third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom b/third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom index 94ce877..410dc6e 100644 --- a/third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom +++ b/third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom
@@ -3650,6 +3650,7 @@ kReplacedElementPaintedWithLargeOverflow = 4329, kFlexboxAbsPosJustifyContent = 4330, kMultipleFetchHandlersInServiceWorker = 4331, + kStorageAccessAPI_requestStorageAccessForSite_Method = 4332, // Add new features immediately above this line. Don't change assigned // numbers of any item, and don't reuse removed slots.
diff --git a/third_party/blink/public/mojom/webid/federated_auth_request.mojom b/third_party/blink/public/mojom/webid/federated_auth_request.mojom index 675d957..1df8053f 100644 --- a/third_party/blink/public/mojom/webid/federated_auth_request.mojom +++ b/third_party/blink/public/mojom/webid/federated_auth_request.mojom
@@ -56,9 +56,9 @@ // This interface is called from a renderer process and implemented in the // browser process. interface FederatedAuthRequest { - // Requests a token to be generated, given an IdentityProvider. + // Requests a token to be generated, given an array of IdentityProviders. // Returns the raw content of the token. - RequestToken(IdentityProvider identity_provider_ptr, + RequestToken(array<IdentityProvider> identity_providers, bool prefer_auto_sign_in) => (RequestTokenStatus status, string? token);
diff --git a/third_party/blink/public/platform/web_runtime_features.h b/third_party/blink/public/platform/web_runtime_features.h index 48a65f7..6c7f175 100644 --- a/third_party/blink/public/platform/web_runtime_features.h +++ b/third_party/blink/public/platform/web_runtime_features.h
@@ -162,6 +162,9 @@ BLINK_PLATFORM_EXPORT static void EnableSharedAutofill(bool); BLINK_PLATFORM_EXPORT static void EnableSharedStorageAPI(bool); BLINK_PLATFORM_EXPORT static void EnableSharedWorker(bool); + BLINK_PLATFORM_EXPORT static void EnableStorageAccessAPIForSiteExtension( + bool); + BLINK_PLATFORM_EXPORT static bool IsStorageAccessAPIForSiteExtensionEnabled(); BLINK_PLATFORM_EXPORT static void EnableTextFragmentAnchor(bool); BLINK_PLATFORM_EXPORT static void EnableCSSSelectorFragmentAnchor(bool); BLINK_PLATFORM_EXPORT static void EnableTopicsAPI(bool);
diff --git a/third_party/blink/public/web/web_plugin_container.h b/third_party/blink/public/web/web_plugin_container.h index 2e31e4f1..073d56fc 100644 --- a/third_party/blink/public/web/web_plugin_container.h +++ b/third_party/blink/public/web/web_plugin_container.h
@@ -133,7 +133,9 @@ virtual void ReportFindInPageMatchCount(int identifier, int total, bool final_update) = 0; - virtual void ReportFindInPageSelection(int identifier, int index) = 0; + virtual void ReportFindInPageSelection(int identifier, + int index, + bool final_update) = 0; virtual float PageScaleFactor() = 0; virtual float PageZoomFactor() = 0;
diff --git a/third_party/blink/renderer/bindings/generated_in_modules.gni b/third_party/blink/renderer/bindings/generated_in_modules.gni index 9a957c0..93ebfd1c 100644 --- a/third_party/blink/renderer/bindings/generated_in_modules.gni +++ b/third_party/blink/renderer/bindings/generated_in_modules.gni
@@ -1364,6 +1364,8 @@ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_sdp_semantics.h", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_secure_payment_confirmation_action.cc", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_secure_payment_confirmation_action.h", + "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_self_capture_preference_enum.cc", + "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_self_capture_preference_enum.h", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_service_worker_state.cc", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_service_worker_state.h", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_service_worker_update_via_cache.cc",
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc index 817a321..45835c81 100644 --- a/third_party/blink/renderer/core/dom/document.cc +++ b/third_party/blink/renderer/core/dom/document.cc
@@ -6074,6 +6074,94 @@ return promise; } +ScriptPromise Document::requestStorageAccessForSite(ScriptState* script_state, + const AtomicString& site) { + ScriptPromiseResolver* resolver = + MakeGarbageCollected<ScriptPromiseResolver>(script_state); + + // Access the promise first to ensure it is created so that the proper state + // can be changed when it is resolved or rejected. + ScriptPromise promise = resolver->Promise(); + + if (!GetFrame()) { + AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>( + mojom::blink::ConsoleMessageSource::kSecurity, + mojom::blink::ConsoleMessageLevel::kError, + "requestStorageAccessForSite: Must not be called from a detached " + "frame.")); + + resolver->Reject(); + return promise; + } + + const bool has_user_gesture = + LocalFrame::HasTransientUserActivation(GetFrame()); + if (!has_user_gesture) { + AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>( + mojom::blink::ConsoleMessageSource::kSecurity, + mojom::blink::ConsoleMessageLevel::kError, + "requestStorageAccessForSite: Must be handling a user gesture to " + "use.")); + + resolver->Reject(); + return promise; + } + + if (!IsInOutermostMainFrame()) { + AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>( + mojom::blink::ConsoleMessageSource::kSecurity, + mojom::blink::ConsoleMessageLevel::kError, + "requestStorageAccessForSite: Only supported in primary top-level " + "browsing contexts.")); + resolver->Reject(); + return promise; + } + + if (dom_window_->GetSecurityOrigin()->IsOpaque()) { + AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>( + mojom::blink::ConsoleMessageSource::kSecurity, + mojom::blink::ConsoleMessageLevel::kError, + "requestStorageAccessForSite: Cannot be used by opaque origins.")); + + resolver->Reject(); + return promise; + } + + KURL site_as_kurl{site}; + if (!site_as_kurl.IsValid()) { + AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>( + mojom::blink::ConsoleMessageSource::kSecurity, + mojom::blink::ConsoleMessageLevel::kError, + "requestStorageAccessForSite: Invalid site parameter.")); + resolver->Reject(); + return promise; + } + + scoped_refptr<SecurityOrigin> supplied_origin = + SecurityOrigin::Create(site_as_kurl); + if (supplied_origin->IsOpaque()) { + AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>( + mojom::blink::ConsoleMessageSource::kSecurity, + mojom::blink::ConsoleMessageLevel::kError, + "requestStorageAccessForSite: Invalid site parameter.")); + resolver->Reject(); + return promise; + } + + if (dom_window_->GetSecurityOrigin()->IsSameSiteWith(supplied_origin.get())) { + // Access is not actually disabled, so accept the request. + resolver->Resolve(); + return promise; + } + + resolver->Reject(); + AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>( + mojom::blink::ConsoleMessageSource::kSecurity, + mojom::blink::ConsoleMessageLevel::kError, + "requestStorageAccessForSite: Rejecting experimental API request.")); + return promise; +} + ScriptPromise Document::requestStorageAccess(ScriptState* script_state) { DCHECK(GetFrame()); ScriptPromiseResolver* resolver =
diff --git a/third_party/blink/renderer/core/dom/document.h b/third_party/blink/renderer/core/dom/document.h index facd4fdc..b7c74ca 100644 --- a/third_party/blink/renderer/core/dom/document.h +++ b/third_party/blink/renderer/core/dom/document.h
@@ -1197,6 +1197,8 @@ // may otherwise be blocked. ScriptPromise hasStorageAccess(ScriptState* script_state); ScriptPromise requestStorageAccess(ScriptState* script_state); + ScriptPromise requestStorageAccessForSite(ScriptState* script_state, + const AtomicString& site); // Fragment directive API, currently used to feature detect text-fragments. // https://wicg.github.io/scroll-to-text-fragment/#feature-detectability
diff --git a/third_party/blink/renderer/core/dom/document.idl b/third_party/blink/renderer/core/dom/document.idl index 88767b9..e024618 100644 --- a/third_party/blink/renderer/core/dom/document.idl +++ b/third_party/blink/renderer/core/dom/document.idl
@@ -183,6 +183,7 @@ // Storage Access API [CallWith=ScriptState, NewObject, RuntimeEnabled=StorageAccessAPI, MeasureAs=StorageAccessAPI_HasStorageAccess_Method] Promise<boolean> hasStorageAccess(); [CallWith=ScriptState, NewObject, RuntimeEnabled=StorageAccessAPI, MeasureAs=StorageAccessAPI_requestStorageAccess_Method] Promise<void> requestStorageAccess(); + [CallWith=ScriptState, NewObject, RuntimeEnabled=StorageAccessAPIForSiteExtension, MeasureAs=StorageAccessAPI_requestStorageAccessForSite_Method] Promise<void> requestStorageAccessForSite(USVString site); // Text fragment directive API // https://wicg.github.io/scroll-to-text-fragment/#feature-detectability
diff --git a/third_party/blink/renderer/core/exported/web_plugin_container_impl.cc b/third_party/blink/renderer/core/exported/web_plugin_container_impl.cc index af1e17b..3c22420 100644 --- a/third_party/blink/renderer/core/exported/web_plugin_container_impl.cc +++ b/third_party/blink/renderer/core/exported/web_plugin_container_impl.cc
@@ -320,19 +320,20 @@ if (!frame) return; - final_find_update_ = final_update; frame->GetFindInPage()->ReportFindInPageMatchCount(identifier, total, final_update); } void WebPluginContainerImpl::ReportFindInPageSelection(int identifier, - int index) { + int index, + bool final_update) { WebLocalFrameImpl* frame = WebLocalFrameImpl::FromFrame(element_->GetDocument().GetFrame()); if (!frame) return; - frame->GetFindInPage()->ReportFindInPageSelection( - identifier, index, gfx::Rect(), final_find_update_); + + frame->GetFindInPage()->ReportFindInPageSelection(identifier, index, + gfx::Rect(), final_update); } float WebPluginContainerImpl::PageScaleFactor() {
diff --git a/third_party/blink/renderer/core/exported/web_plugin_container_impl.h b/third_party/blink/renderer/core/exported/web_plugin_container_impl.h index b43e30f..a7ff05f 100644 --- a/third_party/blink/renderer/core/exported/web_plugin_container_impl.h +++ b/third_party/blink/renderer/core/exported/web_plugin_container_impl.h
@@ -137,7 +137,9 @@ void ReportFindInPageMatchCount(int identifier, int total, bool final_update) override; - void ReportFindInPageSelection(int identifier, int index) override; + void ReportFindInPageSelection(int identifier, + int index, + bool final_update) override; float PageScaleFactor() override; float PageZoomFactor() override; void SetCcLayer(cc::Layer*) override; @@ -234,10 +236,6 @@ cc::Layer* layer_ = nullptr; TouchEventRequestType touch_event_request_type_ = kTouchEventRequestTypeNone; bool wants_wheel_events_ = false; - - // Whether the most recent `ReportFindInPageMatchCount()` call was the final - // update or not. - bool final_find_update_ = false; }; template <>
diff --git a/third_party/blink/renderer/core/frame/local_frame.cc b/third_party/blink/renderer/core/frame/local_frame.cc index 819b99c..c3785349 100644 --- a/third_party/blink/renderer/core/frame/local_frame.cc +++ b/third_party/blink/renderer/core/frame/local_frame.cc
@@ -2579,18 +2579,11 @@ Vector<WebScriptSource> script_sources; script_sources.Append(sources.data(), base::checked_cast<wtf_size_t>(sources.size())); - auto* executor = MakeGarbageCollected<PausableScriptExecutor>( + + PausableScriptExecutor::CreateAndRun( DomWindow(), std::move(world), std::move(script_sources), user_gesture, - want_result_option, std::move(callback)); - executor->set_wait_for_promise(promise_behavior); - switch (evaluation_timing) { - case mojom::blink::EvaluationTiming::kAsynchronous: - executor->RunAsync(blocking_option); - break; - case mojom::blink::EvaluationTiming::kSynchronous: - executor->Run(); - break; - } + evaluation_timing, blocking_option, want_result_option, promise_behavior, + std::move(callback)); } void LocalFrame::SetEvictCachedSessionStorageOnFreezeOrUnload() {
diff --git a/third_party/blink/renderer/core/frame/pausable_script_executor.cc b/third_party/blink/renderer/core/frame/pausable_script_executor.cc index 5e7e5b8..bfefb80 100644 --- a/third_party/blink/renderer/core/frame/pausable_script_executor.cc +++ b/third_party/blink/renderer/core/frame/pausable_script_executor.cc
@@ -143,35 +143,21 @@ class WebScriptExecutor : public PausableScriptExecutor::Executor { public: - WebScriptExecutor(Vector<WebScriptSource>, - int32_t world_id, - mojom::blink::UserActivationOption); + WebScriptExecutor(Vector<WebScriptSource>, int32_t world_id); Vector<v8::Local<v8::Value>> Execute(LocalDOMWindow*) override; private: Vector<WebScriptSource> sources_; int32_t world_id_; - mojom::blink::UserActivationOption user_gesture_; }; -WebScriptExecutor::WebScriptExecutor( - Vector<WebScriptSource> sources, - int32_t world_id, - mojom::blink::UserActivationOption user_gesture) - : sources_(std::move(sources)), - world_id_(world_id), - user_gesture_(user_gesture) {} +WebScriptExecutor::WebScriptExecutor(Vector<WebScriptSource> sources, + int32_t world_id) + : sources_(std::move(sources)), world_id_(world_id) {} Vector<v8::Local<v8::Value>> WebScriptExecutor::Execute( LocalDOMWindow* window) { - if (user_gesture_ == mojom::blink::UserActivationOption::kActivate) { - // TODO(mustaq): Need to make sure this is safe. https://crbug.com/1082273 - LocalFrame::NotifyUserActivation( - window->GetFrame(), - mojom::blink::UserActivationNotificationType::kWebScriptExec); - } - Vector<v8::Local<v8::Value>> results; for (const auto& source : sources_) { // Note: An error event in an isolated world will never be dispatched to @@ -265,12 +251,42 @@ } PausableScriptExecutor* executor = MakeGarbageCollected<PausableScriptExecutor>( - window, script_state, want_result_option, std::move(callback), + window, script_state, + mojom::blink::UserActivationOption::kDoNotActivate, + mojom::blink::LoadEventBlockingOption::kDoNotBlock, + want_result_option, mojom::blink::PromiseResultOption::kDoNotWait, + std::move(callback), MakeGarbageCollected<V8FunctionExecutor>( window->GetIsolate(), function, receiver, argc, argv)); executor->Run(); } +void PausableScriptExecutor::CreateAndRun( + LocalDOMWindow* window, + scoped_refptr<DOMWrapperWorld> world, + Vector<WebScriptSource> sources, + mojom::blink::UserActivationOption user_activation_option, + mojom::blink::EvaluationTiming evaluation_timing, + mojom::blink::LoadEventBlockingOption blocking_option, + mojom::blink::WantResultOption want_result_option, + mojom::blink::PromiseResultOption promise_result_option, + WebScriptExecutionCallback callback) { + auto* executor = MakeGarbageCollected<PausableScriptExecutor>( + window, ToScriptState(window, *world), user_activation_option, + blocking_option, want_result_option, promise_result_option, + std::move(callback), + MakeGarbageCollected<WebScriptExecutor>(std::move(sources), + world->GetWorldId())); + switch (evaluation_timing) { + case mojom::blink::EvaluationTiming::kAsynchronous: + executor->RunAsync(); + break; + case mojom::blink::EvaluationTiming::kSynchronous: + executor->Run(); + break; + } +} + void PausableScriptExecutor::ContextDestroyed() { if (callback_) { // Though the context is (about to be) destroyed, the callback is invoked @@ -285,34 +301,25 @@ PausableScriptExecutor::PausableScriptExecutor( LocalDOMWindow* window, - scoped_refptr<DOMWrapperWorld> world, - Vector<WebScriptSource> sources, - mojom::blink::UserActivationOption user_gesture, - mojom::blink::WantResultOption want_result_option, - WebScriptExecutionCallback callback) - : PausableScriptExecutor( - window, - ToScriptState(window, *world), - want_result_option, - std::move(callback), - MakeGarbageCollected<WebScriptExecutor>(std::move(sources), - world->GetWorldId(), - user_gesture)) {} - -PausableScriptExecutor::PausableScriptExecutor( - LocalDOMWindow* window, ScriptState* script_state, + mojom::blink::UserActivationOption user_activation_option, + mojom::blink::LoadEventBlockingOption blocking_option, mojom::blink::WantResultOption want_result_option, + mojom::blink::PromiseResultOption promise_result_option, WebScriptExecutionCallback callback, Executor* executor) : ExecutionContextLifecycleObserver(window), script_state_(script_state), callback_(std::move(callback)), - blocking_option_(mojom::blink::LoadEventBlockingOption::kDoNotBlock), + user_activation_option_(user_activation_option), + blocking_option_(blocking_option), want_result_option_(want_result_option), + wait_for_promise_(promise_result_option), executor_(executor) { CHECK(script_state_); CHECK(script_state_->ContextIsValid()); + if (blocking_option_ == mojom::blink::LoadEventBlockingOption::kBlock) + window->document()->IncrementLoadEventDelayCount(); } PausableScriptExecutor::~PausableScriptExecutor() = default; @@ -327,14 +334,9 @@ PostExecuteAndDestroySelf(context); } -void PausableScriptExecutor::RunAsync( - mojom::blink::LoadEventBlockingOption blocking) { +void PausableScriptExecutor::RunAsync() { ExecutionContext* context = GetExecutionContext(); DCHECK(context); - blocking_option_ = blocking; - if (blocking_option_ == mojom::blink::LoadEventBlockingOption::kBlock) - To<LocalDOMWindow>(context)->document()->IncrementLoadEventDelayCount(); - PostExecuteAndDestroySelf(context); } @@ -353,6 +355,15 @@ auto* window = To<LocalDOMWindow>(GetExecutionContext()); ScriptState::Scope script_scope(script_state_); + + if (user_activation_option_ == + mojom::blink::UserActivationOption::kActivate) { + // TODO(mustaq): Need to make sure this is safe. https://crbug.com/1082273 + LocalFrame::NotifyUserActivation( + window->GetFrame(), + mojom::blink::UserActivationNotificationType::kWebScriptExec); + } + Vector<v8::Local<v8::Value>> results = executor_->Execute(window); // The script may have removed the frame, in which case contextDestroyed()
diff --git a/third_party/blink/renderer/core/frame/pausable_script_executor.h b/third_party/blink/renderer/core/frame/pausable_script_executor.h index f20e895..b137c5a 100644 --- a/third_party/blink/renderer/core/frame/pausable_script_executor.h +++ b/third_party/blink/renderer/core/frame/pausable_script_executor.h
@@ -35,6 +35,15 @@ v8::Local<v8::Value> argv[], mojom::blink::WantResultOption, WebScriptExecutionCallback); + static void CreateAndRun(LocalDOMWindow*, + scoped_refptr<DOMWrapperWorld>, + Vector<WebScriptSource>, + mojom::blink::UserActivationOption, + mojom::blink::EvaluationTiming, + mojom::blink::LoadEventBlockingOption, + mojom::blink::WantResultOption, + mojom::blink::PromiseResultOption, + WebScriptExecutionCallback); class Executor : public GarbageCollected<Executor> { public: @@ -46,30 +55,22 @@ }; PausableScriptExecutor(LocalDOMWindow*, - scoped_refptr<DOMWrapperWorld>, - Vector<WebScriptSource>, - mojom::blink::UserActivationOption, - mojom::blink::WantResultOption, - WebScriptExecutionCallback); - PausableScriptExecutor(LocalDOMWindow*, ScriptState*, + mojom::blink::UserActivationOption, + mojom::blink::LoadEventBlockingOption, mojom::blink::WantResultOption, + mojom::blink::PromiseResultOption, WebScriptExecutionCallback, Executor*); ~PausableScriptExecutor() override; - void Run(); - void RunAsync(mojom::blink::LoadEventBlockingOption); void ContextDestroyed() override; void Trace(Visitor*) const override; - void set_wait_for_promise( - mojom::blink::PromiseResultOption wait_for_promise) { - wait_for_promise_ = wait_for_promise; - } - private: + void Run(); + void RunAsync(); void PostExecuteAndDestroySelf(ExecutionContext* context); void ExecuteAndDestroySelf(); void Dispose(); @@ -79,17 +80,17 @@ Member<ScriptState> script_state_; WebScriptExecutionCallback callback_; base::TimeTicks start_time_; - mojom::blink::LoadEventBlockingOption blocking_option_; + const mojom::blink::UserActivationOption user_activation_option_; + const mojom::blink::LoadEventBlockingOption blocking_option_; const mojom::blink::WantResultOption want_result_option_; + // Whether to wait for a promise to resolve, if the executed script evaluates + // to a promise. + const mojom::blink::PromiseResultOption wait_for_promise_; + TaskHandle task_handle_; Member<Executor> executor_; - // Whether to wait for a promise to resolve, if the executed script evaluates - // to a promise. - mojom::blink::PromiseResultOption wait_for_promise_ = - mojom::blink::PromiseResultOption::kDoNotWait; - // A keepalive used when waiting on promises to settle. SelfKeepAlive<PausableScriptExecutor> keep_alive_; };
diff --git a/third_party/blink/renderer/core/html/html_frame_owner_element.cc b/third_party/blink/renderer/core/html/html_frame_owner_element.cc index 4a41c8a..54d886186 100644 --- a/third_party/blink/renderer/core/html/html_frame_owner_element.cc +++ b/third_party/blink/renderer/core/html/html_frame_owner_element.cc
@@ -25,6 +25,7 @@ #include "base/metrics/histogram_functions.h" #include "services/network/public/mojom/content_security_policy.mojom-blink-forward.h" #include "third_party/blink/public/common/features.h" +#include "third_party/blink/public/common/frame/fenced_frame_sandbox_flags.h" #include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h" #include "third_party/blink/public/mojom/frame/color_scheme.mojom-blink.h" #include "third_party/blink/public/mojom/frame/frame.mojom-blink.h" @@ -674,18 +675,21 @@ // https://docs.google.com/document/d/1ijTZJT3DHQ1ljp4QQe4E4XCCRaYAxmInNzN1SzeJM8s/edit. if (ContainingShadowRoot() && ContainingShadowRoot()->IsUserAgent() && IsA<HTMLFencedFrameElement>(ContainingShadowRoot()->host())) { - // Note that if a fenced frame's `is_fenced` status or `mode` attribute ever - // changes, the browser process will bad-message the renderer since this - // should never happen. Therefore it is safe to just naively always set it - // here because: + // Note that if a fenced frame's `is_fenced`, `mode`, or `sandbox_flags` + // attribute ever changes, the browser process will terminate the renderer + // since this should never happen. Therefore it is safe to just naively + // always set it here because: // - A fenced frame always has `is_fenced = true` // - A fenced frame's mode is only settable once, enforced by // `HTMLFencedFrameElement::ParseAttribute()` as well as the browser // process + // - A fenced frame's sandbox flags must be set to + // kFencedFrameForcedSandboxFlags frame_policy_.is_fenced = true; frame_policy_.fenced_frame_mode = DynamicTo<HTMLFencedFrameElement>(ContainingShadowRoot()->host()) ->GetMode(); + frame_policy_.sandbox_flags = blink::kFencedFrameForcedSandboxFlags; } // Update the |should_lazy_load_children_| value according to the "loading"
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 078aaaba..e958c9e 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
@@ -3000,8 +3000,11 @@ if (properties->TransformIsolationNode()) return true; if (auto* offset_translation = properties->PaintOffsetTranslation()) { - if (offset_translation->RequiresCompositingForFixedPosition()) + if (offset_translation->RequiresCompositingForFixedPosition() && + // This is to keep the de facto CLS behavior with crrev.com/1036822. + object.GetFrameView()->LayoutViewport()->HasOverflow()) { return true; + } } if (auto* sticky_translation = properties->StickyTranslation()) return true;
diff --git a/third_party/blink/renderer/modules/credentialmanagement/credentials_container.cc b/third_party/blink/renderer/modules/credentialmanagement/credentials_container.cc index c0bea7dc..ff99129 100644 --- a/third_party/blink/renderer/modules/credentialmanagement/credentials_container.cc +++ b/third_party/blink/renderer/modules/credentialmanagement/credentials_container.cc
@@ -1234,14 +1234,19 @@ options->signal()->AddAlgorithm(WTF::Bind(&AbortIdentityCredentialRequest, WrapPersistent(script_state))); } - mojom::blink::IdentityProviderPtr identity_provider = - blink::mojom::blink::IdentityProvider::From(*provider); + + Vector<mojom::blink::IdentityProviderPtr> identity_provider_ptrs; + for (const auto& provider : options->identity()->providers()) { + mojom::blink::IdentityProviderPtr identity_provider = + blink::mojom::blink::IdentityProvider::From(*provider); + identity_provider_ptrs.push_back(std::move(identity_provider)); + } bool prefer_auto_sign_in = options->identity()->preferAutoSignIn(); auto* auth_request = CredentialManagerProxy::From(script_state)->FederatedAuthRequest(); auth_request->RequestToken( - std::move(identity_provider), prefer_auto_sign_in, + std::move(identity_provider_ptrs), prefer_auto_sign_in, WTF::Bind(&OnRequestToken, WrapPersistent(resolver), provider_url, client_id, WrapPersistent(options)));
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_constraints.idl b/third_party/blink/renderer/modules/mediastream/media_stream_constraints.idl index 9a16c0f..861a89f 100644 --- a/third_party/blink/renderer/modules/mediastream/media_stream_constraints.idl +++ b/third_party/blink/renderer/modules/mediastream/media_stream_constraints.idl
@@ -8,6 +8,12 @@ "exclude" }; +// https://github.com/w3c/mediacapture-screen-share/pull/216/files +enum SelfCapturePreferenceEnum { + "include", + "exclude" +}; + // https://w3c.github.io/mediacapture-main/#idl-def-mediastreamconstraints dictionary MediaStreamConstraints { (boolean or MediaTrackConstraints) video = false; @@ -24,4 +30,9 @@ [ RuntimeEnabled = SystemAudioConstraint ] SystemAudioPreferenceEnum systemAudio; + + // https://github.com/w3c/mediacapture-screen-share/pull/216/files + [ + RuntimeEnabled = SelfBrowserSurfaceConstraint + ] SelfCapturePreferenceEnum selfBrowserSurface; };
diff --git a/third_party/blink/renderer/modules/mediastream/user_media_processor.cc b/third_party/blink/renderer/modules/mediastream/user_media_processor.cc index 5f21b76..7373388 100644 --- a/third_party/blink/renderer/modules/mediastream/user_media_processor.cc +++ b/third_party/blink/renderer/modules/mediastream/user_media_processor.cc
@@ -813,7 +813,9 @@ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK(current_request_info_); - if (!current_request_info_->request()->Video()) { + UserMediaRequest* const request = current_request_info_->request(); + + if (!request->Video()) { absl::optional<base::UnguessableToken> audio_session_id = DetermineExistingAudioSessionId(); GenerateStreamForCurrentRequestInfo( @@ -822,40 +824,35 @@ : StreamSelectionStrategy::FORCE_NEW_STREAM); return; } - SendLogMessage( - base::StringPrintf("SetupVideoInput. request_id=%d, video constraints=%s", - current_request_info_->request_id(), - current_request_info_->request() - ->VideoConstraints() - .ToString() - .Utf8() - .c_str())); + SendLogMessage(base::StringPrintf( + "SetupVideoInput. request_id=%d, video constraints=%s", + current_request_info_->request_id(), + request->VideoConstraints().ToString().Utf8().c_str())); auto& video_controls = current_request_info_->stream_controls()->video; - InitializeVideoTrackControls(current_request_info_->request(), - &video_controls); + InitializeVideoTrackControls(request, &video_controls); - current_request_info_->stream_controls()->request_pan_tilt_zoom_permission = - IsPanTiltZoomPermissionRequested( - current_request_info_->request()->VideoConstraints()); + StreamControls* const stream_controls = + current_request_info_->stream_controls(); + + stream_controls->request_pan_tilt_zoom_permission = + IsPanTiltZoomPermissionRequested(request->VideoConstraints()); // TODO(crbug.com/1337788): Clean up naming inconsistency with // auto_select_all_screens. - current_request_info_->stream_controls()->request_all_screens = - current_request_info_->request()->auto_select_all_screens(); + stream_controls->request_all_screens = request->auto_select_all_screens(); + + stream_controls->exclude_self_browser_surface = + request->exclude_self_browser_surface(); if (blink::IsDeviceMediaType(video_controls.stream_type)) { GetMediaDevicesDispatcher()->GetVideoInputCapabilities( WTF::Bind(&UserMediaProcessor::SelectVideoDeviceSettings, - WrapWeakPersistent(this), - WrapPersistent(current_request_info_->request()))); + WrapWeakPersistent(this), WrapPersistent(request))); } else { if (!blink::IsVideoInputMediaType(video_controls.stream_type)) { - String failed_constraint_name = - String(current_request_info_->request() - ->VideoConstraints() - .Basic() - .media_stream_source.GetName()); + String failed_constraint_name = String( + request->VideoConstraints().Basic().media_stream_source.GetName()); MediaStreamRequestResult result = MediaStreamRequestResult::CONSTRAINT_NOT_SATISFIED; GetUserMediaRequestFailed(result, failed_constraint_name);
diff --git a/third_party/blink/renderer/modules/mediastream/user_media_request.cc b/third_party/blink/renderer/modules/mediastream/user_media_request.cc index 5cce683f..0f01d9f 100644 --- a/third_party/blink/renderer/modules/mediastream/user_media_request.cc +++ b/third_party/blink/renderer/modules/mediastream/user_media_request.cc
@@ -412,6 +412,12 @@ options->systemAudio().AsEnum() == V8SystemAudioPreferenceEnum::Enum::kExclude); + // The default is to include. + result->set_exclude_self_browser_surface( + options->hasSelfBrowserSurface() && + options->selfBrowserSurface().AsEnum() == + V8SelfCapturePreferenceEnum::Enum::kExclude); + return result; }
diff --git a/third_party/blink/renderer/modules/mediastream/user_media_request.h b/third_party/blink/renderer/modules/mediastream/user_media_request.h index 74dd4e1..9ac342a 100644 --- a/third_party/blink/renderer/modules/mediastream/user_media_request.h +++ b/third_party/blink/renderer/modules/mediastream/user_media_request.h
@@ -150,6 +150,12 @@ void set_exclude_system_audio(bool value) { exclude_system_audio_ = value; } bool exclude_system_audio() const { return exclude_system_audio_; } + void set_exclude_self_browser_surface(bool value) { + exclude_self_browser_surface_ = value; + } + bool exclude_self_browser_surface() const { + return exclude_self_browser_surface_; + } bool auto_select_all_screens() const { return auto_select_all_screens_; } // Mark this request as an GetOpenDevice request for initializing a @@ -180,6 +186,7 @@ MediaConstraints video_; const bool should_prefer_current_tab_ = false; bool exclude_system_audio_ = false; + bool exclude_self_browser_surface_ = false; const bool auto_select_all_screens_ = false; bool should_disable_hardware_noise_suppression_; bool has_transient_user_activation_ = false;
diff --git a/third_party/blink/renderer/platform/exported/web_runtime_features.cc b/third_party/blink/renderer/platform/exported/web_runtime_features.cc index 5dc521cc..c1a474db 100644 --- a/third_party/blink/renderer/platform/exported/web_runtime_features.cc +++ b/third_party/blink/renderer/platform/exported/web_runtime_features.cc
@@ -369,6 +369,14 @@ RuntimeEnabledFeatures::SetSharedWorkerEnabled(enable); } +void WebRuntimeFeatures::EnableStorageAccessAPIForSiteExtension(bool enable) { + RuntimeEnabledFeatures::SetStorageAccessAPIForSiteExtensionEnabled(enable); +} + +bool WebRuntimeFeatures::IsStorageAccessAPIForSiteExtensionEnabled() { + return RuntimeEnabledFeatures::StorageAccessAPIForSiteExtensionEnabled(); +} + void WebRuntimeFeatures::EnableTextFragmentAnchor(bool enable) { RuntimeEnabledFeatures::SetTextFragmentIdentifiersEnabled(enable); }
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5 index f24c0c6..266e173b 100644 --- a/third_party/blink/renderer/platform/runtime_enabled_features.json5 +++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -2036,6 +2036,15 @@ origin_trial_allows_third_party: true }, { + // When a Web application calls getDisplayMedia() and asks for video, + // allow a hint to be provided as to whether the current tab should be + // excluded from the list of tabs offered to the user. + // + // https://github.com/w3c/mediacapture-screen-share/pull/216/files + name: "SelfBrowserSurfaceConstraint", + status: "stable", + }, + { name: "SendBeaconThrowForBlobWithNonSimpleType", status: "stable", }, @@ -2149,6 +2158,11 @@ status: "test", }, { + // Enabled when blink::features::kStorageAccessAPIForSiteExtension is enabled. + name: "StorageAccessAPIForSiteExtension", + status: "test", + }, + { name: "StorageBuckets", status: "experimental", },
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites index abbe10c..a614c79 100644 --- a/third_party/blink/web_tests/VirtualTestSuites +++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -735,6 +735,12 @@ "args": [ "--enable-features=StorageAccessAPI" ] }, { + "prefix": "storage-access-api-for-site-extension", + "platforms": ["Linux", "Mac", "Win"], + "bases": [ "wpt_internal/storage-access-api" ], + "args": [ "--enable-features=StorageAccessAPI,StorageAccessAPIForSiteExtension" ] + }, + { "prefix": "web-bluetooth-new-permissions-backend", "platforms": ["Linux", "Mac", "Win"], "bases": ["wpt_internal/bluetooth", "external/wpt/bluetooth"],
diff --git a/third_party/blink/web_tests/external/wpt/shadow-dom/declarative/innerhtml-before-closing-tag.tentative.html b/third_party/blink/web_tests/external/wpt/shadow-dom/declarative/innerhtml-before-closing-tag.tentative.html index 9a60677..cfa471d1a 100644 --- a/third_party/blink/web_tests/external/wpt/shadow-dom/declarative/innerhtml-before-closing-tag.tentative.html +++ b/third_party/blink/web_tests/external/wpt/shadow-dom/declarative/innerhtml-before-closing-tag.tentative.html
@@ -23,7 +23,8 @@ <div id=host> <template id=shadow shadowroot=open> <span id=toreplace>This should get removed</span> - <script></script> <!-- Ensure observer runs --> + <!-- Ensure observer runs at this point (https://github.com/web-platform-tests/wpt/issues/35393) --> + <script> // some content, which shouldn't be necessary </script> </template> </div>
diff --git a/third_party/blink/web_tests/external/wpt/shadow-dom/declarative/innerhtml-on-ordinary-template.tentative.html b/third_party/blink/web_tests/external/wpt/shadow-dom/declarative/innerhtml-on-ordinary-template.tentative.html index 6d01ced..221b252a 100644 --- a/third_party/blink/web_tests/external/wpt/shadow-dom/declarative/innerhtml-on-ordinary-template.tentative.html +++ b/third_party/blink/web_tests/external/wpt/shadow-dom/declarative/innerhtml-on-ordinary-template.tentative.html
@@ -21,7 +21,9 @@ </script> <div id='has-imperative-root'> - <script></script> <!-- Ensure observer runs, attaches imperative shadow root --> + <!-- Ensure observer runs at this point (https://github.com/web-platform-tests/wpt/issues/35393) --> + <script> // some content, which shouldn't be necessary </script> + <!-- The imperative shadow root should be attached now. --> <template id=ordinarytemplate shadowroot=open> <span id=toreplace>This should get removed</span> </template>
diff --git a/third_party/blink/web_tests/platform/generic/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/platform/generic/webexposed/global-interface-listing-expected.txt index 6388acf..9d18b17a 100644 --- a/third_party/blink/web_tests/platform/generic/webexposed/global-interface-listing-expected.txt +++ b/third_party/blink/web_tests/platform/generic/webexposed/global-interface-listing-expected.txt
@@ -1990,6 +1990,7 @@ method releaseEvents method replaceChildren method requestStorageAccess + method requestStorageAccessForSite method webkitCancelFullScreen method webkitExitFullscreen method write
diff --git a/third_party/blink/web_tests/virtual/storage-access-api-for-site-extension/README.md b/third_party/blink/web_tests/virtual/storage-access-api-for-site-extension/README.md new file mode 100644 index 0000000..e38dfa3 --- /dev/null +++ b/third_party/blink/web_tests/virtual/storage-access-api-for-site-extension/README.md
@@ -0,0 +1 @@ +See third_party/blink/web_tests/wpt_internal/storage-access-api/README.md
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-anchor-position/anchor-position-grid-001.html b/third_party/blink/web_tests/wpt_internal/css/css-anchor-position/anchor-position-grid-001.html new file mode 100644 index 0000000..32851d0 --- /dev/null +++ b/third_party/blink/web_tests/wpt_internal/css/css-anchor-position/anchor-position-grid-001.html
@@ -0,0 +1,82 @@ +<!DOCTYPE html> +<link rel="help" href="https://tabatkins.github.io/specs/css-anchor-position/#anchor-pos"> +<link rel="help" href="https://tabatkins.github.io/specs/css-anchor-position/#anchor-size"> +<link rel="author" href="mailto:kojii@chromium.org"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/check-layout-th.js"></script> +<style> +.cb { + position: relative; +} +.columns { + column-count: 3; + column-fill: auto; + column-gap: 10px; + width: 620px; + height: 100px; +} +.grid { + display: grid; + grid-template-columns: repeat(2, 100px); + grid-template-rows: 50px 100px; +} +.spacer { + background: yellow; +} +.anchor1 { + anchor-name: --a1; + grid-column: 2; + grid-row: 2; + border: 2px solid orange; + border-width: 5px 6px 7px 8px; +} +.target { + grid-column: 2; + grid-row: 2; + position: absolute; + width: anchor-size(--a1 width); + height: anchor-size(--a1 height); + background: lime; + opacity: .2; +} +.target1-l { + left: anchor(--a1 left); + top: anchor(--a1 top); + width: 8px; +} +.target1-r { + right: anchor(--a1 right); + bottom: anchor(--a1 bottom); + width: 6px; +} +.target1-t { + left: anchor(--a1 left); + top: anchor(--a1 top); + height: 5px; +} +.target1-b { + right: anchor(--a1 right); + bottom: anchor(--a1 bottom); + height: 5px; +} +</style> +<body onload="checkLayout('.target')"> + <div> + <div class="spacer" style="height: 10px"></div> + <div class="columns"> + <div class="spacer" style="height: 10px"></div> + <div class="grid cb"> + <div>1</div> + <div>2</div> + <div>3</div> + <div class="anchor1"></div> + + <div class="target target1-l" data-offset-x=100 data-expected-height=100></div> + <div class="target target1-r" data-offset-x=404 data-expected-height=100></div> + <div class="target target1-t" data-offset-y=0 data-expected-width=310></div> + <div class="target target1-b" data-offset-y=95 data-expected-width=310></div> + </div> + </div> + </div> +</body>
diff --git a/third_party/blink/web_tests/wpt_internal/storage-access-api/README.md b/third_party/blink/web_tests/wpt_internal/storage-access-api/README.md new file mode 100644 index 0000000..e343e47 --- /dev/null +++ b/third_party/blink/web_tests/wpt_internal/storage-access-api/README.md
@@ -0,0 +1,18 @@ +# requestStorageAccessForSite Tests +These tests are tentative. They are based on a proposed requestStorageAccessForSite extension to the Storage Access API which can be read about [in the explainer](https://github.com/mreichhoff/requestStorageAccessForSite). + +Note that the spec is not yet defined, though very early [prose](https://github.com/mreichhoff/requestStorageAccessForSite#proposed-draft-spec-addition) and [bikeshed](https://github.com/mreichhoff/storage-access/commit/93ba79fdbb737f57a7ce757f994b2f8c53d2cd53) drafts are available. + +## Running Tests + +The WPTs run as [virtual tests](https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/web_tests/VirtualTestSuites). This is required as the proposed API is behind a feature flag. + +```bash +# Build web tests +autoninja -C out/Default blink_tests + +# Run a single test +third_party/blink/tools/run_web_tests.py -t Default third_party/blink/web_tests/wpt_internal/storage-access-api/requestStorageAccessForSite.sub.tentative.window.js +``` + +See the [web tests doc](https://chromium.googlesource.com/chromium/src/+/HEAD/docs/testing/web_tests.md#running-the-tests) for more details on using the test runner.
diff --git a/third_party/blink/web_tests/wpt_internal/storage-access-api/requestStorageAccessForSite.sub.tentative.window.js b/third_party/blink/web_tests/wpt_internal/storage-access-api/requestStorageAccessForSite.sub.tentative.window.js new file mode 100644 index 0000000..8e82dbe --- /dev/null +++ b/third_party/blink/web_tests/wpt_internal/storage-access-api/requestStorageAccessForSite.sub.tentative.window.js
@@ -0,0 +1,139 @@ +// META: script=/storage-access-api/helpers.js +// META: script=/resources/testdriver.js +// META: script=/resources/testdriver-vendor.js +'use strict'; + +// Note that this file follows the pattern in: +// third_party/blink/web_tests/external/wpt/storage-access-api/requestStorageAccess.sub.window.js +// +// Some tests are run at the top-level, and an iframe is added to validate API +// behavior in that context. + +// Prefix each test case with an indicator so we know what context they are run +// in if they are used in multiple iframes. +let testPrefix = 'top-level-context'; + +// Keep track of if we run these tests in a nested context, we don't want to +// recurse forever. +let topLevelDocument = true; + +// The query string allows derivation of test conditions, like whether the tests +// are running in a top-level context. +let queryParams = window.location.search.substring(1).split('&'); +queryParams.forEach(function(param, index) { + if (param.toLowerCase() == 'rootdocument=false') { + topLevelDocument = false; + } else if (param.split('=')[0].toLowerCase() == 'testcase') { + testPrefix = param.split('=')[1]; + } +}); + +// Common tests to run in all frames. +test( + () => { + assert_not_equals(document.requestStorageAccessForSite, undefined); + }, + '[' + testPrefix + + '] document.requestStorageAccessForSite() should be supported on the document interface'); + +if (topLevelDocument) { + promise_test( + t => { + let promise = document.requestStorageAccessForSite('https://test.com'); + let description = + 'document.requestStorageAccessForSite() call without user gesture'; + return promise + .then(t.unreached_func('Should have rejected: ' + description)) + .catch(function(e) { + assert_equals(undefined, e, description); + }); + }, + '[' + testPrefix + + '] document.requestStorageAccessForSite() should be rejected by default with no user gesture'); + + // Create a test with a single-child same-origin iframe. + // This will validate that calls to requestStorageAccessForSite are rejected + // in non-top-level contexts. + RunTestsInIFrame( + './resources/requestStorageAccessForSite-iframe.html?testCase=same-origin-frame&rootdocument=false'); + + promise_test( + async t => { + let access_promise = null; + let testMethod = function() { + access_promise = + document.requestStorageAccessForSite(document.location.origin); + }; + await ClickButtonWithGesture(testMethod); + + return access_promise; + }, + '[' + testPrefix + + '] document.requestStorageAccessForSite() should be resolved when called properly with a user gesture and the same site'); + + promise_test( + async t => { + let access_promise = null; + let description = + 'document.requestStorageAccessForSite() call with bogus URL'; + let testMethod = function() { + access_promise = document.requestStorageAccessForSite('bogus-url') + .then(t.unreached_func( + 'Should have rejected: ' + description)) + .catch(function(e) { + assert_equals(undefined, e, description); + }); + ; + }; + await ClickButtonWithGesture(testMethod); + + return access_promise; + }, + '[' + testPrefix + + '] document.requestStorageAccessForSite() should be rejected when called with an invalid site'); + + promise_test( + async t => { + let access_promise = null; + let description = + 'document.requestStorageAccessForSite() call with data URL'; + let testMethod = function() { + access_promise = + document.requestStorageAccessForSite('data:,Hello%2C%20World%21') + .then( + t.unreached_func('Should have rejected: ' + description)) + .catch(function(e) { + assert_equals(undefined, e, description); + }); + ; + }; + await ClickButtonWithGesture(testMethod); + + return access_promise; + }, + '[' + testPrefix + + '] document.requestStorageAccessForSite() should be rejected when called with an opaque origin'); + +} else { + promise_test( + async t => { + let access_promise = null; + let description = + 'document.requestStorageAccessForSite() call in a non-top-level context'; + let testMethod = function() { + access_promise = + document.requestStorageAccessForSite(document.location.origin) + .then( + t.unreached_func('Should have rejected: ' + description)) + .catch(function(e) { + assert_equals(undefined, e, description); + }); + ; + }; + await ClickButtonWithGesture(testMethod); + + return access_promise; + }, + '[' + testPrefix + + '] document.requestStorageAccessForSite() should be rejected when called in an iframe'); +}
diff --git a/third_party/blink/web_tests/wpt_internal/storage-access-api/resources/requestStorageAccessForSite-iframe.html b/third_party/blink/web_tests/wpt_internal/storage-access-api/resources/requestStorageAccessForSite-iframe.html new file mode 100644 index 0000000..1da32c1 --- /dev/null +++ b/third_party/blink/web_tests/wpt_internal/storage-access-api/resources/requestStorageAccessForSite-iframe.html
@@ -0,0 +1,9 @@ +<!doctype html> +<meta charset=utf-8> + +<script src="/storage-access-api/helpers.js"></script> +<script src="/resources/testharness.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<div id=log></div> +<script src="../requestStorageAccessForSite.sub.tentative.window.js"></script>
diff --git a/third_party/crashpad/crashpad/snapshot/mac/system_snapshot_mac_test.cc b/third_party/crashpad/crashpad/snapshot/mac/system_snapshot_mac_test.cc index ab09b5b..6bf32b1f 100644 --- a/third_party/crashpad/crashpad/snapshot/mac/system_snapshot_mac_test.cc +++ b/third_party/crashpad/crashpad/snapshot/mac/system_snapshot_mac_test.cc
@@ -82,13 +82,7 @@ EXPECT_GE(system_snapshot().CPUCount(), 1); } -#if defined(ARCH_CPU_ARM64) -// https://crbug.com/1222625 -#define MAYBE_CPUVendor DISABLED_CPUVendor -#else -#define MAYBE_CPUVendor CPUVendor -#endif -TEST_F(SystemSnapshotMacTest, MAYBE_CPUVendor) { +TEST_F(SystemSnapshotMacTest, CPUVendor) { std::string cpu_vendor = system_snapshot().CPUVendor(); #if defined(ARCH_CPU_X86_FAMILY)
diff --git a/third_party/ipcz/src/BUILD.gn b/third_party/ipcz/src/BUILD.gn index 4fa9f4fd..78187739 100644 --- a/third_party/ipcz/src/BUILD.gn +++ b/third_party/ipcz/src/BUILD.gn
@@ -138,13 +138,11 @@ public = [ "reference_drivers/async_reference_driver.h", - "reference_drivers/blob.h", "reference_drivers/sync_reference_driver.h", ] sources = [ "reference_drivers/async_reference_driver.cc", - "reference_drivers/blob.cc", "reference_drivers/object.cc", "reference_drivers/object.h", "reference_drivers/random.cc",
diff --git a/third_party/ipcz/src/box_test.cc b/third_party/ipcz/src/box_test.cc index f13203ab..cdbfce0a 100644 --- a/third_party/ipcz/src/box_test.cc +++ b/third_party/ipcz/src/box_test.cc
@@ -6,7 +6,6 @@ #include <string_view> #include "ipcz/ipcz.h" -#include "reference_drivers/blob.h" #include "test/multinode_test.h" #include "testing/gtest/include/gtest/gtest.h" #include "util/ref_counted.h" @@ -14,71 +13,45 @@ namespace ipcz { namespace { -using Blob = reference_drivers::Blob; - using BoxTestNode = test::TestNode; using BoxTest = test::MultinodeTest<BoxTestNode>; -IpczDriverHandle CreateTestBlob(std::string_view message) { - return Blob::ReleaseAsHandle(MakeRefCounted<Blob>(message)); -} - -std::string GetBlobContents(IpczDriverHandle handle) { - Ref<Blob> blob = Blob::TakeFromHandle(handle); - return std::string(blob->message()); -} - -TEST_P(BoxTest, BoxAndUnbox) { +MULTINODE_TEST(BoxTest, BoxAndUnbox) { constexpr const char kMessage[] = "Hello, world?"; - IpczDriverHandle blob_handle = CreateTestBlob(kMessage); - - IpczHandle box; - EXPECT_EQ(IPCZ_RESULT_OK, - ipcz().Box(node(), blob_handle, IPCZ_NO_FLAGS, nullptr, &box)); - - blob_handle = IPCZ_INVALID_DRIVER_HANDLE; - EXPECT_EQ(IPCZ_RESULT_OK, - ipcz().Unbox(box, IPCZ_NO_FLAGS, nullptr, &blob_handle)); - EXPECT_EQ(kMessage, GetBlobContents(blob_handle)); + EXPECT_EQ(kMessage, UnboxBlob(BoxBlob(kMessage))); } -TEST_P(BoxTest, CloseBox) { - Ref<Blob> blob = MakeRefCounted<Blob>("meh"); - Ref<Blob::RefCountedFlag> destroyed = blob->destruction_flag_for_testing(); - IpczDriverHandle blob_handle = Blob::ReleaseAsHandle(std::move(blob)); - - IpczHandle box; +MULTINODE_TEST(BoxTest, CloseBox) { + // Verifies that box closure releases its underlying driver object. This test + // does not explicitly observe side effects of that release, but LSan will + // fail if something's off. EXPECT_EQ(IPCZ_RESULT_OK, - ipcz().Box(node(), blob_handle, IPCZ_NO_FLAGS, nullptr, &box)); - - EXPECT_FALSE(destroyed->get()); - EXPECT_EQ(IPCZ_RESULT_OK, ipcz().Close(box, IPCZ_NO_FLAGS, nullptr)); - EXPECT_TRUE(destroyed->get()); + ipcz().Close(BoxBlob("meh"), IPCZ_NO_FLAGS, nullptr)); } -TEST_P(BoxTest, Peek) { - constexpr const char kMessage[] = "Hello, world?"; - IpczDriverHandle blob_handle = CreateTestBlob(kMessage); - IpczHandle box; - EXPECT_EQ(IPCZ_RESULT_OK, - ipcz().Box(node(), blob_handle, IPCZ_NO_FLAGS, nullptr, &box)); +MULTINODE_TEST(BoxTest, Peek) { + constexpr std::string_view kMessage = "Hello, world?"; + IpczHandle box = BoxBlob(kMessage); - blob_handle = IPCZ_INVALID_DRIVER_HANDLE; + IpczDriverHandle memory = IPCZ_INVALID_DRIVER_HANDLE; EXPECT_EQ(IPCZ_RESULT_OK, - ipcz().Unbox(box, IPCZ_UNBOX_PEEK, nullptr, &blob_handle)); + ipcz().Unbox(box, IPCZ_UNBOX_PEEK, nullptr, &memory)); EXPECT_EQ(IPCZ_RESULT_OK, - ipcz().Unbox(box, IPCZ_UNBOX_PEEK, nullptr, &blob_handle)); + ipcz().Unbox(box, IPCZ_UNBOX_PEEK, nullptr, &memory)); EXPECT_EQ(IPCZ_RESULT_OK, - ipcz().Unbox(box, IPCZ_UNBOX_PEEK, nullptr, &blob_handle)); + ipcz().Unbox(box, IPCZ_UNBOX_PEEK, nullptr, &memory)); + EXPECT_NE(IPCZ_INVALID_DRIVER_HANDLE, memory); - Blob* blob = Blob::FromHandle(blob_handle); - EXPECT_EQ(kMessage, blob->message()); - + IpczDriverHandle mapping; + void* base; EXPECT_EQ(IPCZ_RESULT_OK, - ipcz().Unbox(box, IPCZ_NO_FLAGS, nullptr, &blob_handle)); + GetDriver().MapSharedMemory(memory, IPCZ_NO_FLAGS, nullptr, &base, + &mapping)); + std::string contents(static_cast<const char*>(base), kMessage.size()); + EXPECT_EQ(kMessage, contents); + EXPECT_EQ(IPCZ_RESULT_OK, GetDriver().Close(mapping, IPCZ_NO_FLAGS, nullptr)); - Ref<Blob> released_blob = Blob::TakeFromHandle(blob_handle); - EXPECT_EQ(blob, released_blob.get()); + EXPECT_EQ(kMessage, UnboxBlob(box)); } constexpr const char kMessage1[] = "Hello, world?"; @@ -91,25 +64,14 @@ IpczHandle box; EXPECT_EQ(IPCZ_RESULT_OK, WaitToGet(b, &message, {&box, 1})); EXPECT_EQ(kMessage2, message); - - IpczDriverHandle blob_handle; - EXPECT_EQ(IPCZ_RESULT_OK, - ipcz().Unbox(box, IPCZ_NO_FLAGS, nullptr, &blob_handle)); - EXPECT_EQ(kMessage1, GetBlobContents(blob_handle)); - + EXPECT_EQ(kMessage1, UnboxBlob(box)); Close(b); } -TEST_P(BoxTest, TransferBox) { +MULTINODE_TEST(BoxTest, TransferBox) { IpczHandle c = SpawnTestNode<TransferBoxClient>(); - - IpczDriverHandle blob_handle = CreateTestBlob(kMessage1); - IpczHandle box; - EXPECT_EQ(IPCZ_RESULT_OK, - ipcz().Box(node(), blob_handle, IPCZ_NO_FLAGS, nullptr, &box)); - + IpczHandle box = BoxBlob(kMessage1); EXPECT_EQ(IPCZ_RESULT_OK, Put(c, kMessage2, {&box, 1})); - Close(c); } @@ -121,19 +83,14 @@ EXPECT_EQ(IPCZ_RESULT_OK, WaitToGet(b, nullptr, {&q, 1})); for (size_t i = 0; i < TransferBoxBetweenNonBrokersNumIterations; ++i) { - IpczDriverHandle blob_handle = CreateTestBlob(kMessage1); - IpczHandle box; - EXPECT_EQ(IPCZ_RESULT_OK, - ipcz().Box(node(), blob_handle, IPCZ_NO_FLAGS, nullptr, &box)); + IpczHandle box = BoxBlob(kMessage1); EXPECT_EQ(IPCZ_RESULT_OK, Put(q, kMessage2, {&box, 1})); box = IPCZ_INVALID_DRIVER_HANDLE; std::string message; EXPECT_EQ(IPCZ_RESULT_OK, WaitToGet(q, &message, {&box, 1})); EXPECT_EQ(kMessage1, message); - EXPECT_EQ(IPCZ_RESULT_OK, - ipcz().Unbox(box, IPCZ_NO_FLAGS, nullptr, &blob_handle)); - EXPECT_EQ(kMessage2, GetBlobContents(blob_handle)); + EXPECT_EQ(kMessage2, UnboxBlob(box)); } WaitForDirectRemoteLink(q); @@ -147,17 +104,12 @@ for (size_t i = 0; i < TransferBoxBetweenNonBrokersNumIterations; ++i) { IpczHandle box; - IpczDriverHandle blob_handle; std::string message; EXPECT_EQ(IPCZ_RESULT_OK, WaitToGet(p, &message, {&box, 1})); EXPECT_EQ(kMessage2, message); - EXPECT_EQ(IPCZ_RESULT_OK, - ipcz().Unbox(box, IPCZ_NO_FLAGS, nullptr, &blob_handle)); - EXPECT_EQ(kMessage1, GetBlobContents(blob_handle)); + EXPECT_EQ(kMessage1, UnboxBlob(box)); - blob_handle = CreateTestBlob(kMessage2); - EXPECT_EQ(IPCZ_RESULT_OK, - ipcz().Box(node(), blob_handle, IPCZ_NO_FLAGS, nullptr, &box)); + box = BoxBlob(kMessage2); EXPECT_EQ(IPCZ_RESULT_OK, Put(p, kMessage1, {&box, 1})); } @@ -165,7 +117,7 @@ CloseAll({p, b}); } -TEST_P(BoxTest, TransferBoxBetweenNonBrokers) { +MULTINODE_TEST(BoxTest, TransferBoxBetweenNonBrokers) { IpczHandle c1 = SpawnTestNode<TransferBoxBetweenNonBrokersClient1>(); IpczHandle c2 = SpawnTestNode<TransferBoxBetweenNonBrokersClient2>(); @@ -181,7 +133,5 @@ CloseAll({c1, c2}); } -INSTANTIATE_MULTINODE_TEST_SUITE_P(BoxTest); - } // namespace } // namespace ipcz
diff --git a/third_party/ipcz/src/connect_test.cc b/third_party/ipcz/src/connect_test.cc index 10d4df5..41cb3d54 100644 --- a/third_party/ipcz/src/connect_test.cc +++ b/third_party/ipcz/src/connect_test.cc
@@ -6,7 +6,6 @@ #include "ipcz/ipcz.h" #include "ipcz/node_messages.h" -#include "reference_drivers/blob.h" #include "test/multinode_test.h" #include "test/test_transport_listener.h" #include "testing/gtest/include/gtest/gtest.h" @@ -25,7 +24,7 @@ Close(b); } -TEST_P(ConnectTest, BrokerToNonBroker) { +MULTINODE_TEST(ConnectTest, BrokerToNonBroker) { IpczHandle c = SpawnTestNode<BrokerToNonBrokerClient>(); Close(c); } @@ -47,7 +46,7 @@ CloseAll(portals); } -TEST_P(ConnectTest, SurplusPortals) { +MULTINODE_TEST(ConnectTest, SurplusPortals) { IpczHandle portals[kNumBrokerPortals]; SpawnTestNode<SurplusPortalsClient>(portals); CloseAll(portals); @@ -59,12 +58,12 @@ Close(b); } -TEST_P(ConnectTest, DisconnectWithoutBrokerHandshake) { - TransportPair transports = CreateTransports(); +MULTINODE_TEST(ConnectTest, DisconnectWithoutBrokerHandshake) { + IpczDriverHandle our_transport; auto controller = - SpawnTestNodeWithTransport<ExpectDisconnectFromBroker>(transports.theirs); + SpawnTestNodeNoConnect<ExpectDisconnectFromBroker>(our_transport); EXPECT_EQ(IPCZ_RESULT_OK, - GetDriver().Close(transports.ours, IPCZ_NO_FLAGS, nullptr)); + GetDriver().Close(our_transport, IPCZ_NO_FLAGS, nullptr)); controller->WaitForShutdown(); } @@ -74,25 +73,25 @@ // we never call ConnectToBroker(). No action required. } -TEST_P(ConnectTest, DisconnectWithoutNonBrokerHandshake) { +MULTINODE_TEST(ConnectTest, DisconnectWithoutNonBrokerHandshake) { IpczHandle c = SpawnTestNode<DisconnectWithoutNonBrokerHandshakeClient>(); EXPECT_EQ(IPCZ_RESULT_OK, WaitForConditionFlags(c, IPCZ_TRAP_PEER_CLOSED)); Close(c); } -TEST_P(ConnectTest, DisconnectOnBadBrokerMessage) { - TransportPair transports = CreateTransports(); +MULTINODE_TEST(ConnectTest, DisconnectOnBadBrokerMessage) { + IpczDriverHandle our_transport; auto controller = - SpawnTestNodeWithTransport<ExpectDisconnectFromBroker>(transports.theirs); + SpawnTestNodeNoConnect<ExpectDisconnectFromBroker>(our_transport); // Send some garbage to the other node. const char kBadMessage[] = "this will never be a valid handshake message!"; EXPECT_EQ( IPCZ_RESULT_OK, - GetDriver().Transmit(transports.ours, kBadMessage, std::size(kBadMessage), + GetDriver().Transmit(our_transport, kBadMessage, std::size(kBadMessage), nullptr, 0, IPCZ_NO_FLAGS, nullptr)); EXPECT_EQ(IPCZ_RESULT_OK, - GetDriver().Close(transports.ours, IPCZ_NO_FLAGS, nullptr)); + GetDriver().Close(our_transport, IPCZ_NO_FLAGS, nullptr)); // The other node will only shut down once it's observed peer closure on its // portal to us; which it should, because we just sent it some garbage. @@ -115,7 +114,7 @@ listener.StopListening(); } -TEST_P(ConnectTest, DisconnectOnBadNonBrokerMessage) { +MULTINODE_TEST(ConnectTest, DisconnectOnBadNonBrokerMessage) { IpczHandle c; auto controller = SpawnTestNode<TransmitSomeGarbage>({&c, 1}); @@ -160,7 +159,7 @@ CloseAll({c, b}); } -TEST_P(ConnectTest, NonBrokerToNonBroker) { +MULTINODE_TEST(ConnectTest, NonBrokerToNonBroker) { IpczHandle c1 = SpawnTestNode<NonBrokerToNonBrokerClient>(); IpczHandle c2 = SpawnTestNode<NonBrokerToNonBrokerClient>(); @@ -212,7 +211,7 @@ GetDriver().Close(transports.theirs, IPCZ_NO_FLAGS, nullptr)); } -TEST_P(ConnectTest, BadNonBrokerReferral) { +MULTINODE_TEST(ConnectTest, BadNonBrokerReferral) { IpczHandle c = SpawnTestNode<BadNonBrokerReferralClient>(); EXPECT_EQ(IPCZ_RESULT_OK, WaitForConditionFlags(c, IPCZ_TRAP_PEER_CLOSED)); Close(c); @@ -230,27 +229,25 @@ MULTINODE_TEST_NODE(ConnectTestNode, FailedNonBrokerReferralClient) { IpczHandle b = ConnectToBroker(); - TransportPair transports = CreateTransports(); + IpczDriverHandle our_transport; auto controller = - SpawnTestNodeWithTransport<FailedNonBrokerReferralReferredClient>( - transports.theirs); + SpawnTestNodeNoConnect<FailedNonBrokerReferralReferredClient>( + our_transport); // Disconnect the transport instead of passing to our broker with // ConnectNode(). The referred client should observe disconnection of its // initial portals and terminate itself. EXPECT_EQ(IPCZ_RESULT_OK, - GetDriver().Close(transports.ours, IPCZ_NO_FLAGS, nullptr)); + GetDriver().Close(our_transport, IPCZ_NO_FLAGS, nullptr)); controller->WaitForShutdown(); Close(b); } -TEST_P(ConnectTest, FailedNonBrokerReferral) { +MULTINODE_TEST(ConnectTest, FailedNonBrokerReferral) { IpczHandle c = SpawnTestNode<FailedNonBrokerReferralClient>(); EXPECT_EQ(IPCZ_RESULT_OK, WaitForConditionFlags(c, IPCZ_TRAP_PEER_CLOSED)); Close(c); } -INSTANTIATE_MULTINODE_TEST_SUITE_P(ConnectTest); - } // namespace } // namespace ipcz
diff --git a/third_party/ipcz/src/merge_portals_test.cc b/third_party/ipcz/src/merge_portals_test.cc index a25008a..306605b 100644 --- a/third_party/ipcz/src/merge_portals_test.cc +++ b/third_party/ipcz/src/merge_portals_test.cc
@@ -30,7 +30,7 @@ Close(b); } -TEST_P(MergePortalsTest, MergeWithInitialPortal) { +MULTINODE_TEST(MergePortalsTest, MergeWithInitialPortal) { IpczHandle c = SpawnTestNode<MergeWithInitialPortalClient>(); auto [q, p] = OpenPortals(); EXPECT_EQ(IPCZ_RESULT_OK, Merge(c, p)); @@ -43,7 +43,7 @@ Close(q); } -TEST_P(MergePortalsTest, MergeWithClosedLocalPeer) { +MULTINODE_TEST(MergePortalsTest, MergeWithClosedLocalPeer) { auto [q, p] = OpenPortals(); auto [d, b] = OpenPortals(); @@ -64,7 +64,7 @@ Close(b); } -TEST_P(MergePortalsTest, MergeWithClosedRemotePeer) { +MULTINODE_TEST(MergePortalsTest, MergeWithClosedRemotePeer) { IpczHandle c = SpawnTestNode<MergeWithClosedRemotePeerClient>(); auto [r, s] = OpenPortals(); EXPECT_EQ(IPCZ_RESULT_OK, Put(c, "", {&r, 1})); @@ -95,7 +95,7 @@ CloseAll({b, portal, other_client}); } -TEST_P(MergePortalsTest, MergeComplexRoutes) { +MULTINODE_TEST(MergePortalsTest, MergeComplexRoutes) { IpczHandle c1 = SpawnTestNode<MergeComplexRoutesClient>(); IpczHandle c2 = SpawnTestNode<MergeComplexRoutesClient>(); @@ -123,7 +123,5 @@ CloseAll({c1, c2}); } -INSTANTIATE_MULTINODE_TEST_SUITE_P(MergePortalsTest); - } // namespace } // namespace ipcz
diff --git a/third_party/ipcz/src/queueing_test.cc b/third_party/ipcz/src/queueing_test.cc index a3ed6b74..d560dc5 100644 --- a/third_party/ipcz/src/queueing_test.cc +++ b/third_party/ipcz/src/queueing_test.cc
@@ -41,7 +41,7 @@ Close(b); } -TEST_P(QueueingTest, RemoteQueueFeedback) { +MULTINODE_TEST(QueueingTest, RemoteQueueFeedback) { // Exercises operations which rely on feedback from the remote peer regarding // its inbound parcel queue state. IpczHandle c = SpawnTestNode<RemoteQueueFeedbackClient>(); @@ -126,7 +126,7 @@ Close(b); } -TEST_P(QueueingTest, TwoPhaseQueueing) { +MULTINODE_TEST(QueueingTest, TwoPhaseQueueing) { IpczHandle c = SpawnTestNode<TwoPhaseQueueingClient>(); WaitForDirectRemoteLink(c); @@ -176,7 +176,7 @@ Close(b); } -TEST_P(QueueingTest, TwoPhaseFeedback) { +MULTINODE_TEST(QueueingTest, TwoPhaseFeedback) { IpczHandle c = SpawnTestNode<TwoPhaseFeedbackClient>(); WaitForDirectRemoteLink(c); EXPECT_EQ(IPCZ_RESULT_OK, Put(c, "hello?")); @@ -186,7 +186,5 @@ Close(c); } -INSTANTIATE_MULTINODE_TEST_SUITE_P(QueueingTest); - } // namespace } // namespace ipcz
diff --git a/third_party/ipcz/src/reference_drivers/blob.cc b/third_party/ipcz/src/reference_drivers/blob.cc deleted file mode 100644 index bbebebe9..0000000 --- a/third_party/ipcz/src/reference_drivers/blob.cc +++ /dev/null
@@ -1,41 +0,0 @@ -// Copyright 2022 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "reference_drivers/blob.h" - -#include <iterator> - -#include "util/ref_counted.h" - -namespace ipcz::reference_drivers { - -Blob::RefCountedFlag::RefCountedFlag() = default; - -Blob::RefCountedFlag::~RefCountedFlag() = default; - -Blob::Blob(std::string_view message) : message_(message) {} - -Blob::~Blob() = default; - -IpczResult Blob::Close() { - destruction_flag_for_testing_->set(true); - return IPCZ_RESULT_OK; -} - -// static -Blob* Blob::FromHandle(IpczDriverHandle handle) { - Object* object = Object::FromHandle(handle); - if (!object || object->type() != kBlob) { - return nullptr; - } - - return static_cast<Blob*>(object); -} - -// static -Ref<Blob> Blob::TakeFromHandle(IpczDriverHandle handle) { - return AdoptRef(FromHandle(handle)); -} - -} // namespace ipcz::reference_drivers
diff --git a/third_party/ipcz/src/reference_drivers/blob.h b/third_party/ipcz/src/reference_drivers/blob.h deleted file mode 100644 index 84be3788..0000000 --- a/third_party/ipcz/src/reference_drivers/blob.h +++ /dev/null
@@ -1,62 +0,0 @@ -// Copyright 2022 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef IPCZ_SRC_REFERENCE_DRIVERS_BLOB_H_ -#define IPCZ_SRC_REFERENCE_DRIVERS_BLOB_H_ - -#include <string> -#include <string_view> - -#include "reference_drivers/object.h" -#include "util/ref_counted.h" - -namespace ipcz::reference_drivers { - -// A driver-managed object which packages arbitrary string data. Blobs are used -// to exercise driver object boxing in tests. -// -// Note that unlike the transport and memory objects defined by the reference -// drivers, a blob is not a type of object known to ipcz. Instead it is used to -// demonstrate how drivers can define arbitrary new types of transferrable -// objects to extend ipcz. -class Blob : public ObjectImpl<Blob, Object::kBlob> { - public: - class RefCountedFlag : public RefCounted { - public: - RefCountedFlag(); - - bool get() const { return flag_; } - void set(bool flag) { flag_ = flag; } - - private: - ~RefCountedFlag() override; - bool flag_ = false; - }; - - explicit Blob(std::string_view message); - - // Object: - IpczResult Close() override; - - std::string& message() { return message_; } - - const Ref<RefCountedFlag>& destruction_flag_for_testing() const { - return destruction_flag_for_testing_; - } - - static Blob* FromHandle(IpczDriverHandle handle); - static Ref<Blob> TakeFromHandle(IpczDriverHandle handle); - - protected: - ~Blob() override; - - private: - std::string message_; - const Ref<RefCountedFlag> destruction_flag_for_testing_{ - MakeRefCounted<RefCountedFlag>()}; -}; - -} // namespace ipcz::reference_drivers - -#endif // IPCZ_SRC_REFERENCE_DRIVERS_BLOB_H_
diff --git a/third_party/ipcz/src/reference_drivers/multiprocess_reference_driver.cc b/third_party/ipcz/src/reference_drivers/multiprocess_reference_driver.cc index fe967b1..9efb49d 100644 --- a/third_party/ipcz/src/reference_drivers/multiprocess_reference_driver.cc +++ b/third_party/ipcz/src/reference_drivers/multiprocess_reference_driver.cc
@@ -11,7 +11,6 @@ #include <utility> #include "ipcz/ipcz.h" -#include "reference_drivers/blob.h" #include "reference_drivers/file_descriptor.h" #include "reference_drivers/memfd_memory.h" #include "reference_drivers/object.h" @@ -206,11 +205,6 @@ required_num_handles = 1; break; - case Object::kBlob: - required_num_bytes += Blob::FromObject(object)->message().size(); - required_num_handles = 0; - break; - default: return IPCZ_RESULT_INVALID_ARGUMENT; } @@ -246,12 +240,6 @@ break; } - case Object::kBlob: { - auto blob = Blob::TakeFromObject(object); - memcpy(&header + 1, blob->message().data(), blob->message().size()); - break; - } - default: return IPCZ_RESULT_INVALID_ARGUMENT; } @@ -290,12 +278,6 @@ } break; - case Object::kBlob: - object = MakeRefCounted<Blob>( - std::string_view(reinterpret_cast<const char*>(&header + 1), - num_bytes - sizeof(header))); - break; - default: break; }
diff --git a/third_party/ipcz/src/reference_drivers/object.h b/third_party/ipcz/src/reference_drivers/object.h index 56e88cd..58bc368 100644 --- a/third_party/ipcz/src/reference_drivers/object.h +++ b/third_party/ipcz/src/reference_drivers/object.h
@@ -21,11 +21,6 @@ kMemory, kMapping, - // A non-standard driver object type, used to exercise more complex, custom - // driver object de/serialization via boxing and unboxing in tests. See the - // Blob definition in src/reference_drivers/blob.h. - kBlob, - #if defined(OS_LINUX) // A non-standard driver object type which wraps a FileDescriptor object. kFileDescriptor,
diff --git a/third_party/ipcz/src/remote_portal_test.cc b/third_party/ipcz/src/remote_portal_test.cc index 798fdfe9..fb554c8 100644 --- a/third_party/ipcz/src/remote_portal_test.cc +++ b/third_party/ipcz/src/remote_portal_test.cc
@@ -6,8 +6,8 @@ #include <string_view> #include <utility> +#include "build/build_config.h" #include "ipcz/ipcz.h" -#include "reference_drivers/blob.h" #include "test/multinode_test.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/abseil-cpp/absl/strings/str_cat.h" @@ -31,7 +31,7 @@ Close(b); } -TEST_P(RemotePortalTest, BasicConnection) { +MULTINODE_TEST(RemotePortalTest, BasicConnection) { IpczHandle c = SpawnTestNode<BasicConnectionClient>(); std::string message; @@ -55,7 +55,7 @@ CloseAll({p, b}); } -TEST_P(RemotePortalTest, PortalTransfer) { +MULTINODE_TEST(RemotePortalTest, PortalTransfer) { IpczHandle c = SpawnTestNode<PortalTransferClient>(); auto [q, p] = OpenPortals(); @@ -110,7 +110,7 @@ CloseAll({p, b}); } -TEST_P(RemotePortalTest, MultipleHops) { +MULTINODE_TEST(RemotePortalTest, MultipleHops) { IpczHandle c1 = SpawnTestNode<MultipleHopsClient1>(); IpczHandle c2 = SpawnTestNode<MultipleHopsClient2>(); @@ -138,7 +138,7 @@ Close(b); } -TEST_P(RemotePortalTest, TransferBackAndForth) { +MULTINODE_TEST(RemotePortalTest, TransferBackAndForth) { IpczHandle c = SpawnTestNode<TransferBackAndForthClient>(); constexpr std::string_view kMessage = "hihihihi"; @@ -176,22 +176,14 @@ EXPECT_EQ(IPCZ_RESULT_OK, WaitToGet(other_client, nullptr, {&portals[i], 1})); - IpczDriverHandle blob = reference_drivers::Blob::ReleaseAsHandle( - MakeRefCounted<reference_drivers::Blob>(absl::StrCat(absl::Dec(i)))); - IpczHandle box; - EXPECT_EQ(IPCZ_RESULT_OK, - ipcz().Box(node(), blob, IPCZ_NO_FLAGS, nullptr, &box)); + IpczHandle box = BoxBlob(absl::StrCat(absl::Dec(i))); EXPECT_EQ(IPCZ_RESULT_OK, Put(portals[i], "", {&box, 1})); } for (size_t i = 0; i < kHugeNumberOfPortalsCount; ++i) { IpczHandle box; EXPECT_EQ(IPCZ_RESULT_OK, WaitToGet(portals[i], nullptr, {&box, 1})); - - IpczDriverHandle blob; - EXPECT_EQ(IPCZ_RESULT_OK, ipcz().Unbox(box, IPCZ_NO_FLAGS, nullptr, &blob)); - EXPECT_EQ(absl::StrCat(absl::Dec(i)), - reference_drivers::Blob::TakeFromHandle(blob)->message()); + EXPECT_EQ(absl::StrCat(absl::Dec(i)), UnboxBlob(box)); } EXPECT_EQ(IPCZ_RESULT_OK, Put(b, "", {&other_client, 1})); @@ -200,7 +192,7 @@ Close(b); } -TEST_P(RemotePortalTest, HugeNumberOfPortals) { +MULTINODE_TEST(RemotePortalTest, HugeNumberOfPortals) { // Opens a very large number of portals, and sends them all to client nodes. // The client nodes exchange these portals with each other and transmit // parcels over them, with and without driver objects. This exercises @@ -238,7 +230,7 @@ Close(b); } -TEST_P(RemotePortalTest, RoutingStressTest) { +MULTINODE_TEST(RemotePortalTest, RoutingStressTest) { // This test spawns a bunch of nodes and bounces two portals back and forth // among them over a large number of iterations, then waits for all the // intermediate routers to be removed. Every iteration also sends a message @@ -254,11 +246,7 @@ auto [a, b] = OpenPortals(); for (size_t j = 0; j < kRouteExpansionStressTestNumIterations; ++j) { - IpczDriverHandle blob = reference_drivers::Blob::ReleaseAsHandle( - MakeRefCounted<reference_drivers::Blob>(absl::StrCat(absl::Dec(j)))); - IpczHandle box; - EXPECT_EQ(IPCZ_RESULT_OK, - ipcz().Box(node(), blob, IPCZ_NO_FLAGS, nullptr, &box)); + IpczHandle box = BoxBlob(absl::StrCat(absl::Dec(j))); EXPECT_EQ(IPCZ_RESULT_OK, Put(a, absl::StrCat("a", absl::Dec(j)), {&box, 1})); EXPECT_EQ(IPCZ_RESULT_OK, Put(b, absl::StrCat("b", absl::Dec(j)))); @@ -279,11 +267,7 @@ EXPECT_EQ(absl::StrCat("b", absl::Dec(i)), message); EXPECT_EQ(IPCZ_RESULT_OK, WaitToGet(b, &message, {&box, 1})); EXPECT_EQ(absl::StrCat("a", absl::Dec(i)), message); - - IpczDriverHandle blob; - EXPECT_EQ(IPCZ_RESULT_OK, ipcz().Unbox(box, IPCZ_NO_FLAGS, nullptr, &blob)); - EXPECT_EQ(absl::StrCat(absl::Dec(i)), - reference_drivers::Blob::TakeFromHandle(blob)->message()); + EXPECT_EQ(absl::StrCat(absl::Dec(i)), UnboxBlob(box)); } for (auto& pair : client_pairs) { @@ -340,7 +324,7 @@ #else #define MAYBE_DisconnectThroughProxy DisconnectThroughProxy #endif -TEST_P(RemotePortalTest, MAYBE_DisconnectThroughProxy) { +MULTINODE_TEST(RemotePortalTest, MAYBE_DisconnectThroughProxy) { // Exercises node disconnection. Namely if portals on nodes 1 and 3 are // connected via proxy on node 2, and node 3 disappears, node 1's portal // should observe peer closure. @@ -372,7 +356,5 @@ CloseAll({c1, c2, c3}); } -INSTANTIATE_MULTINODE_TEST_SUITE_P(RemotePortalTest); - } // namespace } // namespace ipcz
diff --git a/third_party/ipcz/src/test/multinode_test.cc b/third_party/ipcz/src/test/multinode_test.cc index 6d92c89e..e2d7855 100644 --- a/third_party/ipcz/src/test/multinode_test.cc +++ b/third_party/ipcz/src/test/multinode_test.cc
@@ -4,15 +4,19 @@ #include "test/multinode_test.h" +#include <cstring> #include <map> #include <string> #include <thread> #include "ipcz/ipcz.h" #include "reference_drivers/async_reference_driver.h" -#include "reference_drivers/blob.h" #include "reference_drivers/sync_reference_driver.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "testing/multiprocess_func_list.h" #include "third_party/abseil-cpp/absl/base/macros.h" +#include "third_party/abseil-cpp/absl/strings/str_cat.h" +#include "third_party/abseil-cpp/absl/strings/str_split.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/abseil-cpp/absl/types/variant.h" #include "third_party/ipcz/src/test_buildflags.h" @@ -28,15 +32,43 @@ namespace { +using TestDriverMap = std::map<std::string, TestDriver*>; +TestDriverMap& GetTestDrivers() { + static TestDriverMap* drivers = new TestDriverMap(); + return *drivers; +} + +using TestNodeMap = std::map<std::string, TestNodeFactory>; +TestNodeMap& GetTestNodes() { + static TestNodeMap* nodes = new TestNodeMap(); + return *nodes; +} + +struct RegisteredMultinodeTest { + RegisteredMultinodeTest() = default; + ~RegisteredMultinodeTest() = default; + + const char* test_suite_name; + const char* test_name; + const char* filename; + int line; + MultinodeTestFactory factory; +}; + +std::vector<RegisteredMultinodeTest>& GetRegisteredMultinodeTests() { + static auto* tests = new std::vector<RegisteredMultinodeTest>(); + return *tests; +} + // Launches a new node on a dedicated thread within the same process. All // connections use the synchronous single-process driver. class InProcessTestNodeController : public TestNode::TestNodeController { public: - InProcessTestNodeController(DriverMode driver_mode, + InProcessTestNodeController(TestDriver* test_driver, std::unique_ptr<TestNode> test_node) : client_thread_(absl::in_place, &RunTestNode, - driver_mode, + test_driver, std::move(test_node)) {} ~InProcessTestNodeController() override { ABSL_ASSERT(!client_thread_); } @@ -61,15 +93,112 @@ } private: - static void RunTestNode(DriverMode driver_mode, + static void RunTestNode(TestDriver* test_driver, std::unique_ptr<TestNode> test_node) { - test_node->Initialize(driver_mode, IPCZ_NO_FLAGS); + test_node->Initialize(test_driver); test_node->NodeBody(); } absl::optional<std::thread> client_thread_; }; +class InProcessTestDriverBase : public TestDriver { + public: + Ref<TestNode::TestNodeController> SpawnTestNode( + TestNode& source, + const TestNodeDetails& details, + IpczDriverHandle our_transport, + IpczDriverHandle their_transport) override { + std::unique_ptr<TestNode> test_node = details.factory(); + test_node->SetTransport(their_transport); + return MakeRefCounted<InProcessTestNodeController>(this, + std::move(test_node)); + } + + IpczDriverHandle GetClientTestNodeTransport() override { + ABSL_HARDENING_ASSERT(false); + return IPCZ_INVALID_DRIVER_HANDLE; + } +}; + +class SyncTestDriver : public InProcessTestDriverBase { + public: + const IpczDriver& GetIpczDriver() const override { + return reference_drivers::kSyncReferenceDriver; + } + + const char* GetName() const override { return internal::kSyncTestDriverName; } + + TestNode::TransportPair CreateTransports(TestNode& source) const override { + TestNode::TransportPair transports; + const IpczResult result = GetIpczDriver().CreateTransports( + IPCZ_INVALID_DRIVER_HANDLE, IPCZ_INVALID_DRIVER_HANDLE, IPCZ_NO_FLAGS, + nullptr, &transports.ours, &transports.theirs); + ABSL_ASSERT(result == IPCZ_RESULT_OK); + return transports; + } + + IpczConnectNodeFlags GetExtraClientConnectNodeFlags() const override { + return IPCZ_NO_FLAGS; + } +}; + +class AsyncTestDriver : public InProcessTestDriverBase { + public: + enum Mode { + kDefault, + kForceBrokering, + kDelegateAllocation, + kForceBrokeringAndDelegateAllocation, + }; + AsyncTestDriver(const char* name, Mode mode) : name_(name), mode_(mode) {} + + const IpczDriver& GetIpczDriver() const override { + if (mode_ == kForceBrokering || + mode_ == kForceBrokeringAndDelegateAllocation) { + return reference_drivers::kAsyncReferenceDriverWithForcedBrokering; + } + return reference_drivers::kAsyncReferenceDriver; + } + + const char* GetName() const override { return name_; } + + TestNode::TransportPair CreateTransports(TestNode& source) const override { + reference_drivers::AsyncTransportPair transports = + reference_drivers::CreateAsyncTransportPair(); + return { + .ours = transports.broker, + .theirs = transports.non_broker, + }; + } + + IpczConnectNodeFlags GetExtraClientConnectNodeFlags() const override { + if (mode_ == kDelegateAllocation || + mode_ == kForceBrokeringAndDelegateAllocation) { + return IPCZ_CONNECT_NODE_TO_ALLOCATION_DELEGATE; + } + return IPCZ_NO_FLAGS; + } + + private: + const char* const name_; + const Mode mode_; +}; + +TestDriverRegistration<SyncTestDriver> kRegisterSyncDriver; +TestDriverRegistration<AsyncTestDriver> kRegisterAsyncDriver{ + internal::kAsyncTestDriverName, AsyncTestDriver::kDefault}; +TestDriverRegistration<AsyncTestDriver> kRegisterAsyncDriverWithDelegatedAlloc{ + internal::kAsyncDelegatedAllocTestDriverName, + AsyncTestDriver::kDelegateAllocation}; +TestDriverRegistration<AsyncTestDriver> kRegisterAsyncDriverWithForcedBrokering{ + internal::kAsyncForcedBrokeringTestDriverName, + AsyncTestDriver::kForceBrokering}; +TestDriverRegistration<AsyncTestDriver> + kRegisterAsyncDriverWithDelegatedAllocAndForcedBrokering{ + internal::kAsyncDelegatedAllocAndForcedBrokeringTestDriverName, + AsyncTestDriver::kForceBrokeringAndDelegateAllocation}; + #if BUILDFLAG(ENABLE_IPCZ_MULTIPROCESS_TESTS) // Controls a node running within an isolated child process. class ChildProcessTestNodeController : public TestNode::TestNodeController { @@ -92,10 +221,73 @@ const pid_t pid_; absl::optional<bool> result_; }; + +class MultiprocessTestDriver : public TestDriver { + public: + const IpczDriver& GetIpczDriver() const override { + return reference_drivers::kMultiprocessReferenceDriver; + } + + const char* GetName() const override { + return internal::kMultiprocessTestDriverName; + } + + TestNode::TransportPair CreateTransports(TestNode& source) const override { + TestNode::TransportPair transports; + const IpczResult result = GetIpczDriver().CreateTransports( + IPCZ_INVALID_DRIVER_HANDLE, IPCZ_INVALID_DRIVER_HANDLE, IPCZ_NO_FLAGS, + nullptr, &transports.ours, &transports.theirs); + ABSL_ASSERT(result == IPCZ_RESULT_OK); + return transports; + } + + Ref<TestNode::TestNodeController> SpawnTestNode( + TestNode& source, + const TestNodeDetails& details, + IpczDriverHandle our_transport, + IpczDriverHandle their_transport) override { + reference_drivers::FileDescriptor socket = + reference_drivers::TakeMultiprocessTransportDescriptor(their_transport); + return MakeRefCounted<ChildProcessTestNodeController>( + child_launcher_.Launch(details.name, std::move(socket))); + } + + IpczConnectNodeFlags GetExtraClientConnectNodeFlags() const override { + return IPCZ_NO_FLAGS; + } + + IpczDriverHandle GetClientTestNodeTransport() override { + auto transport = MakeRefCounted<reference_drivers::SocketTransport>( + TestChildLauncher::TakeChildSocketDescriptor()); + return reference_drivers::CreateMultiprocessTransport(std::move(transport)); + } + + private: + TestChildLauncher child_launcher_; +}; + +TestDriverRegistration<MultiprocessTestDriver> kRegisterMultiprocessDriver; + #endif } // namespace +namespace internal { + +const char kSyncTestDriverName[] = "Sync"; +const char kAsyncTestDriverName[] = "Async"; +const char kAsyncDelegatedAllocTestDriverName[] = "AsyncDelegatedAlloc"; +const char kAsyncForcedBrokeringTestDriverName[] = "AsyncForcedBrokering"; +const char kAsyncDelegatedAllocAndForcedBrokeringTestDriverName[] = + "AsyncDelegatedAllocAndForcedBrokering"; +const char kMultiprocessTestDriverName[] = "Multiprocess"; + +} // namespace internal + +TestDriverRegistrationImpl::TestDriverRegistrationImpl(TestDriver& driver) { + GetTestDrivers()[driver.GetName()] = &driver; +} + TestNode::~TestNode() { for (auto& spawned_node : spawned_nodes_) { EXPECT_TRUE(spawned_node->WaitForShutdown()); @@ -103,59 +295,31 @@ // If we never connected to the broker, make sure we don't leak our transport. if (transport_ != IPCZ_INVALID_DRIVER_HANDLE) { - GetDriver().Close(transport_, IPCZ_NO_FLAGS, nullptr); + test_driver_->GetIpczDriver().Close(transport_, IPCZ_NO_FLAGS, nullptr); } CloseThisNode(); } const IpczDriver& TestNode::GetDriver() const { - static IpczDriver kInvalidDriver = {}; - switch (driver_mode_) { - case DriverMode::kSync: - return reference_drivers::kSyncReferenceDriver; - - case DriverMode::kAsync: - return reference_drivers::kAsyncReferenceDriver; - - case DriverMode::kAsyncDelegatedAlloc: - return reference_drivers::kAsyncReferenceDriver; - - case DriverMode::kAsyncObjectBrokering: - return reference_drivers::kAsyncReferenceDriverWithForcedBrokering; - - case DriverMode::kAsyncObjectBrokeringAndDelegatedAlloc: - return reference_drivers::kAsyncReferenceDriverWithForcedBrokering; - -#if BUILDFLAG(ENABLE_IPCZ_MULTIPROCESS_TESTS) - case DriverMode::kMultiprocess: - return reference_drivers::kMultiprocessReferenceDriver; -#endif - - default: - // Other modes not yet supported. - ABSL_ASSERT(false); - return kInvalidDriver; - } + return test_driver_->GetIpczDriver(); } -void TestNode::Initialize(DriverMode driver_mode, - IpczCreateNodeFlags create_node_flags) { - driver_mode_ = driver_mode; +void TestNode::Initialize(TestDriver* test_driver) { + test_driver_ = test_driver; + const IpczCreateNodeFlags flags = + GetDetails().is_broker ? IPCZ_CREATE_NODE_AS_BROKER : IPCZ_NO_FLAGS; ABSL_ASSERT(node_ == IPCZ_INVALID_HANDLE); const IpczResult result = - ipcz().CreateNode(&GetDriver(), IPCZ_INVALID_DRIVER_HANDLE, - create_node_flags, nullptr, &node_); + ipcz().CreateNode(&test_driver_->GetIpczDriver(), + IPCZ_INVALID_DRIVER_HANDLE, flags, nullptr, &node_); ABSL_ASSERT(result == IPCZ_RESULT_OK); } void TestNode::ConnectToParent(absl::Span<IpczHandle> portals, IpczConnectNodeFlags flags) { - if (driver_mode_ == DriverMode::kAsyncDelegatedAlloc || - driver_mode_ == DriverMode::kAsyncObjectBrokeringAndDelegatedAlloc) { - flags |= IPCZ_CONNECT_NODE_TO_ALLOCATION_DELEGATE; - } + flags |= test_driver_->GetExtraClientConnectNodeFlags(); IpczDriverHandle transport = std::exchange(transport_, IPCZ_INVALID_DRIVER_HANDLE); ABSL_ASSERT(transport != IPCZ_INVALID_DRIVER_HANDLE); @@ -183,22 +347,45 @@ } IpczHandle TestNode::BoxBlob(std::string_view contents) { - auto blob = MakeRefCounted<reference_drivers::Blob>(contents); + IpczDriverHandle memory; + IpczResult result = GetDriver().AllocateSharedMemory( + contents.size(), IPCZ_NO_FLAGS, nullptr, &memory); + ABSL_ASSERT(result == IPCZ_RESULT_OK); + + IpczDriverHandle mapping; + void* base; + result = GetDriver().MapSharedMemory(memory, IPCZ_NO_FLAGS, nullptr, &base, + &mapping); + ABSL_ASSERT(result == IPCZ_RESULT_OK); + memcpy(base, contents.data(), contents.size()); + GetDriver().Close(mapping, IPCZ_NO_FLAGS, nullptr); + IpczHandle box; - const IpczResult result = ipcz().Box( - node_, reference_drivers::Blob::ReleaseAsHandle(std::move(blob)), - IPCZ_NO_FLAGS, nullptr, &box); + result = ipcz().Box(node_, memory, IPCZ_NO_FLAGS, nullptr, &box); ABSL_ASSERT(result == IPCZ_RESULT_OK); return box; } -// Extracts the string contents of a boxed test driver blob. std::string TestNode::UnboxBlob(IpczHandle box) { - IpczDriverHandle handle; - const IpczResult result = ipcz().Unbox(box, IPCZ_NO_FLAGS, nullptr, &handle); + IpczDriverHandle memory; + IpczResult result = ipcz().Unbox(box, IPCZ_NO_FLAGS, nullptr, &memory); ABSL_ASSERT(result == IPCZ_RESULT_OK); - auto blob = reference_drivers::Blob::TakeFromHandle(handle); - return blob->message(); + + IpczSharedMemoryInfo info = {.size = sizeof(info)}; + result = + GetDriver().GetSharedMemoryInfo(memory, IPCZ_NO_FLAGS, nullptr, &info); + ABSL_ASSERT(result == IPCZ_RESULT_OK); + + IpczDriverHandle mapping; + void* base; + result = GetDriver().MapSharedMemory(memory, IPCZ_NO_FLAGS, nullptr, &base, + &mapping); + ABSL_ASSERT(result == IPCZ_RESULT_OK); + + std::string contents(static_cast<const char*>(base), info.region_num_bytes); + GetDriver().Close(mapping, IPCZ_NO_FLAGS, nullptr); + GetDriver().Close(memory, IPCZ_NO_FLAGS, nullptr); + return contents; } void TestNode::CloseThisNode() { @@ -209,74 +396,18 @@ } Ref<TestNode::TestNodeController> TestNode::SpawnTestNodeImpl( - IpczHandle from_node, - const internal::TestNodeDetails& details, - PortalsOrTransport portals_or_transport, - IpczConnectNodeFlags flags) { - struct Connect { - Connect(TestNode& test, IpczConnectNodeFlags flags) - : test(test), flags(flags) {} - - IpczDriverHandle operator()(absl::Span<IpczHandle> portals) { - TransportPair transports = test.CreateTransports(); - const IpczResult result = - test.ipcz().ConnectNode(test.node(), transports.ours, portals.size(), - flags, nullptr, portals.data()); - ABSL_ASSERT(result == IPCZ_RESULT_OK); - return transports.theirs; - } - - IpczDriverHandle operator()(IpczDriverHandle transport) { - return transport; - } - - TestNode& test; - const IpczConnectNodeFlags flags; - }; - - Connect connect(*this, flags); - IpczDriverHandle their_transport = absl::visit(connect, portals_or_transport); - - Ref<TestNodeController> controller; -#if BUILDFLAG(ENABLE_IPCZ_MULTIPROCESS_TESTS) - if (driver_mode_ == DriverMode::kMultiprocess) { - reference_drivers::FileDescriptor socket = - reference_drivers::TakeMultiprocessTransportDescriptor(their_transport); - controller = MakeRefCounted<ChildProcessTestNodeController>( - child_launcher_.Launch(details.name, std::move(socket))); - } -#endif - - if (!controller) { - std::unique_ptr<TestNode> test_node = details.factory(); - test_node->SetTransport(their_transport); - controller = MakeRefCounted<InProcessTestNodeController>( - driver_mode_, std::move(test_node)); - } - + const TestNodeDetails& details, + IpczDriverHandle& our_transport) { + TransportPair transports = CreateTransports(); + Ref<TestNodeController> controller = test_driver_->SpawnTestNode( + *this, details, transports.ours, transports.theirs); spawned_nodes_.push_back(controller); + our_transport = transports.ours; return controller; } TestNode::TransportPair TestNode::CreateTransports() { - if (driver_mode_ == DriverMode::kAsync || - driver_mode_ == DriverMode::kAsyncDelegatedAlloc || - driver_mode_ == DriverMode::kAsyncObjectBrokering || - driver_mode_ == DriverMode::kAsyncObjectBrokeringAndDelegatedAlloc) { - reference_drivers::AsyncTransportPair transports = - reference_drivers::CreateAsyncTransportPair(); - return { - .ours = transports.broker, - .theirs = transports.non_broker, - }; - } - - TransportPair transports; - const IpczResult result = GetDriver().CreateTransports( - IPCZ_INVALID_DRIVER_HANDLE, IPCZ_INVALID_DRIVER_HANDLE, IPCZ_NO_FLAGS, - nullptr, &transports.ours, &transports.theirs); - ABSL_ASSERT(result == IPCZ_RESULT_OK); - return transports; + return test_driver_->CreateTransports(*this); } void TestNode::SetTransport(IpczDriverHandle transport) { @@ -284,22 +415,72 @@ transport_ = transport; } -int TestNode::RunAsChild() { -#if BUILDFLAG(ENABLE_IPCZ_MULTIPROCESS_TESTS) - auto transport = MakeRefCounted<reference_drivers::SocketTransport>( - TestChildLauncher::TakeChildSocketDescriptor()); - SetTransport( - reference_drivers::CreateMultiprocessTransport(std::move(transport))); - Initialize(DriverMode::kMultiprocess, IPCZ_NO_FLAGS); +int TestNode::RunAsChild(TestDriver* test_driver) { + SetTransport(test_driver->GetClientTestNodeTransport()); + Initialize(test_driver); NodeBody(); const int exit_code = ::testing::Test::HasFailure() ? 1 : 0; return exit_code; -#else - // Not supported outside of Linux. - ABSL_ASSERT(false); - return 0; -#endif +} + +void RegisterMultinodeTestNode(std::string_view node_name, + TestNodeFactory factory) { + GetTestNodes()[std::string(node_name)] = factory; +} + +void RegisterMultinodeTest( + const char* test_suite_name, + const char* test_name, + const char* filename, + int line, + std::function<testing::Test*(TestDriver* driver)> factory) { + RegisteredMultinodeTest test; + test.test_suite_name = test_suite_name; + test.test_name = test_name; + test.filename = filename; + test.line = line; + test.factory = factory; + GetRegisteredMultinodeTests().push_back(std::move(test)); +} + +int RunChildProcessTest(const std::string& test_name) { + std::pair<std::string, std::string> split = absl::StrSplit(test_name, '/'); + auto [node_name, driver_name] = split; + if (driver_name.empty()) { + return multi_process_function_list::InvokeChildProcessTestMain(test_name); + } + + auto& drivers = GetTestDrivers(); + auto driver_it = drivers.find(driver_name); + if (driver_it == drivers.end()) { + return -1; + } + + auto& nodes = GetTestNodes(); + auto node_it = nodes.find(node_name); + if (node_it == nodes.end()) { + return -1; + } + + std::unique_ptr<TestNode> node = node_it->second(); + return node->RunAsChild(driver_it->second); +} + +void RegisterMultinodeTests() { + multi_process_function_list::SetChildProcessTestRunner(&RunChildProcessTest); + for (auto& test : GetRegisteredMultinodeTests()) { + for (const auto& [test_driver_name, test_driver] : GetTestDrivers()) { + const std::string test_name = + absl::StrCat(test.test_name, "/", test_driver_name); + ::testing::RegisterTest( + test.test_suite_name, test_name.c_str(), nullptr, nullptr, + test.filename, test.line, + [factory = test.factory, test_driver = test_driver] { + return factory(test_driver); + }); + } + } } } // namespace ipcz::test
diff --git a/third_party/ipcz/src/test/multinode_test.h b/third_party/ipcz/src/test/multinode_test.h index eb7f437..3951840 100644 --- a/third_party/ipcz/src/test/multinode_test.h +++ b/third_party/ipcz/src/test/multinode_test.h
@@ -9,22 +9,18 @@ #include <string> #include <string_view> #include <type_traits> +#include <utility> #include <vector> #include "ipcz/ipcz.h" #include "test/test_base.h" #include "testing/gtest/include/gtest/gtest.h" -#include "testing/multiprocess_func_list.h" #include "third_party/abseil-cpp/absl/base/macros.h" #include "third_party/abseil-cpp/absl/types/span.h" #include "third_party/abseil-cpp/absl/types/variant.h" #include "third_party/ipcz/src/test_buildflags.h" #include "util/ref_counted.h" -#if BUILDFLAG(ENABLE_IPCZ_MULTIPROCESS_TESTS) -#include "test/test_child_launcher.h" -#endif - namespace ipcz::test { class TestNode; @@ -32,79 +28,45 @@ template <typename TestNodeType> class MultinodeTest; -// Selects which driver will be used by test nodes. Interconnecting nodes must -// always use the same driver. -// -// Multinode tests are parameterized over these modes to provide coverage of -// various interesting constraints encountered in production. Some platforms -// require driver objects to be relayed through a broker. Some environments -// prevent nodes from allocating their own shared memory regions. -// -// Incongruity between synchronous and asynchronous test failures generally -// indicates race conditions within ipcz, but many bugs will cause failures in -// all driver modes. The synchronous version is generally easier to debug in -// such cases. -enum class DriverMode { - // Use the synchronous, single-process reference driver. This driver does not - // create any background threads and all ipcz operations (e.g. message - // delivery, portal transfer, proxy elimination, etc) complete synchronously - // from end-to-end. Each test node runs its test body on a dedicated thread - // within the test process. - kSync, - - // Use the asynchronous single-process reference driver. Transport messages - // are received asynchronously, similar to how most production drivers are - // likely to operate in practice. Such asynchrony gives rise to - // non-determinism throughout ipcz proper and provides good coverage of - // potential race conditions. - // - // As with the kSync driver, each test node runs its test body on a dedicated - // thread within the test process. - kAsync, - - // Use the same driver as kAsync, but non-broker nodes are forced to delegate - // shared memory allocation to their broker. This simulates the production - // constraints of some sandbox environments and exercises additional - // asynchrony in ipcz proper. - kAsyncDelegatedAlloc, - - // Use the same driver as kAsync, but driver objects cannot be transmitted - // directly between non-brokers and must instead be relayed by a broker. This - // simulates the production constraints of some sandbox environments and - // exercises additional asynchrony in ipcz proper. - kAsyncObjectBrokering, - - // Use the same driver as kAsync, imposing the additional constraints of both - // kAsyncDelegatedAlloc and kAsyncObjectBrokering as described above. - kAsyncObjectBrokeringAndDelegatedAlloc, - -#if BUILDFLAG(ENABLE_IPCZ_MULTIPROCESS_TESTS) - // Use a multiprocess-capable driver (Linux only for now), with each test node - // running in its own isolated child process. - kMultiprocess, -#endif -}; - namespace internal { -using TestNodeFactory = std::unique_ptr<TestNode> (*)(); - template <typename TestNodeType> std::unique_ptr<TestNode> MakeTestNode() { return std::make_unique<TestNodeType>(); } -// Type used to package metadata about a MULTINODE_TEST_NODE() invocation. -struct TestNodeDetails { - const std::string_view name; - const TestNodeFactory factory; -}; - template <typename T> static constexpr bool IsValidTestNodeType = std::is_base_of_v<TestNode, T>; +extern const char kSyncTestDriverName[]; +extern const char kAsyncTestDriverName[]; +extern const char kAsyncDelegatedAllocTestDriverName[]; +extern const char kAsyncForcedBrokeringTestDriverName[]; +extern const char kAsyncDelegatedAllocAndForcedBrokeringTestDriverName[]; +extern const char kMultiprocessTestDriverName[]; + } // namespace internal +class TestDriver; + +using TestNodeFactory = std::unique_ptr<TestNode> (*)(); + +// Type used to package metadata about a MULTINODE_TEST_NODE() or +// MULTINODE_TEST() invocation. +struct TestNodeDetails { + // A unique display name for the defined node body. + const std::string_view name; + + // A factory function which can be used to instantiate the TestNode. Null for + // main MULTINODE_TEST() invocations. + const TestNodeFactory factory; + + // Indicates whether the node is defined as a broker or non-broker node. By + // default, all nodes on non-brokers except for those emitted by main + // MULTINODE_TEST() invocations. + const bool is_broker; +}; + // Base class to support tests which exercise behavior across multiple ipcz // nodes. These may be single-process on a synchronous driver, single-process on // an asynchronous (e.g. multiprocess) driver, or fully multiprocess. @@ -115,9 +77,9 @@ // GTest's Test class is not compatible with that behavior. // // Instead, while MULTINODE_TEST_NODE() invocations should be based directly on -// TestNode or a derivative thereof. TEST_P() invocations for multinode tests -// should be based on derivatives of MultinodeTest<T> (see below this class), -// where T itself is a TestNode or some derivative thereof. +// TestNode or a derivative thereof. MULTINODE_TEST() invocations for multinode +// tests should be based on derivatives of MultinodeTest<T> (see below this +// class), where T itself is a TestNode or some derivative thereof. // // This arrangement allows the main test body and its related // MULTINODE_TEST_NODE() invocations to be based on the same essential type, @@ -142,6 +104,9 @@ // ConnectToBroker() hasn't been called yet. IpczDriverHandle transport() const { return transport_; } + // Returns metadata regarding the definition of this TestNode type. + virtual const TestNodeDetails& GetDetails() const = 0; + // Releases transport() to the caller. After calling this, it is no longer // valid to call either transport() or ConnectToBroker(), and this fixture // will not automatically close the transport on destruction. @@ -149,13 +114,15 @@ return std::exchange(transport_, IPCZ_INVALID_DRIVER_HANDLE); } - // The driver currently in use. Selected by test parameter. + // The active TestDriver implementation. + TestDriver* GetTestDriver() { return test_driver_; } + + // The ipcz driver currently in use, as specified by the active TestDriver. const IpczDriver& GetDriver() const; // One-time initialization. Called internally during test setup. Should never // be called by individual test code. - void Initialize(DriverMode driver_mode, - IpczCreateNodeFlags create_node_flags); + void Initialize(TestDriver* test_driver); // May be called at most once by the TestNode body to connect initial // `portals` to the node that spawned this one. Extra `flags` may be passed to @@ -174,11 +141,11 @@ // Opens a new portal pair on this node. std::pair<IpczHandle, IpczHandle> OpenPortals(); - // Creates a new test driver blob object and boxes it. Returns a handle to the - // box. + // Creates a new driver memory object populated with `contents`, boxes it, and + // returns a handle to the new box. IpczHandle BoxBlob(std::string_view contents); - // Extracts the string contents of a boxed test driver blob. + // Extracts the string contents of a boxed driver memory object. std::string UnboxBlob(IpczHandle box); // Spawns a new test node of TestNodeType and populates `portals` with a set @@ -187,7 +154,12 @@ Ref<TestNodeController> SpawnTestNode( absl::Span<IpczHandle> portals, IpczConnectNodeFlags flags = IPCZ_NO_FLAGS) { - return SpawnTestNodeImpl(node_, TestNodeType::kDetails, portals, flags); + IpczDriverHandle our_transport; + auto controller = SpawnTestNodeImpl(TestNodeType::kDetails, our_transport); + const IpczResult result = ipcz().ConnectNode( + node(), our_transport, portals.size(), flags, nullptr, portals.data()); + ABSL_ASSERT(result == IPCZ_RESULT_OK); + return controller; } // Shorthand for the above, for the common case with only one initial portal @@ -203,10 +175,8 @@ // its broker connection. The caller is resposible for the other end of that // connection. template <typename TestNodeType> - Ref<TestNodeController> SpawnTestNodeWithTransport( - IpczDriverHandle transport, - IpczConnectNodeFlags flags = IPCZ_NO_FLAGS) { - return SpawnTestNodeImpl(node_, TestNodeType::kDetails, transport, flags); + Ref<TestNodeController> SpawnTestNodeNoConnect(IpczDriverHandle& transport) { + return SpawnTestNodeImpl(TestNodeType::kDetails, transport); } // Forcibly closes this Node, severing all links to other nodes and implicitly @@ -214,8 +184,8 @@ void CloseThisNode(); // The TestNode body provided by a MULTINODE_TEST_NODE() invocation. For main - // test definitions via TEST_P() with a MultinodeTest<T> fixture, this is - // unused in favor of TestBody(). + // test definitions via MULTINODE_TEST() with a MultinodeTest<T> fixture, this + // is unused in favor of TestBody(). virtual void NodeBody() {} // Creates a pair of transports appropriate for connecting this (broker or @@ -229,71 +199,132 @@ TransportPair CreateTransports(); // Helper used to support multiprocess TestNode invocation. - int RunAsChild(); + int RunAsChild(TestDriver* test_driver); - private: // Sets the transport to use when connecting to a broker via ConnectBroker. // Must only be called once. void SetTransport(IpczDriverHandle transport); + private: // Spawns a new node using an appropriate configuration for the current // driver. Returns a controller which can be used to interact with the node - // outside of ipcz (e.g. to wait on its termination). `factory` is a function - // which can produce an in-process instance of the TestNode; `test_node_name` - // is a string which can be used to run the same TestNode subclass in a child - // process. - // - // If `portals_or_transport` is a span of IpczHandles, this creates a new - // pair of transports. One is given to the new node for connection back to us, - // and the other is connected immediately by the broker, filling in the - // handles with initial portals for the connection. - // - // Otherwise it's assumed to be a transport that will be given to the new - // node for connecting back to us. In this case the caller is responsible for - // the transport's peer. - using PortalsOrTransport = - absl::variant<absl::Span<IpczHandle>, IpczDriverHandle>; - Ref<TestNodeController> SpawnTestNodeImpl( - IpczHandle from_node, - const internal::TestNodeDetails& details, - PortalsOrTransport portals_or_transport, - IpczConnectNodeFlags flags); + // outside of ipcz (e.g. to wait on its termination). `details` describes the + // node to be launched, and `our_transport` on output receives a locally owned + // transport to the spawned node. + Ref<TestNodeController> SpawnTestNodeImpl(const TestNodeDetails& details, + IpczDriverHandle& our_transport); - DriverMode driver_mode_ = DriverMode::kSync; + TestDriver* test_driver_ = nullptr; IpczHandle node_ = IPCZ_INVALID_HANDLE; IpczDriverHandle transport_ = IPCZ_INVALID_DRIVER_HANDLE; std::vector<Ref<TestNodeController>> spawned_nodes_; - -#if BUILDFLAG(ENABLE_IPCZ_MULTIPROCESS_TESTS) - TestChildLauncher child_launcher_; -#endif }; // Actual parameterized GTest Test fixture for multinode tests. This or a -// subclass of it is required for TEST_P() invocations to function as proper -// multinode tests. +// subclass of it is required for MULTINODE_TEST() invocations to function as +// proper multinode tests. template <typename TestNodeType = TestNode> -class MultinodeTest : public TestNodeType, - public ::testing::Test, - public ::testing::WithParamInterface<DriverMode> { +class MultinodeTest : public TestNodeType, public ::testing::Test { public: static_assert(internal::IsValidTestNodeType<TestNodeType>, "MultinodeTest<T> requires T to be a subclass of TestNode."); - MultinodeTest() { - TestNode::Initialize(GetParam(), IPCZ_CREATE_NODE_AS_BROKER); +}; + +// TestDriver specifies an IpczDriver implementation to use for multinode tests. +// It also implements launching and joining of other test nodes. A TestDriver +// can be registered by statically initializing a corresponding +// TestDriverRegistration. All multinode tests are run against all registered +// TestDrivers. +class TestDriver { + public: + // A reference to the actual IpczDriver implementation used by this + // TestDriver. + virtual const IpczDriver& GetIpczDriver() const = 0; + + // A unique name for this test driver. + virtual const char* GetName() const = 0; + + // Creates a new pair of transports suitable for connecting a broker node to a + // non-broker node. Called by `source`, who will adopt `ours` from the + // returned pair and pass `theirs` to some newly spawned test node. + virtual TestNode::TransportPair CreateTransports(TestNode& source) const = 0; + + // Spawns a new TestNode instance for a TestNode described by `details`, + // passing `their_transport` to the new node so it can establish a connection. + // `our_transport` is the local driver transport endpoint that will be used to + // connect to the new node. + virtual Ref<TestNode::TestNodeController> SpawnTestNode( + TestNode& source, + const TestNodeDetails& details, + IpczDriverHandle our_transport, + IpczDriverHandle their_transport) = 0; + + // Returns any extra flags to be provided to ConnectNode() when connecting to + // the main test node from a node spawned by the test. + virtual IpczConnectNodeFlags GetExtraClientConnectNodeFlags() const = 0; + + // If the test driver launches test nodes in a separate subprocess, this is + // called to retrieve the driver transport which the test node should use to + // connect to the broker. + virtual IpczDriverHandle GetClientTestNodeTransport() = 0; +}; + +// Registers a TestDriver globally so that all MULTINODE_TEST() invocations are +// parameterized over it. +class TestDriverRegistrationImpl { + public: + explicit TestDriverRegistrationImpl(TestDriver& driver); +}; + +template <typename TestDriverType> +class TestDriverRegistration { + public: + template <typename... Args> + explicit TestDriverRegistration(Args&&... args) + : driver(std::forward<Args>(args)...) {} + + TestDriverType driver; + TestDriverRegistrationImpl registration{driver}; +}; + +void RegisterMultinodeTestNode(std::string_view node_name, + TestNodeFactory factory); + +template <typename NodeType> +class MultinodeTestNodeRegistration { + public: + MultinodeTestNodeRegistration() { + RegisterMultinodeTestNode(NodeType::kDetails.name, + NodeType::kDetails.factory); } }; -} // namespace ipcz::test +using MultinodeTestFactory = std::function<testing::Test*(TestDriver*)>; +void RegisterMultinodeTest(const char* test_suite_name, + const char* test_name, + const char* filename, + int line, + MultinodeTestFactory factory); -#define MULTINODE_TEST_CHILD_MAIN_HELPER(func, node_name) \ - MULTIPROCESS_TEST_MAIN(func) { \ - node_name node; \ - return node.RunAsChild(); \ +// Registers a MULTINODE_TEST() test to be run when all tests are run. This +// registers a unique instance of the test for each registered test driver. +template <typename Test> +class MultinodeTestRegistration { + public: + MultinodeTestRegistration(const char* test_suite_name, + const char* test_name, + const char* filename, + int line) { + RegisterMultinodeTest(test_suite_name, test_name, filename, line, + [](TestDriver* driver) { return new Test(driver); }); } +}; -#define MULTINODE_TEST_CHILD_MAIN(fixture, node_name) \ - MULTINODE_TEST_CHILD_MAIN_HELPER(fixture##_##node_name##_Node, node_name) +// Must be called before RUN_ALL_TESTS() is invoked in order for any defined +// multinode tests to be run. +void RegisterMultinodeTests(); + +} // namespace ipcz::test // Defines the main body of a non-broker test node for a multinode test. The // named node can be spawned by another node using SpawnTestNode<T> where T is @@ -306,30 +337,53 @@ "ipcz::test::TestNode."); \ \ public: \ - static constexpr ::ipcz::test::internal::TestNodeDetails kDetails = { \ + static constexpr ::ipcz::test::TestNodeDetails kDetails = { \ .name = #fixture "_" #node_name "_Node", \ .factory = &::ipcz::test::internal::MakeTestNode<node_name>, \ + .is_broker = false, \ }; \ + const ::ipcz::test::TestNodeDetails& GetDetails() const override { \ + return kDetails; \ + } \ void NodeBody() override; \ }; \ - MULTINODE_TEST_CHILD_MAIN(fixture, node_name); \ + ::ipcz::test::MultinodeTestNodeRegistration<node_name> \ + kRegister_##node_name; \ void node_name::NodeBody() -#if BUILDFLAG(ENABLE_IPCZ_MULTIPROCESS_TESTS) -#define IPCZ_EXTRA_DRIVER_MODES , ipcz::test::DriverMode::kMultiprocess -#else -#define IPCZ_EXTRA_DRIVER_MODES -#endif +#define MULTINODE_TEST_NAME(name) #name +#define MULTINODE_TEST_CLASS_NAME(name) name##_Test +#define MULTINODE_TEST_REGISTRATION_NAME(name) kRegister_##name##_Test -// TODO: Add other DriverMode enumerators here as support is landed. -#define INSTANTIATE_MULTINODE_TEST_SUITE_P(suite) \ - INSTANTIATE_TEST_SUITE_P( \ - , suite, \ - ::testing::Values( \ - ipcz::test::DriverMode::kSync, ipcz::test::DriverMode::kAsync, \ - ipcz::test::DriverMode::kAsyncDelegatedAlloc, \ - ipcz::test::DriverMode::kAsyncObjectBrokering, \ - ipcz::test::DriverMode::kAsyncObjectBrokeringAndDelegatedAlloc \ - IPCZ_EXTRA_DRIVER_MODES)) +#define MULTINODE_TEST(fixture, test_name) \ + class MULTINODE_TEST_CLASS_NAME(test_name) : public fixture { \ + public: \ + static constexpr ::ipcz::test::TestNodeDetails kDetails = { \ + .name = #fixture "_" #test_name "_Node", \ + .factory = nullptr, \ + .is_broker = true, \ + }; \ + explicit MULTINODE_TEST_CLASS_NAME(test_name)(::ipcz::test::TestDriver * \ + test_driver) { \ + TestNode::Initialize(test_driver); \ + } \ + ~MULTINODE_TEST_CLASS_NAME(test_name)() override = default; \ + MULTINODE_TEST_CLASS_NAME(test_name) \ + (const MULTINODE_TEST_CLASS_NAME(test_name) &) = delete; \ + void operator=(const MULTINODE_TEST_CLASS_NAME(test_name) &) = delete; \ + const ::ipcz::test::TestNodeDetails& GetDetails() const override { \ + return kDetails; \ + } \ + \ + private: \ + void TestBody() override; \ + }; \ + namespace { \ + ::ipcz::test::MultinodeTestRegistration< \ + MULTINODE_TEST_CLASS_NAME(test_name)> \ + MULTINODE_TEST_REGISTRATION_NAME(test_name){ \ + #fixture, MULTINODE_TEST_NAME(test_name), __FILE__, __LINE__}; \ + } \ + void MULTINODE_TEST_CLASS_NAME(test_name)::TestBody() #endif // IPCZ_SRC_TEST_MULTINODE_TEST_H_
diff --git a/third_party/ipcz/src/test/test_base.h b/third_party/ipcz/src/test/test_base.h index 3b3df98b..458082e 100644 --- a/third_party/ipcz/src/test/test_base.h +++ b/third_party/ipcz/src/test/test_base.h
@@ -22,7 +22,7 @@ // use ipcz::test::Test as a base. For multinode tests, use ipcz::test:TestNode // as a base for MULTINODE_TEST_NODE() invocations, and use // ipcz::test::MultinodeTest<T> (where T is a subclass of TestNode) for -// TEST_P() invocations for parameterized multinode test bodies. +// MULTINODE_TEST() invocations for parameterized multinode test bodies. class TestBase { public: using TrapEventHandler = std::function<void(const IpczTrapEvent&)>;
diff --git a/third_party/ipcz/src/test/test_child_launcher.cc b/third_party/ipcz/src/test/test_child_launcher.cc index b6d9b0e..30d15b9e 100644 --- a/third_party/ipcz/src/test/test_child_launcher.cc +++ b/third_party/ipcz/src/test/test_child_launcher.cc
@@ -162,7 +162,9 @@ // Execute the test binary with an extra command-line switch that circumvents // the normal test runner path and instead runs the named TestNode's body. ArgList child_args = GetArgList(); - child_args.push_back(MakeSwitch(kTestChildProcess, node_name.data())); + std::string test_main_name = absl::StrCat( + node_name.data(), "/", internal::kMultiprocessTestDriverName); + child_args.push_back(MakeSwitch(kTestChildProcess, test_main_name)); child_args.push_back(MakeSwitch(kSocketFd, socket.release())); std::vector<char*> child_argv = MakeExecArgv(child_args);
diff --git a/third_party/nearby/README.chromium b/third_party/nearby/README.chromium index 8d59afe..9011d4f 100644 --- a/third_party/nearby/README.chromium +++ b/third_party/nearby/README.chromium
@@ -1,7 +1,7 @@ Name: Nearby Connections Library Short Name: Nearby URL: https://github.com/google/nearby -Version: d92f1d47573427e6417e29a3e82ea7d4c34fe0b5 +Version: 5b7bb37d41f45635fcb848841524cb18664336dd License: Apache 2.0 License File: LICENSE Security Critical: yes
diff --git a/tools/android/avd/proto/creation/generic_android28.textpb b/tools/android/avd/proto/creation/generic_android28.textpb index 40f9280..62f1c62 100644 --- a/tools/android/avd/proto/creation/generic_android28.textpb +++ b/tools/android/avd/proto/creation/generic_android28.textpb
@@ -38,7 +38,7 @@ min_sdk: 28 install_privileged_apk_partition: "/system" -privileged_apk { +additional_apk { package_name: "chrome_internal/third_party/google3/apks/gmscore/x86" version: "0h92P9pOxl5e5D8ImqTtJydx6qu6qxOhsZxzeKerjCwC" dest_path: "generic_android28/gmscore_apks"
diff --git a/tools/clang/scripts/build.py b/tools/clang/scripts/build.py index 970f53cf..fdac582 100755 --- a/tools/clang/scripts/build.py +++ b/tools/clang/scripts/build.py
@@ -136,9 +136,15 @@ # Try updating the current repo if it exists and has no local diff. if os.path.isdir(dir): os.chdir(dir) + # Force re-clone if we're not using the GoB LLVM mirror since some users + # may still have the github repo checked out locally. + # TODO: remove this after a while + remotes = subprocess.check_output(['git', 'remote', '-v'], + universal_newlines=True) # git diff-index --quiet returns success when there is no diff. # Also check that the first commit is reachable. - if (RunCommand(['git', 'diff-index', '--quiet', 'HEAD'], fail_hard=False) + if ('googlesource' in remotes and RunCommand( + ['git', 'diff-index', '--quiet', 'HEAD'], fail_hard=False) and RunCommand(['git', 'fetch'], fail_hard=False) and RunCommand(['git', 'checkout', commit], fail_hard=False)): return
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 9f410296..2201eb8 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -10741,6 +10741,7 @@ <int value="281" label="MSDH_REQUEST_ALL_SCREENS_NOT_ALLOWED_FOR_ORIGIN"/> <int value="282" label="RFHI_CREATE_FENCED_FRAME_BAD_FRAME_TOKEN"/> <int value="283" label="RFHI_CREATE_FENCED_FRAME_BAD_DEVTOOLS_FRAME_TOKEN"/> + <int value="284" label="FF_FROZEN_SANDBOX_FLAGS_CHANGED"/> </enum> <enum name="BadMessageReasonExtensions"> @@ -13185,11 +13186,6 @@ <int value="1" label="Tablet"/> </enum> -<enum name="BooleanTabSearchWithSearchQuery"> - <int value="0" label="Action occurred from an unfiltered item list"/> - <int value="1" label="Action occurred from a filtered item list"/> -</enum> - <enum name="BooleanTerminated"> <int value="0" label="Not terminated"/> <int value="1" label="Terminated"/> @@ -41137,6 +41133,8 @@ <int value="4329" label="ReplacedElementPaintedWithLargeOverflow"/> <int value="4330" label="FlexboxAbsPosJustifyContent"/> <int value="4331" label="MultipleFetchHandlersInServiceWorker"/> + <int value="4332" + label="StorageAccessAPI_requestStorageAccessForSite_Method"/> </enum> <enum name="FeaturePolicyAllowlistType"> @@ -51784,6 +51782,14 @@ </int> </enum> +<enum name="IOSLensEntrypoint"> + <summary>The entrypoint that the user entered Lens by.</summary> + <int value="0" label="Context Menu"/> + <int value="1" label="Home Screen Widget"/> + <int value="2" label="New Tab Page"/> + <int value="3" label="Omnibox Keyboard"/> +</enum> + <enum name="IOSLensSupportStatus"> <summary>Whether lens is supported and if not the reason why.</summary> <int value="0" label="Lens Search Supported"/> @@ -56111,7 +56117,6 @@ <int value="-1969625771" label="MessagesForAndroidOfferNotification:enabled"/> <int value="-1966445414" label="StylusBatteryStatus:disabled"/> <int value="-1965587041" label="omnibox-tab-switch-suggestions"/> - <int value="-1965232124" label="TabSearchMediaTabs:disabled"/> <int value="-1964730371" label="AutofillFillMerchantPromoCodeFields:disabled"/> <int value="-1964261747" label="WebVrVsyncAlign:disabled"/> @@ -60763,7 +60768,6 @@ <int value="910725730" label="WebRtcHWVP9Encoding:disabled"/> <int value="911256399" label="GlobalMediaControlsModernUI:enabled"/> <int value="912119426" label="InfiniteSessionRestore:disabled"/> - <int value="912279548" label="TabSearchMediaTabs:enabled"/> <int value="913138924" label="RecurrentInterstitialFeature:disabled"/> <int value="913855453" label="VirtualKeyboardFloatingResizable:disabled"/> <int value="914708297" label="CCTResizableAllowResizeByUserGesture:enabled"/> @@ -61607,6 +61611,7 @@ label="CellularBypassESimInstallationConnectivityCheck:enabled"/> <int value="1446066818" label="WebRtcAnalogAgcClippingControl:enabled"/> <int value="1446349255" label="ArcEnableUsap:disabled"/> + <int value="1446904662" label="CCTResizableWindowAboveNavbar:disabled"/> <int value="1446946673" label="DesktopRestructuredLanguageSettings:disabled"/> <int value="1447295459" label="SyncPseudoUSSApps:enabled"/> <int value="1448684258" label="TabHoverCardImages:enabled"/> @@ -62422,6 +62427,7 @@ <int value="1969860311" label="DynamicColorGamut:enabled"/> <int value="1971472561" label="CrostiniImeSupport:disabled"/> <int value="1971964569" label="NewEncodeCpuLoadEstimator:disabled"/> + <int value="1972178452" label="CCTResizableWindowAboveNavbar:enabled"/> <int value="1972232935" label="DisplayMoveWindowAccels:enabled"/> <int value="1972720114" label="WebPaymentsJustInTimePaymentApp:enabled"/> <int value="1973376634" label="WebXRMultiGpu:enabled"/>
diff --git a/tools/metrics/histograms/metadata/arc/histograms.xml b/tools/metrics/histograms/metadata/arc/histograms.xml index 315d869f..1b0eafd 100644 --- a/tools/metrics/histograms/metadata/arc/histograms.xml +++ b/tools/metrics/histograms/metadata/arc/histograms.xml
@@ -1435,7 +1435,7 @@ </histogram> <histogram name="Arc.Notifications.ActionEnabled" enum="BooleanEnabled" - expires_after="2022-09-27"> + expires_after="2023-02-15"> <owner>yaoqq@google.com</owner> <owner>arc-framework@google.com</owner> <summary> @@ -1445,7 +1445,7 @@ </histogram> <histogram name="Arc.Notifications.ExpandState" - enum="ArcNotificationExpandState" expires_after="2022-10-05"> + enum="ArcNotificationExpandState" expires_after="2023-02-15"> <owner>yaoqq@google.com</owner> <owner>arc-framework@google.com</owner> <summary> @@ -1459,7 +1459,7 @@ </histogram> <histogram name="Arc.Notifications.InlineReplyEnabled" enum="BooleanEnabled" - expires_after="2022-10-07"> + expires_after="2023-02-15"> <owner>yaoqq@google.com</owner> <owner>arc-framework@google.com</owner> <summary> @@ -1469,7 +1469,7 @@ </histogram> <histogram name="Arc.Notifications.Style" enum="ArcNotificationStyle" - expires_after="2022-09-27"> + expires_after="2023-02-15"> <owner>yaoqq@google.com</owner> <owner>arc-framework@google.com</owner> <summary>Records the style of an Arc notification when it's created.</summary>
diff --git a/tools/metrics/histograms/metadata/network/histograms.xml b/tools/metrics/histograms/metadata/network/histograms.xml index 750ac8c..214ddbb 100644 --- a/tools/metrics/histograms/metadata/network/histograms.xml +++ b/tools/metrics/histograms/metadata/network/histograms.xml
@@ -1224,6 +1224,16 @@ </summary> </histogram> +<histogram name="Network.PortalSuspectedToOnlineTime" units="ms" + expires_after="2023-09-18"> + <owner>stevenjb@chromium.org</owner> + <owner>cros-network-health@google.com</owner> + <summary> + Captive portal time from a portal-suspected state to an online state on + ChromeOS. + </summary> +</histogram> + <histogram name="Network.Radio.PossibleWakeupTrigger.RadioUtilsOverhead" units="ms" expires_after="2023-02-05"> <owner>bashi@chromium.org</owner> @@ -1309,6 +1319,16 @@ </summary> </histogram> +<histogram name="Network.RedirectFoundToOnlineTime" units="ms" + expires_after="2023-09-18"> + <owner>stevenjb@chromium.org</owner> + <owner>cros-network-health@google.com</owner> + <summary> + Captive portal time from a redirect-found state to an online state on + ChromeOS. + </summary> +</histogram> + <histogram name="Network.Shill.Cellular.3GPPRegistrationDelayedDrop" enum="NetworkCellular3GPPRegistrationDelayedDrop" expires_after="2022-12-30">
diff --git a/tools/metrics/histograms/metadata/phonehub/histograms.xml b/tools/metrics/histograms/metadata/phonehub/histograms.xml index 570f577..c4c0816 100644 --- a/tools/metrics/histograms/metadata/phonehub/histograms.xml +++ b/tools/metrics/histograms/metadata/phonehub/histograms.xml
@@ -466,6 +466,7 @@ request message was sent and a response was received. </summary> <token key="MessageType"> + <variant name="FeatureSetup"/> <variant name="FetchCameraRollItemData"/> <variant name="FetchCameraRollItems"/> <variant name="InitiateCameraRollItemTransfer"/>
diff --git a/tools/metrics/histograms/metadata/tab/histograms.xml b/tools/metrics/histograms/metadata/tab/histograms.xml index 7b649ea..5038c241 100644 --- a/tools/metrics/histograms/metadata/tab/histograms.xml +++ b/tools/metrics/histograms/metadata/tab/histograms.xml
@@ -2350,33 +2350,6 @@ </summary> </histogram> -<histogram - name="Tabs.TabSearch.DistanceOf{Action}FromInitiallySelectedTabIn{State}List" - units="tabs" expires_after="2022-09-27"> - <owner>elainechien@chromium.org</owner> - <owner>tluk@chromium.org</owner> - <owner>robliao@chromium.org</owner> - <owner>yuhengh@chromium.org</owner> - <owner>romanarora@chromium.org</owner> - <summary> - Tab Search is a feature that allows users to efficiently navigate, search, - and interact with their open and recently closed tabs. - - This metric is emitted when the user performs a {Action} action on a tab in - the Open Tabs or Audio and Video section in a {State} state. This records - the absolute distance of the index of the tab from the index of the - initially selected tab. - </summary> - <token key="Action"> - <variant name="CloseTab"/> - <variant name="SwitchTab"/> - </token> - <token key="State"> - <variant name="Filtered" summary="Filtered by user search query."/> - <variant name="Unfiltered" summary="Unfiltered by user search query."/> - </token> -</histogram> - <histogram name="Tabs.TabSearch.Mojo.SwitchToTab" units="ms" expires_after="2022-12-25"> <owner>kerenzhu@chromium.org</owner> @@ -2430,21 +2403,6 @@ </summary> </histogram> -<histogram name="Tabs.TabSearch.NumMediaTabsOnOpen" units="tabs" - expires_after="2022-12-25"> - <owner>elainechien@chromium.org</owner> - <owner>romanarora@chromium.org</owner> - <owner>tluk@chromium.org</owner> - <owner>robliao@chromium.org</owner> - <owner>yuhengh@chromium.org</owner> - <summary> - Tab Search is a feature that allows users to efficiently navigate, search, - and interact with their open and recently closed tabs. This records the - number of tabs using audio or video in the payload Tab Search receives when - it is first opened. This metric will be zero if Media Tabs are not enabled. - </summary> -</histogram> - <histogram name="Tabs.TabSearch.NumTabsClosedPerInstance" units="tabs" expires_after="2022-12-25"> <owner>tluk@chromium.org</owner> @@ -2573,28 +2531,6 @@ </token> </histogram> -<histogram - name="Tabs.TabSearch.WebUI.IndexRelativeToOpenTabsSectionOf{Action}InUnfilteredList" - units="tabs" expires_after="2022-09-27"> - <owner>elainechien@chromium.org</owner> - <owner>tluk@chromium.org</owner> - <owner>robliao@chromium.org</owner> - <owner>yuhengh@chromium.org</owner> - <owner>romanarora@chromium.org</owner> - <summary> - Tab Search is a feature that allows users to efficiently navigate, search, - and interact with their open and recently closed tabs. - - This records the index relative to the top of the Open Tabs section. This - metric is emitted when the user performs a {Action} action on a tab in the - Open Tabs section with no search query. - </summary> - <token key="Action"> - <variant name="CloseTab"/> - <variant name="SwitchTab"/> - </token> -</histogram> - <histogram name="Tabs.TabSearch.WebUI.LoadCompletedTime" units="ms" expires_after="2022-12-25"> <owner>tluk@chromium.org</owner> @@ -2616,28 +2552,6 @@ </summary> </histogram> -<histogram name="Tabs.TabSearch.WebUI.MediaTab{Action}Action" - enum="BooleanTabSearchWithSearchQuery" expires_after="2022-10-26"> - <owner>elainechien@chromium.org</owner> - <owner>romanarora@chromium.org</owner> - <owner>tluk@chromium.org</owner> - <owner>robliao@chromium.org</owner> - <owner>yuhengh@chromium.org</owner> - <summary> - Tab Search is a feature that allows users to efficiently navigate, search, - and interact with their open and recently closed tabs. - - This metric will be emitted when the user uses Tab Search to perform a - {Action} action on a tab in the Audio and Video section and will track - whether this action was taken from a filtered search results list or the - default unfiltered list. - </summary> - <token key="Action"> - <variant name="CloseTab"/> - <variant name="SwitchTab"/> - </token> -</histogram> - <histogram name="Tabs.TabSearch.WebUI.RecentlyClosed{Item}OpenAction" enum="TabSearchRecentlyClosedItemOpenAction" expires_after="2022-10-26"> <owner>tluk@chromium.org</owner>
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json index 7220043..b5ce17f 100644 --- a/tools/perf/core/perfetto_binary_roller/binary_deps.json +++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -14,7 +14,7 @@ }, "mac": { "hash": "65e00b832831bd94638cc93f391882a1539e5080", - "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/mac/5b39b1050966a57df482206b84e96e31e602f48b/trace_processor_shell" + "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/mac/f87b4c862dcd8acc8879f7d69aa8e2a968f07bed/trace_processor_shell" }, "mac_arm64": { "hash": "e1ad4861384b06d911a65f035317914b8cc975c6",
diff --git a/ui/accessibility/ax_tree_manager.cc b/ui/accessibility/ax_tree_manager.cc index 311c239..5df0bcf3 100644 --- a/ui/accessibility/ax_tree_manager.cc +++ b/ui/accessibility/ax_tree_manager.cc
@@ -20,7 +20,7 @@ } // static -AXTreeManager* AXTreeManager::FromID(AXTreeID ax_tree_id) { +AXTreeManager* AXTreeManager::FromID(const AXTreeID& ax_tree_id) { return ax_tree_id != AXTreeIDUnknown() ? GetMap().GetManager(ax_tree_id) : nullptr; }
diff --git a/ui/accessibility/ax_tree_manager.h b/ui/accessibility/ax_tree_manager.h index df43f35..2a2dfac 100644 --- a/ui/accessibility/ax_tree_manager.h +++ b/ui/accessibility/ax_tree_manager.h
@@ -21,7 +21,7 @@ // trees). class AX_EXPORT AXTreeManager : public AXTreeObserver { public: - static AXTreeManager* FromID(AXTreeID ax_tree_id); + static AXTreeManager* FromID(const AXTreeID& ax_tree_id); // If the child of `parent_node` exists in a separate child tree, return the // tree manager for that child tree. Otherwise, return nullptr. static AXTreeManager* ForChildTree(const AXNode& parent_node); @@ -35,7 +35,7 @@ // given |tree_id|. This allows for callers to access nodes outside of their // own tree. Returns nullptr if |tree_id| or |node_id| is not found. // TODO(kschmi): Remove |tree_id| parameter, as it's unnecessary. - virtual AXNode* GetNodeFromTree(const AXTreeID tree_id, + virtual AXNode* GetNodeFromTree(const AXTreeID& tree_id, const AXNodeID node_id) const = 0; // Returns the AXNode in the current tree that has the given |node_id|. @@ -68,22 +68,22 @@ AXEventGenerator& event_generator() { return event_generator_; } // AXTreeObserver implementation. - void OnTreeDataChanged(ui::AXTree* tree, - const ui::AXTreeData& old_data, - const ui::AXTreeData& new_data) override; - void OnNodeWillBeDeleted(ui::AXTree* tree, ui::AXNode* node) override {} - void OnSubtreeWillBeDeleted(ui::AXTree* tree, ui::AXNode* node) override {} - void OnNodeCreated(ui::AXTree* tree, ui::AXNode* node) override {} - void OnNodeDeleted(ui::AXTree* tree, int32_t node_id) override {} - void OnNodeReparented(ui::AXTree* tree, ui::AXNode* node) override {} - void OnRoleChanged(ui::AXTree* tree, - ui::AXNode* node, + void OnTreeDataChanged(AXTree* tree, + const AXTreeData& old_data, + const AXTreeData& new_data) override; + void OnNodeWillBeDeleted(AXTree* tree, AXNode* node) override {} + void OnSubtreeWillBeDeleted(AXTree* tree, AXNode* node) override {} + void OnNodeCreated(AXTree* tree, AXNode* node) override {} + void OnNodeDeleted(AXTree* tree, int32_t node_id) override {} + void OnNodeReparented(AXTree* tree, AXNode* node) override {} + void OnRoleChanged(AXTree* tree, + AXNode* node, ax::mojom::Role old_role, ax::mojom::Role new_role) override {} void OnAtomicUpdateFinished( - ui::AXTree* tree, + AXTree* tree, bool root_changed, - const std::vector<ui::AXTreeObserver::Change>& changes) override {} + const std::vector<AXTreeObserver::Change>& changes) override {} protected: AXTreeManager();
diff --git a/ui/accessibility/test_ax_tree_manager.cc b/ui/accessibility/test_ax_tree_manager.cc index 392ba91..8e546fb 100644 --- a/ui/accessibility/test_ax_tree_manager.cc +++ b/ui/accessibility/test_ax_tree_manager.cc
@@ -59,7 +59,7 @@ GetMap().AddTreeManager(GetTreeID(), this); } -AXNode* TestAXTreeManager::GetNodeFromTree(const AXTreeID tree_id, +AXNode* TestAXTreeManager::GetNodeFromTree(const AXTreeID& tree_id, const AXNodeID node_id) const { return (ax_tree_ && GetTreeID() == tree_id) ? ax_tree_->GetFromId(node_id) : nullptr;
diff --git a/ui/accessibility/test_ax_tree_manager.h b/ui/accessibility/test_ax_tree_manager.h index a3299a3..71e3740 100644 --- a/ui/accessibility/test_ax_tree_manager.h +++ b/ui/accessibility/test_ax_tree_manager.h
@@ -44,7 +44,7 @@ void SetTree(std::unique_ptr<AXTree> tree); // AXTreeManager implementation. - AXNode* GetNodeFromTree(const AXTreeID tree_id, + AXNode* GetNodeFromTree(const AXTreeID& tree_id, const AXNodeID node_id) const override; AXNode* GetNodeFromTree(const AXNodeID node_id) const override; AXNode* GetParentNodeFromParentTreeAsAXNode() const override;
diff --git a/ui/chromeos/strings/network_element_localized_strings_provider.cc b/ui/chromeos/strings/network_element_localized_strings_provider.cc index 6a40281..5b64c64e 100644 --- a/ui/chromeos/strings/network_element_localized_strings_provider.cc +++ b/ui/chromeos/strings/network_element_localized_strings_provider.cc
@@ -431,6 +431,8 @@ {"networkProxyWpad", IDS_SETTINGS_INTERNET_NETWORK_PROXY_WPAD}, {"networkProxyWpadNone", IDS_SETTINGS_INTERNET_NETWORK_PROXY_WPAD_NONE}, {"remove", IDS_REMOVE}, + {"controlledSettingPolicy", + IDS_SETTINGS_INTERNET_NETWORK_SETTING_MANAGED_BY_ADMIN_TOOLTIP}, }; html_source->AddLocalizedStrings(kLocalizedStrings);
diff --git a/ui/chromeos/ui_chromeos_strings.grd b/ui/chromeos/ui_chromeos_strings.grd index 720fc77d..b50da92 100644 --- a/ui/chromeos/ui_chromeos_strings.grd +++ b/ui/chromeos/ui_chromeos_strings.grd
@@ -1728,6 +1728,9 @@ <message name="IDS_SETTINGS_INTERNET_NETWORK_PROXY_PORT_INPUT_ACCESSIBILITY_LABEL" desc="Settings > Internet > Network details: Accessibility only label for proxy port number input field."> <ph name="INPUT_LABEL">$1<ex>HTTP Proxy</ex></ph> - Port </message> + <message name="IDS_SETTINGS_INTERNET_NETWORK_SETTING_MANAGED_BY_ADMIN_TOOLTIP" desc="Text displayed in the controlled settings bubble when a setting's value is managed by policy."> + This setting is managed by your administrator. + </message> <!-- Settings > Internet > SIM lock/unlock dialog --> <message name="IDS_SETTINGS_INTERNET_NETWORK_SIM_CHANGE_PIN" desc="Settings > Internet > Network details > Lock/unlock SIM card: Label for buton to change the PIN.">
diff --git a/ui/chromeos/ui_chromeos_strings_grd/IDS_SETTINGS_INTERNET_NETWORK_SETTING_MANAGED_BY_ADMIN_TOOLTIP.png.sha1 b/ui/chromeos/ui_chromeos_strings_grd/IDS_SETTINGS_INTERNET_NETWORK_SETTING_MANAGED_BY_ADMIN_TOOLTIP.png.sha1 new file mode 100644 index 0000000..4bfbef1 --- /dev/null +++ b/ui/chromeos/ui_chromeos_strings_grd/IDS_SETTINGS_INTERNET_NETWORK_SETTING_MANAGED_BY_ADMIN_TOOLTIP.png.sha1
@@ -0,0 +1 @@ +9675c2df69fe7b2c050d0d200a4e2b83d583044a \ No newline at end of file
diff --git a/ui/views/accessibility/views_ax_tree_manager.cc b/ui/views/accessibility/views_ax_tree_manager.cc index 8e3d657..abad8ac 100644 --- a/ui/views/accessibility/views_ax_tree_manager.cc +++ b/ui/views/accessibility/views_ax_tree_manager.cc
@@ -58,7 +58,7 @@ } ui::AXNode* ViewsAXTreeManager::GetNodeFromTree( - const ui::AXTreeID tree_id, + const ui::AXTreeID& tree_id, const ui::AXNodeID node_id) const { if (!widget_ || !widget_->GetRootView()) return nullptr;
diff --git a/ui/views/accessibility/views_ax_tree_manager.h b/ui/views/accessibility/views_ax_tree_manager.h index 651c013..a94de70a 100644 --- a/ui/views/accessibility/views_ax_tree_manager.h +++ b/ui/views/accessibility/views_ax_tree_manager.h
@@ -79,7 +79,7 @@ void UnsetGeneratedEventCallbackForTesting(); // AXTreeManager implementation. - ui::AXNode* GetNodeFromTree(const ui::AXTreeID tree_id, + ui::AXNode* GetNodeFromTree(const ui::AXTreeID& tree_id, const ui::AXNodeID node_id) const override; ui::AXNode* GetNodeFromTree(const ui::AXNodeID node_id) const override; ui::AXTreeID GetParentTreeID() const override;
diff --git a/ui/views/cocoa/bridged_native_widget_unittest.mm b/ui/views/cocoa/bridged_native_widget_unittest.mm index c132e64..dd060ee 100644 --- a/ui/views/cocoa/bridged_native_widget_unittest.mm +++ b/ui/views/cocoa/bridged_native_widget_unittest.mm
@@ -291,6 +291,27 @@ } @end +@interface NativeWidgetMacNSWindowForTesting : NativeWidgetMacNSWindow { + BOOL hasShadowForTesting; +} +@end + +@implementation NativeWidgetMacNSWindowForTesting + +// Preserves the value of the hasShadow flag. During testing, -hasShadow will +// always return NO because shadows are disabled on the bots. +- (void)setHasShadow:(BOOL)flag { + hasShadowForTesting = flag; + [super setHasShadow:flag]; +} + +// Returns the value of the hasShadow flag during tests. +- (BOOL)hasShadowForTesting { + return hasShadowForTesting; +} + +@end + namespace views { namespace test { @@ -311,7 +332,7 @@ ownership_ = params.ownership; base::scoped_nsobject<NativeWidgetMacNSWindow> window( - [[NativeWidgetMacNSWindow alloc] + [[NativeWidgetMacNSWindowForTesting alloc] initWithContentRect:ui::kWindowSizeDeterminedLater styleMask:NSWindowStyleMaskBorderless backing:NSBackingStoreBuffered @@ -406,6 +427,12 @@ return nil; } + bool BridgeWindowHasShadow() { + return + [base::mac::ObjCCast<NativeWidgetMacNSWindowForTesting>(bridge_window()) + hasShadowForTesting]; + } + protected: std::unique_ptr<Widget> widget_; raw_ptr<MockNativeWidgetMac> native_widget_mac_; // Weak. Owned by |widget_|. @@ -903,9 +930,7 @@ } // Tests the shadow type given in InitParams. -// Disabled because shadows are disabled on the bots - see -// https://crbug.com/899286. -TEST_F(BridgedNativeWidgetInitTest, DISABLED_ShadowType) { +TEST_F(BridgedNativeWidgetInitTest, ShadowType) { // Verify Widget::InitParam defaults and arguments added from SetUp(). EXPECT_EQ(Widget::InitParams::TYPE_WINDOW_FRAMELESS, type_); EXPECT_EQ(Widget::InitParams::WindowOpacity::kOpaque, opacity_); @@ -913,29 +938,27 @@ CreateNewWidgetToInit(); EXPECT_FALSE( - [bridge_window() hasShadow]); // Default for NSWindowStyleMaskBorderless. + BridgeWindowHasShadow()); // Default for NSWindowStyleMaskBorderless. PerformInit(); // Borderless is 0, so isn't really a mask. Check that nothing is set. EXPECT_EQ(NSWindowStyleMaskBorderless, [bridge_window() styleMask]); - EXPECT_TRUE( - [bridge_window() hasShadow]); // ShadowType::kDefault means a shadow. + EXPECT_TRUE(BridgeWindowHasShadow()); // ShadowType::kDefault means a shadow. CreateNewWidgetToInit(); shadow_type_ = Widget::InitParams::ShadowType::kNone; PerformInit(); - EXPECT_FALSE([bridge_window() hasShadow]); // Preserves lack of shadow. + EXPECT_FALSE(BridgeWindowHasShadow()); // Preserves lack of shadow. // Default for Widget::InitParams::TYPE_WINDOW. CreateNewWidgetToInit(); PerformInit(); - EXPECT_FALSE( - [bridge_window() hasShadow]); // ShadowType::kNone removes shadow. + EXPECT_FALSE(BridgeWindowHasShadow()); // ShadowType::kNone removes shadow. shadow_type_ = Widget::InitParams::ShadowType::kDefault; CreateNewWidgetToInit(); PerformInit(); - EXPECT_TRUE([bridge_window() hasShadow]); // Preserves shadow. + EXPECT_TRUE(BridgeWindowHasShadow()); // Preserves shadow. widget_.reset(); }
diff --git a/ui/webui/resources/cr_components/help_bubble/help_bubble.html b/ui/webui/resources/cr_components/help_bubble/help_bubble.html index 5ec2a385c8..e19004e 100644 --- a/ui/webui/resources/cr_components/help_bubble/help_bubble.html +++ b/ui/webui/resources/cr_components/help_bubble/help_bubble.html
@@ -1,70 +1,88 @@ <style include="cr-hidden-style"> :host { + border-radius: 8px; + box-shadow: 0 6px 10px 4px rgba(60, 64, 67, 0.15), 0 2px 3px rgba(60, 64, 67, 0.3); position: absolute; z-index: 1; } - /* HelpBubblePosition.ABOVE */ - :host([position='0']) { - transform: translateY(-100%); - } - - /* HelpBubblePosition.BELOW */ - :host([position='1']) { - transform: none; - } - - /* HelpBubblePosition.LEFT */ - :host([position='2']) { - transform: translate(-100%, -50%); - } - - /* HelpBubblePosition.RIGHT */ - :host([position='3']) { - transform: translateY(-50%); - } - #arrow { - --help-bubble-arrow-size: 16px; - --help-bubble-arrow-offset: calc(var(--help-bubble-arrow-size) / 2); + --help-bubble-arrow-size: 11.3px; + --help-bubble-arrow-size-half: calc(var(--help-bubble-arrow-size) / 2); + --help-bubble-arrow-diameter: 16px; /* approx. */ + --help-bubble-arrow-radius: calc(var(--help-bubble-arrow-diameter) / 2); + --help-bubble-arrow-edge-offset: 22px; + --help-bubble-arrow-offset: calc(var(--help-bubble-arrow-edge-offset) + var(--help-bubble-arrow-radius)); + --help-bubble-arrow-border-radius: 2px; + position: absolute; + } + + /* #arrow is rotated and positioned in a container to simplify positioning */ + #inner-arrow { background-color: var(--help-bubble-background); height: var(--help-bubble-arrow-size); + left: calc(0px - var(--help-bubble-arrow-size-half)); position: absolute; - transform: rotate(-45deg); + top: calc(0px - var(--help-bubble-arrow-size-half)); + transform: rotate(45deg); width: var(--help-bubble-arrow-size); z-index: -1; } - /* Turns the arrow direction downwards, when the bubble is placed above - * the anchor element */ - #arrow.above { - border-bottom-left-radius: 2px; - bottom: calc(0 - var(--help-bubble-arrow-offset)); - left: calc(50% - var(--help-bubble-arrow-offset)); + #arrow.bottom-edge { + bottom: 0; } - /* Turns the arrow direction upwards, when the bubble is placed below - * the anchor element */ - #arrow.below { - border-top-right-radius: 2px; - left: calc(50% - var(--help-bubble-arrow-offset)); - top: calc(0 - var(--help-bubble-arrow-offset)); + #arrow.bottom-edge #inner-arrow { + border-bottom-right-radius: var(--help-bubble-arrow-border-radius); } - /* Turns the arrow direction to the right, when the bubble is placed to the - * left of the anchor element */ - #arrow.left { - border-bottom-right-radius: 2px; - right: calc(0 - var(--help-bubble-arrow-offset)); - top: calc(50% - var(--help-bubble-arrow-offset)); + #arrow.top-edge { + top: 0; } - /* Turns the arrow direction to the left, when the bubble is placed to the - * right of the anchor element */ - #arrow.right { - border-top-left-radius: 2px; - left: calc(0 - var(--help-bubble-arrow-offset)); - top: calc(50% - var(--help-bubble-arrow-offset)); + #arrow.top-edge #inner-arrow { + border-top-left-radius: var(--help-bubble-arrow-border-radius); + } + + #arrow.right-edge { + right: 0; + } + + #arrow.right-edge #inner-arrow { + border-top-right-radius: var(--help-bubble-arrow-border-radius); + } + + #arrow.left-edge { + left: 0; + } + + #arrow.left-edge #inner-arrow { + border-bottom-left-radius: var(--help-bubble-arrow-border-radius); + } + + #arrow.top-position { + top: var(--help-bubble-arrow-offset); + } + + #arrow.vertical-center-position { + top: 50%; + } + + #arrow.bottom-position { + bottom: var(--help-bubble-arrow-offset); + } + + #arrow.left-position { + left: var(--help-bubble-arrow-offset); + } + + #arrow.horizontal-center-position { + left: 50%; + } + + #arrow.right-position { + right: var(--help-bubble-arrow-offset); } #topContainer { @@ -115,19 +133,19 @@ * themes, which is why the values below do not change based on theme * preference. */ - .help-bubble { + .help-bubble { --help-bubble-background: var(--google-blue-700); --help-bubble-element-spacing: 8px; --help-bubble-text-color: var(--google-grey-200); background-color: var(--help-bubble-background); border-radius: 8px; - box-shadow: 0 6px 10px 4px rgba(60, 64, 67, 0.15), 0 2px 3px rgba(60, 64, 67, 0.3); color: var(--help-bubble-text-color); display: flex; flex-direction: column; justify-content: space-between; padding: 16px 20px; - width: 340px; + position: relative; + width: 300px; } #main { @@ -210,12 +228,10 @@ </template> </div> <div id="infoIcon" hidden$="[[!shouldShowInfoIcon_(progress, infoIcon)]]"></div> - <div class="title" - hidden$="[[!shouldShowTitleInTopContainer_(progress, titleText)]]"> + <div class="title" hidden$="[[!shouldShowTitleInTopContainer_(progress, titleText)]]"> [[titleText]] </div> - <div class="body" - hidden$="[[!shouldShowBodyInTopContainer_(progress, titleText)]]"> + <div class="body" hidden$="[[!shouldShowBodyInTopContainer_(progress, titleText)]]"> [[bodyText]] </div> <cr-icon-button id="close" iron-icon="cr:close" @@ -229,11 +245,11 @@ </div> <div id="buttons" hidden$="[[!buttons.length]]"> <template is="dom-repeat" items="[[buttons]]" sort="buttonSortFunc_"> - <cr-button id$="[[getButtonId_(itemsIndex)]]" - tabindex$="[[getButtonTabIndex_(itemsIndex, item.isDefault)]]" - class$="[[getButtonClass_(item.isDefault)]]" - on-click="onButtonClick_">[[item.text]]</cr-button> + <cr-button id$="[[getButtonId_(itemsIndex)]]" tabindex$="[[getButtonTabIndex_(itemsIndex, item.isDefault)]]" + class$="[[getButtonClass_(item.isDefault)]]" on-click="onButtonClick_">[[item.text]]</cr-button> </template> </div> - <div id="arrow" class$="[[getArrowClass_(position)]]"></div> + <div id="arrow" class$="[[getArrowClass_(position)]]"> + <div id="inner-arrow"></div> + </div> </div>
diff --git a/ui/webui/resources/cr_components/help_bubble/help_bubble.mojom b/ui/webui/resources/cr_components/help_bubble/help_bubble.mojom index 28deb1be..d6c96a5 100644 --- a/ui/webui/resources/cr_components/help_bubble/help_bubble.mojom +++ b/ui/webui/resources/cr_components/help_bubble/help_bubble.mojom
@@ -15,11 +15,22 @@ // more detailed usage information, see README.md. // Where the help bubble floats relative to its anchor. -enum HelpBubblePosition { - ABOVE, - BELOW, - LEFT, - RIGHT +enum HelpBubbleArrowPosition { + TOP_LEFT, + TOP_CENTER, + TOP_RIGHT, + + BOTTOM_LEFT, + BOTTOM_CENTER, + BOTTOM_RIGHT, + + LEFT_TOP, + LEFT_CENTER, + LEFT_BOTTOM, + + RIGHT_TOP, + RIGHT_CENTER, + RIGHT_BOTTOM, }; // Simplified version of user_education::HelpBubbleButtonParams. @@ -41,7 +52,7 @@ // element ID. string native_identifier; - HelpBubblePosition position = HelpBubblePosition.BELOW; + HelpBubbleArrowPosition position = HelpBubbleArrowPosition.TOP_CENTER; string? title_text; string body_text; string close_button_alt_text;
diff --git a/ui/webui/resources/cr_components/help_bubble/help_bubble.ts b/ui/webui/resources/cr_components/help_bubble/help_bubble.ts index 07b5920..9a4b4b2 100644 --- a/ui/webui/resources/cr_components/help_bubble/help_bubble.ts +++ b/ui/webui/resources/cr_components/help_bubble/help_bubble.ts
@@ -20,7 +20,7 @@ import {DomRepeatEvent, PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {getTemplate} from './help_bubble.html.js'; -import {HelpBubbleButtonParams, HelpBubblePosition, Progress} from './help_bubble.mojom-webui.js'; +import {HelpBubbleButtonParams, HelpBubbleArrowPosition, Progress} from './help_bubble.mojom-webui.js'; const ANCHOR_HIGHLIGHT_CLASS = 'help-anchor-highlight'; @@ -65,8 +65,8 @@ closeText: String, position: { - type: HelpBubblePosition, - value: HelpBubblePosition.BELOW, + type: HelpBubbleArrowPosition, + value: HelpBubbleArrowPosition.TOP_CENTER, reflectToAttribute: true, }, }; @@ -76,7 +76,7 @@ bodyText: string; titleText: string; closeText: string; - position: HelpBubblePosition; + position: HelpBubbleArrowPosition; buttons: HelpBubbleButtonParams[] = []; progress: Progress|null = null; infoIcon: string|null = null; @@ -241,19 +241,67 @@ return 0; } - private getArrowClass_(position: HelpBubblePosition): string { + /** + * Determine classes that describe the arrow position relative to the + * HelpBubble + */ + private getArrowClass_(position: HelpBubbleArrowPosition): string { + let classList = ''; + // `*-edge` classes move arrow to a HelpBubble edge switch (position) { - case HelpBubblePosition.ABOVE: - return 'above'; - case HelpBubblePosition.BELOW: - return 'below'; - case HelpBubblePosition.LEFT: - return 'left'; - case HelpBubblePosition.RIGHT: - return 'right'; + case HelpBubbleArrowPosition.TOP_LEFT: + case HelpBubbleArrowPosition.TOP_CENTER: + case HelpBubbleArrowPosition.TOP_RIGHT: + classList = 'top-edge '; + break; + case HelpBubbleArrowPosition.BOTTOM_LEFT: + case HelpBubbleArrowPosition.BOTTOM_CENTER: + case HelpBubbleArrowPosition.BOTTOM_RIGHT: + classList = 'bottom-edge '; + break; + case HelpBubbleArrowPosition.LEFT_TOP: + case HelpBubbleArrowPosition.LEFT_CENTER: + case HelpBubbleArrowPosition.LEFT_BOTTOM: + classList = 'left-edge '; + break; + case HelpBubbleArrowPosition.RIGHT_TOP: + case HelpBubbleArrowPosition.RIGHT_CENTER: + case HelpBubbleArrowPosition.RIGHT_BOTTOM: + classList = 'right-edge '; + break; default: assertNotReached('Unknown help bubble position: ' + position); } + // `*-position` classes move arrow along the HelpBubble edge + switch (position) { + case HelpBubbleArrowPosition.TOP_LEFT: + case HelpBubbleArrowPosition.BOTTOM_LEFT: + classList += 'left-position'; + break; + case HelpBubbleArrowPosition.TOP_CENTER: + case HelpBubbleArrowPosition.BOTTOM_CENTER: + classList += 'horizontal-center-position'; + break; + case HelpBubbleArrowPosition.TOP_RIGHT: + case HelpBubbleArrowPosition.BOTTOM_RIGHT: + classList += 'right-position'; + break; + case HelpBubbleArrowPosition.LEFT_TOP: + case HelpBubbleArrowPosition.RIGHT_TOP: + classList += 'top-position'; + break; + case HelpBubbleArrowPosition.LEFT_CENTER: + case HelpBubbleArrowPosition.RIGHT_CENTER: + classList += 'vertical-center-position'; + break; + case HelpBubbleArrowPosition.LEFT_BOTTOM: + case HelpBubbleArrowPosition.RIGHT_BOTTOM: + classList += 'bottom-position'; + break; + default: + assertNotReached('Unknown help bubble position: ' + position); + } + return classList; } /** @@ -264,52 +312,90 @@ assert( this.anchorElement_, 'Update position: expected valid anchor element.'); + // How far HelpBubble is from anchorElement + const ANCHOR_OFFSET = 16; + const ARROW_WIDTH = 16; + // The nearest an arrow can be to the adjacent HelpBubble edge + const ARROW_OFFSET_FROM_EDGE = 22 + (ARROW_WIDTH / 2); + // Inclusive of 8px visible arrow and 8px margin. - const parentRect = this.offsetParent!.getBoundingClientRect(); const anchorRect = this.anchorElement_.getBoundingClientRect(); - const anchorLeft = anchorRect.left - parentRect.left; - const anchorHorizontalCenter = anchorLeft + anchorRect.width / 2; - const anchorTop = anchorRect.top - parentRect.top; - const ARROW_OFFSET = 16; - const LEFT_MARGIN = 8; - const HELP_BUBBLE_WIDTH = 362; + const helpBubbleRect = this.getBoundingClientRect(); - let helpLeft: string = ''; - let helpTop: string = ''; - + let transform = ''; + // Move HelpBubble to correct side of the anchorElement switch (this.position) { - case HelpBubblePosition.ABOVE: - // Anchor the help bubble to the top center of the anchor element. - helpTop = `${anchorTop - ARROW_OFFSET}px`; - helpLeft = `${ - Math.max( - LEFT_MARGIN, - anchorHorizontalCenter - HELP_BUBBLE_WIDTH / 2)}px`; + case HelpBubbleArrowPosition.TOP_LEFT: + case HelpBubbleArrowPosition.TOP_CENTER: + case HelpBubbleArrowPosition.TOP_RIGHT: + transform += `translateY(${ + anchorRect.height + }px) translateY(${ANCHOR_OFFSET}px) `; break; - case HelpBubblePosition.BELOW: - // Anchor the help bubble to the bottom center of the anchor element. - helpTop = `${anchorTop + anchorRect.height + ARROW_OFFSET}px`; - helpLeft = `${ - Math.max( - LEFT_MARGIN, - anchorHorizontalCenter - HELP_BUBBLE_WIDTH / 2)}px`; + case HelpBubbleArrowPosition.BOTTOM_LEFT: + case HelpBubbleArrowPosition.BOTTOM_CENTER: + case HelpBubbleArrowPosition.BOTTOM_RIGHT: + transform += `translateY(-100%) translateY(-${ANCHOR_OFFSET}px) `; break; - case HelpBubblePosition.LEFT: - // Anchor the help bubble to the center left of the anchor element. - helpTop = `${anchorTop + anchorRect.height / 2}px`; - helpLeft = `${anchorLeft - ARROW_OFFSET}px`; + case HelpBubbleArrowPosition.LEFT_TOP: + case HelpBubbleArrowPosition.LEFT_CENTER: + case HelpBubbleArrowPosition.LEFT_BOTTOM: + transform += `translateX(${ + anchorRect.width + }px) translateX(${ANCHOR_OFFSET}px) `; break; - case HelpBubblePosition.RIGHT: - // Anchor the help bubble to the center right of the anchor element. - helpTop = `${anchorTop + anchorRect.height / 2}px`; - helpLeft = `${anchorLeft + anchorRect.width + ARROW_OFFSET}px`; + case HelpBubbleArrowPosition.RIGHT_TOP: + case HelpBubbleArrowPosition.RIGHT_CENTER: + case HelpBubbleArrowPosition.RIGHT_BOTTOM: + transform += `translateX(-100%) translateX(-${ANCHOR_OFFSET}px) `; break; default: assertNotReached(); } - - this.style.top = helpTop; - this.style.left = helpLeft; + // Move HelpBubble along the anchorElement edge according to arrow position + switch (this.position) { + case HelpBubbleArrowPosition.TOP_LEFT: + case HelpBubbleArrowPosition.BOTTOM_LEFT: + transform += `translateX(${ + (anchorRect.width / 2) - ARROW_OFFSET_FROM_EDGE + }px)`; + break; + case HelpBubbleArrowPosition.TOP_CENTER: + case HelpBubbleArrowPosition.BOTTOM_CENTER: + transform += `translateX(${ + (anchorRect.width / 2) - (helpBubbleRect.width / 2) + }px)`; + break; + case HelpBubbleArrowPosition.TOP_RIGHT: + case HelpBubbleArrowPosition.BOTTOM_RIGHT: + transform += `translateX(${ + (anchorRect.width / 2) + - (helpBubbleRect.width - ARROW_OFFSET_FROM_EDGE) + }px)`; + break; + case HelpBubbleArrowPosition.LEFT_TOP: + case HelpBubbleArrowPosition.RIGHT_TOP: + transform += `translateY(${ + (anchorRect.height / 2) - ARROW_OFFSET_FROM_EDGE + }px)`; + break; + case HelpBubbleArrowPosition.LEFT_CENTER: + case HelpBubbleArrowPosition.RIGHT_CENTER: + transform += `translateY(${ + (anchorRect.height / 2) - (helpBubbleRect.height / 2) + }px)`; + break; + case HelpBubbleArrowPosition.LEFT_BOTTOM: + case HelpBubbleArrowPosition.RIGHT_BOTTOM: + transform += `translateY(${ + (anchorRect.height / 2) + - (helpBubbleRect.height - ARROW_OFFSET_FROM_EDGE) + }px)`; + break; + default: + assertNotReached(); + } + this.style.transform = transform; } /**
diff --git a/ui/webui/resources/mojo/BUILD.gn b/ui/webui/resources/mojo/BUILD.gn index dcd7487..7ff9d04 100644 --- a/ui/webui/resources/mojo/BUILD.gn +++ b/ui/webui/resources/mojo/BUILD.gn
@@ -16,6 +16,7 @@ in_files = [ "mojo/public/mojom/base/big_buffer.mojom-webui.js", "mojo/public/mojom/base/file_path.mojom-webui.js", + "mojo/public/mojom/base/int128.mojom-webui.js", "mojo/public/mojom/base/process_id.mojom-webui.js", "mojo/public/mojom/base/safe_base_name.mojom-webui.js", "mojo/public/mojom/base/string16.mojom-webui.js",