diff --git a/DEPS b/DEPS index d8f4697..48f6bae 100644 --- a/DEPS +++ b/DEPS
@@ -304,19 +304,19 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. - 'src_internal_revision': 'ac35abe17d096d337e8a739b940517c76a37fb86', + 'src_internal_revision': '88f3b828bb668e23cbc133370ad3ca13665cacc9', # 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': '46e211e887401943a5bd029a3a61aa12c792d337', + 'skia_revision': '53de7d8fa378818d0d528808156563e720fbfb59', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. - 'v8_revision': '8f62f791b8aac6b55fd24da89f0397e56fb80210', + 'v8_revision': '8e52cbb459346bcafde3d1718bedd3ec93bbfdbd', # 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': '28290eae4b384c26d329f3efd8516447759d543b', + 'angle_revision': '3461be1ae88258d65299f9fd1f86d6f99c5d89e4', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. @@ -379,7 +379,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': '73730a049e81a4f396f40d5d2b36b5d70ba0ed1c', + 'catapult_revision': '6fd04d10d17ae5354fcf53f499c5837e7a438138', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling chromium_variations # and whatever else without interference from each other. @@ -399,7 +399,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': '453169c84a1949b2bf28a6a13f711e80db5b2bf8', + 'devtools_frontend_revision': '909e3f281caba659131183443d24e087965f22a8', # 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. @@ -823,7 +823,7 @@ 'src/clank': { 'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' + - 'c473ec58befafb3e6bb8d9d4f5450d5bc7816402', + '6f4ebe62d8f81240abcd44282b03ab25f7314bb2', 'condition': 'checkout_android and checkout_src_internal', }, @@ -985,7 +985,7 @@ 'packages': [ { 'package': 'chromium/third_party/androidx', - 'version': 'JWIpSfRyqxvIqkYKCEWTSEN6AhoQzea0rhxIYowl0GwC', + 'version': 'Az0661QhG5Cpfft2oBSAmdixodnucJQS7_m8Is-kJ6IC', }, ], 'condition': 'checkout_android', @@ -1045,7 +1045,7 @@ 'packages': [ { 'package': 'chromium/third_party/android_build_tools/lint', - 'version': 'cBQ1qc7aJ6gwBvrCOJNVq6Mlijj4HlNtTmzJEXpgmBQC', + 'version': 'X7sJxpJN0p6qi1dgpI9-UFA2YDe2O2A1kF0QZjBJpmYC', }, ], 'condition': 'checkout_android', @@ -1195,13 +1195,13 @@ }, 'src/third_party/depot_tools': - Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '39bc04eb9f4fbbd05ae68894cc7e1fdbbe17484e', + Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '6592c255249330478d24c29866cc4e5967a7a951', 'src/third_party/devtools-frontend/src': Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'), 'src/third_party/devtools-frontend-internal': { - 'url': Var('chrome_git') + '/devtools/devtools-internal.git' + '@' + '528abbe76e1bd38980a1d69fcc103598aac2980a', + 'url': Var('chrome_git') + '/devtools/devtools-internal.git' + '@' + 'c06ef133407ac7b84a375b798a1429025bf69d3d', 'condition': 'checkout_src_internal', }, @@ -1661,7 +1661,7 @@ Var('pdfium_git') + '/pdfium.git' + '@' + Var('pdfium_revision'), 'src/third_party/perfetto': - Var('android_git') + '/platform/external/perfetto.git' + '@' + 'd1ee2c6acf48c1042e2d99e9a62e354a72ec6f93', + Var('android_git') + '/platform/external/perfetto.git' + '@' + '22522e4de21d80de5d67311ca1c0f2321f46f2f5', 'src/third_party/perl': { 'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3', @@ -1846,7 +1846,7 @@ Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '705abe536630df7d722bd7b4c866fc35a0ff662f', 'src/third_party/webrtc': - Var('webrtc_git') + '/src.git' + '@' + '7cb56f5fbd334060cedf343b38a4fba56417b632', + Var('webrtc_git') + '/src.git' + '@' + 'dc48289b46e028e6f64e1f7b4e80585853284cbc', # Wuffs' canonical repository is at github.com/google/wuffs, but we use # Skia's mirror of Wuffs, the same as in upstream Skia's DEPS file. @@ -3949,7 +3949,7 @@ 'src/components/optimization_guide/internal': { 'url': Var('chrome_git') + '/chrome/components/optimization_guide.git' + '@' + - '7108a78492fbb8778d8783ea54643d63f600447d', + 'dd1eb9fc0d4693ea83317b624df6c6f1002b04e7', 'condition': 'checkout_src_internal', },
diff --git a/ash/BUILD.gn b/ash/BUILD.gn index 3b0cda45..ac9273ca 100644 --- a/ash/BUILD.gn +++ b/ash/BUILD.gn
@@ -1679,6 +1679,8 @@ "system/locale/unified_locale_detailed_view_controller.h", "system/lock_screen_notification_controller.cc", "system/lock_screen_notification_controller.h", + "system/mahi/mahi_panel_widget.cc", + "system/mahi/mahi_panel_widget.h", "system/media/media_color_theme.cc", "system/media/media_color_theme.h", "system/media/media_notification_provider.cc", @@ -3605,6 +3607,7 @@ "system/locale/locale_detailed_view_unittest.cc", "system/locale/locale_feature_pod_controller_unittest.cc", "system/lock_screen_notification_controller_unittest.cc", + "system/mahi/mahi_panel_widget_unittest.cc", "system/media/media_tray_unittest.cc", "system/media/quick_settings_media_view_container_unittest.cc", "system/media/quick_settings_media_view_controller_unittest.cc",
diff --git a/ash/ambient/ui/ambient_animation_view.cc b/ash/ambient/ui/ambient_animation_view.cc index da4eea7e..2d35ca2e0 100644 --- a/ash/ambient/ui/ambient_animation_view.cc +++ b/ash/ambient/ui/ambient_animation_view.cc
@@ -105,7 +105,7 @@ << " expected_fps=" << data.frames_expected / duration_sec << " actual_fps=" << data.frames_produced / duration_sec << " duration=" << duration; - metrics_util::ForSmoothness( + metrics_util::ForSmoothnessV3( base::BindRepeating(&LogCompositorThroughput, ui_settings)) .Run(data); }
diff --git a/ash/ambient/ui/photo_view.cc b/ash/ambient/ui/photo_view.cc index 2717dc0..33bdaf4a 100644 --- a/ash/ambient/ui/photo_view.cc +++ b/ash/ambient/ui/photo_view.cc
@@ -139,7 +139,7 @@ ui::AnimationThroughputReporter reporter( animation.GetAnimator(), - metrics_util::ForSmoothness(base::BindRepeating(ReportSmoothness))); + metrics_util::ForSmoothnessV3(base::BindRepeating(ReportSmoothness))); visible_layer->SetOpacity(0.0f); } @@ -157,7 +157,7 @@ ui::AnimationThroughputReporter reporter( animation.GetAnimator(), - metrics_util::ForSmoothness(base::BindRepeating(ReportSmoothness))); + metrics_util::ForSmoothnessV3(base::BindRepeating(ReportSmoothness))); invisible_layer->SetOpacity(1.0f); }
diff --git a/ash/app_list/app_list_controller_impl.cc b/ash/app_list/app_list_controller_impl.cc index 0c5a184..2cb741c 100644 --- a/ash/app_list/app_list_controller_impl.cc +++ b/ash/app_list/app_list_controller_impl.cc
@@ -1968,7 +1968,7 @@ auto* compositor = root_window->layer()->GetCompositor(); smoothness_tracker_ = compositor->RequestNewThroughputTracker(); smoothness_tracker_->Start( - metrics_util::ForSmoothness(base::BindRepeating([](int smoothness) { + metrics_util::ForSmoothnessV3(base::BindRepeating([](int smoothness) { UMA_HISTOGRAM_PERCENTAGE(kHomescreenAnimationHistogram, smoothness); }))); }
diff --git a/ash/app_list/app_list_presenter_impl.cc b/ash/app_list/app_list_presenter_impl.cc index b0a426fa..5f7c4cb2 100644 --- a/ash/app_list/app_list_presenter_impl.cc +++ b/ash/app_list/app_list_presenter_impl.cc
@@ -475,7 +475,7 @@ if (settings.has_value() && transition.has_value()) { view_->OnTabletModeAnimationTransitionNotified(*transition); reporter.emplace(settings->GetAnimator(), - metrics_util::ForSmoothness( + metrics_util::ForSmoothnessV3( view_->GetStateTransitionMetricsReportCallback())); }
diff --git a/ash/app_list/views/app_list_bubble_apps_page.cc b/ash/app_list/views/app_list_bubble_apps_page.cc index eea5608..2cc43f0c 100644 --- a/ash/app_list/views/app_list_bubble_apps_page.cc +++ b/ash/app_list/views/app_list_bubble_apps_page.cc
@@ -302,7 +302,7 @@ // handled in AppListBubbleView, so track overall smoothness here. ui::AnimationThroughputReporter reporter( scrollable_apps_grid_view_->layer()->GetAnimator(), - metrics_util::ForSmoothness(base::BindRepeating([](int value) { + metrics_util::ForSmoothnessV3(base::BindRepeating([](int value) { // This histogram name is used in Tast tests. Do not rename. base::UmaHistogramPercentage( "Apps.ClamshellLauncher.AnimationSmoothness.OpenAppsPage", value); @@ -397,7 +397,7 @@ ui::AnimationThroughputReporter reporter( scroll_contents->layer()->GetAnimator(), - metrics_util::ForSmoothness(base::BindRepeating([](int value) { + metrics_util::ForSmoothnessV3(base::BindRepeating([](int value) { base::UmaHistogramPercentage( "Apps.ClamshellLauncher.AnimationSmoothness.ShowAppsPage", value); }))); @@ -464,7 +464,7 @@ ui::AnimationThroughputReporter reporter( scroll_contents->layer()->GetAnimator(), - metrics_util::ForSmoothness(base::BindRepeating([](int value) { + metrics_util::ForSmoothnessV3(base::BindRepeating([](int value) { base::UmaHistogramPercentage( "Apps.ClamshellLauncher.AnimationSmoothness.HideAppsPage", value); })));
diff --git a/ash/app_list/views/app_list_bubble_view.cc b/ash/app_list/views/app_list_bubble_view.cc index f8f94988..6fcfd2e 100644 --- a/ash/app_list/views/app_list_bubble_view.cc +++ b/ash/app_list/views/app_list_bubble_view.cc
@@ -405,7 +405,7 @@ ui::AnimationThroughputReporter reporter( layer()->GetAnimator(), - metrics_util::ForSmoothness(base::BindRepeating([](int value) { + metrics_util::ForSmoothnessV3(base::BindRepeating([](int value) { base::UmaHistogramPercentage( "Apps.ClamshellLauncher.AnimationSmoothness.Open", value); }))); @@ -479,7 +479,7 @@ ui::AnimationThroughputReporter reporter( layer()->GetAnimator(), - metrics_util::ForSmoothness(base::BindRepeating([](int value) { + metrics_util::ForSmoothnessV3(base::BindRepeating([](int value) { base::UmaHistogramPercentage( "Apps.ClamshellLauncher.AnimationSmoothness.Close", value); })));
diff --git a/ash/app_list/views/app_list_folder_view.cc b/ash/app_list/views/app_list_folder_view.cc index 26ba73c..cbec4cb 100644 --- a/ash/app_list/views/app_list_folder_view.cc +++ b/ash/app_list/views/app_list_folder_view.cc
@@ -785,7 +785,7 @@ show_hide_metrics_tracker_ = GetWidget()->GetCompositor()->RequestNewThroughputTracker(); show_hide_metrics_tracker_->Start( - metrics_util::ForSmoothness(base::BindRepeating([](int smoothness) { + metrics_util::ForSmoothnessV3(base::BindRepeating([](int smoothness) { UMA_HISTOGRAM_PERCENTAGE( "Apps.AppListFolder.ShowHide.AnimationSmoothness", smoothness); })));
diff --git a/ash/app_list/views/app_list_item_view.cc b/ash/app_list/views/app_list_item_view.cc index 8deeb0b..e9b290a 100644 --- a/ash/app_list/views/app_list_item_view.cc +++ b/ash/app_list/views/app_list_item_view.cc
@@ -798,6 +798,12 @@ return app_list_config_->folder_icon_size(); } if (is_promise_app_ && features::ArePromiseIconsEnabled() && item_weak_) { + // Placeholder icons do not change size between states. + if (icon_image_model_.IsVectorIcon() || + (ShouldUseFallbackIconImageModel() && + fallback_icon_image_model_.IsVectorIcon())) { + return gfx::Size(kPlaceholderIconDimension, kPlaceholderIconDimension); + } return GetPreferredIconSizeForProgressRing(); } @@ -883,13 +889,8 @@ } gfx::Size AppListItemView::GetPreferredIconSizeForProgressRing() const { - DCHECK(is_promise_app_); + DCHECK(is_promise_app_ || ShouldUseFallbackIconImageModel()); CHECK(item_weak_); - // Placeholder icons do not change size between states. - // TODO(b/314251625): Evaluate the correct size for icons across spec. - if (icon_image_model_.IsVectorIcon()) { - return gfx::Size(kPlaceholderIconDimension, kPlaceholderIconDimension); - } switch (item_weak_->app_status()) { case AppStatus::kPending: @@ -919,6 +920,7 @@ layer()->SetTransform(gfx::Transform()); if (progress_indicator_) { UpdateProgressRingBounds(); + progress_indicator_->layer()->SetTransform(gfx::Transform()); } } @@ -1006,6 +1008,9 @@ const gfx::Transform scale_transform = gfx::GetScaleTransform( GetIconView()->bounds().CenterPoint(), 1 / kDragDropAppIconScale); layer()->SetTransform(scale_transform); + if (progress_indicator_) { + progress_indicator_->layer()->SetTransform(scale_transform); + } } else if (drag_state_ != DragState::kNone) { // If a drag view has been created for this icon, the item transition to // target bounds is handled by the apps grid view bounds animator. At the @@ -1023,13 +1028,20 @@ : gfx::Tween::EASE_OUT_2); if (scale_up) { layer()->SetTransform(gfx::Transform()); + if (progress_indicator_) { + progress_indicator_->layer()->SetTransform(gfx::Transform()); + } } else { if (drag_state_ == DragState::kNone) { // To avoid poor quality icons, update icon image with the correct scale // after the transform animation is completed. settings.AddObserver(this); - layer()->SetTransform(gfx::GetScaleTransform( - GetContentsBounds().CenterPoint(), 1 / kDragDropAppIconScale)); + const gfx::Transform reverse_scale_transform = gfx::GetScaleTransform( + GetContentsBounds().CenterPoint(), 1 / kDragDropAppIconScale); + layer()->SetTransform(reverse_scale_transform); + if (progress_indicator_) { + progress_indicator_->layer()->SetTransform(reverse_scale_transform); + } } } } @@ -2206,6 +2218,20 @@ gfx::Rect progress_bounds = gfx::Rect( views::View::ConvertRectToTarget(icon_, this, icon_->GetImageBounds())); + const gfx::Size promise_icon_preferred_size = gfx::ScaleToRoundedSize( + GetPreferredIconSizeForProgressRing(), icon_scale_); + + // If the icon is smaller than the expected icon size (i,e for placeholder + // icons), add padding to ensure the overall size of the promise icon is + // correct regardless of the image icon size. + progress_bounds.Inset(gfx::Insets::VH( + std::max( + 0, + (progress_bounds.width() - promise_icon_preferred_size.width()) / 2), + std::max( + 0, (progress_bounds.height() - promise_icon_preferred_size.height()) / + 2))); + const gfx::Insets progress_ring_padding = icon_image_model_.IsVectorIcon() || item()->app_status() != AppStatus::kPending
diff --git a/ash/app_list/views/app_list_item_view_pixeltest.cc b/ash/app_list/views/app_list_item_view_pixeltest.cc index 7831137..ec9de89c 100644 --- a/ash/app_list/views/app_list_item_view_pixeltest.cc +++ b/ash/app_list/views/app_list_item_view_pixeltest.cc
@@ -427,7 +427,7 @@ EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnPrimaryScreen( base::JoinString({"promise_app_waiting", GenerateScreenshotName()}, "."), - /*revision_number=*/1, GetItemViewAt(0), GetItemViewAt(1))); + /*revision_number=*/2, GetItemViewAt(0), GetItemViewAt(1))); } TEST_P(AppListViewPromiseAppPixelTest, PromiseAppInstalling) { @@ -455,7 +455,7 @@ EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnPrimaryScreen( base::JoinString({"promise_app_installing", GenerateScreenshotName()}, "."), - /*revision_number=*/1, GetItemViewAt(0), GetItemViewAt(1))); + /*revision_number=*/2, GetItemViewAt(0), GetItemViewAt(1))); } class AppListItemViewWebAppShortcutPixelTest
diff --git a/ash/app_list/views/apps_grid_view.cc b/ash/app_list/views/apps_grid_view.cc index 1453beb..8c27b7fa 100644 --- a/ash/app_list/views/apps_grid_view.cc +++ b/ash/app_list/views/apps_grid_view.cc
@@ -1625,7 +1625,7 @@ item_reorder_animation_tracker_ = layer()->GetCompositor()->RequestNewThroughputTracker(); item_reorder_animation_tracker_->Start( - metrics_util::ForSmoothness(base::BindRepeating( + metrics_util::ForSmoothnessV3(base::BindRepeating( &ReportItemDragReorderAnimationSmoothness, IsTabletMode()))); } @@ -2453,7 +2453,7 @@ grid_animation_status_ = AppListGridAnimationStatus::kReorderFadeOut; reorder_animation_tracker_.emplace( layer()->GetCompositor()->RequestNewThroughputTracker()); - reorder_animation_tracker_->Start(metrics_util::ForSmoothness( + reorder_animation_tracker_->Start(metrics_util::ForSmoothnessV3( base::BindRepeating(&ReportReorderAnimationSmoothness, IsTabletMode()))); views::AnimationBuilder animation_builder;
diff --git a/ash/app_list/views/assistant/assistant_page_view.cc b/ash/app_list/views/assistant/assistant_page_view.cc index 2cddcb3..077943eb4 100644 --- a/ash/app_list/views/assistant/assistant_page_view.cc +++ b/ash/app_list/views/assistant/assistant_page_view.cc
@@ -278,7 +278,7 @@ ui::AnimationThroughputReporter reporter( settings->GetAnimator(), - metrics_util::ForSmoothness(base::BindRepeating([](int value) { + metrics_util::ForSmoothnessV3(base::BindRepeating([](int value) { base::UmaHistogramPercentage( "Ash.Assistant.AnimationSmoothness.ResizeAssistantPageView", value);
diff --git a/ash/app_list/views/assistant/assistant_page_view_unittest.cc b/ash/app_list/views/assistant/assistant_page_view_unittest.cc index be70993..a95ef7d 100644 --- a/ash/app_list/views/assistant/assistant_page_view_unittest.cc +++ b/ash/app_list/views/assistant/assistant_page_view_unittest.cc
@@ -388,8 +388,38 @@ EXPECT_FALSE(current_interaction().has_value()); } +TEST_F(AssistantPageViewTest, ShouldNotShowOptInViewWithZeroStateView) { + ShowAssistantUi(); + + // When Launcher Search IPH is enabled, there is no suggestion or opt-in chips + // on the zero state page. + const views::View* suggestion_chips = suggestion_chip_container(); + const views::View* opt_in = opt_in_view(); + + SetConsentStatus(ConsentStatus::kUnauthorized); + EXPECT_FALSE(opt_in->IsDrawn()); + EXPECT_FALSE(suggestion_chips->IsDrawn()); + + SetConsentStatus(ConsentStatus::kNotFound); + EXPECT_FALSE(opt_in->IsDrawn()); + EXPECT_FALSE(suggestion_chips->IsDrawn()); + + SetConsentStatus(ConsentStatus::kUnknown); + EXPECT_FALSE(opt_in->IsDrawn()); + EXPECT_FALSE(suggestion_chips->IsDrawn()); + + SetConsentStatus(ConsentStatus::kActivityControlAccepted); + EXPECT_FALSE(opt_in->IsDrawn()); + EXPECT_FALSE(suggestion_chips->IsDrawn()); +} + TEST_F(AssistantPageViewTest, ShouldShowOptInViewUnlessUserHasGivenConsent) { ShowAssistantUi(); + + // When Launcher Search IPH is enabled and it is not in zero state view, we + // show the suggestion or opt-in chips as needed. + MockTextInteraction().WithTextResponse("The response"); + const views::View* suggestion_chips = suggestion_chip_container(); const views::View* opt_in = opt_in_view(); @@ -587,11 +617,13 @@ EXPECT_TRUE(input_text_field()->GetText().empty()); } -TEST_F(AssistantPageViewTest, ShouldHaveConversationStarters) { +TEST_F(AssistantPageViewTest, ShouldNotHaveConversationStarters) { ShowAssistantUi(); EXPECT_FALSE(onboarding_view()->IsDrawn()); - EXPECT_FALSE(GetSuggestionChips().empty()); + + // When Launcher Search IPH is enabled, there is no suggestion chips. + EXPECT_TRUE(GetSuggestionChips().empty()); } TEST_F(AssistantPageViewTest, ShouldHavePopulatedSuggestionChips) {
diff --git a/ash/app_list/views/paged_apps_grid_view.cc b/ash/app_list/views/paged_apps_grid_view.cc index adc5b6d..3627a656 100644 --- a/ash/app_list/views/paged_apps_grid_view.cc +++ b/ash/app_list/views/paged_apps_grid_view.cc
@@ -596,7 +596,7 @@ pagination_metrics_tracker_ = GetWidget()->GetCompositor()->RequestNewThroughputTracker(); - pagination_metrics_tracker_->Start(metrics_util::ForSmoothness( + pagination_metrics_tracker_->Start(metrics_util::ForSmoothnessV3( base::BindRepeating(&ReportPaginationSmoothness))); } @@ -835,7 +835,7 @@ for (auto& background_card : background_cards_) { reporters.push_back(std::make_unique<ui::AnimationThroughputReporter>( background_card->layer()->GetAnimator(), - metrics_util::ForSmoothness(base::BindRepeating( + metrics_util::ForSmoothnessV3(base::BindRepeating( &ReportCardifiedSmoothness, cardified_state_)))); }
diff --git a/ash/assistant/assistant_setup_controller_unittest.cc b/ash/assistant/assistant_setup_controller_unittest.cc index b4d4f24..45e01e2 100644 --- a/ash/assistant/assistant_setup_controller_unittest.cc +++ b/ash/assistant/assistant_setup_controller_unittest.cc
@@ -28,6 +28,10 @@ ShowAssistantUi(AssistantEntryPoint::kUnspecified); EXPECT_TRUE(IsVisible()); + // When Launcher Search IPH is enabled and it is not in zero state view, we + // show the opt-in chips as needed. + MockTextInteraction().WithTextResponse("The response"); + SetConsentStatus(assistant::prefs::ConsentStatus::kUnknown); EXPECT_TRUE(opt_in_view()->GetVisible()); @@ -43,6 +47,12 @@ ShowAssistantUi(AssistantEntryPoint::kUnspecified); EXPECT_TRUE(IsVisible()); + // When Launcher Search IPH is enabled and it is not in zero state view, we + // show the opt-in chips as needed. + // Show Assistant UI in text mode, which is required to set text query. + TapOnAndWait(keyboard_input_toggle()); + MockTextInteraction().WithTextResponse("The response"); + SetConsentStatus(assistant::prefs::ConsentStatus::kUnknown); EXPECT_TRUE(opt_in_view()->GetVisible()); @@ -56,6 +66,10 @@ ShowAssistantUi(AssistantEntryPoint::kUnspecified); EXPECT_TRUE(IsVisible()); + // When Launcher Search IPH is enabled and it is not in zero state view, we + // show the opt-in chips as needed. + MockTextInteraction().WithTextResponse("The response"); + SetConsentStatus(assistant::prefs::ConsentStatus::kUnknown); EXPECT_TRUE(opt_in_view()->GetVisible()); @@ -73,6 +87,10 @@ ShowAssistantUi(AssistantEntryPoint::kUnspecified); EXPECT_TRUE(IsVisible()); + // When Launcher Search IPH is enabled and it is not in zero state view, we + // show the opt-in chips as needed. + MockTextInteraction().WithTextResponse("The response"); + SetConsentStatus(assistant::prefs::ConsentStatus::kUnknown); EXPECT_TRUE(opt_in_view()->GetVisible());
diff --git a/ash/assistant/ui/main_stage/assistant_zero_state_view_unittest.cc b/ash/assistant/ui/main_stage/assistant_zero_state_view_unittest.cc index 7651ce78..c7cf0570 100644 --- a/ash/assistant/ui/main_stage/assistant_zero_state_view_unittest.cc +++ b/ash/assistant/ui/main_stage/assistant_zero_state_view_unittest.cc
@@ -87,13 +87,13 @@ SetTabletMode(true); ShowAssistantUi(); - // The onboarding and greeting views are shown in a mutually exclusive way. - // An onboarding view should be shown instead of a greeting label. + // When Launcher Search IPH is enabled, both onboarding and greeting views are + // not visible in tablet mode. const views::View* onboarding_view = page_view()->GetViewByID(AssistantViewID::kOnboardingView); ASSERT_TRUE(onboarding_view); - EXPECT_TRUE(onboarding_view->GetVisible()); - EXPECT_TRUE(onboarding_view->IsDrawn()); + EXPECT_FALSE(onboarding_view->GetVisible()); + EXPECT_FALSE(onboarding_view->IsDrawn()); const views::View* greeting_label = page_view()->GetViewByID(AssistantViewID::kGreetingLabel); @@ -110,8 +110,8 @@ SetTabletMode(true); ShowAssistantUi(); - // The onboarding and greeting views are shown in a mutually exclusive way. - // A greeting label should be shown instead of an onboarding view. + // When Launcher Search IPH is enabled, both onboarding and greeting views are + // not visible in tablet mode. views::View* onboarding_view = page_view()->GetViewByID(AssistantViewID::kOnboardingView); ASSERT_TRUE(onboarding_view); @@ -121,8 +121,8 @@ const views::View* greeting_label = page_view()->GetViewByID(AssistantViewID::kGreetingLabel); ASSERT_TRUE(greeting_label); - EXPECT_TRUE(greeting_label->GetVisible()); - EXPECT_TRUE(greeting_label->IsDrawn()); + EXPECT_FALSE(greeting_label->GetVisible()); + EXPECT_FALSE(greeting_label->IsDrawn()); } TEST_F(AssistantZeroStateViewUnittest, OnboardingViewIsVisible) {
diff --git a/ash/assistant/util/animation_util.cc b/ash/assistant/util/animation_util.cc index 7b30100..22b51ed 100644 --- a/ash/assistant/util/animation_util.cc +++ b/ash/assistant/util/animation_util.cc
@@ -123,7 +123,7 @@ std::optional<ui::AnimationThroughputReporter> reporter; if (smoothness_callback) { - reporter.emplace(layer_animator, ash::metrics_util::ForSmoothness( + reporter.emplace(layer_animator, ash::metrics_util::ForSmoothnessV3( smoothness_callback.value())); } layer_animator->StartAnimation(layer_animation_sequence);
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc index 26f1478..b8f23ed5 100644 --- a/ash/constants/ash_features.cc +++ b/ash/constants/ash_features.cc
@@ -2607,7 +2607,7 @@ // Enables the consumer and enterprise support for provisioning eSIM profiles // using Subscription Manager Discovery Service (SM-DS). This flag is a no-op // unless the SmdsDbusMigration flag is enabled. -BASE_FEATURE(kSmdsSupport, "SmdsSupport", base::FEATURE_DISABLED_BY_DEFAULT); +BASE_FEATURE(kSmdsSupport, "SmdsSupport", base::FEATURE_ENABLED_BY_DEFAULT); // Controls whether the snap group feature is enabled or not. BASE_FEATURE(kSnapGroup, "SnapGroup", base::FEATURE_DISABLED_BY_DEFAULT);
diff --git a/ash/metrics/login_unlock_throughput_recorder.cc b/ash/metrics/login_unlock_throughput_recorder.cc index e7118e6..f658feb 100644 --- a/ash/metrics/login_unlock_throughput_recorder.cc +++ b/ash/metrics/login_unlock_throughput_recorder.cc
@@ -109,8 +109,8 @@ int duration_ms = (base::TimeTicks::Now() - start).InMilliseconds(); int smoothness, jank; - smoothness = metrics_util::CalculateSmoothness(data); - jank = metrics_util::CalculateJank(data); + smoothness = metrics_util::CalculateSmoothnessV3(data); + jank = metrics_util::CalculateJankV3(data); std::string suffix = GetDeviceModeSuffix(); base::UmaHistogramPercentage(smoothness_name + suffix, smoothness); @@ -163,7 +163,7 @@ return; } - const int smoothness = metrics_util::CalculateSmoothness(data); + const int smoothness = metrics_util::CalculateSmoothnessV3(data); const std::string suffix = GetDeviceModeSuffix(); base::UmaHistogramPercentage(smoothness_name + suffix, smoothness);
diff --git a/ash/public/cpp/metrics_util.cc b/ash/public/cpp/metrics_util.cc index a878b69..8befb5c8 100644 --- a/ash/public/cpp/metrics_util.cc +++ b/ash/public/cpp/metrics_util.cc
@@ -45,7 +45,6 @@ // Calculates smoothness from |throughput| and sends to |callback|. void ForwardSmoothness(base::TimeTicks start_tick, SmoothnessCallback callback, - bool use_v3, const cc::FrameSequenceMetrics::CustomReportData& data) { bool animation_in_test = ui::ScopedAnimationDurationScaleMode::duration_multiplier() != @@ -57,13 +56,9 @@ // * frame_expected == 1 && frames_produced == 0 // when there is one BeginFrame but no frame generated between // start and stop; should not included this case in tests. - if (use_v3 && (!data.frames_expected_v3 || - (!animation_in_test && data.frames_expected_v3 == 1 && - data.frames_expected_v3 == data.frames_dropped_v3))) { - return; - } else if (!data.frames_expected || - (!animation_in_test && data.frames_expected == 1 && - data.frames_produced == 0)) { + if (!data.frames_expected_v3 || + (!animation_in_test && data.frames_expected_v3 == 1 && + data.frames_expected_v3 == data.frames_dropped_v3)) { return; } @@ -72,8 +67,7 @@ constexpr int kLowSmoothness = 20; const base::TimeDelta duration = base::TimeTicks::Now() - start_tick; - const int smoothness = - use_v3 ? CalculateSmoothnessV3(data) : CalculateSmoothness(data); + const int smoothness = CalculateSmoothnessV3(data); if (duration > kLongAnimation) { VLOG(1) << "Ash system animation takes longer than usual, duration= " @@ -88,24 +82,11 @@ } // namespace -ReportCallback ForSmoothness(SmoothnessCallback callback, - bool exclude_from_data_collection) { - const base::TimeTicks now = base::TimeTicks::Now(); - auto forward_smoothness = base::BindRepeating( - &ForwardSmoothness, now, std::move(callback), /*use_v3=*/false); - if (!g_data_collection_enabled || exclude_from_data_collection) { - return forward_smoothness; - } - - return base::BindRepeating(&CollectDataAndForwardReport, now, - std::move(forward_smoothness)); -} - ReportCallback ForSmoothnessV3(SmoothnessCallback callback, bool exclude_from_data_collection) { const base::TimeTicks now = base::TimeTicks::Now(); - auto forward_smoothness = base::BindRepeating( - &ForwardSmoothness, now, std::move(callback), /*use_v3=*/true); + auto forward_smoothness = + base::BindRepeating(&ForwardSmoothness, now, std::move(callback)); if (!g_data_collection_enabled || exclude_from_data_collection) return forward_smoothness; @@ -130,27 +111,16 @@ return data; } -int CalculateSmoothness( - const cc::FrameSequenceMetrics::CustomReportData& data) { - DCHECK(data.frames_expected); - return std::floor(100.0f * data.frames_produced / data.frames_expected); -} - int CalculateSmoothnessV3( const cc::FrameSequenceMetrics::CustomReportData& data) { - DCHECK(data.frames_expected); + DCHECK(data.frames_expected_v3); return std::floor(100.0f * (data.frames_expected_v3 - data.frames_dropped_v3) / data.frames_expected_v3); } -int CalculateJank(const cc::FrameSequenceMetrics::CustomReportData& data) { - DCHECK(data.frames_expected); - return std::floor(100.0f * data.jank_count / data.frames_expected); -} - int CalculateJankV3(const cc::FrameSequenceMetrics::CustomReportData& data) { - DCHECK(data.frames_expected); + DCHECK(data.frames_expected_v3); return std::floor(100.0f * data.jank_count_v3 / data.frames_expected_v3); }
diff --git a/ash/public/cpp/metrics_util.h b/ash/public/cpp/metrics_util.h index 5f62289..603cfe0d 100644 --- a/ash/public/cpp/metrics_util.h +++ b/ash/public/cpp/metrics_util.h
@@ -35,11 +35,6 @@ // cc::FrameSequenceMetrics::ThroughputData, calculates the smoothness // out of it and forward it to the smoothness report callback. ASH_PUBLIC_EXPORT ReportCallback -ForSmoothness(SmoothnessCallback callback, - bool exclude_from_data_collection = false); - -// As ForSmoothness, but using the validated V3 graphics smoothness metrics. -ASH_PUBLIC_EXPORT ReportCallback ForSmoothnessV3(SmoothnessCallback callback, bool exclude_from_data_collection = false); @@ -54,14 +49,10 @@ ASH_PUBLIC_EXPORT std::vector<AnimationData> GetCollectedData(); // Returns smoothness calculated from given data. -ASH_PUBLIC_EXPORT int CalculateSmoothness( - const cc::FrameSequenceMetrics::CustomReportData& data); ASH_PUBLIC_EXPORT int CalculateSmoothnessV3( const cc::FrameSequenceMetrics::CustomReportData& data); // Returns jank percentage calculated from given data. -ASH_PUBLIC_EXPORT int CalculateJank( - const cc::FrameSequenceMetrics::CustomReportData& data); ASH_PUBLIC_EXPORT int CalculateJankV3( const cc::FrameSequenceMetrics::CustomReportData& data);
diff --git a/ash/public/cpp/metrics_util_unittest.cc b/ash/public/cpp/metrics_util_unittest.cc index 1a1d3a15..9f5ef97 100644 --- a/ash/public/cpp/metrics_util_unittest.cc +++ b/ash/public/cpp/metrics_util_unittest.cc
@@ -15,8 +15,8 @@ TEST(MetricsUtilTest, ReportSmoothness) { cc::FrameSequenceMetrics::CustomReportData report_data; - report_data.frames_produced = 30; - report_data.frames_expected = 60; + report_data.frames_dropped_v3 = 30; + report_data.frames_expected_v3 = 60; constexpr int kExpectedSmoothes = 50; std::optional<int> reported_smoothness; @@ -48,7 +48,7 @@ reported_smoothness.reset(); ReportCallback report_callback = - ForSmoothness(smoothness_callback, test.exclude_from_collection); + ForSmoothnessV3(smoothness_callback, test.exclude_from_collection); report_callback.Run(report_data); ASSERT_TRUE(reported_smoothness.has_value()); EXPECT_EQ(kExpectedSmoothes, reported_smoothness.value());
diff --git a/ash/rotator/screen_rotation_animator.cc b/ash/rotator/screen_rotation_animator.cc index e26d3dda..aae8bbe 100644 --- a/ash/rotator/screen_rotation_animator.cc +++ b/ash/rotator/screen_rotation_animator.cc
@@ -440,7 +440,7 @@ } ui::AnimationThroughputReporter reporter( old_layer_animator, - metrics_util::ForSmoothness(base::BindRepeating([](int smoothness) { + metrics_util::ForSmoothnessV3(base::BindRepeating([](int smoothness) { UMA_HISTOGRAM_PERCENTAGE(kRotationAnimationSmoothness, smoothness); })));
diff --git a/ash/shelf/hotseat_transition_animator.cc b/ash/shelf/hotseat_transition_animator.cc index 684bb01..09dcac65 100644 --- a/ash/shelf/hotseat_transition_animator.cc +++ b/ash/shelf/hotseat_transition_animator.cc
@@ -144,7 +144,7 @@ ui::AnimationThroughputReporter reporter( shelf_bg_animation_setter.GetAnimator(), - metrics_util::ForSmoothness( + metrics_util::ForSmoothnessV3( base::BindRepeating(&ReportSmoothness, new_state))); shelf_widget_->GetAnimatingBackground()->SetTransform(transform);
diff --git a/ash/shelf/scrollable_shelf_view.cc b/ash/shelf/scrollable_shelf_view.cc index 500f76a..44db96dc 100644 --- a/ash/shelf/scrollable_shelf_view.cc +++ b/ash/shelf/scrollable_shelf_view.cc
@@ -672,7 +672,7 @@ ui::AnimationThroughputReporter reporter( animation_settings.GetAnimator(), - metrics_util::ForSmoothness( + metrics_util::ForSmoothnessV3( base::BindRepeating(&ReportSmoothness, Shell::Get()->IsInTabletMode(), Shell::Get()->app_list_controller()->IsVisible( GetDisplayIdForView(this)))));
diff --git a/ash/shelf/shelf.cc b/ash/shelf/shelf.cc index 30561c54..478ea42 100644 --- a/ash/shelf/shelf.cc +++ b/ash/shelf/shelf.cc
@@ -136,7 +136,7 @@ metrics_util::ReportCallback GetReportCallback(HotseatState target_state) { DCHECK_NE(target_state, HotseatState::kNone); - return metrics_util::ForSmoothness(base::BindRepeating( + return metrics_util::ForSmoothnessV3(base::BindRepeating( &HotseatWidgetAnimationMetricsReporter::ReportSmoothness, weak_ptr_factory_.GetWeakPtr(), target_state)); } @@ -191,7 +191,7 @@ metrics_util::ReportCallback GetReportCallback( HotseatState target_hotseat_state) { DCHECK_NE(target_hotseat_state, HotseatState::kNone); - return metrics_util::ForSmoothness(base::BindRepeating( + return metrics_util::ForSmoothnessV3(base::BindRepeating( &NavigationWidgetAnimationMetricsReporter::ReportSmoothness, weak_ptr_factory_.GetWeakPtr(), target_hotseat_state)); }
diff --git a/ash/shelf/shelf_navigation_widget.cc b/ash/shelf/shelf_navigation_widget.cc index dccccb0..4c4dd46 100644 --- a/ash/shelf/shelf_navigation_widget.cc +++ b/ash/shelf/shelf_navigation_widget.cc
@@ -236,7 +236,7 @@ metrics_util::ReportCallback GetReportCallback( HotseatState target_hotseat_state) { DCHECK_NE(target_hotseat_state, HotseatState::kNone); - return metrics_util::ForSmoothness(base::BindRepeating( + return metrics_util::ForSmoothnessV3(base::BindRepeating( &NavigationButtonAnimationMetricsReporter::ReportSmoothness, weak_ptr_factory_.GetWeakPtr(), target_hotseat_state)); }
diff --git a/ash/shelf/shelf_view.cc b/ash/shelf/shelf_view.cc index 038cf32..2c11d63 100644 --- a/ash/shelf/shelf_view.cc +++ b/ash/shelf/shelf_view.cc
@@ -1515,7 +1515,7 @@ move_animation_tracker_.emplace( GetWidget()->GetCompositor()->RequestNewThroughputTracker()); - move_animation_tracker_->Start(metrics_util::ForSmoothness( + move_animation_tracker_->Start(metrics_util::ForSmoothnessV3( base::BindRepeating(&ReportMoveAnimationSmoothness))); for (size_t i = 0; i < view_model_->view_size(); ++i) { @@ -1580,7 +1580,7 @@ ui::AnimationThroughputReporter reporter( fade_in_animation_settings.GetAnimator(), - metrics_util::ForSmoothness( + metrics_util::ForSmoothnessV3( base::BindRepeating(&ReportFadeInAnimationSmoothness))); view->layer()->SetOpacity(1.f); @@ -2375,7 +2375,7 @@ if (!fade_out_animation_tracker_) { fade_out_animation_tracker_.emplace( GetWidget()->GetCompositor()->RequestNewThroughputTracker()); - fade_out_animation_tracker_->Start(metrics_util::ForSmoothness( + fade_out_animation_tracker_->Start(metrics_util::ForSmoothnessV3( base::BindRepeating(&ReportFadeOutAnimationSmoothness))); }
diff --git a/ash/system/holding_space/holding_space_tray_bubble.cc b/ash/system/holding_space/holding_space_tray_bubble.cc index dd08e61..4abb6a07 100644 --- a/ash/system/holding_space/holding_space_tray_bubble.cc +++ b/ash/system/holding_space/holding_space_tray_bubble.cc
@@ -344,7 +344,7 @@ layout_animation_throughput_tracker_ = GetWidget()->GetCompositor()->RequestNewThroughputTracker(); layout_animation_throughput_tracker_->Start( - metrics_util::ForSmoothness(base::BindRepeating( + metrics_util::ForSmoothnessV3(base::BindRepeating( holding_space_metrics::RecordBubbleResizeAnimationSmoothness))); layout_animation_->Show(); }
diff --git a/ash/system/holding_space/holding_space_tray_icon.cc b/ash/system/holding_space/holding_space_tray_icon.cc index a066fe0..27195768 100644 --- a/ash/system/holding_space/holding_space_tray_icon.cc +++ b/ash/system/holding_space/holding_space_tray_icon.cc
@@ -121,7 +121,7 @@ void Start() { animation_throughput_tracker_.Start( - metrics_util::ForSmoothness(base::BindRepeating( + metrics_util::ForSmoothnessV3(base::BindRepeating( holding_space_metrics::RecordPodResizeAnimationSmoothness))); animation_.Show();
diff --git a/ash/system/mahi/mahi_panel_widget.cc b/ash/system/mahi/mahi_panel_widget.cc new file mode 100644 index 0000000..1e19d1b --- /dev/null +++ b/ash/system/mahi/mahi_panel_widget.cc
@@ -0,0 +1,93 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/system/mahi/mahi_panel_widget.h" + +#include <cstdint> +#include <memory> + +#include "ash/public/cpp/shell_window_ids.h" +#include "ash/public/cpp/style/color_provider.h" +#include "ash/shell.h" +#include "ui/aura/window.h" +#include "ui/chromeos/styles/cros_tokens_color_mappings.h" +#include "ui/compositor/layer.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/geometry/rounded_corners_f.h" +#include "ui/views/background.h" +#include "ui/views/controls/label.h" +#include "ui/views/highlight_border.h" +#include "ui/views/layout/box_layout_view.h" +#include "ui/views/widget/unique_widget_ptr.h" +#include "ui/views/widget/widget.h" + +namespace ash { + +namespace { + +constexpr int kPanelCornerRadius = 16; +constexpr int kPanelDefaultWidth = 340; +constexpr int kPanelDefaultHeight = 450; +constexpr int kPanelBoundsPadding = 8; + +gfx::Rect CalculateWidgetBounds(aura::Window* root_window) { + auto display = + display::Screen::GetScreen()->GetDisplayNearestWindow(root_window); + auto bottom_right = display.work_area().bottom_right(); + + // The panel is positioned at the bottom right corner of the screen. + // TODO(b/319476980): Make sure Mahi main panel bounds work when shelf + // alignment changes. + return gfx::Rect(bottom_right.x() - kPanelDefaultWidth - kPanelBoundsPadding, + bottom_right.y() - kPanelDefaultHeight - kPanelBoundsPadding, + kPanelDefaultWidth, kPanelDefaultHeight); +} + +} // namespace + +// static +views::UniqueWidgetPtr MahiPanelWidget::CreatePanelWidget(int64_t display_id) { + auto* root_window = Shell::GetRootWindowForDisplayId(display_id); + + views::Widget::InitParams params( + views::Widget::InitParams::TYPE_WINDOW_FRAMELESS); + params.name = "MahiPanel"; + // TODO(b/319467834): Decide what container this widget should be on. + params.parent = Shell::GetContainer(root_window, kShellWindowId_PipContainer); + + // The widget's view handles round corners and blur via layers. + params.opacity = views::Widget::InitParams::WindowOpacity::kTranslucent; + params.layer_type = ui::LAYER_NOT_DRAWN; + + views::UniqueWidgetPtr widget = + std::make_unique<views::Widget>(std::move(params)); + + // TODO(b/319329821): Finish creating main panel layout. + auto view = std::make_unique<views::BoxLayoutView>(); + view->SetBackground(views::CreateRoundedRectBackground( + cros_tokens::kCrosSysSystemBaseElevated, kPanelCornerRadius)); + + // Create a layer for the view for background blur and rounded corners. + view->SetPaintToLayer(); + view->layer()->SetRoundedCornerRadius( + gfx::RoundedCornersF{kPanelCornerRadius}); + view->layer()->SetFillsBoundsOpaquely(false); + view->layer()->SetIsFastRoundedCorner(true); + view->layer()->SetBackgroundBlur(ColorProvider::kBackgroundBlurSigma); + view->layer()->SetBackdropFilterQuality( + ColorProvider::kBackgroundBlurQuality); + view->SetBorder(std::make_unique<views::HighlightBorder>( + kPanelCornerRadius, + views::HighlightBorder::Type::kHighlightBorderOnShadow, + /*insets_type=*/views::HighlightBorder::InsetsType::kHalfInsets)); + + auto label = std::make_unique<views::Label>(u"Mahi Panel"); + view->AddChildView(std::move(label)); + + widget->SetContentsView(std::move(view)); + widget->SetBounds(CalculateWidgetBounds(root_window)); + return widget; +} + +} // namespace ash
diff --git a/ash/system/mahi/mahi_panel_widget.h b/ash/system/mahi/mahi_panel_widget.h new file mode 100644 index 0000000..cd9ffb1 --- /dev/null +++ b/ash/system/mahi/mahi_panel_widget.h
@@ -0,0 +1,28 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_SYSTEM_MAHI_MAHI_PANEL_WIDGET_H_ +#define ASH_SYSTEM_MAHI_MAHI_PANEL_WIDGET_H_ + +#include "ash/ash_export.h" +#include "ui/views/widget/widget.h" + +namespace views { +class UniqueWidgetPtr; +} // namespace views + +namespace ash { + +// The widget that contains the Mahi panel. +// TODO(b/319329379): Use this class in `CreatePanelWidget()` when resizing and +// closing capability is added. +class ASH_EXPORT MahiPanelWidget : public views::Widget { + public: + // Creates the Mahi panel widget within the display with `display_id`. + static views::UniqueWidgetPtr CreatePanelWidget(int64_t display_id); +}; + +} // namespace ash + +#endif // ASH_SYSTEM_MAHI_MAHI_PANEL_WIDGET_H_
diff --git a/ash/system/mahi/mahi_panel_widget_unittest.cc b/ash/system/mahi/mahi_panel_widget_unittest.cc new file mode 100644 index 0000000..b85f8ede --- /dev/null +++ b/ash/system/mahi/mahi_panel_widget_unittest.cc
@@ -0,0 +1,39 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/system/mahi/mahi_panel_widget.h" + +#include "ash/public/cpp/shelf_config.h" +#include "ash/test/ash_test_base.h" +#include "ui/aura/window.h" +#include "ui/display/display.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/views/widget/unique_widget_ptr.h" +#include "ui/views/widget/widget.h" + +namespace ash { +namespace { + +constexpr int kPanelDefaultWidth = 340; +constexpr int kPanelDefaultHeight = 450; +constexpr int kPanelBoundsShelfPadding = 8; + +using MahiPanelWidgetTest = AshTestBase; + +TEST_F(MahiPanelWidgetTest, WidgetBounds) { + auto* root_window = GetContext(); + auto widget = MahiPanelWidget::CreatePanelWidget(GetPrimaryDisplay().id()); + + auto bottom_right = root_window->bounds().bottom_right(); + EXPECT_EQ( + gfx::Rect( + bottom_right.x() - kPanelDefaultWidth - kPanelBoundsShelfPadding, + bottom_right.y() - kPanelDefaultHeight - + ShelfConfig::Get()->shelf_size() - kPanelBoundsShelfPadding, + kPanelDefaultWidth, kPanelDefaultHeight), + widget->GetRestoredBounds()); +} + +} // namespace +} // namespace ash
diff --git a/ash/system/notification_center/ash_message_popup_collection.cc b/ash/system/notification_center/ash_message_popup_collection.cc index 29de74a..86700dc 100644 --- a/ash/system/notification_center/ash_message_popup_collection.cc +++ b/ash/system/notification_center/ash_message_popup_collection.cc
@@ -433,7 +433,7 @@ animation_tracker_.emplace(last_pop_up_added_->GetWidget() ->GetCompositor() ->RequestNewThroughputTracker()); - animation_tracker_->Start(metrics_util::ForSmoothness( + animation_tracker_->Start(metrics_util::ForSmoothnessV3( base::BindRepeating(&ReportPopupAnimationSmoothness))); } ++popups_animating_;
diff --git a/ash/system/notification_center/message_center_utils.cc b/ash/system/notification_center/message_center_utils.cc index 4302f36..a5c1e8b 100644 --- a/ash/system/notification_center/message_center_utils.cc +++ b/ash/system/notification_center/message_center_utils.cc
@@ -216,7 +216,7 @@ ui::AnimationThroughputReporter reporter( view->layer()->GetAnimator(), - metrics_util::ForSmoothness(base::BindRepeating( + metrics_util::ForSmoothnessV3(base::BindRepeating( &ReportAnimationSmoothness, animation_histogram_name))); views::AnimationBuilder() @@ -251,7 +251,7 @@ ui::AnimationThroughputReporter reporter( view->layer()->GetAnimator(), - metrics_util::ForSmoothness(base::BindRepeating( + metrics_util::ForSmoothnessV3(base::BindRepeating( &ReportAnimationSmoothness, animation_histogram_name))); view->SetVisible(true); @@ -286,7 +286,7 @@ ui::AnimationThroughputReporter reporter( view->layer()->GetAnimator(), - metrics_util::ForSmoothness(base::BindRepeating( + metrics_util::ForSmoothnessV3(base::BindRepeating( &ReportAnimationSmoothness, animation_histogram_name))); gfx::Transform transform;
diff --git a/ash/system/notification_center/views/ash_notification_expand_button.cc b/ash/system/notification_center/views/ash_notification_expand_button.cc index 369b6a6a..505a6a0 100644 --- a/ash/system/notification_center/views/ash_notification_expand_button.cc +++ b/ash/system/notification_center/views/ash_notification_expand_button.cc
@@ -253,7 +253,7 @@ ui::AnimationThroughputReporter reporter( layer()->GetAnimator(), - metrics_util::ForSmoothness(base::BindRepeating( + metrics_util::ForSmoothnessV3(base::BindRepeating( [](const std::string& animation_histogram_name, int smoothness) { base::UmaHistogramPercentage(animation_histogram_name, smoothness); },
diff --git a/ash/system/notification_center/views/ash_notification_view.cc b/ash/system/notification_center/views/ash_notification_view.cc index 18e0ab64..e9178dd 100644 --- a/ash/system/notification_center/views/ash_notification_view.cc +++ b/ash/system/notification_center/views/ash_notification_view.cc
@@ -265,7 +265,7 @@ ui::AnimationThroughputReporter reporter( view->layer()->GetAnimator(), - ash::metrics_util::ForSmoothness(base::BindRepeating( + ash::metrics_util::ForSmoothnessV3(base::BindRepeating( [](const std::string& animation_histogram_name, int smoothness) { base::UmaHistogramPercentage(animation_histogram_name, smoothness); }, @@ -920,7 +920,7 @@ ui::AnimationThroughputReporter reporter( left_content()->layer()->GetAnimator(), - metrics_util::ForSmoothness(base::BindRepeating([](int smoothness) { + metrics_util::ForSmoothnessV3(base::BindRepeating([](int smoothness) { base::UmaHistogramPercentage( "Ash.NotificationView.ConvertSingleToGroup.FadeOut." "AnimationSmoothness", @@ -2092,12 +2092,13 @@ ui::AnimationThroughputReporter reporter( image_container_view()->layer()->GetAnimator(), - ash::metrics_util::ForSmoothness(base::BindRepeating([](int smoothness) { - base::UmaHistogramPercentage( - "Ash.NotificationView.ImageContainerView.ScaleDown." - "AnimationSmoothness", - smoothness); - }))); + ash::metrics_util::ForSmoothnessV3( + base::BindRepeating([](int smoothness) { + base::UmaHistogramPercentage( + "Ash.NotificationView.ImageContainerView.ScaleDown." + "AnimationSmoothness", + smoothness); + }))); views::AnimationBuilder() .SetPreemptionStrategy(
diff --git a/ash/system/notification_center/views/ash_notification_view_unittest.cc b/ash/system/notification_center/views/ash_notification_view_unittest.cc index c15c4e1..ce9e455 100644 --- a/ash/system/notification_center/views/ash_notification_view_unittest.cc +++ b/ash/system/notification_center/views/ash_notification_view_unittest.cc
@@ -312,11 +312,13 @@ ui::LayerAnimationStoppedWaiter animation_waiter; animation_waiter.Wait(view->layer()); - // Force a frame then wait, ensuring there is one more frame presented after - // animation finishes to allow animation throughput data to be passed from - // cc to ui. - compositor->ScheduleFullRedraw(); - EXPECT_TRUE(ui::WaitForNextFrameToBePresented(compositor)); + // Force frames and wait for all throughput trackers to be gone to allow + // animation throughput data to be passed from cc to ui. + while (compositor->has_throughput_trackers_for_testing()) { + compositor->ScheduleFullRedraw(); + std::ignore = ui::WaitForNextFrameToBePresented(compositor, + base::Milliseconds(500)); + } // Smoothness should be recorded. histograms.ExpectTotalCount(animation_histogram_name, data_point_count); @@ -860,7 +862,7 @@ TEST_F(AshNotificationViewTest, ExpandCollapseAnimationsRecordSmoothness) { // Enable animations. ui::ScopedAnimationDurationScaleMode duration( - ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION); + ui::ScopedAnimationDurationScaleMode::FAST_DURATION); message_center::MessageCenter::Get()->RemoveAllNotifications( /*by_user=*/true, message_center::MessageCenter::RemoveType::ALL); @@ -920,7 +922,7 @@ TEST_F(AshNotificationViewTest, ImageExpandCollapseAnimationsRecordSmoothness) { // Enable animations. ui::ScopedAnimationDurationScaleMode duration( - ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION); + ui::ScopedAnimationDurationScaleMode::FAST_DURATION); message_center::MessageCenter::Get()->RemoveAllNotifications( /*by_user=*/true, message_center::MessageCenter::RemoveType::ALL); @@ -987,7 +989,7 @@ // Enable animations. ui::ScopedAnimationDurationScaleMode duration( - ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION); + ui::ScopedAnimationDurationScaleMode::FAST_DURATION); message_center::MessageCenter::Get()->RemoveAllNotifications( /*by_user=*/true, message_center::MessageCenter::RemoveType::ALL); @@ -1052,7 +1054,7 @@ // Enable animations. ui::ScopedAnimationDurationScaleMode duration( - ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION); + ui::ScopedAnimationDurationScaleMode::FAST_DURATION); message_center::MessageCenter::Get()->RemoveAllNotifications( /*by_user=*/true, message_center::MessageCenter::RemoveType::ALL); @@ -1086,7 +1088,7 @@ // Enable animations. ui::ScopedAnimationDurationScaleMode duration( - ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION); + ui::ScopedAnimationDurationScaleMode::FAST_DURATION); message_center::MessageCenter::Get()->RemoveAllNotifications( /*by_user=*/true, message_center::MessageCenter::RemoveType::ALL); @@ -1128,7 +1130,7 @@ // Enable animations. ui::ScopedAnimationDurationScaleMode duration( - ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION); + ui::ScopedAnimationDurationScaleMode::FAST_DURATION); message_center::MessageCenter::Get()->RemoveAllNotifications( /*by_user=*/true, message_center::MessageCenter::RemoveType::ALL); @@ -1195,7 +1197,7 @@ // Enable animations. ui::ScopedAnimationDurationScaleMode duration( - ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION); + ui::ScopedAnimationDurationScaleMode::FAST_DURATION); auto* child_view = GetFirstGroupedChildNotificationView(notification_view); notification_view->RemoveGroupNotification(child_view->notification_id()); @@ -1306,7 +1308,7 @@ // Enable animations. ui::ScopedAnimationDurationScaleMode duration( - ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION); + ui::ScopedAnimationDurationScaleMode::FAST_DURATION); // Ensure a duplicate call to RemoveGroupNotification does not cause a crash. auto* child_view = GetFirstGroupedChildNotificationView(notification_view);
diff --git a/ash/system/notification_center/views/notification_list_view.cc b/ash/system/notification_center/views/notification_list_view.cc index 4b8d3a0..bb1d636 100644 --- a/ash/system/notification_center/views/notification_list_view.cc +++ b/ash/system/notification_center/views/notification_list_view.cc
@@ -77,7 +77,7 @@ } tracker.emplace(widget->GetCompositor()->RequestNewThroughputTracker()); - tracker->Start(ash::metrics_util::ForSmoothness( + tracker->Start(ash::metrics_util::ForSmoothnessV3( base::BindRepeating(&RecordAnimationSmoothness, histogram_name))); }
diff --git a/ash/system/power/tray_power.cc b/ash/system/power/tray_power.cc index 661cbdd..7cda6801 100644 --- a/ash/system/power/tray_power.cc +++ b/ash/system/power/tray_power.cc
@@ -103,7 +103,7 @@ icon_fg_token = cros_tokens::kCrosSysSystemOnPrimaryContainer; } else if (features::IsBatterySaverAvailable() && PowerStatus::Get()->IsBatterySaverActive()) { - icon_fg_token = cros_tokens::kCrosSysSystemWarningInverse; + icon_fg_token = cros_tokens::kCrosSysOnWarningContainer; } const SkColor icon_fg_color = GetColorProvider()->GetColor(icon_fg_token);
diff --git a/ash/system/privacy/privacy_indicators_tray_item_view.cc b/ash/system/privacy/privacy_indicators_tray_item_view.cc index c7f703be..e4382fe 100644 --- a/ash/system/privacy/privacy_indicators_tray_item_view.cc +++ b/ash/system/privacy/privacy_indicators_tray_item_view.cc
@@ -83,8 +83,8 @@ return; tracker.emplace(widget->GetCompositor()->RequestNewThroughputTracker()); - tracker->Start( - ash::metrics_util::ForSmoothness(base::BindRepeating([](int smoothness) { + tracker->Start(ash::metrics_util::ForSmoothnessV3( + base::BindRepeating([](int smoothness) { base::UmaHistogramPercentage( "Ash.PrivacyIndicators.AnimationSmoothness", smoothness); }))); @@ -111,7 +111,7 @@ ui::AnimationThroughputReporter reporter( view->layer()->GetAnimator(), - metrics_util::ForSmoothness(base::BindRepeating( + metrics_util::ForSmoothnessV3(base::BindRepeating( &StartReportLayerAnimationSmoothness, animation_histogram_name))); views::AnimationBuilder()
diff --git a/ash/system/time/calendar_metrics.cc b/ash/system/time/calendar_metrics.cc index 227b286..60def613 100644 --- a/ash/system/time/calendar_metrics.cc +++ b/ash/system/time/calendar_metrics.cc
@@ -113,7 +113,7 @@ // TODO(crbug.com/1297376): Add unit tests for animation metrics recording. return ui::AnimationThroughputReporter( view->layer()->GetAnimator(), - metrics_util::ForSmoothness(base::BindRepeating( + metrics_util::ForSmoothnessV3(base::BindRepeating( [](const std::string& animation_histogram_name, int smoothness) { base::UmaHistogramPercentage(animation_histogram_name, smoothness); },
diff --git a/ash/system/tray/tray_background_view.cc b/ash/system/tray/tray_background_view.cc index d9523ec..64841cac 100644 --- a/ash/system/tray/tray_background_view.cc +++ b/ash/system/tray/tray_background_view.cc
@@ -719,7 +719,7 @@ ui::AnimationThroughputReporter reporter( layer()->GetAnimator(), - metrics_util::ForSmoothness(base::BindRepeating([](int smoothness) { + metrics_util::ForSmoothnessV3(base::BindRepeating([](int smoothness) { DCHECK(0 <= smoothness && smoothness <= 100); base::UmaHistogramPercentage(kFadeInAnimationSmoothnessHistogramName, smoothness); @@ -790,7 +790,7 @@ ui::AnimationThroughputReporter reporter( layer()->GetAnimator(), - metrics_util::ForSmoothness(base::BindRepeating([](int smoothness) { + metrics_util::ForSmoothnessV3(base::BindRepeating([](int smoothness) { DCHECK(0 <= smoothness && smoothness <= 100); base::UmaHistogramPercentage(kBounceInAnimationSmoothnessHistogramName, smoothness); @@ -866,7 +866,7 @@ ui::AnimationThroughputReporter reporter( layer()->GetAnimator(), - metrics_util::ForSmoothness(base::BindRepeating([](int smoothness) { + metrics_util::ForSmoothnessV3(base::BindRepeating([](int smoothness) { DCHECK(0 <= smoothness && smoothness <= 100); base::UmaHistogramPercentage(kHideAnimationSmoothnessHistogramName, smoothness);
diff --git a/ash/system/tray/tray_item_view.cc b/ash/system/tray/tray_item_view.cc index 9694a8aa..fa916b1 100644 --- a/ash/system/tray/tray_item_view.cc +++ b/ash/system/tray/tray_item_view.cc
@@ -59,7 +59,7 @@ return; tracker.emplace(widget->GetCompositor()->RequestNewThroughputTracker()); - tracker->Start(ash::metrics_util::ForSmoothness( + tracker->Start(ash::metrics_util::ForSmoothnessV3( base::BindRepeating(&RecordAnimationSmoothness, histogram_name))); }
diff --git a/ash/system/tray/tray_item_view_unittest.cc b/ash/system/tray/tray_item_view_unittest.cc index 4cd0782..e4d1ffda 100644 --- a/ash/system/tray/tray_item_view_unittest.cc +++ b/ash/system/tray/tray_item_view_unittest.cc
@@ -104,10 +104,15 @@ TrayItemViewAnimationWaiter waiter(tray_item()); waiter.Wait(); - // Ensure there is one more frame presented after animation finishes to - // allow animation throughput data to be passed from cc to ui. - EXPECT_TRUE(ui::WaitForNextFrameToBePresented( - tray_item()->GetWidget()->GetCompositor())); + // Force frames and wait for all throughput trackers to be gone to allow + // animation throughput data to be passed from cc to ui. + ui::Compositor* const compositor = + tray_item()->GetWidget()->GetCompositor(); + while (compositor->has_throughput_trackers_for_testing()) { + compositor->ScheduleFullRedraw(); + std::ignore = ui::WaitForNextFrameToBePresented(compositor, + base::Milliseconds(500)); + } } views::Widget* widget() { return widget_.get(); }
diff --git a/ash/system/video_conference/bubble/return_to_app_panel.cc b/ash/system/video_conference/bubble/return_to_app_panel.cc index 1a2786c..0e71b41 100644 --- a/ash/system/video_conference/bubble/return_to_app_panel.cc +++ b/ash/system/video_conference/bubble/return_to_app_panel.cc
@@ -77,8 +77,8 @@ } tracker.emplace(widget->GetCompositor()->RequestNewThroughputTracker()); - tracker->Start( - ash::metrics_util::ForSmoothness(base::BindRepeating([](int smoothness) { + tracker->Start(ash::metrics_util::ForSmoothnessV3( + base::BindRepeating([](int smoothness) { base::UmaHistogramPercentage( "Ash.VideoConference.ReturnToAppPanel.BoundsChange." "AnimationSmoothness", @@ -103,7 +103,7 @@ ui::AnimationThroughputReporter reporter( view->layer()->GetAnimator(), - metrics_util::ForSmoothness(base::BindRepeating( + metrics_util::ForSmoothnessV3(base::BindRepeating( &StartReportLayerAnimationSmoothness, animation_histogram_name))); views::AnimationBuilder() @@ -137,7 +137,7 @@ ui::AnimationThroughputReporter reporter( view->layer()->GetAnimator(), - metrics_util::ForSmoothness(base::BindRepeating( + metrics_util::ForSmoothnessV3(base::BindRepeating( &StartReportLayerAnimationSmoothness, animation_histogram_name))); view->SetVisible(true);
diff --git a/ash/system/video_conference/effects/fake_video_conference_tray_effects_manager.h b/ash/system/video_conference/effects/fake_video_conference_tray_effects_manager.h index cd16d01..14fc006 100644 --- a/ash/system/video_conference/effects/fake_video_conference_tray_effects_manager.h +++ b/ash/system/video_conference/effects/fake_video_conference_tray_effects_manager.h
@@ -5,6 +5,7 @@ #ifndef ASH_SYSTEM_VIDEO_CONFERENCE_EFFECTS_FAKE_VIDEO_CONFERENCE_TRAY_EFFECTS_MANAGER_H_ #define ASH_SYSTEM_VIDEO_CONFERENCE_EFFECTS_FAKE_VIDEO_CONFERENCE_TRAY_EFFECTS_MANAGER_H_ +#include "ash/ash_export.h" #include "ash/system/video_conference/bubble/vc_tile_ui_controller.h" #include "ash/system/video_conference/effects/video_conference_tray_effects_manager.h" @@ -22,7 +23,7 @@ // default behavior of `GetUiControllerForEffectId()` can only support returning // a single tile UI controller for any given id. Once http://b/312496000 is // addressed, this class may no longer be needed. -class FakeVideoConferenceTrayEffectsManager +class ASH_EXPORT FakeVideoConferenceTrayEffectsManager : public VideoConferenceTrayEffectsManager { public: FakeVideoConferenceTrayEffectsManager();
diff --git a/ash/webui/common/resources/sea_pen/constants.ts b/ash/webui/common/resources/sea_pen/constants.ts index a12b3d1..bc47845 100644 --- a/ash/webui/common/resources/sea_pen/constants.ts +++ b/ash/webui/common/resources/sea_pen/constants.ts
@@ -7,7 +7,7 @@ import {isSeaPenTextInputEnabled} from './load_time_booleans.js'; -export const QUERY: string = 'Query'; +export type Query = 'Query'; /** * An interface for the data of a recent sea pen image. @@ -25,7 +25,7 @@ } export interface SeaPenTemplate { - id: string; + id: SeaPenTemplateId|Query; // `title` is the user-visible string in collection titles and breadcrumbs. title: string; preview: Url[]; @@ -38,9 +38,9 @@ export function getSeaPenTemplates(): SeaPenTemplate[] { // Generated by sea_pen_client_generator.py, do not edit. // TODO(b/318565684): Move generated code to a separate file. - const templates = [ + const templates: SeaPenTemplate[] = [ { - id: SeaPenTemplateId.kFlower.toString(), + id: SeaPenTemplateId.kFlower, title: 'Airbrush', text: `A radiant <${SeaPenTemplateChip.kFlowerColor}> <${ SeaPenTemplateChip.kFlowerType}> in bloom`, @@ -133,7 +133,7 @@ ]), }, { - id: SeaPenTemplateId.kMineral.toString(), + id: SeaPenTemplateId.kMineral, title: 'Minerals', text: `A close-up image of <${SeaPenTemplateChip.kMineralName}> with <${ SeaPenTemplateChip.kMineralColor}> hues`, @@ -282,7 +282,7 @@ ]), }, { - id: SeaPenTemplateId.kLandscape.toString(), + id: SeaPenTemplateId.kLandscape, title: 'Landscape', text: `A <${SeaPenTemplateChip.kLandscapeBiome}> landscape with <${ SeaPenTemplateChip.kLandscapeLighting}> lighting`, @@ -367,7 +367,7 @@ ]), }, { - id: SeaPenTemplateId.kScifi.toString(), + id: SeaPenTemplateId.kScifi, title: 'Scifi', text: `Otherworldly <${SeaPenTemplateChip.kScifiFeature}> in <${ SeaPenTemplateChip.kScifiColor}> colors`, @@ -464,7 +464,7 @@ ]), }, { - id: SeaPenTemplateId.kArt.toString(), + id: SeaPenTemplateId.kArt, title: 'Classic Art', text: `A painting of a <${SeaPenTemplateChip.kArtFeature}> in the <${ SeaPenTemplateChip.kArtMovement}> style`, @@ -621,7 +621,7 @@ ]), }, { - id: SeaPenTemplateId.kCharacters.toString(), + id: SeaPenTemplateId.kCharacters, title: 'Characters', text: `<${SeaPenTemplateChip.kCharactersColor}> <${ SeaPenTemplateChip.kCharactersSubjects}> on a <${ @@ -1092,7 +1092,7 @@ ]), }, { - id: SeaPenTemplateId.kTerrain.toString(), + id: SeaPenTemplateId.kTerrain, title: 'Terrain', text: `<${SeaPenTemplateChip.kTerrainFeature}> in shades of <${ SeaPenTemplateChip.kTerrainColor}>`, @@ -1193,7 +1193,7 @@ ]), }, { - id: SeaPenTemplateId.kCurious.toString(), + id: SeaPenTemplateId.kCurious, title: 'Curious World', text: `A <${SeaPenTemplateChip.kCuriousColor}> <${ SeaPenTemplateChip.kCuriousFeature}> with <${ @@ -1372,7 +1372,7 @@ ]), }, { - id: SeaPenTemplateId.kDreamscapes.toString(), + id: SeaPenTemplateId.kDreamscapes, title: 'Dreamscapes', text: `A surreal <${SeaPenTemplateChip.kDreamscapesObject}> made of <${ SeaPenTemplateChip.kDreamscapesMaterial}> in <${ @@ -1563,7 +1563,7 @@ ]), }, { - id: SeaPenTemplateId.kTranslucent.toString(), + id: SeaPenTemplateId.kTranslucent, title: 'Translucent', text: `Translucent <${SeaPenTemplateChip.kTranslucentItem}> in <${ SeaPenTemplateChip.kTranslucentColor}>`, @@ -1772,7 +1772,7 @@ }], title: 'Freeform', text: 'Freeform', - id: QUERY, + id: 'Query', options: new Map(), }); }
diff --git a/ash/webui/common/resources/sea_pen/sea_pen_images_element.ts b/ash/webui/common/resources/sea_pen/sea_pen_images_element.ts index 84d3a5e..01b12f8 100644 --- a/ash/webui/common/resources/sea_pen/sea_pen_images_element.ts +++ b/ash/webui/common/resources/sea_pen/sea_pen_images_element.ts
@@ -15,12 +15,13 @@ import 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.js'; import 'chrome://resources/cr_elements/icons.html.js'; -import {MantaStatusCode, SeaPenThumbnail} from './sea_pen.mojom-webui.js'; +import {Query} from './constants.js'; +import {MantaStatusCode, SeaPenTemplateId, SeaPenThumbnail} from './sea_pen.mojom-webui.js'; import {selectSeaPenWallpaper} from './sea_pen_controller.js'; import {getTemplate} from './sea_pen_images_element.html.js'; import {getSeaPenProvider} from './sea_pen_interface_provider.js'; import {WithSeaPenStore} from './sea_pen_store.js'; -import {isNonEmptyArray} from './sea_pen_utils.js'; +import {isNonEmptyArray, logSeaPenTemplateFeedback} from './sea_pen_utils.js'; export class SeaPenImagesElement extends WithSeaPenStore { static get is() { @@ -56,7 +57,7 @@ }; } - private templateId: string; + private templateId: SeaPenTemplateId|Query; private thumbnails_: SeaPenThumbnail[]|null; private thumbnailsLoading_: boolean; private pendingSelected_: SeaPenThumbnail|null; @@ -128,12 +129,41 @@ return thumbnail === pendingSelected; } + private getTemplateNameFromId_(templateId: SeaPenTemplateId|Query): string { + switch (templateId) { + case SeaPenTemplateId.kFlower: + return 'Flower'; + case SeaPenTemplateId.kMineral: + return 'Mineral'; + case SeaPenTemplateId.kLandscape: + return 'Landscape'; + case SeaPenTemplateId.kScifi: + return 'Scifi'; + case SeaPenTemplateId.kArt: + return 'Art'; + case SeaPenTemplateId.kCharacters: + return 'Characters'; + case SeaPenTemplateId.kTerrain: + return 'Terrain'; + case SeaPenTemplateId.kCurious: + return 'Curious'; + case SeaPenTemplateId.kDreamscapes: + return 'Dreamscapes'; + case SeaPenTemplateId.kTranslucent: + return 'Translucent'; + case 'Query': + return 'Query'; + } + } + private onClickThumbsUp_() { - // TODO(b/313667113): Implement thumbs up. + logSeaPenTemplateFeedback( + this.getTemplateNameFromId_(this.templateId), true); } private onClickThumbsDown_() { - // TODO(b/313667113): Implement thumbs down. + logSeaPenTemplateFeedback( + this.getTemplateNameFromId_(this.templateId), false); } }
diff --git a/ash/webui/common/resources/sea_pen/sea_pen_input_query_element.ts b/ash/webui/common/resources/sea_pen/sea_pen_input_query_element.ts index a23f1f00..e10ba36 100644 --- a/ash/webui/common/resources/sea_pen/sea_pen_input_query_element.ts +++ b/ash/webui/common/resources/sea_pen/sea_pen_input_query_element.ts
@@ -19,7 +19,6 @@ import {MAXIMUM_SEARCH_WALLPAPER_TEXT_BYTES, SeaPenQuery} from './sea_pen.mojom-webui.js'; import {assert} from 'chrome://resources/js/assert.js'; -import {QUERY} from './constants.js'; import {isSeaPenTextInputEnabled} from './load_time_booleans.js'; import {searchSeaPenThumbnails} from './sea_pen_controller.js'; import {getTemplate} from './sea_pen_input_query_element.html.js'; @@ -69,7 +68,7 @@ }; searchSeaPenThumbnails(query, getSeaPenProvider(), this.getStore()); SeaPenRouterElement.instance().goToRoute( - SeaPenPaths.RESULTS, {seaPenTemplateId: QUERY}); + SeaPenPaths.RESULTS, {seaPenTemplateId: 'Query'}); } private getSearchButtonText_(path: string|null): string {
diff --git a/ash/webui/common/resources/sea_pen/sea_pen_router_element.html b/ash/webui/common/resources/sea_pen/sea_pen_router_element.html index 87392cd..138b2bb 100644 --- a/ash/webui/common/resources/sea_pen/sea_pen_router_element.html +++ b/ash/webui/common/resources/sea_pen/sea_pen_router_element.html
@@ -11,6 +11,7 @@ position: relative; width: 100%; } + sea-pen-input-query, sea-pen-template-query { background-color: var(--cros-sys-app_base_shaded); @@ -20,11 +21,13 @@ top: 56px; z-index: 1; } + #seaPenBottomContainer { background-color: var(--cros-bg-color); grid-area: imagegrid; padding: 10px 0; } + div[class$='spacertop'] { background-color: var(--cros-sys-app_base_shaded); position: sticky; @@ -76,7 +79,7 @@ <sea-pen-recent-wallpapers></sea-pen-recent-wallpapers> </template> <template is="dom-if" if="[[shouldShowSeaPenImages_(relativePath_)]]"> - <sea-pen-images template-id="[[queryParams.seaPenTemplateId]]"> + <sea-pen-images template-id="[[getTemplateIdFromQueryParams_(queryParams_.seaPenTemplateId)]]"> </sea-pen-images> </template> </div>
diff --git a/ash/webui/common/resources/sea_pen/sea_pen_router_element.ts b/ash/webui/common/resources/sea_pen/sea_pen_router_element.ts index 1e5a8f4..06b7dd8 100644 --- a/ash/webui/common/resources/sea_pen/sea_pen_router_element.ts +++ b/ash/webui/common/resources/sea_pen/sea_pen_router_element.ts
@@ -12,8 +12,9 @@ import {assert} from 'chrome://resources/js/assert.js'; import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; -import {QUERY} from './constants.js'; +import {Query} from './constants.js'; import {isSeaPenEnabled, isSeaPenTextInputEnabled} from './load_time_booleans.js'; +import {SeaPenTemplateId} from './sea_pen.mojom-webui.js'; import {getTemplate} from './sea_pen_router_element.html.js'; export enum SeaPenPaths { @@ -73,8 +74,8 @@ instance = null; } - selectSeaPenTemplate(templateId: string) { - this.goToRoute(SeaPenPaths.ROOT, {seaPenTemplateId: templateId}); + selectSeaPenTemplate(templateId: SeaPenTemplateId|Query) { + this.goToRoute(SeaPenPaths.ROOT, {seaPenTemplateId: templateId.toString()}); } goToRoute(path: SeaPenPaths, queryParams: SeaPenQueryParams = {}) { @@ -125,14 +126,14 @@ return isSeaPenTextInputEnabled() && (relativePath === SeaPenPaths.ROOT || relativePath === SeaPenPaths.RESULTS) && - templateId === QUERY; + templateId === 'Query'; } private shouldShowTemplateQuery_( relativePath: string|null, templateId: string|null): boolean { return (relativePath === SeaPenPaths.ROOT || relativePath === SeaPenPaths.RESULTS) && - (!!templateId && templateId !== QUERY); + (!!templateId && templateId !== 'Query'); } private shouldShowSeaPenRoot_(relativePath: string|null): boolean { @@ -148,6 +149,14 @@ } return relativePath === SeaPenPaths.RESULTS; } + + private getTemplateIdFromQueryParams_(templateId: string): SeaPenTemplateId + |Query { + if (templateId === 'Query') { + return 'Query'; + } + return parseInt(templateId) as SeaPenTemplateId; + } } declare global {
diff --git a/ash/webui/common/resources/sea_pen/sea_pen_template_query_element.ts b/ash/webui/common/resources/sea_pen/sea_pen_template_query_element.ts index d1da6ae..9bbc860 100644 --- a/ash/webui/common/resources/sea_pen/sea_pen_template_query_element.ts +++ b/ash/webui/common/resources/sea_pen/sea_pen_template_query_element.ts
@@ -71,7 +71,7 @@ static get properties() { return { templateId: { - type: String, + type: SeaPenTemplateId, }, path: String, @@ -120,7 +120,7 @@ private computeSeaPenTemplate_(templateId: string|null) { const seaPenTemplates = getSeaPenTemplates(); const correctTemplate = seaPenTemplates.find( - (seaPenTemplate) => seaPenTemplate.id === templateId); + (seaPenTemplate) => seaPenTemplate.id.toString() === templateId); return correctTemplate as SeaPenTemplate; }
diff --git a/ash/webui/common/resources/sea_pen/sea_pen_utils.ts b/ash/webui/common/resources/sea_pen/sea_pen_utils.ts index efd6595..bfe33d8 100644 --- a/ash/webui/common/resources/sea_pen/sea_pen_utils.ts +++ b/ash/webui/common/resources/sea_pen/sea_pen_utils.ts
@@ -23,3 +23,9 @@ return !!obj && typeof obj === 'object' && 'path' in obj && typeof obj.path === 'string' && !!obj.path; } + +export function logSeaPenTemplateFeedback( + templateName: string, positiveFeedback: boolean) { + chrome.metricsPrivate.recordBoolean( + `Ash.SeaPen.${templateName}.UserFeedback`, positiveFeedback); +}
diff --git a/ash/webui/personalization_app/resources/js/personalization_breadcrumb_element.ts b/ash/webui/personalization_app/resources/js/personalization_breadcrumb_element.ts index e76debde..295378f 100644 --- a/ash/webui/personalization_app/resources/js/personalization_breadcrumb_element.ts +++ b/ash/webui/personalization_app/resources/js/personalization_breadcrumb_element.ts
@@ -21,6 +21,7 @@ import {assert} from 'chrome://resources/ash/common/assert.js'; import {getSeaPenTemplates, SeaPenTemplate} from 'chrome://resources/ash/common/sea_pen/constants.js'; import {isSeaPenEnabled} from 'chrome://resources/ash/common/sea_pen/load_time_booleans.js'; +import {SeaPenTemplateId} from 'chrome://resources/ash/common/sea_pen/sea_pen.mojom-webui.js'; import {isNonEmptyArray} from 'chrome://resources/ash/common/sea_pen/sea_pen_utils.js'; import {AnchorAlignment} from 'chrome://resources/cr_elements/cr_action_menu/cr_action_menu.js'; import {IronA11yKeysElement} from 'chrome://resources/polymer/v3_0/iron-a11y-keys/iron-a11y-keys.js'; @@ -230,7 +231,7 @@ breadcrumbs.push(this.i18n('seaPenLabel')); if (this.seaPenTemplateId && isNonEmptyArray(this.seaPenTemplates_)) { const template = this.seaPenTemplates_.find( - template => template.id === this.seaPenTemplateId); + template => template.id.toString() === this.seaPenTemplateId); if (template) { breadcrumbs.push(template.title); } @@ -316,9 +317,9 @@ return path === Paths.SEA_PEN_RESULTS && !!template; } - private getAriaSelected_(templateId: string, seaPenTemplateId: string): - 'true'|'false' { - return templateId === seaPenTemplateId ? 'true' : 'false'; + private getAriaSelected_( + templateId: SeaPenTemplateId, seaPenTemplateId: string): 'true'|'false' { + return templateId.toString() === seaPenTemplateId ? 'true' : 'false'; } private onHomeIconClick_() {
diff --git a/ash/webui/shimless_rma/resources/BUILD.gn b/ash/webui/shimless_rma/resources/BUILD.gn index b25390a6..a3d3357 100644 --- a/ash/webui/shimless_rma/resources/BUILD.gn +++ b/ash/webui/shimless_rma/resources/BUILD.gn
@@ -50,9 +50,9 @@ "onboarding_wait_for_manual_wp_disable_page.ts", "onboarding_wp_disable_complete_page.ts", "reboot_page.ts", - "reimaging_calibration_failed_page.js", - "reimaging_calibration_run_page.js", - "reimaging_calibration_setup_page.js", + "reimaging_calibration_failed_page.ts", + "reimaging_calibration_run_page.ts", + "reimaging_calibration_setup_page.ts", "reimaging_device_information_page.js", "reimaging_firmware_update_page.js", "reimaging_provisioning_page.js",
diff --git a/ash/webui/shimless_rma/resources/calibration_component_chip.ts b/ash/webui/shimless_rma/resources/calibration_component_chip.ts index 9d11d4d..9679d807 100644 --- a/ash/webui/shimless_rma/resources/calibration_component_chip.ts +++ b/ash/webui/shimless_rma/resources/calibration_component_chip.ts
@@ -12,14 +12,12 @@ import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {getTemplate} from './calibration_component_chip.html.js'; +import {CLICK_CALIBRATION_COMPONENT_BUTTON, ClickCalibrationComponentEvent} from './events.js'; import {modifyTabbableElement} from './shimless_rma_util.js'; - -export type ClickCalibrationComponentButtonEvent = CustomEvent<number>; - declare global { interface HTMLElementEventMap { - 'click-calibration-component-button': ClickCalibrationComponentButtonEvent; + [CLICK_CALIBRATION_COMPONENT_BUTTON]: ClickCalibrationComponentEvent; } }
diff --git a/ash/webui/shimless_rma/resources/events.ts b/ash/webui/shimless_rma/resources/events.ts index fe41834..5484203d 100644 --- a/ash/webui/shimless_rma/resources/events.ts +++ b/ash/webui/shimless_rma/resources/events.ts
@@ -32,6 +32,10 @@ export type OnSelectedChangedEvent = CustomEvent<{value: string}>; +export const CLICK_CALIBRATION_COMPONENT_BUTTON = + 'click-calibration-component-button'; +export type ClickCalibrationComponentEvent = CustomEvent<number>; + type ExtractDetail<T> = T extends CustomEvent<infer U>? U : never; /**
diff --git a/ash/webui/shimless_rma/resources/reimaging_calibration_failed_page.js b/ash/webui/shimless_rma/resources/reimaging_calibration_failed_page.ts similarity index 68% rename from ash/webui/shimless_rma/resources/reimaging_calibration_failed_page.js rename to ash/webui/shimless_rma/resources/reimaging_calibration_failed_page.ts index d2c8756..982da86 100644 --- a/ash/webui/shimless_rma/resources/reimaging_calibration_failed_page.js +++ b/ash/webui/shimless_rma/resources/reimaging_calibration_failed_page.ts
@@ -10,11 +10,15 @@ import './icons.html.js'; import './shimless_rma_shared.css.js'; -import {assert} from 'chrome://resources/ash/common/assert.js'; -import {I18nBehavior, I18nBehaviorInterface} from 'chrome://resources/ash/common/i18n_behavior.js'; -import {afterNextRender, html, mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {CrButtonElement} from 'chrome://resources/cr_elements/cr_button/cr_button.js'; +import {CrDialogElement} from 'chrome://resources/cr_elements/cr_dialog/cr_dialog.js'; +import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js'; +import {assert} from 'chrome://resources/js/assert.js'; +import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {CalibrationComponentChipElement} from './calibration_component_chip.js'; import {ComponentTypeToId} from './data.js'; +import {CLICK_CALIBRATION_COMPONENT_BUTTON, ClickCalibrationComponentEvent} from './events.js'; import {getShimlessRmaService} from './mojo_interface_provider.js'; import {getTemplate} from './reimaging_calibration_failed_page.html.js'; import {CalibrationComponentStatus, CalibrationStatus, ComponentType, ShimlessRmaServiceInterface, StateResult} from './shimless_rma.mojom-webui.js'; @@ -28,33 +32,32 @@ * functioning state.) */ -/** - * @typedef {{ - * component: !ComponentType, - * uniqueId: number, - * id: string, - * name: string, - * checked: boolean, - * failed: boolean, - * }} - */ -let ComponentCheckbox; +interface ComponentCheckbox { + component: ComponentType; + uniqueId: number; + id: string; + name: string; + checked: boolean; + failed: boolean; + disabled?: boolean; + isFirstClickableComponent?: boolean; +} + +declare global { + interface WindowEventMap { + [CLICK_CALIBRATION_COMPONENT_BUTTON]: ClickCalibrationComponentEvent; + } +} + const NUM_COLUMNS = 1; -/** - * @constructor - * @extends {PolymerElement} - * @implements {I18nBehaviorInterface} - */ -const ReimagingCalibrationFailedPageBase = - mixinBehaviors([I18nBehavior], PolymerElement); +const ReimagingCalibrationFailedPageBase = I18nMixin(PolymerElement); -/** @polymer */ export class ReimagingCalibrationFailedPage extends ReimagingCalibrationFailedPageBase { static get is() { - return 'reimaging-calibration-failed-page'; + return 'reimaging-calibration-failed-page' as const; } static get template() { @@ -64,12 +67,10 @@ static get properties() { return { /** - * Set by shimless_rma.js. - * @type {boolean} + * Set by shimless_rma.ts. */ allButtonsDisabled: Boolean, - /** @private {!Array<!ComponentCheckbox>} */ componentCheckboxes: { type: Array, value: () => [], @@ -78,7 +79,6 @@ /** * The index into componentCheckboxes for keyboard navigation between * components. - * @private */ focusedComponentIndex: { type: Number, @@ -87,6 +87,14 @@ }; } + allButtonsDisabled: boolean; + shimlessRmaService: ShimlessRmaServiceInterface = getShimlessRmaService(); + private componentCheckboxes: ComponentCheckbox[]; + private focusedComponentIndex: number; + componentClicked: (event: ClickCalibrationComponentEvent) => void; + handleKeyDownEvent: (event: KeyboardEvent) => void; + onExitButtonClick: () => Promise<{stateResult: StateResult}>; + static get observers() { return [ 'updateIsFirstClickableComponent(componentCheckboxes.*)', @@ -96,14 +104,10 @@ constructor() { super(); - /** @private {ShimlessRmaServiceInterface} */ - this.shimlessRmaService = getShimlessRmaService(); - /** * The componentClickedCallback callback is used to capture events when * components are clicked, so that the page can put the focus on the * component that was clicked. - * @private {?Function} */ this.componentClicked = (event) => { const componentIndex = this.componentCheckboxes.findIndex( @@ -122,9 +126,8 @@ * Handles keyboard navigation over the list of components. * TODO(240717594): Find a way to avoid duplication of this code in the * repair components page. - * @private {?Function} */ - this.HandleKeyDownEvent = (event) => { + this.handleKeyDownEvent = (event: KeyboardEvent) => { if (event.key !== 'ArrowRight' && event.key !== 'ArrowDown' && event.key !== 'ArrowLeft' && event.key !== 'ArrowUp') { return; @@ -137,8 +140,8 @@ // Don't use keyboard navigation if the user tabbed out of the // component list. - if (!this.shadowRoot.activeElement || - this.shadowRoot.activeElement.tagName !== + if (!this.shadowRoot!.activeElement || + this.shadowRoot!.activeElement.tagName !== 'CALIBRATION-COMPONENT-CHIP') { return; } @@ -187,14 +190,16 @@ /** * The "Skip calibration" button on this page is styled and positioned like - * a exit button. So we use the common exit button from shimless_rma.js + * a exit button. So we use the common exit button from shimless_rma.ts * This function needs to be public, because it's invoked by - * shimless_rma.js as part of the response to the exit button click. - * @return {!Promise<!{stateResult: !StateResult}>} + * shimless_rma.ts as part of the response to the exit button click. */ this.onExitButtonClick = () => { if (this.tryingToSkipWithFailedComponents()) { - this.shadowRoot.querySelector('#failedComponentsDialog').showModal(); + const dialog: CrDialogElement|null = + this.shadowRoot!.querySelector('#failedComponentsDialog'); + assert(dialog); + dialog.showModal(); return Promise.reject( new Error('Attempting to skip with failed components.')); } @@ -203,17 +208,22 @@ }; } - /** @override */ - ready() { + override ready() { super.ready(); this.getInitialComponentsList(); // Hide the gradient when the list is scrolled to the end. - this.shadowRoot.querySelector('.scroll-container') - .addEventListener('scroll', (event) => { - const gradient = this.shadowRoot.querySelector('.gradient'); - if (event.target.scrollHeight - event.target.scrollTop === - event.target.clientHeight) { + (this.shadowRoot!.querySelector('.scroll-container') as HTMLDivElement) + .addEventListener('scroll', (event: Event) => { + const gradient = + this.shadowRoot!.querySelector('.gradient') as HTMLDivElement; + const dialog: CrDialogElement|null = + this.shadowRoot!.querySelector('#failedComponentsDialog'); + assert(dialog); + dialog.close(); + const target = (event.target as HTMLElement); + assert(target); + if (target.scrollHeight - target.scrollTop === target.clientHeight) { gradient.style.setProperty('visibility', 'hidden'); } else { gradient.style.setProperty('visibility', 'visible'); @@ -223,8 +233,7 @@ focusPageTitle(this); } - /** @private */ - getInitialComponentsList() { + private getInitialComponentsList(): void { this.shimlessRmaService.getCalibrationComponentList().then((result) => { if (!result || !result.hasOwnProperty('components')) { // TODO(gavindodd): Set an error state? @@ -252,40 +261,34 @@ }); } - /** @override */ - connectedCallback() { + override connectedCallback() { super.connectedCallback(); - window.addEventListener('keydown', this.HandleKeyDownEvent); + window.addEventListener('keydown', this.handleKeyDownEvent); window.addEventListener( - 'click-calibration-component-button', this.componentClicked); + CLICK_CALIBRATION_COMPONENT_BUTTON, this.componentClicked); } - /** @override */ - disconnectedCallback() { + override disconnectedCallback() { super.disconnectedCallback(); - window.removeEventListener('keydown', this.HandleKeyDownEvent); + window.removeEventListener('keydown', this.handleKeyDownEvent); window.removeEventListener( - 'click-calibration-component-button', this.componentClicked); + CLICK_CALIBRATION_COMPONENT_BUTTON, this.componentClicked); } - /** - * Make the page focus on the component at focusedComponentIndex. - * @private - */ - focusOnCurrentComponent() { - if (this.focusedComponentIndex != -1) { - const componentChip = this.shadowRoot.querySelector(`[unique-id="${ - this.componentCheckboxes[this.focusedComponentIndex].uniqueId}"]`); - componentChip.shadowRoot.querySelector('#componentButton').focus(); + private focusOnCurrentComponent() { + if (this.focusedComponentIndex !== -1) { + const componentChip: CalibrationComponentChipElement|null = + this.shadowRoot!.querySelector(`[unique-id="${ + this.componentCheckboxes[this.focusedComponentIndex] + .uniqueId}"]`); + assert(componentChip); + (componentChip.shadowRoot!.querySelector('#componentButton') as + CrButtonElement) + .focus(); } } - - /** - * @return {!Array<!CalibrationComponentStatus>} - * @private - */ - getComponentsList() { + private getComponentsList(): CalibrationComponentStatus[] { return this.componentCheckboxes.map(item => { // These statuses tell rmad how to treat each component in this request. // If the component didn't fail a calibration, its status needs to be @@ -309,11 +312,7 @@ }); } - /** - * @return {!Promise<!{stateResult: !StateResult}>} - * @private - */ - skipCalibration() { + private skipCalibration(): Promise<{stateResult: StateResult}> { const skippedComponents = this.componentCheckboxes.map(item => { return { component: item.component, @@ -328,42 +327,32 @@ return this.shimlessRmaService.startCalibration(skippedComponents); } - /** @return {!Promise<!{stateResult: !StateResult}>} */ - onNextButtonClick() { + onNextButtonClick(): Promise<{stateResult: StateResult}> { return this.shimlessRmaService.startCalibration(this.getComponentsList()); } - /** - * @param {boolean} componentDisabled - * @return {boolean} - * @private - */ - isComponentDisabled(componentDisabled) { + private isComponentDisabled(componentDisabled: boolean): boolean { return componentDisabled || this.allButtonsDisabled; } - /** @protected */ - onSkipDialogButtonClicked() { + protected onSkipDialogButtonClicked(): void { this.closeDialog(); executeThenTransitionState(this, () => this.skipCalibration()); } - /** @protected */ - closeDialog() { - this.shadowRoot.querySelector('#failedComponentsDialog').close(); + protected closeDialog(): void { + const dialog: CrDialogElement|null = + this.shadowRoot!.querySelector('#failedComponentsDialog'); + assert(dialog); + dialog.close(); } - /** - * @return {boolean} - * @private - */ - tryingToSkipWithFailedComponents() { + private tryingToSkipWithFailedComponents(): boolean { return this.componentCheckboxes.some( component => component.failed && !component.checked); } - /** @private */ - updateIsFirstClickableComponent() { + private updateIsFirstClickableComponent(): void { const firstClickableComponent = this.componentCheckboxes.find(component => !component.disabled); this.componentCheckboxes.forEach(component => { @@ -372,8 +361,7 @@ }); } - /** @private */ - updateNextButtonAvailability() { + private updateNextButtonAvailability(): void { if (this.componentCheckboxes.some(component => component.checked)) { enableNextButton(this); } else { @@ -382,5 +370,11 @@ } } +declare global { + interface HTMLElementTagNameMap { + [ReimagingCalibrationFailedPage.is]: ReimagingCalibrationFailedPage; + } +} + customElements.define( ReimagingCalibrationFailedPage.is, ReimagingCalibrationFailedPage);
diff --git a/ash/webui/shimless_rma/resources/reimaging_calibration_run_page.js b/ash/webui/shimless_rma/resources/reimaging_calibration_run_page.ts similarity index 62% rename from ash/webui/shimless_rma/resources/reimaging_calibration_run_page.js rename to ash/webui/shimless_rma/resources/reimaging_calibration_run_page.ts index 613eb9d..57917b61 100644 --- a/ash/webui/shimless_rma/resources/reimaging_calibration_run_page.js +++ b/ash/webui/shimless_rma/resources/reimaging_calibration_run_page.ts
@@ -2,19 +2,18 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'chrome://resources/cr_elements/icons.html.js'; -import 'chrome://resources/polymer/v3_0/iron-icon/iron-icon.js'; import './shimless_rma_shared.css.js'; import './base_page.js'; import './icons.html.js'; +import 'chrome://resources/cr_elements/icons.html.js'; +import 'chrome://resources/polymer/v3_0/iron-icon/iron-icon.js'; -import {I18nBehavior, I18nBehaviorInterface} from 'chrome://resources/ash/common/i18n_behavior.js'; -import {mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js'; +import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; -import {ComponentTypeToId} from './data.js'; import {getShimlessRmaService} from './mojo_interface_provider.js'; import {getTemplate} from './reimaging_calibration_run_page.html.js'; -import {CalibrationComponentStatus, CalibrationObserverInterface, CalibrationObserverReceiver, CalibrationOverallStatus, ShimlessRmaServiceInterface, StateResult} from './shimless_rma.mojom-webui.js'; +import {CalibrationComponentStatus, CalibrationObserverReceiver, CalibrationOverallStatus, ShimlessRmaServiceInterface, StateResult} from './shimless_rma.mojom-webui.js'; import {enableNextButton, executeThenTransitionState, focusPageTitle} from './shimless_rma_util.js'; /** @@ -23,19 +22,12 @@ * various components during the reimaging process. */ -/** - * @constructor - * @extends {PolymerElement} - * @implements {I18nBehaviorInterface} - */ -const ReimagingCalibrationRunPageBase = - mixinBehaviors([I18nBehavior], PolymerElement); +const ReimagingCalibrationRunPageBase = I18nMixin(PolymerElement); -/** @polymer */ export class ReimagingCalibrationRunPage extends ReimagingCalibrationRunPageBase { static get is() { - return 'reimaging-calibration-run-page'; + return 'reimaging-calibration-run-page' as const; } static get template() { @@ -44,9 +36,6 @@ static get properties() { return { - /** - * @protected - */ calibrationComplete: { type: Boolean, value: false, @@ -54,27 +43,26 @@ }; } + private shimlessRmaService: ShimlessRmaServiceInterface = + getShimlessRmaService(); + private calibrationObserverReceiver: CalibrationObserverReceiver; + protected calibrationComplete: boolean; + constructor() { super(); - /** @private {ShimlessRmaServiceInterface} */ - this.shimlessRmaService = getShimlessRmaService(); - /** @private {!CalibrationObserverReceiver} */ - this.calibrationObserverReceiver = new CalibrationObserverReceiver( - /** @type {!CalibrationObserverInterface} */ (this)); + this.calibrationObserverReceiver = new CalibrationObserverReceiver(this); this.shimlessRmaService.observeCalibrationProgress( this.calibrationObserverReceiver.$.bindNewPipeAndPassRemote()); } - /** @override */ - ready() { + override ready() { super.ready(); focusPageTitle(this); } - /** @return {!Promise<!{stateResult: !StateResult}>} */ - onNextButtonClick() { + onNextButtonClick(): Promise<{stateResult: StateResult}> { if (this.calibrationComplete) { return this.shimlessRmaService.calibrationComplete(); } @@ -83,15 +71,13 @@ /** * Implements CalibrationObserver.onCalibrationUpdated() - * @param {!CalibrationComponentStatus} componentStatus */ - onCalibrationUpdated(componentStatus) {} + onCalibrationUpdated(_componentStatus: CalibrationComponentStatus): void {} /** - * Implements CalibrationObserver.onCalibrationUpdated() - * @param {!CalibrationOverallStatus} status + * Implements CalibrationObserver.onCalibrationStepComplete() */ - onCalibrationStepComplete(status) { + onCalibrationStepComplete(status: CalibrationOverallStatus): void { switch (status) { case CalibrationOverallStatus.kCalibrationOverallComplete: this.calibrationComplete = true; @@ -106,16 +92,18 @@ } } - /** - * @return {string} - * @protected - */ - getCalibrationTitleString() { + protected getCalibrationTitleString(): string { return this.i18n( this.calibrationComplete ? 'runCalibrationCompleteTitleText' : 'runCalibrationTitleText'); } } +declare global { + interface HTMLElementTagNameMap { + [ReimagingCalibrationRunPage.is]: ReimagingCalibrationRunPage; + } +} + customElements.define( ReimagingCalibrationRunPage.is, ReimagingCalibrationRunPage);
diff --git a/ash/webui/shimless_rma/resources/reimaging_calibration_setup_page.js b/ash/webui/shimless_rma/resources/reimaging_calibration_setup_page.ts similarity index 69% rename from ash/webui/shimless_rma/resources/reimaging_calibration_setup_page.js rename to ash/webui/shimless_rma/resources/reimaging_calibration_setup_page.ts index 8d5107d..781d5f5 100644 --- a/ash/webui/shimless_rma/resources/reimaging_calibration_setup_page.js +++ b/ash/webui/shimless_rma/resources/reimaging_calibration_setup_page.ts
@@ -2,22 +2,21 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'chrome://resources/cr_elements/icons.html.js'; -import 'chrome://resources/polymer/v3_0/iron-icon/iron-icon.js'; import './shimless_rma_shared.css.js'; import './base_page.js'; import './icons.html.js'; +import 'chrome://resources/cr_elements/icons.html.js'; +import 'chrome://resources/polymer/v3_0/iron-icon/iron-icon.js'; -import {assert} from 'chrome://resources/ash/common/assert.js'; -import {I18nBehavior, I18nBehaviorInterface} from 'chrome://resources/ash/common/i18n_behavior.js'; -import {mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js'; +import {assert} from 'chrome://resources/js/assert.js'; +import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {getShimlessRmaService} from './mojo_interface_provider.js'; import {getTemplate} from './reimaging_calibration_setup_page.html.js'; import {CalibrationSetupInstruction, ShimlessRmaServiceInterface, StateResult} from './shimless_rma.mojom-webui.js'; import {enableNextButton, focusPageTitle} from './shimless_rma_util.js'; -/** @type {!Object<!CalibrationSetupInstruction, string>} */ const INSRUCTION_MESSAGE_KEY_MAP = { [CalibrationSetupInstruction.kCalibrationInstructionPlaceBaseOnFlatSurface]: 'calibrateBaseInstructionsText', @@ -25,7 +24,6 @@ 'calibrateLidInstructionsText', }; -/** @type {!Object<!CalibrationSetupInstruction, string>} */ const CALIBRATION_IMG_MAP = { [CalibrationSetupInstruction.kCalibrationInstructionPlaceBaseOnFlatSurface]: 'base_on_flat_surface', @@ -33,7 +31,6 @@ 'lid_on_flat_surface', }; -/** @type {!Object<!CalibrationSetupInstruction, string>} */ const CALIBRATION_ALT_MAP = { [CalibrationSetupInstruction.kCalibrationInstructionPlaceBaseOnFlatSurface]: 'baseOnFlatSurfaceAltText', @@ -47,19 +44,12 @@ * user to prepare the device for a calibration step. */ -/** - * @constructor - * @extends {PolymerElement} - * @implements {I18nBehaviorInterface} - */ -const ReimagingCalibrationSetupPageBase = - mixinBehaviors([I18nBehavior], PolymerElement); +const ReimagingCalibrationSetupPageBase = I18nMixin(PolymerElement); -/** @polymer */ export class ReimagingCalibrationSetupPage extends ReimagingCalibrationSetupPageBase { static get is() { - return 'reimaging-calibration-setup-page'; + return 'reimaging-calibration-setup-page' as const; } static get template() { @@ -68,79 +58,67 @@ static get properties() { return { - /** @protected {?CalibrationSetupInstruction} */ calibrationSetupInstruction: { type: Object, }, - /** @protected {string} */ imgSrc: { type: String, value: '', }, - /** @protected {string} */ imgAlt: { type: String, value: '', }, - /** @protected {string} */ calibrationInstructionsText: { type: String, }, }; } - constructor() { - super(); - /** @private {ShimlessRmaServiceInterface} */ - this.shimlessRmaService = getShimlessRmaService(); - } + calibrationSetupInstruction: CalibrationSetupInstruction; + shimlessRmaService: ShimlessRmaServiceInterface = getShimlessRmaService(); + protected imgSrc: string; + protected imgAlt: string; + protected calibrationInstructionsText: string; static get observers() { return ['onStatusChanged(calibrationSetupInstruction)']; } - /** @override */ - ready() { + override ready() { super.ready(); - this.shimlessRmaService.getCalibrationSetupInstructions().then((result) => { - this.calibrationSetupInstruction = result.instructions; - }); + this.shimlessRmaService.getCalibrationSetupInstructions().then( + (result: {instructions: CalibrationSetupInstruction}) => { + this.calibrationSetupInstruction = result.instructions; + }); enableNextButton(this); focusPageTitle(this); } - /** @return {!Promise<{stateResult: !StateResult}>} */ - onNextButtonClick() { + onNextButtonClick(): Promise<{stateResult: StateResult}> { return this.shimlessRmaService.runCalibrationStep(); } /** * Groups state changes related to the |calibrationSetupInstruction| * updating. - * @protected */ - onStatusChanged() { + protected onStatusChanged(): void { this.setCalibrationInstructionsText(); this.setImgSrcAndAlt(); } - /** - * @protected - */ - setCalibrationInstructionsText() { + protected setCalibrationInstructionsText(): void { assert(this.calibrationSetupInstruction); this.calibrationInstructionsText = this.i18n(INSRUCTION_MESSAGE_KEY_MAP[this.calibrationSetupInstruction]); } - /** - * @protected - */ - setImgSrcAndAlt() { + protected setImgSrcAndAlt(): void { assert(this.calibrationSetupInstruction); this.imgSrc = `illustrations/${ CALIBRATION_IMG_MAP[this.calibrationSetupInstruction]}.svg`; @@ -149,5 +127,11 @@ } } +declare global { + interface HTMLElementTagNameMap { + [ReimagingCalibrationSetupPage.is]: ReimagingCalibrationSetupPage; + } +} + customElements.define( ReimagingCalibrationSetupPage.is, ReimagingCalibrationSetupPage);
diff --git a/ash/wm/default_state.cc b/ash/wm/default_state.cc index 2ba8345..fcf3ef47 100644 --- a/ash/wm/default_state.cc +++ b/ash/wm/default_state.cc
@@ -706,7 +706,7 @@ bounds_in_parent.size() != window->bounds().size()) { reporter.emplace( window_state->window()->layer()->GetAnimator(), - metrics_util::ForSmoothness(base::BindRepeating([](int smoothness) { + metrics_util::ForSmoothnessV3(base::BindRepeating([](int smoothness) { UMA_HISTOGRAM_PERCENTAGE(kSnapWindowSmoothnessHistogramName, smoothness); })));
diff --git a/ash/wm/desks/desk_animation_impl.cc b/ash/wm/desks/desk_animation_impl.cc index 410192d..6c313a2 100644 --- a/ash/wm/desks/desk_animation_impl.cc +++ b/ash/wm/desks/desk_animation_impl.cc
@@ -226,7 +226,7 @@ throughput_tracker_ = desks_util::GetSelectedCompositorForPerformanceMetrics() ->RequestNewThroughputTracker(); throughput_tracker_->Start( - metrics_util::ForSmoothness(base::BindRepeating([](int smoothness) { + metrics_util::ForSmoothnessV3(base::BindRepeating([](int smoothness) { UMA_HISTOGRAM_PERCENTAGE(kDeskEndGestureSmoothnessHistogramName, smoothness); }))); @@ -290,7 +290,7 @@ metrics_util::ReportCallback DeskActivationAnimation::GetSmoothnessReportCallback() const { - return metrics_util::ForSmoothness(base::BindRepeating([](int smoothness) { + return metrics_util::ForSmoothnessV3(base::BindRepeating([](int smoothness) { UMA_HISTOGRAM_PERCENTAGE(kDeskActivationSmoothnessHistogramName, smoothness); })); @@ -386,7 +386,7 @@ metrics_util::ReportCallback DeskRemovalAnimation::GetSmoothnessReportCallback() const { - return ash::metrics_util::ForSmoothness( + return ash::metrics_util::ForSmoothnessV3( base::BindRepeating([](int smoothness) { UMA_HISTOGRAM_PERCENTAGE(kDeskRemovalSmoothnessHistogramName, smoothness);
diff --git a/ash/wm/multi_display/persistent_window_controller_unittest.cc b/ash/wm/multi_display/persistent_window_controller_unittest.cc index 91921d1..87adf2d 100644 --- a/ash/wm/multi_display/persistent_window_controller_unittest.cc +++ b/ash/wm/multi_display/persistent_window_controller_unittest.cc
@@ -339,9 +339,6 @@ EXPECT_EQ(gfx::Rect(200, 0, 100, 200), w1->GetBoundsInScreen()); EXPECT_EQ(gfx::Rect(1, 0, 200, 100), w2->GetBoundsInScreen()); - // Spin a run loop to ensure shelf is deleted. https://crbug.com/810807. - base::RunLoop().RunUntilIdle(); - // Enters locked session state and reconnects secondary display. GetSessionControllerClient()->SetSessionState(SessionState::LOCKED); display_info_list.push_back(secondary_info);
diff --git a/ash/wm/splitview/split_view_controller.cc b/ash/wm/splitview/split_view_controller.cc index efa6451..35cfd95 100644 --- a/ash/wm/splitview/split_view_controller.cc +++ b/ash/wm/splitview/split_view_controller.cc
@@ -285,7 +285,7 @@ tracker_.emplace(widget->GetCompositor()->RequestNewThroughputTracker()); tracker_->Start( - metrics_util::ForSmoothness(base::BindRepeating([](int smoothness) { + metrics_util::ForSmoothnessV3(base::BindRepeating([](int smoothness) { UMA_HISTOGRAM_PERCENTAGE(kDividerAnimationSmoothness, smoothness); }))); }
diff --git a/ash/wm/tablet_mode/tablet_mode_controller.cc b/ash/wm/tablet_mode/tablet_mode_controller.cc index 316d93dd..1efb5ad 100644 --- a/ash/wm/tablet_mode/tablet_mode_controller.cc +++ b/ash/wm/tablet_mode/tablet_mode_controller.cc
@@ -804,7 +804,7 @@ if (!transition_tracker_) { transition_tracker_ = animating_layer_->GetCompositor()->RequestNewThroughputTracker(); - transition_tracker_->Start(metrics_util::ForSmoothness( + transition_tracker_->Start(metrics_util::ForSmoothnessV3( base::BindRepeating(&ReportTrasitionSmoothness, display::Screen::GetScreen()->GetTabletState() == display::TabletState::kEnteringTabletMode)));
diff --git a/ash/wm/window_animations.cc b/ash/wm/window_animations.cc index ab97e4a..01ccc2b 100644 --- a/ash/wm/window_animations.cc +++ b/ash/wm/window_animations.cc
@@ -122,16 +122,18 @@ smoothness_tracker_ = layer_->GetCompositor()->RequestNewThroughputTracker(); - smoothness_tracker_->Start(metrics_util::ForSmoothness(base::BindRepeating( - [](const std::optional<std::string>& histogram_name, int smoothness) { - if (histogram_name) { - DCHECK(!histogram_name->empty()); - base::UmaHistogramPercentage(*histogram_name, smoothness); - } else { - UMA_HISTOGRAM_PERCENTAGE(kCrossFadeSmoothness, smoothness); - } - }, - std::move(histogram_name)))); + smoothness_tracker_->Start( + metrics_util::ForSmoothnessV3(base::BindRepeating( + [](const std::optional<std::string>& histogram_name, + int smoothness) { + if (histogram_name) { + DCHECK(!histogram_name->empty()); + base::UmaHistogramPercentage(*histogram_name, smoothness); + } else { + UMA_HISTOGRAM_PERCENTAGE(kCrossFadeSmoothness, smoothness); + } + }, + std::move(histogram_name)))); } CrossFadeObserver(const CrossFadeObserver&) = delete; CrossFadeObserver& operator=(const CrossFadeObserver&) = delete; @@ -470,7 +472,7 @@ ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator()); ui::AnimationThroughputReporter reporter( settings.GetAnimator(), - metrics_util::ForSmoothness( + metrics_util::ForSmoothnessV3( base::BindRepeating(static_cast<void (*)(const char*, int)>( &base::UmaHistogramPercentage), "Ash.Window.AnimationSmoothness.Unminimize"))); @@ -491,7 +493,7 @@ // Report animation smoothness for animations created within this scope. ui::AnimationThroughputReporter reporter( hiding_settings.layer_animation_settings()->GetAnimator(), - metrics_util::ForSmoothness( + metrics_util::ForSmoothnessV3( base::BindRepeating(static_cast<void (*)(const char*, int)>( &base::UmaHistogramPercentage), "Ash.Window.AnimationSmoothness.Minimize")));
diff --git a/base/android/java/src/org/chromium/base/Flag.java b/base/android/java/src/org/chromium/base/Flag.java index 1570195..a808164b 100644 --- a/base/android/java/src/org/chromium/base/Flag.java +++ b/base/android/java/src/org/chromium/base/Flag.java
@@ -11,23 +11,25 @@ /** * Defines a feature flag for use in Java. * - * Duplicate flag definitions are not permitted, so only a single - * instance can be created with a given feature name. + * <p>Duplicate flag definitions are not permitted, so only a single instance can be created with a + * given feature name. * - * To create a flag, instantiate a concrete subclass, i.e. CachedFlag, MutableFlagWithSafeDefault or + * <p>To instantiate a Flag, use a concrete subclass, i.e. CachedFlag, MutableFlagWithSafeDefault or * PostNativeFlag. * - * This class and its subclasses are not thread safe. + * <p>This class and its subclasses are not thread safe. */ @NotThreadSafe public abstract class Flag { - private static HashMap<String, Flag> sFlagsCreated = new HashMap<>(); - protected final String mFeatureName; - protected Boolean mValue; - protected Flag(String featureName) { + private static HashMap<String, Flag> sFlagsCreated = new HashMap<>(); + protected final FeatureMap mFeatureMap; + protected final String mFeatureName; + + protected Flag(FeatureMap featureMap, String featureName) { assert !sFlagsCreated.containsKey(featureName) : "Duplicate flag creation for feature: " + featureName; + mFeatureMap = featureMap; mFeatureName = featureName; sFlagsCreated.put(mFeatureName, this); }
diff --git a/base/android/java/src/org/chromium/base/MutableFlagWithSafeDefault.java b/base/android/java/src/org/chromium/base/MutableFlagWithSafeDefault.java index 0927cb77..c92722a 100644 --- a/base/android/java/src/org/chromium/base/MutableFlagWithSafeDefault.java +++ b/base/android/java/src/org/chromium/base/MutableFlagWithSafeDefault.java
@@ -15,13 +15,11 @@ */ public class MutableFlagWithSafeDefault extends Flag { private final boolean mDefaultValue; - private final FeatureMap mFeatureMap; private Boolean mInMemoryCachedValue; public MutableFlagWithSafeDefault( FeatureMap featureMap, String featureName, boolean defaultValue) { - super(featureName); - mFeatureMap = featureMap; + super(featureMap, featureName); mDefaultValue = defaultValue; }
diff --git a/base/containers/fixed_flat_map_unittest.cc b/base/containers/fixed_flat_map_unittest.cc index 5c74faa..00ea140 100644 --- a/base/containers/fixed_flat_map_unittest.cc +++ b/base/containers/fixed_flat_map_unittest.cc
@@ -57,7 +57,7 @@ // Tests that even though the keys are immutable, the values of a non-const map // can still be changed. TEST(FixedFlatMapTest, MutableValues) { - auto map = MakeFixedFlatMap<std::string, int>({{"bar", 1}, {"foo", 2}}); + auto map = MakeFixedFlatMap<StringPiece, int>({{"bar", 1}, {"foo", 2}}); EXPECT_THAT(map, ElementsAre(Pair("bar", 1), Pair("foo", 2))); map.at("bar") = 2; EXPECT_THAT(map, ElementsAre(Pair("bar", 2), Pair("foo", 2)));
diff --git a/base/task/thread_pool/worker_thread_waitable_event_unittest.cc b/base/task/thread_pool/worker_thread_waitable_event_unittest.cc index abc4120a..e0249ac 100644 --- a/base/task/thread_pool/worker_thread_waitable_event_unittest.cc +++ b/base/task/thread_pool/worker_thread_waitable_event_unittest.cc
@@ -1029,29 +1029,35 @@ size_t cached_memory_after = partition_alloc::ThreadCache::Get()->CachedMemory(); - if (!first_wakeup_done_) { - // First time we sleep is a short sleep, no cache purging. - // - // Here and below, cannot assert on exact thread cache size, since - // anything that allocates will make it fluctuate. - EXPECT_GT(cached_memory_after, cached_memory_before / 2); - first_wakeup_done_.store(true, std::memory_order_release); - } else { - // Second one is long, should purge. - EXPECT_LT(cached_memory_after, cached_memory_before / 2); + if (!test_done_) { + if (purge_expected_) { + EXPECT_LT(cached_memory_after, cached_memory_before / 2); + } else { + EXPECT_GT(cached_memory_after, cached_memory_before / 2); + } + // Unblock the test. + wakeup_done_.Signal(); + test_done_ = true; } } - std::atomic<bool> first_wakeup_done_{false}; + // Avoid using the default sleep timeout which is infinite and prevents the + // tests for completing. + TimeDelta GetSleepTimeout() override { + return WorkerThread::Delegate::kPurgeThreadCacheIdleDelay + + TestTimeouts::tiny_timeout(); + } + + void SetPurgeExpectation(bool purge_expected) { + purge_expected_ = purge_expected; + } + + bool test_done_ = false; + bool purge_expected_ = false; + base::WaitableEvent wakeup_done_; }; -// TODO(crbug.com/1469364): Re-enable this test on Mac. -#if BUILDFLAG(IS_MAC) -#define MAYBE_WorkerThreadCachePurgeTest DISABLED_WorkerThreadCachePurgeTest -#else -#define MAYBE_WorkerThreadCachePurgeTest WorkerThreadCachePurgeTest -#endif -TYPED_TEST(ThreadPoolWorkerTest, MAYBE_WorkerThreadCachePurgeTest) { +TYPED_TEST(ThreadPoolWorkerTest, WorkerThreadCacheNoPurgeOnSignal) { // Make sure the thread cache is enabled in the main partition. partition_alloc::internal::ThreadCacheProcessScopeForTesting scope( allocator_shim::internal::PartitionAllocMalloc::Allocator()); @@ -1059,19 +1065,41 @@ this->template ConstructWorker<WorkerThreadThreadCacheDelegate>( ThreadType::kDefault); - // Wake up before the thread is started to make sure the first sleep is short. + auto* delegate = static_cast< + WorkerThreadThreadCacheDelegate<typename TestFixture::WorkerType>*>( + this->delegate_raw_); + + // No purge is expected on waking up from a signal. + delegate->SetPurgeExpectation(false); + + // Wake up before the thread is started to make sure the first wakeup is + // caused by a signal. this->WakeUpWorker(); this->StartWorker(false); + // Wait until a wakeup has completed. + delegate->wakeup_done_.Wait(); +} + +TYPED_TEST(ThreadPoolWorkerTest, PurgeOnUninteruptedSleep) { + // Make sure the thread cache is enabled in the main partition. + partition_alloc::internal::ThreadCacheProcessScopeForTesting scope( + allocator_shim::internal::PartitionAllocMalloc::Allocator()); + + this->template ConstructWorker<WorkerThreadThreadCacheDelegate>( + ThreadType::kDefault); + auto* delegate = static_cast< WorkerThreadThreadCacheDelegate<typename TestFixture::WorkerType>*>( this->delegate_raw_); - while (delegate->first_wakeup_done_.load(std::memory_order_acquire)) { - } - // Have to use real sleep unfortunately rather than virtual time, because - // WaitableEvent uses the non-overridable variant of TimeTicks. - PlatformThread::Sleep(2 * WorkerThread::Delegate::kPurgeThreadCacheIdleDelay); + // A purge will take place + delegate->SetPurgeExpectation(true); + + this->StartWorker(false); + + // Wait until a wakeup has completed. + delegate->wakeup_done_.Wait(); } #endif // BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) &&
diff --git a/build/linux/sysroot_scripts/sysroot_creator.py b/build/linux/sysroot_scripts/sysroot_creator.py index 637ce2e..d14a316f 100755 --- a/build/linux/sysroot_scripts/sysroot_creator.py +++ b/build/linux/sysroot_scripts/sysroot_creator.py
@@ -858,11 +858,17 @@ # Check if the symlink is absolute and points inside the # install_root. - if os.path.isabs(target_path) and target_path.startswith( - install_root): - # Compute the relative path from the symlink to the target - relative_path = os.path.relpath(target_path, - os.path.dirname(full_path)) + if os.path.isabs(target_path): + # Compute the relative path from the symlink to the target. + relative_path = os.path.relpath( + os.path.join(install_root, target_path.strip("/")), + os.path.dirname(full_path)) + # Verify that the target exists inside the install_root. + joined_path = os.path.join(os.path.dirname(full_path), + relative_path) + if not os.path.exists(joined_path): + raise Exception( + f"Link target doesn't exist: {joined_path}") os.remove(full_path) os.symlink(relative_path, full_path)
diff --git a/chrome/VERSION b/chrome/VERSION index b97611c..8d3e431 100644 --- a/chrome/VERSION +++ b/chrome/VERSION
@@ -1,4 +1,4 @@ MAJOR=122 MINOR=0 -BUILD=6244 +BUILD=6245 PATCH=0
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn index 44a44501..953672b8 100644 --- a/chrome/android/BUILD.gn +++ b/chrome/android/BUILD.gn
@@ -182,6 +182,7 @@ "//chrome/browser/feedback/android:java_resources", "//chrome/browser/image_descriptions:java_resources", "//chrome/browser/lens:java_resources", + "//chrome/browser/magic_stack/android:java_resources", "//chrome/browser/mandatory_reauth/android/internal:java_resources", "//chrome/browser/password_check/android:java_resources", "//chrome/browser/password_manager/android:java_resources", @@ -372,6 +373,7 @@ "//chrome/browser/language/android:java", "//chrome/browser/lens:java", "//chrome/browser/locale:java", + "//chrome/browser/magic_stack/android:java", "//chrome/browser/notifications/chime/android:java", "//chrome/browser/omaha/android:java", "//chrome/browser/optimization_guide/android:java", @@ -999,6 +1001,7 @@ "//chrome/browser/lens:java", "//chrome/browser/loading_modal/android:junit", "//chrome/browser/locale:java", + "//chrome/browser/magic_stack/android:java", "//chrome/browser/magic_stack/android:junit", "//chrome/browser/mandatory_reauth/android/internal:junit", "//chrome/browser/notifications:java",
diff --git a/chrome/android/features/cablev2_authenticator/java/src/org/chromium/chrome/browser/webauth/authenticator/CableAuthenticator.java b/chrome/android/features/cablev2_authenticator/java/src/org/chromium/chrome/browser/webauth/authenticator/CableAuthenticator.java index 02ff3a44..a16f6f3 100644 --- a/chrome/android/features/cablev2_authenticator/java/src/org/chromium/chrome/browser/webauth/authenticator/CableAuthenticator.java +++ b/chrome/android/features/cablev2_authenticator/java/src/org/chromium/chrome/browser/webauth/authenticator/CableAuthenticator.java
@@ -5,20 +5,13 @@ package org.chromium.chrome.browser.webauth.authenticator; import android.app.Activity; -import android.app.PendingIntent; import android.content.Context; import android.content.Intent; -import android.content.IntentSender; import android.hardware.usb.UsbAccessory; -import android.net.Uri; import android.os.Build; -import android.os.Bundle; -import android.os.Parcel; import android.provider.Settings; import android.util.Pair; -import com.google.android.gms.tasks.Task; - import org.jni_zero.CalledByNative; import org.jni_zero.NativeMethods; @@ -33,16 +26,12 @@ import org.chromium.blink.mojom.PublicKeyCredentialRequestOptions; import org.chromium.blink.mojom.ResidentKeyRequirement; import org.chromium.components.webauthn.Fido2Api; -import org.chromium.components.webauthn.Fido2ApiCall; import org.chromium.components.webauthn.Fido2CredentialRequest; import org.chromium.components.webauthn.WebauthnModeProvider; -import org.chromium.device.DeviceFeatureList; -import org.chromium.device.DeviceFeatureMap; import org.chromium.url.GURL; import org.chromium.url.Origin; import java.nio.ByteBuffer; -import java.security.NoSuchAlgorithmException; /** * CableAuthenticator implements makeCredential and getAssertion operations on top of the Privileged @@ -152,70 +141,45 @@ // in Play Services and so it continued not to be supported. params.prfInput = null; - if (DeviceFeatureMap.isEnabled(DeviceFeatureList.WEBAUTHN_CABLE_VIA_CREDMAN)) { - final Fido2CredentialRequest request = new Fido2CredentialRequest(mUi); - request.setIsHybridRequest(true); - final Origin origin = Origin.create(new GURL("https://" + params.relyingParty.id)); - request.handleMakeCredentialRequest( - mContext, - params, - null, - params.challenge, - origin, - (status, response) -> { - mTaskRunner.postTask( - () -> - CableAuthenticatorJni.get() - .onAuthenticatorAttestationResponse( - CTAP2_OK, - response.attestationObject, - response.prf)); - mUi.onAuthenticatorResult(Result.REGISTER_OK); - }, - (status) -> { - final boolean isInvalidStateError = - status == AuthenticatorStatus.CREDENTIAL_EXCLUDED; - - mTaskRunner.postTask( - () -> - CableAuthenticatorJni.get() - .onAuthenticatorAttestationResponse( - isInvalidStateError - ? CTAP2_ERR_CREDENTIAL_EXCLUDED - : CTAP2_ERR_OPERATION_DENIED, - null, - false)); - - mUi.onAuthenticatorResult( - isInvalidStateError ? Result.REGISTER_OK : Result.REGISTER_ERROR); - }); - return; - } - mAttestationAcceptable = params.authenticatorSelection.residentKey == ResidentKeyRequirement.DISCOURAGED; - Fido2ApiCall call = new Fido2ApiCall(mContext); - Parcel args = call.start(); - Fido2ApiCall.PendingIntentResult result = new Fido2ApiCall.PendingIntentResult(); - args.writeStrongBinder(result); - args.writeInt(1); // This indicates that the following options are present. + final Fido2CredentialRequest request = new Fido2CredentialRequest(mUi); + request.setIsHybridRequest(true); + final Origin origin = Origin.create(new GURL("https://" + params.relyingParty.id)); + request.handleMakeCredentialRequest( + mContext, + params, + null, + params.challenge, + origin, + (status, response) -> { + mTaskRunner.postTask( + () -> + CableAuthenticatorJni.get() + .onAuthenticatorAttestationResponse( + CTAP2_OK, + response.attestationObject, + response.prf)); + mUi.onAuthenticatorResult(Result.REGISTER_OK); + }, + (status) -> { + final boolean isInvalidStateError = + status == AuthenticatorStatus.CREDENTIAL_EXCLUDED; - try { - Fido2Api.appendBrowserMakeCredentialOptionsToParcel( - params, Uri.parse("https://" + params.relyingParty.id), params.challenge, args); - } catch (NoSuchAlgorithmException e) { - onAuthenticatorAttestationResponse(CTAP2_ERR_UNSUPPORTED_ALGORITHM, null, false); - return; - } + mTaskRunner.postTask( + () -> + CableAuthenticatorJni.get() + .onAuthenticatorAttestationResponse( + isInvalidStateError + ? CTAP2_ERR_CREDENTIAL_EXCLUDED + : CTAP2_ERR_OPERATION_DENIED, + null, + false)); - Task<PendingIntent> task = - call.run( - Fido2ApiCall.METHOD_BROWSER_REGISTER, - Fido2ApiCall.TRANSACTION_REGISTER, - args, - result); - awaitPendingIntent(task, REGISTER_REQUEST_CODE); + mUi.onAuthenticatorResult( + isInvalidStateError ? Result.REGISTER_OK : Result.REGISTER_ERROR); + }); } @CalledByNative @@ -223,82 +187,37 @@ PublicKeyCredentialRequestOptions params = PublicKeyCredentialRequestOptions.deserialize(ByteBuffer.wrap(serializedParams)); - if (DeviceFeatureMap.isEnabled(DeviceFeatureList.WEBAUTHN_CABLE_VIA_CREDMAN)) { - final Fido2CredentialRequest request = new Fido2CredentialRequest(mUi); - request.setIsHybridRequest(true); - final Origin origin = Origin.create(new GURL("https://" + params.relyingPartyId)); - request.handleGetAssertionRequest( - mContext, - params, - /* frameHost= */ null, - /* maybeClientDataHash= */ params.challenge, - origin, - origin, - /* payment= */ null, - (status, response) -> { - response.info.clientDataJson = new byte[0]; - ByteBuffer buffer = response.serialize(); - byte[] serialized = new byte[buffer.remaining()]; - buffer.get(serialized); - mTaskRunner.postTask( - () -> - CableAuthenticatorJni.get() - .onAuthenticatorAssertionResponse( - CTAP2_OK, serialized)); - mUi.onAuthenticatorResult(Result.SIGN_OK); - }, - (status) -> { - mTaskRunner.postTask( - () -> - CableAuthenticatorJni.get() - .onAuthenticatorAssertionResponse( - CTAP2_ERR_OPERATION_DENIED, null)); - mUi.onAuthenticatorResult(Result.SIGN_ERROR); - }); - return; - } - - Fido2ApiCall call = new Fido2ApiCall(mContext); - Parcel args = call.start(); - Fido2ApiCall.PendingIntentResult result = new Fido2ApiCall.PendingIntentResult(); - args.writeStrongBinder(result); - args.writeInt(1); // This indicates that the following options are present. - Fido2Api.appendBrowserGetAssertionOptionsToParcel( + final Fido2CredentialRequest request = new Fido2CredentialRequest(mUi); + request.setIsHybridRequest(true); + final Origin origin = Origin.create(new GURL("https://" + params.relyingPartyId)); + request.handleGetAssertionRequest( + mContext, params, - Uri.parse("https://" + params.relyingPartyId), - params.challenge, - tunnelId, - args); - - Task<PendingIntent> task = - call.run( - Fido2ApiCall.METHOD_BROWSER_SIGN, - Fido2ApiCall.TRANSACTION_SIGN, - args, - result); - awaitPendingIntent(task, SIGN_REQUEST_CODE); - } - - private void awaitPendingIntent(Task<PendingIntent> task, int requestCode) { - task.addOnSuccessListener( - pendingIntent -> { - try { - mUi.startIntentSenderForResult( - pendingIntent.getIntentSender(), - requestCode, - null, // fillInIntent, - 0, // flagsMask, - 0, // flagsValue, - 0, // extraFlags, - Bundle.EMPTY); - } catch (IntentSender.SendIntentException e) { - Log.e(TAG, "SendIntentException", e); - } - }) - .addOnFailureListener( - exception -> { - Log.e(TAG, "FIDO2 call failed", exception); - }); + /* frameHost= */ null, + /* maybeClientDataHash= */ params.challenge, + origin, + origin, + /* payment= */ null, + (status, response) -> { + response.info.clientDataJson = new byte[0]; + ByteBuffer buffer = response.serialize(); + byte[] serialized = new byte[buffer.remaining()]; + buffer.get(serialized); + mTaskRunner.postTask( + () -> + CableAuthenticatorJni.get() + .onAuthenticatorAssertionResponse( + CTAP2_OK, serialized)); + mUi.onAuthenticatorResult(Result.SIGN_OK); + }, + (status) -> { + mTaskRunner.postTask( + () -> + CableAuthenticatorJni.get() + .onAuthenticatorAssertionResponse( + CTAP2_ERR_OPERATION_DENIED, null)); + mUi.onAuthenticatorResult(Result.SIGN_ERROR); + }); } /**
diff --git a/chrome/android/features/start_surface/java/res/layout/tasks_view_layout_polish.xml b/chrome/android/features/start_surface/java/res/layout/tasks_view_layout_polish.xml index a75ee2782..b1caaf3 100644 --- a/chrome/android/features/start_surface/java/res/layout/tasks_view_layout_polish.xml +++ b/chrome/android/features/start_surface/java/res/layout/tasks_view_layout_polish.xml
@@ -56,6 +56,7 @@ <include layout="@layout/mv_tiles_container_polish" /> <!-- TODO(crbug.com/982018): Make view stub to inflate only when needed. --> <include layout="@layout/tab_switcher_module_container" /> + <include layout="@layout/home_modules_recycler_view_layout" /> </com.google.android.material.appbar.AppBarLayout> <!-- This incognito_description_container_layout_stub and the below tasks_surface_body
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 9664407..6e721af 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
@@ -131,8 +131,8 @@ || !isTablet && ChromeFeatureList.sShowNtpAtStartupAndroid.isEnabled(); } - /** Returns whether a magic space is enabled on Start surface. */ - public static boolean useMagicSpace() { + /** Returns whether a magic stack is enabled on Start surface. */ + public static boolean useMagicStack() { return ChromeFeatureList.sSurfacePolish.isEnabled() && ChromeFeatureList.sMagicStackAndroid.isEnabled() && ChromeFeatureList.sStartSurfaceRefactor.isEnabled();
diff --git a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinator.java b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinator.java index 4c8a477..3b957b90 100644 --- a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinator.java +++ b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinator.java
@@ -46,6 +46,7 @@ import org.chromium.chrome.browser.init.ChromeActivityNativeDelegate; import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher; import org.chromium.chrome.browser.logo.LogoUtils; +import org.chromium.chrome.browser.magic_stack.HomeModulesCoordinator; import org.chromium.chrome.browser.multiwindow.MultiWindowModeStateDispatcher; import org.chromium.chrome.browser.omnibox.OmniboxFeatures; import org.chromium.chrome.browser.omnibox.OmniboxStub; @@ -321,7 +322,7 @@ mProfileSupplier = profileSupplier; mTabStripHeightSupplier = tabStripHeightSupplier; - mUseMagicSpace = mIsStartSurfaceEnabled && StartSurfaceConfiguration.useMagicSpace(); + mUseMagicSpace = mIsStartSurfaceEnabled && StartSurfaceConfiguration.useMagicStack(); mTabSwitcherCustomViewManagerSupplier = new ObservableSupplierImpl<>(); mIsStartSurfaceRefactorEnabled = ReturnToChromeUtil.isStartSurfaceRefactorEnabled(mActivity); @@ -391,12 +392,16 @@ startSurfaceOneshotSupplier, hadWarmStart, initializeMVTilesRunnable, + (moduleDelegateHost) -> + new HomeModulesCoordinator( + mActivity, + moduleDelegateHost, + mView.findViewById(R.id.task_surface_header)), mParentTabSupplier, logoContainerView, mGridTabSwitcher == null ? backPressManager : null, feedPlaceholderParentView, mActivityLifecycleDispatcher, - tabSwitcherClickHandler, mProfileSupplier); startSurfaceOneshotSupplier.set(this);
diff --git a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceMediator.java b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceMediator.java index b01f1b7..e3bef51 100644 --- a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceMediator.java +++ b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceMediator.java
@@ -23,6 +23,7 @@ import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.IS_TAB_CARD_VISIBLE; import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.IS_VOICE_RECOGNITION_BUTTON_VISIBLE; import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.LENS_BUTTON_CLICK_LISTENER; +import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.MAGIC_STACK_VISIBLE; import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.MV_TILES_CONTAINER_TOP_MARGIN; import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.MV_TILES_VISIBLE; import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.QUERY_TILES_VISIBLE; @@ -33,9 +34,9 @@ import android.content.Context; import android.content.res.Resources; +import android.graphics.Point; import android.text.Editable; import android.view.View; -import android.view.View.OnClickListener; import android.view.ViewGroup; import androidx.annotation.ColorInt; @@ -61,6 +62,7 @@ import org.chromium.chrome.browser.feed.FeedActionDelegate; import org.chromium.chrome.browser.feed.FeedReliabilityLogger; import org.chromium.chrome.browser.flags.ChromeFeatureList; +import org.chromium.chrome.browser.homepage.HomepageManager; import org.chromium.chrome.browser.lens.LensEntryPoint; import org.chromium.chrome.browser.lens.LensMetrics; import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher; @@ -68,6 +70,9 @@ import org.chromium.chrome.browser.logo.LogoCoordinator; import org.chromium.chrome.browser.logo.LogoUtils; import org.chromium.chrome.browser.logo.LogoView; +import org.chromium.chrome.browser.magic_stack.HomeModulesCoordinator; +import org.chromium.chrome.browser.magic_stack.ModuleDelegate; +import org.chromium.chrome.browser.magic_stack.ModuleDelegateHost; import org.chromium.chrome.browser.ntp.NewTabPageLaunchOrigin; import org.chromium.chrome.browser.omnibox.OmniboxFocusReason; import org.chromium.chrome.browser.omnibox.OmniboxStub; @@ -93,6 +98,7 @@ import org.chromium.chrome.browser.tasks.tab_management.TabSwitcher; import org.chromium.chrome.browser.tasks.tab_management.TabSwitcher.Controller; import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager; +import org.chromium.chrome.browser.util.BrowserUiUtils.HostSurface; import org.chromium.chrome.features.start_surface.StartSurface.TabSwitcherViewObserver; import org.chromium.components.browser_ui.styles.ChromeColors; import org.chromium.components.browser_ui.widget.gesture.BackPressHandler; @@ -102,6 +108,7 @@ import org.chromium.ui.modelutil.PropertyModel; import org.chromium.ui.text.EmptyTextWatcher; import org.chromium.ui.util.ColorUtils; +import org.chromium.url.GURL; import java.util.List; @@ -111,7 +118,8 @@ StartSurface.OnTabSelectingListener, BackPressHandler, LogoCoordinator.VisibilityObserver, - PauseResumeWithNativeObserver { + PauseResumeWithNativeObserver, + ModuleDelegateHost { /** Interface to initialize a secondary tasks surface for more tabs. */ interface SecondaryTasksSurfaceInitializer { /** @@ -130,6 +138,16 @@ boolean isFinishingOrDestroyed(); } + /** Interface to create the magic stack. */ + interface ModuleDelegateCreator { + /** + * Creates the magic stack {@link ModuleDelegate} object. + * + * @param moduleDelegateHost The home surface which owns the magic stack. + */ + ModuleDelegate create(ModuleDelegateHost moduleDelegateHost); + } + private final ObserverList<TabSwitcherViewObserver> mObservers = new ObserverList<>(); private TabSwitcher.Controller mController; private final TabModelSelector mTabModelSelector; @@ -147,9 +165,9 @@ private final boolean mMoveDownLogo; private final ActivityLifecycleDispatcher mActivityLifecycleDispatcher; private final TabCreatorManager mTabCreatorManager; - private final boolean mUseMagicSpace; + private final boolean mUseMagicStack; private final boolean mIsSurfacePolishEnabled; - + @Nullable private final ModuleDelegateCreator mModuleDelegateCreator; private boolean mShouldIgnoreTabSelecting; // Boolean histogram used to record whether cached @@ -175,6 +193,7 @@ @NewTabPageLaunchOrigin private int mLaunchOrigin; @Nullable private TabModel mNormalTabModel; @Nullable private TabModelObserver mNormalTabModelObserver; + private final int mStartMargin; @Nullable // Observes both regular and incognito TabModel. This observer is responsible to initiate the @@ -223,9 +242,11 @@ // The timestamp at which the Start Surface was last shown to the user. private long mLastShownTimeMs = LAST_SHOW_TIME_NOT_SET; private boolean mIsStartSurfaceRefactorEnabled; - private OnClickListener mTabSwitcherClickHandler; private ObservableSupplier<Profile> mProfileSupplier; + private HomeModulesCoordinator mHomeModulesCoordinator; + private Point mContextMenuStartPosotion; + // TODO(crbug.com/1315676): Clean up TabSwitcher#Controller once the start surface refactoring // is done. StartSurfaceMediator( @@ -243,22 +264,22 @@ OneshotSupplier<StartSurface> startSurfaceSupplier, boolean hadWarmStart, Runnable initializeMVTilesRunnable, + @Nullable ModuleDelegateCreator moduleDelegateCreator, Supplier<Tab> parentTabSupplier, View logoContainerView, @Nullable BackPressManager backPressManager, ViewGroup feedPlaceholderParentView, ActivityLifecycleDispatcher activityLifecycleDispatcher, - OnClickListener tabSwitcherClickHandler, ObservableSupplier<Profile> profileSupplier) { mTabSwitcherContainer = tabSwitcherContainer; mTabSwitcherModule = tabSwitcherModule; mController = mTabSwitcherModule != null ? mTabSwitcherModule.getController() : controller; mIsSurfacePolishEnabled = isStartSurfaceEnabled && ChromeFeatureList.sSurfacePolish.isEnabled(); - mUseMagicSpace = isStartSurfaceEnabled && StartSurfaceConfiguration.useMagicSpace(); - // When a magic space is enabled on Start surface, it doesn't need a controller to handle + mUseMagicStack = isStartSurfaceEnabled && StartSurfaceConfiguration.useMagicStack(); + // When a magic stack is enabled on Start surface, it doesn't need a controller to handle // its showing and hiding. - assert mController != null || mUseMagicSpace; + assert mController != null || mUseMagicStack; mTabModelSelector = tabModelSelector; mPropertyModel = propertyModel; @@ -272,16 +293,20 @@ mHadWarmStart = hadWarmStart; mLaunchOrigin = NewTabPageLaunchOrigin.UNKNOWN; mInitializeMVTilesRunnable = initializeMVTilesRunnable; + mModuleDelegateCreator = moduleDelegateCreator; mParentTabSupplier = parentTabSupplier; mLogoContainerView = logoContainerView; mActivityLifecycleDispatcher = activityLifecycleDispatcher; mActivityLifecycleDispatcher.register(this); mMoveDownLogo = ReturnToChromeUtil.moveDownLogo(); mIsStartSurfaceRefactorEnabled = ReturnToChromeUtil.isStartSurfaceRefactorEnabled(context); - mTabSwitcherClickHandler = tabSwitcherClickHandler; mProfileSupplier = profileSupplier; mProfileSupplier.addObserver(this::onProfileAvailable); + mStartMargin = + context.getResources() + .getDimensionPixelSize(R.dimen.mvt_container_lateral_margin_polish); + if (mPropertyModel != null) { assert mIsStartSurfaceEnabled; @@ -289,7 +314,7 @@ mPropertyModel.set(IS_TAB_CARD_VISIBLE, false); } - if (mTabSwitcherModule != null || mUseMagicSpace) { + if (mTabSwitcherModule != null || mUseMagicStack) { // Set the initial state. mPropertyModel.set(IS_SURFACE_BODY_VISIBLE, true); mPropertyModel.set(IS_FAKE_SEARCH_BOX_VISIBLE, true); @@ -319,7 +344,7 @@ mPropertyModel.set(IS_INCOGNITO, mIsIncognito); updateBackgroundColor(mPropertyModel); - if (!mUseMagicSpace) { + if (!mUseMagicStack) { // Hide tab carousel, which does not exist in incognito mode, when closing all // normal tabs. // This TabModelObserver observes the regular TabModel only. @@ -379,7 +404,7 @@ @Override public void didSelectTab(Tab tab, int type, int lastId) { - if (mUseMagicSpace) return; + if (mUseMagicStack) return; if (type == TabSelectionType.FROM_CLOSE && UrlUtilities.isNtpUrl(tab.getUrl())) { @@ -398,7 +423,7 @@ return; } - assert mUseMagicSpace; + assert mUseMagicStack; if (type == TabSelectionType.FROM_CLOSE || type == TabSelectionType.FROM_UNDO) { return; @@ -406,6 +431,9 @@ onTabSelecting(mTabModelSelector.getCurrentTabId()); } }; + mContextMenuStartPosotion = + ReturnToChromeUtil.calculateContextMenuStartPosition( + mContext.getResources()); } if (mTabModelSelector.getModels().isEmpty()) { TabModelSelectorObserver selectorObserver = @@ -425,7 +453,7 @@ mNormalTabModel = mTabModelSelector.getModel(false); if (mPendingObserver) { mPendingObserver = false; - if (!mUseMagicSpace) { + if (!mUseMagicStack) { mNormalTabModel.addObserver(mNormalTabModelObserver); } else { mTabModelSelector @@ -538,6 +566,26 @@ } } + private void initContextMenuStartPosition() { + Resources resources = mContext.getResources(); + int contextMenuStartX = + resources.getDimensionPixelSize( + org.chromium.chrome.start_surface.R.dimen + .single_tab_module_lateral_margin) + + resources.getDimensionPixelSize( + org.chromium.chrome.start_surface.R.dimen + .single_tab_module_padding_bottom) + + resources.getDimensionPixelSize( + org.chromium.chrome.start_surface.R.dimen + .single_tab_module_tab_thumbnail_size); + int contextMenuStartY = + resources.getDimensionPixelSize( + org.chromium.chrome.start_surface.R.dimen + .single_tab_module_padding_top) + * 3; + mContextMenuStartPosotion = new Point(contextMenuStartX, contextMenuStartY); + } + void initWithNative( @Nullable OmniboxStub omniboxStub, @Nullable ExploreSurfaceCoordinatorFactory exploreSurfaceCoordinatorFactory, @@ -568,7 +616,7 @@ if (mLogoCoordinator != null) mLogoCoordinator.initWithNative(); } - if (mTabSwitcherModule != null || mUseMagicSpace) { + if (mTabSwitcherModule != null || mUseMagicStack) { mPropertyModel.set( FAKE_SEARCH_BOX_CLICK_LISTENER, v -> { @@ -647,6 +695,9 @@ mLogoCoordinator.destroy(); mLogoCoordinator = null; } + if (mHomeModulesCoordinator != null) { + mHomeModulesCoordinator.hide(); + } if (mCallbackController != null) { mCallbackController.destroy(); } @@ -707,6 +758,7 @@ mPropertyModel.set(IS_INCOGNITO, mIsIncognito); updateBackgroundColor(mPropertyModel); setMVTilesVisibility(!mIsIncognito); + setMagicStackVisibility(!mIsIncognito); setLogoVisibility(!mIsIncognito); setTabCardVisibility(getNormalTabCount() > 0 && !mIsIncognito); setExploreSurfaceVisibility(!mIsIncognito && mExploreSurfaceCoordinatorFactory != null); @@ -735,7 +787,7 @@ mPropertyModel.set(IS_SHOWING_OVERVIEW, true); if (mNormalTabModel != null) { - if (!mUseMagicSpace) { + if (!mUseMagicStack) { mNormalTabModel.addObserver(mNormalTabModelObserver); } else { mTabModelSelector @@ -1201,6 +1253,9 @@ mPropertyModel.set(IS_SHOWING_OVERVIEW, false); destroyExploreSurfaceCoordinator(); + if (mHomeModulesCoordinator != null) { + mHomeModulesCoordinator.hide(); + } if (mNormalTabModel != null) { if (mNormalTabModelObserver != null) { mNormalTabModel.removeObserver(mNormalTabModelObserver); @@ -1444,7 +1499,7 @@ } private void setTabCardVisibility(boolean isVisible) { - if (mUseMagicSpace) return; + if (mUseMagicStack) return; // If the single tab switcher is shown and the current selected tab is a new tab page, we // shouldn't show the tab switcher layout on Start. @@ -1462,6 +1517,24 @@ if (isVisible && mInitializeMVTilesRunnable != null) mInitializeMVTilesRunnable.run(); } + @VisibleForTesting + void setMagicStackVisibility(boolean isVisible) { + if (!StartSurfaceConfiguration.useMagicStack()) return; + + assert mModuleDelegateCreator != null; + if (isVisible) { + if (mHomeModulesCoordinator == null) { + mHomeModulesCoordinator = + (HomeModulesCoordinator) mModuleDelegateCreator.create(this); + } + mHomeModulesCoordinator.show(this::onMagicStackShown); + } + } + + private void onMagicStackShown(boolean isVisible) { + mPropertyModel.set(MAGIC_STACK_VISIBLE, isVisible); + } + private void setLogoVisibility(boolean isVisible) { if (!mMoveDownLogo) return; @@ -1764,6 +1837,41 @@ : mStartSurfaceState == StartSurfaceState.SHOWN_HOMEPAGE; } + @Override + public int getHostSurfaceType() { + return HostSurface.START_SURFACE; + } + + @Override + public Point getContextMenuStartPoint() { + return mContextMenuStartPosotion; + } + + @Override + public void onUrlClicked(GURL gurl) { + ReturnToChromeUtil.handleLoadUrlFromStartSurface(new LoadUrlParams(gurl), false, null); + } + + @Override + public void onTabSelected(int tabId) { + mOnTabSelectingListener.onTabSelecting(tabId); + } + + @Override + public void customizeSettings() { + HomepageManager.getInstance().onMenuClick(mContext); + } + + @Override + public boolean showScrollableMvt() { + return true; + } + + @Override + public int getStartMargin() { + return mStartMargin; + } + public FeedActionDelegate getFeedActionDelegateForTesting() { assert mPropertyModel.get(EXPLORE_SURFACE_COORDINATOR) != null; return mPropertyModel @@ -1783,6 +1891,10 @@ return mInitializeMVTilesRunnable; } + HomeModulesCoordinator getHomeModulesCoordinatorForTesting() { + return mHomeModulesCoordinator; + } + /** * Update the background color of the start surface based on whether it is polished or not , * in the incognito mode or non-incognito mode.
diff --git a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/tasks/TasksSurfaceProperties.java b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/tasks/TasksSurfaceProperties.java index a57cbfd0..1dd03fd9 100644 --- a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/tasks/TasksSurfaceProperties.java +++ b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/tasks/TasksSurfaceProperties.java
@@ -58,6 +58,8 @@ LENS_BUTTON_CLICK_LISTENER = new PropertyModel.WritableObjectPropertyKey<>(); public static final PropertyModel.WritableBooleanPropertyKey MV_TILES_VISIBLE = IS_CONTAINER_VISIBLE; + public static final PropertyModel.WritableBooleanPropertyKey MAGIC_STACK_VISIBLE = + new PropertyModel.WritableBooleanPropertyKey(); public static final PropertyModel.WritableBooleanPropertyKey QUERY_TILES_VISIBLE = new PropertyModel.WritableBooleanPropertyKey(); public static final PropertyModel.WritableObjectPropertyKey<View.OnClickListener> @@ -95,6 +97,7 @@ LENS_BUTTON_CLICK_LISTENER, MV_TILES_VISIBLE, QUERY_TILES_VISIBLE, + MAGIC_STACK_VISIBLE, VOICE_SEARCH_BUTTON_CLICK_LISTENER, TASKS_SURFACE_BODY_TOP_MARGIN, MV_TILES_CONTAINER_TOP_MARGIN,
diff --git a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/tasks/TasksView.java b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/tasks/TasksView.java index 5253ecc..8b74425 100644 --- a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/tasks/TasksView.java +++ b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/tasks/TasksView.java
@@ -19,6 +19,7 @@ import android.widget.FrameLayout; import androidx.annotation.ColorInt; +import androidx.annotation.Nullable; import androidx.appcompat.content.res.AppCompatResources; import androidx.coordinatorlayout.widget.CoordinatorLayout; @@ -48,6 +49,7 @@ private FrameLayout mCardTabSwitcherContainer; private AppBarLayout mHeaderView; private ViewGroup mMvTilesContainerLayout; + @Nullable private ViewGroup mHomeModulesLayout; private SearchBoxCoordinator mSearchBoxCoordinator; private IncognitoDescriptionView mIncognitoDescriptionView; private View.OnClickListener mIncognitoDescriptionLearnMoreListener; @@ -88,6 +90,7 @@ mCardTabSwitcherContainer = (FrameLayout) findViewById(R.id.tab_switcher_module_container); mMvTilesContainerLayout = findViewById(R.id.mv_tiles_container); mSearchBoxCoordinator = new SearchBoxCoordinator(getContext(), this); + mHomeModulesLayout = findViewById(R.id.home_modules_recycler_view); mHeaderView = (AppBarLayout) findViewById(R.id.task_surface_header); @@ -140,7 +143,12 @@ mMvTilesContainerLayout.setVisibility(visibility); } - /** Set the visibility of the Most Visited Tiles. */ + /** Set the visibility of the Magic stack. */ + void setMagicStackVisibility(int visibility) { + mHomeModulesLayout.setVisibility(visibility); + } + + /** Set the visibility of the Query Tiles. */ void setQueryTilesVisibility(int visibility) { findViewById(R.id.query_tiles_container).setVisibility(visibility); }
diff --git a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/tasks/TasksViewBinder.java b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/tasks/TasksViewBinder.java index 368342b..035c702 100644 --- a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/tasks/TasksViewBinder.java +++ b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/tasks/TasksViewBinder.java
@@ -22,6 +22,7 @@ import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.IS_TAB_CARD_VISIBLE; import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.IS_VOICE_RECOGNITION_BUTTON_VISIBLE; import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.LENS_BUTTON_CLICK_LISTENER; +import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.MAGIC_STACK_VISIBLE; import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.MV_TILES_CONTAINER_TOP_MARGIN; import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.MV_TILES_VISIBLE; import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.QUERY_TILES_VISIBLE; @@ -90,6 +91,8 @@ .addLensButtonClickListener(model.get(LENS_BUTTON_CLICK_LISTENER)); } else if (propertyKey == MV_TILES_VISIBLE) { view.setMostVisitedVisibility(model.get(MV_TILES_VISIBLE) ? View.VISIBLE : View.GONE); + } else if (propertyKey == MAGIC_STACK_VISIBLE) { + view.setMagicStackVisibility(model.get(MAGIC_STACK_VISIBLE) ? View.VISIBLE : View.GONE); } else if (propertyKey == QUERY_TILES_VISIBLE) { view.setQueryTilesVisibility(model.get(QUERY_TILES_VISIBLE) ? View.VISIBLE : View.GONE); } else if (propertyKey == VOICE_SEARCH_BUTTON_CLICK_LISTENER) {
diff --git a/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/StartSurfaceMediatorUnitTest.java b/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/StartSurfaceMediatorUnitTest.java index 64727e2..a60737a 100644 --- a/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/StartSurfaceMediatorUnitTest.java +++ b/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/StartSurfaceMediatorUnitTest.java
@@ -54,7 +54,6 @@ import android.app.Activity; import android.content.res.Resources; import android.view.View; -import android.view.View.OnClickListener; import androidx.annotation.ColorInt; import androidx.test.ext.junit.rules.ActivityScenarioRule; @@ -93,6 +92,7 @@ import org.chromium.chrome.browser.logo.LogoBridge; import org.chromium.chrome.browser.logo.LogoBridgeJni; import org.chromium.chrome.browser.logo.LogoView; +import org.chromium.chrome.browser.magic_stack.HomeModulesCoordinator; import org.chromium.chrome.browser.ntp.NewTabPageLaunchOrigin; import org.chromium.chrome.browser.omnibox.OmniboxStub; import org.chromium.chrome.browser.omnibox.UrlFocusChangeListener; @@ -172,9 +172,9 @@ @Mock private Profile mProfile; @Mock private TemplateUrlService mTemplateUrlService; @Mock private ActivityLifecycleDispatcher mActivityLifecycleDispatcher; - @Mock private OnClickListener mTabSwitcherClickHandler; @Mock private TabSwitcher mTabSwitcherModule; @Mock private TabListDelegate mTabListDelegate; + @Mock private HomeModulesCoordinator mHomeModulesCoordinator; @Captor private ArgumentCaptor<TabModelSelectorObserver> mTabModelSelectorObserverCaptor; @Captor private ArgumentCaptor<TabModelObserver> mTabModelObserverCaptor; @@ -266,6 +266,8 @@ .getFeedReliabilityLogger(); mJniMocker.mock(LogoBridgeJni.TEST_HOOKS, mLogoBridge); doReturn(mLogoView).when(mLogoContainerView).findViewById(R.id.search_provider_logo); + + when(mOmniboxStub.getVoiceRecognitionHandler()).thenReturn(mVoiceRecognitionHandler); } @After @@ -302,7 +304,6 @@ @Test public void showAndHideSingleSurface() { doReturn(false).when(mTabModelSelector).isIncognitoSelected(); - doReturn(mVoiceRecognitionHandler).when(mOmniboxStub).getVoiceRecognitionHandler(); doReturn(true).when(mVoiceRecognitionHandler).isVoiceSearchEnabled(); StartSurfaceMediator mediator = @@ -355,7 +356,6 @@ @Test public void hideTabCardWithNoTabs() { doReturn(false).when(mTabModelSelector).isIncognitoSelected(); - doReturn(mVoiceRecognitionHandler).when(mOmniboxStub).getVoiceRecognitionHandler(); doReturn(true).when(mVoiceRecognitionHandler).isVoiceSearchEnabled(); StartSurfaceMediator mediator = @@ -371,7 +371,6 @@ @Test public void hideTabCardWhenClosingLastTab() { doReturn(false).when(mTabModelSelector).isIncognitoSelected(); - doReturn(mVoiceRecognitionHandler).when(mOmniboxStub).getVoiceRecognitionHandler(); doReturn(true).when(mVoiceRecognitionHandler).isVoiceSearchEnabled(); StartSurfaceMediator mediator = @@ -397,7 +396,6 @@ @Test public void hideTabCardWhenClosingAndSelectingNtpTab() { doReturn(false).when(mTabModelSelector).isIncognitoSelected(); - doReturn(mVoiceRecognitionHandler).when(mOmniboxStub).getVoiceRecognitionHandler(); doReturn(true).when(mVoiceRecognitionHandler).isVoiceSearchEnabled(); StartSurfaceMediator mediator = @@ -426,7 +424,6 @@ @Test public void reshowTabCardWhenTabClosureUndone() { doReturn(false).when(mTabModelSelector).isIncognitoSelected(); - doReturn(mVoiceRecognitionHandler).when(mOmniboxStub).getVoiceRecognitionHandler(); doReturn(true).when(mVoiceRecognitionHandler).isVoiceSearchEnabled(); StartSurfaceMediator mediator = @@ -460,7 +457,6 @@ @Test public void pendingTabModelObserverWithBothShowOverviewAndHideBeforeTabModelInitialization() { doReturn(false).when(mTabModelSelector).isIncognitoSelected(); - doReturn(mVoiceRecognitionHandler).when(mOmniboxStub).getVoiceRecognitionHandler(); doReturn(true).when(mVoiceRecognitionHandler).isVoiceSearchEnabled(); mTabModels.clear(); @@ -478,7 +474,6 @@ @Test public void pendingTabModelObserverWithShowOverviewBeforeAndHideAfterTabModelInitialization() { doReturn(false).when(mTabModelSelector).isIncognitoSelected(); - doReturn(mVoiceRecognitionHandler).when(mOmniboxStub).getVoiceRecognitionHandler(); doReturn(true).when(mVoiceRecognitionHandler).isVoiceSearchEnabled(); mTabModels.clear(); @@ -502,7 +497,6 @@ @Test public void pendingTabModelObserverWithBothShowAndHideOverviewAfterTabModelInitialization() { doReturn(false).when(mTabModelSelector).isIncognitoSelected(); - doReturn(mVoiceRecognitionHandler).when(mOmniboxStub).getVoiceRecognitionHandler(); doReturn(true).when(mVoiceRecognitionHandler).isVoiceSearchEnabled(); mTabModels.clear(); @@ -526,7 +520,6 @@ @Test public void addAndRemoveTabModelSelectorObserverWithOverviewAfterTabModelInitialization() { doReturn(false).when(mTabModelSelector).isIncognitoSelected(); - doReturn(mVoiceRecognitionHandler).when(mOmniboxStub).getVoiceRecognitionHandler(); doReturn(true).when(mVoiceRecognitionHandler).isVoiceSearchEnabled(); StartSurfaceMediator mediator = @@ -543,7 +536,6 @@ @Test public void addAndRemoveTabModelSelectorObserverWithOverview() { doReturn(false).when(mTabModelSelector).isIncognitoSelected(); - doReturn(mVoiceRecognitionHandler).when(mOmniboxStub).getVoiceRecognitionHandler(); doReturn(true).when(mVoiceRecognitionHandler).isVoiceSearchEnabled(); StartSurfaceMediator mediator = @@ -565,7 +557,6 @@ @DisableFeatures(ChromeFeatureList.START_SURFACE_REFACTOR) public void overviewModeStatesNormalModeSinglePane() { doReturn(false).when(mTabModelSelector).isIncognitoSelected(); - doReturn(mVoiceRecognitionHandler).when(mOmniboxStub).getVoiceRecognitionHandler(); doReturn(true).when(mVoiceRecognitionHandler).isVoiceSearchEnabled(); StartSurfaceMediator mediator = @@ -613,7 +604,6 @@ @Test public void overviewModeIncognitoModeSinglePane() { doReturn(true).when(mTabModelSelector).isIncognitoSelected(); - doReturn(mVoiceRecognitionHandler).when(mOmniboxStub).getVoiceRecognitionHandler(); doReturn(true).when(mVoiceRecognitionHandler).isVoiceSearchEnabled(); StartSurfaceMediator mediator = @@ -646,7 +636,6 @@ @Test public void overviewModeSwitchToIncognitoModeAndBackSinglePane() { doReturn(false).when(mTabModelSelector).isIncognitoSelected(); - doReturn(mVoiceRecognitionHandler).when(mOmniboxStub).getVoiceRecognitionHandler(); doReturn(true).when(mVoiceRecognitionHandler).isVoiceSearchEnabled(); StartSurfaceMediator mediator = @@ -692,7 +681,6 @@ @DisableFeatures(ChromeFeatureList.START_SURFACE_REFACTOR) public void activityIsFinishingOrDestroyedSinglePane() { doReturn(false).when(mTabModelSelector).isIncognitoSelected(); - doReturn(mVoiceRecognitionHandler).when(mOmniboxStub).getVoiceRecognitionHandler(); doReturn(true).when(mVoiceRecognitionHandler).isVoiceSearchEnabled(); StartSurfaceMediator mediator = @@ -745,7 +733,6 @@ @EnableFeatures(ChromeFeatureList.START_SURFACE_REFACTOR) public void activityIsFinishingOrDestroyedSinglePaneWithRefactorEnabled() { doReturn(false).when(mTabModelSelector).isIncognitoSelected(); - doReturn(mVoiceRecognitionHandler).when(mOmniboxStub).getVoiceRecognitionHandler(); doReturn(true).when(mVoiceRecognitionHandler).isVoiceSearchEnabled(); StartSurfaceMediator mediator = @@ -771,7 +758,6 @@ @Test public void overviewModeIncognitoTabswitcher() { doReturn(false).when(mTabModelSelector).isIncognitoSelected(); - doReturn(mVoiceRecognitionHandler).when(mOmniboxStub).getVoiceRecognitionHandler(); doReturn(true).when(mVoiceRecognitionHandler).isVoiceSearchEnabled(); StartSurfaceMediator mediator = @@ -808,7 +794,6 @@ @Test public void paddingForBottomBarSinglePane() { doReturn(false).when(mTabModelSelector).isIncognitoSelected(); - doReturn(mVoiceRecognitionHandler).when(mOmniboxStub).getVoiceRecognitionHandler(); doReturn(true).when(mVoiceRecognitionHandler).isVoiceSearchEnabled(); StartSurfaceMediator mediator = @@ -847,7 +832,6 @@ @Test public void setIncognitoDescriptionShowSinglePane() { doReturn(false).when(mTabModelSelector).isIncognitoSelected(); - doReturn(mVoiceRecognitionHandler).when(mOmniboxStub).getVoiceRecognitionHandler(); doReturn(true).when(mVoiceRecognitionHandler).isVoiceSearchEnabled(); StartSurfaceMediator mediator = @@ -898,7 +882,6 @@ @Test public void setIncognitoDescriptionHideSinglePane() { doReturn(false).when(mTabModelSelector).isIncognitoSelected(); - doReturn(mVoiceRecognitionHandler).when(mOmniboxStub).getVoiceRecognitionHandler(); doReturn(true).when(mVoiceRecognitionHandler).isVoiceSearchEnabled(); StartSurfaceMediator mediator = @@ -943,7 +926,6 @@ @Test public void showAndHideTabSwitcherToolbarHomePage() { doReturn(false).when(mTabModelSelector).isIncognitoSelected(); - doReturn(mVoiceRecognitionHandler).when(mOmniboxStub).getVoiceRecognitionHandler(); doReturn(true).when(mVoiceRecognitionHandler).isVoiceSearchEnabled(); StartSurfaceMediator mediator = @@ -989,7 +971,6 @@ @Test public void setOverviewState_webFeed_resetsFeedInstanceState() { doReturn(false).when(mTabModelSelector).isIncognitoSelected(); - doReturn(mVoiceRecognitionHandler).when(mOmniboxStub).getVoiceRecognitionHandler(); doReturn(true).when(mVoiceRecognitionHandler).isVoiceSearchEnabled(); StartSurfaceMediator mediator = createStartSurfaceMediator(/* isStartSurfaceEnabled= */ true); @@ -1006,7 +987,6 @@ @Test public void setOverviewState_nonWebFeed_doesNotResetFeedInstanceState() { doReturn(false).when(mTabModelSelector).isIncognitoSelected(); - doReturn(mVoiceRecognitionHandler).when(mOmniboxStub).getVoiceRecognitionHandler(); doReturn(true).when(mVoiceRecognitionHandler).isVoiceSearchEnabled(); StartSurfaceMediator mediator = createStartSurfaceMediator(/* isStartSurfaceEnabled= */ true); @@ -1035,7 +1015,6 @@ @Test public void defaultStateSinglePane() { doReturn(false).when(mTabModelSelector).isIncognitoSelected(); - doReturn(mVoiceRecognitionHandler).when(mOmniboxStub).getVoiceRecognitionHandler(); doReturn(true).when(mVoiceRecognitionHandler).isVoiceSearchEnabled(); StartSurfaceMediator mediator = @@ -1052,7 +1031,6 @@ @Test public void showAndHideTabSwitcherToolbarTabswitcher() { doReturn(false).when(mTabModelSelector).isIncognitoSelected(); - doReturn(mVoiceRecognitionHandler).when(mOmniboxStub).getVoiceRecognitionHandler(); doReturn(true).when(mVoiceRecognitionHandler).isVoiceSearchEnabled(); StartSurfaceMediator mediator = @@ -1097,7 +1075,6 @@ @DisableFeatures(ChromeFeatureList.START_SURFACE_REFACTOR) public void singleShowingPrevious() { doReturn(false).when(mTabModelSelector).isIncognitoSelected(); - doReturn(mVoiceRecognitionHandler).when(mOmniboxStub).getVoiceRecognitionHandler(); doReturn(true).when(mVoiceRecognitionHandler).isVoiceSearchEnabled(); StartSurfaceMediator mediator = @@ -1159,7 +1136,6 @@ @Test public void singleShowingPreviousFromATabOfFeeds() { doReturn(false).when(mTabModelSelector).isIncognitoSelected(); - doReturn(mVoiceRecognitionHandler).when(mOmniboxStub).getVoiceRecognitionHandler(); doReturn(true).when(mVoiceRecognitionHandler).isVoiceSearchEnabled(); StartSurfaceMediator mediator = @@ -1203,7 +1179,6 @@ @Test public void changeTopContentOffset() { doReturn(false).when(mTabModelSelector).isIncognitoSelected(); - doReturn(mVoiceRecognitionHandler).when(mOmniboxStub).getVoiceRecognitionHandler(); doReturn(true).when(mVoiceRecognitionHandler).isVoiceSearchEnabled(); doNothing() @@ -1263,7 +1238,6 @@ @Test public void exploreSurfaceInitializedAfterNativeInSinglePane() { doReturn(false).when(mTabModelSelector).isIncognitoSelected(); - doReturn(mVoiceRecognitionHandler).when(mOmniboxStub).getVoiceRecognitionHandler(); doReturn(true).when(mVoiceRecognitionHandler).isVoiceSearchEnabled(); StartSurfaceMediator mediator = @@ -1271,7 +1245,7 @@ /* isStartSurfaceEnabled= */ true, /* isRefactorEnabled= */ false, /* hadWarmStart= */ false, - /* useMagicSpace= */ false); + /* useMagicStack= */ false); verify(mSingleTabSwitcherModuleController) .addTabSwitcherViewObserver( mCardTabSwitcherModuleVisibilityObserverCaptor.capture()); @@ -1299,7 +1273,7 @@ /* isStartSurfaceEnabled= */ true, /* isRefactorEnabled= */ false, /* hadWarmStart= */ false, - /* useMagicSpace= */ false); + /* useMagicStack= */ false); assertThat( mPropertyModel.get(TASKS_SURFACE_BODY_TOP_MARGIN), equalTo(tasksSurfaceBodyTopMarginPolished)); @@ -1326,7 +1300,7 @@ /* isStartSurfaceEnabled= */ true, /* isRefactorEnabled= */ false, /* hadWarmStart= */ false, - /* useMagicSpace= */ false); + /* useMagicStack= */ false); // Tasks surface body top margin should be updated when tab single card visibility // is changed. @@ -1353,7 +1327,6 @@ @EnableFeatures(INSTANT_START) public void feedPlaceholderFromWarmStart() { doReturn(false).when(mTabModelSelector).isIncognitoSelected(); - doReturn(mVoiceRecognitionHandler).when(mOmniboxStub).getVoiceRecognitionHandler(); doReturn(true).when(mVoiceRecognitionHandler).isVoiceSearchEnabled(); StartSurfaceMediator mediator = @@ -1361,7 +1334,7 @@ /* isStartSurfaceEnabled= */ true, /* isRefactorEnabled= */ false, /* hadWarmStart= */ true, - /* useMagicSpace= */ false); + /* useMagicStack= */ false); assertFalse(mediator.shouldShowFeedPlaceholder()); mPropertyModel.set(IS_EXPLORE_SURFACE_VISIBLE, true); @@ -1377,7 +1350,6 @@ @Test public void setSecondaryTasksSurfaceVisibilityWhenShowingTabSwitcher() { doReturn(false).when(mTabModelSelector).isIncognitoSelected(); - doReturn(mVoiceRecognitionHandler).when(mOmniboxStub).getVoiceRecognitionHandler(); doReturn(true).when(mVoiceRecognitionHandler).isVoiceSearchEnabled(); StartSurfaceMediator mediator = @@ -1399,7 +1371,6 @@ @Test public void singeTabSwitcherHideTabSwitcherTitle() { doReturn(false).when(mTabModelSelector).isIncognitoSelected(); - doReturn(mVoiceRecognitionHandler).when(mOmniboxStub).getVoiceRecognitionHandler(); doReturn(true).when(mVoiceRecognitionHandler).isVoiceSearchEnabled(); doReturn(TabSwitcherType.SINGLE) .when(mSingleTabSwitcherModuleController) @@ -1419,7 +1390,6 @@ @Test public void hideSingleTabSwitcherWhenCurrentSelectedTabIsNtp() { doReturn(false).when(mTabModelSelector).isIncognitoSelected(); - doReturn(mVoiceRecognitionHandler).when(mOmniboxStub).getVoiceRecognitionHandler(); doReturn(true).when(mVoiceRecognitionHandler).isVoiceSearchEnabled(); doReturn(2).when(mNormalTabModel).getCount(); doReturn(true).when(mTabModelSelector).isTabStateInitialized(); @@ -1443,7 +1413,6 @@ @Test public void testInitializeMVTilesWhenShownHomepage() { doReturn(false).when(mTabModelSelector).isIncognitoSelected(); - doReturn(mVoiceRecognitionHandler).when(mOmniboxStub).getVoiceRecognitionHandler(); doReturn(true).when(mVoiceRecognitionHandler).isVoiceSearchEnabled(); doReturn(2).when(mNormalTabModel).getCount(); doReturn(true).when(mTabModelSelector).isTabStateInitialized(); @@ -1456,7 +1425,6 @@ @Test public void testNotInitializeLogoWhenShownHomepage() { - doReturn(mVoiceRecognitionHandler).when(mOmniboxStub).getVoiceRecognitionHandler(); when(mTemplateUrlService.doesDefaultSearchEngineHaveLogo()).thenReturn(true); StartSurfaceMediator mediator = @@ -1464,7 +1432,7 @@ /* isStartSurfaceEnabled= */ true, /* isRefactorEnabled= */ false, /* hadWarmStart= */ false, - /* useMagicSpace= */ false); + /* useMagicStack= */ false); showHomepageAndVerify(mediator, StartSurfaceState.SHOWN_HOMEPAGE); verify(mLogoContainerView, times(0)).setVisibility(View.VISIBLE); @@ -1474,7 +1442,6 @@ @Test @EnableFeatures(ChromeFeatureList.SURFACE_POLISH) public void testInitializeLogoWhenSurfacePolishedMoveDownLogoEnabled() { - doReturn(mVoiceRecognitionHandler).when(mOmniboxStub).getVoiceRecognitionHandler(); when(mTemplateUrlService.doesDefaultSearchEngineHaveLogo()).thenReturn(true); StartSurfaceConfiguration.SURFACE_POLISH_MOVE_DOWN_LOGO.setForTesting(true); @@ -1485,7 +1452,7 @@ /* isStartSurfaceEnabled= */ true, /* isRefactorEnabled= */ false, /* hadWarmStart= */ false, - /* useMagicSpace= */ false); + /* useMagicStack= */ false); showHomepageAndVerify(mediator, StartSurfaceState.SHOWN_HOMEPAGE); verify(mLogoContainerView).setVisibility(View.VISIBLE); @@ -1496,7 +1463,6 @@ @Test @EnableFeatures(ChromeFeatureList.SURFACE_POLISH) public void testNotInitializeLogoWhenSurfacePolishedMoveDownLogoDisabled() { - doReturn(mVoiceRecognitionHandler).when(mOmniboxStub).getVoiceRecognitionHandler(); when(mTemplateUrlService.doesDefaultSearchEngineHaveLogo()).thenReturn(true); Assert.assertFalse(ReturnToChromeUtil.moveDownLogo()); @@ -1506,7 +1472,7 @@ /* isStartSurfaceEnabled= */ true, /* isRefactorEnabled= */ false, /* hadWarmStart= */ false, - /* useMagicSpace= */ false); + /* useMagicStack= */ false); showHomepageAndVerify(mediator, StartSurfaceState.SHOWN_HOMEPAGE); verify(mLogoContainerView, times(0)).setVisibility(View.VISIBLE); @@ -1515,8 +1481,6 @@ @Test public void testFeedReliabilityLoggerPageLoadStarted() { - doReturn(mVoiceRecognitionHandler).when(mOmniboxStub).getVoiceRecognitionHandler(); - StartSurfaceMediator mediator = createStartSurfaceMediator(/* isStartSurfaceEnabled= */ true); showHomepageAndVerify(mediator, StartSurfaceState.SHOWN_HOMEPAGE); @@ -1529,8 +1493,6 @@ @Test public void testFeedReliabilityLoggerObservesUrlFocus() { - doReturn(mVoiceRecognitionHandler).when(mOmniboxStub).getVoiceRecognitionHandler(); - StartSurfaceMediator mediator = createStartSurfaceMediator(/* isStartSurfaceEnabled= */ true); verify(mSingleTabSwitcherModuleController) @@ -1556,7 +1518,6 @@ @Test public void testFeedReliabilityLoggerBackPressed() { - doReturn(mVoiceRecognitionHandler).when(mOmniboxStub).getVoiceRecognitionHandler(); StartSurfaceMediator mediator = createStartSurfaceMediator(/* isStartSurfaceEnabled= */ true); showHomepageAndVerify(mediator, StartSurfaceState.SHOWN_HOMEPAGE); @@ -1572,7 +1533,6 @@ @DisableFeatures(ChromeFeatureList.START_SURFACE_REFACTOR) public void testBackPressHandler() { doReturn(false).when(mTabModelSelector).isIncognitoSelected(); - doReturn(mVoiceRecognitionHandler).when(mOmniboxStub).getVoiceRecognitionHandler(); doReturn(true).when(mVoiceRecognitionHandler).isVoiceSearchEnabled(); doAnswer((inv) -> mCardTabSwitcherModuleControllerDialogVisibleSupplier.get()) .when(mSingleTabSwitcherModuleController) @@ -1650,7 +1610,6 @@ @StartSurfaceState Integer state) { doReturn(false).when(mTabModelSelector).isIncognitoSelected(); doReturn(false).when(mTabModelSelector).isIncognitoSelected(); - doReturn(mVoiceRecognitionHandler).when(mOmniboxStub).getVoiceRecognitionHandler(); doReturn(true).when(mVoiceRecognitionHandler).isVoiceSearchEnabled(); StartSurfaceMediator mediator = createStartSurfaceMediator(/* isStartSurfaceEnabled= */ true); @@ -1677,7 +1636,6 @@ public void testBackPressHandlerOnStartSurfaceWithTabSwitcherCreated() { doReturn(false).when(mTabModelSelector).isIncognitoSelected(); doReturn(false).when(mTabModelSelector).isIncognitoSelected(); - doReturn(mVoiceRecognitionHandler).when(mOmniboxStub).getVoiceRecognitionHandler(); doReturn(true).when(mVoiceRecognitionHandler).isVoiceSearchEnabled(); StartSurfaceMediator mediator = @@ -1706,7 +1664,6 @@ public void testBackPressHandlerOnStartSurfaceWithTabSwitcherCreatedAndRefactorEnabled() { doReturn(false).when(mTabModelSelector).isIncognitoSelected(); doReturn(false).when(mTabModelSelector).isIncognitoSelected(); - doReturn(mVoiceRecognitionHandler).when(mOmniboxStub).getVoiceRecognitionHandler(); doReturn(true).when(mVoiceRecognitionHandler).isVoiceSearchEnabled(); StartSurfaceMediator mediator = @@ -1731,7 +1688,6 @@ public void testBackPressHandlerOnTabSwitcher() { doReturn(false).when(mTabModelSelector).isIncognitoSelected(); doReturn(false).when(mTabModelSelector).isIncognitoSelected(); - doReturn(mVoiceRecognitionHandler).when(mOmniboxStub).getVoiceRecognitionHandler(); doReturn(true).when(mVoiceRecognitionHandler).isVoiceSearchEnabled(); StartSurfaceMediator mediator = @@ -1781,7 +1737,6 @@ @Test public void testRecordTimeSpendInStart() { doReturn(false).when(mTabModelSelector).isIncognitoSelected(); - doReturn(mVoiceRecognitionHandler).when(mOmniboxStub).getVoiceRecognitionHandler(); doReturn(true).when(mVoiceRecognitionHandler).isVoiceSearchEnabled(); StartSurfaceMediator mediator = createStartSurfaceMediator(/* isStartSurfaceEnabled= */ true); @@ -1817,7 +1772,6 @@ @EnableFeatures(ChromeFeatureList.START_SURFACE_REFACTOR) public void testShowAndOnHide() { doReturn(false).when(mTabModelSelector).isIncognitoSelected(); - doReturn(mVoiceRecognitionHandler).when(mOmniboxStub).getVoiceRecognitionHandler(); doReturn(true).when(mVoiceRecognitionHandler).isVoiceSearchEnabled(); doReturn(mSingleTabSwitcherModuleController).when(mTabSwitcherModule).getController(); doReturn(TabSwitcherType.SINGLE) @@ -1853,15 +1807,13 @@ @Test public void testDefaultSearchEngineChanged() { - doReturn(mVoiceRecognitionHandler).when(mOmniboxStub).getVoiceRecognitionHandler(); - mProfileSupplier = new ObservableSupplierImpl<>(); StartSurfaceMediator mediator = createStartSurfaceMediator( /* isStartSurfaceEnabled= */ true, /* isRefactorEnabled= */ false, /* hadWarmStart= */ false, - /* useMagicSpace= */ false); + /* useMagicStack= */ false); showHomepageAndVerify(mediator, StartSurfaceState.SHOWN_HOMEPAGE); mProfileSupplier.set(mProfile); @@ -1889,7 +1841,6 @@ Assert.assertTrue(ChromeFeatureList.sMagicStackAndroid.isEnabled()); doReturn(false).when(mTabModelSelector).isIncognitoSelected(); - doReturn(mVoiceRecognitionHandler).when(mOmniboxStub).getVoiceRecognitionHandler(); doReturn(true).when(mVoiceRecognitionHandler).isVoiceSearchEnabled(); doReturn(mTabModelFilterProvider).when(mTabModelSelector).getTabModelFilterProvider(); doReturn(true).when(mOmniboxStub).isLensEnabled(LensEntryPoint.TASKS_SURFACE); @@ -1899,7 +1850,7 @@ /* isStartSurfaceEnabled= */ true, /* isRefactorEnabled= */ true, /* hadWarmStart= */ false, - /* useMagicSpace= */ true); + /* useMagicStack= */ true); assertEquals(mInitializeMVTilesRunnable, mediator.getInitializeMVTilesRunnableForTesting()); assertNull(mediator.getTabSwitcherModuleForTesting()); assertNull(mediator.getControllerForTesting()); @@ -1965,7 +1916,6 @@ Assert.assertTrue(ChromeFeatureList.sMagicStackAndroid.isEnabled()); doReturn(false).when(mTabModelSelector).isIncognitoSelected(); - doReturn(mVoiceRecognitionHandler).when(mOmniboxStub).getVoiceRecognitionHandler(); doReturn(true).when(mVoiceRecognitionHandler).isVoiceSearchEnabled(); doReturn(mTabModelFilterProvider).when(mTabModelSelector).getTabModelFilterProvider(); doReturn(true).when(mOmniboxStub).isLensEnabled(LensEntryPoint.TASKS_SURFACE); @@ -1975,7 +1925,7 @@ /* isStartSurfaceEnabled= */ true, /* isRefactorEnabled= */ true, /* hadWarmStart= */ false, - /* useMagicSpace= */ true); + /* useMagicStack= */ true); assertEquals(mInitializeMVTilesRunnable, mediator.getInitializeMVTilesRunnableForTesting()); assertNull(mediator.getTabSwitcherModuleForTesting()); assertNull(mediator.getControllerForTesting()); @@ -2014,7 +1964,6 @@ public void testUpdateStartSurfaceBackgroundColor() { Assert.assertTrue(ChromeFeatureList.sSurfacePolish.isEnabled()); doReturn(false).when(mTabModelSelector).isIncognitoSelected(); - doReturn(mVoiceRecognitionHandler).when(mOmniboxStub).getVoiceRecognitionHandler(); // Make sure the background color is not set. assertEquals(0, mPropertyModel.get(BACKGROUND_COLOR)); @@ -2038,12 +1987,33 @@ assertEquals(newBackgroundColor, mPropertyModel.get(BACKGROUND_COLOR)); } + @Test + @EnableFeatures({ChromeFeatureList.SURFACE_POLISH, ChromeFeatureList.MAGIC_STACK_ANDROID}) + public void testSetMagicStackVisibility() { + assertTrue(StartSurfaceConfiguration.useMagicStack()); + StartSurfaceMediator mediator = + createStartSurfaceMediator( + /* isStartSurfaceEnabled= */ true, + /* isRefactorEnabled= */ false, + /* hadWarmStart= */ false, + /* useMagicStack= */ true); + assertNull(mediator.getHomeModulesCoordinatorForTesting()); + + mediator.setMagicStackVisibility(true); + // Verifies that a HomeModulesCoordinator is created and shown. + assertEquals(mHomeModulesCoordinator, mediator.getHomeModulesCoordinatorForTesting()); + verify(mHomeModulesCoordinator).show(any()); + + mediator.setMagicStackVisibility(false); + verify(mHomeModulesCoordinator).show(any()); + } + private StartSurfaceMediator createStartSurfaceMediator(boolean isStartSurfaceEnabled) { return createStartSurfaceMediator( isStartSurfaceEnabled, /* isRefactorEnabled= */ false, /* hadWarmStart= */ false, - /* useMagicSpace= */ false); + /* useMagicStack= */ false); } private StartSurfaceMediator createStartSurfaceMediator( @@ -2052,17 +2022,17 @@ isStartSurfaceEnabled, isRefactorEnabled, /* hadWarmStart= */ false, - /* useMagicSpace= */ false); + /* useMagicStack= */ false); } private StartSurfaceMediator createStartSurfaceMediator( boolean isStartSurfaceEnabled, boolean isRefactorEnabled, boolean hadWarmStart, - boolean useMagicSpace) { + boolean useMagicStack) { StartSurfaceMediator mediator = createStartSurfaceMediatorWithoutInit( - isStartSurfaceEnabled, isRefactorEnabled, hadWarmStart, useMagicSpace); + isStartSurfaceEnabled, isRefactorEnabled, hadWarmStart, useMagicStack); mediator.initWithNative( mOmniboxStub, isStartSurfaceEnabled ? mExploreSurfaceCoordinatorFactory : null, @@ -2075,11 +2045,11 @@ boolean isStartSurfaceEnabled, boolean isRefactorEnabled, boolean hadWarmStart, - boolean useMagicSpace) { + boolean useMagicStack) { boolean hasTasksView = isStartSurfaceEnabled && !isRefactorEnabled; - boolean hasTabSwitcherModule = isStartSurfaceEnabled && isRefactorEnabled && !useMagicSpace; + boolean hasTabSwitcherModule = isStartSurfaceEnabled && isRefactorEnabled && !useMagicStack; return new StartSurfaceMediator( - useMagicSpace ? null : mSingleTabSwitcherModuleController, + useMagicStack ? null : mSingleTabSwitcherModuleController, /* tabSwitcherContainer= */ null, hasTabSwitcherModule ? mTabSwitcherModule : null, mTabModelSelector, @@ -2093,12 +2063,12 @@ mStartSurfaceSupplier, hadWarmStart, isStartSurfaceEnabled ? mInitializeMVTilesRunnable : null, + useMagicStack ? (homeSurfaceHost) -> mHomeModulesCoordinator : null, mParentTabSupplier, mLogoContainerView, mBackPressManager, /* feedPlaceholderParentView= */ null, mActivityLifecycleDispatcher, - mTabSwitcherClickHandler, mProfileSupplier); }
diff --git a/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/tasks/TasksViewBinderUnitTest.java b/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/tasks/TasksViewBinderUnitTest.java index 2c51d40..a55603e 100644 --- a/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/tasks/TasksViewBinderUnitTest.java +++ b/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/tasks/TasksViewBinderUnitTest.java
@@ -22,6 +22,7 @@ import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.IS_TAB_CARD_VISIBLE; import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.IS_VOICE_RECOGNITION_BUTTON_VISIBLE; import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.LENS_BUTTON_CLICK_LISTENER; +import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.MAGIC_STACK_VISIBLE; import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.MV_TILES_CONTAINER_TOP_MARGIN; import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.MV_TILES_VISIBLE; import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.TASKS_SURFACE_BODY_TOP_MARGIN; @@ -104,13 +105,7 @@ when(mProfile.getPrimaryOTRProfile(true)).thenReturn(mProfile); Profile.setLastUsedProfileForTesting(mProfile); when(mUserPrefsJniMock.get(mProfile)).thenReturn(mPrefService); - mTasksView = - (TasksView) mActivity.getLayoutInflater().inflate(R.layout.tasks_view_layout, null); - mActivity.setContentView(mTasksView); - - mTasksViewPropertyModel = new PropertyModel(TasksSurfaceProperties.ALL_KEYS); - PropertyModelChangeProcessor.create( - mTasksViewPropertyModel, mTasksView, TasksViewBinder::bind); + createTasksView(R.layout.tasks_view_layout); } private boolean isViewVisible(int viewId) { @@ -346,4 +341,24 @@ mTasksViewPropertyModel.set(BACKGROUND_COLOR, newBackgroundColor); assertEquals(newBackgroundColor, ((ColorDrawable) mTasksView.getBackground()).getColor()); } + + @Test + @SmallTest + public void testSetMagicStackVisibility() { + createTasksView(R.layout.tasks_view_layout_polish); + + mTasksViewPropertyModel.set(MAGIC_STACK_VISIBLE, true); + assertTrue(isViewVisible(R.id.home_modules_recycler_view)); + + mTasksViewPropertyModel.set(MAGIC_STACK_VISIBLE, false); + assertFalse(isViewVisible(R.id.home_modules_recycler_view)); + } + + private void createTasksView(int layoutId) { + mTasksView = (TasksView) mActivity.getLayoutInflater().inflate(layoutId, null); + mActivity.setContentView(mTasksView); + mTasksViewPropertyModel = new PropertyModel(TasksSurfaceProperties.ALL_KEYS); + PropertyModelChangeProcessor.create( + mTasksViewPropertyModel, mTasksView, TasksViewBinder::bind); + } }
diff --git a/chrome/android/java/res/layout/new_tab_page_layout.xml b/chrome/android/java/res/layout/new_tab_page_layout.xml index b951d05b..81532c9 100644 --- a/chrome/android/java/res/layout/new_tab_page_layout.xml +++ b/chrome/android/java/res/layout/new_tab_page_layout.xml
@@ -56,6 +56,13 @@ android:inflatedId="@+id/tile_grid_placeholder" android:layout="@layout/new_tab_page_tile_grid_placeholder" /> + <ViewStub + android:id="@+id/home_modules_recycler_view_stub" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout="@layout/home_modules_recycler_view_layout" + android:visibility="gone" /> + <!-- Single tab card --> <ViewStub android:id="@+id/tab_switcher_module_container_stub"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelper.java index a3edc520..42fbac97 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelper.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelper.java
@@ -1354,6 +1354,12 @@ mUpdateHost.requestUpdate(); } + void dragForTabDrop(long time, float x, float y, float deltaX, boolean draggedTabIncognito) { + if (mIncognito == draggedTabIncognito) { + drag(time, x, y, deltaX); + } + } + private void onStripScrollStart() { long currentTime = SystemClock.elapsedRealtime(); @@ -3681,18 +3687,23 @@ return mLastOffsetX; } - void prepareForTabDrop(long time, float currX, float lastX, boolean isSourceStrip) { + void prepareForTabDrop( + long time, + float currX, + float lastX, + boolean isSourceStrip, + boolean draggedTabIncognito) { if (isSourceStrip) { dragActiveClickedTabOntoStrip(time, lastX); - } else { + } else if (mIncognito == draggedTabIncognito) { startReorderModeForTabDrop(currX); } } - void clearForTabDrop(long time, boolean isSourceStrip) { + void clearForTabDrop(long time, boolean isSourceStrip, boolean draggedTabIncognito) { if (isSourceStrip) { dragActiveClickedTabOutOfStrip(time); - } else { + } else if (mIncognito == draggedTabIncognito) { onUpOrCancel(time); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/TabDragSource.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/TabDragSource.java index 1c9dff1..9554ad2 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/TabDragSource.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/TabDragSource.java
@@ -74,6 +74,8 @@ @Nullable private Drawable mAppIcon; /** Drag Event Listener trackers * */ + private static TrackerToken sDragTrackerToken; + // Drag start screen position. private PointF mStartScreenPos; // Last drag positions relative to the source view. Set when drag starts or is moved within @@ -81,7 +83,6 @@ private float mLastXDp; private int mLastAction; private boolean mHoveringInStrip; - private TrackerToken mDragTrackerToken; /** * Prepares the toolbar view to listen to the drag events and data drop after the drag is @@ -146,6 +147,9 @@ if (MultiWindowUtils.getInstance().hasAtMostOneTabWithHomepageEnabled(mTabModelSelector)) { return false; } + if (sDragTrackerToken != null) { + Log.w(TAG, "Attempting to start drag before clearing state from prior drag"); + } // Build shared state with all info. ChromeDropDataAndroid dropData = @@ -153,13 +157,13 @@ updateShadowView(tabBeingDragged, dragSourceView); DragShadowBuilder builder = createDragShadowBuilder(dragSourceView, startPoint, tabPositionX); - mDragTrackerToken = + sDragTrackerToken = DragDropGlobalState.store( mMultiInstanceManager.getCurrentInstanceId(), dropData, builder); boolean res = mDragAndDropDelegate.startDragAndDrop(dragSourceView, builder, dropData); if (!res) { - DragDropGlobalState.clear(mDragTrackerToken); - mDragTrackerToken = null; + DragDropGlobalState.clear(sDragTrackerToken); + sDragTrackerToken = null; } return res; } @@ -268,14 +272,25 @@ mStripLayoutHelperSupplier .get() .prepareForTabDrop( - LayoutManagerImpl.time(), xPx * mPxToDp, mLastXDp, isDragSource()); + LayoutManagerImpl.time(), + xPx * mPxToDp, + mLastXDp, + isDragSource(), + isDraggedTabIncognito()); return true; } private boolean onDragLocation(float xPx, float yPx) { float xDp = xPx * mPxToDp; float yDp = yPx * mPxToDp; - mStripLayoutHelperSupplier.get().drag(LayoutManagerImpl.time(), xDp, yDp, xDp - mLastXDp); + mStripLayoutHelperSupplier + .get() + .dragForTabDrop( + LayoutManagerImpl.time(), + xDp, + yDp, + xDp - mLastXDp, + isDraggedTabIncognito()); return true; } @@ -317,46 +332,47 @@ private boolean onDragEnd( View view, float xPx, float yPx, boolean dropHandled, boolean didExitToolbar) { - try { - mHoveringInStrip = false; - // No-op for destination strip. Note: If we add updates for target strip, also check for - // !TabUiFeatureUtilities.DISABLE_STRIP_TO_STRIP_DD.getValue() - if (!isDragSource()) return false; + mHoveringInStrip = false; - // If tab was dragged and dropped out of source toolbar but the drop was not handled, - // move to a new window. - DragDropGlobalState globalState = DragDropGlobalState.getState(mDragTrackerToken); - Tab tabBeingDragged = globalState != null ? globalState.getData().mTab : null; - if (TabUiFeatureUtilities.isTabDragAsWindowEnabled() - && didExitToolbar - && !dropHandled - && tabBeingDragged != null) { - // Following call is device specific and is intended for specific platform - // SysUI. - sendPositionInfoToSysUI(view, mStartScreenPos.x, mStartScreenPos.y, xPx, yPx); + // No-op for destination strip. Note: If we add updates for target strip, also check for + // !TabUiFeatureUtilities.DISABLE_STRIP_TO_STRIP_DD.getValue() + if (!isDragSource()) return false; - // Hence move the tab to a new Chrome window. - mMultiInstanceManager.moveTabToNewWindow(tabBeingDragged); - } - // TODO (crbug.com/1497784): Remove this method. - mStripLayoutHelperSupplier.get().clearActiveClickedTab(); - if (mShadowView != null) { - mShadowView.clear(); - } - return true; - } finally { - if (mDragTrackerToken != null) { - DragDropGlobalState.clear(mDragTrackerToken); - mDragTrackerToken = null; - } + // If tab was dragged and dropped out of source toolbar but the drop was not handled, + // move to a new window. + DragDropGlobalState globalState = getGlobalState(); + Tab tabBeingDragged = globalState.getData().mTab; + if (TabUiFeatureUtilities.isTabDragAsWindowEnabled() + && didExitToolbar + && !dropHandled + && tabBeingDragged != null) { + // Following call is device specific and is intended for specific platform + // SysUI. + sendPositionInfoToSysUI(view, mStartScreenPos.x, mStartScreenPos.y, xPx, yPx); + + // Hence move the tab to a new Chrome window. + mMultiInstanceManager.moveTabToNewWindow(tabBeingDragged); } + + // TODO (crbug.com/1497784): Remove this method. + mStripLayoutHelperSupplier.get().clearActiveClickedTab(); + if (mShadowView != null) { + mShadowView.clear(); + } + if (sDragTrackerToken != null) { + DragDropGlobalState.clear(sDragTrackerToken); + sDragTrackerToken = null; + } + return true; } private boolean onDragExit() { mHoveringInStrip = false; // Show drag shadow when drag exits strip. showDragShadow(true); - mStripLayoutHelperSupplier.get().clearForTabDrop(LayoutManagerImpl.time(), isDragSource()); + mStripLayoutHelperSupplier + .get() + .clearForTabDrop(LayoutManagerImpl.time(), isDragSource(), isDraggedTabIncognito()); return true; } @@ -372,8 +388,22 @@ builder.update(show); } + private DragDropGlobalState getGlobalState() { + return DragDropGlobalState.getState(sDragTrackerToken); + } + private boolean isDragSource() { - return mDragTrackerToken != null; + DragDropGlobalState globalState = getGlobalState(); + // May attempt to check source on drag end. + if (globalState == null) return false; + return globalState.isDragSourceInstance(mMultiInstanceManager.getCurrentInstanceId()); + } + + private boolean isDraggedTabIncognito() { + DragDropGlobalState globalState = getGlobalState(); + // We should only attempt to access this while we know there's an active drag. + assert globalState != null : "Attempting to access dragged tab with invalid drag state."; + return globalState.getData().mTab.isIncognito(); } private int getTabIdFromClipData(ClipData.Item item) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java index c0ee6b9bd..c9dda30 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java
@@ -34,6 +34,7 @@ import org.chromium.base.metrics.RecordHistogram; import org.chromium.base.metrics.RecordUserAction; import org.chromium.base.supplier.ObservableSupplier; +import org.chromium.base.supplier.ObservableSupplierImpl; import org.chromium.base.supplier.Supplier; import org.chromium.chrome.R; import org.chromium.chrome.browser.app.feed.FeedActionDelegateImpl; @@ -56,10 +57,13 @@ import org.chromium.chrome.browser.feed.componentinterfaces.SurfaceCoordinator; import org.chromium.chrome.browser.feedback.HelpAndFeedbackLauncherImpl; import org.chromium.chrome.browser.flags.ChromeFeatureList; +import org.chromium.chrome.browser.homepage.HomepageManager; import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher; import org.chromium.chrome.browser.lifecycle.LifecycleObserver; import org.chromium.chrome.browser.lifecycle.PauseResumeWithNativeObserver; import org.chromium.chrome.browser.logo.LogoUtils; +import org.chromium.chrome.browser.magic_stack.HomeModulesCoordinator; +import org.chromium.chrome.browser.magic_stack.ModuleDelegateHost; import org.chromium.chrome.browser.native_page.ContextMenuManager; import org.chromium.chrome.browser.omnibox.OmniboxFocusReason; import org.chromium.chrome.browser.omnibox.OmniboxStub; @@ -92,12 +96,14 @@ import org.chromium.chrome.browser.ui.native_page.NativePage; import org.chromium.chrome.browser.ui.native_page.NativePageHost; import org.chromium.chrome.browser.util.BrowserUiUtils; +import org.chromium.chrome.browser.util.BrowserUiUtils.HostSurface; import org.chromium.chrome.browser.xsurface.feed.FeedLaunchReliabilityLogger.SurfaceType; import org.chromium.chrome.features.start_surface.StartSurfaceConfiguration; import org.chromium.chrome.features.tasks.SingleTabSwitcherCoordinator; import org.chromium.components.browser_ui.bottomsheet.BottomSheetController; import org.chromium.components.browser_ui.styles.ChromeColors; import org.chromium.components.browser_ui.styles.SemanticColorUtils; +import org.chromium.components.browser_ui.widget.displaystyle.UiConfig; import org.chromium.components.embedder_support.util.UrlConstants; import org.chromium.components.embedder_support.util.UrlUtilities; import org.chromium.components.feature_engagement.EventConstants; @@ -108,6 +114,7 @@ import org.chromium.content_public.browser.NavigationController; import org.chromium.ui.base.DeviceFormFactor; import org.chromium.ui.base.WindowAndroid; +import org.chromium.url.GURL; import java.util.List; @@ -118,7 +125,8 @@ TemplateUrlServiceObserver, BrowserControlsStateProvider.Observer, FeedSurfaceDelegate, - VoiceRecognitionHandler.Observer { + VoiceRecognitionHandler.Observer, + ModuleDelegateHost { private static final String TAG = "NewTabPage"; // Key for the scroll position data that may be stored in a navigation entry. @@ -170,6 +178,11 @@ private SingleTabSwitcherCoordinator mSingleTabSwitcherCoordinator; private ViewGroup mSingleTabCardContainer; + @Nullable private HomeModulesCoordinator mHomeModulesCoordinator; + @Nullable private ViewGroup mHomeModulesContainer; + private ObservableSupplierImpl<Tab> mMostRecentTabSupplier = new ObservableSupplierImpl<>(); + @Nullable private Point mContextMenuStartPosition; + private final Activity mActivity; @Nullable private final HomeSurfaceTracker mHomeSurfaceTracker; private final boolean mIsNtpAsHomeSurfaceEnabled; @@ -559,10 +572,20 @@ mIsTablet, mTabStripHeightSupplier); + boolean useMagicStack = StartSurfaceConfiguration.useMagicStack(); + if (useMagicStack) { + mContextMenuStartPosition = + ReturnToChromeUtil.calculateContextMenuStartPosition(mActivity.getResources()); + } + // If new NewTabPage is created via back operations, re-show the single Tab card with the // previously tracked Tab. if (mHomeSurfaceTracker != null && mHomeSurfaceTracker.isHomeSurfaceTab(mTab)) { - showHomeSurfaceUi(mHomeSurfaceTracker.getLastActiveTabToTrack()); + if (useMagicStack) { + showMagicStackWithHomeSurfaceUi(mHomeSurfaceTracker.getLastActiveTabToTrack()); + } else { + showHomeSurfaceUi(mHomeSurfaceTracker.getLastActiveTabToTrack()); + } ReturnToChromeUtil.recordHomeSurfaceShown(); } @@ -1180,6 +1203,23 @@ } } + /** + * Shows the magic stack on the home surface NTP. + * + * @param mostRecentTab The last shown Tab. + */ + public void showMagicStackWithHomeSurfaceUi(Tab mostRecentTab) { + if (mostRecentTab != null && !UrlUtilities.isNtpUrl(mostRecentTab.getUrl())) { + mMostRecentTabSupplier.set(mostRecentTab); + } + + if (mHomeModulesCoordinator == null) { + initializeMagicStack(mostRecentTab); + } else { + mHomeModulesCoordinator.show(this::onMagicStackShown); + } + } + /** Show the module when the current new tab page is been used as the home surface. */ private void initializeSingleTabCard(Tab mostRecentTab) { if (mostRecentTab == null || UrlUtilities.isNtpUrl(mostRecentTab.getUrl())) { @@ -1192,7 +1232,7 @@ mNewTabPageLayout.findViewById( R.id.tab_switcher_module_container_stub)) .inflate(); - updateSingleTabCardContainerMargins(); + updateSingleTabCardContainerMargins(mSingleTabCardContainer); mSingleTabSwitcherCoordinator = new SingleTabSwitcherCoordinator( mActivity, @@ -1212,6 +1252,26 @@ mSingleTabSwitcherCoordinator.showModule(); } + /** + * Initializes the magic stack to show home modules on the current new tab page which is used as + * the home surface. + */ + private void initializeMagicStack(Tab mostRecentTab) { + mHomeModulesContainer = + (ViewGroup) + ((ViewStub) + mNewTabPageLayout.findViewById( + R.id.home_modules_recycler_view_stub)) + .inflate(); + updateSingleTabCardContainerMargins(mHomeModulesContainer); + mHomeModulesCoordinator = new HomeModulesCoordinator(mActivity, this, mNewTabPageLayout); + mHomeModulesCoordinator.show(this::onMagicStackShown); + } + + private void onMagicStackShown(boolean isVisible) { + mHomeModulesContainer.setVisibility(isVisible ? View.VISIBLE : View.GONE); + } + private void onSingleTabCardClicked() { mTabModelSelector.getModel(false).closeTab(mTab); if (mHomeSurfaceTracker != null) { @@ -1220,11 +1280,10 @@ } /** Updates the margins for the single tab card container based on the type of MV tiles. */ - private void updateSingleTabCardContainerMargins() { + private void updateSingleTabCardContainerMargins(ViewGroup view) { if (!mIsNtpAsHomeSurfaceEnabled || mIsSurfacePolishEnabled) return; - MarginLayoutParams marginLayoutParams = - (MarginLayoutParams) mSingleTabCardContainer.getLayoutParams(); + MarginLayoutParams marginLayoutParams = (MarginLayoutParams) view.getLayoutParams(); marginLayoutParams.topMargin = -mNewTabPageLayout @@ -1270,4 +1329,60 @@ private boolean isNtpAsHomeSurfaceOnTablet() { return mIsNtpAsHomeSurfaceEnabled && mIsTablet; } + + @Override + public int getHostSurfaceType() { + return HostSurface.NEW_TAB_PAGE; + } + + @Override + public Point getContextMenuStartPoint() { + return mContextMenuStartPosition; + } + + @Override + public UiConfig getUiConfig() { + return mIsTablet ? mFeedSurfaceProvider.getUiConfig() : null; + } + + @Override + public void onUrlClicked(GURL gurl) { + mTab.loadUrl(new LoadUrlParams(gurl)); + } + + @Override + public void onTabSelected(int tabid) { + onSingleTabCardClicked(); + } + + @Override + public void onCaptureThumbnailStatusChanged() { + mSnapshotSingleTabCardChanged = true; + } + + @Override + public void customizeSettings() { + HomepageManager.getInstance().onMenuClick(mContext); + } + + @Override + public boolean showScrollableMvt() { + return isScrollableMvtEnabled(mContext); + } + + @Override + public int getStartMargin() { + return mContext.getResources() + .getDimensionPixelSize(R.dimen.single_tab_card_lateral_margin); + } + + @Nullable + @Override + public Tab getTrackingTab() { + if (!mMostRecentTabSupplier.hasValue()) { + return null; + } + + return mMostRecentTabSupplier.get(); + } }
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 7ec95a0..b620d07 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
@@ -9,6 +9,8 @@ import android.app.Activity; import android.content.Context; import android.content.Intent; +import android.content.res.Resources; +import android.graphics.Point; import android.os.Bundle; import android.text.TextUtils; import android.text.format.DateUtils; @@ -987,6 +989,32 @@ && ChromeFeatureList.sStartSurfaceOnTablet.isEnabled(); } + /** + * Returns the start position of the context menu of a home module. + * + * @param resources The {@link Resources} instance to load Android resources from. + */ + public static Point calculateContextMenuStartPosition(Resources resources) { + // On the single tab module, the x starts from the right of the tab thumbnail. + int contextMenuStartX = + resources.getDimensionPixelSize( + org.chromium.chrome.start_surface.R.dimen + .single_tab_module_lateral_margin) + + resources.getDimensionPixelSize( + org.chromium.chrome.start_surface.R.dimen + .single_tab_module_padding_bottom) + + resources.getDimensionPixelSize( + org.chromium.chrome.start_surface.R.dimen + .single_tab_module_tab_thumbnail_size); + // The y starts from the same height of the tab thumbnail. + int contextMenuStartY = + resources.getDimensionPixelSize( + org.chromium.chrome.start_surface.R.dimen + .single_tab_module_padding_top) + * 3; + return new Point(contextMenuStartX, contextMenuStartY); + } + /** Shows the home surface UI on the given NTP on tablets. */ static void showHomeSurfaceUiOnNtp( Tab ntpTab, Tab lastActiveTab, HomeSurfaceTracker homeSurfaceTracker) { @@ -1010,7 +1038,11 @@ // This cast is now guaranteed to succeed to a non-null value. NewTabPage newTabPage = (NewTabPage) nativePage; homeSurfaceTracker.updateHomeSurfaceAndTrackingTabs(ntpTab, lastActiveTab); - newTabPage.showHomeSurfaceUi(lastActiveTab); + if (StartSurfaceConfiguration.useMagicStack()) { + newTabPage.showMagicStackWithHomeSurfaceUi(lastActiveTab); + } else { + newTabPage.showHomeSurfaceUi(lastActiveTab); + } } // TODO(https://crbug.com/1450578): Removes this histogram once we understand the root cause of
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperTest.java index 07e73f7..4b983a6 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperTest.java
@@ -2668,7 +2668,7 @@ // Drag tab back onto strip. float expectedOffsetX = 123.45f; mStripLayoutHelper.setLastOffsetXForTesting(expectedOffsetX); - mStripLayoutHelper.prepareForTabDrop(TIMESTAMP, 0f, 0f, true); + mStripLayoutHelper.prepareForTabDrop(TIMESTAMP, 0f, 0f, true, false); // Verify we continue reorder mode with the correct x-offset. assertFalse( @@ -2693,10 +2693,10 @@ // Drag tab out of strip. float expectedOffsetX = 123.45f; - mStripLayoutHelper.prepareForTabDrop(TIMESTAMP, 0f, 0f, true); + mStripLayoutHelper.prepareForTabDrop(TIMESTAMP, 0f, 0f, true, false); StripLayoutTab draggedTab = mStripLayoutHelper.getInteractingTabForTesting(); draggedTab.setOffsetX(expectedOffsetX); - mStripLayoutHelper.clearForTabDrop(TIMESTAMP, true); + mStripLayoutHelper.clearForTabDrop(TIMESTAMP, true, false); // Finish animations. assertNotNull( @@ -2761,7 +2761,7 @@ mStripLayoutHelper.updateLayout(TIMESTAMP); // Prepare for tab drop. - mStripLayoutHelper.prepareForTabDrop(TIMESTAMP, 0.f, 0.f, false); + mStripLayoutHelper.prepareForTabDrop(TIMESTAMP, 0.f, 0.f, false, false); // Start gap will be tabWidth(265) / 2 = 132.5 mStripLayoutHelper.setScrollOffsetForTesting(-132); @@ -2802,7 +2802,7 @@ groupTabs(1, 3); // Prepare for tab drop. - mStripLayoutHelper.prepareForTabDrop(TIMESTAMP, 0.f, 0.f, false); + mStripLayoutHelper.prepareForTabDrop(TIMESTAMP, 0.f, 0.f, false, false); // Verify. StripLayoutTab[] tabs = mStripLayoutHelper.getStripLayoutTabsForTesting(); @@ -2824,7 +2824,7 @@ mStripLayoutHelper.updateLayout(TIMESTAMP); // Prepare for tab drop. - mStripLayoutHelper.prepareForTabDrop(TIMESTAMP, 0.f, 0.f, false); + mStripLayoutHelper.prepareForTabDrop(TIMESTAMP, 0.f, 0.f, false, false); // Hover between 2nd and 3rd tab: // 2 * (tabWidth(265) - overlapWidth(28)) = 474 @@ -2860,7 +2860,7 @@ mStripLayoutHelper.updateLayout(TIMESTAMP); // Prepare for tab drop. - mStripLayoutHelper.prepareForTabDrop(TIMESTAMP, 0.f, 0.f, false); + mStripLayoutHelper.prepareForTabDrop(TIMESTAMP, 0.f, 0.f, false, false); // Start gap will be tabWidth(265) / 2 = 132.5 mStripLayoutHelper.setScrollOffsetForTesting(-132); @@ -2887,6 +2887,35 @@ } @Test + public void testDestinationStripForTabDrop_DifferentIncognitoState() { + // Setup with 3 tabs. + boolean isIncognito = false; + initializeTest(false, isIncognito, true, 1, 3); + + // Prepare and verify no interaction. + mStripLayoutHelper.prepareForTabDrop(TIMESTAMP, 0.f, 0.f, false, !isIncognito); + assertFalse( + "Shouldn't start reorder when dragged tab Incognito state is different.", + mStripLayoutHelper.getInReorderModeForTesting()); + + // Drag and verify no interaction. + float expectedOffset = mStripLayoutHelper.getScrollOffset(); + mStripLayoutHelper.dragForTabDrop(TIMESTAMP, 0.f, 0.f, 50.f, !isIncognito); + assertEquals( + "Shouldn't have scrolled when dragged tab Incognito is different.", + expectedOffset, + mStripLayoutHelper.getScrollOffset(), + EPSILON); + + // Set reorder mode for testing, then clear for tab drop and verify no interaction. + mStripLayoutHelper.startReorderModeAtIndexForTesting(0); + mStripLayoutHelper.clearForTabDrop(TIMESTAMP, false, !isIncognito); + assertTrue( + "Shouldn't stop reorder when dragged tab Incognito state is different.", + mStripLayoutHelper.getInReorderModeForTesting()); + } + + @Test public void testUpdateLastHoveredTab() { // Assume tab0 is selected, tab1 is hovered on. initializeTabHoverTest();
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/TabDragSourceTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/TabDragSourceTest.java index 165cd07..f678ecd 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/TabDragSourceTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/TabDragSourceTest.java
@@ -20,7 +20,6 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoInteractions; -import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import android.app.Activity; @@ -386,7 +385,7 @@ // Verify appropriate events are generated. // Strip prepares for drop on drag enter. verify(mSourceStripLayoutHelper, times(1)) - .prepareForTabDrop(anyLong(), anyFloat(), anyFloat(), anyBoolean()); + .prepareForTabDrop(anyLong(), anyFloat(), anyFloat(), anyBoolean(), anyBoolean()); // Stop reorder on drop. verify(mSourceStripLayoutHelper, times(1)).onUpOrCancel(anyLong()); // Verify tab is not moved. @@ -412,9 +411,10 @@ // Verify appropriate events are generated. // Strip prepares for drop on drag enter. verify(mSourceStripLayoutHelper, times(1)) - .prepareForTabDrop(anyLong(), anyFloat(), anyFloat(), anyBoolean()); + .prepareForTabDrop(anyLong(), anyFloat(), anyFloat(), anyBoolean(), anyBoolean()); // Strip clears state for drop on drag exit. - verify(mSourceStripLayoutHelper, times(1)).clearForTabDrop(anyLong(), anyBoolean()); + verify(mSourceStripLayoutHelper, times(1)) + .clearForTabDrop(anyLong(), anyBoolean(), anyBoolean()); // Verify tab is not moved since drop is on source toolbar. verify(mSourceMultiInstanceManager, times(0)).moveTabToNewWindow(mTabBeingDragged); verify(mSourceMultiInstanceManager, times(0)).moveTabToWindow(any(), any(), anyInt()); @@ -432,9 +432,10 @@ // Verify appropriate events are generated. // Strip prepares for drop on drag enter. verify(mSourceStripLayoutHelper, times(1)) - .prepareForTabDrop(anyLong(), anyFloat(), anyFloat(), anyBoolean()); + .prepareForTabDrop(anyLong(), anyFloat(), anyFloat(), anyBoolean(), anyBoolean()); // Strip clears state for drop on drag exit. - verify(mSourceStripLayoutHelper, times(1)).clearForTabDrop(anyLong(), anyBoolean()); + verify(mSourceStripLayoutHelper, times(1)) + .clearForTabDrop(anyLong(), anyBoolean(), anyBoolean()); // Verify tab is not moved since drop is outside strip. verify(mSourceMultiInstanceManager, times(0)).moveTabToNewWindow(mTabBeingDragged); verify(mSourceMultiInstanceManager, times(0)).moveTabToWindow(any(), any(), anyInt()); @@ -454,9 +455,10 @@ // Verify appropriate events are generated. // Strip prepares for drop on drag enter. verify(mSourceStripLayoutHelper, times(1)) - .prepareForTabDrop(anyLong(), anyFloat(), anyFloat(), anyBoolean()); + .prepareForTabDrop(anyLong(), anyFloat(), anyFloat(), anyBoolean(), anyBoolean()); // Strip clears state for drop on drag exit. - verify(mSourceStripLayoutHelper, times(1)).clearForTabDrop(anyLong(), anyBoolean()); + verify(mSourceStripLayoutHelper, times(1)) + .clearForTabDrop(anyLong(), anyBoolean(), anyBoolean()); // Verify Since the drop is outside the TabToolbar area the tab will be move to a new // Chrome Window. verify(mSourceMultiInstanceManager, times(1)).moveTabToNewWindow(mTabBeingDragged); @@ -480,7 +482,7 @@ verify(mSourceStripLayoutHelper, times(1)).clearActiveClickedTab(); // Verify destination strip calls. verify(mDestStripLayoutHelper) - .prepareForTabDrop(anyLong(), anyFloat(), anyFloat(), anyBoolean()); + .prepareForTabDrop(anyLong(), anyFloat(), anyFloat(), anyBoolean(), anyBoolean()); verify(mDestStripLayoutHelper).onUpOrCancel(anyLong()); assertNull(ShadowToast.getLatestToast()); @@ -543,14 +545,16 @@ // Verify appropriate events are generated. // Source strip prepares for drop on drag enter. verify(mSourceStripLayoutHelper, times(1)) - .prepareForTabDrop(anyLong(), anyFloat(), anyFloat(), anyBoolean()); + .prepareForTabDrop(anyLong(), anyFloat(), anyFloat(), anyBoolean(), anyBoolean()); // Source strip clears state for drop on drag exit. - verify(mSourceStripLayoutHelper, times(1)).clearForTabDrop(anyLong(), anyBoolean()); + verify(mSourceStripLayoutHelper, times(1)) + .clearForTabDrop(anyLong(), anyBoolean(), anyBoolean()); // Destination strip prepares for drop on drag enter. verify(mDestStripLayoutHelper, times(1)) - .prepareForTabDrop(anyLong(), anyFloat(), anyFloat(), anyBoolean()); + .prepareForTabDrop(anyLong(), anyFloat(), anyFloat(), anyBoolean(), anyBoolean()); // Destination strip clears state for drop on drag exit. - verify(mDestStripLayoutHelper, times(1)).clearForTabDrop(anyLong(), anyBoolean()); + verify(mDestStripLayoutHelper, times(1)) + .clearForTabDrop(anyLong(), anyBoolean(), anyBoolean()); // Verify tab is not moved since drop is on source toolbar. verify(mSourceMultiInstanceManager, times(0)).moveTabToNewWindow(mTabBeingDragged); verify(mSourceMultiInstanceManager, times(0)).moveTabToWindow(any(), any(), anyInt()); @@ -572,7 +576,7 @@ // Verify appropriate events are generated. // Strip prepares for drop on drag enter. Entered twice. verify(mSourceStripLayoutHelper, times(2)) - .prepareForTabDrop(anyLong(), anyFloat(), anyFloat(), anyBoolean()); + .prepareForTabDrop(anyLong(), anyFloat(), anyFloat(), anyBoolean(), anyBoolean()); // Stop reorder on drop. verify(mSourceStripLayoutHelper, times(1)).onUpOrCancel(anyLong()); // Verify tab is not moved. @@ -620,7 +624,8 @@ mTabsToolbarView, mockDragEvent(DragEvent.ACTION_DRAG_ENDED, POS_X, mPosY)); // Verify - Move to new window not invoked. - verifyNoMoreInteractions(mSourceMultiInstanceManager); + verify(mDestMultiInstanceManager, times(0)) + .moveTabToWindow(any(), eq(mTabBeingDragged), anyInt()); } /** Test for {@link #ONDRAG_TEST_CASES} - Scenario G.3 */
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/tasks/ReturnToChromeUtilUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/tasks/ReturnToChromeUtilUnitTest.java index 117f529..5982c66 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/tasks/ReturnToChromeUtilUnitTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/tasks/ReturnToChromeUtilUnitTest.java
@@ -4,6 +4,7 @@ package org.chromium.chrome.browser.tasks; +import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; @@ -11,6 +12,7 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import static org.chromium.chrome.browser.tasks.ReturnToChromeUtil.FAIL_TO_SHOW_HOME_SURFACE_UI_UMA; import static org.chromium.chrome.browser.tasks.ReturnToChromeUtil.HOME_SURFACE_SHOWN_AT_STARTUP_UMA; @@ -151,10 +153,10 @@ ShadowHomepageManager.sHomepageGurl = UrlConstants.ntpGurl(); ShadowHomepageManager.sIsHomepageEnabled = true; Assert.assertEquals(UrlConstants.ntpGurl(), HomepageManager.getHomepageGurl()); - Assert.assertTrue(HomepageManager.isHomepageEnabled()); + assertTrue(HomepageManager.isHomepageEnabled()); ShadowHomepagePolicyManager.sIsInitialized = true; - Assert.assertTrue(HomepagePolicyManager.isInitializedWithNative()); + assertTrue(HomepagePolicyManager.isInitializedWithNative()); // Low end devices: Assert.assertFalse(SysUtils.isLowEndDevice()); @@ -185,7 +187,7 @@ System.currentTimeMillis() - returnTimeMs + DELTA_MS, false)); // When return time arrives, return true: - Assert.assertTrue( + assertTrue( ReturnToChromeUtil.shouldShowTabSwitcher( System.currentTimeMillis() - returnTimeMs - 1, false)); } @@ -206,7 +208,7 @@ Assert.assertEquals(updatedReturnTimeMs, START_SURFACE_RETURN_TIME_SECONDS.getValue()); long returnTimeMs = updatedReturnTimeMs * DateUtils.SECOND_IN_MILLIS; // When return time on phones arrives, return true on phones: - Assert.assertTrue( + assertTrue( ReturnToChromeUtil.shouldShowTabSwitcher( System.currentTimeMillis() - returnTimeMs - 1, false)); // Verifies that return time on phones doesn't impact the return time on tablets. @@ -221,7 +223,7 @@ Assert.assertEquals( updatedReturnTimeMs, START_SURFACE_RETURN_TIME_ON_TABLET_SECONDS.getValue()); // When return time on tablets arrives, return true on tablets: - Assert.assertTrue( + assertTrue( ReturnToChromeUtil.shouldShowTabSwitcher( System.currentTimeMillis() - returnTimeMs - 1, true)); // Verifies that return time on tablets doesn't impact the return time on phones. @@ -246,9 +248,8 @@ // Sets to immediate return. START_SURFACE_RETURN_TIME_SECONDS.setForTesting(0); Assert.assertEquals(0, START_SURFACE_RETURN_TIME_SECONDS.getValue()); - Assert.assertTrue(ReturnToChromeUtil.shouldShowTabSwitcher(-1, false)); - Assert.assertTrue( - ReturnToChromeUtil.shouldShowTabSwitcher(System.currentTimeMillis(), false)); + assertTrue(ReturnToChromeUtil.shouldShowTabSwitcher(-1, false)); + assertTrue(ReturnToChromeUtil.shouldShowTabSwitcher(System.currentTimeMillis(), false)); // Sets to an random time. int expectedReturnTimeSeconds = 60; // one minute @@ -257,7 +258,7 @@ Assert.assertEquals( expectedReturnTimeSeconds, START_SURFACE_RETURN_TIME_SECONDS.getValue()); Assert.assertFalse(ReturnToChromeUtil.shouldShowTabSwitcher(-1, false)); - Assert.assertTrue( + assertTrue( ReturnToChromeUtil.shouldShowTabSwitcher( System.currentTimeMillis() - expectedReturnTimeMs, false)); Assert.assertFalse( @@ -327,7 +328,7 @@ Assert.assertEquals(doubleReturnTimeMs, START_SURFACE_RETURN_TIME_SECONDS.getValue()); // When segmentation platform's return time arrives, return true: - Assert.assertTrue( + assertTrue( ReturnToChromeUtil.shouldShowTabSwitcher( System.currentTimeMillis() - returnTimeMs - 1, false)); @@ -344,11 +345,11 @@ @SmallTest public void testShouldShowStartSurfaceAsTheHomePageUseVisibleTime() { START_SURFACE_OPEN_START_AS_HOMEPAGE.setForTesting(true); - Assert.assertTrue(ReturnToChromeUtil.isStartSurfaceEnabled(mContext)); + assertTrue(ReturnToChromeUtil.isStartSurfaceEnabled(mContext)); // Sets main intent from launcher: Intent intent = createMainIntentFromLauncher(); - Assert.assertTrue(IntentUtils.isMainIntentFromLauncher(intent)); + assertTrue(IntentUtils.isMainIntentFromLauncher(intent)); // Tests the case when the total tab count > 0: doReturn(true).when(mTabModelSelector).isTabStateInitialized(); doReturn(1).when(mTabModelSelector).getTotalTabCount(); @@ -363,10 +364,10 @@ // Verifies that Start will show if the threshold of return time has reached using last // visible time, while last background time is lost or not set. - Assert.assertTrue(ReturnToChromeUtil.shouldShowTabSwitcher(expectedVisibleTime, false)); + assertTrue(ReturnToChromeUtil.shouldShowTabSwitcher(expectedVisibleTime, false)); Assert.assertFalse( ReturnToChromeUtil.shouldShowTabSwitcher(expectedLastBackgroundTime, false)); - Assert.assertTrue( + assertTrue( ReturnToChromeUtil.shouldShowOverviewPageOnStart( mContext, intent, @@ -398,7 +399,7 @@ expectedLastBackgroundTime = currentTime - returnTimeMS + DELTA_MS; // doesn't reach doReturn(expectedVisibleTime).when(mInactivityTracker).getLastVisibleTimeMs(); doReturn(expectedLastBackgroundTime).when(mInactivityTracker).getLastBackgroundedTimeMs(); - Assert.assertTrue(ReturnToChromeUtil.shouldShowTabSwitcher(expectedVisibleTime, false)); + assertTrue(ReturnToChromeUtil.shouldShowTabSwitcher(expectedVisibleTime, false)); Assert.assertFalse( ReturnToChromeUtil.shouldShowTabSwitcher(expectedLastBackgroundTime, false)); Assert.assertFalse( @@ -416,10 +417,9 @@ expectedLastBackgroundTime = currentTime - returnTimeMS - 1; // has reached doReturn(expectedVisibleTime).when(mInactivityTracker).getLastVisibleTimeMs(); doReturn(expectedLastBackgroundTime).when(mInactivityTracker).getLastBackgroundedTimeMs(); - Assert.assertTrue(ReturnToChromeUtil.shouldShowTabSwitcher(expectedVisibleTime, false)); - Assert.assertTrue( - ReturnToChromeUtil.shouldShowTabSwitcher(expectedLastBackgroundTime, false)); - Assert.assertTrue( + assertTrue(ReturnToChromeUtil.shouldShowTabSwitcher(expectedVisibleTime, false)); + assertTrue(ReturnToChromeUtil.shouldShowTabSwitcher(expectedLastBackgroundTime, false)); + assertTrue( ReturnToChromeUtil.shouldShowOverviewPageOnStart( mContext, intent, @@ -432,7 +432,7 @@ @SmallTest public void testShouldShowStartSurfaceAtStartupWithDefaultChromeHomepage() { START_SURFACE_OPEN_START_AS_HOMEPAGE.setForTesting(true); - Assert.assertTrue(ReturnToChromeUtil.isStartSurfaceEnabled(mContext)); + assertTrue(ReturnToChromeUtil.isStartSurfaceEnabled(mContext)); // Sets main intent from launcher: Intent intent = createMainIntentFromLauncher(); @@ -444,8 +444,8 @@ // Tests the case when there isn't any Tab: doReturn(true).when(mTabModelSelector).isTabStateInitialized(); doReturn(0).when(mTabModelSelector).getTotalTabCount(); - Assert.assertTrue(HomepagePolicyManager.isInitializedWithNative()); - Assert.assertTrue( + assertTrue(HomepagePolicyManager.isInitializedWithNative()); + assertTrue( ReturnToChromeUtil.shouldShowOverviewPageOnStart( mContext, intent, @@ -468,10 +468,10 @@ .addToStringSet( ChromePreferenceKeys.TABBED_ACTIVITY_LAST_BACKGROUNDED_TIME_MS_PREF, "0"); START_SURFACE_RETURN_TIME_SECONDS.setForTesting(0); - Assert.assertTrue(ReturnToChromeUtil.shouldShowTabSwitcher(0, false)); + assertTrue(ReturnToChromeUtil.shouldShowTabSwitcher(0, false)); // Verifies that Start will show since the return time has arrived. - Assert.assertTrue( + assertTrue( ReturnToChromeUtil.shouldShowOverviewPageOnStart( mContext, intent, @@ -487,7 +487,7 @@ @SmallTest public void testShouldShowStartSurfaceWithCustomizedHomePage() { START_SURFACE_OPEN_START_AS_HOMEPAGE.setForTesting(true); - Assert.assertTrue(ReturnToChromeUtil.isStartSurfaceEnabled(mContext)); + assertTrue(ReturnToChromeUtil.isStartSurfaceEnabled(mContext)); // Sets a customized homepage: ShadowHomepageManager.sHomepageGurl = new GURL("http://foo.com"); @@ -501,7 +501,7 @@ .addToStringSet( ChromePreferenceKeys.TABBED_ACTIVITY_LAST_BACKGROUNDED_TIME_MS_PREF, "0"); START_SURFACE_RETURN_TIME_SECONDS.setForTesting(0); - Assert.assertTrue(ReturnToChromeUtil.shouldShowTabSwitcher(0, false)); + assertTrue(ReturnToChromeUtil.shouldShowTabSwitcher(0, false)); // Tests the case when there isn't any Tab but with customized homepage: doReturn(true).when(mTabModelSelector).isTabStateInitialized(); @@ -516,7 +516,7 @@ // Tests the case when the total tab count > 0 and return time arrives, Start will show. doReturn(1).when(mTabModelSelector).getTotalTabCount(); - Assert.assertTrue( + assertTrue( ReturnToChromeUtil.shouldShowOverviewPageOnStart( mContext, intent, @@ -533,7 +533,7 @@ @SmallTest public void testShouldShowStartSurfaceAtStartupWithHomepageDisabled() { START_SURFACE_OPEN_START_AS_HOMEPAGE.setForTesting(true); - Assert.assertTrue(ReturnToChromeUtil.isStartSurfaceEnabled(mContext)); + assertTrue(ReturnToChromeUtil.isStartSurfaceEnabled(mContext)); // Sets main intent from launcher: Intent intent = createMainIntentFromLauncher(); @@ -543,7 +543,7 @@ .addToStringSet( ChromePreferenceKeys.TABBED_ACTIVITY_LAST_BACKGROUNDED_TIME_MS_PREF, "0"); START_SURFACE_RETURN_TIME_SECONDS.setForTesting(0); - Assert.assertTrue(ReturnToChromeUtil.shouldShowTabSwitcher(0, false)); + assertTrue(ReturnToChromeUtil.shouldShowTabSwitcher(0, false)); // When homepage is disabled, verifies that Start isn't shown when there isn't any Tab, even // if the return time has arrived. @@ -576,7 +576,7 @@ ChromeSharedPreferences.getInstance() .writeBoolean(ChromePreferenceKeys.IS_DSE_GOOGLE, false); - Assert.assertTrue(ReturnToChromeUtil.isStartSurfaceEnabled(mContext)); + assertTrue(ReturnToChromeUtil.isStartSurfaceEnabled(mContext)); ChromeSharedPreferences.getInstance().removeKey(ChromePreferenceKeys.IS_DSE_GOOGLE); } @@ -584,7 +584,7 @@ @SmallTest @EnableFeatures({ChromeFeatureList.SHOW_NTP_AT_STARTUP_ANDROID}) public void testStartSurfaceIsDisabledWithShowNtpAtStartup() { - Assert.assertTrue(ChromeFeatureList.sShowNtpAtStartupAndroid.isEnabled()); + assertTrue(ChromeFeatureList.sShowNtpAtStartupAndroid.isEnabled()); Assert.assertFalse(ReturnToChromeUtil.isStartSurfaceEnabled(mContext)); } @@ -592,7 +592,7 @@ @SmallTest @EnableFeatures({ChromeFeatureList.NEW_TAB_SEARCH_ENGINE_URL_ANDROID}) public void testStartSurfaceMayBeDisabledWithNewTabSearchEngineUrlEnabled() { - Assert.assertTrue(ReturnToChromeUtil.isStartSurfaceEnabled(mContext)); + assertTrue(ReturnToChromeUtil.isStartSurfaceEnabled(mContext)); ChromeSharedPreferences.getInstance() .writeBoolean(ChromePreferenceKeys.IS_DSE_GOOGLE, false); @@ -605,7 +605,7 @@ @SmallTest public void testShouldNotShowStartSurfaceOnStartWhenHomepagePolicyManagerIsNotInitialized() { START_SURFACE_OPEN_START_AS_HOMEPAGE.setForTesting(true); - Assert.assertTrue(ReturnToChromeUtil.isStartSurfaceEnabled(mContext)); + assertTrue(ReturnToChromeUtil.isStartSurfaceEnabled(mContext)); ShadowHomepagePolicyManager.sIsInitialized = false; Assert.assertFalse(HomepagePolicyManager.isInitializedWithNative()); @@ -617,13 +617,13 @@ .addToStringSet( ChromePreferenceKeys.TABBED_ACTIVITY_LAST_BACKGROUNDED_TIME_MS_PREF, "0"); START_SURFACE_RETURN_TIME_SECONDS.setForTesting(0); - Assert.assertTrue(ReturnToChromeUtil.shouldShowTabSwitcher(0, false)); + assertTrue(ReturnToChromeUtil.shouldShowTabSwitcher(0, false)); // Tests the case when there isn't any Tab. Verifies that Start isn't shown if // HomepagePolicyManager isn't initialized. doReturn(true).when(mTabModelSelector).isTabStateInitialized(); doReturn(0).when(mTabModelSelector).getTotalTabCount(); - Assert.assertTrue(HomepageManager.isHomepageEnabled()); + assertTrue(HomepageManager.isHomepageEnabled()); Assert.assertFalse(ReturnToChromeUtil.useChromeHomepage()); Assert.assertFalse( ReturnToChromeUtil.shouldShowOverviewPageOnStart( @@ -640,7 +640,7 @@ // Tests the case when the total tab count > 0. Verifies that Start is shown when the return // time arrives. doReturn(1).when(mTabModelSelector).getTotalTabCount(); - Assert.assertTrue( + assertTrue( ReturnToChromeUtil.shouldShowOverviewPageOnStart( mContext, intent, @@ -658,7 +658,7 @@ @SmallTest @EnableFeatures(ChromeFeatureList.START_SURFACE_ON_TABLET) public void testShouldShowNtpAsHomeSurfaceAtStartupOnTablet() { - Assert.assertTrue(StartSurfaceConfiguration.isNtpAsHomeSurfaceEnabled(true)); + assertTrue(StartSurfaceConfiguration.isNtpAsHomeSurfaceEnabled(true)); // Sets main intent from launcher: Intent intent = createMainIntentFromLauncher(); @@ -668,18 +668,18 @@ .addToStringSet( ChromePreferenceKeys.TABBED_ACTIVITY_LAST_BACKGROUNDED_TIME_MS_PREF, "0"); START_SURFACE_RETURN_TIME_SECONDS.setForTesting(0); - Assert.assertTrue(ReturnToChromeUtil.shouldShowTabSwitcher(0, false)); + assertTrue(ReturnToChromeUtil.shouldShowTabSwitcher(0, false)); // Tests the case when there isn't any Tab. Verifies that Start is only shown on tablets. doReturn(true).when(mTabModelSelector).isTabStateInitialized(); doReturn(0).when(mTabModelSelector).getTotalTabCount(); - Assert.assertTrue(HomepagePolicyManager.isInitializedWithNative()); - Assert.assertTrue(HomepageManager.isHomepageEnabled()); - Assert.assertTrue(IntentUtils.isMainIntentFromLauncher(intent)); + assertTrue(HomepagePolicyManager.isInitializedWithNative()); + assertTrue(HomepageManager.isHomepageEnabled()); + assertTrue(IntentUtils.isMainIntentFromLauncher(intent)); Assert.assertFalse( ReturnToChromeUtil.shouldShowNtpAsHomeSurfaceAtStartup( false, intent, null, mTabModelSelector, mInactivityTracker)); - Assert.assertTrue( + assertTrue( ReturnToChromeUtil.shouldShowNtpAsHomeSurfaceAtStartup( true, intent, null, mTabModelSelector, mInactivityTracker)); @@ -689,7 +689,7 @@ Assert.assertFalse( ReturnToChromeUtil.shouldShowNtpAsHomeSurfaceAtStartup( false, intent, null, mTabModelSelector, mInactivityTracker)); - Assert.assertTrue( + assertTrue( ReturnToChromeUtil.shouldShowNtpAsHomeSurfaceAtStartup( true, intent, null, mTabModelSelector, mInactivityTracker)); @@ -711,7 +711,7 @@ Assert.assertFalse( ReturnToChromeUtil.shouldShowNtpAsHomeSurfaceAtStartup( false, intent, null, mTabModelSelector, mInactivityTracker)); - Assert.assertTrue( + assertTrue( ReturnToChromeUtil.shouldShowNtpAsHomeSurfaceAtStartup( true, intent, mSaveInstanceState, mTabModelSelector, mInactivityTracker)); } @@ -720,7 +720,7 @@ @SmallTest @EnableFeatures(ChromeFeatureList.START_SURFACE_ON_TABLET) public void testShowNtpAsHomeSurfaceAtResumeOnTabletWithExistingNtp() { - Assert.assertTrue(StartSurfaceConfiguration.isNtpAsHomeSurfaceEnabled(true)); + assertTrue(StartSurfaceConfiguration.isNtpAsHomeSurfaceEnabled(true)); doReturn(2).when(mCurrentTabModel).getCount(); doReturn(JUnitTestGURLs.URL_1).when(mTab1).getUrl(); @@ -798,7 +798,7 @@ @SmallTest @EnableFeatures(ChromeFeatureList.START_SURFACE_ON_TABLET) public void testShowNtpAsHomeSurfaceAtResumeOnTabletWithoutAnyExistingNtp() { - Assert.assertTrue(StartSurfaceConfiguration.isNtpAsHomeSurfaceEnabled(true)); + assertTrue(StartSurfaceConfiguration.isNtpAsHomeSurfaceEnabled(true)); doReturn(1).when(mCurrentTabModel).getCount(); doReturn(JUnitTestGURLs.URL_1).when(mTab1).getUrl(); @@ -844,7 +844,7 @@ @SmallTest @EnableFeatures(ChromeFeatureList.START_SURFACE_ON_TABLET) public void testShowNtpAsHomeSurfaceAtResumeOnTabletWithMixedNtps() { - Assert.assertTrue(StartSurfaceConfiguration.isNtpAsHomeSurfaceEnabled(true)); + assertTrue(StartSurfaceConfiguration.isNtpAsHomeSurfaceEnabled(true)); doReturn(3).when(mCurrentTabModel).getCount(); doReturn(JUnitTestGURLs.URL_1).when(mTab1).getUrl(); @@ -909,7 +909,7 @@ @SmallTest @EnableFeatures(ChromeFeatureList.START_SURFACE_ON_TABLET) public void testNoAnyTabCase() { - Assert.assertTrue(StartSurfaceConfiguration.isNtpAsHomeSurfaceEnabled(true)); + assertTrue(StartSurfaceConfiguration.isNtpAsHomeSurfaceEnabled(true)); doReturn(0).when(mCurrentTabModel).getCount(); @@ -928,7 +928,7 @@ @SmallTest @EnableFeatures(ChromeFeatureList.START_SURFACE_ON_TABLET) public void testColdStartupWithOnlyLastActiveTabUrl() { - Assert.assertTrue(StartSurfaceConfiguration.isNtpAsHomeSurfaceEnabled(true)); + assertTrue(StartSurfaceConfiguration.isNtpAsHomeSurfaceEnabled(true)); doReturn(JUnitTestGURLs.URL_1).when(mTab1).getUrl(); doReturn(true).when(mNtpTab).isNativePage(); @@ -956,6 +956,41 @@ @Test @SmallTest + @EnableFeatures({ + ChromeFeatureList.START_SURFACE_ON_TABLET, + ChromeFeatureList.SURFACE_POLISH, + ChromeFeatureList.MAGIC_STACK_ANDROID + }) + public void testColdStartupWithOnlyLastActiveTabUrl_MagicStack() { + assertTrue(StartSurfaceConfiguration.isNtpAsHomeSurfaceEnabled(true)); + assertTrue(StartSurfaceConfiguration.useMagicStack()); + + when(mTab1.getUrl()).thenReturn(JUnitTestGURLs.URL_1); + when(mNtpTab.isNativePage()).thenReturn(true); + when(mNtpTab.getNativePage()).thenReturn(mNewTabPage); + + when(mTabCreater.createNewTab(any(), eq(TabLaunchType.FROM_STARTUP), eq(null))) + .thenReturn(mNtpTab); + when(mTabModelSelector.getModel(false)).thenReturn(mCurrentTabModel); + + // Tests the case that a new NTP is created and waits for its tracking last active Tab being + // restored. + ReturnToChromeUtil.createNewTabAndShowHomeSurfaceUi( + mTabCreater, + mHomeSurfaceTracker, + mTabModelSelector, + JUnitTestGURLs.URL_1.getSpec(), + null); + verify(mCurrentTabModel).addObserver(mTabModelObserverCaptor.capture()); + + // Verifies if the added Tab matches the tracking URL, call showHomeSurfaceUi(). + mTabModelObserverCaptor.getValue().willAddTab(mTab1, TabLaunchType.FROM_RESTORE); + verify(mNewTabPage).showMagicStackWithHomeSurfaceUi(eq(mTab1)); + verify(mHomeSurfaceTracker).updateHomeSurfaceAndTrackingTabs(eq(mNtpTab), eq(mTab1)); + } + + @Test + @SmallTest public void testShouldResumeHomeSurfaceOnFoldConfigurationChange() { Assert.assertFalse( ReturnToChromeUtil.shouldResumeHomeSurfaceOnFoldConfigurationChange(null)); @@ -986,7 +1021,7 @@ doReturn(true) .when(mSaveInstanceState) .getBoolean(RESUME_HOME_SURFACE_ON_MODE_CHANGE, false); - Assert.assertTrue( + assertTrue( ReturnToChromeUtil.shouldResumeHomeSurfaceOnFoldConfigurationChange( mSaveInstanceState)); } @@ -1036,15 +1071,14 @@ // Verifies ReturnToChromeUtil.shouldHandleTabSwitcherShown() returns true. doReturn(true).when(layoutStateProvider).isLayoutVisible(eq(LayoutType.TAB_SWITCHER)); - Assert.assertTrue( - ReturnToChromeUtil.shouldHandleTabSwitcherShown(true, layoutStateProvider)); + assertTrue(ReturnToChromeUtil.shouldHandleTabSwitcherShown(true, layoutStateProvider)); } @Test @EnableFeatures({ChromeFeatureList.SURFACE_POLISH}) @DisableFeatures({ChromeFeatureList.SHOW_SCROLLABLE_MVT_ON_NTP_ANDROID}) public void testIsScrollableMvtEnabledWhenSurfacePolishEnabled_tablets() { - Assert.assertTrue(ChromeFeatureList.sSurfacePolish.isEnabled()); + assertTrue(ChromeFeatureList.sSurfacePolish.isEnabled()); Assert.assertFalse( ChromeFeatureList.isEnabled(ChromeFeatureList.SHOW_SCROLLABLE_MVT_ON_NTP_ANDROID)); Assert.assertFalse(StartSurfaceConfiguration.SURFACE_POLISH_SCROLLABLE_MVT.getValue()); @@ -1053,7 +1087,7 @@ // Verifies if feature ChromeFeatureList.SURFACE_POLISH is enabled on tablets, always show // the scrollable MV tiles. - Assert.assertTrue(ReturnToChromeUtil.isScrollableMvtEnabled(mContext)); + assertTrue(ReturnToChromeUtil.isScrollableMvtEnabled(mContext)); } @Test @@ -1064,7 +1098,7 @@ }) public void testIsScrollableMvtEnabled_SurfacePolishDisabled_ScrollableMvtEnabled_tablets() { Assert.assertFalse(ChromeFeatureList.sSurfacePolish.isEnabled()); - Assert.assertTrue( + assertTrue( ChromeFeatureList.isEnabled(ChromeFeatureList.SHOW_SCROLLABLE_MVT_ON_NTP_ANDROID)); Assert.assertFalse(StartSurfaceConfiguration.SURFACE_POLISH_SCROLLABLE_MVT.getValue()); @@ -1074,7 +1108,7 @@ // Verifies if feature ChromeFeatureList.SURFACE_POLISH is disabled on tablets, the // scrollable MV tiles is only shown when both features // SHOW_SCROLLABLE_MVT_ON_NTP_ANDROID and START_SURFACE_ON_TABLET are enabled. - Assert.assertTrue(ReturnToChromeUtil.isScrollableMvtEnabled(mContext)); + assertTrue(ReturnToChromeUtil.isScrollableMvtEnabled(mContext)); } @Test @@ -1101,7 +1135,7 @@ @EnableFeatures({ChromeFeatureList.SURFACE_POLISH}) @DisableFeatures({ChromeFeatureList.SHOW_SCROLLABLE_MVT_ON_NTP_PHONE_ANDROID}) public void testIsScrollableMvtEnabledWhenSurfacePolishEnabled_phones() { - Assert.assertTrue(ChromeFeatureList.sSurfacePolish.isEnabled()); + assertTrue(ChromeFeatureList.sSurfacePolish.isEnabled()); Assert.assertFalse( ChromeFeatureList.isEnabled( ChromeFeatureList.SHOW_SCROLLABLE_MVT_ON_NTP_PHONE_ANDROID)); @@ -1116,7 +1150,7 @@ Assert.assertFalse(ReturnToChromeUtil.isScrollableMvtEnabled(mContext)); StartSurfaceConfiguration.SURFACE_POLISH_SCROLLABLE_MVT.setForTesting(true); - Assert.assertTrue(ReturnToChromeUtil.isScrollableMvtEnabled(mContext)); + assertTrue(ReturnToChromeUtil.isScrollableMvtEnabled(mContext)); } @Test @@ -1124,7 +1158,7 @@ @EnableFeatures({ChromeFeatureList.SHOW_SCROLLABLE_MVT_ON_NTP_PHONE_ANDROID}) public void testIsScrollableMvtEnabled_SurfacePolishDisabled_ScrollableMvtEnabled_phones() { Assert.assertFalse(ChromeFeatureList.sSurfacePolish.isEnabled()); - Assert.assertTrue( + assertTrue( ChromeFeatureList.isEnabled( ChromeFeatureList.SHOW_SCROLLABLE_MVT_ON_NTP_PHONE_ANDROID)); Assert.assertFalse(StartSurfaceConfiguration.SURFACE_POLISH_SCROLLABLE_MVT.getValue()); @@ -1134,7 +1168,7 @@ // scrollable MV tiles depends on feature flag // ChromeFeatureList.SHOW_SCROLLABLE_MVT_ON_NTP_PHONE_ANDROID. Assert.assertFalse(DeviceFormFactor.isNonMultiDisplayContextOnTablet(mContext)); - Assert.assertTrue(ReturnToChromeUtil.isScrollableMvtEnabled(mContext)); + assertTrue(ReturnToChromeUtil.isScrollableMvtEnabled(mContext)); } @Test @@ -1162,14 +1196,14 @@ doReturn(DeviceFormFactor.SCREEN_BUCKET_TABLET) .when(mResources) .getInteger(org.chromium.ui.R.integer.min_screen_width_bucket); - Assert.assertTrue(DeviceFormFactor.isNonMultiDisplayContextOnTablet(mContext)); + assertTrue(DeviceFormFactor.isNonMultiDisplayContextOnTablet(mContext)); } private Intent createMainIntentFromLauncher() { Intent intent = new Intent(); intent.setAction(Intent.ACTION_MAIN); intent.addCategory(Intent.CATEGORY_LAUNCHER); - Assert.assertTrue(IntentUtils.isMainIntentFromLauncher(intent)); + assertTrue(IntentUtils.isMainIntentFromLauncher(intent)); return intent; } }
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 8d649950..4d5823e 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd
@@ -8005,8 +8005,8 @@ <message name="IDS_NTP_WALLPAPER_SEARCH_DISCLAIMER" desc="Disclaimer text used for the Create theme with AI feature."> This is an experimental AI feature and won't always get it right. </message> - <message name="IDS_NTP_WALLPAPER_SEARCH_MEADOW_INSPIRATION_TITLE" desc="Title for the wallpaper search's Meadow inspiration."> - Meadow, Oil Painting, Intellectual, Yellow + <message name="IDS_NTP_WALLPAPER_SEARCH_INSPIRATION_CARD_TOGGLE_TITLE" desc="Accessibility title for the toggle used to hide/show wallpaper search's inspiration."> + Toggle Inspiration </message> <!-- NTP Modules -->
diff --git a/chrome/app/generated_resources_grd/IDS_NTP_WALLPAPER_SEARCH_INSPIRATION_CARD_TOGGLE_TITLE.png.sha1 b/chrome/app/generated_resources_grd/IDS_NTP_WALLPAPER_SEARCH_INSPIRATION_CARD_TOGGLE_TITLE.png.sha1 new file mode 100644 index 0000000..94d8e368 --- /dev/null +++ b/chrome/app/generated_resources_grd/IDS_NTP_WALLPAPER_SEARCH_INSPIRATION_CARD_TOGGLE_TITLE.png.sha1
@@ -0,0 +1 @@ +6b39c406d93cddbff55e4788b516e2fe5592b72d \ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_NTP_WALLPAPER_SEARCH_MEADOW_INSPIRATION_TITLE.png.sha1 b/chrome/app/generated_resources_grd/IDS_NTP_WALLPAPER_SEARCH_MEADOW_INSPIRATION_TITLE.png.sha1 deleted file mode 100644 index 85c63bce..0000000 --- a/chrome/app/generated_resources_grd/IDS_NTP_WALLPAPER_SEARCH_MEADOW_INSPIRATION_TITLE.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -8c8c4f8534b2fca5571aa7cffc6a66ea7ad536d9 \ No newline at end of file
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp index 31d58500..9495d3b 100644 --- a/chrome/app/settings_strings.grdp +++ b/chrome/app/settings_strings.grdp
@@ -4361,7 +4361,7 @@ Helps you write short-form content for things on the web, like reviews. Suggested content is based on your prompts and the content of the web page. To use this feature, right-click on a text box. </message> <message name="IDS_SETTINGS_EXPERIMENTAL_ADVANCED_FEATURE2_LABEL" desc="Toggle primary description" translateable="false"> - Tab Organizer + Tab organizer </message> <message name="IDS_SETTINGS_EXPERIMENTAL_ADVANCED_FEATURE2_SUBLABEL" desc="Toggle secondary description" translateable="false"> Automatically creates tab groups based on your open tabs. To use this feature, right-click on a tab and click Organize similar tabs.
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 0e44b2d..fc7538e 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -9555,6 +9555,11 @@ FEATURE_VALUE_TYPE( autofill::features::kAutofillEnableRankingFormulaCreditCards)}, + {"safe-browsing-async-real-time-check", + flag_descriptions::kSafeBrowsingAsyncRealTimeCheckName, + flag_descriptions::kSafeBrowsingAsyncRealTimeCheckDescription, kOsAll, + FEATURE_VALUE_TYPE(safe_browsing::kSafeBrowsingAsyncRealTimeCheck)}, + {"safe-browsing-hash-prefix", flag_descriptions::kSafeBrowsingHashPrefixRealTimeLookupsName, flag_descriptions::kSafeBrowsingHashPrefixRealTimeLookupsDescription, @@ -10485,6 +10490,10 @@ {"read-aloud", flag_descriptions::kReadAloudName, flag_descriptions::kReadAloudDescription, kOsAndroid, FEATURE_VALUE_TYPE(chrome::android::kReadAloud)}, + + {"read-aloud-in-cct", flag_descriptions::kReadAloudInCCTName, + flag_descriptions::kReadAloudInCCTDescription, kOsAndroid, + FEATURE_VALUE_TYPE(chrome::android::kReadAloudInOverflowMenuInCCT)}, #endif {"hide-incognito-media-metadata", @@ -10998,21 +11007,16 @@ #endif #if BUILDFLAG(IS_ANDROID) - {"offline-auto-fetch", - flag_descriptions::kOfflineAutoFetchName, - flag_descriptions::kOfflineAutoFetchDescription, - kOsAndroid, - FEATURE_VALUE_TYPE( - features::kOfflineAutoFetch)}, + {"offline-auto-fetch", flag_descriptions::kOfflineAutoFetchName, + flag_descriptions::kOfflineAutoFetchDescription, kOsAndroid, + FEATURE_VALUE_TYPE(features::kOfflineAutoFetch)}, #endif // BUILDFLAG(IS_ANDROID) #if BUILDFLAG(IS_ANDROID) {"offline-content-on-net-error", flag_descriptions::kOfflineContentOnNetErrorName, - flag_descriptions::kOfflineContentOnNetErrorDescription, - kOsAndroid, - FEATURE_VALUE_TYPE( - features::kOfflineContentOnNetError)}, + flag_descriptions::kOfflineContentOnNetErrorDescription, kOsAndroid, + FEATURE_VALUE_TYPE(features::kOfflineContentOnNetError)}, #endif // BUILDFLAG(IS_ANDROID) #if BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/chrome/browser/ash/BUILD.gn b/chrome/browser/ash/BUILD.gn index cf1cb06..73653fb 100644 --- a/chrome/browser/ash/BUILD.gn +++ b/chrome/browser/ash/BUILD.gn
@@ -5671,6 +5671,7 @@ "login/version_updater/update_time_estimator_unittest.cc", "login/version_updater/version_updater_unittest.cc", "login/wizard_controller_unittest.cc", + "mahi/mahi_manager_ash_unittest.cc", "mobile/mobile_activator_unittest.cc", "nearby/bluetooth_adapter_manager_unittest.cc", "nearby/nearby_process_manager_impl_unittest.cc", @@ -6379,6 +6380,7 @@ "//components/favicon/core", "//components/favicon/core/test:test_support", "//components/favicon_base", + "//components/feature_engagement/public", "//components/feedback", "//components/feedback/proto", "//components/file_access",
diff --git a/chrome/browser/ash/app_list/launcher_search_iph_browsertest.cc b/chrome/browser/ash/app_list/launcher_search_iph_browsertest.cc index 82a7698..eb3c029 100644 --- a/chrome/browser/ash/app_list/launcher_search_iph_browsertest.cc +++ b/chrome/browser/ash/app_list/launcher_search_iph_browsertest.cc
@@ -172,6 +172,9 @@ tracker_ = feature_engagement::TrackerFactory::GetForBrowserContext( browser()->profile()); + scoped_iph_feature_list_.InitWithExistingFeatures( + {feature_engagement::kIPHLauncherSearchHelpUiFeature}); + MixinBasedInProcessBrowserTest::SetUpOnMainThread(); } @@ -352,6 +355,8 @@ raw_ptr<feature_engagement::Tracker> tracker_ = nullptr; + feature_engagement::test::ScopedIphFeatureList scoped_iph_feature_list_; + private: ash::TestAssistantService test_service_; ash::AssistantTestApiImpl test_api_impl_; @@ -361,23 +366,13 @@ raw_ptr<AppListClientImpl> app_list_client_impl_ = nullptr; }; -class AppListIphBrowserTestWithTestConfig : public AppListIphBrowserTest { - public: - void SetUpCommandLine(base::CommandLine* command_line) override { - scoped_iph_feature_list_.InitAndEnableFeatures( - {feature_engagement::kIPHLauncherSearchHelpUiFeature}); +using AppListIphBrowserTestWithTestConfig = AppListIphBrowserTest; - MixinBasedInProcessBrowserTest::SetUpCommandLine(command_line); - } +IN_PROC_BROWSER_TEST_P(AppListIphBrowserTest, LauncherSearchIphShownByDefault) { + IphWaiter().Run(tracker_); + ClickAssistantIconAndWaitForIphView(); - private: - feature_engagement::test::ScopedIphFeatureList scoped_iph_feature_list_; -}; - -IN_PROC_BROWSER_TEST_P(AppListIphBrowserTest, - LauncherSearchIphNotShownByDefault) { - OpenAppListForSearch(); - EXPECT_FALSE(IsLauncherSearchIphViewVisible()); + EXPECT_TRUE(IsLauncherSearchIphViewVisible()); } IN_PROC_BROWSER_TEST_P(AppListIphBrowserTestWithTestConfig, @@ -641,22 +636,24 @@ } }; -IN_PROC_BROWSER_TEST_P(AppListIphBrowserTest, NoAssistantZeroStateIphFlagOff) { - ASSERT_FALSE(base::FeatureList::IsEnabled( +IN_PROC_BROWSER_TEST_P(AppListIphBrowserTest, + HasAssistantZeroStateIphByDefault) { + ASSERT_TRUE(base::FeatureList::IsEnabled( feature_engagement::kIPHLauncherSearchHelpUiFeature)); + tracker_->NotifyEvent("IPH_LauncherSearchHelpUi_assistant_click"); OpenAppList(); ClickAssistantButton(); - // The LauncherSearchIphView is not shown in the zero state view. + // The LauncherSearchIphView will show in the zero state view. ASSERT_TRUE(IsAssistantPageActive()); ASSERT_TRUE(GetAssistantZeroStateView()->GetVisible()); ash::LauncherSearchIphView* launcher_search_iph = GetAssistantLauncherSearchIph(); - EXPECT_FALSE(launcher_search_iph->GetVisible()); - EXPECT_FALSE(launcher_search_iph->IsDrawn()); + EXPECT_TRUE(launcher_search_iph->GetVisible()); + EXPECT_TRUE(launcher_search_iph->IsDrawn()); } IN_PROC_BROWSER_TEST_P(AppListIphBrowserTestAssistantZeroState,
diff --git a/chrome/browser/ash/app_list/search/assistant_text_search_provider_unittest.cc b/chrome/browser/ash/app_list/search/assistant_text_search_provider_unittest.cc index 93d775b..5b61949 100644 --- a/chrome/browser/ash/app_list/search/assistant_text_search_provider_unittest.cc +++ b/chrome/browser/ash/app_list/search/assistant_text_search_provider_unittest.cc
@@ -15,6 +15,7 @@ #include "chrome/browser/ash/app_list/app_list_test_util.h" #include "chrome/browser/ash/app_list/search/chrome_search_result.h" #include "chrome/browser/ash/app_list/search/test/test_search_controller.h" +#include "components/feature_engagement/public/feature_constants.h" #include "testing/gmock/include/gmock/gmock.h" #include "url/gurl.h" @@ -29,6 +30,10 @@ auto search_provider = std::make_unique<AssistantTextSearchProvider>(); search_provider_ = search_provider.get(); search_controller_.AddProvider(std::move(search_provider)); + + // This test suite will be deleted after the Launcher Search IPH is enabled. + feature_list_.InitAndDisableFeature( + feature_engagement::kIPHLauncherSearchHelpUiFeature); } AssistantTextSearchProviderTest(const AssistantTextSearchProviderTest&) = delete;
diff --git a/chrome/browser/ash/bluetooth/bluetooth_integration_test.cc b/chrome/browser/ash/bluetooth/bluetooth_integration_test.cc index 9a4f4a63..15895492 100644 --- a/chrome/browser/ash/bluetooth/bluetooth_integration_test.cc +++ b/chrome/browser/ash/bluetooth/bluetooth_integration_test.cc
@@ -127,12 +127,6 @@ return WaitForStateChange(element_id, toggle_selection_change); } - // Clicks on an element in the DOM. - auto ClickElement(const ui::ElementIdentifier& element_id, - const DeepQuery& element) { - return Steps(MoveMouseTo(element_id, element), ClickMouse()); - } - protected: base::test::ScopedFeatureList feature_list_; raw_ptr<BluezDBusManager> bluez_dbus_manager_ = nullptr;
diff --git a/chrome/browser/ash/mahi/mahi_manager_ash.cc b/chrome/browser/ash/mahi/mahi_manager_ash.cc index 0622d433..d909abe 100644 --- a/chrome/browser/ash/mahi/mahi_manager_ash.cc +++ b/chrome/browser/ash/mahi/mahi_manager_ash.cc
@@ -4,10 +4,22 @@ #include "chrome/browser/ash/mahi/mahi_manager_ash.h" +#include <stdint.h> + +#include "ash/system/mahi/mahi_panel_widget.h" +#include "ui/views/widget/unique_widget_ptr.h" + namespace ash { MahiManagerAsh::MahiManagerAsh() = default; -MahiManagerAsh::~MahiManagerAsh() = default; +MahiManagerAsh::~MahiManagerAsh() { + mahi_panel_widget_.reset(); +} + +void MahiManagerAsh::OpenMahiPanel(int64_t display_id) { + mahi_panel_widget_ = MahiPanelWidget::CreatePanelWidget(display_id); + mahi_panel_widget_->Show(); +} } // namespace ash
diff --git a/chrome/browser/ash/mahi/mahi_manager_ash.h b/chrome/browser/ash/mahi/mahi_manager_ash.h index 975a43f9..549d9c23 100644 --- a/chrome/browser/ash/mahi/mahi_manager_ash.h +++ b/chrome/browser/ash/mahi/mahi_manager_ash.h
@@ -6,6 +6,7 @@ #define CHROME_BROWSER_ASH_MAHI_MAHI_MANAGER_ASH_H_ #include "chromeos/components/mahi/public/cpp/mahi_manager.h" +#include "ui/views/widget/unique_widget_ptr.h" namespace ash { @@ -18,6 +19,15 @@ MahiManagerAsh& operator=(const MahiManagerAsh&) = delete; ~MahiManagerAsh() override; + + // chromeos::MahiManager: + void OpenMahiPanel(int64_t display_id) override; + + private: + friend class MahiManagerAshTest; + + // The widget contains the Mahi main panel. + views::UniqueWidgetPtr mahi_panel_widget_; }; } // namespace ash
diff --git a/chrome/browser/ash/mahi/mahi_manager_ash_unittest.cc b/chrome/browser/ash/mahi/mahi_manager_ash_unittest.cc new file mode 100644 index 0000000..dc5e844f --- /dev/null +++ b/chrome/browser/ash/mahi/mahi_manager_ash_unittest.cc
@@ -0,0 +1,71 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ash/mahi/mahi_manager_ash.h" + +#include <memory> + +#include "ash/test/ash_test_helper.h" +#include "content/public/test/browser_task_environment.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/aura/window.h" +#include "ui/display/display.h" +#include "ui/display/screen.h" +#include "ui/views/widget/widget.h" + +namespace ash { + +class MahiManagerAshTest : public testing::Test { + public: + MahiManagerAshTest() = default; + + MahiManagerAshTest(const MahiManagerAshTest&) = delete; + MahiManagerAshTest& operator=(const MahiManagerAshTest&) = delete; + + ~MahiManagerAshTest() override = default; + + // testing::Test: + void SetUp() override { + ash_test_helper_.SetUp(); + + mahi_manager_ash_ = std::make_unique<MahiManagerAsh>(); + } + + void TearDown() override { ash_test_helper_.TearDown(); } + + views::Widget* GetMahiPanelWidget() { + if (!mahi_manager_ash_->mahi_panel_widget_) { + return nullptr; + } + return mahi_manager_ash_->mahi_panel_widget_->AsWidget(); + } + + protected: + // This instance is needed for setting up `ash_test_helper_`. + // See //docs/threading_and_tasks_testing.md. + content::BrowserTaskEnvironment task_environment_; + + // Need this to set up `Shell` and display. + AshTestHelper ash_test_helper_; + std::unique_ptr<MahiManagerAsh> mahi_manager_ash_; +}; + +TEST_F(MahiManagerAshTest, OpenPanel) { + EXPECT_FALSE(GetMahiPanelWidget()); + + auto* screen = display::Screen::GetScreen(); + auto display_id = screen->GetPrimaryDisplay().id(); + + mahi_manager_ash_->OpenMahiPanel(display_id); + + // Widget should be created. + auto* widget = GetMahiPanelWidget(); + EXPECT_TRUE(widget); + + // The widget should be in the same display as the given `display_id`. + EXPECT_EQ(display_id, + screen->GetDisplayNearestWindow(widget->GetNativeWindow()).id()); +} + +} // namespace ash
diff --git a/chrome/browser/ash/os_feedback/os_feedback_interactive_uitest.cc b/chrome/browser/ash/os_feedback/os_feedback_interactive_uitest.cc index c89a3df0..9a40a62 100644 --- a/chrome/browser/ash/os_feedback/os_feedback_interactive_uitest.cc +++ b/chrome/browser/ash/os_feedback/os_feedback_interactive_uitest.cc
@@ -85,11 +85,6 @@ } #endif // BUILDFLAG(GOOGLE_CHROME_BRANDING) - // Clicks on an element in the DOM. - auto ClickElement(const ui::ElementIdentifier& element_id, - const DeepQuery& element) { - return Steps(MoveMouseTo(element_id, element), ClickMouse()); - } // Wait for the Feedback SWA to be present. auto WaitForFeedbackSWAReady(const ui::ElementIdentifier& element_id) { return Steps(
diff --git a/chrome/browser/ash/scanning/multi_page_scan_integration_test.cc b/chrome/browser/ash/scanning/multi_page_scan_integration_test.cc index 7e9f0d0..20662b0 100644 --- a/chrome/browser/ash/scanning/multi_page_scan_integration_test.cc +++ b/chrome/browser/ash/scanning/multi_page_scan_integration_test.cc
@@ -124,7 +124,8 @@ } }; -IN_PROC_BROWSER_TEST_F(MultiPageScanIntegrationTest, MultiPageScan) { +// TODO(b:319899858): Re-enable the test. +IN_PROC_BROWSER_TEST_F(MultiPageScanIntegrationTest, DISABLED_MultiPageScan) { // Set up context for element tracking for InteractiveBrowserTest. SetupContextWidget();
diff --git a/chrome/browser/ash/scanning/scan_integration_test.cc b/chrome/browser/ash/scanning/scan_integration_test.cc index f354c1e..84a2aff 100644 --- a/chrome/browser/ash/scanning/scan_integration_test.cc +++ b/chrome/browser/ash/scanning/scan_integration_test.cc
@@ -100,7 +100,8 @@ }; // TODO(b:307385730): Add tests that select various scan settings combinations. -IN_PROC_BROWSER_TEST_F(ScanIntegrationTest, ScanWithDefaultSettings) { +// TODO(b:319899858): Re-enable the test. +IN_PROC_BROWSER_TEST_F(ScanIntegrationTest, DISABLED_ScanWithDefaultSettings) { // Set up context for element tracking for InteractiveBrowserTest. SetupContextWidget();
diff --git a/chrome/browser/ash/security_files_integration_test.cc b/chrome/browser/ash/security_files_integration_test.cc index 5fa264d..dd9dfaa 100644 --- a/chrome/browser/ash/security_files_integration_test.cc +++ b/chrome/browser/ash/security_files_integration_test.cc
@@ -71,7 +71,9 @@ } }; -IN_PROC_BROWSER_TEST_F(SecurityFilesIntegrationTest, UserFilesLoggedIn) { +// TODO(b:319899858): Re-enable the test. +IN_PROC_BROWSER_TEST_F(SecurityFilesIntegrationTest, + DISABLED_UserFilesLoggedIn) { login_mixin().Login(); ash::test::WaitForPrimaryUserSessionStart();
diff --git a/chrome/browser/download/android/BUILD.gn b/chrome/browser/download/android/BUILD.gn index c7f19bf..720f7fb 100644 --- a/chrome/browser/download/android/BUILD.gn +++ b/chrome/browser/download/android/BUILD.gn
@@ -49,7 +49,10 @@ "java/src/org/chromium/chrome/browser/download/dialogs/DownloadLocationDialogProperties.java", "java/src/org/chromium/chrome/browser/download/dialogs/DownloadLocationDialogViewBinder.java", "java/src/org/chromium/chrome/browser/download/dialogs/InsecureDownloadDialog.java", + "java/src/org/chromium/chrome/browser/download/dialogs/OpenDownloadCustomView.java", "java/src/org/chromium/chrome/browser/download/dialogs/OpenDownloadDialog.java", + "java/src/org/chromium/chrome/browser/download/dialogs/OpenDownloadDialogProperties.java", + "java/src/org/chromium/chrome/browser/download/dialogs/OpenDownloadDialogViewBinder.java", "java/src/org/chromium/chrome/browser/download/home/DownloadManagerCoordinator.java", "java/src/org/chromium/chrome/browser/download/home/DownloadManagerUiConfig.java", "java/src/org/chromium/chrome/browser/download/home/DownloadManagerUiConfigHelper.java", @@ -220,6 +223,7 @@ "java/res/layout/download_location_preference_item.xml", "java/res/layout/download_location_spinner_dropdown_item.xml", "java/res/layout/download_location_spinner_item.xml", + "java/res/layout/open_download_dialog.xml", "java/res/values-v17/dimens.xml", "java/res/values-v17/styles.xml", "java/res/xml/download_preferences.xml",
diff --git a/chrome/browser/download/android/java/res/layout/open_download_dialog.xml b/chrome/browser/download/android/java/res/layout/open_download_dialog.xml new file mode 100644 index 0000000..d7bf13b --- /dev/null +++ b/chrome/browser/download/android/java/res/layout/open_download_dialog.xml
@@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +Copyright 2024 The Chromium Authors +Use of this source code is governed by a BSD-style license that can be +found in the LICENSE file. +--> + +<org.chromium.chrome.browser.download.dialogs.OpenDownloadCustomView + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="wrap_content" > + + <LinearLayout + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="wrap_content" + style="@style/AlertDialogContent"> + + <TextView + android:id="@+id/title" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginBottom="@dimen/download_dialog_title_margin_bottom" + android:textAppearance="@style/TextAppearance.AlertDialogTitleStyle" /> + + <TextView + android:id="@+id/subtitle" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/download_dialog_subtitle_margin_top" + android:textAppearance="@style/TextAppearance.TextMedium.Secondary"/> + + <CheckBox + android:id="@+id/auto_open_checkbox" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/download_dialog_checkbox_margin_top" + android:layout_marginStart="@dimen/download_dialog_checkbox_margin_start" + android:text="@string/open_download_dialog_auto_open_text" + style="@style/DefaultCheckboxStyle"/> + + </LinearLayout> + +</org.chromium.chrome.browser.download.dialogs.OpenDownloadCustomView>
diff --git a/chrome/browser/download/android/java/res/values-v17/dimens.xml b/chrome/browser/download/android/java/res/values-v17/dimens.xml index e58196c..b906636 100644 --- a/chrome/browser/download/android/java/res/values-v17/dimens.xml +++ b/chrome/browser/download/android/java/res/values-v17/dimens.xml
@@ -8,6 +8,7 @@ <resources xmlns:tools="http://schemas.android.com/tools"> <dimen name="download_dialog_title_margin_bottom">3dp</dimen> <dimen name="download_dialog_subtitle_margin_bottom">10dp</dimen> + <dimen name="download_dialog_subtitle_margin_top">16dp</dimen> <dimen name="download_dialog_checkbox_margin_start">-5dp</dimen> <dimen name="download_dialog_checkbox_margin_top">16dp</dimen> <dimen name="download_dialog_location_space_margin_start">49dp</dimen>
diff --git a/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/OpenDownloadDialogBridge.java b/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/OpenDownloadDialogBridge.java index aca3a30..b9a3f78 100644 --- a/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/OpenDownloadDialogBridge.java +++ b/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/OpenDownloadDialogBridge.java
@@ -6,43 +6,21 @@ import android.app.Activity; -import androidx.annotation.IntDef; - import org.jni_zero.CalledByNative; import org.jni_zero.NativeMethods; import org.chromium.base.metrics.RecordHistogram; import org.chromium.chrome.browser.download.dialogs.OpenDownloadDialog; +import org.chromium.chrome.browser.download.dialogs.OpenDownloadDialog.OpenDownloadDialogEvent; import org.chromium.chrome.browser.download.interstitial.NewDownloadTab; import org.chromium.chrome.browser.preferences.Pref; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.components.user_prefs.UserPrefs; import org.chromium.ui.base.WindowAndroid; -import org.chromium.ui.modaldialog.DialogDismissalCause; import org.chromium.ui.modaldialog.ModalDialogManagerHolder; /** Glues open download dialogs UI code and handles the communication to download native backend. */ public class OpenDownloadDialogBridge { - /** - * Events related to the open download dialog, used for UMA reporting. These values are - * persisted to logs. Entries should not be renumbered and numeric values should never be - * reused. - */ - @IntDef({ - OpenDownloadDialogEvent.OPEN_DOWNLOAD_DIALOG_SHOW, - OpenDownloadDialogEvent.OPEN_DOWNLOAD_DIALOG_ALWAYS_OPEN, - OpenDownloadDialogEvent.OPEN_DOWNLOAD_DIALOG_JUST_ONCE, - OpenDownloadDialogEvent.OPEN_DOWNLOAD_DIALOG_DISMISS - }) - private @interface OpenDownloadDialogEvent { - int OPEN_DOWNLOAD_DIALOG_SHOW = 0; - int OPEN_DOWNLOAD_DIALOG_ALWAYS_OPEN = 1; - int OPEN_DOWNLOAD_DIALOG_JUST_ONCE = 2; - int OPEN_DOWNLOAD_DIALOG_DISMISS = 3; - - int COUNT = 4; - } - private long mNativeOpenDownloadDialogBridge; /** @@ -78,20 +56,23 @@ .show( activity, ((ModalDialogManagerHolder) activity).getModalDialogManager(), + UserPrefs.get(profile).getBoolean(Pref.AUTO_OPEN_PDF_ENABLED), (result) -> { - if (result == DialogDismissalCause.POSITIVE_BUTTON_CLICKED) { + if (result + == OpenDownloadDialogEvent.OPEN_DOWNLOAD_DIALOG_ALWAYS_OPEN) { UserPrefs.get(profile).setBoolean(Pref.AUTO_OPEN_PDF_ENABLED, true); + onConfirmed(guid); recordOpenDownloadDialogEvent( OpenDownloadDialogEvent.OPEN_DOWNLOAD_DIALOG_ALWAYS_OPEN); + } else if (result + == OpenDownloadDialogEvent.OPEN_DOWNLOAD_DIALOG_JUST_ONCE) { onConfirmed(guid); - } else if (result == DialogDismissalCause.NEGATIVE_BUTTON_CLICKED) { recordOpenDownloadDialogEvent( OpenDownloadDialogEvent.OPEN_DOWNLOAD_DIALOG_JUST_ONCE); - onConfirmed(guid); } else { + onCancel(guid, windowAndroid); recordOpenDownloadDialogEvent( OpenDownloadDialogEvent.OPEN_DOWNLOAD_DIALOG_DISMISS); - onCancel(guid, windowAndroid); } }); recordOpenDownloadDialogEvent(OpenDownloadDialogEvent.OPEN_DOWNLOAD_DIALOG_SHOW);
diff --git a/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/dialogs/OpenDownloadCustomView.java b/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/dialogs/OpenDownloadCustomView.java new file mode 100644 index 0000000..0d848263 --- /dev/null +++ b/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/dialogs/OpenDownloadCustomView.java
@@ -0,0 +1,52 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.download.dialogs; + +import android.content.Context; +import android.util.AttributeSet; +import android.widget.CheckBox; +import android.widget.ScrollView; +import android.widget.TextView; + +import org.chromium.chrome.browser.download.R; + +/** Dialog that is displayed to ask user where they want to open a download. */ +public class OpenDownloadCustomView extends ScrollView { + private TextView mTitle; + private TextView mSubtitleView; + private CheckBox mAutoOpenCheckbox; + + public OpenDownloadCustomView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + + mTitle = findViewById(R.id.title); + mSubtitleView = findViewById(R.id.subtitle); + mAutoOpenCheckbox = findViewById(R.id.auto_open_checkbox); + } + + void setTitle(CharSequence title) { + mTitle.setText(title); + } + + void setSubtitle(CharSequence subtitle) { + mSubtitleView.setText(subtitle); + } + + void setAutoOpenCheckbox(boolean checked) { + mAutoOpenCheckbox.setChecked(checked); + } + + /** + * @return Whether the "auto open" checkbox is checked. + */ + boolean getAutoOpenEnabled() { + return mAutoOpenCheckbox.isChecked(); + } +}
diff --git a/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/dialogs/OpenDownloadDialog.java b/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/dialogs/OpenDownloadDialog.java index 8a4de29..42eff25 100644 --- a/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/dialogs/OpenDownloadDialog.java +++ b/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/dialogs/OpenDownloadDialog.java
@@ -5,26 +5,61 @@ package org.chromium.chrome.browser.download.dialogs; import android.content.Context; +import android.view.LayoutInflater; + +import androidx.annotation.IntDef; import org.chromium.base.Callback; import org.chromium.chrome.browser.download.R; import org.chromium.ui.modaldialog.DialogDismissalCause; import org.chromium.ui.modaldialog.ModalDialogManager; import org.chromium.ui.modaldialog.ModalDialogProperties; +import org.chromium.ui.modelutil.PropertyKey; import org.chromium.ui.modelutil.PropertyModel; +import org.chromium.ui.modelutil.PropertyModelChangeProcessor; /** Dialog for confirming that the user wants to open a pdf download after download completion. */ public class OpenDownloadDialog { /** + * Events related to the open download dialog, used for UMA reporting. These values are + * persisted to logs. Entries should not be renumbered and numeric values should never be + * reused. + */ + @IntDef({ + OpenDownloadDialogEvent.OPEN_DOWNLOAD_DIALOG_SHOW, + OpenDownloadDialogEvent.OPEN_DOWNLOAD_DIALOG_ALWAYS_OPEN, + OpenDownloadDialogEvent.OPEN_DOWNLOAD_DIALOG_JUST_ONCE, + OpenDownloadDialogEvent.OPEN_DOWNLOAD_DIALOG_DISMISS + }) + public @interface OpenDownloadDialogEvent { + int OPEN_DOWNLOAD_DIALOG_SHOW = 0; + int OPEN_DOWNLOAD_DIALOG_ALWAYS_OPEN = 1; + int OPEN_DOWNLOAD_DIALOG_JUST_ONCE = 2; + int OPEN_DOWNLOAD_DIALOG_DISMISS = 3; + + int COUNT = 4; + } + + private PropertyModelChangeProcessor<PropertyModel, OpenDownloadCustomView, PropertyKey> + mPropertyModelChangeProcessor; + + /** * Called to show a dialog for opening a download. * * @param context Context for showing the dialog. * @param modalDialogManager Manager for managing the modal dialog. + * @param autoOpenEnabled Whether auto-open PDF is enabled. * @param callback Callback to run when confirming the dialog, dismissalCause is passed as a * param. */ public void show( - Context context, ModalDialogManager modalDialogManager, Callback<Integer> callback) { + Context context, + ModalDialogManager modalDialogManager, + boolean autoOpenEnabled, + Callback<Integer> callback) { + OpenDownloadCustomView customView = + (OpenDownloadCustomView) + LayoutInflater.from(context).inflate(R.layout.open_download_dialog, null); var controller = new ModalDialogProperties.Controller() { @Override @@ -40,27 +75,53 @@ @Override public void onDismiss(PropertyModel model, int dismissalCause) { - if (callback != null) callback.onResult(dismissalCause); + if (callback != null) { + @OpenDownloadDialogEvent + int result = OpenDownloadDialogEvent.OPEN_DOWNLOAD_DIALOG_DISMISS; + if (dismissalCause == DialogDismissalCause.POSITIVE_BUTTON_CLICKED) { + result = + customView.getAutoOpenEnabled() + ? OpenDownloadDialogEvent + .OPEN_DOWNLOAD_DIALOG_ALWAYS_OPEN + : OpenDownloadDialogEvent + .OPEN_DOWNLOAD_DIALOG_JUST_ONCE; + } + callback.onResult(result); + } } }; var resources = context.getResources(); + PropertyModel propertyModel = - new PropertyModel.Builder(ModalDialogProperties.ALL_KEYS) - .with(ModalDialogProperties.CONTROLLER, controller) + new PropertyModel.Builder(OpenDownloadDialogProperties.ALL_KEYS) .with( - ModalDialogProperties.TITLE, + OpenDownloadDialogProperties.TITLE, resources.getString(R.string.open_download_dialog_title)) .with( - ModalDialogProperties.MESSAGE_PARAGRAPH_1, + OpenDownloadDialogProperties.SUBTITLE, resources.getString(R.string.open_download_dialog_text)) .with( + OpenDownloadDialogProperties.AUTO_OPEN_CHECKBOX_CHECKED, + autoOpenEnabled) + .build(); + mPropertyModelChangeProcessor = + PropertyModelChangeProcessor.create( + propertyModel, + customView, + OpenDownloadDialogViewBinder::bind, + /* performInitialBind= */ true); + + PropertyModel showPropertyModel = + new PropertyModel.Builder(ModalDialogProperties.ALL_KEYS) + .with(ModalDialogProperties.CONTROLLER, controller) + .with(ModalDialogProperties.CUSTOM_VIEW, customView) + .with( ModalDialogProperties.POSITIVE_BUTTON_TEXT, - resources.getString(R.string.open_download_dialog_always_open_text)) + resources.getString(R.string.open_download_dialog_open_text)) .with( ModalDialogProperties.NEGATIVE_BUTTON_TEXT, - resources.getString(R.string.open_download_dialog_just_once_text)) + resources.getString(R.string.open_download_dialog_cancel_text)) .build(); - - modalDialogManager.showDialog(propertyModel, ModalDialogManager.ModalDialogType.TAB); + modalDialogManager.showDialog(showPropertyModel, ModalDialogManager.ModalDialogType.TAB); } }
diff --git a/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/dialogs/OpenDownloadDialogProperties.java b/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/dialogs/OpenDownloadDialogProperties.java new file mode 100644 index 0000000..6ddd91e1 --- /dev/null +++ b/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/dialogs/OpenDownloadDialogProperties.java
@@ -0,0 +1,29 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.download.dialogs; + +import org.chromium.ui.modelutil.PropertyKey; +import org.chromium.ui.modelutil.PropertyModel; + +/** + * Properties used by the MVC model between {@link OpenDownloadDialogCoordinator} and {@link + * OpenDownloadCustomView}. + */ +class OpenDownloadDialogProperties { + /** The title text of the open download dialog. */ + static final PropertyModel.ReadableObjectPropertyKey<CharSequence> TITLE = + new PropertyModel.ReadableObjectPropertyKey<>(); + + /** The subtitle text of the open download dialog. */ + static final PropertyModel.ReadableObjectPropertyKey<CharSequence> SUBTITLE = + new PropertyModel.ReadableObjectPropertyKey<>(); + + /** Whether the auto open checkbox is checked. Default to false. */ + static final PropertyModel.ReadableBooleanPropertyKey AUTO_OPEN_CHECKBOX_CHECKED = + new PropertyModel.ReadableBooleanPropertyKey(); + + static final PropertyKey[] ALL_KEYS = + new PropertyKey[] {TITLE, SUBTITLE, AUTO_OPEN_CHECKBOX_CHECKED}; +}
diff --git a/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/dialogs/OpenDownloadDialogViewBinder.java b/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/dialogs/OpenDownloadDialogViewBinder.java new file mode 100644 index 0000000..a1437060 --- /dev/null +++ b/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/dialogs/OpenDownloadDialogViewBinder.java
@@ -0,0 +1,25 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.download.dialogs; + +import org.chromium.ui.modelutil.PropertyKey; +import org.chromium.ui.modelutil.PropertyModel; + +/** + * The view binder that connects {@link OpenDownloadCustomView} and {@link + * OpenDownloadDialogCoordinator} which defines the UI properties. + */ +class OpenDownloadDialogViewBinder { + static void bind(PropertyModel model, OpenDownloadCustomView view, PropertyKey propertyKey) { + if (propertyKey == OpenDownloadDialogProperties.TITLE) { + view.setTitle(model.get(OpenDownloadDialogProperties.TITLE)); + } else if (propertyKey == OpenDownloadDialogProperties.SUBTITLE) { + view.setSubtitle(model.get(OpenDownloadDialogProperties.SUBTITLE)); + } else if (propertyKey == OpenDownloadDialogProperties.AUTO_OPEN_CHECKBOX_CHECKED) { + view.setAutoOpenCheckbox( + model.get(OpenDownloadDialogProperties.AUTO_OPEN_CHECKBOX_CHECKED)); + } + } +}
diff --git a/chrome/browser/extensions/event_metrics_browsertest.cc b/chrome/browser/extensions/event_metrics_browsertest.cc index 0a40cf6..b7339e6 100644 --- a/chrome/browser/extensions/event_metrics_browsertest.cc +++ b/chrome/browser/extensions/event_metrics_browsertest.cc
@@ -217,12 +217,49 @@ histogram_tester.ExpectTotalCount( "Extensions.Events.DispatchToAckTime.ExtensionServiceWorker2", /*expected_count=*/0); - // We are not yet emitting a DidDispatchToAckSucceed for persistent background - // pages yet, so ensure we aren't accidentally emitting event page version - // since they use the same event acknowledgement flow. +} + +// Tests that only the dispatch time histogram for a persistent background page +// extension is emitted with a sane value, and that the same metric for other +// background context types are not emitted. +IN_PROC_BROWSER_TEST_F(EventMetricsBrowserTest, + PersistentBackgroundStaleEventsMetricTest) { + ASSERT_TRUE(embedded_test_server()->Start()); + ExtensionTestMessageListener extension_oninstall_listener_fired( + "installed listener fired"); + // Load the extension for a persistent background page + scoped_refptr<const Extension> extension = LoadExtension( + test_data_dir_.AppendASCII("events/metrics/persistent_background")); + ASSERT_TRUE(extension); + // This ensures that we wait until the the browser receives the ack from the + // renderer. This prevents unexpected histogram emits later. + ASSERT_TRUE(extension_oninstall_listener_fired.WaitUntilSatisfied()); + + base::HistogramTester histogram_tester; + ExtensionTestMessageListener test_event_listener_fired("listener fired"); + // Navigate somewhere to trigger the webNavigation.onBeforeRequest event to + // the extension listener. + ASSERT_TRUE(ui_test_utils::NavigateToURL( + browser(), + embedded_test_server()->GetURL("example.com", "/simple.html"))); + ASSERT_TRUE(test_event_listener_fired.WaitUntilSatisfied()); + + // Call to webNavigation.onCompleted expected. + histogram_tester.ExpectTotalCount( + "Extensions.Events.DidDispatchToAckSucceed.ExtensionPersistentPage", + /*expected_count=*/1); + // Verify that the value is `true` since the event wasn't delayed in acking. + histogram_tester.ExpectBucketCount( + "Extensions.Events.DidDispatchToAckSucceed.ExtensionPersistentPage", + /*sample=*/true, /*expected_count=*/1); + + // Verify other extension background context types are not logged. histogram_tester.ExpectTotalCount( "Extensions.Events.DidDispatchToAckSucceed.ExtensionPage", /*expected_count=*/0); + histogram_tester.ExpectTotalCount( + "Extensions.Events.DidDispatchToAckSucceed.ExtensionServiceWorker2", + /*expected_count=*/0); } // Tests that for every event received there is a corresponding emit of starting
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index cc89f405..3db4603 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -882,7 +882,7 @@ { "name": "bluetooth-use-llprivacy", "owners": ["jiangzp@chromium.org", "chromeos-bt-champs@google.com"], - "expiry_milestone": 111 + "expiry_milestone": 124 }, { "name": "boarding-pass-detector", @@ -6849,6 +6849,14 @@ "expiry_milestone": 133 }, { + "name": "read-aloud-in-cct", + "owners": [ + "basiaz@google.com", + "iwells@google.com" + ], + "expiry_milestone": 133 + }, + { "name": "read-aloud-playback", "owners": [ "basiaz@google.com", @@ -7074,6 +7082,14 @@ "expiry_milestone": 140 }, { + "name": "safe-browsing-async-real-time-check", + "owners": [ + "xinghuilu@chromium.org", + "chrome-counter-abuse-alerts@google.com" + ], + "expiry_milestone": 125 + }, + { "name": "safe-browsing-hash-prefix", "owners": [ "xinghuilu@chromium.org",
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index 065a9f6..1b348e40 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -1612,6 +1612,12 @@ const char kExperimentalWebPlatformFeaturesDescription[] = "Enables experimental Web Platform features that are in development."; +const char kSafeBrowsingAsyncRealTimeCheckName[] = + "Safe Browsing Async Real Time Check"; +const char kSafeBrowsingAsyncRealTimeCheckDescription[] = + "Safe Browsing real-time checks are conducted asynchronously. They no " + "longer delay page load."; + const char kSafeBrowsingHashPrefixRealTimeLookupsName[] = "Safe Browsing Hash Prefix Real Time Lookups"; const char kSafeBrowsingHashPrefixRealTimeLookupsDescription[] = @@ -4261,6 +4267,10 @@ const char kReadAloudName[] = "Read Aloud"; const char kReadAloudDescription[] = "Controls the Read Aloud feature"; +const char kReadAloudInCCTName[] = "Read Aloud entrypoint in CCT"; +const char kReadAloudInCCTDescription[] = + "Controls the Read Aloud entrypoint in the overflow menu for CCT"; + const char kReadLaterFlagId[] = "read-later"; const char kReadLaterName[] = "Reading List"; const char kReadLaterDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index b22fa33..fc9d4b3 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -904,6 +904,9 @@ extern const char kExperimentalWebPlatformFeaturesName[]; extern const char kExperimentalWebPlatformFeaturesDescription[]; +extern const char kSafeBrowsingAsyncRealTimeCheckName[]; +extern const char kSafeBrowsingAsyncRealTimeCheckDescription[]; + extern const char kSafeBrowsingHashPrefixRealTimeLookupsName[]; extern const char kSafeBrowsingHashPrefixRealTimeLookupsDescription[]; @@ -2507,6 +2510,8 @@ extern const char kReadAloudName[]; extern const char kReadAloudDescription[]; +extern const char kReadAloudInCCTName[]; +extern const char kReadAloudInCCTDescription[]; extern const char kReaderModeHeuristicsName[]; extern const char kReaderModeHeuristicsDescription[];
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/BaseFlagTestRule.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/BaseFlagTestRule.java index 4e2809b..c0c63ff 100644 --- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/BaseFlagTestRule.java +++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/BaseFlagTestRule.java
@@ -11,6 +11,7 @@ import org.junit.runners.model.Statement; import org.chromium.base.FeatureList; +import org.chromium.base.FeatureMap; import org.chromium.base.Flag; import java.util.Map; @@ -45,6 +46,18 @@ static final Map<String, Boolean> A_ON_B_OFF = Map.of(FEATURE_A, true, FEATURE_B, false); static final Map<String, Boolean> A_ON_B_ON = Map.of(FEATURE_A, true, FEATURE_B, true); + /** A stub FeatureMap instance to create flags on. */ + public static final FeatureMap FEATURE_MAP = + new FeatureMap() { + @Override + protected long getNativeMap() { + throw new UnsupportedOperationException( + "FeatureMap stub for testing does not support getting the flag value" + + " across the native boundary, provide test override values" + + " instead."); + } + }; + static void assertIsEnabledMatches(Map<String, Boolean> state, Flag feature1, Flag feature2) { assertEquals(state.get(FEATURE_A), feature1.isEnabled()); assertEquals(state.get(FEATURE_B), feature2.isEnabled());
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/CachedFeatureFlagsSafeModeUnitTest.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/CachedFeatureFlagsSafeModeUnitTest.java index be86412..a0b9a66 100644 --- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/CachedFeatureFlagsSafeModeUnitTest.java +++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/CachedFeatureFlagsSafeModeUnitTest.java
@@ -16,6 +16,7 @@ import org.chromium.base.FeatureList; import org.chromium.base.FeatureList.TestValues; +import org.chromium.base.FeatureMap; import org.chromium.base.task.test.PausedExecutorTestRule; import org.chromium.base.test.BaseRobolectricTestRunner; import org.chromium.chrome.browser.flags.CachedFlagsSafeMode.Behavior; @@ -27,13 +28,15 @@ public class CachedFeatureFlagsSafeModeUnitTest { @Rule public PausedExecutorTestRule mExecutorRule = new PausedExecutorTestRule(); + private static final FeatureMap FEATURE_MAP = BaseFlagTestRule.FEATURE_MAP; private static final String CRASHY_FEATURE = "CrashyFeature"; private static final String OK_FEATURE = "OkFeature"; private static final boolean CRASHY_FEATURE_DEFAULT = false; private static final boolean OK_FEATURE_DEFAULT = false; private static final CachedFlag sCrashyFeature = - new CachedFlag(CRASHY_FEATURE, CRASHY_FEATURE_DEFAULT); - private static final CachedFlag sOkFeature = new CachedFlag(OK_FEATURE, OK_FEATURE_DEFAULT); + new CachedFlag(FEATURE_MAP, CRASHY_FEATURE, CRASHY_FEATURE_DEFAULT); + private static final CachedFlag sOkFeature = + new CachedFlag(FEATURE_MAP, OK_FEATURE, OK_FEATURE_DEFAULT); private static final String BOOL_PARAM_NAME = "BoolParam"; private static final String INT_PARAM_NAME = "IntParam";
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/CachedFlag.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/CachedFlag.java index e4ada3f9..1b4da28 100644 --- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/CachedFlag.java +++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/CachedFlag.java
@@ -7,6 +7,7 @@ import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; +import org.chromium.base.FeatureMap; import org.chromium.base.Flag; import org.chromium.base.cached_flags.CachedFlagsSharedPreferences; import org.chromium.base.shared_preferences.SharedPreferencesManager; @@ -19,18 +20,21 @@ * CachedFlags are Flags that may be used before native is loaded and the FeatureList is * initialized. * - * They return a flag value read from native in a previous run, using SharedPreferences as + * <p>They return a flag value read from native in a previous run, using SharedPreferences as * persistence. * - * @see {@link #isEnabled()} for more details about the logic. + * <p>@see {@link #isEnabled()} for more details about the logic. * - * To cache a flag from ChromeFeatureList: - * - Create a static CachedFlag object in {@link ChromeFeatureList} "sMyFlag" - * - Add it to the list {@link ChromeFeatureList#sFlagsCachedFullBrowser} - * - Call {@code ChromeFeatureList.sMyFlag.isEnabled()} to query whether the cached flag is enabled. - * Consider this the source of truth for whether the flag is turned on in the current session. + * <p>To cache a flag from a {@link FeatureMap}, e.g. FooFeatureMap: * - * Metrics caveat: For cached flags that are queried before native is initialized, when a new + * <ul> + * <li>Create a static CachedFlag object in FooFeatureMap "sMyFlag" + * <li>Add it to the list FooFeatureMap#sFlagsCachedFullBrowser + * <li>Call {@code FooFeatureMap.sMyFlag.isEnabled()} to query whether the cached flag is enabled. + * Consider this the source of truth for whether the flag is turned on in the current session. + * </ul> + * + * <p>Metrics caveat: For cached flags that are queried before native is initialized, when a new * experiment configuration is received the metrics reporting system will record metrics as if the * experiment is enabled despite the experimental behavior not yet taking effect. This will be * remedied on the next process restart. @@ -38,8 +42,8 @@ public class CachedFlag extends Flag { private final boolean mDefaultValue; - public CachedFlag(String featureName, boolean defaultValue) { - super(featureName); + public CachedFlag(FeatureMap featureMap, String featureName, boolean defaultValue) { + super(featureMap, featureName); mDefaultValue = defaultValue; } @@ -51,8 +55,8 @@ * CachedFlag#setForTesting}, the forced value is returned. * <li>2. If a value was previously returned in the same run, the same value is returned for * consistency. - * <li>3. If in a previous run, the value from {@link ChromeFeatureList} was cached to - * SharedPrefs, it is returned. + * <li>3. If in a previous run, the value from {@link FeatureMap} was cached to SharedPrefs, + * it is returned. * <li>4. The |defaultValue| passed as a constructor parameter is returned. * </ul> */ @@ -113,9 +117,9 @@ } } - /** Caches the value of the feature from {@link ChromeFeatureList} to SharedPrefs. */ + /** Caches the value of the feature from {@link FeatureMap} to SharedPrefs. */ void cacheFeature() { - boolean isEnabledInNative = ChromeFeatureList.isEnabled(mFeatureName); + boolean isEnabledInNative = mFeatureMap.isEnabledInNative(mFeatureName); CachedFlagsSharedPreferences.getInstance() .writeBoolean(getSharedPreferenceKey(), isEnabledInNative);
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/CachedFlagUnitTest.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/CachedFlagUnitTest.java index a664292..823b4fc 100644 --- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/CachedFlagUnitTest.java +++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/CachedFlagUnitTest.java
@@ -22,18 +22,18 @@ /** Unit Tests for {@link CachedFlag}. */ @RunWith(BaseRobolectricTestRunner.class) public class CachedFlagUnitTest { - @Rule public final BaseFlagTestRule baseFlagTestRule = new BaseFlagTestRule(); + @Rule public final BaseFlagTestRule mBaseFlagTestRule = new BaseFlagTestRule(); @Test(expected = AssertionError.class) public void testDuplicateFeature_throwsException() { - new CachedFlag(FEATURE_A, true); - new CachedFlag(FEATURE_A, true); + new CachedFlag(BaseFlagTestRule.FEATURE_MAP, FEATURE_A, true); + new CachedFlag(BaseFlagTestRule.FEATURE_MAP, FEATURE_A, true); } @Test public void testNativeInitialized_getsFromChromeFeatureList() { - CachedFlag featureA = new CachedFlag(FEATURE_A, false); - CachedFlag featureB = new CachedFlag(FEATURE_B, false); + CachedFlag featureA = new CachedFlag(BaseFlagTestRule.FEATURE_MAP, FEATURE_A, false); + CachedFlag featureB = new CachedFlag(BaseFlagTestRule.FEATURE_MAP, FEATURE_B, false); // Cache native flags, meaning values from ChromeFeatureList should be used from now on. FeatureList.setTestFeatures(A_OFF_B_ON); @@ -46,8 +46,8 @@ @Test public void testNativeNotInitializedNotCached_useDefault() { - CachedFlag featureA = new CachedFlag(FEATURE_A, true); - CachedFlag featureB = new CachedFlag(FEATURE_B, false); + CachedFlag featureA = new CachedFlag(BaseFlagTestRule.FEATURE_MAP, FEATURE_A, true); + CachedFlag featureB = new CachedFlag(BaseFlagTestRule.FEATURE_MAP, FEATURE_B, false); // Do not cache values from native. There are no values stored in prefs either. FeatureList.setTestFeatures(A_OFF_B_ON); @@ -65,8 +65,8 @@ @Test public void testNativeNotInitializedPrefsCached_getsFromPrefs() { - CachedFlag featureA = new CachedFlag(FEATURE_A, false); - CachedFlag featureB = new CachedFlag(FEATURE_B, false); + CachedFlag featureA = new CachedFlag(BaseFlagTestRule.FEATURE_MAP, FEATURE_A, false); + CachedFlag featureB = new CachedFlag(BaseFlagTestRule.FEATURE_MAP, FEATURE_B, false); // Cache native flags, meaning values from ChromeFeatureList should be used from now on. FeatureList.setTestFeatures(A_OFF_B_ON); @@ -101,8 +101,8 @@ @Test public void testSetForTesting_returnsForcedValue() { - CachedFlag featureA = new CachedFlag(FEATURE_A, false); - CachedFlag featureB = new CachedFlag(FEATURE_B, false); + CachedFlag featureA = new CachedFlag(BaseFlagTestRule.FEATURE_MAP, FEATURE_A, false); + CachedFlag featureB = new CachedFlag(BaseFlagTestRule.FEATURE_MAP, FEATURE_B, false); // Do not cache values from native. There are no values stored in prefs either. // Query the flags to make sure the default values are returned.
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 5881fc2..af59d6e8 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
@@ -97,6 +97,10 @@ return ChromeFeatureMap.getInstance().getFieldTrialParamsForFeature(featureName); } + private static CachedFlag newCachedFlag(String featureName, boolean defaultValue) { + return new CachedFlag(ChromeFeatureMap.getInstance(), featureName, defaultValue); + } + private static MutableFlagWithSafeDefault newMutableFlagWithSafeDefault( String featureName, boolean defaultValue) { return ChromeFeatureMap.getInstance().mutableFlagWithSafeDefault(featureName, defaultValue); @@ -455,139 +459,136 @@ /* Alphabetical: */ public static final CachedFlag sAndroidAppIntegration = - new CachedFlag(ANDROID_APP_INTEGRATION, false); + newCachedFlag(ANDROID_APP_INTEGRATION, false); public static final CachedFlag sAndroidElegantTextHeight = - new CachedFlag(ANDROID_ELEGANT_TEXT_HEIGHT, false); + newCachedFlag(ANDROID_ELEGANT_TEXT_HEIGHT, false); - public static final CachedFlag sAndroidHub = new CachedFlag(ANDROID_HUB, false); - public static final CachedFlag sArchiveTabService = new CachedFlag(ARCHIVE_TAB_SERVICE, false); + public static final CachedFlag sAndroidHub = newCachedFlag(ANDROID_HUB, false); + public static final CachedFlag sArchiveTabService = newCachedFlag(ARCHIVE_TAB_SERVICE, false); public static final CachedFlag sBackGestureActivityTabProvider = - new CachedFlag(BACK_GESTURE_ACTIVITY_TAB_PROVIDER, false); + newCachedFlag(BACK_GESTURE_ACTIVITY_TAB_PROVIDER, false); public static final CachedFlag sBackGestureMoveToBackDuringStartup = - new CachedFlag(BACK_GESTURE_MOVE_TO_BACK_DURING_STARTUP, true); + newCachedFlag(BACK_GESTURE_MOVE_TO_BACK_DURING_STARTUP, true); public static final CachedFlag sBackGestureRefactorAndroid = - new CachedFlag(BACK_GESTURE_REFACTOR, false); + newCachedFlag(BACK_GESTURE_REFACTOR, false); public static final CachedFlag sBlockIntentsWhileLocked = - new CachedFlag(BLOCK_INTENTS_WHILE_LOCKED, false); - public static final CachedFlag sCctAutoTranslate = new CachedFlag(CCT_AUTO_TRANSLATE, true); + newCachedFlag(BLOCK_INTENTS_WHILE_LOCKED, false); + public static final CachedFlag sCctAutoTranslate = newCachedFlag(CCT_AUTO_TRANSLATE, true); public static final CachedFlag sCctBrandTransparencyMemoryImprovement = - new CachedFlag(CCT_BRAND_TRANSPARENCY_MEMORY_IMPROVEMENT, true); - public static final CachedFlag sCctFeatureUsage = new CachedFlag(CCT_FEATURE_USAGE, false); + newCachedFlag(CCT_BRAND_TRANSPARENCY_MEMORY_IMPROVEMENT, true); + public static final CachedFlag sCctFeatureUsage = newCachedFlag(CCT_FEATURE_USAGE, false); public static final CachedFlag sCctIncognitoAvailableToThirdParty = - new CachedFlag(CCT_INCOGNITO_AVAILABLE_TO_THIRD_PARTY, false); + newCachedFlag(CCT_INCOGNITO_AVAILABLE_TO_THIRD_PARTY, false); public static final CachedFlag sCctIntentFeatureOverrides = - new CachedFlag(CCT_INTENT_FEATURE_OVERRIDES, true); - public static final CachedFlag sCctMinimized = new CachedFlag(CCT_MINIMIZED, false); + newCachedFlag(CCT_INTENT_FEATURE_OVERRIDES, true); + public static final CachedFlag sCctMinimized = newCachedFlag(CCT_MINIMIZED, false); public static final CachedFlag sCctPageInsightsHub = - new CachedFlag(CCT_PAGE_INSIGHTS_HUB, false); + newCachedFlag(CCT_PAGE_INSIGHTS_HUB, false); public static final CachedFlag sCctResizableForThirdParties = - new CachedFlag(CCT_RESIZABLE_FOR_THIRD_PARTIES, true); + newCachedFlag(CCT_RESIZABLE_FOR_THIRD_PARTIES, true); public static final CachedFlag sCctResizableSideSheet = - new CachedFlag(CCT_RESIZABLE_SIDE_SHEET, true); + newCachedFlag(CCT_RESIZABLE_SIDE_SHEET, true); public static final CachedFlag sCctResizableSideSheetForThirdParties = - new CachedFlag(CCT_RESIZABLE_SIDE_SHEET_FOR_THIRD_PARTIES, true); - public static final CachedFlag sCctTabModalDialog = new CachedFlag(CCT_TAB_MODAL_DIALOG, true); + newCachedFlag(CCT_RESIZABLE_SIDE_SHEET_FOR_THIRD_PARTIES, true); + public static final CachedFlag sCctTabModalDialog = newCachedFlag(CCT_TAB_MODAL_DIALOG, true); public static final CachedFlag sCollectAndroidFrameTimelineMetrics = - new CachedFlag(COLLECT_ANDROID_FRAME_TIMELINE_METRICS, false); + newCachedFlag(COLLECT_ANDROID_FRAME_TIMELINE_METRICS, false); public static final CachedFlag sCommandLineOnNonRooted = - new CachedFlag(COMMAND_LINE_ON_NON_ROOTED, false); + newCachedFlag(COMMAND_LINE_ON_NON_ROOTED, false); public static final CachedFlag sDeferTabSwitcherLayoutCreation = - new CachedFlag(DEFER_TAB_SWITCHER_LAYOUT_CREATION, false); + newCachedFlag(DEFER_TAB_SWITCHER_LAYOUT_CREATION, false); public static final CachedFlag sDelayTempStripRemoval = - new CachedFlag(DELAY_TEMP_STRIP_REMOVAL, true); + newCachedFlag(DELAY_TEMP_STRIP_REMOVAL, true); public static final CachedFlag sDragDropIntoOmnibox = - new CachedFlag(DRAG_DROP_INTO_OMNIBOX, false); + newCachedFlag(DRAG_DROP_INTO_OMNIBOX, false); public static final CachedFlag sDownloadsMigrateToJobsAPI = - new CachedFlag(DOWNLOADS_MIGRATE_TO_JOBS_API, false); - public static final CachedFlag sDrawEdgeToEdge = new CachedFlag(DRAW_EDGE_TO_EDGE, false); + newCachedFlag(DOWNLOADS_MIGRATE_TO_JOBS_API, false); + public static final CachedFlag sDrawEdgeToEdge = newCachedFlag(DRAW_EDGE_TO_EDGE, false); public static final CachedFlag sDrawNativeEdgeToEdge = - new CachedFlag(DRAW_NATIVE_EDGE_TO_EDGE, false); - public static final CachedFlag sDrawWebEdgeToEdge = - new CachedFlag(DRAW_WEB_EDGE_TO_EDGE, false); + newCachedFlag(DRAW_NATIVE_EDGE_TO_EDGE, false); + public static final CachedFlag sDrawWebEdgeToEdge = newCachedFlag(DRAW_WEB_EDGE_TO_EDGE, false); public static final CachedFlag sEarlyInitializeStartupMetrics = - new CachedFlag(EARLY_INITIALIZE_STARTUP_METRICS, false); - public static final CachedFlag sExperimentsForAgsa = new CachedFlag(EXPERIMENTS_FOR_AGSA, true); + newCachedFlag(EARLY_INITIALIZE_STARTUP_METRICS, false); + public static final CachedFlag sExperimentsForAgsa = newCachedFlag(EXPERIMENTS_FOR_AGSA, true); public static final CachedFlag sFeedLoadingPlaceholder = - new CachedFlag(FEED_LOADING_PLACEHOLDER, false); + newCachedFlag(FEED_LOADING_PLACEHOLDER, false); public static final CachedFlag sFriendlierSafeBrowsingSettingsEnhancedProtection = - new CachedFlag(FRIENDLIER_SAFE_BROWSING_SETTINGS_ENHANCED_PROTECTION, false); + newCachedFlag(FRIENDLIER_SAFE_BROWSING_SETTINGS_ENHANCED_PROTECTION, false); public static final CachedFlag sFriendlierSafeBrowsingSettingsStandardProtection = - new CachedFlag(FRIENDLIER_SAFE_BROWSING_SETTINGS_STANDARD_PROTECTION, false); + newCachedFlag(FRIENDLIER_SAFE_BROWSING_SETTINGS_STANDARD_PROTECTION, false); public static final CachedFlag sGridTabSwitcherAndroidAnimations = - new CachedFlag(GRID_TAB_SWITCHER_ANDROID_ANIMATIONS, false); + newCachedFlag(GRID_TAB_SWITCHER_ANDROID_ANIMATIONS, false); public static final CachedFlag sIncognitoReauthenticationForAndroid = - new CachedFlag(INCOGNITO_REAUTHENTICATION_FOR_ANDROID, true); - public static final CachedFlag sInstantStart = new CachedFlag(INSTANT_START, false); + newCachedFlag(INCOGNITO_REAUTHENTICATION_FOR_ANDROID, true); + public static final CachedFlag sInstantStart = newCachedFlag(INSTANT_START, false); public static final CachedFlag sHideTabOnTabSwitcher = - new CachedFlag(HIDE_TAB_ON_TAB_SWITCHER, true); - public static final CachedFlag sMagicStackAndroid = new CachedFlag(MAGIC_STACK_ANDROID, false); + newCachedFlag(HIDE_TAB_ON_TAB_SWITCHER, true); + public static final CachedFlag sMagicStackAndroid = newCachedFlag(MAGIC_STACK_ANDROID, false); public static final CachedFlag sMultiInstanceApplicationStatusCleanup = - new CachedFlag(MUlTI_INSTANCE_APPLICATION_STATUS_CLEANUP, false); + newCachedFlag(MUlTI_INSTANCE_APPLICATION_STATUS_CLEANUP, false); public static final CachedFlag sNewTabSearchEngineUrlAndroid = - new CachedFlag(NEW_TAB_SEARCH_ENGINE_URL_ANDROID, false); - public static final CachedFlag sPriceChangeModule = new CachedFlag(PRICE_CHANGE_MODULE, false); + newCachedFlag(NEW_TAB_SEARCH_ENGINE_URL_ANDROID, false); + public static final CachedFlag sPriceChangeModule = newCachedFlag(PRICE_CHANGE_MODULE, false); public static final CachedFlag sPrivacyGuideAndroid3 = - new CachedFlag(PRIVACY_GUIDE_ANDROID_3, false); + newCachedFlag(PRIVACY_GUIDE_ANDROID_3, false); public static final CachedFlag sPrivacyGuidePreloadAndroid = - new CachedFlag(PRIVACY_GUIDE_PRELOAD_ANDROID, false); + newCachedFlag(PRIVACY_GUIDE_PRELOAD_ANDROID, false); public static final CachedFlag sQueryTilesInZPSOnNTP = - new CachedFlag(QUERY_TILES_IN_ZPS_ON_NTP, false); + newCachedFlag(QUERY_TILES_IN_ZPS_ON_NTP, false); public static final CachedFlag sOmniboxMatchToolbarAndStatusBarColor = - new CachedFlag(OMNIBOX_MATCH_TOOLBAR_AND_STATUS_BAR_COLOR, false); + newCachedFlag(OMNIBOX_MATCH_TOOLBAR_AND_STATUS_BAR_COLOR, false); public static final CachedFlag sOmniboxModernizeVisualUpdate = - new CachedFlag(OMNIBOX_MODERNIZE_VISUAL_UPDATE, true); + newCachedFlag(OMNIBOX_MODERNIZE_VISUAL_UPDATE, true); public static final CachedFlag sOptimizationGuidePushNotifications = - new CachedFlag(OPTIMIZATION_GUIDE_PUSH_NOTIFICATIONS, false); - public static final CachedFlag sPaintPreviewDemo = new CachedFlag(PAINT_PREVIEW_DEMO, false); + newCachedFlag(OPTIMIZATION_GUIDE_PUSH_NOTIFICATIONS, false); + public static final CachedFlag sPaintPreviewDemo = newCachedFlag(PAINT_PREVIEW_DEMO, false); public static final CachedFlag sPaintPreviewNewColdStartHeuristic = - new CachedFlag(PAINT_PREVIEW_NEW_COLD_START_HEURISTIC, true); - public static final CachedFlag sQueryTiles = new CachedFlag(QUERY_TILES, false); + newCachedFlag(PAINT_PREVIEW_NEW_COLD_START_HEURISTIC, true); + public static final CachedFlag sQueryTiles = newCachedFlag(QUERY_TILES, false); public static final CachedFlag sRedirectExplicitCTAIntentsToExistingActivity = - new CachedFlag(REDIRECT_EXPLICIT_CTA_INTENTS_TO_EXISTING_ACTIVITY, true); - public static final CachedFlag sSearchEngineChoice = - new CachedFlag(SEARCH_ENGINE_CHOICE, false); + newCachedFlag(REDIRECT_EXPLICIT_CTA_INTENTS_TO_EXISTING_ACTIVITY, true); + public static final CachedFlag sSearchEngineChoice = newCachedFlag(SEARCH_ENGINE_CHOICE, false); public static final CachedFlag sShowNtpAtStartupAndroid = - new CachedFlag(SHOW_NTP_AT_STARTUP_ANDROID, false); + newCachedFlag(SHOW_NTP_AT_STARTUP_ANDROID, false); public static final CachedFlag sStartSurfaceAndroid = - new CachedFlag(START_SURFACE_ANDROID, true); + newCachedFlag(START_SURFACE_ANDROID, true); public static final CachedFlag sStartSurfaceOnTablet = - new CachedFlag(START_SURFACE_ON_TABLET, true); + newCachedFlag(START_SURFACE_ON_TABLET, true); public static final CachedFlag sStartSurfaceRefactor = - new CachedFlag(START_SURFACE_REFACTOR, true); + newCachedFlag(START_SURFACE_REFACTOR, true); public static final CachedFlag sStartSurfaceReturnTime = - new CachedFlag(START_SURFACE_RETURN_TIME, true); + newCachedFlag(START_SURFACE_RETURN_TIME, true); public static final CachedFlag sAccountReauthenticationRecentTimeWindow = - new CachedFlag(ACCOUNT_REAUTHENTICATION_RECENT_TIME_WINDOW, true); + newCachedFlag(ACCOUNT_REAUTHENTICATION_RECENT_TIME_WINDOW, true); public static final CachedFlag sStartSurfaceWithAccessibility = - new CachedFlag(START_SURFACE_WITH_ACCESSIBILITY, true); - public static final CachedFlag sSurfacePolish = new CachedFlag(SURFACE_POLISH, false); + newCachedFlag(START_SURFACE_WITH_ACCESSIBILITY, true); + public static final CachedFlag sSurfacePolish = newCachedFlag(SURFACE_POLISH, false); public static final CachedFlag sTabDragDropAsWindowAndroid = - new CachedFlag(TAB_DRAG_DROP_ANDROID, false); + newCachedFlag(TAB_DRAG_DROP_ANDROID, false); public static final CachedFlag sTabGroupParityAndroid = - new CachedFlag(TAB_GROUP_PARITY_ANDROID, false); + newCachedFlag(TAB_GROUP_PARITY_ANDROID, false); public static final CachedFlag sTabLinkDragDropAndroid = - new CachedFlag(TAB_LINK_DRAG_DROP_ANDROID, false); + newCachedFlag(TAB_LINK_DRAG_DROP_ANDROID, false); public static final CachedFlag sTabResumptionModuleAndroid = - new CachedFlag(TAB_RESUMPTION_MODULE_ANDROID, false); - public static final CachedFlag sTabStateFlatBuffer = - new CachedFlag(TAB_STATE_FLATBUFFER, false); + newCachedFlag(TAB_RESUMPTION_MODULE_ANDROID, false); + public static final CachedFlag sTabStateFlatBuffer = newCachedFlag(TAB_STATE_FLATBUFFER, false); public static final CachedFlag sTabStripStartupRefactoring = - new CachedFlag(TAB_STRIP_STARTUP_REFACTORING, false); + newCachedFlag(TAB_STRIP_STARTUP_REFACTORING, false); public static final CachedFlag sTabletToolbarReordering = - new CachedFlag(TABLET_TOOLBAR_REORDERING, false); - public static final CachedFlag sTabToGTSAnimation = new CachedFlag(TAB_TO_GTS_ANIMATION, true); + newCachedFlag(TABLET_TOOLBAR_REORDERING, false); + public static final CachedFlag sTabToGTSAnimation = newCachedFlag(TAB_TO_GTS_ANIMATION, true); public static final CachedFlag sTestDefaultDisabled = - new CachedFlag(TEST_DEFAULT_DISABLED, false); - public static final CachedFlag sTestDefaultEnabled = new CachedFlag(TEST_DEFAULT_ENABLED, true); + newCachedFlag(TEST_DEFAULT_DISABLED, false); + public static final CachedFlag sTestDefaultEnabled = newCachedFlag(TEST_DEFAULT_ENABLED, true); public static final CachedFlag sToolbarUseHardwareBitmapDraw = - new CachedFlag(TOOLBAR_USE_HARDWARE_BITMAP_DRAW, false); + newCachedFlag(TOOLBAR_USE_HARDWARE_BITMAP_DRAW, false); public static final CachedFlag sUseChimeAndroidSdk = - new CachedFlag(USE_CHIME_ANDROID_SDK, false); + newCachedFlag(USE_CHIME_ANDROID_SDK, false); public static final CachedFlag sUseLibunwindstackNativeUnwinderAndroid = - new CachedFlag(USE_LIBUNWINDSTACK_NATIVE_UNWINDER_ANDROID, true); + newCachedFlag(USE_LIBUNWINDSTACK_NATIVE_UNWINDER_ANDROID, true); public static final CachedFlag sVerticalAutomotiveBackButtonToolbar = - new CachedFlag(VERTICAL_AUTOMOTIVE_BACK_BUTTON_TOOLBAR, false); + newCachedFlag(VERTICAL_AUTOMOTIVE_BACK_BUTTON_TOOLBAR, false); public static final List<CachedFlag> sFlagsCachedFullBrowser = List.of(
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/FlagUnitTest.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/FlagUnitTest.java index 7836e1b..9f24eadf 100644 --- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/FlagUnitTest.java +++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/FlagUnitTest.java
@@ -20,52 +20,46 @@ public class FlagUnitTest { @Rule public final BaseFlagTestRule mBaseFlagTestRule = new BaseFlagTestRule(); - private final FeatureMap mFeatureMap = - new FeatureMap() { - @Override - protected long getNativeMap() { - return 0; - } - }; + private static final FeatureMap FEATURE_MAP = BaseFlagTestRule.FEATURE_MAP; @Test public void testDuplicateFeatureFlags_throwsAssertionError() { - new PostNativeFlag(FEATURE_A); + new PostNativeFlag(BaseFlagTestRule.FEATURE_MAP, FEATURE_A); try { - new MutableFlagWithSafeDefault(mFeatureMap, FEATURE_A, false); + new MutableFlagWithSafeDefault(FEATURE_MAP, FEATURE_A, false); throw new RuntimeException("Duplicate feature"); } catch (AssertionError e) { } try { - new CachedFlag(FEATURE_A, false); + new CachedFlag(BaseFlagTestRule.FEATURE_MAP, FEATURE_A, false); throw new RuntimeException("Duplicate feature"); } catch (AssertionError e) { } Flag.resetFlagsForTesting(); - new MutableFlagWithSafeDefault(mFeatureMap, FEATURE_A, false); + new MutableFlagWithSafeDefault(FEATURE_MAP, FEATURE_A, false); try { - new PostNativeFlag(FEATURE_A); + new PostNativeFlag(BaseFlagTestRule.FEATURE_MAP, FEATURE_A); throw new RuntimeException("Duplicate feature"); } catch (AssertionError e) { } try { - new CachedFlag(FEATURE_A, false); + new CachedFlag(BaseFlagTestRule.FEATURE_MAP, FEATURE_A, false); throw new RuntimeException("Duplicate feature"); } catch (AssertionError e) { } Flag.resetFlagsForTesting(); - new CachedFlag(FEATURE_A, false); + new CachedFlag(BaseFlagTestRule.FEATURE_MAP, FEATURE_A, false); try { - new MutableFlagWithSafeDefault(mFeatureMap, FEATURE_A, false); + new MutableFlagWithSafeDefault(FEATURE_MAP, FEATURE_A, false); throw new RuntimeException("Duplicate feature"); } catch (AssertionError e) { } try { - new PostNativeFlag(FEATURE_A); + new PostNativeFlag(BaseFlagTestRule.FEATURE_MAP, FEATURE_A); throw new RuntimeException("Duplicate feature"); } catch (AssertionError e) { }
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/PostNativeFlag.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/PostNativeFlag.java index 36ece37..84b965e 100644 --- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/PostNativeFlag.java +++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/PostNativeFlag.java
@@ -5,6 +5,7 @@ package org.chromium.chrome.browser.flags; import org.chromium.base.FeatureList; +import org.chromium.base.FeatureMap; import org.chromium.base.Flag; /** @@ -13,8 +14,8 @@ public class PostNativeFlag extends Flag { private Boolean mInMemoryCachedValue; - public PostNativeFlag(String featureName) { - super(featureName); + public PostNativeFlag(FeatureMap featureMap, String featureName) { + super(featureMap, featureName); } @Override @@ -22,10 +23,10 @@ if (mInMemoryCachedValue != null) return mInMemoryCachedValue; if (FeatureList.hasTestFeature(mFeatureName)) { - return ChromeFeatureList.isEnabled(mFeatureName); + return mFeatureMap.isEnabledInNative(mFeatureName); } - mInMemoryCachedValue = ChromeFeatureList.isEnabled(mFeatureName); + mInMemoryCachedValue = mFeatureMap.isEnabledInNative(mFeatureName); return mInMemoryCachedValue; }
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/PostNativeFlagUnitTest.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/PostNativeFlagUnitTest.java index fdf44f5c..30ccfeeb9 100644 --- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/PostNativeFlagUnitTest.java +++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/PostNativeFlagUnitTest.java
@@ -23,20 +23,20 @@ @Test(expected = AssertionError.class) public void testDuplicateFeature_throwsException() { - new PostNativeFlag(FEATURE_A); - new PostNativeFlag(FEATURE_A); + new PostNativeFlag(BaseFlagTestRule.FEATURE_MAP, FEATURE_A); + new PostNativeFlag(BaseFlagTestRule.FEATURE_MAP, FEATURE_A); } @Test(expected = AssertionError.class) public void testNativeNotInitialized_throwAssertionError() { - PostNativeFlag featureA = new PostNativeFlag(FEATURE_A); + PostNativeFlag featureA = new PostNativeFlag(BaseFlagTestRule.FEATURE_MAP, FEATURE_A); featureA.isEnabled(); } @Test public void testNativeInitialized_getsFromChromeFeatureList() { - PostNativeFlag featureA = new PostNativeFlag(FEATURE_A); - PostNativeFlag featureB = new PostNativeFlag(FEATURE_B); + PostNativeFlag featureA = new PostNativeFlag(BaseFlagTestRule.FEATURE_MAP, FEATURE_A); + PostNativeFlag featureB = new PostNativeFlag(BaseFlagTestRule.FEATURE_MAP, FEATURE_B); // Values from ChromeFeatureList should be used from now on. FeatureList.setTestFeatures(A_OFF_B_ON);
diff --git a/chrome/browser/image_editor/screenshot_flow.cc b/chrome/browser/image_editor/screenshot_flow.cc index a3e869b..9c42bd07 100644 --- a/chrome/browser/image_editor/screenshot_flow.cc +++ b/chrome/browser/image_editor/screenshot_flow.cc
@@ -171,18 +171,16 @@ } gfx::Rect bounds = web_contents_->GetViewBounds(); -#if BUILDFLAG(IS_MAC) - const gfx::NativeView& native_view = web_contents_->GetContentNativeView(); - gfx::Image img; - bool rval = ui::GrabViewSnapshot(native_view, region, &img); - // If |img| is empty, clients should treat it as a canceled action, but - // we have a DCHECK for development as we expected this call to succeed. - DCHECK(rval); - RunScreenshotCompleteCallback(result_code, bounds, img); -#else ui::GrabSnapshotImageCallback screenshot_callback = base::BindOnce(&ScreenshotFlow::RunScreenshotCompleteCallback, weak_this_, result_code, bounds); +#if BUILDFLAG(IS_MAC) + // TODO: Why is the view captured on the Mac but the window captured on all + // other platforms? + const gfx::NativeView& native_view = web_contents_->GetContentNativeView(); + ui::GrabViewSnapshotAsync(native_view, region, + std::move(screenshot_callback)); +#else const gfx::NativeWindow& native_window = web_contents_->GetNativeView(); ui::GrabWindowSnapshotAsync(native_window, region, std::move(screenshot_callback));
diff --git a/chrome/browser/magic_stack/android/java/src/org/chromium/chrome/browser/magic_stack/HomeModulesCoordinator.java b/chrome/browser/magic_stack/android/java/src/org/chromium/chrome/browser/magic_stack/HomeModulesCoordinator.java index 1538d5c..58ee374 100644 --- a/chrome/browser/magic_stack/android/java/src/org/chromium/chrome/browser/magic_stack/HomeModulesCoordinator.java +++ b/chrome/browser/magic_stack/android/java/src/org/chromium/chrome/browser/magic_stack/HomeModulesCoordinator.java
@@ -6,7 +6,6 @@ import android.app.Activity; import android.graphics.Point; -import android.view.View; import android.view.ViewGroup; import androidx.annotation.NonNull; @@ -14,6 +13,7 @@ import androidx.recyclerview.widget.PagerSnapHelper; import androidx.recyclerview.widget.RecyclerView; +import org.chromium.base.Callback; import org.chromium.chrome.browser.magic_stack.ModuleRegistry.OnViewCreatedCallback; import org.chromium.components.browser_ui.styles.SemanticColorUtils; import org.chromium.ui.base.DeviceFormFactor; @@ -29,6 +29,7 @@ private final ModuleDelegateHost mModuleDelegateHost; private final HomeModulesMediator mMediator; private final SimpleRecyclerViewAdapter mAdapter; + private final RecyclerView mRecyclerView; private final ModelList mModel; private final HomeModulesContextMenuManager mHomeModulesContextMenuManager; @@ -49,16 +50,15 @@ mModel = new ModelList(); mAdapter = new SimpleRecyclerViewAdapter(mModel); ModuleRegistry.getInstance().registerAdapter(mAdapter, this::onViewCreated); - RecyclerView recyclerView = parentView.findViewById(R.id.home_modules_recycler_view); + mRecyclerView = parentView.findViewById(R.id.home_modules_recycler_view); - recyclerView.setAdapter(mAdapter); - recyclerView.setHasFixedSize(true); + mRecyclerView.setAdapter(mAdapter); LinearLayoutManager linearLayoutManager = new LinearLayoutManager(activity, LinearLayoutManager.HORIZONTAL, false); - recyclerView.setLayoutManager(linearLayoutManager); + mRecyclerView.setLayoutManager(linearLayoutManager); // Add pager indicator. - recyclerView.addItemDecoration( + mRecyclerView.addItemDecoration( new CirclePagerIndicatorDecoration( activity, moduleDelegateHost.getUiConfig(), @@ -69,23 +69,29 @@ .color_primary_with_alpha_15), DeviceFormFactor.isNonMultiDisplayContextOnTablet(activity))); PagerSnapHelper snapHelper = new PagerSnapHelper(); - snapHelper.attachToRecyclerView(recyclerView); + snapHelper.attachToRecyclerView(mRecyclerView); - mMediator = - new HomeModulesMediator( - mModel, - (isVisible) -> { - recyclerView.setVisibility(isVisible ? View.VISIBLE : View.GONE); - }, - ModuleRegistry.getInstance()); + mMediator = new HomeModulesMediator(mModel, ModuleRegistry.getInstance()); } - /** Gets the module ranking list and shows the home modules. */ - public void show() { + /** + * Gets the module ranking list and shows the home modules. + * + * @param onHomeModulesShownCallback The callback called when the magic stack is shown. + */ + public void show(Callback<Boolean> onHomeModulesShownCallback) { List<Integer> moduleList = getModuleList(); - if (moduleList == null) return; + if (moduleList == null) { + onHomeModulesShownCallback.onResult(false); + return; + } - mMediator.buildModulesAndShow(moduleList, this); + mMediator.buildModulesAndShow( + moduleList, + this, + (isVisible) -> { + onHomeModulesShownCallback.onResult(isVisible); + }); } /** Hides the modules and cleans up. */
diff --git a/chrome/browser/magic_stack/android/java/src/org/chromium/chrome/browser/magic_stack/HomeModulesMediator.java b/chrome/browser/magic_stack/android/java/src/org/chromium/chrome/browser/magic_stack/HomeModulesMediator.java index 940a957a..246bcc4 100644 --- a/chrome/browser/magic_stack/android/java/src/org/chromium/chrome/browser/magic_stack/HomeModulesMediator.java +++ b/chrome/browser/magic_stack/android/java/src/org/chromium/chrome/browser/magic_stack/HomeModulesMediator.java
@@ -22,7 +22,6 @@ public class HomeModulesMediator { private static final int INVALID_INDEX = -1; private final ModelList mModel; - private final Callback<Boolean> mSetVisibilityCallback; private final ModuleRegistry mModuleRegistry; /** A map of <ModuleType, ModuleProvider>. */ @@ -47,19 +46,14 @@ /** The ranking index of the module whose response that the magic stack is waiting for. */ private int mModuleResultsWaitingIndex; - private boolean mIsShown; + private Callback<Boolean> mSetVisibilityCallback; /** * @param model The instance of {@link ModelList} of the RecyclerView. - * @param setVisibilityCallback The callback to update the visibility of the magic stack. */ - public HomeModulesMediator( - @NonNull ModelList model, - @NonNull Callback<Boolean> setVisibilityCallback, - @NonNull ModuleRegistry moduleRegistry) { + public HomeModulesMediator(@NonNull ModelList model, @NonNull ModuleRegistry moduleRegistry) { mModel = model; - mSetVisibilityCallback = setVisibilityCallback; mModuleRegistry = moduleRegistry; } @@ -70,7 +64,10 @@ * @param moduleDelegate The instance of the magic stack {@link ModuleDelegate}. */ void buildModulesAndShow( - @NonNull @ModuleType List<Integer> moduleList, @NonNull ModuleDelegate moduleDelegate) { + @NonNull @ModuleType List<Integer> moduleList, + @NonNull ModuleDelegate moduleDelegate, + @NonNull Callback<Boolean> setVisibilityCallback) { + mSetVisibilityCallback = setVisibilityCallback; assert mModel.size() == 0; mIsShown = true; cacheRanking(moduleList);
diff --git a/chrome/browser/magic_stack/android/java/src/org/chromium/chrome/browser/magic_stack/ModuleDelegateHost.java b/chrome/browser/magic_stack/android/java/src/org/chromium/chrome/browser/magic_stack/ModuleDelegateHost.java index 1ff4cd3..d9cdfbbe 100644 --- a/chrome/browser/magic_stack/android/java/src/org/chromium/chrome/browser/magic_stack/ModuleDelegateHost.java +++ b/chrome/browser/magic_stack/android/java/src/org/chromium/chrome/browser/magic_stack/ModuleDelegateHost.java
@@ -9,6 +9,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.util.BrowserUiUtils.HostSurface; import org.chromium.components.browser_ui.widget.displaystyle.UiConfig; import org.chromium.url.GURL; @@ -58,4 +59,12 @@ * offset of the recyclerview item. */ int getStartMargin(); + + /** + * Returns the tab that the home surface is tracking. It is non-null on NTP home surface only. + */ + @Nullable + default Tab getTrackingTab() { + return null; + } }
diff --git a/chrome/browser/magic_stack/android/junit/src/org/chromium/chrome/browser/magic_stack/HomeModulesMediatorUnitTest.java b/chrome/browser/magic_stack/android/junit/src/org/chromium/chrome/browser/magic_stack/HomeModulesMediatorUnitTest.java index d256685..3bd4901c 100644 --- a/chrome/browser/magic_stack/android/junit/src/org/chromium/chrome/browser/magic_stack/HomeModulesMediatorUnitTest.java +++ b/chrome/browser/magic_stack/android/junit/src/org/chromium/chrome/browser/magic_stack/HomeModulesMediatorUnitTest.java
@@ -70,7 +70,7 @@ doReturn(true).when(mModuleProviderBuilderList[i]).build(eq(mModuleDelegate), any()); mListItems[i] = new ListItem(mModuleTypeList[i], Mockito.mock(PropertyModel.class)); } - mMediator = new HomeModulesMediator(mModel, mSetVisibilityCallback, mModuleRegistry); + mMediator = new HomeModulesMediator(mModel, mModuleRegistry); } @Test @@ -98,7 +98,7 @@ assertEquals(0, mMediator.getModuleResultsWaitingIndexForTesting()); // Calls buildModulesAndShow() to initialize ranking index map. - mMediator.buildModulesAndShow(moduleList, mModuleDelegate); + mMediator.buildModulesAndShow(moduleList, mModuleDelegate, mSetVisibilityCallback); Boolean[] moduleFetchResultsIndicator = mMediator.getModuleFetchResultsIndicatorForTesting(); @@ -124,7 +124,7 @@ assertEquals(0, mMediator.getModuleResultsWaitingIndexForTesting()); // Calls buildModulesAndShow() to initialize ranking index map. - mMediator.buildModulesAndShow(moduleList, mModuleDelegate); + mMediator.buildModulesAndShow(moduleList, mModuleDelegate, mSetVisibilityCallback); Boolean[] moduleFetchResultsIndicator = mMediator.getModuleFetchResultsIndicatorForTesting(); SimpleRecyclerViewAdapter.ListItem[] moduleFetchResultsCache = @@ -170,7 +170,7 @@ assertEquals(0, mMediator.getModuleResultsWaitingIndexForTesting()); // Calls buildModulesAndShow() to initialize ranking index map. - mMediator.buildModulesAndShow(moduleList, mModuleDelegate); + mMediator.buildModulesAndShow(moduleList, mModuleDelegate, mSetVisibilityCallback); Boolean[] moduleFetchResultsIndicator = mMediator.getModuleFetchResultsIndicatorForTesting(); SimpleRecyclerViewAdapter.ListItem[] moduleFetchResultsCache = @@ -207,6 +207,10 @@ @SmallTest public void testHide() { // Adds 3 modules' data to the magic stack's RecyclerView. + List<Integer> moduleList = + List.of(mModuleTypeList[0], mModuleTypeList[1], mModuleTypeList[2]); + mMediator.buildModulesAndShow(moduleList, mModuleDelegate, mSetVisibilityCallback); + ModuleProvider[] moduleProviders = new ModuleProvider[MODULE_TYPES]; for (int i = 0; i < MODULE_TYPES; i++) { moduleProviders[i] = Mockito.mock(ModuleProvider.class); @@ -255,6 +259,9 @@ @Test @SmallTest public void testAppend() { + List<Integer> moduleList = List.of(mModuleTypeList[0], mModuleTypeList[1]); + mMediator.buildModulesAndShow(moduleList, mModuleDelegate, mSetVisibilityCallback); + // Verifies that the RecyclerView is changed to be visible when the first item is added. doReturn(1).when(mModel).size(); mMediator.append(mListItems[0]); @@ -273,7 +280,7 @@ @SmallTest public void testRemove() { List<Integer> moduleList = List.of(mModuleTypeList[0]); - mMediator.buildModulesAndShow(moduleList, mModuleDelegate); + mMediator.buildModulesAndShow(moduleList, mModuleDelegate, mSetVisibilityCallback); ModuleProvider moduleProvider = Mockito.mock(ModuleProvider.class); mMediator.onModuleBuilt(mModuleTypeList[0], moduleProvider);
diff --git a/chrome/browser/net/storage_test_utils.cc b/chrome/browser/net/storage_test_utils.cc index 804705a2..750d312 100644 --- a/chrome/browser/net/storage_test_utils.cc +++ b/chrome/browser/net/storage_test_utils.cc
@@ -53,8 +53,9 @@ base::flat_map<std::string, bool> actual; base::flat_map<std::string, bool> expected; for (const auto& data_type : GetStorageTypesForFrame(include_cookies)) { - actual[data_type] = - content::EvalJs(frame, "set" + data_type + "()").ExtractBool(); + actual[data_type] = content::EvalJs(frame, "set" + data_type + "()", + content::EXECUTE_SCRIPT_NO_USER_GESTURE) + .ExtractBool(); if (frame->GetLastCommittedOrigin() != frame->GetMainFrame()->GetLastCommittedOrigin() && data_type == "WebSql") { @@ -73,8 +74,9 @@ base::flat_map<std::string, bool> actual; base::flat_map<std::string, bool> expected; for (const auto& data_type : kStorageTypesForWorker) { - actual[data_type] = - content::EvalJs(frame, "set" + data_type + "()").ExtractBool(); + actual[data_type] = content::EvalJs(frame, "set" + data_type + "()", + content::EXECUTE_SCRIPT_NO_USER_GESTURE) + .ExtractBool(); expected[data_type] = true; } EXPECT_THAT(actual, testing::UnorderedElementsAreArray(expected)) @@ -87,8 +89,9 @@ base::flat_map<std::string, bool> actual; base::flat_map<std::string, bool> expected_elts; for (const auto& data_type : GetStorageTypesForFrame(false)) { - actual[data_type] = - content::EvalJs(frame, "has" + data_type + "();").ExtractBool(); + actual[data_type] = content::EvalJs(frame, "has" + data_type + "();", + content::EXECUTE_SCRIPT_NO_USER_GESTURE) + .ExtractBool(); if (frame->GetLastCommittedOrigin() != frame->GetMainFrame()->GetLastCommittedOrigin() && data_type == "WebSql") { @@ -108,8 +111,9 @@ base::flat_map<std::string, bool> actual; base::flat_map<std::string, bool> expected_elts; for (const auto& data_type : kStorageTypesForWorker) { - actual[data_type] = - content::EvalJs(frame, "has" + data_type + "();").ExtractBool(); + actual[data_type] = content::EvalJs(frame, "has" + data_type + "();", + content::EXECUTE_SCRIPT_NO_USER_GESTURE) + .ExtractBool(); expected_elts[data_type] = expected; } EXPECT_THAT(actual, testing::UnorderedElementsAreArray(expected_elts)) @@ -121,8 +125,9 @@ base::flat_map<std::string, bool> actual; base::flat_map<std::string, bool> expected; for (const auto& data_type : kCrossTabCommunicationTypes) { - actual[data_type] = - content::EvalJs(frame, "set" + data_type + "()").ExtractBool(); + actual[data_type] = content::EvalJs(frame, "set" + data_type + "()", + content::EXECUTE_SCRIPT_NO_USER_GESTURE) + .ExtractBool(); expected[data_type] = true; } EXPECT_THAT(actual, testing::UnorderedElementsAreArray(expected)) @@ -135,8 +140,9 @@ base::flat_map<std::string, bool> actual; base::flat_map<std::string, bool> expected_elts; for (const auto& data_type : kCrossTabCommunicationTypes) { - actual[data_type] = - content::EvalJs(frame, "has" + data_type + "();").ExtractBool(); + actual[data_type] = content::EvalJs(frame, "has" + data_type + "();", + content::EXECUTE_SCRIPT_NO_USER_GESTURE) + .ExtractBool(); expected_elts[data_type] = expected; } EXPECT_THAT(actual, testing::UnorderedElementsAreArray(expected_elts))
diff --git a/chrome/browser/pdf/pdf_extension_test.cc b/chrome/browser/pdf/pdf_extension_test.cc index 6cf008fb..2e287e05 100644 --- a/chrome/browser/pdf/pdf_extension_test.cc +++ b/chrome/browser/pdf/pdf_extension_test.cc
@@ -39,6 +39,8 @@ #include "chrome/browser/download/download_prefs.h" #include "chrome/browser/pdf/pdf_extension_test_base.h" #include "chrome/browser/pdf/pdf_extension_test_util.h" +#include "chrome/browser/pdf/pdf_viewer_stream_manager.h" +#include "chrome/browser/pdf/test_pdf_viewer_stream_manager.h" #include "chrome/browser/plugins/plugin_test_utils.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/renderer_context_menu/render_view_context_menu_browsertest_util.h" @@ -135,27 +137,6 @@ const int kDefaultKeyModifier = blink::WebInputEvent::kControlKey; #endif -// A promise that receives and sends postMessage() messages to the PDF iframe. -// The iframe must be accessed differently than the embed, so -// `EnsurePDFHasLoaded()` can't be used here. -const char kOopifPostMessageIframe[] = R"( - new Promise(resolve => { - window.addEventListener('message', event => { - if (event.origin !== - 'chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai') { - return; - } - if (event.data.type === 'documentLoaded') { - resolve( - event.data.load_state === 'success'); - } else if (event.data.type === 'passwordPrompted') { - resolve(true); - } - }); - window.frames[0][0].postMessage({type: 'initialize'}, '*'); - }); - )"; - struct PDFExtensionLoadTestPassToString { std::string operator()( const ::testing::TestParamInfo<std::tuple<int, bool>>& i) const { @@ -3725,17 +3706,21 @@ GTEST_SKIP() << "GuestView PDF viewer cannot ensure PDF load in an iframe."; } + content::WebContents* contents = + incognito_browser()->tab_strip_model()->GetActiveWebContents(); + EXPECT_FALSE(pdf::PdfViewerStreamManager::FromWebContents(contents)); + + auto* manager = + pdf::TestPdfViewerStreamManager::CreateForWebContents(contents); + // Load the HTML containing an iframe embedding a PDF. ASSERT_TRUE(ui_test_utils::NavigateToURL( incognito_browser(), embedded_test_server()->GetURL("/pdf/test-iframe.html"))); + ASSERT_EQ(manager, pdf::PdfViewerStreamManager::FromWebContents(contents)); - content::WebContents* contents = - incognito_browser()->tab_strip_model()->GetActiveWebContents(); - - // Verify the pdf has loaded. - EXPECT_EQ(true, content::EvalJs(contents->GetPrimaryMainFrame(), - kOopifPostMessageIframe)); + // Verify the pdf has loaded. The test will timeout if the PDF fails to load. + manager->WaitUntilPdfLoaded(); } // PDF extension tests for the OOPIF PDF viewer. @@ -3772,18 +3757,6 @@ GetActiveWebContents()->GetPrimaryMainFrame())); } -// Test that an iframe-embedded PDF can send and receive postMessage() messages -// from its embedder. -IN_PROC_BROWSER_TEST_F(PDFExtensionOopifTest, OopifPdfPostMessageIframe) { - // Load the HTML containing an iframe embedding a PDF. - ASSERT_TRUE(ui_test_utils::NavigateToURL( - browser(), embedded_test_server()->GetURL("/pdf/test-iframe.html"))); - - // Verify the pdf has loaded. - EXPECT_EQ(true, content::EvalJs(GetActiveWebContents()->GetPrimaryMainFrame(), - kOopifPostMessageIframe)); -} - // TODO(crbug.com/1445746): Stop testing both modes after OOPIF PDF viewer // launches. INSTANTIATE_FEATURE_OVERRIDE_TEST_SUITE(PDFExtensionTest);
diff --git a/chrome/browser/policy/BUILD.gn b/chrome/browser/policy/BUILD.gn index bdd4fa6..99439c00 100644 --- a/chrome/browser/policy/BUILD.gn +++ b/chrome/browser/policy/BUILD.gn
@@ -240,6 +240,7 @@ if (!is_android) { sources += [ + "test/autofill_policy_browsertest.cc", "test/autoplay_policy_browsertest.cc", "test/block_truncated_cookies_policy_browsertest.cc", "test/bookmark_bar_enabled_browsertest.cc", @@ -261,8 +262,10 @@ ] deps += [ + "//chrome/browser/autofill", "//chrome/browser/devtools:test_support", "//chrome/browser/profiles:profile", + "//components/autofill/content/browser:test_support", "//components/bookmarks/common:common", "//components/enterprise", "//components/enterprise:test_support",
diff --git a/chrome/browser/policy/test/autofill_policy_browsertest.cc b/chrome/browser/policy/test/autofill_policy_browsertest.cc new file mode 100644 index 0000000..ee9441f2 --- /dev/null +++ b/chrome/browser/policy/test/autofill_policy_browsertest.cc
@@ -0,0 +1,220 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <string> +#include <unordered_map> + +#include "base/test/bind.h" +#include "base/values.h" +#include "build/build_config.h" +#include "chrome/browser/autofill/autofill_uitest_util.h" +#include "chrome/browser/autofill/personal_data_manager_factory.h" +#include "chrome/browser/policy/policy_test_utils.h" +#include "chrome/browser/ui/autofill/chrome_autofill_client.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/test/base/ui_test_utils.h" +#include "components/autofill/content/browser/test_autofill_client_injector.h" +#include "components/autofill/content/browser/test_autofill_manager_injector.h" +#include "components/autofill/core/browser/autofill_manager.h" +#include "components/autofill/core/browser/browser_autofill_manager.h" +#include "components/autofill/core/browser/form_structure.h" +#include "components/autofill/core/browser/personal_data_manager.h" +#include "components/autofill/core/browser/test_autofill_manager_waiter.h" +#include "components/autofill/core/browser/ui/suggestion.h" +#include "components/policy/core/common/policy_map.h" +#include "components/policy/policy_constants.h" +#include "content/public/browser/render_frame_host.h" +#include "content/public/browser/render_view_host.h" +#include "content/public/browser/render_widget_host.h" +#include "content/public/browser/render_widget_host_view.h" +#include "content/public/browser/web_contents.h" +#include "content/public/test/browser_test.h" +#include "content/public/test/browser_test_utils.h" +#include "url/gurl.h" + +namespace policy { + +namespace { +const char kAutofillTestPageURL[] = "/autofill/autofill_address_enabled.html"; +} // namespace + +class AutofillPolicyTest : public PolicyTest { + public: + void SetUpOnMainThread() override { + InProcessBrowserTest::SetUpOnMainThread(); + // Don't want Keychain coming up on Mac. + autofill::test::DisableSystemServices(browser()->profile()->GetPrefs()); + + // Wait for Personal Data Manager to be fully loaded to prevent that + // spurious notifications deceive the tests. + autofill::WaitForPersonalDataManagerToBeLoaded(browser()->profile()); + + ASSERT_TRUE(embedded_test_server()->Start()); + } + + content::WebContents* GetWebContents() { + return browser()->tab_strip_model()->GetActiveWebContents(); + } + + autofill::PersonalDataManager* personal_data_manager() { + return autofill::PersonalDataManagerFactory::GetForProfile( + browser()->profile()); + } + + [[nodiscard]] testing::AssertionResult ImportAddress() { + if (personal_data_manager()->GetProfiles().size() != 0u) { + return testing::AssertionFailure() << "Should be empty profile."; + } + autofill::PdmChangeWaiter observer(browser()->profile()); + personal_data_manager()->AddProfile(autofill::test::GetFullProfile()); + observer.Wait(); + expected_suggestions_["name"] = u"John H. Doe"; + expected_suggestions_["street-address"] = u"666 Erebus St., Apt 8"; + expected_suggestions_["postal-code"] = u"91111"; + expected_suggestions_["city"] = u"Elysium"; + expected_suggestions_["phone"] = u"16502111111"; + expected_suggestions_["email"] = u"johndoe@hades.com"; + return personal_data_manager()->GetProfiles().size() == 1u + ? testing::AssertionSuccess() + : testing::AssertionFailure() << "Should be one profile."; + } + + std::unordered_map<std::string, std::u16string> GetExpectedSuggestions() { + return expected_suggestions_; + } + + [[nodiscard]] testing::AssertionResult NavigateToTestPage() { + if (!(ui_test_utils::NavigateToURL( + browser(), embedded_test_server()->GetURL(kAutofillTestPageURL)))) { + return testing::AssertionFailure(); + } + // Wait for the test page to be rendered to receive clicks. + content::MainThreadFrameObserver frame_observer( + GetWebContents()->GetRenderWidgetHostView()->GetRenderWidgetHost()); + frame_observer.Wait(); + return testing::AssertionSuccess(); + } + + protected: + class TestAutofillManager : public autofill::BrowserAutofillManager { + public: + TestAutofillManager(autofill::ContentAutofillDriver* driver, + autofill::AutofillClient* client) + : autofill::BrowserAutofillManager(driver, client, "en-US") {} + + void WaitForAskForValuesToFill() { + base::RunLoop run_loop; + run_loop_ = &run_loop; + run_loop_->Run(); + } + + // The test can not wait for autofill popup to show, because when + // autofill gets disabled, the test will hang there. An alternative is to + // have a timeout, but it could be flaky on bots with different specs. + // Hence the test checks the OnAskForValues event, if this event got + // fired, Autofill popup should have appeared, otherwise it is disabled by + // policy. + void OnAskForValuesToFill( + const autofill::FormData& form, + const autofill::FormFieldData& field, + const gfx::RectF& bounding_box, + autofill::AutofillSuggestionTriggerSource trigger_source) override { + autofill::TestAutofillManagerWaiter waiter( + *this, {autofill::AutofillManagerEvent::kAskForValuesToFill}); + autofill::AutofillManager::OnAskForValuesToFill(form, field, bounding_box, + trigger_source); + ASSERT_TRUE(waiter.Wait()); + if (run_loop_) { + run_loop_->Quit(); + run_loop_ = nullptr; + } + } + + const autofill::FormStructure* WaitForFormWithNFields(size_t n) { + return WaitForMatchingForm( + this, + base::BindLambdaForTesting([n](const autofill::FormStructure& form) { + return form.active_field_count() == n; + })); + } + + private: + raw_ptr<base::RunLoop> run_loop_ = nullptr; + }; + + class TestAutofillClient : public autofill::ChromeAutofillClient { + public: + explicit TestAutofillClient(content::WebContents* web_contents) + : autofill::ChromeAutofillClient(web_contents) {} + + void ShowAutofillPopup( + const autofill::AutofillClient::PopupOpenArgs& open_args, + base::WeakPtr<autofill::AutofillPopupDelegate> delegate) override { + autofill::ChromeAutofillClient::ShowAutofillPopup(open_args, delegate); + popup_shown_ = true; + } + + bool HasShownAutofillPopup() const { return popup_shown_; } + + void ResetPopupShown() { popup_shown_ = false; } + + private: + bool popup_shown_ = false; + }; + + TestAutofillClient* autofill_client() { + return autofill_client_injector_[GetWebContents()]; + } + + TestAutofillManager* autofill_manager() { + return autofill_manager_injector_[GetWebContents()]; + } + + private: + autofill::TestAutofillClientInjector<TestAutofillClient> + autofill_client_injector_; + + autofill::TestAutofillManagerInjector<TestAutofillManager> + autofill_manager_injector_; + + std::unordered_map<std::string, std::u16string> expected_suggestions_; +}; + +IN_PROC_BROWSER_TEST_F(AutofillPolicyTest, AutofillEnabledByPolicy) { + ASSERT_TRUE(ImportAddress()); + PolicyMap policies; + SetPolicy(&policies, key::kAutofillAddressEnabled, base::Value(true)); + UpdateProviderPolicy(policies); + ASSERT_TRUE(NavigateToTestPage()); + EXPECT_TRUE(autofill_manager()->WaitForFormWithNFields(6u)); + for (const auto& [element, expectation] : GetExpectedSuggestions()) { + content::SimulateMouseClickOrTapElementWithId(GetWebContents(), element); + autofill_manager()->WaitForAskForValuesToFill(); + EXPECT_TRUE(autofill_client()->HasShownAutofillPopup()); + // There may be more suggestions, but the first one in the vector + // should be the expected and shown in the popup. + std::vector<autofill::Suggestion> suggestions = + autofill_client()->GetPopupSuggestions(); + ASSERT_GE(suggestions.size(), 1u); + EXPECT_EQ(expectation, suggestions[0].main_text.value); + autofill_client()->ResetPopupShown(); + } +} + +IN_PROC_BROWSER_TEST_F(AutofillPolicyTest, AutofillDisabledByPolicy) { + ASSERT_TRUE(ImportAddress()); + PolicyMap policies; + SetPolicy(&policies, key::kAutofillAddressEnabled, base::Value(false)); + UpdateProviderPolicy(policies); + ASSERT_TRUE(NavigateToTestPage()); + EXPECT_TRUE(autofill_manager()->WaitForFormWithNFields(6u)); + for (const auto& [element, _] : GetExpectedSuggestions()) { + content::SimulateMouseClickOrTapElementWithId(GetWebContents(), element); + autofill_manager()->WaitForAskForValuesToFill(); + EXPECT_FALSE(autofill_client()->HasShownAutofillPopup()); + EXPECT_EQ(autofill_client()->GetPopupSuggestions().size(), 0u); + } +} + +} // namespace policy
diff --git a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/DeprecatedChromePreferenceKeys.java b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/DeprecatedChromePreferenceKeys.java index 0c971604..c2c39c7 100644 --- a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/DeprecatedChromePreferenceKeys.java +++ b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/DeprecatedChromePreferenceKeys.java
@@ -152,6 +152,7 @@ "prefetch_notification_offline_counter", "prefetch_notification_shown_time", "prioritize_bootstrap_tasks", + "reached_code_profiler_enabled", "reached_code_profiler_group", "reached_code_sampling_interval", "service_manager_for_background_prefetch",
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/MenuItem.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/MenuItem.java index db1e5ff9..5ba242d 100644 --- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/MenuItem.java +++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/MenuItem.java
@@ -175,6 +175,12 @@ mPlayButton.setImageResource(R.drawable.mini_pause_button); } + void setSecondLine(String text) { + TextView view = mLayout.findViewById(R.id.item_sublabel); + view.setText(text); + view.setVisibility(View.VISIBLE); + } + private void setEndView(LinearLayout layout, View view) { ((FrameLayout) layout.findViewById(R.id.end_view)).addView(view); }
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/VoiceMenuSheetContent.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/VoiceMenuSheetContent.java index 2522e427..bf91771c 100644 --- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/VoiceMenuSheetContent.java +++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/VoiceMenuSheetContent.java
@@ -13,6 +13,8 @@ import android.content.Context; +import androidx.annotation.Nullable; + import org.chromium.base.Log; import org.chromium.chrome.browser.readaloud.player.InteractionHandler; import org.chromium.chrome.browser.readaloud.player.PlayerProperties; @@ -59,6 +61,10 @@ mMenu.addItem( id, /* iconId= */ 0, voice.getDisplayName(), MenuItem.Action.RADIO); item.addPlayButton(); + String secondLine = getAttributesString(voice); + if (secondLine != null) { + item.setSecondLine(secondLine); + } mVoices[id] = voice; mVoiceIdToMenuItemId.put(voice.getVoiceId(), id); ++id; @@ -133,4 +139,42 @@ } mInteractionHandler.onVoiceSelected(mVoices[itemId]); } + + @Nullable + private String getAttributesString(PlaybackVoice voice) { + String pitch = getPitchString(voice); + String tone = getToneString(voice); + if (pitch == null || tone == null) { + return null; + } + return mContext.getResources().getString(R.string.readaloud_voice_description, pitch, tone); + } + + @Nullable + private String getPitchString(PlaybackVoice voice) { + return getStringOrNull( + switch (voice.getPitch()) { + case PlaybackVoice.Pitch.LOW -> R.string.readaloud_pitch_low; + case PlaybackVoice.Pitch.MID -> R.string.readaloud_pitch_mid; + default -> 0; + }); + } + + @Nullable + private String getToneString(PlaybackVoice voice) { + return getStringOrNull( + switch (voice.getTone()) { + case PlaybackVoice.Tone.BOLD -> R.string.readaloud_tone_bold; + case PlaybackVoice.Tone.CALM -> R.string.readaloud_tone_calm; + case PlaybackVoice.Tone.STEADY -> R.string.readaloud_tone_steady; + case PlaybackVoice.Tone.SMOOTH -> R.string.readaloud_tone_smooth; + case PlaybackVoice.Tone.RELAXED -> R.string.readaloud_tone_relaxed; + default -> 0; + }); + } + + @Nullable + private String getStringOrNull(int id) { + return id != 0 ? mContext.getResources().getString(id) : null; + } }
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/VoiceMenuSheetContentUnitTest.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/VoiceMenuSheetContentUnitTest.java index 4183415..25c71b4 100644 --- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/VoiceMenuSheetContentUnitTest.java +++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/VoiceMenuSheetContentUnitTest.java
@@ -99,10 +99,24 @@ assertNull(mMenu.getItem(3)); mContent.setVoices( - List.of(createVoice("en", "d", "voice d"), createVoice("en", "e", "voice e"))); + List.of( + createVoice( + "en", + "d", + "voice d", + PlaybackVoice.Pitch.LOW, + PlaybackVoice.Tone.SMOOTH), + createVoice( + "en", + "e", + "voice e", + PlaybackVoice.Pitch.MID, + PlaybackVoice.Tone.CALM))); assertEquals("voice d", getText(mMenu.getItem(0), R.id.item_label)); + assertEquals("Low-pitch, Smooth", getText(mMenu.getItem(0), R.id.item_sublabel)); assertEquals("voice e", getText(mMenu.getItem(1), R.id.item_label)); + assertEquals("Mid-pitch, Calm", getText(mMenu.getItem(1), R.id.item_sublabel)); assertNull(mMenu.getItem(2)); } @@ -178,12 +192,17 @@ } private static PlaybackVoice createVoice(String language, String id, String displayName) { + return createVoice( + language, id, displayName, PlaybackVoice.Pitch.NONE, PlaybackVoice.Tone.NONE); + } + + private static PlaybackVoice createVoice( + String language, + String id, + String displayName, + @PlaybackVoice.Pitch int pitch, + @PlaybackVoice.Tone int tone) { return new PlaybackVoice( - language, - /* accentRegionCode= */ null, - id, - displayName, - PlaybackVoice.Pitch.NONE, - PlaybackVoice.Tone.NONE); + language, /* accentRegionCode= */ null, id, displayName, pitch, tone); } }
diff --git a/chrome/browser/readaloud/android/resources/android_readaloud_strings.grd b/chrome/browser/readaloud/android/resources/android_readaloud_strings.grd index 73a350e..afc6be6c 100644 --- a/chrome/browser/readaloud/android/resources/android_readaloud_strings.grd +++ b/chrome/browser/readaloud/android/resources/android_readaloud_strings.grd
@@ -252,6 +252,30 @@ <message name="IDS_READALOUD_SPEED_MENU_DESCRIPTION" desc="Accessibility string announced when the playback speed menu is opened."> Playback speed menu </message> + <message name="IDS_READALOUD_PITCH_LOW" desc="Words to show that a voice is low-pitched, as would be typically recognized as male, included in the voice description."> + Low-pitch + </message> + <message name="IDS_READALOUD_PITCH_MID" desc="Words to show that a voice is medium-pitched, as would be typically recognized as female, included in the voice description."> + Mid-pitch + </message> + <message name="IDS_READALOUD_TONE_BOLD" desc="Word to show that a voice has a bold tone, included in the voice description."> + Bold + </message> + <message name="IDS_READALOUD_TONE_CALM" desc="Word to show that a voice has a calm tone, included in the voice description."> + Calm + </message> + <message name="IDS_READALOUD_TONE_STEADY" desc="Word to show that a voice has a steady tone, included in the voice description."> + Steady + </message> + <message name="IDS_READALOUD_TONE_SMOOTH" desc="Word to show that a voice has a smooth tone, included in the voice description."> + Smooth + </message> + <message name="IDS_READALOUD_TONE_RELAXED" desc="Word to show that a voice has a relaxed tone, included in the voice description."> + Relaxed + </message> + <message name="IDS_READALOUD_VOICE_DESCRIPTION" desc="List of descriptive words shown with a voice in the 'Listen to this page' voice selection menu."> + <ph name="PITCH">%1$s<ex>Mid-pitch</ex></ph>, <ph name="TONE">%2$s<ex>Calm</ex></ph> + </message> </messages> </release> </grit> \ No newline at end of file
diff --git a/chrome/browser/readaloud/android/resources/android_readaloud_strings_grd/IDS_READALOUD_PITCH_LOW.png.sha1 b/chrome/browser/readaloud/android/resources/android_readaloud_strings_grd/IDS_READALOUD_PITCH_LOW.png.sha1 new file mode 100644 index 0000000..6890d37 --- /dev/null +++ b/chrome/browser/readaloud/android/resources/android_readaloud_strings_grd/IDS_READALOUD_PITCH_LOW.png.sha1
@@ -0,0 +1 @@ +2b41abbeea251129b8d4a22259ab66045c217118 \ No newline at end of file
diff --git a/chrome/browser/readaloud/android/resources/android_readaloud_strings_grd/IDS_READALOUD_PITCH_MID.png.sha1 b/chrome/browser/readaloud/android/resources/android_readaloud_strings_grd/IDS_READALOUD_PITCH_MID.png.sha1 new file mode 100644 index 0000000..33c0f04 --- /dev/null +++ b/chrome/browser/readaloud/android/resources/android_readaloud_strings_grd/IDS_READALOUD_PITCH_MID.png.sha1
@@ -0,0 +1 @@ +629fa1df0868a86c3dc37072d80d97a5dc24b64a \ No newline at end of file
diff --git a/chrome/browser/readaloud/android/resources/android_readaloud_strings_grd/IDS_READALOUD_TONE_BOLD.png.sha1 b/chrome/browser/readaloud/android/resources/android_readaloud_strings_grd/IDS_READALOUD_TONE_BOLD.png.sha1 new file mode 100644 index 0000000..6f140c59 --- /dev/null +++ b/chrome/browser/readaloud/android/resources/android_readaloud_strings_grd/IDS_READALOUD_TONE_BOLD.png.sha1
@@ -0,0 +1 @@ +bf3b50264ec49b9b0c3eabdf68259497b9fa171d \ No newline at end of file
diff --git a/chrome/browser/readaloud/android/resources/android_readaloud_strings_grd/IDS_READALOUD_TONE_CALM.png.sha1 b/chrome/browser/readaloud/android/resources/android_readaloud_strings_grd/IDS_READALOUD_TONE_CALM.png.sha1 new file mode 100644 index 0000000..d37eecf --- /dev/null +++ b/chrome/browser/readaloud/android/resources/android_readaloud_strings_grd/IDS_READALOUD_TONE_CALM.png.sha1
@@ -0,0 +1 @@ +fce5f650cf07edf6f9d332594dff8fd151b63307 \ No newline at end of file
diff --git a/chrome/browser/readaloud/android/resources/android_readaloud_strings_grd/IDS_READALOUD_TONE_RELAXED.png.sha1 b/chrome/browser/readaloud/android/resources/android_readaloud_strings_grd/IDS_READALOUD_TONE_RELAXED.png.sha1 new file mode 100644 index 0000000..4c17998d --- /dev/null +++ b/chrome/browser/readaloud/android/resources/android_readaloud_strings_grd/IDS_READALOUD_TONE_RELAXED.png.sha1
@@ -0,0 +1 @@ +76c7b9faa40059bb21517580320fd0c17f54be54 \ No newline at end of file
diff --git a/chrome/browser/readaloud/android/resources/android_readaloud_strings_grd/IDS_READALOUD_TONE_SMOOTH.png.sha1 b/chrome/browser/readaloud/android/resources/android_readaloud_strings_grd/IDS_READALOUD_TONE_SMOOTH.png.sha1 new file mode 100644 index 0000000..6b9adbc --- /dev/null +++ b/chrome/browser/readaloud/android/resources/android_readaloud_strings_grd/IDS_READALOUD_TONE_SMOOTH.png.sha1
@@ -0,0 +1 @@ +068292ea54b99855818655acb43ccf042a11dc88 \ No newline at end of file
diff --git a/chrome/browser/readaloud/android/resources/android_readaloud_strings_grd/IDS_READALOUD_TONE_STEADY.png.sha1 b/chrome/browser/readaloud/android/resources/android_readaloud_strings_grd/IDS_READALOUD_TONE_STEADY.png.sha1 new file mode 100644 index 0000000..3890121 --- /dev/null +++ b/chrome/browser/readaloud/android/resources/android_readaloud_strings_grd/IDS_READALOUD_TONE_STEADY.png.sha1
@@ -0,0 +1 @@ +b5e451b2c8a54a3161cdf1c3e751d76ee8f4933b \ No newline at end of file
diff --git a/chrome/browser/readaloud/android/resources/android_readaloud_strings_grd/IDS_READALOUD_VOICE_DESCRIPTION.png.sha1 b/chrome/browser/readaloud/android/resources/android_readaloud_strings_grd/IDS_READALOUD_VOICE_DESCRIPTION.png.sha1 new file mode 100644 index 0000000..e86e6f22 --- /dev/null +++ b/chrome/browser/readaloud/android/resources/android_readaloud_strings_grd/IDS_READALOUD_VOICE_DESCRIPTION.png.sha1
@@ -0,0 +1 @@ +8d6510fb4a1d1e1478333a56f9ad013c43747490 \ No newline at end of file
diff --git a/chrome/browser/recent_tabs/android/java/src/org/chromium/chrome/browser/recent_tabs/RestoreTabsFeatureHelper.java b/chrome/browser/recent_tabs/android/java/src/org/chromium/chrome/browser/recent_tabs/RestoreTabsFeatureHelper.java index d7da59e..b8463fa 100644 --- a/chrome/browser/recent_tabs/android/java/src/org/chromium/chrome/browser/recent_tabs/RestoreTabsFeatureHelper.java +++ b/chrome/browser/recent_tabs/android/java/src/org/chromium/chrome/browser/recent_tabs/RestoreTabsFeatureHelper.java
@@ -11,6 +11,7 @@ import org.chromium.chrome.browser.feature_engagement.TrackerFactory; import org.chromium.chrome.browser.flags.BooleanCachedFieldTrialParameter; import org.chromium.chrome.browser.flags.ChromeFeatureList; +import org.chromium.chrome.browser.flags.ChromeFeatureMap; import org.chromium.chrome.browser.flags.PostNativeFlag; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.recent_tabs.ForeignSessionHelper.ForeignSession; @@ -26,7 +27,8 @@ /** A class of helper methods that assist in the restore tabs workflow. */ public class RestoreTabsFeatureHelper { public static final PostNativeFlag RESTORE_TABS_PROMO = - new PostNativeFlag(ChromeFeatureList.RESTORE_TABS_ON_FRE); + new PostNativeFlag( + ChromeFeatureMap.getInstance(), ChromeFeatureList.RESTORE_TABS_ON_FRE); public static final BooleanCachedFieldTrialParameter RESTORE_TABS_PROMO_SKIP_FEATURE_ENGAGEMENT = new BooleanCachedFieldTrialParameter(
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/chromevox_range.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/chromevox_range.js index 30d44a3cc..0e93632 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/chromevox_range.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/chromevox_range.js
@@ -326,6 +326,11 @@ const start = this.current_.start.node; start.makeVisible(); + + chrome.metricsPrivate.recordBoolean( + 'Accessibility.ScreenReader.ScrollToImage', + start.role === RoleType.IMAGE); + start.setAccessibilityFocus(); const root = AutomationUtil.getTopLevelRoot(start);
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/panel/panel.ts b/chrome/browser/resources/chromeos/accessibility/chromevox/panel/panel.ts index eaee42d8..d8e6380 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/panel/panel.ts +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/panel/panel.ts
@@ -297,29 +297,24 @@ const sideBySide = SettingsManager.get('brailleSideBySide'); this.brailleContainer_!.addEventListener( - 'mouseover', event => PanelCaptions.braille.addBorders( - event.target as Element)); + 'mouseover', + event => PanelCaptions.braille.addBorders( + event.target as HTMLTableCellElement)); this.brailleContainer_!.addEventListener( - 'mouseout', event => PanelCaptions.braille.removeBorders( - event.target as Element)); + 'mouseout', + event => PanelCaptions.braille.removeBorders( + event.target as HTMLTableCellElement)); this.brailleContainer_!.addEventListener( - 'click', event => PanelCaptions.braille.routeCursor( - event.target as Element)); + 'click', + event => PanelCaptions.braille.routeCursor( + event.target as HTMLTableCellElement)); - // Clear the tables. - let rowCount = this.brailleTableElement_.rows.length; - for (let i = 0; i < rowCount; i++) { - this.brailleTableElement_.deleteRow(0); - } - rowCount = this.brailleTableElement2_.rows.length; - for (let i = 0; i < rowCount; i++) { - this.brailleTableElement2_.deleteRow(0); - } + PanelCaptions.braille.clearTables(); let row1; let row2; // Number of rows already written. - rowCount = 0; + let rowCount = 0; // Number of cells already written in this row. let cellCount = cols; for (let i = 0; i < groups.length; i++) {
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/panel/panel_captions.ts b/chrome/browser/resources/chromeos/accessibility/chromevox/panel/panel_captions.ts index 72c3a40..906c0d2 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/panel/panel_captions.ts +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/panel/panel_captions.ts
@@ -8,7 +8,10 @@ */ class BrailleCaptions { - addBorders(cell: Element): void { + private brailleTableElement_ = $('braille-table') as HTMLTableElement; + private brailleTableElement2_ = $('braille-table2') as HTMLTableElement; + + addBorders(cell: HTMLTableCellElement): void { if (cell.tagName === 'TD') { cell.className = 'highlighted-cell'; const companionIDs = cell.getAttribute('data-companionIDs'); @@ -17,7 +20,12 @@ } } - removeBorders(cell: Element): void { + clearTables(): void { + this.clearTable_(this.brailleTableElement_); + this.clearTable_(this.brailleTableElement2_); + } + + removeBorders(cell: HTMLTableCellElement): void { if (cell.tagName === 'TD') { cell.className = 'unhighlighted-cell'; const companionIDs = cell.getAttribute('data-companionIDs'); @@ -26,7 +34,7 @@ } } - routeCursor(cell: Element): void { + routeCursor(cell: HTMLTableCellElement): void { if (cell.tagName === 'TD') { const displayPosition = parseInt(cell.id.split('-')[0], 10); if (Number.isNaN(displayPosition)) { @@ -39,6 +47,13 @@ displayPosition); } } + + private clearTable_(table: HTMLTableElement): void { + const rowCount = table.rows.length; + for (let i = 0; i < rowCount; i++) { + table.deleteRow(0); + } + } } function $(id: string): HTMLElement | null {
diff --git a/chrome/browser/resources/compose/app.html b/chrome/browser/resources/compose/app.html index 344917a..01946a9 100644 --- a/chrome/browser/resources/compose/app.html +++ b/chrome/browser/resources/compose/app.html
@@ -415,9 +415,9 @@ </div> <div id="firstRunFooter" class="footer"> - <cr-button id="firstRunLetsGoButton" class="action-button" - on-click="onfirstRunLetsGoButtonClick_"> - $i18n{firstRunLetsGoButton} + <cr-button id="firstRunOkButton" class="action-button" + on-click="onFirstRunOkButtonClick_"> + $i18n{firstRunOkButton} </cr-button> </div> </div> @@ -539,7 +539,10 @@ >$i18nRaw{onDeviceUsedFooter} </b> - <span inner-h-t-m-l="[[getResultFooterText_()]]"></span> + <span hidden="[[!showOnDeviceDogfoodFooter_(response_)]]" + >$i18nRaw{dogfoodFooter}</span> + <span hidden="[[showOnDeviceDogfoodFooter_(response_)]]" + >$i18nRaw{resultFooter}</span> </div> <cr-feedback-buttons on-selected-option-changed="onFeedbackSelectedOptionChanged_"
diff --git a/chrome/browser/resources/compose/app.ts b/chrome/browser/resources/compose/app.ts index 9c09911..afeb1445 100644 --- a/chrome/browser/resources/compose/app.ts +++ b/chrome/browser/resources/compose/app.ts
@@ -42,7 +42,7 @@ $: { firstRunDialog: HTMLElement, firstRunFooter: HTMLElement, - firstRunLetsGoButton: CrButtonElement, + firstRunOkButton: CrButtonElement, freMsbbDialog: HTMLElement, appDialog: HTMLElement, body: HTMLElement, @@ -341,7 +341,7 @@ return this.partialResponse_?.result.trim(); } - private onfirstRunLetsGoButtonClick_() { + private onFirstRunOkButtonClick_() { this.apiProxy_.completeFirstRun(); if (this.shouldShowMSBBDialog_) { @@ -605,13 +605,6 @@ } } - private getResultFooterText_(): TrustedHTML { - if (this.showOnDeviceDogfoodFooter_()) { - return this.i18nAdvanced('dogfoodFooter'); - } - return this.i18nAdvanced('resultFooter'); - } - private saveComposeAppState_() { if (this.saveAppStateDebouncer_?.isActive()) { this.saveAppStateDebouncer_.flush();
diff --git a/chrome/browser/resources/side_panel/customize_chrome/icons/BUILD.gn b/chrome/browser/resources/side_panel/customize_chrome/icons/BUILD.gn index eb7678bb..58f65e3 100644 --- a/chrome/browser/resources/side_panel/customize_chrome/icons/BUILD.gn +++ b/chrome/browser/resources/side_panel/customize_chrome/icons/BUILD.gn
@@ -10,10 +10,12 @@ grd_prefix = "side_panel_customize_chrome" out_grd = "$target_gen_dir/resources.grdp" input_files = [ + "collapse_carets.svg", "chrome_web_store.svg", "corner_new_tab_page.svg", "coupons.svg", "delete.svg", + "expand_carets.svg", "generated_image.svg", "gm3_corner_new_tab_page.svg", "gm3_mini_new_tab_page.svg",
diff --git a/chrome/browser/resources/side_panel/customize_chrome/icons/collapse_carets.svg b/chrome/browser/resources/side_panel/customize_chrome/icons/collapse_carets.svg new file mode 100644 index 0000000..40480b87 --- /dev/null +++ b/chrome/browser/resources/side_panel/customize_chrome/icons/collapse_carets.svg
@@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" viewBox="0 0 16 16"><g clip-path="url(#a)"><path fill="#474747" d="m5.919 13.55-1.106-1.106L8 9.256l3.188 3.188-1.107 1.106L8 11.469 5.919 13.55ZM8 6.744 4.812 3.556 5.92 2.45 8 4.531l2.081-2.081 1.107 1.106L8 6.744Z"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h16v16H0z"/></clipPath></defs></svg> \ No newline at end of file
diff --git a/chrome/browser/resources/side_panel/customize_chrome/icons/expand_carets.svg b/chrome/browser/resources/side_panel/customize_chrome/icons/expand_carets.svg new file mode 100644 index 0000000..26696d6 --- /dev/null +++ b/chrome/browser/resources/side_panel/customize_chrome/icons/expand_carets.svg
@@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" viewBox="0 0 16 16"><g clip-path="url(#a)"><path fill="#444746" d="m8 13.6-2.7-2.7.85-.85L8 11.9l1.85-1.85.85.85L8 13.6ZM6.15 5.95 5.3 5.1 8 2.4l2.7 2.7-.85.85L8 4.1 6.15 5.95Z"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h16v16H0z"/></clipPath></defs></svg> \ No newline at end of file
diff --git a/chrome/browser/resources/side_panel/customize_chrome/wallpaper_search/wallpaper_search.html b/chrome/browser/resources/side_panel/customize_chrome/wallpaper_search/wallpaper_search.html index 0e2ca7f43..7d020eb8 100644 --- a/chrome/browser/resources/side_panel/customize_chrome/wallpaper_search/wallpaper_search.html +++ b/chrome/browser/resources/side_panel/customize_chrome/wallpaper_search/wallpaper_search.html
@@ -253,10 +253,12 @@ } .inspirations-content { - margin: 8px 16px 8px; + margin-bottom: 8px; + margin-inline-end: 16px; + margin-inline-start: 16px; } - .inspirations-title { + .inspiration-title { /* TODO(b/317382384): Replace color variable with something specific to Inspirations. */ color: var(--color-side-panel-filter-chip-icon); @@ -265,6 +267,19 @@ line-height: 16px; width: 100%; margin-bottom: 8px; + margin-top: 8px; + } + + #inspirationToggle { + --cr-icon-button-size: 16px; + } + + .collapse-carets { + --cr-icon-image: url(icons/collapse_carets.svg); + } + + .expand-carets { + --cr-icon-image: url(icons/expand_carets.svg); } </style> <div class="sp-card"> @@ -421,22 +436,30 @@ <div class="sp-card" id="inspirationCard"> <sp-heading hide-back-button> <h2 slot="heading">$i18n{wallpaperSearchInspirationHeader}</h2> + <cr-icon-button id="inspirationToggle" class$="[[inspirationToggleIcon_]]" + aria-label="$i18n{showInspirationCardToggle}" + title="$i18n{showInspirationCardToggle}" slot="buttons" + on-click="onInspirationToggleClick_"> + </cr-icon-button> </sp-heading> - <div class="inspirations-content"> - <div class="inspirations-title"> - $i18n{wallpaperSearchMeadowInspirationTitle} - </div> - <cr-grid columns="3" disable-arrow-navigation> - <template is="dom-repeat" items="[[inspirations_.inspirationA]]"> - <div class="tile result" on-click="onInspirationImageClick_" - tabindex="0" role="button"> - <div class="image-container"> - <img is="cr-auto-img" auto-src="[[item.thumbnailUrl.url]]"></img> - </div> - </div> + <iron-collapse opened="[[openInspirations_]]"> + <div class="inspirations-content"> + <template is="dom-repeat" items="[[inspirationGroups_]]"> + <div class="inspiration-title">[[item.descriptors.subject]]</div> + <cr-grid columns="3" disable-arrow-navigation> + <template is="dom-repeat" items="[[item.inspirations]]"> + <div class="tile result" on-click="onInspirationImageClick_" + tabindex="0" role="button"> + <div class="image-container"> + <img is="cr-auto-img" auto-src="[[item.thumbnailUrl.url]]"> + </img> + </div> + </div> + </template> + </cr-grid> </template> - </cr-grid> - </div> + </div> + </iron-collapse> </div> </template> <hr class="sp-cards-separator" hidden$="[[!shouldShowHistory_(history_)]]">
diff --git a/chrome/browser/resources/side_panel/customize_chrome/wallpaper_search/wallpaper_search.ts b/chrome/browser/resources/side_panel/customize_chrome/wallpaper_search/wallpaper_search.ts index c65b9a2..a98d7a5 100644 --- a/chrome/browser/resources/side_panel/customize_chrome/wallpaper_search/wallpaper_search.ts +++ b/chrome/browser/resources/side_panel/customize_chrome/wallpaper_search/wallpaper_search.ts
@@ -35,7 +35,7 @@ import {CustomizeChromeAction, recordCustomizeChromeAction} from '../common.js'; import {CustomizeChromePageCallbackRouter, CustomizeChromePageHandlerInterface, Theme} from '../customize_chrome.mojom-webui.js'; import {CustomizeChromeApiProxy} from '../customize_chrome_api_proxy.js'; -import {DescriptorA, DescriptorB, DescriptorDValue, Descriptors, Inspiration, Inspirations, ResultDescriptors, UserFeedback, WallpaperSearchClientCallbackRouter, WallpaperSearchHandlerInterface, WallpaperSearchResult, WallpaperSearchStatus} from '../wallpaper_search.mojom-webui.js'; +import {DescriptorA, DescriptorB, DescriptorDValue, Descriptors, Inspiration, InspirationGroup, ResultDescriptors, UserFeedback, WallpaperSearchClientCallbackRouter, WallpaperSearchHandlerInterface, WallpaperSearchResult, WallpaperSearchStatus} from '../wallpaper_search.mojom-webui.js'; import {WindowProxy} from '../window_proxy.js'; import {ComboboxGroup, ComboboxItem, CustomizeChromeCombobox} from './combobox/customize_chrome_combobox.js'; @@ -153,7 +153,12 @@ value: () => loadTimeData.getBoolean('wallpaperSearchInspirationCardEnabled'), }, - inspirations_: Object, + inspirationGroups_: Object, + inspirationToggleIcon_: { + type: String, + computed: 'computeInspirationToggleIcon_(openInspirations_)', + }, + openInspirations_: Boolean, resultsDescriptors_: Object, results_: Object, selectedFeedbackOption_: { @@ -201,9 +206,11 @@ private errorState_: ErrorState|null = null; private expandedCategories_: {[categoryIndex: number]: boolean} = {}; private history_: WallpaperSearchResult[] = []; - private inspirations_: Inspirations|null; + private inspirationGroups_: InspirationGroup[]|null; private inspirationCardEnabled_: boolean; + private inspirationToggleIcon_: string; private loading_: boolean; + private openInspirations_: boolean|undefined = false; private results_: WallpaperSearchResult[] = []; private resultsDescriptors_: ResultDescriptors|null = null; private resultsPromises_: Array<Promise< @@ -235,9 +242,10 @@ this.wallpaperSearchCallbackRouter_ = WallpaperSearchProxy.getInstance().callbackRouter; this.fetchDescriptors_(); - this.wallpaperSearchHandler_.getInspirations().then(({inspirations}) => { - this.inspirations_ = inspirations; - }); + this.wallpaperSearchHandler_.getInspirations().then( + ({inspirationGroups}) => { + this.inspirationGroups_ = inspirationGroups; + }); } override connectedCallback() { @@ -252,6 +260,7 @@ (history: WallpaperSearchResult[]) => { this.history_ = history; this.emptyHistoryContainers_ = this.calculateEmptyTiles(history); + this.openInspirations_ = !this.shouldShowHistory_(); }); this.wallpaperSearchHandler_.updateHistory(); this.loadingUiResizeObserver_ = new ResizeObserver(() => { @@ -313,6 +322,10 @@ } } + private computeInspirationToggleIcon_(): string { + return this.openInspirations_ ? 'collapse-carets' : 'expand-carets'; + } + private expandCategoryForDescriptorA_(label: string) { if (!this.descriptors_) { return; @@ -554,6 +567,10 @@ e.model.item.id, e.model.item.descriptors ?? {}); } + private onInspirationToggleClick_() { + this.openInspirations_ = !this.openInspirations_; + } + private onInspirationImageClick_(e: DomRepeatEvent<Inspiration>) { this.wallpaperSearchHandler_.setBackgroundToInspirationImage( e.model.item.id, e.model.item.backgroundUrl);
diff --git a/chrome/browser/site_isolation/DEPS b/chrome/browser/site_isolation/DEPS index c03caa8..7d6f2785 100644 --- a/chrome/browser/site_isolation/DEPS +++ b/chrome/browser/site_isolation/DEPS
@@ -2,4 +2,7 @@ "chrome_site_per_process_browsertest.cc": [ "+pdf/pdf_features.h", ], + "site_per_process_interactive_browsertest.cc": [ + "+pdf/pdf_features.h", + ], } \ No newline at end of file
diff --git a/chrome/browser/site_isolation/site_per_process_interactive_browsertest.cc b/chrome/browser/site_isolation/site_per_process_interactive_browsertest.cc index 5d37a94..bc5ad6d 100644 --- a/chrome/browser/site_isolation/site_per_process_interactive_browsertest.cc +++ b/chrome/browser/site_isolation/site_per_process_interactive_browsertest.cc
@@ -23,9 +23,6 @@ #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/interactive_test_utils.h" #include "chrome/test/base/ui_test_utils.h" -#include "components/guest_view/browser/guest_view_base.h" -#include "components/guest_view/browser/guest_view_manager_delegate.h" -#include "components/guest_view/browser/test_guest_view_manager.h" #include "components/security_state/core/security_state.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/focused_node_details.h" @@ -43,11 +40,11 @@ #include "content/public/test/test_navigation_observer.h" #include "content/public/test/test_utils.h" #include "extensions/browser/api/extensions_api_client.h" -#include "extensions/browser/guest_view/mime_handler_view/test_mime_handler_view_guest.h" #include "extensions/common/constants.h" #include "net/dns/mock_host_resolver.h" #include "net/test/embedded_test_server/default_handlers.h" #include "net/test/embedded_test_server/embedded_test_server.h" +#include "pdf/buildflags.h" #include "ui/base/test/ui_controls.h" #include "ui/display/display.h" #include "ui/display/screen.h" @@ -56,6 +53,17 @@ #include "ui/gfx/geometry/vector2d.h" #include "url/gurl.h" +#if BUILDFLAG(ENABLE_PDF) +#include "base/test/with_feature_override.h" +#include "chrome/browser/pdf/test_pdf_viewer_stream_manager.h" +#include "components/guest_view/browser/guest_view_base.h" +#include "components/guest_view/browser/guest_view_manager_delegate.h" +#include "components/guest_view/browser/test_guest_view_manager.h" +#include "extensions/browser/guest_view/mime_handler_view/test_mime_handler_view_guest.h" +#include "pdf/pdf_features.h" +#include "third_party/abseil-cpp/absl/types/variant.h" +#endif // BUILDFLAG(ENABLE_PDF) + namespace autofill { class AutofillPopupDelegate; struct Suggestion; @@ -1454,11 +1462,14 @@ EXPECT_FALSE(main_frame->GetView()->IsMouseLocked()); } +#if BUILDFLAG(ENABLE_PDF) // Base test class for interactive tests which load and test PDF files. class SitePerProcessInteractivePDFTest - : public SitePerProcessInteractiveBrowserTest { + : public base::test::WithFeatureOverride, + public SitePerProcessInteractiveBrowserTest { public: - SitePerProcessInteractivePDFTest() : test_guest_view_manager_(nullptr) {} + SitePerProcessInteractivePDFTest() + : base::test::WithFeatureOverride(chrome_pdf::features::kPdfOopif) {} SitePerProcessInteractivePDFTest(const SitePerProcessInteractivePDFTest&) = delete; @@ -1469,24 +1480,55 @@ void SetUpOnMainThread() override { SitePerProcessInteractiveBrowserTest::SetUpOnMainThread(); - test_guest_view_manager_ = factory_.GetOrCreateTestGuestViewManager( - browser()->profile(), extensions::ExtensionsAPIClient::Get() - ->CreateGuestViewManagerDelegate()); + if (UseOopif()) { + manager_ = pdf::TestPdfViewerStreamManager::CreateForWebContents( + browser()->tab_strip_model()->GetActiveWebContents()); + } else { + manager_ = factory_.GetOrCreateTestGuestViewManager( + browser()->profile(), extensions::ExtensionsAPIClient::Get() + ->CreateGuestViewManagerDelegate()); + } } void TearDownOnMainThread() override { - test_guest_view_manager_ = nullptr; + manager_ = absl::monostate(); SitePerProcessInteractiveBrowserTest::TearDownOnMainThread(); } + bool UseOopif() const { return GetParam(); } + protected: - guest_view::TestGuestViewManager* test_guest_view_manager() const { - return test_guest_view_manager_; + guest_view::TestGuestViewManager* GetTestGuestViewManager() const { + return absl::get<raw_ptr<guest_view::TestGuestViewManager>>(manager_); + } + + pdf::TestPdfViewerStreamManager* GetTestPdfViewerStreamManager() const { + return absl::get<raw_ptr<pdf::TestPdfViewerStreamManager>>(manager_); + } + + void WaitUntilPdfLoaded() { + if (UseOopif()) { + GetTestPdfViewerStreamManager()->WaitUntilPdfLoaded(); + } else { + auto* guest_view = + GetTestGuestViewManager()->WaitForSingleGuestViewCreated(); + ASSERT_TRUE(guest_view); + auto* embedder_web_contents = + browser()->tab_strip_model()->GetActiveWebContents(); + EXPECT_NE(embedder_web_contents->GetPrimaryMainFrame(), + guest_view->GetGuestMainFrame()); + + extensions::TestMimeHandlerViewGuest::WaitForGuestLoadStartThenStop( + guest_view); + } } private: guest_view::TestGuestViewManagerFactory factory_; - raw_ptr<guest_view::TestGuestViewManager> test_guest_view_manager_ = nullptr; + absl::variant<absl::monostate, + raw_ptr<guest_view::TestGuestViewManager>, + raw_ptr<pdf::TestPdfViewerStreamManager>> + manager_; }; // This test loads a PDF inside an OOPIF and then verifies that context menu @@ -1498,16 +1540,19 @@ #else #define MAYBE_ContextMenuPositionForEmbeddedPDFInCrossOriginFrame \ ContextMenuPositionForEmbeddedPDFInCrossOriginFrame -#endif -IN_PROC_BROWSER_TEST_F( +#endif // (BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX)) && + // defined(ADDRESS_SANITIZER) +IN_PROC_BROWSER_TEST_P( SitePerProcessInteractivePDFTest, MAYBE_ContextMenuPositionForEmbeddedPDFInCrossOriginFrame) { // Navigate to a page with an <iframe>. GURL main_url(embedded_test_server()->GetURL("a.com", "/iframe.html")); ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), main_url)); - // Initially, no guests are created. - EXPECT_EQ(0U, test_guest_view_manager()->num_guests_created()); + if (!UseOopif()) { + // Initially, no guests are created. + EXPECT_EQ(0U, GetTestGuestViewManager()->num_guests_created()); + } content::WebContents* active_web_contents = browser()->tab_strip_model()->GetActiveWebContents(); @@ -1524,12 +1569,7 @@ // Ensure the page finishes loading without crashing. EXPECT_TRUE(NavigateIframeToURL(active_web_contents, "test", frame_url)); - // Wait until the guest contents for PDF is created. - guest_view::GuestViewBase* guest_view = - test_guest_view_manager()->WaitForSingleGuestViewCreated(); - ASSERT_TRUE(guest_view); - extensions::TestMimeHandlerViewGuest::WaitForGuestLoadStartThenStop( - guest_view); + WaitUntilPdfLoaded(); content::RenderWidgetHostView* child_view = ChildFrameAt(active_web_contents->GetPrimaryMainFrame(), 0)->GetView(); @@ -1561,7 +1601,7 @@ EXPECT_EQ(point_in_root_window.y(), menu_waiter.params().y); } -IN_PROC_BROWSER_TEST_F(SitePerProcessInteractivePDFTest, +IN_PROC_BROWSER_TEST_P(SitePerProcessInteractivePDFTest, LoadingPdfDoesNotStealFocus) { // Load test HTML, and verify the text area has focus. GURL main_url(embedded_test_server()->GetURL("/pdf/two_iframes.html")); @@ -1621,14 +1661,7 @@ content::JsReplace("document.getElementById('iframe2').src = $1;", pdf_url.spec()))); - // Verify the pdf has loaded. - auto* guest_view = test_guest_view_manager()->WaitForSingleGuestViewCreated(); - ASSERT_TRUE(guest_view); - EXPECT_NE(embedder_web_contents->GetPrimaryMainFrame(), - guest_view->GetGuestMainFrame()); - - extensions::TestMimeHandlerViewGuest::WaitForGuestLoadStartThenStop( - guest_view); + WaitUntilPdfLoaded(); // Make sure the text area still has focus. ASSERT_TRUE( @@ -1644,6 +1677,11 @@ .ExtractBool()); } +// TODO(crbug.com/1445746): Stop testing both modes after OOPIF PDF viewer +// launches. +INSTANTIATE_FEATURE_OVERRIDE_TEST_SUITE(SitePerProcessInteractivePDFTest); +#endif // BUILDFLAG(ENABLE_PDF) + class SitePerProcessAutofillTest : public SitePerProcessInteractiveBrowserTest { public: SitePerProcessAutofillTest() : SitePerProcessInteractiveBrowserTest() {}
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chrome/browser/ui/android/strings/android_chrome_strings.grd index 91e1811c..e5230ae 100644 --- a/chrome/browser/ui/android/strings/android_chrome_strings.grd +++ b/chrome/browser/ui/android/strings/android_chrome_strings.grd
@@ -1910,16 +1910,19 @@ <!-- Download open dialog --> <message name="IDS_OPEN_DOWNLOAD_DIALOG_TITLE" desc="Title of the dialog for asking user to confirm they want to open a downloaded pdf file."> - Automatically open PDFs? + Open PDF? </message> - <message name="IDS_OPEN_DOWNLOAD_DIALOG_TEXT" desc="Warning message shown on a dialog to ask user to confirm they want to open a downloaded pdf file."> - Chrome can automatically open a PDF when you download them. + <message name="IDS_OPEN_DOWNLOAD_DIALOG_TEXT" desc="Message shown on a dialog to ask user to confirm they want to open a downloaded pdf file."> + Chrome can open your downloaded PDF </message> - <message name="IDS_OPEN_DOWNLOAD_DIALOG_ALWAYS_OPEN_TEXT" desc="Text label for the button on the open download dialog for user to open the download always."> - Always open + <message name="IDS_OPEN_DOWNLOAD_DIALOG_OPEN_TEXT" desc="Text label for the button on the open download dialog for user to open the downloaded pdf."> + Open </message> - <message name="IDS_OPEN_DOWNLOAD_DIALOG_JUST_ONCE_TEXT" desc="Text label for the button on the open download dialog for user to just open the current download once."> - Just once + <message name="IDS_OPEN_DOWNLOAD_DIALOG_CANCEL_TEXT" desc="Text label for the button on the open download dialog for user to cancel opening a downloaded pdf."> + Cancel + </message> + <message name="IDS_OPEN_DOWNLOAD_DIALOG_AUTO_OPEN_TEXT" desc="Text label for the check box on the open download dialog that allows user to auto-open downloaded PDF files in future."> + Automatically open downloaded PDFs in the future </message> <message name="IDS_AUTO_OPEN_PDF_ENABLED_TITLE" desc="Title for preference that allows the user to indicate whether they want to automatically open a pdf after download completion if the download is triggered by an external app."> Automatically open pdf after download
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_OPEN_DOWNLOAD_DIALOG_ALWAYS_OPEN_TEXT.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_OPEN_DOWNLOAD_DIALOG_ALWAYS_OPEN_TEXT.png.sha1 deleted file mode 100644 index fd9ff189..0000000 --- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_OPEN_DOWNLOAD_DIALOG_ALWAYS_OPEN_TEXT.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -8c61343ed68211364fbd0eb266f2fb4ebb539855 \ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_OPEN_DOWNLOAD_DIALOG_AUTO_OPEN_TEXT.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_OPEN_DOWNLOAD_DIALOG_AUTO_OPEN_TEXT.png.sha1 new file mode 100644 index 0000000..90cfa214 --- /dev/null +++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_OPEN_DOWNLOAD_DIALOG_AUTO_OPEN_TEXT.png.sha1
@@ -0,0 +1 @@ +96c44158155bd59746e6f2a8be5d62612ce456d8 \ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_OPEN_DOWNLOAD_DIALOG_CANCEL_TEXT.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_OPEN_DOWNLOAD_DIALOG_CANCEL_TEXT.png.sha1 new file mode 100644 index 0000000..90cfa214 --- /dev/null +++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_OPEN_DOWNLOAD_DIALOG_CANCEL_TEXT.png.sha1
@@ -0,0 +1 @@ +96c44158155bd59746e6f2a8be5d62612ce456d8 \ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_OPEN_DOWNLOAD_DIALOG_JUST_ONCE_TEXT.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_OPEN_DOWNLOAD_DIALOG_JUST_ONCE_TEXT.png.sha1 deleted file mode 100644 index fd9ff189..0000000 --- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_OPEN_DOWNLOAD_DIALOG_JUST_ONCE_TEXT.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -8c61343ed68211364fbd0eb266f2fb4ebb539855 \ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_OPEN_DOWNLOAD_DIALOG_OPEN_TEXT.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_OPEN_DOWNLOAD_DIALOG_OPEN_TEXT.png.sha1 new file mode 100644 index 0000000..90cfa214 --- /dev/null +++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_OPEN_DOWNLOAD_DIALOG_OPEN_TEXT.png.sha1
@@ -0,0 +1 @@ +96c44158155bd59746e6f2a8be5d62612ce456d8 \ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_OPEN_DOWNLOAD_DIALOG_TEXT.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_OPEN_DOWNLOAD_DIALOG_TEXT.png.sha1 index fd9ff189..90cfa214 100644 --- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_OPEN_DOWNLOAD_DIALOG_TEXT.png.sha1 +++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_OPEN_DOWNLOAD_DIALOG_TEXT.png.sha1
@@ -1 +1 @@ -8c61343ed68211364fbd0eb266f2fb4ebb539855 \ No newline at end of file +96c44158155bd59746e6f2a8be5d62612ce456d8 \ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_OPEN_DOWNLOAD_DIALOG_TITLE.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_OPEN_DOWNLOAD_DIALOG_TITLE.png.sha1 index fd9ff189..90cfa214 100644 --- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_OPEN_DOWNLOAD_DIALOG_TITLE.png.sha1 +++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_OPEN_DOWNLOAD_DIALOG_TITLE.png.sha1
@@ -1 +1 @@ -8c61343ed68211364fbd0eb266f2fb4ebb539855 \ No newline at end of file +96c44158155bd59746e6f2a8be5d62612ce456d8 \ No newline at end of file
diff --git a/chrome/browser/ui/quick_answers/ui/rich_answers_translation_view.cc b/chrome/browser/ui/quick_answers/ui/rich_answers_translation_view.cc index 9389f74c..70ad1bf 100644 --- a/chrome/browser/ui/quick_answers/ui/rich_answers_translation_view.cc +++ b/chrome/browser/ui/quick_answers/ui/rich_answers_translation_view.cc
@@ -17,7 +17,6 @@ #include "ui/chromeos/styles/cros_tokens_color_mappings.h" #include "ui/views/controls/label.h" #include "ui/views/controls/webview/webview.h" -#include "ui/views/layout/box_layout_view.h" #include "ui/views/layout/flex_layout_view.h" namespace { @@ -66,11 +65,22 @@ AddLanguageTitle(translation_result_.target_locale, /*is_header_view=*/false); // Translated text. - views::BoxLayoutView* translated_text_view = AddLanguageText( + views::FlexLayoutView* translated_text_view = AddLanguageText( translation_result_.translated_text, /*maybe_append_buttons=*/true); // Read and copy buttons. - AddReadAndCopyButtons(translated_text_view); + // + // If `translated_text_view` is a valid container view, then append the button + // views to it. Else, create a separate horizontal child view in + // `content_view_` to contain the buttons. + views::View* buttons_container_view; + if (translated_text_view) { + buttons_container_view = translated_text_view; + } else { + buttons_container_view = + content_view_->AddChildView(CreateHorizontalBoxLayoutView()); + } + AddReadAndCopyButtons(buttons_container_view); } void RichAnswersTranslationView::AddLanguageTitle(const std::string& locale, @@ -89,7 +99,7 @@ /*is_multi_line=*/false, cros_tokens::kCrosSysSecondary)); } -views::BoxLayoutView* RichAnswersTranslationView::AddLanguageText( +views::FlexLayoutView* RichAnswersTranslationView::AddLanguageText( const std::string& language_text, bool maybe_append_buttons) { std::unique_ptr<QuickAnswersTextLabel> language_text_label = @@ -97,23 +107,22 @@ language_text, GetFontList(TypographyToken::kCrosTitle1), kContentTextWidth, /*is_multi_line=*/true, cros_tokens::kCrosSysOnSurface); + // If appending the read and copy buttons is an option, then check if - // the button views can fit on a single line with the text label. + // the buttons can fit on a single line with the language text label. + // + // If there's enough space to append the buttons, return the container view + // that the button views should be added to. if (maybe_append_buttons && (language_text_label->CalculatePreferredSize().width() + kReadAndCopyButtonsWidth) <= kContentTextWidth) { - should_append_buttons_ = true; - - // This box layout will have the view flex values as: - // - text label (flex=1): resize (either shrink or expand as necessary) - // - read and copy buttons (flex=0): no resize - views::BoxLayoutView* box_layout_view = + views::View* box_layout_view = content_view_->AddChildView(CreateHorizontalBoxLayoutView()); - views::View* text_label_view = - box_layout_view->AddChildView(std::move(language_text_label)); - box_layout_view->SetFlexForView(text_label_view, /*flex=*/1); + box_layout_view->AddChildView(std::move(language_text_label)); + views::FlexLayoutView* buttons_view = + box_layout_view->AddChildView(CreateHorizontalFlexLayoutView()); - return box_layout_view; + return buttons_view; } content_view_->AddChildView(std::move(language_text_label)); @@ -121,23 +130,8 @@ } void RichAnswersTranslationView::AddReadAndCopyButtons( - views::BoxLayoutView* container_view) { - views::BoxLayoutView* box_layout_view; - - // If `should_append_buttons_` is true and the provided `container_view` - // is valid, then append the buttons to the `container_view`. - // Otherwise, add the buttons in a separate horizontal view. - if (should_append_buttons_ && container_view) { - box_layout_view = container_view; - } else { - box_layout_view = - content_view_->AddChildView(CreateHorizontalBoxLayoutView()); - } - - views::View* button_views = - box_layout_view->AddChildView(CreateHorizontalFlexLayoutView()); - // We never want button_views to resize, either appended or not. - box_layout_view->SetFlexForView(button_views, /*flex=*/0); + views::View* container_view) { + CHECK(container_view); // Setup an invisible web view to play TTS audio. tts_audio_web_view_ = container_view->AddChildView( @@ -152,7 +146,7 @@ ui::ImageModel read_image_model = ui::ImageModel::FromVectorIcon( vector_icons::kVolumeUpIcon, cros_tokens::kCrosSysOnSurface, /*icon_size=*/kRichAnswersIconSizeDip); - button_views->AddChildView(CreateImageButtonView( + container_view->AddChildView(CreateImageButtonView( read_closure, read_image_model, cros_tokens::kCrosSysHoverOnSubtle, l10n_util::GetStringUTF16( IDS_QUICK_ANSWERS_PHONETICS_BUTTON_TOOLTIP_TEXT))); @@ -164,7 +158,7 @@ ui::ImageModel copy_image_model = ui::ImageModel::FromVectorIcon( vector_icons::kContentCopyIcon, cros_tokens::kCrosSysOnSurface, /*icon_size=*/kRichAnswersIconSizeDip); - button_views->AddChildView(CreateImageButtonView( + container_view->AddChildView(CreateImageButtonView( copy_closure, copy_image_model, cros_tokens::kCrosSysHoverOnSubtle, l10n_util::GetStringUTF16(IDS_QUICK_ANSWERS_COPY_BUTTON_TOOLTIP_TEXT))); }
diff --git a/chrome/browser/ui/quick_answers/ui/rich_answers_translation_view.h b/chrome/browser/ui/quick_answers/ui/rich_answers_translation_view.h index 7de8ef4..f112539 100644 --- a/chrome/browser/ui/quick_answers/ui/rich_answers_translation_view.h +++ b/chrome/browser/ui/quick_answers/ui/rich_answers_translation_view.h
@@ -11,7 +11,7 @@ #include "ui/base/metadata/metadata_header_macros.h" #include "ui/events/event_handler.h" #include "ui/views/controls/webview/webview.h" -#include "ui/views/layout/box_layout_view.h" +#include "ui/views/layout/flex_layout_view.h" #include "ui/views/view.h" namespace quick_answers { @@ -34,9 +34,9 @@ private: void InitLayout(); void AddLanguageTitle(const std::string& locale, bool is_header_view); - views::BoxLayoutView* AddLanguageText(const std::string& language_text, - bool maybe_append_buttons); - void AddReadAndCopyButtons(views::BoxLayoutView* container_view); + views::FlexLayoutView* AddLanguageText(const std::string& language_text, + bool maybe_append_buttons); + void AddReadAndCopyButtons(views::View* container_view); void OnReadButtonPressed(const std::string& read_text, const std::string& locale); void OnCopyButtonPressed(const std::string& copy_text); @@ -45,7 +45,6 @@ raw_ptr<views::WebView> tts_audio_web_view_ = nullptr; TranslationResult translation_result_; - bool should_append_buttons_ = false; base::WeakPtrFactory<RichAnswersTranslationView> weak_factory_{this}; };
diff --git a/chrome/browser/ui/tabs/organization/tab_organization.cc b/chrome/browser/ui/tabs/organization/tab_organization.cc index 9aa0da9d..17bed34a 100644 --- a/chrome/browser/ui/tabs/organization/tab_organization.cc +++ b/chrome/browser/ui/tabs/organization/tab_organization.cc
@@ -7,6 +7,7 @@ #include <optional> #include <string> +#include "base/debug/dump_without_crashing.h" #include "chrome/browser/ui/tabs/organization/tab_data.h" #include "chrome/browser/ui/tabs/tab_group.h" #include "chrome/browser/ui/tabs/tab_group_model.h" @@ -153,6 +154,16 @@ } std::sort(valid_indices.begin(), valid_indices.end()); + // TODO(b/319273296): Find a more permanent fix. + // From this point on, we start modifying the tab strip, which + // potentially notifies a large set of observers. TabOrganizationSession + // (which owns |this|) gets destroyed when a tab is added or removed + // from the tab strip. There is a risk that a tab strip observer modifies + // the tab strip and therefore causes |this| to be deleted. So we keep + // a WeakPtr to |this| to detect this case and avoid accessing member + // variables, just in case. + base::WeakPtr<TabOrganization> this_weak_ref = + weak_ptr_factory_.GetWeakPtr(); tab_groups::TabGroupId group_id = tab_strip_model->AddToNewGroup(valid_indices); TabGroup* const tab_group = @@ -178,8 +189,19 @@ if (tab_strip_model->GetTabGroupForTab(move_index) != tab_group->id()) { tab_strip_model->MoveGroupTo(tab_group->id(), move_index); } - - NotifyObserversOfUpdate(); + // If |this| has been destroyed, there is no need to notify the observers: + // in practice, the only observer is the TabOrganizationSession which owns + // this object (and therefore has been destroyed) and who will just + // notify WebUI it has been updated (of which there is no need because + // WebUI is now tracking the new TabOrganizationSession which has replaced + // the destroyed one). + if (this_weak_ref) { + NotifyObserversOfUpdate(); + } else { + // We'd like to know if this really happens: if so, we should really + // change the ownership model of TabOrganizationSession. + base::debug::DumpWithoutCrashing(); + } } void TabOrganization::Reject() {
diff --git a/chrome/browser/ui/tabs/organization/tab_organization.h b/chrome/browser/ui/tabs/organization/tab_organization.h index 7c38c23..fc1287a 100644 --- a/chrome/browser/ui/tabs/organization/tab_organization.h +++ b/chrome/browser/ui/tabs/organization/tab_organization.h
@@ -9,6 +9,7 @@ #include <string> #include <vector> +#include "base/memory/weak_ptr.h" #include "chrome/browser/ui/tabs/organization/tab_data.h" #include "components/optimization_guide/core/optimization_guide_model_executor.h" #include "third_party/abseil-cpp/absl/types/variant.h" @@ -113,6 +114,7 @@ bool invalidated_by_tab_change_ = false; base::ObserverList<Observer>::Unchecked observers_; + base::WeakPtrFactory<TabOrganization> weak_ptr_factory_{this}; }; #endif // CHROME_BROWSER_UI_TABS_ORGANIZATION_TAB_ORGANIZATION_H_
diff --git a/chrome/browser/ui/views/compose/compose_interactive_uitest.cc b/chrome/browser/ui/views/compose/compose_interactive_uitest.cc index 1bdf15ed..cedffde 100644 --- a/chrome/browser/ui/views/compose/compose_interactive_uitest.cc +++ b/chrome/browser/ui/views/compose/compose_interactive_uitest.cc
@@ -54,8 +54,7 @@ const char kTestPageDomain[] = "a.test"; const char kTestPageUrl[] = "/compose/compose_happy_path.html"; -const DeepQuery kFirstRunLetsGoButton = {"compose-app", - "#firstRunLetsGoButton"}; +const DeepQuery kFirstRunOkButton = {"compose-app", "#firstRunOkButton"}; const DeepQuery kSubmitButton = {"compose-app", "#submitButton"}; const DeepQuery kAcceptButton = {"compose-app", "#acceptButton"}; const DeepQuery kComposeTextArea = {"compose-app", "compose-textarea"}; @@ -166,7 +165,7 @@ } InteractiveTestApi::MultiStep AcceptFRE() { - return Steps(PressJsButton(kComposeWebContents, kFirstRunLetsGoButton)); + return Steps(PressJsButton(kComposeWebContents, kFirstRunOkButton)); } InteractiveTestApi::MultiStep RequestCompose() {
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc index 1fdb159..7208b112 100644 --- a/chrome/browser/ui/views/frame/browser_view.cc +++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -1553,7 +1553,7 @@ #if BUILDFLAG(IS_CHROMEOS_ASH) loading_animation_tracker_.emplace( GetWidget()->GetCompositor()->RequestNewThroughputTracker()); - loading_animation_tracker_->Start(ash::metrics_util::ForSmoothness( + loading_animation_tracker_->Start(ash::metrics_util::ForSmoothnessV3( base::BindRepeating(&RecordTabLoadingSmoothness))); #endif // Loads are happening, and the timer isn't running, so start it.
diff --git a/chrome/browser/ui/views/mahi/BUILD.gn b/chrome/browser/ui/views/mahi/BUILD.gn index f5b212c8..5d9fa16 100644 --- a/chrome/browser/ui/views/mahi/BUILD.gn +++ b/chrome/browser/ui/views/mahi/BUILD.gn
@@ -16,7 +16,9 @@ "//base", "//chrome/browser/ui/views/editor_menu:utils", "//chromeos/components/editor_menu/public/cpp", + "//chromeos/components/mahi/public/cpp", "//ui/chromeos/styles:cros_tokens_color_mappings_generator", + "//ui/display", "//ui/gfx", "//ui/views", ]
diff --git a/chrome/browser/ui/views/mahi/mahi_menu_view.cc b/chrome/browser/ui/views/mahi/mahi_menu_view.cc index a8807bb..3fbf18a 100644 --- a/chrome/browser/ui/views/mahi/mahi_menu_view.cc +++ b/chrome/browser/ui/views/mahi/mahi_menu_view.cc
@@ -9,11 +9,13 @@ #include "base/functional/bind.h" #include "chrome/browser/ui/views/editor_menu/utils/pre_target_handler.h" #include "chrome/browser/ui/views/editor_menu/utils/utils.h" +#include "chromeos/components/mahi/public/cpp/mahi_manager.h" #include "components/vector_icons/vector_icons.h" #include "ui/base/metadata/metadata_impl_macros.h" #include "ui/base/models/image_model.h" #include "ui/chromeos/styles/cros_tokens_color_mappings.h" #include "ui/color/color_id.h" +#include "ui/display/screen.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" #include "ui/views/background.h" @@ -97,7 +99,9 @@ } void MahiMenuView::OnSummaryButtonPressed() { - // TODO(b/319329379): Create and open the main panel UI. + auto display = display::Screen::GetScreen()->GetDisplayNearestWindow( + GetWidget()->GetNativeWindow()); + chromeos::MahiManager::Get()->OpenMahiPanel(display.id()); } BEGIN_METADATA(MahiMenuView, views::View)
diff --git a/chrome/browser/ui/views/user_education/browser_user_education_service_browsertest.cc b/chrome/browser/ui/views/user_education/browser_user_education_service_browsertest.cc index c7eb53fb..5849d3d7 100644 --- a/chrome/browser/ui/views/user_education/browser_user_education_service_browsertest.cc +++ b/chrome/browser/ui/views/user_education/browser_user_education_service_browsertest.cc
@@ -543,7 +543,7 @@ EXPECT_EQ( feature_engagement::EventConfig( "WebUiHelpBubbleTest_trigger", - feature_engagement::Comparator(feature_engagement::LESS_THAN, 3), + feature_engagement::Comparator(feature_engagement::LESS_THAN, 5), feature_engagement::kMaxStoragePeriod, feature_engagement::kMaxStoragePeriod), config.trigger);
diff --git a/chrome/browser/ui/views/webauthn/authenticator_dialog_view_browsertest.cc b/chrome/browser/ui/views/webauthn/authenticator_dialog_view_browsertest.cc index de24b15..e9752ac3 100644 --- a/chrome/browser/ui/views/webauthn/authenticator_dialog_view_browsertest.cc +++ b/chrome/browser/ui/views/webauthn/authenticator_dialog_view_browsertest.cc
@@ -21,6 +21,11 @@ #include "content/public/test/browser_test.h" #include "ui/views/controls/label.h" +#if BUILDFLAG(IS_WIN) +#include "device/fido/win/authenticator.h" +#include "device/fido/win/fake_webauthn_api.h" +#endif // BUILDFLAG(IS_WIN) + namespace { class TestSheetModel : public AuthenticatorRequestSheetModel { @@ -99,6 +104,21 @@ class AuthenticatorDialogViewTest : public DialogBrowserTest { public: +#if BUILDFLAG(IS_WIN) + // TODO(https://crbug.com/1517923): Make this test work with webauth versions + // that support hybrid mode. + void SetUpOnMainThread() override { + DialogBrowserTest::SetUpOnMainThread(); + + // Set up the fake Windows platform authenticator. + fake_webauthn_api_ = std::make_unique<device::FakeWinWebAuthnApi>(); + fake_webauthn_api_->set_version(WEBAUTHN_API_VERSION_4); + win_webauthn_api_override_ = + std::make_unique<device::WinWebAuthnApi::ScopedOverride>( + fake_webauthn_api_.get()); + } +#endif // BUILDFLAG(IS_WIN) + // DialogBrowserTest: void ShowUi(const std::string& name) override { dialog_model_ = std::make_unique<AuthenticatorRequestDialogModel>( @@ -163,6 +183,13 @@ } std::unique_ptr<AuthenticatorRequestDialogModel> dialog_model_; + + protected: +#if BUILDFLAG(IS_WIN) + std::unique_ptr<device::FakeWinWebAuthnApi> fake_webauthn_api_; + std::unique_ptr<device::WinWebAuthnApi::ScopedOverride> + win_webauthn_api_override_; +#endif // BUILDFLAG(IS_WIN) }; // Test the dialog with a custom delegate.
diff --git a/chrome/browser/ui/web_applications/web_app_run_on_os_login_notification.cc b/chrome/browser/ui/web_applications/web_app_run_on_os_login_notification.cc index 366c02b..57221829 100644 --- a/chrome/browser/ui/web_applications/web_app_run_on_os_login_notification.cc +++ b/chrome/browser/ui/web_applications/web_app_run_on_os_login_notification.cc
@@ -10,6 +10,7 @@ #include "base/functional/callback_forward.h" #include "base/i18n/message_formatter.h" #include "base/memory/weak_ptr.h" +#include "base/ranges/algorithm.h" #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" #include "chrome/browser/notifications/notification_display_service.h" @@ -18,10 +19,14 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser_navigator.h" #include "chrome/browser/ui/browser_navigator_params.h" +#include "chrome/browser/web_applications/web_app_provider.h" +#include "chrome/browser/web_applications/web_app_registrar.h" #include "chrome/browser/web_applications/web_app_utils.h" #include "chrome/common/webui_url_constants.h" #include "chromeos/strings/grit/chromeos_strings.h" #include "ui/base/l10n/l10n_util.h" +#include "ui/gfx/text_constants.h" +#include "ui/gfx/text_elider.h" #include "ui/message_center/public/cpp/notification_delegate.h" #if BUILDFLAG(IS_CHROMEOS_ASH) @@ -30,23 +35,66 @@ namespace { +constexpr size_t kAppLength = 18; + message_center::Notification CreateNotification( - const std::vector<std::string>& app_names, + const base::flat_map<webapps::AppId, + web_app::WebAppUiManager::RoolNotificationBehavior>& + apps, base::WeakPtr<Profile> profile) { - DCHECK(app_names.size() > 0); + CHECK(apps.size() > 0); + + const auto& [first_app_id, first_app_behavior] = *apps.begin(); + CHECK(first_app_behavior.is_rool_enabled); + + web_app::WebAppRegistrar& registrar = + web_app::WebAppProvider::GetForWebApps(profile.get())->registrar_unsafe(); + const std::u16string truncated_app_name = gfx::TruncateString( + base::UTF8ToUTF16(registrar.GetAppShortName(first_app_id)), kAppLength, + gfx::BreakType::WORD_BREAK); + std::u16string title = base::i18n::MessageFormatter::FormatWithNamedArgs( l10n_util::GetStringUTF16(IDS_RUN_ON_OS_LOGIN_ENABLED_TITLE), - /*name0=*/"NUM_ROOL_APPS", static_cast<int>(app_names.size()), - /*name1=*/"APP_NAME_1", base::UTF8ToUTF16(app_names[0])); + /*name0=*/"NUM_ROOL_APPS", static_cast<int>(apps.size()), + /*name1=*/"APP_NAME_1", truncated_app_name); - std::u16string message = base::i18n::MessageFormatter::FormatWithNamedArgs( - l10n_util::GetStringUTF16(IDS_RUN_ON_OS_LOGIN_ENABLED_MESSAGE), - /*name0=*/"NUM_ROOL_APPS", static_cast<int>(app_names.size()), - /*name1=*/"APP_NAME_1", base::UTF8ToUTF16(app_names[0]), - /*name2=*/"APP_NAME_2", - app_names.size() > 1 ? base::UTF8ToUTF16(app_names[1]) : u"", - /*name3=*/"APP_NAME_3", - app_names.size() > 2 ? base::UTF8ToUTF16(app_names[2]) : u""); + std::u16string message; + // Cases: + // - One app, is_prevent_close_enabled = true: Point out which app is + // autostarted and unclosable. + // - One app, is_prevent_close_enabled = false: Point out which app is + // autostarted. + // - Multiple apps, one or more has is_prevent_close_enabled = true: Generic + // message that multiple apps were autostarted and are unclosable. + // - Multiple apps, no app has is_prevent_close_enabled = true: Generic + // message that multiple apps were autostarted. + if (apps.size() == 1) { + if (first_app_behavior.is_prevent_close_enabled) { + message = base::i18n::MessageFormatter::FormatWithNamedArgs( + l10n_util::GetStringUTF16( + IDS_RUN_ON_OS_LOGIN_ENABLED_ONE_APP_ROOL_AND_PREVENTCLOSE_MESSAGE), + "APP_NAME", truncated_app_name); + } else { + message = base::i18n::MessageFormatter::FormatWithNamedArgs( + l10n_util::GetStringUTF16( + IDS_RUN_ON_OS_LOGIN_ENABLED_NO_PREVENTCLOSE_MESSAGE), + "NUM_ROOL_APPS", 1, "APP_NAME", truncated_app_name); + } + } else { + if (base::ranges::any_of(apps, [](const auto& app) { + return app.second.is_prevent_close_enabled; + })) { + message = base::i18n::MessageFormatter::FormatWithNamedArgs( + l10n_util::GetStringUTF16( + IDS_RUN_ON_OS_LOGIN_ENABLED_MULTIPLE_APPS_ROOL_AND_PREVENTCLOSE_MESSAGE)); + } else { + message = base::i18n::MessageFormatter::FormatWithNamedArgs( + l10n_util::GetStringUTF16( + IDS_RUN_ON_OS_LOGIN_ENABLED_NO_PREVENTCLOSE_MESSAGE), + "NUM_ROOL_APPS", static_cast<int>(apps.size()), "APP_NAME", + truncated_app_name); + } + } auto notification_data = message_center::RichNotificationData(); notification_data.buttons.emplace_back( @@ -97,14 +145,15 @@ const char kRunOnOsLoginNotificationId[] = "run_on_os_login"; const char kRunOnOsLoginNotifierId[] = "run_on_os_login_notifier"; -void DisplayRunOnOsLoginNotification(const std::vector<std::string>& app_names, - base::WeakPtr<Profile> profile) { +void DisplayRunOnOsLoginNotification( + const base::flat_map<webapps::AppId, + WebAppUiManager::RoolNotificationBehavior>& apps, + base::WeakPtr<Profile> profile) { if (!profile) { return; } - message_center::Notification notification = - CreateNotification(app_names, profile); + message_center::Notification notification = CreateNotification(apps, profile); NotificationDisplayService::GetForProfile(profile.get()) ->Display(NotificationHandler::Type::TRANSIENT, notification,
diff --git a/chrome/browser/ui/web_applications/web_app_run_on_os_login_notification.h b/chrome/browser/ui/web_applications/web_app_run_on_os_login_notification.h index 8e11937..2a5f084 100644 --- a/chrome/browser/ui/web_applications/web_app_run_on_os_login_notification.h +++ b/chrome/browser/ui/web_applications/web_app_run_on_os_login_notification.h
@@ -5,10 +5,10 @@ #ifndef CHROME_BROWSER_UI_WEB_APPLICATIONS_WEB_APP_RUN_ON_OS_LOGIN_NOTIFICATION_H_ #define CHROME_BROWSER_UI_WEB_APPLICATIONS_WEB_APP_RUN_ON_OS_LOGIN_NOTIFICATION_H_ -#include <string> -#include <vector> - +#include "base/containers/flat_map.h" #include "base/memory/weak_ptr.h" +#include "chrome/browser/web_applications/web_app_ui_manager.h" +#include "components/webapps/common/web_app_id.h" class Profile; @@ -17,8 +17,10 @@ extern const char kRunOnOsLoginNotificationId[]; extern const char kRunOnOsLoginNotifierId[]; -void DisplayRunOnOsLoginNotification(const std::vector<std::string>& app_names, - base::WeakPtr<Profile> profile); +void DisplayRunOnOsLoginNotification( + const base::flat_map<webapps::AppId, + WebAppUiManager::RoolNotificationBehavior>& apps, + base::WeakPtr<Profile> profile); } // namespace web_app #endif // CHROME_BROWSER_UI_WEB_APPLICATIONS_WEB_APP_RUN_ON_OS_LOGIN_NOTIFICATION_H_
diff --git a/chrome/browser/ui/web_applications/web_app_ui_manager_impl.cc b/chrome/browser/ui/web_applications/web_app_ui_manager_impl.cc index d678f85..99cdec1 100644 --- a/chrome/browser/ui/web_applications/web_app_ui_manager_impl.cc +++ b/chrome/browser/ui/web_applications/web_app_ui_manager_impl.cc
@@ -449,9 +449,9 @@ } void WebAppUiManagerImpl::DisplayRunOnOsLoginNotification( - const std::vector<std::string>& app_names, + const base::flat_map<webapps::AppId, RoolNotificationBehavior>& apps, base::WeakPtr<Profile> profile) { - web_app::DisplayRunOnOsLoginNotification(app_names, profile); + web_app::DisplayRunOnOsLoginNotification(apps, profile); } #endif // BUILDFLAG(IS_CHROMEOS)
diff --git a/chrome/browser/ui/web_applications/web_app_ui_manager_impl.h b/chrome/browser/ui/web_applications/web_app_ui_manager_impl.h index f9bbf586..f66841e 100644 --- a/chrome/browser/ui/web_applications/web_app_ui_manager_impl.h +++ b/chrome/browser/ui/web_applications/web_app_ui_manager_impl.h
@@ -119,9 +119,9 @@ base::OnceClosure callback) override; void DisplayRunOnOsLoginNotification( - const std::vector<std::string>& app_names, + const base::flat_map<webapps::AppId, RoolNotificationBehavior>& apps, base::WeakPtr<Profile> profile) override; -#endif +#endif // BUILDFLAG(IS_CHROMEOS) void NotifyAppRelaunchState(const webapps::AppId& placeholder_app_id, const webapps::AppId& final_app_id,
diff --git a/chrome/browser/ui/webui/compose/compose_ui.cc b/chrome/browser/ui/webui/compose/compose_ui.cc index 95fbb94..d2e7412 100644 --- a/chrome/browser/ui/webui/compose/compose_ui.cc +++ b/chrome/browser/ui/webui/compose/compose_ui.cc
@@ -45,7 +45,7 @@ {"firstRunMainTop", IDS_COMPOSE_FRE_MAIN_TOP}, {"firstRunMainMid", IDS_COMPOSE_FRE_MAIN_MID}, {"firstRunMainBottom", IDS_COMPOSE_EXPERIMENTAL_DISCLAIMER_FOOTER}, - {"firstRunLetsGoButton", IDS_COMPOSE_FRE_LETS_GO_BUTTON}, + {"firstRunOkButton", IDS_COMPOSE_FRE_OK_BUTTON}, {"dialogTitle", IDS_COMPOSE_DIALOG_TITLE}, {"inputPlaceholderTitle", IDS_COMPOSE_INPUT_PLACEHOLDER_TITLE}, {"inputPlaceholderLine1", IDS_COMPOSE_INPUT_PLACEHOLDER_LINE_1},
diff --git a/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_ui.cc b/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_ui.cc index 7ff643f..9f13cd2 100644 --- a/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_ui.cc +++ b/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_ui.cc
@@ -206,8 +206,8 @@ IDS_NTP_WALLPAPER_SEARCH_HISTORY_RESULT_LABEL_WITH_DESCRIPTOR_C}, {"wallpaperSearchHistoryResultLabelBC", IDS_NTP_WALLPAPER_SEARCH_HISTORY_RESULT_LABEL_WITH_DESCRIPTORS_B_AND_C}, - {"wallpaperSearchMeadowInspirationTitle", - IDS_NTP_WALLPAPER_SEARCH_MEADOW_INSPIRATION_TITLE}}; + {"showInspirationCardToggle", + IDS_NTP_WALLPAPER_SEARCH_INSPIRATION_CARD_TOGGLE_TITLE}}; source->AddLocalizedStrings(kLocalizedStrings); source->AddBoolean(
diff --git a/chrome/browser/ui/webui/side_panel/customize_chrome/wallpaper_search/wallpaper_search.mojom b/chrome/browser/ui/webui/side_panel/customize_chrome/wallpaper_search/wallpaper_search.mojom index 8805e4b..8744d9a 100644 --- a/chrome/browser/ui/webui/side_panel/customize_chrome/wallpaper_search/wallpaper_search.mojom +++ b/chrome/browser/ui/webui/side_panel/customize_chrome/wallpaper_search/wallpaper_search.mojom
@@ -42,8 +42,9 @@ url.mojom.Url thumbnail_url; }; -struct Inspirations { - array<Inspiration> inspiration_a; +struct InspirationGroup { + ResultDescriptors descriptors; + array<Inspiration> inspirations; }; struct WallpaperSearchResult { @@ -94,7 +95,7 @@ GetDescriptors() => (Descriptors? descriptors); // Retrieves image URLs of example results. - GetInspirations() => (Inspirations? inspirations); + GetInspirations() => (array<InspirationGroup>? inspirationGroups); // Searches NTP wallpaper for descriptors. // Returns list of sanitized image data.
diff --git a/chrome/browser/ui/webui/side_panel/customize_chrome/wallpaper_search/wallpaper_search_handler.cc b/chrome/browser/ui/webui/side_panel/customize_chrome/wallpaper_search/wallpaper_search_handler.cc index 674b405..2dbc800 100644 --- a/chrome/browser/ui/webui/side_panel/customize_chrome/wallpaper_search/wallpaper_search_handler.cc +++ b/chrome/browser/ui/webui/side_panel/customize_chrome/wallpaper_search/wallpaper_search_handler.cc
@@ -227,8 +227,8 @@ } void WallpaperSearchHandler::GetInspirations(GetInspirationsCallback callback) { - callback = - mojo::WrapCallbackWithDefaultInvokeIfNotRun(std::move(callback), nullptr); + callback = mojo::WrapCallbackWithDefaultInvokeIfNotRun(std::move(callback), + absl::nullopt); net::NetworkTrafficAnnotationTag traffic_annotation = net::DefineNetworkTrafficAnnotation( @@ -270,7 +270,7 @@ })"); auto resource_request = std::make_unique<network::ResourceRequest>(); resource_request->url = - GURL(base::StrCat({kGstaticBaseURL, "inspirations.json"})); + GURL(base::StrCat({kGstaticBaseURL, "inspirations_en-US.json"})); resource_request->request_initiator = url::Origin::Create(GURL(chrome::kChromeUINewTabURL)); @@ -718,7 +718,7 @@ // Network errors (i.e. the server did not provide a response). DVLOG(1) << "Request failed with error: " << inspirations_simple_url_loader_->NetError(); - std::move(callback).Run(nullptr); + std::move(callback).Run(absl::nullopt); return; } @@ -739,49 +739,56 @@ void WallpaperSearchHandler::OnInspirationsJsonParsed( GetInspirationsCallback callback, data_decoder::DataDecoder::ValueOrError result) { - if (!result.has_value() || !result->is_dict()) { + if (!result.has_value() || !result->is_list()) { DVLOG(1) << "Parsing JSON failed: " << result.error(); - std::move(callback).Run(nullptr); + std::move(callback).Run(absl::nullopt); return; } - - const base::Value::List* inspiration_a = - result->GetDict().FindList("inspiration_a"); - if (!inspiration_a) { - DVLOG(1) << "Parsing JSON failed: no valid inspirations."; - std::move(callback).Run(nullptr); - return; - } - - std::vector<side_panel::customize_chrome::mojom::InspirationPtr> - mojo_inspiration_a_list; - if (inspiration_a) { - for (const auto& inspiration : *inspiration_a) { - const base::Value::Dict& inspiration_a_dict = inspiration.GetDict(); - auto* background_image = - inspiration_a_dict.FindString("background_image"); - auto* thumbnail_image = inspiration_a_dict.FindString("thumbnail_image"); + std::vector<side_panel::customize_chrome::mojom::InspirationGroupPtr> + mojo_inspiration_groups; + for (const auto& inspiration : result->GetList()) { + if (!inspiration.is_dict()) { + continue; + } + const base::Value::Dict& inspiration_dict = inspiration.GetDict(); + const base::Value::List* images = inspiration_dict.FindList("images"); + const std::string* descriptor_a = + inspiration_dict.FindString("descriptor_a"); + if (!images || !descriptor_a) { + continue; + } + auto mojo_inspiration_group = + side_panel::customize_chrome::mojom::InspirationGroup::New(); + mojo_inspiration_group->descriptors = + side_panel::customize_chrome::mojom::ResultDescriptors::New(); + mojo_inspiration_group->descriptors->subject = *descriptor_a; + std::vector<side_panel::customize_chrome::mojom::InspirationPtr> + mojo_inspiration_list; + for (const auto& image : *images) { + const base::Value::Dict& image_dict = image.GetDict(); + const std::string* background_image = + image_dict.FindString("background_image"); + const std::string* thumbnail_image = + image_dict.FindString("thumbnail_image"); if (!background_image || !thumbnail_image) { continue; } - auto mojo_inspiration_a = + auto mojo_inspiration = side_panel::customize_chrome::mojom::Inspiration::New(); - // TODO(b/317402041): Ensure inspiration images have the same token - // everywhere they show in the UI. - mojo_inspiration_a->id = base::Token::CreateRandom(); - mojo_inspiration_a->background_url = + mojo_inspiration->id = base::Token::CreateRandom(); + mojo_inspiration->background_url = GURL(base::StrCat({kGstaticBaseURL, *background_image})); - mojo_inspiration_a->thumbnail_url = + mojo_inspiration->thumbnail_url = GURL(base::StrCat({kGstaticBaseURL, *thumbnail_image})); - mojo_inspiration_a_list.push_back(std::move(mojo_inspiration_a)); + mojo_inspiration_list.push_back(std::move(mojo_inspiration)); } + mojo_inspiration_group->inspirations = std::move(mojo_inspiration_list); + mojo_inspiration_groups.push_back(std::move(mojo_inspiration_group)); } - - if (!mojo_inspiration_a_list.empty()) { - auto mojo_inspirations = - side_panel::customize_chrome::mojom::Inspirations::New(); - mojo_inspirations->inspiration_a = std::move(mojo_inspiration_a_list); - std::move(callback).Run(std::move(mojo_inspirations)); + if (mojo_inspiration_groups.size() > 0) { + std::move(callback).Run(std::move(mojo_inspiration_groups)); + } else { + std::move(callback).Run(absl::nullopt); } }
diff --git a/chrome/browser/ui/webui/side_panel/customize_chrome/wallpaper_search/wallpaper_search_handler_unittest.cc b/chrome/browser/ui/webui/side_panel/customize_chrome/wallpaper_search/wallpaper_search_handler_unittest.cc index 9ce7480..777b91a 100644 --- a/chrome/browser/ui/webui/side_panel/customize_chrome/wallpaper_search/wallpaper_search_handler_unittest.cc +++ b/chrome/browser/ui/webui/side_panel/customize_chrome/wallpaper_search/wallpaper_search_handler_unittest.cc
@@ -167,7 +167,7 @@ } const std::string kInspirationsLoadURL = - base::StrCat({kGstaticBaseURL, "inspirations.json"}); + base::StrCat({kGstaticBaseURL, "inspirations_en-US.json"}); void SetUpInspirationsResponseWithData(const std::string& response) { test_url_loader_factory_.SetInterceptor(base::BindLambdaForTesting( [&](const network::ResourceRequest& request) {})); @@ -1469,29 +1469,52 @@ } TEST_F(WallpaperSearchHandlerTest, GetInspirations_Success) { - side_panel::customize_chrome::mojom::InspirationsPtr inspirations; + std::vector<side_panel::customize_chrome::mojom::InspirationGroupPtr> + inspiration_groups; base::MockCallback<WallpaperSearchHandler::GetInspirationsCallback> callback; EXPECT_CALL(callback, Run(_)) .Times(1) .WillOnce(testing::Invoke( - [&inspirations](side_panel::customize_chrome::mojom::InspirationsPtr - inspirations_ptr_arg) { - inspirations = std::move(inspirations_ptr_arg); + [&inspiration_groups]( + std::optional<std::vector< + side_panel::customize_chrome::mojom::InspirationGroupPtr>> + inspiration_groups_ptr_arg) { + inspiration_groups = std::move(inspiration_groups_ptr_arg.value()); })); SetUpInspirationsResponseWithData( R"()]}' - {"inspiration_a":[ - {"background_image":"foo_1.png","thumbnail_image":"foo_2.png"}, - {"background_image":"bar_1.png","thumbnail_image":"bar_2.png"} - ]})"); - ASSERT_FALSE(inspirations); + [{ + "descriptor_a": "foobar", + "images": [ + { + "background_image": "foo_1.png", + "thumbnail_image": "foo_2.png" + }, + { + "background_image": "bar_1.png", + "thumbnail_image": "bar_2.png" + } + ] + }, + { + "descriptor_a": "baz", + "images": [ + { + "background_image": "baz_1.png", + "thumbnail_image": "baz_2.png" + } + ] + }] + )"); auto handler = MakeHandler(/*session_id=*/123); handler->GetInspirations(callback.Get()); task_environment().RunUntilIdle(); - EXPECT_TRUE(inspirations); - const auto& inspiration_a = inspirations->inspiration_a; + EXPECT_EQ(2u, inspiration_groups.size()); + const auto& inspiration_group_a = inspiration_groups[0]; + EXPECT_EQ("foobar", inspiration_group_a->descriptors->subject); + const auto& inspiration_a = inspiration_group_a->inspirations; EXPECT_EQ(2u, inspiration_a.size()); const auto& foo_inspiration = inspiration_a[0]; EXPECT_EQ(foo_inspiration->background_url, @@ -1503,52 +1526,85 @@ base::StrCat({kGstaticBaseURL, "bar_1.png"})); EXPECT_EQ(bar_inspiration->thumbnail_url, base::StrCat({kGstaticBaseURL, "bar_2.png"})); + const auto& inspiration_group_b = inspiration_groups[1]; + EXPECT_EQ("baz", inspiration_group_b->descriptors->subject); + const auto& inspiration_b = inspiration_group_b->inspirations; + EXPECT_EQ(1u, inspiration_b.size()); + const auto& baz_inspiration = inspiration_b[0]; + EXPECT_EQ(baz_inspiration->background_url, + base::StrCat({kGstaticBaseURL, "baz_1.png"})); + EXPECT_EQ(baz_inspiration->thumbnail_url, + base::StrCat({kGstaticBaseURL, "baz_2.png"})); } TEST_F(WallpaperSearchHandlerTest, GetInspirations_Failure_InspirationsFormatIncorrect) { - side_panel::customize_chrome::mojom::InspirationsPtr inspirations; + std::optional< + std::vector<side_panel::customize_chrome::mojom::InspirationGroupPtr>> + inspiration_groups; base::MockCallback<WallpaperSearchHandler::GetInspirationsCallback> callback; EXPECT_CALL(callback, Run(_)) .Times(1) .WillOnce(testing::Invoke( - [&inspirations](side_panel::customize_chrome::mojom::InspirationsPtr - inspirations_ptr_arg) { - inspirations = std::move(inspirations_ptr_arg); + [&inspiration_groups]( + std::optional<std::vector< + side_panel::customize_chrome::mojom::InspirationGroupPtr>> + inspiration_groups_ptr_arg) { + inspiration_groups = std::move(inspiration_groups_ptr_arg); })); SetUpInspirationsResponseWithData( R"()]}' - {"inspiration_a":[ - {"background_image":"foo_1.png"}, - {"thumbnail_image":"bar_2.png"} - ]})"); - ASSERT_FALSE(inspirations); + [{ + "descriptor_a": "foo", + "images": [ + { + "background_image": "foo_1.png", + }, + { + "thumbnail_image": "bar_2.png" + } + ] + }, + { + "images": [ + { + "background_image": "baz_1.png", + "thumbnail_image": "baz_2.png" + } + ] + }] + )"); + ASSERT_FALSE(inspiration_groups.has_value()); auto handler = MakeHandler(/*session_id=*/123); handler->GetInspirations(callback.Get()); task_environment().RunUntilIdle(); - EXPECT_FALSE(inspirations); + EXPECT_FALSE(inspiration_groups.has_value()); } TEST_F(WallpaperSearchHandlerTest, GetInspirations_Failure_DataUnreachable) { - side_panel::customize_chrome::mojom::InspirationsPtr inspirations; + std::optional< + std::vector<side_panel::customize_chrome::mojom::InspirationGroupPtr>> + inspiration_groups; base::MockCallback<WallpaperSearchHandler::GetInspirationsCallback> callback; EXPECT_CALL(callback, Run(_)) .Times(1) .WillOnce(testing::Invoke( - [&inspirations](side_panel::customize_chrome::mojom::InspirationsPtr - inspirations_ptr_arg) { - inspirations = std::move(inspirations_ptr_arg); + [&inspiration_groups]( + std::optional<std::vector< + side_panel::customize_chrome::mojom::InspirationGroupPtr>> + inspiration_groups_ptr_arg) { + inspiration_groups = std::move(inspiration_groups_ptr_arg); })); SetUpInspirationsResponseWithNetworkError(); - ASSERT_FALSE(inspirations); + ASSERT_FALSE(inspiration_groups.has_value()); auto handler = MakeHandler(/*session_id=*/123); handler->GetInspirations(callback.Get()); task_environment().RunUntilIdle(); - EXPECT_FALSE(inspirations); + EXPECT_FALSE(inspiration_groups.has_value()); } TEST_F(WallpaperSearchHandlerTest, SetBackgroundToInspirationImage) {
diff --git a/chrome/browser/user_education/user_education_configuration_provider.cc b/chrome/browser/user_education/user_education_configuration_provider.cc index 07f98ad..566c3d7f 100644 --- a/chrome/browser/user_education/user_education_configuration_provider.cc +++ b/chrome/browser/user_education/user_education_configuration_provider.cc
@@ -7,6 +7,7 @@ #include <cstring> #include "base/feature_list.h" +#include "base/notreached.h" #include "base/strings/string_util.h" #include "components/feature_engagement/public/configuration.h" #include "components/user_education/common/feature_promo_registry.h" @@ -31,16 +32,14 @@ user_education::FeaturePromoRegistry& registry); UserEducationConfigurationProvider::UserEducationConfigurationProvider() - : overwrite_valid_configurations_( - user_education::features::IsUserEducationV2()) { + : use_v2_behavior_(user_education::features::IsUserEducationV2()) { MaybeRegisterChromeFeaturePromos(registry_); } UserEducationConfigurationProvider::UserEducationConfigurationProvider( user_education::FeaturePromoRegistry registry_for_testing) : registry_(std::move(registry_for_testing)), - overwrite_valid_configurations_( - user_education::features::IsUserEducationV2()) {} + use_v2_behavior_(user_education::features::IsUserEducationV2()) {} UserEducationConfigurationProvider::~UserEducationConfigurationProvider() = default; @@ -50,12 +49,19 @@ feature_engagement::FeatureConfig& config, const feature_engagement::FeatureVector& known_features, const feature_engagement::GroupVector& known_groups) const { - - // Never override existing configurations unless 2.0 is enabled. - if (config.valid && !overwrite_valid_configurations_) { + // Determine if a configuration needs to be provided or modified. + // + // Provide a configuration in v1 if there is no existing config, so that IPH + // added after the v2 transition without explicit configuration still work on + // browsers without the v2 flag enabled. + // + // In v2, a configuration is always provided; if one already exists, any + // values that mandatory in v2 are overwritten. + if (config.valid && !use_v2_behavior_) { return false; } + // Features not controlled by FeaturePromoController are ignored. if (!registry_.IsFeatureRegistered(feature)) { return false; } @@ -69,40 +75,35 @@ promo_spec->promo_subtype() == user_education::FeaturePromoSpecification:: PromoSubtype::kActionableAlert; - switch (promo_spec->promo_type()) { - case user_education::FeaturePromoSpecification::PromoType::kToast: - // Toasts can always show and do not impact other IPH. - config.session_rate.type = feature_engagement::ANY; - config.session_rate.value = 0; - config.session_rate_impact.type = - feature_engagement::SessionRateImpact::Type::NONE; - config.session_rate_impact.affected_features.reset(); - break; + // These are baseline session rate values. + config.session_rate.type = feature_engagement::ANY; + config.session_rate.value = 0; + config.session_rate_impact.type = + feature_engagement::SessionRateImpact::Type::NONE; + config.session_rate_impact.affected_features.reset(); + switch (promo_spec->promo_type()) { case user_education::FeaturePromoSpecification::PromoType::kSnooze: case user_education::FeaturePromoSpecification::PromoType::kCustomAction: case user_education::FeaturePromoSpecification::PromoType::kTutorial: - if (is_unlimited) { - config.session_rate.type = feature_engagement::ANY; - config.session_rate_impact.type = - feature_engagement::SessionRateImpact::Type::ALL; - config.session_rate_impact.affected_features.reset(); - } else { - // Heavyweight IPH can only show once per session. + // Heavyweight promos prevent future low-priority heavyweight promos. + config.session_rate_impact.type = + feature_engagement::SessionRateImpact::Type::ALL; + // Heavyweight IPH can only show once per session. However, in V2, + // sessions are controlled by the session policy. + if (!is_unlimited && !use_v2_behavior_) { config.session_rate.type = feature_engagement::EQUAL; - config.session_rate.value = 0; - config.session_rate_impact.type = - feature_engagement::SessionRateImpact::Type::ALL; - config.session_rate_impact.affected_features.reset(); } break; + case user_education::FeaturePromoSpecification::PromoType::kToast: case user_education::FeaturePromoSpecification::PromoType::kLegacy: + // Toasts can always show and do not impact other IPH. + break; + case user_education::FeaturePromoSpecification::PromoType::kUnspecified: - // No configuration is provided for legacy IPH. - CHECK(!overwrite_valid_configurations_) - << "Legacy promos not allowed in User Education Experience V2."; - return false; + // Should never get here. + NOTREACHED_NORETURN(); } // All IPH block all other IPH. @@ -114,12 +115,12 @@ if (config.trigger.name.empty()) { config.trigger.name = GetDefaultTriggerName(feature); } - if (is_unlimited) { + if (is_unlimited || use_v2_behavior_) { config.trigger.comparator.type = feature_engagement::ANY; config.trigger.comparator.value = 0; } else { config.trigger.comparator.type = feature_engagement::LESS_THAN; - config.trigger.comparator.value = 3; + config.trigger.comparator.value = 5; } config.trigger.storage = feature_engagement::kMaxStoragePeriod; config.trigger.window = feature_engagement::kMaxStoragePeriod;
diff --git a/chrome/browser/user_education/user_education_configuration_provider.h b/chrome/browser/user_education/user_education_configuration_provider.h index effa0e0..b9bab7c1 100644 --- a/chrome/browser/user_education/user_education_configuration_provider.h +++ b/chrome/browser/user_education/user_education_configuration_provider.h
@@ -39,7 +39,7 @@ private: user_education::FeaturePromoRegistry registry_; - const bool overwrite_valid_configurations_; + const bool use_v2_behavior_; }; #endif // CHROME_BROWSER_USER_EDUCATION_USER_EDUCATION_CONFIGURATION_PROVIDER_H_
diff --git a/chrome/browser/user_education/user_education_configuration_provider_unittest.cc b/chrome/browser/user_education/user_education_configuration_provider_unittest.cc index f55e8bc..3ebc4c3 100644 --- a/chrome/browser/user_education/user_education_configuration_provider_unittest.cc +++ b/chrome/browser/user_education/user_education_configuration_provider_unittest.cc
@@ -122,8 +122,13 @@ } auto GetDefaultTrigger(const char* name) { + const auto trigger = + base::FeatureList::IsEnabled( + user_education::features::kUserEducationExperienceVersion2) + ? kAny + : kLessThan5; return feature_engagement::EventConfig( - name, kLessThan3, feature_engagement::kMaxStoragePeriod, + name, trigger, feature_engagement::kMaxStoragePeriod, feature_engagement::kMaxStoragePeriod); } @@ -145,8 +150,8 @@ const feature_engagement::BlockedBy kBlockedByAll; const feature_engagement::Comparator kEqualsZero{feature_engagement::EQUAL, 0}; - const feature_engagement::Comparator kLessThan3{feature_engagement::LESS_THAN, - 3}; + const feature_engagement::Comparator kLessThan5{feature_engagement::LESS_THAN, + 5}; const feature_engagement::Comparator kAtLeast7{ feature_engagement::GREATER_THAN_OR_EQUAL, 7}; feature_engagement::SessionRateImpact kSessionRateImpactNone; @@ -376,3 +381,27 @@ EXPECT_EQ(GetDefaultTrigger("foo"), config.trigger); EXPECT_EQ(GetDefaultUsed("bar"), config.used); } + +TEST_F(UserEducationConfigurationProviderTest, v1_SessionRate) { + SetEnableV2(false); + feature_engagement::FeatureConfig config; + EXPECT_TRUE(CreateProvider()->MaybeProvideFeatureConfiguration( + kSnoozeIphFeature, config, kKnownFeatures, kKnownGroups)); + + EXPECT_EQ(feature_engagement::EQUAL, config.session_rate.type); + EXPECT_EQ(0U, config.session_rate.value); + EXPECT_EQ(feature_engagement::SessionRateImpact::Type::ALL, + config.session_rate_impact.type); +} + +TEST_F(UserEducationConfigurationProviderTest, v2_SessionRate) { + SetEnableV2(true); + feature_engagement::FeatureConfig config; + EXPECT_TRUE(CreateProvider()->MaybeProvideFeatureConfiguration( + kSnoozeIphFeature, config, kKnownFeatures, kKnownGroups)); + + EXPECT_EQ(feature_engagement::ANY, config.session_rate.type); + EXPECT_EQ(0U, config.session_rate.value); + EXPECT_EQ(feature_engagement::SessionRateImpact::Type::ALL, + config.session_rate_impact.type); +}
diff --git a/chrome/browser/web_applications/test/fake_web_app_ui_manager.cc b/chrome/browser/web_applications/test/fake_web_app_ui_manager.cc index 2f1aba8..fdd18f0 100644 --- a/chrome/browser/web_applications/test/fake_web_app_ui_manager.cc +++ b/chrome/browser/web_applications/test/fake_web_app_ui_manager.cc
@@ -171,11 +171,12 @@ } void FakeWebAppUiManager::DisplayRunOnOsLoginNotification( - const std::vector<std::string>& app_names, + const base::flat_map<webapps::AppId, + WebAppUiManager::RoolNotificationBehavior>& apps, base::WeakPtr<Profile> profile) { // Still show the notification so it can be tested using the // NotificationDisplayServiceTester - web_app::DisplayRunOnOsLoginNotification(app_names, profile); + web_app::DisplayRunOnOsLoginNotification(apps, std::move(profile)); } #endif // BUILDFLAG(IS_CHROMEOS)
diff --git a/chrome/browser/web_applications/test/fake_web_app_ui_manager.h b/chrome/browser/web_applications/test/fake_web_app_ui_manager.h index 24ed94f..5fe7f08 100644 --- a/chrome/browser/web_applications/test/fake_web_app_ui_manager.h +++ b/chrome/browser/web_applications/test/fake_web_app_ui_manager.h
@@ -96,7 +96,8 @@ base::OnceClosure callback) override; void DisplayRunOnOsLoginNotification( - const std::vector<std::string>& app_names, + const base::flat_map<webapps::AppId, + WebAppUiManager::RoolNotificationBehavior>& apps, base::WeakPtr<Profile> profile) override; #endif void NotifyAppRelaunchState(const webapps::AppId& placeholder_app_id,
diff --git a/chrome/browser/web_applications/web_app_run_on_os_login_manager.cc b/chrome/browser/web_applications/web_app_run_on_os_login_manager.cc index 2a91e0e..468d4fb 100644 --- a/chrome/browser/web_applications/web_app_run_on_os_login_manager.cc +++ b/chrome/browser/web_applications/web_app_run_on_os_login_manager.cc
@@ -8,6 +8,7 @@ #include <utility> #include <vector> +#include "base/containers/flat_map.h" #include "base/functional/bind.h" #include "base/functional/callback_helpers.h" #include "chrome/browser/apps/app_service/app_launch_params.h" @@ -55,7 +56,8 @@ void WebAppRunOnOsLoginManager::RunAppsOnOsLogin( AllAppsLock& lock, base::Value::Dict& debug_value) { - std::vector<std::string> app_names; + base::flat_map<webapps::AppId, WebAppUiManager::RoolNotificationBehavior> + notification_behaviors; for (const webapps::AppId& app_id : lock.registrar().GetAppIds()) { if (!IsRunOnOsLoginModeEnabledForAutostart( @@ -63,9 +65,12 @@ continue; } - std::string app_name = lock.registrar().GetAppShortName(app_id); - app_names.push_back(std::move(app_name)); - debug_value.EnsureList("app_names")->Append(app_name); + WebAppUiManager::RoolNotificationBehavior behavior{ + .is_rool_enabled = true, + .is_prevent_close_enabled = + lock.registrar().IsPreventCloseEnabled(app_id)}; + notification_behaviors.insert({app_id, std::move(behavior)}); + debug_value.EnsureList("app_ids")->Append(app_id); // In case of already opened/restored apps, we do not launch them again if (lock.ui_manager().GetNumWindowsForApp(app_id) > 0) { @@ -85,9 +90,9 @@ base::DoNothing()); } - if (!app_names.empty()) { + if (!notification_behaviors.empty()) { provider_->ui_manager().DisplayRunOnOsLoginNotification( - app_names, profile_->GetWeakPtr()); + notification_behaviors, profile_->GetWeakPtr()); } }
diff --git a/chrome/browser/web_applications/web_app_run_on_os_login_manager_browsertest.cc b/chrome/browser/web_applications/web_app_run_on_os_login_manager_browsertest.cc index 30c7e093..b8961bf 100644 --- a/chrome/browser/web_applications/web_app_run_on_os_login_manager_browsertest.cc +++ b/chrome/browser/web_applications/web_app_run_on_os_login_manager_browsertest.cc
@@ -2,6 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "chrome/browser/web_applications/web_app_run_on_os_login_manager.h" + +#include <vector> + +#include "base/strings/strcat.h" +#include "base/strings/string_number_conversions.h" #include "base/test/run_until.h" #include "base/test/test_future.h" #include "base/values.h" @@ -28,6 +34,7 @@ #include "chrome/common/pref_names.h" #include "content/public/test/browser_test.h" #include "testing/gmock/include/gmock/gmock.h" +#include "third_party/abseil-cpp/absl/cleanup/cleanup.h" using testing::_; using testing::AllOf; @@ -39,12 +46,9 @@ namespace { -constexpr char kTestApp1[] = "https://test.test1/"; -constexpr char kTestApp2[] = "https://test.test2/"; -constexpr char kTestApp3[] = "https://test.test3/"; -constexpr char kTestApp4[] = "https://test.test4/"; +constexpr char kTestApp[] = "https://test.test"; -constexpr char kTestAppName[] = "A Web App"; +constexpr char kTestAppName[] = "WebApp"; class WebAppRunOnOsLoginManagerBrowserTest : public WebAppControllerBrowserTest, @@ -67,10 +71,6 @@ notification_tester_ = std::make_unique<NotificationDisplayServiceTester>( /*profile=*/profile()); WebAppControllerBrowserTest::SetUpOnMainThread(); - - // WebAppSettings to use during next launch. - AddForceInstalledApp(kTestApp1, kTestAppName); - AddRoolApp(kTestApp1, kRunWindowed); } // NotificationDisplayService::Observer: @@ -111,7 +111,8 @@ } void AddRoolApp(const std::string& manifest_id, - const std::string& run_on_os_login) { + const std::string& run_on_os_login, + bool prevent_close = false) { base::test::TestFuture<void> policy_refresh_sync_future; provider() .policy_manager() @@ -122,13 +123,18 @@ prefs->GetList(prefs::kWebAppSettings).Clone(); web_app_settings.Append(base::Value::Dict() .Set(kManifestId, manifest_id) - .Set(kRunOnOsLogin, run_on_os_login)); + .Set(kRunOnOsLogin, run_on_os_login) + .Set(kPreventClose, prevent_close)); prefs->SetList(prefs::kWebAppSettings, std::move(web_app_settings)); EXPECT_TRUE(policy_refresh_sync_future.Wait()); } - Browser* FindAppBrowser() { - auto web_app = FindAppWithUrlInScope(GURL(kTestApp1)); + void ClearWebAppSettings() { + profile()->GetPrefs()->SetList(prefs::kWebAppSettings, base::Value::List()); + } + + Browser* FindAppBrowser(GURL app_url) { + auto web_app = FindAppWithUrlInScope(app_url); if (!web_app) { return nullptr; } @@ -155,38 +161,70 @@ IN_PROC_BROWSER_TEST_F( WebAppRunOnOsLoginManagerBrowserTest, WebAppRunOnOsLoginWithInitialPolicyValueLaunchesBrowserWindow) { + AddForceInstalledApp(kTestApp, kTestAppName); + AddRoolApp(kTestApp, kRunWindowed); + // Wait for ROOL. RunOsLoginAndWait(); // Should have 2 browsers: normal and app. ASSERT_EQ(2u, chrome::GetBrowserCount(browser()->profile())); - Browser* app_browser = FindAppBrowser(); - + Browser* app_browser = FindAppBrowser(GURL(kTestApp)); ASSERT_TRUE(app_browser); } IN_PROC_BROWSER_TEST_F( WebAppRunOnOsLoginManagerBrowserTest, WebAppRunOnOsLoginWithForceInstallLaunchesBrowserWindow) { + AddForceInstalledApp(kTestApp, kTestAppName); + AddRoolApp(kTestApp, kRunWindowed); + // Wait for ROOL. RunOsLoginAndWait(); // Should have 2 browsers: normal and app. ASSERT_EQ(2u, chrome::GetBrowserCount(browser()->profile())); - - Browser* app_browser = FindAppBrowser(); + Browser* app_browser = FindAppBrowser(GURL(kTestApp)); ASSERT_TRUE(app_browser); } -IN_PROC_BROWSER_TEST_F(WebAppRunOnOsLoginManagerBrowserTest, +struct WebAppRunOnOsLoginNotificationTestParameters { + size_t number_of_rool_apps; + size_t number_of_prevent_close_apps; + + std::u16string expected_notification_title; + std::u16string expected_notification_message; +}; + +class WebAppRunOnOsLoginNotificationBrowserTest + : public WebAppRunOnOsLoginManagerBrowserTest, + public testing::WithParamInterface< + WebAppRunOnOsLoginNotificationTestParameters> { + public: + WebAppRunOnOsLoginNotificationBrowserTest() = default; + ~WebAppRunOnOsLoginNotificationBrowserTest() override = default; +}; + +IN_PROC_BROWSER_TEST_P(WebAppRunOnOsLoginNotificationBrowserTest, WebAppRunOnOsLoginNotificationOpensManagementUI) { + const auto test_params = GetParam(); + for (size_t i = 0; i < test_params.number_of_rool_apps; i++) { + const auto app_id = base::StrCat({kTestApp, base::ToString(i)}); + AddForceInstalledApp(app_id, kTestAppName); + AddRoolApp(app_id, kRunWindowed, + /*prevent_close=*/i < test_params.number_of_prevent_close_apps); + } + const absl::Cleanup policy_cleanup = [this]() { ClearWebAppSettings(); }; + // Wait for ROOL. RunOsLoginAndWait(); - // Should have 2 browsers: normal and app. - ASSERT_EQ(2u, chrome::GetBrowserCount(browser()->profile())); + // Should have `number_of_rool_apps` + 1 browsers: normal and + // `number_of_rool_apps` apps. + ASSERT_EQ(test_params.number_of_rool_apps + 1, + chrome::GetBrowserCount(browser()->profile())); bool notification_shown = base::test::RunUntil([&]() { return notification_tester_->GetNotification(kRunOnOsLoginNotificationId) @@ -203,12 +241,7 @@ AllOf(Property(&message_center::Notification::id, Eq("run_on_os_login")), Property(&message_center::Notification::notifier_id, Field(&message_center::NotifierId::id, - Eq("run_on_os_login_notifier"))), - Property(&message_center::Notification::title, - Eq(u"A Web App was started automatically")), - Property(&message_center::Notification::message, - Eq(u"Your administrator has set A Web App to start " - u"automatically every time you log in.")))); + Eq("run_on_os_login_notifier"))))); notification_tester_->SimulateClick(NotificationHandler::Type::TRANSIENT, kRunOnOsLoginNotificationId, @@ -220,51 +253,16 @@ EXPECT_EQ(GURL(chrome::kChromeUIManagementURL), active_contents->GetURL()); } -IN_PROC_BROWSER_TEST_F(WebAppRunOnOsLoginManagerBrowserTest, - ClickOnLearnMoreOpensManagementUI) { - // Wait for ROOL. - RunOsLoginAndWait(); - - // Should have 2 browsers: normal and app. - ASSERT_EQ(2u, chrome::GetBrowserCount(browser()->profile())); - - bool notification_shown = base::test::RunUntil([&]() { - return notification_tester_->GetNotification(kRunOnOsLoginNotificationId) - .has_value(); - }); - // Should have notification - ASSERT_TRUE(notification_shown); - - message_center::Notification notification = - notification_tester_->GetNotification(kRunOnOsLoginNotificationId) - .value(); - EXPECT_THAT( - notification, - AllOf(Property(&message_center::Notification::id, Eq("run_on_os_login")), - Property(&message_center::Notification::notifier_id, - Field(&message_center::NotifierId::id, - Eq("run_on_os_login_notifier"))), - Property(&message_center::Notification::title, - Eq(u"A Web App was started automatically")), - Property(&message_center::Notification::message, - Eq(u"Your administrator has set A Web App to start " - u"automatically every time you log in.")))); - - notification_tester_->SimulateClick(NotificationHandler::Type::TRANSIENT, - kRunOnOsLoginNotificationId, 1, - absl::nullopt); - - content::WebContents* active_contents = - chrome::FindLastActive()->tab_strip_model()->GetActiveWebContents(); - ASSERT_TRUE(active_contents); - EXPECT_EQ(GURL(chrome::kChromeUIManagementURL), active_contents->GetURL()); -} - -IN_PROC_BROWSER_TEST_F(WebAppRunOnOsLoginManagerBrowserTest, - WebAppRunOnOsLoginNotificationWithTwoApps) { - AddForceInstalledApp(kTestApp2, kTestAppName); - - AddRoolApp(kTestApp2, kRunWindowed); +IN_PROC_BROWSER_TEST_P(WebAppRunOnOsLoginNotificationBrowserTest, + WebAppRunOnOsLoginNotification) { + const auto test_params = GetParam(); + for (size_t i = 0; i < test_params.number_of_rool_apps; i++) { + const auto app_id = base::StrCat({kTestApp, base::ToString(i)}); + AddForceInstalledApp(app_id, kTestAppName); + AddRoolApp(app_id, kRunWindowed, + /*prevent_close=*/i < test_params.number_of_prevent_close_apps); + } + const absl::Cleanup policy_cleanup = [this]() { ClearWebAppSettings(); }; // Wait for ROOL. RunOsLoginAndWait(); @@ -276,8 +274,10 @@ // Should have notification ASSERT_TRUE(notification_shown); - // Should have 3 browsers: normal and 2 apps. - ASSERT_EQ(3u, chrome::GetBrowserCount(browser()->profile())); + // Should have `number_of_rool_apps` + 1 browsers: normal and + // `number_of_rool_apps` apps. + ASSERT_EQ(GetParam().number_of_rool_apps + 1, + chrome::GetBrowserCount(browser()->profile())); message_center::Notification notification = notification_tester_->GetNotification(kRunOnOsLoginNotificationId) @@ -290,50 +290,80 @@ Field(&message_center::NotifierId::id, Eq("run_on_os_login_notifier"))), Property(&message_center::Notification::title, - Eq(u"2 apps were started automatically")), + Eq(test_params.expected_notification_title)), Property(&message_center::Notification::message, - Eq(u"Your administrator has set A Web App and A Web App " - u"to start automatically every time you log in.")))); + Eq(test_params.expected_notification_message)))); } -IN_PROC_BROWSER_TEST_F(WebAppRunOnOsLoginManagerBrowserTest, - WebAppRunOnOsLoginNotificationWithFourApps) { - AddForceInstalledApp(kTestApp2, kTestAppName); - AddForceInstalledApp(kTestApp3, kTestAppName); - AddForceInstalledApp(kTestApp4, kTestAppName); - AddRoolApp(kTestApp2, kRunWindowed); - AddRoolApp(kTestApp3, kRunWindowed); - AddRoolApp(kTestApp4, kRunWindowed); - - // Wait for ROOL. - RunOsLoginAndWait(); - - bool notification_shown = base::test::RunUntil([&]() { - return notification_tester_->GetNotification(kRunOnOsLoginNotificationId) - .has_value(); - }); - // Should have notification - ASSERT_TRUE(notification_shown); - - // Should have 5 browsers: normal and 4 apps. - ASSERT_EQ(5u, chrome::GetBrowserCount(browser()->profile())); - - message_center::Notification notification = - notification_tester_->GetNotification(kRunOnOsLoginNotificationId) - .value(); - EXPECT_THAT( - notification, - AllOf(Property(&message_center::Notification::id, Eq("run_on_os_login")), - Property(&message_center::Notification::notifier_id, - Field(&message_center::NotifierId::id, - Eq("run_on_os_login_notifier"))), - Property(&message_center::Notification::title, - Eq(u"4 apps were started automatically")), - Property(&message_center::Notification::message, - Eq(u"Your administrator has set A Web App, A Web App " - u"and 2 other apps to start automatically every time " - u"you log in.")))); -} +INSTANTIATE_TEST_SUITE_P( + WebAppRunOnOsLoginNotificationBrowserTest, + WebAppRunOnOsLoginNotificationBrowserTest, + testing::Values( + WebAppRunOnOsLoginNotificationTestParameters{ + .number_of_rool_apps = 1u, + .number_of_prevent_close_apps = 0u, + .expected_notification_title = + u"\"WebApp\" was started automatically", + .expected_notification_message = + u"Your administrator has set up \"WebApp\" to start " + u"automatically every time you log in."}, + WebAppRunOnOsLoginNotificationTestParameters{ + .number_of_rool_apps = 1u, + .number_of_prevent_close_apps = 1u, + .expected_notification_title = + u"\"WebApp\" was started automatically", + .expected_notification_message = + u"Your administrator has set up \"WebApp\" to start " + u"automatically. This app may not be closed."}, + WebAppRunOnOsLoginNotificationTestParameters{ + .number_of_rool_apps = 2u, + .number_of_prevent_close_apps = 0u, + .expected_notification_title = u"2 apps were started automatically", + .expected_notification_message = + u"Your administrator has set up \"WebApp\" and 1 other app to " + u"start automatically every time you log in."}, + WebAppRunOnOsLoginNotificationTestParameters{ + .number_of_rool_apps = 2u, + .number_of_prevent_close_apps = 1u, + .expected_notification_title = u"2 apps were started automatically", + .expected_notification_message = + u"Your administrator has set up some apps to start " + u"automatically. Some of these apps may not be closed."}, + WebAppRunOnOsLoginNotificationTestParameters{ + .number_of_rool_apps = 2u, + .number_of_prevent_close_apps = 2u, + .expected_notification_title = u"2 apps were started automatically", + .expected_notification_message = + u"Your administrator has set up some apps to start " + u"automatically. Some of these apps may not be closed."}, + WebAppRunOnOsLoginNotificationTestParameters{ + .number_of_rool_apps = 3u, + .number_of_prevent_close_apps = 0u, + .expected_notification_title = u"3 apps were started automatically", + .expected_notification_message = + u"Your administrator has set up \"WebApp\" and 2 other apps to " + u"start automatically every time you log in."}, + WebAppRunOnOsLoginNotificationTestParameters{ + .number_of_rool_apps = 3u, + .number_of_prevent_close_apps = 1u, + .expected_notification_title = u"3 apps were started automatically", + .expected_notification_message = + u"Your administrator has set up some apps to start " + u"automatically. Some of these apps may not be closed."}, + WebAppRunOnOsLoginNotificationTestParameters{ + .number_of_rool_apps = 3u, + .number_of_prevent_close_apps = 2u, + .expected_notification_title = u"3 apps were started automatically", + .expected_notification_message = + u"Your administrator has set up some apps to start " + u"automatically. Some of these apps may not be closed."}, + WebAppRunOnOsLoginNotificationTestParameters{ + .number_of_rool_apps = 3u, + .number_of_prevent_close_apps = 3u, + .expected_notification_title = u"3 apps were started automatically", + .expected_notification_message = + u"Your administrator has set up some apps to start " + u"automatically. Some of these apps may not be closed."})); } // namespace
diff --git a/chrome/browser/web_applications/web_app_ui_manager.h b/chrome/browser/web_applications/web_app_ui_manager.h index 40636c3..e14c7fe 100644 --- a/chrome/browser/web_applications/web_app_ui_manager.h +++ b/chrome/browser/web_applications/web_app_ui_manager.h
@@ -101,6 +101,11 @@ // events from WebAppTabHelpers. class WebAppUiManager { public: + struct RoolNotificationBehavior { + bool is_rool_enabled = false; + bool is_prevent_close_enabled = false; + }; + static std::unique_ptr<WebAppUiManager> Create(Profile* profile); // The returned params are populated except for the disposition and container, @@ -214,7 +219,7 @@ // Displays a notification for web apps launched on login via the RunOnOsLogin // feature on the provided |profile|. virtual void DisplayRunOnOsLoginNotification( - const std::vector<std::string>& app_names, + const base::flat_map<webapps::AppId, RoolNotificationBehavior>& apps, base::WeakPtr<Profile> profile) = 0; #endif
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt index 7d29395f..98dbaca 100644 --- a/chrome/build/linux.pgo.txt +++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@ -chrome-linux-main-1705060674-1d5704376bb36c4ba069f4b9982ff707780e57f1.profdata +chrome-linux-main-1705082277-2cf9eec3578bd2e7419b30cfcbd22891bb636cf3.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt index e33dc64..6d603638 100644 --- a/chrome/build/mac-arm.pgo.txt +++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@ -chrome-mac-arm-main-1705075026-84e646d28257278d1aeb749a147efc3a107399a5.profdata +chrome-mac-arm-main-1705096463-90e00525414657368acdc426dd7a2d7139163c4d.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt index d823b4c8..8d8b0eeb 100644 --- a/chrome/build/mac.pgo.txt +++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@ -chrome-mac-main-1705060674-4786251bca9670b38335ca44b1489036b0295f49.profdata +chrome-mac-main-1705082277-b7c3f0f215ced12863ab03acf3d49223b8c99614.profdata
diff --git a/chrome/build/win-arm64.pgo.txt b/chrome/build/win-arm64.pgo.txt index d4137412..6e381eaa 100644 --- a/chrome/build/win-arm64.pgo.txt +++ b/chrome/build/win-arm64.pgo.txt
@@ -1 +1 @@ -chrome-win-arm64-main-1705060674-22d8a72d9a0ff4d45717717cf0df435d8c8faf50.profdata +chrome-win-arm64-main-1705082277-c7caed4436f56e7450e9f1f430c0595d58fbd46d.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt index 1677105..8e5c8c2 100644 --- a/chrome/build/win64.pgo.txt +++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@ -chrome-win64-main-1705071588-cefeb6e33f3a6c0bfec0a8f46e871056ff5c61e6.profdata +chrome-win64-main-1705082277-fc35713cc634d56c90b01a322f20e03bb4f240aa.profdata
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc index 18f939f..3eea566 100644 --- a/chrome/common/chrome_features.cc +++ b/chrome/common/chrome_features.cc
@@ -240,6 +240,10 @@ base::FEATURE_ENABLED_BY_DEFAULT); #endif +BASE_FEATURE(kEnableWatermarkView, + "EnableWatermarkView", + base::FEATURE_DISABLED_BY_DEFAULT); + #if !BUILDFLAG(IS_ANDROID) // Enables migration of apps that are loaded erroneously but installed // correctly by policy in the web app system.
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h index 5c0be68e..7e45056 100644 --- a/chrome/common/chrome_features.h +++ b/chrome/common/chrome_features.h
@@ -140,6 +140,8 @@ BASE_DECLARE_FEATURE(kDMServerOAuthForChildUser); #endif +COMPONENT_EXPORT(CHROME_FEATURES) BASE_DECLARE_FEATURE(kEnableWatermarkView); + #if !BUILDFLAG(IS_ANDROID) COMPONENT_EXPORT(CHROME_FEATURES) BASE_DECLARE_FEATURE(kMigrateErrorLoadedPolicyApps);
diff --git a/chrome/test/base/chromeos/crosier/interactive_ash_test.cc b/chrome/test/base/chromeos/crosier/interactive_ash_test.cc index ca08a31..96f136e5 100644 --- a/chrome/test/base/chromeos/crosier/interactive_ash_test.cc +++ b/chrome/test/base/chromeos/crosier/interactive_ash_test.cc
@@ -137,3 +137,9 @@ state_change.event = kTextFound; return WaitForStateChange(element_id, state_change); } + +ui::test::internal::InteractiveTestPrivate::MultiStep +InteractiveAshTest::ClickElement(const ui::ElementIdentifier& element_id, + const DeepQuery& query) { + return Steps(MoveMouseTo(element_id, query), ClickMouse()); +}
diff --git a/chrome/test/base/chromeos/crosier/interactive_ash_test.h b/chrome/test/base/chromeos/crosier/interactive_ash_test.h index c8e21c6..1ad95c7f 100644 --- a/chrome/test/base/chromeos/crosier/interactive_ash_test.h +++ b/chrome/test/base/chromeos/crosier/interactive_ash_test.h
@@ -98,6 +98,13 @@ const ui::ElementIdentifier& element_id, const WebContentsInteractionTestUtil::DeepQuery& query, const std::string& expected); + + // Clicks on an element in the DOM. `element_id` is the identifier + // of the WebContents to query. `query` is a DeepQuery path to the + // element to start with, it can be {} to query the entire page. + ui::test::internal::InteractiveTestPrivate::MultiStep ClickElement( + const ui::ElementIdentifier& element_id, + const DeepQuery& query); }; #endif // CHROME_TEST_BASE_CHROMEOS_CROSIER_INTERACTIVE_ASH_TEST_H_
diff --git a/chrome/test/data/autofill/autofill_address_enabled.html b/chrome/test/data/autofill/autofill_address_enabled.html new file mode 100644 index 0000000..a0d5afed --- /dev/null +++ b/chrome/test/data/autofill/autofill_address_enabled.html
@@ -0,0 +1,32 @@ +<!DOCTYPE html> +<html lang="en"> + +<head> + <meta charset="utf-8"> + <title>AutofillAddressEnabled</title> +</head> + +<body> + <form method="post"> + <label for="name">Name</label> + <input name="name" id="name" type='text'> + + <label for="street-address">Address</label> + <input name="street-address" id="street-address" required autocomplete="street-address"> + + <label for="postal-code">Postal code</label> + <input name="postal-code" id="postal-code" required autocomplete="postal-code"> + + <label for="city">City</label> + <input name="city" id="city" required autocomplete="address-level2"> + + <label for="phone">Phone</label> + <input name="phone" id="phone" type="tel" required autocomplete="tel"> + + <label for="email">Email</label> + <input name="email" id="email" required placeholder="email@email.com" autocomplete="email"> + + <input type="submit" id="button" value="OK" class="test-target-button"> + </form> +</body> +</html> \ No newline at end of file
diff --git a/chrome/test/data/webui/chromeos/personalization_app/sea_pen_router_element_test.ts b/chrome/test/data/webui/chromeos/personalization_app/sea_pen_router_element_test.ts index 6f0ccab1..922de97 100644 --- a/chrome/test/data/webui/chromeos/personalization_app/sea_pen_router_element_test.ts +++ b/chrome/test/data/webui/chromeos/personalization_app/sea_pen_router_element_test.ts
@@ -5,6 +5,7 @@ import 'chrome://personalization/strings.m.js'; import {SeaPenInputQueryElement, SeaPenPaths, SeaPenRecentWallpapersElement, SeaPenRouterElement, SeaPenTemplateQueryElement, SeaPenTemplatesElement} from 'chrome://personalization/js/personalization_app.js'; +import {SeaPenTemplateId} from 'chrome://resources/ash/common/sea_pen/sea_pen.mojom-webui.js'; import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js'; import {waitAfterNextRender} from 'chrome://webui-test/polymer_test_util.js'; @@ -37,7 +38,7 @@ !!router.shadowRoot!.querySelector(SeaPenTemplateQueryElement.is), 'no template query element on root'); - router.selectSeaPenTemplate('123'); + router.selectSeaPenTemplate(0 as SeaPenTemplateId); await waitAfterNextRender(router); assertTrue(
diff --git a/chrome/test/data/webui/compose/compose_app_test.ts b/chrome/test/data/webui/compose/compose_app_test.ts index 0d17718..29043224 100644 --- a/chrome/test/data/webui/compose/compose_app_test.ts +++ b/chrome/test/data/webui/compose/compose_app_test.ts
@@ -241,22 +241,22 @@ assertEquals(CloseReason.kMSBBCloseButton, closeReason); }); - test('FirstRunLetsGoButtonToMainDialog', async () => { + test('FirstRunOkButtonToMainDialog', async () => { const appWithFirstRunDialog = await initializeNewAppWithFirstRunAndMsbbState(false, true); - appWithFirstRunDialog.$.firstRunLetsGoButton.click(); + appWithFirstRunDialog.$.firstRunOkButton.click(); // View state should change from FRE UI to main app UI. assertFalse(isVisible(appWithFirstRunDialog.$.firstRunDialog)); assertFalse(isVisible(appWithFirstRunDialog.$.freMsbbDialog)); assertTrue(isVisible(appWithFirstRunDialog.$.appDialog)); }); - test('FirstRunLetsGoButtonToMSBBDialog', async () => { + test('FirstRunOkButtonToMSBBDialog', async () => { const appWithFirstRunDialog = await initializeNewAppWithFirstRunAndMsbbState(false, false); - appWithFirstRunDialog.$.firstRunLetsGoButton.click(); + appWithFirstRunDialog.$.firstRunOkButton.click(); // View state should change from FRE UI to MSBB UI. assertFalse(isVisible(appWithFirstRunDialog.$.firstRunDialog)); assertTrue(isVisible(appWithFirstRunDialog.$.freMsbbDialog));
diff --git a/chrome/test/data/webui/cr_components/chromeos/cellular_setup/esim_flow_ui_legacy_test.js b/chrome/test/data/webui/cr_components/chromeos/cellular_setup/esim_flow_ui_legacy_test.js index 0348122..7a779e0d 100644 --- a/chrome/test/data/webui/cr_components/chromeos/cellular_setup/esim_flow_ui_legacy_test.js +++ b/chrome/test/data/webui/cr_components/chromeos/cellular_setup/esim_flow_ui_legacy_test.js
@@ -104,10 +104,6 @@ endFlowAndVerifyResult(ESimSetupFlowResult.ERROR_FETCHING_PROFILES); }); - function setSmdsSupportEnabled(value) { - eSimPage.smdsSupportEnabled_ = value; - } - setup(async function() { networkConfigRemote = new FakeNetworkConfig(); @@ -124,7 +120,6 @@ eSimPage = document.createElement('esim-flow-ui'); eSimPage.delegate = new FakeCellularSetupDelegate(); document.body.appendChild(eSimPage); - setSmdsSupportEnabled(false); flush(); ironPages = eSimPage.shadowRoot.querySelector('iron-pages'); @@ -161,6 +156,10 @@ assertTrue(!!finalPage); }); + suiteSetup(() => { + loadTimeData.overrideValues({isSmdsSupportEnabled: false}); + }); + function assertSelectedPage(pageName, page) { assertEquals(ironPages.selected, pageName); assertEquals(ironPages.selected, page.id);
diff --git a/chrome/test/data/webui/settings/chromeos/cellular_networks_list_test.js b/chrome/test/data/webui/settings/chromeos/cellular_networks_list_test.js index 837d69e..79e3320 100644 --- a/chrome/test/data/webui/settings/chromeos/cellular_networks_list_test.js +++ b/chrome/test/data/webui/settings/chromeos/cellular_networks_list_test.js
@@ -120,49 +120,56 @@ return new Promise(resolve => setTimeout(resolve)); } - test('Tether, cellular and eSIM profiles', async () => { - eSimManagerRemote.addEuiccForTest(2); - init(); - browserProxy.setInstantTetheringStateForTest( - MultiDeviceFeatureState.ENABLED_BY_USER); + [true, false].forEach(shouldEnableSmdsSupport => { + test('Tether, cellular and eSIM profiles', async () => { + eSimManagerRemote.addEuiccForTest(2); + init(); + browserProxy.setInstantTetheringStateForTest( + MultiDeviceFeatureState.ENABLED_BY_USER); + setIsSmdsSupportEnabled(shouldEnableSmdsSupport); - const eSimNetwork1 = OncMojo.getDefaultManagedProperties( - NetworkType.kCellular, 'cellular_esim1'); - eSimNetwork1.typeProperties.cellular.eid = - '11111111111111111111111111111111'; - const eSimNetwork2 = OncMojo.getDefaultManagedProperties( - NetworkType.kCellular, 'cellular_esim2'); - eSimNetwork2.typeProperties.cellular.eid = - '22222222222222222222222222222222'; - setManagedPropertiesForTest(NetworkType.kCellular, [ - OncMojo.getDefaultManagedProperties(NetworkType.kCellular, 'cellular1'), - OncMojo.getDefaultManagedProperties(NetworkType.kCellular, 'cellular2'), - eSimNetwork1, - eSimNetwork2, - OncMojo.getDefaultManagedProperties(NetworkType.kTether, 'tether1'), - OncMojo.getDefaultManagedProperties(NetworkType.kTether, 'tether2'), - ]); - addPSimSlot(); - addESimSlot(); + const eSimNetwork1 = OncMojo.getDefaultManagedProperties( + NetworkType.kCellular, 'cellular_esim1'); + eSimNetwork1.typeProperties.cellular.eid = + '11111111111111111111111111111111'; + const eSimNetwork2 = OncMojo.getDefaultManagedProperties( + NetworkType.kCellular, 'cellular_esim2'); + eSimNetwork2.typeProperties.cellular.eid = + '22222222222222222222222222222222'; + setManagedPropertiesForTest(NetworkType.kCellular, [ + OncMojo.getDefaultManagedProperties(NetworkType.kCellular, 'cellular1'), + OncMojo.getDefaultManagedProperties(NetworkType.kCellular, 'cellular2'), + eSimNetwork1, + eSimNetwork2, + OncMojo.getDefaultManagedProperties(NetworkType.kTether, 'tether1'), + OncMojo.getDefaultManagedProperties(NetworkType.kTether, 'tether2'), + ]); + addPSimSlot(); + addESimSlot(); - await flushAsync(); + await flushAsync(); - const eSimNetworkList = - cellularNetworkList.shadowRoot.querySelector('#esimNetworkList'); - assertTrue(!!eSimNetworkList); + const eSimNetworkList = + cellularNetworkList.shadowRoot.querySelector('#esimNetworkList'); + assertTrue(!!eSimNetworkList); - const pSimNetworkList = - cellularNetworkList.shadowRoot.querySelector('#psimNetworkList'); - assertTrue(!!pSimNetworkList); + const pSimNetworkList = + cellularNetworkList.shadowRoot.querySelector('#psimNetworkList'); + assertTrue(!!pSimNetworkList); - const tetherNetworkList = - cellularNetworkList.shadowRoot.querySelector('#tetherNetworkList'); - assertTrue(!!tetherNetworkList); + const tetherNetworkList = + cellularNetworkList.shadowRoot.querySelector('#tetherNetworkList'); + assertTrue(!!tetherNetworkList); - assertEquals(2, eSimNetworkList.networks.length); - assertEquals(2, pSimNetworkList.networks.length); - assertEquals(2, tetherNetworkList.networks.length); - assertEquals(2, eSimNetworkList.customItems.length); + assertEquals(2, eSimNetworkList.networks.length); + assertEquals(2, pSimNetworkList.networks.length); + assertEquals(2, tetherNetworkList.networks.length); + if (shouldEnableSmdsSupport) { + assertEquals(0, eSimNetworkList.customItems.length); + } else { + assertEquals(2, eSimNetworkList.customItems.length); + } + }); }); test( @@ -227,37 +234,50 @@ }); }); - test( - 'Hide esim section when no EUICC is found or no eSIM slots', async () => { - init(); - setManagedPropertiesForTest(NetworkType.kCellular, [ - OncMojo.getDefaultManagedProperties(NetworkType.kTether, 'tether1'), - ]); - flush(); - await flushAsync(); - // The list should be hidden with no EUICC or eSIM slots. - assertFalse( - !!cellularNetworkList.shadowRoot.querySelector('#esimNetworkList')); + [true, false].forEach(shouldEnableSmdsSupport => { + test( + 'Hide eSIM section when no EUICC is found or no eSIM slots', + async () => { + init(); + setIsSmdsSupportEnabled(shouldEnableSmdsSupport); - // Add an eSIM slot. - await addESimSlot(); - // The list should still be hidden. - assertFalse( - !!cellularNetworkList.shadowRoot.querySelector('#esimNetworkList')); + const eSimNetwork = OncMojo.getDefaultManagedProperties( + NetworkType.kCellular, 'cellular_esim'); + eSimNetwork.typeProperties.cellular.eid = + '11111111111111111111111111111111'; + eSimNetwork.typeProperties.cellular.iccid = + '11111111111111111111111111111111'; + setManagedPropertiesForTest(NetworkType.kCellular, [ + eSimNetwork, + OncMojo.getDefaultManagedProperties(NetworkType.kTether, 'tether1'), + ]); + flush(); + await flushAsync(); - // Add an EUICC. - eSimManagerRemote.addEuiccForTest(1); - await flushAsync(); - // The list should now be showing - assertTrue( - !!cellularNetworkList.shadowRoot.querySelector('#esimNetworkList')); + // The list should be hidden with no EUICC or eSIM slots. + assertFalse(!!cellularNetworkList.shadowRoot.querySelector( + '#esimNetworkList')); - // Remove the eSIM slot - clearSimSlots(); - // The list should be hidden again. - assertFalse( - !!cellularNetworkList.shadowRoot.querySelector('#esimNetworkList')); - }); + // Add an eSIM slot. + await addESimSlot(); + // The list should still be hidden. + assertFalse(!!cellularNetworkList.shadowRoot.querySelector( + '#esimNetworkList')); + + // Add an EUICC. + eSimManagerRemote.addEuiccForTest(1); + await flushAsync(); + // The list should now be showing + assertTrue(!!cellularNetworkList.shadowRoot.querySelector( + '#esimNetworkList')); + + // Remove the eSIM slot + clearSimSlots(); + // The list should be hidden again. + assertFalse(!!cellularNetworkList.shadowRoot.querySelector( + '#esimNetworkList')); + }); + }); test('Hide pSIM section when no pSIM slots', async () => { init(); @@ -322,6 +342,9 @@ async () => { eSimManagerRemote.addEuiccForTest(1); init(); + // Pending profiles are never shown in the UI when SM-DS Support is + // enabled. + setIsSmdsSupportEnabled(false); addESimSlot(); cellularNetworkList.globalPolicy = { allowOnlyPolicyCellularNetworks: false, @@ -357,6 +380,9 @@ async () => { eSimManagerRemote.addEuiccForTest(1); init(); + // Pending profiles are never shown in the UI when SM-DS Support is + // enabled. + setIsSmdsSupportEnabled(false); addESimSlot(); cellularNetworkList.isConnectedToNonCellularNetwork = false; await flushAsync(); @@ -475,6 +501,8 @@ NetworkType.kCellular, 'cellular_esim1'); eSimNetwork1.typeProperties.cellular.eid = '11111111111111111111111111111111'; + eSimNetwork1.typeProperties.cellular.iccid = + '11111111111111111111111111111111'; setManagedPropertiesForTest(NetworkType.kCellular, [ OncMojo.getDefaultManagedProperties(NetworkType.kCellular, 'cellular1'), eSimNetwork1,
diff --git a/chrome/test/data/webui/side_panel/customize_chrome/wallpaper_search/wallpaper_search_test.ts b/chrome/test/data/webui/side_panel/customize_chrome/wallpaper_search/wallpaper_search_test.ts index ef88248..6cbacd9 100644 --- a/chrome/test/data/webui/side_panel/customize_chrome/wallpaper_search/wallpaper_search_test.ts +++ b/chrome/test/data/webui/side_panel/customize_chrome/wallpaper_search/wallpaper_search_test.ts
@@ -8,16 +8,18 @@ import {CustomizeChromeAction} from 'chrome://customize-chrome-side-panel.top-chrome/common.js'; import {CustomizeChromePageRemote} from 'chrome://customize-chrome-side-panel.top-chrome/customize_chrome.mojom-webui.js'; import {CustomizeChromeApiProxy} from 'chrome://customize-chrome-side-panel.top-chrome/customize_chrome_api_proxy.js'; -import {Descriptors, Inspirations, ResultDescriptors, UserFeedback, WallpaperSearchClientCallbackRouter, WallpaperSearchClientRemote, WallpaperSearchHandlerInterface, WallpaperSearchHandlerRemote, WallpaperSearchStatus} from 'chrome://customize-chrome-side-panel.top-chrome/wallpaper_search.mojom-webui.js'; +import {Descriptors, InspirationGroup, ResultDescriptors, UserFeedback, WallpaperSearchClientCallbackRouter, WallpaperSearchClientRemote, WallpaperSearchHandlerInterface, WallpaperSearchHandlerRemote, WallpaperSearchStatus} from 'chrome://customize-chrome-side-panel.top-chrome/wallpaper_search.mojom-webui.js'; import {CustomizeChromeCombobox} from 'chrome://customize-chrome-side-panel.top-chrome/wallpaper_search/combobox/customize_chrome_combobox.js'; import {DESCRIPTOR_D_VALUE, WallpaperSearchElement} from 'chrome://customize-chrome-side-panel.top-chrome/wallpaper_search/wallpaper_search.js'; import {WallpaperSearchProxy} from 'chrome://customize-chrome-side-panel.top-chrome/wallpaper_search/wallpaper_search_proxy.js'; import {WindowProxy} from 'chrome://customize-chrome-side-panel.top-chrome/window_proxy.js'; import {CrAutoImgElement} from 'chrome://resources/cr_elements/cr_auto_img/cr_auto_img.js'; import {CrFeedbackOption} from 'chrome://resources/cr_elements/cr_feedback_buttons/cr_feedback_buttons.js'; +import {CrIconButtonElement} from 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.js'; import {hexColorToSkColor} from 'chrome://resources/js/color_utils.js'; import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; import {PromiseResolver} from 'chrome://resources/js/promise_resolver.js'; +import {IronCollapseElement} from 'chrome://resources/polymer/v3_0/iron-collapse/iron-collapse.js'; import {assertDeepEquals, assertEquals, assertFalse, assertGE, assertNotEquals, assertTrue} from 'chrome://webui-test/chai_assert.js'; import {fakeMetricsPrivate, MetricsTracker} from 'chrome://webui-test/metrics_test_support.js'; import {flushTasks, waitAfterNextRender} from 'chrome://webui-test/polymer_test_util.js'; @@ -36,9 +38,11 @@ async function createWallpaperSearchElement( descriptors: Descriptors|null = null, - inspirations: Inspirations|null = null): Promise<WallpaperSearchElement> { + inspirationGroups: InspirationGroup[]|null = + null): Promise<WallpaperSearchElement> { handler.setResultFor('getDescriptors', Promise.resolve({descriptors})); - handler.setResultFor('getInspirations', Promise.resolve({inspirations})); + handler.setResultFor( + 'getInspirations', Promise.resolve({inspirationGroups})); wallpaperSearchElement = document.createElement('customize-chrome-wallpaper-search'); document.body.appendChild(wallpaperSearchElement); @@ -1490,42 +1494,104 @@ }); test('inspirations populate correctly', async () => { - createWallpaperSearchElement(/*descriptors=*/ null, { - inspirationA: [ - { - id: {high: BigInt(10), low: BigInt(1)}, - backgroundUrl: {url: 'https://example.com/foo_1.png'}, - thumbnailUrl: {url: 'https://example.com/foo_2.png'}, - }, - { - id: {high: BigInt(8), low: BigInt(2)}, - backgroundUrl: {url: 'https://example.com/bar_1.png'}, - thumbnailUrl: {url: 'https://example.com/bar_2.png'}, - }, - ], - }); + createWallpaperSearchElement( + /*descriptors=*/ null, /*inspirationGroups=*/[ + { + descriptors: { + subject: 'foobar', + style: undefined, + mood: undefined, + color: undefined, + }, + inspirations: [ + { + id: {high: BigInt(10), low: BigInt(1)}, + backgroundUrl: {url: 'https://example.com/foo_1.png'}, + thumbnailUrl: {url: 'https://example.com/foo_2.png'}, + }, + { + id: {high: BigInt(8), low: BigInt(2)}, + backgroundUrl: {url: 'https://example.com/bar_1.png'}, + thumbnailUrl: {url: 'https://example.com/bar_2.png'}, + }, + ], + }, + { + descriptors: { + subject: 'baz', + style: undefined, + mood: undefined, + color: undefined, + }, + inspirations: [ + { + id: {high: BigInt(7), low: BigInt(2)}, + backgroundUrl: {url: 'https://example.com/baz_1.png'}, + thumbnailUrl: {url: 'https://example.com/baz_2.png'}, + }, + ], + }, + ]); await flushTasks(); + // Ensure inspiration titles are correct. + const inspirationTitles = + wallpaperSearchElement.shadowRoot!.querySelectorAll( + '#inspirationCard .inspiration-title'); + assertTrue(!!inspirationTitles); + assertEquals(2, inspirationTitles.length); + assertEquals(inspirationTitles[0]!.textContent, 'foobar'); + assertEquals(inspirationTitles[1]!.textContent, 'baz'); + // Ensure the correct amount of groups show. + const inspirationsGroups = + wallpaperSearchElement.shadowRoot!.querySelectorAll( + '#inspirationCard cr-grid'); + assertTrue(!!inspirationsGroups); + assertEquals(2, inspirationsGroups.length); + // Ensure the correct amount of inspirations show. const inspirations = wallpaperSearchElement.shadowRoot!.querySelectorAll( '#inspirationCard .tile.result'); assertTrue(!!inspirations); - assertEquals(2, inspirations.length); + assertEquals(3, inspirations.length); + // Ensure that inspirations are populated in the correct group with the + // right image. + const inspirationGridResults1 = + inspirationsGroups[0]!.querySelectorAll('.tile.result'); + assertEquals(inspirations[0], inspirationGridResults1[0]); assertEquals( 'https://example.com/foo_2.png', (inspirations[0]!.querySelector('img')! as CrAutoImgElement).autoSrc); + assertEquals(inspirations[1], inspirationGridResults1[1]); assertEquals( 'https://example.com/bar_2.png', (inspirations[1]!.querySelector('img')! as CrAutoImgElement).autoSrc); + const inspirationGridResults2 = + inspirationsGroups[1]!.querySelectorAll('.tile.result'); + assertEquals(inspirations[2], inspirationGridResults2[0]); + assertEquals( + 'https://example.com/baz_2.png', + (inspirations[2]!.querySelector('img')! as CrAutoImgElement).autoSrc); }); test('setting inspiration to background calls backend', async () => { - createWallpaperSearchElement(/*descriptors=*/ null, { - inspirationA: [{ - id: {high: BigInt(10), low: BigInt(1)}, - backgroundUrl: {url: 'https://example.com/foo_1.png'}, - thumbnailUrl: {url: 'https://example.com/foo_2.png'}, - }], - }); + createWallpaperSearchElement( + /*descriptors=*/ null, /*inspirationGroups=*/[ + { + descriptors: { + subject: 'foobar', + style: undefined, + mood: undefined, + color: undefined, + }, + inspirations: [ + { + id: {high: BigInt(10), low: BigInt(1)}, + backgroundUrl: {url: 'https://example.com/foo_1.png'}, + thumbnailUrl: {url: 'https://example.com/foo_2.png'}, + }, + ], + }, + ]); await flushTasks(); const result = @@ -1543,5 +1609,62 @@ 'https://example.com/foo_1.png', handler.getArgs('setBackgroundToInspirationImage')[0][1].url); }); + + test('inspiration card toggles on click', async () => { + createWallpaperSearchElement(); + await flushTasks(); + + const ironCollapse = + $$<IronCollapseElement>(wallpaperSearchElement, 'iron-collapse')!; + assertFalse(ironCollapse.opened); + assertEquals( + 'expand-carets', + wallpaperSearchElement.shadowRoot! + .querySelector('#inspirationToggle')!.className); + + $$<CrIconButtonElement>( + wallpaperSearchElement, '#inspirationToggle')!.click(); + + assertTrue(ironCollapse.opened); + assertEquals( + 'collapse-carets', + wallpaperSearchElement.shadowRoot! + .querySelector('#inspirationToggle')!.className); + + $$<CrIconButtonElement>( + wallpaperSearchElement, '#inspirationToggle')!.click(); + + assertFalse(ironCollapse.opened); + assertEquals( + 'expand-carets', + wallpaperSearchElement.shadowRoot! + .querySelector('#inspirationToggle')!.className); + }); + + test('inspiration card collapsible reacts to history updates', async () => { + createWallpaperSearchElement(); + await flushTasks(); + + // Card collapsed when the element is created. + const ironCollapse = + $$<IronCollapseElement>(wallpaperSearchElement, 'iron-collapse')!; + assertFalse(ironCollapse.opened); + + // Card opens if there is no history. + wallpaperSearchCallbackRouterRemote.setHistory([]); + await wallpaperSearchCallbackRouterRemote.$.flushForTesting(); + + assertTrue(ironCollapse.opened); + + // Card collapses if there is history. + wallpaperSearchCallbackRouterRemote.setHistory([ + {image: '123', id: {high: BigInt(10), low: BigInt(1)}}, + {image: '456', id: {high: BigInt(8), low: BigInt(2)}}, + ]); + await wallpaperSearchCallbackRouterRemote.$.flushForTesting(); + + assertTrue(!!$$(wallpaperSearchElement, '#historyCard .tile.result')); + assertFalse(ironCollapse.opened); + }); }); });
diff --git a/chromeos/ash/components/network/cellular_policy_handler_legacy_unittest.cc b/chromeos/ash/components/network/cellular_policy_handler_legacy_unittest.cc index 78c3e5d..9b689ce 100644 --- a/chromeos/ash/components/network/cellular_policy_handler_legacy_unittest.cc +++ b/chromeos/ash/components/network/cellular_policy_handler_legacy_unittest.cc
@@ -345,6 +345,12 @@ }; TEST_F(CellularPolicyHandlerLegacyTest, InstallProfileSuccess) { + base::test::ScopedFeatureList feature_list; + feature_list.InitWithFeatures( + /*enabled_features=*/{}, + /*disabled_features=*/{features::kCellularUseSecondEuicc, + features::kSmdsSupport}); + SetupEuicc(); const std::string policy = GenerateCellularPolicy(HermesEuiccClient::Get() @@ -365,6 +371,12 @@ } TEST_F(CellularPolicyHandlerLegacyTest, InstallWaitForDeviceState) { + base::test::ScopedFeatureList feature_list; + feature_list.InitWithFeatures( + /*enabled_features=*/{}, + /*disabled_features=*/{features::kCellularUseSecondEuicc, + features::kSmdsSupport}); + SetupEuicc(); ShillManagerClient::Get()->GetTestInterface()->ClearDevices(); base::RunLoop().RunUntilIdle(); @@ -391,6 +403,12 @@ } TEST_F(CellularPolicyHandlerLegacyTest, InstallWaitForEuicc) { + base::test::ScopedFeatureList feature_list; + feature_list.InitWithFeatures( + /*enabled_features=*/{}, + /*disabled_features=*/{features::kCellularUseSecondEuicc, + features::kSmdsSupport}); + HermesManagerClient::Get()->GetTestInterface()->ClearEuiccs(); const std::string policy = GenerateCellularPolicy(HermesEuiccClient::Get() @@ -413,6 +431,12 @@ } TEST_F(CellularPolicyHandlerLegacyTest, RetryInstallProfile) { + base::test::ScopedFeatureList feature_list; + feature_list.InitWithFeatures( + /*enabled_features=*/{}, + /*disabled_features=*/{features::kCellularUseSecondEuicc, + features::kSmdsSupport}); + SetupEuicc(); const std::string policy = @@ -484,6 +508,12 @@ } TEST_F(CellularPolicyHandlerLegacyTest, InstallProfileFailure) { + base::test::ScopedFeatureList feature_list; + feature_list.InitWithFeatures( + /*enabled_features=*/{}, + /*disabled_features=*/{features::kCellularUseSecondEuicc, + features::kSmdsSupport}); + SetupEuicc(); // Make the first installation attempt fail, resulting in an immediate retry @@ -527,7 +557,10 @@ // Verify esim profile get installed successfully when installing policy // on the external EUICC. base::test::ScopedFeatureList feature_list; - feature_list.InitAndEnableFeature(features::kCellularUseSecondEuicc); + feature_list.InitWithFeatures( + /*enabled_features=*/{features::kCellularUseSecondEuicc}, + /*disabled_features=*/{features::kSmdsSupport}); + SetupEuicc2(); const std::string policy = GenerateCellularPolicy(HermesEuiccClient::Get() @@ -543,6 +576,12 @@ } TEST_F(CellularPolicyHandlerLegacyTest, InstallNoEUICCAvailable) { + base::test::ScopedFeatureList feature_list; + feature_list.InitWithFeatures( + /*enabled_features=*/{}, + /*disabled_features=*/{features::kCellularUseSecondEuicc, + features::kSmdsSupport}); + SetupEuicc(); // Verify esim profile doesn't get installed when installing policy esim // with no available EUICC. @@ -562,6 +601,12 @@ } TEST_F(CellularPolicyHandlerLegacyTest, UpdateSMDPAddress) { + base::test::ScopedFeatureList feature_list; + feature_list.InitWithFeatures( + /*enabled_features=*/{}, + /*disabled_features=*/{features::kCellularUseSecondEuicc, + features::kSmdsSupport}); + SetupEuicc(); // Verify that the first request should be invalidated when the second // request is queued. @@ -583,6 +628,12 @@ } TEST_F(CellularPolicyHandlerLegacyTest, InstallExistingESimProfileSuccess) { + base::test::ScopedFeatureList feature_list; + feature_list.InitWithFeatures( + /*enabled_features=*/{}, + /*disabled_features=*/{features::kCellularUseSecondEuicc, + features::kSmdsSupport}); + SetupEuicc(); SetupESimProfile(); @@ -601,6 +652,12 @@ } TEST_F(CellularPolicyHandlerLegacyTest, InstallExistingESimProfileFailure) { + base::test::ScopedFeatureList feature_list; + feature_list.InitWithFeatures( + /*enabled_features=*/{}, + /*disabled_features=*/{features::kCellularUseSecondEuicc, + features::kSmdsSupport}); + SetupEuicc(); SetupESimProfile(); ShillManagerClient::Get()->GetTestInterface()->SetSimulateConfigurationResult( @@ -621,6 +678,12 @@ } TEST_F(CellularPolicyHandlerLegacyTest, NoInternetConnection) { + base::test::ScopedFeatureList feature_list; + feature_list.InitWithFeatures( + /*enabled_features=*/{}, + /*disabled_features=*/{features::kCellularUseSecondEuicc, + features::kSmdsSupport}); + SetupEuicc(); auto* shill_service = ShillServiceClient::Get()->GetTestInterface(); shill_service->ClearServices();
diff --git a/chromeos/chromeos_strings.grd b/chromeos/chromeos_strings.grd index c559d13..47e9c5f 100644 --- a/chromeos/chromeos_strings.grd +++ b/chromeos/chromeos_strings.grd
@@ -4747,18 +4747,23 @@ </if> <!-- Strings for WebAppSettings --> - <message name="IDS_RUN_ON_OS_LOGIN_ENABLED_MESSAGE" desc="This is the message of the notification when an application is automatically started on OS login.[ICU Syntax]"> - {NUM_ROOL_APPS, plural, offset:2 - =1 {Your administrator has set <ph name="APP_NAME_1">{APP_NAME_1}</ph> to start automatically every time you log in.} - =2 {Your administrator has set <ph name="APP_NAME_1">{APP_NAME_1}</ph> and <ph name="APP_NAME_2">{APP_NAME_2}</ph> to start automatically every time you log in.} - =3 {Your administrator has set <ph name="APP_NAME_1">{APP_NAME_1}</ph>, <ph name="APP_NAME_2">{APP_NAME_2}</ph> and <ph name="APP_NAME_3">{APP_NAME_3}</ph> to start automatically every time you log in.} - other {Your administrator has set <ph name="APP_NAME_1">{APP_NAME_1}</ph>, <ph name="APP_NAME_2">{APP_NAME_2}</ph> and # other apps to start automatically every time you log in.} + <message name="IDS_RUN_ON_OS_LOGIN_ENABLED_NO_PREVENTCLOSE_MESSAGE" desc="This is the message of the notification when an application is automatically started on OS login.[ICU Syntax]"> + {NUM_ROOL_APPS, plural, offset:1 + =1 {Your administrator has set up "<ph name="APP_NAME">{APP_NAME}</ph>" to start automatically every time you log in.} + =2 {Your administrator has set up "<ph name="APP_NAME">{APP_NAME}</ph>" and 1 other app to start automatically every time you log in.} + other {Your administrator has set up "<ph name="APP_NAME">{APP_NAME}</ph>" and # other apps to start automatically every time you log in.} } </message> + <message name="IDS_RUN_ON_OS_LOGIN_ENABLED_ONE_APP_ROOL_AND_PREVENTCLOSE_MESSAGE" desc="This is the message of the notification when one application is automatically started on OS login and is prevented from closing.[ICU Syntax]"> + Your administrator has set up "<ph name="APP_NAME">{APP_NAME}</ph>" to start automatically. This app may not be closed. + </message> + <message name="IDS_RUN_ON_OS_LOGIN_ENABLED_MULTIPLE_APPS_ROOL_AND_PREVENTCLOSE_MESSAGE" desc="This is the message of the notification when multiple applications are automatically started on OS login and are prevented from closing.[ICU Syntax]"> + Your administrator has set up some apps to start automatically. Some of these apps may not be closed. + </message> <message name="IDS_RUN_ON_OS_LOGIN_ENABLED_TITLE" desc="This is the title of the notification when an application is automatically started on OS login. [ICU Syntax]"> {NUM_ROOL_APPS, plural, - =1 {<ph name="APP_NAME_1">{APP_NAME_1}</ph> was started automatically} + =1 {"<ph name="APP_NAME_1">{APP_NAME_1}</ph>" was started automatically} other {# apps were started automatically} } </message>
diff --git a/chromeos/chromeos_strings_grd/IDS_RUN_ON_OS_LOGIN_ENABLED_MESSAGE.png.sha1 b/chromeos/chromeos_strings_grd/IDS_RUN_ON_OS_LOGIN_ENABLED_MESSAGE.png.sha1 deleted file mode 100644 index ed643d4..0000000 --- a/chromeos/chromeos_strings_grd/IDS_RUN_ON_OS_LOGIN_ENABLED_MESSAGE.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -00f5aad7b10e129bb8644694b84dca67b876f20d \ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_RUN_ON_OS_LOGIN_ENABLED_MULTIPLE_APPS_ROOL_AND_PREVENTCLOSE_MESSAGE.png.sha1 b/chromeos/chromeos_strings_grd/IDS_RUN_ON_OS_LOGIN_ENABLED_MULTIPLE_APPS_ROOL_AND_PREVENTCLOSE_MESSAGE.png.sha1 new file mode 100644 index 0000000..3afc249 --- /dev/null +++ b/chromeos/chromeos_strings_grd/IDS_RUN_ON_OS_LOGIN_ENABLED_MULTIPLE_APPS_ROOL_AND_PREVENTCLOSE_MESSAGE.png.sha1
@@ -0,0 +1 @@ +7a0d9a8ba2bdb339e48cebc3cf9caaf2ce1b4723 \ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_RUN_ON_OS_LOGIN_ENABLED_NO_PREVENTCLOSE_MESSAGE.png.sha1 b/chromeos/chromeos_strings_grd/IDS_RUN_ON_OS_LOGIN_ENABLED_NO_PREVENTCLOSE_MESSAGE.png.sha1 new file mode 100644 index 0000000..66404a8 --- /dev/null +++ b/chromeos/chromeos_strings_grd/IDS_RUN_ON_OS_LOGIN_ENABLED_NO_PREVENTCLOSE_MESSAGE.png.sha1
@@ -0,0 +1 @@ +1844a75519b1c020b3526592e206c8e858c1b266 \ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_RUN_ON_OS_LOGIN_ENABLED_ONE_APP_ROOL_AND_PREVENTCLOSE_MESSAGE.png.sha1 b/chromeos/chromeos_strings_grd/IDS_RUN_ON_OS_LOGIN_ENABLED_ONE_APP_ROOL_AND_PREVENTCLOSE_MESSAGE.png.sha1 new file mode 100644 index 0000000..7328e89 --- /dev/null +++ b/chromeos/chromeos_strings_grd/IDS_RUN_ON_OS_LOGIN_ENABLED_ONE_APP_ROOL_AND_PREVENTCLOSE_MESSAGE.png.sha1
@@ -0,0 +1 @@ +3f0b2b6841d25507b2c5fe46945c8e844f8552e7 \ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_RUN_ON_OS_LOGIN_ENABLED_TITLE.png.sha1 b/chromeos/chromeos_strings_grd/IDS_RUN_ON_OS_LOGIN_ENABLED_TITLE.png.sha1 index ed643d4..d765a69 100644 --- a/chromeos/chromeos_strings_grd/IDS_RUN_ON_OS_LOGIN_ENABLED_TITLE.png.sha1 +++ b/chromeos/chromeos_strings_grd/IDS_RUN_ON_OS_LOGIN_ENABLED_TITLE.png.sha1
@@ -1 +1 @@ -00f5aad7b10e129bb8644694b84dca67b876f20d \ No newline at end of file +29b4eab632042421af4bf2fc707447eb1093e1ae \ No newline at end of file
diff --git a/chromeos/components/cdm_factory_daemon/cdm_factory_daemon_proxy_ash.cc b/chromeos/components/cdm_factory_daemon/cdm_factory_daemon_proxy_ash.cc index 440ac13..ea0bc7c3 100644 --- a/chromeos/components/cdm_factory_daemon/cdm_factory_daemon_proxy_ash.cc +++ b/chromeos/components/cdm_factory_daemon/cdm_factory_daemon_proxy_ash.cc
@@ -105,6 +105,23 @@ size, std::move(callback)); } + void ParseEncryptedSliceHeader( + uint64_t secure_handle, + uint32_t offset, + const std::vector<uint8_t>& stream_data, + ParseEncryptedSliceHeaderCallback callback) override { + if (!task_runner_->RunsTasksInCurrentSequence()) { + task_runner_->PostTask( + FROM_HERE, + base::BindOnce(&BrowserCdmFactoryProxy::ParseEncryptedSliceHeader, + weak_factory_.GetWeakPtr(), secure_handle, offset, + stream_data, std::move(callback))); + return; + } + CdmFactoryDaemonProxyAsh::GetInstance().ParseEncryptedSliceHeader( + secure_handle, offset, stream_data, std::move(callback)); + } + private: scoped_refptr<base::SequencedTaskRunner> task_runner_; base::WeakPtrFactory<BrowserCdmFactoryProxy> weak_factory_{this}; @@ -285,6 +302,27 @@ base::Unretained(this), size, std::move(callback))); } +void CdmFactoryDaemonProxyAsh::ParseEncryptedSliceHeader( + uint64_t secure_handle, + uint32_t offset, + const std::vector<uint8_t>& stream_data, + ParseEncryptedSliceHeaderCallback callback) { + DCHECK(mojo_task_runner_->RunsTasksInCurrentSequence()); + DVLOG(1) << "CdmFactoryDaemonProxyAsh::ParseEncryptedSliceHeader called"; + if (daemon_remote_.is_bound()) { + DVLOG(1) << "CdmFactoryDaemon mojo connection already exists, re-use it"; + ProxyParseEncryptedSliceHeader(secure_handle, offset, stream_data, + std::move(callback)); + return; + } + + // base::Unretained is safe below because this class is a singleton. + EstablishDaemonConnection( + base::BindOnce(&CdmFactoryDaemonProxyAsh::ProxyParseEncryptedSliceHeader, + base::Unretained(this), secure_handle, offset, stream_data, + std::move(callback))); +} + void CdmFactoryDaemonProxyAsh::EstablishDaemonConnection( base::OnceClosure callback) { // This may have happened already. @@ -368,6 +406,20 @@ daemon_remote_->AllocateSecureBuffer(size, std::move(callback)); } +void CdmFactoryDaemonProxyAsh::ProxyParseEncryptedSliceHeader( + uint64_t secure_handle, + uint32_t offset, + const std::vector<uint8_t>& stream_data, + ParseEncryptedSliceHeaderCallback callback) { + if (!daemon_remote_) { + LOG(ERROR) << "daemon_remote_ interface is not connected"; + std::move(callback).Run(false, {}); + return; + } + daemon_remote_->ParseEncryptedSliceHeader(secure_handle, offset, stream_data, + std::move(callback)); +} + void CdmFactoryDaemonProxyAsh::SendDBusRequest(base::ScopedFD fd, base::OnceClosure callback) { ash::CdmFactoryDaemonClient::Get()->BootstrapMojoConnection(
diff --git a/chromeos/components/cdm_factory_daemon/cdm_factory_daemon_proxy_ash.h b/chromeos/components/cdm_factory_daemon/cdm_factory_daemon_proxy_ash.h index 332d5fc..5c51ce94 100644 --- a/chromeos/components/cdm_factory_daemon/cdm_factory_daemon_proxy_ash.h +++ b/chromeos/components/cdm_factory_daemon/cdm_factory_daemon_proxy_ash.h
@@ -67,6 +67,11 @@ GetAndroidHwKeyDataCallback callback) override; void AllocateSecureBuffer(uint32_t size, AllocateSecureBufferCallback callback) override; + void ParseEncryptedSliceHeader( + uint64_t secure_handle, + uint32_t offset, + const std::vector<uint8_t>& stream_data, + ParseEncryptedSliceHeaderCallback callback) override; private: void EstablishDaemonConnection(base::OnceClosure callback); @@ -78,6 +83,11 @@ GetAndroidHwKeyDataCallback callback); void ProxyAllocateSecureBuffer(uint32_t size, AllocateSecureBufferCallback callback); + void ProxyParseEncryptedSliceHeader( + uint64_t secure_handle, + uint32_t offset, + const std::vector<uint8_t>& stream_data, + ParseEncryptedSliceHeaderCallback callback); void SendDBusRequest(base::ScopedFD fd, base::OnceClosure callback); void OnBootstrapMojoConnection(base::OnceClosure callback, bool result); void CompleteOemCryptoConnection(
diff --git a/chromeos/components/cdm_factory_daemon/cdm_factory_daemon_proxy_lacros.cc b/chromeos/components/cdm_factory_daemon/cdm_factory_daemon_proxy_lacros.cc index f8c209b..3f5f0928 100644 --- a/chromeos/components/cdm_factory_daemon/cdm_factory_daemon_proxy_lacros.cc +++ b/chromeos/components/cdm_factory_daemon/cdm_factory_daemon_proxy_lacros.cc
@@ -98,6 +98,21 @@ } } +void CdmFactoryDaemonProxyLacros::ParseEncryptedSliceHeader( + uint64_t secure_handle, + uint32_t offset, + const std::vector<uint8_t>& stream_data, + ParseEncryptedSliceHeaderCallback callback) { + if (ash_remote_) { + // This should always be bound unless it became disconnected in the middle + // of setting things up. + ash_remote_->ParseEncryptedSliceHeader(secure_handle, offset, stream_data, + std::move(callback)); + } else { + std::move(callback).Run(false, {}); + } +} + void CdmFactoryDaemonProxyLacros::EstablishAshConnection( base::OnceClosure callback) { // This may have happened already.
diff --git a/chromeos/components/cdm_factory_daemon/cdm_factory_daemon_proxy_lacros.h b/chromeos/components/cdm_factory_daemon/cdm_factory_daemon_proxy_lacros.h index 63f060be..568ccaa 100644 --- a/chromeos/components/cdm_factory_daemon/cdm_factory_daemon_proxy_lacros.h +++ b/chromeos/components/cdm_factory_daemon/cdm_factory_daemon_proxy_lacros.h
@@ -44,6 +44,11 @@ GetAndroidHwKeyDataCallback callback) override; void AllocateSecureBuffer(uint32_t size, AllocateSecureBufferCallback callback) override; + void ParseEncryptedSliceHeader( + uint64_t secure_handle, + uint32_t offset, + const std::vector<uint8_t>& stream_data, + ParseEncryptedSliceHeaderCallback callback) override; private: void EstablishAshConnection(base::OnceClosure callback);
diff --git a/chromeos/components/cdm_factory_daemon/chromeos_cdm_context.h b/chromeos/components/cdm_factory_daemon/chromeos_cdm_context.h index a74c8b1..7a10ade3 100644 --- a/chromeos/components/cdm_factory_daemon/chromeos_cdm_context.h +++ b/chromeos/components/cdm_factory_daemon/chromeos_cdm_context.h
@@ -39,6 +39,10 @@ using AllocateSecureBufferCB = base::OnceCallback<void(mojo::PlatformHandle secure_fd)>; + using ParseEncryptedSliceHeaderCB = + base::OnceCallback<void(bool success, + const std::vector<uint8_t>& slice_hdr)>; + // Gets the HW specific key information for the key specified in // |decrypt_config| and returns it via |callback|. virtual void GetHwKeyData(const media::DecryptConfig* decrypt_config, @@ -69,6 +73,16 @@ virtual void AllocateSecureBuffer(uint32_t size, AllocateSecureBufferCB callback) = 0; + // Parses the H264 slice header contained in the secure buffer referenced by + // |secure_handle| at |offset| bytes into the data. The required SPS/PPS data + // is in |stream_data|. The invoked callback will contain the H264 slice + // header details. + virtual void ParseEncryptedSliceHeader( + uint64_t secure_handle, + uint32_t offset, + const std::vector<uint8_t>& stream_data, + ParseEncryptedSliceHeaderCB callback) = 0; + protected: virtual ~ChromeOsCdmContext() = default; };
diff --git a/chromeos/components/cdm_factory_daemon/chromeos_cdm_factory.cc b/chromeos/components/cdm_factory_daemon/chromeos_cdm_factory.cc index d3ed2acf..ea91870 100644 --- a/chromeos/components/cdm_factory_daemon/chromeos_cdm_factory.cc +++ b/chromeos/components/cdm_factory_daemon/chromeos_cdm_factory.cc
@@ -145,6 +145,14 @@ AllocateSecureBufferCB callback) override { ChromeOsCdmFactory::AllocateSecureBuffer(size, std::move(callback)); } + void ParseEncryptedSliceHeader( + uint64_t secure_handle, + uint32_t offset, + const std::vector<uint8_t>& stream_data, + ParseEncryptedSliceHeaderCB callback) override { + ChromeOsCdmFactory::ParseEncryptedSliceHeader( + secure_handle, offset, stream_data, std::move(callback)); + } // media::CdmContext implementation. ChromeOsCdmContext* GetChromeOsCdmContext() override { return this; } @@ -234,6 +242,24 @@ GetBrowserCdmFactoryRemote()->AllocateSecureBuffer(size, std::move(callback)); } +// static +void ChromeOsCdmFactory::ParseEncryptedSliceHeader( + uint64_t secure_handle, + uint32_t offset, + const std::vector<uint8_t>& stream_data, + ChromeOsCdmContext::ParseEncryptedSliceHeaderCB callback) { + if (!GetFactoryTaskRunner()->RunsTasksInCurrentSequence()) { + GetFactoryTaskRunner()->PostTask( + FROM_HERE, + base::BindOnce(&ChromeOsCdmFactory::ParseEncryptedSliceHeader, + secure_handle, offset, stream_data, + std::move(callback))); + return; + } + GetBrowserCdmFactoryRemote()->ParseEncryptedSliceHeader( + secure_handle, offset, stream_data, std::move(callback)); +} + #if BUILDFLAG(IS_CHROMEOS_ASH) // static void ChromeOsCdmFactory::SetBrowserCdmFactoryRemote(
diff --git a/chromeos/components/cdm_factory_daemon/chromeos_cdm_factory.h b/chromeos/components/cdm_factory_daemon/chromeos_cdm_factory.h index 0ae6e90cd..165bdcaf 100644 --- a/chromeos/components/cdm_factory_daemon/chromeos_cdm_factory.h +++ b/chromeos/components/cdm_factory_daemon/chromeos_cdm_factory.h
@@ -68,6 +68,14 @@ uint32_t size, ChromeOsCdmContext::AllocateSecureBufferCB callback); + // Parses H264 slice header data referenced in TrustZone memory by + // |secure_handle|. + static void ParseEncryptedSliceHeader( + uint64_t secure_handle, + uint32_t offset, + const std::vector<uint8_t>& stream_data, + ChromeOsCdmContext::ParseEncryptedSliceHeaderCB callback); + #if BUILDFLAG(IS_CHROMEOS_ASH) // Invoked in the OOP Video Decoder utility process to set the Mojo connection // back to the browser process. Normally the GPU process has a Mojo connection
diff --git a/chromeos/components/cdm_factory_daemon/content_decryption_module_adapter.cc b/chromeos/components/cdm_factory_daemon/content_decryption_module_adapter.cc index ae9311b..e40d01f 100644 --- a/chromeos/components/cdm_factory_daemon/content_decryption_module_adapter.cc +++ b/chromeos/components/cdm_factory_daemon/content_decryption_module_adapter.cc
@@ -270,6 +270,15 @@ ChromeOsCdmFactory::AllocateSecureBuffer(size, std::move(callback)); } +void ContentDecryptionModuleAdapter::ParseEncryptedSliceHeader( + uint64_t secure_handle, + uint32_t offset, + const std::vector<uint8_t>& stream_data, + ParseEncryptedSliceHeaderCB callback) { + ChromeOsCdmFactory::ParseEncryptedSliceHeader( + secure_handle, offset, stream_data, std::move(callback)); +} + void ContentDecryptionModuleAdapter::OnSessionMessage( const std::string& session_id, media::CdmMessageType message_type,
diff --git a/chromeos/components/cdm_factory_daemon/content_decryption_module_adapter.h b/chromeos/components/cdm_factory_daemon/content_decryption_module_adapter.h index 56e10006..4417d05 100644 --- a/chromeos/components/cdm_factory_daemon/content_decryption_module_adapter.h +++ b/chromeos/components/cdm_factory_daemon/content_decryption_module_adapter.h
@@ -112,6 +112,10 @@ bool IsRemoteCdm() const override; void AllocateSecureBuffer(uint32_t size, AllocateSecureBufferCB callback) override; + void ParseEncryptedSliceHeader(uint64_t secure_handle, + uint32_t offset, + const std::vector<uint8_t>& stream_data, + ParseEncryptedSliceHeaderCB callback) override; // cdm::mojom::ContentDecryptionModuleClient: void OnSessionMessage(const std::string& session_id,
diff --git a/chromeos/components/cdm_factory_daemon/mojom/browser_cdm_factory.mojom b/chromeos/components/cdm_factory_daemon/mojom/browser_cdm_factory.mojom index b848597e2..5e19a38 100644 --- a/chromeos/components/cdm_factory_daemon/mojom/browser_cdm_factory.mojom +++ b/chromeos/components/cdm_factory_daemon/mojom/browser_cdm_factory.mojom
@@ -7,7 +7,7 @@ // browser process for creating a CDM factory that will utilizes native HW // backed DRM protection for ChromeOS. -// Next MinVersion: 3 +// Next MinVersion: 4 module chromeos.cdm.mojom; @@ -17,11 +17,14 @@ import "sandbox/policy/mojom/sandbox.mojom"; import "ui/gfx/geometry/mojom/geometry.mojom"; -// Next Method ID: 6 +// Next Method ID: 7 // Used for the connection between browser (receiver) and GPU (remote) process; // or between the ash (receiver) and lacros (remote) browser processes; or // between the GPU (receiver) and OOP video decoder (remote) processes as a // proxy back to the browser. +// TODO(jkardatzke): Replace all of the calls that proxy to the CdmFactoryDaemon +// interface with another Mojo interface that we acquire directly from the +// CdmFactoryDaemon to avoid having all these proxied calls. [Stable, Uuid="7b6bba3b-5ff8-42c7-a802-40a848945b16", ServiceSandbox=sandbox.mojom.Sandbox.kGpu] interface BrowserCdmFactory { @@ -29,6 +32,8 @@ // interface. |key_system| should specify what key system we are using, // currently only com.widevine.alpha is supported. Returns null if we can't // get the interface from the daemon. + // NOTE: This will proxy to the CdmFactoryDaemon interface which is + // implemented by the cdm-oemcrypto daemon in ChromeOS. CreateFactory@0(string key_system) => (pending_remote<CdmFactory>? factory); // Creates a new OutputProtection interface to be used for passing into the @@ -38,6 +43,8 @@ // Returns binary configuration data used for setting up HW decrypt+decode. If // successful, |success| will be true and |config_data| will be valid. // Otherwise |success| will be false and |config_data| should not be used. + // NOTE: This will proxy to the CdmFactoryDaemon interface which is + // implemented by the cdm-oemcrypto daemon in ChromeOS. GetHwConfigData@2() => (bool success, array<uint8> config_data); // Returns an array of the screen resolutions of all the connected displays. @@ -47,6 +54,8 @@ // playback. This mirrors the ContentDecryptionModule::GetHwKeyData call as // they serve the same purpose (Chrome will invoke this one for Android // playback and ContentDecryptionModule::GetHwKeyData for Chrome playback). + // NOTE: This will proxy to the CdmFactoryDaemon interface which is + // implemented by the cdm-oemcrypto daemon in ChromeOS. [MinVersion=1] GetAndroidHwKeyData@4(array<uint8> key_id, array<uint8> hw_identifier) => (DecryptStatus status, array<uint8> key_data); @@ -56,6 +65,22 @@ // secure handle through V4L2; the resulting secure handle can then be used // for the target of decryption. If the allocation fails, a null handle is // returned. + // NOTE: This will proxy to the CdmFactoryDaemon interface which is + // implemented by the cdm-oemcrypto daemon in ChromeOS. [MinVersion=2] AllocateSecureBuffer@5(uint32 size) => (handle<platform>? fd); + + // Parses the data in the secure buffer referenced by |secure_handle| at + // |offset| bytes into it as an H264 slice header. |stream_data| should + // contain the required SPS/PPS structure defined in Chrome and the Trusted + // Application. Returns a bool for success/fail and on success the array will + // be populated with the slice header structure. + // NOTE: This will proxy to the CdmFactoryDaemon interface which is + // implemented by the cdm-oemcrypto daemon in ChromeOS. We do not establish + // the structures in Mojo because we are not using Mojo in the end-to-end + // communication. + [MinVersion=3] + ParseEncryptedSliceHeader@6(uint64 secure_handle, uint32 offset, + array<uint8> stream_data) => + (bool success, array<uint8> slice_header); };
diff --git a/chromeos/components/cdm_factory_daemon/mojom/cdm_factory_daemon.mojom b/chromeos/components/cdm_factory_daemon/mojom/cdm_factory_daemon.mojom index 2ea2dc3d..cef17c4 100644 --- a/chromeos/components/cdm_factory_daemon/mojom/cdm_factory_daemon.mojom +++ b/chromeos/components/cdm_factory_daemon/mojom/cdm_factory_daemon.mojom
@@ -9,7 +9,7 @@ // interface can also be used to connect directly to the OEMCrypto // implementation for ARC. -// Next MinVersion: 8 +// Next MinVersion: 9 module chromeos.cdm.mojom; @@ -44,7 +44,7 @@ pending_associated_receiver<ContentDecryptionModule> cdm); }; -// Next Method ID: 9 +// Next Method ID: 10 // Used for bootstrapping the connection between ash-chrome browser and the // cdm-oemcrypto ChromeOS daemon, then methods can be invoked to obtain // interfaces to perform CDM or OEMCrypto operations. For the OEMCrypto @@ -105,4 +105,16 @@ // returned. [MinVersion=7] AllocateSecureBuffer@8(uint32 size) => (handle<platform>? fd); + + // Parses the data in the secure buffer referenced by |secure_handle| at + // |offset| bytes into it as an H264 slice header. |stream_data| should + // contain the required SPS/PPS structure defined in Chrome and the TA. + // Returns a bool for success/fail and on success the array will be populated + // with the slice header structure. + // NOTE: We do not establish the structures in Mojo because we are not using + // Mojo in the end-to-end communication. + [MinVersion=8] + ParseEncryptedSliceHeader@9(uint64 secure_handle, uint32 offset, + array<uint8> stream_data) => + (bool success, array<uint8> slice_header); };
diff --git a/chromeos/components/cdm_factory_daemon/remote_cdm_context.cc b/chromeos/components/cdm_factory_daemon/remote_cdm_context.cc index d832f626..e39de2f 100644 --- a/chromeos/components/cdm_factory_daemon/remote_cdm_context.cc +++ b/chromeos/components/cdm_factory_daemon/remote_cdm_context.cc
@@ -142,6 +142,15 @@ size, std::move(callback)); } +void RemoteCdmContext::ParseEncryptedSliceHeader( + uint64_t secure_handle, + uint32_t offset, + const std::vector<uint8_t>& stream_data, + ParseEncryptedSliceHeaderCB callback) { + mojo_sequence_state_->GetStableCdmContext()->ParseEncryptedSliceHeader( + secure_handle, offset, stream_data, std::move(callback)); +} + std::unique_ptr<media::CdmContextRef> RemoteCdmContext::GetCdmContextRef() { return std::make_unique<RemoteCdmContextRef>(base::WrapRefCounted(this)); }
diff --git a/chromeos/components/cdm_factory_daemon/remote_cdm_context.h b/chromeos/components/cdm_factory_daemon/remote_cdm_context.h index 96200cd..cf425443 100644 --- a/chromeos/components/cdm_factory_daemon/remote_cdm_context.h +++ b/chromeos/components/cdm_factory_daemon/remote_cdm_context.h
@@ -58,6 +58,10 @@ bool IsRemoteCdm() const override; void AllocateSecureBuffer(uint32_t size, AllocateSecureBufferCB callback) override; + void ParseEncryptedSliceHeader(uint64_t secure_handle, + uint32_t offset, + const std::vector<uint8_t>& stream_data, + ParseEncryptedSliceHeaderCB callback) override; private: friend class base::RefCountedThreadSafe<RemoteCdmContext>;
diff --git a/chromeos/components/cdm_factory_daemon/stable_cdm_context_impl.cc b/chromeos/components/cdm_factory_daemon/stable_cdm_context_impl.cc index 8ca11ebd..440f970 100644 --- a/chromeos/components/cdm_factory_daemon/stable_cdm_context_impl.cc +++ b/chromeos/components/cdm_factory_daemon/stable_cdm_context_impl.cc
@@ -72,6 +72,16 @@ size, std::move(callback)); } +void StableCdmContextImpl::ParseEncryptedSliceHeader( + uint64_t secure_handle, + uint32_t offset, + const std::vector<uint8_t>& stream_data, + ParseEncryptedSliceHeaderCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + cdm_context_->GetChromeOsCdmContext()->ParseEncryptedSliceHeader( + secure_handle, offset, stream_data, std::move(callback)); +} + void StableCdmContextImpl::CdmEventCallback(media::CdmContext::Event event) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); for (auto& cb : remote_event_callbacks_)
diff --git a/chromeos/components/cdm_factory_daemon/stable_cdm_context_impl.h b/chromeos/components/cdm_factory_daemon/stable_cdm_context_impl.h index ba402aa..9c049a4 100644 --- a/chromeos/components/cdm_factory_daemon/stable_cdm_context_impl.h +++ b/chromeos/components/cdm_factory_daemon/stable_cdm_context_impl.h
@@ -46,6 +46,11 @@ void GetScreenResolutions(GetScreenResolutionsCallback callback) override; void AllocateSecureBuffer(uint32_t size, AllocateSecureBufferCallback callback) override; + void ParseEncryptedSliceHeader( + uint64_t secure_handle, + uint32_t offset, + const std::vector<uint8_t>& stream_data, + ParseEncryptedSliceHeaderCallback callback) override; private: // Receives callbacks from the |cdm_context_| after we register with it.
diff --git a/chromeos/components/mahi/public/cpp/mahi_manager.h b/chromeos/components/mahi/public/cpp/mahi_manager.h index 2c3d7622..30a46eda 100644 --- a/chromeos/components/mahi/public/cpp/mahi_manager.h +++ b/chromeos/components/mahi/public/cpp/mahi_manager.h
@@ -5,6 +5,8 @@ #ifndef CHROMEOS_COMPONENTS_MAHI_PUBLIC_CPP_MAHI_MANAGER_H_ #define CHROMEOS_COMPONENTS_MAHI_PUBLIC_CPP_MAHI_MANAGER_H_ +#include <stdint.h> + #include "base/component_export.h" namespace chromeos { @@ -17,6 +19,9 @@ static MahiManager* Get(); + // Opens the Mahi Panel in the display with `display_id`. + virtual void OpenMahiPanel(int64_t display_id) = 0; + protected: MahiManager(); virtual ~MahiManager();
diff --git a/clank b/clank index c473ec5..6f4ebe6 160000 --- a/clank +++ b/clank
@@ -1 +1 @@ -Subproject commit c473ec58befafb3e6bb8d9d4f5450d5bc7816402 +Subproject commit 6f4ebe62d8f81240abcd44282b03ab25f7314bb2
diff --git a/components/commerce/core/internals/BUILD.gn b/components/commerce/core/internals/BUILD.gn index 48cc960..63bdc31 100644 --- a/components/commerce/core/internals/BUILD.gn +++ b/components/commerce/core/internals/BUILD.gn
@@ -15,7 +15,11 @@ "../:pref_names", "../:shopping_service", "//base", + "//components/bookmarks/browser:browser", + "//components/payments/core:core", + "//components/power_bookmarks/core:core", "//components/prefs", + "//components/url_formatter:url_formatter", "//mojo/public/cpp/bindings", "//ui/base", "//url",
diff --git a/components/commerce/core/internals/commerce_internals_handler.cc b/components/commerce/core/internals/commerce_internals_handler.cc index b637e897..35ca06cf 100644 --- a/components/commerce/core/internals/commerce_internals_handler.cc +++ b/components/commerce/core/internals/commerce_internals_handler.cc
@@ -5,11 +5,96 @@ #include "components/commerce/core/internals/commerce_internals_handler.h" #include "base/check_is_test.h" +#include "base/functional/bind.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/utf_string_conversions.h" +#include "components/bookmarks/browser/bookmark_model.h" +#include "components/commerce/core/commerce_constants.h" #include "components/commerce/core/commerce_feature_list.h" +#include "components/commerce/core/mojom/shopping_list.mojom.h" #include "components/commerce/core/pref_names.h" +#include "components/commerce/core/price_tracking_utils.h" #include "components/commerce/core/shopping_service.h" #include "components/commerce/core/webui/webui_utils.h" +#include "components/payments/core/currency_formatter.h" +#include "components/power_bookmarks/core/power_bookmark_utils.h" +#include "components/power_bookmarks/core/proto/power_bookmark_meta.pb.h" #include "components/prefs/pref_service.h" +#include "components/url_formatter/elide_url.h" + +namespace { + +shopping_list::mojom::BookmarkProductInfoPtr GetBookmarkProductInfo( + const bookmarks::BookmarkNode* bookmark, + power_bookmarks::PowerBookmarkMeta* meta, + const std::string& locale_on_startup) { + const power_bookmarks::ShoppingSpecifics& specifics = + meta->shopping_specifics(); + auto bookmark_info = shopping_list::mojom::BookmarkProductInfo::New(); + bookmark_info->bookmark_id = bookmark->id(); + bookmark_info->info = shopping_list::mojom::ProductInfo::New(); + bookmark_info->info->title = specifics.title(); + bookmark_info->info->product_url = bookmark->url(); + bookmark_info->info->domain = base::UTF16ToUTF8( + url_formatter::FormatUrlForDisplayOmitSchemePathAndTrivialSubdomains( + GURL(bookmark->url()))); + bookmark_info->info->image_url = GURL(meta->lead_image().url()); + bookmark_info->info->cluster_id = specifics.product_cluster_id(); + const power_bookmarks::ProductPrice price = specifics.current_price(); + + std::unique_ptr<payments::CurrencyFormatter> formatter = + std::make_unique<payments::CurrencyFormatter>(price.currency_code(), + locale_on_startup); + formatter->SetMaxFractionalDigits(2); + + bookmark_info->info->current_price = base::UTF16ToUTF8(formatter->Format( + base::NumberToString(static_cast<float>(price.amount_micros()) / + commerce::kToMicroCurrency))); + if (specifics.has_previous_price() && + specifics.previous_price().amount_micros() > + specifics.current_price().amount_micros()) { + const power_bookmarks::ProductPrice previous_price = + specifics.previous_price(); + bookmark_info->info->previous_price = + base::UTF16ToUTF8(formatter->Format(base::NumberToString( + static_cast<float>(previous_price.amount_micros()) / + commerce::kToMicroCurrency))); + } + return bookmark_info; +} + +std::vector<commerce::mojom::SubscriptionPtr> GetSubscriptionsMojom( + bookmarks::BookmarkModel* bookmark_model, + const std::string& locale_on_startup, + std::vector<commerce::CommerceSubscription> subscriptions) { + std::vector<commerce::mojom::SubscriptionPtr> subscription_list; + for (auto sub : subscriptions) { + uint64_t cluster_id; + if (base::StringToUint64(sub.id, &cluster_id)) { + std::vector<const bookmarks::BookmarkNode*> bookmarks = + commerce::GetBookmarksWithClusterId(bookmark_model, cluster_id); + + std::vector<shopping_list::mojom::BookmarkProductInfoPtr> info_list; + for (auto* bookmark : bookmarks) { + std::unique_ptr<power_bookmarks::PowerBookmarkMeta> meta = + power_bookmarks::GetNodePowerBookmarkMeta(bookmark_model, bookmark); + if (!meta || !meta->has_shopping_specifics()) { + continue; + } + info_list.push_back( + GetBookmarkProductInfo(bookmark, meta.get(), locale_on_startup)); + } + commerce::mojom::SubscriptionPtr subscription = + commerce::mojom::Subscription::New(); + subscription->cluster_id = cluster_id; + subscription->product_infos = std::move(info_list); + subscription_list.push_back(std::move(subscription)); + } + } + return subscription_list; +} + +} // namespace namespace commerce { @@ -86,8 +171,9 @@ detail->is_anonymized_url_data_collection_enabled = mojom::EligibleEntry::New( account_checker->IsAnonymizedUrlDataCollectionEnabled(), /*expected_value=*/true); - detail->is_subject_to_parental_controls = mojom::EligibleEntry::New( - account_checker->IsSubjectToParentalControls(), /*expected_value=*/false); + detail->is_subject_to_parental_controls = + mojom::EligibleEntry::New(account_checker->IsSubjectToParentalControls(), + /*expected_value=*/false); std::move(callback).Run(std::move(detail)); } @@ -124,4 +210,21 @@ std::move(callback), shopping_service_->AsWeakPtr())); } +void CommerceInternalsHandler::GetSubscriptionDetails( + GetSubscriptionDetailsCallback callback) { + shopping_service_->GetAllSubscriptions( + SubscriptionType::kPriceTrack, + base::BindOnce( + [](GetSubscriptionDetailsCallback callback, + bookmarks::BookmarkModel* bookmark_model, + const std::string& locale_on_startup, + std::vector<CommerceSubscription> subscriptions) { + std::move(callback).Run(GetSubscriptionsMojom( + bookmark_model, locale_on_startup, subscriptions)); + }, + std::move(callback), + std::move(shopping_service_->GetBookmarkModelUsedForSync()), + shopping_service_->locale_on_startup_)); +} + } // namespace commerce
diff --git a/components/commerce/core/internals/commerce_internals_handler.h b/components/commerce/core/internals/commerce_internals_handler.h index b15e94d..ae675dd5 100644 --- a/components/commerce/core/internals/commerce_internals_handler.h +++ b/components/commerce/core/internals/commerce_internals_handler.h
@@ -36,6 +36,7 @@ void ResetPriceTrackingEmailPref() override; void GetProductInfoForUrl(const GURL& url, GetProductInfoForUrlCallback callback) override; + void GetSubscriptionDetails(GetSubscriptionDetailsCallback callback) override; private: mojo::Remote<mojom::CommerceInternalsPage> page_;
diff --git a/components/commerce/core/internals/mojom/commerce_internals.mojom b/components/commerce/core/internals/mojom/commerce_internals.mojom index cac3eef5..d6d79a8a 100644 --- a/components/commerce/core/internals/mojom/commerce_internals.mojom +++ b/components/commerce/core/internals/mojom/commerce_internals.mojom
@@ -4,8 +4,8 @@ module commerce.mojom; -import "url/mojom/url.mojom"; import "components/commerce/core/mojom/shopping_list.mojom"; +import "url/mojom/url.mojom"; // This contains the current state and the expected state of a feature. struct EligibleEntry { @@ -36,6 +36,11 @@ pending_receiver<CommerceInternalsHandler> handler); }; +struct Subscription { + int64 cluster_id; + array<shopping_list.mojom.BookmarkProductInfo> product_infos; +}; + // Browser-side handler for requests from WebUI page. interface CommerceInternalsHandler { // Returns whether the user is eligible to use the shopping list feature. @@ -49,6 +54,9 @@ // Returns the product info for the provided URL if it exists. GetProductInfoForUrl(url.mojom.Url url) => (shopping_list.mojom.ProductInfo info); + // Returns the products the user has subscribed to. + GetSubscriptionDetails() => + (array<Subscription> subscriptions); }; // WebUI-side handler for requests from the browser.
diff --git a/components/commerce/core/internals/resources/commerce_internals.css b/components/commerce/core/internals/resources/commerce_internals.css index 8e4c20c..2bd5c92 100644 --- a/components/commerce/core/internals/resources/commerce_internals.css +++ b/components/commerce/core/internals/resources/commerce_internals.css
@@ -10,4 +10,8 @@ .ineligible { color: red; font-weight: bold; -} \ No newline at end of file +} + +.error-row { + color: 'FF7F7F'; +}
diff --git a/components/commerce/core/internals/resources/commerce_internals.html b/components/commerce/core/internals/resources/commerce_internals.html index a368a47..fdb6c4e0 100644 --- a/components/commerce/core/internals/resources/commerce_internals.html +++ b/components/commerce/core/internals/resources/commerce_internals.html
@@ -23,6 +23,13 @@ <div>Shopping list eligible?: <span id="shopping-list-eligible"></span> <button id="shopping-list-eligible-see-details-btn">See details</button></div> <div id="shopping-list-eligible-details"></div> + <div> + <!-- TODO(b/312262758 Migrate to Polymer/WebUI --> + <!-- TODO(b/312262758) Move subscriptions to their own page. --> + <h2>Subscriptions</h2> + <ul id="subscriptions"></ul> + </div> + <h2>Utilities:</h2> <button id="reset-price-tracking-email-pref-button">Reset price tracking email preference</button> </body>
diff --git a/components/commerce/core/internals/resources/commerce_internals.ts b/components/commerce/core/internals/resources/commerce_internals.ts index c8a434d..070b5333 100644 --- a/components/commerce/core/internals/resources/commerce_internals.ts +++ b/components/commerce/core/internals/resources/commerce_internals.ts
@@ -8,6 +8,14 @@ import {EligibleEntry} from './commerce_internals.mojom-webui.js'; import {CommerceInternalsApiProxy} from './commerce_internals_api_proxy.js'; +const SUBSCRIPTION_ROWS = + ['Cluster ID', 'Domain', 'Price', 'Previous Price', 'Product']; +const CLUSTER_ID_COLUMN_IDX = 0; +const DOMAIN_COLUMN_IDX = 1; +const CURRENT_PRICE_COLUMN_IDX = 2; +const PREVIOUS_PRICE_COLUMN_IDX = 3; +const PRODUCT_COLUMN_IDX = 4; + function getProxy(): CommerceInternalsApiProxy { return CommerceInternalsApiProxy.getInstance(); } @@ -76,6 +84,96 @@ getProxy().getIsShoppingListEligible().then(({eligible}) => { updateShoppingListEligibleStatus(eligible); }); + + getProxy().getSubscriptionDetails().then(({subscriptions}) => { + if (!subscriptions || subscriptions.length == 0) { + return; + } + + const subscriptionsElement = document.getElementById('subscriptions'); + if (!subscriptionsElement) { + return; + } + const table = document.createElement('table'); + const thead = document.createElement('thead'); + const tr = document.createElement('tr'); + + for (const colName of SUBSCRIPTION_ROWS) { + const th = document.createElement('th'); + th.innerText = colName; + th.setAttribute('align', 'left'); + tr.appendChild(th); + } + thead.appendChild(tr); + table.appendChild(thead); + + for (let i = 0; i < subscriptions.length; i++) { + const productInfos = subscriptions[i]!.productInfos; + + // Highlight red if there are no bookmarks for the subscription. + const row = createRow(); + if (productInfos.length == 0) { + row.classList.add('error-row'); + row.setAttribute('bgcolor', 'FF7F7F'); + const columns = row.getElementsByTagName('td'); + columns[CLUSTER_ID_COLUMN_IDX]!.textContent = + BigInt(subscriptions[i]!.clusterId).toString(); + table.appendChild(row); + continue; + } + + for (let j = 0; j < productInfos.length; j++) { + const columns = row.getElementsByTagName('td'); + columns[CLUSTER_ID_COLUMN_IDX]!.textContent = + BigInt(productInfos[j]!.info!.clusterId!).toString(); + columns[DOMAIN_COLUMN_IDX]!.textContent = productInfos[j]!.info.domain!; + columns[CURRENT_PRICE_COLUMN_IDX]!.textContent = + productInfos[j]!.info.currentPrice!; + columns[PREVIOUS_PRICE_COLUMN_IDX]!.textContent = + productInfos[j]!.info.previousPrice!; + + const url = productInfos[j]!.info.productUrl.url; + const productCell = columns[PRODUCT_COLUMN_IDX]!; + if (url == undefined) { + productCell.textContent = productInfos[j]!.info.title!; + } else { + const a = document.createElement('a'); + a.textContent = productInfos[j]!.info.title!; + a.setAttribute('href', url); + productCell.appendChild(a); + } + const imageUrl = productInfos[j]?.info.imageUrl; + if (imageUrl != undefined) { + const space = document.createElement('span'); + space.textContent = ' '; + productCell.appendChild(space); + const imgLink = document.createElement('a'); + imgLink.textContent = '(image)'; + imgLink.setAttribute('href', imageUrl.url); + productCell.appendChild(imgLink); + } + + row.appendChild(productCell); + table.appendChild(row); + subscriptionsElement.appendChild(table); + } + } + }); +} + +function createRow() { + const clusterIdCell = document.createElement('td'); + const domainCell = document.createElement('td'); + const currentPriceCell = document.createElement('td'); + const previousPriceCell = document.createElement('td'); + const productCell = document.createElement('td'); + const row = document.createElement('tr'); + for (const cell + of [clusterIdCell, domainCell, currentPriceCell, previousPriceCell, + productCell]) { + row.appendChild(cell); + } + return row; } function updateShoppingListEligibleStatus(eligible: boolean) {
diff --git a/components/commerce/core/internals/resources/commerce_internals_api_proxy.ts b/components/commerce/core/internals/resources/commerce_internals_api_proxy.ts index 79ba9bd..b757bbd 100644 --- a/components/commerce/core/internals/resources/commerce_internals_api_proxy.ts +++ b/components/commerce/core/internals/resources/commerce_internals_api_proxy.ts
@@ -4,7 +4,7 @@ import {Url} from 'chrome://resources/mojo/url/mojom/url.mojom-webui.js'; -import {CommerceInternalsHandlerFactory, CommerceInternalsHandlerRemote, CommerceInternalsPageCallbackRouter, ShoppingListEligibleDetail} from './commerce_internals.mojom-webui.js'; +import {CommerceInternalsHandlerFactory, CommerceInternalsHandlerRemote, CommerceInternalsPageCallbackRouter, ShoppingListEligibleDetail, Subscription} from './commerce_internals.mojom-webui.js'; import {ProductInfo} from './shopping_list.mojom-webui.js'; export class CommerceInternalsApiProxy { @@ -45,6 +45,10 @@ getCallbackRouter(): CommerceInternalsPageCallbackRouter { return this.callbackRouter; } + + getSubscriptionDetails(): Promise<{subscriptions: Subscription[]}> { + return this.handler.getSubscriptionDetails(); + } } let instance: CommerceInternalsApiProxy|null = null;
diff --git a/components/compose_strings.grdp b/components/compose_strings.grdp index 1ff3902..aef4a55 100644 --- a/components/compose_strings.grdp +++ b/components/compose_strings.grdp
@@ -19,17 +19,17 @@ </message> <!-- FRE dialog --> - <message name="IDS_COMPOSE_FRE_TITLE" desc="The title of the Help me write disclaimer dialog." translateable="false"> - Write better and with more confidence anywhere on the web + <message name="IDS_COMPOSE_FRE_TITLE" desc="The title of the Help me write disclaimer dialog."> + Write with more confidence anywhere on the web </message> - <message name="IDS_COMPOSE_FRE_MAIN_TOP" desc="The top main text of the Help me write disclaimer dialog." translateable="false"> - Just start with a few words or enter a first draft to get writing and editing suggestions. + <message name="IDS_COMPOSE_FRE_MAIN_TOP" desc="The top main text of the Help me write disclaimer dialog."> + Just start with a few words or a first draft to get writing suggestions. </message> - <message name="IDS_COMPOSE_FRE_MAIN_MID" desc="The middle main text of the Help me write disclaimer dialog." translateable="false"> - Your text and the content and url of the page you're writing on will be sent to Google, reviewed by humans, and used to improve this feature. Avoid entering personal information (like medical or financial details) or using this tool on sites that contain private or sensitive information. + <message name="IDS_COMPOSE_FRE_MAIN_MID" desc="The middle main text of the Help me write disclaimer dialog."> + Your text and the content and URL of the page you're writing on will be sent to Google, reviewed by humans, and used to improve this feature. Avoid entering personal information (like medical or financial details) or using this tool on sites that contain private or sensitive information. </message> - <message name="IDS_COMPOSE_FRE_LETS_GO_BUTTON" desc="The button to acknowledge the Help me write disclaimer message."> - Let's go + <message name="IDS_COMPOSE_FRE_OK_BUTTON" desc="The button to acknowledge the Help me write disclaimer message."> + OK </message> <!-- MSBB consent dialog --> @@ -131,10 +131,10 @@ <!-- Errors --> <message name="IDS_COMPOSE_ERROR_TOO_SHORT" desc="Error that the input was too short."> - This is too short. Write at least 3 words. + Enter 3 or more words to get writing help </message> <message name="IDS_COMPOSE_ERROR_TOO_LONG" desc="Error that the input was too long."> - This is too long. Shorten and try again. + Shorten your text to get writing help </message> <message name="IDS_COMPOSE_ERROR_TRY_AGAIN" desc="Error indicating that the request should be tried again."> Something went wrong. Try again. @@ -146,7 +146,7 @@ Your request wasn't understood. Try a different request. </message> <message name="IDS_COMPOSE_ERROR_PERMISSION_DENIED" desc="Error that the request failed by denied permission."> - Something went wrong. Are you signed in? + Sign in again, then come back to this tab to get writing help </message> <message name="IDS_COMPOSE_ERROR_GENERIC" desc="Error without further details."> Something went wrong.
diff --git a/components/compose_strings_grdp/IDS_COMPOSE_ERROR_PERMISSION_DENIED.png.sha1 b/components/compose_strings_grdp/IDS_COMPOSE_ERROR_PERMISSION_DENIED.png.sha1 index ee52dde30..ba7ef20 100644 --- a/components/compose_strings_grdp/IDS_COMPOSE_ERROR_PERMISSION_DENIED.png.sha1 +++ b/components/compose_strings_grdp/IDS_COMPOSE_ERROR_PERMISSION_DENIED.png.sha1
@@ -1 +1 @@ -c2c846b652090c5c700889b7ed1b3cf4349831f9 \ No newline at end of file +f3b676171987a0a6316228f3aa19174394b3b65f \ No newline at end of file
diff --git a/components/compose_strings_grdp/IDS_COMPOSE_ERROR_TOO_LONG.png.sha1 b/components/compose_strings_grdp/IDS_COMPOSE_ERROR_TOO_LONG.png.sha1 index 481709d8..539d88d 100644 --- a/components/compose_strings_grdp/IDS_COMPOSE_ERROR_TOO_LONG.png.sha1 +++ b/components/compose_strings_grdp/IDS_COMPOSE_ERROR_TOO_LONG.png.sha1
@@ -1 +1 @@ -248d3e9fc160c5631fe62a34854c54dfb9c75c7b \ No newline at end of file +074bd0fa61632033a247004017f3c9ee00683a33 \ No newline at end of file
diff --git a/components/compose_strings_grdp/IDS_COMPOSE_ERROR_TOO_SHORT.png.sha1 b/components/compose_strings_grdp/IDS_COMPOSE_ERROR_TOO_SHORT.png.sha1 index 9efc058..1ae585f 100644 --- a/components/compose_strings_grdp/IDS_COMPOSE_ERROR_TOO_SHORT.png.sha1 +++ b/components/compose_strings_grdp/IDS_COMPOSE_ERROR_TOO_SHORT.png.sha1
@@ -1 +1 @@ -f5c97997a5d8d1c5838d17763b0a43b239a6e3dc \ No newline at end of file +6826683bbdc57c7da96d6066befdb772cee3f4b3 \ No newline at end of file
diff --git a/components/compose_strings_grdp/IDS_COMPOSE_FRE_LETS_GO_BUTTON.png.sha1 b/components/compose_strings_grdp/IDS_COMPOSE_FRE_LETS_GO_BUTTON.png.sha1 deleted file mode 100644 index 4bbeb3fa..0000000 --- a/components/compose_strings_grdp/IDS_COMPOSE_FRE_LETS_GO_BUTTON.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -cd5338e9d960aa03f3ae6f8deb43455890ca8635 \ No newline at end of file
diff --git a/components/compose_strings_grdp/IDS_COMPOSE_FRE_MAIN_MID.png.sha1 b/components/compose_strings_grdp/IDS_COMPOSE_FRE_MAIN_MID.png.sha1 new file mode 100644 index 0000000..2f8dfd5c --- /dev/null +++ b/components/compose_strings_grdp/IDS_COMPOSE_FRE_MAIN_MID.png.sha1
@@ -0,0 +1 @@ +4abe7242bea0bbb2b53df0c3213bde583f3df6a5 \ No newline at end of file
diff --git a/components/compose_strings_grdp/IDS_COMPOSE_FRE_MAIN_TOP.png.sha1 b/components/compose_strings_grdp/IDS_COMPOSE_FRE_MAIN_TOP.png.sha1 new file mode 100644 index 0000000..2f8dfd5c --- /dev/null +++ b/components/compose_strings_grdp/IDS_COMPOSE_FRE_MAIN_TOP.png.sha1
@@ -0,0 +1 @@ +4abe7242bea0bbb2b53df0c3213bde583f3df6a5 \ No newline at end of file
diff --git a/components/compose_strings_grdp/IDS_COMPOSE_FRE_OK_BUTTON.png.sha1 b/components/compose_strings_grdp/IDS_COMPOSE_FRE_OK_BUTTON.png.sha1 new file mode 100644 index 0000000..2f8dfd5c --- /dev/null +++ b/components/compose_strings_grdp/IDS_COMPOSE_FRE_OK_BUTTON.png.sha1
@@ -0,0 +1 @@ +4abe7242bea0bbb2b53df0c3213bde583f3df6a5 \ No newline at end of file
diff --git a/components/compose_strings_grdp/IDS_COMPOSE_FRE_TITLE.png.sha1 b/components/compose_strings_grdp/IDS_COMPOSE_FRE_TITLE.png.sha1 new file mode 100644 index 0000000..2f8dfd5c --- /dev/null +++ b/components/compose_strings_grdp/IDS_COMPOSE_FRE_TITLE.png.sha1
@@ -0,0 +1 @@ +4abe7242bea0bbb2b53df0c3213bde583f3df6a5 \ No newline at end of file
diff --git a/components/feature_engagement/public/feature_constants.cc b/components/feature_engagement/public/feature_constants.cc index dcba2a4..261760d 100644 --- a/components/feature_engagement/public/feature_constants.cc +++ b/components/feature_engagement/public/feature_constants.cc
@@ -628,7 +628,7 @@ base::FEATURE_DISABLED_BY_DEFAULT); BASE_FEATURE(kIPHLauncherSearchHelpUiFeature, "IPH_LauncherSearchHelpUi", - base::FEATURE_DISABLED_BY_DEFAULT); + base::FEATURE_ENABLED_BY_DEFAULT); BASE_FEATURE(kIPHScalableIphTimerBasedOneFeature, "IPH_ScalableIphTimerBasedOne", base::FEATURE_DISABLED_BY_DEFAULT);
diff --git a/components/guest_view/browser/guest_view_base.cc b/components/guest_view/browser/guest_view_base.cc index 6a9de4f..5aee39a 100644 --- a/components/guest_view/browser/guest_view_base.cc +++ b/components/guest_view/browser/guest_view_base.cc
@@ -875,18 +875,12 @@ } void GuestViewBase::SetOwnerHost() { - const GURL& url = GetOwnerLastCommittedURL(); if (IsOwnedByExtension()) { - owner_host_ = url.host(); + owner_host_ = GetOwnerLastCommittedURL().host(); } else if (IsOwnedByWebUI()) { owner_host_ = std::string(); } else if (IsOwnedByControlledFrameEmbedder()) { - // TODO(cmp): This function must return an empty string currently since - // events that pass a non-empty string are validated and will break - // Controlled Frame. A future CL will modify the validation to support the - // Controlled Frame case and allow us to use the following: - // owner_host_ = url.spec(); - owner_host_ = std::string(); + owner_host_ = owner_rfh()->GetLastCommittedOrigin().Serialize(); } else { owner_host_ = std::string(); }
diff --git a/components/guest_view/browser/guest_view_base.h b/components/guest_view/browser/guest_view_base.h index 852e5b8..217d101a 100644 --- a/components/guest_view/browser/guest_view_base.h +++ b/components/guest_view/browser/guest_view_base.h
@@ -208,8 +208,11 @@ // Returns the URL of the owner RenderFrameHost's SiteInstance. const GURL& GetOwnerSiteURL() const; - // Returns the host of the owner WebContents. For extensions, this is the - // extension ID. + // Returns the host of the owner WebContents. If the owner RenderFrameHost is + // for an extension, returns the host of its URL, which is an extension ID. If + // the owner RenderFrameHost is a non-extension embedder of a Controlled + // Frame, returns its serialized origin. + // TODO(crbug.com/1517391): Expose this information as a url::Origin. std::string owner_host() const { return owner_host_; } // Whether the guest view is inside a plugin document.
diff --git a/components/messages/android/internal/BUILD.gn b/components/messages/android/internal/BUILD.gn index 54062c5..6278848 100644 --- a/components/messages/android/internal/BUILD.gn +++ b/components/messages/android/internal/BUILD.gn
@@ -92,6 +92,7 @@ "..:java", "//base:base_java", "//base:base_java_test_support", + "//base:base_java_test_support_uncommon", "//components/browser_ui/test/android:test_support_java", "//components/browser_ui/widget/android:java", "//content/public/test/android:content_java_test_support",
diff --git a/components/messages/android/internal/java/src/org/chromium/components/messages/MessageAnimationCoordinator.java b/components/messages/android/internal/java/src/org/chromium/components/messages/MessageAnimationCoordinator.java index 72aeb73..8ad6a54 100644 --- a/components/messages/android/internal/java/src/org/chromium/components/messages/MessageAnimationCoordinator.java +++ b/components/messages/android/internal/java/src/org/chromium/components/messages/MessageAnimationCoordinator.java
@@ -46,11 +46,13 @@ private Animator mBackAnimator; private final MessageContainer mContainer; private final Callback<Animator> mAnimatorStartCallback; + private final boolean mAreExtraHistogramsEnabled; public MessageAnimationCoordinator( MessageContainer messageContainer, Callback<Animator> animatorStartCallback) { mContainer = messageContainer; mAnimatorStartCallback = animatorStartCallback; + mAreExtraHistogramsEnabled = MessageFeatureList.areExtraHistogramsEnabled(); } public void updateWithoutStacking( @@ -183,6 +185,10 @@ return; } + if (mAreExtraHistogramsEnabled && currentFront != nextFront && nextFront != null) { + MessagesMetrics.recordRequestToFullyShow(nextFront.handler.getMessageIdentifier()); + } + if (!isSuspended && !mMessageQueueDelegate.isReadyForShowing()) { // Make sure everything is ready for showing a message, unless messages are about to // be removed immediately. By "showing", it does mean not just triggering a showing @@ -193,6 +199,10 @@ if (!mMessageQueueDelegate.isPendingShow()) { mMessageQueueDelegate.onRequestShowing(onFinished); } + if (mAreExtraHistogramsEnabled && currentFront != nextFront && nextFront != null) { + MessagesMetrics.recordBlockedByBrowserControl( + nextFront.handler.getMessageIdentifier()); + } return; } @@ -200,6 +210,10 @@ // message is still waiting its animation to be triggered. Early return to avoid cancelling // that animation accidentally. Second message will be added after its animation is done. if (mContainer.isIsInitializingLayout()) { + if (mAreExtraHistogramsEnabled && currentFront != nextFront && nextFront != null) { + MessagesMetrics.recordBlockedByContainerInitializing( + nextFront.handler.getMessageIdentifier()); + } return; } @@ -342,7 +356,11 @@ if (candidates.get(0) == null) { runnable.run(); } else { - mContainer.runAfterInitialMessageLayout(runnable); + boolean initialized = mContainer.runAfterInitialMessageLayout(runnable); + if (mAreExtraHistogramsEnabled && !initialized) { + MessagesMetrics.recordBlockedByContainerNotInitialized( + candidates.get(0).handler.getMessageIdentifier()); + } } }
diff --git a/components/messages/android/internal/java/src/org/chromium/components/messages/MessageAnimationCoordinatorUnitTest.java b/components/messages/android/internal/java/src/org/chromium/components/messages/MessageAnimationCoordinatorUnitTest.java index 74e3efd5..2be8090 100644 --- a/components/messages/android/internal/java/src/org/chromium/components/messages/MessageAnimationCoordinatorUnitTest.java +++ b/components/messages/android/internal/java/src/org/chromium/components/messages/MessageAnimationCoordinatorUnitTest.java
@@ -39,6 +39,7 @@ import org.robolectric.annotation.LooperMode; import org.chromium.base.Callback; +import org.chromium.base.FeatureList; import org.chromium.base.test.BaseRobolectricTestRunner; import org.chromium.base.test.util.CallbackHelper; import org.chromium.base.test.util.HistogramWatcher; @@ -100,6 +101,10 @@ @Before public void setUp() { + var testValues = new FeatureList.TestValues(); + testValues.addFeatureFlagOverride( + MessageFeatureList.MESSAGES_ANDROID_EXTRA_HISTOGRAMS, true); + FeatureList.setTestValues(testValues); mAnimationCoordinator = new MessageAnimationCoordinator(mContainer, Animator::start); mAnimationCoordinator.setMessageQueueDelegate(mQueueDelegate); when(mContainer.isIsInitializingLayout()).thenReturn(false); @@ -250,6 +255,7 @@ .expectIntRecord( "Android.Messages.Stacking", MessagesMetrics.StackingAnimationType.SHOW_ALL) + .expectIntRecord("Android.Messages.Stacking.RequestToFullyShow", 1) .expectIntRecord("Android.Messages.Stacking.InsertAtFront", 1) .expectIntRecord("Android.Messages.Stacking.Hiding", 1) .expectIntRecord( @@ -284,7 +290,12 @@ MessageState m2 = buildMessageState(); setMessageIdentifier(m2, 2); + var requestToFullyShow = + HistogramWatcher.newSingleRecordWatcher( + "Android.Messages.Stacking.RequestToFullyShow", 1); + mAnimationCoordinator.updateWithStacking(Arrays.asList(m1, m2), false, () -> {}); + requestToFullyShow.assertExpected("M1 is not fully shown."); InOrder inOrder = Mockito.inOrder(m1.handler, m2.handler); inOrder.verify(m1.handler).show(Position.INVISIBLE, Position.FRONT); @@ -295,6 +306,7 @@ .expectIntRecord( "Android.Messages.Stacking", MessagesMetrics.StackingAnimationType.REMOVE_FRONT_AND_SHOW_BACK) + .expectIntRecord("Android.Messages.Stacking.RequestToFullyShow", 2) .expectIntRecord("Android.Messages.Stacking.RemoveFront", 1) .expectIntRecord("Android.Messages.Stacking.PushToFront", 2) .expectNoRecords("Android.Messages.Stacking.Hidden") @@ -320,8 +332,12 @@ setMessageIdentifier(m1, 1); MessageState m2 = buildMessageState(); setMessageIdentifier(m2, 2); + var requestToFullyShow = + HistogramWatcher.newSingleRecordWatcher( + "Android.Messages.Stacking.RequestToFullyShow", 1); mAnimationCoordinator.updateWithStacking(Arrays.asList(m1, m2), false, () -> {}); + requestToFullyShow.assertExpected("M1 is not fully shown"); InOrder inOrder = Mockito.inOrder(m1.handler, m2.handler); inOrder.verify(m1.handler).show(Position.INVISIBLE, Position.FRONT); inOrder.verify(m2.handler).show(Position.FRONT, Position.BACK); @@ -329,6 +345,9 @@ MessageState m3 = buildMessageState(); setMessageIdentifier(m3, 3); + requestToFullyShow = + HistogramWatcher.newSingleRecordWatcher( + "Android.Messages.Stacking.RequestToFullyShow", 2); // Hide the front one so that the back one is brought to front. mAnimationCoordinator.updateWithStacking(Arrays.asList(m2, m3), false, () -> {}); inOrder.verify(m1.handler).hide(Position.FRONT, Position.INVISIBLE, true); @@ -336,6 +355,7 @@ var currentMessages = mAnimationCoordinator.getCurrentDisplayedMessages(); Assert.assertArrayEquals(new MessageState[] {m2, null}, currentMessages.toArray()); + requestToFullyShow.assertExpected("M2 is not fully shown"); var histogramWatcher = HistogramWatcher.newBuilder() @@ -362,8 +382,12 @@ setMessageIdentifier(m1, 1); MessageState m2 = buildMessageState(); setMessageIdentifier(m2, 2); + var requestToFullyShow = + HistogramWatcher.newSingleRecordWatcher( + "Android.Messages.Stacking.RequestToFullyShow", 1); mAnimationCoordinator.updateWithStacking(Arrays.asList(m1, m2), false, () -> {}); + requestToFullyShow.assertExpected("M1 is not fully shown"); InOrder inOrder = Mockito.inOrder(m1.handler, m2.handler); inOrder.verify(m1.handler).show(Position.INVISIBLE, Position.FRONT); inOrder.verify(m2.handler).show(Position.FRONT, Position.BACK); @@ -376,6 +400,8 @@ .expectIntRecord("Android.Messages.Stacking.RemoveBack", 2) .expectNoRecords("Android.Messages.Stacking.Hidden") .expectNoRecords("Android.Messages.Stacking.Hiding") + // do not trigger again as m1 stays in the foreground + .expectNoRecords("Android.Messages.Stacking.RequestToFullyShow") .build(); mAnimationCoordinator.updateWithStacking(Arrays.asList(m1, null), false, () -> {}); inOrder.verify(m1.handler, never()).hide(anyInt(), anyInt(), anyBoolean()); @@ -609,6 +635,7 @@ MessagesMetrics.StackingAnimationType.SHOW_ALL) .expectIntRecord("Android.Messages.Stacking.InsertAtFront", 1) .expectIntRecord("Android.Messages.Stacking.InsertAtBack", 2) + .expectIntRecord("Android.Messages.Stacking.BlockedByBrowserControl", 1) .build(); MessageState m1 = buildMessageState(); setMessageIdentifier(m1, 1); @@ -681,6 +708,11 @@ mAnimationCoordinator.updateWithStacking( Arrays.asList(m1, m2), false, () -> {}); }); + + var blockedByBrowserControl = + HistogramWatcher.newSingleRecordWatcher( + "Android.Messages.Stacking.BlockedByBrowserControl", 1); + // M1 is waiting to be shown. currentMessages = mAnimationCoordinator.getCurrentDisplayedMessages(); Assert.assertArrayEquals(new MessageState[] {null, null}, currentMessages.toArray()); @@ -693,7 +725,16 @@ // Nothing happens, as message queue is not ready yet. currentMessages = mAnimationCoordinator.getCurrentDisplayedMessages(); Assert.assertArrayEquals(new MessageState[] {null, null}, currentMessages.toArray()); + blockedByBrowserControl.assertExpected("Messages should be blocked by browser control."); + var histogramWatcher = + HistogramWatcher.newBuilder() + .expectIntRecord( + "Android.Messages.Stacking", + MessagesMetrics.StackingAnimationType.SHOW_ALL) + .expectIntRecord("Android.Messages.Stacking.InsertAtFront", 1) + .expectIntRecord("Android.Messages.Stacking.InsertAtBack", 2) + .build(); // onStartShowing is finished. Showing two messages at the same time. captor.getValue().run(); @@ -703,11 +744,22 @@ Assert.assertArrayEquals(new MessageState[] {m1, m2}, currentMessages.toArray()); verify(mAnimatorStartCallback).onResult(any()); + histogramWatcher.assertExpected("Stacking histogram not correctly recorded during showing"); + + histogramWatcher = + HistogramWatcher.newBuilder() + .expectIntRecord( + "Android.Messages.Stacking", + MessagesMetrics.StackingAnimationType.REMOVE_ALL) + .expectIntRecord("Android.Messages.Stacking.RemoveFront", 1) + .expectIntRecord("Android.Messages.Stacking.RemoveBack", 2) + .build(); mAnimationCoordinator.updateWithStacking(Arrays.asList(null, null), false, () -> {}); verify(m1.handler).hide(anyInt(), anyInt(), anyBoolean()); verify(m2.handler).hide(anyInt(), anyInt(), anyBoolean()); verify(queueDelegate, times(2)).onAnimationStart(); verify(mAnimatorStartCallback, times(2)).onResult(any()); + histogramWatcher.assertExpected("Stacking histogram not correctly recorded during hiding"); } // Test when suspension cancels a hiding animation. @@ -770,6 +822,11 @@ setMessageIdentifier(m1, 1); MessageState m2 = buildMessageState(); setMessageIdentifier(m2, 2); + doReturn(false).when(mContainer).runAfterInitialMessageLayout(any()); + var histogramWatcher = + HistogramWatcher.newSingleRecordWatcher( + "Android.Messages.Stacking.BlockedByContainerNotInitialized", 1); + mAnimationCoordinator.updateWithStacking(Arrays.asList(m1, null), false, () -> {}); InOrder inOrder = Mockito.inOrder(m1.handler, m2.handler); @@ -785,6 +842,7 @@ var currentMessages = mAnimationCoordinator.getCurrentDisplayedMessages(); Assert.assertArrayEquals(new MessageState[] {m1, null}, currentMessages.toArray()); + histogramWatcher.assertExpected(); } @Test
diff --git a/components/messages/android/internal/java/src/org/chromium/components/messages/MessageDispatcherUnitTest.java b/components/messages/android/internal/java/src/org/chromium/components/messages/MessageDispatcherUnitTest.java index 984e29bd..8ebefd4 100644 --- a/components/messages/android/internal/java/src/org/chromium/components/messages/MessageDispatcherUnitTest.java +++ b/components/messages/android/internal/java/src/org/chromium/components/messages/MessageDispatcherUnitTest.java
@@ -13,9 +13,9 @@ import androidx.test.filters.SmallTest; import org.junit.Assert; -import org.junit.Before; import org.junit.Rule; import org.junit.Test; +import org.junit.rules.TestRule; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Mock; @@ -23,30 +23,26 @@ import org.mockito.junit.MockitoRule; import org.robolectric.annotation.LooperMode; -import org.chromium.base.FeatureList; import org.chromium.base.test.BaseRobolectricTestRunner; +import org.chromium.base.test.util.Features; import org.chromium.ui.modelutil.PropertyModel; -import java.util.HashMap; - /** Unit tests for {@link MessageDispatcherImpl}. */ @SmallTest @RunWith(BaseRobolectricTestRunner.class) @LooperMode(PAUSED) +@Features.EnableFeatures({ + MessageFeatureList.MESSAGES_FOR_ANDROID_STACKING_ANIMATION, + MessageFeatureList.MESSAGES_FOR_ANDROID_FULLY_VISIBLE_CALLBACK, + MessageFeatureList.MESSAGES_ANDROID_EXTRA_HISTOGRAMS +}) public class MessageDispatcherUnitTest { @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule(); + @Rule public TestRule mFeaturesProcessorRule = new Features.JUnitProcessor(); @Mock private MessageQueueManager mQueueManager; @Mock private MessageAnimationCoordinator mAnimationCoordinator; - @Before - public void setUp() { - var map = new HashMap<String, Boolean>(); - map.put(MessageFeatureList.MESSAGES_FOR_ANDROID_FULLY_VISIBLE_CALLBACK, true); - map.put(MessageFeatureList.MESSAGES_FOR_ANDROID_STACKING_ANIMATION, false); - FeatureList.setTestFeatures(map); - } - @Test public void testEnqueueWindowScopedMessage() { doReturn(mAnimationCoordinator).when(mQueueManager).getAnimationCoordinator();
diff --git a/components/messages/android/internal/java/src/org/chromium/components/messages/MessageQueueManager.java b/components/messages/android/internal/java/src/org/chromium/components/messages/MessageQueueManager.java index 19b15ea6..9963252 100644 --- a/components/messages/android/internal/java/src/org/chromium/components/messages/MessageQueueManager.java +++ b/components/messages/android/internal/java/src/org/chromium/components/messages/MessageQueueManager.java
@@ -55,8 +55,11 @@ private ScopeChangeController mScopeChangeController = new ScopeChangeController(this); + private final boolean mAreExtraHistogramsEnabled; + public MessageQueueManager(MessageAnimationCoordinator animationCoordinator) { mAnimationCoordinator = animationCoordinator; + mAreExtraHistogramsEnabled = MessageFeatureList.areExtraHistogramsEnabled(); } /** @@ -83,13 +86,25 @@ mScopeChangeController.firstMessageEnqueued(scopeKey); } + if (mAreExtraHistogramsEnabled) { + MessagesMetrics.recordMessageEnqueuedScopeActive( + message.getMessageIdentifier(), mScopeChangeController.isActive(scopeKey)); + + MessagesMetrics.recordMessageEnqueuedQueueSuspended( + message.getMessageIdentifier(), isQueueSuspended()); + } + MessageState messageState = new MessageState(scopeKey, messageKey, message, highPriority); messageQueue.add(messageState); mMessages.put(messageKey, messageState); MessagesMetrics.recordMessageEnqueued(message.getMessageIdentifier()); + // The candidate which will be fully visible. Null if no message will be displayed. + MessageState primaryCandidate; if (MessageFeatureList.isStackAnimationEnabled()) { - updateCurrentDisplayedWithStacking(); + List<MessageState> candidates = updateCurrentDisplayedWithStacking(); + assert candidates.size() == 2 : "There must be 2 candidates when stacking is enabled."; + primaryCandidate = candidates.get(0); } else { MessageState candidate = updateCurrentDisplayedWithoutStacking(); if (candidate != null) { @@ -99,15 +114,18 @@ candidate.handler.getMessageIdentifier(), candidate.messageKey); } + primaryCandidate = candidate; + } - if (candidate == messageState) { - MessagesMetrics.recordMessageEnqueuedVisible(message.getMessageIdentifier()); - } else { - @MessageIdentifier int visibleMessageId = MessageIdentifier.INVALID_MESSAGE; - if (candidate != null) visibleMessageId = candidate.handler.getMessageIdentifier(); - MessagesMetrics.recordMessageEnqueuedHidden( - message.getMessageIdentifier(), visibleMessageId); + if (primaryCandidate == messageState) { + MessagesMetrics.recordMessageEnqueuedVisible(message.getMessageIdentifier()); + } else if (mAreExtraHistogramsEnabled) { + @MessageIdentifier int visibleMessageId = MessageIdentifier.INVALID_MESSAGE; + if (primaryCandidate != null) { + visibleMessageId = primaryCandidate.handler.getMessageIdentifier(); } + MessagesMetrics.recordMessageEnqueuedHidden( + message.getMessageIdentifier(), visibleMessageId); } }
diff --git a/components/messages/android/internal/java/src/org/chromium/components/messages/MessageQueueManagerTest.java b/components/messages/android/internal/java/src/org/chromium/components/messages/MessageQueueManagerTest.java index d5f1886..bedf9b6 100644 --- a/components/messages/android/internal/java/src/org/chromium/components/messages/MessageQueueManagerTest.java +++ b/components/messages/android/internal/java/src/org/chromium/components/messages/MessageQueueManagerTest.java
@@ -43,8 +43,6 @@ import org.chromium.content_public.browser.test.mock.MockWebContents; import org.chromium.ui.base.WindowAndroid; -import java.util.Map; - /** Unit tests for MessageQueueManager. */ @RunWith(BaseRobolectricTestRunner.class) @Config(manifest = Config.NONE) @@ -92,6 +90,15 @@ }; private class EmptyMessageStateHandler implements MessageStateHandler { + + private int mId = MessageIdentifier.TEST_MESSAGE; + + public EmptyMessageStateHandler(int id) { + mId = id; + } + + public EmptyMessageStateHandler() {} + @Override public Animator show(int fromIndex, int toIndex) { return new AnimatorSet(); @@ -107,7 +114,7 @@ @Override public int getMessageIdentifier() { - return MessageIdentifier.TEST_MESSAGE; + return mId; } } @@ -151,6 +158,8 @@ var testValues = new TestValues(); testValues.addFeatureFlagOverride( MessageFeatureList.MESSAGES_FOR_ANDROID_STACKING_ANIMATION, false); + testValues.addFeatureFlagOverride( + MessageFeatureList.MESSAGES_ANDROID_EXTRA_HISTOGRAMS, true); FeatureList.setTestValues(testValues); MessageContainer container = Mockito.mock(MessageContainer.class); doAnswer( @@ -175,17 +184,25 @@ public void testEnqueueMessage() { MessageQueueManager queueManager = new MessageQueueManager(mAnimationCoordinator); queueManager.setDelegate(mEmptyDelegate); - MessageStateHandler m1 = Mockito.spy(new EmptyMessageStateHandler()); - MessageStateHandler m2 = Mockito.spy(new EmptyMessageStateHandler()); + MessageStateHandler m1 = + Mockito.spy(new EmptyMessageStateHandler(MessageIdentifier.POPUP_BLOCKED)); + MessageStateHandler m2 = + Mockito.spy(new EmptyMessageStateHandler(MessageIdentifier.SYNC_ERROR)); var enqueued = - HistogramWatcher.newSingleRecordWatcher( - "Android.Messages.Enqueued", MessageIdentifier.TEST_MESSAGE); + HistogramWatcher.newBuilder() + .expectIntRecord("Android.Messages.Enqueued", m1.getMessageIdentifier()) + .expectIntRecord( + "Android.Messages.Enqueued.Visible", m1.getMessageIdentifier()) + .expectNoRecords("Android.Messages.Enqueued.Hiding") + .expectNoRecords("Android.Messages.Enqueued.Hidden") + .build(); var dismissed = HistogramWatcher.newSingleRecordWatcher( - "Android.Messages.Dismissed.TestMessage", DismissReason.TIMER); + "Android.Messages.Dismissed.PopupBlocked", DismissReason.TIMER); queueManager.enqueueMessage(m1, m1, SCOPE_INSTANCE_ID, false); enqueued.assertExpected(); + verify(m1).show(eq(Position.INVISIBLE), eq(Position.FRONT)); queueManager.dismissMessage(m1, DismissReason.TIMER); verify(m1).hide(eq(Position.FRONT), eq(Position.INVISIBLE), anyBoolean()); @@ -194,10 +211,10 @@ enqueued = HistogramWatcher.newSingleRecordWatcher( - "Android.Messages.Enqueued", MessageIdentifier.TEST_MESSAGE); + "Android.Messages.Enqueued", m2.getMessageIdentifier()); dismissed = HistogramWatcher.newSingleRecordWatcher( - "Android.Messages.Dismissed.TestMessage", DismissReason.TIMER); + "Android.Messages.Dismissed.SyncError", DismissReason.TIMER); queueManager.enqueueMessage(m2, m2, SCOPE_INSTANCE_ID, false); enqueued.assertExpected(); verify(m2).show(eq(Position.INVISIBLE), eq(Position.FRONT)); @@ -214,11 +231,194 @@ @Test @SmallTest public void testEnqueueMessage_withStacking() { - FeatureList.setTestFeatures( - Map.of(MessageFeatureList.MESSAGES_FOR_ANDROID_STACKING_ANIMATION, true)); + var testValues = new TestValues(); + testValues.addFeatureFlagOverride( + MessageFeatureList.MESSAGES_FOR_ANDROID_STACKING_ANIMATION, true); + testValues.addFeatureFlagOverride( + MessageFeatureList.MESSAGES_ANDROID_EXTRA_HISTOGRAMS, true); + FeatureList.setTestValues(testValues); testEnqueueMessage(); } + /** + * Tests lifecycle of a single message: - enqueueMessage() calls show() - dismissMessage() calls + * hide() and dismiss() when a queue is enqueued with multiple messages + */ + @Test + @SmallTest + public void testEnqueueMultipleMessages() { + testEnqueueMultipleMessagesInternal(false); + } + + @Test + @SmallTest + public void testEnqueueMultipleMessages_withStacking() { + testEnqueueMultipleMessagesInternal(true); + } + + // TODO(crbug.com/1517771): replace with ParameterizedRunner or remove non-stacking animation + // test case + private void testEnqueueMultipleMessagesInternal(boolean isStackingEnabled) { + var testValues = new TestValues(); + testValues.addFeatureFlagOverride( + MessageFeatureList.MESSAGES_FOR_ANDROID_STACKING_ANIMATION, isStackingEnabled); + testValues.addFeatureFlagOverride( + MessageFeatureList.MESSAGES_ANDROID_EXTRA_HISTOGRAMS, true); + FeatureList.setTestValues(testValues); + MessageQueueManager queueManager = new MessageQueueManager(mAnimationCoordinator); + queueManager.setDelegate(mEmptyDelegate); + MessageStateHandler m1 = + Mockito.spy(new EmptyMessageStateHandler(MessageIdentifier.POPUP_BLOCKED)); + MessageStateHandler m2 = + Mockito.spy(new EmptyMessageStateHandler(MessageIdentifier.SYNC_ERROR)); + + var enqueued = + HistogramWatcher.newBuilder() + .expectIntRecords( + "Android.Messages.Enqueued", + m1.getMessageIdentifier(), + m2.getMessageIdentifier()) + .expectIntRecord( + "Android.Messages.Enqueued.Visible", m1.getMessageIdentifier()) + .expectIntRecord( + "Android.Messages.Enqueued.Hiding", m1.getMessageIdentifier()) + .expectIntRecord( + "Android.Messages.Enqueued.Hidden", m2.getMessageIdentifier()) + .build(); + var dismissed = + HistogramWatcher.newSingleRecordWatcher( + "Android.Messages.Dismissed.PopupBlocked", DismissReason.TIMER); + queueManager.enqueueMessage(m1, m1, SCOPE_INSTANCE_ID, false); + queueManager.enqueueMessage(m2, m2, SCOPE_INSTANCE_ID, false); + enqueued.assertExpected(); + + verify(m1).show(eq(Position.INVISIBLE), eq(Position.FRONT)); + queueManager.dismissMessage(m1, DismissReason.TIMER); + verify(m1).hide(eq(Position.FRONT), eq(Position.INVISIBLE), anyBoolean()); + verify(m1).dismiss(DismissReason.TIMER); + dismissed.assertExpected(); + + dismissed = + HistogramWatcher.newSingleRecordWatcher( + "Android.Messages.Dismissed.SyncError", DismissReason.TIMER); + enqueued.assertExpected(); + if (isStackingEnabled) { + verify(m2).show(eq(Position.BACK), eq(Position.FRONT)); + } else { + verify(m2).show(eq(Position.INVISIBLE), eq(Position.FRONT)); + } + queueManager.dismissMessage(m2, DismissReason.TIMER); + dismissed.assertExpected(); + verify(m2).hide(eq(Position.FRONT), eq(Position.INVISIBLE), anyBoolean()); + verify(m2).dismiss(DismissReason.TIMER); + } + + /** Histograms are recorded with whether queue is suspended. */ + @Test + @SmallTest + public void testEnqueueWithQueueSuspension() { + MessageQueueManager queueManager = new MessageQueueManager(mAnimationCoordinator); + queueManager.setDelegate(mEmptyDelegate); + int token = queueManager.suspend(); + + MessageStateHandler m1 = + Mockito.spy(new EmptyMessageStateHandler(MessageIdentifier.POPUP_BLOCKED)); + MessageStateHandler m2 = + Mockito.spy(new EmptyMessageStateHandler(MessageIdentifier.SYNC_ERROR)); + + var enqueued = + HistogramWatcher.newBuilder() + .expectIntRecords( + "Android.Messages.Enqueued", + m1.getMessageIdentifier(), + m2.getMessageIdentifier()) + .expectIntRecords( + "Android.Messages.Enqueued.Suspended", + m1.getMessageIdentifier(), + m2.getMessageIdentifier()) + .expectNoRecords("Android.Messages.Enqueued.Resumed") + .build(); + + queueManager.enqueueMessage(m1, m1, SCOPE_INSTANCE_ID, false); + queueManager.enqueueMessage(m2, m2, SCOPE_INSTANCE_ID, false); + enqueued.assertExpected(); + + MessageStateHandler m3 = + Mockito.spy(new EmptyMessageStateHandler(MessageIdentifier.ABOUT_THIS_SITE)); + MessageStateHandler m4 = + Mockito.spy(new EmptyMessageStateHandler(MessageIdentifier.DOWNLOAD_PROGRESS)); + enqueued = + HistogramWatcher.newBuilder() + .expectIntRecords( + "Android.Messages.Enqueued", + m3.getMessageIdentifier(), + m4.getMessageIdentifier()) + .expectIntRecords( + "Android.Messages.Enqueued.Resumed", + m3.getMessageIdentifier(), + m4.getMessageIdentifier()) + .expectNoRecords("Android.Messages.Enqueued.Suspended") + .build(); + queueManager.resume(token); + + queueManager.enqueueMessage(m3, m3, SCOPE_INSTANCE_ID, false); + queueManager.enqueueMessage(m4, m4, SCOPE_INSTANCE_ID, false); + enqueued.assertExpected(); + } + + /** Histograms are recorded with whether scope is active. */ + @Test + @SmallTest + public void testEnqueueWithScopeActivation() { + MessageQueueManager queueManager = new MessageQueueManager(mAnimationCoordinator); + queueManager.setDelegate(mEmptyDelegate); + + MessageStateHandler m1 = + Mockito.spy(new EmptyMessageStateHandler(MessageIdentifier.POPUP_BLOCKED)); + MessageStateHandler m2 = + Mockito.spy(new EmptyMessageStateHandler(MessageIdentifier.SYNC_ERROR)); + MessageStateHandler m3 = + Mockito.spy(new EmptyMessageStateHandler(MessageIdentifier.DOWNLOAD_PROGRESS)); + + var enqueued = + HistogramWatcher.newBuilder() + .expectIntRecords( + "Android.Messages.Enqueued", + m1.getMessageIdentifier(), + m2.getMessageIdentifier(), + m3.getMessageIdentifier()) + .expectIntRecords( + "Android.Messages.Enqueued.ScopeInactive", + m2.getMessageIdentifier()) + .expectIntRecords( + "Android.Messages.Enqueued.ScopeActive", + m1.getMessageIdentifier(), + m3.getMessageIdentifier()) + .build(); + + final ScopeKey inactiveScopeKey = new ScopeKey(SCOPE_TYPE, new InactiveMockWebContents()); + final ScopeKey windowScopeKey = + new ScopeKey(new MockWindowAndroidWebContents().getTopLevelNativeWindow()); + queueManager.enqueueMessage(m1, m1, SCOPE_INSTANCE_ID, false); + queueManager.enqueueMessage(m2, m2, inactiveScopeKey, true); + queueManager.enqueueMessage(m3, m3, windowScopeKey, false); + enqueued.assertExpected(); + + // Do not record again when there scopes are updated + enqueued = + HistogramWatcher.newBuilder() + .expectNoRecords("Android.Messages.Enqueued.ScopeInactive") + .expectNoRecords("Android.Messages.Enqueued.ScopeActive") + .build(); + queueManager.onScopeChange( + new MessageScopeChange( + MessageScopeType.NAVIGATION, SCOPE_INSTANCE_ID, ChangeType.INACTIVE)); + queueManager.onScopeChange( + new MessageScopeChange( + MessageScopeType.NAVIGATION, inactiveScopeKey, ChangeType.ACTIVE)); + enqueued.assertExpected(); + } + /** Test method {@link MessageQueueManager#dismissAllMessages(int)}. */ @Test @SmallTest
diff --git a/components/messages/android/internal/java/src/org/chromium/components/messages/ScopeChangeController.java b/components/messages/android/internal/java/src/org/chromium/components/messages/ScopeChangeController.java index 7f53e1f..5e700615 100644 --- a/components/messages/android/internal/java/src/org/chromium/components/messages/ScopeChangeController.java +++ b/components/messages/android/internal/java/src/org/chromium/components/messages/ScopeChangeController.java
@@ -33,6 +33,8 @@ interface ScopeObserver { void destroy(); + + boolean isActive(); } private final Delegate mDelegate; @@ -65,6 +67,12 @@ observer.destroy(); } + boolean isActive(ScopeKey scopeKey) { + if (!mObservers.containsKey(scopeKey)) return false; + var scopeObserver = mObservers.get(scopeKey); + return scopeObserver.isActive(); + } + /** * This handles both navigation type and webContents type. Only navigation type * will destroy scopes on page navigation. @@ -75,6 +83,7 @@ private final ScopeKey mScopeKey; // TODO(crbug.com/1340572): Replace GURL with Origin. private GURL mLastVisitedUrl; + private boolean mIsActive; public NavigationWebContentsScopeObserver(Delegate delegate, ScopeKey scopeKey) { super(scopeKey.webContents); @@ -87,18 +96,21 @@ : ChangeType.INACTIVE; mDelegate.onScopeChange( new MessageScopeChange(mScopeKey.scopeType, scopeKey, changeType)); + mIsActive = changeType == ChangeType.ACTIVE; } @Override public void wasShown() { mDelegate.onScopeChange( new MessageScopeChange(mScopeKey.scopeType, mScopeKey, ChangeType.ACTIVE)); + mIsActive = true; } @Override public void wasHidden() { mDelegate.onScopeChange( new MessageScopeChange(mScopeKey.scopeType, mScopeKey, ChangeType.INACTIVE)); + mIsActive = false; } @Override @@ -131,6 +143,12 @@ // #destroy will remove the observers. mDelegate.onScopeChange( new MessageScopeChange(mScopeKey.scopeType, mScopeKey, ChangeType.DESTROY)); + mIsActive = false; + } + + @Override + public boolean isActive() { + return mIsActive; } @Override @@ -153,6 +171,7 @@ static class WindowScopeObserver implements ScopeObserver, ActivityStateObserver { private final Delegate mDelegate; private final ScopeKey mScopeKey; + private boolean mIsActive; public WindowScopeObserver(Delegate delegate, ScopeKey scopeKey) { mDelegate = delegate; @@ -161,36 +180,45 @@ : "WindowScopeObserver should only monitor window scope events."; WindowAndroid windowAndroid = scopeKey.windowAndroid; windowAndroid.addActivityStateObserver(this); + @ChangeType + int changeType = + windowAndroid.getActivityState() == ActivityState.RESUMED + ? ChangeType.ACTIVE + : ChangeType.INACTIVE; mDelegate.onScopeChange( - new MessageScopeChange( - scopeKey.scopeType, - scopeKey, - windowAndroid.getActivityState() == ActivityState.RESUMED - ? ChangeType.ACTIVE - : ChangeType.INACTIVE)); + new MessageScopeChange(scopeKey.scopeType, scopeKey, changeType)); + mIsActive = changeType == ChangeType.ACTIVE; } @Override public void onActivityPaused() { mDelegate.onScopeChange( new MessageScopeChange(mScopeKey.scopeType, mScopeKey, ChangeType.INACTIVE)); + mIsActive = false; } @Override public void onActivityResumed() { mDelegate.onScopeChange( new MessageScopeChange(mScopeKey.scopeType, mScopeKey, ChangeType.ACTIVE)); + mIsActive = true; } @Override public void onActivityDestroyed() { mDelegate.onScopeChange( new MessageScopeChange(mScopeKey.scopeType, mScopeKey, ChangeType.DESTROY)); + mIsActive = false; } @Override public void destroy() { mScopeKey.windowAndroid.removeActivityStateObserver(this); } + + @Override + public boolean isActive() { + return mIsActive; + } } }
diff --git a/components/messages/android/internal/java/src/org/chromium/components/messages/SingleActionMessage.java b/components/messages/android/internal/java/src/org/chromium/components/messages/SingleActionMessage.java index d180b05..7ceea00 100644 --- a/components/messages/android/internal/java/src/org/chromium/components/messages/SingleActionMessage.java +++ b/components/messages/android/internal/java/src/org/chromium/components/messages/SingleActionMessage.java
@@ -39,7 +39,11 @@ private final SwipeAnimationHandler mSwipeAnimationHandler; private final boolean mIsFullyVisibileCallbackEnabled; private boolean mMessageDismissed; + private boolean mFullyVisibleBefore; + private boolean mFullyVisibleCallbackInvoked; + private final boolean mAreExtraHistogramsEnabled; + private long mMessageEnqueuedTime; // The timestamp when the message was shown. Used for reproting visible duration. private long mMessageShownTime; @@ -85,6 +89,8 @@ mModel.set( MessageBannerProperties.PRIMARY_BUTTON_CLICK_LISTENER, this::handlePrimaryAction); mModel.set(MessageBannerProperties.ON_SECONDARY_BUTTON_CLICK, this::handleSecondaryAction); + mMessageEnqueuedTime = MessagesMetrics.now(); + mAreExtraHistogramsEnabled = MessageFeatureList.areExtraHistogramsEnabled(); } /** @@ -132,13 +138,23 @@ mContainer.addMessage(mView); } + mMessageShownTime = MessagesMetrics.now(); if (toIndex == Position.FRONT) { mContainer.setA11yDelegate(this); + if (mAreExtraHistogramsEnabled) { + if (!mFullyVisibleBefore) { + MessagesMetrics.recordTimeToFullyShow( + getMessageIdentifier(), mMessageShownTime - mMessageEnqueuedTime); + } + MessagesMetrics.recordFullyVisible(getMessageIdentifier()); + mFullyVisibleBefore = true; + } + notifyVisibilityChange(true); } else { notifyVisibilityChange(false); } - mMessageShownTime = MessagesMetrics.now(); + return mMessageBanner.show(fromIndex, toIndex, () -> MessageDimens.from(mContainer, mView)); } @@ -177,6 +193,20 @@ dismissReason == DismissReason.GESTURE, MessagesMetrics.now() - mMessageShownTime); } + if (mAreExtraHistogramsEnabled) { + if (dismissReason == DismissReason.PRIMARY_ACTION + || dismissReason == DismissReason.SECONDARY_ACTION + || dismissReason == DismissReason.GESTURE + || dismissReason == DismissReason.TIMER) { + if (getOnFullyVisibleCallback() != null && !mFullyVisibleCallbackInvoked) { + MessagesMetrics.recordErrorFullyVisibleNotInformed(getMessageIdentifier()); + } + } + + if (!mFullyVisibleBefore) { + MessagesMetrics.recordDismissedWithoutFullyVisible(getMessageIdentifier()); + } + } } @Override @@ -210,18 +240,25 @@ mModel.get(MessageBannerProperties.ON_SECONDARY_ACTION).run(); } - private void notifyVisibilityChange(boolean fullyVisible) { + @VisibleForTesting + void notifyVisibilityChange(boolean fullyVisible) { if (!mIsFullyVisibileCallbackEnabled) return; - if (!mModel.containsKey(MessageBannerProperties.ON_FULLY_VISIBLE)) return; - var callback = mModel.get(MessageBannerProperties.ON_FULLY_VISIBLE); + var callback = getOnFullyVisibleCallback(); if (callback == null) return; if (fullyVisible == mModel.get(MessageBannerProperties.IS_FULLY_VISIBLE)) return; + mFullyVisibleCallbackInvoked = true; mModel.set(MessageBannerProperties.IS_FULLY_VISIBLE, fullyVisible); callback.onResult(fullyVisible); } + private @Nullable Callback<Boolean> getOnFullyVisibleCallback() { + if (!mModel.containsKey(MessageBannerProperties.ON_FULLY_VISIBLE)) return null; + + return mModel.get(MessageBannerProperties.ON_FULLY_VISIBLE); + } + @VisibleForTesting long getAutoDismissDuration() { return mAutodismissDurationMs.get();
diff --git a/components/messages/android/internal/java/src/org/chromium/components/messages/SingleActionMessageTest.java b/components/messages/android/internal/java/src/org/chromium/components/messages/SingleActionMessageTest.java index 3767275..7e4a5f70 100644 --- a/components/messages/android/internal/java/src/org/chromium/components/messages/SingleActionMessageTest.java +++ b/components/messages/android/internal/java/src/org/chromium/components/messages/SingleActionMessageTest.java
@@ -20,6 +20,7 @@ import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; +import org.junit.rules.TestRule; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Mock; @@ -29,11 +30,13 @@ import org.chromium.base.ApiCompatibilityUtils; import org.chromium.base.Callback; -import org.chromium.base.FeatureList; +import org.chromium.base.FakeTimeTestRule; import org.chromium.base.test.BaseActivityTestRule; import org.chromium.base.test.BaseJUnit4ClassRunner; import org.chromium.base.test.util.Batch; import org.chromium.base.test.util.CallbackHelper; +import org.chromium.base.test.util.Features; +import org.chromium.base.test.util.HistogramWatcher; import org.chromium.components.messages.MessageStateHandler.Position; import org.chromium.content_public.browser.test.util.TestThreadUtils; import org.chromium.ui.modelutil.PropertyModel; @@ -41,12 +44,14 @@ import org.chromium.ui.test.util.BlankUiTestActivity; import org.chromium.ui.test.util.DisableAnimationsTestRule; -import java.util.HashMap; -import java.util.Map; - /** Tests for {@link SingleActionMessage}. */ @RunWith(BaseJUnit4ClassRunner.class) @Batch(Batch.UNIT_TESTS) +@Features.EnableFeatures({ + MessageFeatureList.MESSAGES_ANDROID_EXTRA_HISTOGRAMS, + MessageFeatureList.MESSAGES_FOR_ANDROID_FULLY_VISIBLE_CALLBACK, + MessageFeatureList.MESSAGES_FOR_ANDROID_STACKING_ANIMATION +}) public class SingleActionMessageTest { @ClassRule public static DisableAnimationsTestRule sDisableAnimationsRule = @@ -72,6 +77,8 @@ } @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule(); + @Rule public TestRule mFeaturesProcessorRule = new Features.JUnitProcessor(); + @Rule public FakeTimeTestRule mFakeTime = new FakeTimeTestRule(); @Mock private SwipeAnimationHandler mSwipeAnimationHandler; @Mock private MessageBannerCoordinator mMessageBanner; @@ -80,7 +87,6 @@ private CallbackHelper mDismissCallback; private SingleActionMessage.DismissCallback mEmptyDismissCallback = (model, dismissReason) -> {}; - private Map<String, Boolean> mFeatureMap = new HashMap<>(); @BeforeClass public static void setupSuite() { @@ -96,9 +102,6 @@ mDismissCallback = new CallbackHelper(); mPrimaryActionCallback = new CallbackHelper(); mSecondaryActionCallback = new CallbackHelper(); - mFeatureMap.put(MessageFeatureList.MESSAGES_FOR_ANDROID_FULLY_VISIBLE_CALLBACK, true); - mFeatureMap.put(MessageFeatureList.MESSAGES_FOR_ANDROID_STACKING_ANIMATION, false); - FeatureList.setTestFeatures(mFeatureMap); } @Test @@ -148,6 +151,56 @@ @Test @MediumTest + public void testHistogramRecordOnDismiss() { + MessageContainer container = new MessageContainer(sActivity, null); + PropertyModel m1 = createBasicSingleActionMessageModel(MessageIdentifier.SYNC_ERROR); + PropertyModel m2 = createBasicSingleActionMessageModel(MessageIdentifier.DOWNLOAD_PROGRESS); + PropertyModel m3 = createBasicSingleActionMessageModel(MessageIdentifier.POPUP_BLOCKED); + + var fullyVisible = + HistogramWatcher.newBuilder() + .expectIntRecords( + "Android.Messages.FullyVisible", + MessageIdentifier.SYNC_ERROR, + MessageIdentifier.DOWNLOAD_PROGRESS) + .build(); + + var dismissal = + HistogramWatcher.newBuilder() + .expectIntRecords( + "Android.Messages.DismissedWithoutFullyVisible", + MessageIdentifier.POPUP_BLOCKED) + .expectIntRecord("Android.Messages.TimeToFullyShow.SyncError", 1000) + .expectIntRecord("Android.Messages.TimeToFullyShow.DownloadProgress", 1500) + .build(); + + final MessageBannerView view1 = createMessageBannerView(container); + final MessageBannerView view2 = createMessageBannerView(container); + final MessageBannerView view3 = createMessageBannerView(container); + var sam1 = createSingleActionMessage(container, m1, view1); + var sam2 = createSingleActionMessage(container, m2, view2); + var sam3 = createSingleActionMessage(container, m3, view3); + + // dismiss without showing + sam3.dismiss(DismissReason.DISMISSED_BY_FEATURE); + + mFakeTime.advanceMillis(1000); + sam1.show(Position.INVISIBLE, Position.FRONT); + sam2.show(Position.FRONT, Position.BACK); + + // to test this will not trigger a recordation of DismissedWithoutFullyVisible. + sam1.dismiss(DismissReason.GESTURE); + + mFakeTime.advanceMillis(500); + // move to front to make sam2 also fully visible. + sam2.show(Position.BACK, Position.FRONT); + + fullyVisible.assertExpected("Messages should have been fully visible before"); + dismissal.assertExpected("Histograms are not recorded when a message is dismissed"); + } + + @Test + @MediumTest public void testAutoDismissDuration() { MessageContainer container = new MessageContainer(sActivity, null); PropertyModel model = createBasicSingleActionMessageModel(); @@ -191,6 +244,7 @@ @Test(expected = IllegalStateException.class) @MediumTest + @Features.DisableFeatures(MessageFeatureList.MESSAGES_FOR_ANDROID_STACKING_ANIMATION) public void testAddMultipleSingleActionMessage() { MessageContainer container = new MessageContainer(sActivity, null); PropertyModel m1 = createBasicSingleActionMessageModel(); @@ -204,8 +258,6 @@ @Test @MediumTest public void testAddAndRemoveSingleActionMessage_withStacking() { - mFeatureMap.put(MessageFeatureList.MESSAGES_FOR_ANDROID_STACKING_ANIMATION, true); - FeatureList.setTestFeatures(mFeatureMap); MessageContainer container = new MessageContainer(sActivity, null); PropertyModel m1 = createBasicSingleActionMessageModel(); PropertyModel m2 = createBasicSingleActionMessageModel(); @@ -235,8 +287,6 @@ @Test(expected = IllegalStateException.class) @MediumTest public void testAddMultipleSingleActionMessage_withStacking() { - mFeatureMap.put(MessageFeatureList.MESSAGES_FOR_ANDROID_STACKING_ANIMATION, true); - FeatureList.setTestFeatures(mFeatureMap); MessageContainer container = new MessageContainer(sActivity, null); PropertyModel m1 = createBasicSingleActionMessageModel(); PropertyModel m2 = createBasicSingleActionMessageModel(); @@ -272,16 +322,19 @@ @Test @MediumTest public void testOnFullyVisible() { - mFeatureMap.put(MessageFeatureList.MESSAGES_FOR_ANDROID_STACKING_ANIMATION, true); - FeatureList.setTestFeatures(mFeatureMap); MessageContainer container = new MessageContainer(sActivity, null); - PropertyModel m1 = createBasicSingleActionMessageModel(); - PropertyModel m2 = createBasicSingleActionMessageModel(); + PropertyModel m1 = createBasicSingleActionMessageModel(1); + PropertyModel m2 = createBasicSingleActionMessageModel(2); Callback<Boolean> callback1 = Mockito.mock(Callback.class); m1.set(MessageBannerProperties.ON_FULLY_VISIBLE, callback1); Callback<Boolean> callback2 = Mockito.mock(Callback.class); m2.set(MessageBannerProperties.ON_FULLY_VISIBLE, callback2); + var fullyVisible = + HistogramWatcher.newBuilder() + .expectIntRecords("Android.Messages.FullyVisible", 1, 2) + .build(); + final MessageBannerView view1 = createMessageBannerView(container); final MessageBannerView view2 = createMessageBannerView(container); var sam1 = @@ -299,6 +352,58 @@ sam2.show(Position.BACK, Position.FRONT); verify(callback2).onResult(true); + fullyVisible.assertExpected("Messages should have been fully visible before"); + } + + @Test + @MediumTest + public void testOnFullyVisibleNotCalled() { + MessageContainer container = new MessageContainer(sActivity, null); + PropertyModel m1 = createBasicSingleActionMessageModel(MessageIdentifier.SYNC_ERROR); + m1.set(MessageBannerProperties.ON_FULLY_VISIBLE, (unused) -> {}); + + final var fullyVisible = + HistogramWatcher.newBuilder() + .expectIntRecords( + "Android.Messages.FullyVisible", MessageIdentifier.SYNC_ERROR) + .build(); + + final var dismissal = + HistogramWatcher.newBuilder() + .expectIntRecord("Android.Messages.TimeToFullyShow.SyncError", 1000) + .expectIntRecord( + "Android.Messages.Error.FullyVisibleNotInformed", + MessageIdentifier.SYNC_ERROR) + .build(); + + final MessageBannerView view1 = createMessageBannerView(container); + var sam1 = + new SingleActionMessage( + container, + m1, + mEmptyDismissCallback, + () -> 0, + () -> 0, + new MockDurationProvider(0L), + mSwipeAnimationHandler) { + @Override + void notifyVisibilityChange(boolean fullyVisible) { + // Do nothing + } + }; + view1.setId(R.id.message_banner); + PropertyModelChangeProcessor.create(m1, view1, MessageBannerViewBinder::bind); + sam1.setMessageBannerForTesting(mMessageBanner); + sam1.setViewForTesting(view1); + + mFakeTime.advanceMillis(1000); + sam1.show(Position.INVISIBLE, Position.FRONT); + + mFakeTime.advanceMillis(500); + sam1.dismiss(DismissReason.GESTURE); + + fullyVisible.assertExpected("Messages should have been fully visible before"); + dismissal.assertExpected("Incorrect histograms on dismiss"); } private void executeAndVerifyRepeatedButtonClicks( @@ -333,12 +438,8 @@ mSecondaryActionCallback.getCallCount()); } - private SingleActionMessage createAndShowSingleActionMessage( - MessageContainer container, - PropertyModel model, - MessageBannerView view, - @Position int from, - @Position int to) { + private SingleActionMessage createSingleActionMessage( + MessageContainer container, PropertyModel model, MessageBannerView view) { SingleActionMessage message = new SingleActionMessage( container, @@ -352,6 +453,16 @@ PropertyModelChangeProcessor.create(model, view, MessageBannerViewBinder::bind); message.setMessageBannerForTesting(mMessageBanner); message.setViewForTesting(view); + return message; + } + + private SingleActionMessage createAndShowSingleActionMessage( + MessageContainer container, + PropertyModel model, + MessageBannerView view, + @Position int from, + @Position int to) { + SingleActionMessage message = createSingleActionMessage(container, model, view); message.show(from, to); return message; } @@ -368,9 +479,9 @@ .inflate(R.layout.message_banner_view, container, false); } - private PropertyModel createBasicSingleActionMessageModel() { + private PropertyModel createBasicSingleActionMessageModel(int id) { return new PropertyModel.Builder(MessageBannerProperties.ALL_KEYS) - .with(MessageBannerProperties.MESSAGE_IDENTIFIER, MessageIdentifier.TEST_MESSAGE) + .with(MessageBannerProperties.MESSAGE_IDENTIFIER, id) .with(MessageBannerProperties.TITLE, "test") .with(MessageBannerProperties.DESCRIPTION, "Description") .with( @@ -396,4 +507,8 @@ }) .build(); } + + private PropertyModel createBasicSingleActionMessageModel() { + return createBasicSingleActionMessageModel(MessageIdentifier.TEST_MESSAGE); + } }
diff --git a/components/messages/android/java/src/org/chromium/components/messages/MessageContainer.java b/components/messages/android/java/src/org/chromium/components/messages/MessageContainer.java index f0144716..115c066 100644 --- a/components/messages/android/java/src/org/chromium/components/messages/MessageContainer.java +++ b/components/messages/android/java/src/org/chromium/components/messages/MessageContainer.java
@@ -172,15 +172,17 @@ /** * Runs a {@link Runnable} after the message's initial layout. If the view is already laid out, * the {@link Runnable} will be called immediately. + * * @param runnable The {@link Runnable}. + * @return True if the callback is triggered immediately (i.e. synchronously). */ - void runAfterInitialMessageLayout(Runnable runnable) { + boolean runAfterInitialMessageLayout(Runnable runnable) { View view = getChildAt(0); assert view != null; if (view.getHeight() > 0) { mIsInitializingLayout = false; runnable.run(); - return; + return true; } mIsInitializingLayout = true; @@ -204,6 +206,7 @@ mIsInitializingLayout = false; } }); + return false; } /**
diff --git a/components/messages/android/java/src/org/chromium/components/messages/MessageFeatureList.java b/components/messages/android/java/src/org/chromium/components/messages/MessageFeatureList.java index 8584035..4db8446 100644 --- a/components/messages/android/java/src/org/chromium/components/messages/MessageFeatureList.java +++ b/components/messages/android/java/src/org/chromium/components/messages/MessageFeatureList.java
@@ -15,6 +15,7 @@ "MessagesForAndroidStackingAnimation"; public static final String MESSAGES_FOR_ANDROID_FULLY_VISIBLE_CALLBACK = "MessagesForAndroidFullyVisibleCallback"; + public static final String MESSAGES_ANDROID_EXTRA_HISTOGRAMS = "MessagesAndroidExtraHistograms"; public static boolean isStackAnimationEnabled() { return MessageFeatureMap.isEnabled(MESSAGES_FOR_ANDROID_STACKING_ANIMATION); @@ -23,4 +24,8 @@ public static boolean isFullyVisibleCallbackEnabled() { return MessageFeatureMap.isEnabled(MESSAGES_FOR_ANDROID_FULLY_VISIBLE_CALLBACK); } + + public static boolean areExtraHistogramsEnabled() { + return MessageFeatureMap.isEnabled(MESSAGES_ANDROID_EXTRA_HISTOGRAMS); + } }
diff --git a/components/messages/android/java/src/org/chromium/components/messages/MessagesMetrics.java b/components/messages/android/java/src/org/chromium/components/messages/MessagesMetrics.java index ec18e0e..cc64f3c 100644 --- a/components/messages/android/java/src/org/chromium/components/messages/MessagesMetrics.java +++ b/components/messages/android/java/src/org/chromium/components/messages/MessagesMetrics.java
@@ -4,11 +4,11 @@ package org.chromium.components.messages; -import android.os.SystemClock; import androidx.annotation.IntDef; import org.chromium.base.Log; +import org.chromium.base.TimeUtils; import org.chromium.base.metrics.RecordHistogram; /** @@ -18,10 +18,23 @@ public class MessagesMetrics { private static final String TAG = "MessagesMetrics"; private static final String ENQUEUED_HISTOGRAM_NAME = "Android.Messages.Enqueued"; + private static final String ENQUEUED_SUSPEND_HISTOGRAM_NAME = + "Android.Messages.Enqueued.Suspended"; + private static final String ENQUEUED_RESUME_HISTOGRAM_NAME = + "Android.Messages.Enqueued.Resumed"; + private static final String ENQUEUED_SCOPE_ACTIVE_HISTOGRAM_NAME = + "Android.Messages.Enqueued.ScopeActive"; + private static final String ENQUEUED_SCOPE_INACTIVE_HISTOGRAM_NAME = + "Android.Messages.Enqueued.ScopeInactive"; private static final String ENQUEUED_VISIBLE_HISTOGRAM_NAME = "Android.Messages.Enqueued.Visible"; private static final String ENQUEUED_HIDDEN_HISTOGRAM_NAME = "Android.Messages.Enqueued.Hidden"; private static final String ENQUEUED_HIDING_HISTOGRAM_NAME = "Android.Messages.Enqueued.Hiding"; + private static final String FULLY_VISIBLE_NAME = "Android.Messages.FullyVisible"; + private static final String ERROR_FULLY_VISIBLE_NOT_INFORMED_NAME = + "Android.Messages.Error.FullyVisibleNotInformed"; + private static final String DISMISSED_WITHOUT_FULLY_VISIBLE = + "Android.Messages.DismissedWithoutFullyVisible"; private static final String DISMISSED_HISTOGRAM_PREFIX = "Android.Messages.Dismissed."; private static final String TIME_TO_ACTION_HISTOGRAM_PREFIX = "Android.Messages.TimeToAction."; private static final String TIME_TO_ACTION_DISMISS_HISTOGRAM_PREFIX = @@ -29,6 +42,15 @@ static final String STACKING_HISTOGRAM_NAME = "Android.Messages.Stacking"; static final String STACKING_HIDDEN_NAME = "Android.Messages.Stacking.Hidden"; static final String STACKING_HIDING_NAME = "Android.Messages.Stacking.Hiding"; + static final String STACKING_REQUEST_TO_SHOW_NAME = + "Android.Messages.Stacking.RequestToFullyShow"; + static final String STACKING_BLOCKED_BY_BROWSER_CONTROL_NAME = + "Android.Messages.Stacking.BlockedByBrowserControl"; + static final String STACKING_BLOCKED_BY_CONTAINER_INITING_NAME = + "Android.Messages.Stacking.BlockedByContainerInitializing"; + static final String STACKING_BLOCKED_BY_CONTAINER_NOT_INITED_NAME = + "Android.Messages.Stacking.BlockedByContainerNotInitialized"; + static final String STACKING_TIME_TO_FULLY_SHOW_PREFIX = "Android.Messages.TimeToFullyShow."; static final String STACKING_ACTION_HISTOGRAM_PREFIX = "Android.Messages.Stacking."; static final String THREE_STACKED_HISTOGRAM_NAME = "Android.Messages.Stacking.ThreeStacked"; @@ -91,6 +113,24 @@ ENQUEUED_HISTOGRAM_NAME, messageIdentifier, MessageIdentifier.COUNT); } + static void recordMessageEnqueuedScopeActive( + @MessageIdentifier int messageIdentifier, boolean active) { + String histogram = + active + ? ENQUEUED_SCOPE_ACTIVE_HISTOGRAM_NAME + : ENQUEUED_SCOPE_INACTIVE_HISTOGRAM_NAME; + RecordHistogram.recordEnumeratedHistogram( + histogram, messageIdentifier, MessageIdentifier.COUNT); + } + + static void recordMessageEnqueuedQueueSuspended( + @MessageIdentifier int messageIdentifier, boolean suspended) { + String histogram = + suspended ? ENQUEUED_SUSPEND_HISTOGRAM_NAME : ENQUEUED_RESUME_HISTOGRAM_NAME; + RecordHistogram.recordEnumeratedHistogram( + histogram, messageIdentifier, MessageIdentifier.COUNT); + } + /** Records metrics when a message is visible after being enqueued. */ static void recordMessageEnqueuedVisible(@MessageIdentifier int messageIdentifier) { RecordHistogram.recordEnumeratedHistogram( @@ -134,6 +174,61 @@ } /** + * Record the id of candidate which will be displayed in the foreground. + * + * @param messageIdentifier The id of the next front message. + */ + static void recordRequestToFullyShow(@MessageIdentifier int messageIdentifier) { + RecordHistogram.recordEnumeratedHistogram( + STACKING_REQUEST_TO_SHOW_NAME, messageIdentifier, MessageIdentifier.COUNT); + } + + /** + * Record the id of candidate which will be displayed in the foreground but now is waiting for + * browser control to be ready. + * + * @param messageIdentifier The id of the next front message. + */ + static void recordBlockedByBrowserControl(@MessageIdentifier int messageIdentifier) { + RecordHistogram.recordEnumeratedHistogram( + STACKING_BLOCKED_BY_BROWSER_CONTROL_NAME, + messageIdentifier, + MessageIdentifier.COUNT); + } + + /** + * Record the id of candidate which will be displayed in the foreground but now is waiting for + * message container to finishing initialization. + * + * @param messageIdentifier The id of the next front message. + */ + static void recordBlockedByContainerInitializing(@MessageIdentifier int messageIdentifier) { + RecordHistogram.recordEnumeratedHistogram( + STACKING_BLOCKED_BY_CONTAINER_INITING_NAME, + messageIdentifier, + MessageIdentifier.COUNT); + } + + /** + * Record the id of candidate which will be displayed in the foreground but container has not + * been initialized. + * + * @param messageIdentifier The id of the next front message. + */ + static void recordBlockedByContainerNotInitialized(@MessageIdentifier int messageIdentifier) { + RecordHistogram.recordEnumeratedHistogram( + STACKING_BLOCKED_BY_CONTAINER_NOT_INITED_NAME, + messageIdentifier, + MessageIdentifier.COUNT); + } + + static void recordTimeToFullyShow(@MessageIdentifier int messageIdentifier, long durationMs) { + String histogramSuffix = messageIdentifierToHistogramSuffix(messageIdentifier); + RecordHistogram.recordMediumTimesHistogram( + STACKING_TIME_TO_FULLY_SHOW_PREFIX + histogramSuffix, durationMs); + } + + /** * Record the id of background message when it is stacked. * @param messageIdentifier The id of the background message. */ @@ -171,12 +266,33 @@ THREE_STACKED_HISTOGRAM_NAME, scenario, ThreeStackedScenario.MAX_VALUE); } + /** Record the message has been fully visible. */ + static void recordFullyVisible(@MessageIdentifier int messageIdentifier) { + RecordHistogram.recordEnumeratedHistogram( + FULLY_VISIBLE_NAME, messageIdentifier, MessageIdentifier.COUNT); + } + + /** + * Record the fully visible callback is not triggered when it is supposed to be. E.g. when the + * message is dismissed by gesture, primary action, secondary action, timer. + */ + static void recordErrorFullyVisibleNotInformed(@MessageIdentifier int messageIdentifier) { + RecordHistogram.recordEnumeratedHistogram( + ERROR_FULLY_VISIBLE_NOT_INFORMED_NAME, messageIdentifier, MessageIdentifier.COUNT); + } + + /** Record when the message is dismissed without being fully visible before. */ + static void recordDismissedWithoutFullyVisible(@MessageIdentifier int messageIdentifier) { + RecordHistogram.recordEnumeratedHistogram( + DISMISSED_WITHOUT_FULLY_VISIBLE, messageIdentifier, MessageIdentifier.COUNT); + } + /** * Returns current timestamp in milliseconds to be used when recording message's visible * duration. */ static long now() { - return SystemClock.uptimeMillis(); + return TimeUtils.uptimeMillis(); } private static String stackingAnimationActionToHistogramSuffix(
diff --git a/components/messages/android/messages_feature.cc b/components/messages/android/messages_feature.cc index 5a056a6..f67ca9a3 100644 --- a/components/messages/android/messages_feature.cc +++ b/components/messages/android/messages_feature.cc
@@ -17,6 +17,7 @@ const base::Feature* kFeaturesExposedToJava[] = { &kMessagesForAndroidStackingAnimation, &kMessagesForAndroidFullyVisibleCallback, + &kMessagesAndroidExtraHistograms, }; // static @@ -56,6 +57,11 @@ "MessagesForAndroidFullyVisibleCallback", base::FEATURE_ENABLED_BY_DEFAULT); +// Feature that enables extra histogram recordings. +BASE_FEATURE(kMessagesAndroidExtraHistograms, + "MessagesAndroidExtraHistograms", + base::FEATURE_ENABLED_BY_DEFAULT); + bool IsAdsBlockedMessagesUiEnabled() { return base::FeatureList::IsEnabled(kMessagesForAndroidAdsBlocked); }
diff --git a/components/messages/android/messages_feature.h b/components/messages/android/messages_feature.h index 4ad0b388..b34b4c7 100644 --- a/components/messages/android/messages_feature.h +++ b/components/messages/android/messages_feature.h
@@ -37,6 +37,9 @@ // is fully visible. BASE_DECLARE_FEATURE(kMessagesForAndroidFullyVisibleCallback); +// Feature that enables extra histogram recordings. +BASE_DECLARE_FEATURE(kMessagesAndroidExtraHistograms); + bool IsAdsBlockedMessagesUiEnabled(); bool IsOfferNotificationMessagesUiEnabled();
diff --git a/components/metrics/test/test_metrics_log_uploader.h b/components/metrics/test/test_metrics_log_uploader.h index 2168069..ad90c56 100644 --- a/components/metrics/test/test_metrics_log_uploader.h +++ b/components/metrics/test/test_metrics_log_uploader.h
@@ -12,9 +12,7 @@ namespace metrics { -class TestMetricsLogUploader - : public MetricsLogUploader, - public base::SupportsWeakPtr<TestMetricsLogUploader> { +class TestMetricsLogUploader : public MetricsLogUploader { public: explicit TestMetricsLogUploader( const MetricsLogUploader::UploadCallback& on_upload_complete); @@ -32,6 +30,10 @@ const ReportingInfo& reporting_info() const { return last_reporting_info_; } + base::WeakPtr<TestMetricsLogUploader> AsWeakPtr() { + return weak_ptr_factory_.GetWeakPtr(); + } + private: // MetricsLogUploader: void UploadLog(const std::string& compressed_log_data, @@ -43,6 +45,7 @@ const MetricsLogUploader::UploadCallback on_upload_complete_; ReportingInfo last_reporting_info_; bool is_uploading_; + base::WeakPtrFactory<TestMetricsLogUploader> weak_ptr_factory_{this}; }; } // namespace metrics
diff --git a/components/mirroring/service/rtp_stream.h b/components/mirroring/service/rtp_stream.h index fd1f1dd..90990d1 100644 --- a/components/mirroring/service/rtp_stream.h +++ b/components/mirroring/service/rtp_stream.h
@@ -101,8 +101,7 @@ }; // Receives audio data and submits the data to media::cast::AudioSender. -class COMPONENT_EXPORT(MIRRORING_SERVICE) AudioRtpStream - : public base::SupportsWeakPtr<AudioRtpStream> { +class COMPONENT_EXPORT(MIRRORING_SERVICE) AudioRtpStream final { public: AudioRtpStream(std::unique_ptr<media::cast::AudioSender> audio_sender, base::WeakPtr<RtpStreamClient> client); @@ -123,9 +122,14 @@ // changing the bitrate in realtime. int GetEncoderBitrate() const; + base::WeakPtr<AudioRtpStream> AsWeakPtr() { + return weak_ptr_factory_.GetWeakPtr(); + } + private: const std::unique_ptr<media::cast::AudioSender> audio_sender_; const base::WeakPtr<RtpStreamClient> client_; + base::WeakPtrFactory<AudioRtpStream> weak_ptr_factory_{this}; }; } // namespace mirroring
diff --git a/components/optimization_guide/core/model_execution/model_execution_manager.cc b/components/optimization_guide/core/model_execution/model_execution_manager.cc index 2bf88db..b1b049fe 100644 --- a/components/optimization_guide/core/model_execution/model_execution_manager.cc +++ b/components/optimization_guide/core/model_execution/model_execution_manager.cc
@@ -232,8 +232,8 @@ } RecordSessionUsedRemoteExecutionHistogram(feature, /*is_remote=*/true); - return std::make_unique<SessionImpl>(base::DoNothing(), feature, nullptr, - nullptr, std::move(execute_fn), + return std::make_unique<SessionImpl>(base::DoNothing(), feature, std::nullopt, + nullptr, nullptr, std::move(execute_fn), optimization_guide_logger_.get()); }
diff --git a/components/optimization_guide/core/model_execution/on_device_model_service_controller.cc b/components/optimization_guide/core/model_execution/on_device_model_service_controller.cc index e2daeb4..8434760 100644 --- a/components/optimization_guide/core/model_execution/on_device_model_service_controller.cc +++ b/components/optimization_guide/core/model_execution/on_device_model_service_controller.cc
@@ -92,24 +92,27 @@ auto model_path_override_switch = switches::GetOnDeviceModelExecutionOverride(); if (model_path_override_switch) { - SetModelPath(*StringToFilePath(*model_path_override_switch)); + SetModelPath(*StringToFilePath(*model_path_override_switch), "override"); } else if (on_device_component_state_manager_) { const OnDeviceModelComponentState* state = on_device_component_state_manager_->GetState(); if (state) { - SetModelPath(state->GetInstallDirectory()); + SetModelPath(state->GetInstallDirectory(), + state->GetVersion().GetString()); } } } void OnDeviceModelServiceController::ClearModelPath() { model_paths_ = std::nullopt; + model_versions_ = std::nullopt; config_interpreter_->ClearState(); model_remote_.reset(); } void OnDeviceModelServiceController::SetModelPath( - const base::FilePath& model_path) { + const base::FilePath& model_path, + const std::string& version) { // Even if model_path didn't change, we want to go through this process anyway // because the content in the directory may have changed. ClearModelPath(); @@ -125,6 +128,7 @@ *(safety_model_info_->GetAdditionalFileWithBaseName(kTsSpModelFile)); } model_paths_ = std::move(model_paths); + model_versions_ = GetModelVersions(version); config_interpreter_->UpdateConfigWithFileDir(model_path); } @@ -167,8 +171,9 @@ return std::make_unique<SessionImpl>( base::BindRepeating(&OnDeviceModelServiceController::StartMojoSession, weak_ptr_factory_.GetWeakPtr()), - feature, config_interpreter_.get(), weak_ptr_factory_.GetWeakPtr(), - std::move(execute_remote_fn), optimization_guide_logger); + feature, model_versions_, config_interpreter_.get(), + weak_ptr_factory_.GetWeakPtr(), std::move(execute_remote_fn), + optimization_guide_logger); } void OnDeviceModelServiceController::GetEstimatedPerformanceClass( @@ -238,6 +243,9 @@ model_paths_->ts_sp_model = *(safety_model_info_->GetAdditionalFileWithBaseName(kTsSpModelFile)); } + if (model_versions_) { + model_versions_->set_text_safety_model_version(model_info->GetVersion()); + } } else if (model_paths_) { safety_model_info_ = std::nullopt; // Clear out T&S model paths if we shouldn't use the current safety model @@ -255,7 +263,7 @@ } if (state) { - SetModelPath(state->GetInstallDirectory()); + SetModelPath(state->GetInstallDirectory(), state->GetVersion().GetString()); } else { ClearModelPath(); } @@ -299,4 +307,19 @@ model_remote_.reset(); } +proto::OnDeviceModelVersions OnDeviceModelServiceController::GetModelVersions( + const std::string& component_version) const { + CHECK(!component_version.empty()); + + proto::OnDeviceModelVersions versions; + versions.mutable_on_device_model_service_version()->set_component_version( + component_version); + + if (safety_model_info_) { + versions.set_text_safety_model_version(safety_model_info_->GetVersion()); + } + + return versions; +} + } // namespace optimization_guide
diff --git a/components/optimization_guide/core/model_execution/on_device_model_service_controller.h b/components/optimization_guide/core/model_execution/on_device_model_service_controller.h index f551247..c316666 100644 --- a/components/optimization_guide/core/model_execution/on_device_model_service_controller.h +++ b/components/optimization_guide/core/model_execution/on_device_model_service_controller.h
@@ -116,7 +116,8 @@ // Sets the base model directory and initializes the on-device model // controller with the parameters, to be ready to load models and execute. - void SetModelPath(const base::FilePath& model_path); + void SetModelPath(const base::FilePath& model_path, + const std::string& component_version); void ClearModelPath(); // Makes sure the service is running and starts a mojo session. @@ -139,11 +140,16 @@ // idle. void OnRemoteIdle(); + // Gets the model versions based on the current model paths set. + proto::OnDeviceModelVersions GetModelVersions( + const std::string& component_version) const; + // This may be null in the destructor, otherwise non-null. std::unique_ptr<OnDeviceModelAccessController> access_controller_; base::WeakPtr<OnDeviceModelComponentStateManager> on_device_component_state_manager_; std::optional<on_device_model::ModelAssetPaths> model_paths_; + std::optional<proto::OnDeviceModelVersions> model_versions_; std::optional<ModelInfo> safety_model_info_; std::unique_ptr<OnDeviceModelExecutionConfigInterpreter> config_interpreter_; mojo::Remote<on_device_model::mojom::OnDeviceModelService> service_remote_;
diff --git a/components/optimization_guide/core/model_execution/on_device_model_service_controller_unittest.cc b/components/optimization_guide/core/model_execution/on_device_model_service_controller_unittest.cc index d7528d1..6030df6 100644 --- a/components/optimization_guide/core/model_execution/on_device_model_service_controller_unittest.cc +++ b/components/optimization_guide/core/model_execution/on_device_model_service_controller_unittest.cc
@@ -497,15 +497,16 @@ EXPECT_TRUE(*provided_by_on_device_); EXPECT_THAT(streamed_responses_, ElementsAre(expected_response)); EXPECT_TRUE(log_entry_received_); - EXPECT_GT(log_entry_received_->log_ai_data_request() - ->model_execution_info() - .on_device_model_execution_info() - .execution_infos_size(), - 0); - EXPECT_EQ(log_entry_received_->log_ai_data_request() - ->model_execution_info() - .on_device_model_execution_info() - .execution_infos(0) + const auto logged_on_device_model_execution_info = + log_entry_received_->log_ai_data_request() + ->model_execution_info() + .on_device_model_execution_info(); + EXPECT_EQ(logged_on_device_model_execution_info.model_versions() + .on_device_model_service_version() + .component_version(), + "0.0.1"); + EXPECT_GT(logged_on_device_model_execution_info.execution_infos_size(), 0); + EXPECT_EQ(logged_on_device_model_execution_info.execution_infos(0) .response() .on_device_model_service_response() .status(),
diff --git a/components/optimization_guide/core/model_execution/session_impl.cc b/components/optimization_guide/core/model_execution/session_impl.cc index 49ec394..32d439a3 100644 --- a/components/optimization_guide/core/model_execution/session_impl.cc +++ b/components/optimization_guide/core/model_execution/session_impl.cc
@@ -93,12 +93,14 @@ SessionImpl::SessionImpl( StartSessionFn start_session_fn, proto::ModelExecutionFeature feature, + std::optional<proto::OnDeviceModelVersions> on_device_model_versions, const OnDeviceModelExecutionConfigInterpreter* config_interpreter, base::WeakPtr<OnDeviceModelServiceController> controller, ExecuteRemoteFn execute_remote_fn, OptimizationGuideLogger* optimization_guide_logger) : controller_(controller), feature_(feature), + on_device_model_versions_(on_device_model_versions), execute_remote_fn_(std::move(execute_remote_fn)), optimization_guide_logger_(optimization_guide_logger) { if (controller_ && controller_->ShouldStartNewSession()) { @@ -215,6 +217,11 @@ return; } + CHECK(on_device_model_versions_); + *(log_ai_data_request->mutable_model_execution_info() + ->mutable_on_device_model_execution_info() + ->mutable_model_versions()) = *on_device_model_versions_; + if (on_device_state_->add_context_before_execute) { CHECK(context_); std::unique_ptr<google::protobuf::MessageLite> context =
diff --git a/components/optimization_guide/core/model_execution/session_impl.h b/components/optimization_guide/core/model_execution/session_impl.h index 6d4e266..ca42fdb 100644 --- a/components/optimization_guide/core/model_execution/session_impl.h +++ b/components/optimization_guide/core/model_execution/session_impl.h
@@ -79,12 +79,14 @@ kMaxValue = kContainedPII, }; - SessionImpl(StartSessionFn start_session_fn, - proto::ModelExecutionFeature feature, - const OnDeviceModelExecutionConfigInterpreter* config_interpreter, - base::WeakPtr<OnDeviceModelServiceController> controller, - ExecuteRemoteFn execute_remote_fn, - OptimizationGuideLogger* optimization_guide_logger); + SessionImpl( + StartSessionFn start_session_fn, + proto::ModelExecutionFeature feature, + std::optional<proto::OnDeviceModelVersions> on_device_model_versions, + const OnDeviceModelExecutionConfigInterpreter* config_interpreter, + base::WeakPtr<OnDeviceModelServiceController> controller, + ExecuteRemoteFn execute_remote_fn, + OptimizationGuideLogger* optimization_guide_logger); ~SessionImpl() override; // optimization_guide::OptimizationGuideModelExecutor::Session: @@ -200,6 +202,7 @@ base::WeakPtr<OnDeviceModelServiceController> controller_; const proto::ModelExecutionFeature feature_; + const std::optional<proto::OnDeviceModelVersions> on_device_model_versions_; ExecuteRemoteFn execute_remote_fn_;
diff --git a/components/optimization_guide/core/model_execution/test_on_device_model_component.cc b/components/optimization_guide/core/model_execution/test_on_device_model_component.cc index b6d9f0b..931f117 100644 --- a/components/optimization_guide/core/model_execution/test_on_device_model_component.cc +++ b/components/optimization_guide/core/model_execution/test_on_device_model_component.cc
@@ -107,7 +107,7 @@ void TestOnDeviceModelComponentStateManager::SetReady( const base::FilePath& install_dir) { - get()->SetReady(base::Version(), install_dir, base::Value::Dict()); + get()->SetReady(base::Version("0.0.1"), install_dir, base::Value::Dict()); } } // namespace optimization_guide
diff --git a/components/optimization_guide/core/model_quality/model_quality_logs_uploader_service.cc b/components/optimization_guide/core/model_quality/model_quality_logs_uploader_service.cc index be5b014d..d7dcdbfc 100644 --- a/components/optimization_guide/core/model_quality/model_quality_logs_uploader_service.cc +++ b/components/optimization_guide/core/model_quality/model_quality_logs_uploader_service.cc
@@ -221,6 +221,68 @@ resource_request->method = "POST"; resource_request->credentials_mode = network::mojom::CredentialsMode::kOmit; + net::NetworkTrafficAnnotationTag traffic_annotation = + net::DefineNetworkTrafficAnnotation("model_quality_logging", + R"( + semantics { + sender: "Optimization Guide Model Quality Logger" + description: + "Sends logging data about machine learning model requests, " + "responses and user interaction with the feature using the " + "machine learning model. Google may use this data to improve " + "Google products, including the machine learning models " + "themselves, or to develop new models." + trigger: + "Sent after the feature using the machine learning model " + "is no longer using the model response, and the user is " + "done interacting with the feature." + data: "The machine learning model request, response and " + "usage statistics, feedback data and device information " + "(platform, chrome version, etc.)." + internal { + contacts { + email: "chrome-intelligence-core@google.com" + } + } + user_data { + type: SENSITIVE_URL + type: WEB_CONTENT + type: USER_AGENT + type: USER_CONTENT + type: HW_OS_INFO + } + last_reviewed: "2024-01-12" + destination: GOOGLE_OWNED_SERVICE + } + policy { + cookies_allowed: NO + setting: + "Users can disable this by signing out of Chrome or by " + "disabling each feature using a machine learning model." + chrome_policy { + CreateThemesSettings { + CreateThemesSettings: 1 + } + TabOrganizerSettings { + TabOrganizerSettings: 1 + } + HelpMeWriteSettings { + HelpMeWriteSettings: 1 + } + } + chrome_policy { + CreateThemesSettings { + CreateThemesSettings: 2 + } + TabOrganizerSettings { + TabOrganizerSettings: 2 + } + HelpMeWriteSettings { + HelpMeWriteSettings: 2 + } + } + })"); + // Holds the currently active url request. std::unique_ptr<network::SimpleURLLoader> active_url_loader; active_url_loader = variations::CreateSimpleURLLoaderWithVariationsHeader( @@ -228,9 +290,7 @@ // This is always InIncognito::kNo as model quality logs upload is not // enabled on incognito sessions and is rechecked before each upload. variations::InIncognito::kNo, variations::SignedIn::kNo, - // TODO(crbug/1485313): Update the traffic annotations with more details - // about the features. - MISSING_TRAFFIC_ANNOTATION); + traffic_annotation); active_url_loader->AttachStringForUpload(serialized_logs, "application/x-protobuf");
diff --git a/components/optimization_guide/internal b/components/optimization_guide/internal index 7108a78..dd1eb9f 160000 --- a/components/optimization_guide/internal +++ b/components/optimization_guide/internal
@@ -1 +1 @@ -Subproject commit 7108a78492fbb8778d8783ea54643d63f600447d +Subproject commit dd1eb9fc0d4693ea83317b624df6c6f1002b04e7
diff --git a/components/optimization_guide/proto/model_quality_metadata.proto b/components/optimization_guide/proto/model_quality_metadata.proto index 4574b20..82972552 100644 --- a/components/optimization_guide/proto/model_quality_metadata.proto +++ b/components/optimization_guide/proto/model_quality_metadata.proto
@@ -58,13 +58,27 @@ } message OnDeviceModelExecutionInfo { - // The configuration that specifies how the device should have fulfilled the - // request. - OnDeviceModelExecutionFeatureConfig feature_config = 1; + reserved 1; // List of internal requests/responses that were performed to fulfill the // on-device model execution request. repeated InternalOnDeviceModelExecutionInfo execution_infos = 2; + + // Versions of the model being used for this execution. + OnDeviceModelVersions model_versions = 3; +} + +message OnDeviceModelVersions { + // The model version for the on-device model. + OnDeviceModelServiceVersion on_device_model_service_version = 1; + + // The model version for the text-safety model. + int64 text_safety_model_version = 2; +} + +message OnDeviceModelServiceVersion { + // The version of the component used. + string component_version = 1; } // InternalOnDeviceModelExecutionInfo is a request/response pair from a call to @@ -78,6 +92,8 @@ oneof request { // The request made to the on-device model service. OnDeviceModelServiceRequest on_device_model_service_request = 1; + // The request made to the text safety model. + TextSafetyModelRequest text_safety_model_request = 2; } } @@ -85,6 +101,8 @@ oneof response { // The response returned from the on-device model service. OnDeviceModelServiceResponse on_device_model_service_response = 1; + // The response returned from the text safety model. + TextSafetyModelResponse text_safety_model_response = 2; } } @@ -134,3 +152,13 @@ // The response is retracted by the service. ON_DEVICE_MODEL_SERVICE_RESPONSE_STATUS_RETRACTED = 2; } + +message TextSafetyModelRequest { + // The text sent to the text safety model for evaluation. + string text = 1; +} + +message TextSafetyModelResponse { + // The scores output by the model. + repeated float scores = 1; +}
diff --git a/components/user_education/common/feature_promo_session_manager.cc b/components/user_education/common/feature_promo_session_manager.cc index 1fbcc064..2fde4af 100644 --- a/components/user_education/common/feature_promo_session_manager.cc +++ b/components/user_education/common/feature_promo_session_manager.cc
@@ -8,6 +8,8 @@ #include "base/check_op.h" #include "base/functional/bind.h" #include "base/metrics/field_trial_params.h" +#include "base/metrics/histogram_functions.h" +#include "base/metrics/user_metrics.h" #include "base/time/time.h" #include "components/user_education/common/feature_promo_storage_service.h" #include "components/user_education/common/user_education_features.h" @@ -110,12 +112,60 @@ is_locked_); } -void FeaturePromoSessionManager::OnNewSession() {} +void FeaturePromoSessionManager::OnNewSession( + const base::Time old_start_time, + const base::Time old_active_time, + const base::Time new_active_time) { + base::RecordAction( + base::UserMetricsAction("UserEducation.Session.ActivePeriodStart")); + + // Now starting new session. The Active Period of the old session + // is the difference between old session times. + RecordActivePeriodDuration(old_active_time - old_start_time); + + // The now-elapsed Idle Period is difference between now and the + // previous most_recent_active_time. + RecordIdlePeriodDuration(new_active_time - old_active_time); +} void FeaturePromoSessionManager::OnIdleStateUpdating( base::Time new_last_active_time, bool new_locked_state) {} +void FeaturePromoSessionManager::RecordActivePeriodDuration( + base::TimeDelta duration) { + // Increments of 1 minute under 1 hour. + base::UmaHistogramCustomCounts( + "UserEducation.Session.ActivePeriodDuration.Min.Under1Hour", + duration.InMinutes(), /*min=*/1, + /*exclusive_max=*/60, + /*buckets=*/60); + + // Increments of 15 minutes under 24 hours. + base::UmaHistogramCustomCounts( + "UserEducation.Session.ActivePeriodDuration.Min.Under24Hours", + duration.InMinutes(), /*min=*/1, + /*exclusive_max=*/60 * 24 /* minutes per 24 hours */, + /*buckets=*/24 * 4 /* per 15 minutes */); +} + +void FeaturePromoSessionManager::RecordIdlePeriodDuration( + base::TimeDelta duration) { + // Increments of 15 minutes under 24 hours. + base::UmaHistogramCustomCounts( + "UserEducation.Session.IdlePeriodDuration.Min.Under24Hours", + duration.InMinutes(), /*min=*/1, + /*exclusive_max=*/60 * 24 /* minutes per 24 hours */, + /*buckets=*/24 * 4 /* per 15 minute */); + + // Increments of ~13 hours under 28 days. + base::UmaHistogramCustomCounts( + "UserEducation.Session.IdlePeriodDuration.Hr.Under28Days", + duration.InHours(), /*min=*/1, + /*exclusive_max=*/24 * 28 /* hours per 28 days */, + /*buckets=*/50); +} + void FeaturePromoSessionManager::UpdateIdleState( const IdleState& new_idle_state) { CHECK(idle_policy_); @@ -134,7 +184,7 @@ if (idle_policy_->IsNewSession(old_start_time, old_active_time, new_active_time)) { session_data.start_time = new_active_time; - OnNewSession(); + OnNewSession(old_start_time, old_active_time, new_active_time); } } storage_service_->SaveSessionData(session_data);
diff --git a/components/user_education/common/feature_promo_session_manager.h b/components/user_education/common/feature_promo_session_manager.h index 3b21404..93d71f1 100644 --- a/components/user_education/common/feature_promo_session_manager.h +++ b/components/user_education/common/feature_promo_session_manager.h
@@ -150,7 +150,9 @@ // Called when a new session is started. By default, does nothing. Override to // (for example) log metrics, or notify observers. - virtual void OnNewSession(); + virtual void OnNewSession(const base::Time old_start_time, + const base::Time old_active_time, + const base::Time new_active_time); // Called whenever the idle state is updated, before the session data is // updated in the storage service, so that both the current update and the @@ -160,6 +162,9 @@ bool new_locked_state); private: + void RecordActivePeriodDuration(base::TimeDelta duration); + void RecordIdlePeriodDuration(base::TimeDelta duration); + friend class FeaturePromoSessionManagerTest; friend test::FeaturePromoSessionTestUtil;
diff --git a/components/user_education/common/feature_promo_session_manager_unittest.cc b/components/user_education/common/feature_promo_session_manager_unittest.cc index ead874e..95a3cad 100644 --- a/components/user_education/common/feature_promo_session_manager_unittest.cc +++ b/components/user_education/common/feature_promo_session_manager_unittest.cc
@@ -203,7 +203,8 @@ .WillOnce(testing::Return(true)); EXPECT_CALL(session_manager(), OnIdleStateUpdating(kSecondNewActiveTime, false)); - EXPECT_CALL(session_manager(), OnNewSession); + EXPECT_CALL(session_manager(), OnNewSession(kSessionStartTime, kNewActiveTime, + kSecondNewActiveTime)); clock_.SetNow(kNow2); idle_observer().UpdateState({kSecondNewActiveTime, false}); }
diff --git a/components/user_education/test/mock_feature_promo_session_manager.h b/components/user_education/test/mock_feature_promo_session_manager.h index cf73697c..31d8706 100644 --- a/components/user_education/test/mock_feature_promo_session_manager.h +++ b/components/user_education/test/mock_feature_promo_session_manager.h
@@ -59,7 +59,10 @@ ~MockFeaturePromoSessionManager() override; MOCK_METHOD(void, OnIdleStateUpdating, (base::Time, bool), (override)); - MOCK_METHOD(void, OnNewSession, (), (override)); + MOCK_METHOD(void, + OnNewSession, + (const base::Time, const base::Time, const base::Time), + (override)); }; } // namespace user_education::test
diff --git a/components/viz/service/display/skia_renderer.cc b/components/viz/service/display/skia_renderer.cc index 56b436e..8b8a8d4 100644 --- a/components/viz/service/display/skia_renderer.cc +++ b/components/viz/service/display/skia_renderer.cc
@@ -3807,8 +3807,7 @@ return; } - // Clear the backing to ARGB(0,0,0,0). - current_canvas_->clear(SkColorSetARGB(0, 0, 0, 0)); + current_canvas_->clear(SK_ColorTRANSPARENT); // Adjust the |content_device_transform| to make sure filter extends are // drawn inside of the buffer.
diff --git a/components/viz/test/test_context_provider.cc b/components/viz/test/test_context_provider.cc index 70ff478..a3d7248c 100644 --- a/components/viz/test/test_context_provider.cc +++ b/components/viz/test/test_context_provider.cc
@@ -320,7 +320,7 @@ DestroySharedImage(sync_token, client_shared_image->mailbox()); } -gpu::SharedImageInterface::SwapChainMailboxes +gpu::SharedImageInterface::SwapChainSharedImages TestSharedImageInterface::CreateSwapChain(SharedImageFormat format, const gfx::Size& size, const gfx::ColorSpace& color_space, @@ -331,7 +331,8 @@ auto back_buffer = gpu::Mailbox::GenerateForSharedImage(); shared_images_.insert(front_buffer); shared_images_.insert(back_buffer); - return {front_buffer, back_buffer}; + return {base::MakeRefCounted<gpu::ClientSharedImage>(front_buffer), + base::MakeRefCounted<gpu::ClientSharedImage>(back_buffer)}; } void TestSharedImageInterface::PresentSwapChain(
diff --git a/components/viz/test/test_context_provider.h b/components/viz/test/test_context_provider.h index 7056c5ae..e22f141 100644 --- a/components/viz/test/test_context_provider.h +++ b/components/viz/test/test_context_provider.h
@@ -124,12 +124,12 @@ const gpu::SyncToken& sync_token, scoped_refptr<gpu::ClientSharedImage> client_shared_image) override; - SwapChainMailboxes CreateSwapChain(SharedImageFormat format, - const gfx::Size& size, - const gfx::ColorSpace& color_space, - GrSurfaceOrigin surface_origin, - SkAlphaType alpha_type, - uint32_t usage) override; + SwapChainSharedImages CreateSwapChain(SharedImageFormat format, + const gfx::Size& size, + const gfx::ColorSpace& color_space, + GrSurfaceOrigin surface_origin, + SkAlphaType alpha_type, + uint32_t usage) override; void PresentSwapChain(const gpu::SyncToken& sync_token, const gpu::Mailbox& mailbox) override;
diff --git a/content/browser/accessibility/browser_accessibility_manager.cc b/content/browser/accessibility/browser_accessibility_manager.cc index e115313..cca825aa 100644 --- a/content/browser/accessibility/browser_accessibility_manager.cc +++ b/content/browser/accessibility/browser_accessibility_manager.cc
@@ -995,6 +995,9 @@ base::RecordAction( base::UserMetricsAction("Accessibility.NativeApi.ScrollToMakeVisible")); + base::UmaHistogramBoolean("Accessibility.ScreenReader.ScrollToImage", + node.GetRole() == ax::mojom::Role::kImage); + ui::AXActionData action_data; action_data.target_node_id = node.GetId(); action_data.action = ax::mojom::Action::kScrollToMakeVisible;
diff --git a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc index 2bc8125..8b649f3 100644 --- a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc +++ b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
@@ -3139,16 +3139,6 @@ RunHtmlTest(FILE_PATH_LITERAL("selectlist-open.html")); } -// TODO(https://crbug.com/1309941): Flaky on Fuchsia -#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_FUCHSIA) -#define MAYBE_AccessibilitySource DISABLED_AccessibilitySource -#else -#define MAYBE_AccessibilitySource AccessibilitySource -#endif -IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest, MAYBE_AccessibilitySource) { - RunHtmlTest(FILE_PATH_LITERAL("source.html")); -} - IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest, AccessibilitySpan) { RunHtmlTest(FILE_PATH_LITERAL("span.html")); }
diff --git a/content/browser/attribution_reporting/attribution_src_browsertest.cc b/content/browser/attribution_reporting/attribution_src_browsertest.cc index 2240b7cc..4b3305b 100644 --- a/content/browser/attribution_reporting/attribution_src_browsertest.cc +++ b/content/browser/attribution_reporting/attribution_src_browsertest.cc
@@ -6,6 +6,7 @@ #include <utility> #include <vector> +#include "base/barrier_closure.h" #include "base/containers/contains.h" #include "base/location.h" #include "base/run_loop.h" @@ -16,22 +17,33 @@ #include "base/time/time.h" #include "components/attribution_reporting/aggregatable_dedup_key.h" #include "components/attribution_reporting/aggregatable_trigger_data.h" +#include "components/attribution_reporting/aggregation_keys.h" +#include "components/attribution_reporting/destination_set.h" #include "components/attribution_reporting/event_trigger_data.h" +#include "components/attribution_reporting/filters.h" #include "components/attribution_reporting/os_registration.h" #include "components/attribution_reporting/registration_eligibility.mojom.h" #include "components/attribution_reporting/source_registration.h" #include "components/attribution_reporting/source_registration_time_config.mojom.h" +#include "components/attribution_reporting/source_type.mojom.h" #include "components/attribution_reporting/suitable_origin.h" #include "components/attribution_reporting/test_utils.h" +#include "components/attribution_reporting/trigger_registration.h" #include "content/browser/attribution_reporting/attribution_constants.h" +#include "content/browser/attribution_reporting/attribution_data_host_manager_impl.h" +#include "content/browser/attribution_reporting/attribution_manager.h" #include "content/browser/attribution_reporting/attribution_manager_impl.h" #include "content/browser/attribution_reporting/attribution_os_level_manager.h" #include "content/browser/attribution_reporting/attribution_test_utils.h" +#include "content/browser/attribution_reporting/attribution_trigger.h" +#include "content/browser/attribution_reporting/os_registration.h" #include "content/browser/attribution_reporting/test/mock_attribution_host.h" +#include "content/browser/attribution_reporting/test/mock_attribution_manager.h" #include "content/browser/attribution_reporting/test/mock_content_browser_client.h" #include "content/browser/attribution_reporting/test/mock_data_host.h" #include "content/browser/attribution_reporting/test/source_observer.h" #include "content/browser/renderer_host/render_frame_host_impl.h" +#include "content/browser/storage_partition_impl.h" #include "content/browser/web_contents/web_contents_impl.h" #include "content/public/browser/navigation_handle.h" #include "content/public/common/content_features.h" @@ -65,11 +77,24 @@ namespace { +using ::attribution_reporting::AggregationKeys; +using ::attribution_reporting::DestinationSet; +using ::attribution_reporting::EventTriggerData; +using ::attribution_reporting::FilterData; +using ::attribution_reporting::SourceRegistration; +using ::attribution_reporting::SuitableOrigin; +using ::attribution_reporting::TriggerRegistration; using ::attribution_reporting::mojom::RegistrationEligibility; +using ::attribution_reporting::mojom::SourceType; using ::net::test_server::EmbeddedTestServer; +using ::testing::_; +using ::testing::AllOf; using ::testing::ElementsAre; +using ::testing::Field; using ::testing::IsEmpty; +using ::testing::Property; using ::testing::SizeIs; +using ::testing::StrictMock; } // namespace @@ -83,7 +108,13 @@ https_server_ = CreateAttributionTestHttpsServer(); ASSERT_TRUE(https_server_->Start()); - MockAttributionHost::Override(web_contents()); + auto mock_manager = std::make_unique<StrictMock<MockAttributionManager>>(); + auto data_host_manager = + std::make_unique<AttributionDataHostManagerImpl>(mock_manager.get()); + mock_manager->SetDataHostManager(std::move(data_host_manager)); + static_cast<StoragePartitionImpl*>( + web_contents()->GetBrowserContext()->GetDefaultStoragePartition()) + ->OverrideAttributionManagerForTesting(std::move(mock_manager)); } void SetUpCommandLine(base::CommandLine* command_line) override { @@ -94,15 +125,29 @@ WebContents* web_contents() { return shell()->web_contents(); } + protected: net::EmbeddedTestServer* https_server() { return https_server_.get(); } + StrictMock<MockAttributionManager>& mock_attribution_manager() { + return *static_cast<StrictMock<MockAttributionManager>*>( + AttributionManager::FromWebContents(web_contents())); + } + + // By default, the attribution_host isn't mocked. A real attribution host will + // be used and assertions should be on the `mock_attribution_manager`. If a + // test case wants to ensure that the attribution_host isn't reached, it can + // setup the mock attribution host with this method. + void SetupMockAttributionHost() { + MockAttributionHost::Override(web_contents()); + attribution_host_mocked_ = true; + } MockAttributionHost& mock_attribution_host() { + CHECK(attribution_host_mocked_); AttributionHost* attribution_host = AttributionHost::FromWebContents(web_contents()); return *static_cast<MockAttributionHost*>(attribution_host); } - protected: std::unique_ptr<EmbeddedTestServer> CreateAttributionTestHttpsServer() { auto https_server = std::make_unique<EmbeddedTestServer>(EmbeddedTestServer::TYPE_HTTPS); @@ -117,6 +162,7 @@ } private: + bool attribution_host_mocked_ = false; AttributionManagerImpl::ScopedUseInMemoryStorageForTesting attribution_manager_in_memory_setting_; std::unique_ptr<net::EmbeddedTestServer> https_server_; @@ -127,38 +173,39 @@ https_server()->GetURL("b.test", "/page_with_impression_creator.html"); EXPECT_TRUE(NavigateToURL(web_contents(), page_url)); - std::unique_ptr<MockDataHost> data_host; - base::RunLoop loop; - EXPECT_CALL(mock_attribution_host(), RegisterDataHost) - .WillOnce( - [&](mojo::PendingReceiver<blink::mojom::AttributionDataHost> host, - RegistrationEligibility) { - data_host = GetRegisteredDataHost(std::move(host)); - loop.Quit(); - }); - GURL register_url = https_server()->GetURL("c.test", "/register_source_headers.html"); + base::RunLoop run_loop; + // TODO: These checks are redundant with a variety of unit and/or WPT tests. + EXPECT_CALL( + mock_attribution_manager(), + HandleSource( + AllOf(SourceRegistrationIs(AllOf( + Field(&SourceRegistration::source_event_id, 5u), + Field(&SourceRegistration::priority, 0), + Field(&SourceRegistration::debug_key, std::nullopt), + Field(&SourceRegistration::debug_reporting, false), + Field(&SourceRegistration::expiry, base::Days(30)), + Field(&SourceRegistration::filter_data, + Property(&FilterData::filter_values, IsEmpty())), + Field(&SourceRegistration::aggregation_keys, + Property(&AggregationKeys::keys, IsEmpty())), + Field(&SourceRegistration::destination_set, + Property(&DestinationSet::destinations, + ElementsAre(net::SchemefulSite::Deserialize( + "https://d.test")))))), + SourceTypeIs(SourceType::kEvent), + ImpressionOriginIs(*SuitableOrigin::Create(page_url)), + ReportingOriginIs(*SuitableOrigin::Create(register_url))), + web_contents()->GetPrimaryMainFrame()->GetGlobalId())) + .Times(1) + .WillOnce([&run_loop]() { run_loop.Quit(); }); + EXPECT_TRUE(ExecJs(web_contents(), JsReplace("createAttributionSrcImg($1);", register_url))); - if (!data_host) { - loop.Run(); - } - data_host->WaitForSourceData(/*num_source_data=*/1); - const auto& source_data = data_host->source_data(); - // TODO: These checks are redundant with a variety of unit and/or WPT tests. - EXPECT_EQ(source_data.size(), 1u); - EXPECT_EQ(source_data.front().source_event_id, 5UL); - EXPECT_THAT(source_data.front().destination_set.destinations(), - ElementsAre(net::SchemefulSite::Deserialize("https://d.test"))); - EXPECT_EQ(source_data.front().priority, 0); - EXPECT_EQ(source_data.front().expiry, base::Days(30)); - EXPECT_FALSE(source_data.front().debug_key); - EXPECT_THAT(source_data.front().filter_data.filter_values(), IsEmpty()); - EXPECT_THAT(source_data.front().aggregation_keys.keys(), IsEmpty()); - EXPECT_FALSE(source_data.front().debug_reporting); + run_loop.Run(); } IN_PROC_BROWSER_TEST_F(AttributionSrcBrowserTest, @@ -172,43 +219,38 @@ for (const char* registration_js : kTestCases) { EXPECT_TRUE(NavigateToURL(web_contents(), page_url)); - std::unique_ptr<MockDataHost> data_host; - base::RunLoop loop, disconnect_loop; - EXPECT_CALL(mock_attribution_host(), RegisterDataHost) - .WillOnce( - [&](mojo::PendingReceiver<blink::mojom::AttributionDataHost> host, - RegistrationEligibility) { - data_host = GetRegisteredDataHost(std::move(host)); - data_host->receiver().set_disconnect_handler( - disconnect_loop.QuitClosure()); - loop.Quit(); - }); - GURL register_url = https_server()->GetURL("c.test", "/register_source_headers.html"); - + base::RunLoop run_loop; + // TODO: These checks are redundant with a variety of unit and/or WPT tests. + EXPECT_CALL( + mock_attribution_manager(), + HandleSource( + AllOf( + SourceRegistrationIs(AllOf( + Field(&SourceRegistration::source_event_id, 5u), + Field(&SourceRegistration::priority, 0), + Field(&SourceRegistration::debug_key, std::nullopt), + Field(&SourceRegistration::debug_reporting, false), + Field(&SourceRegistration::expiry, base::Days(30)), + Field(&SourceRegistration::filter_data, + Property(&FilterData::filter_values, IsEmpty())), + Field(&SourceRegistration::aggregation_keys, + Property(&AggregationKeys::keys, IsEmpty())), + Field(&SourceRegistration::destination_set, + Property(&DestinationSet::destinations, + ElementsAre(net::SchemefulSite::Deserialize( + "https://d.test")))))), + SourceTypeIs(SourceType::kEvent), + ImpressionOriginIs(*SuitableOrigin::Create(page_url)), + ReportingOriginIs(*SuitableOrigin::Create(register_url))), + web_contents()->GetPrimaryMainFrame()->GetGlobalId())) + .Times(1) + .WillOnce([&run_loop]() { run_loop.Quit(); }); EXPECT_TRUE( ExecJs(web_contents(), JsReplace(registration_js, register_url))); - if (!data_host) { - loop.Run(); - } - data_host->WaitForSourceData(/*num_source_data=*/1); - const auto& source_data = data_host->source_data(); - // Regression test for crbug.com/1336797. This will timeout flakily if the - // data host isn't disconnected promptly. - disconnect_loop.Run(); - // TODO: These checks are redundant with a variety of unit and/or WPT tests. - EXPECT_EQ(source_data.size(), 1u); - EXPECT_EQ(source_data.front().source_event_id, 5UL); - EXPECT_THAT(source_data.front().destination_set.destinations(), - ElementsAre(net::SchemefulSite::Deserialize("https://d.test"))); - EXPECT_EQ(source_data.front().priority, 0); - EXPECT_EQ(source_data.front().expiry, base::Days(30)); - EXPECT_FALSE(source_data.front().debug_key); - EXPECT_THAT(source_data.front().filter_data.filter_values(), IsEmpty()); - EXPECT_THAT(source_data.front().aggregation_keys.keys(), IsEmpty()); - EXPECT_FALSE(source_data.front().debug_reporting); + run_loop.Run(); } } @@ -335,6 +377,8 @@ IN_PROC_BROWSER_TEST_F( AttributionSrcBrowserTest, AttributionSrcWindowOpenNoUserGesture_NoBackgroundRequestNoImpression) { + SetupMockAttributionHost(); + // Create a separate server as we cannot register a `ControllableHttpResponse` // after the server starts. std::unique_ptr<EmbeddedTestServer> https_server = @@ -351,6 +395,9 @@ ASSERT_TRUE(NavigateToURL(web_contents(), page_url)); EXPECT_CALL(mock_attribution_host(), RegisterNavigationDataHost).Times(0); + EXPECT_CALL(mock_attribution_host(), + NotifyNavigationWithBackgroundRegistrationsWillStart) + .Times(0); ASSERT_TRUE(ExecJs(web_contents(), R"( window.open("page_with_conversion_redirect.html", "_top", @@ -368,34 +415,40 @@ https_server()->GetURL("b.test", "/page_with_impression_creator.html"); EXPECT_TRUE(NavigateToURL(web_contents(), page_url)); - std::unique_ptr<MockDataHost> data_host; - base::RunLoop loop; - EXPECT_CALL(mock_attribution_host(), RegisterDataHost) - .WillOnce( - [&](mojo::PendingReceiver<blink::mojom::AttributionDataHost> host, - RegistrationEligibility) { - data_host = GetRegisteredDataHost(std::move(host)); - loop.Quit(); - }); + base::RunLoop run_loop; + const auto on_source = base::BarrierClosure(2, run_loop.QuitClosure()); + EXPECT_CALL( + mock_attribution_manager(), + HandleSource( + SourceRegistrationIs( + AllOf(Field(&SourceRegistration::source_event_id, 1u), + Field(&SourceRegistration::destination_set, + Property(&DestinationSet::destinations, + ElementsAre(net::SchemefulSite::Deserialize( + "https://d.test")))))), + _)) + .Times(1) + .WillOnce([&on_source]() { on_source.Run(); }); + EXPECT_CALL( + mock_attribution_manager(), + HandleSource( + SourceRegistrationIs( + AllOf(Field(&SourceRegistration::source_event_id, 5u), + Field(&SourceRegistration::destination_set, + Property(&DestinationSet::destinations, + ElementsAre(net::SchemefulSite::Deserialize( + "https://d.test")))))), + _)) + .Times(1) + .WillOnce([&on_source]() { on_source.Run(); }); GURL register_url = https_server()->GetURL( "c.test", "/register_source_headers_and_redirect.html"); EXPECT_TRUE(ExecJs(web_contents(), JsReplace("createAttributionSrcImg($1);", register_url))); - if (!data_host) { - loop.Run(); - } - data_host->WaitForSourceData(/*num_source_data=*/2); - const auto& source_data = data_host->source_data(); - EXPECT_EQ(source_data.size(), 2u); - EXPECT_EQ(source_data.front().source_event_id, 1UL); - EXPECT_THAT(source_data.front().destination_set.destinations(), - ElementsAre(net::SchemefulSite::Deserialize("https://d.test"))); - EXPECT_EQ(source_data.back().source_event_id, 5UL); - EXPECT_THAT(source_data.back().destination_set.destinations(), - ElementsAre(net::SchemefulSite::Deserialize("https://d.test"))); + run_loop.Run(); } IN_PROC_BROWSER_TEST_F(AttributionSrcBrowserTest, @@ -404,32 +457,28 @@ https_server()->GetURL("b.test", "/page_with_impression_creator.html"); EXPECT_TRUE(NavigateToURL(web_contents(), page_url)); - std::unique_ptr<MockDataHost> data_host; - base::RunLoop loop; - EXPECT_CALL(mock_attribution_host(), RegisterDataHost) - .WillOnce( - [&](mojo::PendingReceiver<blink::mojom::AttributionDataHost> host, - RegistrationEligibility) { - data_host = GetRegisteredDataHost(std::move(host)); - loop.Quit(); - }); + base::RunLoop run_loop; + EXPECT_CALL( + mock_attribution_manager(), + HandleSource( + SourceRegistrationIs( + AllOf(Field(&SourceRegistration::source_event_id, 5u), + Field(&SourceRegistration::destination_set, + Property(&DestinationSet::destinations, + ElementsAre(net::SchemefulSite::Deserialize( + "https://d.test")))))), + _)) + .Times(1) + .WillOnce([&run_loop]() { run_loop.Quit(); }); GURL register_url = https_server()->GetURL( "c.test", "/register_source_headers_and_redirect_invalid.html"); EXPECT_TRUE(ExecJs(web_contents(), JsReplace("createAttributionSrcImg($1);", register_url))); - if (!data_host) { - loop.Run(); - } - data_host->WaitForSourceData(/*num_source_data=*/1); - const auto& source_data = data_host->source_data(); // Only the second source is registered. - EXPECT_EQ(source_data.size(), 1u); - EXPECT_EQ(source_data.back().source_event_id, 5UL); - EXPECT_THAT(source_data.back().destination_set.destinations(), - ElementsAre(net::SchemefulSite::Deserialize("https://d.test"))); + run_loop.Run(); } IN_PROC_BROWSER_TEST_F(AttributionSrcBrowserTest, @@ -448,15 +497,19 @@ https_server->GetURL("b.test", "/page_with_impression_creator.html"); EXPECT_TRUE(NavigateToURL(web_contents(), page_url)); - std::unique_ptr<MockDataHost> data_host; - base::RunLoop loop; - EXPECT_CALL(mock_attribution_host(), RegisterDataHost) - .WillOnce( - [&](mojo::PendingReceiver<blink::mojom::AttributionDataHost> host, - RegistrationEligibility) { - data_host = GetRegisteredDataHost(std::move(host)); - loop.Quit(); - }); + base::RunLoop run_loop; + EXPECT_CALL( + mock_attribution_manager(), + HandleSource( + SourceRegistrationIs( + AllOf(Field(&SourceRegistration::source_event_id, 5u), + Field(&SourceRegistration::destination_set, + Property(&DestinationSet::destinations, + ElementsAre(net::SchemefulSite::Deserialize( + "https://d.test")))))), + _)) + .Times(1) + .WillOnce([&run_loop]() { run_loop.Quit(); }); GURL register_url = https_server->GetURL("d.test", "/register_source"); EXPECT_TRUE(ExecJs(web_contents(), @@ -477,17 +530,8 @@ register_response->Send(http_response->ToResponseString()); register_response->Done(); - if (!data_host) { - loop.Run(); - } - data_host->WaitForSourceData(/*num_source_data=*/1); - const auto& source_data = data_host->source_data(); - // Only the second source is registered. - EXPECT_EQ(source_data.size(), 1u); - EXPECT_EQ(source_data.back().source_event_id, 5UL); - EXPECT_THAT(source_data.back().destination_set.destinations(), - ElementsAre(net::SchemefulSite::Deserialize("https://d.test"))); + run_loop.Run(); } IN_PROC_BROWSER_TEST_F(AttributionSrcBrowserTest, @@ -645,31 +689,23 @@ https_server()->GetURL("b.test", "/page_with_impression_creator.html"); EXPECT_TRUE(NavigateToURL(web_contents(), page_url)); - std::unique_ptr<MockDataHost> data_host; - base::RunLoop loop; - EXPECT_CALL(mock_attribution_host(), RegisterDataHost) - .WillOnce( - [&](mojo::PendingReceiver<blink::mojom::AttributionDataHost> host, - RegistrationEligibility) { - data_host = GetRegisteredDataHost(std::move(host)); - loop.Quit(); - }); - + base::RunLoop run_loop; + EXPECT_CALL(mock_attribution_manager(), HandleTrigger) + .Times(1) + .WillOnce([&run_loop]() { run_loop.Quit(); }); GURL register_url = https_server()->GetURL("c.test", "/register_trigger_headers.html"); const std::string& js_template = GetParam().second; EXPECT_TRUE(ExecJs(web_contents(), JsReplace(js_template, register_url))); - if (!data_host) { - loop.Run(); - } - data_host->WaitForTriggerData(/*num_trigger_data=*/1); - EXPECT_THAT(data_host->trigger_data(), SizeIs(1)); + run_loop.Run(); } IN_PROC_BROWSER_TEST_F(AttributionSrcBrowserTest, PermissionsPolicyDisabled_SourceNotRegistered) { + SetupMockAttributionHost(); + GURL page_url = https_server()->GetURL( "b.test", "/page_with_conversion_measurement_disabled.html"); EXPECT_TRUE(NavigateToURL(web_contents(), page_url)); @@ -693,30 +729,24 @@ https_server()->GetURL("b.test", "/page_with_impression_creator.html"); EXPECT_TRUE(NavigateToURL(web_contents(), page_url)); - std::unique_ptr<MockDataHost> data_host; - base::RunLoop loop; - EXPECT_CALL(mock_attribution_host(), RegisterDataHost) - .WillOnce( - [&](mojo::PendingReceiver<blink::mojom::AttributionDataHost> host, - RegistrationEligibility) { - data_host = GetRegisteredDataHost(std::move(host)); - loop.Quit(); - }); + base::RunLoop run_loop; + EXPECT_CALL( + mock_attribution_manager(), + HandleTrigger( + Property(&AttributionTrigger::registration, + Field(&TriggerRegistration::event_triggers, + ElementsAre(Field(&EventTriggerData::data, 7u)))), + _)) + .Times(1) + .WillOnce([&run_loop]() { run_loop.Quit(); }); GURL register_url = https_server()->GetURL( "c.test", "/register_trigger_headers_then_redirect_invalid.html"); EXPECT_TRUE(ExecJs(web_contents(), JsReplace("createAttributionSrcImg($1);", register_url))); - if (!data_host) { - loop.Run(); - } - data_host->WaitForTriggerData(/*num_trigger_data=*/1); - const auto& trigger_data = data_host->trigger_data(); - EXPECT_EQ(trigger_data.size(), 1u); - EXPECT_EQ(trigger_data.front().event_triggers.size(), 1u); - EXPECT_EQ(trigger_data.front().event_triggers.front().data, 7u); + run_loop.Run(); } IN_PROC_BROWSER_TEST_F(AttributionSrcBrowserTest, @@ -778,15 +808,10 @@ https_server->GetURL("c.test", "/page_with_impression_creator.html"); NavigateIframeToURL(web_contents(), "test_iframe", subframe_url); - std::unique_ptr<MockDataHost> data_host; - base::RunLoop loop; - EXPECT_CALL(mock_attribution_host(), RegisterDataHost) - .WillOnce( - [&](mojo::PendingReceiver<blink::mojom::AttributionDataHost> host, - RegistrationEligibility) { - data_host = GetRegisteredDataHost(std::move(host)); - loop.Quit(); - }); + base::RunLoop run_loop; + EXPECT_CALL(mock_attribution_manager(), HandleSource) + .Times(1) + .WillOnce([&run_loop]() { run_loop.Quit(); }); RenderFrameHost* subframe = ChildFrameAt(web_contents()->GetPrimaryMainFrame(), 0); @@ -804,16 +829,12 @@ auto http_response = std::make_unique<net::test_server::BasicHttpResponse>(); http_response->set_code(net::HTTP_OK); - http_response->AddCustomHeader( - kAttributionReportingRegisterSourceHeader, - R"({"destination":"https://d.test"})"); + http_response->AddCustomHeader(kAttributionReportingRegisterSourceHeader, + R"({"destination":"https://d.test"})"); register_response->Send(http_response->ToResponseString()); register_response->Done(); - if (!data_host) { - loop.Run(); - } - data_host->WaitForSourceData(/*num_source_data=*/1); + run_loop.Run(); } class AttributionSrcMultipleBackgroundRequestTest @@ -845,15 +866,15 @@ https_server.get(), "/trigger1"); ASSERT_TRUE(https_server->Start()); - std::unique_ptr<MockDataHost> data_host; - base::RunLoop loop; - EXPECT_CALL(mock_attribution_host(), RegisterDataHost) - .WillRepeatedly( - [&](mojo::PendingReceiver<blink::mojom::AttributionDataHost> host, - RegistrationEligibility) { - data_host = GetRegisteredDataHost(std::move(host)); - loop.Quit(); - }); + base::RunLoop run_loop; + const auto receive_registration = + base::BarrierClosure(2, run_loop.QuitClosure()); + EXPECT_CALL(mock_attribution_manager(), HandleSource) + .Times(1) + .WillOnce([&]() { receive_registration.Run(); }); + EXPECT_CALL(mock_attribution_manager(), HandleTrigger) + .Times(1) + .WillOnce([&]() { receive_registration.Run(); }); SourceObserver source_observer(web_contents()); GURL page_url = @@ -887,11 +908,7 @@ register_response2->Done(); } - if (!data_host) { - loop.Run(); - } - data_host->WaitForSourceAndTriggerData(/*num_source_data=*/1, - /*num_trigger_data=*/1); + run_loop.Run(); } class AttributionSrcPrerenderBrowserTest : public AttributionSrcBrowserTest { @@ -909,6 +926,7 @@ IN_PROC_BROWSER_TEST_F(AttributionSrcPrerenderBrowserTest, SourceNotRegisteredOnPrerender) { + SetupMockAttributionHost(); EXPECT_CALL(mock_attribution_host(), RegisterDataHost).Times(0); const GURL kInitialUrl = @@ -937,15 +955,13 @@ IN_PROC_BROWSER_TEST_F(AttributionSrcPrerenderBrowserTest, SourceRegisteredOnActivatedPrerender) { - std::unique_ptr<MockDataHost> data_host; - base::RunLoop loop; - EXPECT_CALL(mock_attribution_host(), RegisterDataHost) - .WillOnce( - [&](mojo::PendingReceiver<blink::mojom::AttributionDataHost> host, - RegistrationEligibility) { - data_host = GetRegisteredDataHost(std::move(host)); - loop.Quit(); - }); + base::RunLoop run_loop; + EXPECT_CALL(mock_attribution_manager(), + HandleSource(SourceRegistrationIs( + Field(&SourceRegistration::source_event_id, 5u)), + _)) + .Times(1) + .WillOnce([&run_loop]() { run_loop.Quit(); }); const GURL kInitialUrl = https_server()->GetURL("b.test", "/page_with_impression_creator.html"); @@ -969,18 +985,12 @@ prerender_helper_.NavigatePrimaryPage(page_url); ASSERT_EQ(page_url, web_contents()->GetLastCommittedURL()); - if (!data_host) { - loop.Run(); - } - data_host->WaitForSourceData(/*num_source_data=*/1); - const auto& source_data = data_host->source_data(); - - EXPECT_EQ(source_data.size(), 1u); - EXPECT_EQ(source_data.front().source_event_id, 5UL); + run_loop.Run(); } IN_PROC_BROWSER_TEST_F(AttributionSrcPrerenderBrowserTest, SubresourceTriggerNotRegisteredOnPrerender) { + SetupMockAttributionHost(); EXPECT_CALL(mock_attribution_host(), RegisterDataHost).Times(0); const GURL kInitialUrl = @@ -1009,15 +1019,16 @@ IN_PROC_BROWSER_TEST_F(AttributionSrcPrerenderBrowserTest, SubresourceTriggerRegisteredOnActivatedPrerender) { - std::unique_ptr<MockDataHost> data_host; base::RunLoop loop; - EXPECT_CALL(mock_attribution_host(), RegisterDataHost) - .WillOnce( - [&](mojo::PendingReceiver<blink::mojom::AttributionDataHost> host, - RegistrationEligibility) { - data_host = GetRegisteredDataHost(std::move(host)); - loop.Quit(); - }); + EXPECT_CALL( + mock_attribution_manager(), + HandleTrigger( + Property(&AttributionTrigger::registration, + Field(&TriggerRegistration::event_triggers, + ElementsAre(Field(&EventTriggerData::data, 7u)))), + _)) + .Times(1) + .WillOnce([&loop]() { loop.Quit(); }); const GURL kInitialUrl = https_server()->GetURL("b.test", "/page_with_impression_creator.html"); @@ -1049,15 +1060,7 @@ ASSERT_EQ(page_url, web_contents()->GetLastCommittedURL()); ASSERT_TRUE(host_observer.was_activated()); - if (!data_host) { - loop.Run(); - } - data_host->WaitForTriggerData(/*num_trigger_data=*/1); - const auto& trigger_data = data_host->trigger_data(); - - ASSERT_EQ(trigger_data.size(), 1u); - ASSERT_EQ(trigger_data.front().event_triggers.size(), 1u); - EXPECT_EQ(trigger_data.front().event_triggers.front().data, 7u); + loop.Run(); } class AttributionSrcFencedFrameBrowserTest : public AttributionSrcBrowserTest { @@ -1074,6 +1077,7 @@ IN_PROC_BROWSER_TEST_F(AttributionSrcFencedFrameBrowserTest, DefaultMode_SourceNotRegistered) { + SetupMockAttributionHost(); GURL main_url = https_server()->GetURL("b.test", "/title1.html"); EXPECT_TRUE(NavigateToURL(shell(), main_url)); @@ -1141,16 +1145,10 @@ EXPECT_TRUE(fenced_frame_host2->IsFencedFrameRoot()); - std::unique_ptr<MockDataHost> data_host; - base::RunLoop loop; - - EXPECT_CALL(mock_attribution_host(), RegisterDataHost) - .WillOnce( - [&](mojo::PendingReceiver<blink::mojom::AttributionDataHost> host, - RegistrationEligibility) { - data_host = GetRegisteredDataHost(std::move(host)); - loop.Quit(); - }); + base::RunLoop run_loop; + EXPECT_CALL(mock_attribution_manager(), HandleSource) + .Times(1) + .WillOnce([&run_loop]() { run_loop.Quit(); }); EXPECT_TRUE(ExecJs( fenced_frame_host2.get(), @@ -1158,12 +1156,7 @@ "createAttributionSrcImg($1);", https_server()->GetURL("c.test", "/register_source_headers.html")))); - if (!data_host) { - loop.Run(); - } - - data_host->WaitForSourceData(/*num_source_data=*/1); - EXPECT_EQ(data_host->source_data().size(), 1u); + run_loop.Run(); } // Tests to verify that cross app web is not enabled when base::Feature is @@ -1410,10 +1403,8 @@ struct OsRegistrationTestCase { const char* name; const char* header; - std::vector<std::vector<attribution_reporting::OsRegistrationItem>> - expected_os_sources; - std::vector<std::vector<attribution_reporting::OsRegistrationItem>> - expected_os_triggers; + std::vector<attribution_reporting::OsRegistrationItem> + expected_os_registrations; }; class AttributionSrcCrossAppWebEnabledOsRegistrationBrowserTest @@ -1427,30 +1418,26 @@ OsRegistrationTestCase{ .name = "source", .header = "Attribution-Reporting-Register-OS-Source", - .expected_os_sources = + .expected_os_registrations = { - { - attribution_reporting::OsRegistrationItem{ - .url = GURL("https://r1.test/x")}, - attribution_reporting::OsRegistrationItem{ - .url = GURL("https://r2.test/y"), - .debug_reporting = true, - }, + attribution_reporting::OsRegistrationItem{ + .url = GURL("https://r1.test/x")}, + attribution_reporting::OsRegistrationItem{ + .url = GURL("https://r2.test/y"), + .debug_reporting = true, }, }, }, OsRegistrationTestCase{ .name = "trigger", .header = "Attribution-Reporting-Register-OS-Trigger", - .expected_os_triggers = + .expected_os_registrations = { - { - attribution_reporting::OsRegistrationItem{ - .url = GURL("https://r1.test/x")}, - attribution_reporting::OsRegistrationItem{ - .url = GURL("https://r2.test/y"), - .debug_reporting = true, - }, + attribution_reporting::OsRegistrationItem{ + .url = GURL("https://r1.test/x")}, + attribution_reporting::OsRegistrationItem{ + .url = GURL("https://r2.test/y"), + .debug_reporting = true, }, }, }), @@ -1466,15 +1453,16 @@ std::unique_ptr<EmbeddedTestServer> https_server = CreateAttributionTestHttpsServer(); - std::unique_ptr<MockDataHost> data_host; - base::RunLoop loop; - EXPECT_CALL(mock_attribution_host(), RegisterDataHost) - .WillOnce( - [&](mojo::PendingReceiver<blink::mojom::AttributionDataHost> host, - RegistrationEligibility) { - data_host = GetRegisteredDataHost(std::move(host)); - loop.Quit(); - }); + base::RunLoop run_loop; + const auto on_registration = base::BarrierClosure( + test_case.expected_os_registrations.size(), run_loop.QuitClosure()); + for (auto item : test_case.expected_os_registrations) { + EXPECT_CALL(mock_attribution_manager(), + HandleOsRegistration( + AllOf(Field(&OsRegistration::registration_url, item.url)))) + .Times(1) + .WillOnce([&on_registration]() { on_registration.Run(); }); + } auto register_response = std::make_unique<net::test_server::ControllableHttpResponse>( @@ -1501,14 +1489,7 @@ register_response->Send(http_response->ToResponseString()); register_response->Done(); - if (!data_host) { - loop.Run(); - } - data_host->WaitForOsSources(test_case.expected_os_sources.size()); - data_host->WaitForOsTriggers(test_case.expected_os_triggers.size()); - - EXPECT_EQ(data_host->os_sources(), test_case.expected_os_sources); - EXPECT_EQ(data_host->os_triggers(), test_case.expected_os_triggers); + run_loop.Run(); } class AttributionSrcInBrowserMigrationEnabledBrowserTest @@ -1527,6 +1508,8 @@ IN_PROC_BROWSER_TEST_F(AttributionSrcInBrowserMigrationEnabledBrowserTest, BackgroundSourceRegistrationRequestSent) { + SetupMockAttributionHost(); + // Create a separate server as we cannot register a `ControllableHttpResponse` // after the server starts. std::unique_ptr<EmbeddedTestServer> https_server =
diff --git a/content/browser/attribution_reporting/trigger_registration_browsertest.cc b/content/browser/attribution_reporting/trigger_registration_browsertest.cc index f6e0c778..e1bf47bb 100644 --- a/content/browser/attribution_reporting/trigger_registration_browsertest.cc +++ b/content/browser/attribution_reporting/trigger_registration_browsertest.cc
@@ -4,15 +4,16 @@ #include <memory> +#include "base/barrier_closure.h" #include "base/functional/bind.h" #include "components/attribution_reporting/event_trigger_data.h" #include "components/attribution_reporting/registration_eligibility.mojom.h" #include "components/attribution_reporting/test_utils.h" #include "components/attribution_reporting/trigger_registration.h" +#include "content/browser/attribution_reporting/attribution_data_host_manager_impl.h" #include "content/browser/attribution_reporting/attribution_manager_impl.h" #include "content/browser/attribution_reporting/attribution_test_utils.h" -#include "content/browser/attribution_reporting/test/mock_attribution_host.h" -#include "content/browser/attribution_reporting/test/mock_data_host.h" +#include "content/browser/attribution_reporting/test/mock_attribution_manager.h" #include "content/browser/web_contents/web_contents_impl.h" #include "content/public/common/content_switches.h" #include "content/public/test/browser_test.h" @@ -33,9 +34,13 @@ namespace { +using ::attribution_reporting::EventTriggerData; +using ::attribution_reporting::TriggerRegistration; using ::attribution_reporting::mojom::RegistrationEligibility; +using ::testing::_; using ::testing::ElementsAre; using ::testing::Field; +using ::testing::StrictMock; } // namespace @@ -63,17 +68,22 @@ "content/test/data/attribution_reporting"); ASSERT_TRUE(https_server_->Start()); - MockAttributionHost::Override(web_contents()); + auto mock_manager = std::make_unique<StrictMock<MockAttributionManager>>(); + auto data_host_manager = + std::make_unique<AttributionDataHostManagerImpl>(mock_manager.get()); + mock_manager->SetDataHostManager(std::move(data_host_manager)); + static_cast<StoragePartitionImpl*>( + web_contents()->GetBrowserContext()->GetDefaultStoragePartition()) + ->OverrideAttributionManagerForTesting(std::move(mock_manager)); } WebContents* web_contents() { return shell()->web_contents(); } net::EmbeddedTestServer* https_server() { return https_server_.get(); } - MockAttributionHost& mock_attribution_host() { - AttributionHost* attribution_host = - AttributionHost::FromWebContents(web_contents()); - return *static_cast<MockAttributionHost*>(attribution_host); + StrictMock<MockAttributionManager>& mock_attribution_manager() { + return *static_cast<StrictMock<MockAttributionManager>*>( + AttributionManager::FromWebContents(web_contents())); } private: @@ -89,17 +99,26 @@ shell(), https_server()->GetURL("c.test", "/page_with_conversion_redirect.html"))); - std::vector<std::unique_ptr<MockDataHost>> data_hosts; - base::RunLoop loop; - EXPECT_CALL(mock_attribution_host(), RegisterDataHost) - .WillRepeatedly( - [&](mojo::PendingReceiver<blink::mojom::AttributionDataHost> host, - RegistrationEligibility) { - data_hosts.push_back(GetRegisteredDataHost(std::move(host))); - if (data_hosts.size() == 2) { - loop.Quit(); - } - }); + base::RunLoop run_loop; + const auto on_trigger = base::BarrierClosure(2, run_loop.QuitClosure()); + EXPECT_CALL( + mock_attribution_manager(), + HandleTrigger( + Property(&AttributionTrigger::registration, + Field(&TriggerRegistration::event_triggers, + ElementsAre(Field(&EventTriggerData::data, 5u)))), + _)) + .Times(1) + .WillOnce([&on_trigger]() { on_trigger.Run(); }); + EXPECT_CALL( + mock_attribution_manager(), + HandleTrigger( + Property(&AttributionTrigger::registration, + Field(&TriggerRegistration::event_triggers, + ElementsAre(Field(&EventTriggerData::data, 7u)))), + _)) + .Times(1) + .WillOnce([&on_trigger]() { on_trigger.Run(); }); GURL register_url = https_server()->GetURL( "c.test", "/register_trigger_headers_and_redirect.html"); @@ -107,27 +126,7 @@ EXPECT_TRUE(ExecJs(web_contents(), JsReplace("createTrackingPixel($1);", register_url))); - if (data_hosts.size() != 2) { - loop.Run(); - } - - data_hosts.front()->WaitForTriggerData(/*num_trigger_data=*/1); - const auto& trigger_data1 = data_hosts.front()->trigger_data(); - - EXPECT_THAT(trigger_data1, - ElementsAre(Field( - &attribution_reporting::TriggerRegistration::event_triggers, - ElementsAre(Field( - &attribution_reporting::EventTriggerData::data, 5))))); - - data_hosts.back()->WaitForTriggerData(/*num_trigger_data=*/1); - const auto& trigger_data2 = data_hosts.back()->trigger_data(); - - EXPECT_THAT(trigger_data2, - ElementsAre(Field( - &attribution_reporting::TriggerRegistration::event_triggers, - ElementsAre(Field( - &attribution_reporting::EventTriggerData::data, 7))))); + run_loop.Run(); } } // namespace content
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc index 286ed37..b62442d 100644 --- a/content/browser/renderer_host/render_widget_host_impl.cc +++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -2237,9 +2237,9 @@ } #if BUILDFLAG(IS_MAC) - // MacOS version of underlying GrabViewSnapshot() blocks while - // display/GPU are in a power-saving mode, so make sure display - // does not go to sleep for the duration of reading a snapshot. + // The Mac version of underlying GrabViewSnapshotAsync() blocks while the + // display/GPU are in a power-saving mode, so make sure the display does not + // go to sleep for the duration of reading a snapshot. if (pending_browser_snapshots_.empty()) { GetWakeLock()->RequestWakeLock(); } @@ -3577,13 +3577,6 @@ gfx::Rect snapshot_bounds(GetView()->GetViewBounds().size()); #endif - gfx::Image image; - if (ui::GrabViewSnapshot(GetView()->GetNativeView(), snapshot_bounds, - &image)) { - OnSnapshotReceived(snapshot_id, image); - return; - } - ui::GrabViewSnapshotAsync( GetView()->GetNativeView(), snapshot_bounds, base::BindOnce(&RenderWidgetHostImpl::OnSnapshotReceived,
diff --git a/content/test/content_test_bundle_data.filelist b/content/test/content_test_bundle_data.filelist index fc5d1d36..d555851e 100644 --- a/content/test/content_test_bundle_data.filelist +++ b/content/test/content_test_bundle_data.filelist
@@ -4643,12 +4643,6 @@ data/accessibility/html/small-expected-uia-win.txt data/accessibility/html/small-expected-win.txt data/accessibility/html/small.html -data/accessibility/html/source-expected-android.txt -data/accessibility/html/source-expected-auralinux.txt -data/accessibility/html/source-expected-fuchsia.txt -data/accessibility/html/source-expected-mac.txt -data/accessibility/html/source-expected-win.txt -data/accessibility/html/source.html data/accessibility/html/span-expected-android-assist-data.txt data/accessibility/html/span-expected-android-external.txt data/accessibility/html/span-expected-android.txt
diff --git a/content/test/data/accessibility/html/audio-expected-auralinux.txt b/content/test/data/accessibility/html/audio-expected-auralinux.txt index a9f5ed7af..2146298 100644 --- a/content/test/data/accessibility/html/audio-expected-auralinux.txt +++ b/content/test/data/accessibility/html/audio-expected-auralinux.txt
@@ -1,15 +1,15 @@ -[document web] +[document web] focusable focused ++[section] -++++[audio] +++++[audio] focusable ++++++[section] ++++++++[section] ++++++++++[section] -++++++++++++[push button] name='play' +++++++++++++[push button] name='play' focusable ++++++++++++++[section] -++++++++++++[slider] name='audio time scrubber' description='total time: 0:00' horizontal description:total time: 0:00 description-from:aria-description current=0.000000 minimum=0.000000 maximum=0.313469 +++++++++++++[slider] name='audio time scrubber' description='total time: 0:00' focusable horizontal description:total time: 0:00 description-from:aria-description current=0.000000 minimum=0.000000 maximum=0.313469 ++++++++++++[section] ++++++++++++++[section] -++++++++++++++[slider] name='volume' horizontal current=100.000000 minimum=0.000000 maximum=100.000000 -++++++++++++++[push button] name='mute' -++++++++++++[push button] name='show more media controls' description='more options' description-from:tooltip +++++++++++++++[slider] name='volume' focusable horizontal current=100.000000 minimum=0.000000 maximum=100.000000 +++++++++++++++[push button] name='mute' focusable +++++++++++++[push button] name='show more media controls' description='more options' focusable description-from:tooltip ++++++++++++++[section]
diff --git a/content/test/data/accessibility/html/audio.html b/content/test/data/accessibility/html/audio.html index 0b166eaa..657c60778 100644 --- a/content/test/data/accessibility/html/audio.html +++ b/content/test/data/accessibility/html/audio.html
@@ -7,6 +7,7 @@ @AURALINUX-ALLOW:description* @AURALINUX-ALLOW:horizontal @AURALINUX-ALLOW:vertical +@AURALINUX-ALLOW:focus* @WAIT-FOR:volume --> <!DOCTYPE html>
diff --git a/content/test/data/accessibility/html/source-expected-android.txt b/content/test/data/accessibility/html/source-expected-android.txt deleted file mode 100644 index 4a45339..0000000 --- a/content/test/data/accessibility/html/source-expected-android.txt +++ /dev/null
@@ -1,8 +0,0 @@ -#<skip -- crbug.com/281952> -android.webkit.WebView focusable focused scrollable -++android.view.View -++++android.view.View focusable name='0:00' -++++++android.view.View name='audio' -++++++++android.view.View name='audio' -++++++++++android.widget.Button clickable focusable name='play' -++++++++++android.widget.SeekBar clickable focusable range name='movie time scrubber'
diff --git a/content/test/data/accessibility/html/source-expected-auralinux.txt b/content/test/data/accessibility/html/source-expected-auralinux.txt deleted file mode 100644 index 9f30f2d..0000000 --- a/content/test/data/accessibility/html/source-expected-auralinux.txt +++ /dev/null
@@ -1,13 +0,0 @@ -[document web] focusable focused -++[section] -++++[audio] focusable -++++++[section] -++++++++[tool bar] name='audio' description='audio' horizontal -++++++++++[tool bar] name='audio' description='audio' horizontal -++++++++++++[push button] name='play' focusable -++++++++++++[static] name='0:00' -++++++++++++[static] name='/ 0:00' -++++++++++++[slider] description='audio time scrubber' focusable horizontal -++++++++++++[section] -++++++++++++++[section] -++++++++++++++[push button] name='mute'
diff --git a/content/test/data/accessibility/html/source-expected-fuchsia.txt b/content/test/data/accessibility/html/source-expected-fuchsia.txt deleted file mode 100644 index 7ca7ed3..0000000 --- a/content/test/data/accessibility/html/source-expected-fuchsia.txt +++ /dev/null
@@ -1,64 +0,0 @@ -UNKNOWN focusable has_input_focus -++UNKNOWN hidden -++++UNKNOWN -++++++UNKNOWN focusable -++++++++UNKNOWN -++++++++++UNKNOWN hidden -++++++++++++BUTTON hidden -++++++++++UNKNOWN -++++++++++++UNKNOWN -++++++++++++++BUTTON focusable label='play' actions='{DEFAULT}' -++++++++++++++++UNKNOWN -++++++++++++++UNKNOWN label='elapsed time: 0:00' -++++++++++++++++STATIC_TEXT label='0:00' -++++++++++++++++++UNKNOWN label='0:00' -++++++++++++++UNKNOWN label='total time: / 0:00' -++++++++++++++++STATIC_TEXT label='/ 0:00' -++++++++++++++++++UNKNOWN label='/ 0:00' -++++++++++++++SLIDER focusable label='audio time scrubber 0:00 / 0:00' actions='{SET_VALUE}' value='elapsed time: 0:00' -++++++++++++++UNKNOWN -++++++++++++++++UNKNOWN -++++++++++++++++SLIDER focusable label='volume' actions='{SET_VALUE}' -++++++++++++++++BUTTON focusable label='mute' actions='{DEFAULT}' -++++++++++++++BUTTON hidden -++++++++++++++++UNKNOWN hidden -++++++++++++++BUTTON focusable label='show more media controls' actions='{DEFAULT}' secondary_label='more options' -++++++++++++++++UNKNOWN -++++++++++UNKNOWN hidden -++++++++++UNKNOWN hidden -++++++++++UNKNOWN hidden -++++++++++++UNKNOWN hidden -++++++++++++++BUTTON hidden -++++++++++++++UNKNOWN hidden -++++++++++++++++UNKNOWN hidden -++++++++++++++++++STATIC_TEXT hidden label='Play' -++++++++++++UNKNOWN hidden -++++++++++++++BUTTON hidden -++++++++++++++UNKNOWN hidden -++++++++++++++++UNKNOWN hidden -++++++++++++++++++STATIC_TEXT hidden label='Fullscreen' -++++++++++++UNKNOWN hidden -++++++++++++++BUTTON hidden -++++++++++++++UNKNOWN hidden -++++++++++++++++UNKNOWN hidden -++++++++++++++++++STATIC_TEXT hidden label='Download' -++++++++++++UNKNOWN hidden -++++++++++++++BUTTON hidden -++++++++++++++UNKNOWN hidden -++++++++++++++++UNKNOWN hidden -++++++++++++++++++STATIC_TEXT hidden label='Mute' -++++++++++++UNKNOWN hidden -++++++++++++++BUTTON hidden -++++++++++++++UNKNOWN hidden -++++++++++++++++UNKNOWN hidden -++++++++++++++++++STATIC_TEXT hidden label='Cast' -++++++++++++UNKNOWN hidden -++++++++++++++BUTTON hidden -++++++++++++++UNKNOWN hidden -++++++++++++++++UNKNOWN hidden -++++++++++++++++++STATIC_TEXT hidden label='Captions' -++++++++++++UNKNOWN hidden -++++++++++++++BUTTON hidden -++++++++++++++UNKNOWN hidden -++++++++++++++++UNKNOWN hidden -++++++++++++++++++STATIC_TEXT hidden label='Playback speed'
diff --git a/content/test/data/accessibility/html/source-expected-mac.txt b/content/test/data/accessibility/html/source-expected-mac.txt deleted file mode 100644 index b278a4c..0000000 --- a/content/test/data/accessibility/html/source-expected-mac.txt +++ /dev/null
@@ -1,11 +0,0 @@ -#<skip -- crbug.com/281952> -AXWebArea -++AXGroup -++++AXUnknown AXTitle='0:00' -++++++AXToolbar AXTitle='media control' -++++++++AXToolbar AXTitle='media control' -++++++++++AXButton -++++++++++AXSlider AXValue='0' -++++++++++AXGroup -++++++++++++AXStaticText AXValue='0:00' -++++++++++AXButton
diff --git a/content/test/data/accessibility/html/source-expected-win.txt b/content/test/data/accessibility/html/source-expected-win.txt deleted file mode 100644 index bb6b1f6..0000000 --- a/content/test/data/accessibility/html/source-expected-win.txt +++ /dev/null
@@ -1,11 +0,0 @@ -#<skip -- crbug.com/281952> -ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE -++IA2_ROLE_SECTION READONLY -++++ROLE_SYSTEM_CLIENT name='0:00' FOCUSABLE -++++++ROLE_SYSTEM_TOOLBAR name='audio' READONLY -++++++++ROLE_SYSTEM_TOOLBAR name='audio' READONLY -++++++++++ROLE_SYSTEM_PUSHBUTTON name='play' FOCUSABLE -++++++++++ROLE_SYSTEM_SLIDER name='movie time scrubber' FOCUSABLE -++++++++++IA2_ROLE_SECTION READONLY -++++++++++++ROLE_SYSTEM_STATICTEXT name='0:00' -++++++++++ROLE_SYSTEM_PUSHBUTTON name='mute' FOCUSABLE
diff --git a/content/test/data/accessibility/html/source.html b/content/test/data/accessibility/html/source.html deleted file mode 100644 index 238e8b7e7..0000000 --- a/content/test/data/accessibility/html/source.html +++ /dev/null
@@ -1,13 +0,0 @@ -<!-- -@AURALINUX-ALLOW:focus* -@AURALINUX-ALLOW:horizontal -@AURALINUX-ALLOW:vertical ---> -<!DOCTYPE html> -<html> -<body> - <audio controls> - <source src="sfx.mp3" type="audio/mpeg"> - </audio> -</body> -</html>
diff --git a/content/test/gpu/gpu_tests/test_expectations/context_lost_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/context_lost_expectations.txt index a3ab5b6c..e20256a 100644 --- a/content/test/gpu/gpu_tests/test_expectations/context_lost_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/context_lost_expectations.txt
@@ -201,6 +201,10 @@ crbug.com/1505662 [ angle-swiftshader fuchsia fuchsia-board-qemu-x64 google-0xc0de ] ContextLost_WebGLContextLostFromSelectElement [ Failure ] +# Broadly flaky unsymbolized crashes on Jacuzzi +crbug.com/1518007 [ chromeos cros-chrome chromeos-board-jacuzzi ] ContextLost_* [ RetryOnFailure ] +crbug.com/1518007 [ chromeos cros-chrome chromeos-board-jacuzzi ] GpuNormalTermination_OriginalWebGLNotBlocked [ RetryOnFailure ] + ####################################################################### # Automated Entries After This Point - Do Not Manually Add Below Here # #######################################################################
diff --git a/content/test/gpu/gpu_tests/test_expectations/gpu_process_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/gpu_process_expectations.txt index 33bbd17d..a1471e3 100644 --- a/content/test/gpu/gpu_tests/test_expectations/gpu_process_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/gpu_process_expectations.txt
@@ -137,8 +137,8 @@ ################### # Non-"Skip" expectations go here to suppress regular flakes/failures. - - +# Broadly flaky unsymbolized crashes on Jacuzzi +crbug.com/1518007 [ chromeos cros-chrome chromeos-board-jacuzzi ] GpuProcess_* [ RetryOnFailure ] ####################################################################### # Automated Entries After This Point - Do Not Manually Add Below Here #
diff --git a/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt index 6e46331a..feff364 100644 --- a/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
@@ -427,6 +427,10 @@ crbug.com/1516974 [ chromeos cros-chrome chromeos-board-volteer ] Pixel_WebGLTransparentGreenTriangle_NoAlpha_ImplicitClear [ Failure ] crbug.com/1516977 [ chromeos cros-chrome chromeos-board-volteer ] Pixel_WebGLContextRestored [ Failure ] +# Broadly flaky unsymbolized crashes on Jacuzzi +crbug.com/1518007 [ chromeos cros-chrome chromeos-board-jacuzzi ] Pixel_OffscreenCanvas* [ RetryOnFailure ] +crbug.com/1518007 [ chromeos cros-chrome chromeos-board-jacuzzi ] Pixel_Video* [ RetryOnFailure ] +crbug.com/1518007 [ chromeos cros-chrome chromeos-board-jacuzzi ] Pixel_WebGL* [ RetryOnFailure ] ####################################################################### # Automated Entries After This Point - Do Not Manually Add Below Here #
diff --git a/content/test/gpu/gpu_tests/test_expectations/screenshot_sync_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/screenshot_sync_expectations.txt index 0c43e402..20c3913 100644 --- a/content/test/gpu/gpu_tests/test_expectations/screenshot_sync_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/screenshot_sync_expectations.txt
@@ -99,6 +99,8 @@ ################### # Non-"Skip" expectations go here to suppress regular flakes/failures. +# Broadly flaky unsymbolized crashes on Jacuzzi +crbug.com/1518007 [ chromeos cros-chrome chromeos-board-jacuzzi ] ScreenshotSync_* [ RetryOnFailure ] ####################################################################### # Automated Entries After This Point - Do Not Manually Add Below Here #
diff --git a/content/test/gpu/gpu_tests/test_expectations/trace_test_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/trace_test_expectations.txt index b2dc913..0d0d384 100644 --- a/content/test/gpu/gpu_tests/test_expectations/trace_test_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/trace_test_expectations.txt
@@ -244,7 +244,13 @@ # Win AMD failure since test added crbug.com/1446057 [ win10 amd-0x7340 angle-d3d11 ] VideoPathTraceTest_DirectComposition_Video_SW_Decode [ Failure ] - +# Broadly flaky unsymbolized crashes on Jacuzzi +crbug.com/1518007 [ chromeos cros-chrome chromeos-board-jacuzzi ] TraceTest_BackgroundImage [ RetryOnFailure ] +crbug.com/1518007 [ chromeos cros-chrome chromeos-board-jacuzzi ] TraceTest_Canvas2D* [ RetryOnFailure ] +crbug.com/1518007 [ chromeos cros-chrome chromeos-board-jacuzzi ] TraceTest_SolidColorBackground [ RetryOnFailure ] +crbug.com/1518007 [ chromeos cros-chrome chromeos-board-jacuzzi ] TraceTest_Video_* [ RetryOnFailure ] +crbug.com/1518007 [ chromeos cros-chrome chromeos-board-jacuzzi ] TraceTest_WebGL* [ RetryOnFailure ] +crbug.com/1518007 [ chromeos cros-chrome chromeos-board-jacuzzi ] WebGLCanvasCaptureTraceTest_VideoStream* [ RetryOnFailure ] ####################################################################### # Automated Entries After This Point - Do Not Manually Add Below Here #
diff --git a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt index 30a5bc6..ff7c9a4 100644 --- a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
@@ -873,6 +873,11 @@ crbug.com/1499536 [ chromeos cros-chrome chromeos-board-jacuzzi ] deqp/functional/gles3/uniformbuffers/single_basic_array.html [ Failure ] crbug.com/1499536 [ chromeos cros-chrome chromeos-board-jacuzzi ] deqp/functional/gles3/uniformbuffers/single_basic_type.html [ Failure ] crbug.com/1500045 [ chromeos cros-chrome chromeos-board-jacuzzi ] conformance2/rendering/blitframebuffer-r11f-g11f-b10f.html [ Failure ] +# Broadly flaky unsymbolized crashes on Jacuzzi +crbug.com/1518007 [ chromeos cros-chrome chromeos-board-jacuzzi ] WebglExtension_* [ RetryOnFailure ] +crbug.com/1518007 [ chromeos cros-chrome chromeos-board-jacuzzi ] conformance/* [ RetryOnFailure ] +crbug.com/1518007 [ chromeos cros-chrome chromeos-board-jacuzzi ] conformance2/* [ RetryOnFailure ] +crbug.com/1518007 [ chromeos cros-chrome chromeos-board-jacuzzi ] deqp/* [ RetryOnFailure ] ## Volteer ## crbug.com/1507164 [ chromeos cros-chrome chromeos-board-volteer ] conformance2/rendering/blitframebuffer-filter-outofbounds.html [ Failure ]
diff --git a/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt index fd91a80..78e71c43 100644 --- a/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt
@@ -708,6 +708,9 @@ crbug.com/1492234 [ chromeos cros-chrome chromeos-board-jacuzzi angle-opengles passthrough arm ] conformance/extensions/angle-instanced-arrays-out-of-bounds.html [ Failure ] crbug.com/1492240 [ chromeos cros-chrome chromeos-board-jacuzzi ] conformance/extensions/ext-disjoint-timer-query.html [ Failure ] crbug.com/1492241 [ chromeos cros-chrome chromeos-board-jacuzzi ] conformance/rendering/clear-default-framebuffer-with-scissor-test.html [ Failure ] +# Broadly flaky unsymbolized crashes on Jacuzzi +crbug.com/1518007 [ chromeos cros-chrome chromeos-board-jacuzzi ] WebglExtension_* [ RetryOnFailure ] +crbug.com/1518007 [ chromeos cros-chrome chromeos-board-jacuzzi ] conformance/* [ RetryOnFailure ] ##################### # Lacros failures #
diff --git a/device/fido/features.cc b/device/fido/features.cc index 48e235f..b0fce505 100644 --- a/device/fido/features.cc +++ b/device/fido/features.cc
@@ -102,11 +102,6 @@ base::FEATURE_ENABLED_BY_DEFAULT); // Enabled in M117. Remove in or after M120. -BASE_FEATURE(kWebAuthnCableViaCredMan, - "WebAuthenticationCableViaCredMan", - base::FEATURE_ENABLED_BY_DEFAULT); - -// Enabled in M117. Remove in or after M120. BASE_FEATURE(kWebAuthnLinkingExperimentation, "WebAuthenticationLinkingExperimentation", base::FEATURE_ENABLED_BY_DEFAULT);
diff --git a/device/fido/features.h b/device/fido/features.h index 4c71805b..a5f54cf 100644 --- a/device/fido/features.h +++ b/device/fido/features.h
@@ -78,10 +78,6 @@ COMPONENT_EXPORT(DEVICE_FIDO) BASE_DECLARE_FEATURE(kWebAuthConditionalUIExperimentation); -// Handle caBLE requests on Android with the CredMan-capable code path. -COMPONENT_EXPORT(DEVICE_FIDO) -BASE_DECLARE_FEATURE(kWebAuthnCableViaCredMan); - // Allow some sites to experiment with removing caBLE linking in requests. COMPONENT_EXPORT(DEVICE_FIDO) BASE_DECLARE_FEATURE(kWebAuthnLinkingExperimentation);
diff --git a/device/vr/openxr/openxr_extension_helper.cc b/device/vr/openxr/openxr_extension_helper.cc index 6e89d18..6ce8fb8 100644 --- a/device/vr/openxr/openxr_extension_helper.cc +++ b/device/vr/openxr/openxr_extension_helper.cc
@@ -15,6 +15,9 @@ #include "device/vr/openxr/openxr_scene_understanding_manager.h" #include "device/vr/openxr/openxr_stage_bounds_provider_basic.h" #include "device/vr/public/mojom/xr_session.mojom.h" +// Included on all platforms so that we can check the extension names, even +// if they may not be supported there. +#include "third_party/openxr/dev/xr_android.h" #if BUILDFLAG(IS_ANDROID) #include "device/vr/openxr/android/openxr_hand_tracker_android.h" @@ -181,7 +184,8 @@ return IsExtensionSupported(XR_EXT_HAND_TRACKING_EXTENSION_NAME) && (IsExtensionSupported(XR_EXT_HAND_INTERACTION_EXTENSION_NAME) || IsExtensionSupported(XR_MSFT_HAND_INTERACTION_EXTENSION_NAME) || - IsExtensionSupported(XR_FB_HAND_TRACKING_AIM_EXTENSION_NAME)); + IsExtensionSupported(XR_FB_HAND_TRACKING_AIM_EXTENSION_NAME) || + IsExtensionSupported(XR_ANDROID_HAND_GESTURE_EXTENSION_NAME)); case device::mojom::XRSessionFeature::HIT_TEST: return IsExtensionSupported(XR_MSFT_SCENE_UNDERSTANDING_EXTENSION_NAME); case device::mojom::XRSessionFeature::SECONDARY_VIEWS:
diff --git a/docs/ios/build_instructions.md b/docs/ios/build_instructions.md index 0da74c1..8a3a76e 100644 --- a/docs/ios/build_instructions.md +++ b/docs/ios/build_instructions.md
@@ -209,7 +209,8 @@ with Chromium and other applications from the same organisation and can be used to send commands to Chromium. -`${prefix}.chrome.ios.dev.CredentialProviderExtension` needs the AutoFill +`${prefix}.chrome.ios.dev` and +`${prefix}.chrome.ios.dev.CredentialProviderExtension` need the AutoFill Credential Provider Entitlement, which corresponds to the key `com.apple.developer.authentication-services.autofill-credential-provider` Please refer to Apple's documentation on how to set this up.
diff --git a/docs/rust.md b/docs/rust.md index 913f98c..c3f4967a 100644 --- a/docs/rust.md +++ b/docs/rust.md
@@ -47,6 +47,11 @@ itself is never built, it is only used to collect dependencies through the `[dependencies]` section. +These instructions require the presence of nightly `cargo` which is normally found +in `//third_party/rust-toolchain/bin`. But [on Mac Arm](https://crbug.com/1515913) +it is missing, and will need to be installed separately with +[`rustup install nightly`](https://rustup.rs/) and added to the `PATH` environment. + To use a third-party crate "bar" version 3 from first party code: 1. Change directory to the root `src/` dir of Chromium. 1. Add the crate to `//third_party/rust/chromium_crates_io/Cargo.toml`: @@ -78,14 +83,11 @@ * Or, directly through (nightly) cargo: `cargo run --release --manifest-path tools/crates/gnrt/Cargo.toml --target-dir out/gnrt gen` 1. Verify if all new dependencies are already audited by running `cargo vet`: - * To install and use `cargo vet`, you need nightly cargo in your `PATH`, which can be - found in `//third_party/rust-toolchain/bin` (except [on Mac Arm](https://crbug.com/1515913), - where it will need to be installed separately with - [`rustup install nightly`](https://rustup.rs/)). - * `cargo install --git https://github.com/mozilla/cargo-vet cargo-vet` + * Install `cargo vet` if it's not yet installed: + * `./tools/crates/run_cargo.py install --git https://github.com/mozilla/cargo-vet cargo-vet` * We use `--git` to install cargo-vet from HEAD in order to use the `--cargo-arg` argument which is not released yet. - * `cargo -Zunstable-options -C third_party/rust/chromium_crates_io/ vet check --cargo-arg=-Zbindeps --no-registry-suggestions` + * `./tools/crates/run_cargo.py -Zunstable-options -C third_party/rust/chromium_crates_io/ vet check --cargo-arg=-Zbindeps --no-registry-suggestions` * If `check` fails, then there are missing audits, which need to be added to `//third_party/rust/chromium_crates_io/supply-chain/audits.toml`. * See [auditing_standards.md](https://github.com/google/rust-crate-audits/blob/main/auditing_standards.md)
diff --git a/extensions/browser/api/web_request/extension_web_request_event_router.cc b/extensions/browser/api/web_request/extension_web_request_event_router.cc index f8fcf5e..cd1add50 100644 --- a/extensions/browser/api/web_request/extension_web_request_event_router.cc +++ b/extensions/browser/api/web_request/extension_web_request_event_router.cc
@@ -1528,7 +1528,10 @@ // regular event dispatching code for this case, as well? EventRouter::Get(id.browser_context) ->DispatchEventToSender( - render_process, id.browser_context, listener->id.extension_id, + render_process, id.browser_context, + /*host_id=*/ + mojom::HostID(mojom::HostID::HostType::kExtensions, + listener->id.extension_id), listener->histogram_value, listener->id.sub_event_name, listener->id.worker_thread_id, listener->id.service_worker_version_id,
diff --git a/extensions/browser/event_router.cc b/extensions/browser/event_router.cc index af33f0a..17045cc 100644 --- a/extensions/browser/event_router.cc +++ b/extensions/browser/event_router.cc
@@ -49,6 +49,7 @@ #include "extensions/common/mojom/context_type.mojom.h" #include "extensions/common/mojom/event_dispatcher.mojom.h" #include "extensions/common/permissions/permissions_data.h" +#include "extensions/common/utils/extension_utils.h" #include "ipc/ipc_channel_proxy.h" #include "url/origin.h" @@ -170,17 +171,21 @@ content::RenderProcessHost* rph, int worker_thread_id, content::BrowserContext* browser_context, - const std::string& extension_id, + const mojom::HostID& host_id, int event_id, const std::string& event_name, base::Value::List event_args, UserGestureState user_gesture, mojom::EventFilteringInfoPtr info, mojom::EventDispatcher::DispatchEventCallback callback) { - NotifyEventDispatched(browser_context, extension_id, event_name, event_args); + if (host_id.type == mojom::HostID::HostType::kExtensions) { + NotifyEventDispatched(browser_context, + GenerateExtensionIdFromHostId(host_id), event_name, + event_args); + } auto params = mojom::DispatchEventParams::New(); params->worker_thread_id = worker_thread_id; - params->extension_id = extension_id; + params->host_id = host_id.Clone(); params->event_name = event_name; params->event_id = event_id; params->is_user_gesture = user_gesture == USER_GESTURE_ENABLED; @@ -235,7 +240,7 @@ void EventRouter::DispatchEventToSender( content::RenderProcessHost* rph, content::BrowserContext* browser_context, - const std::string& extension_id, + const mojom::HostID& host_id, events::HistogramValue histogram_value, const std::string& event_name, int worker_thread_id, @@ -247,8 +252,11 @@ auto* registry = ExtensionRegistry::Get(browser_context); CHECK(registry); - const Extension* extension = - registry->enabled_extensions().GetByID(extension_id); + const Extension* extension = nullptr; + if (host_id.type == mojom::HostID::HostType::kExtensions) { + extension = registry->enabled_extensions().GetByID(host_id.id); + } + mojom::EventDispatcher::DispatchEventCallback callback; // If this is ever false, we won't log the metric for dispatch_start_time. But // this means we aren't dispatching an event to an extension so the metric @@ -274,24 +282,24 @@ if (BackgroundInfo::HasLazyBackgroundPage(extension)) { callback = base::BindOnce( &EventRouter::DecrementInFlightEventsForRenderFrameHost, - weak_factory_.GetWeakPtr(), rph->GetID(), extension_id, event_id); + weak_factory_.GetWeakPtr(), rph->GetID(), host_id.id, event_id); } else { callback = base::DoNothing(); } } else { - callback = - base::BindOnce(&EventRouter::DecrementInFlightEventsForServiceWorker, - weak_factory_.GetWeakPtr(), - WorkerId{extension_id, rph->GetID(), - service_worker_version_id, worker_thread_id}, - event_id); + callback = base::BindOnce( + &EventRouter::DecrementInFlightEventsForServiceWorker, + weak_factory_.GetWeakPtr(), + WorkerId{GenerateExtensionIdFromHostId(host_id), rph->GetID(), + service_worker_version_id, worker_thread_id}, + event_id); } #endif } else { callback = base::DoNothing(); } ObserveProcess(rph); - DispatchExtensionMessage(rph, worker_thread_id, browser_context, extension_id, + DispatchExtensionMessage(rph, worker_thread_id, browser_context, host_id, event_id, event_name, std::move(event_args), UserGestureState::USER_GESTURE_UNKNOWN, std::move(info), std::move(callback)); @@ -1204,7 +1212,8 @@ #endif DispatchExtensionMessage(process, worker_thread_id, listener_context, - extension_id, event_id, event.event_name, + GenerateHostIdFromExtensionId(extension_id), + event_id, event.event_name, std::move(event_args_to_use), event.user_gesture, std::move(filter_info), std::move(callback)); @@ -1303,13 +1312,10 @@ // Only increment in-flight events if the lazy background page is active. if (BackgroundInfo::HasLazyBackgroundPage(extension)) { pm->IncrementLazyKeepaliveCount(extension, Activity::EVENT, event_name); - host->OnBackgroundEventDispatched(event_name, dispatch_start_time, - event_id, dispatch_source, - lazy_background_active_on_dispatch); - } else { // persistent background page. - host->OnPersistentBackgroundEventDispatched( - event_name, dispatch_start_time, event_id, dispatch_source); } + host->OnBackgroundEventDispatched(event_name, dispatch_start_time, + event_id, dispatch_source, + lazy_background_active_on_dispatch); } } else if (service_worker_version_id != blink::mojom::kInvalidServiceWorkerVersionId) {
diff --git a/extensions/browser/event_router.h b/extensions/browser/event_router.h index fb2d5ac..3a803f664 100644 --- a/extensions/browser/event_router.h +++ b/extensions/browser/event_router.h
@@ -35,6 +35,7 @@ #include "extensions/common/mojom/context_type.mojom-forward.h" #include "extensions/common/mojom/event_dispatcher.mojom.h" #include "extensions/common/mojom/event_router.mojom.h" +#include "extensions/common/mojom/host_id.mojom.h" #include "ipc/ipc_sender.h" #include "mojo/public/cpp/bindings/associated_receiver_set.h" #include "mojo/public/cpp/bindings/associated_remote.h" @@ -140,7 +141,7 @@ // `EventRouter` is shared between on- and off-the-record contexts. void DispatchEventToSender(content::RenderProcessHost* rph, content::BrowserContext* browser_context, - const std::string& extension_id, + const mojom::HostID& host_id, events::HistogramValue histogram_value, const std::string& event_name, int worker_thread_id, @@ -388,7 +389,7 @@ content::RenderProcessHost* rph, int worker_thread_id, content::BrowserContext* browser_context, - const std::string& extension_id, + const mojom::HostID& host_id, int event_id, const std::string& event_name, base::Value::List event_args, @@ -609,7 +610,9 @@ base::TimeTicks dispatch_start_time; // `true` if the event was dispatched to a active/running lazy background. - // Used in UMA histograms. + // This is only used for lazy background contexts (event pages and service + // workers), it is unused for persistent background pages. Used in UMA + // histograms. bool lazy_background_active_on_dispatch; // Whether a user gesture triggered the event.
diff --git a/extensions/browser/extension_host.cc b/extensions/browser/extension_host.cc index 110849f..52e6a29f 100644 --- a/extensions/browser/extension_host.cc +++ b/extensions/browser/extension_host.cc
@@ -222,7 +222,10 @@ int event_id, EventDispatchSource dispatch_source, bool lazy_background_active_on_dispatch) { + // TODO(crbug.com/1441221): Make IsBackgroundPage() a real CHECK. It's + // effectively a DCHECK right now. CHECK(IsBackgroundPage()); + CHECK(BackgroundInfo::HasBackgroundPage(extension())); // See ExtensionHost::OnEventAck() for an explanation on the restriction to // this event flow. if (dispatch_source == EventDispatchSource::kDispatchEventToProcess) { @@ -244,28 +247,6 @@ observer.OnBackgroundEventDispatched(this, event_name, event_id); } -// TODO(crbug.com/1441221): Condense with -// ExtensionHost::OnBackgroundEventDispatched() once stale events metric is -// added for persistent background pages. -void ExtensionHost::OnPersistentBackgroundEventDispatched( - const std::string& event_name, - base::TimeTicks dispatch_start_time, - int event_id, - EventDispatchSource dispatch_source) { - CHECK(IsBackgroundPage()); - - // We don't expect unacked_messages to be written more than once per event_id - // since event_ids are supposed to be unique per event dispatch to each - // extension. - CHECK(unacked_messages_.count(event_id) == 0); - unacked_messages_[event_id] = - UnackedEventData{event_name, dispatch_start_time, dispatch_source}; - - for (auto& observer : observer_list_) { - observer.OnBackgroundEventDispatched(this, event_name, event_id); - } -} - void ExtensionHost::OnNetworkRequestStarted(uint64_t request_id) { for (auto& observer : observer_list_) observer.OnNetworkRequestStarted(this, request_id); @@ -402,11 +383,16 @@ // If the event is still present then we haven't received the ack yet in // `ExtensionHost::OnEventAck()`. if (unacked_messages_.contains(event_id)) { - // TODO(crbug.com/1470045): Update this histogram once we have a way to ack - // only for lazy background page events. Until then this could be slightly - // inaccurate and not perfectly comparable to the service worker version. - base::UmaHistogramBoolean( - "Extensions.Events.DidDispatchToAckSucceed.ExtensionPage", false); + const char* metric_name = + BackgroundInfo::HasLazyBackgroundPage(extension()) + ? "Extensions.Events.DidDispatchToAckSucceed.ExtensionPage" + : "Extensions.Events.DidDispatchToAckSucceed." + "ExtensionPersistentPage"; + // TODO(crbug.com/1470045): Update this histogram once we have a way to + // ack only for lazy background page events. Until then this could be + // slightly inaccurate and not perfectly comparable to the service worker + // version. + base::UmaHistogramBoolean(metric_name, false); } } @@ -469,18 +455,20 @@ // can't exclude non-script extensions page contexts (e.g. popup scripts) yet // so we have to emit this for all events to remain proportionate to the // `false` emits. - if (BackgroundInfo::HasLazyBackgroundPage(extension())) { - bool late_ack = - (base::TimeTicks::Now() - unacked_message_data.dispatch_start_time) > - kEventAckMetricTimeLimit; - if (!late_ack) { - // Emit only if we're within the expected event ack time limit. We'll take - // care of the emit for a late ack via a delayed task we started on event - // dispatch. - // TODO(crbug.com/1441221): Emit this metric for persistent background - // pages. + bool late_ack = + (base::TimeTicks::Now() - unacked_message_data.dispatch_start_time) > + kEventAckMetricTimeLimit; + if (!late_ack) { + // Emit only if we're within the expected event ack time limit. We'll take + // care of the emit for a late ack via a delayed task we started on event + // dispatch. + if (BackgroundInfo::HasLazyBackgroundPage(extension())) { base::UmaHistogramBoolean( "Extensions.Events.DidDispatchToAckSucceed.ExtensionPage", true); + } else if (BackgroundInfo::HasPersistentBackgroundPage(extension())) { + base::UmaHistogramBoolean( + "Extensions.Events.DidDispatchToAckSucceed.ExtensionPersistentPage", + true); } }
diff --git a/extensions/browser/extension_host.h b/extensions/browser/extension_host.h index 0759d7a5..94b02bc 100644 --- a/extensions/browser/extension_host.h +++ b/extensions/browser/extension_host.h
@@ -111,19 +111,13 @@ void AddObserver(ExtensionHostObserver* observer); void RemoveObserver(ExtensionHostObserver* observer); - // Called when an event is dispatched to the event page associated with this - // ExtensionHost. + // Called when an event is dispatched to a lazy background page associated + // with this ExtensionHost. void OnBackgroundEventDispatched(const std::string& event_name, base::TimeTicks dispatch_start_time, int event_id, EventDispatchSource dispatch_source, bool lazy_background_active_on_dispatch); - // The same as above, but for persistent background pages. - void OnPersistentBackgroundEventDispatched( - const std::string& event_name, - base::TimeTicks dispatch_start_time, - int event_id, - EventDispatchSource dispatch_source); // Called by the ProcessManager when a network request is started by the // extension corresponding to this ExtensionHost.
diff --git a/extensions/browser/extension_util.cc b/extensions/browser/extension_util.cc index c43da8a..54f60f7 100644 --- a/extensions/browser/extension_util.cc +++ b/extensions/browser/extension_util.cc
@@ -58,7 +58,7 @@ } // namespace -mojom::HostID::HostType HostIDTypeFromGuestView( +mojom::HostID::HostType HostIdTypeFromGuestView( const guest_view::GuestViewBase& guest) { if (guest.IsOwnedByWebUI()) { return mojom::HostID::HostType::kWebUi; @@ -78,9 +78,9 @@ return mojom::HostID::HostType::kExtensions; } -mojom::HostID GenerateHostIDFromGuestView( +mojom::HostID GenerateHostIdFromGuestView( const guest_view::GuestViewBase& guest) { - return mojom::HostID(HostIDTypeFromGuestView(guest), guest.owner_host()); + return mojom::HostID(HostIdTypeFromGuestView(guest), guest.owner_host()); } bool CanBeIncognitoEnabled(const Extension* extension) {
diff --git a/extensions/browser/extension_util.h b/extensions/browser/extension_util.h index 13cf4fc..02351b4 100644 --- a/extensions/browser/extension_util.h +++ b/extensions/browser/extension_util.h
@@ -46,11 +46,11 @@ // extensions/ here. // Returns a HostID type based on the given GuestViewBase. -mojom::HostID::HostType HostIDTypeFromGuestView( +mojom::HostID::HostType HostIdTypeFromGuestView( const guest_view::GuestViewBase& guest); // Returns a HostID instance based on the given GuestViewBase. -mojom::HostID GenerateHostIDFromGuestView( +mojom::HostID GenerateHostIdFromGuestView( const guest_view::GuestViewBase& guest); // Returns true if the extension can be enabled in incognito mode.
diff --git a/extensions/browser/guest_view/extensions_guest_view_manager_delegate.cc b/extensions/browser/guest_view/extensions_guest_view_manager_delegate.cc index da3f37b..80aba24 100644 --- a/extensions/browser/guest_view/extensions_guest_view_manager_delegate.cc +++ b/extensions/browser/guest_view/extensions_guest_view_manager_delegate.cc
@@ -32,6 +32,7 @@ #include "extensions/common/features/feature_provider.h" #include "extensions/common/mojom/event_dispatcher.mojom.h" #include "extensions/common/mojom/view_type.mojom.h" +#include "extensions/common/utils/extension_utils.h" #include "third_party/blink/public/mojom/service_worker/service_worker_object.mojom-forward.h" using guest_view::GuestViewBase; @@ -86,6 +87,7 @@ base::Value::Dict args, GuestViewBase* guest, int instance_id) { + CHECK(guest); mojom::EventFilteringInfoPtr info = mojom::EventFilteringInfo::New(); info->has_instance_id = true; info->instance_id = instance_id; @@ -109,7 +111,8 @@ EventRouter::Get(guest->browser_context()) ->DispatchEventToSender(owner->GetProcess(), guest->browser_context(), - guest->owner_host(), histogram_value, event_name, + util::GenerateHostIdFromGuestView(*guest), + histogram_value, event_name, extensions::kMainThreadId, blink::mojom::kInvalidServiceWorkerVersionId, std::move(event_args), std::move(info));
diff --git a/extensions/common/mojom/event_dispatcher.mojom b/extensions/common/mojom/event_dispatcher.mojom index fe4f7e5..aaf3537 100644 --- a/extensions/common/mojom/event_dispatcher.mojom +++ b/extensions/common/mojom/event_dispatcher.mojom
@@ -4,6 +4,7 @@ module extensions.mojom; +import "extensions/common/mojom/host_id.mojom"; import "mojo/public/mojom/base/values.mojom"; import "url/mojom/url.mojom"; // EventDispatch is a one-per-renderer-processs interface that is responsible @@ -46,8 +47,8 @@ // id. Otherwise, this is 0. int32 worker_thread_id; - // The id of the extension to dispatch the event to. - string extension_id; + // The |HostID| to route the event to. + HostID host_id; // The name of the event to dispatch. string event_name;
diff --git a/extensions/common/utils/extension_utils.h b/extensions/common/utils/extension_utils.h index e769885..21c19656 100644 --- a/extensions/common/utils/extension_utils.h +++ b/extensions/common/utils/extension_utils.h
@@ -7,6 +7,8 @@ #include <string> +#include "extensions/common/mojom/host_id.mojom.h" + namespace extensions { class Extension; @@ -14,6 +16,30 @@ // Returns the extension ID or an empty string if null. const std::string& MaybeGetExtensionId(const Extension* extension); +// Returns a HostID instance based on an |extension_id|. +inline mojom::HostID GenerateHostIdFromExtensionId( + const std::string& extension_id) { + // Note: an empty |extension_id| can be used to refer to *all* extensions. + // See comment in dispatcher.cc. + return mojom::HostID(mojom::HostID::HostType::kExtensions, extension_id); +} + +// Returns a HostID instance based on an |extension|. +inline mojom::HostID GenerateHostIdFromExtension(const Extension* extension) { + // Note: in some cases, a null Extension can be used. These cases should + // result in a HostID that's kExtensions with an id that's the empty string. + // See runtime_hooks_delegate_unittest.cc for an example. + return GenerateHostIdFromExtensionId(MaybeGetExtensionId(extension)); +} + +// Returns an |extension_id| from a HostID instance. Will CHECK if +// the HostID type isn't kExtensions. +inline const std::string& GenerateExtensionIdFromHostId( + const mojom::HostID& host_id) { + CHECK_EQ(host_id.type, mojom::HostID::HostType::kExtensions); + return host_id.id; +} + } // namespace extensions #endif // EXTENSIONS_COMMON_UTILS_EXTENSION_UTILS_H_
diff --git a/extensions/renderer/api/messaging/native_renderer_messaging_service.cc b/extensions/renderer/api/messaging/native_renderer_messaging_service.cc index ff83140..c35bd16 100644 --- a/extensions/renderer/api/messaging/native_renderer_messaging_service.cc +++ b/extensions/renderer/api/messaging/native_renderer_messaging_service.cc
@@ -24,6 +24,7 @@ #include "extensions/common/manifest_handlers/externally_connectable.h" #include "extensions/common/mojom/context_type.mojom.h" #include "extensions/common/mojom/message_port.mojom-shared.h" +#include "extensions/common/utils/extension_utils.h" #include "extensions/renderer/api/messaging/message_target.h" #include "extensions/renderer/api/messaging/messaging_util.h" #include "extensions/renderer/api_activity_logger.h" @@ -307,7 +308,7 @@ bool port_created = false; context_set->ForEach( - info.target_id, restrict_to_render_frame, + GenerateHostIdFromExtensionId(info.target_id), restrict_to_render_frame, base::BindRepeating( &NativeRendererMessagingService::DispatchOnConnectToScriptContext, base::Unretained(this), target_port_id, channel_type, channel_name,
diff --git a/extensions/renderer/api_activity_logger_unittest.cc b/extensions/renderer/api_activity_logger_unittest.cc index c3bf8bf..52f5448 100644 --- a/extensions/renderer/api_activity_logger_unittest.cc +++ b/extensions/renderer/api_activity_logger_unittest.cc
@@ -12,6 +12,7 @@ #include "extensions/common/extension_messages.h" #include "extensions/common/features/feature.h" #include "extensions/common/mojom/context_type.mojom.h" +#include "extensions/common/utils/extension_utils.h" #include "extensions/renderer/bindings/api_binding_test.h" #include "extensions/renderer/bindings/api_binding_test_util.h" #include "extensions/renderer/ipc_message_sender.h" @@ -60,8 +61,8 @@ const mojom::ContextType kContextType = mojom::ContextType::kPrivilegedExtension; script_context_set.AddForTesting(std::make_unique<ScriptContext>( - context, nullptr, extension.get(), kContextType, extension.get(), - kContextType)); + context, nullptr, GenerateHostIdFromExtensionId(extension->id()), + extension.get(), kContextType, extension.get(), kContextType)); ScriptContext* script_context = script_context_set.GetByV8Context(context); v8::LocalVector<v8::Value> args(isolate(), {v8::Undefined(isolate())});
diff --git a/extensions/renderer/dispatcher.cc b/extensions/renderer/dispatcher.cc index 3756195..037262a9 100644 --- a/extensions/renderer/dispatcher.cc +++ b/extensions/renderer/dispatcher.cc
@@ -58,6 +58,7 @@ #include "extensions/common/permissions/permission_set.h" #include "extensions/common/permissions/permissions_data.h" #include "extensions/common/switches.h" +#include "extensions/common/utils/extension_utils.h" #include "extensions/grit/extensions_renderer_resources.h" #include "extensions/renderer/api/app_window_custom_bindings.h" #include "extensions/renderer/api/automation/automation_internal_custom_bindings.h" @@ -551,8 +552,9 @@ // by extensions minimal bindings, just as we might want to give them to // service workers that aren't registered by extensions. ScriptContext* context = new ScriptContext( - v8_context, nullptr, extension, mojom::ContextType::kPrivilegedExtension, - extension, mojom::ContextType::kPrivilegedExtension); + v8_context, nullptr, GenerateHostIdFromExtensionId(extension->id()), + extension, mojom::ContextType::kPrivilegedExtension, extension, + mojom::ContextType::kPrivilegedExtension); context->set_url(script_url); context->set_service_worker_scope(service_worker_scope); context->set_service_worker_version_id(service_worker_version_id); @@ -816,12 +818,12 @@ } void Dispatcher::DispatchEventHelper( - const std::string& extension_id, + const mojom::HostID& host_id, const std::string& event_name, const base::Value::List& event_args, mojom::EventFilteringInfoPtr filtering_info) const { script_context_set_->ForEach( - extension_id, nullptr, + host_id, nullptr, base::BindRepeating( &NativeExtensionBindingsSystem::DispatchEventInContext, base::Unretained(bindings_system_.get()), event_name, @@ -834,7 +836,7 @@ const std::string& function_name, const base::Value::List& args) { script_context_set_->ForEach( - extension_id, render_frame, + GenerateHostIdFromExtensionId(extension_id), render_frame, base::BindRepeating(&CallModuleMethod, module_name, function_name, &args)); } @@ -1200,7 +1202,7 @@ // to clear out context-specific data, and then remove the contexts // themselves. script_context_set_->ForEach( - extension_id, nullptr, + GenerateHostIdFromExtensionId(extension_id), nullptr, base::BindRepeating( &NativeExtensionBindingsSystem::WillReleaseScriptContext, base::Unretained(bindings_system_.get()))); @@ -1235,14 +1237,14 @@ // the browser know when we are starting and stopping the event dispatch, so // that it still considers the extension idle despite any activity the suspend // event creates. - DispatchEventHelper(extension_id, kOnSuspendEvent, base::Value::List(), - nullptr); + DispatchEventHelper(GenerateHostIdFromExtensionId(extension_id), + kOnSuspendEvent, base::Value::List(), nullptr); std::move(callback).Run(); } void Dispatcher::CancelSuspendExtension(const std::string& extension_id) { - DispatchEventHelper(extension_id, kOnSuspendCanceledEvent, - base::Value::List(), nullptr); + DispatchEventHelper(GenerateHostIdFromExtensionId(extension_id), + kOnSuspendCanceledEvent, base::Value::List(), nullptr); } void Dispatcher::SetSystemFont(const std::string& font_family, @@ -1379,8 +1381,12 @@ base::Value::List event_args, DispatchEventCallback callback) { CHECK_EQ(params->worker_thread_id, kMainThreadId); - content::RenderFrame* background_frame = - ExtensionFrameHelper::GetBackgroundPageFrame(params->extension_id); + CHECK(params->host_id); + content::RenderFrame* background_frame = nullptr; + if (params->host_id->type == mojom::HostID::HostType::kExtensions) { + background_frame = ExtensionFrameHelper::GetBackgroundPageFrame( + GenerateExtensionIdFromHostId(*params->host_id)); + } ScriptContext* background_context = nullptr; if (background_frame) { background_context = @@ -1405,14 +1411,14 @@ blink::mojom::UserActivationNotificationType::kExtensionEvent); } - DispatchEventHelper(params->extension_id, params->event_name, event_args, + DispatchEventHelper(*params->host_id, params->event_name, event_args, std::move(params->filtering_info)); #if BUILDFLAG(ENABLE_EXTENSIONS_LEGACY_IPC) if (background_frame) { // Tell the browser process when an event has been dispatched with a lazy // background page active. - const Extension* extension = - RendererExtensionRegistry::Get()->GetByID(params->extension_id); + const Extension* extension = RendererExtensionRegistry::Get()->GetByID( + GenerateExtensionIdFromHostID(*params->host_id)); if (extension && BackgroundInfo::HasBackgroundPage(extension)) { background_frame->Send(new ExtensionHostMsg_EventAck( background_frame->GetRoutingID(), params->event_id,
diff --git a/extensions/renderer/dispatcher.h b/extensions/renderer/dispatcher.h index c46667ab..928c3952 100644 --- a/extensions/renderer/dispatcher.h +++ b/extensions/renderer/dispatcher.h
@@ -181,7 +181,7 @@ void RunScriptsAtDocumentIdle(content::RenderFrame* render_frame); // Dispatches the event named |event_name| to all render views. - void DispatchEventHelper(const std::string& extension_id, + void DispatchEventHelper(const mojom::HostID& extension_id, const std::string& event_name, const base::Value::List& event_args, mojom::EventFilteringInfoPtr filtering_info) const;
diff --git a/extensions/renderer/module_system_test.cc b/extensions/renderer/module_system_test.cc index b9a3fc51..7e9db632 100644 --- a/extensions/renderer/module_system_test.cc +++ b/extensions/renderer/module_system_test.cc
@@ -24,6 +24,7 @@ #include "extensions/common/extension_builder.h" #include "extensions/common/extension_paths.h" #include "extensions/common/mojom/context_type.mojom.h" +#include "extensions/common/utils/extension_utils.h" #include "extensions/renderer/ipc_message_sender.h" #include "extensions/renderer/logging_native_handler.h" #include "extensions/renderer/native_extension_bindings_system.h" @@ -162,8 +163,9 @@ auto context = std::make_unique<ScriptContext>( context_holder_->context(), nullptr, // WebFrame - extension_.get(), mojom::ContextType::kPrivilegedExtension, - extension_.get(), mojom::ContextType::kPrivilegedExtension); + GenerateHostIdFromExtensionId(extension_->id()), extension_.get(), + mojom::ContextType::kPrivilegedExtension, extension_.get(), + mojom::ContextType::kPrivilegedExtension); context_ = context.get(); context_set_->AddForTesting(std::move(context)); }
diff --git a/extensions/renderer/native_extension_bindings_system.cc b/extensions/renderer/native_extension_bindings_system.cc index e67b7b72..1cf0231 100644 --- a/extensions/renderer/native_extension_bindings_system.cc +++ b/extensions/renderer/native_extension_bindings_system.cc
@@ -27,6 +27,7 @@ #include "extensions/common/mojom/context_type.mojom.h" #include "extensions/common/mojom/event_dispatcher.mojom.h" #include "extensions/common/mojom/frame.mojom.h" +#include "extensions/common/utils/extension_utils.h" #include "extensions/renderer/api/declarative_content_hooks_delegate.h" #include "extensions/renderer/api/dom_hooks_delegate.h" #include "extensions/renderer/api/feedback_private_hooks_delegate.h" @@ -693,7 +694,7 @@ } script_context_set->ForEach( - extension_id, + GenerateHostIdFromExtensionId(extension_id), base::BindRepeating( &NativeExtensionBindingsSystem::UpdateBindingsForContext, // Called synchronously.
diff --git a/extensions/renderer/native_extension_bindings_system_test_base.cc b/extensions/renderer/native_extension_bindings_system_test_base.cc index c3a9d36..34ed8fd 100644 --- a/extensions/renderer/native_extension_bindings_system_test_base.cc +++ b/extensions/renderer/native_extension_bindings_system_test_base.cc
@@ -12,6 +12,7 @@ #include "extensions/common/mojom/context_type.mojom.h" #include "extensions/common/mojom/frame.mojom.h" #include "extensions/common/permissions/permissions_data.h" +#include "extensions/common/utils/extension_utils.h" #include "extensions/renderer/module_system.h" #include "extensions/renderer/native_extension_bindings_system.h" #include "extensions/renderer/script_context.h" @@ -77,7 +78,8 @@ const Extension* extension, mojom::ContextType context_type) { auto script_context = std::make_unique<ScriptContext>( - v8_context, nullptr, extension, context_type, extension, context_type); + v8_context, nullptr, GenerateHostIdFromExtension(extension), extension, + context_type, extension, context_type); script_context->SetModuleSystem( std::make_unique<ModuleSystem>(script_context.get(), source_map())); ScriptContext* raw_script_context = script_context.get();
diff --git a/extensions/renderer/script_context.cc b/extensions/renderer/script_context.cc index 1964270..e3404eb 100644 --- a/extensions/renderer/script_context.cc +++ b/extensions/renderer/script_context.cc
@@ -127,6 +127,7 @@ ScriptContext::ScriptContext(const v8::Local<v8::Context>& v8_context, blink::WebLocalFrame* web_frame, + const mojom::HostID& host_id, const Extension* extension, mojom::ContextType context_type, const Extension* effective_extension, @@ -134,6 +135,7 @@ : is_valid_(true), v8_context_(v8_context->GetIsolate(), v8_context), web_frame_(web_frame), + host_id_(host_id), extension_(extension), context_type_(context_type), effective_extension_(effective_extension), @@ -146,6 +148,12 @@ v8_context_.AnnotateStrongRetainer("extensions::ScriptContext::v8_context_"); if (web_frame_) url_ = GetAccessCheckedFrameURL(web_frame_); + // Enforce the invariant that an extension should have a HostID that's set to + // the extension id. + if (extension_) { + CHECK_EQ(host_id_.type, mojom::HostID::HostType::kExtensions); + CHECK_EQ(host_id_.id, extension_->id()); + } } ScriptContext::~ScriptContext() {
diff --git a/extensions/renderer/script_context.h b/extensions/renderer/script_context.h index 49108aa..38f8733 100644 --- a/extensions/renderer/script_context.h +++ b/extensions/renderer/script_context.h
@@ -18,6 +18,7 @@ #include "extensions/common/features/feature.h" #include "extensions/common/mojom/api_permission_id.mojom-shared.h" #include "extensions/common/mojom/context_type.mojom-forward.h" +#include "extensions/common/mojom/host_id.mojom.h" #include "extensions/common/permissions/api_permission_set.h" #include "extensions/common/script_constants.h" #include "extensions/renderer/module_system.h" @@ -56,6 +57,7 @@ ScriptContext(const v8::Local<v8::Context>& context, blink::WebLocalFrame* frame, + const mojom::HostID& host_id, const Extension* extension, mojom::ContextType context_type, const Extension* effective_extension, @@ -91,6 +93,8 @@ return v8::Local<v8::Context>::New(isolate_, v8_context_); } + const mojom::HostID& host_id() const { return host_id_; } + const Extension* extension() const { return extension_.get(); } const Extension* effective_extension() const { @@ -294,6 +298,11 @@ // this object can outlive is destroyed asynchronously. raw_ptr<blink::WebLocalFrame, ExperimentalRenderer> web_frame_; + // The HostID associated with this context. For extensions, the HostID + // HostType should match kExtensions and the ID should match + // |extension()->id()|. + const mojom::HostID host_id_; + // The extension associated with this context, or NULL if there is none. This // might be a hosted app in the case that this context is hosting a web URL. scoped_refptr<const Extension> extension_;
diff --git a/extensions/renderer/script_context_set.cc b/extensions/renderer/script_context_set.cc index 02efa44..045f6a5 100644 --- a/extensions/renderer/script_context_set.cc +++ b/extensions/renderer/script_context_set.cc
@@ -14,9 +14,12 @@ #include "extensions/common/constants.h" #include "extensions/common/extension.h" #include "extensions/common/mojom/context_type.mojom.h" +#include "extensions/common/mojom/host_id.mojom.h" +#include "extensions/common/utils/extension_utils.h" #include "extensions/renderer/extension_frame_helper.h" #include "extensions/renderer/extensions_renderer_client.h" #include "extensions/renderer/isolated_world_manager.h" +#include "extensions/renderer/renderer_frame_context_data.h" #include "extensions/renderer/script_context.h" #include "third_party/blink/public/platform/scheduler/web_agent_group_scheduler.h" #include "third_party/blink/public/web/web_document.h" @@ -71,8 +74,32 @@ ScriptContext::GetEffectiveDocumentURLForContext(frame, frame_url, true), frame->GetDocument().GetSecurityOrigin(), view_type, is_webview); + mojom::HostID host_id; + RendererFrameContextData context_data = RendererFrameContextData(frame); + // By default, the context will use a HostID kExtensions type. Specific + // cases override that value below. + host_id.type = mojom::HostID::HostType::kExtensions; + if (extension) { + host_id.id = extension->id(); + } else if (effective_context_type == mojom::ContextType::kWebUi) { + host_id.type = mojom::HostID::HostType::kWebUi; + } else if (effective_context_type == mojom::ContextType::kWebPage && + !is_webview && context_data.IsIsolatedApplication()) { + host_id.type = mojom::HostID::HostType::kControlledFrameEmbedder; + // TODO(crbug.com/1517392): Improve how we derive origin for controlled + // frame embedders in renderer. + host_id.id = ""; + if (frame_url.has_scheme()) { + host_id.id += frame_url.scheme() + "://"; + } + host_id.id += frame_url.host(); + if (frame_url.has_port()) { + host_id.id += ":" + frame_url.port(); + } + } + ScriptContext* context = - new ScriptContext(v8_context, frame, extension, context_type, + new ScriptContext(v8_context, frame, host_id, extension, context_type, effective_extension, effective_context_type); contexts_.insert(context); // takes ownership return context; @@ -126,7 +153,7 @@ } void ScriptContextSet::ForEach( - const std::string& extension_id, + const mojom::HostID& host_id, content::RenderFrame* render_frame, const base::RepeatingCallback<void(ScriptContext*)>& callback) { // We copy the context list, because calling into javascript may modify it @@ -135,26 +162,50 @@ for (ScriptContext* context : contexts_copy) { // For the same reason as above, contexts may become invalid while we run. - if (!context->is_valid()) + if (!context->is_valid()) { continue; - - if (!extension_id.empty()) { - const Extension* extension = context->extension(); - if (!extension || (extension_id != extension->id())) - continue; } - content::RenderFrame* context_render_frame = context->GetRenderFrame(); - if (render_frame && render_frame != context_render_frame) - continue; + switch (host_id.type) { + case mojom::HostID::HostType::kExtensions: + // Note: If the type is kExtensions and host_id.id is empty, then the + // call should affect all extensions. See comment in dispatcher.cc + // UpdateAllBindings(). + if (host_id.id.empty() || context->GetExtensionID() == host_id.id) { + ExecuteCallbackWithContext(context, render_frame, callback); + } + break; + case mojom::HostID::HostType::kWebUi: + DCHECK(host_id.id.empty()); + ExecuteCallbackWithContext(context, render_frame, callback); + break; + + case mojom::HostID::HostType::kControlledFrameEmbedder: + DCHECK(!host_id.id.empty()); + // Verify that host_id matches context->host_id. + if (context->host_id().type == host_id.type && + context->host_id().id == host_id.id) { + ExecuteCallbackWithContext(context, render_frame, callback); + } + } + } +} + +void ScriptContextSet::ExecuteCallbackWithContext( + ScriptContext* context, + content::RenderFrame* render_frame, + const base::RepeatingCallback<void(ScriptContext*)>& callback) { + CHECK(context); + content::RenderFrame* context_render_frame = context->GetRenderFrame(); + if (!render_frame || render_frame == context_render_frame) { callback.Run(context); } } void ScriptContextSet::OnExtensionUnloaded(const std::string& extension_id) { ScriptContextSetIterable::ForEach( - extension_id, + GenerateHostIdFromExtensionId(extension_id), base::BindRepeating(&ScriptContextSet::Remove, base::Unretained(this))); }
diff --git a/extensions/renderer/script_context_set.h b/extensions/renderer/script_context_set.h index e1f9743e..82aeca6c 100644 --- a/extensions/renderer/script_context_set.h +++ b/extensions/renderer/script_context_set.h
@@ -96,12 +96,18 @@ static ScriptContext* GetMainWorldContextForFrame( content::RenderFrame* render_frame); - // ScriptContextIterable: + // ScriptContextSetIterable: void ForEach( - const std::string& extension_id, + const mojom::HostID& host_id, content::RenderFrame* render_frame, const base::RepeatingCallback<void(ScriptContext*)>& callback) override; + // Runs |callback| after verifying |render_frame| matches context's. + void ExecuteCallbackWithContext( + ScriptContext* context, + content::RenderFrame* render_frame, + const base::RepeatingCallback<void(ScriptContext*)>& callback); + // Cleans up contexts belonging to an unloaded extension. void OnExtensionUnloaded(const std::string& extension_id);
diff --git a/extensions/renderer/script_context_set_iterable.cc b/extensions/renderer/script_context_set_iterable.cc index 5e488a1..854e258c 100644 --- a/extensions/renderer/script_context_set_iterable.cc +++ b/extensions/renderer/script_context_set_iterable.cc
@@ -4,18 +4,20 @@ #include "extensions/renderer/script_context_set_iterable.h" +#include "extensions/common/mojom/host_id.mojom.h" + namespace extensions { void ScriptContextSetIterable::ForEach( content::RenderFrame* render_frame, const base::RepeatingCallback<void(ScriptContext*)>& callback) { - ForEach(std::string(), render_frame, callback); + ForEach(mojom::HostID(), render_frame, callback); } void ScriptContextSetIterable::ForEach( - const std::string& extension_id, + const mojom::HostID& host_id, const base::RepeatingCallback<void(ScriptContext*)>& callback) { - ForEach(extension_id, nullptr, callback); + ForEach(host_id, nullptr, callback); } } // namespace extensions
diff --git a/extensions/renderer/script_context_set_iterable.h b/extensions/renderer/script_context_set_iterable.h index 8e16965..fe3a4ed963 100644 --- a/extensions/renderer/script_context_set_iterable.h +++ b/extensions/renderer/script_context_set_iterable.h
@@ -5,28 +5,29 @@ #ifndef EXTENSIONS_RENDERER_SCRIPT_CONTEXT_SET_ITERABLE_H_ #define EXTENSIONS_RENDERER_SCRIPT_CONTEXT_SET_ITERABLE_H_ -#include <string> - #include "base/functional/callback_forward.h" namespace content { class RenderFrame; -} +} // namespace content namespace extensions { class ScriptContext; +namespace mojom { +class HostID; +} // namespace mojom // Iterable base class to iterate over a ScriptContextSet. class ScriptContextSetIterable { public: // Synchronously runs |callback| with each ScriptContext that belongs to - // |extension_id| in |render_frame|. + // |host_id| in |render_frame|. // - // An empty |extension_id| will match all extensions, and a null + // An empty |host_id.id| will match all extensions, and a null // |render_frame| will match all render views, but try to use the inline // variants of these methods instead. virtual void ForEach( - const std::string& extension_id, + const mojom::HostID& host_id, content::RenderFrame* render_frame, const base::RepeatingCallback<void(ScriptContext*)>& callback) = 0; @@ -35,7 +36,7 @@ const base::RepeatingCallback<void(ScriptContext*)>& callback); // ForEach which matches all render views. - void ForEach(const std::string& extension_id, + void ForEach(const mojom::HostID& host_id, const base::RepeatingCallback<void(ScriptContext*)>& callback); virtual ~ScriptContextSetIterable() {}
diff --git a/extensions/renderer/v8_schema_registry.cc b/extensions/renderer/v8_schema_registry.cc index af33151..c34c6bb 100644 --- a/extensions/renderer/v8_schema_registry.cc +++ b/extensions/renderer/v8_schema_registry.cc
@@ -17,6 +17,7 @@ #include "content/public/renderer/v8_value_converter.h" #include "extensions/common/extension_api.h" #include "extensions/common/mojom/context_type.mojom.h" +#include "extensions/common/mojom/host_id.mojom.h" #include "extensions/renderer/object_backed_native_handler.h" #include "extensions/renderer/script_context.h" #include "extensions/renderer/static_v8_external_one_byte_string_resource.h" @@ -112,8 +113,9 @@ v8::Isolate* isolate) { std::unique_ptr<ScriptContext> context( new ScriptContext(GetOrCreateContext(isolate), - nullptr, // no frame - nullptr, // no extension + nullptr, // no frame + mojom::HostID(), // no host_id + nullptr, // no extension mojom::ContextType::kUnspecified, nullptr, // no effective extension mojom::ContextType::kUnspecified));
diff --git a/extensions/renderer/worker_script_context_set.cc b/extensions/renderer/worker_script_context_set.cc index 57c9a8b..867040bce 100644 --- a/extensions/renderer/worker_script_context_set.cc +++ b/extensions/renderer/worker_script_context_set.cc
@@ -44,19 +44,48 @@ WorkerScriptContextSet::~WorkerScriptContextSet() = default; void WorkerScriptContextSet::ForEach( - const std::string& extension_id, + const mojom::HostID& host_id, content::RenderFrame* render_frame, const base::RepeatingCallback<void(ScriptContext*)>& callback) { DCHECK(!render_frame); + for (const std::unique_ptr<ScriptContext>& context : *contexts) { DCHECK(!context->GetRenderFrame()); - if (!extension_id.empty() && context->GetExtensionID() != extension_id) - continue; - callback.Run(context.get()); + switch (host_id.type) { + case mojom::HostID::HostType::kExtensions: + // Note: If the type is kExtensions and host_id.id is empty, then the + // call should affect all extensions. See comment in dispatcher.cc + // UpdateAllBindings(). + if (host_id.id.empty() || context->GetExtensionID() == host_id.id) { + ExecuteCallbackWithContext(context.get(), callback); + } + break; + + case mojom::HostID::HostType::kWebUi: + DCHECK(host_id.id.empty()); + ExecuteCallbackWithContext(context.get(), callback); + break; + + case mojom::HostID::HostType::kControlledFrameEmbedder: + DCHECK(!host_id.id.empty()); + // Verify that host_id matches context->host_id. + if (context->host_id().type == host_id.type || + context->host_id().id == host_id.id) { + ExecuteCallbackWithContext(context.get(), callback); + } + break; + } } } +void WorkerScriptContextSet::ExecuteCallbackWithContext( + ScriptContext* context, + const base::RepeatingCallback<void(ScriptContext*)>& callback) { + CHECK(context); + callback.Run(context); +} + void WorkerScriptContextSet::Insert(std::unique_ptr<ScriptContext> context) { DCHECK(worker_thread_util::IsWorkerThread()) << "Must be called on a worker thread";
diff --git a/extensions/renderer/worker_script_context_set.h b/extensions/renderer/worker_script_context_set.h index fbb5168..2b3cb4e 100644 --- a/extensions/renderer/worker_script_context_set.h +++ b/extensions/renderer/worker_script_context_set.h
@@ -36,10 +36,15 @@ // ScriptContextSetIterable: void ForEach( - const std::string& extension_id, + const mojom::HostID& host_id, content::RenderFrame* render_frame, const base::RepeatingCallback<void(ScriptContext*)>& callback) override; + // Runs |callback| with the given |context|. + void ExecuteCallbackWithContext( + ScriptContext* context, + const base::RepeatingCallback<void(ScriptContext*)>& callback); + // Inserts |context| into the set. Contexts are stored in TLS. void Insert(std::unique_ptr<ScriptContext> context);
diff --git a/gin/gin_features.cc b/gin/gin_features.cc index acf61662..3a53a248 100644 --- a/gin/gin_features.cc +++ b/gin/gin_features.cc
@@ -254,6 +254,11 @@ "kJavaScriptImportAttributes", base::FEATURE_ENABLED_BY_DEFAULT); +// Enables the set methods proposal. +BASE_FEATURE(kJavaScriptSetMethods, + "JavaScriptSetMethods", + base::FEATURE_ENABLED_BY_DEFAULT); + // WebAssembly features. // Enable support for the WebAssembly tail-call proposal:
diff --git a/gin/gin_features.h b/gin/gin_features.h index 2e92053de..dcd2a5ea 100644 --- a/gin/gin_features.h +++ b/gin/gin_features.h
@@ -71,6 +71,7 @@ GIN_EXPORT BASE_DECLARE_FEATURE(kJavaScriptArrayFromAsync); GIN_EXPORT BASE_DECLARE_FEATURE(kJavaScriptRegExpModifiers); GIN_EXPORT BASE_DECLARE_FEATURE(kJavaScriptImportAttributes); +GIN_EXPORT BASE_DECLARE_FEATURE(kJavaScriptSetMethods); GIN_EXPORT BASE_DECLARE_FEATURE(kWebAssemblyTailCall); GIN_EXPORT BASE_DECLARE_FEATURE(kWebAssemblyInlining); GIN_EXPORT BASE_DECLARE_FEATURE(kWebAssemblyGenericWrapper);
diff --git a/gin/v8_initializer.cc b/gin/v8_initializer.cc index bc74835..b508f9a8 100644 --- a/gin/v8_initializer.cc +++ b/gin/v8_initializer.cc
@@ -397,6 +397,8 @@ SetV8FlagsIfOverridden(features::kJavaScriptImportAttributes, "--harmony-import-attributes", "--no-harmony-import-attributes"); + SetV8FlagsIfOverridden(features::kJavaScriptSetMethods, + "--harmony-set-methods", "--no-harmony-set-methods"); if (IsolateHolder::kStrictMode == mode) { SetV8Flags("--use_strict");
diff --git a/gpu/command_buffer/client/shared_image_interface.cc b/gpu/command_buffer/client/shared_image_interface.cc index f6d1c5e..a07e390 100644 --- a/gpu/command_buffer/client/shared_image_interface.cc +++ b/gpu/command_buffer/client/shared_image_interface.cc
@@ -15,6 +15,15 @@ namespace gpu { +SharedImageInterface::SwapChainSharedImages::SwapChainSharedImages( + scoped_refptr<gpu::ClientSharedImage> front_buffer, + scoped_refptr<gpu::ClientSharedImage> back_buffer) + : front_buffer(std::move(front_buffer)), + back_buffer(std::move(back_buffer)) {} +SharedImageInterface::SwapChainSharedImages::SwapChainSharedImages( + const SwapChainSharedImages& shared_images) = default; +SharedImageInterface::SwapChainSharedImages::~SwapChainSharedImages() = default; + scoped_refptr<ClientSharedImage> SharedImageInterface::CreateSharedImage( viz::SharedImageFormat format, const gfx::Size& size,
diff --git a/gpu/command_buffer/client/shared_image_interface.h b/gpu/command_buffer/client/shared_image_interface.h index 946b4324..000d7298 100644 --- a/gpu/command_buffer/client/shared_image_interface.h +++ b/gpu/command_buffer/client/shared_image_interface.h
@@ -234,22 +234,28 @@ const Mailbox& mailbox, uint32_t usage) = 0; - struct SwapChainMailboxes { - Mailbox front_buffer; - Mailbox back_buffer; + struct GPU_EXPORT SwapChainSharedImages { + SwapChainSharedImages(scoped_refptr<gpu::ClientSharedImage> front_buffer, + scoped_refptr<gpu::ClientSharedImage> back_buffer); + SwapChainSharedImages(const SwapChainSharedImages& shared_images); + ~SwapChainSharedImages(); + + scoped_refptr<gpu::ClientSharedImage> front_buffer; + scoped_refptr<gpu::ClientSharedImage> back_buffer; }; // Creates a swap chain. - // Returns mailboxes for front and back buffers of a DXGI Swap Chain that can - // be imported into GL command buffer using shared image functions (e.g. + // Returns shared images for front and back buffers of a DXGI Swap Chain that + // can be imported into GL command buffer using shared image functions (e.g. // GLES2Interface::CreateAndTexStorage2DSharedImageCHROMIUM) or (deprecated) // mailbox functions (e.g. GLES2Interface::CreateAndConsumeTextureCHROMIUM). - virtual SwapChainMailboxes CreateSwapChain(viz::SharedImageFormat format, - const gfx::Size& size, - const gfx::ColorSpace& color_space, - GrSurfaceOrigin surface_origin, - SkAlphaType alpha_type, - uint32_t usage) = 0; + virtual SwapChainSharedImages CreateSwapChain( + viz::SharedImageFormat format, + const gfx::Size& size, + const gfx::ColorSpace& color_space, + GrSurfaceOrigin surface_origin, + SkAlphaType alpha_type, + uint32_t usage) = 0; // Swaps front and back buffer of a swap chain. Back buffer mailbox still // refers to the back buffer of the swap chain after calling PresentSwapChain.
diff --git a/gpu/command_buffer/service/shared_image_interface_in_process.cc b/gpu/command_buffer/service/shared_image_interface_in_process.cc index 2264a145..e096b8aa 100644 --- a/gpu/command_buffer/service/shared_image_interface_in_process.cc +++ b/gpu/command_buffer/service/shared_image_interface_in_process.cc
@@ -602,7 +602,7 @@ sync_point_client_state_->ReleaseFenceSync(sync_token.release_count()); } -SharedImageInterface::SwapChainMailboxes +SharedImageInterface::SwapChainSharedImages SharedImageInterfaceInProcess::CreateSwapChain( viz::SharedImageFormat format, const gfx::Size& size, @@ -611,7 +611,7 @@ SkAlphaType alpha_type, uint32_t usage) { NOTREACHED(); - return {}; + return SharedImageInterface::SwapChainSharedImages(nullptr, nullptr); } void SharedImageInterfaceInProcess::PresentSwapChain(
diff --git a/gpu/command_buffer/service/shared_image_interface_in_process.h b/gpu/command_buffer/service/shared_image_interface_in_process.h index bbec0c4..f9df8d6 100644 --- a/gpu/command_buffer/service/shared_image_interface_in_process.h +++ b/gpu/command_buffer/service/shared_image_interface_in_process.h
@@ -138,12 +138,12 @@ const SyncToken& sync_token, const Mailbox& mailbox, uint32_t usage) override; - SwapChainMailboxes CreateSwapChain(viz::SharedImageFormat format, - const gfx::Size& size, - const gfx::ColorSpace& color_space, - GrSurfaceOrigin surface_origin, - SkAlphaType alpha_type, - uint32_t usage) override; + SwapChainSharedImages CreateSwapChain(viz::SharedImageFormat format, + const gfx::Size& size, + const gfx::ColorSpace& color_space, + GrSurfaceOrigin surface_origin, + SkAlphaType alpha_type, + uint32_t usage) override; void PresentSwapChain(const SyncToken& sync_token, const Mailbox& mailbox) override; #if BUILDFLAG(IS_FUCHSIA)
diff --git a/gpu/ipc/client/client_shared_image_interface.cc b/gpu/ipc/client/client_shared_image_interface.cc index be1c297..02e5c21 100644 --- a/gpu/ipc/client/client_shared_image_interface.cc +++ b/gpu/ipc/client/client_shared_image_interface.cc
@@ -232,7 +232,7 @@ } #endif -ClientSharedImageInterface::SwapChainMailboxes +ClientSharedImageInterface::SwapChainSharedImages ClientSharedImageInterface::CreateSwapChain(viz::SharedImageFormat format, const gfx::Size& size, const gfx::ColorSpace& color_space, @@ -244,7 +244,9 @@ surface_origin, alpha_type, usage); AddMailbox(mailboxes.front_buffer); AddMailbox(mailboxes.back_buffer); - return mailboxes; + return ClientSharedImageInterface::SwapChainSharedImages( + base::MakeRefCounted<ClientSharedImage>(mailboxes.front_buffer), + base::MakeRefCounted<ClientSharedImage>(mailboxes.back_buffer)); } void ClientSharedImageInterface::DestroySharedImage(const SyncToken& sync_token,
diff --git a/gpu/ipc/client/client_shared_image_interface.h b/gpu/ipc/client/client_shared_image_interface.h index 0e14b1d..0e7c5be2 100644 --- a/gpu/ipc/client/client_shared_image_interface.h +++ b/gpu/ipc/client/client_shared_image_interface.h
@@ -115,12 +115,12 @@ scoped_refptr<gfx::D3DSharedFence> d3d_shared_fence, const Mailbox& mailbox) override; #endif - SwapChainMailboxes CreateSwapChain(viz::SharedImageFormat format, - const gfx::Size& size, - const gfx::ColorSpace& color_space, - GrSurfaceOrigin surface_origin, - SkAlphaType alpha_type, - uint32_t usage) override; + SwapChainSharedImages CreateSwapChain(viz::SharedImageFormat format, + const gfx::Size& size, + const gfx::ColorSpace& color_space, + GrSurfaceOrigin surface_origin, + SkAlphaType alpha_type, + uint32_t usage) override; void DestroySharedImage(const SyncToken& sync_token, const Mailbox& mailbox) override; void DestroySharedImage(
diff --git a/gpu/ipc/client/shared_image_interface_proxy.cc b/gpu/ipc/client/shared_image_interface_proxy.cc index 74d7e7e7..fac38ef 100644 --- a/gpu/ipc/client/shared_image_interface_proxy.cc +++ b/gpu/ipc/client/shared_image_interface_proxy.cc
@@ -514,7 +514,7 @@ return true; } -SharedImageInterface::SwapChainMailboxes +SharedImageInterfaceProxy::SwapChainMailboxes SharedImageInterfaceProxy::CreateSwapChain(viz::SharedImageFormat format, const gfx::Size& size, const gfx::ColorSpace& color_space, @@ -522,8 +522,8 @@ SkAlphaType alpha_type, uint32_t usage) { #if BUILDFLAG(IS_WIN) - const SharedImageInterface::SwapChainMailboxes mailboxes = { - Mailbox::GenerateForSharedImage(), Mailbox::GenerateForSharedImage()}; + const SwapChainMailboxes mailboxes = {Mailbox::GenerateForSharedImage(), + Mailbox::GenerateForSharedImage()}; auto params = mojom::CreateSwapChainParams::New(); params->front_buffer_mailbox = mailboxes.front_buffer; params->back_buffer_mailbox = mailboxes.back_buffer;
diff --git a/gpu/ipc/client/shared_image_interface_proxy.h b/gpu/ipc/client/shared_image_interface_proxy.h index 4b2b74e..059b027c 100644 --- a/gpu/ipc/client/shared_image_interface_proxy.h +++ b/gpu/ipc/client/shared_image_interface_proxy.h
@@ -35,6 +35,11 @@ // Proxy that sends commands over GPU channel IPCs for managing shared images. class SharedImageInterfaceProxy { public: + struct SwapChainMailboxes { + Mailbox front_buffer; + Mailbox back_buffer; + }; + explicit SharedImageInterfaceProxy( GpuChannelHost* host, int32_t route_id, @@ -121,13 +126,12 @@ void WaitSyncToken(const SyncToken& sync_token); void Flush(); - SharedImageInterface::SwapChainMailboxes CreateSwapChain( - viz::SharedImageFormat format, - const gfx::Size& size, - const gfx::ColorSpace& color_space, - GrSurfaceOrigin surface_origin, - SkAlphaType alpha_type, - uint32_t usage); + SwapChainMailboxes CreateSwapChain(viz::SharedImageFormat format, + const gfx::Size& size, + const gfx::ColorSpace& color_space, + GrSurfaceOrigin surface_origin, + SkAlphaType alpha_type, + uint32_t usage); void PresentSwapChain(const SyncToken& sync_token, const Mailbox& mailbox); #if BUILDFLAG(IS_FUCHSIA)
diff --git a/infra/config/generated/health-specs/health-specs.json b/infra/config/generated/health-specs/health-specs.json index 95df34e..6ebc696 100644 --- a/infra/config/generated/health-specs/health-specs.json +++ b/infra/config/generated/health-specs/health-specs.json
@@ -30,6 +30,67 @@ ], "specs": { "ci": { + "3pp-linux-amd64-packager": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "3pp-mac-amd64-packager": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "3pp-windows-amd64-packager": { + "contact_team_email": "chrome-browser-infra-team@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "ASAN Debug": { "contact_team_email": "chrome-sanitizer-builder-owners@google.com", "problem_specs": [ @@ -176,6 +237,153 @@ } ] }, + "Android FYI Release (NVIDIA Shield TV)": { + "contact_team_email": "chrome-gpu-infra@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "Android FYI Release (Nexus 5X)": { + "contact_team_email": "chrome-gpu-infra@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "Android FYI Release (Pixel 2)": { + "contact_team_email": "chrome-gpu-infra@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "Android FYI Release (Pixel 4)": { + "contact_team_email": "chrome-gpu-infra@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "Android FYI Release (Pixel 6)": { + "contact_team_email": "chrome-gpu-infra@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "Android FYI Release (Samsung A13)": { + "contact_team_email": "chrome-gpu-infra@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "Android FYI Release (Samsung A23)": { + "contact_team_email": "chrome-gpu-infra@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "Android Release (Nexus 5X)": { "contact_team_email": "chrome-gpu-infra@google.com", "problem_specs": [ @@ -365,6 +573,26 @@ } ] }, + "Blink Unexpected Pass Finder": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "CFI Linux CF": { "contact_team_email": "lexan@google.com", "problem_specs": [ @@ -515,6 +743,48 @@ } ] }, + "ChromeOS FYI Release (amd64-generic)": { + "contact_team_email": "chrome-gpu-infra@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "ChromeOS FYI Release Skylab (volteer)": { + "contact_team_email": "chrome-gpu-infra@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "ChromiumOS ASAN Release": { "contact_team_email": "chrome-sanitizer-builder-owners@google.com", "problem_specs": [ @@ -536,6 +806,286 @@ } ] }, + "Comparison Android (reclient)": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "Comparison Android (reclient) (reproxy cache)": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "Comparison Android (reclient)(CQ)": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "Comparison Mac (reclient)": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "Comparison Mac (reclient)(CQ)": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "Comparison Mac arm64 (reclient)": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "Comparison Mac arm64 on arm64 (reclient)": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "Comparison Simple Chrome (reclient)": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "Comparison Simple Chrome (reclient)(CQ)": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "Comparison Windows (8 cores) (reclient)": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "Comparison Windows (reclient)": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "Comparison Windows (reclient)(CQ)": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "Comparison ios (reclient)": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "Comparison ios (reclient)(CQ)": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "CrWinAsan": { "contact_team_email": "lexan@google.com", "problem_specs": [ @@ -1571,6 +2121,342 @@ } ] }, + "GPU FYI Android arm Builder": { + "contact_team_email": "chrome-gpu-infra@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "GPU FYI Android arm64 Builder": { + "contact_team_email": "chrome-gpu-infra@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "GPU FYI Lacros x64 Builder": { + "contact_team_email": "chrome-gpu-infra@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "GPU FYI Linux Builder": { + "contact_team_email": "chrome-gpu-infra@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "GPU FYI Linux Builder (dbg)": { + "contact_team_email": "chrome-gpu-infra@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "GPU FYI Mac Builder": { + "contact_team_email": "chrome-gpu-infra@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "GPU FYI Mac Builder (asan)": { + "contact_team_email": "chrome-gpu-infra@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "GPU FYI Mac Builder (dbg)": { + "contact_team_email": "chrome-gpu-infra@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "GPU FYI Mac arm64 Builder": { + "contact_team_email": "chrome-gpu-infra@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "GPU FYI Win Builder": { + "contact_team_email": "chrome-gpu-infra@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "GPU FYI Win x64 Builder": { + "contact_team_email": "chrome-gpu-infra@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "GPU FYI Win x64 Builder (dbg)": { + "contact_team_email": "chrome-gpu-infra@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "GPU FYI Win x64 DX12 Vulkan Builder": { + "contact_team_email": "chrome-gpu-infra@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "GPU FYI Win x64 DX12 Vulkan Builder (dbg)": { + "contact_team_email": "chrome-gpu-infra@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "GPU FYI XR Win x64 Builder": { + "contact_team_email": "chrome-gpu-infra@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "GPU Flake Finder": { + "contact_team_email": "chrome-gpu-infra@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "GPU Linux Builder": { "contact_team_email": "chrome-gpu-infra@google.com", "problem_specs": [ @@ -1697,6 +2583,48 @@ } ] }, + "Lacros FYI x64 Release (AMD)": { + "contact_team_email": "chrome-gpu-infra@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "Lacros FYI x64 Release (Intel)": { + "contact_team_email": "chrome-gpu-infra@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "Leak Detection Linux": { "problem_specs": [ { @@ -2095,6 +3023,26 @@ } ] }, + "Linux Builder (reclient compare)": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "Linux CFI": { "contact_team_email": "chrome-sanitizer-builder-owners@google.com", "problem_specs": [ @@ -2221,6 +3169,153 @@ } ] }, + "Linux FYI Debug (NVIDIA)": { + "contact_team_email": "chrome-gpu-infra@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "Linux FYI Experimental Release (Intel UHD 630)": { + "contact_team_email": "chrome-gpu-infra@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "Linux FYI Experimental Release (NVIDIA)": { + "contact_team_email": "chrome-gpu-infra@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "Linux FYI GPU TSAN Release": { + "contact_team_email": "chrome-gpu-infra@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "Linux FYI Release (AMD RX 5500 XT)": { + "contact_team_email": "chrome-gpu-infra@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "Linux FYI Release (Intel UHD 630)": { + "contact_team_email": "chrome-gpu-infra@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "Linux FYI Release (NVIDIA)": { + "contact_team_email": "chrome-gpu-infra@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "Linux MSan Builder": { "contact_team_email": "chrome-sanitizer-builder-owners@google.com", "problem_specs": [ @@ -2389,6 +3484,26 @@ } ] }, + "Linux Viz": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "MSAN Release (chained origins)": { "contact_team_email": "chrome-sanitizer-builder-owners@google.com", "problem_specs": [ @@ -2561,6 +3676,46 @@ } ] }, + "Mac Builder (reclient compare)": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "Mac Builder Next": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "Mac Debug (Intel)": { "contact_team_email": "chrome-gpu-infra@google.com", "problem_specs": [ @@ -2582,6 +3737,300 @@ } ] }, + "Mac FYI ASAN (Intel)": { + "contact_team_email": "chrome-gpu-infra@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "Mac FYI Debug (Intel)": { + "contact_team_email": "chrome-gpu-infra@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "Mac FYI Experimental Release (Apple M1)": { + "contact_team_email": "chrome-gpu-infra@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "Mac FYI Experimental Release (Intel)": { + "contact_team_email": "chrome-gpu-infra@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "Mac FYI Experimental Retina Release (AMD)": { + "contact_team_email": "chrome-gpu-infra@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "Mac FYI Experimental Retina Release (NVIDIA)": { + "contact_team_email": "chrome-gpu-infra@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "Mac FYI Release (Apple M1)": { + "contact_team_email": "chrome-gpu-infra@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "Mac FYI Release (Intel)": { + "contact_team_email": "chrome-gpu-infra@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "Mac FYI Retina ASAN (AMD)": { + "contact_team_email": "chrome-gpu-infra@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "Mac FYI Retina Debug (AMD)": { + "contact_team_email": "chrome-gpu-infra@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "Mac FYI Retina Release (AMD)": { + "contact_team_email": "chrome-gpu-infra@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "Mac FYI Retina Release (Apple M2)": { + "contact_team_email": "chrome-gpu-infra@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "Mac FYI Retina Release (NVIDIA)": { + "contact_team_email": "chrome-gpu-infra@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "Mac Pro FYI Release (AMD)": { + "contact_team_email": "chrome-gpu-infra@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "Mac Release (Intel)": { "contact_team_email": "chrome-gpu-infra@google.com", "problem_specs": [ @@ -2645,6 +4094,46 @@ } ] }, + "Mac deterministic": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "Mac deterministic (dbg)": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "Mac10.15 Tests": { "contact_team_email": "bling-engprod@google.com", "problem_specs": [ @@ -2789,6 +4278,26 @@ } ] }, + "Site Isolation Android": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "TSAN Debug": { "contact_team_email": "chrome-sanitizer-builder-owners@google.com", "problem_specs": [ @@ -3917,6 +5426,26 @@ } ] }, + "Win 10 Fast Ring": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "Win ASan Release": { "contact_team_email": "chrome-sanitizer-builder-owners@google.com", "problem_specs": [ @@ -4043,6 +5572,256 @@ } ] }, + "Win x64 Builder (reclient compare)": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "Win x64 Builder (reclient)": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "Win10 FYI x64 DX12 Vulkan Debug (NVIDIA)": { + "contact_team_email": "chrome-gpu-infra@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "Win10 FYI x64 DX12 Vulkan Release (NVIDIA)": { + "contact_team_email": "chrome-gpu-infra@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "Win10 FYI x64 Debug (NVIDIA)": { + "contact_team_email": "chrome-gpu-infra@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "Win10 FYI x64 Exp Release (NVIDIA)": { + "contact_team_email": "chrome-gpu-infra@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "Win10 FYI x64 Experimental Release (Intel)": { + "contact_team_email": "chrome-gpu-infra@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "Win10 FYI x64 Release (AMD RX 5500 XT)": { + "contact_team_email": "chrome-gpu-infra@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "Win10 FYI x64 Release (Intel)": { + "contact_team_email": "chrome-gpu-infra@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "Win10 FYI x64 Release (NVIDIA)": { + "contact_team_email": "chrome-gpu-infra@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "Win10 FYI x64 Release XR Perf (NVIDIA)": { + "contact_team_email": "chrome-gpu-infra@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "Win10 FYI x86 Release (NVIDIA)": { + "contact_team_email": "chrome-gpu-infra@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "Win10 Tests x64": { "contact_team_email": "chrome-desktop-engprod@google.com", "problem_specs": [ @@ -4190,6 +5969,26 @@ } ] }, + "android-11-x86-fyi-rel": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "android-11-x86-rel": { "problem_specs": [ { @@ -4210,6 +6009,46 @@ } ] }, + "android-12-x64-dbg-tests": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "android-12-x64-fyi-rel": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "android-12-x64-rel": { "contact_team_email": "clank-engprod@google.com", "problem_specs": [ @@ -4252,6 +6091,46 @@ } ] }, + "android-12l-x64-fyi-dbg": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "android-13-x64-fyi-rel": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "android-13-x64-rel": { "problem_specs": [ { @@ -4272,6 +6151,27 @@ } ] }, + "android-androidx-packager": { + "contact_team_email": "clank-build@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "android-angle-chromium-arm64-builder": { "contact_team_email": "angle-team@google.com", "problem_specs": [ @@ -4314,6 +6214,26 @@ } ] }, + "android-annotator-rel": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "android-archive-rel": { "contact_team_email": "clank-engprod@google.com", "problem_specs": [ @@ -4397,6 +6317,26 @@ } ] }, + "android-avd-packager": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "android-bfcache-rel": { "contact_team_email": "clank-engprod@google.com", "problem_specs": [ @@ -4439,6 +6379,86 @@ } ] }, + "android-chrome-pie-x86-wpt-android-specific": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "android-chrome-pie-x86-wpt-fyi-rel": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "android-code-coverage": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "android-code-coverage-native": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "android-cronet-arm-dbg": { "contact_team_email": "cronet-team@google.com", "problem_specs": [ @@ -4544,6 +6564,27 @@ } ] }, + "android-cronet-asan-x86-rel": { + "contact_team_email": "cronet-team@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "android-cronet-mainline-clang-arm64-dbg": { "contact_team_email": "cronet-team@google.com", "problem_specs": [ @@ -5027,6 +7068,46 @@ } ] }, + "android-device-flasher": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "android-fieldtrial-rel": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "android-official": { "contact_team_email": "clank-engprod@google.com", "problem_specs": [ @@ -5069,6 +7150,26 @@ } ] }, + "android-perfetto-rel": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "android-pie-arm64-dbg": { "contact_team_email": "clank-engprod@google.com", "problem_specs": [ @@ -5111,6 +7212,26 @@ } ] }, + "android-pie-x86-fyi-rel": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "android-pie-x86-rel": { "contact_team_email": "clank-engprod@google.com", "problem_specs": [ @@ -5132,6 +7253,86 @@ } ] }, + "android-rust-arm32-rel": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "android-rust-arm64-dbg": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "android-rust-arm64-rel": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "android-sdk-packager": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "android-webview-10-x86-rel-tests": { "contact_team_email": "woa-engprod@google.com", "problem_specs": [ @@ -5153,6 +7354,107 @@ } ] }, + "android-webview-12-x64-dbg-tests": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "android-webview-13-x64-dbg-hostside": { + "contact_team_email": "woa-engprod@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "android-webview-13-x64-dbg-tests": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "android-webview-pie-x86-wpt-fyi-rel": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "android-x86-code-coverage": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "android-x86-rel": { "contact_team_email": "woa-engprod@google.com", "problem_specs": [ @@ -5174,6 +7476,48 @@ } ] }, + "blink-flake-suppressor": { + "contact_team_email": "chrome-blink-engprod@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "blink-web-test-analyzer": { + "contact_team_email": "chrome-blink-engprod@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "chromeos-amd64-generic-asan-rel": { "contact_team_email": "chrome-sanitizer-builder-owners@google.com", "problem_specs": [ @@ -5344,6 +7688,46 @@ } ] }, + "chromeos-amd64-generic-rel (reclient compare)": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "chromeos-amd64-generic-rel (reclient)": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "chromeos-amd64-generic-rel-gtest": { "contact_team_email": "chromeos-sw-engprod@google.com", "problem_specs": [ @@ -5581,6 +7965,47 @@ } ] }, + "chromeos-jacuzzi-rel-skylab-fyi": { + "contact_team_email": "chromeos-velocity@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "chromeos-js-code-coverage": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "chromeos-octopus-rel": { "problem_specs": [ { @@ -5614,6 +8039,27 @@ } ] }, + "chromeos-octopus-rel-skylab-fyi": { + "contact_team_email": "chromeos-velocity@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "fuchsia-angle-builder": { "contact_team_email": "angle-team@google.com", "problem_specs": [ @@ -5677,6 +8123,130 @@ } ] }, + "fuchsia-code-coverage": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "fuchsia-fyi-arm64-dbg": { + "contact_team_email": "chrome-fuchsia-engprod@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "fuchsia-fyi-x64-asan": { + "contact_team_email": "chrome-fuchsia-engprod@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "fuchsia-fyi-x64-dbg": { + "contact_team_email": "chrome-fuchsia-engprod@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "fuchsia-fyi-x64-dbg-persistent-emulator": { + "contact_team_email": "chrome-fuchsia-engprod@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "fuchsia-x64-accessibility-rel": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "fuchsia-x64-cast-receiver-rel": { "contact_team_email": "chrome-fuchsia-engprod@google.com", "problem_specs": [ @@ -5803,6 +8373,26 @@ } ] }, + "ios-blink-dbg-fyi": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "ios-catalyst": { "problem_specs": [ { @@ -5843,6 +8433,47 @@ } ] }, + "ios-fieldtrial-rel": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "ios-m1-simulator": { + "contact_team_email": "bling-engprod@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "ios-simulator": { "problem_specs": [ { @@ -5863,6 +8494,26 @@ } ] }, + "ios-simulator-code-coverage": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "ios-simulator-full-configs": { "problem_specs": [ { @@ -5883,6 +8534,26 @@ } ] }, + "ios-simulator-multi-window": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "ios-simulator-noncq": { "problem_specs": [ { @@ -5903,6 +8574,166 @@ } ] }, + "ios-webkit-tot": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "ios-wpt-fyi-rel": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "ios16-beta-simulator": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "ios16-sdk-simulator": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "ios17-beta-simulator": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "ios17-sdk-device": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "ios17-sdk-simulator": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "lacros-amd64-generic-rel (reclient)": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "lacros-amd64-generic-rel-non-skylab": { "contact_team_email": "chrome-desktop-engprod@google.com", "problem_specs": [ @@ -6168,6 +8999,27 @@ } ] }, + "linux-3p-licenses": { + "contact_team_email": "chops-security-core@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "linux-angle-chromium-builder": { "contact_team_email": "angle-team@google.com", "problem_specs": [ @@ -6231,6 +9083,26 @@ } ] }, + "linux-annotator-rel": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "linux-archive-rel": { "contact_team_email": "chrome-browser-infra-team@google.com", "problem_specs": [ @@ -6327,6 +9199,86 @@ } ] }, + "linux-blink-animation-use-time-delta": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "linux-blink-heap-verification": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "linux-blink-web-tests-force-accessibility-rel": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "linux-blink-wpt-reset-rel": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "linux-cfm-rel": { "contact_team_email": "core-devices-eng@google.com", "problem_specs": [ @@ -6361,6 +9313,26 @@ } ] }, + "linux-chromeos-annotator-rel": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "linux-chromeos-archive-rel": { "problem_specs": [ { @@ -6381,6 +9353,26 @@ } ] }, + "linux-chromeos-code-coverage": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "linux-chromeos-dbg": { "contact_team_email": "chromeos-sw-engprod@google.com", "problem_specs": [ @@ -6443,6 +9435,66 @@ } ] }, + "linux-code-coverage": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "linux-exp-msan-fyi-rel": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "linux-exp-tsan-fyi-rel": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "linux-extended-tracing-rel": { "contact_team_email": "chrome-linux-engprod@google.com", "problem_specs": [ @@ -6464,6 +9516,46 @@ } ] }, + "linux-fieldtrial-rel": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "linux-fuzz-coverage": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "linux-gcc-rel": { "contact_team_email": "build@chromium.org", "problem_specs": [ @@ -6485,6 +9577,46 @@ } ] }, + "linux-headless-shell-rel": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "linux-js-code-coverage": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "linux-lacros-archive-rel": { "problem_specs": [ { @@ -6526,6 +9658,26 @@ } ] }, + "linux-lacros-builder-fyi-rel": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "linux-lacros-builder-rel": { "contact_team_email": "chrome-desktop-engprod@google.com", "problem_specs": [ @@ -6560,6 +9712,46 @@ } ] }, + "linux-lacros-builder-rel (reclient)": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "linux-lacros-code-coverage": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "linux-lacros-dbg": { "contact_team_email": "chrome-desktop-engprod@google.com", "problem_specs": [ @@ -6594,6 +9786,66 @@ } ] }, + "linux-lacros-dbg-fyi": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "linux-lacros-dbg-tests-fyi": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "linux-lacros-tester-fyi-rel": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "linux-lacros-tester-rel": { "contact_team_email": "chrome-desktop-engprod@google.com", "problem_specs": [ @@ -6628,6 +9880,26 @@ } ] }, + "linux-network-sandbox-rel": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "linux-official": { "problem_specs": [ { @@ -6655,6 +9927,47 @@ } ] }, + "linux-perfetto-rel": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "linux-presubmit": { + "contact_team_email": "chrome-browser-infra-team@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "linux-rel-cft": { "contact_team_email": "browser-automation-staff@google.com", "problem_specs": [ @@ -6676,6 +9989,66 @@ } ] }, + "linux-rel-no-external-ip": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "linux-rust-x64-dbg": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "linux-rust-x64-rel": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "linux-swangle-chromium-x64": { "contact_team_email": "chrome-gpu-infra@google.com", "problem_specs": [ @@ -6781,6 +10154,26 @@ } ] }, + "linux-ubsan-fyi-rel": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "linux-ubsan-vptr": { "contact_team_email": "chrome-sanitizer-builder-owners@google.com", "problem_specs": [ @@ -6802,6 +10195,106 @@ } ] }, + "linux-updater-builder-dbg": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "linux-updater-builder-rel": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "linux-updater-tester-dbg": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "linux-updater-tester-rel": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "linux-upload-perfetto": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "linux-v4l2-codec-rel": { "problem_specs": [ { @@ -6846,6 +10339,86 @@ } ] }, + "linux-wpt-chromium-rel": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "linux-wpt-content-shell-asan-fyi-rel": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "linux-wpt-content-shell-fyi-rel": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "linux-wpt-content-shell-leak-detection": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "mac-angle-chromium-amd": { "contact_team_email": "angle-team@google.com", "problem_specs": [ @@ -7014,6 +10587,46 @@ } ] }, + "mac-code-coverage": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "mac-fieldtrial-tester": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "mac-intel-on-arm64-rel": { "problem_specs": [ { @@ -7034,6 +10647,26 @@ } ] }, + "mac-lsan-fyi-rel": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "mac-official": { "contact_team_email": "bling-engprod@google.com", "problem_specs": [ @@ -7055,6 +10688,46 @@ } ] }, + "mac-osxbeta-rel": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "mac-perfetto-rel": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "mac-rel-cft": { "contact_team_email": "browser-automation-staff@google.com", "problem_specs": [ @@ -7076,6 +10749,26 @@ } ] }, + "mac-rust-x64-dbg": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "mac-swangle-chromium-x64": { "contact_team_email": "chrome-gpu-infra@google.com", "problem_specs": [ @@ -7097,6 +10790,186 @@ } ] }, + "mac-updater-builder-arm64-dbg": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "mac-updater-builder-arm64-rel": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "mac-updater-builder-asan-dbg": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "mac-updater-builder-dbg": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "mac-updater-builder-rel": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "mac-upload-perfetto": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "mac10.15-updater-tester-dbg": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "mac10.15-updater-tester-rel": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "mac10.15-wpt-content-shell-fyi-rel": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "mac11-arm64-rel-tests": { "contact_team_email": "bling-engprod@google.com", "problem_specs": [ @@ -7118,6 +10991,126 @@ } ] }, + "mac11-arm64-updater-tester-dbg": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "mac11-arm64-updater-tester-rel": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "mac11-arm64-wpt-content-shell-fyi-rel": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "mac11-wpt-content-shell-fyi-rel": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "mac11-x64-updater-tester-dbg": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "mac11-x64-updater-tester-rel": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "mac12-arm64-rel-tests": { "contact_team_email": "bling-engprod@google.com", "problem_specs": [ @@ -7139,6 +11132,86 @@ } ] }, + "mac12-arm64-updater-tester-rel": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "mac12-arm64-wpt-content-shell-fyi-rel": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "mac12-wpt-content-shell-fyi-rel": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "mac12-x64-updater-tester-asan-dbg": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "mac13-arm64-rel-tests": { "contact_team_email": "bling-engprod@google.com", "problem_specs": [ @@ -7160,6 +11233,146 @@ } ] }, + "mac13-arm64-updater-tester-dbg": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "mac13-arm64-wpt-content-shell-fyi-rel": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "mac13-wpt-content-shell-fyi-rel": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "mac13-x64-updater-tester-rel": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "metadata-exporter": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "rts-model-packager": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "rts-suite-analysis": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "win-angle-chromium-x64-builder": { "contact_team_email": "angle-team@google.com", "problem_specs": [ @@ -7202,6 +11415,26 @@ } ] }, + "win-annotator-rel": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "win-archive-rel": { "contact_team_email": "chrome-desktop-engprod@google.com", "problem_specs": [ @@ -7244,6 +11477,66 @@ } ] }, + "win-celab-builder-rel": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "win-fieldtrial-rel": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "win-network-sandbox-tester": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "win-official": { "contact_team_email": "chrome-desktop-engprod@google.com", "problem_specs": [ @@ -7265,6 +11558,47 @@ } ] }, + "win-perfetto-rel": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "win-presubmit": { + "contact_team_email": "chrome-browser-infra-team@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "win-rel-cft": { "contact_team_email": "browser-automation-staff@google.com", "problem_specs": [ @@ -7286,6 +11620,46 @@ } ] }, + "win-rust-x64-dbg": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "win-rust-x64-rel": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "win-swangle-chromium-x86": { "contact_team_email": "chrome-gpu-infra@google.com", "problem_specs": [ @@ -7391,6 +11765,106 @@ } ] }, + "win-updater-builder-dbg": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "win-updater-builder-rel": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "win-upload-perfetto": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "win10-32-on-64-updater-tester-dbg": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "win10-32-on-64-updater-tester-rel": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "win10-angle-chromium-x64-intel": { "contact_team_email": "angle-team@google.com", "problem_specs": [ @@ -7433,6 +11907,227 @@ } ] }, + "win10-code-coverage": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "win10-multiscreen-fyi-rel": { + "contact_team_email": "web-windowing-team@google.com", + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "win10-rel-no-external-ip": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "win10-updater-tester-dbg": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "win10-updater-tester-dbg-uac": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "win10-updater-tester-rel": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "win10-updater-tester-rel-uac": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "win10-wpt-content-shell-fyi-rel": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "win11-updater-tester-dbg-uac": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "win11-updater-tester-rel": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "win11-wpt-content-shell-fyi-rel": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "win32-archive-rel": { "contact_team_email": "chrome-desktop-engprod@google.com", "problem_specs": [ @@ -7454,6 +12149,26 @@ } ] }, + "win32-arm64-rel": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, "win32-official": { "contact_team_email": "chrome-desktop-engprod@google.com", "problem_specs": [ @@ -7474,6 +12189,46 @@ } } ] + }, + "win32-updater-builder-dbg": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] + }, + "win32-updater-builder-rel": { + "problem_specs": [ + { + "name": "Unhealthy", + "period_days": 7, + "score": 5, + "thresholds": { + "_default": "_default" + } + }, + { + "name": "Low Value", + "period_days": 90, + "score": 1, + "thresholds": { + "_default": "_default" + } + } + ] } } }
diff --git a/infra/config/generated/luci/cr-buildbucket.cfg b/infra/config/generated/luci/cr-buildbucket.cfg index dc36fa8b..40a6867 100644 --- a/infra/config/generated/luci/cr-buildbucket.cfg +++ b/infra/config/generated/luci/cr-buildbucket.cfg
@@ -36545,7 +36545,7 @@ use_invocation_timestamp: true } } - description_html: "This is a tester builder for Ash chrome. This builder only run tast tests.<br/>This builder is mirrored by any of the following try builders:<br/><ul><li><a href=\"https://ci.chromium.org/p/chromium/builders/try/chromeos-amd64-generic-rel-gtest-and-tast\">chromeos-amd64-generic-rel-gtest-and-tast</a></li></ul>" + description_html: "This is a tester builder for Ash chrome. This builder only run tast tests. If you see test failures, please contact ChromeOS gardeners for help.<br/>This builder is mirrored by any of the following try builders:<br/><ul><li><a href=\"https://ci.chromium.org/p/chromium/builders/try/chromeos-amd64-generic-rel-gtest-and-tast\">chromeos-amd64-generic-rel-gtest-and-tast</a></li></ul>" shadow_builder_adjustments { service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com" pool: "luci.chromium.try" @@ -70932,7 +70932,7 @@ use_invocation_timestamp: true } } - description_html: "This is an Ash chrome builder which runs gtest and Tast tests. This builder is the default CQ builder for ChromeOS engineers only. For a CL, infra would check the CL’s owner to see if the owner is a ChromeOS org engineer or not. If the owner is a ChromeOS org engineer, the default CQ would include this builder which runs both Tast tests and gtests. Otherwise, the default CQ would include `chromeos-amd64-generic-rel-gtest` which only runs gtests.<br/>This builder mirrors the following CI builders:<br/><ul><li><a href=\"https://ci.chromium.org/p/chromium/builders/ci/chromeos-amd64-generic-rel\">chromeos-amd64-generic-rel</a></li><li><a href=\"https://ci.chromium.org/p/chromium/builders/ci/chromeos-amd64-generic-rel-gtest\">chromeos-amd64-generic-rel-gtest</a></li><li><a href=\"https://ci.chromium.org/p/chromium/builders/ci/chromeos-amd64-generic-rel-tast\">chromeos-amd64-generic-rel-tast</a></li></ul><br/>This is the orchestrator half of an orchestrator + compilator pair of builders. The compilator is <a href=\"https://ci.chromium.org/p/chromium/builders/try/chromeos-amd64-generic-rel-gtest-and-tast-compilator\">chromeos-amd64-generic-rel-gtest-and-tast-compilator</a>." + description_html: "This is an Ash chrome builder which runs gtest and Tast tests. This builder is the default CQ builder for ChromeOS engineers only. For a CL, infra would check the CL’s owner to see if the owner is a ChromeOS org engineer or not. If the owner is a ChromeOS org engineer, the default CQ would include this builder which runs both Tast tests and gtests. Otherwise, the default CQ would include `chromeos-amd64-generic-rel-gtest` which only runs gtests. If you encounter unexpected Tast tests failures, please contact ChromeOS gardeners for help.<br/>This builder mirrors the following CI builders:<br/><ul><li><a href=\"https://ci.chromium.org/p/chromium/builders/ci/chromeos-amd64-generic-rel\">chromeos-amd64-generic-rel</a></li><li><a href=\"https://ci.chromium.org/p/chromium/builders/ci/chromeos-amd64-generic-rel-gtest\">chromeos-amd64-generic-rel-gtest</a></li><li><a href=\"https://ci.chromium.org/p/chromium/builders/ci/chromeos-amd64-generic-rel-tast\">chromeos-amd64-generic-rel-tast</a></li></ul><br/>This is the orchestrator half of an orchestrator + compilator pair of builders. The compilator is <a href=\"https://ci.chromium.org/p/chromium/builders/try/chromeos-amd64-generic-rel-gtest-and-tast-compilator\">chromeos-amd64-generic-rel-gtest-and-tast-compilator</a>." contact_team_email: "chromeos-sw-engprod@google.com" } builders {
diff --git a/infra/config/generated/testing/gn_isolate_map.pyl b/infra/config/generated/testing/gn_isolate_map.pyl index 7b1dc28..f68be587 100644 --- a/infra/config/generated/testing/gn_isolate_map.pyl +++ b/infra/config/generated/testing/gn_isolate_map.pyl
@@ -1253,6 +1253,10 @@ "label": "//chrome/browser/media/router:openscreen_unittests", "type": "console_test_launcher", }, + "optimization_guide_gpu_unittests": { + "label": "//components/optimization_guide/internal:optimization_guide_gpu_unittests", + "type": "console_test_launcher", + }, "optimization_guide_unittests": { "label": "//components/optimization_guide/internal:optimization_guide_unittests", "type": "console_test_launcher",
diff --git a/infra/config/generated/testing/test_suites.pyl b/infra/config/generated/testing/test_suites.pyl index 795ac734..4647cf1 100644 --- a/infra/config/generated/testing/test_suites.pyl +++ b/infra/config/generated/testing/test_suites.pyl
@@ -4759,7 +4759,25 @@ }, }, - 'optimization_guide_gtests': { + 'optimization_guide_desktop_gtests': { + 'chrome_ml_unittests': {}, + 'optimization_guide_browser_tests': { + 'test': 'browser_tests', + 'args': [ + '--gtest_filter=*OptimizationGuide*:*PageContentAnnotations*', + ], + }, + 'optimization_guide_components_unittests': { + 'test': 'components_unittests', + 'args': [ + '--gtest_filter=*OptimizationGuide*:*PageEntities*:*EntityAnnotator*', + ], + }, + 'optimization_guide_gpu_unittests': {}, + 'optimization_guide_unittests': {}, + }, + + 'optimization_guide_desktop_gtests_nogpu': { 'chrome_ml_unittests': {}, 'optimization_guide_browser_tests': { 'test': 'browser_tests',
diff --git a/infra/config/subprojects/chromium/ci/blink.infra.star b/infra/config/subprojects/chromium/ci/blink.infra.star index e4a9741..7b51eb5 100644 --- a/infra/config/subprojects/chromium/ci/blink.infra.star +++ b/infra/config/subprojects/chromium/ci/blink.infra.star
@@ -6,6 +6,7 @@ load("//lib/builders.star", "os") load("//lib/ci.star", "ci") load("//lib/consoles.star", "consoles") +load("//lib/builder_health_indicators.star", "health_spec") ci.defaults.set( pool = ci.DEFAULT_POOL, @@ -13,6 +14,7 @@ os = os.LINUX_DEFAULT, console_view = "blink.infra", execution_timeout = 10 * time.hour, + health_spec = health_spec.DEFAULT, ) consoles.console_view(
diff --git a/infra/config/subprojects/chromium/ci/checks.star b/infra/config/subprojects/chromium/ci/checks.star index 777f3ce..3484b0a 100644 --- a/infra/config/subprojects/chromium/ci/checks.star +++ b/infra/config/subprojects/chromium/ci/checks.star
@@ -6,10 +6,12 @@ load("//lib/builders.star", "os", "sheriff_rotations") load("//lib/ci.star", "ci") load("//lib/consoles.star", "consoles") +load("//lib/builder_health_indicators.star", "health_spec") ci.defaults.set( pool = ci.DEFAULT_POOL, console_view = "checks", + health_spec = health_spec.DEFAULT, service_account = ci.DEFAULT_SERVICE_ACCOUNT, shadow_service_account = ci.DEFAULT_SHADOW_SERVICE_ACCOUNT, )
diff --git a/infra/config/subprojects/chromium/ci/chromium.accessibility.star b/infra/config/subprojects/chromium/ci/chromium.accessibility.star index 662550ea5..31059753 100644 --- a/infra/config/subprojects/chromium/ci/chromium.accessibility.star +++ b/infra/config/subprojects/chromium/ci/chromium.accessibility.star
@@ -9,6 +9,7 @@ load("//lib/ci.star", "ci") load("//lib/consoles.star", "consoles") load("//lib/gn_args.star", "gn_args") +load("//lib/builder_health_indicators.star", "health_spec") ci.defaults.set( executable = ci.DEFAULT_EXECUTABLE, @@ -17,6 +18,7 @@ cores = 8, os = os.LINUX_DEFAULT, execution_timeout = ci.DEFAULT_EXECUTION_TIMEOUT, + health_spec = health_spec.DEFAULT, notifies = ["cr-accessibility"], reclient_instance = reclient.instance.DEFAULT_TRUSTED, reclient_jobs = reclient.jobs.HIGH_JOBS_FOR_CI,
diff --git a/infra/config/subprojects/chromium/ci/chromium.android.fyi.star b/infra/config/subprojects/chromium/ci/chromium.android.fyi.star index 77251d3..acd14b2 100644 --- a/infra/config/subprojects/chromium/ci/chromium.android.fyi.star +++ b/infra/config/subprojects/chromium/ci/chromium.android.fyi.star
@@ -8,6 +8,7 @@ load("//lib/ci.star", "ci") load("//lib/consoles.star", "consoles") load("//lib/gn_args.star", "gn_args") +load("//lib/builder_health_indicators.star", "health_spec") ci.defaults.set( executable = ci.DEFAULT_EXECUTABLE, @@ -16,6 +17,7 @@ cores = 8, os = os.LINUX_DEFAULT, execution_timeout = ci.DEFAULT_EXECUTION_TIMEOUT, + health_spec = health_spec.DEFAULT, priority = ci.DEFAULT_FYI_PRIORITY, reclient_instance = reclient.instance.DEFAULT_TRUSTED, reclient_jobs = reclient.jobs.DEFAULT,
diff --git a/infra/config/subprojects/chromium/ci/chromium.chromiumos.star b/infra/config/subprojects/chromium/ci/chromium.chromiumos.star index 3878492..6b9c2cd 100644 --- a/infra/config/subprojects/chromium/ci/chromium.chromiumos.star +++ b/infra/config/subprojects/chromium/ci/chromium.chromiumos.star
@@ -420,7 +420,9 @@ name = "chromeos-amd64-generic-rel-tast", branch_selector = branches.selector.CROS_LTS_BRANCHES, description_html = "This is a tester builder for Ash chrome." + - " This builder only run tast tests.", + " This builder only run tast tests. If you see" + + " test failures, please contact ChromeOS gardeners" + + " for help.", triggered_by = ["ci/chromeos-amd64-generic-rel"], builder_spec = builder_config.builder_spec( execution_mode = builder_config.execution_mode.TEST,
diff --git a/infra/config/subprojects/chromium/ci/chromium.coverage.star b/infra/config/subprojects/chromium/ci/chromium.coverage.star index 5d1cb73..b0b1cfb 100644 --- a/infra/config/subprojects/chromium/ci/chromium.coverage.star +++ b/infra/config/subprojects/chromium/ci/chromium.coverage.star
@@ -9,6 +9,7 @@ load("//lib/consoles.star", "consoles") load("//lib/gn_args.star", "gn_args") load("//project.star", "settings") +load("//lib/builder_health_indicators.star", "health_spec") # crbug/1408581 - The code coverage CI builders are expected to be triggered # off the same ref every 24 hours. This poller is configured with a schedule @@ -30,6 +31,7 @@ cores = 32, ssd = True, execution_timeout = 20 * time.hour, + health_spec = health_spec.DEFAULT, priority = ci.DEFAULT_FYI_PRIORITY, reclient_instance = reclient.instance.DEFAULT_TRUSTED, reclient_jobs = reclient.jobs.DEFAULT,
diff --git a/infra/config/subprojects/chromium/ci/chromium.fuchsia.fyi.star b/infra/config/subprojects/chromium/ci/chromium.fuchsia.fyi.star index 9990492e..7c517f47 100644 --- a/infra/config/subprojects/chromium/ci/chromium.fuchsia.fyi.star +++ b/infra/config/subprojects/chromium/ci/chromium.fuchsia.fyi.star
@@ -9,6 +9,7 @@ load("//lib/ci.star", "ci") load("//lib/consoles.star", "consoles") load("//lib/gn_args.star", "gn_args") +load("//lib/builder_health_indicators.star", "health_spec") ci.defaults.set( executable = ci.DEFAULT_EXECUTABLE, @@ -18,6 +19,7 @@ os = os.LINUX_DEFAULT, sheriff_rotations = sheriff_rotations.FUCHSIA, execution_timeout = 10 * time.hour, + health_spec = health_spec.DEFAULT, notifies = ["cr-fuchsia"], reclient_instance = reclient.instance.DEFAULT_TRUSTED, reclient_jobs = reclient.jobs.DEFAULT,
diff --git a/infra/config/subprojects/chromium/ci/chromium.fyi.star b/infra/config/subprojects/chromium/ci/chromium.fyi.star index bf1a0f4..9a70138 100644 --- a/infra/config/subprojects/chromium/ci/chromium.fyi.star +++ b/infra/config/subprojects/chromium/ci/chromium.fyi.star
@@ -10,6 +10,7 @@ load("//lib/consoles.star", "consoles") load("//lib/gn_args.star", "gn_args") load("//lib/structs.star", "structs") +load("//lib/builder_health_indicators.star", "health_spec") ci.defaults.set( executable = ci.DEFAULT_EXECUTABLE, @@ -17,6 +18,7 @@ pool = ci.DEFAULT_POOL, cores = 8, execution_timeout = 10 * time.hour, + health_spec = health_spec.DEFAULT, priority = ci.DEFAULT_FYI_PRIORITY, reclient_instance = reclient.instance.DEFAULT_TRUSTED, reclient_jobs = reclient.jobs.DEFAULT,
diff --git a/infra/config/subprojects/chromium/ci/chromium.gpu.fyi.star b/infra/config/subprojects/chromium/ci/chromium.gpu.fyi.star index 266a6ff..e5ee7b0 100644 --- a/infra/config/subprojects/chromium/ci/chromium.gpu.fyi.star +++ b/infra/config/subprojects/chromium/ci/chromium.gpu.fyi.star
@@ -9,6 +9,7 @@ load("//lib/ci.star", "ci") load("//lib/consoles.star", "consoles") load("//lib/gn_args.star", "gn_args") +load("//lib/builder_health_indicators.star", "health_spec") ci.defaults.set( executable = ci.DEFAULT_EXECUTABLE, @@ -17,6 +18,7 @@ sheriff_rotations = sheriff_rotations.CHROMIUM_GPU, contact_team_email = "chrome-gpu-infra@google.com", execution_timeout = 6 * time.hour, + health_spec = health_spec.DEFAULT, properties = { "perf_dashboard_machine_group": "ChromiumGPUFYI", },
diff --git a/infra/config/subprojects/chromium/ci/chromium.infra.star b/infra/config/subprojects/chromium/ci/chromium.infra.star index 99d993fe..3033cf6f 100644 --- a/infra/config/subprojects/chromium/ci/chromium.infra.star +++ b/infra/config/subprojects/chromium/ci/chromium.infra.star
@@ -4,6 +4,7 @@ """Definitions of builders in the chromium.infra builder group.""" load("//lib/branches.star", "branches") +load("//lib/builder_health_indicators.star", "health_spec") load("//lib/builders.star", "os", "sheriff_rotations") load("//lib/ci.star", "ci") load("//lib/consoles.star", "consoles") @@ -14,6 +15,7 @@ cores = 8, os = os.LINUX_DEFAULT, execution_timeout = ci.DEFAULT_EXECUTION_TIMEOUT, + health_spec = health_spec.DEFAULT, service_account = ci.DEFAULT_SERVICE_ACCOUNT, shadow_service_account = ci.DEFAULT_SHADOW_SERVICE_ACCOUNT, )
diff --git a/infra/config/subprojects/chromium/ci/chromium.memory.fyi.star b/infra/config/subprojects/chromium/ci/chromium.memory.fyi.star index 1da180b..27726e6 100644 --- a/infra/config/subprojects/chromium/ci/chromium.memory.fyi.star +++ b/infra/config/subprojects/chromium/ci/chromium.memory.fyi.star
@@ -8,6 +8,7 @@ load("//lib/ci.star", "ci") load("//lib/consoles.star", "consoles") load("//lib/gn_args.star", "gn_args") +load("//lib/builder_health_indicators.star", "health_spec") ci.defaults.set( executable = ci.DEFAULT_EXECUTABLE, @@ -16,6 +17,7 @@ cores = 8, os = os.LINUX_DEFAULT, execution_timeout = ci.DEFAULT_EXECUTION_TIMEOUT, + health_spec = health_spec.DEFAULT, priority = ci.DEFAULT_FYI_PRIORITY, reclient_instance = reclient.instance.DEFAULT_TRUSTED, reclient_jobs = reclient.jobs.LOW_JOBS_FOR_CI,
diff --git a/infra/config/subprojects/chromium/ci/chromium.rust.star b/infra/config/subprojects/chromium/ci/chromium.rust.star index a5d2248e..b021f8e 100644 --- a/infra/config/subprojects/chromium/ci/chromium.rust.star +++ b/infra/config/subprojects/chromium/ci/chromium.rust.star
@@ -8,6 +8,7 @@ load("//lib/ci.star", "ci") load("//lib/consoles.star", "consoles") load("//lib/gn_args.star", "gn_args") +load("//lib/builder_health_indicators.star", "health_spec") ci.defaults.set( executable = ci.DEFAULT_EXECUTABLE, @@ -17,6 +18,7 @@ cores = 8, os = os.LINUX_DEFAULT, execution_timeout = ci.DEFAULT_EXECUTION_TIMEOUT, + health_spec = health_spec.DEFAULT, notifies = ["chrome-rust-experiments"], reclient_instance = reclient.instance.DEFAULT_TRUSTED, reclient_jobs = reclient.jobs.DEFAULT,
diff --git a/infra/config/subprojects/chromium/ci/chromium.updater.star b/infra/config/subprojects/chromium/ci/chromium.updater.star index a18d6c5..b81aa38 100644 --- a/infra/config/subprojects/chromium/ci/chromium.updater.star +++ b/infra/config/subprojects/chromium/ci/chromium.updater.star
@@ -9,6 +9,7 @@ load("//lib/ci.star", "ci") load("//lib/consoles.star", "consoles") load("//lib/gn_args.star", "gn_args") +load("//lib/builder_health_indicators.star", "health_spec") ci.defaults.set( executable = ci.DEFAULT_EXECUTABLE, @@ -17,6 +18,7 @@ cores = 8, os = os.LINUX_DEFAULT, execution_timeout = ci.DEFAULT_EXECUTION_TIMEOUT, + health_spec = health_spec.DEFAULT, reclient_instance = reclient.instance.DEFAULT_TRUSTED, reclient_jobs = reclient.jobs.DEFAULT, service_account = ci.DEFAULT_SERVICE_ACCOUNT,
diff --git a/infra/config/subprojects/chromium/ci/metadata.exporter.star b/infra/config/subprojects/chromium/ci/metadata.exporter.star index f29d4d35..3aff268 100644 --- a/infra/config/subprojects/chromium/ci/metadata.exporter.star +++ b/infra/config/subprojects/chromium/ci/metadata.exporter.star
@@ -6,12 +6,14 @@ load("//lib/builders.star", "os") load("//lib/ci.star", "ci") load("//lib/consoles.star", "consoles") +load("//lib/builder_health_indicators.star", "health_spec") ci.defaults.set( pool = ci.DEFAULT_POOL, cores = 8, os = os.LINUX_DEFAULT, execution_timeout = ci.DEFAULT_EXECUTION_TIMEOUT, + health_spec = health_spec.DEFAULT, ) consoles.console_view(
diff --git a/infra/config/subprojects/chromium/try/tryserver.chromium.chromiumos.star b/infra/config/subprojects/chromium/try/tryserver.chromium.chromiumos.star index da96972..f95c9b4 100644 --- a/infra/config/subprojects/chromium/try/tryserver.chromium.chromiumos.star +++ b/infra/config/subprojects/chromium/try/tryserver.chromium.chromiumos.star
@@ -131,7 +131,9 @@ " default CQ would include this builder which runs" + " both Tast tests and gtests. Otherwise, the default" + " CQ would include `chromeos-amd64-generic-rel-gtest`" + - " which only runs gtests.", + " which only runs gtests. If you encounter unexpected" + + " Tast tests failures, please contact ChromeOS" + + " gardeners for help.", mirrors = [ "ci/chromeos-amd64-generic-rel", "ci/chromeos-amd64-generic-rel-gtest",
diff --git a/infra/config/subprojects/codesearch/codesearch.star b/infra/config/subprojects/codesearch/codesearch.star index 7df6873..13a4e219 100644 --- a/infra/config/subprojects/codesearch/codesearch.star +++ b/infra/config/subprojects/codesearch/codesearch.star
@@ -119,7 +119,7 @@ "ios_disable_code_signing", ], ), - os = os.MAC_13, + os = os.MAC_DEFAULT, cpu = cpu.ARM64, properties = { "recipe_properties": {
diff --git a/infra/config/targets/basic_suites.star b/infra/config/targets/basic_suites.star index ba3d7194..5858a73 100644 --- a/infra/config/targets/basic_suites.star +++ b/infra/config/targets/basic_suites.star
@@ -4417,7 +4417,18 @@ ) targets.legacy_basic_suite( - name = "optimization_guide_gtests", + name = "optimization_guide_desktop_gtests", + tests = { + "chrome_ml_unittests": targets.legacy_test_config(), + "optimization_guide_browser_tests": targets.legacy_test_config(), + "optimization_guide_components_unittests": targets.legacy_test_config(), + "optimization_guide_gpu_unittests": targets.legacy_test_config(), + "optimization_guide_unittests": targets.legacy_test_config(), + }, +) + +targets.legacy_basic_suite( + name = "optimization_guide_desktop_gtests_nogpu", tests = { "chrome_ml_unittests": targets.legacy_test_config(), "optimization_guide_browser_tests": targets.legacy_test_config(),
diff --git a/infra/config/targets/binaries.star b/infra/config/targets/binaries.star index 7a54f391..5f792fb 100644 --- a/infra/config/targets/binaries.star +++ b/infra/config/targets/binaries.star
@@ -1336,6 +1336,11 @@ ) targets.binaries.console_test_launcher( + name = "optimization_guide_gpu_unittests", + label = "//components/optimization_guide/internal:optimization_guide_gpu_unittests", +) + +targets.binaries.console_test_launcher( name = "optimization_guide_unittests", label = "//components/optimization_guide/internal:optimization_guide_unittests", )
diff --git a/infra/config/targets/tests.star b/infra/config/targets/tests.star index 09312af..fd089f0 100644 --- a/infra/config/targets/tests.star +++ b/infra/config/targets/tests.star
@@ -1666,6 +1666,10 @@ ) targets.tests.gtest_test( + name = "optimization_guide_gpu_unittests", +) + +targets.tests.gtest_test( name = "optimization_guide_unittests", )
diff --git a/internal b/internal index ac35abe1..88f3b82 160000 --- a/internal +++ b/internal
@@ -1 +1 @@ -Subproject commit ac35abe17d096d337e8a739b940517c76a37fb86 +Subproject commit 88f3b828bb668e23cbc133370ad3ca13665cacc9
diff --git a/ios/chrome/test/wpt/BUILD.gn b/ios/chrome/test/wpt/BUILD.gn index 314a777..34ae05e 100644 --- a/ios/chrome/test/wpt/BUILD.gn +++ b/ios/chrome/test/wpt/BUILD.gn
@@ -20,29 +20,11 @@ "--zero-tests-executed-ok", "--no-retry-failures", "--use-upstream-wpt", - - # TODO(crbug.com/1351820): Update the dependency to third_party/blink/tools build file. ] deps = [ ":all_tests" ] - data = [ - "//third_party/blink/tools/run_wpt_tests.py", - "//third_party/wpt_tools/", - "//third_party/blink/tools/blinkpy/", - "//build/skia_gold_common/", - "//third_party/blink/web_tests/external/", - "//third_party/blink/web_tests/wpt_internal/", - "//third_party/blink/web_tests/resources/testdriver-vendor.js", - "//third_party/blink/web_tests/wptrunner.blink.ini", - "//third_party/blink/web_tests/FlagSpecificConfig", - "//third_party/blink/web_tests/TestLists/", - "//third_party/blink/web_tests/VirtualTestSuites", - "//.vpython3", - ] data_deps = [ ":tools", - "//testing:test_scripts_shared", - "//third_party/catapult/third_party/typ:typ", - "//tools/imagediff", + "//third_party/blink/tools:wpt_tests_isolate", ] }
diff --git a/media/audio/audio_device_description.cc b/media/audio/audio_device_description.cc index f769570..7bdd9cff 100644 --- a/media/audio/audio_device_description.cc +++ b/media/audio/audio_device_description.cc
@@ -134,12 +134,27 @@ } } +AudioDeviceDescription::AudioDeviceDescription() = default; +AudioDeviceDescription::~AudioDeviceDescription() = default; + +AudioDeviceDescription::AudioDeviceDescription( + const AudioDeviceDescription& other) = default; +AudioDeviceDescription& AudioDeviceDescription::operator=( + const AudioDeviceDescription& other) = default; + +AudioDeviceDescription::AudioDeviceDescription(AudioDeviceDescription&& other) = + default; +AudioDeviceDescription& AudioDeviceDescription::operator=( + AudioDeviceDescription&& other) = default; + AudioDeviceDescription::AudioDeviceDescription(std::string device_name, std::string unique_id, - std::string group_id) - : device_name(std::move(device_name)), - unique_id(std::move(unique_id)), - group_id(std::move(group_id)) {} + std::string group_id, + bool is_system_default) + : device_name(device_name), + unique_id(unique_id), + group_id(group_id), + is_system_default(is_system_default) {} bool AudioDeviceDescription::operator==( const AudioDeviceDescription& other) const {
diff --git a/media/audio/audio_device_description.h b/media/audio/audio_device_description.h index 6d80942..8a252ca2 100644 --- a/media/audio/audio_device_description.h +++ b/media/audio/audio_device_description.h
@@ -83,19 +83,25 @@ static void LocalizeDeviceDescriptions( std::vector<AudioDeviceDescription>* device_descriptions); - AudioDeviceDescription() = default; - AudioDeviceDescription(const AudioDeviceDescription& other) = default; + AudioDeviceDescription(); + AudioDeviceDescription(const AudioDeviceDescription& other); + AudioDeviceDescription& operator=(const AudioDeviceDescription& other); + AudioDeviceDescription(AudioDeviceDescription&& other); + AudioDeviceDescription& operator=(AudioDeviceDescription&& other); AudioDeviceDescription(std::string device_name, std::string unique_id, - std::string group_id); + std::string group_id, + bool is_system_default = false); - ~AudioDeviceDescription() = default; + ~AudioDeviceDescription(); bool operator==(const AudioDeviceDescription& other) const; - std::string device_name; // Friendly name of the device. - std::string unique_id; // Unique identifier for the device. - std::string group_id; // Group identifier. + std::string device_name; // Friendly name of the device. + std::string unique_id; // Unique identifier for the device. + std::string group_id; // Group identifier. + bool is_system_default = false; // True if the device represented by this + // description is the system default. }; typedef std::vector<AudioDeviceDescription> AudioDeviceDescriptions;
diff --git a/media/audio/audio_manager_base.cc b/media/audio/audio_manager_base.cc index 8aac238..28fbca8 100644 --- a/media/audio/audio_manager_base.cc +++ b/media/audio/audio_manager_base.cc
@@ -178,14 +178,17 @@ } for (auto& name : device_names) { - if (AudioDeviceDescription::IsDefaultDevice(name.unique_id)) + bool is_system_default = name.unique_id == real_default_device_id; + if (AudioDeviceDescription::IsDefaultDevice(name.unique_id)) { name.device_name = real_default_name; - else if (AudioDeviceDescription::IsCommunicationsDevice(name.unique_id)) + is_system_default = true; + } else if (AudioDeviceDescription::IsCommunicationsDevice(name.unique_id)) { name.device_name = real_communications_name; + } std::string group_id = (this->*get_group_id)(name.unique_id); device_descriptions->emplace_back(std::move(name.device_name), std::move(name.unique_id), - std::move(group_id)); + std::move(group_id), is_system_default); } }
diff --git a/media/audio/audio_manager_unittest.cc b/media/audio/audio_manager_unittest.cc index 739e7785..c646c6d0 100644 --- a/media/audio/audio_manager_unittest.cc +++ b/media/audio/audio_manager_unittest.cc
@@ -122,6 +122,8 @@ EXPECT_TRUE(base::EndsWith(description.device_name, real_communications_label, base::CompareCase::SENSITIVE)); + } else if (description.unique_id == real_default_id) { + EXPECT_TRUE(description.is_system_default); } } }
diff --git a/media/base/media_types.h b/media/base/media_types.h index ed9b7c3..5802cce 100644 --- a/media/base/media_types.h +++ b/media/base/media_types.h
@@ -11,6 +11,7 @@ #include "media/base/video_codecs.h" #include "media/base/video_color_space.h" #include "media/base/video_decoder_config.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { @@ -18,6 +19,13 @@ // These are generally a subset of {Audio|Video}DecoderConfig classes, which can // only be created after demuxing. +enum class YuvSubsampling { + k400, + k420, + k422, + k444, +}; + struct MEDIA_EXPORT AudioType { static AudioType FromDecoderConfig(const AudioDecoderConfig& config); @@ -34,6 +42,7 @@ VideoCodecLevel level = kNoVideoCodecLevel; VideoColorSpace color_space; gfx::HdrMetadataType hdr_metadata_type = gfx::HdrMetadataType::kNone; + absl::optional<YuvSubsampling> subsampling; }; MEDIA_EXPORT bool operator==(const AudioType& x, const AudioType& y);
diff --git a/media/base/video_codec_string_parsers.cc b/media/base/video_codec_string_parsers.cc index 1018e74..75ebcea 100644 --- a/media/base/video_codec_string_parsers.cc +++ b/media/base/video_codec_string_parsers.cc
@@ -33,6 +33,7 @@ VideoType result = { .codec = VideoCodec::kVP9, .color_space = VideoColorSpace::REC709(), + .subsampling = YuvSubsampling::k420, }; std::vector<std::string> fields = base::SplitString( @@ -116,9 +117,27 @@ return result; } const int chroma_subsampling = values[3]; - if (chroma_subsampling > 3) { - DVLOG(3) << __func__ << " Invalid chroma subsampling (" - << chroma_subsampling << ")"; + switch (chroma_subsampling) { + case 0: + case 1: + result.subsampling = YuvSubsampling::k420; + break; + case 2: + result.subsampling = YuvSubsampling::k422; + break; + case 3: + result.subsampling = YuvSubsampling::k444; + break; + default: + DVLOG(3) << __func__ << " Invalid chroma subsampling (" + << chroma_subsampling << ")"; + return absl::nullopt; + } + + if (result.subsampling != YuvSubsampling::k420 && profile_idc != 1 && + profile_idc != 3) { + DVLOG(3) << __func__ + << " 4:2:2 and 4:4:4 are only supported in profile 1, 3"; return absl::nullopt; } @@ -219,6 +238,7 @@ VideoType result = { .codec = VideoCodec::kAV1, .color_space = VideoColorSpace::REC709(), + .subsampling = YuvSubsampling::k420, }; if (fields[0] != "av01") { @@ -302,6 +322,9 @@ } if (values.size() <= 5) { + if (monochrome == 1) { + result.subsampling = YuvSubsampling::k400; + } return result; } @@ -331,6 +354,24 @@ return absl::nullopt; } + if (subsampling_x == '0' && subsampling_y == '0' && monochrome == 0) { + result.subsampling = YuvSubsampling::k444; + if (result.profile == AV1PROFILE_PROFILE_MAIN) { + DVLOG(3) << __func__ << "4:4:4 isn't supported in main profile."; + return absl::nullopt; + } + } else if (subsampling_x == '1' && subsampling_y == '0' && monochrome == 0) { + result.subsampling = YuvSubsampling::k422; + if (result.profile != AV1PROFILE_PROFILE_PRO) { + DVLOG(3) << __func__ << "4:2:2 is only supported in pro profile."; + return absl::nullopt; + } + } else if (subsampling_x == '1' && subsampling_y == '1' && monochrome == 0) { + result.subsampling = YuvSubsampling::k420; + } else if (subsampling_x == '1' && subsampling_y == '1' && monochrome == 1) { + result.subsampling = YuvSubsampling::k400; + } + if (values.size() <= 6) { return result; }
diff --git a/media/base/video_codec_string_parsers_unittest.cc b/media/base/video_codec_string_parsers_unittest.cc index db2dcd08..7555447 100644 --- a/media/base/video_codec_string_parsers_unittest.cc +++ b/media/base/video_codec_string_parsers_unittest.cc
@@ -29,6 +29,7 @@ EXPECT_EQ(VP9PROFILE_PROFILE0, result->profile); EXPECT_EQ(10u, result->level); EXPECT_EQ(VideoColorSpace::TransferID::BT709, result->color_space.transfer); + EXPECT_EQ(YuvSubsampling::k420, result->subsampling); } // Verify profile's 1, 2, and 3 parse correctly. @@ -81,13 +82,48 @@ EXPECT_FALSE(ParseNewStyleVp9CodecID("vp09.02.10.13")); // Verify chroma subsampling values. - EXPECT_TRUE(ParseNewStyleVp9CodecID("vp09.02.10.10.00")); - EXPECT_TRUE(ParseNewStyleVp9CodecID("vp09.02.10.10.01")); - EXPECT_TRUE(ParseNewStyleVp9CodecID("vp09.02.10.10.02")); - EXPECT_TRUE(ParseNewStyleVp9CodecID("vp09.02.10.10.03")); + { + auto result = ParseNewStyleVp9CodecID("vp09.02.10.10.00"); + ASSERT_TRUE(result); + EXPECT_EQ(YuvSubsampling::k420, result->subsampling); + } + { + auto result = ParseNewStyleVp9CodecID("vp09.02.10.10.01"); + ASSERT_TRUE(result); + EXPECT_EQ(YuvSubsampling::k420, result->subsampling); + } + { + auto result = ParseNewStyleVp9CodecID("vp09.01.10.10.02"); + ASSERT_TRUE(result); + EXPECT_EQ(YuvSubsampling::k422, result->subsampling); + } + { + auto result = ParseNewStyleVp9CodecID("vp09.03.10.10.02"); + ASSERT_TRUE(result); + EXPECT_EQ(YuvSubsampling::k422, result->subsampling); + } + { + auto result = ParseNewStyleVp9CodecID("vp09.01.10.10.03"); + ASSERT_TRUE(result); + EXPECT_EQ(YuvSubsampling::k444, result->subsampling); + } + { + auto result = ParseNewStyleVp9CodecID("vp09.03.10.10.03"); + ASSERT_TRUE(result); + EXPECT_EQ(YuvSubsampling::k444, result->subsampling); + } + // Values 4 - 7 are reserved. EXPECT_FALSE(ParseNewStyleVp9CodecID("vp09.02.10.10.04")); + // Test invalid profile + sampling combinations. + EXPECT_FALSE(ParseNewStyleVp9CodecID("vp09.00.10.10.02")); + EXPECT_FALSE(ParseNewStyleVp9CodecID("vp09.00.10.10.02")); + EXPECT_FALSE(ParseNewStyleVp9CodecID("vp09.02.10.10.02")); + EXPECT_FALSE(ParseNewStyleVp9CodecID("vp09.02.10.10.02")); + EXPECT_FALSE(ParseNewStyleVp9CodecID("vp09.02.10.10.03")); + EXPECT_FALSE(ParseNewStyleVp9CodecID("vp09.02.10.10.03")); + // Verify a few color profiles. // BT709 EXPECT_TRUE(ParseNewStyleVp9CodecID("vp09.02.10.10.00.01")); @@ -142,6 +178,7 @@ EXPECT_EQ(AV1PROFILE_PROFILE_MAIN, result->profile); EXPECT_EQ(4u, result->level); EXPECT_EQ(VideoColorSpace::TransferID::BT709, result->color_space.transfer); + EXPECT_EQ(YuvSubsampling::k420, result->subsampling); } // Verify high and pro profiles parse correctly. @@ -235,19 +272,55 @@ for (int i = 0; i <= 9; ++i) { const std::string codec_string = base::StringPrintf("av01.0.00M.08.%d", i); SCOPED_TRACE(codec_string); - EXPECT_EQ(i < 2, !!ParseAv1CodecId(codec_string)); + if (i < 2) { + auto result = ParseAv1CodecId(codec_string); + ASSERT_TRUE(result); + EXPECT_EQ(result->subsampling, + i == 0 ? YuvSubsampling::k420 : YuvSubsampling::k400); + } else { + EXPECT_FALSE(ParseAv1CodecId(codec_string)); + } } } TEST(ParseAv1CodecId, VerifyOptionalSubsampling) { // chroma subsampling values are {0,1}{0,1}{0,3} with the last value always // zero if either of the first two values are zero. - EXPECT_TRUE(ParseAv1CodecId("av01.0.00M.10.0.000")); - EXPECT_TRUE(ParseAv1CodecId("av01.0.00M.10.0.100")); - EXPECT_TRUE(ParseAv1CodecId("av01.0.00M.10.0.010")); - EXPECT_TRUE(ParseAv1CodecId("av01.0.00M.10.0.111")); - EXPECT_TRUE(ParseAv1CodecId("av01.0.00M.10.0.112")); - EXPECT_TRUE(ParseAv1CodecId("av01.0.00M.10.0.113")); + { + auto result = ParseAv1CodecId("av01.1.00M.10.0.000"); + ASSERT_TRUE(result); + EXPECT_EQ(result->subsampling, YuvSubsampling::k444); + } + { + auto result = ParseAv1CodecId("av01.2.00M.10.0.000"); + ASSERT_TRUE(result); + EXPECT_EQ(result->subsampling, YuvSubsampling::k444); + } + { + auto result = ParseAv1CodecId("av01.2.00M.10.0.100"); + ASSERT_TRUE(result); + EXPECT_EQ(result->subsampling, YuvSubsampling::k422); + } + { + auto result = ParseAv1CodecId("av01.0.00M.10.0.010"); + ASSERT_TRUE(result); + EXPECT_EQ(result->subsampling, YuvSubsampling::k420); + } + { + auto result = ParseAv1CodecId("av01.0.00M.10.0.111"); + ASSERT_TRUE(result); + EXPECT_EQ(result->subsampling, YuvSubsampling::k420); + } + { + auto result = ParseAv1CodecId("av01.0.00M.10.0.112"); + ASSERT_TRUE(result); + EXPECT_EQ(result->subsampling, YuvSubsampling::k420); + } + { + auto result = ParseAv1CodecId("av01.0.00M.10.0.113"); + ASSERT_TRUE(result); + EXPECT_EQ(result->subsampling, YuvSubsampling::k420); + } // Invalid cases. EXPECT_FALSE(ParseAv1CodecId("av01.0.00M.10.0.101")); @@ -256,11 +329,26 @@ EXPECT_FALSE(ParseAv1CodecId("av01.0.00M.10.0.011")); EXPECT_FALSE(ParseAv1CodecId("av01.0.00M.10.0.012")); EXPECT_FALSE(ParseAv1CodecId("av01.0.00M.10.0.013")); + EXPECT_FALSE(ParseAv1CodecId("av01.0.00M.10.0.100")); + EXPECT_FALSE(ParseAv1CodecId("av01.1.00M.10.0.100")); + EXPECT_FALSE(ParseAv1CodecId("av01.0.00M.10.0.000")); // The last-value may be non-zero if the first two values are non-zero. - EXPECT_TRUE(ParseAv1CodecId("av01.0.00M.10.0.110")); - EXPECT_TRUE(ParseAv1CodecId("av01.0.00M.10.0.100")); - EXPECT_TRUE(ParseAv1CodecId("av01.0.00M.10.0.010")); + { + auto result = ParseAv1CodecId("av01.0.00M.10.0.110"); + ASSERT_TRUE(result); + EXPECT_EQ(result->subsampling, YuvSubsampling::k420); + } + { + auto result = ParseAv1CodecId("av01.2.00M.10.0.100"); + ASSERT_TRUE(result); + EXPECT_EQ(result->subsampling, YuvSubsampling::k422); + } + { + auto result = ParseAv1CodecId("av01.0.00M.10.0.010"); + ASSERT_TRUE(result); + EXPECT_EQ(result->subsampling, YuvSubsampling::k420); + } for (int i = 2; i <= 9; ++i) { for (int j = 2; j <= 9; ++j) { @@ -286,30 +374,30 @@ // BT709 { - auto result = ParseAv1CodecId("av01.0.00M.10.0.000.01"); + auto result = ParseAv1CodecId("av01.0.00M.10.0.110.01"); ASSERT_TRUE(result); EXPECT_EQ(VideoColorSpace::PrimaryID::BT709, result->color_space.primaries); } // BT2020 { - auto result = ParseAv1CodecId("av01.0.00M.10.0.000.09"); + auto result = ParseAv1CodecId("av01.0.00M.10.0.110.09"); ASSERT_TRUE(result); EXPECT_EQ(VideoColorSpace::PrimaryID::BT2020, result->color_space.primaries); } // 0 is invalid. - EXPECT_FALSE(ParseAv1CodecId("av01.0.00M.10.0.000.00")); + EXPECT_FALSE(ParseAv1CodecId("av01.0.00M.10.0.110.00")); // 23 - 255 are reserved. - EXPECT_FALSE(ParseAv1CodecId("av01.0.00M.10.0.000.23")); + EXPECT_FALSE(ParseAv1CodecId("av01.0.00M.10.0.110.23")); // Leading zeros must be provided. - EXPECT_FALSE(ParseAv1CodecId("av01.0.00M.10.0.000.01.1")); + EXPECT_FALSE(ParseAv1CodecId("av01.0.00M.10.0.110.01.1")); // Negative values are not allowed. - EXPECT_FALSE(ParseAv1CodecId("av01.0.00M.10.0.000.01.-1")); + EXPECT_FALSE(ParseAv1CodecId("av01.0.00M.10.0.110.01.-1")); // Verify a few common EOTFs parse correctly. for (int eotf : {1, 4, 6, 14, 15, 13, 16}) { - auto codec_string = base::StringPrintf("av01.0.00M.10.0.000.01.%02d", eotf); + auto codec_string = base::StringPrintf("av01.0.00M.10.0.110.01.%02d", eotf); auto result = ParseAv1CodecId(codec_string); ASSERT_TRUE(result) << "eotf=" << eotf; EXPECT_EQ(static_cast<VideoColorSpace::TransferID>(eotf), @@ -317,52 +405,52 @@ } // Verify 0 and 3 are reserved EOTF values. - EXPECT_FALSE(ParseAv1CodecId("av01.0.00M.10.0.000.01.00")); - EXPECT_FALSE(ParseAv1CodecId("av01.0.00M.10.0.000.01.03")); + EXPECT_FALSE(ParseAv1CodecId("av01.0.00M.10.0.110.01.00")); + EXPECT_FALSE(ParseAv1CodecId("av01.0.00M.10.0.110.01.03")); // Leading zeros must be provided. - EXPECT_FALSE(ParseAv1CodecId("av01.0.00M.10.0.000.01.01.1")); + EXPECT_FALSE(ParseAv1CodecId("av01.0.00M.10.0.110.01.01.1")); // Negative values are not allowed. - EXPECT_FALSE(ParseAv1CodecId("av01.0.00M.10.0.000.01.01.-1")); + EXPECT_FALSE(ParseAv1CodecId("av01.0.00M.10.0.110.01.01.-1")); // Verify a few matrix coefficients. { - auto result = ParseAv1CodecId("av01.0.00M.10.0.000.01.01.00"); + auto result = ParseAv1CodecId("av01.0.00M.10.0.110.01.01.00"); ASSERT_TRUE(result); EXPECT_EQ(VideoColorSpace::MatrixID::RGB, result->color_space.matrix); } { - auto result = ParseAv1CodecId("av01.0.00M.10.0.000.01.01.01"); + auto result = ParseAv1CodecId("av01.0.00M.10.0.110.01.01.01"); ASSERT_TRUE(result); EXPECT_EQ(VideoColorSpace::MatrixID::BT709, result->color_space.matrix); } { - auto result = ParseAv1CodecId("av01.0.00M.10.0.000.01.01.10"); + auto result = ParseAv1CodecId("av01.0.00M.10.0.110.01.01.10"); ASSERT_TRUE(result); EXPECT_EQ(VideoColorSpace::MatrixID::BT2020_CL, result->color_space.matrix); } // Values 12 - 255 reserved. Though 12 at least is a valid value we should // support in the future. https://crbug.com/854290 - EXPECT_FALSE(ParseAv1CodecId("av01.0.00M.10.0.000.01.01.12")); + EXPECT_FALSE(ParseAv1CodecId("av01.0.00M.10.0.110.01.01.12")); // Leading zeros are not allowed. - EXPECT_FALSE(ParseAv1CodecId("av01.0.00M.10.0.000.01.01.00.00")); + EXPECT_FALSE(ParseAv1CodecId("av01.0.00M.10.0.110.01.01.00.00")); // Negative values are not allowed. - EXPECT_FALSE(ParseAv1CodecId("av01.0.00M.10.0.000.01.01.00.-1")); + EXPECT_FALSE(ParseAv1CodecId("av01.0.00M.10.0.110.01.01.00.-1")); // Verify full range flag (boolean 0 or 1). { - auto result = ParseAv1CodecId("av01.0.00M.10.0.000.01.01.00.0"); + auto result = ParseAv1CodecId("av01.0.00M.10.0.110.01.01.00.0"); ASSERT_TRUE(result); EXPECT_EQ(gfx::ColorSpace::RangeID::LIMITED, result->color_space.range); } { - auto result = ParseAv1CodecId("av01.0.00M.10.0.000.01.01.00.1"); + auto result = ParseAv1CodecId("av01.0.00M.10.0.110.01.01.00.1"); ASSERT_TRUE(result); EXPECT_EQ(gfx::ColorSpace::RangeID::FULL, result->color_space.range); } - EXPECT_FALSE(ParseAv1CodecId("av01.0.00M.10.0.000.01.01.00.2")); + EXPECT_FALSE(ParseAv1CodecId("av01.0.00M.10.0.110.01.01.00.2")); } TEST(ParseHEVCCodecIdTest, InvalidHEVCCodecIds) {
diff --git a/media/base/video_frame.cc b/media/base/video_frame.cc index 70e70b5..ab73424f 100644 --- a/media/base/video_frame.cc +++ b/media/base/video_frame.cc
@@ -1321,10 +1321,10 @@ return NumDmabufFds() > 0; } -const base::ScopedFD& VideoFrame::GetDmabufFd(size_t i) const { +int VideoFrame::GetDmabufFd(size_t i) const { DCHECK_EQ(storage_type_, STORAGE_DMABUFS); - return dmabuf_fds_->fds()[i]; + return dmabuf_fds_->fds()[i].get(); } bool VideoFrame::IsSameDmaBufsAs(const VideoFrame& frame) const {
diff --git a/media/base/video_frame.h b/media/base/video_frame.h index b83630ea..81366ff 100644 --- a/media/base/video_frame.h +++ b/media/base/video_frame.h
@@ -605,7 +605,7 @@ // The returned FDs are still owned by the VideoFrame. This means that the // caller shall not close them, or use them after the VideoFrame is destroyed. // For such use cases, use dup() to obtain your own copy of the FDs. - const base::ScopedFD& GetDmabufFd(size_t i) const; + int GetDmabufFd(size_t i) const; // Returns true if both VideoFrames are backed by DMABUF memory and point // to the same set of DMABUFs, meaning that both frames use the same memory.
diff --git a/media/fuchsia/video/fuchsia_video_decoder_unittest.cc b/media/fuchsia/video/fuchsia_video_decoder_unittest.cc index 7c24813..cdf04e3 100644 --- a/media/fuchsia/video/fuchsia_video_decoder_unittest.cc +++ b/media/fuchsia/video/fuchsia_video_decoder_unittest.cc
@@ -203,14 +203,15 @@ DestroySharedImage(sync_token, client_shared_image->mailbox()); } - SwapChainMailboxes CreateSwapChain(viz::SharedImageFormat format, - const gfx::Size& size, - const gfx::ColorSpace& color_space, - GrSurfaceOrigin surface_origin, - SkAlphaType alpha_type, - uint32_t usage) override { + gpu::SharedImageInterface::SwapChainSharedImages CreateSwapChain( + viz::SharedImageFormat format, + const gfx::Size& size, + const gfx::ColorSpace& color_space, + GrSurfaceOrigin surface_origin, + SkAlphaType alpha_type, + uint32_t usage) override { ADD_FAILURE(); - return SwapChainMailboxes(); + return gpu::SharedImageInterface::SwapChainSharedImages(nullptr, nullptr); } void PresentSwapChain(const gpu::SyncToken& sync_token, const gpu::Mailbox& mailbox) override {
diff --git a/media/gpu/chromeos/generic_dmabuf_video_frame_mapper.cc b/media/gpu/chromeos/generic_dmabuf_video_frame_mapper.cc index 1e446c59..0631ebe 100644 --- a/media/gpu/chromeos/generic_dmabuf_video_frame_mapper.cc +++ b/media/gpu/chromeos/generic_dmabuf_video_frame_mapper.cc
@@ -232,7 +232,7 @@ } uint8_t* mapped_addr = - Mmap(mapped_size, video_frame->GetDmabufFd(i).get(), permissions); + Mmap(mapped_size, video_frame->GetDmabufFd(i), permissions); if (!mapped_addr) { VLOGF(1) << "nullptr returned by Mmap"; MunmapBuffers(chunks, /*video_frame=*/nullptr);
diff --git a/media/gpu/chromeos/platform_video_frame_utils.cc b/media/gpu/chromeos/platform_video_frame_utils.cc index 4a834cc..4472242 100644 --- a/media/gpu/chromeos/platform_video_frame_utils.cc +++ b/media/gpu/chromeos/platform_video_frame_utils.cc
@@ -410,12 +410,11 @@ // Duplicate the FD's that are present. If there are more planes than // FD's, then duplicate the fd of the last plane until the number of // fds are the same as the number of planes. - const base::ScopedFD& source_fd = (i < video_frame->NumDmabufFds()) - ? video_frame->GetDmabufFd(i) - : duped_fds.back(); + int source_fd = (i < video_frame->NumDmabufFds()) + ? video_frame->GetDmabufFd(i) + : duped_fds.back().get(); - base::ScopedFD dup_fd = - base::ScopedFD(HANDLE_EINTR(dup(source_fd.get()))); + base::ScopedFD dup_fd = base::ScopedFD(HANDLE_EINTR(dup(source_fd))); // TODO(crbug.com/1097956): handle a failure gracefully. PCHECK(dup_fd.is_valid()); duped_fds.push_back(std::move(dup_fd));
diff --git a/media/gpu/chromeos/platform_video_frame_utils_unittest.cc b/media/gpu/chromeos/platform_video_frame_utils_unittest.cc index aab5348..f321bd5 100644 --- a/media/gpu/chromeos/platform_video_frame_utils_unittest.cc +++ b/media/gpu/chromeos/platform_video_frame_utils_unittest.cc
@@ -93,7 +93,7 @@ for (size_t i = 0; i < num_planes; i++) { const ColorPlaneLayout& plane = video_frame->layout().planes()[i]; // The original and duplicated FDs should be different. - EXPECT_NE(native_pixmap->GetDmaBufFd(i), video_frame->GetDmabufFd(i).get()); + EXPECT_NE(native_pixmap->GetDmaBufFd(i), video_frame->GetDmabufFd(i)); EXPECT_EQ(native_pixmap->GetDmaBufPitch(i), base::checked_cast<uint32_t>(plane.stride)); EXPECT_EQ(native_pixmap->GetDmaBufOffset(i), plane.offset);
diff --git a/media/gpu/chromeos/video_decoder_pipeline_unittest.cc b/media/gpu/chromeos/video_decoder_pipeline_unittest.cc index e7bce78..e82c994 100644 --- a/media/gpu/chromeos/video_decoder_pipeline_unittest.cc +++ b/media/gpu/chromeos/video_decoder_pipeline_unittest.cc
@@ -121,6 +121,11 @@ MOCK_METHOD2(AllocateSecureBuffer, void(uint32_t, chromeos::ChromeOsCdmContext::AllocateSecureBufferCB)); + MOCK_METHOD4(ParseEncryptedSliceHeader, + void(uint64_t, + uint32_t, + const std::vector<uint8_t>&, + ParseEncryptedSliceHeaderCB)); }; // A real implementation of this class would actually hold onto a reference of // the owner of the CdmContext to ensure it is not destructed before the
diff --git a/media/gpu/h264_decoder.cc b/media/gpu/h264_decoder.cc index aca19b5..b1925dd8 100644 --- a/media/gpu/h264_decoder.cc +++ b/media/gpu/h264_decoder.cc
@@ -101,6 +101,7 @@ H264Decoder::H264Accelerator::ParseEncryptedSliceHeader( const std::vector<base::span<const uint8_t>>& data, const std::vector<SubsampleEntry>& subsamples, + uint64_t secure_handle, H264SliceHeader* slice_header_out) { return H264Decoder::H264Accelerator::Status::kNotSupported; } @@ -1323,8 +1324,8 @@ prior_cencv1_subsamples_.end()); all_subsamples.insert(all_subsamples.end(), subsamples.begin(), subsamples.end()); - auto rv = accelerator_->ParseEncryptedSliceHeader(spans, all_subsamples, - curr_slice_hdr_.get()); + auto rv = accelerator_->ParseEncryptedSliceHeader( + spans, all_subsamples, secure_handle_, curr_slice_hdr_.get()); // Return now if this isn't fully processed and don't store the NALU info // since we will get called again in the kTryAgain case, and on an error we // want to exist.
diff --git a/media/gpu/h264_decoder.h b/media/gpu/h264_decoder.h index 59f576d..79d0e46 100644 --- a/media/gpu/h264_decoder.h +++ b/media/gpu/h264_decoder.h
@@ -119,15 +119,16 @@ // for the NALU type byte, is encrypted. |data| represents the encrypted // ranges which will include any SEI NALUs along with the encrypted slice // NALU. |subsamples| specifies what is encrypted and should have just a - // single clear byte for each and the rest is encrypted. |sps_nalu_data| - // and |pps_nalu_data| are the SPS and PPS NALUs respectively. - // |slice_header_out| should have its fields filled in upon successful + // single clear byte for each and the rest is encrypted. |secure_handle| is + // used on ARM to store the secure buffer reference to parse the header + // from. |slice_header_out| should have its fields filled in upon successful // return. Returns kOk if successful, kFail if there are errors, or // kTryAgain if the accelerator needs additional data before being able to // proceed. virtual Status ParseEncryptedSliceHeader( const std::vector<base::span<const uint8_t>>& data, const std::vector<SubsampleEntry>& subsamples, + uint64_t secure_handle, H264SliceHeader* slice_header_out); // Submit one slice for the current frame, passing the current |pps| and
diff --git a/media/gpu/h264_decoder_unittest.cc b/media/gpu/h264_decoder_unittest.cc index 7636eb2..5dfcdb35 100644 --- a/media/gpu/h264_decoder_unittest.cc +++ b/media/gpu/h264_decoder_unittest.cc
@@ -119,9 +119,10 @@ MOCK_METHOD0(CreateH264Picture, scoped_refptr<H264Picture>()); MOCK_METHOD1(SubmitDecode, Status(scoped_refptr<H264Picture> pic)); - MOCK_METHOD3(ParseEncryptedSliceHeader, + MOCK_METHOD4(ParseEncryptedSliceHeader, Status(const std::vector<base::span<const uint8_t>>& data, const std::vector<SubsampleEntry>& subsamples, + uint64_t secure_handle, H264SliceHeader* slice_hdr_out)); MOCK_METHOD7(SubmitFrameMetadata, Status(const H264SPS* sps, @@ -308,9 +309,10 @@ { InSequence sequence; - EXPECT_CALL(*accelerator_, ParseEncryptedSliceHeader(_, _, _)) + EXPECT_CALL(*accelerator_, ParseEncryptedSliceHeader(_, _, _, _)) .WillOnce([this](const std::vector<base::span<const uint8_t>>& data, const std::vector<SubsampleEntry>& subsamples, + uint64_t /*secure_handle*/, H264SliceHeader* slice_hdr_out) { return ParseSliceHeader( data, subsamples, accelerator_->last_sps_nalu_data, @@ -623,22 +625,23 @@ EXPECT_EQ(H264PROFILE_BASELINE, decoder_->GetProfile()); EXPECT_LE(9u, decoder_->GetRequiredNumOfPictures()); - EXPECT_CALL(*accelerator_, ParseEncryptedSliceHeader(_, _, _)) + EXPECT_CALL(*accelerator_, ParseEncryptedSliceHeader(_, _, _, _)) .WillOnce(Return(H264Decoder::H264Accelerator::Status::kTryAgain)); ASSERT_EQ(AcceleratedVideoDecoder::kTryAgain, Decode(true)); // Try again, assuming key still not set. Only ParseEncryptedSliceHeader() // should be called again. - EXPECT_CALL(*accelerator_, ParseEncryptedSliceHeader(_, _, _)) + EXPECT_CALL(*accelerator_, ParseEncryptedSliceHeader(_, _, _, _)) .WillOnce(Return(H264Decoder::H264Accelerator::Status::kTryAgain)); ASSERT_EQ(AcceleratedVideoDecoder::kTryAgain, Decode(true)); // Assume key has been provided now, next call to Decode() should proceed. { InSequence sequence; - EXPECT_CALL(*accelerator_, ParseEncryptedSliceHeader(_, _, _)) + EXPECT_CALL(*accelerator_, ParseEncryptedSliceHeader(_, _, _, _)) .WillOnce([this](const std::vector<base::span<const uint8_t>>& data, const std::vector<SubsampleEntry>& subsamples, + uint64_t /*secure_handle*/, H264SliceHeader* slice_hdr_out) { return ParseSliceHeader( data, subsamples, accelerator_->last_sps_nalu_data,
diff --git a/media/gpu/v4l2/v4l2_decode_surface_handler.h b/media/gpu/v4l2/v4l2_decode_surface_handler.h index 790e1b7..f5a944f 100644 --- a/media/gpu/v4l2/v4l2_decode_surface_handler.h +++ b/media/gpu/v4l2/v4l2_decode_surface_handler.h
@@ -33,6 +33,10 @@ // Decode the surface |dec_surface|. virtual void DecodeSurface(scoped_refptr<V4L2DecodeSurface> dec_surface) = 0; + + // Resumes decoding if stalled due to a kTryAgain state, this only occurs + // with CENCV1 H264 and VP9 superframe encrypted content. + virtual void ResumeDecoding() = 0; }; } // namespace media
diff --git a/media/gpu/v4l2/v4l2_jpeg_encode_accelerator.cc b/media/gpu/v4l2/v4l2_jpeg_encode_accelerator.cc index 4f55da2..8ade5ab 100644 --- a/media/gpu/v4l2/v4l2_jpeg_encode_accelerator.cc +++ b/media/gpu/v4l2/v4l2_jpeg_encode_accelerator.cc
@@ -518,7 +518,7 @@ // additional planes. const size_t dmabuf_index = std::min<size_t>(i, num_fds - 1); const auto& layout_planes = frame->layout().planes(); - qbuf.m.planes[i].m.fd = frame->GetDmabufFd(dmabuf_index).get(); + qbuf.m.planes[i].m.fd = frame->GetDmabufFd(dmabuf_index); qbuf.m.planes[i].data_offset = layout_planes[i].offset; qbuf.m.planes[i].bytesused += qbuf.m.planes[i].data_offset; qbuf.m.planes[i].length = @@ -549,7 +549,7 @@ auto& job_record = running_job_queue_.back(); for (size_t i = 0; i < qbuf.length; i++) { - planes[i].m.fd = job_record->output_frame->GetDmabufFd(i).get(); + planes[i].m.fd = job_record->output_frame->GetDmabufFd(i); } IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QBUF, &qbuf); free_output_buffers_.pop_back();
diff --git a/media/gpu/v4l2/v4l2_queue.cc b/media/gpu/v4l2/v4l2_queue.cc index a1d6a9b..ad2defd 100644 --- a/media/gpu/v4l2/v4l2_queue.cc +++ b/media/gpu/v4l2/v4l2_queue.cc
@@ -1441,7 +1441,7 @@ if (auto* gmb = frame.GetGpuMemoryBuffer()) { id = gmb->GetId(); } else if (frame.HasDmaBufs()) { - id = gfx::GenericSharedMemoryId(frame.GetDmabufFd(0).get()); + id = gfx::GenericSharedMemoryId(frame.GetDmabufFd(0)); } else { DVLOGF(1) << "Unsupported frame provided"; return absl::nullopt;
diff --git a/media/gpu/v4l2/v4l2_video_decoder.cc b/media/gpu/v4l2/v4l2_video_decoder.cc index 0085049..28bb415 100644 --- a/media/gpu/v4l2/v4l2_video_decoder.cc +++ b/media/gpu/v4l2/v4l2_video_decoder.cc
@@ -477,7 +477,8 @@ << GetProfileName(profile_) << " and fourcc: " << FourccToString(input_format_fourcc_); backend_ = std::make_unique<V4L2StatelessVideoDecoderBackend>( - this, device_, profile_, color_space_, decoder_task_runner_); + this, device_, profile_, color_space_, decoder_task_runner_, + cdm_context_ref_ ? cdm_context_ref_->GetCdmContext() : nullptr); } if (!backend_->Initialize()) {
diff --git a/media/gpu/v4l2/v4l2_video_decoder_backend_stateless.cc b/media/gpu/v4l2/v4l2_video_decoder_backend_stateless.cc index 7e288557..5218850 100644 --- a/media/gpu/v4l2/v4l2_video_decoder_backend_stateless.cc +++ b/media/gpu/v4l2/v4l2_video_decoder_backend_stateless.cc
@@ -107,12 +107,14 @@ scoped_refptr<V4L2Device> device, VideoCodecProfile profile, const VideoColorSpace& color_space, - scoped_refptr<base::SequencedTaskRunner> task_runner) + scoped_refptr<base::SequencedTaskRunner> task_runner, + CdmContext* cdm_context) : V4L2VideoDecoderBackend(client, std::move(device)), profile_(profile), color_space_(color_space), bitstream_id_to_timestamp_(kTimestampCacheSize), - task_runner_(task_runner) { + task_runner_(task_runner), + cdm_context_(cdm_context) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); weak_this_ = weak_this_factory_.GetWeakPtr(); @@ -363,6 +365,11 @@ PumpOutputSurfaces(); } +void V4L2StatelessVideoDecoderBackend::ResumeDecoding() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DoDecodeWork(); +} + void V4L2StatelessVideoDecoderBackend::EnqueueDecodeTask( scoped_refptr<DecoderBuffer> buffer, VideoDecoder::DecodeCB decode_cb) { @@ -479,10 +486,11 @@ return false; case AcceleratedVideoDecoder::kTryAgain: - NOTREACHED() << "Should not reach here unless this class accepts " - "encrypted streams."; - DVLOGF(4) << "No key for decoding stream."; - return false; + // In this case we are waiting for an async operation relating to secure + // content. When that is complete, ResumeDecoding will be invoked and we + // will start decoding again; or a reset will occur and that will resume + // decoding. + return true; } } } @@ -719,7 +727,8 @@ if (profile_ >= H264PROFILE_MIN && profile_ <= H264PROFILE_MAX) { decoder_ = std::make_unique<H264Decoder>( - std::make_unique<V4L2VideoDecoderDelegateH264>(this, device_.get()), + std::make_unique<V4L2VideoDecoderDelegateH264>(this, device_.get(), + cdm_context_), profile_, color_space_); #if BUILDFLAG(ENABLE_HEVC_PARSER_AND_HW_DECODER) } else if (profile_ >= HEVCPROFILE_MIN && profile_ <= HEVCPROFILE_MAX) {
diff --git a/media/gpu/v4l2/v4l2_video_decoder_backend_stateless.h b/media/gpu/v4l2/v4l2_video_decoder_backend_stateless.h index 4209173..9d6822c1 100644 --- a/media/gpu/v4l2/v4l2_video_decoder_backend_stateless.h +++ b/media/gpu/v4l2/v4l2_video_decoder_backend_stateless.h
@@ -14,6 +14,7 @@ #include "base/task/sequenced_task_runner.h" #include "base/time/time.h" #include "base/types/id_type.h" +#include "media/base/cdm_context.h" #include "media/base/decoder_status.h" #include "media/base/video_decoder.h" #include "media/gpu/chromeos/dmabuf_video_frame_pool.h" @@ -38,7 +39,8 @@ scoped_refptr<V4L2Device> device, VideoCodecProfile profile, const VideoColorSpace& color_space, - scoped_refptr<base::SequencedTaskRunner> task_runner); + scoped_refptr<base::SequencedTaskRunner> task_runner, + CdmContext* cdm_context); V4L2StatelessVideoDecoderBackend(const V4L2StatelessVideoDecoderBackend&) = delete; @@ -72,6 +74,7 @@ int32_t bitstream_id, const gfx::Rect& visible_rect, const VideoColorSpace& color_space) override; + void ResumeDecoding() override; private: // Request for displaying the surface or calling the decode callback. @@ -196,6 +199,8 @@ base::IdType32<BitstreamID>::Generator bitstream_id_generator_ GUARDED_BY_CONTEXT(sequence_checker_); + raw_ptr<CdmContext> cdm_context_; + base::WeakPtr<V4L2StatelessVideoDecoderBackend> weak_this_; base::WeakPtrFactory<V4L2StatelessVideoDecoderBackend> weak_this_factory_{ this};
diff --git a/media/gpu/v4l2/v4l2_video_decoder_delegate_h264.cc b/media/gpu/v4l2/v4l2_video_decoder_delegate_h264.cc index fbd27e2..740f3bb 100644 --- a/media/gpu/v4l2/v4l2_video_decoder_delegate_h264.cc +++ b/media/gpu/v4l2/v4l2_video_decoder_delegate_h264.cc
@@ -11,11 +11,20 @@ #include <type_traits> #include "base/logging.h" +#include "base/numerics/safe_conversions.h" +#include "build/chromeos_buildflags.h" #include "media/gpu/macros.h" #include "media/gpu/v4l2/v4l2_decode_surface.h" #include "media/gpu/v4l2/v4l2_decode_surface_handler.h" #include "media/gpu/v4l2/v4l2_device.h" +#if BUILDFLAG(IS_CHROMEOS_ASH) +// gn check does not account for BUILDFLAG(), so including this header will +// make gn check fail for builds other than ash-chrome. See gn help nogncheck +// for more information. +#include "chromeos/components/cdm_factory_daemon/chromeos_cdm_context.h" // nogncheck +#endif // BUILDFLAG(IS_CHROMEOS_ASH) + namespace media { namespace { @@ -56,11 +65,46 @@ scoped_refptr<V4L2DecodeSurface> dec_surface_; }; +// Structure used when we parse encrypted slice headers in secure buffers. The +// same structure exists in the secure world code. This is all the fields we +// need to satisfy the V4L2 interface and the needs of the H264Decoder. +typedef struct CencV1SliceParameterBufferH264 { + uint8_t nal_ref_idc; + uint8_t idr_pic_flag; + uint8_t slice_type; + uint8_t field_pic_flag; + uint32_t frame_num; + uint32_t idr_pic_id; + uint32_t pic_order_cnt_lsb; + int32_t delta_pic_order_cnt_bottom; + int32_t delta_pic_order_cnt0; + int32_t delta_pic_order_cnt1; + union { + struct { + uint32_t no_output_of_prior_pics_flag : 1; + uint32_t long_term_reference_flag : 1; + uint32_t adaptive_ref_pic_marking_mode_flag : 1; + uint32_t dec_ref_pic_marking_count : 8; + uint32_t reserved : 21; + } bits; + uint32_t value; + } ref_pic_fields; + uint8_t memory_management_control_operation[32]; + int32_t difference_of_pic_nums_minus1[32]; + int32_t long_term_pic_num[32]; + int32_t max_long_term_frame_idx_plus1[32]; + int32_t long_term_frame_idx[32]; + uint32_t dec_ref_pic_marking_bit_size; + uint32_t pic_order_cnt_bit_size; +} CencV1SliceParameterBufferH264; + V4L2VideoDecoderDelegateH264::V4L2VideoDecoderDelegateH264( V4L2DecodeSurfaceHandler* surface_handler, - V4L2Device* device) + V4L2Device* device, + CdmContext* cdm_context) : surface_handler_(surface_handler), device_(device), + cdm_context_(cdm_context), priv_(std::make_unique<V4L2VideoDecoderDelegateH264Private>()) { DCHECK(surface_handler_); } @@ -87,6 +131,39 @@ return new V4L2H264Picture(dec_surface); } +void V4L2VideoDecoderDelegateH264::ProcessSPS( + const H264SPS* sps, + base::span<const uint8_t> sps_nalu_data) { + if (cdm_context_) { + cencv1_stream_data_.log2_max_frame_num_minus4 = + sps->log2_max_frame_num_minus4; + cencv1_stream_data_.log2_max_pic_order_cnt_lsb_minus4 = + sps->log2_max_pic_order_cnt_lsb_minus4; + cencv1_stream_data_.pic_order_cnt_type = sps->pic_order_cnt_type; + cencv1_stream_data_.chroma_array_type = sps->chroma_array_type; + cencv1_stream_data_.frame_mbs_only_flag = sps->frame_mbs_only_flag; + cencv1_stream_data_.delta_pic_order_always_zero_flag = + sps->delta_pic_order_always_zero_flag; + } +} + +void V4L2VideoDecoderDelegateH264::ProcessPPS( + const H264PPS* pps, + base::span<const uint8_t> pps_nalu_data) { + if (cdm_context_) { + cencv1_stream_data_.num_ref_idx_l0_default_active_minus1 = + pps->num_ref_idx_l0_default_active_minus1; + cencv1_stream_data_.num_ref_idx_l1_default_active_minus1 = + pps->num_ref_idx_l1_default_active_minus1; + cencv1_stream_data_.weighted_bipred_idc = pps->weighted_bipred_idc; + cencv1_stream_data_.bottom_field_pic_order_in_frame_present_flag = + pps->bottom_field_pic_order_in_frame_present_flag; + cencv1_stream_data_.redundant_pic_cnt_present_flag = + pps->redundant_pic_cnt_present_flag; + cencv1_stream_data_.weighted_pred_flag = pps->weighted_pred_flag; + } +} + std::vector<scoped_refptr<V4L2DecodeSurface>> V4L2VideoDecoderDelegateH264::H264DPBToV4L2DPB(const H264DPB& dpb) { std::vector<scoped_refptr<V4L2DecodeSurface>> ref_surfaces; @@ -319,6 +396,103 @@ return Status::kOk; } +H264Decoder::H264Accelerator::Status +V4L2VideoDecoderDelegateH264::ParseEncryptedSliceHeader( + const std::vector<base::span<const uint8_t>>& data, + const std::vector<SubsampleEntry>& /*subsamples*/, + uint64_t secure_handle, + H264SliceHeader* slice_header_out) { +#if BUILDFLAG(IS_CHROMEOS_ASH) + if (!cdm_context_ || !cdm_context_->GetChromeOsCdmContext()) { + LOG(ERROR) << "Missing ChromeOSCdmContext"; + return Status::kFail; + } + if (!secure_handle) { + LOG(ERROR) << "Invalid secure buffer"; + return Status::kFail; + } + if (encrypted_slice_header_parsing_failed_) { + encrypted_slice_header_parsing_failed_ = false; + last_parsed_encrypted_slice_header_.clear(); + return Status::kFail; + } + + std::vector<uint8_t> stream_data_vec( + reinterpret_cast<uint8_t*>(&cencv1_stream_data_), + reinterpret_cast<uint8_t*>(&cencv1_stream_data_) + + sizeof(cencv1_stream_data_)); + + // Send the request for the slice header if we don't have a pending result. + if (last_parsed_encrypted_slice_header_.empty()) { + cdm_context_->GetChromeOsCdmContext()->ParseEncryptedSliceHeader( + secure_handle, + base::checked_cast<uint32_t>(encrypted_slice_header_offset_), + stream_data_vec, + base::BindPostTaskToCurrentDefault(base::BindOnce( + &V4L2VideoDecoderDelegateH264::OnEncryptedSliceHeaderParsed, + weak_factory_.GetWeakPtr()))); + return Status::kTryAgain; + } + // We have the result, map it to the structure and copy the fields. + if (last_parsed_encrypted_slice_header_.size() != + sizeof(CencV1SliceParameterBufferH264)) { + return Status::kFail; + } + CencV1SliceParameterBufferH264 slice_param_buf; + memcpy(&slice_param_buf, last_parsed_encrypted_slice_header_.data(), + sizeof(slice_param_buf)); + last_parsed_encrypted_slice_header_.clear(); + + // Read the parsed slice header data back and populate the structure with it. + slice_header_out->idr_pic_flag = !!slice_param_buf.idr_pic_flag; + slice_header_out->nal_ref_idc = slice_param_buf.nal_ref_idc; + slice_header_out->field_pic_flag = slice_param_buf.field_pic_flag; + // The last span in |data| will be the slice header NALU. + slice_header_out->nalu_data = data.back().data(); + slice_header_out->nalu_size = data.back().size(); + slice_header_out->slice_type = slice_param_buf.slice_type; + slice_header_out->frame_num = slice_param_buf.frame_num; + slice_header_out->idr_pic_id = slice_param_buf.idr_pic_id; + slice_header_out->pic_order_cnt_lsb = slice_param_buf.pic_order_cnt_lsb; + slice_header_out->delta_pic_order_cnt_bottom = + slice_param_buf.delta_pic_order_cnt_bottom; + slice_header_out->delta_pic_order_cnt0 = slice_param_buf.delta_pic_order_cnt0; + slice_header_out->delta_pic_order_cnt1 = slice_param_buf.delta_pic_order_cnt1; + slice_header_out->no_output_of_prior_pics_flag = + slice_param_buf.ref_pic_fields.bits.no_output_of_prior_pics_flag; + slice_header_out->long_term_reference_flag = + slice_param_buf.ref_pic_fields.bits.long_term_reference_flag; + slice_header_out->adaptive_ref_pic_marking_mode_flag = + slice_param_buf.ref_pic_fields.bits.adaptive_ref_pic_marking_mode_flag; + const size_t num_dec_ref_pics = + slice_param_buf.ref_pic_fields.bits.dec_ref_pic_marking_count; + if (num_dec_ref_pics > H264SliceHeader::kRefListSize) { + DVLOG(1) << "Invalid number of dec_ref_pics: " << num_dec_ref_pics; + return Status::kFail; + } + for (size_t i = 0; i < num_dec_ref_pics; ++i) { + slice_header_out->ref_pic_marking[i].memory_mgmnt_control_operation = + slice_param_buf.memory_management_control_operation[i]; + slice_header_out->ref_pic_marking[i].difference_of_pic_nums_minus1 = + slice_param_buf.difference_of_pic_nums_minus1[i]; + slice_header_out->ref_pic_marking[i].long_term_pic_num = + slice_param_buf.long_term_pic_num[i]; + slice_header_out->ref_pic_marking[i].long_term_frame_idx = + slice_param_buf.long_term_frame_idx[i]; + slice_header_out->ref_pic_marking[i].max_long_term_frame_idx_plus1 = + slice_param_buf.max_long_term_frame_idx_plus1[i]; + } + slice_header_out->dec_ref_pic_marking_bit_size = + slice_param_buf.dec_ref_pic_marking_bit_size; + slice_header_out->pic_order_cnt_bit_size = + slice_param_buf.pic_order_cnt_bit_size; + slice_header_out->full_sample_encryption = true; + return Status::kOk; +#else + return Status::kFail; +#endif // BUILDFLAG(IS_CHROMEOS_ASH) +} + H264Decoder::H264Accelerator::Status V4L2VideoDecoderDelegateH264::SubmitSlice( const H264PPS* pps, const H264SliceHeader* slice_hdr, @@ -348,6 +522,8 @@ // TODO: don't do it here, but have it passed from the parser? const size_t data_copy_size = size + 3; if (dec_surface->secure_handle()) { + // If this is multi-slice CENCv1, then we need to increase this offset. + encrypted_slice_header_offset_ += size; // The secure world already post-processed the secure buffer so that all of // the slice NALUs w/ 3 byte start codes are the only contents. return surface_handler_->SubmitSlice(dec_surface.get(), nullptr, @@ -432,6 +608,9 @@ void V4L2VideoDecoderDelegateH264::Reset() { memset(&priv_->v4l2_decode_param, 0, sizeof(priv_->v4l2_decode_param)); + encrypted_slice_header_offset_ = 0; + last_parsed_encrypted_slice_header_.clear(); + encrypted_slice_header_parsing_failed_ = false; } scoped_refptr<V4L2DecodeSurface> @@ -441,4 +620,12 @@ return v4l2_pic->dec_surface(); } +void V4L2VideoDecoderDelegateH264::OnEncryptedSliceHeaderParsed( + bool status, + const std::vector<uint8_t>& parsed_headers) { + encrypted_slice_header_parsing_failed_ = !status; + last_parsed_encrypted_slice_header_ = parsed_headers; + surface_handler_->ResumeDecoding(); +} + } // namespace media
diff --git a/media/gpu/v4l2/v4l2_video_decoder_delegate_h264.h b/media/gpu/v4l2/v4l2_video_decoder_delegate_h264.h index b8212f5..0678871 100644 --- a/media/gpu/v4l2/v4l2_video_decoder_delegate_h264.h +++ b/media/gpu/v4l2/v4l2_video_decoder_delegate_h264.h
@@ -10,8 +10,11 @@ #include "base/memory/raw_ptr.h" #include "base/memory/scoped_refptr.h" +#include "base/memory/weak_ptr.h" +#include "media/base/cdm_context.h" #include "media/gpu/h264_decoder.h" #include "media/gpu/h264_dpb.h" +#include "media/video/h264_parser.h" namespace media { @@ -20,13 +23,34 @@ class V4L2DecodeSurfaceHandler; struct V4L2VideoDecoderDelegateH264Private; +// This is used by the secure world when parsing the stream to create +// CencV1SliceParameterBufferH264 (defined in the .cc file). This contains all +// the required SPS/PPS fields used in slice header parsing so that we don't +// need to re-parse the SPS/PPS in the secure world. +struct CencV1StreamDataForSliceHeader { + int32_t log2_max_frame_num_minus4; + int32_t log2_max_pic_order_cnt_lsb_minus4; + int32_t pic_order_cnt_type; + int32_t num_ref_idx_l0_default_active_minus1; + int32_t num_ref_idx_l1_default_active_minus1; + int32_t weighted_bipred_idc; + int32_t chroma_array_type; + uint8_t frame_mbs_only_flag; + uint8_t bottom_field_pic_order_in_frame_present_flag; + uint8_t delta_pic_order_always_zero_flag; + uint8_t redundant_pic_cnt_present_flag; + uint8_t weighted_pred_flag; + uint8_t padding[3]; +}; + class V4L2VideoDecoderDelegateH264 : public H264Decoder::H264Accelerator { public: using Status = H264Decoder::H264Accelerator::Status; explicit V4L2VideoDecoderDelegateH264( V4L2DecodeSurfaceHandler* surface_handler, - V4L2Device* device); + V4L2Device* device, + CdmContext* cdm_context); V4L2VideoDecoderDelegateH264(const V4L2VideoDecoderDelegateH264&) = delete; V4L2VideoDecoderDelegateH264& operator=(const V4L2VideoDecoderDelegateH264&) = @@ -38,6 +62,10 @@ scoped_refptr<H264Picture> CreateH264Picture() override; scoped_refptr<H264Picture> CreateH264PictureSecure( uint64_t secure_handle) override; + void ProcessSPS(const H264SPS* sps, + base::span<const uint8_t> sps_nalu_data) override; + void ProcessPPS(const H264PPS* pps, + base::span<const uint8_t> pps_nalu_data) override; Status SubmitFrameMetadata(const H264SPS* sps, const H264PPS* pps, const H264DPB& dpb, @@ -45,6 +73,11 @@ const H264Picture::Vector& ref_pic_listb0, const H264Picture::Vector& ref_pic_listb1, scoped_refptr<H264Picture> pic) override; + Status ParseEncryptedSliceHeader( + const std::vector<base::span<const uint8_t>>& data, + const std::vector<SubsampleEntry>& subsamples, + uint64_t secure_handle, + H264SliceHeader* slice_header_out) override; Status SubmitSlice(const H264PPS* pps, const H264SliceHeader* slice_hdr, const H264Picture::Vector& ref_pic_list0, @@ -62,13 +95,33 @@ const H264DPB& dpb); scoped_refptr<V4L2DecodeSurface> H264PictureToV4L2DecodeSurface( H264Picture* pic); + void OnEncryptedSliceHeaderParsed(bool status, + const std::vector<uint8_t>& parsed_headers); raw_ptr<V4L2DecodeSurfaceHandler> const surface_handler_; raw_ptr<V4L2Device> const device_; + raw_ptr<CdmContext> cdm_context_; + + // The last returned data for async encrypted slice header parsing, we hold + // onto this so when we get invoked a second time to parse it we know the + // result and can immediately return it. + std::vector<uint8_t> last_parsed_encrypted_slice_header_; + bool encrypted_slice_header_parsing_failed_ = false; + + // For multi-slice CENCv1 H264 content we will need to track the size of the + // headers already processed so we know where the subsequent headers are at in + // the secure buffer. + size_t encrypted_slice_header_offset_ = 0; + + // Tracking of the last SPS/PPS data so we can use the values for encrypted + // slice header parsing. + struct CencV1StreamDataForSliceHeader cencv1_stream_data_; // Contains the kernel-specific structures that we don't want to expose // outside of the compilation unit. const std::unique_ptr<V4L2VideoDecoderDelegateH264Private> priv_; + + base::WeakPtrFactory<V4L2VideoDecoderDelegateH264> weak_factory_{this}; }; } // namespace media
diff --git a/media/gpu/vaapi/h264_vaapi_video_decoder_delegate.cc b/media/gpu/vaapi/h264_vaapi_video_decoder_delegate.cc index 123e437..65c4774 100644 --- a/media/gpu/vaapi/h264_vaapi_video_decoder_delegate.cc +++ b/media/gpu/vaapi/h264_vaapi_video_decoder_delegate.cc
@@ -231,6 +231,7 @@ DecodeStatus H264VaapiVideoDecoderDelegate::ParseEncryptedSliceHeader( const std::vector<base::span<const uint8_t>>& data, const std::vector<SubsampleEntry>& subsamples, + uint64_t /*secure_handle*/, H264SliceHeader* slice_header_out) { DCHECK(slice_header_out); DCHECK(!subsamples.empty());
diff --git a/media/gpu/vaapi/h264_vaapi_video_decoder_delegate.h b/media/gpu/vaapi/h264_vaapi_video_decoder_delegate.h index 9b160e9..d259143 100644 --- a/media/gpu/vaapi/h264_vaapi_video_decoder_delegate.h +++ b/media/gpu/vaapi/h264_vaapi_video_decoder_delegate.h
@@ -55,6 +55,7 @@ Status ParseEncryptedSliceHeader( const std::vector<base::span<const uint8_t>>& data, const std::vector<SubsampleEntry>& subsamples, + uint64_t secure_handle, H264SliceHeader* slice_header_out) override; Status SubmitSlice(const H264PPS* pps, const H264SliceHeader* slice_hdr,
diff --git a/media/gpu/vaapi/vaapi_video_decoder.cc b/media/gpu/vaapi/vaapi_video_decoder.cc index 3b93a4e..a5fb440 100644 --- a/media/gpu/vaapi/vaapi_video_decoder.cc +++ b/media/gpu/vaapi/vaapi_video_decoder.cc
@@ -515,7 +515,7 @@ const gfx::GpuMemoryBufferId frame_id = frame->GetGpuMemoryBuffer() ? frame->GetGpuMemoryBuffer()->GetId() - : gfx::GpuMemoryBufferId(frame->GetDmabufFd(0).get()); + : gfx::GpuMemoryBufferId(frame->GetDmabufFd(0)); scoped_refptr<VASurface> va_surface; if (!base::Contains(allocated_va_surfaces_, frame_id)) {
diff --git a/media/mojo/mojom/stable/stable_video_decoder.mojom b/media/mojo/mojom/stable/stable_video_decoder.mojom index add47b2..9342e354 100644 --- a/media/mojo/mojom/stable/stable_video_decoder.mojom +++ b/media/mojo/mojom/stable/stable_video_decoder.mojom
@@ -69,8 +69,8 @@ }; // Maps to the media::CdmContext interface for remoting it to another process. -// Next MinVersion: 3 -// Next min method ID: 5 +// Next MinVersion: 4 +// Next min method ID: 6 [Stable, Uuid="33c7a00e-2970-41b3-8c7b-f1074a539740"] interface StableCdmContext { // Proxies to media::CdmContext::GetChromeOsCdmContext()->GetHwKeyData. @@ -96,6 +96,13 @@ // media::CdmContext::GetChromeOsCdmContext()->AllocateSecureBuffer. [MinVersion=2] AllocateSecureBuffer@4(uint32 size) => (handle<platform>? secure_buffer); + + // Proxies to + // media::CdmContext::GetChromeOsCdmContext()->ParseEncryptedSliceHeader. + [MinVersion=3] + ParseEncryptedSliceHeader@5(uint64 secure_handle, uint32 offset, + array<uint8> stream_data) + => (bool success, array<uint8> slice_header); }; // Based on |media.mojom.VideoDecoder|.
diff --git a/mojo/public/tools/mojom/check_stable_mojom_compatibility.py b/mojo/public/tools/mojom/check_stable_mojom_compatibility.py index 35cd1cf..e74115e 100755 --- a/mojo/public/tools/mojom/check_stable_mojom_compatibility.py +++ b/mojo/public/tools/mojom/check_stable_mojom_compatibility.py
@@ -18,6 +18,7 @@ import os.path import sys +from mojom.generate import compatibility_checker from mojom.generate import module from mojom.generate import translate from mojom.parse import parser @@ -155,7 +156,7 @@ 'renamed, please add a [RenamedFrom] attribute to the new type. This ' 'can be deleted by a subsequent change.' % qualified_name) - checker = module.BackwardCompatibilityChecker() + checker = compatibility_checker.BackwardCompatibilityChecker() try: if not checker.IsBackwardCompatible(new_types[new_name], kind): raise Exception(
diff --git a/mojo/public/tools/mojom/mojom/BUILD.gn b/mojo/public/tools/mojom/mojom/BUILD.gn index a0edf0e..cb4f07c 100644 --- a/mojo/public/tools/mojom/mojom/BUILD.gn +++ b/mojo/public/tools/mojom/mojom/BUILD.gn
@@ -9,6 +9,7 @@ "fileutil.py", "generate/__init__.py", "generate/check.py", + "generate/compatibility_checker.py", "generate/generator.py", "generate/module.py", "generate/pack.py",
diff --git a/mojo/public/tools/mojom/mojom/generate/compatibility_checker.py b/mojo/public/tools/mojom/mojom/generate/compatibility_checker.py new file mode 100644 index 0000000..de31cab --- /dev/null +++ b/mojo/public/tools/mojom/mojom/generate/compatibility_checker.py
@@ -0,0 +1,336 @@ +# Copyright 2024 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +from mojom.generate import pack +from mojom.generate import module as mojom +from functools import singledispatchmethod + + +class BackwardCompatibilityChecker: + """Used for memoization while recursively checking two type definitions for + backward-compatibility.""" + + def __init__(self): + self._cache = {} + + def IsBackwardCompatible(self, new_kind: mojom.Kind, old_kind: mojom.Kind): + key = (new_kind, old_kind) + result = self._cache.get(key) + if result is None: + # Ensure that the type of two types are compatible before doing more work. + if isinstance(new_kind, type(old_kind)): + # Assume they're compatible at first to effectively ignore recursive + # checks between these types, e.g. if both kinds are a struct or union + # that references itself in a field. + self._cache[key] = True + result = self._CheckCompat(new_kind, old_kind) + self._cache[key] = result + else: + self._cache[key] = False + return result + + def _IsFieldBackwardCompatible(self, new_field: mojom.Kind, + old_field: mojom.Kind): + if (new_field.min_version or 0) != (old_field.min_version or 0): + return False + + return self.IsBackwardCompatible(new_field.kind, old_field.kind) + + # Each type should register their own compatibility check under this + # dispatcher. Assume that both new and old are the same type when the + # type specific compatibility checker is invoked. + @singledispatchmethod + def _CheckCompat(self, new, old): + raise NotImplementedError("unknown types: (%s, %s)" % + (repr(new), repr(old))) + + @_CheckCompat.register(mojom.Kind) + def _(self, new: mojom.Kind, old: mojom.Kind): + return new == old + + @_CheckCompat.register(mojom.Struct) + def _(self, new: mojom.Struct, old: mojom.Struct): + """The new struct is backward-compatible with older_struct if and only if + all of the following conditions hold: + - Any newly added field is tagged with a [MinVersion] attribute specifying + a version number greater than all previously used [MinVersion] + attributes within the struct. + - All fields present in the old struct remain present in the new struct, + with the same ordinal position, same optional or non-optional status, + same (or backward-compatible) type and where applicable, the same + [MinVersion] attribute value. + - All [MinVersion] attributes must be non-decreasing in ordinal order. + - All reference-typed (string, array, map, struct, or union) fields tagged + with a [MinVersion] greater than zero must be optional. + """ + + def buildOrdinalFieldMap(struct): + fields_by_ordinal = {} + for field in struct.fields: + if field.ordinal in fields_by_ordinal: + raise Exception('Multiple fields with ordinal %s in struct %s.' % + (field.ordinal, struct.mojom_name)) + fields_by_ordinal[field.ordinal] = field + return fields_by_ordinal + + new_fields = buildOrdinalFieldMap(new) + old_fields = buildOrdinalFieldMap(old) + if len(new_fields) < len(old_fields): + # At least one field was removed, which is not OK. + raise Exception('Removing struct fields from struct %s is not allowed.' % + (new.mojom_name)) + + # If there are N fields, existing ordinal values must exactly cover the + # range from 0 to N-1. + num_old_ordinals = len(old_fields) + max_old_min_version = 0 + for ordinal in range(num_old_ordinals): + new_field = new_fields[ordinal] + old_field = old_fields[ordinal] + if (old_field.min_version or 0) > max_old_min_version: + max_old_min_version = old_field.min_version + if not self._IsFieldBackwardCompatible(new_field, old_field): + # Type or min-version mismatch between old and new versions of the same + # ordinal field. + raise Exception( + 'Struct %s field with ordinal value %d have different type' + ' or min version, old name %s, new name %s.' % + (new.mojom_name, ordinal, old_field.mojom_name, + new_field.mojom_name)) + + # At this point we know all old fields are intact in the new struct + # definition. Now verify that all new fields have a high enough min version + # and are appropriately optional where required. + num_new_ordinals = len(new_fields) + last_min_version = max_old_min_version + for ordinal in range(num_old_ordinals, num_new_ordinals): + new_field = new_fields[ordinal] + min_version = new_field.min_version or 0 + if min_version <= max_old_min_version: + # A new field is being added to an existing version, which is not OK. + raise Exception( + 'Adding new fields to an existing MinVersion is not allowed' + ' for struct %s' % (new.mojom_name)) + if min_version < last_min_version: + # The [MinVersion] of a field cannot be lower than the [MinVersion] of + # a field with lower ordinal value. + raise Exception( + 'MinVersion of struct %s field %s cannot be lower than MinVersion' + ' of preceding fields' % (new.mojom_name, new_field)) + if mojom.IsReferenceKind( + new_field.kind) and not mojom.IsNullableKind(new_field.kind): + # New fields whose type can be nullable MUST be nullable. + raise Exception('New struct %s field %s must be nullable' % + (new.mojom_name, new_field)) + + return True + + @_CheckCompat.register(mojom.Union) + def _(self, new: mojom.Union, old: mojom.Union): + """This union is backward-compatible with old union if and only if + all of the following conditions hold: + - Any newly added field is tagged with a [MinVersion] attribute specifying + a version number greater than all previously used [MinVersion] + attributes within the union. + - All fields present in old union remain present in the new union, + with the same ordinal value, same optional or non-optional status, + same (or backward-compatible) type, and where applicable, the same + [MinVersion] attribute value. + """ + + def buildOrdinalFieldMap(union): + fields_by_ordinal = {} + for field in union.fields: + if field.ordinal in fields_by_ordinal: + raise Exception('Multiple fields with ordinal %s in union %s.' % + (field.ordinal, union.mojom_name)) + fields_by_ordinal[field.ordinal] = field + return fields_by_ordinal + + new_fields = buildOrdinalFieldMap(new) + old_fields = buildOrdinalFieldMap(old) + if len(new_fields) < len(old_fields): + # At least one field was removed, which is not OK. + return False + + max_old_min_version = 0 + for ordinal, old_field in old_fields.items(): + new_field = new_fields.get(ordinal) + if not new_field: + # A field was removed, which is not OK. + return False + if not self._IsFieldBackwardCompatible(new_field, old_field): + # An field changed its type or MinVersion, which is not OK. + return False + old_min_version = old_field.min_version or 0 + if old_min_version > max_old_min_version: + max_old_min_version = old_min_version + + new_ordinals = set(new_fields.keys()) - set(old_fields.keys()) + for ordinal in new_ordinals: + if (new_fields[ordinal].min_version or 0) <= max_old_min_version: + # New fields must use a MinVersion greater than any old fields. + return False + + return True + + @_CheckCompat.register(mojom.Array) + def _(self, new: mojom.Array, old: mojom.Array): + return new.length == old.length and self.IsBackwardCompatible( + new.kind, old.kind) + + @_CheckCompat.register(mojom.Map) + def _(self, new: mojom.Map, old: mojom.Map): + return self.IsBackwardCompatible( + new.key_kind, old.key_kind) and self.IsBackwardCompatible( + new.value_kind, old.value_kind) + + @_CheckCompat.register(mojom.PendingRemote) + def _(self, new: mojom.PendingRemote, old: mojom.PendingRemote): + return self.IsBackwardCompatible(new.kind, old.kind) + + @_CheckCompat.register(mojom.PendingReceiver) + def _(self, new: mojom.PendingReceiver, old: mojom.PendingReceiver): + return self.IsBackwardCompatible(new.kind, old.kind) + + @_CheckCompat.register(mojom.PendingAssociatedRemote) + def _(self, new: mojom.PendingAssociatedRemote, + old: mojom.PendingAssociatedRemote): + return self.IsBackwardCompatible(new.kind, old.kind) + + @_CheckCompat.register(mojom.PendingAssociatedReceiver) + def _(self, new: mojom.PendingAssociatedReceiver, + old: mojom.PendingAssociatedReceiver): + return self.IsBackwardCompatible(new.kind, old.kind) + + @_CheckCompat.register(mojom.InterfaceRequest) + def _(self, new: mojom.InterfaceRequest, old: mojom.InterfaceRequest): + return self.IsBackwardCompatible(new.kind, old.kind) + + @_CheckCompat.register(mojom.AssociatedInterfaceRequest) + def _(self, new: mojom.AssociatedInterfaceRequest, + old: mojom.AssociatedInterfaceRequest): + return self.IsBackwardCompatible(new.kind, old.kind) + + @_CheckCompat.register(mojom.Interface) + def _(self, new: mojom.Interface, old: mojom.Interface): + """This interface is backward-compatible with old interface if and + only if all of the following conditions hold: + - All defined methods in the old interface (when identified by ordinal) + have backward-compatible definitions in this interface. For each method + this means: + - The parameter list is backward-compatible, according to backward- + compatibility rules for structs, where each parameter is essentially + a struct field. + - If the old method definition does not specify a reply message, the + new method definition must not specify a reply message. + - If the old method definition specifies a reply message, the new + method definition must also specify a reply message with a parameter + list that is backward-compatible according to backward-compatibility + rules for structs. + - All newly introduced methods in this interface have a [MinVersion] + attribute specifying a version greater than any method in + the old interface. + """ + + def buildOrdinalMethodMap(interface): + methods_by_ordinal = {} + for method in interface.methods: + if method.ordinal in methods_by_ordinal: + raise Exception('Multiple methods with ordinal %s in interface %s.' % + (method.ordinal, interface.mojom_name)) + methods_by_ordinal[method.ordinal] = method + return methods_by_ordinal + + new_methods = buildOrdinalMethodMap(new) + old_methods = buildOrdinalMethodMap(old) + max_old_min_version = 0 + for ordinal, old_method in old_methods.items(): + new_method = new_methods.get(ordinal) + if not new_method: + # A method was removed, which is not OK. + return False + + if not self.IsBackwardCompatible(new_method.param_struct, + old_method.param_struct): + # The parameter list is not backward-compatible, which is not OK. + return False + + if old_method.response_param_struct is None: + if new_method.response_param_struct is not None: + # A reply was added to a message which didn't have one before, and + # this is not OK. + return False + else: + if new_method.response_param_struct is None: + # A reply was removed from a message, which is not OK. + return False + if not self.IsBackwardCompatible(new_method.response_param_struct, + old_method.response_param_struct): + # The new message's reply is not backward-compatible with the old + # message's reply, which is not OK. + return False + + if (old_method.min_version or 0) > max_old_min_version: + max_old_min_version = old_method.min_version + + # All the old methods are compatible with their new counterparts. Now verify + # that newly added methods are properly versioned. + new_ordinals = set(new_methods.keys()) - set(old_methods.keys()) + for ordinal in new_ordinals: + new_method = new_methods[ordinal] + if (new_method.min_version or 0) <= max_old_min_version: + # A method was added to an existing version, which is not OK. + return False + + return True + + @_CheckCompat.register(mojom.AssociatedInterface) + def _(self, new: mojom.AssociatedInterface, old: mojom.AssociatedInterface): + return self.IsBackwardCompatible(new.kind, old.kind) + + @_CheckCompat.register(mojom.Enum) + def _(self, new: mojom.Enum, old: mojom.Enum): + """This enum is backward-compatible with old enum if and only if one + of the following conditions holds: + - Neither enum is [Extensible] and both have the exact same set of valid + numeric values. Field names and aliases for the same numeric value do + not affect compatibility. + - old is [Extensible], and for every version defined by + the old enum, this enum has the exact same set of valid numeric + values. + """ + + def buildVersionFieldMap(enum): + fields_by_min_version = {} + for field in enum.fields: + if field.min_version not in fields_by_min_version: + fields_by_min_version[field.min_version] = set() + fields_by_min_version[field.min_version].add(field.numeric_value) + return fields_by_min_version + + old_fields = buildVersionFieldMap(old) + new_fields = buildVersionFieldMap(new) + + if new_fields.keys() != old_fields.keys() and not old.extensible: + raise Exception("Non-extensible enum cannot be modified") + + for min_version, valid_values in old_fields.items(): + if min_version not in new_fields: + raise Exception('New values added to an extensible enum ' + 'did not specify MinVersion: %s' % new_fields) + + if (new_fields[min_version] != valid_values): + if (len(new_fields[min_version]) < len(valid_values)): + raise Exception('Removing values for an existing MinVersion %s ' + 'is not allowed' % min_version) + + raise Exception( + 'New values don\'t match old values ' + 'for an existing MinVersion %s, ' + 'please specify MinVersion equal to "Next version" ' + 'in the enum description ' + 'for the following values:\n%s' % + (min_version, new_fields[min_version].difference(valid_values))) + return True
diff --git a/mojo/public/tools/mojom/mojom/generate/module.py b/mojo/public/tools/mojom/mojom/generate/module.py index ca5c8b4..70c8264 100644 --- a/mojo/public/tools/mojom/mojom/generate/module.py +++ b/mojo/public/tools/mojom/mojom/generate/module.py
@@ -18,27 +18,6 @@ # pylint: disable=raise-missing-from - -class BackwardCompatibilityChecker: - """Used for memoization while recursively checking two type definitions for - backward-compatibility.""" - - def __init__(self): - self._cache = {} - - def IsBackwardCompatible(self, new_kind, old_kind): - key = (new_kind, old_kind) - result = self._cache.get(key) - if result is None: - # Assume they're compatible at first to effectively ignore recursive - # checks between these types, e.g. if both kinds are a struct or union - # that references itself in a field. - self._cache[key] = True - result = new_kind.IsBackwardCompatible(old_kind, self) - self._cache[key] = result - return result - - # We use our own version of __repr__ when displaying the AST, as the # AST currently doesn't capture which nodes are reference (e.g. to # types) and which nodes are definitions. This allows us to e.g. print @@ -164,10 +143,6 @@ # during a subsequent run of the parser. return hash((self.spec, self.parent_kind, self.is_nullable)) - # pylint: disable=unused-argument - def IsBackwardCompatible(self, rhs, checker): - return self == rhs - class ValueKind(Kind): """ValueKind represents values that aren't reference kinds. @@ -559,13 +534,6 @@ if self.attributes else False -def _IsFieldBackwardCompatible(new_field, old_field, checker): - if (new_field.min_version or 0) != (old_field.min_version or 0): - return False - - return checker.IsBackwardCompatible(new_field.kind, old_field.kind) - - class Feature(ReferenceKind): """A runtime enabled feature defined from mojom. @@ -669,81 +637,6 @@ for constant in self.constants: constant.Stylize(stylizer) - def IsBackwardCompatible(self, rhs, checker): - """This struct is backward-compatible with rhs (older_struct) if and only if - all of the following conditions hold: - - Any newly added field is tagged with a [MinVersion] attribute specifying - a version number greater than all previously used [MinVersion] - attributes within the struct. - - All fields present in rhs remain present in the new struct, - with the same ordinal position, same optional or non-optional status, - same (or backward-compatible) type and where applicable, the same - [MinVersion] attribute value. - - All [MinVersion] attributes must be non-decreasing in ordinal order. - - All reference-typed (string, array, map, struct, or union) fields tagged - with a [MinVersion] greater than zero must be optional. - """ - - def buildOrdinalFieldMap(struct): - fields_by_ordinal = {} - for field in struct.fields: - if field.ordinal in fields_by_ordinal: - raise Exception('Multiple fields with ordinal %s in struct %s.' % - (field.ordinal, struct.mojom_name)) - fields_by_ordinal[field.ordinal] = field - return fields_by_ordinal - - new_fields = buildOrdinalFieldMap(self) - old_fields = buildOrdinalFieldMap(rhs) - if len(new_fields) < len(old_fields): - # At least one field was removed, which is not OK. - raise Exception('Removing struct fields from struct %s is not allowed.' % - (self.mojom_name)) - - # If there are N fields, existing ordinal values must exactly cover the - # range from 0 to N-1. - num_old_ordinals = len(old_fields) - max_old_min_version = 0 - for ordinal in range(num_old_ordinals): - new_field = new_fields[ordinal] - old_field = old_fields[ordinal] - if (old_field.min_version or 0) > max_old_min_version: - max_old_min_version = old_field.min_version - if not _IsFieldBackwardCompatible(new_field, old_field, checker): - # Type or min-version mismatch between old and new versions of the same - # ordinal field. - raise Exception( - 'Struct %s field with ordinal value %d have different type' - ' or min version, old name %s, new name %s.' % - (self.mojom_name, ordinal, old_field.mojom_name, - new_field.mojom_name)) - - # At this point we know all old fields are intact in the new struct - # definition. Now verify that all new fields have a high enough min version - # and are appropriately optional where required. - num_new_ordinals = len(new_fields) - last_min_version = max_old_min_version - for ordinal in range(num_old_ordinals, num_new_ordinals): - new_field = new_fields[ordinal] - min_version = new_field.min_version or 0 - if min_version <= max_old_min_version: - # A new field is being added to an existing version, which is not OK. - raise Exception( - 'Adding new fields to an existing MinVersion is not allowed' - ' for struct %s' % (self.mojom_name)) - if min_version < last_min_version: - # The [MinVersion] of a field cannot be lower than the [MinVersion] of - # a field with lower ordinal value. - raise Exception( - 'MinVersion of struct %s field %s cannot be lower than MinVersion' - ' of preceding fields' % (self.mojom_name, new_field)) - if IsReferenceKind(new_field.kind) and not IsNullableKind(new_field.kind): - # New fields whose type can be nullable MUST be nullable. - raise Exception('New struct %s field %s must be nullable' % - (self.mojom_name, new_field)) - - return True - @property def stable(self): return self.attributes.get(ATTRIBUTE_STABLE, False) \ @@ -820,54 +713,6 @@ for field in self.fields: field.Stylize(stylizer) - def IsBackwardCompatible(self, rhs, checker): - """This union is backward-compatible with rhs (older_union) if and only if - all of the following conditions hold: - - Any newly added field is tagged with a [MinVersion] attribute specifying - a version number greater than all previously used [MinVersion] - attributes within the union. - - All fields present in rhs remain present in the new union, - with the same ordinal value, same optional or non-optional status, - same (or backward-compatible) type, and where applicable, the same - [MinVersion] attribute value. - """ - - def buildOrdinalFieldMap(union): - fields_by_ordinal = {} - for field in union.fields: - if field.ordinal in fields_by_ordinal: - raise Exception('Multiple fields with ordinal %s in union %s.' % - (field.ordinal, union.mojom_name)) - fields_by_ordinal[field.ordinal] = field - return fields_by_ordinal - - new_fields = buildOrdinalFieldMap(self) - old_fields = buildOrdinalFieldMap(rhs) - if len(new_fields) < len(old_fields): - # At least one field was removed, which is not OK. - return False - - max_old_min_version = 0 - for ordinal, old_field in old_fields.items(): - new_field = new_fields.get(ordinal) - if not new_field: - # A field was removed, which is not OK. - return False - if not _IsFieldBackwardCompatible(new_field, old_field, checker): - # An field changed its type or MinVersion, which is not OK. - return False - old_min_version = old_field.min_version or 0 - if old_min_version > max_old_min_version: - max_old_min_version = old_min_version - - new_ordinals = set(new_fields.keys()) - set(old_fields.keys()) - for ordinal in new_ordinals: - if (new_fields[ordinal].min_version or 0) <= max_old_min_version: - # New fields must use a MinVersion greater than any old fields. - return False - - return True - @property def extensible(self): return self.attributes.get(ATTRIBUTE_EXTENSIBLE, False) \ @@ -944,10 +789,6 @@ def __hash__(self): return id(self) - def IsBackwardCompatible(self, rhs, checker): - return (isinstance(rhs, Array) and self.length == rhs.length - and checker.IsBackwardCompatible(self.kind, rhs.kind)) - class Map(ReferenceKind): """A map. @@ -991,11 +832,6 @@ def __hash__(self): return id(self) - def IsBackwardCompatible(self, rhs, checker): - return (isinstance(rhs, Map) - and checker.IsBackwardCompatible(self.key_kind, rhs.key_kind) - and checker.IsBackwardCompatible(self.value_kind, rhs.value_kind)) - class PendingRemote(ReferenceKind): Kind.AddSharedProperty('kind') @@ -1017,10 +853,6 @@ def __hash__(self): return id(self) - def IsBackwardCompatible(self, rhs, checker): - return (isinstance(rhs, PendingRemote) - and checker.IsBackwardCompatible(self.kind, rhs.kind)) - class PendingReceiver(ReferenceKind): Kind.AddSharedProperty('kind') @@ -1042,10 +874,6 @@ def __hash__(self): return id(self) - def IsBackwardCompatible(self, rhs, checker): - return isinstance(rhs, PendingReceiver) and checker.IsBackwardCompatible( - self.kind, rhs.kind) - class PendingAssociatedRemote(ReferenceKind): Kind.AddSharedProperty('kind') @@ -1067,11 +895,6 @@ def __hash__(self): return id(self) - def IsBackwardCompatible(self, rhs, checker): - return isinstance(rhs, - PendingAssociatedRemote) and checker.IsBackwardCompatible( - self.kind, rhs.kind) - class PendingAssociatedReceiver(ReferenceKind): Kind.AddSharedProperty('kind') @@ -1093,11 +916,6 @@ def __hash__(self): return id(self) - def IsBackwardCompatible(self, rhs, checker): - return isinstance( - rhs, PendingAssociatedReceiver) and checker.IsBackwardCompatible( - self.kind, rhs.kind) - class InterfaceRequest(ReferenceKind): Kind.AddSharedProperty('kind') @@ -1118,10 +936,6 @@ def __hash__(self): return id(self) - def IsBackwardCompatible(self, rhs, checker): - return isinstance(rhs, InterfaceRequest) and checker.IsBackwardCompatible( - self.kind, rhs.kind) - class AssociatedInterfaceRequest(ReferenceKind): Kind.AddSharedProperty('kind') @@ -1144,11 +958,6 @@ def __hash__(self): return id(self) - def IsBackwardCompatible(self, rhs, checker): - return isinstance( - rhs, AssociatedInterfaceRequest) and checker.IsBackwardCompatible( - self.kind, rhs.kind) - class Parameter: def __init__(self, @@ -1341,78 +1150,6 @@ for constant in self.constants: constant.Stylize(stylizer) - def IsBackwardCompatible(self, rhs, checker): - """This interface is backward-compatible with rhs (older_interface) if and - only if all of the following conditions hold: - - All defined methods in rhs (when identified by ordinal) have - backward-compatible definitions in this interface. For each method this - means: - - The parameter list is backward-compatible, according to backward- - compatibility rules for structs, where each parameter is essentially - a struct field. - - If the old method definition does not specify a reply message, the - new method definition must not specify a reply message. - - If the old method definition specifies a reply message, the new - method definition must also specify a reply message with a parameter - list that is backward-compatible according to backward-compatibility - rules for structs. - - All newly introduced methods in this interface have a [MinVersion] - attribute specifying a version greater than any method in - rhs. - """ - - def buildOrdinalMethodMap(interface): - methods_by_ordinal = {} - for method in interface.methods: - if method.ordinal in methods_by_ordinal: - raise Exception('Multiple methods with ordinal %s in interface %s.' % - (method.ordinal, interface.mojom_name)) - methods_by_ordinal[method.ordinal] = method - return methods_by_ordinal - - new_methods = buildOrdinalMethodMap(self) - old_methods = buildOrdinalMethodMap(rhs) - max_old_min_version = 0 - for ordinal, old_method in old_methods.items(): - new_method = new_methods.get(ordinal) - if not new_method: - # A method was removed, which is not OK. - return False - - if not checker.IsBackwardCompatible(new_method.param_struct, - old_method.param_struct): - # The parameter list is not backward-compatible, which is not OK. - return False - - if old_method.response_param_struct is None: - if new_method.response_param_struct is not None: - # A reply was added to a message which didn't have one before, and - # this is not OK. - return False - else: - if new_method.response_param_struct is None: - # A reply was removed from a message, which is not OK. - return False - if not checker.IsBackwardCompatible(new_method.response_param_struct, - old_method.response_param_struct): - # The new message's reply is not backward-compatible with the old - # message's reply, which is not OK. - return False - - if (old_method.min_version or 0) > max_old_min_version: - max_old_min_version = old_method.min_version - - # All the old methods are compatible with their new counterparts. Now verify - # that newly added methods are properly versioned. - new_ordinals = set(new_methods.keys()) - set(old_methods.keys()) - for ordinal in new_ordinals: - new_method = new_methods[ordinal] - if (new_method.min_version or 0) <= max_old_min_version: - # A method was added to an existing version, which is not OK. - return False - - return True - @property def service_sandbox(self): if not self.attributes: @@ -1510,11 +1247,6 @@ def __hash__(self): return id(self) - def IsBackwardCompatible(self, rhs, checker): - return isinstance(rhs, - AssociatedInterface) and checker.IsBackwardCompatible( - self.kind, rhs.kind) - class EnumField: def __init__(self, @@ -1601,50 +1333,6 @@ prefix = self.module.GetNamespacePrefix() return '%s%s' % (prefix, self.mojom_name) - # pylint: disable=unused-argument - def IsBackwardCompatible(self, rhs, checker): - """This enum is backward-compatible with rhs (older_enum) if and only if one - of the following conditions holds: - - Neither enum is [Extensible] and both have the exact same set of valid - numeric values. Field names and aliases for the same numeric value do - not affect compatibility. - - rhs is [Extensible], and for every version defined by - rhs, this enum has the exact same set of valid numeric values. - """ - - def buildVersionFieldMap(enum): - fields_by_min_version = {} - for field in enum.fields: - if field.min_version not in fields_by_min_version: - fields_by_min_version[field.min_version] = set() - fields_by_min_version[field.min_version].add(field.numeric_value) - return fields_by_min_version - - old_fields = buildVersionFieldMap(rhs) - new_fields = buildVersionFieldMap(self) - - if new_fields.keys() != old_fields.keys() and not rhs.extensible: - raise Exception("Non-extensible enum cannot be modified") - - for min_version, valid_values in old_fields.items(): - if min_version not in new_fields: - raise Exception('New values added to an extensible enum ' - 'do not specify MinVersion: %s' % new_fields) - - if (new_fields[min_version] != valid_values): - if (len(new_fields[min_version]) < len(valid_values)): - raise Exception('Removing values for an existing MinVersion %s ' - 'is not allowed' % min_version) - - raise Exception( - 'New values don\'t match old values' - 'for an existing MinVersion %s,' - ' please specify MinVersion equal to "Next version" ' - 'in the enum description' - ' for the following values:\n%s' % - (min_version, new_fields[min_version].difference(valid_values))) - return True - def _tuple(self): return (self.mojom_name, self.native_only, self.fields, self.attributes, self.min_value, self.max_value, self.default_field)
diff --git a/mojo/public/tools/mojom/version_compatibility_unittest.py b/mojo/public/tools/mojom/version_compatibility_unittest.py index 45e45ec5..1891f3b 100644 --- a/mojo/public/tools/mojom/version_compatibility_unittest.py +++ b/mojo/public/tools/mojom/version_compatibility_unittest.py
@@ -3,6 +3,7 @@ # found in the LICENSE file. from mojom.generate import module +from mojom.generate import compatibility_checker from mojom_parser_test_case import MojomParserTestCase @@ -21,7 +22,7 @@ self.assertEqual(set(old.keys()), set(new.keys()), 'Old and new test mojoms should use the same type names.') - checker = module.BackwardCompatibilityChecker() + checker = compatibility_checker.BackwardCompatibilityChecker() compatibility_map = {} for name in old: try:
diff --git a/services/audio/public/cpp/audio_device_description_mojom_traits.cc b/services/audio/public/cpp/audio_device_description_mojom_traits.cc index 8cbf60c..6013c0b 100644 --- a/services/audio/public/cpp/audio_device_description_mojom_traits.cc +++ b/services/audio/public/cpp/audio_device_description_mojom_traits.cc
@@ -10,6 +10,7 @@ media::AudioDeviceDescription>:: Read(audio::mojom::AudioDeviceDescriptionDataView data, media::AudioDeviceDescription* output) { + output->is_system_default = data.is_system_default(); return data.ReadDeviceName(&output->device_name) && data.ReadUniqueId(&output->unique_id) && data.ReadGroupId(&output->group_id);
diff --git a/services/audio/public/cpp/audio_device_description_mojom_traits.h b/services/audio/public/cpp/audio_device_description_mojom_traits.h index f7d5f70..ffe2e3ff 100644 --- a/services/audio/public/cpp/audio_device_description_mojom_traits.h +++ b/services/audio/public/cpp/audio_device_description_mojom_traits.h
@@ -24,6 +24,9 @@ static std::string group_id(const media::AudioDeviceDescription& input) { return input.group_id; } + static bool is_system_default(const media::AudioDeviceDescription& input) { + return input.is_system_default; + } static bool Read(audio::mojom::AudioDeviceDescriptionDataView data, media::AudioDeviceDescription* output);
diff --git a/services/audio/public/mojom/audio_device_description.mojom b/services/audio/public/mojom/audio_device_description.mojom index 606ed80..e98f9da 100644 --- a/services/audio/public/mojom/audio_device_description.mojom +++ b/services/audio/public/mojom/audio_device_description.mojom
@@ -10,4 +10,5 @@ string device_name; string unique_id; string group_id; + bool is_system_default; };
diff --git a/services/device/public/cpp/device_feature_map.cc b/services/device/public/cpp/device_feature_map.cc index 57fff06..1973165b 100644 --- a/services/device/public/cpp/device_feature_map.cc +++ b/services/device/public/cpp/device_feature_map.cc
@@ -22,7 +22,6 @@ &device::kWebAuthnAndroidCredManForHybrid, &device::kWebAuthnAndroidFidoJson, &device::kWebAuthnAndroidIncognitoConfirmation, - &device::kWebAuthnCableViaCredMan, &device::kWebAuthnDontPrelinkInProfiles, &device::kWebAuthnHybridLinkWithoutNotifications, &kGenericSensorExtraClasses,
diff --git a/services/device/public/java/src/org/chromium/device/DeviceFeatureList.java b/services/device/public/java/src/org/chromium/device/DeviceFeatureList.java index 5534ea07..7004e67b 100644 --- a/services/device/public/java/src/org/chromium/device/DeviceFeatureList.java +++ b/services/device/public/java/src/org/chromium/device/DeviceFeatureList.java
@@ -21,7 +21,6 @@ public static final String WEBAUTHN_ANDROID_FIDO_JSON = "WebAuthenticationAndroidFidoJson"; public static final String WEBAUTHN_ANDROID_INCOGNITO_CONFIRMATION = "WebAuthenticationAndroidIncognitoConfirmation"; - public static final String WEBAUTHN_CABLE_VIA_CREDMAN = "WebAuthenticationCableViaCredMan"; public static final String WEBAUTHN_DONT_PRELINK_IN_PROFILES = "WebAuthenticationDontPrelinkInProfiles"; public static final String WEBAUTHN_HYBRID_LINK_WITHOUT_NOTIFICATIONS =
diff --git a/services/network/public/cpp/BUILD.gn b/services/network/public/cpp/BUILD.gn index 7e6a493..5ecedb37 100644 --- a/services/network/public/cpp/BUILD.gn +++ b/services/network/public/cpp/BUILD.gn
@@ -278,6 +278,7 @@ "proxy_config_with_annotation_mojom_traits.h", ] deps = [ + ":network_param_mojom_support", "//mojo/public/mojom/base", "//net", "//services/network/public/mojom:mojom_proxy_config_shared",
diff --git a/services/network/public/cpp/proxy_config_mojom_traits.cc b/services/network/public/cpp/proxy_config_mojom_traits.cc index 9651b1b8..da846e8 100644 --- a/services/network/public/cpp/proxy_config_mojom_traits.cc +++ b/services/network/public/cpp/proxy_config_mojom_traits.cc
@@ -6,7 +6,9 @@ #include "base/debug/dump_without_crashing.h" #include "mojo/public/cpp/bindings/scoped_message_error_crash_key.h" +#include "net/base/proxy_chain.h" #include "net/base/proxy_string_util.h" +#include "services/network/public/cpp/network_param_mojom_traits.h" #include "url/gurl.h" namespace mojo { @@ -39,40 +41,15 @@ return true; } -std::vector<std::vector<std::string>> -StructTraits<network::mojom::ProxyListDataView, net::ProxyList>::proxies( - const net::ProxyList& r) { - std::vector<std::vector<std::string>> out; - for (const auto& proxy_chain : r.AllChains()) { - std::vector<std::string> proxy_servers; - for (const auto& proxy : proxy_chain.proxy_servers()) { - proxy_servers.push_back(net::ProxyServerToPacResultElement(proxy)); - } - out.push_back(std::move(proxy_servers)); - } - return out; -} - bool StructTraits<network::mojom::ProxyListDataView, net::ProxyList>::Read( network::mojom::ProxyListDataView data, net::ProxyList* out_proxy_list) { - std::vector<std::vector<std::string>> proxy_chains; + std::vector<net::ProxyChain> proxy_chains; if (!data.ReadProxies(&proxy_chains)) { return false; } for (const auto& proxy_chain : proxy_chains) { - std::vector<net::ProxyServer> proxy_servers; - for (const auto& proxy : proxy_chain) { - net::ProxyServer proxy_server = net::PacResultElementToProxyServer(proxy); - if (!proxy_server.is_valid()) { - mojo::debug::ScopedMessageErrorCrashKey crash_key_value( - "!proxy_server.is_valid()"); - base::debug::DumpWithoutCrashing(); - return false; - } - proxy_servers.push_back(std::move(proxy_server)); - } - out_proxy_list->AddProxyChain(net::ProxyChain(proxy_servers)); + out_proxy_list->AddProxyChain(proxy_chain); } return true; }
diff --git a/services/network/public/cpp/proxy_config_mojom_traits.h b/services/network/public/cpp/proxy_config_mojom_traits.h index 2ac00ae889..0f7d07e 100644 --- a/services/network/public/cpp/proxy_config_mojom_traits.h +++ b/services/network/public/cpp/proxy_config_mojom_traits.h
@@ -12,10 +12,12 @@ #include "mojo/public/cpp/base/big_string_mojom_traits.h" #include "mojo/public/cpp/bindings/enum_traits.h" #include "mojo/public/cpp/bindings/struct_traits.h" +#include "net/base/proxy_chain.h" #include "net/proxy_resolution/proxy_bypass_rules.h" #include "net/proxy_resolution/proxy_config.h" #include "net/proxy_resolution/proxy_config_with_annotation.h" #include "net/proxy_resolution/proxy_list.h" +#include "services/network/public/cpp/network_param_mojom_traits.h" #include "services/network/public/mojom/proxy_config.mojom-shared.h" // This file handles the serialization of net::ProxyConfig. @@ -36,7 +38,9 @@ struct COMPONENT_EXPORT(NETWORK_CPP_PROXY_CONFIG) StructTraits<network::mojom::ProxyListDataView, net::ProxyList> { public: - static std::vector<std::vector<std::string>> proxies(const net::ProxyList& r); + static const std::vector<net::ProxyChain>& proxies(const net::ProxyList& r) { + return r.AllChains(); + } static bool Read(network::mojom::ProxyListDataView data, net::ProxyList* out_proxy_list); };
diff --git a/services/network/public/mojom/BUILD.gn b/services/network/public/mojom/BUILD.gn index 17b8ef10..4cb2d01d 100644 --- a/services/network/public/mojom/BUILD.gn +++ b/services/network/public/mojom/BUILD.gn
@@ -321,7 +321,10 @@ "proxy_config_with_annotation.mojom", ] - public_deps = [ "//mojo/public/mojom/base" ] + public_deps = [ + ":mojom_network_param", + "//mojo/public/mojom/base", + ] shared_cpp_typemaps = [ { @@ -886,6 +889,10 @@ mojom = "network.mojom.NetLogSource" cpp = "::net::NetLogSource" }, + { + mojom = "network.mojom.ProxyChain" + cpp = "::net::ProxyChain" + }, ] traits_headers = [ "//services/network/public/cpp/network_param_mojom_traits.h" ] @@ -915,10 +922,6 @@ cpp = "::net::HttpVersion" }, { - mojom = "network.mojom.ProxyChain" - cpp = "::net::ProxyChain" - }, - { mojom = "network.mojom.ProxyServer" cpp = "::net::ProxyServer" },
diff --git a/services/network/public/mojom/proxy_config.mojom b/services/network/public/mojom/proxy_config.mojom index 9d8450e..bbaef05f 100644 --- a/services/network/public/mojom/proxy_config.mojom +++ b/services/network/public/mojom/proxy_config.mojom
@@ -5,17 +5,16 @@ module network.mojom; import "mojo/public/mojom/base/big_string.mojom"; +import "services/network/public/mojom/network_param.mojom"; + // This corresponds to the string representation of net::ProxyConfigBypassRules. struct ProxyBypassRules { array<string> rules; }; -// A list of proxy chains. Each chain is represented by a list of its proxy -// servers, each server in the format of a single semi-colon delimited entry -// in the output of a PAC script (e.g., "PROXY foo.com", "DIRECT"). +// A list of proxy chains. struct ProxyList { - // TODO(crbug.com/1491092): Update to be list of ProxyChain elements. - array<array<string>> proxies; + array<network.mojom.ProxyChain> proxies; }; // This corresponds to net::ProxyConfig::ProxyRules::Type.
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json index fae23bff..d6c1506 100644 --- a/testing/buildbot/chromium.android.json +++ b/testing/buildbot/chromium.android.json
@@ -10762,7 +10762,6 @@ "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_12l.chrome_public_test_apk.filter" ], "ci_only": true, - "experiment_percentage": 100, "merge": { "args": [ "--bucket",
diff --git a/testing/buildbot/filters/android.emulator_12l.chrome_public_test_apk.filter b/testing/buildbot/filters/android.emulator_12l.chrome_public_test_apk.filter index cec4865..46a3e961 100644 --- a/testing/buildbot/filters/android.emulator_12l.chrome_public_test_apk.filter +++ b/testing/buildbot/filters/android.emulator_12l.chrome_public_test_apk.filter
@@ -68,11 +68,13 @@ # crbug.com/1416433 -org.chromium.chrome.browser.externalnav.UrlOverridingTest.testExternalNavigationMessage +-org.chromium.chrome.browser.externalnav.UrlOverridingTest.testIntentToSelf -org.chromium.chrome.browser.externalnav.UrlOverridingTest.testIntentURIWithFileSchemeDoesNothing -org.chromium.chrome.browser.externalnav.UrlOverridingTest.testIntentURIWithMixedCaseFileSchemeDoesNothing -org.chromium.chrome.browser.externalnav.UrlOverridingTest.testNavigationFromXHRCallback -org.chromium.chrome.browser.externalnav.UrlOverridingTest.testNavigationFromXHRCallbackAndLostActivationLongTimeout -org.chromium.chrome.browser.externalnav.UrlOverridingTest.testNavigationWithFallbackURL +-org.chromium.chrome.browser.externalnav.UrlOverridingTest.testOpenWindowFromLinkUserGesture -org.chromium.chrome.browser.externalnav.UrlOverridingTest.testOpenWindowFromUserGesture -org.chromium.chrome.browser.externalnav.UrlOverridingTest.testWindowServerRedirect @@ -96,8 +98,9 @@ # crbug.com/1511801 -org.chromium.chrome.browser.app.bookmarks.BookmarkTest.testEmptyBookmarkFolder -org.chromium.chrome.browser.app.bookmarks.BookmarkTest.testEmptyReadingListFolder --org.chromium.chrome.browser.app.bookmarks.BookmarkTest.testOpenBookmarkManagerFolder -org.chromium.chrome.browser.app.bookmarks.BookmarkTest.testMoveDownMenuItem +-org.chromium.chrome.browser.app.bookmarks.BookmarkTest.testOpenBookmarkManagerFolder +-org.chromium.chrome.browser.app.bookmarks.BookmarkTest.testPartnerFolderDraggability # crbug.com/1511804 -org.chromium.chrome.browser.tasks.tab_management.SelectableTabListEditorTest.testToolbarMenuItem_GroupActionAndUndo @@ -179,6 +182,7 @@ -org.chromium.chrome.browser.tab.InterceptNavigationDelegateTest.testExternalAppIframeNavigation -org.chromium.chrome.browser.tab.InterceptNavigationDelegateTest.testExternalAppPrerenderingNavigation -org.chromium.chrome.browser.tab.InterceptNavigationDelegateTest.testNavigationFromImageOnLoad +-org.chromium.chrome.browser.tab.InterceptNavigationDelegateTest.testNavigationFromXHRCallbackAndLongTimeout -org.chromium.chrome.browser.tab.InterceptNavigationDelegateTest.testNavigationFromXHRCallbackAndShortTimeout # crbug.com/1513570 @@ -209,6 +213,7 @@ -org.chromium.chrome.browser.site_settings.FamilyLinkControlsTest.* # crbug.com/1515449 +-org.chromium.chrome.browser.TabsTest.testHideKeyboard -org.chromium.chrome.browser.TabsTest.testHideKeyboardWhenOpeningWindow # crbug.com/1517104
diff --git a/testing/buildbot/gn_isolate_map.pyl b/testing/buildbot/gn_isolate_map.pyl index 7b1dc28..f68be587 100644 --- a/testing/buildbot/gn_isolate_map.pyl +++ b/testing/buildbot/gn_isolate_map.pyl
@@ -1253,6 +1253,10 @@ "label": "//chrome/browser/media/router:openscreen_unittests", "type": "console_test_launcher", }, + "optimization_guide_gpu_unittests": { + "label": "//components/optimization_guide/internal:optimization_guide_gpu_unittests", + "type": "console_test_launcher", + }, "optimization_guide_unittests": { "label": "//components/optimization_guide/internal:optimization_guide_unittests", "type": "console_test_launcher",
diff --git a/testing/buildbot/internal.optimization_guide.json b/testing/buildbot/internal.optimization_guide.json index 2180e65..72ee25d 100644 --- a/testing/buildbot/internal.optimization_guide.json +++ b/testing/buildbot/internal.optimization_guide.json
@@ -303,6 +303,22 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "optimization_guide_gpu_unittests", + "swarming": { + "dimensions": { + "cpu": "arm64", + "os": "Mac-13", + "pool": "chrome.tests" + }, + "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "optimization_guide_gpu_unittests", + "test_id_prefix": "ninja://components/optimization_guide/internal:optimization_guide_gpu_unittests/" + }, + { + "merge": { + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, "name": "optimization_guide_unittests", "swarming": { "dimensions": { @@ -435,6 +451,22 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "optimization_guide_gpu_unittests", + "swarming": { + "dimensions": { + "cpu": "x86-64", + "os": "Mac-13", + "pool": "chrome.tests" + }, + "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "optimization_guide_gpu_unittests", + "test_id_prefix": "ninja://components/optimization_guide/internal:optimization_guide_gpu_unittests/" + }, + { + "merge": { + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, "name": "optimization_guide_unittests", "swarming": { "dimensions": {
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl index 89c9637c..79351e8 100644 --- a/testing/buildbot/test_suite_exceptions.pyl +++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -1484,10 +1484,8 @@ 'args': [ '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_12l.chrome_public_test_apk.filter', ], - # TODO(crbug.com/1439624): Remove experiment and ci_only - # once the test suite is stable. + # TODO(crbug.com/1439624): Remove ci_only once the test suite is stable. 'ci_only': True, - 'experiment_percentage': 100, }, 'android-12l-x64-fyi-dbg': { 'args': [
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl index 795ac734..4647cf1 100644 --- a/testing/buildbot/test_suites.pyl +++ b/testing/buildbot/test_suites.pyl
@@ -4759,7 +4759,25 @@ }, }, - 'optimization_guide_gtests': { + 'optimization_guide_desktop_gtests': { + 'chrome_ml_unittests': {}, + 'optimization_guide_browser_tests': { + 'test': 'browser_tests', + 'args': [ + '--gtest_filter=*OptimizationGuide*:*PageContentAnnotations*', + ], + }, + 'optimization_guide_components_unittests': { + 'test': 'components_unittests', + 'args': [ + '--gtest_filter=*OptimizationGuide*:*PageEntities*:*EntityAnnotator*', + ], + }, + 'optimization_guide_gpu_unittests': {}, + 'optimization_guide_unittests': {}, + }, + + 'optimization_guide_desktop_gtests_nogpu': { 'chrome_ml_unittests': {}, 'optimization_guide_browser_tests': { 'test': 'browser_tests',
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl index 7f4fdceea..59ac89a6 100644 --- a/testing/buildbot/waterfalls.pyl +++ b/testing/buildbot/waterfalls.pyl
@@ -6669,7 +6669,7 @@ 'linux-jammy', ], 'test_suites': { - 'gtest_tests': 'optimization_guide_gtests', + 'gtest_tests': 'optimization_guide_desktop_gtests_nogpu', }, 'os_type': 'cros', }, @@ -6683,7 +6683,8 @@ 'linux-jammy', ], 'test_suites': { - 'gtest_tests': 'optimization_guide_gtests', + # TODO(b/317243012): Add GPU suite when machines become available. + 'gtest_tests': 'optimization_guide_desktop_gtests_nogpu', 'isolated_scripts': 'model_validation_tests_full', }, 'os_type': 'linux', @@ -6698,7 +6699,7 @@ 'mac_default_arm64', ], 'test_suites': { - 'gtest_tests': 'optimization_guide_gtests', + 'gtest_tests': 'optimization_guide_desktop_gtests', 'isolated_scripts': 'model_validation_tests_full', }, 'os_type': 'mac', @@ -6713,7 +6714,7 @@ 'mac_default_x64', ], 'test_suites': { - 'gtest_tests': 'optimization_guide_gtests', + 'gtest_tests': 'optimization_guide_desktop_gtests', 'isolated_scripts': 'model_validation_tests_full', }, 'os_type': 'mac', @@ -6728,7 +6729,8 @@ 'win10', ], 'test_suites': { - 'gtest_tests': 'optimization_guide_gtests', + # TODO(b/317243012): Add GPU suite when machines become available. + 'gtest_tests': 'optimization_guide_desktop_gtests_nogpu', 'isolated_scripts': 'model_validation_tests_full', }, 'os_type': 'win', @@ -6744,7 +6746,8 @@ 'win10', ], 'test_suites': { - 'gtest_tests': 'optimization_guide_gtests', + # TODO(b/317243012): Add GPU suite when machines become available. + 'gtest_tests': 'optimization_guide_desktop_gtests_nogpu', 'isolated_scripts': 'model_validation_tests_full', },
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index 6d8f03a..753adac 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -1837,27 +1837,6 @@ ] } ], - "AutofillSuggestServerCardInsteadOfLocalCard": [ - { - "platforms": [ - "android", - "chromeos", - "chromeos_lacros", - "ios", - "linux", - "mac", - "windows" - ], - "experiments": [ - { - "name": "Enabled", - "enable_features": [ - "AutofillSuggestServerCardInsteadOfLocalCard" - ] - } - ] - } - ], "AutofillSurveys": [ { "platforms": [
diff --git a/third_party/angle b/third_party/angle index 28290ea..3461be1 160000 --- a/third_party/angle +++ b/third_party/angle
@@ -1 +1 @@ -Subproject commit 28290eae4b384c26d329f3efd8516447759d543b +Subproject commit 3461be1ae88258d65299f9fd1f86d6f99c5d89e4
diff --git a/third_party/blink/public/platform/web_font.h b/third_party/blink/public/platform/web_font.h index 7ff344d..50438577 100644 --- a/third_party/blink/public/platform/web_font.h +++ b/third_party/blink/public/platform/web_font.h
@@ -5,10 +5,9 @@ #ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_FONT_H_ #define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_FONT_H_ -#include <memory> - #include "third_party/blink/public/platform/web_common.h" #include "third_party/skia/include/core/SkColor.h" +#include "v8/include/cppgc/persistent.h" // To avoid conflicts with the DrawText macro from the Windows SDK... #undef DrawText @@ -53,7 +52,7 @@ explicit WebFont(const WebFontDescription&); class Impl; - std::unique_ptr<Impl> private_; + cppgc::Persistent<Impl> private_; }; } // namespace blink
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.cc b/third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.cc index 207b7c79..a5d8a1c 100644 --- a/third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.cc +++ b/third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.cc
@@ -85,21 +85,22 @@ DCHECK(descriptor.has_writable()); info.GetReturnValue().Set( V8ObjectBuilder(ScriptState::ForCurrentRealm(info)) - .Add("configurable", descriptor.configurable()) - .Add("enumerable", descriptor.enumerable()) - .Add("value", descriptor.value()) - .Add("writable", descriptor.writable()) + .AddBoolean("configurable", descriptor.configurable()) + .AddBoolean("enumerable", descriptor.enumerable()) + .AddV8Value("value", descriptor.value()) + .AddBoolean("writable", descriptor.writable()) .V8Value()); return; } // Accessor property DCHECK(descriptor.has_get() || descriptor.has_set()); - info.GetReturnValue().Set(V8ObjectBuilder(ScriptState::ForCurrentRealm(info)) - .Add("configurable", descriptor.configurable()) - .Add("enumerable", descriptor.enumerable()) - .Add("get", descriptor.get()) - .Add("set", descriptor.set()) - .V8Value()); + info.GetReturnValue().Set( + V8ObjectBuilder(ScriptState::ForCurrentRealm(info)) + .AddBoolean("configurable", descriptor.configurable()) + .AddBoolean("enumerable", descriptor.enumerable()) + .AddV8Value("get", descriptor.get()) + .AddV8Value("set", descriptor.set()) + .V8Value()); } const int32_t kMaxInt32 = 0x7fffffff;
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_object_builder.cc b/third_party/blink/renderer/bindings/core/v8/v8_object_builder.cc index 6e61b23c..c0d668f 100644 --- a/third_party/blink/renderer/bindings/core/v8/v8_object_builder.cc +++ b/third_party/blink/renderer/bindings/core/v8/v8_object_builder.cc
@@ -36,6 +36,13 @@ return *this; } +V8ObjectBuilder& V8ObjectBuilder::AddInteger(const StringView& name, + uint64_t value) { + AddInternal(name, ToV8Traits<IDLUnsignedLongLong>::ToV8(script_state_, value) + .ToLocalChecked()); + return *this; +} + V8ObjectBuilder& V8ObjectBuilder::AddString(const StringView& name, const StringView& value) { AddInternal(name, V8String(script_state_->GetIsolate(), value)); @@ -52,6 +59,12 @@ return *this; } +V8ObjectBuilder& V8ObjectBuilder::AddV8Value(const StringView& name, + v8::Local<v8::Value> value) { + AddInternal(name, value); + return *this; +} + ScriptValue V8ObjectBuilder::GetScriptValue() const { return ScriptValue(script_state_->GetIsolate(), object_); }
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_object_builder.h b/third_party/blink/renderer/bindings/core/v8/v8_object_builder.h index 11dc610..d7a3a1f 100644 --- a/third_party/blink/renderer/bindings/core/v8/v8_object_builder.h +++ b/third_party/blink/renderer/bindings/core/v8/v8_object_builder.h
@@ -5,7 +5,7 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_V8_OBJECT_BUILDER_H_ #define THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_V8_OBJECT_BUILDER_H_ -#include "third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h" +#include "third_party/blink/renderer/bindings/core/v8/to_v8_traits.h" #include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" @@ -29,15 +29,25 @@ V8ObjectBuilder& AddNull(const StringView& name); V8ObjectBuilder& AddBoolean(const StringView& name, bool value); V8ObjectBuilder& AddNumber(const StringView& name, double value); + V8ObjectBuilder& AddInteger(const StringView& name, uint64_t value); V8ObjectBuilder& AddString(const StringView& name, const StringView& value); V8ObjectBuilder& AddStringOrNull(const StringView& name, const StringView& value); + V8ObjectBuilder& AddV8Value(const StringView& name, v8::Local<v8::Value>); template <typename T> - V8ObjectBuilder& Add(const StringView& name, const T& value) { - AddInternal(name, v8::Local<v8::Value>( - ToV8(value, script_state_->GetContext()->Global(), - script_state_->GetIsolate()))); + requires std::derived_from<T, bindings::DictionaryBase> || + std::derived_from<T, ScriptWrappable> + V8ObjectBuilder& Add(const StringView& name, T* value) { + AddInternal(name, + ToV8Traits<T>::ToV8(script_state_, value).ToLocalChecked()); + return *this; + } + + template <typename T, typename Container> + V8ObjectBuilder& AddVector(const StringView& name, const Container& value) { + AddInternal(name, ToV8Traits<IDLSequence<T>>::ToV8(script_state_, value) + .ToLocalChecked()); return *this; }
diff --git a/third_party/blink/renderer/bindings/modules/v8/v8_binding_for_modules_test.cc b/third_party/blink/renderer/bindings/modules/v8/v8_binding_for_modules_test.cc index 03f85ce..c60a476 100644 --- a/third_party/blink/renderer/bindings/modules/v8/v8_binding_for_modules_test.cc +++ b/third_party/blink/renderer/bindings/modules/v8/v8_binding_for_modules_test.cc
@@ -229,7 +229,7 @@ // object = { foo: "zoo" } ScriptValue script_value = V8ObjectBuilder(scope.GetScriptState()) - .Add("foo", "zoo") + .AddString("foo", "zoo") .GetScriptValue(); CheckKeyPathStringValue(isolate, script_value, "foo", "zoo"); CheckKeyPathNullValue(isolate, script_value, "bar"); @@ -259,7 +259,7 @@ // object = { foo: { bar: "zee" } } ScriptValue script_value = V8ObjectBuilder(script_state) - .Add("foo", V8ObjectBuilder(script_state).Add("bar", "zee")) + .Add("foo", V8ObjectBuilder(script_state).AddString("bar", "zee")) .GetScriptValue(); CheckKeyPathStringValue(isolate, script_value, "foo.bar", "zee"); CheckKeyPathNullValue(isolate, script_value, "bar"); @@ -517,7 +517,7 @@ // object = { foo: { bar: "zee" }, bad: null } ScriptValue script_value = V8ObjectBuilder(script_state) - .Add("foo", V8ObjectBuilder(script_state).Add("bar", "zee")) + .Add("foo", V8ObjectBuilder(script_state).AddString("bar", "zee")) .AddNull("bad") .GetScriptValue(); @@ -584,7 +584,7 @@ // object = { foo: "zoo" } ScriptValue script_object = V8ObjectBuilder(scope.GetScriptState()) - .Add("foo", "zoo") + .AddString("foo", "zoo") .GetScriptValue(); std::unique_ptr<IDBKey> idb_string_key = IDBKey::CreateString("myNewKey"); CheckInjection(scope.GetScriptState(), idb_string_key.get(), script_object, @@ -604,7 +604,7 @@ // object = { foo: { bar: "zee" } } ScriptValue script_object = V8ObjectBuilder(script_state) - .Add("foo", V8ObjectBuilder(script_state).Add("bar", "zee")) + .Add("foo", V8ObjectBuilder(script_state).AddString("bar", "zee")) .GetScriptValue(); std::unique_ptr<IDBKey> idb_string_key = IDBKey::CreateString("myNewKey");
diff --git a/third_party/blink/renderer/core/animation/keyframe.cc b/third_party/blink/renderer/core/animation/keyframe.cc index d33749ac..dac3a02 100644 --- a/third_party/blink/renderer/core/animation/keyframe.cc +++ b/third_party/blink/renderer/core/animation/keyframe.cc
@@ -48,11 +48,11 @@ CSSPrimitiveValue::UnitType::kPercentage)); object_builder.Add("offset", timeline_range_offset); } else if (offset_) { - object_builder.Add("offset", offset_.value()); + object_builder.AddNumber("offset", offset_.value()); } else { object_builder.AddNull("offset"); } - object_builder.Add("easing", easing_->ToString()); + object_builder.AddString("easing", easing_->ToString()); object_builder.AddString("composite", EffectModel::CompositeOperationToString(composite_)); }
diff --git a/third_party/blink/renderer/core/animation/keyframe_effect.cc b/third_party/blink/renderer/core/animation/keyframe_effect.cc index ada57fc..fe36e03 100644 --- a/third_party/blink/renderer/core/animation/keyframe_effect.cc +++ b/third_party/blink/renderer/core/animation/keyframe_effect.cc
@@ -329,7 +329,7 @@ V8ObjectBuilder object_builder(script_state); keyframes[indices[i]]->AddKeyframePropertiesToV8Object(object_builder, target()); - object_builder.Add("computedOffset", computed_offsets[indices[i]]); + object_builder.AddNumber("computedOffset", computed_offsets[indices[i]]); computed_keyframes.push_back(object_builder.GetScriptValue()); }
diff --git a/third_party/blink/renderer/core/animation/string_keyframe.cc b/third_party/blink/renderer/core/animation/string_keyframe.cc index 1917871..a3f7b43 100644 --- a/third_party/blink/renderer/core/animation/string_keyframe.cc +++ b/third_party/blink/renderer/core/animation/string_keyframe.cc
@@ -219,7 +219,7 @@ AnimationInputHelpers::PropertyHandleToKeyframeAttribute( property_handle); - object_builder.Add(property_name, property_value->CssText()); + object_builder.AddString(property_name, property_value->CssText()); } // Legacy code path for SVG and Presentation attributes. @@ -241,7 +241,7 @@ DCHECK(property.IsSVGAttribute()); property_value = SvgPropertyValue(property.SvgAttribute()); } - object_builder.Add(property_name, property_value); + object_builder.AddString(property_name, property_value); } }
diff --git a/third_party/blink/renderer/core/animation/transition_keyframe.cc b/third_party/blink/renderer/core/animation/transition_keyframe.cc index 053bd9d7..8af2219 100644 --- a/third_party/blink/renderer/core/animation/transition_keyframe.cc +++ b/third_party/blink/renderer/core/animation/transition_keyframe.cc
@@ -59,7 +59,7 @@ String property_name = AnimationInputHelpers::PropertyHandleToKeyframeAttribute(property_); - object_builder.Add(property_name, property_value); + object_builder.AddString(property_name, property_value); } void TransitionKeyframe::Trace(Visitor* visitor) const {
diff --git a/third_party/blink/renderer/core/dom/build.gni b/third_party/blink/renderer/core/dom/build.gni index 67b062db4..29f26ed 100644 --- a/third_party/blink/renderer/core/dom/build.gni +++ b/third_party/blink/renderer/core/dom/build.gni
@@ -213,6 +213,7 @@ "node_with_index.h", "nth_index_cache.cc", "nth_index_cache.h", + "observable_internal_observer.h", "observable.cc", "observable.h", "parser_content_policy.h",
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc index 3db6edc..d97d341 100644 --- a/third_party/blink/renderer/core/dom/element.cc +++ b/third_party/blink/renderer/core/dom/element.cc
@@ -5061,6 +5061,53 @@ : nullptr; } +void Element::SetIsEligibleForElementCapture(bool value) { + CHECK(GetRestrictionTargetId()); + + const bool has_checked = + HasElementFlag(ElementFlags::kHasCheckedElementCaptureEligibility); + if (!has_checked) { + SetElementFlag(ElementFlags::kHasCheckedElementCaptureEligibility, true); + } + + ConsoleMessage* console_message = nullptr; + if (has_checked) { + const bool old_value = + !HasRareData() || + HasElementFlag(ElementFlags::kIsEligibleForElementCapture); + + if (value != old_value) { + console_message = MakeGarbageCollected<ConsoleMessage>( + mojom::blink::ConsoleMessageSource::kRendering, + mojom::blink::ConsoleMessageLevel::kInfo, + String::Format("restrictTo(): Element %s restriction eligibility. " + "For eligibility conditions, see " + "https://screen-share.github.io/element-capture/" + "#elements-eligible-for-restriction", + value ? "gained" : "lost")); + } + } else { + // We want to issue a different log message if the element is not eligible + // when first painted. + if (!value) { + console_message = MakeGarbageCollected<ConsoleMessage>( + mojom::blink::ConsoleMessageSource::kRendering, + mojom::blink::ConsoleMessageLevel::kWarning, + "restrictTo(): Element is not eligible for restriction. For " + "eligibility conditions, see " + "https://screen-share.github.io/element-capture/" + "#elements-eligible-for-restriction"); + } + } + + if (console_message) { + console_message->SetNodes(GetDocument().GetFrame(), {this->GetDomNodeId()}); + GetDocument().AddConsoleMessage(console_message); + } + + return SetElementFlag(ElementFlags::kIsEligibleForElementCapture, value); +} + void Element::SetCustomElementDefinition(CustomElementDefinition* definition) { DCHECK(definition); DCHECK(!GetCustomElementDefinition());
diff --git a/third_party/blink/renderer/core/dom/element.h b/third_party/blink/renderer/core/dom/element.h index 8592bb156..85e92ebe 100644 --- a/third_party/blink/renderer/core/dom/element.h +++ b/third_party/blink/renderer/core/dom/element.h
@@ -149,8 +149,10 @@ kContainsFullScreenElement = 1 << 3, kIsInTopLayer = 1 << 4, kContainsPersistentVideo = 1 << 5, + kIsEligibleForElementCapture = 1 << 6, + kHasCheckedElementCaptureEligibility = 1 << 7, - kNumberOfElementFlags = 6, // Size of bitfield used to store the flags. + kNumberOfElementFlags = 8, // Size of bitfield used to store the flags. }; enum class ShadowRootType; @@ -703,6 +705,11 @@ // Otherwise, returns a nullptr. const RestrictionTargetId* GetRestrictionTargetId() const; + // Set whether the element is eligible for element level capture. This is + // based on how the element is painted. Should only be called if the element + // has a RestrictionTargetId. + void SetIsEligibleForElementCapture(bool value); + ShadowRoot* attachShadow(const ShadowRootInit*, ExceptionState&); // Returns true if the attachment was successful.
diff --git a/third_party/blink/renderer/core/dom/node_rare_data.h b/third_party/blink/renderer/core/dom/node_rare_data.h index efe6d00..8f825776 100644 --- a/third_party/blink/renderer/core/dom/node_rare_data.h +++ b/third_party/blink/renderer/core/dom/node_rare_data.h
@@ -79,7 +79,7 @@ public: enum { kConnectedFrameCountBits = 10, // Must fit Page::maxNumberOfFrames. - kNumberOfElementFlags = 6, + kNumberOfElementFlags = 8, kNumberOfDynamicRestyleFlags = 15 }; @@ -247,7 +247,6 @@ uint16_t connected_frame_count_ : kConnectedFrameCountBits; uint16_t element_flags_ : kNumberOfElementFlags; - // 16 free bits here. private: NodeListsNodeData& CreateNodeLists();
diff --git a/third_party/blink/renderer/core/dom/observable.cc b/third_party/blink/renderer/core/dom/observable.cc index 3798b9f8..0b7ac29 100644 --- a/third_party/blink/renderer/core/dom/observable.cc +++ b/third_party/blink/renderer/core/dom/observable.cc
@@ -6,8 +6,11 @@ #include "base/types/pass_key.h" #include "third_party/blink/renderer/bindings/core/v8/v8_observer.h" +#include "third_party/blink/renderer/bindings/core/v8/v8_observer_callback.h" +#include "third_party/blink/renderer/bindings/core/v8/v8_observer_complete_callback.h" #include "third_party/blink/renderer/bindings/core/v8/v8_subscribe_callback.h" #include "third_party/blink/renderer/bindings/core/v8/v8_union_observer_observercallback.h" +#include "third_party/blink/renderer/core/dom/observable_internal_observer.h" #include "third_party/blink/renderer/core/dom/subscriber.h" #include "third_party/blink/renderer/core/execution_context/execution_context.h" #include "third_party/blink/renderer/platform/bindings/script_state.h" @@ -16,6 +19,55 @@ namespace blink { +namespace { + +class ScriptCallbackInternalObserver final : public ObservableInternalObserver { + public: + ScriptCallbackInternalObserver(V8ObserverCallback* next_callback, + V8ObserverCallback* error_callback, + V8ObserverCompleteCallback* complete_callback) + : next_callback_(next_callback), + error_callback_(error_callback), + complete_callback_(complete_callback) {} + + void Next(ScriptValue value) override { + if (next_callback_) { + next_callback_->InvokeAndReportException(nullptr, value); + } + } + void Error(ScriptState* script_state, ScriptValue error_value) override { + if (error_callback_) { + error_callback_->InvokeAndReportException(nullptr, error_value); + } else { + // This is the "default error algorithm" [1] that must be invoked in the + // case where `error_callback_` was not provided. + // + // [1]: https://wicg.github.io/observable/#default-error-algorithm + ObservableInternalObserver::Error(script_state, error_value); + } + } + void Complete() override { + if (complete_callback_) { + complete_callback_->InvokeAndReportException(nullptr); + } + } + + void Trace(Visitor* visitor) const override { + ObservableInternalObserver::Trace(visitor); + + visitor->Trace(next_callback_); + visitor->Trace(error_callback_); + visitor->Trace(complete_callback_); + } + + private: + Member<V8ObserverCallback> next_callback_; + Member<V8ObserverCallback> error_callback_; + Member<V8ObserverCompleteCallback> complete_callback_; +}; + +} // namespace + using PassKey = base::PassKey<Observable>; // static @@ -60,18 +112,24 @@ switch (observer_union->GetContentType()) { case V8UnionObserverOrObserverCallback::ContentType::kObserver: { Observer* observer = observer_union->GetAsObserver(); - subscriber = MakeGarbageCollected<Subscriber>( - PassKey(), script_state, - observer->hasNext() ? observer->next() : nullptr, - observer->hasComplete() ? observer->complete() : nullptr, - observer->hasError() ? observer->error() : nullptr, options); + ScriptCallbackInternalObserver* internal_observer = + MakeGarbageCollected<ScriptCallbackInternalObserver>( + observer->hasNext() ? observer->next() : nullptr, + observer->hasError() ? observer->error() : nullptr, + observer->hasComplete() ? observer->complete() : nullptr); + + subscriber = MakeGarbageCollected<Subscriber>(PassKey(), script_state, + internal_observer, options); break; } case V8UnionObserverOrObserverCallback::ContentType::kObserverCallback: - subscriber = MakeGarbageCollected<Subscriber>( - PassKey(), script_state, - /*next=*/observer_union->GetAsObserverCallback(), - /*complete=*/nullptr, /*error=*/nullptr, options); + ScriptCallbackInternalObserver* internal_observer = + MakeGarbageCollected<ScriptCallbackInternalObserver>( + /*next=*/observer_union->GetAsObserverCallback(), + /*error_callback=*/nullptr, /*complete_callback=*/nullptr); + + subscriber = MakeGarbageCollected<Subscriber>(PassKey(), script_state, + internal_observer, options); break; }
diff --git a/third_party/blink/renderer/core/dom/observable_internal_observer.h b/third_party/blink/renderer/core/dom/observable_internal_observer.h new file mode 100644 index 0000000..bf6c760 --- /dev/null +++ b/third_party/blink/renderer/core/dom/observable_internal_observer.h
@@ -0,0 +1,65 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_DOM_OBSERVABLE_INTERNAL_OBSERVER_H_ +#define THIRD_PARTY_BLINK_RENDERER_CORE_DOM_OBSERVABLE_INTERNAL_OBSERVER_H_ + +#include "third_party/blink/renderer/bindings/core/v8/script_value.h" +#include "third_party/blink/renderer/bindings/core/v8/v8_script_runner.h" +#include "third_party/blink/renderer/core/core_export.h" +#include "third_party/blink/renderer/platform/bindings/script_state.h" + +namespace blink { + +// Implementation of the DOM `Observable` API's "internal observer" concept. +// See: https://wicg.github.io/observable/#internal-observer. It is responsible +// for holding onto the concrete "next", "error", and "complete" algorithms that +// `Subscriber::{next(), error(), complete()} ultimately invoke. +// +// Most of the time these algorithms are whatever JavaScript passes in as +// callbacks in the Web IDL `Observer` dictionary. But for the various +// Promise-returning operators on the Observable interface [1], it is C++ that +// subscribes to an Observable, passing in its own native "next", "error", and +// "complete" algorithms in the `ObservableInternalObserver`. +// +// [1]: https://wicg.github.io/observable/#promise-returning-operators) +class CORE_EXPORT ObservableInternalObserver + : public GarbageCollected<ObservableInternalObserver> { + public: + // See https://wicg.github.io/observable/#internal-observer: + // + // An internal observer is a struct with the following items: + // next steps + // An algorithm that takes a single parameter of type `any`. Initially, + // these steps do nothing. + virtual void Next(ScriptValue) = 0; + + // error steps + // An algorithm that takes a single parameter of type `any`. Initially, the + // default error algorithm. + virtual void Error(ScriptState* script_state, ScriptValue error_value) { + // The given observer's `error()` handler can be null here if the error + // callback was simply not passed in (it is not required). + // + // Reporting the exception requires a valid `ScriptState`, which we don't + // have if we're in a detached context. See observable-constructor.window.js + // for tests. + if (!script_state->ContextIsValid()) { + return; + } + ScriptState::Scope scope(script_state); + V8ScriptRunner::ReportException(script_state->GetIsolate(), + error_value.V8Value()); + } + + // complete steps + // An algorithm with no parameters. Initially, these steps do nothing. + virtual void Complete() = 0; + + virtual void Trace(Visitor*) const {} +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_CORE_DOM_OBSERVABLE_INTERNAL_OBSERVER_H_
diff --git a/third_party/blink/renderer/core/dom/subscriber.cc b/third_party/blink/renderer/core/dom/subscriber.cc index 57c4891d9..11bc8d1 100644 --- a/third_party/blink/renderer/core/dom/subscriber.cc +++ b/third_party/blink/renderer/core/dom/subscriber.cc
@@ -14,6 +14,7 @@ #include "third_party/blink/renderer/bindings/core/v8/v8_void_function.h" #include "third_party/blink/renderer/core/dom/abort_controller.h" #include "third_party/blink/renderer/core/dom/abort_signal.h" +#include "third_party/blink/renderer/core/dom/observable_internal_observer.h" #include "third_party/blink/renderer/core/execution_context/execution_context.h" #include "third_party/blink/renderer/platform/instrumentation/use_counter.h" @@ -59,14 +60,10 @@ Subscriber::Subscriber(base::PassKey<Observable>, ScriptState* script_state, - V8ObserverCallback* next, - V8ObserverCompleteCallback* complete, - V8ObserverCallback* error, + ObservableInternalObserver* internal_observer, SubscribeOptions* options) : ExecutionContextClient(ExecutionContext::From(script_state)), - next_(next), - complete_(complete), - error_(error), + internal_observer_(internal_observer), complete_or_error_controller_(AbortController::Create(script_state)) { // Initialize `signal_` as a dependent signal on based on two input signals: // 1. [Possibly null]: The input `Observer#signal` member, if it exists. @@ -117,21 +114,21 @@ } void Subscriber::next(ScriptValue value) { - if (next_) { - next_->InvokeAndReportException(nullptr, value); + if (internal_observer_) { + internal_observer_->Next(value); } } void Subscriber::complete(ScriptState* script_state) { - V8ObserverCompleteCallback* complete = complete_; + ObservableInternalObserver* internal_observer = internal_observer_; CloseSubscription(); - if (complete) { + if (internal_observer) { // Once `signal_` is aborted, the first thing that runs is // `CloseSubscription()`, which makes it impossible to invoke user-provided // callbacks anymore. CHECK(!signal_->aborted()); - complete->InvokeAndReportException(nullptr); + internal_observer->Complete(); } // This will trigger the abort of `signal_`, which will run all of the @@ -140,24 +137,22 @@ } void Subscriber::error(ScriptState* script_state, ScriptValue error_value) { - V8ObserverCallback* error = error_; + ObservableInternalObserver* internal_observer = internal_observer_; CloseSubscription(); - if (error) { + if (internal_observer) { // Once `signal_` is aborted, the first thing that runs is // `CloseSubscription()`, which makes it impossible to invoke user-provided // callbacks anymore. CHECK(!signal_->aborted()); - error->InvokeAndReportException(nullptr, error_value); + internal_observer->Error(script_state, error_value); } else { - // The given observer's `error()` handler can be null here for one of two - // reasons: - // 1. The given observer simply doesn't have an `error()` handler (since - // it is optional) - // 2. The subscription is already closed (in which case - // `CloseSubscription()` manually clears `error_`) - // In both of these cases, if the observable is still producing errors, we - // must surface them to the global via "report the exception": + // The given `internal_observer` can be null here if the subscription is + // already closed (`CloseSubscription() manually clears + // `internal_observer_`). + // + // In this case, if the observable is still producing errors, we must + // surface them to the global via "report the exception": // https://html.spec.whatwg.org/C#report-the-exception. // // Reporting the exception requires a valid `ScriptState`, which we don't @@ -193,19 +188,15 @@ // Reset all handlers, making it impossible to signal any more values to the // subscriber. - next_ = nullptr; - complete_ = nullptr; - error_ = nullptr; + internal_observer_ = nullptr; } void Subscriber::Trace(Visitor* visitor) const { - visitor->Trace(next_); - visitor->Trace(complete_); - visitor->Trace(error_); visitor->Trace(complete_or_error_controller_); visitor->Trace(signal_); visitor->Trace(close_subscription_algorithm_handle_); visitor->Trace(teardown_callbacks_); + visitor->Trace(internal_observer_); ScriptWrappable::Trace(visitor); ExecutionContextClient::Trace(visitor);
diff --git a/third_party/blink/renderer/core/dom/subscriber.h b/third_party/blink/renderer/core/dom/subscriber.h index ae68b719..30f67f5 100644 --- a/third_party/blink/renderer/core/dom/subscriber.h +++ b/third_party/blink/renderer/core/dom/subscriber.h
@@ -17,11 +17,10 @@ namespace blink { class AbortController; +class ObservableInternalObserver; class Observable; class ScriptState; class SubscribeOptions; -class V8ObserverCallback; -class V8ObserverCompleteCallback; class V8VoidFunction; class CORE_EXPORT Subscriber final : public ScriptWrappable, @@ -31,9 +30,7 @@ public: Subscriber(base::PassKey<Observable>, ScriptState*, - V8ObserverCallback* next, - V8ObserverCompleteCallback* complete, - V8ObserverCallback* error, + ObservableInternalObserver*, SubscribeOptions*); // API methods. @@ -55,12 +52,20 @@ // constructor implementation. void CloseSubscription(); - // Any of these may be null, since they are derived from non-required - // dictionary members passed into `Observable::subscribe()` used to construct - // `this`. - Member<V8ObserverCallback> next_; - Member<V8ObserverCompleteCallback> complete_; - Member<V8ObserverCallback> error_; + // The `ObservableInternalObserver` class encapsulates algorithms to call when + // `this` produces values or actions that need to be pushed to the subscriber + // handlers. + // + // https://wicg.github.io/observable/#subscriber-next-algorithm: + // "Each Subscriber has a next algorithm, which is a next steps-or-null." + // + // https://wicg.github.io/observable/#subscriber-error-algorithm: + // "Each Subscriber has a error algorithm, which is an error steps-or-null." + + // https://wicg.github.io/observable/#subscriber-complete-algorithm: + // "Each Subscriber has a complete algorithm, which is a complete + // steps-or-null." + Member<ObservableInternalObserver> internal_observer_; // This starts out true, and becomes false only once `Subscriber::{complete(), // error()}` are called (just before the corresponding `Observer` callbacks
diff --git a/third_party/blink/renderer/core/frame/navigator_ua_data.cc b/third_party/blink/renderer/core/frame/navigator_ua_data.cc index c3b785db..b4b7817f 100644 --- a/third_party/blink/renderer/core/frame/navigator_ua_data.cc +++ b/third_party/blink/renderer/core/frame/navigator_ua_data.cc
@@ -267,9 +267,9 @@ ScriptValue NavigatorUAData::toJSON(ScriptState* script_state) const { V8ObjectBuilder builder(script_state); - builder.Add("brands", brands()); - builder.Add("mobile", mobile()); - builder.Add("platform", platform()); + builder.AddVector<NavigatorUABrandVersion>("brands", brands()); + builder.AddBoolean("mobile", mobile()); + builder.AddString("platform", platform()); // Record IdentifiabilityStudy metrics for `mobile()` and `platform()` // (the `brands()` part is already recorded inside that function).
diff --git a/third_party/blink/renderer/core/frame/visual_viewport.cc b/third_party/blink/renderer/core/frame/visual_viewport.cc index d0b9dbb1..6aa280a6 100644 --- a/third_party/blink/renderer/core/frame/visual_viewport.cc +++ b/third_party/blink/renderer/core/frame/visual_viewport.cc
@@ -169,7 +169,7 @@ GetChromeClient()->GetDeviceEmulationTransform(); if (!device_emulation_transform.IsIdentity()) { TransformPaintPropertyNode::State state{{device_emulation_transform}}; - state.flags.in_subtree_of_page_scale = false; + state.in_subtree_of_page_scale = false; if (!device_emulation_transform_node_) { device_emulation_transform_node_ = TransformPaintPropertyNode::Create( *transform_parent, std::move(state)); @@ -189,7 +189,7 @@ DCHECK(!transform_parent->Unalias().IsInSubtreeOfPageScale()); TransformPaintPropertyNode::State state; - state.flags.in_subtree_of_page_scale = false; + state.in_subtree_of_page_scale = false; // TODO(crbug.com/877794) Should create overscroll elasticity transform node // based on settings. if (!overscroll_elasticity_transform_node_) { @@ -214,7 +214,7 @@ TransformPaintPropertyNode::State state; if (scale_ != 1.f) state.transform_and_origin.matrix = gfx::Transform::MakeScale(scale_); - state.flags.in_subtree_of_page_scale = false; + state.in_subtree_of_page_scale = false; state.direct_compositing_reasons = CompositingReason::kViewport; state.compositor_element_id = page_scale_element_id_;
diff --git a/third_party/blink/renderer/core/html/canvas/canvas_font_cache.h b/third_party/blink/renderer/core/html/canvas/canvas_font_cache.h index cc7e9ad..4b5f587 100644 --- a/third_party/blink/renderer/core/html/canvas/canvas_font_cache.h +++ b/third_party/blink/renderer/core/html/canvas/canvas_font_cache.h
@@ -66,7 +66,7 @@ struct FontWrapper : public GarbageCollected<FontWrapper> { explicit FontWrapper(Font&& font) : font(font) {} - void Trace(Visitor* visitor) const {} + void Trace(Visitor* visitor) const { visitor->Trace(font); } Font font; };
diff --git a/third_party/blink/renderer/core/html/fenced_frame/fence.cc b/third_party/blink/renderer/core/html/fenced_frame/fence.cc index 336981d..8e83d61 100644 --- a/third_party/blink/renderer/core/html/fenced_frame/fence.cc +++ b/third_party/blink/renderer/core/html/fenced_frame/fence.cc
@@ -73,22 +73,19 @@ ExecutionContextClient::Trace(visitor); } -void Fence::reportEvent(ScriptState* script_state, - const V8UnionFenceEventOrString* event, +void Fence::reportEvent(const V8UnionFenceEventOrString* event, ExceptionState& exception_state) { switch (event->GetContentType()) { case V8UnionFenceEventOrString::ContentType::kString: - reportPrivateAggregationEvent(script_state, event->GetAsString(), - exception_state); + reportPrivateAggregationEvent(event->GetAsString(), exception_state); return; case V8UnionFenceEventOrString::ContentType::kFenceEvent: - reportEvent(script_state, event->GetAsFenceEvent(), exception_state); + reportEvent(event->GetAsFenceEvent(), exception_state); return; } } -void Fence::reportEvent(ScriptState* script_state, - const FenceEvent* event, +void Fence::reportEvent(const FenceEvent* event, ExceptionState& exception_state) { if (!DomWindow()) { exception_state.ThrowSecurityError( @@ -106,14 +103,13 @@ if (event->hasDestinationURL() && base::FeatureList::IsEnabled( blink::features::kAdAuctionReportingWithMacroApi)) { - reportEventToDestinationURL(script_state, event, exception_state); + reportEventToDestinationURL(event, exception_state); } else { - reportEventToDestinationEnum(script_state, event, exception_state); + reportEventToDestinationEnum(event, exception_state); } } -void Fence::reportEventToDestinationEnum(ScriptState* script_state, - const FenceEvent* event, +void Fence::reportEventToDestinationEnum(const FenceEvent* event, ExceptionState& exception_state) { if (!event->hasDestination()) { exception_state.ThrowTypeError("Missing required 'destination' property."); @@ -155,8 +151,7 @@ event->getEventDataOr(String{""}), event->eventType(), destinations); } -void Fence::reportEventToDestinationURL(ScriptState* script_state, - const FenceEvent* event, +void Fence::reportEventToDestinationURL(const FenceEvent* event, ExceptionState& exception_state) { if (event->hasEventType()) { exception_state.ThrowTypeError( @@ -214,7 +209,6 @@ } void Fence::setReportEventDataForAutomaticBeacons( - ScriptState* script_state, const FenceEvent* event, ExceptionState& exception_state) { if (!DomWindow()) { @@ -333,8 +327,7 @@ resolver->Resolve(); } -void Fence::reportPrivateAggregationEvent(ScriptState* script_state, - const String& event, +void Fence::reportPrivateAggregationEvent(const String& event, ExceptionState& exception_state) { if (!base::FeatureList::IsEnabled(blink::features::kPrivateAggregationApi) || !blink::features::kPrivateAggregationApiEnabledInProtectedAudience
diff --git a/third_party/blink/renderer/core/html/fenced_frame/fence.h b/third_party/blink/renderer/core/html/fenced_frame/fence.h index d880125..a884d5c 100644 --- a/third_party/blink/renderer/core/html/fenced_frame/fence.h +++ b/third_party/blink/renderer/core/html/fenced_frame/fence.h
@@ -37,16 +37,14 @@ // If `event` is a string of the name of the event (i.e. // FenceEvent.eventType), calls reportPrivateAggregationEvent() to trigger // sending the contributions associated with the given event. - void reportEvent(ScriptState* script_state, - const V8UnionFenceEventOrString* event, + void reportEvent(const V8UnionFenceEventOrString* event, ExceptionState& exception_state); // Saves the event data that will be used when an automatic beacon of type // event.eventType is sent. Right now, it only supports saving data for the // "reserved.top_navigation_start", "reserved.top_navigation_commit", and the // deprecated "reserved.top_navigation" beacons. - void setReportEventDataForAutomaticBeacons(ScriptState* script_state, - const FenceEvent* event, + void setReportEventDataForAutomaticBeacons(const FenceEvent* event, ExceptionState& exception_state); // Returns a list of nested inner configurations for the fenced frame, if any @@ -65,26 +63,21 @@ private: // Dispatches to `reportEventToDestinationEnum` or // `reportEventToDestinationURL` depending on the format of `event`. - void reportEvent(ScriptState* script_state, - const FenceEvent* event, - ExceptionState& exception_state); + void reportEvent(const FenceEvent* event, ExceptionState& exception_state); // Sends a report with `eventData` to the reporting destinations specified by // `destination`. - void reportEventToDestinationEnum(ScriptState* script_state, - const FenceEvent* event, + void reportEventToDestinationEnum(const FenceEvent* event, ExceptionState& exception_state); // Sends a report to `destinationURL`, with substitution of buyer macros. - void reportEventToDestinationURL(ScriptState* script_state, - const FenceEvent* event, + void reportEventToDestinationURL(const FenceEvent* event, ExceptionState& exception_state); // Triggers the sending of any contributions associated with the given event. // This function simply passes off the work to the fenced frame reporter in // the browser to handle the actual sending of contributions. - void reportPrivateAggregationEvent(ScriptState* script_state, - const String& event, + void reportPrivateAggregationEvent(const String& event, ExceptionState& exception_state); void AddConsoleMessage(const String& message,
diff --git a/third_party/blink/renderer/core/html/fenced_frame/fence.idl b/third_party/blink/renderer/core/html/fenced_frame/fence.idl index 9870b013c..e62ea122 100644 --- a/third_party/blink/renderer/core/html/fenced_frame/fence.idl +++ b/third_party/blink/renderer/core/html/fenced_frame/fence.idl
@@ -8,8 +8,8 @@ [Exposed=Window, RuntimeEnabled=FencedFrames] interface Fence { - [CallWith=ScriptState, RaisesException] void reportEvent(ReportEventType event); - [CallWith=ScriptState, RaisesException] void setReportEventDataForAutomaticBeacons(FenceEvent event); + [RaisesException] void reportEvent(ReportEventType event); + [RaisesException] void setReportEventDataForAutomaticBeacons(FenceEvent event); [RaisesException] sequence<FencedFrameConfig> getNestedConfigs(); [CallWith=ScriptState, RaisesException, RuntimeEnabled=FencedFramesLocalUnpartitionedDataAccess] Promise<void> disableUntrustedNetwork(); };
diff --git a/third_party/blink/renderer/core/html/fenced_frame/fence_test.cc b/third_party/blink/renderer/core/html/fenced_frame/fence_test.cc index f05b3ba..f57a574 100644 --- a/third_party/blink/renderer/core/html/fenced_frame/fence_test.cc +++ b/third_party/blink/renderer/core/html/fenced_frame/fence_test.cc
@@ -34,8 +34,7 @@ V8TestingScope scope(base_url); Fence* fence = MakeGarbageCollected<Fence>(*(GetDocument().GetFrame()->DomWindow())); - fence->reportPrivateAggregationEvent(scope.GetScriptState(), "event", - scope.GetExceptionState()); + fence->reportPrivateAggregationEvent("event", scope.GetExceptionState()); // We expect this to make it past all the other checks, except for the // reporting metadata check. Since this is loaded in a vacuum and not the @@ -51,7 +50,7 @@ V8TestingScope scope(base_url); Fence* fence = MakeGarbageCollected<Fence>(*(GetDocument().GetFrame()->DomWindow())); - fence->reportPrivateAggregationEvent(scope.GetScriptState(), "reserved.event", + fence->reportPrivateAggregationEvent("reserved.event", scope.GetExceptionState()); // There should be a "Reserved events cannot be triggered manually." console @@ -70,8 +69,7 @@ event->setEventType("reserved.top_navigation"); V8UnionFenceEventOrString* event_union = MakeGarbageCollected<V8UnionFenceEventOrString>(event); - fence->reportEvent(scope.GetScriptState(), event_union, - scope.GetExceptionState()); + fence->reportEvent(event_union, scope.GetExceptionState()); // There should be a "Reserved events cannot be triggered manually." console // warning.
diff --git a/third_party/blink/renderer/core/html/parser/html_document_parser_fastpath.cc b/third_party/blink/renderer/core/html/parser/html_document_parser_fastpath.cc index 04b38ac4..7d8dfdf 100644 --- a/third_party/blink/renderer/core/html/parser/html_document_parser_fastpath.cc +++ b/third_party/blink/renderer/core/html/parser/html_document_parser_fastpath.cc
@@ -129,6 +129,44 @@ V(Strong) \ V(Ul) +using UCharLiteralBufferType = UCharLiteralBuffer<32>; + +template <class Char> +struct ScanTextResult { + // Converts `text` to a String. This handles converting UChar to LChar if + // possible. + String TextToString() const; + + // HTML strings of the form '\n<space>*' are widespread on the web. Caching + // them saves us allocations, which improves the runtime. + String TryCanonicalizeString() const { + DCHECK(!text.empty()); + if (is_newline_then_whitespace_string && + text.size() < WTF::NewlineThenWhitespaceStringsTable::kTableSize) { + DCHECK(WTF::NewlineThenWhitespaceStringsTable::IsNewlineThenWhitespaces( + String(text.data(), static_cast<unsigned>(text.size())))); + return WTF::NewlineThenWhitespaceStringsTable::GetStringForLength( + text.size()); + } + return TextToString(); + } + + base::span<const Char> text; + UCharLiteralBufferType* escaped_text = nullptr; + bool is_newline_then_whitespace_string = false; +}; + +template <> +String ScanTextResult<LChar>::TextToString() const { + return String(text.data(), static_cast<unsigned>(text.size())); +} + +template <> +String ScanTextResult<UChar>::TextToString() const { + return String(StringImpl::Create8BitIfPossible( + text.data(), static_cast<wtf_size_t>(text.size()))); +} + // This HTML parser is used as a fast-path for setting innerHTML. // It is faster than the general parser by only supporting a subset of valid // HTML. This way, it can be spec-compliant without following the algorithm @@ -175,7 +213,6 @@ typedef std::conditional<std::is_same_v<Char, UChar>, UCharLiteralBuffer<32>, LCharLiteralBuffer<32>>::type LiteralBufferType; - typedef UCharLiteralBuffer<32> UCharLiteralBufferType; static_assert(std::is_same_v<Char, UChar> || std::is_same_v<Char, LChar>); public: @@ -501,35 +538,13 @@ } } - struct ScanTextResult { - // HTML strings of the form '\n<space>*' are widespread on the web. Caching - // them saves us allocations, which improves the runtime. - String TryCanonicalizeString() const { - DCHECK(!text.empty()); - if (is_newline_then_whitespace_string && - text.size() < WTF::NewlineThenWhitespaceStringsTable::kTableSize) { -#if DCHECK_IS_ON() - DCHECK(WTF::NewlineThenWhitespaceStringsTable::IsNewlineThenWhitespaces( - String(text.data(), static_cast<unsigned>(text.size())))); -#endif // DCHECK_IS_ON() - return WTF::NewlineThenWhitespaceStringsTable::GetStringForLength( - text.size()); - } - return String(text.data(), static_cast<unsigned>(text.size())); - } - - Span text; - USpan escaped_text; - bool is_newline_then_whitespace_string = false; - }; - // We first try to scan text as an unmodified subsequence of the input. // However, if there are escape sequences, we have to copy the text to a // separate buffer and we might go outside of `Char` range if we are in an // `LChar` parser. Therefore, this function returns either a `Span` or a // `USpan`. Callers distinguish the two cases by checking if the `Span` is // empty, as only one of them can be non-empty. - ScanTextResult ScanText() { + ScanTextResult<Char> ScanText() { const Char* start = pos_; bool is_newline_then_whitespace_string = false; if (pos_ != end_ && *pos_ == '\n') { @@ -544,7 +559,7 @@ return {Span{}, ScanEscapedText()}; } else if (UNLIKELY(*pos_ == '\0')) { return Fail(HtmlFastPathResult::kFailedContainsNull, - ScanTextResult{Span{}, USpan{}}); + ScanTextResult<Char>{Span{}, nullptr}); } if (*pos_ != ' ') { is_newline_then_whitespace_string = false; @@ -552,19 +567,19 @@ ++pos_; } return {{start, static_cast<size_t>(pos_ - start)}, - USpan{}, + nullptr, is_newline_then_whitespace_string}; } // Slow-path of `ScanText()`, which supports escape sequences by copying to a // separate buffer. - USpan ScanEscapedText() { + UCharLiteralBufferType* ScanEscapedText() { uchar_buffer_.clear(); while (pos_ != end_ && *pos_ != '<') { if (*pos_ == '&') { ScanHTMLCharacterReference(&uchar_buffer_); if (failed_) { - return USpan{}; + return nullptr; } } else if (*pos_ == '\r') { // Normalize "\r\n" to "\n" according to @@ -575,13 +590,13 @@ uchar_buffer_.AddChar('\n'); ++pos_; } else if (UNLIKELY(*pos_ == '\0')) { - return Fail(HtmlFastPathResult::kFailedContainsNull, USpan{}); + return Fail(HtmlFastPathResult::kFailedContainsNull, nullptr); } else { uchar_buffer_.AddChar(*pos_); ++pos_; } } - return {uchar_buffer_.data(), uchar_buffer_.size()}; + return &uchar_buffer_; } // Scan a tagname and convert to lowercase if necessary. @@ -882,11 +897,11 @@ template <class ParentTag> void ParseChildren(ContainerNode* parent) { while (true) { - ScanTextResult scanned_text = ScanText(); + ScanTextResult<Char> scanned_text = ScanText(); if (failed_) { return; } - DCHECK(scanned_text.text.empty() || scanned_text.escaped_text.empty()); + DCHECK(scanned_text.text.empty() || !scanned_text.escaped_text); if (!scanned_text.text.empty()) { const auto text = scanned_text.text; if (text.size() >= Text::kDefaultLengthLimit) { @@ -899,20 +914,16 @@ parent->ParserAppendChild( Text::Create(document_, scanned_text.TryCanonicalizeString())); } - } else if (!scanned_text.escaped_text.empty()) { - if (scanned_text.escaped_text.size() >= Text::kDefaultLengthLimit) { + } else if (scanned_text.escaped_text) { + if (scanned_text.escaped_text->size() >= Text::kDefaultLengthLimit) { return Fail(HtmlFastPathResult::kFailedBigText); } if (bulk_insert_notify_) { - parent->ParserAppendChildInDocumentFragment(Text::Create( - document_, - String(scanned_text.escaped_text.data(), - static_cast<unsigned>(scanned_text.escaped_text.size())))); + parent->ParserAppendChildInDocumentFragment( + Text::Create(document_, scanned_text.escaped_text->AsString())); } else { parent->ParserAppendChild(Text::Create( - document_, - String(scanned_text.escaped_text.data(), - static_cast<unsigned>(scanned_text.escaped_text.size())))); + document_, String(scanned_text.escaped_text->AsString()))); } } if (pos_ == end_) {
diff --git a/third_party/blink/renderer/core/html/parser/html_document_parser_fastpath_test.cc b/third_party/blink/renderer/core/html/parser/html_document_parser_fastpath_test.cc index e02d5e1..6f90a58 100644 --- a/third_party/blink/renderer/core/html/parser/html_document_parser_fastpath_test.cc +++ b/third_party/blink/renderer/core/html/parser/html_document_parser_fastpath_test.cc
@@ -16,6 +16,7 @@ #include "third_party/blink/renderer/core/html/html_document.h" #include "third_party/blink/renderer/core/html/parser/html_construction_site.h" #include "third_party/blink/renderer/core/testing/null_execution_context.h" +#include "third_party/blink/renderer/core/xml/dom_parser.h" #include "third_party/blink/renderer/platform/wtf/text/string_builder.h" namespace blink { @@ -323,5 +324,33 @@ EXPECT_EQ(AtomicString(String(u"x\uFFFDy")), new_div->GetNameAttribute()); } +TEST(HTMLDocumentParserFastpathTest, MixedEncoding) { + ScopedNullExecutionContext execution_context; + auto* document = + HTMLDocument::CreateForTest(execution_context.GetExecutionContext()); + document->write("<body></body>"); + auto* div = MakeGarbageCollected<HTMLDivElement>(*document); + div->setInnerHTML(u"Hello"); + Text* text_node = To<Text>(div->firstChild()); + ASSERT_TRUE(text_node); + // Even though the supplied string was utf16, it only contained 8-bit chars, + // so should end up as 8-bit. + EXPECT_TRUE(text_node->data().Is8Bit()); +} + +TEST(HTMLDocumentParserFastpathTest, Escaped8BitText) { + ScopedNullExecutionContext execution_context; + auto* document = + HTMLDocument::CreateForTest(execution_context.GetExecutionContext()); + document->write("<body></body>"); + auto* div = MakeGarbageCollected<HTMLDivElement>(*document); + + div->setInnerHTML("&"); + Text* text_node = To<Text>(div->firstChild()); + ASSERT_TRUE(text_node); + // "&" should be represented as 8-bit. + EXPECT_TRUE(text_node->data().Is8Bit()); +} + } // namespace } // namespace blink
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_inline_text.h b/third_party/blink/renderer/core/layout/svg/layout_svg_inline_text.h index 76a8238..e65f133e 100644 --- a/third_party/blink/renderer/core/layout/svg/layout_svg_inline_text.h +++ b/third_party/blink/renderer/core/layout/svg/layout_svg_inline_text.h
@@ -30,6 +30,11 @@ public: LayoutSVGInlineText(Node*, String); + void Trace(Visitor* visitor) const override { + visitor->Trace(scaled_font_); + LayoutText::Trace(visitor); + } + float ScalingFactor() const { NOT_DESTROYED(); return scaling_factor_;
diff --git a/third_party/blink/renderer/core/paint/build.gni b/third_party/blink/renderer/core/paint/build.gni index 87829057..9fb5b4d3 100644 --- a/third_party/blink/renderer/core/paint/build.gni +++ b/third_party/blink/renderer/core/paint/build.gni
@@ -203,6 +203,8 @@ "timing/media_record_id.cc", "timing/media_record_id.h", "timing/paint_timing.cc", + "timing/paint_timing_callback_manager.h", + "timing/paint_timing_callback_manager.cc", "timing/paint_timing_detector.cc", "timing/paint_timing_detector.h", "timing/paint_timing.h",
diff --git a/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.cc b/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.cc index ff24ca8..8cc8209 100644 --- a/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.cc +++ b/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.cc
@@ -387,7 +387,9 @@ auto* element = DynamicTo<Element>(object.GetNode()); if (element && element->GetRestrictionTargetId()) { - if (IsEligibleForElementCapture(object)) { + const bool is_eligible = IsEligibleForElementCapture(object); + element->SetIsEligibleForElementCapture(is_eligible); + if (is_eligible) { reasons |= CompositingReason::kElementCapture; } }
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 af1ff698..851caa96 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
@@ -659,7 +659,7 @@ if (paint_offset_translation) { TransformPaintPropertyNode::State state{ {gfx::Transform::MakeTranslation(*paint_offset_translation)}}; - state.flags.flattens_inherited_transform = + state.flattens_inherited_transform = context_.should_flatten_inherited_transform; state.rendering_context_id = context_.rendering_context_id; state.direct_compositing_reasons = @@ -677,7 +677,7 @@ if (IsA<LayoutView>(object_)) { DCHECK(object_.GetFrame()); - state.flags.is_frame_paint_offset_translation = true; + state.is_frame_paint_offset_translation = true; state.visible_frame_element_id = object_.GetFrame()->GetVisibleToHitTesting() ? CompositorElementIdFromUniqueObjectId( @@ -722,7 +722,7 @@ box_model.UniqueId(), CompositorElementIdNamespace::kStickyTranslation); state.rendering_context_id = context_.rendering_context_id; - state.flags.flattens_inherited_transform = + state.flattens_inherited_transform = context_.should_flatten_inherited_transform; if (state.direct_compositing_reasons) { @@ -824,7 +824,7 @@ box.UniqueId(), CompositorElementIdNamespace::kAnchorPositionScrollTranslation); state.rendering_context_id = context_.rendering_context_id; - state.flags.flattens_inherited_transform = + state.flattens_inherited_transform = context_.should_flatten_inherited_transform; state.anchor_position_scrollers_data = @@ -974,10 +974,10 @@ // be included here, such as setting animation_is_axis_aligned. state.direct_compositing_reasons = direct_compositing_reasons & CompositingReasonsForTransformProperty(); - state.flags.flattens_inherited_transform = + state.flattens_inherited_transform = context_.should_flatten_inherited_transform; state.rendering_context_id = context_.rendering_context_id; - state.flags.is_for_svg_child = true; + state.is_for_svg_child = true; state.compositor_element_id = GetCompositorElementId( CompositorElementIdNamespace::kPrimaryTransform); @@ -1207,7 +1207,7 @@ // TODO(crbug.com/1185254): Make this work correctly for block // fragmentation. It's the size of each individual PhysicalBoxFragment // that's interesting, not the total LayoutBox size. - state.flags.animation_is_axis_aligned = + state.animation_is_axis_aligned = UpdateBoxSizeAndCheckActiveAnimationAxisAlignment( box, full_context_.direct_compositing_reasons); } @@ -1216,7 +1216,7 @@ full_context_.direct_compositing_reasons & compositing_reasons_for_property; - state.flags.flattens_inherited_transform = + state.flattens_inherited_transform = context_.should_flatten_inherited_transform; if (running_on_compositor_test) { state.compositor_element_id = @@ -1227,33 +1227,20 @@ if (object_.HasHiddenBackface()) { state.backface_visibility = TransformPaintPropertyNode::BackfaceVisibility::kHidden; - } else if (RuntimeEnabledFeatures:: - BackfaceVisibilityNewInheritanceEnabled()) { - if (!context_.can_inherit_backface_visibility || - style.Has3DTransformOperation()) { - // We want to set backface-visibility back to visible, if the - // parent doesn't allow this element to inherit backface visibility - // (e.g. if the parent preserves 3d), or this element has a - // syntactically-3D transform in *any* of the transform properties - // (not just 'transform'). This means that backface-visibility on - // an ancestor element no longer affects this element. - state.backface_visibility = - TransformPaintPropertyNode::BackfaceVisibility::kVisible; - } else { - // Otherwise we want to inherit backface-visibility. - DCHECK_EQ( - state.backface_visibility, - TransformPaintPropertyNode::BackfaceVisibility::kInherited); - } - } else if (state.direct_compositing_reasons != - CompositingReason::kNone) { - // The above condition fixes a CompositeAfterPaint regression - // (crbug.com/1260603) by letting non-directly-composited transforms - // inherit parent's backface visibility. - // TODO(crbug.com/1261905): Fix the the root cause, and revisit the - // above condition and make it at least more web developer friendly. + } else if (!context_.can_inherit_backface_visibility || + style.Has3DTransformOperation()) { + // We want to set backface-visibility back to visible, if the + // parent doesn't allow this element to inherit backface visibility + // (e.g. if the parent preserves 3d), or this element has a + // syntactically-3D transform in *any* of the transform properties + // (not just 'transform'). This means that backface-visibility on + // an ancestor element no longer affects this element. state.backface_visibility = TransformPaintPropertyNode::BackfaceVisibility::kVisible; + } else { + // Otherwise we want to inherit backface-visibility. + DCHECK_EQ(state.backface_visibility, + TransformPaintPropertyNode::BackfaceVisibility::kInherited); } } @@ -2427,7 +2414,7 @@ {matrix, gfx::Point3F(PerspectiveOrigin(To<LayoutBox>(object_)) + gfx::Vector2dF(context_.current.paint_offset))}}; - state.flags.flattens_inherited_transform = + state.flattens_inherited_transform = context_.should_flatten_inherited_transform; state.rendering_context_id = context_.rendering_context_id; OnUpdateTransform(properties_->UpdatePerspective( @@ -2461,7 +2448,7 @@ if (!content_to_parent_space.IsIdentity()) { TransformPaintPropertyNode::State state; state.transform_and_origin = {content_to_parent_space.ToTransform()}; - state.flags.flattens_inherited_transform = + state.flattens_inherited_transform = context_.should_flatten_inherited_transform; state.rendering_context_id = context_.rendering_context_id; OnUpdateTransform(properties_->UpdateReplacedContentTransform( @@ -2678,25 +2665,20 @@ box.GetScrollableArea()->PendingScrollAnchorAdjustment(); box.GetScrollableArea()->ClearPendingScrollAnchorAdjustment(); } - state.flags.flattens_inherited_transform = + state.flattens_inherited_transform = context_.should_flatten_inherited_transform; state.rendering_context_id = context_.rendering_context_id; state.direct_compositing_reasons = full_context_.direct_compositing_reasons & CompositingReason::kDirectReasonsForScrollTranslationProperty; state.scroll = properties_->Scroll(); - // If scroll and transform are both present, we should use the - // transform property tree node to determine visibility of the - // scrolling contents. - if (object_.HasTransform() && object_.StyleRef().BackfaceVisibility() == - EBackfaceVisibility::kHidden) { - if (RuntimeEnabledFeatures::BackfaceVisibilityNewInheritanceEnabled()) { - CHECK_EQ(state.backface_visibility, - TransformPaintPropertyNode::BackfaceVisibility::kInherited); - } else { - state.flags.delegates_to_parent_for_backface = true; - } - } + + // The scroll translation node always inherits backface visibility, which + // means if scroll and transform are both present, we will use the + // transform property tree node to determine visibility of the scrolling + // contents. + DCHECK_EQ(state.backface_visibility, + TransformPaintPropertyNode::BackfaceVisibility::kInherited); auto effective_change_type = properties_->UpdateScrollTranslation( *context_.current.transform, std::move(state));
diff --git a/third_party/blink/renderer/core/paint/timing/image_paint_timing_detector.h b/third_party/blink/renderer/core/paint/timing/image_paint_timing_detector.h index e7f31311..f8b6eed 100644 --- a/third_party/blink/renderer/core/paint/timing/image_paint_timing_detector.h +++ b/third_party/blink/renderer/core/paint/timing/image_paint_timing_detector.h
@@ -18,7 +18,7 @@ #include "third_party/blink/renderer/core/loader/resource/image_resource_content.h" #include "third_party/blink/renderer/core/paint/timing/lcp_objects.h" #include "third_party/blink/renderer/core/paint/timing/media_record_id.h" -#include "third_party/blink/renderer/core/paint/timing/paint_timing_detector.h" +#include "third_party/blink/renderer/core/paint/timing/paint_timing_visualizer.h" #include "third_party/blink/renderer/platform/allow_discouraged_type.h" #include "third_party/blink/renderer/platform/heap/collection_support/heap_deque.h" #include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h" @@ -35,6 +35,8 @@ class PropertyTreeStateOrAlias; class TracedValue; class Image; +class PaintTimingCallbackManager; +class StyleFetchedImage; // TODO(crbug/960502): we should limit the access of these properties. // TODO(yoav): Rename all mentions of "image" to "media"
diff --git a/third_party/blink/renderer/core/paint/timing/paint_timing_callback_manager.cc b/third_party/blink/renderer/core/paint/timing/paint_timing_callback_manager.cc new file mode 100644 index 0000000..63a16fa3 --- /dev/null +++ b/third_party/blink/renderer/core/paint/timing/paint_timing_callback_manager.cc
@@ -0,0 +1,56 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/renderer/core/paint/timing/paint_timing_callback_manager.h" + +#include "third_party/blink/renderer/core/frame/local_frame.h" +#include "third_party/blink/renderer/core/page/chrome_client.h" +#include "third_party/blink/renderer/core/page/page.h" +#include "third_party/blink/renderer/core/paint/timing/paint_timing_detector.h" +#include "third_party/blink/renderer/platform/wtf/cross_thread_copier_std.h" +#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h" + +namespace blink { + +void PaintTimingCallbackManagerImpl::ReportPaintTime( + std::unique_ptr<PaintTimingCallbackManager::CallbackQueue> frame_callbacks, + base::TimeTicks paint_time) { + // Do not report any paint timings for detached frames. + if (frame_view_->GetFrame().IsDetached()) { + return; + } + + while (!frame_callbacks->empty()) { + std::move(frame_callbacks->front()).Run(paint_time); + frame_callbacks->pop(); + } + frame_view_->GetPaintTimingDetector().UpdateLcpCandidate(); +} + +void PaintTimingCallbackManagerImpl:: + RegisterPaintTimeCallbackForCombinedCallbacks() { + DCHECK(!frame_callbacks_->empty()); + LocalFrame& frame = frame_view_->GetFrame(); + if (!frame.GetPage()) { + return; + } + + auto combined_callback = CrossThreadBindOnce( + &PaintTimingCallbackManagerImpl::ReportPaintTime, + WrapCrossThreadWeakPersistent(this), std::move(frame_callbacks_)); + frame_callbacks_ = + std::make_unique<PaintTimingCallbackManager::CallbackQueue>(); + + // |ReportPaintTime| on |layerTreeView| will queue a presentation-promise, the + // callback is called when the presentation for current render frame completes + // or fails to happen. + frame.GetPage()->GetChromeClient().NotifyPresentationTime( + frame, std::move(combined_callback)); +} + +void PaintTimingCallbackManagerImpl::Trace(Visitor* visitor) const { + visitor->Trace(frame_view_); + PaintTimingCallbackManager::Trace(visitor); +} +} // namespace blink
diff --git a/third_party/blink/renderer/core/paint/timing/paint_timing_callback_manager.h b/third_party/blink/renderer/core/paint/timing/paint_timing_callback_manager.h new file mode 100644 index 0000000..3a4b7f2 --- /dev/null +++ b/third_party/blink/renderer/core/paint/timing/paint_timing_callback_manager.h
@@ -0,0 +1,93 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_TIMING_PAINT_TIMING_CALLBACK_MANAGER_H_ +#define THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_TIMING_PAINT_TIMING_CALLBACK_MANAGER_H_ + +#include <queue> + +#include "base/functional/callback_forward.h" +#include "base/time/time.h" +#include "third_party/blink/renderer/core/core_export.h" +#include "third_party/blink/renderer/core/frame/local_frame_view.h" +#include "third_party/blink/renderer/platform/heap/garbage_collected.h" + +namespace blink { + +// `PaintTimingCallbackManager` is an interface between +// `ImagePaintTimingDetector`/`TextPaintTimingDetector` and `ChromeClient`. +// As `ChromeClient` is shared among the paint-timing-detectors, it +// makes it hard to test each detector without being affected other detectors. +// The interface, however, allows unit tests to mock `ChromeClient` for each +// detector. With the mock, `ImagePaintTimingDetector`'s callback does not need +// to store in the same queue as `TextPaintTimingDetector`'s. The separate +// queue makes it possible to pop an `ImagePaintTimingDetector`'s callback +// without having to popping the `TextPaintTimingDetector`'s. +class PaintTimingCallbackManager : public GarbageCollectedMixin { + public: + using LocalThreadCallback = base::OnceCallback<void(base::TimeTicks)>; + using CallbackQueue = std::queue<LocalThreadCallback>; + + virtual void RegisterCallback( + PaintTimingCallbackManager::LocalThreadCallback) = 0; +}; + +// This class is responsible for managing the swap-time callback for Largest +// Image Paint and Largest Text Paint. In frames where both text and image are +// painted, Largest Image Paint and Largest Text Paint need to assign the same +// paint-time for their records. In this case, `PaintTimeCallbackManager` +// requests a swap-time callback and share the swap-time with LIP and LTP. +// Otherwise LIP and LTP would have to request their own swap-time callbacks. +// An extra benefit of this design is that `LargestContentfulPaintCalculator` +// can thus hook to the end of the LIP and LTP's record assignments. +// +// `GarbageCollected` inheritance is required by the swap-time callback +// registration. +class CORE_EXPORT PaintTimingCallbackManagerImpl final + : public GarbageCollected<PaintTimingCallbackManagerImpl>, + public PaintTimingCallbackManager { + public: + PaintTimingCallbackManagerImpl(LocalFrameView* frame_view) + : frame_view_(frame_view), + frame_callbacks_( + std::make_unique<std::queue< + PaintTimingCallbackManager::LocalThreadCallback>>()) {} + ~PaintTimingCallbackManagerImpl() { frame_callbacks_.reset(); } + + // Instead of registering the callback right away, this impl of the interface + // combine the callback into `frame_callbacks_` before registering a separate + // swap-time callback for the combined callbacks. When the swap-time callback + // is invoked, the swap-time is then assigned to each callback of + // `frame_callbacks_`. + void RegisterCallback( + PaintTimingCallbackManager::LocalThreadCallback callback) override { + frame_callbacks_->push(std::move(callback)); + } + + void RegisterPaintTimeCallbackForCombinedCallbacks(); + + inline size_t CountCallbacks() { return frame_callbacks_->size(); } + + void ReportPaintTime( + std::unique_ptr<std::queue< + PaintTimingCallbackManager::LocalThreadCallback>> frame_callbacks, + base::TimeTicks paint_time); + + void Trace(Visitor* visitor) const override; + + private: + Member<LocalFrameView> frame_view_; + // `frame_callbacks_` stores the callbacks of `TextPaintTimingDetector` and + // `ImagePaintTimingDetector` in an (animated) frame. It is passed as an + // argument of a swap-time callback which once is invoked, invokes every + // callback in `frame_callbacks_`. This hierarchical callback design is to + // reduce the need of calling ChromeClient to register swap-time callbacks for + // both detectos. + // Although `frame_callbacks_` intends to store callbacks + // of a frame, it occasionally has to do that for more than one frame, when it + // fails to register a swap-time callback. + std::unique_ptr<PaintTimingCallbackManager::CallbackQueue> frame_callbacks_; +}; +} // namespace blink +#endif // THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_TIMING_PAINT_TIMING_CALLBACK_MANAGER_H_
diff --git a/third_party/blink/renderer/core/paint/timing/paint_timing_detector.cc b/third_party/blink/renderer/core/paint/timing/paint_timing_detector.cc index 3f11aa6..651e9a2 100644 --- a/third_party/blink/renderer/core/paint/timing/paint_timing_detector.cc +++ b/third_party/blink/renderer/core/paint/timing/paint_timing_detector.cc
@@ -587,44 +587,4 @@ visitor->Trace(potential_soft_navigation_text_record_); } -void PaintTimingCallbackManagerImpl:: - RegisterPaintTimeCallbackForCombinedCallbacks() { - DCHECK(!frame_callbacks_->empty()); - LocalFrame& frame = frame_view_->GetFrame(); - if (!frame.GetPage()) { - return; - } - - auto combined_callback = CrossThreadBindOnce( - &PaintTimingCallbackManagerImpl::ReportPaintTime, - WrapCrossThreadWeakPersistent(this), std::move(frame_callbacks_)); - frame_callbacks_ = - std::make_unique<PaintTimingCallbackManager::CallbackQueue>(); - - // |ReportPaintTime| on |layerTreeView| will queue a presentation-promise, the - // callback is called when the presentation for current render frame completes - // or fails to happen. - frame.GetPage()->GetChromeClient().NotifyPresentationTime( - frame, std::move(combined_callback)); -} - -void PaintTimingCallbackManagerImpl::ReportPaintTime( - std::unique_ptr<PaintTimingCallbackManager::CallbackQueue> frame_callbacks, - base::TimeTicks paint_time) { - // Do not report any paint timings for detached frames. - if (frame_view_->GetFrame().IsDetached()) { - return; - } - - while (!frame_callbacks->empty()) { - std::move(frame_callbacks->front()).Run(paint_time); - frame_callbacks->pop(); - } - frame_view_->GetPaintTimingDetector().UpdateLcpCandidate(); -} - -void PaintTimingCallbackManagerImpl::Trace(Visitor* visitor) const { - visitor->Trace(frame_view_); - PaintTimingCallbackManager::Trace(visitor); -} } // namespace blink
diff --git a/third_party/blink/renderer/core/paint/timing/paint_timing_detector.h b/third_party/blink/renderer/core/paint/timing/paint_timing_detector.h index 011c705..72cff55 100644 --- a/third_party/blink/renderer/core/paint/timing/paint_timing_detector.h +++ b/third_party/blink/renderer/core/paint/timing/paint_timing_detector.h
@@ -5,8 +5,6 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_TIMING_PAINT_TIMING_DETECTOR_H_ #define THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_TIMING_PAINT_TIMING_DETECTOR_H_ -#include <queue> - #include "base/auto_reset.h" #include "base/gtest_prod_util.h" #include "base/time/time.h" @@ -15,12 +13,12 @@ #include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/core/layout/layout_box_model_object.h" #include "third_party/blink/renderer/core/paint/timing/lcp_objects.h" +#include "third_party/blink/renderer/core/paint/timing/paint_timing_callback_manager.h" #include "third_party/blink/renderer/core/paint/timing/paint_timing_visualizer.h" #include "third_party/blink/renderer/core/scroll/scroll_types.h" #include "third_party/blink/renderer/platform/graphics/paint/ignore_paint_timing_scope.h" #include "third_party/blink/renderer/platform/heap/member.h" #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h" -#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h" #include "ui/gfx/geometry/rect.h" namespace blink { @@ -38,81 +36,6 @@ class TextPaintTimingDetector; class TextRecord; -// |PaintTimingCallbackManager| is an interface between -// |ImagePaintTimingDetector|/|TextPaintTimingDetector| and |ChromeClient|. -// As |ChromeClient| is shared among the paint-timing-detecters, it -// makes it hard to test each detector without being affected other detectors. -// The interface, however, allows unit tests to mock |ChromeClient| for each -// detector. With the mock, |ImagePaintTimingDetector|'s callback does not need -// to store in the same queue as |TextPaintTimingDetector|'s. The separate -// queue makes it possible to pop an |ImagePaintTimingDetector|'s callback -// without having to popping the |TextPaintTimingDetector|'s. -class PaintTimingCallbackManager : public GarbageCollectedMixin { - public: - using LocalThreadCallback = base::OnceCallback<void(base::TimeTicks)>; - using CallbackQueue = std::queue<LocalThreadCallback>; - - virtual void RegisterCallback( - PaintTimingCallbackManager::LocalThreadCallback) = 0; -}; - -// This class is responsible for managing the swap-time callback for Largest -// Image Paint and Largest Text Paint. In frames where both text and image are -// painted, Largest Image Paint and Largest Text Paint need to assign the same -// paint-time for their records. In this case, |PaintTimeCallbackManager| -// requests a swap-time callback and share the swap-time with LIP and LTP. -// Otherwise LIP and LTP would have to request their own swap-time callbacks. -// An extra benefit of this design is that |LargestContentfulPaintCalculator| -// can thus hook to the end of the LIP and LTP's record assignments. -// -// |GarbageCollected| inheritance is required by the swap-time callback -// registration. -class CORE_EXPORT PaintTimingCallbackManagerImpl final - : public GarbageCollected<PaintTimingCallbackManagerImpl>, - public PaintTimingCallbackManager { - public: - PaintTimingCallbackManagerImpl(LocalFrameView* frame_view) - : frame_view_(frame_view), - frame_callbacks_( - std::make_unique<std::queue< - PaintTimingCallbackManager::LocalThreadCallback>>()) {} - ~PaintTimingCallbackManagerImpl() { frame_callbacks_.reset(); } - - // Instead of registering the callback right away, this impl of the interface - // combine the callback into |frame_callbacks_| before registering a separate - // swap-time callback for the combined callbacks. When the swap-time callback - // is invoked, the swap-time is then assigned to each callback of - // |frame_callbacks_|. - void RegisterCallback( - PaintTimingCallbackManager::LocalThreadCallback callback) override { - frame_callbacks_->push(std::move(callback)); - } - - void RegisterPaintTimeCallbackForCombinedCallbacks(); - - inline size_t CountCallbacks() { return frame_callbacks_->size(); } - - void ReportPaintTime( - std::unique_ptr<std::queue< - PaintTimingCallbackManager::LocalThreadCallback>> frame_callbacks, - base::TimeTicks paint_time); - - void Trace(Visitor* visitor) const override; - - private: - Member<LocalFrameView> frame_view_; - // |frame_callbacks_| stores the callbacks of |TextPaintTimingDetector| and - // |ImagePaintTimingDetector| in an (animated) frame. It is passed as an - // argument of a swap-time callback which once is invoked, invokes every - // callback in |frame_callbacks_|. This hierarchical callback design is to - // reduce the need of calling ChromeClient to register swap-time callbacks for - // both detectos. - // Although |frame_callbacks_| intends to store callbacks - // of a frame, it occasionally has to do that for more than one frame, when it - // fails to register a swap-time callback. - std::unique_ptr<PaintTimingCallbackManager::CallbackQueue> frame_callbacks_; -}; - // PaintTimingDetector receives signals regarding text and image paints and // orchestrates the functionality of more specific paint detectors // (ImagePaintTimingDetector and TextPaintTimingDetector), to ensure proper
diff --git a/third_party/blink/renderer/core/paint/timing/paint_timing_test_helper.h b/third_party/blink/renderer/core/paint/timing/paint_timing_test_helper.h index b3f7637..bd48eb9 100644 --- a/third_party/blink/renderer/core/paint/timing/paint_timing_test_helper.h +++ b/third_party/blink/renderer/core/paint/timing/paint_timing_test_helper.h
@@ -2,7 +2,7 @@ #define THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_TIMING_PAINT_TIMING_TEST_HELPER_H_ #include "base/check_op.h" -#include "third_party/blink/renderer/core/paint/timing/paint_timing_detector.h" +#include "third_party/blink/renderer/core/paint/timing/paint_timing_callback_manager.h" namespace blink {
diff --git a/third_party/blink/renderer/core/paint/timing/text_paint_timing_detector.h b/third_party/blink/renderer/core/paint/timing/text_paint_timing_detector.h index 527385c5..995c1c4 100644 --- a/third_party/blink/renderer/core/paint/timing/text_paint_timing_detector.h +++ b/third_party/blink/renderer/core/paint/timing/text_paint_timing_detector.h
@@ -10,7 +10,6 @@ #include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/core/dom/node.h" #include "third_party/blink/renderer/core/paint/timing/lcp_objects.h" -#include "third_party/blink/renderer/core/paint/timing/paint_timing_detector.h" #include "third_party/blink/renderer/core/paint/timing/text_element_timing.h" #include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h" #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
diff --git a/third_party/blink/renderer/core/timing/back_forward_cache_restoration.cc b/third_party/blink/renderer/core/timing/back_forward_cache_restoration.cc index 9fe1e30d..1149046 100644 --- a/third_party/blink/renderer/core/timing/back_forward_cache_restoration.cc +++ b/third_party/blink/renderer/core/timing/back_forward_cache_restoration.cc
@@ -29,7 +29,7 @@ void BackForwardCacheRestoration::BuildJSONValue( V8ObjectBuilder& builder) const { PerformanceEntry::BuildJSONValue(builder); - builder.Add("pageshowEventStart", pageshow_event_start_); - builder.Add("pageshowEventEnd", pageshow_event_end_); + builder.AddNumber("pageshowEventStart", pageshow_event_start_); + builder.AddNumber("pageshowEventEnd", pageshow_event_end_); } } // namespace blink
diff --git a/third_party/blink/renderer/core/timing/largest_contentful_paint.cc b/third_party/blink/renderer/core/timing/largest_contentful_paint.cc index 32b9239..2a25f03 100644 --- a/third_party/blink/renderer/core/timing/largest_contentful_paint.cc +++ b/third_party/blink/renderer/core/timing/largest_contentful_paint.cc
@@ -59,12 +59,12 @@ void LargestContentfulPaint::BuildJSONValue(V8ObjectBuilder& builder) const { PerformanceEntry::BuildJSONValue(builder); - builder.Add("size", size_); - builder.Add("renderTime", render_time_); - builder.Add("loadTime", load_time_); - builder.Add("firstAnimatedFrameTime", first_animated_frame_time_); - builder.Add("id", id_); - builder.Add("url", url_); + builder.AddInteger("size", size_); + builder.AddNumber("renderTime", render_time_); + builder.AddNumber("loadTime", load_time_); + builder.AddNumber("firstAnimatedFrameTime", first_animated_frame_time_); + builder.AddString("id", id_); + builder.AddString("url", url_); } void LargestContentfulPaint::Trace(Visitor* visitor) const {
diff --git a/third_party/blink/renderer/core/timing/layout_shift.cc b/third_party/blink/renderer/core/timing/layout_shift.cc index 5d410ab8..f826fa4 100644 --- a/third_party/blink/renderer/core/timing/layout_shift.cc +++ b/third_party/blink/renderer/core/timing/layout_shift.cc
@@ -47,12 +47,13 @@ void LayoutShift::BuildJSONValue(V8ObjectBuilder& builder) const { PerformanceEntry::BuildJSONValue(builder); - builder.Add("value", value_); - builder.Add("hadRecentInput", had_recent_input_); - builder.Add("lastInputTime", most_recent_input_timestamp_); - builder.Add("sources", ToV8Traits<IDLArray<LayoutShiftAttribution>>::ToV8( - builder.GetScriptState(), sources_) - .ToLocalChecked()); + builder.AddNumber("value", value_); + builder.AddBoolean("hadRecentInput", had_recent_input_); + builder.AddNumber("lastInputTime", most_recent_input_timestamp_); + builder.AddV8Value("sources", + ToV8Traits<IDLArray<LayoutShiftAttribution>>::ToV8( + builder.GetScriptState(), sources_) + .ToLocalChecked()); } void LayoutShift::Trace(Visitor* visitor) const {
diff --git a/third_party/blink/renderer/core/timing/layout_shift_attribution.cc b/third_party/blink/renderer/core/timing/layout_shift_attribution.cc index 3e5cfde2..8043834b 100644 --- a/third_party/blink/renderer/core/timing/layout_shift_attribution.cc +++ b/third_party/blink/renderer/core/timing/layout_shift_attribution.cc
@@ -46,8 +46,8 @@ ScriptValue LayoutShiftAttribution::toJSONForBinding( ScriptState* script_state) const { V8ObjectBuilder builder(script_state); - builder.Add("previousRect", previous_rect_); - builder.Add("currentRect", current_rect_); + builder.Add("previousRect", previous_rect_.Get()); + builder.Add("currentRect", current_rect_.Get()); return builder.GetScriptValue(); }
diff --git a/third_party/blink/renderer/core/timing/not_restored_reasons.cc b/third_party/blink/renderer/core/timing/not_restored_reasons.cc index 679f156b..7b2ce236 100644 --- a/third_party/blink/renderer/core/timing/not_restored_reasons.cc +++ b/third_party/blink/renderer/core/timing/not_restored_reasons.cc
@@ -74,7 +74,7 @@ for (const auto& reason : reasons_) { reason_strings.push_back(reason); } - builder.Add("reasons", reason_strings); + builder.AddVector<IDLString>("reasons", reason_strings); } else { builder.AddNull("reasons"); } @@ -84,7 +84,7 @@ for (Member<NotRestoredReasons> child : children_) { children_result.push_back(child->toJSON(script_state).V8Value()); } - builder.Add("children", children_result); + builder.AddVector<IDLAny>("children", children_result); } else { builder.AddNull("children"); }
diff --git a/third_party/blink/renderer/core/timing/performance_element_timing.cc b/third_party/blink/renderer/core/timing/performance_element_timing.cc index 89c79d0..794c4949 100644 --- a/third_party/blink/renderer/core/timing/performance_element_timing.cc +++ b/third_party/blink/renderer/core/timing/performance_element_timing.cc
@@ -92,14 +92,14 @@ void PerformanceElementTiming::BuildJSONValue(V8ObjectBuilder& builder) const { PerformanceEntry::BuildJSONValue(builder); - builder.Add("renderTime", render_time_); - builder.Add("loadTime", load_time_); - builder.Add("intersectionRect", intersection_rect_); - builder.Add("identifier", identifier_); - builder.Add("naturalWidth", naturalWidth_); - builder.Add("naturalHeight", naturalHeight_); - builder.Add("id", id_); - builder.Add("url", url_); + builder.AddNumber("renderTime", render_time_); + builder.AddNumber("loadTime", load_time_); + builder.Add("intersectionRect", intersection_rect_.Get()); + builder.AddString("identifier", identifier_); + builder.AddNumber("naturalWidth", naturalWidth_); + builder.AddNumber("naturalHeight", naturalHeight_); + builder.AddString("id", id_); + builder.AddString("url", url_); } void PerformanceElementTiming::Trace(Visitor* visitor) const {
diff --git a/third_party/blink/renderer/core/timing/performance_long_animation_frame_timing.cc b/third_party/blink/renderer/core/timing/performance_long_animation_frame_timing.cc index de21e03..3179930 100644 --- a/third_party/blink/renderer/core/timing/performance_long_animation_frame_timing.cc +++ b/third_party/blink/renderer/core/timing/performance_long_animation_frame_timing.cc
@@ -102,9 +102,10 @@ builder.AddNumber("styleAndLayoutStart", styleAndLayoutStart()); builder.AddNumber("firstUIEventTimestamp", firstUIEventTimestamp()); builder.AddNumber("blockingDuration", blockingDuration()); - builder.Add("scripts", ToV8Traits<IDLArray<PerformanceScriptTiming>>::ToV8( - builder.GetScriptState(), scripts()) - .ToLocalChecked()); + builder.AddV8Value("scripts", + ToV8Traits<IDLArray<PerformanceScriptTiming>>::ToV8( + builder.GetScriptState(), scripts()) + .ToLocalChecked()); } void PerformanceLongAnimationFrameTiming::Trace(Visitor* visitor) const {
diff --git a/third_party/blink/renderer/core/timing/performance_long_task_timing.cc b/third_party/blink/renderer/core/timing/performance_long_task_timing.cc index 2ad4685..7c2ddad 100644 --- a/third_party/blink/renderer/core/timing/performance_long_task_timing.cc +++ b/third_party/blink/renderer/core/timing/performance_long_task_timing.cc
@@ -46,9 +46,10 @@ void PerformanceLongTaskTiming::BuildJSONValue(V8ObjectBuilder& builder) const { PerformanceEntry::BuildJSONValue(builder); - builder.Add("attribution", ToV8Traits<IDLArray<TaskAttributionTiming>>::ToV8( - builder.GetScriptState(), attribution_) - .ToLocalChecked()); + builder.AddV8Value("attribution", + ToV8Traits<IDLArray<TaskAttributionTiming>>::ToV8( + builder.GetScriptState(), attribution_) + .ToLocalChecked()); } void PerformanceLongTaskTiming::Trace(Visitor* visitor) const {
diff --git a/third_party/blink/renderer/core/timing/performance_navigation_timing.cc b/third_party/blink/renderer/core/timing/performance_navigation_timing.cc index 47722bf..8c90ef71 100644 --- a/third_party/blink/renderer/core/timing/performance_navigation_timing.cc +++ b/third_party/blink/renderer/core/timing/performance_navigation_timing.cc
@@ -382,14 +382,18 @@ if (RuntimeEnabledFeatures::BackForwardCacheNotRestoredReasonsEnabled( ExecutionContext::From(builder.GetScriptState()))) { - builder.Add("notRestoredReasons", notRestoredReasons()); + if (auto* not_restored_reasons = notRestoredReasons()) { + builder.Add("notRestoredReasons", not_restored_reasons); + } else { + builder.AddNull("notRestoredReasons"); + } ExecutionContext::From(builder.GetScriptState()) ->CountUse(WebFeature::kBackForwardCacheNotRestoredReasons); } if (RuntimeEnabledFeatures::PerformanceNavigateSystemEntropyEnabled( ExecutionContext::From(builder.GetScriptState()))) { - builder.Add("systemEntropy", GetSystemEntropy(GetDocumentLoader())); + builder.AddString("systemEntropy", GetSystemEntropy(GetDocumentLoader())); } }
diff --git a/third_party/blink/renderer/core/timing/performance_resource_timing.cc b/third_party/blink/renderer/core/timing/performance_resource_timing.cc index 77516bc6..6588e5d 100644 --- a/third_party/blink/renderer/core/timing/performance_resource_timing.cc +++ b/third_party/blink/renderer/core/timing/performance_resource_timing.cc
@@ -451,10 +451,10 @@ builder.AddNumber("responseStatus", responseStatus()); } - builder.Add("serverTiming", - ToV8Traits<IDLArray<PerformanceServerTiming>>::ToV8( - builder.GetScriptState(), serverTiming()) - .ToLocalChecked()); + builder.AddV8Value("serverTiming", + ToV8Traits<IDLArray<PerformanceServerTiming>>::ToV8( + builder.GetScriptState(), serverTiming()) + .ToLocalChecked()); } void PerformanceResourceTiming::Trace(Visitor* visitor) const {
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_state.cc b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_state.cc index 3e636d6..6fd76ab5 100644 --- a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_state.cc +++ b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_state.cc
@@ -183,6 +183,8 @@ visitor->Trace(stroke_style_); visitor->Trace(fill_style_); visitor->Trace(css_filter_value_); + visitor->Trace(font_); + visitor->Trace(font_for_filter_); visitor->Trace(canvas_filter_); FontSelectorClient::Trace(visitor); }
diff --git a/third_party/blink/renderer/modules/clipboard/clipboard_promise.cc b/third_party/blink/renderer/modules/clipboard/clipboard_promise.cc index a3da42e..b47081d 100644 --- a/third_party/blink/renderer/modules/clipboard/clipboard_promise.cc +++ b/third_party/blink/renderer/modules/clipboard/clipboard_promise.cc
@@ -362,20 +362,21 @@ return; } ScriptState::Scope scope(script_state); - if (!RuntimeEnabledFeatures::EmptyClipboardReadEnabled() && - !clipboard_item_data_.size()) { - script_promise_resolver_->RejectWithDOMException( - DOMExceptionCode::kDataError, "No valid data on clipboard."); - return; - } HeapVector<std::pair<String, ScriptPromise>> items; items.ReserveInitialCapacity(clipboard_item_data_.size()); - for (const auto& item : clipboard_item_data_) { - ScriptPromise promise = ScriptPromise::Cast( - script_state, - ToV8Traits<Blob>::ToV8(script_state, item.second).ToLocalChecked()); - items.emplace_back(item.first, promise); + for (const auto& [type, data] : clipboard_item_data_) { + if (data) { + ScriptPromise promise = ScriptPromise::Cast( + script_state, + ToV8Traits<Blob>::ToV8(script_state, data).ToLocalChecked()); + items.emplace_back(type, promise); + } + if (!RuntimeEnabledFeatures::EmptyClipboardReadEnabled() && !items.size()) { + script_promise_resolver_->RejectWithDOMException( + DOMExceptionCode::kDataError, "No valid data on clipboard."); + return; + } } HeapVector<Member<ClipboardItem>> clipboard_items = { MakeGarbageCollected<ClipboardItem>(items)};
diff --git a/third_party/blink/renderer/modules/compute_pressure/pressure_record.cc b/third_party/blink/renderer/modules/compute_pressure/pressure_record.cc index 89dc592..12adb39f 100644 --- a/third_party/blink/renderer/modules/compute_pressure/pressure_record.cc +++ b/third_party/blink/renderer/modules/compute_pressure/pressure_record.cc
@@ -30,9 +30,9 @@ ScriptValue PressureRecord::toJSON(ScriptState* script_state) const { V8ObjectBuilder result(script_state); - result.Add("source", source()); - result.Add("state", state()); - result.Add("time", time()); + result.AddString("source", source().AsCStr()); + result.AddString("state", state().AsCStr()); + result.AddNumber("time", time()); return result.GetScriptValue(); }
diff --git a/third_party/blink/renderer/modules/credentialmanagement/json.cc b/third_party/blink/renderer/modules/credentialmanagement/json.cc index e2ec5622..16f0855 100644 --- a/third_party/blink/renderer/modules/credentialmanagement/json.cc +++ b/third_party/blink/renderer/modules/credentialmanagement/json.cc
@@ -265,11 +265,11 @@ } if (prf.hasResults()) { V8ObjectBuilder results_builder(script_state); - results_builder.Add("first", - WebAuthnBase64UrlEncode(prf.results()->first())); + results_builder.AddString( + "first", WebAuthnBase64UrlEncode(prf.results()->first())); if (prf.results()->hasSecond()) { - results_builder.Add("second", - WebAuthnBase64UrlEncode(prf.results()->second())); + results_builder.AddString( + "second", WebAuthnBase64UrlEncode(prf.results()->second())); } } json->setPrf(builder.GetScriptValue()); @@ -279,7 +279,8 @@ supplemental_pub_keys = *in.supplementalPubKeys(); V8ObjectBuilder builder(script_state); if (supplemental_pub_keys.hasSignatures()) { - builder.Add("signatures", supplemental_pub_keys.signatures()); + builder.AddVector<DOMArrayBuffer>("signatures", + supplemental_pub_keys.signatures()); } json->setSupplementalPubKeys(builder.GetScriptValue()); }
diff --git a/third_party/blink/renderer/modules/crypto/crypto_result_impl.cc b/third_party/blink/renderer/modules/crypto/crypto_result_impl.cc index 9a9ee964..abcd0e4 100644 --- a/third_party/blink/renderer/modules/crypto/crypto_result_impl.cc +++ b/third_party/blink/renderer/modules/crypto/crypto_result_impl.cc
@@ -235,12 +235,8 @@ V8ObjectBuilder key_pair(script_state); - key_pair.Add("publicKey", - ScriptValue::From(script_state, - MakeGarbageCollected<CryptoKey>(public_key))); - key_pair.Add("privateKey", - ScriptValue::From(script_state, - MakeGarbageCollected<CryptoKey>(private_key))); + key_pair.Add("publicKey", MakeGarbageCollected<CryptoKey>(public_key)); + key_pair.Add("privateKey", MakeGarbageCollected<CryptoKey>(private_key)); resolver_->Resolve(key_pair.V8Value()); ClearResolver();
diff --git a/third_party/blink/renderer/modules/managed_device/navigator_managed_data.cc b/third_party/blink/renderer/modules/managed_device/navigator_managed_data.cc index bfebf74f..020097b 100644 --- a/third_party/blink/renderer/modules/managed_device/navigator_managed_data.cc +++ b/third_party/blink/renderer/modules/managed_device/navigator_managed_data.cc
@@ -242,7 +242,7 @@ if (v8::JSON::Parse(script_state->GetContext(), V8String(script_state->GetIsolate(), config_pair.value)) .ToLocal(&v8_object)) { - result.Add(config_pair.key, v8_object); + result.AddV8Value(config_pair.key, v8_object); } } scoped_resolver->Resolve(result.GetScriptValue());
diff --git a/third_party/blink/renderer/modules/payments/payment_address.cc b/third_party/blink/renderer/modules/payments/payment_address.cc index e6d2cabd..922195e 100644 --- a/third_party/blink/renderer/modules/payments/payment_address.cc +++ b/third_party/blink/renderer/modules/payments/payment_address.cc
@@ -27,7 +27,7 @@ ScriptValue PaymentAddress::toJSONForBinding(ScriptState* script_state) const { V8ObjectBuilder result(script_state); result.AddString("country", country()); - result.Add("addressLine", addressLine()); + result.AddVector<IDLString>("addressLine", addressLine()); result.AddString("region", region()); result.AddString("city", city()); result.AddString("dependentLocality", dependentLocality());
diff --git a/third_party/blink/renderer/modules/payments/payment_response.cc b/third_party/blink/renderer/modules/payments/payment_response.cc index d9d8b59..abda79bd 100644 --- a/third_party/blink/renderer/modules/payments/payment_response.cc +++ b/third_party/blink/renderer/modules/payments/payment_response.cc
@@ -151,13 +151,15 @@ V8ObjectBuilder result(script_state); result.AddString("requestId", requestId()); result.AddString("methodName", methodName()); - result.Add("details", details(script_state)); + result.AddV8Value("details", details(script_state).V8Value()); - if (shippingAddress()) - result.Add("shippingAddress", - shippingAddress()->toJSONForBinding(script_state)); - else + if (shippingAddress()) { + result.AddV8Value( + "shippingAddress", + shippingAddress()->toJSONForBinding(script_state).V8Value()); + } else { result.AddNull("shippingAddress"); + } result.AddStringOrNull("shippingOption", shippingOption()) .AddStringOrNull("payerName", payerName())
diff --git a/third_party/blink/renderer/modules/push_messaging/push_subscription.cc b/third_party/blink/renderer/modules/push_messaging/push_subscription.cc index 11fe3a4..5f29dc5 100644 --- a/third_party/blink/renderer/modules/push_messaging/push_subscription.cc +++ b/third_party/blink/renderer/modules/push_messaging/push_subscription.cc
@@ -138,8 +138,8 @@ } V8ObjectBuilder keys(script_state); - keys.Add("p256dh", ToBase64URLWithoutPadding(p256dh_)); - keys.Add("auth", ToBase64URLWithoutPadding(auth_)); + keys.AddString("p256dh", ToBase64URLWithoutPadding(p256dh_)); + keys.AddString("auth", ToBase64URLWithoutPadding(auth_)); result.Add("keys", keys);
diff --git a/third_party/blink/renderer/modules/webaudio/analyser_handler.cc b/third_party/blink/renderer/modules/webaudio/analyser_handler.cc index b2f3242..490143f 100644 --- a/third_party/blink/renderer/modules/webaudio/analyser_handler.cc +++ b/third_party/blink/renderer/modules/webaudio/analyser_handler.cc
@@ -40,9 +40,14 @@ } void AnalyserHandler::Process(uint32_t frames_to_process) { - AudioBus* output_bus = Output(0).Bus(); + DCHECK(Context()->IsAudioThread()); - if (!IsInitialized()) { + // It's possible that output is not connected. Assign nullptr to indicate + // such case. + AudioBus* output_bus = Output(0).RenderingFanOutCount() > 0 + ? Output(0).Bus() : nullptr; + + if (!IsInitialized() && output_bus) { output_bus->Zero(); return; } @@ -54,6 +59,11 @@ // Analyser reflects the current input. analyser_.WriteInput(input_bus.get(), frames_to_process); + // Subsequent steps require `output_bus` to be valid. + if (!output_bus) { + return; + } + if (!Input(0).IsConnected()) { // No inputs, so clear the output, and propagate the silence hint. output_bus->Zero(); @@ -178,8 +188,12 @@ } void AnalyserHandler::PullInputs(uint32_t frames_to_process) { - // Render directly into the output bus - Input(0).Pull(Output(0).Bus(), frames_to_process); + DCHECK(Context()->IsAudioThread()); + + AudioBus* output_bus = Output(0).RenderingFanOutCount() > 0 + ? Output(0).Bus() : nullptr; + + Input(0).Pull(output_bus, frames_to_process); } void AnalyserHandler::CheckNumberOfChannelsForInput(AudioNodeInput* input) {
diff --git a/third_party/blink/renderer/modules/webaudio/audio_worklet_handler.cc b/third_party/blink/renderer/modules/webaudio/audio_worklet_handler.cc index 0bf86b7..903e817 100644 --- a/third_party/blink/renderer/modules/webaudio/audio_worklet_handler.cc +++ b/third_party/blink/renderer/modules/webaudio/audio_worklet_handler.cc
@@ -119,12 +119,14 @@ return; } - // If the input is not connected, inform the processor with nullptr. + // If the input or the output is not connected, inform the processor with + // nullptr. for (unsigned i = 0; i < NumberOfInputs(); ++i) { inputs_[i] = Input(i).IsConnected() ? Input(i).Bus() : nullptr; } for (unsigned i = 0; i < NumberOfOutputs(); ++i) { - outputs_[i] = WrapRefCounted(Output(i).Bus()); + outputs_[i] = Output(i).RenderingFanOutCount() > 0 + ? WrapRefCounted(Output(i).Bus()) : nullptr; } for (const auto& param_name : param_value_map_.Keys()) {
diff --git a/third_party/blink/renderer/modules/webaudio/audio_worklet_processor.cc b/third_party/blink/renderer/modules/webaudio/audio_worklet_processor.cc index 181dfa9..c3c53d7a 100644 --- a/third_party/blink/renderer/modules/webaudio/audio_worklet_processor.cc +++ b/third_party/blink/renderer/modules/webaudio/audio_worklet_processor.cc
@@ -376,6 +376,12 @@ for (uint32_t bus_index = 0; bus_index < audio_port.size(); ++bus_index) { const scoped_refptr<AudioBus>& audio_bus = audio_port[bus_index]; + + // nullptr indicates the output bus is not connected. Do not proceed. + if (!audio_bus) { + break; + } + for (uint32_t channel_index = 0; channel_index < audio_bus->NumberOfChannels(); ++channel_index) { auto backing_store = array_buffers[bus_index][channel_index]
diff --git a/third_party/blink/renderer/modules/webaudio/deferred_task_handler.cc b/third_party/blink/renderer/modules/webaudio/deferred_task_handler.cc index fa1de8f..4730383d 100644 --- a/third_party/blink/renderer/modules/webaudio/deferred_task_handler.cc +++ b/third_party/blink/renderer/modules/webaudio/deferred_task_handler.cc
@@ -172,6 +172,16 @@ base::AutoTryLock try_locker(automatic_pull_handlers_lock_); if (try_locker.is_acquired()) { rendering_automatic_pull_handlers_.assign(automatic_pull_handlers_); + + // In rare cases, it is possible for automatic pull nodes' output bus + // to become stale. Make sure update their rendering output counts. + // crbug.com/1505080. + for (auto& handler : rendering_automatic_pull_handlers_) { + for (unsigned i = 0; i < handler->NumberOfOutputs(); ++i) { + handler->Output(i).UpdateRenderingState(); + } + } + automatic_pull_handlers_need_updating_ = false; } }
diff --git a/third_party/blink/renderer/platform/exported/web_font.cc b/third_party/blink/renderer/platform/exported/web_font.cc index 88cca03..3695377 100644 --- a/third_party/blink/renderer/platform/exported/web_font.cc +++ b/third_party/blink/renderer/platform/exported/web_font.cc
@@ -20,12 +20,11 @@ return new WebFont(description); } -class WebFont::Impl final { - USING_FAST_MALLOC(WebFont::Impl); - +class WebFont::Impl final : public GarbageCollected<WebFont::Impl> { public: - explicit Impl(const WebFontDescription& description) : font_(description) { - } + explicit Impl(const WebFontDescription& description) : font_(description) {} + + void Trace(Visitor* visitor) const { visitor->Trace(font_); } const Font& GetFont() const { return font_; } @@ -34,7 +33,7 @@ }; WebFont::WebFont(const WebFontDescription& description) - : private_(std::make_unique<Impl>(description)) {} + : private_(MakeGarbageCollected<Impl>(description)) {} WebFont::~WebFont() = default;
diff --git a/third_party/blink/renderer/platform/fonts/font.cc b/third_party/blink/renderer/platform/fonts/font.cc index 9263f29..fcc60f0 100644 --- a/third_party/blink/renderer/platform/fonts/font.cc +++ b/third_party/blink/renderer/platform/fonts/font.cc
@@ -56,7 +56,7 @@ return FontCache::Get().GetFontFallbackMap(); } -scoped_refptr<FontFallbackList> GetOrCreateFontFallbackList( +FontFallbackList* GetOrCreateFontFallbackList( const FontDescription& font_description, FontSelector* font_selector) { return GetFontFallbackMap(font_selector).Get(font_description); @@ -75,54 +75,16 @@ ? GetOrCreateFontFallbackList(font_description, font_selector) : nullptr) {} -Font::Font(const Font& other) = default; - -Font& Font::operator=(const Font& other) { - if (this == &other || *this == other) - return *this; - ReleaseFontFallbackListRef(); - font_description_ = other.font_description_; - font_fallback_list_ = other.font_fallback_list_; - return *this; -} - -Font::~Font() { - ReleaseFontFallbackListRef(); -} - -// Ensures that FontFallbackMap only keeps FontFallbackLists that are still in -// use by at least one Font object. If the last Font releases its reference, we -// should clear the entry from FontFallbackMap. -// Note that we must not persist a FontFallbackList reference outside Font. -void Font::ReleaseFontFallbackListRef() const { - if (!font_fallback_list_ || !font_fallback_list_->IsValid() || - !font_fallback_list_->HasFontFallbackMap()) { - font_fallback_list_.reset(); - return; - } - - FontFallbackList& list_ref = *font_fallback_list_; - // Failing this CHECK causes use-after-free below. - CHECK(!list_ref.HasOneRef()); - font_fallback_list_.reset(); - if (list_ref.HasOneRef()) - list_ref.GetFontFallbackMap().Remove(font_description_); -} - -void Font::RevalidateFontFallbackList() const { - DCHECK(font_fallback_list_); - font_fallback_list_ = - font_fallback_list_->GetFontFallbackMap().Get(font_description_); -} - FontFallbackList* Font::EnsureFontFallbackList() const { if (!font_fallback_list_ || !font_fallback_list_->HasFontFallbackMap()) { font_fallback_list_ = GetOrCreateFontFallbackList(font_description_, nullptr); } - if (!font_fallback_list_->IsValid()) - RevalidateFontFallbackList(); - return font_fallback_list_.get(); + if (!font_fallback_list_->IsValid()) { + font_fallback_list_ = + font_fallback_list_->GetFontFallbackMap().Get(font_description_); + } + return font_fallback_list_.Get(); } bool Font::operator==(const Font& other) const {
diff --git a/third_party/blink/renderer/platform/fonts/font.h b/third_party/blink/renderer/platform/fonts/font.h index 00f71248..24e8f4d 100644 --- a/third_party/blink/renderer/platform/fonts/font.h +++ b/third_party/blink/renderer/platform/fonts/font.h
@@ -67,10 +67,13 @@ Font(); explicit Font(const FontDescription&); Font(const FontDescription&, FontSelector*); - ~Font(); - Font(const Font&); - Font& operator=(const Font&); + Font(const Font&) = default; + Font(Font&&) = default; + Font& operator=(const Font&) = default; + Font& operator=(Font&&) = default; + + void Trace(Visitor* visitor) const { visitor->Trace(font_fallback_list_); } bool operator==(const Font& other) const; bool operator!=(const Font& other) const { return !(*this == other); } @@ -248,11 +251,9 @@ // TODO(xiaochengh): The function not only initializes null FontFallbackList, // but also syncs invalid FontFallbackList. Rename it for better readability. FontFallbackList* EnsureFontFallbackList() const; - void RevalidateFontFallbackList() const; - void ReleaseFontFallbackListRef() const; FontDescription font_description_; - mutable scoped_refptr<FontFallbackList> font_fallback_list_; + mutable Member<FontFallbackList> font_fallback_list_; }; inline const SimpleFontData* Font::PrimaryFont() const {
diff --git a/third_party/blink/renderer/platform/fonts/font_fallback_iterator.cc b/third_party/blink/renderer/platform/fonts/font_fallback_iterator.cc index bb6625f..5192a65 100644 --- a/third_party/blink/renderer/platform/fonts/font_fallback_iterator.cc +++ b/third_party/blink/renderer/platform/fonts/font_fallback_iterator.cc
@@ -14,10 +14,10 @@ FontFallbackIterator::FontFallbackIterator( const FontDescription& description, - scoped_refptr<FontFallbackList> fallback_list, + FontFallbackList* fallback_list, FontFallbackPriority font_fallback_priority) : font_description_(description), - font_fallback_list_(std::move(fallback_list)), + font_fallback_list_(fallback_list), current_font_data_index_(0), segmented_face_index_(0), fallback_stage_(kFontGroupFonts),
diff --git a/third_party/blink/renderer/platform/fonts/font_fallback_iterator.h b/third_party/blink/renderer/platform/fonts/font_fallback_iterator.h index f0697f8..2093e0ef 100644 --- a/third_party/blink/renderer/platform/fonts/font_fallback_iterator.h +++ b/third_party/blink/renderer/platform/fonts/font_fallback_iterator.h
@@ -25,7 +25,7 @@ public: FontFallbackIterator(const FontDescription&, - scoped_refptr<FontFallbackList>, + FontFallbackList*, FontFallbackPriority); FontFallbackIterator(FontFallbackIterator&&) = default; FontFallbackIterator(const FontFallbackIterator&) = delete; @@ -60,7 +60,7 @@ const Vector<UChar32>& hint_list); const FontDescription& font_description_; - scoped_refptr<FontFallbackList> font_fallback_list_; + FontFallbackList* font_fallback_list_; int current_font_data_index_; unsigned segmented_face_index_;
diff --git a/third_party/blink/renderer/platform/fonts/font_fallback_list.cc b/third_party/blink/renderer/platform/fonts/font_fallback_list.cc index 0921ae1..4f98eae2 100644 --- a/third_party/blink/renderer/platform/fonts/font_fallback_list.cc +++ b/third_party/blink/renderer/platform/fonts/font_fallback_list.cc
@@ -56,6 +56,10 @@ ReleaseFontData(); } +void FontFallbackList::Trace(Visitor* visitor) const { + visitor->Trace(font_fallback_map_); +} + FontSelector* FontFallbackList::GetFontSelector() const { // FontFallbackList objects are managed in FontFallbackMap, and should not be // used after FontFallbackMap is destroyed. FontFallbackList may outlive its
diff --git a/third_party/blink/renderer/platform/fonts/font_fallback_list.h b/third_party/blink/renderer/platform/fonts/font_fallback_list.h index aebf0e0..12dcbd8 100644 --- a/third_party/blink/renderer/platform/fonts/font_fallback_list.h +++ b/third_party/blink/renderer/platform/fonts/font_fallback_list.h
@@ -43,19 +43,17 @@ // FontFallbackList caches FontData from FontSelector and FontCache. If font // updates occur (e.g., @font-face rule changes, web font is loaded, etc.), // the cached data becomes stale and hence, invalid. -class PLATFORM_EXPORT FontFallbackList : public RefCounted<FontFallbackList> { - USING_FAST_MALLOC(FontFallbackList); - +class PLATFORM_EXPORT FontFallbackList + : public GarbageCollected<FontFallbackList> { public: - static scoped_refptr<FontFallbackList> Create( - FontFallbackMap& font_fallback_map) { - return base::AdoptRef(new FontFallbackList(font_fallback_map)); - } + explicit FontFallbackList(FontFallbackMap& font_fallback_map); FontFallbackList(const FontFallbackList&) = delete; FontFallbackList& operator=(const FontFallbackList&) = delete; ~FontFallbackList(); + void Trace(Visitor*) const; + // Returns whether the cached data is valid. We can use a FontFallbackList // only when it's valid. bool IsValid() const { return !is_invalid_; } @@ -69,7 +67,7 @@ bool ShouldSkipDrawing() const; - // Returns false only after the WeakPersistent to FontFallbackMap is turned to + // Returns false only after the WeakMember to FontFallbackMap is turned to // nullptr due to GC. bool HasFontFallbackMap() const { return font_fallback_map_; } FontFallbackMap& GetFontFallbackMap() const { return *font_fallback_map_; } @@ -125,8 +123,6 @@ bool HasCustomFont() const { return has_custom_font_; } private: - explicit FontFallbackList(FontFallbackMap& font_fallback_map); - scoped_refptr<FontData> GetFontData(const FontDescription&); const SimpleFontData* DeterminePrimarySimpleFontData(const FontDescription&); @@ -138,7 +134,7 @@ Vector<scoped_refptr<FontData>, 1> font_list_; const SimpleFontData* cached_primary_simple_font_data_ = nullptr; - const WeakPersistent<FontFallbackMap> font_fallback_map_; + const WeakMember<FontFallbackMap> font_fallback_map_; int family_index_ = 0; const uint16_t generation_; bool has_loading_fallback_ : 1;
diff --git a/third_party/blink/renderer/platform/fonts/font_fallback_map.cc b/third_party/blink/renderer/platform/fonts/font_fallback_map.cc index f4c4e80d..f676cda4 100644 --- a/third_party/blink/renderer/platform/fonts/font_fallback_map.cc +++ b/third_party/blink/renderer/platform/fonts/font_fallback_map.cc
@@ -10,34 +10,22 @@ void FontFallbackMap::Trace(Visitor* visitor) const { visitor->Trace(font_selector_); + visitor->Trace(fallback_list_for_description_); FontCacheClient::Trace(visitor); FontSelectorClient::Trace(visitor); } -FontFallbackMap::~FontFallbackMap() { - InvalidateAll(); -} - -scoped_refptr<FontFallbackList> FontFallbackMap::Get( +FontFallbackList* FontFallbackMap::Get( const FontDescription& font_description) { - auto iter = fallback_list_for_description_.find(font_description); - if (iter != fallback_list_for_description_.end()) { - DCHECK(iter->value->IsValid()); - return iter->value; + auto add_result = + fallback_list_for_description_.insert(font_description, nullptr); + if (add_result.is_new_entry) { + add_result.stored_value->value = + MakeGarbageCollected<FontFallbackList>(*this); } - auto add_result = fallback_list_for_description_.insert( - font_description, FontFallbackList::Create(*this)); return add_result.stored_value->value; } -void FontFallbackMap::Remove(const FontDescription& font_description) { - auto iter = fallback_list_for_description_.find(font_description); - DCHECK_NE(iter, fallback_list_for_description_.end()); - DCHECK(iter->value->IsValid()); - DCHECK(iter->value->HasOneRef()); - fallback_list_for_description_.erase(iter); -} - void FontFallbackMap::InvalidateAll() { for (auto& entry : fallback_list_for_description_) entry.value->MarkInvalid();
diff --git a/third_party/blink/renderer/platform/fonts/font_fallback_map.h b/third_party/blink/renderer/platform/fonts/font_fallback_map.h index dbe646f..1a722a8 100644 --- a/third_party/blink/renderer/platform/fonts/font_fallback_map.h +++ b/third_party/blink/renderer/platform/fonts/font_fallback_map.h
@@ -9,6 +9,7 @@ #include "third_party/blink/renderer/platform/fonts/font_description.h" #include "third_party/blink/renderer/platform/fonts/font_fallback_list.h" #include "third_party/blink/renderer/platform/fonts/font_selector_client.h" +#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h" #include "third_party/blink/renderer/platform/heap/garbage_collected.h" #include "third_party/blink/renderer/platform/platform_export.h" #include "third_party/blink/renderer/platform/wtf/vector.h" @@ -17,19 +18,20 @@ namespace blink { +// This class acts as a cache ensuring that equivalent `FontDescription`s will +// have the same `FontFallbackList`. +// +// This class doesn't retain the `FontFallbackList`s however, only having a weak +// reference to them. class PLATFORM_EXPORT FontFallbackMap : public FontCacheClient, public FontSelectorClient { public: explicit FontFallbackMap(FontSelector* font_selector) : font_selector_(font_selector) {} - ~FontFallbackMap() override; - FontSelector* GetFontSelector() const { return font_selector_.Get(); } - scoped_refptr<FontFallbackList> Get(const FontDescription& font_description); - - void Remove(const FontDescription& font_description); + FontFallbackList* Get(const FontDescription& font_description); void Trace(Visitor* visitor) const override; @@ -46,7 +48,7 @@ void InvalidateInternal(Predicate predicate); Member<FontSelector> font_selector_; - HashMap<FontDescription, scoped_refptr<FontFallbackList>> + HeapHashMap<FontDescription, WeakMember<FontFallbackList>> fallback_list_for_description_; };
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource.cc b/third_party/blink/renderer/platform/graphics/canvas_resource.cc index 6422e08..310a911 100644 --- a/third_party/blink/renderer/platform/graphics/canvas_resource.cc +++ b/third_party/blink/renderer/platform/graphics/canvas_resource.cc
@@ -1101,9 +1101,9 @@ base::RetainedRef(this)); return AcceleratedStaticBitmapImage::CreateFromCanvasMailbox( - back_buffer_mailbox_, GetSyncToken(), shared_texture_id, image_info, - GL_TEXTURE_2D, true /*is_origin_top_left*/, context_provider_wrapper_, - owning_thread_ref_, owning_thread_task_runner_, + back_buffer_shared_image_->mailbox(), GetSyncToken(), shared_texture_id, + image_info, GL_TEXTURE_2D, true /*is_origin_top_left*/, + context_provider_wrapper_, owning_thread_ref_, owning_thread_task_runner_, std::move(release_callback), /*supports_display_compositing=*/true, /*is_overlay_candidate=*/true); } @@ -1133,18 +1133,21 @@ auto* sii = context_provider_wrapper_->ContextProvider()->SharedImageInterface(); DCHECK(sii); - sii->DestroySharedImage(gpu::SyncToken(), front_buffer_mailbox_); - sii->DestroySharedImage(gpu::SyncToken(), back_buffer_mailbox_); + sii->DestroySharedImage(gpu::SyncToken(), + std::move(front_buffer_shared_image_)); + sii->DestroySharedImage(gpu::SyncToken(), + std::move(back_buffer_shared_image_)); } const gpu::Mailbox& CanvasResourceSwapChain::GetOrCreateGpuMailbox( MailboxSyncMode sync_mode) { DCHECK_EQ(sync_mode, kVerifiedSyncToken); - return front_buffer_mailbox_; + return (front_buffer_shared_image_) ? front_buffer_shared_image_->mailbox() + : empty_mailbox_; } bool CanvasResourceSwapChain::HasGpuMailbox() const { - return !front_buffer_mailbox_.IsZero(); + return front_buffer_shared_image_ != nullptr; } const gpu::SyncToken CanvasResourceSwapChain::GetSyncToken() { @@ -1167,7 +1170,7 @@ // Synchronize presentation and rendering. raster_interface->GenUnverifiedSyncTokenCHROMIUM(sync_token_.GetData()); - sii->PresentSwapChain(sync_token_, back_buffer_mailbox_); + sii->PresentSwapChain(sync_token_, back_buffer_shared_image_->mailbox()); // This only gets called via the CanvasResourceDispatcher export path so a // verified sync token will be needed ultimately. sync_token_ = sii->GenVerifiedSyncToken(); @@ -1184,7 +1187,8 @@ // copied into the back buffer to support a retained mode like canvas expects. // The wait sync token ensure that the present executes before we do the copy. // Don't generate sync token after the copy so that it's not on critical path. - raster_interface->CopySharedImage(front_buffer_mailbox_, back_buffer_mailbox_, + raster_interface->CopySharedImage(front_buffer_shared_image_->mailbox(), + back_buffer_shared_image_->mailbox(), GL_TEXTURE_2D, 0, 0, 0, 0, size_.width(), size_.height(), false /* unpack_flip_y */, false /* unpack_premultiply_alpha */); @@ -1229,12 +1233,14 @@ auto* sii = context_provider_wrapper_->ContextProvider()->SharedImageInterface(); DCHECK(sii); - gpu::SharedImageInterface::SwapChainMailboxes mailboxes = + gpu::SharedImageInterface::SwapChainSharedImages shared_images = sii->CreateSwapChain(GetSharedImageFormat(), Size(), GetColorSpace(), kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType, usage); - back_buffer_mailbox_ = mailboxes.back_buffer; - front_buffer_mailbox_ = mailboxes.front_buffer; + CHECK(shared_images.back_buffer); + CHECK(shared_images.front_buffer); + back_buffer_shared_image_ = std::move(shared_images.back_buffer); + front_buffer_shared_image_ = std::move(shared_images.front_buffer); sync_token_ = sii->GenVerifiedSyncToken(); // Wait for the mailboxes to be ready to be used. @@ -1248,8 +1254,8 @@ if (use_oop_rasterization_) return; - back_buffer_texture_id_ = - raster_interface->CreateAndConsumeForGpuRaster(back_buffer_mailbox_); + back_buffer_texture_id_ = raster_interface->CreateAndConsumeForGpuRaster( + back_buffer_shared_image_->mailbox()); raster_interface->BeginSharedImageAccessDirectCHROMIUM( back_buffer_texture_id_, GL_SHARED_IMAGE_ACCESS_MODE_READWRITE_CHROMIUM); }
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource.h b/third_party/blink/renderer/platform/graphics/canvas_resource.h index 0bc32fc..b415b0e6 100644 --- a/third_party/blink/renderer/platform/graphics/canvas_resource.h +++ b/third_party/blink/renderer/platform/graphics/canvas_resource.h
@@ -590,7 +590,10 @@ GLenum TextureTarget() const final { return GL_TEXTURE_2D; } GLuint GetBackBufferTextureId() const { return back_buffer_texture_id_; } - const gpu::Mailbox& GetBackBufferMailbox() { return back_buffer_mailbox_; } + const gpu::Mailbox& GetBackBufferMailbox() { + CHECK(back_buffer_shared_image_); + return back_buffer_shared_image_->mailbox(); + } void PresentSwapChain(); const gpu::Mailbox& GetOrCreateGpuMailbox(MailboxSyncMode) override; @@ -611,11 +614,12 @@ const base::WeakPtr<WebGraphicsContext3DProviderWrapper> context_provider_wrapper_; const gfx::Size size_; - gpu::Mailbox front_buffer_mailbox_; - gpu::Mailbox back_buffer_mailbox_; + scoped_refptr<gpu::ClientSharedImage> front_buffer_shared_image_; + scoped_refptr<gpu::ClientSharedImage> back_buffer_shared_image_; GLuint back_buffer_texture_id_ = 0u; gpu::SyncToken sync_token_; const bool use_oop_rasterization_; + const gpu::Mailbox empty_mailbox_; bool is_origin_clean_ = true; };
diff --git a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc index 8e70425..6b0f6189 100644 --- a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc +++ b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc
@@ -448,8 +448,7 @@ CreateTransform(*transform1, MakeRotationMatrix(0, 45, 0)); TransformPaintPropertyNode::State transform3_state{ {MakeRotationMatrix(0, 45, 0)}}; - transform3_state.flags.flattens_inherited_transform = - transform_is_flattened; + transform3_state.flattens_inherited_transform = transform_is_flattened; auto transform3 = TransformPaintPropertyNode::Create( *transform2, std::move(transform3_state)); @@ -502,8 +501,7 @@ auto transform2 = TransformPaintPropertyNodeAlias::Create(*real_transform2); TransformPaintPropertyNode::State transform3_state{ {MakeRotationMatrix(0, 45, 0)}}; - transform3_state.flags.flattens_inherited_transform = - transform_is_flattened; + transform3_state.flattens_inherited_transform = transform_is_flattened; auto real_transform3 = TransformPaintPropertyNode::Create( *transform2, std::move(transform3_state)); auto transform3 = TransformPaintPropertyNodeAlias::Create(*real_transform3); @@ -4109,7 +4107,7 @@ TEST_P(PaintArtifactCompositorTest, CreatesViewportNodes) { auto matrix = MakeScaleMatrix(2); TransformPaintPropertyNode::State transform_state{{matrix}}; - transform_state.flags.in_subtree_of_page_scale = false; + transform_state.in_subtree_of_page_scale = false; const CompositorElementId compositor_element_id = CompositorElementIdFromUniqueObjectId(1); transform_state.compositor_element_id = compositor_element_id; @@ -4134,12 +4132,12 @@ // the page scale transform node or ancestors, and is set on descendants. TEST_P(PaintArtifactCompositorTest, InSubtreeOfPageScale) { TransformPaintPropertyNode::State ancestor_transform_state; - ancestor_transform_state.flags.in_subtree_of_page_scale = false; + ancestor_transform_state.in_subtree_of_page_scale = false; auto ancestor_transform = TransformPaintPropertyNode::Create( TransformPaintPropertyNode::Root(), std::move(ancestor_transform_state)); TransformPaintPropertyNode::State page_scale_transform_state; - page_scale_transform_state.flags.in_subtree_of_page_scale = false; + page_scale_transform_state.in_subtree_of_page_scale = false; const CompositorElementId page_scale_compositor_element_id = CompositorElementIdFromUniqueObjectId(1); page_scale_transform_state.compositor_element_id = @@ -4152,7 +4150,7 @@ CompositorElementIdFromUniqueObjectId(2); descendant_transform_state.compositor_element_id = descendant_compositor_element_id; - descendant_transform_state.flags.in_subtree_of_page_scale = true; + descendant_transform_state.in_subtree_of_page_scale = true; descendant_transform_state.direct_compositing_reasons = CompositingReason::kWillChangeTransform; auto descendant_transform = TransformPaintPropertyNode::Create( @@ -4189,7 +4187,7 @@ TEST_P(PaintArtifactCompositorTest, ViewportPageScale) { // Create a page scale transform node with a page scale factor of 2.0. TransformPaintPropertyNode::State transform_state{{MakeScaleMatrix(2)}}; - transform_state.flags.in_subtree_of_page_scale = false; + transform_state.in_subtree_of_page_scale = false; transform_state.compositor_element_id = CompositorElementIdFromUniqueObjectId(1); auto scale_transform_node = TransformPaintPropertyNode::Create(
diff --git a/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc b/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc index 17f9801..ca7663b 100644 --- a/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc +++ b/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc
@@ -616,7 +616,7 @@ // Populate the output mailbox and callback. { *out_resource = viz::TransferableResource::MakeGpu( - color_buffer_for_mailbox->mailbox, + color_buffer_for_mailbox->shared_image, color_buffer_for_mailbox->texture_target, color_buffer_for_mailbox->produce_sync_token, size_, color_buffer_for_mailbox->format, @@ -782,7 +782,7 @@ using_swap_chain_ ? front_color_buffer_ : back_color_buffer_; viz::TransferableResource resource; - resource.mailbox_holder.mailbox = color_buffer->mailbox; + resource.mailbox_holder.mailbox = color_buffer->shared_image->mailbox(); resource.mailbox_holder.texture_target = color_buffer->texture_target; resource.size = color_buffer->size; resource.format = color_buffer->format; @@ -826,7 +826,7 @@ GLenum texture_target, GLuint texture_id, bool is_overlay_candidate, - gpu::Mailbox mailbox) + scoped_refptr<gpu::ClientSharedImage> shared_image) : owning_thread_ref(base::PlatformThread::CurrentRef()), drawing_buffer(std::move(drawing_buffer)), size(size), @@ -836,7 +836,9 @@ texture_target(texture_target), texture_id(texture_id), is_overlay_candidate(is_overlay_candidate), - mailbox(mailbox) {} + shared_image(std::move(shared_image)) { + CHECK(this->shared_image); +} DrawingBuffer::ColorBuffer::~ColorBuffer() { if (base::PlatformThread::CurrentRef() != owning_thread_ref || @@ -868,7 +870,7 @@ return; } - sii->DestroySharedImage(receive_sync_token, mailbox); + sii->DestroySharedImage(receive_sync_token, std::move(shared_image)); gl->DeleteTextures(1u, &texture_id); } @@ -1050,7 +1052,8 @@ // Use an empty sync token for `mailbox_holder` because we have already waited // on the required sync tokens above. - gpu::MailboxHolder mailbox_holder(src_color_buffer->mailbox, gpu::SyncToken(), + gpu::MailboxHolder mailbox_holder(src_color_buffer->shared_image->mailbox(), + gpu::SyncToken(), src_color_buffer->texture_target); bool succeeded = copy_function(mailbox_holder, src_color_buffer->format, src_alpha_type, @@ -1848,7 +1851,8 @@ gl_->GenUnverifiedSyncTokenCHROMIUM(sync_token.GetData()); auto* sii = ContextProvider()->SharedImageInterface(); - sii->PresentSwapChain(sync_token, back_color_buffer_->mailbox); + sii->PresentSwapChain(sync_token, + back_color_buffer_->shared_image->mailbox()); sync_token = sii->GenUnverifiedSyncToken(); gl_->WaitSyncTokenCHROMIUM(sync_token.GetConstData()); @@ -1889,9 +1893,9 @@ gpu::SharedImageInterface* sii = ContextProvider()->SharedImageInterface(); - gpu::Mailbox back_buffer_mailbox; + scoped_refptr<gpu::ClientSharedImage> back_buffer_shared_image; // Set only when using swap chains. - gpu::Mailbox front_buffer_mailbox; + scoped_refptr<gpu::ClientSharedImage> front_buffer_shared_image; GLenum texture_target = GL_TEXTURE_2D; GLuint texture_id = 0; bool created_mappable_si = false; @@ -1923,12 +1927,12 @@ SkAlphaType back_buffer_alpha_type = kPremul_SkAlphaType; if (using_swap_chain_) { - gpu::SharedImageInterface::SwapChainMailboxes mailboxes = + gpu::SharedImageInterface::SwapChainSharedImages shared_images = sii->CreateSwapChain(color_buffer_format_, size, color_space_, origin, back_buffer_alpha_type, usage | gpu::SHARED_IMAGE_USAGE_SCANOUT); - back_buffer_mailbox = mailboxes.back_buffer; - front_buffer_mailbox = mailboxes.front_buffer; + back_buffer_shared_image = std::move(shared_images.back_buffer); + front_buffer_shared_image = std::move(shared_images.front_buffer); } else { if (ShouldUseChromiumImage()) { // TODO(b/286417069): BGRX has issues when Vulkan is used for raster and @@ -1983,7 +1987,7 @@ // prior attempts to be reverted (crbug.com/1346737). client_shared_image->SetColorSpaceOnNativeBuffer(color_space_); #endif - back_buffer_mailbox = client_shared_image->mailbox(); + back_buffer_shared_image = std::move(client_shared_image); #if BUILDFLAG(IS_MAC) // A CHROMIUM_image backed texture requires a specialized set of // parameters on OSX. @@ -2004,12 +2008,11 @@ back_buffer_alpha_type = kUnpremul_SkAlphaType; } - auto client_shared_image = + back_buffer_shared_image = sii->CreateSharedImage(color_buffer_format_, size, color_space_, origin, back_buffer_alpha_type, usage, "WebGLDrawingBuffer", gpu::kNullSurfaceHandle); - CHECK(client_shared_image); - back_buffer_mailbox = client_shared_image->mailbox(); + CHECK(back_buffer_shared_image); } } @@ -2030,20 +2033,20 @@ gpu::SyncToken sync_token = sii->GenUnverifiedSyncToken(); gl_->WaitSyncTokenCHROMIUM(sync_token.GetConstData()); - if (!front_buffer_mailbox.IsZero()) { + if (front_buffer_shared_image) { DCHECK(using_swap_chain_); // Import frontbuffer of swap chain into GL. texture_id = gl_->CreateAndTexStorage2DSharedImageCHROMIUM( - front_buffer_mailbox.name); + front_buffer_shared_image->mailbox().name); front_color_buffer_ = base::MakeRefCounted<ColorBuffer>( weak_factory_.GetWeakPtr(), size, color_space_, color_buffer_format_, back_buffer_alpha_type, texture_target, texture_id, - /*is_overlay_candidate=*/true, front_buffer_mailbox); + /*is_overlay_candidate=*/true, std::move(front_buffer_shared_image)); } // Import the backbuffer of swap chain or allocated SharedImage into GL. - texture_id = - gl_->CreateAndTexStorage2DSharedImageCHROMIUM(back_buffer_mailbox.name); + texture_id = gl_->CreateAndTexStorage2DSharedImageCHROMIUM( + back_buffer_shared_image->mailbox().name); gl_->BeginSharedImageAccessDirectCHROMIUM( texture_id, GL_SHARED_IMAGE_ACCESS_MODE_READWRITE_CHROMIUM); gl_->BindTexture(texture_target, texture_id); @@ -2070,7 +2073,7 @@ return base::MakeRefCounted<ColorBuffer>( weak_factory_.GetWeakPtr(), size, color_space_, color_buffer_format_, back_buffer_alpha_type, texture_target, texture_id, is_overlay_candidate, - back_buffer_mailbox); + std::move(back_buffer_shared_image)); } void DrawingBuffer::AttachColorBufferToReadFramebuffer() {
diff --git a/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.h b/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.h index f504d97..222e3e1 100644 --- a/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.h +++ b/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.h
@@ -425,7 +425,7 @@ GLenum texture_target, GLuint texture_id, bool is_overlay_candidate, - gpu::Mailbox mailbox); + scoped_refptr<gpu::ClientSharedImage> shared_image); ColorBuffer(const ColorBuffer&) = delete; ColorBuffer& operator=(const ColorBuffer&) = delete; ~ColorBuffer(); @@ -446,8 +446,8 @@ const GLuint texture_id; const bool is_overlay_candidate; - // The mailbox used to send this buffer to the compositor. - gpu::Mailbox mailbox; + // The shared image used to send this buffer to the compositor. + scoped_refptr<gpu::ClientSharedImage> shared_image; // The sync token for when this buffer was sent to the compositor. gpu::SyncToken produce_sync_token;
diff --git a/third_party/blink/renderer/platform/graphics/paint/geometry_mapper_test.cc b/third_party/blink/renderer/platform/graphics/paint/geometry_mapper_test.cc index 05950ce..7d0e196ec 100644 --- a/third_party/blink/renderer/platform/graphics/paint/geometry_mapper_test.cc +++ b/third_party/blink/renderer/platform/graphics/paint/geometry_mapper_test.cc
@@ -356,7 +356,7 @@ auto inverse_rotate_transform = MakeRotationMatrix(-45, 0, 0); TransformPaintPropertyNode::State inverse_state{{inverse_rotate_transform}}; - inverse_state.flags.flattens_inherited_transform = true; + inverse_state.flattens_inherited_transform = true; auto transform2 = TransformPaintPropertyNode::Create(*transform1, std::move(inverse_state)); local_state.SetTransform(*transform2);
diff --git a/third_party/blink/renderer/platform/graphics/paint/transform_paint_property_node.cc b/third_party/blink/renderer/platform/graphics/paint/transform_paint_property_node.cc index b153e3fb..d64c4ee 100644 --- a/third_party/blink/renderer/platform/graphics/paint/transform_paint_property_node.cc +++ b/third_party/blink/renderer/platform/graphics/paint/transform_paint_property_node.cc
@@ -70,20 +70,16 @@ const State& other, const AnimationState& animation_state) const { // Whether or not a node is considered a frame root should be invariant. - DCHECK_EQ(flags.is_frame_paint_offset_translation, - other.flags.is_frame_paint_offset_translation); + DCHECK_EQ(is_frame_paint_offset_translation, + other.is_frame_paint_offset_translation); // Changes other than compositing reason and the transform are not simple. - if (flags.flattens_inherited_transform != - other.flags.flattens_inherited_transform || - flags.in_subtree_of_page_scale != other.flags.in_subtree_of_page_scale || - flags.animation_is_axis_aligned != - other.flags.animation_is_axis_aligned || - flags.delegates_to_parent_for_backface != - other.flags.delegates_to_parent_for_backface || - flags.is_frame_paint_offset_translation != - other.flags.is_frame_paint_offset_translation || - flags.is_for_svg_child != other.flags.is_for_svg_child || + if (flattens_inherited_transform != other.flattens_inherited_transform || + in_subtree_of_page_scale != other.in_subtree_of_page_scale || + animation_is_axis_aligned != other.animation_is_axis_aligned || + is_frame_paint_offset_translation != + other.is_frame_paint_offset_translation || + is_for_svg_child != other.is_for_svg_child || backface_visibility != other.backface_visibility || rendering_context_id != other.rendering_context_id || compositor_element_id != other.compositor_element_id || @@ -136,11 +132,8 @@ DEFINE_STATIC_REF( TransformPaintPropertyNode, root, base::AdoptRef(new TransformPaintPropertyNode( - nullptr, State{{}, - &ScrollPaintPropertyNode::Root(), - nullptr, - State::Flags{false /* flattens_inherited_transform */, - false /* in_subtree_of_page_scale */}}))); + nullptr, State{.scroll = &ScrollPaintPropertyNode::Root(), + .in_subtree_of_page_scale = false}))); return *root; } @@ -192,10 +185,12 @@ json->SetString("matrix", matrix.Replace("\n", ", ")); json->SetString("origin", String(Origin().ToString())); } - if (!state_.flags.flattens_inherited_transform) + if (!state_.flattens_inherited_transform) { json->SetBoolean("flattensInheritedTransform", false); - if (!state_.flags.in_subtree_of_page_scale) + } + if (!state_.in_subtree_of_page_scale) { json->SetBoolean("in_subtree_of_page_scale", false); + } if (state_.backface_visibility != BackfaceVisibility::kInherited) { json->SetString("backface", state_.backface_visibility == BackfaceVisibility::kVisible
diff --git a/third_party/blink/renderer/platform/graphics/paint/transform_paint_property_node.h b/third_party/blink/renderer/platform/graphics/paint/transform_paint_property_node.h index 5863336..1614730 100644 --- a/third_party/blink/renderer/platform/graphics/paint/transform_paint_property_node.h +++ b/third_party/blink/renderer/platform/graphics/paint/transform_paint_property_node.h
@@ -109,19 +109,12 @@ scoped_refptr<const TransformPaintPropertyNode> scroll_translation_for_fixed; - // Use bitfield packing instead of separate bools to save space. - struct Flags { - DISALLOW_NEW(); - - public: - bool flattens_inherited_transform : 1; - bool in_subtree_of_page_scale : 1; - bool animation_is_axis_aligned : 1; - bool delegates_to_parent_for_backface : 1; - // Set if a frame is rooted at this node. - bool is_frame_paint_offset_translation : 1; - bool is_for_svg_child : 1; - } flags = {false, true, false, false, false, false}; + bool flattens_inherited_transform : 1 = false; + bool in_subtree_of_page_scale : 1 = true; + bool animation_is_axis_aligned : 1 = false; + // Set if a frame is rooted at this node. + bool is_frame_paint_offset_translation : 1 = false; + bool is_for_svg_child : 1 = false; BackfaceVisibility backface_visibility = BackfaceVisibility::kInherited; unsigned rendering_context_id = 0; @@ -227,7 +220,7 @@ // If true, this node is a descendant of the page scale transform. This is // important for avoiding raster during pinch-zoom (see: crbug.com/951861). bool IsInSubtreeOfPageScale() const { - return state_.flags.in_subtree_of_page_scale; + return state_.in_subtree_of_page_scale; } const CompositorStickyConstraint* GetStickyConstraint() const { @@ -265,7 +258,7 @@ // the plane of its parent. This is implemented by flattening the total // accumulated transform from its ancestors. bool FlattensInheritedTransform() const { - return state_.flags.flattens_inherited_transform; + return state_.flattens_inherited_transform; } // Returns the local BackfaceVisibility value set on this node. To be used @@ -297,8 +290,8 @@ bool FlattensInheritedTransformSameAsParent() const { if (IsRoot()) return true; - return state_.flags.flattens_inherited_transform == - Parent()->Unalias().state_.flags.flattens_inherited_transform; + return state_.flattens_inherited_transform == + Parent()->Unalias().state_.flattens_inherited_transform; } bool HasDirectCompositingReasons() const { @@ -341,7 +334,7 @@ } bool TransformAnimationIsAxisAligned() const { - return state_.flags.animation_is_axis_aligned; + return state_.animation_is_axis_aligned; } bool RequiresCompositingForRootScroller() const { @@ -371,14 +364,11 @@ } bool IsFramePaintOffsetTranslation() const { - return state_.flags.is_frame_paint_offset_translation; + return state_.is_frame_paint_offset_translation; } bool DelegatesToParentForBackface() const { - if (RuntimeEnabledFeatures::BackfaceVisibilityNewInheritanceEnabled()) { - return state_.backface_visibility == BackfaceVisibility::kInherited; - } - return state_.flags.delegates_to_parent_for_backface; + return state_.backface_visibility == BackfaceVisibility::kInherited; } // Content whose transform nodes have a common rendering context ID are 3D @@ -386,7 +376,7 @@ unsigned RenderingContextId() const { return state_.rendering_context_id; } bool HasRenderingContext() const { return state_.rendering_context_id; } - bool IsForSVGChild() const { return state_.flags.is_for_svg_child; } + bool IsForSVGChild() const { return state_.is_for_svg_child; } std::unique_ptr<JSONObject> ToJSON() const;
diff --git a/third_party/blink/renderer/platform/graphics/placeholder_image.cc b/third_party/blink/renderer/platform/graphics/placeholder_image.cc index d82c220..5acbdc4 100644 --- a/third_party/blink/renderer/platform/graphics/placeholder_image.cc +++ b/third_party/blink/renderer/platform/graphics/placeholder_image.cc
@@ -160,36 +160,25 @@ locale.ConvertToLocalizedNumber(numeric_string)); } -} // namespace - -// A simple RefCounted wrapper around a Font, so that multiple PlaceholderImages -// can share the same Font. -class PlaceholderImage::SharedFont : public RefCounted<SharedFont> { +// A simple wrapper around a Font, so that multiple PlaceholderImages can share +// the same Font. +class SharedFont : public GarbageCollected<SharedFont> { public: - static scoped_refptr<SharedFont> GetOrCreateInstance(float scale_factor) { - if (g_instance_) { - scoped_refptr<SharedFont> shared_font(g_instance_); - shared_font->MaybeUpdateForScaleFactor(scale_factor); - return shared_font; - } + SharedFont() + : font_(CreatePlaceholderFontDescription(1.f)), scale_factor_(1.f) {} - scoped_refptr<SharedFont> shared_font = - base::MakeRefCounted<SharedFont>(scale_factor); - g_instance_ = shared_font.get(); - return shared_font; + void Trace(Visitor* visitor) const { visitor->Trace(font_); } + + static SharedFont* Get(float scale_factor) { + DEFINE_STATIC_LOCAL(Persistent<SharedFont>, shared_font, + (MakeGarbageCollected<SharedFont>())); + shared_font->MaybeUpdateForScaleFactor(scale_factor); + return shared_font.Get(); } - // This constructor is public so that base::MakeRefCounted() can call it. - explicit SharedFont(float scale_factor) - : font_(CreatePlaceholderFontDescription(scale_factor)), - scale_factor_(scale_factor) { - } + const Font& font() const { return font_; } - ~SharedFont() { - DCHECK_EQ(this, g_instance_); - g_instance_ = nullptr; - } - + private: void MaybeUpdateForScaleFactor(float scale_factor) { if (scale_factor_ == scale_factor) return; @@ -198,18 +187,11 @@ font_ = Font(CreatePlaceholderFontDescription(scale_factor_)); } - const Font& font() const { return font_; } - - private: - static SharedFont* g_instance_; - Font font_; float scale_factor_; }; -// static -PlaceholderImage::SharedFont* PlaceholderImage::SharedFont::g_instance_ = - nullptr; +} // namespace PlaceholderImage::PlaceholderImage(ImageObserver* observer, const gfx::Size& size, @@ -303,13 +285,10 @@ return; } - if (!shared_font_) - shared_font_ = SharedFont::GetOrCreateInstance(icon_and_text_scale_factor_); - else - shared_font_->MaybeUpdateForScaleFactor(icon_and_text_scale_factor_); + SharedFont* shared_font = SharedFont::Get(icon_and_text_scale_factor_); if (!cached_text_width_.has_value()) - cached_text_width_ = shared_font_->font().Width(TextRun(text_)); + cached_text_width_ = shared_font->font().Width(TextRun(text_)); const float icon_and_text_width = cached_text_width_.value() + @@ -349,7 +328,7 @@ draw_options.sampling_options, icon_and_text_scale_factor_); flags.setColor(SkColorSetARGB(0xAB, 0, 0, 0)); - shared_font_->font().DrawBidiText( + shared_font->font().DrawBidiText( canvas, TextRunPaintInfo(TextRun(text_)), gfx::PointF(text_x, feature_y + icon_and_text_scale_factor_ * (kTextPaddingY + kFontSize)), @@ -371,7 +350,6 @@ void PlaceholderImage::DestroyDecodedData() { paint_record_for_current_frame_.reset(); - shared_font_ = scoped_refptr<SharedFont>(); } Image::SizeAvailability PlaceholderImage::SetData(scoped_refptr<SharedBuffer>, @@ -379,8 +357,8 @@ return Image::kSizeAvailable; } -const Font* PlaceholderImage::GetFontForTesting() const { - return shared_font_ ? &shared_font_->font() : nullptr; +const Font& PlaceholderImage::GetFontForTesting() const { + return SharedFont::Get(icon_and_text_scale_factor_)->font(); } } // namespace blink
diff --git a/third_party/blink/renderer/platform/graphics/placeholder_image.h b/third_party/blink/renderer/platform/graphics/placeholder_image.h index 2ec07399..449c92d 100644 --- a/third_party/blink/renderer/platform/graphics/placeholder_image.h +++ b/third_party/blink/renderer/platform/graphics/placeholder_image.h
@@ -56,7 +56,7 @@ bool IsPlaceholderImage() const override; const String& GetTextForTesting() const { return text_; } - const Font* GetFontForTesting() const; + const Font& GetFontForTesting() const; void SetIconAndTextScaleFactor(float icon_and_text_scale_factor); @@ -83,11 +83,6 @@ float icon_and_text_scale_factor_ = 1.0f; - class SharedFont; - // Lazily initialized. All instances of PlaceholderImage will share the same - // Font object, wrapped as a SharedFont. - scoped_refptr<SharedFont> shared_font_; - // Lazily initialized. absl::optional<float> cached_text_width_; absl::optional<PaintRecord> paint_record_for_current_frame_;
diff --git a/third_party/blink/renderer/platform/graphics/placeholder_image_test.cc b/third_party/blink/renderer/platform/graphics/placeholder_image_test.cc index 59a7b7e..d613081 100644 --- a/third_party/blink/renderer/platform/graphics/placeholder_image_test.cc +++ b/third_party/blink/renderer/platform/graphics/placeholder_image_test.cc
@@ -198,7 +198,7 @@ .WillOnce(InvokeWithoutArgs([&image, scale_factor]() { EXPECT_NEAR( scale_factor * kBaseFontSize, - image.GetFontForTesting()->GetFontDescription().ComputedSize(), + image.GetFontForTesting().GetFontDescription().ComputedSize(), 0.01); })); @@ -454,7 +454,7 @@ .WillOnce(InvokeWithoutArgs([image]() { EXPECT_NEAR( kScaleFactor * kBaseFontSize, - image->GetFontForTesting()->GetFontDescription().ComputedSize(), + image->GetFontForTesting().GetFontDescription().ComputedSize(), 0.01); }));
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5 index 19e7356e..a3b973be 100644 --- a/third_party/blink/renderer/platform/runtime_enabled_features.json5 +++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -418,12 +418,6 @@ { name: "BackfaceVisibilityInterop", }, - // This is a killswitch for the fix for crbug.com/954591 and should be - // removable a few weeks after M120 ships. - { - name: "BackfaceVisibilityNewInheritance", - status: "stable", - }, { name: "BackForwardCache", base_feature: "none",
diff --git a/third_party/blink/tools/BUILD.gn b/third_party/blink/tools/BUILD.gn index ca8f0aea..d91cf6a 100644 --- a/third_party/blink/tools/BUILD.gn +++ b/third_party/blink/tools/BUILD.gn
@@ -34,11 +34,13 @@ "//.vpython3", ] data_deps = [ - ":wpt_tests_mojo_bindings", "//testing:test_scripts_shared", "//third_party/catapult/third_party/typ:typ", "//tools/imagediff", ] + if (!is_ios) { + data_deps += [ ":wpt_tests_mojo_bindings" ] + } if (is_win) { data_deps += [ "//build/win:copy_cdb_to_output" ] } @@ -64,34 +66,38 @@ } } -group("wpt_tests_base_mojo_bindings") { - testonly = true - data_deps = [ - "//:layout_test_data_mojo_bindings", - "//:layout_test_data_mojo_bindings_lite", - "//content/test:mojo_bindings_web_test_mojom_js_data_deps", - "//content/test:mojo_web_test_bindings_js_data_deps", - "//mojo/public/interfaces/bindings/tests:test_data_deps", - "//mojo/public/js/ts/bindings/tests:test_interfaces_js_data_deps", - "//mojo/public/mojom/base:base_js_data_deps", - ] +if (!is_ios) { + group("wpt_tests_base_mojo_bindings") { + testonly = true + data_deps = [ + "//:layout_test_data_mojo_bindings", + "//:layout_test_data_mojo_bindings_lite", + "//content/test:mojo_bindings_web_test_mojom_js_data_deps", + "//content/test:mojo_web_test_bindings_js_data_deps", + "//mojo/public/interfaces/bindings/tests:test_data_deps", + "//mojo/public/js/ts/bindings/tests:test_interfaces_js_data_deps", + "//mojo/public/mojom/base:base_js_data_deps", + ] + } } -group("wpt_tests_mojo_bindings") { - testonly = true - data_deps = [ - ":wpt_tests_base_mojo_bindings", - "//device/bluetooth/public/mojom:fake_bluetooth_interfaces_js_data_deps", - "//device/vr/public/mojom:vr_service_js_data_deps", - "//media/capture/mojom:image_capture_js_data_deps", - "//media/midi:mojo_js_data_deps", - "//services/device/public/mojom:generic_sensor_js_data_deps", - "//services/device/public/mojom:mojom_js_data_deps", - "//services/device/public/mojom:usb_js_data_deps", - "//services/shape_detection/public/mojom:mojom_js_data_deps", - "//skia/public/mojom:mojom_js_data_deps", - "//third_party/blink/public/mojom:mojom_platform_js_data_deps", - ] +if (!is_ios) { + group("wpt_tests_mojo_bindings") { + testonly = true + data_deps = [ + ":wpt_tests_base_mojo_bindings", + "//device/bluetooth/public/mojom:fake_bluetooth_interfaces_js_data_deps", + "//device/vr/public/mojom:vr_service_js_data_deps", + "//media/capture/mojom:image_capture_js_data_deps", + "//media/midi:mojo_js_data_deps", + "//services/device/public/mojom:generic_sensor_js_data_deps", + "//services/device/public/mojom:mojom_js_data_deps", + "//services/device/public/mojom:usb_js_data_deps", + "//services/shape_detection/public/mojom:mojom_js_data_deps", + "//skia/public/mojom:mojom_js_data_deps", + "//third_party/blink/public/mojom:mojom_platform_js_data_deps", + ] + } } group("blink_pytype") {
diff --git a/third_party/blink/web_tests/NeverFixTests b/third_party/blink/web_tests/NeverFixTests index e98d8a9..17407a1f 100644 --- a/third_party/blink/web_tests/NeverFixTests +++ b/third_party/blink/web_tests/NeverFixTests
@@ -2079,6 +2079,64 @@ [ Mac ] external/wpt/webdriver/tests/* [ Skip ] [ Win ] external/wpt/webdriver/tests/* [ Skip ] +# Skip tests that require window.internal and window.testRunner on chrome_wpt_tests +crbug.com/1516468 [ Chrome ] wpt_internal/clipboard-apis/async-navigator-clipboard-events.https.html [ Skip ] +crbug.com/1516468 [ Chrome ] wpt_internal/credential-management/fedcm-3pc-blocked-with-iss-3p-ot.sub.https.html [ Skip ] +crbug.com/1516468 [ Chrome ] wpt_internal/credential-management/fedcm-3pc-blocked-with-iss-ot.https.html [ Skip ] +crbug.com/1516468 [ Chrome ] wpt_internal/css/css-borders/subpixel-border-width-value-recomputed-when-zoom-changes.html [ Skip ] +crbug.com/1516468 [ Chrome ] wpt_internal/css/css-fonts/font-size-adjust-with-zoom.html [ Skip ] +crbug.com/1516468 [ Chrome ] wpt_internal/css/css-fonts/font-size-ex-ch-with-zoom.html [ Skip ] +crbug.com/1516468 [ Chrome ] wpt_internal/css/css-fonts/generic-families/font-family-cursive.html [ Skip ] +crbug.com/1516468 [ Chrome ] wpt_internal/css/css-fonts/generic-families/font-family-fantasy.html [ Skip ] +crbug.com/1516468 [ Chrome ] wpt_internal/css/css-fonts/generic-families/font-family-math.html [ Skip ] +crbug.com/1516468 [ Chrome ] wpt_internal/css/css-fonts/generic-families/font-family-monospace.html [ Skip ] +crbug.com/1516468 [ Chrome ] wpt_internal/css/css-fonts/generic-families/font-family-sans-serif.html [ Skip ] +crbug.com/1516468 [ Chrome ] wpt_internal/css/css-fonts/generic-families/font-family-serif.html [ Skip ] +crbug.com/1516468 [ Chrome ] wpt_internal/css/css-fonts/generic-families/font-family-standard.html [ Skip ] +crbug.com/1516468 [ Chrome ] wpt_internal/css/css-fonts/size-adjust-ex-zoom.html [ Skip ] +crbug.com/1516468 [ Chrome ] wpt_internal/css/css-fonts/variable-opsz-zoom-ref.html [ Skip ] +crbug.com/1516468 [ Chrome ] wpt_internal/css/css-fonts/variable-opsz-zoom-size-adjust-ref.html [ Skip ] +crbug.com/1516468 [ Chrome ] wpt_internal/css/css-fonts/variable-opsz-zoom-size-adjust.html [ Skip ] +crbug.com/1516468 [ Chrome ] wpt_internal/css/css-fonts/variable-opsz-zoom.html [ Skip ] +crbug.com/1516468 [ Chrome ] wpt_internal/encoding/supported-encodings.window.html [ Skip ] +crbug.com/1516468 [ Chrome ] wpt_internal/fenced_frame/ready-state-change-crash.https.html [ Skip ] +crbug.com/1516468 [ Chrome ] wpt_internal/forms/file/file-webkitRelativePath-root.html [ Skip ] +crbug.com/1516468 [ Chrome ] wpt_internal/forms/file/file-webkitRelativePath.html [ Skip ] +crbug.com/1516468 [ Chrome ] wpt_internal/generic-sensor/lose-focus-suspend-readings.https.window.html [ Skip ] +crbug.com/1516468 [ Chrome ] wpt_internal/geolocation-api/getCurrentPosition_visibility.https.html [ Skip ] +crbug.com/1516468 [ Chrome ] wpt_internal/infrastructure/printing-reftest-pages-ref.html [ Skip ] +crbug.com/1516468 [ Chrome ] wpt_internal/infrastructure/printing-reftest-pages.html [ Skip ] +crbug.com/1516468 [ Chrome ] wpt_internal/infrastructure/printing-set-size-ref.html [ Skip ] +crbug.com/1516468 [ Chrome ] wpt_internal/infrastructure/printing-set-size.html [ Skip ] +crbug.com/1516468 [ Chrome ] wpt_internal/long-animation-frame/loaf-ukm.html [ Skip ] +crbug.com/1516468 [ Chrome ] wpt_internal/long-animation-frame/loaf-use-counter.html [ Skip ] +crbug.com/1516468 [ Chrome ] wpt_internal/navigation-api/navigate-from-initial-about-blank-gc.html [ Skip ] +crbug.com/1516468 [ Chrome ] wpt_internal/observable/use-counter.html [ Skip ] +crbug.com/1516468 [ Chrome ] wpt_internal/performance-timeline/performance-user-timing-special-names.html [ Skip ] +crbug.com/1516468 [ Chrome ] wpt_internal/prerender/focus-on-prerendered-window-client.https.html [ Skip ] +crbug.com/1516468 [ Chrome ] wpt_internal/presentation/presentation-onreceiverconnection.https.html [ Skip ] +crbug.com/1516468 [ Chrome ] wpt_internal/reporting/deprecation.html [ Skip ] +crbug.com/1516468 [ Chrome ] wpt_internal/reporting/intervention.html [ Skip ] +crbug.com/1516468 [ Chrome ] wpt_internal/resource-timing/initiator-type-early-hints-preload.h2.window.html [ Skip ] +crbug.com/1516468 [ Chrome ] wpt_internal/shadow-dom/shadow-dom-usecounter.html [ Skip ] +crbug.com/1516468 [ Chrome ] wpt_internal/soft-navigation-heuristics/softnav-after-lcp-paint-zoom-in.tentative.html [ Skip ] +crbug.com/1516468 [ Chrome ] wpt_internal/ukm/ukm-get-metrics.html [ Skip ] +crbug.com/1516468 [ Chrome ] wpt_internal/user-timing/detail-isolated-world.html [ Skip ] +crbug.com/1516468 [ Chrome ] wpt_internal/vibration/vibration-iframe.html [ Skip ] +crbug.com/1516468 [ Chrome ] wpt_internal/view-transition/rtl-vertical-scrollbar-ref.html [ Skip ] +crbug.com/1516468 [ Chrome ] wpt_internal/view-transition/rtl-vertical-scrollbar.html [ Skip ] +crbug.com/1516468 [ Chrome ] wpt_internal/view-transition/snapshot-containing-block-fixed-descendants-ref.html [ Skip ] +crbug.com/1516468 [ Chrome ] wpt_internal/view-transition/snapshot-containing-block-fixed-descendants.html [ Skip ] +crbug.com/1516468 [ Chrome ] wpt_internal/webmidi/add-port.https.html [ Skip ] +crbug.com/1516468 [ Chrome ] wpt_internal/webmidi/permission.https.html [ Skip ] +crbug.com/1516468 [ Chrome ] wpt_internal/webmidi/requestmidiaccess.https.html [ Skip ] +crbug.com/1516468 [ Chrome ] wpt_internal/webmidi/send-system-messages.https.html [ Skip ] +crbug.com/1516468 [ Chrome ] wpt_internal/websocket-cookies/first-party-cookie-accepted.https.html [ Skip ] +crbug.com/1516468 [ Chrome ] wpt_internal/websocket-cookies/third-party-cookie-blocked-on-cross-origin-websocket.https.html [ Skip ] +crbug.com/1516468 [ Chrome ] wpt_internal/websocket-cookies/third-party-cookie-blocked-on-same-origin-websocket.https.html [ Skip ] +crbug.com/1516468 [ Chrome ] wpt_internal/websocket-cookies/third-party-cookie-blocked.https.html [ Skip ] +crbug.com/1516468 [ Chrome ] wpt_internal/webtransport/subresource-filter-disallowed.https.html [ Skip ] + # Bluetooth tests do not work on Chrome [ Chrome ] external/wpt/bluetooth/* [ Skip ] [ Chrome ] wpt_internal/bluetooth/* [ Skip ]
diff --git a/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-audioworklet-interface/audioworkletprocessor-process-frozen-array.https.html b/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-audioworklet-interface/audioworkletprocessor-process-frozen-array.https.html index 33627204..ce0cfa4 100644 --- a/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-audioworklet-interface/audioworkletprocessor-process-frozen-array.https.html +++ b/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-audioworklet-interface/audioworkletprocessor-process-frozen-array.https.html
@@ -43,7 +43,10 @@ if (actual.done) task.done(); }; - sourceNode.connect(workletNode); + // To have valid ArrayBuffers for both input and output, we need + // both connections. + // See: https://github.com/WebAudio/web-audio-api/issues/2566 + sourceNode.connect(workletNode).connect(context.destination); sourceNode.start(); });
diff --git a/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-audioworklet-interface/process-parameters.https-expected.txt b/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-audioworklet-interface/process-parameters.https-expected.txt new file mode 100644 index 0000000..1b44dcd --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-audioworklet-interface/process-parameters.https-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[FAIL] 0 inputs; 3 outputs + assert_equals: outputs[0].length expected 1 but got 0 +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/platform/linux-chrome/external/wpt/attribution-reporting/request-format.sub.https_method=a_expected-eligible=navigation-source-expected.txt b/third_party/blink/web_tests/platform/linux-chrome/external/wpt/attribution-reporting/request-format.sub.https_method=a_expected-eligible=navigation-source-expected.txt deleted file mode 100644 index 1a61401..0000000 --- a/third_party/blink/web_tests/platform/linux-chrome/external/wpt/attribution-reporting/request-format.sub.https_method=a_expected-eligible=navigation-source-expected.txt +++ /dev/null
@@ -1,4 +0,0 @@ -This is a testharness.js-based test. -[FAIL] attributionsrc request has the proper format. - promise_test: Unhandled rejection with value: object "Error: Tried to run in a non-testharness window without a call to set_test_context" -Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/linux-chrome/external/wpt/attribution-reporting/request-format.sub.https_method=open_expected-eligible=navigation-source-expected.txt b/third_party/blink/web_tests/platform/linux-chrome/external/wpt/attribution-reporting/request-format.sub.https_method=open_expected-eligible=navigation-source-expected.txt deleted file mode 100644 index 1a61401..0000000 --- a/third_party/blink/web_tests/platform/linux-chrome/external/wpt/attribution-reporting/request-format.sub.https_method=open_expected-eligible=navigation-source-expected.txt +++ /dev/null
@@ -1,4 +0,0 @@ -This is a testharness.js-based test. -[FAIL] attributionsrc request has the proper format. - promise_test: Unhandled rejection with value: object "Error: Tried to run in a non-testharness window without a call to set_test_context" -Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/linux-chrome/external/wpt/idle-detection/idle-detection-allowed-by-permissions-policy-attribute-redirect-on-load.https.sub-expected.txt b/third_party/blink/web_tests/platform/linux-chrome/external/wpt/idle-detection/idle-detection-allowed-by-permissions-policy-attribute-redirect-on-load.https.sub-expected.txt deleted file mode 100644 index b3eec62cd..0000000 --- a/third_party/blink/web_tests/platform/linux-chrome/external/wpt/idle-detection/idle-detection-allowed-by-permissions-policy-attribute-redirect-on-load.https.sub-expected.txt +++ /dev/null
@@ -1,7 +0,0 @@ -This is a testharness.js-based test. -Harness Error. harness_status.status = 1 , harness_status.message = Error: Tried to run in a non-testharness window without a call to set_test_context -[NOTRUN] Attribute allow="idle-detection" in top-level frame allows same-origin relocation. -[NOTRUN] Attribute allow="idle-detection" in top-level frame allows workers in same-origin relocation. -[NOTRUN] Attribute allow="idle-detection" in top-level frame disallows cross-origin relocation. -[NOTRUN] Attribute allow="idle-detection" in top-level frame disallows workers in cross-origin relocation. -Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/linux-chrome/external/wpt/idle-detection/idle-detection-allowed-by-permissions-policy-attribute.https.sub-expected.txt b/third_party/blink/web_tests/platform/linux-chrome/external/wpt/idle-detection/idle-detection-allowed-by-permissions-policy-attribute.https.sub-expected.txt deleted file mode 100644 index 2c12ad60..0000000 --- a/third_party/blink/web_tests/platform/linux-chrome/external/wpt/idle-detection/idle-detection-allowed-by-permissions-policy-attribute.https.sub-expected.txt +++ /dev/null
@@ -1,7 +0,0 @@ -This is a testharness.js-based test. -Harness Error. harness_status.status = 1 , harness_status.message = Error: Tried to run in a non-testharness window without a call to set_test_context -[NOTRUN] Attribute allow="idle-detection" in top-level frame can be enabled in same-origin iframe using Permissions Policy "idle-detection". -[NOTRUN] Attribute allow="idle-detection" in top-level frame can be enabled in a worker in same-origin iframe using Permissions Policy "idle-detection". -[NOTRUN] Attribute allow="idle-detection" in top-level frame can be enabled in cross-origin iframe using Permissions Policy "idle-detection". -[NOTRUN] Attribute allow="idle-detection" in top-level frame can be enabled in a worker in cross-origin iframe using Permissions Policy "idle-detection". -Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/linux-chrome/external/wpt/idle-detection/idle-detection-allowed-by-permissions-policy.https.sub-expected.txt b/third_party/blink/web_tests/platform/linux-chrome/external/wpt/idle-detection/idle-detection-allowed-by-permissions-policy.https.sub-expected.txt deleted file mode 100644 index c121ec7..0000000 --- a/third_party/blink/web_tests/platform/linux-chrome/external/wpt/idle-detection/idle-detection-allowed-by-permissions-policy.https.sub-expected.txt +++ /dev/null
@@ -1,8 +0,0 @@ -This is a testharness.js-based test. -Harness Error. harness_status.status = 1 , harness_status.message = Error: Tried to run in a non-testharness window without a call to set_test_context -[NOTRUN] Permissions-Policy idle-detection=* explicity set by top-level frame allows the top-level document. -[NOTRUN] Permissions-Policy idle-detection=* explicity set by top-level frame allows same-origin iframes. -[NOTRUN] Permissions-Policy idle-detection=* explicity set by top-level frame allows workers in same-origin iframes. -[NOTRUN] Permissions-Policy idle-detection=* explicity set by top-level frame allows cross-origin iframes. -[NOTRUN] Permissions-Policy idle-detection=* explicity set by top-level frame allows workers in cross-origin iframes. -Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/linux-chrome/external/wpt/idle-detection/idle-detection-default-permissions-policy.https.sub-expected.txt b/third_party/blink/web_tests/platform/linux-chrome/external/wpt/idle-detection/idle-detection-default-permissions-policy.https.sub-expected.txt deleted file mode 100644 index 9f3322b..0000000 --- a/third_party/blink/web_tests/platform/linux-chrome/external/wpt/idle-detection/idle-detection-default-permissions-policy.https.sub-expected.txt +++ /dev/null
@@ -1,6 +0,0 @@ -This is a testharness.js-based test. -Harness Error. harness_status.status = 1 , harness_status.message = Error: Tried to run in a non-testharness window without a call to set_test_context -[NOTRUN] Default "idle-detection" permissions policy "self" allows the top-level document. -[NOTRUN] Default "idle-detection" permissions policy "self" allows same-origin iframes. -[NOTRUN] Default "idle-detection" permissions policy "self" disallows cross-origin iframes. -Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/linux-chrome/external/wpt/idle-detection/idle-detection-detached-frame.https-expected.txt b/third_party/blink/web_tests/platform/linux-chrome/external/wpt/idle-detection/idle-detection-detached-frame.https-expected.txt deleted file mode 100644 index 8de77113..0000000 --- a/third_party/blink/web_tests/platform/linux-chrome/external/wpt/idle-detection/idle-detection-detached-frame.https-expected.txt +++ /dev/null
@@ -1,4 +0,0 @@ -This is a testharness.js-based test. -[FAIL] Using an IdleDetector from a detached frame - promise_test: Unhandled rejection with value: object "Error: Tried to run in a non-testharness window without a call to set_test_context" -Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/linux-chrome/external/wpt/long-animation-frame/tentative/loaf-desired-exec-time-expected.txt b/third_party/blink/web_tests/platform/linux-chrome/external/wpt/long-animation-frame/tentative/loaf-desired-exec-time-expected.txt deleted file mode 100644 index 91723644..0000000 --- a/third_party/blink/web_tests/platform/linux-chrome/external/wpt/long-animation-frame/tentative/loaf-desired-exec-time-expected.txt +++ /dev/null
@@ -1,4 +0,0 @@ -This is a testharness.js-based test. -[FAIL] event-listener entries desiredExecutionStart is the eventTimestamp - promise_test: Unhandled rejection with value: object "Error: Tried to run in a non-testharness window without a call to set_test_context" -Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/linux-chrome/external/wpt/long-animation-frame/tentative/loaf-ui-event-render-start-expected.txt b/third_party/blink/web_tests/platform/linux-chrome/external/wpt/long-animation-frame/tentative/loaf-ui-event-render-start-expected.txt deleted file mode 100644 index 9e9bc0d..0000000 --- a/third_party/blink/web_tests/platform/linux-chrome/external/wpt/long-animation-frame/tentative/loaf-ui-event-render-start-expected.txt +++ /dev/null
@@ -1,5 +0,0 @@ -This is a testharness.js-based test. -[FAIL] UI events should always be before renderStart but still affect blockingDuration - promise_test: Unhandled rejection with value: object "Error: Tried to run in a non-testharness window without a call to set_test_context" -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/clipboard-apis/async-navigator-clipboard-events.https-expected.txt b/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/clipboard-apis/async-navigator-clipboard-events.https-expected.txt deleted file mode 100644 index 91ef9195..0000000 --- a/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/clipboard-apis/async-navigator-clipboard-events.https-expected.txt +++ /dev/null
@@ -1,8 +0,0 @@ -This is a testharness.js-based test. -[FAIL] navigator.clipboard.read() succeeds in paste event - assert_implements: window.internals is required undefined -[FAIL] navigator.clipboard.write() succeeds in cut event - assert_implements: window.internals is required undefined -[FAIL] navigator.clipboard.write() succeeds in copy event - assert_implements: window.internals is required undefined -Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/credential-management/fedcm-3pc-blocked-with-iss-3p-ot.sub.https-expected.txt b/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/credential-management/fedcm-3pc-blocked-with-iss-3p-ot.sub.https-expected.txt deleted file mode 100644 index bb52b12..0000000 --- a/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/credential-management/fedcm-3pc-blocked-with-iss-3p-ot.sub.https-expected.txt +++ /dev/null
@@ -1,3 +0,0 @@ -This is a testharness.js-based test. -Harness Error. harness_status.status = 1 , harness_status.message = Uncaught ReferenceError: testRunner is not defined -Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/credential-management/fedcm-3pc-blocked-with-iss-ot.https-expected.txt b/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/credential-management/fedcm-3pc-blocked-with-iss-ot.https-expected.txt deleted file mode 100644 index bb52b12..0000000 --- a/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/credential-management/fedcm-3pc-blocked-with-iss-ot.https-expected.txt +++ /dev/null
@@ -1,3 +0,0 @@ -This is a testharness.js-based test. -Harness Error. harness_status.status = 1 , harness_status.message = Uncaught ReferenceError: testRunner is not defined -Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/css/css-borders/subpixel-border-width-value-recomputed-when-zoom-changes-expected.txt b/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/css/css-borders/subpixel-border-width-value-recomputed-when-zoom-changes-expected.txt deleted file mode 100644 index 17d6046a..0000000 --- a/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/css/css-borders/subpixel-border-width-value-recomputed-when-zoom-changes-expected.txt +++ /dev/null
@@ -1,4 +0,0 @@ -This is a testharness.js-based test. -[FAIL] Border width responsive to zoom changes - testRunner is not defined -Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/css/css-fonts/font-size-adjust-with-zoom-expected.txt b/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/css/css-fonts/font-size-adjust-with-zoom-expected.txt deleted file mode 100644 index d769c2f..0000000 --- a/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/css/css-fonts/font-size-adjust-with-zoom-expected.txt +++ /dev/null
@@ -1,4 +0,0 @@ -This is a testharness.js-based test. -[FAIL] 1ex equal to the original font-size - 200% page zoom. - assert_true: window.testRunner is required for this test. expected true got false -Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/encoding/supported-encodings.window-expected.txt b/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/encoding/supported-encodings.window-expected.txt deleted file mode 100644 index f5a0dd38a..0000000 --- a/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/encoding/supported-encodings.window-expected.txt +++ /dev/null
@@ -1,3 +0,0 @@ -This is a testharness.js-based test. -Harness Error. harness_status.status = 1 , harness_status.message = Uncaught ReferenceError: internals is not defined -Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/forms/file/file-webkitRelativePath-expected.txt b/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/forms/file/file-webkitRelativePath-expected.txt deleted file mode 100644 index ff954c3c..0000000 --- a/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/forms/file/file-webkitRelativePath-expected.txt +++ /dev/null
@@ -1,4 +0,0 @@ -This is a testharness.js-based test. -[FAIL] webkitRelativePath is relative from the to the parent of the chosen non-root directory - promise_test: Unhandled rejection with value: object "ReferenceError: internals is not defined" -Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/forms/file/file-webkitRelativePath-root-expected.txt b/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/forms/file/file-webkitRelativePath-root-expected.txt deleted file mode 100644 index ed9b74c..0000000 --- a/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/forms/file/file-webkitRelativePath-root-expected.txt +++ /dev/null
@@ -1,4 +0,0 @@ -This is a testharness.js-based test. -[FAIL] webkitRelativePath is relative to the selected root directory - promise_test: Unhandled rejection with value: object "ReferenceError: internals is not defined" -Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/generic-sensor/lose-focus-suspend-readings.https.window-expected.txt b/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/generic-sensor/lose-focus-suspend-readings.https.window-expected.txt deleted file mode 100644 index 3da2b12..0000000 --- a/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/generic-sensor/lose-focus-suspend-readings.https.window-expected.txt +++ /dev/null
@@ -1,4 +0,0 @@ -This is a testharness.js-based test. -[FAIL] Losing focus must cause readings to be suspended - assert_implements: window.internals is required undefined -Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/geolocation-api/getCurrentPosition_visibility.https-expected.txt b/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/geolocation-api/getCurrentPosition_visibility.https-expected.txt deleted file mode 100644 index 9d4eb027..0000000 --- a/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/geolocation-api/getCurrentPosition_visibility.https-expected.txt +++ /dev/null
@@ -1,4 +0,0 @@ -This is a testharness.js-based test. -[FAIL] getCurrentPosition returns after visibilityState changes - promise_test: Unhandled rejection with value: object "ReferenceError: testRunner is not defined" -Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/geolocation-api/watchPosition-page-visibility.https-expected.txt b/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/geolocation-api/watchPosition-page-visibility.https-expected.txt deleted file mode 100644 index 558bbef..0000000 --- a/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/geolocation-api/watchPosition-page-visibility.https-expected.txt +++ /dev/null
@@ -1,5 +0,0 @@ -This is a testharness.js-based test. -Harness Error. harness_status.status = 1 , harness_status.message = Unhandled rejection: testRunner is not defined -[TIMEOUT] Tests that watchPosition does not report position changes when the page is not visible. - Test timed out -Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/long-animation-frame/loaf-ukm-expected.txt b/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/long-animation-frame/loaf-ukm-expected.txt deleted file mode 100644 index b6f2fc9..0000000 --- a/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/long-animation-frame/loaf-ukm-expected.txt +++ /dev/null
@@ -1,4 +0,0 @@ -This is a testharness.js-based test. -[FAIL] UKM recorder should receive LoAF entries - promise_test: Unhandled rejection with value: object "ReferenceError: internals is not defined" -Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/long-animation-frame/loaf-use-counter-expected.txt b/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/long-animation-frame/loaf-use-counter-expected.txt deleted file mode 100644 index 974a91b..0000000 --- a/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/long-animation-frame/loaf-use-counter-expected.txt +++ /dev/null
@@ -1,8 +0,0 @@ -This is a testharness.js-based test. -[FAIL] UseCounter for LoAF should not be triggered for non-loaf types - promise_test: Unhandled rejection with value: object "ReferenceError: internals is not defined" -[FAIL] UseCounter for LoAF requested should be triggered at appropriate times - promise_test: Unhandled rejection with value: object "ReferenceError: internals is not defined" -[FAIL] UseCounter for LoAF observer should be triggered at appropriate times - promise_test: Unhandled rejection with value: object "ReferenceError: internals is not defined" -Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/navigation-api/navigate-from-initial-about-blank-gc-expected.txt b/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/navigation-api/navigate-from-initial-about-blank-gc-expected.txt deleted file mode 100644 index e9716cd..0000000 --- a/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/navigation-api/navigate-from-initial-about-blank-gc-expected.txt +++ /dev/null
@@ -1,4 +0,0 @@ -This is a testharness.js-based test. -[FAIL] navigate() from <iframe> with src="" but still on initial about:blank doesn't cause a crash on GC - promise_test: Unhandled rejection with value: object "ReferenceError: internals is not defined" -Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/observable/use-counter-expected.txt b/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/observable/use-counter-expected.txt deleted file mode 100644 index 75f8596..0000000 --- a/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/observable/use-counter-expected.txt +++ /dev/null
@@ -1,4 +0,0 @@ -This is a testharness.js-based test. -[FAIL] use-counter - internals is not defined -Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/performance-timeline/performance-user-timing-special-names-expected.txt b/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/performance-timeline/performance-user-timing-special-names-expected.txt deleted file mode 100644 index 3c0ce35..0000000 --- a/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/performance-timeline/performance-user-timing-special-names-expected.txt +++ /dev/null
@@ -1,5 +0,0 @@ -This is a testharness.js-based test. -Harness Error. harness_status.status = 1 , harness_status.message = Test named 'Performance measure processes special names that are defined in User Timing API' specified 1 'cleanup' function, and 1 failed. -[FAIL] Performance measure processes special names that are defined in User Timing API - internals is not defined -Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/prerender/focus-on-prerendered-window-client.https-expected.txt b/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/prerender/focus-on-prerendered-window-client.https-expected.txt deleted file mode 100644 index bb52b12..0000000 --- a/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/prerender/focus-on-prerendered-window-client.https-expected.txt +++ /dev/null
@@ -1,3 +0,0 @@ -This is a testharness.js-based test. -Harness Error. harness_status.status = 1 , harness_status.message = Uncaught ReferenceError: testRunner is not defined -Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/presentation/presentation-onreceiverconnection.https-expected.txt b/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/presentation/presentation-onreceiverconnection.https-expected.txt deleted file mode 100644 index 20753658..0000000 --- a/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/presentation/presentation-onreceiverconnection.https-expected.txt +++ /dev/null
@@ -1,4 +0,0 @@ -This is a testharness.js-based test. -[FAIL] Test presentation.receiver.connectionList resolves with incoming connection. - promise_test: Unhandled rejection with value: object "ReferenceError: internals is not defined" -Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/reporting/deprecation-expected.txt b/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/reporting/deprecation-expected.txt deleted file mode 100644 index f855f76..0000000 --- a/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/reporting/deprecation-expected.txt +++ /dev/null
@@ -1,4 +0,0 @@ -This is a testharness.js-based test. -[FAIL] Deprecation reports - internals is not defined -Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/reporting/intervention-expected.txt b/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/reporting/intervention-expected.txt deleted file mode 100644 index 2c39de8a..0000000 --- a/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/reporting/intervention-expected.txt +++ /dev/null
@@ -1,4 +0,0 @@ -This is a testharness.js-based test. -[FAIL] Intervention report - internals is not defined -Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/resource-timing/initiator-type-early-hints-preload.h2.window-expected.txt b/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/resource-timing/initiator-type-early-hints-preload.h2.window-expected.txt deleted file mode 100644 index 2796db94..0000000 --- a/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/resource-timing/initiator-type-early-hints-preload.h2.window-expected.txt +++ /dev/null
@@ -1,4 +0,0 @@ -This is a testharness.js-based test. -[FAIL] Ensure initiatorType is set to 'early-hints' - internals is not defined -Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/shadow-dom/shadow-dom-usecounter-expected.txt b/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/shadow-dom/shadow-dom-usecounter-expected.txt deleted file mode 100644 index 9f09fd2..0000000 --- a/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/shadow-dom/shadow-dom-usecounter-expected.txt +++ /dev/null
@@ -1,4 +0,0 @@ -This is a testharness.js-based test. -[FAIL] Attributes should not be counted in user agent shadow DOM. - internals is not defined -Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/soft-navigation-heuristics/browser-initiated-popstate.tentative-expected.txt b/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/soft-navigation-heuristics/browser-initiated-popstate.tentative-expected.txt deleted file mode 100644 index c800268..0000000 --- a/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/soft-navigation-heuristics/browser-initiated-popstate.tentative-expected.txt +++ /dev/null
@@ -1,5 +0,0 @@ -This is a testharness.js-based test. -Harness Error. harness_status.status = 1 , harness_status.message = Uncaught ReferenceError: testRunner is not defined -[TIMEOUT] A soft navigation that uses a *browser initiated* popstate event is recognized by SoftNavigationHeuristics - Test timed out -Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/ukm/ukm-get-metrics-expected.txt b/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/ukm/ukm-get-metrics-expected.txt deleted file mode 100644 index c740535..0000000 --- a/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/ukm/ukm-get-metrics-expected.txt +++ /dev/null
@@ -1,4 +0,0 @@ -This is a testharness.js-based test. -[FAIL] UKM recorder should receive the Blink.UpdateTime entry - promise_test: Unhandled rejection with value: object "ReferenceError: internals is not defined" -Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/user-timing/detail-isolated-world-expected.txt b/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/user-timing/detail-isolated-world-expected.txt deleted file mode 100644 index ff8b09d..0000000 --- a/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/user-timing/detail-isolated-world-expected.txt +++ /dev/null
@@ -1,4 +0,0 @@ -This is a testharness.js-based test. -[FAIL] A clone should be used in an isolated world, but only one clone - promise_test: Unhandled rejection with value: object "ReferenceError: testRunner is not defined" -Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/webmidi/add-port.https-expected.txt b/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/webmidi/add-port.https-expected.txt deleted file mode 100644 index a2560ed..0000000 --- a/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/webmidi/add-port.https-expected.txt +++ /dev/null
@@ -1,4 +0,0 @@ -This is a testharness.js-based test. -[FAIL] Test if newly connected ports work correctly - internals is not defined -Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/webmidi/permission.https-expected.txt b/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/webmidi/permission.https-expected.txt deleted file mode 100644 index 6a61dac..0000000 --- a/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/webmidi/permission.https-expected.txt +++ /dev/null
@@ -1,4 +0,0 @@ -This is a testharness.js-based test. -[FAIL] sysex permission grants are properly handled - promise_test: Unhandled rejection with value: object "ReferenceError: internals is not defined" -Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/webmidi/requestmidiaccess.https-expected.txt b/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/webmidi/requestmidiaccess.https-expected.txt deleted file mode 100644 index f5a0dd38a..0000000 --- a/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/webmidi/requestmidiaccess.https-expected.txt +++ /dev/null
@@ -1,3 +0,0 @@ -This is a testharness.js-based test. -Harness Error. harness_status.status = 1 , harness_status.message = Uncaught ReferenceError: internals is not defined -Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/webmidi/send-messages.https-expected.txt b/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/webmidi/send-messages.https-expected.txt deleted file mode 100644 index f5a0dd38a..0000000 --- a/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/webmidi/send-messages.https-expected.txt +++ /dev/null
@@ -1,3 +0,0 @@ -This is a testharness.js-based test. -Harness Error. harness_status.status = 1 , harness_status.message = Uncaught ReferenceError: internals is not defined -Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/webmidi/send-system-messages.https-expected.txt b/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/webmidi/send-system-messages.https-expected.txt deleted file mode 100644 index f5a0dd38a..0000000 --- a/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/webmidi/send-system-messages.https-expected.txt +++ /dev/null
@@ -1,3 +0,0 @@ -This is a testharness.js-based test. -Harness Error. harness_status.status = 1 , harness_status.message = Uncaught ReferenceError: internals is not defined -Harness: the test ran to completion.
diff --git a/third_party/breakpad/BUILD.gn b/third_party/breakpad/BUILD.gn index 58169aa6..5fab2687 100644 --- a/third_party/breakpad/BUILD.gn +++ b/third_party/breakpad/BUILD.gn
@@ -428,6 +428,7 @@ script = "scripts/gen_symbol_tools_packager.py" _go_sources = [ "breakpad/src/tools/mac/upload_system_symbols/arch_reader.go", + "breakpad/src/tools/mac/upload_system_symbols/extract.go", "breakpad/src/tools/mac/upload_system_symbols/upload_system_symbols.go", ] _extra_sources = [
diff --git a/third_party/catapult b/third_party/catapult index 73730a0..6fd04d10 160000 --- a/third_party/catapult +++ b/third_party/catapult
@@ -1 +1 @@ -Subproject commit 73730a049e81a4f396f40d5d2b36b5d70ba0ed1c +Subproject commit 6fd04d10d17ae5354fcf53f499c5837e7a438138
diff --git a/third_party/crashpad/README.chromium b/third_party/crashpad/README.chromium index 7689539a..e282e01 100644 --- a/third_party/crashpad/README.chromium +++ b/third_party/crashpad/README.chromium
@@ -2,7 +2,7 @@ Short Name: crashpad URL: https://crashpad.chromium.org/ Version: N/A -Revision: 30b2f4ba38f19b0b4379da721f679621e54d2935 +Revision: 5183bef5f384a0cd390c66b42b273535cb27d4fa License: Apache 2.0 License File: crashpad/LICENSE Security Critical: yes
diff --git a/third_party/crashpad/crashpad/test/win/win_child_process.cc b/third_party/crashpad/crashpad/test/win/win_child_process.cc index d4d9a46..e31a977 100644 --- a/third_party/crashpad/crashpad/test/win/win_child_process.cc +++ b/third_party/crashpad/crashpad/test/win/win_child_process.cc
@@ -44,7 +44,6 @@ ScopedLocalAlloc scoped_args(args); // Take ownership. if (!args) { PLOG(FATAL) << "CommandLineToArgvW"; - return false; } std::string switch_name_with_equals(switch_name);
diff --git a/third_party/depot_tools b/third_party/depot_tools index 39bc04e..6592c25 160000 --- a/third_party/depot_tools +++ b/third_party/depot_tools
@@ -1 +1 @@ -Subproject commit 39bc04eb9f4fbbd05ae68894cc7e1fdbbe17484e +Subproject commit 6592c255249330478d24c29866cc4e5967a7a951
diff --git a/third_party/devtools-frontend-internal b/third_party/devtools-frontend-internal index 528abbe..c06ef13 160000 --- a/third_party/devtools-frontend-internal +++ b/third_party/devtools-frontend-internal
@@ -1 +1 @@ -Subproject commit 528abbe76e1bd38980a1d69fcc103598aac2980a +Subproject commit c06ef133407ac7b84a375b798a1429025bf69d3d
diff --git a/third_party/devtools-frontend/src b/third_party/devtools-frontend/src index 453169c..909e3f2 160000 --- a/third_party/devtools-frontend/src +++ b/third_party/devtools-frontend/src
@@ -1 +1 @@ -Subproject commit 453169c84a1949b2bf28a6a13f711e80db5b2bf8 +Subproject commit 909e3f281caba659131183443d24e087965f22a8
diff --git a/third_party/perfetto b/third_party/perfetto index d1ee2c6..22522e4 160000 --- a/third_party/perfetto +++ b/third_party/perfetto
@@ -1 +1 @@ -Subproject commit d1ee2c6acf48c1042e2d99e9a62e354a72ec6f93 +Subproject commit 22522e4de21d80de5d67311ca1c0f2321f46f2f5
diff --git a/third_party/skia b/third_party/skia index 46e211e..53de7d8 160000 --- a/third_party/skia +++ b/third_party/skia
@@ -1 +1 @@ -Subproject commit 46e211e887401943a5bd029a3a61aa12c792d337 +Subproject commit 53de7d8fa378818d0d528808156563e720fbfb59
diff --git a/third_party/webrtc b/third_party/webrtc index 7cb56f5f..dc48289 160000 --- a/third_party/webrtc +++ b/third_party/webrtc
@@ -1 +1 @@ -Subproject commit 7cb56f5fbd334060cedf343b38a4fba56417b632 +Subproject commit dc48289b46e028e6f64e1f7b4e80585853284cbc
diff --git a/third_party/wpt_tools/README.chromium b/third_party/wpt_tools/README.chromium index 08aa91a6..91e8a7c 100644 --- a/third_party/wpt_tools/README.chromium +++ b/third_party/wpt_tools/README.chromium
@@ -1,7 +1,7 @@ Name: web-platform-tests - Test Suites for Web Platform specifications Short Name: wpt URL: https://github.com/web-platform-tests/wpt/ -Version: 7dac8f99479ebe6835ab0eb38ce242cc0ad6be26 +Version: 60f1bbc36589573c62e4b0e731e1de82f3deb60f License: LICENSES FOR W3C TEST SUITES (https://www.w3.org/Consortium/Legal/2008/03-bsd-license.html) Security Critical: no Shipped: no
diff --git a/third_party/wpt_tools/WPTIncludeList b/third_party/wpt_tools/WPTIncludeList index 8416c9f..838a5ad 100644 --- a/third_party/wpt_tools/WPTIncludeList +++ b/third_party/wpt_tools/WPTIncludeList
@@ -299,6 +299,7 @@ ./tools/webdriver/webdriver/bidi/modules/network.py ./tools/webdriver/webdriver/bidi/modules/script.py ./tools/webdriver/webdriver/bidi/modules/session.py +./tools/webdriver/webdriver/bidi/modules/storage.py ./tools/webdriver/webdriver/bidi/transport.py ./tools/webdriver/webdriver/bidi/undefined.py ./tools/webdriver/webdriver/client.py
diff --git a/third_party/wpt_tools/wpt/tools/ci/requirements_build.txt b/third_party/wpt_tools/wpt/tools/ci/requirements_build.txt index e044376..34baec0 100644 --- a/third_party/wpt_tools/wpt/tools/ci/requirements_build.txt +++ b/third_party/wpt_tools/wpt/tools/ci/requirements_build.txt
@@ -1,5 +1,5 @@ cairocffi==1.6.1 -fonttools==4.39.4 +fonttools==4.47.2 genshi==0.7.7 jinja2==3.1.2 pyyaml==6.0.1
diff --git a/third_party/wpt_tools/wpt/tools/webdriver/webdriver/bidi/client.py b/third_party/wpt_tools/wpt/tools/webdriver/webdriver/bidi/client.py index a9637c9..8f891ff 100644 --- a/third_party/wpt_tools/wpt/tools/webdriver/webdriver/bidi/client.py +++ b/third_party/wpt_tools/wpt/tools/webdriver/webdriver/bidi/client.py
@@ -96,6 +96,7 @@ self.network = modules.Network(self) self.script = modules.Script(self) self.session = modules.Session(self) + self.storage = modules.Storage(self) @property def event_loop(self):
diff --git a/third_party/wpt_tools/wpt/tools/webdriver/webdriver/bidi/modules/__init__.py b/third_party/wpt_tools/wpt/tools/webdriver/webdriver/bidi/modules/__init__.py index acbe117..6f63e85 100644 --- a/third_party/wpt_tools/wpt/tools/webdriver/webdriver/bidi/modules/__init__.py +++ b/third_party/wpt_tools/wpt/tools/webdriver/webdriver/bidi/modules/__init__.py
@@ -6,3 +6,4 @@ from .network import Network from .script import Script from .session import Session +from .storage import Storage
diff --git a/third_party/wpt_tools/wpt/tools/webdriver/webdriver/bidi/modules/network.py b/third_party/wpt_tools/wpt/tools/webdriver/webdriver/bidi/modules/network.py index 073aa63..f0a2a5b 100644 --- a/third_party/wpt_tools/wpt/tools/webdriver/webdriver/bidi/modules/network.py +++ b/third_party/wpt_tools/wpt/tools/webdriver/webdriver/bidi/modules/network.py
@@ -8,6 +8,20 @@ dict.__init__(self, type="password", username=username, password=password) +class NetworkBase64Value(Dict[str, Any]): + def __init__(self, value: str): + dict.__init__(self, type="base64", value=value) + + +class NetworkStringValue(Dict[str, Any]): + def __init__(self, value: str): + dict.__init__(self, type="string", value=value) + + +NetworkBytesValue = Union[NetworkStringValue, NetworkBase64Value] + + + class URLPatternPattern(Dict[str, Any]): def __init__( self,
diff --git a/third_party/wpt_tools/wpt/tools/webdriver/webdriver/bidi/modules/script.py b/third_party/wpt_tools/wpt/tools/webdriver/webdriver/bidi/modules/script.py index f128b0d0..737426a 100644 --- a/third_party/wpt_tools/wpt/tools/webdriver/webdriver/bidi/modules/script.py +++ b/third_party/wpt_tools/wpt/tools/webdriver/webdriver/bidi/modules/script.py
@@ -96,6 +96,7 @@ self, function_declaration: str, arguments: Optional[List[Mapping[str, Any]]] = None, + contexts: Optional[List[str]] = None, sandbox: Optional[str] = None ) -> Mapping[str, Any]: params: MutableMapping[str, Any] = { @@ -104,6 +105,8 @@ if arguments is not None: params["arguments"] = arguments + if contexts is not None: + params["contexts"] = contexts if sandbox is not None: params["sandbox"] = sandbox
diff --git a/third_party/wpt_tools/wpt/tools/webdriver/webdriver/bidi/modules/storage.py b/third_party/wpt_tools/wpt/tools/webdriver/webdriver/bidi/modules/storage.py new file mode 100644 index 0000000..c13b196d --- /dev/null +++ b/third_party/wpt_tools/wpt/tools/webdriver/webdriver/bidi/modules/storage.py
@@ -0,0 +1,68 @@ +from typing import Any, Dict, Mapping, MutableMapping, Optional, Union + +from ._module import BidiModule, command + +from webdriver.bidi.modules.network import NetworkBytesValue + + +class BrowsingContextPartitionDescriptor(Dict[str, Any]): + def __init__(self, context: str): + dict.__init__(self, type="context", context=context) + + +class StorageKeyPartitionDescriptor(Dict[str, Any]): + def __init__(self, user_context: Optional[str] = None, source_origin: Optional[str] = None): + dict.__init__(self, type="storageKey") + if user_context is not None: + self["userContext"] = user_context + if source_origin is not None: + self["sourceOrigin"] = source_origin + + +class PartialCookie(Dict[str, Any]): + def __init__( + self, + name: str, + value: NetworkBytesValue, + domain: str, + path: Optional[str] = None, + http_only: Optional[bool] = None, + secure: Optional[bool] = None, + same_site: Optional[str] = None, + expiry: Optional[int] = None, + ): + dict.__init__(self, name=name, value=value, domain=domain) + if path is not None: + self["path"] = path + if http_only is not None: + self["httpOnly"] = http_only + if secure is not None: + self["secure"] = secure + if same_site is not None: + self["sameSite"] = same_site + if expiry is not None: + self["expiry"] = expiry + + +PartitionDescriptor = Union[StorageKeyPartitionDescriptor, BrowsingContextPartitionDescriptor] + + +class Storage(BidiModule): + + # TODO: extend with `filter`. + @command + def get_cookies(self, partition: Optional[PartitionDescriptor] = None) -> Mapping[str, Any]: + params = {} + if partition is not None: + params["partition"] = partition + return params + + @command + def set_cookie(self, cookie: PartialCookie, partition: Optional[PartitionDescriptor] = None) -> \ + Mapping[str, Any]: + params: MutableMapping[str, Any] = { + 'cookie': cookie, + } + if partition is not None: + params["partition"] = partition + return params
diff --git a/third_party/wpt_tools/wpt/tools/wpt/virtualenv.py b/third_party/wpt_tools/wpt/tools/wpt/virtualenv.py index 742f572..f1fad73 100644 --- a/third_party/wpt_tools/wpt/tools/wpt/virtualenv.py +++ b/third_party/wpt_tools/wpt/tools/wpt/virtualenv.py
@@ -46,7 +46,7 @@ def create(self): if os.path.exists(self.path): - shutil.rmtree(self.path) + shutil.rmtree(self.path, ignore_errors=True) self._working_set = None call(*self.virtualenv, self.path)
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/base.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/base.py index 7ef9c9b..7119c0b0 100644 --- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/base.py +++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/base.py
@@ -89,8 +89,7 @@ def __call__(self, test, result, extra=None): """Convert a JSON result into a (TestResult, [SubtestResult]) tuple""" result_url, status, message, stack, subtest_results = result - assert result_url == test.url, ("Got results from %s, expected %s" % - (result_url, test.url)) + assert result_url == test.url, (f"Got results from {result_url}, expected {test.url}") harness_result = test.result_cls(self.harness_codes[status], message, extra=extra, stack=stack) return (harness_result, [test.subtest_result_cls(st_name, self.test_codes[st_status], st_message, st_stack) @@ -763,8 +762,9 @@ # AttributeError got an obj property in Python 3.10, for older versions we # fall back to looking at the error message. if ((hasattr(e, "obj") and getattr(e, "obj") == self.protocol) or - "'{self.protocol.__class__.__name__}' has no attribute" in str(e)): + f"'{self.protocol.__class__.__name__}' object has no attribute" in str(e)): raise NotImplementedError from e + raise except self.unimplemented_exc: self.logger.warning("Action %s not implemented" % action) self._send_message(cmd_id, "complete", "error", f"Action {action} not implemented")
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/executormarionette.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/executormarionette.py index 4ca15042..21be5e85 100644 --- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/executormarionette.py +++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/executormarionette.py
@@ -88,9 +88,10 @@ def setup(self): self.marionette = self.parent.marionette - def execute_script(self, script, asynchronous=False): + def execute_script(self, script, asynchronous=False, args=None): method = self.marionette.execute_async_script if asynchronous else self.marionette.execute_script - return method(script, new_sandbox=False, sandbox=None) + script_args = args if args is not None else [] + return method(script, script_args=script_args, new_sandbox=False, sandbox=None) def set_timeout(self, timeout): """Set the Marionette script timeout. @@ -986,8 +987,6 @@ if self.protocol.coverage.is_enabled: self.protocol.coverage.reset() - format_map = {"url": strip_server(url)} - protocol.base.execute_script("window.open('about:blank', '%s', 'noopener')" % self.window_id) test_window = protocol.testharness.get_test_window(self.window_id, parent_window, timeout=10 * self.timeout_multiplier) @@ -1001,7 +1000,7 @@ protocol.marionette.navigate(url) while True: result = protocol.base.execute_script( - self.script_resume % format_map, asynchronous=True) + self.script_resume, args=[strip_server(url)], asynchronous=True) if result is None: # This can happen if we get an content process crash return None
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/executorwebdriver.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/executorwebdriver.py index 10b4e4d..05a26bc 100644 --- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/executorwebdriver.py +++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/executorwebdriver.py
@@ -52,9 +52,9 @@ def setup(self): self.webdriver = self.parent.webdriver - def execute_script(self, script, asynchronous=False): + def execute_script(self, script, asynchronous=False, args=None): method = self.webdriver.execute_async_script if asynchronous else self.webdriver.execute_script - return method(script) + return method(script, args=args) def set_timeout(self, timeout): try: @@ -589,8 +589,6 @@ return (test.result_cls(*data), []) def do_testharness(self, protocol, url, timeout): - format_map = {"url": strip_server(url)} - # The previous test may not have closed its old windows (if something # went wrong or if cleanup_after_test was False), so clean up here. parent_window = protocol.testharness.close_old_windows() @@ -610,7 +608,7 @@ while True: result = protocol.base.execute_script( - self.script_resume % format_map, asynchronous=True) + self.script_resume, asynchronous=True, args=[strip_server(url)]) # As of 2019-03-29, WebDriver does not define expected behavior for # cases where the browser crashes during script execution:
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/testharness_webdriver_resume.js b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/testharness_webdriver_resume.js index 36d086c..4e7b630 100644 --- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/testharness_webdriver_resume.js +++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/testharness_webdriver_resume.js
@@ -1,5 +1,5 @@ // We have to set the url here to ensure we get the same escaping as in the harness // and also to handle the case where the test changes the fragment -window.__wptrunner_url = "%(url)s"; +window.__wptrunner_url = arguments[0]; window.__wptrunner_testdriver_callback = arguments[arguments.length - 1]; window.__wptrunner_process_next_event();
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/testdriver-extra.js b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/testdriver-extra.js index 74d5bae..af25bf4 100644 --- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/testdriver-extra.js +++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/testdriver-extra.js
@@ -1,7 +1,6 @@ "use strict"; (function() { - const is_test_context = window.__wptrunner_message_queue !== undefined; const pending = new Map(); let result = null; @@ -15,7 +14,7 @@ return; } - if (is_test_context && data.type === "testdriver-command") { + if (is_test_context() && data.type === "testdriver-command") { const command = data.message; const ctx_id = command.cmd_id; delete command.cmd_id; @@ -37,12 +36,16 @@ pending.delete(cmd_id); const resolver = data.status === "success" ? on_success : on_failure; resolver(data); - if (is_test_context) { + if (is_test_context()) { window.__wptrunner_process_next_event(); } } }); + function is_test_context() { + return window.__wptrunner_message_queue !== undefined; + } + // Code copied from /common/utils.js function rand_int(bits) { if (bits < 1 || bits > 53) { @@ -67,7 +70,7 @@ } function get_window_id(win) { - if (win == window && is_test_context) { + if (win == window && is_test_context()) { return null; } if (!win.__wptrunner_id) { @@ -130,7 +133,7 @@ if (action_msg.context) { action_msg.context = get_window_id(action_msg.context); } - if (is_test_context) { + if (is_test_context()) { cmd_id = window.__wptrunner_message_queue.push(action_msg); } else { if (testharness_context === null) {
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/testrunner.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/testrunner.py index 888731e..63f856d1 100644 --- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/testrunner.py +++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/testrunner.py
@@ -434,7 +434,7 @@ f"and {len(skipped_tests) - 1} others" ) for test in skipped_tests[1:]: - self.logger.debug(f"Test left in the queue: {test[0].id!r}") + self.logger.debug(f"Test left in the queue: {test.id!r}") force_stop = (not isinstance(self.state, RunnerManagerState.stop) or self.state.force_stop)
diff --git a/tools/crates/gnrt/add.rs b/tools/crates/gnrt/add.rs index 252ae14..55021f6 100644 --- a/tools/crates/gnrt/add.rs +++ b/tools/crates/gnrt/add.rs
@@ -8,33 +8,19 @@ use anyhow::{Context, Result}; use std::collections::HashMap; -pub fn add( - args: AddCommandArgs, - tools: &paths::ToolPaths, - paths: &paths::ChromiumPaths, -) -> Result<()> { +pub fn add(args: AddCommandArgs, paths: &paths::ChromiumPaths) -> Result<()> { // Add needs to work with real crates.io, not with our locally vendored // crates. - without_cargo_config_toml(paths, || add_impl(args, tools, paths))?; + without_cargo_config_toml(paths, || add_impl(args, paths))?; println!("Add successful: run gnrt vendor to download new crate versions."); Ok(()) } -fn add_impl( - args: AddCommandArgs, - tools: &paths::ToolPaths, - paths: &paths::ChromiumPaths, -) -> Result<()> { +fn add_impl(args: AddCommandArgs, paths: &paths::ChromiumPaths) -> Result<()> { println!("Updating crates from {}", paths.third_party_cargo_root.display()); - run_cargo_command( - paths.third_party_cargo_root.into(), - "add", - tools, - args.passthrough, - HashMap::new(), - ) - .context("run_cargo_command")?; + run_cargo_command(paths.third_party_cargo_root.into(), "add", args.passthrough, HashMap::new()) + .context("run_cargo_command")?; // Running cargo commands against actual crates.io will put checksum into // the Cargo.lock file, but we don't generate checksums when we download
diff --git a/tools/crates/gnrt/gen.rs b/tools/crates/gnrt/gen.rs index 81a50b5..b0ccf70 100644 --- a/tools/crates/gnrt/gen.rs +++ b/tools/crates/gnrt/gen.rs
@@ -21,23 +21,15 @@ use anyhow::{ensure, format_err, Context, Result}; -pub fn generate( - args: GenCommandArgs, - tools: &paths::ToolPaths, - paths: &paths::ChromiumPaths, -) -> Result<()> { +pub fn generate(args: GenCommandArgs, paths: &paths::ChromiumPaths) -> Result<()> { if args.for_std.is_some() { - generate_for_std(args, tools, paths) + generate_for_std(args, paths) } else { - generate_for_third_party(args, tools, paths) + generate_for_third_party(args, paths) } } -fn generate_for_std( - args: GenCommandArgs, - tools: &paths::ToolPaths, - paths: &paths::ChromiumPaths, -) -> Result<()> { +fn generate_for_std(args: GenCommandArgs, paths: &paths::ChromiumPaths) -> Result<()> { // Load config file, which applies rustenv and cfg flags to some std crates. let config_file_contents = std::fs::read_to_string(paths.std_config_file).unwrap(); let config: config::BuildConfig = toml::de::from_str(&config_file_contents).unwrap(); @@ -105,12 +97,7 @@ // Rust codebase (see // https://github.com/rust-lang/rust/tree/master/library/rustc-std-workspace-core) let mut dependencies = deps::collect_dependencies( - &run_cargo_metadata( - paths.std_fake_root.into(), - tools, - cargo_extra_options, - cargo_extra_env, - )?, + &run_cargo_metadata(paths.std_fake_root.into(), cargo_extra_options, cargo_extra_env)?, Some(vec![config.resolve.root.clone()]), None, &config, @@ -230,11 +217,7 @@ Ok(()) } -fn generate_for_third_party( - args: GenCommandArgs, - tools: &paths::ToolPaths, - paths: &paths::ChromiumPaths, -) -> Result<()> { +fn generate_for_third_party(args: GenCommandArgs, paths: &paths::ChromiumPaths) -> Result<()> { let config_file_contents = std::fs::read_to_string(paths.third_party_config_file).unwrap(); let config: config::BuildConfig = toml::de::from_str(&config_file_contents).unwrap(); @@ -256,7 +239,6 @@ let mut dependencies = deps::collect_dependencies( &run_cargo_metadata( paths.third_party_cargo_root.into(), - tools, cargo_extra_options, HashMap::new(), )?,
diff --git a/tools/crates/gnrt/lib/paths.rs b/tools/crates/gnrt/lib/paths.rs index 97527d6..ab7b280 100644 --- a/tools/crates/gnrt/lib/paths.rs +++ b/tools/crates/gnrt/lib/paths.rs
@@ -9,13 +9,6 @@ use std::io; use std::path::{Path, PathBuf}; -/// Paths to the toolchain tools, if the user specified them. Otherwise they -/// can be found from the user's PATH. -pub struct ToolPaths { - pub rustc: Option<String>, - pub cargo: Option<String>, -} - /// Chromium source tree paths. All members other than `root` are relative to /// `root`. pub struct ChromiumPaths {
diff --git a/tools/crates/gnrt/main.rs b/tools/crates/gnrt/main.rs index 1fde091..284963a 100644 --- a/tools/crates/gnrt/main.rs +++ b/tools/crates/gnrt/main.rs
@@ -17,10 +17,6 @@ #[derive(Debug, Parser)] struct GnrtArgs { - #[arg(long, help = "path to the cargo executable")] - cargo_path: Option<String>, - #[arg(long, help = "path to the rustc executable")] - rustc_path: Option<String>, #[command(subcommand)] command: Command, } @@ -103,13 +99,12 @@ let args = GnrtArgs::parse(); let paths = paths::ChromiumPaths::new().context("Could not find chromium checkout paths")?; - let tools = paths::ToolPaths { cargo: args.cargo_path.clone(), rustc: args.rustc_path.clone() }; match args.command { - Command::Add(args) => add::add(args, &tools, &paths), - Command::Gen(args) => gen::generate(args, &tools, &paths), - Command::Update(args) => update::update(args, &tools, &paths), - Command::Vendor(args) => vendor::vendor(args, &tools, &paths), + Command::Add(args) => add::add(args, &paths), + Command::Gen(args) => gen::generate(args, &paths), + Command::Update(args) => update::update(args, &paths), + Command::Vendor(args) => vendor::vendor(args, &paths), } }
diff --git a/tools/crates/gnrt/update.rs b/tools/crates/gnrt/update.rs index 16fa7caf..efb6b5a 100644 --- a/tools/crates/gnrt/update.rs +++ b/tools/crates/gnrt/update.rs
@@ -8,29 +8,20 @@ use anyhow::{Context, Result}; use std::collections::HashMap; -pub fn update( - args: UpdateCommandArgs, - tools: &paths::ToolPaths, - paths: &paths::ChromiumPaths, -) -> Result<()> { +pub fn update(args: UpdateCommandArgs, paths: &paths::ChromiumPaths) -> Result<()> { // Update needs to work with real crates.io, not with our locally vendored // crates. - without_cargo_config_toml(paths, || update_impl(args, tools, paths))?; + without_cargo_config_toml(paths, || update_impl(args, paths))?; println!("Update successful: run gnrt vendor to download new crate versions."); Ok(()) } -fn update_impl( - args: UpdateCommandArgs, - tools: &paths::ToolPaths, - paths: &paths::ChromiumPaths, -) -> Result<()> { +fn update_impl(args: UpdateCommandArgs, paths: &paths::ChromiumPaths) -> Result<()> { println!("Updating crates from {}", paths.third_party_cargo_root.display()); run_cargo_command( paths.third_party_cargo_root.into(), "update", - tools, args.passthrough, HashMap::new(), )
diff --git a/tools/crates/gnrt/util.rs b/tools/crates/gnrt/util.rs index b25efa9f..f7d621e9 100644 --- a/tools/crates/gnrt/util.rs +++ b/tools/crates/gnrt/util.rs
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -use crate::paths::{ChromiumPaths, ToolPaths}; +use crate::paths::ChromiumPaths; use handlebars::handlebars_helper; use std::collections::HashMap; use std::fs; @@ -91,18 +91,11 @@ /// Run cargo metadata command, optionally with extra flags and environment. pub fn run_cargo_metadata( workspace_path: PathBuf, - tools: &ToolPaths, mut extra_options: Vec<String>, extra_env: HashMap<std::ffi::OsString, std::ffi::OsString>, ) -> Result<cargo_metadata::Metadata> { let mut command = cargo_metadata::MetadataCommand::new(); command.current_dir(workspace_path); - if let Some(cargo_path) = &tools.cargo { - command.cargo_path(cargo_path); - } - if let Some(rustc_path) = &tools.rustc { - command.env("RUSTC", rustc_path); - } // Allow the binary dependency on cxxbridge-cmd. extra_options.push("-Zbindeps".to_string()); @@ -120,18 +113,13 @@ pub fn run_cargo_command( workspace_path: PathBuf, subcommand: &str, - tools: &ToolPaths, extra_options: Vec<String>, extra_env: HashMap<std::ffi::OsString, std::ffi::OsString>, ) -> Result<()> { assert!(subcommand != "metadata"); - let cargo = tools.cargo.as_deref().unwrap_or_else(|| "cargo"); - let mut command = std::process::Command::new(&cargo); + let mut command = std::process::Command::new("cargo"); command.current_dir(workspace_path); - if let Some(rustc_path) = &tools.rustc { - command.env("RUSTC", rustc_path); - } // Allow the binary dependency on cxxbridge-cmd. command.arg("-Zbindeps"); @@ -142,7 +130,7 @@ command.env(k, v); } - log::debug!("invoking cargo {} with:\n`{:?}`", subcommand, cargo); + log::debug!("invoking cargo {}", subcommand); let mut handle = command.spawn().with_context(|| format!("running cargo {}", subcommand))?; let code = handle.wait().context("waiting for cargo process")?; if !code.success() {
diff --git a/tools/crates/gnrt/vendor.rs b/tools/crates/gnrt/vendor.rs index a5c1de5..7539533 100644 --- a/tools/crates/gnrt/vendor.rs +++ b/tools/crates/gnrt/vendor.rs
@@ -21,23 +21,15 @@ use std::collections::{HashMap, HashSet}; use std::path::PathBuf; -pub fn vendor( - args: VendorCommandArgs, - tools: &paths::ToolPaths, - paths: &paths::ChromiumPaths, -) -> Result<()> { +pub fn vendor(args: VendorCommandArgs, paths: &paths::ChromiumPaths) -> Result<()> { // Vendoring needs to work with real crates.io, not with our locally vendored // crates. - without_cargo_config_toml(paths, || vendor_impl(args, tools, paths))?; + without_cargo_config_toml(paths, || vendor_impl(args, paths))?; println!("Vendor successful: run gnrt gen to generate GN rules."); Ok(()) } -fn vendor_impl( - args: VendorCommandArgs, - tools: &paths::ToolPaths, - paths: &paths::ChromiumPaths, -) -> Result<()> { +fn vendor_impl(args: VendorCommandArgs, paths: &paths::ChromiumPaths) -> Result<()> { let config_file_path = paths.third_party_config_file; let config_file_contents = std::fs::read_to_string(config_file_path).unwrap(); let config: config::BuildConfig = toml::de::from_str(&config_file_contents).unwrap(); @@ -59,7 +51,7 @@ println!("Vendoring crates from {}", paths.third_party_cargo_root.display()); let metadata = - run_cargo_metadata(paths.third_party_cargo_root.into(), tools, Vec::new(), HashMap::new()) + run_cargo_metadata(paths.third_party_cargo_root.into(), Vec::new(), HashMap::new()) .context("run_cargo_metadata")?; let packages: HashMap<_, _> = metadata_packages(&metadata)?; let nodes: HashMap<_, _> = metadata_nodes(&metadata);
diff --git a/tools/crates/run_cargo.py b/tools/crates/run_cargo.py new file mode 100755 index 0000000..569ecf9 --- /dev/null +++ b/tools/crates/run_cargo.py
@@ -0,0 +1,59 @@ +#!/usr/bin/env python3 +# Copyright 2024 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +'''Run cargo from the chromium Rust toolchain. + +Arguments are passed through to cargo. + +Should be run from the checkout root (i.e. as `tools/crates/run_cargo.py ...`) +''' + +import argparse +import os +import platform +import subprocess +import sys + +DEFAULT_SYSROOT = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', + '..', 'third_party', 'rust-toolchain') + + +def RunCargo(rust_sysroot, home_dir, cargo_args): + if not os.path.exists(rust_sysroot): + print(f'WARNING: Rust sysroot missing at "{rust_sysroot}"') + + abs_rust_sysroot = os.path.abspath(rust_sysroot) + bin_dir = os.path.join(abs_rust_sysroot, 'bin') + + cargo_env = dict(os.environ) + if home_dir: + cargo_env['CARGO_HOME'] = home_dir + cargo_env['PATH'] = (f'{bin_dir}{os.pathsep}{cargo_env["PATH"]}' + if cargo_env["PATH"] else f'{bin_dir}') + + return subprocess.run([ + 'cargo', + ] + cargo_args, env=cargo_env).returncode + + +def main(): + parser = argparse.ArgumentParser(description='run cargo') + parser.add_argument('--rust-sysroot', + default=DEFAULT_SYSROOT, + help='use cargo and rustc from here') + (args, cargo_args) = parser.parse_known_args() + + if sys.platform == 'darwin' and platform.machine() == 'arm64': + if args.rust_sysroot == 'third_party/rust-toolchain': + args.rust_sysroot = os.path.expanduser( + '~/.rustup/toolchains/nightly-aarch64-apple-darwin') + print('No "cargo" provided in the Chromium toolchain on Mac-ARM. ' + 'Install cargo nightly to ~/.rustup or use --rust-sysroot:') + print("== To install: `rustup install nightly`") + + return RunCargo(args.rust_sysroot, None, cargo_args) + + +if __name__ == '__main__': + sys.exit(main())
diff --git a/tools/crates/run_gnrt.py b/tools/crates/run_gnrt.py index 11a4c69..9e14a75 100755 --- a/tools/crates/run_gnrt.py +++ b/tools/crates/run_gnrt.py
@@ -16,49 +16,25 @@ GNRT_DIR = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'gnrt') GNRT_MANIFEST_PATH = os.path.join(GNRT_DIR, 'Cargo.toml') +from run_cargo import (RunCargo, DEFAULT_SYSROOT) def main(): parser = argparse.ArgumentParser(description='build and run gnrt') parser.add_argument('--rust-sysroot', - default='third_party/rust-toolchain', + default=DEFAULT_SYSROOT, help='use cargo and rustc from here') parser.add_argument('--out-dir', default='out/gnrt', help='put target and cargo home dir here') - parser.add_argument('gnrt_args', - nargs='*', - help='additional arguments to pass to gnrt, e.g. "gen"') - args = parser.parse_args() + (args, gnrt_args) = parser.parse_known_args() - if sys.platform == 'darwin' and platform.machine() == 'arm64': - if args.rust_sysroot == 'third_party/rust-toolchain': - args.rust_sysroot = os.path.expanduser( - '~/.rustup/toolchains/nightly-aarch64-apple-darwin') - print('No "cargo" provided in the Chromium toolchain on Mac-ARM. ' - 'Install cargo nightly to ~/.rustup or use --rust-sysroot:') - print("== To install: `rustup install nightly`") - - exe = '' - if sys.platform == 'win32': - exe = '.exe' - - abs_rust_sysroot = os.path.abspath(args.rust_sysroot) - cargo_bin = os.path.join(abs_rust_sysroot, 'bin', f'cargo{exe}') - rustc_bin = os.path.join(abs_rust_sysroot, 'bin', f'rustc{exe}') - # The paths given to `--config` need to be unix separators. - rustc_bin_unix_style = rustc_bin.replace('\\', '/') - - cargo_env = os.environ - cargo_env['CARGO_HOME'] = os.path.abspath( - os.path.join(args.out_dir, 'cargo_home')) target_dir = os.path.abspath(os.path.join(args.out_dir, 'target')) + home_dir = os.path.abspath(os.path.join(target_dir, 'cargo_home')) - return subprocess.run([ - cargo_bin, '--locked', 'run', '--release', '--manifest-path', - GNRT_MANIFEST_PATH, '--target-dir', target_dir, '--config', - f'build.rustc="{rustc_bin_unix_style}"', '--', - f'--cargo-path={cargo_bin}', f'--rustc-path={rustc_bin}' - ] + args.gnrt_args).returncode + return RunCargo(args.rust_sysroot, home_dir, [ + '--locked', 'run', '--release', '--manifest-path', GNRT_MANIFEST_PATH, + '--target-dir', target_dir, '--' + ] + gnrt_args) if __name__ == '__main__':
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl index 0a263377..3d0e932 100644 --- a/tools/mb/mb_config.pyl +++ b/tools/mb/mb_config.pyl
@@ -943,15 +943,15 @@ ], 'optimization_guide_mac_arm64_rel': [ - 'minimal_symbols', 'optimization_guide', 'reclient', 'release', 'arm64', + 'minimal_symbols', 'ml_internal', 'optimization_guide', 'reclient', 'release', 'arm64', ], 'optimization_guide_rel': [ - 'minimal_symbols', 'optimization_guide', 'reclient', 'release', + 'minimal_symbols', 'ml_internal', 'optimization_guide', 'reclient', 'release', ], 'optimization_guide_x86_rel': [ - 'minimal_symbols', 'optimization_guide', 'reclient', 'release', 'x86', + 'minimal_symbols', 'ml_internal', 'optimization_guide', 'reclient', 'release', 'x86', ], 'release_bot_blink': [ @@ -1337,6 +1337,10 @@ 'gn_args': 'symbol_level=1', }, + 'ml_internal': { + 'gn_args': 'enable_ml_internal=true', + }, + 'no_default_afdo': { 'gn_args': 'clang_use_default_sample_profile=false', },
diff --git a/tools/mb/mb_config_expectations/internal.optimization_guide.json b/tools/mb/mb_config_expectations/internal.optimization_guide.json index a104406..b610e55284 100644 --- a/tools/mb/mb_config_expectations/internal.optimization_guide.json +++ b/tools/mb/mb_config_expectations/internal.optimization_guide.json
@@ -27,6 +27,7 @@ "gn_args": { "build_with_internal_optimization_guide": true, "dcheck_always_on": false, + "enable_ml_internal": true, "is_debug": false, "symbol_level": 1, "use_remoteexec": true @@ -36,6 +37,7 @@ "gn_args": { "build_with_internal_optimization_guide": true, "dcheck_always_on": false, + "enable_ml_internal": true, "is_debug": false, "symbol_level": 1, "target_cpu": "arm64", @@ -46,6 +48,7 @@ "gn_args": { "build_with_internal_optimization_guide": true, "dcheck_always_on": false, + "enable_ml_internal": true, "is_debug": false, "symbol_level": 1, "use_remoteexec": true @@ -55,6 +58,7 @@ "gn_args": { "build_with_internal_optimization_guide": true, "dcheck_always_on": false, + "enable_ml_internal": true, "is_debug": false, "symbol_level": 1, "target_cpu": "x86", @@ -65,6 +69,7 @@ "gn_args": { "build_with_internal_optimization_guide": true, "dcheck_always_on": false, + "enable_ml_internal": true, "is_debug": false, "symbol_level": 1, "use_remoteexec": true
diff --git a/tools/mb/mb_config_expectations/tryserver.internal.optimization_guide.json b/tools/mb/mb_config_expectations/tryserver.internal.optimization_guide.json index fb2fe2a6..0925209 100644 --- a/tools/mb/mb_config_expectations/tryserver.internal.optimization_guide.json +++ b/tools/mb/mb_config_expectations/tryserver.internal.optimization_guide.json
@@ -3,6 +3,7 @@ "gn_args": { "build_with_internal_optimization_guide": true, "dcheck_always_on": false, + "enable_ml_internal": true, "is_debug": false, "symbol_level": 1, "use_remoteexec": true @@ -12,6 +13,7 @@ "gn_args": { "build_with_internal_optimization_guide": true, "dcheck_always_on": false, + "enable_ml_internal": true, "is_debug": false, "symbol_level": 1, "use_remoteexec": true @@ -21,6 +23,7 @@ "gn_args": { "build_with_internal_optimization_guide": true, "dcheck_always_on": false, + "enable_ml_internal": true, "is_debug": false, "symbol_level": 1, "use_remoteexec": true @@ -30,6 +33,7 @@ "gn_args": { "build_with_internal_optimization_guide": true, "dcheck_always_on": false, + "enable_ml_internal": true, "is_debug": false, "symbol_level": 1, "target_cpu": "x86", @@ -40,6 +44,7 @@ "gn_args": { "build_with_internal_optimization_guide": true, "dcheck_always_on": false, + "enable_ml_internal": true, "is_debug": false, "symbol_level": 1, "use_remoteexec": true @@ -73,6 +78,7 @@ "gn_args": { "build_with_internal_optimization_guide": true, "dcheck_always_on": false, + "enable_ml_internal": true, "is_debug": false, "symbol_level": 1, "use_remoteexec": true @@ -82,6 +88,7 @@ "gn_args": { "build_with_internal_optimization_guide": true, "dcheck_always_on": false, + "enable_ml_internal": true, "is_debug": false, "symbol_level": 1, "target_cpu": "arm64", @@ -92,6 +99,7 @@ "gn_args": { "build_with_internal_optimization_guide": true, "dcheck_always_on": false, + "enable_ml_internal": true, "is_debug": false, "symbol_level": 1, "use_remoteexec": true @@ -101,6 +109,7 @@ "gn_args": { "build_with_internal_optimization_guide": true, "dcheck_always_on": false, + "enable_ml_internal": true, "is_debug": false, "symbol_level": 1, "target_cpu": "x86", @@ -111,6 +120,7 @@ "gn_args": { "build_with_internal_optimization_guide": true, "dcheck_always_on": false, + "enable_ml_internal": true, "is_debug": false, "symbol_level": 1, "use_remoteexec": true
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml index 8e7ccbc..53ff78e 100644 --- a/tools/metrics/actions/actions.xml +++ b/tools/metrics/actions/actions.xml
@@ -39707,6 +39707,14 @@ <description>A Tutorial IPH was shown to the user.</description> </action> +<action name="UserEducation.Session.ActivePeriodStart"> + <owner>mickeyburks@chromium.org</owner> + <owner>frizzle-team@google.com</owner> + <description> + Records the starting point of an Active Period in a User Education Session. + </description> +</action> + <action name="UserManager_Cleared_Legacy_User_Prefs"> <owner>mahmadi@chromium.org</owner> <description>
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 21e04887..52576b1 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -22466,6 +22466,7 @@ <int value="-767460914" label="ExperimentalAccessibilityDictationCommands:disabled"/> <int value="-766805224" label="MirroringService:enabled"/> + <int value="-766199617" label="ReadAloudInOverflowMenuInCCT:enabled"/> <int value="-765669184" label="LauncherNudgeShortInterval:disabled"/> <int value="-764463072" label="WebViewMixedContentAutoupgrades:disabled"/> <int value="-764363697" label="OmniboxForceAllowedToBeDefault:disabled"/> @@ -23297,6 +23298,7 @@ <int value="-377883447" label="NtpHistoryClustersModuleDiscounts:disabled"/> <int value="-377215262" label="RenderArcNotificationsByChrome:enabled"/> <int value="-376571345" label="FillingAcrossGroupedSites:enabled"/> + <int value="-375342164" label="SafeBrowsingAsyncRealTimeCheck:disabled"/> <int value="-374657496" label="OmniboxEnableClipboardProvider:enabled"/> <int value="-374423260" label="OmniboxTabSwitchSuggestions:disabled"/> <int value="-373365335" label="JourneysOmniboxAction:disabled"/> @@ -24405,6 +24407,7 @@ <int value="138345654" label="enable-ambient-authentication-in-incognito"/> <int value="138598687" label="HappinessTrackingSurveysForDesktopDevToolsIssuesCookiesSameSite:enabled"/> + <int value="138995035" label="SafeBrowsingAsyncRealTimeCheck:enabled"/> <int value="139569991" label="SharingDeviceExpiration:disabled"/> <int value="139603247" label="AudioHFPMicSRToggle:disabled"/> <int value="140257184" label="ChromeOSAmbientModeNewUrl:enabled"/> @@ -24424,6 +24427,7 @@ <int value="147645817" label="DnsHttpssvc:enabled"/> <int value="147982046" label="OfflineAutoFetch:enabled"/> <int value="148142535" label="ShortcutCustomization:disabled"/> + <int value="148280309" label="ReadAloudInOverflowMenuInCCT:disabled"/> <int value="149272550" label="OmitCorsClientCert:disabled"/> <int value="149336730" label="UseMojoVideoDecoderForPepper:enabled"/> <int value="149914698" label="SearchReadyOmnibox:disabled"/>
diff --git a/tools/metrics/histograms/metadata/accessibility/histograms.xml b/tools/metrics/histograms/metadata/accessibility/histograms.xml index 16f9abe..ae0b94b9 100644 --- a/tools/metrics/histograms/metadata/accessibility/histograms.xml +++ b/tools/metrics/histograms/metadata/accessibility/histograms.xml
@@ -2391,6 +2391,18 @@ </token> </histogram> +<histogram name="Accessibility.ScreenReader.ScrollToImage" enum="Boolean" + expires_after="2024-12-07"> + <owner>dtseng@chromium.org</owner> + <owner>chrome-a11y-core@google.com</owner> + <summary> + Whether the result of a scroll to make visible accessibility action is + performed on an image node. This roughly corresponds to accessibility focus + on an image. Logged from ChromeVox (ChromeOS) and + BrowserAccessibilityManager (non-ChromeOS). + </summary> +</histogram> + <histogram name="Accessibility.VTTContainsStyleBlock" enum="BooleanEnabled" expires_after="2024-08-07"> <owner>evliu@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/android/histograms.xml b/tools/metrics/histograms/metadata/android/histograms.xml index 9ea8059f..2ad0ddc 100644 --- a/tools/metrics/histograms/metadata/android/histograms.xml +++ b/tools/metrics/histograms/metadata/android/histograms.xml
@@ -1875,6 +1875,17 @@ </token> </histogram> +<histogram name="Android.Messages.DismissedWithoutFullyVisible" + enum="MessageIdentifier" expires_after="2024-05-19"> + <owner>lazzzis@chromium.org</owner> + <owner>src/components/messages/OWNERS</owner> + <summary> + Records the message identifier when the message is dismissed without being + fully visible before. This only tracks the case in which message is + dismissed by primary action, secondary action, gesture and timer. + </summary> +</histogram> + <histogram name="Android.Messages.Dismissed{MessageIdentifier}" enum="MessageDismissReason" expires_after="2024-06-30"> <owner>lazzzis@chromium.org</owner> @@ -1937,6 +1948,58 @@ </summary> </histogram> +<histogram name="Android.Messages.Enqueued.{QueueState}" + enum="MessageIdentifier" expires_after="2024-05-19"> + <owner>lazzzis@chromium.org</owner> + <owner>src/components/messages/OWNERS</owner> + <summary> + Records the message identifier when it is enqueued while the queue is + {QueueState}. + </summary> + <token key="QueueState"> + <variant name="Resumed" summary="resumed"/> + <variant name="Suspended" summary="suspended"/> + </token> +</histogram> + +<histogram name="Android.Messages.Enqueued.{ScopeState}" + enum="MessageIdentifier" expires_after="2024-05-19"> + <owner>lazzzis@chromium.org</owner> + <owner>src/components/messages/OWNERS</owner> + <summary> + Records the message identifier when it is enqueued while its associated + scope is {ScopeState}. + </summary> + <token key="ScopeState"> + <variant name="ScopeActive" summary="active"/> + <variant name="ScopeInactive" summary="inactive"/> + </token> +</histogram> + +<histogram name="Android.Messages.Error.FullyVisibleNotInformed" + enum="MessageIdentifier" expires_after="2024-05-19"> + <owner>lazzzis@chromium.org</owner> + <owner>src/components/messages/OWNERS</owner> + <summary> + Records the message identifier at the moment of dismissal if the message has + been fully visible before but the fully visible callback, if set, has never + been invoked. This use the dismissal type as a proxy for message having + become visible, inlcuding primary action, secondary action, gesture and + timer. It is not checked when it is dismissed by reasons, such as + ScopeDestroyed. + </summary> +</histogram> + +<histogram name="Android.Messages.FullyVisible" enum="MessageIdentifier" + expires_after="2024-05-19"> + <owner>lazzzis@chromium.org</owner> + <owner>src/components/messages/OWNERS</owner> + <summary> + Records the message identifier every time it becomes fully visible to users. + Can be recorded multiple times during its lifetime. + </summary> +</histogram> + <histogram name="Android.Messages.Stacking" enum="StackingAnimationType" expires_after="2024-05-19"> <owner>lazzzis@chromium.org</owner> @@ -1968,6 +2031,17 @@ </summary> </histogram> +<histogram name="Android.Messages.Stacking.RequestToFullyShow" + enum="MessageIdentifier" expires_after="2024-05-19"> + <owner>lazzzis@chromium.org</owner> + <owner>src/components/messages/OWNERS</owner> + <summary> + Records the id of front message when the candidate requests to show. The + recorded message is not guranteed to be displayed: it might be blocked by + unready browser control or unintialized container. + </summary> +</histogram> + <histogram name="Android.Messages.Stacking.ThreeStacked" enum="StackingAnimationThreeStackedType" expires_after="2024-05-19"> <owner>lazzzis@chromium.org</owner> @@ -1994,6 +2068,24 @@ </token> </histogram> +<histogram name="Android.Messages.Stacking.{Blocker}" enum="MessageIdentifier" + expires_after="2024-05-19"> + <owner>lazzzis@chromium.org</owner> + <owner>src/components/messages/OWNERS</owner> + <summary> + Records the message identifier of the front message when it is waiting to + trigger the animation because {Blocker}. + </summary> + <token key="Blocker"> + <variant name="BlockedByBrowserControl" + summary="browser controls aren't ready"/> + <variant name="BlockedByContainerInitializing" + summary="container is initializing"/> + <variant name="BlockedByContainerNotInitialized" + summary="container initialization hasn't started"/> + </token> +</histogram> + <histogram name="Android.Messages.TimeToAction.Dismiss{MessageIdentifier}" units="ms" expires_after="2024-06-30"> <owner>lazzzis@chromium.org</owner> @@ -2025,6 +2117,18 @@ <token key="MessageIdentifier" variants="MessageIdentifiers"/> </histogram> +<histogram name="Android.Messages.TimeToFullyShow{MessageIdentifier}" + units="ms" expires_after="2024-06-30"> + <owner>lazzzis@chromium.org</owner> + <owner>src/components/messages/OWNERS</owner> + <summary> + Recorded once per message measuring the duration from the moment it is + enqueued to the first time it becomes fully shown. Recorded when the message + becomes fully shown. + </summary> + <token key="MessageIdentifier" variants="MessageIdentifiers"/> +</histogram> + <histogram name="Android.MultiInstance.MaxInstanceCount" units="instances" expires_after="2024-05-19"> <owner>jinsukkim@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/ash/histograms.xml b/tools/metrics/histograms/metadata/ash/histograms.xml index 25bc07c2..b1d5a233 100644 --- a/tools/metrics/histograms/metadata/ash/histograms.xml +++ b/tools/metrics/histograms/metadata/ash/histograms.xml
@@ -252,6 +252,20 @@ <variant name="Projector" summary="Projector initiated capture mode"/> </variants> +<variants name="SeaPenTemplateName"> + <variant name="Art" summary="Template Art"/> + <variant name="Characters" summary="Template Characters"/> + <variant name="Curious" summary="Template Curious"/> + <variant name="Dreamscapes" summary="Template Dreamscapes"/> + <variant name="Flower" summary="Template Airbrush"/> + <variant name="Landscape" summary="Template Landscape"/> + <variant name="Mineral" summary="Template Minerals"/> + <variant name="Query" summary="Free-form text query"/> + <variant name="Scifi" summary="Template Scifi"/> + <variant name="Terrain" summary="Template Terrain"/> + <variant name="Translucent" summary="Template Translucent"/> +</variants> + <variants name="SnapActionSource"> <variant name="AutoSnapInSplitView" summary="Auto snap a window in split view"/> @@ -6000,6 +6014,17 @@ </summary> </histogram> +<histogram name="Ash.SeaPen.{TemplateName}.UserFeedback" enum="Boolean" + expires_after="2024-12-31"> + <owner>pzliu@google.com</owner> + <owner>assistive-eng@google.com</owner> + <summary> + Record the thumbs up/thumbs down feedback for SeaPen template {TemplateName} + from the user. Emits true if the feedback is positive, false otherwise. + </summary> + <token key="TemplateName" variants="SeaPenTemplateName"/> +</histogram> + <histogram name="Ash.Search.DriveFileSuggestDataValidation.Status" enum="DriveFileSuggestDataValidationStatus" expires_after="2023-08-12"> <owner>andrewxu@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/extensions/histograms.xml b/tools/metrics/histograms/metadata/extensions/histograms.xml index d9801a0..6cd02f4 100644 --- a/tools/metrics/histograms/metadata/extensions/histograms.xml +++ b/tools/metrics/histograms/metadata/extensions/histograms.xml
@@ -1292,6 +1292,18 @@ will generally never be stale and so won't skew the data significantly in the failure case and are therefore mostly comparable."/> + <variant name="ExtensionPersistentPage" + summary="persistent background page. However, unlike for other + contexts that only emit if the the event fired in the + background page of the extension, this will emit for all + events that run in the persistent background page extension + renderer process (background page, tabs, popups, etc.). + Note: this should not be used to perfectly compare against + other contexts like service workers where the above is not + true. But we are presuming that since the other pages that + run in the process are persistent, they will generally never + be stale and so won't skew the data significantly in the + failure case and are therefore mostly comparable."/> <variant name="ExtensionServiceWorker2" summary="service worker. Replaced previous version because values were inconsistent with excluding
diff --git a/tools/metrics/histograms/metadata/feature_engagement/histograms.xml b/tools/metrics/histograms/metadata/feature_engagement/histograms.xml index 75c9fa2b..cad12c38 100644 --- a/tools/metrics/histograms/metadata/feature_engagement/histograms.xml +++ b/tools/metrics/histograms/metadata/feature_engagement/histograms.xml
@@ -736,6 +736,54 @@ </summary> </histogram> +<histogram name="UserEducation.Session.ActivePeriodDuration.Min.Under1Hour" + units="minutes" expires_after="2024-09-21"> + <owner>mickeyburks@chromium.org</owner> + <owner>frizzle-team@google.com</owner> + <summary> + Records the time duration of the Active Period of a User Education Session. + The timer starts when a session starts. The timer is stopped and recorded + when the current session is ended. Resolution is in minutes and the maximum + time recorded in this metric is 1 hour. + </summary> +</histogram> + +<histogram name="UserEducation.Session.ActivePeriodDuration.Min.Under24Hours" + units="minutes" expires_after="2024-09-21"> + <owner>mickeyburks@chromium.org</owner> + <owner>frizzle-team@google.com</owner> + <summary> + Records the time duration of the Active Period of a User Education Session. + The timer starts when a session starts. The timer is stopped and recorded + when the current session is ended. Resolution is in minutes and the maximum + time recorded in this metric is 24 hours. + </summary> +</histogram> + +<histogram name="UserEducation.Session.IdlePeriodDuration.Hr.Under28Days" + units="hours" expires_after="2024-09-21"> + <owner>mickeyburks@chromium.org</owner> + <owner>frizzle-team@google.com</owner> + <summary> + Records the time duration of the Idle Period of a User Education Session. + The timer starts when a session ends. The timer is stopped and recorded when + a new session is started. Resolution in in hours and the maximum time + recorded in this metric is 28 days. + </summary> +</histogram> + +<histogram name="UserEducation.Session.IdlePeriodDuration.Min.Under24Hours" + units="minutes" expires_after="2024-09-21"> + <owner>mickeyburks@chromium.org</owner> + <owner>frizzle-team@google.com</owner> + <summary> + Records the time duration of the Idle Period of a User Education Session. + The timer starts when a session ends. The timer is stopped and recorded when + a new session is started. Resolution is in minutes and the maximum time + recorded in this metric is 24 hours. + </summary> +</histogram> + </histograms> </histogram-configuration>
diff --git a/tools/metrics/histograms/metadata/web_audio/histograms.xml b/tools/metrics/histograms/metadata/web_audio/histograms.xml index 78652df..bf05ed8 100644 --- a/tools/metrics/histograms/metadata/web_audio/histograms.xml +++ b/tools/metrics/histograms/metadata/web_audio/histograms.xml
@@ -141,7 +141,7 @@ </histogram> <histogram name="WebAudio.AudioContextOptions.sampleRate" units="Hz" - expires_after="2024-02-20"> + expires_after="2024-06-30"> <owner>mjwilson@chromium.org</owner> <owner>hongchan@chromium.org</owner> <owner>src/third_party/blink/renderer/modules/webaudio/OWNERS</owner>
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json index 69543c80e..ce1bac5 100644 --- a/tools/perf/core/perfetto_binary_roller/binary_deps.json +++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -6,7 +6,7 @@ }, "win": { "hash": "cec06f972508cb6b34c47e6096cedc4df1b0890e", - "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/44f3100d881b4c96bccadce5eb5b9fc8ee234533/trace_processor_shell.exe" + "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/22522e4de21d80de5d67311ca1c0f2321f46f2f5/trace_processor_shell.exe" }, "linux_arm": { "hash": "b1a376729d0b7aefc4c38db1348d94d068be07f1", @@ -14,7 +14,7 @@ }, "mac": { "hash": "d4fd97f070cb0aaffba0f0071b10f85147ddd8ac", - "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/mac/d1ee2c6acf48c1042e2d99e9a62e354a72ec6f93/trace_processor_shell" + "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/mac/22522e4de21d80de5d67311ca1c0f2321f46f2f5/trace_processor_shell" }, "mac_arm64": { "hash": "8cd6239efb03863974fdc94e5ee004352f999e3a", @@ -22,7 +22,7 @@ }, "linux": { "hash": "c266bf9a41aad99014e5b0b235676e27cd5ee8c6", - "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/d1ee2c6acf48c1042e2d99e9a62e354a72ec6f93/trace_processor_shell" + "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/22522e4de21d80de5d67311ca1c0f2321f46f2f5/trace_processor_shell" } }, "power_profile.sql": {
diff --git a/tools/rust/gnrt_stdlib.py b/tools/rust/gnrt_stdlib.py index 545fc10..f887e56 100755 --- a/tools/rust/gnrt_stdlib.py +++ b/tools/rust/gnrt_stdlib.py
@@ -17,6 +17,10 @@ from build import (RunCommand) from update import (CHROMIUM_DIR) +sys.path.append( + os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'crates')) +from run_cargo import RunCargo + from build_bindgen import (EXE, RUST_BETA_SYSROOT_DIR, InstallRustBetaSysroot) from build_rust import (RustTargetTriple, RUST_SRC_DIR) from update_rust import (RUST_REVISION) @@ -51,22 +55,18 @@ # Build and run gnrt to update the stdlib GN rules. if args.out_dir: - run_gnrt(cargo_bin, rustc_bin, args.out_dir) + run_gnrt(RUST_BETA_SYSROOT_DIR, args.out_dir) else: with tempfile.TemporaryDirectory() as out_dir: - run_gnrt(cargo_bin, rustc_bin, out_dir) + run_gnrt(RUST_BETA_SYSROOT_DIR, out_dir) -def run_gnrt(cargo, rustc, out_dir): - cargo_env = os.environ - cargo_env['CARGO_HOME'] = os.path.abspath( - os.path.join(out_dir, 'cargo_home')) +def run_gnrt(sysroot_dir, out_dir): target_dir = os.path.abspath(os.path.join(out_dir, 'target')) - RunCommand([ - cargo, '--quiet', '--locked', 'run', '--release', '--manifest-path', - GNRT_CARGO_TOML_PATH, f'--target-dir={target_dir}', '--config', - f'build.rustc="{rustc}"', '--', f'--cargo-path={cargo}', - f'--rustc-path={rustc}', 'gen', + home_dir = os.path.join(target_dir, 'cargo_home') + RunCargo(sysroot_dir, home_dir, [ + '--quiet', '--locked', 'run', '--release', '--manifest-path', + GNRT_CARGO_TOML_PATH, f'--target-dir={target_dir}', '--', 'gen', f'--for-std={os.path.relpath(RUST_SRC_DIR, CHROMIUM_DIR)}' ])
diff --git a/tools/traffic_annotation/safe_list.txt b/tools/traffic_annotation/safe_list.txt index afd63b6..8fbda30 100644 --- a/tools/traffic_annotation/safe_list.txt +++ b/tools/traffic_annotation/safe_list.txt
@@ -43,7 +43,6 @@ # Desktop platform specific annotations. missing,components/optimization_guide/core/model_execution/model_execution_fetcher.cc -missing,components/optimization_guide/core/model_quality/model_quality_logs_uploader_service.cc # Android annotations missing fields internal::contact:email, user_data::type, last_reviewed missing_new_fields,missing,android_webview/browser/network_service/aw_proxy_config_monitor.cc
diff --git a/tools/traffic_annotation/summary/annotations.xml b/tools/traffic_annotation/summary/annotations.xml index c545fa4..2e07751 100644 --- a/tools/traffic_annotation/summary/annotations.xml +++ b/tools/traffic_annotation/summary/annotations.xml
@@ -445,4 +445,5 @@ <item id="prewarm_http_disk_cache" added_in_milestone="122" content_hash_code="0797a094" os_list="linux,windows,android,chromeos" file_path="chrome/browser/predictors/lcp_critical_path_predictor/prewarm_http_disk_cache_manager.cc" /> <item id="admin_specified_ppd_fetch" added_in_milestone="122" content_hash_code="009beea1" os_list="chromeos" file_path="chromeos/printing/remote_ppd_fetcher.cc" /> <item id="shopping_list_ui_image_fetcher" added_in_milestone="107" content_hash_code="068247d7" os_list="linux,windows,chromeos" file_path="chrome/browser/ui/commerce/price_tracking_page_action_controller.cc" /> + <item id="model_quality_logging" added_in_milestone="121" content_hash_code="0282aed0" os_list="linux,windows,android,chromeos" file_path="components/optimization_guide/core/model_quality/model_quality_logs_uploader_service.cc" /> </annotations>
diff --git a/tools/traffic_annotation/summary/grouping.xml b/tools/traffic_annotation/summary/grouping.xml index d5ab37e2..8153c33 100644 --- a/tools/traffic_annotation/summary/grouping.xml +++ b/tools/traffic_annotation/summary/grouping.xml
@@ -303,6 +303,7 @@ <annotation id="wallpaper_search_handler_descriptors_fetcher"/> <annotation id="wallpaper_search_handler_inspirations_fetcher"/> <annotation id="wallpaper_search_handler_inspiration_image_downloader"/> + <annotation id="model_quality_logging"/> </sender> </group> <group name="Admin Features" hidden="true">
diff --git a/ui/snapshot/snapshot.h b/ui/snapshot/snapshot.h index 4f4d719..f661046 100644 --- a/ui/snapshot/snapshot.h +++ b/ui/snapshot/snapshot.h
@@ -25,11 +25,6 @@ namespace ui { // DEPRECATED! Use the async calls below. https://crbug.com/1517390 -SNAPSHOT_EXPORT bool GrabWindowSnapshot(gfx::NativeWindow window, - const gfx::Rect& snapshot_bounds, - gfx::Image* image); - -// DEPRECATED! Use the async calls below. https://crbug.com/1517390 SNAPSHOT_EXPORT bool GrabViewSnapshot(gfx::NativeView view, const gfx::Rect& snapshot_bounds, gfx::Image* image);
diff --git a/ui/snapshot/snapshot_android.cc b/ui/snapshot/snapshot_android.cc index 33c5e72..9f858fa 100644 --- a/ui/snapshot/snapshot_android.cc +++ b/ui/snapshot/snapshot_android.cc
@@ -25,12 +25,6 @@ bool GrabViewSnapshot(gfx::NativeView view, const gfx::Rect& snapshot_bounds, gfx::Image* image) { - return GrabWindowSnapshot(view->GetWindowAndroid(), snapshot_bounds, image); -} - -bool GrabWindowSnapshot(gfx::NativeWindow window, - const gfx::Rect& snapshot_bounds, - gfx::Image* image) { return false; }
diff --git a/ui/snapshot/snapshot_aura.cc b/ui/snapshot/snapshot_aura.cc index 20222ed..5160398d 100644 --- a/ui/snapshot/snapshot_aura.cc +++ b/ui/snapshot/snapshot_aura.cc
@@ -101,17 +101,12 @@ } #if !BUILDFLAG(IS_WIN) -bool GrabWindowSnapshot(gfx::NativeWindow window, - const gfx::Rect& snapshot_bounds, - gfx::Image* image) { - // Not supported in Aura. Callers should fall back to the async version. - return false; -} bool GrabViewSnapshot(gfx::NativeView view, const gfx::Rect& snapshot_bounds, gfx::Image* image) { - return GrabWindowSnapshot(view, snapshot_bounds, image); + // Not supported in Aura. Callers should fall back to the async version. + return false; } void GrabWindowSnapshotAndScaleAsync(gfx::NativeWindow window,
diff --git a/ui/snapshot/snapshot_ios.mm b/ui/snapshot/snapshot_ios.mm index e35a9dd1..bba1558 100644 --- a/ui/snapshot/snapshot_ios.mm +++ b/ui/snapshot/snapshot_ios.mm
@@ -47,23 +47,6 @@ return false; } -bool GrabWindowSnapshot(gfx::NativeWindow window, - const gfx::Rect& snapshot_bounds, - gfx::Image* image) { - UIWindow* source_window = window.Get(); - if (source_window == nil) { - return false; - } - - UIImage* snapshot = GetViewSnapshot(source_window.rootViewController.view, - snapshot_bounds.ToCGRect()); - if (snapshot) { - *image = gfx::Image(snapshot); - return true; - } - return false; -} - void GrabViewSnapshotAsync(gfx::NativeView view, const gfx::Rect& source_rect, GrabSnapshotImageCallback callback) { @@ -76,7 +59,16 @@ const gfx::Rect& source_rect, GrabSnapshotImageCallback callback) { gfx::Image image; - GrabWindowSnapshot(window, source_rect, &image); + + UIWindow* source_window = window.Get(); + if (source_window) { + UIImage* snapshot = GetViewSnapshot(source_window.rootViewController.view, + source_rect.ToCGRect()); + if (snapshot) { + image = gfx::Image(snapshot); + } + } + std::move(callback).Run(image); }
diff --git a/ui/snapshot/snapshot_mac.mm b/ui/snapshot/snapshot_mac.mm index 470d2e9..83df3bc 100644 --- a/ui/snapshot/snapshot_mac.mm +++ b/ui/snapshot/snapshot_mac.mm
@@ -53,15 +53,6 @@ return true; } -bool GrabWindowSnapshot(gfx::NativeWindow native_window, - const gfx::Rect& snapshot_bounds, - gfx::Image* image) { - // Make sure to grab the "window frame" view so we get current tab + - // tabstrip. - NSWindow* window = native_window.GetNativeNSWindow(); - return GrabViewSnapshot(window.contentView.superview, snapshot_bounds, image); -} - void GrabWindowSnapshotAsync(gfx::NativeWindow native_window, const gfx::Rect& source_rect, GrabSnapshotImageCallback callback) {
diff --git a/ui/snapshot/snapshot_win.cc b/ui/snapshot/snapshot_win.cc index 90eae7e..06e6043 100644 --- a/ui/snapshot/snapshot_win.cc +++ b/ui/snapshot/snapshot_win.cc
@@ -72,14 +72,6 @@ return true; } -} // namespace - -bool GrabViewSnapshot(gfx::NativeView view_handle, - const gfx::Rect& snapshot_bounds, - gfx::Image* image) { - return GrabWindowSnapshot(view_handle, snapshot_bounds, image); -} - bool GrabWindowSnapshot(gfx::NativeWindow window_handle, const gfx::Rect& snapshot_bounds, gfx::Image* image) { @@ -104,6 +96,14 @@ expanded_window_bounds_in_pixels, image); } +} // namespace + +bool GrabViewSnapshot(gfx::NativeView view_handle, + const gfx::Rect& snapshot_bounds, + gfx::Image* image) { + return GrabWindowSnapshot(view_handle, snapshot_bounds, image); +} + void GrabWindowSnapshotAsync(gfx::NativeWindow window, const gfx::Rect& source_rect, GrabSnapshotImageCallback callback) {
diff --git a/v8 b/v8 index 8f62f79..8e52cbb 160000 --- a/v8 +++ b/v8
@@ -1 +1 @@ -Subproject commit 8f62f791b8aac6b55fd24da89f0397e56fb80210 +Subproject commit 8e52cbb459346bcafde3d1718bedd3ec93bbfdbd