diff --git a/DEPS b/DEPS index 0f257d45..e59ab7c9 100644 --- a/DEPS +++ b/DEPS
@@ -299,11 +299,11 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and whatever else without interference from each other. - 'skia_revision': 'a164720807546097088f7f3aaafaa3abcb76ca7f', + 'skia_revision': '658d34de2b2d7c931797a74a29bfa83406abcf3d', # 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': 'b39d2f97cf09c6a9e07b49329c8be08eb7ea1184', + 'v8_revision': '13a25f01c72fb3e8f467e5ee7752136b86ed9614', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ANGLE # and whatever else without interference from each other. @@ -315,7 +315,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. - 'pdfium_revision': 'bad2c6c8f9549ac9bb0ec4e9e18e7cd2fc9f8d53', + 'pdfium_revision': 'f8963b1c1903358c2cd000d02c4d7074f3836cfe', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling BoringSSL # and whatever else without interference from each other. @@ -326,7 +326,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Fuchsia sdk # and whatever else without interference from each other. - 'fuchsia_version': 'version:11.20230221.0.1', + 'fuchsia_version': 'version:11.20230221.2.1', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling google-toolbox-for-mac # and whatever else without interference from each other. @@ -386,7 +386,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': '628c4c4d103b1c6466f33f9a6ce497435307376a', + 'devtools_frontend_revision': '16124603ab4d4529993ae499e9582185d332eaf6', # 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. @@ -450,7 +450,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling nearby # and whatever else without interference from each other. - 'nearby_revision': 'a977a6bd7c85b417919111bf98c139be782ce6cc', + 'nearby_revision': 'b59ed0b70f86c0dc1496c3145fa114bc38965f51', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling securemessage # and whatever else without interference from each other. @@ -764,7 +764,7 @@ 'src/clank': { 'url': 'https://chrome-internal.googlesource.com/clank/internal/apps.git' + '@' + - '05019a17e835afa456f4fd6e6accb0196d543c08', + '695223e1068af367f337a71c7b0705495c2cf146', 'condition': 'checkout_android and checkout_src_internal', }, @@ -885,7 +885,7 @@ 'packages': [ { 'package': 'chromium/rts/model/windows-amd64', - 'version': '2JIE-BRRHOhSxU-CGPDobqdw0siUDCZjIrNHZigVEKcC', + 'version': 'lzCdoy2dU1rdSMf3suv0OwbFV_lJfXqYPfSZN9WnptAC', }, ], 'dep_type': 'cipd', @@ -991,7 +991,7 @@ 'packages': [ { 'package': 'chromium/third_party/android_build_tools/aapt2', - 'version': 'cbNG7g8Sinh-lsT8hWsU-RyXqLT_uh4jIb1fjCdhrzIC', + 'version': '36NqCian2RIwuM6SFfizdUgKoXyZhy3q6pFfsws0szYC', }, ], 'condition': 'checkout_android', @@ -1024,7 +1024,7 @@ 'packages': [ { 'package': 'chromium/third_party/android_build_tools/lint', - 'version': '6R1spS-Itpxh7oLzwUptWcZyFwQeEH6aFwtkuTo8ROoC', + 'version': 'MSpv-kFDDSPO0SY0dLdHegUJcJT1Yy8cL9r3vlAZ9vkC', }, ], 'condition': 'checkout_android', @@ -1035,7 +1035,7 @@ 'packages': [ { 'package': 'chromium/third_party/android_build_tools/manifest_merger', - 'version': 'EnlN2b-khJhe8B9hSfh7UxvglJXEwWDKaMm4ixhLYTMC', + 'version': 'EbRaK62t9grqlZqL-JTd_zwM4t1u9fm1x4c2rLE0cqQC', }, ], 'condition': 'checkout_android', @@ -1212,7 +1212,7 @@ Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'), 'src/third_party/devtools-frontend-internal': { - 'url': 'https://chrome-internal.googlesource.com/devtools/devtools-internal.git' + '@' + 'aef22f715178521044bb96955acd32e8632b7f0d', + 'url': 'https://chrome-internal.googlesource.com/devtools/devtools-internal.git' + '@' + '499ec7a60ca03f78c80ea8e25a2188cc9838611c', 'condition': 'checkout_src_internal', }, @@ -1684,7 +1684,7 @@ }, 'src/third_party/perfetto': - Var('android_git') + '/platform/external/perfetto.git' + '@' + 'e85c60ec550a5b4f09e5e8efcad6b355f5a7c52d', + Var('android_git') + '/platform/external/perfetto.git' + '@' + '55985e77ff4f3e023d321c7f7236e8cfe098e545', 'src/third_party/perl': { 'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3', @@ -1738,7 +1738,7 @@ 'packages': [ { 'package': 'chromium/third_party/r8', - 'version': 'qGtBu6TtxyR5XNy4cmsslb7c946YtkZF5_QCjVP-wc8C', + 'version': 'PwglNZFRNPkBBXdnY9NfrZFk2ULWDTRxhV9rl2kvkpUC', }, ], 'condition': 'checkout_android',
diff --git a/ash/capture_mode/capture_mode_camera_unittests.cc b/ash/capture_mode/capture_mode_camera_unittests.cc index ac03eab..d79223ae 100644 --- a/ash/capture_mode/capture_mode_camera_unittests.cc +++ b/ash/capture_mode/capture_mode_camera_unittests.cc
@@ -35,6 +35,7 @@ #include "ash/strings/grit/ash_strings.h" #include "ash/style/ash_color_id.h" #include "ash/system/accessibility/autoclick_menu_bubble_controller.h" +#include "ash/system/privacy/privacy_indicators_controller.h" #include "ash/system/privacy/privacy_indicators_tray_item_view.h" #include "ash/system/unified/unified_system_tray.h" #include "ash/test/ash_test_base.h" @@ -63,6 +64,7 @@ #include "ui/gfx/geometry/vector2d.h" #include "ui/gfx/image/image_unittest_util.h" #include "ui/gfx/paint_vector_icon.h" +#include "ui/message_center/message_center.h" #include "ui/views/controls/image_view.h" #include "ui/views/view.h" #include "ui/views/widget/widget.h" @@ -77,6 +79,12 @@ constexpr char kDefaultCameraDisplayName[] = "Default Cam"; constexpr char kDefaultCameraModelId[] = "0def:c000"; +// The app IDs used for the capture mode camera and microphone recording privacy +// indicators. +constexpr char kCameraPrivacyIndicatorId[] = "system-capture-mode-camera"; +constexpr char kMicrophonePrivacyIndicatorId[] = + "system-capture-mode-microphone"; + TestCaptureModeDelegate* GetTestDelegate() { return static_cast<TestCaptureModeDelegate*>( CaptureModeController::Get()->delegate_for_testing()); @@ -3864,17 +3872,8 @@ // Update display size big enough to make sure when capture source is // `kWindow`, the selected window is not system tray. UpdateDisplay("1366x768"); - // Enable autoclick bar. - auto* autoclick_controller = Shell::Get()->autoclick_controller(); - autoclick_controller->SetEnabled(true, /*show_confirmation_dialog=*/false); - Shell::Get() - ->accessibility_controller() - ->GetFeature(A11yFeatureType::kAutoclick) - .SetEnabled(true); - views::Widget* autoclick_bubble_widget = - autoclick_controller->GetMenuBubbleControllerForTesting() - ->GetBubbleWidgetForTesting(); + views::Widget* autoclick_bubble_widget = EnableAndGetAutoClickBubbleWidget(); EXPECT_TRUE(autoclick_bubble_widget->IsVisible()); const gfx::Rect origin_autoclick_bar_bounds = autoclick_bubble_widget->GetWindowBoundsInScreen(); @@ -4529,6 +4528,12 @@ ui::ScopedAnimationDurationScaleMode animation_scale( ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION); + auto* message_center = message_center::MessageCenter::Get(); + auto camera_notification_id = + GetPrivacyIndicatorsNotificationId(kCameraPrivacyIndicatorId); + auto microphone_notification_id = + GetPrivacyIndicatorsNotificationId(kMicrophonePrivacyIndicatorId); + // Initially the session doesn't show any camera preview since the camera // hasn't connected yet. There should be no privacy indicators. StartCaptureSession(CaptureModeSource::kFullscreen, CaptureModeType::kVideo); @@ -4537,13 +4542,20 @@ EXPECT_FALSE(camera_controller->camera_preview_widget()); EXPECT_FALSE(IsCameraIndicatorIconVisible()); EXPECT_FALSE(IsMicrophoneIndicatorIconVisible()); + EXPECT_FALSE(message_center->FindNotificationById(camera_notification_id)); + EXPECT_FALSE( + message_center->FindNotificationById(microphone_notification_id)); - // Once the camera gets connected, the camera privacy indicator icon should - // show. No microphone yet (not until recording starts with audio). + // Once the camera gets connected, the camera privacy indicator + // icon/notification should show. No microphone yet (not until recording + // starts with audio). AddDefaultCamera(); EXPECT_TRUE(camera_controller->camera_preview_widget()); EXPECT_TRUE(IsCameraIndicatorIconVisible()); EXPECT_FALSE(IsMicrophoneIndicatorIconVisible()); + EXPECT_TRUE(message_center->FindNotificationById(camera_notification_id)); + EXPECT_FALSE( + message_center->FindNotificationById(microphone_notification_id)); // If the camera gets disconnected for some reason, the indicator should go // away, and come back once it reconnects again. @@ -4553,16 +4565,29 @@ base::RunLoop().RunUntilIdle(); EXPECT_FALSE(IsCameraIndicatorIconVisible()); EXPECT_FALSE(IsMicrophoneIndicatorIconVisible()); + EXPECT_FALSE(message_center->FindNotificationById(camera_notification_id)); + EXPECT_FALSE( + message_center->FindNotificationById(microphone_notification_id)); + AddDefaultCamera(); EXPECT_TRUE(camera_controller->camera_preview_widget()); EXPECT_TRUE(IsCameraIndicatorIconVisible()); EXPECT_FALSE(IsMicrophoneIndicatorIconVisible()); + EXPECT_TRUE(message_center->FindNotificationById(camera_notification_id)); + EXPECT_FALSE( + message_center->FindNotificationById(microphone_notification_id)); } TEST_F(CaptureModePrivacyIndicatorsTest, DuringRecordingPrivacyIndicators) { ui::ScopedAnimationDurationScaleMode animation_scale( ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION); + auto* message_center = message_center::MessageCenter::Get(); + auto camera_notification_id = + GetPrivacyIndicatorsNotificationId(kCameraPrivacyIndicatorId); + auto microphone_notification_id = + GetPrivacyIndicatorsNotificationId(kMicrophonePrivacyIndicatorId); + // Even with the selected camera present, no indicators will show until the // capture session starts. auto* camera_controller = GetCameraController(); @@ -4571,21 +4596,31 @@ EXPECT_FALSE(camera_controller->camera_preview_widget()); EXPECT_FALSE(IsCameraIndicatorIconVisible()); EXPECT_FALSE(IsMicrophoneIndicatorIconVisible()); + EXPECT_FALSE(message_center->FindNotificationById(camera_notification_id)); + EXPECT_FALSE( + message_center->FindNotificationById(microphone_notification_id)); auto* capture_controller = StartCaptureSession(CaptureModeSource::kFullscreen, CaptureModeType::kVideo); EXPECT_TRUE(camera_controller->camera_preview_widget()); EXPECT_TRUE(IsCameraIndicatorIconVisible()); EXPECT_FALSE(IsMicrophoneIndicatorIconVisible()); + EXPECT_TRUE(message_center->FindNotificationById(camera_notification_id)); + EXPECT_FALSE( + message_center->FindNotificationById(microphone_notification_id)); // When the user selects audio recording, the idicators won't change. // Recording has to start first. capture_controller->EnableAudioRecording(true); EXPECT_FALSE(IsMicrophoneIndicatorIconVisible()); + EXPECT_FALSE( + message_center->FindNotificationById(microphone_notification_id)); StartRecordingFromSource(CaptureModeSource::kFullscreen); EXPECT_TRUE(IsCameraIndicatorIconVisible()); EXPECT_TRUE(IsMicrophoneIndicatorIconVisible()); + EXPECT_TRUE(message_center->FindNotificationById(camera_notification_id)); + EXPECT_TRUE(message_center->FindNotificationById(microphone_notification_id)); // Once recording ends, both indicators should disappear. capture_controller->EndVideoRecording( @@ -4593,6 +4628,9 @@ WaitForCaptureFileToBeSaved(); EXPECT_FALSE(IsCameraIndicatorIconVisible()); EXPECT_FALSE(IsMicrophoneIndicatorIconVisible()); + EXPECT_FALSE(message_center->FindNotificationById(camera_notification_id)); + EXPECT_FALSE( + message_center->FindNotificationById(microphone_notification_id)); } } // namespace ash
diff --git a/ash/capture_mode/capture_mode_controller.cc b/ash/capture_mode/capture_mode_controller.cc index 8c9ddc8..c0d8971 100644 --- a/ash/capture_mode/capture_mode_controller.cc +++ b/ash/capture_mode/capture_mode_controller.cc
@@ -5,6 +5,7 @@ #include "ash/capture_mode/capture_mode_controller.h" #include <utility> +#include <vector> #include "ash/capture_mode/capture_mode_ash_notification_view.h" #include "ash/capture_mode/capture_mode_camera_controller.h" @@ -61,6 +62,7 @@ #include "ui/message_center/public/cpp/notification.h" #include "ui/message_center/public/cpp/notification_delegate.h" #include "ui/snapshot/snapshot.h" +#include "ui/views/widget/widget.h" namespace ash { @@ -797,6 +799,33 @@ return gfx::Rect(); } +std::vector<aura::Window*> +CaptureModeController::GetWindowsForCollisionAvoidance() const { + std::vector<aura::Window*> windows_to_be_avoided; + if (IsActive()) { + aura::Window* capture_bar_window = + capture_mode_session_->capture_mode_bar_widget()->GetNativeWindow(); + windows_to_be_avoided.push_back(capture_bar_window); + } + + auto* camera_preview_widget = camera_controller_->camera_preview_widget(); + if (camera_preview_widget && camera_preview_widget->IsVisible()) { + windows_to_be_avoided.push_back(camera_preview_widget->GetNativeView()); + } + + if (video_recording_watcher_ && + !video_recording_watcher_->is_shutting_down() && + video_recording_watcher_->recording_source() != + CaptureModeSource::kWindow) { + if (auto* key_combo_widget = + video_recording_watcher_->GetKeyComboWidgetIfVisible()) { + windows_to_be_avoided.push_back(key_combo_widget->GetNativeWindow()); + } + } + + return windows_to_be_avoided; +} + void CaptureModeController::OnRecordingEnded( recording::mojom::RecordingStatus status, const gfx::ImageSkia& thumbnail) {
diff --git a/ash/capture_mode/capture_mode_controller.h b/ash/capture_mode/capture_mode_controller.h index 77b69420..717ea75b 100644 --- a/ash/capture_mode/capture_mode_controller.h +++ b/ash/capture_mode/capture_mode_controller.h
@@ -7,6 +7,7 @@ #include <memory> #include <string> +#include <vector> #include "ash/ash_export.h" #include "ash/capture_mode/capture_mode_metrics.h" @@ -245,6 +246,10 @@ // 'kRegion', but in window's coordinate when it is 'kWindow' type. gfx::Rect GetCaptureSurfaceConfineBounds() const; + // Returns the windows that to be avoided for collision with other system + // windows such as the PIP window and the automatic click bubble menu. + std::vector<aura::Window*> GetWindowsForCollisionAvoidance() const; + // recording::mojom::RecordingServiceClient: void OnRecordingEnded(recording::mojom::RecordingStatus status, const gfx::ImageSkia& thumbnail) override;
diff --git a/ash/capture_mode/capture_mode_demo_tools_controller.cc b/ash/capture_mode/capture_mode_demo_tools_controller.cc index 87369a8..0a17a4e 100644 --- a/ash/capture_mode/capture_mode_demo_tools_controller.cc +++ b/ash/capture_mode/capture_mode_demo_tools_controller.cc
@@ -6,7 +6,10 @@ #include <memory> +#include "ash/accessibility/accessibility_controller_impl.h" #include "ash/capture_mode/capture_mode_constants.h" +#include "ash/capture_mode/capture_mode_controller.h" +#include "ash/capture_mode/capture_mode_session.h" #include "ash/capture_mode/capture_mode_util.h" #include "ash/capture_mode/key_combo_view.h" #include "ash/capture_mode/pointer_highlight_layer.h" @@ -47,6 +50,7 @@ constexpr base::TimeDelta kMouseScaleUpDuration = base::Milliseconds(1500); constexpr base::TimeDelta kTouchDownScaleUpDuration = base::Milliseconds(200); constexpr base::TimeDelta kTouchUpScaleUpDuration = base::Milliseconds(1000); +constexpr int kSpaceBetweenKeyComboAndCaptureBar = 8; int GetModifierFlagForKeyCode(ui::KeyboardCode key_code) { switch (key_code) { @@ -173,6 +177,12 @@ void CaptureModeDemoToolsController::RefreshBounds() { if (key_combo_widget_) { key_combo_widget_->SetBounds(CalculateKeyComboWidgetBounds()); + + // Update the autoclick menu bounds and sticky overlay bounds if it collides + // with the bounds of the `key_combo_widget_`. + Shell::Get() + ->accessibility_controller() + ->UpdateFloatingPanelBoundsIfNeeded(); } } @@ -297,9 +307,26 @@ ? confine_bounds.right() - preferred_size.width() - capture_mode::kKeyWidgetBorderPadding : confine_bounds.CenterPoint().x() - preferred_size.width() / 2; - const int key_combo_y = confine_bounds.bottom() - - capture_mode::kKeyWidgetDistanceFromBottom - - preferred_size.height(); + + int key_combo_y = confine_bounds.bottom() - + capture_mode::kKeyWidgetDistanceFromBottom - + preferred_size.height(); + + // Check the existence of capture mode bar and re-calculate `key_combo_y` to + // avoid collision. + auto* capture_mode_controller = CaptureModeController::Get(); + if (capture_mode_controller->IsActive() && + video_recording_watcher_->recording_source() != + CaptureModeSource::kWindow) { + auto* capture_bar_widget = capture_mode_controller->capture_mode_session() + ->capture_mode_bar_widget(); + DCHECK(capture_bar_widget); + key_combo_y = std::min(key_combo_y, + capture_bar_widget->GetWindowBoundsInScreen().y() - + kSpaceBetweenKeyComboAndCaptureBar - + preferred_size.height()); + } + return gfx::Rect(gfx::Point(key_combo_x, key_combo_y), preferred_size); }
diff --git a/ash/capture_mode/capture_mode_demo_tools_controller.h b/ash/capture_mode/capture_mode_demo_tools_controller.h index 2d2a7ff4a..37c027d 100644 --- a/ash/capture_mode/capture_mode_demo_tools_controller.h +++ b/ash/capture_mode/capture_mode_demo_tools_controller.h
@@ -12,6 +12,7 @@ #include "ui/base/ime/text_input_client.h" #include "ui/events/keycodes/keyboard_codes_posix.h" #include "ui/views/widget/unique_widget_ptr.h" +#include "ui/views/widget/widget.h" namespace ui { class KeyEvent; @@ -44,6 +45,10 @@ const CaptureModeDemoToolsController&) = delete; ~CaptureModeDemoToolsController() override; + const views::Widget* key_combo_widget() const { + return key_combo_widget_.get(); + } + // Decides whether to show a helper widget for the `event` or not. void OnKeyEvent(ui::KeyEvent* event); @@ -51,7 +56,7 @@ // grow-and-fade-out animation on it. void PerformMousePressAnimation(const gfx::PointF& event_location_in_window); - // Refreshes the bounds of the key combo viewer. + // Refreshes the bounds of `key_combo_widget_`. void RefreshBounds(); // Decides whether to show the highlight for the touch event or not. @@ -82,7 +87,7 @@ // can not be displayed independently. bool ShouldResetKeyComboWidget() const; - // Resets the `key_combo_widget_` when the `hide_timer_` expires. + // Resets the `key_combo_widget_` when the `key_up_refresh_timer_` expires. void AnimateToResetKeyComboWidget(); void UpdateTextInputType(const ui::TextInputClient* client);
diff --git a/ash/capture_mode/capture_mode_demo_tools_unittests.cc b/ash/capture_mode/capture_mode_demo_tools_unittests.cc index f8bd7c7..85380a3 100644 --- a/ash/capture_mode/capture_mode_demo_tools_unittests.cc +++ b/ash/capture_mode/capture_mode_demo_tools_unittests.cc
@@ -944,6 +944,81 @@ expected_modifier_key_vector); } +// Tests that if a new capture mode session gets triggered by keyboard shortcut +// while in video recording with demo tools on, the bounds of the key combo +// widget will be updated to avoid collision. +TEST_F(CaptureModeDemoToolsTest, KeyComboWidgetDeIntersectsWithCaptureBar) { + UpdateDisplay("800x700"); + CaptureModeController* controller = StartCaptureSession( + CaptureModeSource::kFullscreen, CaptureModeType::kVideo); + controller->EnableDemoTools(true); + StartVideoRecordingImmediately(); + EXPECT_TRUE(controller->is_recording_in_progress()); + CaptureModeDemoToolsController* demo_tools_controller = + GetCaptureModeDemoToolsController(); + EXPECT_TRUE(demo_tools_controller); + CaptureModeDemoToolsTestApi demo_tools_test_api(demo_tools_controller); + + // Start a new capture mode session with keyboard shortcut. + PressAndReleaseKey(ui::VKEY_MEDIA_LAUNCH_APP1, + ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN); + auto* key_combo_widget = demo_tools_test_api.GetKeyComboWidget(); + EXPECT_TRUE(key_combo_widget); + const gfx::Rect original_bounds = key_combo_widget->GetWindowBoundsInScreen(); + + const auto* capture_bar_view = GetCaptureModeBarView(); + EXPECT_TRUE(capture_bar_view); + const auto capture_bar_bounds = capture_bar_view->GetBoundsInScreen(); + const int capture_bar_y = capture_bar_bounds.y(); + EXPECT_LT(capture_bar_y, original_bounds.bottom()); + + PressAndReleaseKey(ui::VKEY_MEDIA_LAUNCH_APP1, + ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN); + key_combo_widget = demo_tools_test_api.GetKeyComboWidget(); + const gfx::Rect new_bounds = key_combo_widget->GetWindowBoundsInScreen(); + EXPECT_GT(capture_bar_y, new_bounds.bottom()); +} + +// Tests that the auto click bar will be repositioned once there is a collision +// with the key combo widget. +TEST_F(CaptureModeDemoToolsTest, KeyComboWidgetDeIntersectsWithAutoClickBar) { + auto* autoclick_bubble_widget = EnableAndGetAutoClickBubbleWidget(); + const gfx::Rect original_auto_click_widget_bounds = + autoclick_bubble_widget->GetWindowBoundsInScreen(); + + CaptureModeController* controller = + StartCaptureSession(CaptureModeSource::kRegion, CaptureModeType::kVideo); + + // Intentionally create a `capture_region` within which the bounds of the key + // combo widget generated will mostly likely to collide with the + // `autoclick_bubble_widget`. + gfx::Rect capture_region = original_auto_click_widget_bounds; + capture_region.Inset(-16); + + controller->SetUserCaptureRegion(capture_region, + /*by_user=*/true); + controller->EnableDemoTools(true); + StartVideoRecordingImmediately(); + + auto* event_generator = GetEventGenerator(); + event_generator->PressKey(ui::VKEY_CONTROL, ui::EF_NONE); + event_generator->PressKey(ui::VKEY_C, ui::EF_NONE); + + CaptureModeDemoToolsTestApi demo_tools_test_api( + GetCaptureModeDemoToolsController()); + auto* key_combo_widget = demo_tools_test_api.GetKeyComboWidget(); + ASSERT_TRUE(key_combo_widget); + const gfx::Rect key_combo_widget_bounds = + key_combo_widget->GetWindowBoundsInScreen(); + EXPECT_TRUE( + key_combo_widget_bounds.Intersects(original_auto_click_widget_bounds)); + + const gfx::Rect new_autoclick_widget_bounds = + autoclick_bubble_widget->GetWindowBoundsInScreen(); + EXPECT_FALSE(key_combo_widget_bounds.Intersects(new_autoclick_widget_bounds)); + controller->EndVideoRecording(EndRecordingReason::kStopRecordingButton); +} + // Tests that the metrics that record if a recording starts with demo tools // feature enabled are recorded correctly in a capture session both in clamshell // and tablet mode.
diff --git a/ash/capture_mode/capture_mode_test_util.cc b/ash/capture_mode/capture_mode_test_util.cc index fc8d57e..a318f3f 100644 --- a/ash/capture_mode/capture_mode_test_util.cc +++ b/ash/capture_mode/capture_mode_test_util.cc
@@ -4,6 +4,9 @@ #include "ash/capture_mode/capture_mode_test_util.h" +#include "ash/accessibility/a11y_feature_type.h" +#include "ash/accessibility/accessibility_controller_impl.h" +#include "ash/accessibility/autoclick/autoclick_controller.h" #include "ash/capture_mode/capture_mode_bar_view.h" #include "ash/capture_mode/capture_mode_controller.h" #include "ash/capture_mode/capture_mode_session_test_api.h" @@ -16,7 +19,7 @@ #include "ash/public/cpp/projector/speech_recognition_availability.h" #include "ash/shell.h" #include "ash/style/icon_button.h" -#include "ash/wm/cursor_manager_chromeos.h" +#include "ash/system/accessibility/autoclick_menu_bubble_controller.h" #include "ash/wm/tablet_mode/tablet_mode_controller_test_api.h" #include "base/files/file_path.h" #include "base/files/file_util.h" @@ -192,6 +195,21 @@ } } +views::Widget* EnableAndGetAutoClickBubbleWidget() { + auto* autoclick_controller = Shell::Get()->autoclick_controller(); + autoclick_controller->SetEnabled(true, /*show_confirmation_dialog=*/false); + Shell::Get() + ->accessibility_controller() + ->GetFeature(A11yFeatureType::kAutoclick) + .SetEnabled(true); + + views::Widget* autoclick_bubble_widget = + autoclick_controller->GetMenuBubbleControllerForTesting() + ->GetBubbleWidgetForTesting(); + EXPECT_TRUE(autoclick_bubble_widget->IsVisible()); + return autoclick_bubble_widget; +} + // ----------------------------------------------------------------------------- // ProjectorCaptureModeIntegrationHelper:
diff --git a/ash/capture_mode/capture_mode_test_util.h b/ash/capture_mode/capture_mode_test_util.h index e846465..92b0ce7c 100644 --- a/ash/capture_mode/capture_mode_test_util.h +++ b/ash/capture_mode/capture_mode_test_util.h
@@ -110,6 +110,10 @@ // Sets the device scale factor for only the first available display. void SetDeviceScaleFactor(float dsf); +// Enables the auto click accessibility feature, and returns the auto click +// bubble widget. +views::Widget* EnableAndGetAutoClickBubbleWidget(); + // Defines a helper class to allow setting up and testing the Projector feature // in multiple test fixtures. Note that this helper initializes the Projector- // related features in its constructor, so test fixtures that use this should
diff --git a/ash/capture_mode/capture_mode_util.cc b/ash/capture_mode/capture_mode_util.cc index 3b3ce5464..519dc25 100644 --- a/ash/capture_mode/capture_mode_util.cc +++ b/ash/capture_mode/capture_mode_util.cc
@@ -504,15 +504,26 @@ void MaybeUpdateCameraPrivacyIndicator(bool camera_on) { if (features::IsPrivacyIndicatorsEnabled()) { - UpdatePrivacyIndicatorsView(kCameraPrivacyIndicatorId, camera_on, - /*is_microphone_used=*/false); + UpdatePrivacyIndicators( + /*app_id=*/kCameraPrivacyIndicatorId, + /*app_name=*/ + l10n_util::GetStringUTF16( + IDS_ASH_STATUS_TRAY_CAPTURE_MODE_BUTTON_LABEL), + camera_on, + /*is_microphone_used=*/false, /*delegate=*/ + base::MakeRefCounted<PrivacyIndicatorsNotificationDelegate>()); } } void MaybeUpdateMicrophonePrivacyIndicator(bool mic_on) { if (features::IsPrivacyIndicatorsEnabled()) { - UpdatePrivacyIndicatorsView(kMicrophonePrivacyIndicatorId, - /*is_camera_used=*/false, mic_on); + UpdatePrivacyIndicators( + /*app_id=*/kMicrophonePrivacyIndicatorId, + /*app_name=*/ + l10n_util::GetStringUTF16( + IDS_ASH_STATUS_TRAY_CAPTURE_MODE_BUTTON_LABEL), + /*is_camera_used=*/false, mic_on, /*delegate=*/ + base::MakeRefCounted<PrivacyIndicatorsNotificationDelegate>()); } }
diff --git a/ash/capture_mode/video_recording_watcher.cc b/ash/capture_mode/video_recording_watcher.cc index a199202..624937e40 100644 --- a/ash/capture_mode/video_recording_watcher.cc +++ b/ash/capture_mode/video_recording_watcher.cc
@@ -42,6 +42,7 @@ #include "ui/gfx/geometry/size_f.h" #include "ui/gfx/native_widget_types.h" #include "ui/gfx/scoped_canvas.h" +#include "ui/views/widget/widget.h" #include "ui/wm/core/coordinate_conversion.h" #include "ui/wm/public/activation_client.h" @@ -327,6 +328,27 @@ } } +gfx::Rect VideoRecordingWatcher::GetEffectivePartialRegionBounds() const { + DCHECK_EQ(recording_source_, CaptureModeSource::kRegion); + // TODO(afakhry): Consider having the region to anchor to the nearest corner, + // so that screen rotation doesn't result in the apparent change of the region + // position. Discussion with PM/UX determined that this is a low priority for + // now. + gfx::Rect result = partial_region_bounds_; + result.AdjustToFit(current_root_->bounds()); + return result; +} + +const views::Widget* VideoRecordingWatcher::GetKeyComboWidgetIfVisible() const { + if (demo_tools_controller_) { + const auto* key_combo_widget = demo_tools_controller_->key_combo_widget(); + if (key_combo_widget && key_combo_widget->IsVisible()) { + return key_combo_widget; + } + } + return nullptr; +} + void VideoRecordingWatcher::OnWindowParentChanged(aura::Window* window, aura::Window* parent) { DCHECK_EQ(window, window_being_recorded_); @@ -588,17 +610,6 @@ : GetCursorLocationInWindow(window_being_recorded_)); } -gfx::Rect VideoRecordingWatcher::GetEffectivePartialRegionBounds() const { - DCHECK_EQ(recording_source_, CaptureModeSource::kRegion); - // TODO(afakhry): Consider having the region to anchor to the nearest corner, - // so that screen rotation doesn't result in the apparent change of the region - // position. Discussion with PM/UX determined that this is a low priority for - // now. - gfx::Rect result = partial_region_bounds_; - result.AdjustToFit(current_root_->bounds()); - return result; -} - bool VideoRecordingWatcher::IsWindowDimmedForTesting( aura::Window* window) const { return dimmers_.contains(window);
diff --git a/ash/capture_mode/video_recording_watcher.h b/ash/capture_mode/video_recording_watcher.h index cddb2de..d5f06beb 100644 --- a/ash/capture_mode/video_recording_watcher.h +++ b/ash/capture_mode/video_recording_watcher.h
@@ -71,6 +71,7 @@ bool is_in_projector_mode() const { return is_in_projector_mode_; } bool should_paint_layer() const { return should_paint_layer_; } bool is_shutting_down() const { return is_shutting_down_; } + CaptureModeSource recording_source() const { return recording_source_; } // Toggles the Projector mode's overlay widget on or off. Can only be called // if |is_in_projector_mode()| is true. @@ -90,6 +91,14 @@ // when recording is in progress. gfx::Rect GetCaptureSurfaceConfineBounds() const; + // Returns the `partial_region_bounds_` clamped to the bounds of the + // `current_root_`. It should only be called if `recording_source_` is + // `kRegion`. + gfx::Rect GetEffectivePartialRegionBounds() const; + + // Returns the `key_combo_widget_` if it is visible. + const views::Widget* GetKeyComboWidgetIfVisible() const; + // aura::WindowObserver: void OnWindowParentChanged(aura::Window* window, aura::Window* parent) override; @@ -136,11 +145,6 @@ // CursorWindowController::Observer: void OnCursorCompositingStateChanged(bool enabled) override; - // Returns the `partial_region_bounds_` clamped to the bounds of the - // `current_root_`. It should only be called if `recording_source_` is - // `kRegion`. - gfx::Rect GetEffectivePartialRegionBounds() const; - bool IsWindowDimmedForTesting(aura::Window* window) const; void BindCursorOverlayForTesting(
diff --git a/ash/clipboard/clipboard_history.cc b/ash/clipboard/clipboard_history.cc index b205494e..4aa9e59 100644 --- a/ash/clipboard/clipboard_history.cc +++ b/ash/clipboard/clipboard_history.cc
@@ -44,6 +44,10 @@ return history_list_; } +std::list<ClipboardHistoryItem>& ClipboardHistory::GetItems() { + return history_list_; +} + void ClipboardHistory::Clear() { history_list_ = std::list<ClipboardHistoryItem>(); for (auto& observer : observers_)
diff --git a/ash/clipboard/clipboard_history.h b/ash/clipboard/clipboard_history.h index 955545ad..5820f4d 100644 --- a/ash/clipboard/clipboard_history.h +++ b/ash/clipboard/clipboard_history.h
@@ -17,7 +17,6 @@ #include "ui/base/clipboard/clipboard_observer.h" namespace ash { - class ScopedClipboardHistoryPauseImpl; namespace clipboard_history_util { @@ -55,6 +54,7 @@ // Returns the list of most recent items. The returned list is sorted by // recency. const std::list<ClipboardHistoryItem>& GetItems() const; + std::list<ClipboardHistoryItem>& GetItems(); // Deletes clipboard history. Does not modify content stored in the clipboard. void Clear(); @@ -73,8 +73,9 @@ base::WeakPtr<ClipboardHistory> GetWeakPtr(); private: - // Friended to allow ScopedClipboardHistoryPauseImpl to `Pause()` and + // Friended to allow `ScopedClipboardHistoryPauseImpl` to `Pause()` and // `Resume()`. + // TODO(b/269470292): Use a `PassKey` for this. friend class ScopedClipboardHistoryPauseImpl; // Ensures that the clipboard buffer contains the same data as the item at the
diff --git a/ash/clipboard/clipboard_history_item.cc b/ash/clipboard/clipboard_history_item.cc index 95e9dd2..e725d01 100644 --- a/ash/clipboard/clipboard_history_item.cc +++ b/ash/clipboard/clipboard_history_item.cc
@@ -6,8 +6,6 @@ #include <vector> -#include "ash/clipboard/clipboard_history_controller_impl.h" -#include "ash/clipboard/clipboard_history_resource_manager.h" #include "ash/clipboard/clipboard_history_util.h" #include "ash/shell.h" #include "ash/style/color_util.h" @@ -22,6 +20,7 @@ #include "ui/base/models/image_model.h" #include "ui/base/webui/web_ui_util.h" #include "ui/color/color_provider_source.h" +#include "ui/gfx/image/image.h" #include "ui/strings/grit/ui_strings.h" namespace ash { @@ -115,7 +114,13 @@ time_copied_(base::Time::Now()), main_format_(clipboard_history_util::CalculateMainFormat(data_).value()), display_format_(CalculateDisplayFormat(main_format_, data_)), - display_text_(DetermineDisplayText(data_)) {} + display_text_(DetermineDisplayText(data_)) { + if (display_format_ == DisplayFormat::kHtml) { + // The `ClipboardHistoryResourceManager` will update this preview once an + // image model is rendered. + html_preview_ = clipboard_history_util::GetHtmlPreviewPlaceholder(); + } +} ClipboardHistoryItem::ClipboardHistoryItem(const ClipboardHistoryItem&) = default; @@ -147,15 +152,9 @@ } break; case DisplayFormat::kHtml: { - // TODO(b/267677307): Make cached image an item field, set and updated - // directly by the resource manager. - const SkBitmap& bitmap = *(Shell::Get() - ->clipboard_history_controller() - ->resource_manager() - ->GetImageModel(*this) - .GetImage() - .ToSkBitmap()); - maybe_url = webui::GetBitmapDataUrl(bitmap); + DCHECK(html_preview_.has_value()); + maybe_url = + webui::GetBitmapDataUrl(*html_preview_->GetImage().ToSkBitmap()); break; } case DisplayFormat::kFile: {
diff --git a/ash/clipboard/clipboard_history_item.h b/ash/clipboard/clipboard_history_item.h index 966b0d5c..b51e2d7 100644 --- a/ash/clipboard/clipboard_history_item.h +++ b/ash/clipboard/clipboard_history_item.h
@@ -12,6 +12,7 @@ #include "base/unguessable_token.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/base/clipboard/clipboard_data.h" +#include "ui/base/models/image_model.h" namespace ash { @@ -54,6 +55,12 @@ const base::Time time_copied() const { return time_copied_; } ui::ClipboardInternalFormat main_format() const { return main_format_; } DisplayFormat display_format() const { return display_format_; } + void set_html_preview(const ui::ImageModel& html_preview) { + html_preview_ = html_preview; + } + const absl::optional<ui::ImageModel>& html_preview() const { + return html_preview_; + } const std::u16string& display_text() const { return display_text_; } private: @@ -74,6 +81,10 @@ // to the user. const DisplayFormat display_format_; + // Cached display image. For HTML items, this will be a placeholder image + // until the preview is ready; for non-HTML items, there will be no value. + absl::optional<ui::ImageModel> html_preview_; + // The text that should be displayed on this item's menu entry. const std::u16string display_text_; };
diff --git a/ash/clipboard/clipboard_history_menu_model_adapter.h b/ash/clipboard/clipboard_history_menu_model_adapter.h index 83cb07f3..d7f086f4 100644 --- a/ash/clipboard/clipboard_history_menu_model_adapter.h +++ b/ash/clipboard/clipboard_history_menu_model_adapter.h
@@ -35,7 +35,8 @@ // Used to show the clipboard history menu, which holds the last few things // copied. -class ASH_EXPORT ClipboardHistoryMenuModelAdapter : views::MenuModelAdapter { +class ASH_EXPORT ClipboardHistoryMenuModelAdapter + : public views::MenuModelAdapter { public: static std::unique_ptr<ClipboardHistoryMenuModelAdapter> Create( ui::SimpleMenuModel::Delegate* delegate,
diff --git a/ash/clipboard/clipboard_history_resource_manager.cc b/ash/clipboard/clipboard_history_resource_manager.cc index 9a7f7b0..def002f 100644 --- a/ash/clipboard/clipboard_history_resource_manager.cc +++ b/ash/clipboard/clipboard_history_resource_manager.cc
@@ -7,81 +7,25 @@ #include <string> #include "ash/clipboard/clipboard_history_item.h" -#include "ash/clipboard/clipboard_history_util.h" #include "ash/display/display_util.h" #include "ash/public/cpp/clipboard_image_model_factory.h" #include "ash/public/cpp/window_tree_host_lookup.h" -#include "ash/resources/vector_icons/vector_icons.h" #include "base/containers/contains.h" -#include "base/containers/cxx20_erase.h" #include "base/functional/bind.h" #include "base/ranges/algorithm.h" -#include "base/stl_util.h" #include "ui/aura/window_tree_host.h" #include "ui/base/clipboard/clipboard_data.h" #include "ui/base/ime/input_method.h" #include "ui/base/ime/text_input_client.h" #include "ui/display/screen.h" -#include "ui/gfx/canvas.h" -#include "ui/gfx/color_palette.h" -#include "ui/gfx/image/canvas_image_source.h" -#include "ui/gfx/paint_vector_icon.h" namespace ash { -namespace { - -constexpr int kPlaceholderImageWidth = 234; -constexpr int kPlaceholderImageHeight = 74; -constexpr int kPlaceholderImageOutlineCornerRadius = 8; -constexpr int kPlaceholderImageSVGSize = 32; - -// Used to draw the UnrenderedHTMLPlaceholderImage, which is shown while HTML is -// rendering. Drawn in order to turn the square and single colored SVG into a -// multicolored rectangle image. -class UnrenderedHTMLPlaceholderImage : public gfx::CanvasImageSource { - public: - UnrenderedHTMLPlaceholderImage() - : gfx::CanvasImageSource( - gfx::Size(kPlaceholderImageWidth, kPlaceholderImageHeight)) {} - UnrenderedHTMLPlaceholderImage(const UnrenderedHTMLPlaceholderImage&) = - delete; - UnrenderedHTMLPlaceholderImage& operator=( - const UnrenderedHTMLPlaceholderImage&) = delete; - ~UnrenderedHTMLPlaceholderImage() override = default; - - // gfx::CanvasImageSource: - void Draw(gfx::Canvas* canvas) override { - cc::PaintFlags flags; - flags.setStyle(cc::PaintFlags::kFill_Style); - flags.setAntiAlias(true); - flags.setColor(gfx::kGoogleGrey100); - canvas->DrawRoundRect( - /*rect=*/{kPlaceholderImageWidth, kPlaceholderImageHeight}, - kPlaceholderImageOutlineCornerRadius, flags); - - flags = cc::PaintFlags(); - flags.setStyle(cc::PaintFlags::kFill_Style); - flags.setAntiAlias(true); - const gfx::ImageSkia center_image = - gfx::CreateVectorIcon(kUnrenderedHtmlPlaceholderIcon, - kPlaceholderImageSVGSize, gfx::kGoogleGrey600); - canvas->DrawImageInt( - center_image, (size().width() - center_image.size().width()) / 2, - (size().height() - center_image.size().height()) / 2, flags); - } -}; - -} // namespace - // ClipboardHistoryResourceManager --------------------------------------------- ClipboardHistoryResourceManager::ClipboardHistoryResourceManager( - const ClipboardHistory* clipboard_history) - : clipboard_history_(clipboard_history), - placeholder_image_model_( - ui::ImageModel::FromImageSkia(gfx::CanvasImageSource::MakeImageSkia< - UnrenderedHTMLPlaceholderImage>())) { + ClipboardHistory* clipboard_history) + : clipboard_history_(clipboard_history) { clipboard_history_->AddObserver(this); } @@ -91,17 +35,6 @@ ClipboardImageModelFactory::Get()->OnShutdown(); } -ui::ImageModel ClipboardHistoryResourceManager::GetImageModel( - const ClipboardHistoryItem& item) const { - // Use a cached image model when possible. - auto cached_image_model = FindCachedImageModelForItem(item); - if (cached_image_model == cached_image_models_.end() || - cached_image_model->image_model.IsEmpty()) { - return placeholder_image_model_; - } - return cached_image_model->image_model; -} - void ClipboardHistoryResourceManager::AddObserver(Observer* observer) const { observers_.AddObserver(observer); } @@ -110,59 +43,66 @@ observers_.RemoveObserver(observer); } -ClipboardHistoryResourceManager::CachedImageModel::CachedImageModel() = default; - -ClipboardHistoryResourceManager::CachedImageModel::CachedImageModel( - const CachedImageModel& other) = default; - -ClipboardHistoryResourceManager::CachedImageModel& -ClipboardHistoryResourceManager::CachedImageModel::operator=( - const CachedImageModel&) = default; - -ClipboardHistoryResourceManager::CachedImageModel::~CachedImageModel() = +ClipboardHistoryResourceManager::ImageModelRequest::ImageModelRequest() = default; -void ClipboardHistoryResourceManager::CacheImageModel( +ClipboardHistoryResourceManager::ImageModelRequest::ImageModelRequest( + const ImageModelRequest& other) = default; + +ClipboardHistoryResourceManager::ImageModelRequest& +ClipboardHistoryResourceManager::ImageModelRequest::operator=( + const ImageModelRequest&) = default; + +ClipboardHistoryResourceManager::ImageModelRequest::~ImageModelRequest() = + default; + +void ClipboardHistoryResourceManager::OnImageModelRendered( const base::UnguessableToken& id, ui::ImageModel image_model) { - auto cached_image_model = base::ConstCastIterator( - cached_image_models_, FindCachedImageModelForId(id)); - if (cached_image_model == cached_image_models_.end()) + auto image_model_request = base::ranges::find( + image_model_requests_, id, + &ClipboardHistoryResourceManager::ImageModelRequest::id); + if (image_model_request == image_model_requests_.end()) { return; + } - cached_image_model->image_model = std::move(image_model); + // Set the HTML preview for each item attached to `id`'s request. + for (auto& item : clipboard_history_->GetItems()) { + if (!base::Contains(image_model_request->clipboard_history_item_ids, + item.id())) { + continue; + } + + DCHECK(item.html_preview().has_value()); + if (item.html_preview().value() != image_model) { + item.set_html_preview(image_model); + } + } for (auto& observer : observers_) { observer.OnCachedImageModelUpdated( - cached_image_model->clipboard_history_item_ids); + image_model_request->clipboard_history_item_ids); } -} -std::vector<ClipboardHistoryResourceManager::CachedImageModel>::const_iterator -ClipboardHistoryResourceManager::FindCachedImageModelForId( - const base::UnguessableToken& id) const { - return base::ranges::find( - cached_image_models_, id, - &ClipboardHistoryResourceManager::CachedImageModel::id); -} - -std::vector<ClipboardHistoryResourceManager::CachedImageModel>::const_iterator -ClipboardHistoryResourceManager::FindCachedImageModelForItem( - const ClipboardHistoryItem& item) const { - return base::ranges::find_if( - cached_image_models_, [&](const auto& cached_image_model) { - return base::Contains(cached_image_model.clipboard_history_item_ids, - item.id()); - }); + image_model_requests_.erase(image_model_request); } void ClipboardHistoryResourceManager::CancelUnfinishedRequests() { - for (const auto& cached_image_model : cached_image_models_) { - if (cached_image_model.image_model.IsEmpty()) - ClipboardImageModelFactory::Get()->CancelRequest(cached_image_model.id); + for (const auto& image_model_request : image_model_requests_) { + ClipboardImageModelFactory::Get()->CancelRequest(image_model_request.id); } } +std::vector<ClipboardHistoryResourceManager::ImageModelRequest>::iterator +ClipboardHistoryResourceManager::GetImageModelRequestForItem( + const ClipboardHistoryItem& item) { + return base::ranges::find_if( + image_model_requests_, [&](const auto& image_model_request) { + return base::Contains(image_model_request.clipboard_history_item_ids, + item.id()); + }); +} + void ClipboardHistoryResourceManager::OnClipboardHistoryItemAdded( const ClipboardHistoryItem& item, bool is_duplicate) { @@ -176,25 +116,31 @@ return; } - const auto& items = clipboard_history_->GetItems(); + auto& items = clipboard_history_->GetItems(); - // See if we have an |existing| item that will render the same as |item|. + // See if we have an `existing` item that will render the same as `item`. auto it = base::ranges::find_if(items, [&](const auto& existing) { return &existing != &item && - !(existing.data().format() & - static_cast<int>(ui::ClipboardInternalFormat::kPng)) && + existing.display_format() == + ClipboardHistoryItem::DisplayFormat::kHtml && existing.data().markup_data() == item.data().markup_data(); }); - // If we don't have an existing image model in the cache, create one and - // instruct ClipboardImageModelFactory to render it. Note that the factory may + // If no existing item will render the same as `item`, create a new request to + // render an HTML preview for `item`. Note that the image model factory may // or may not start rendering immediately depending on its activation status. if (it == items.end()) { base::UnguessableToken id = base::UnguessableToken::Create(); - CachedImageModel cached_image_model; - cached_image_model.id = id; - cached_image_model.clipboard_history_item_ids.push_back(item.id()); - cached_image_models_.push_back(std::move(cached_image_model)); + ImageModelRequest image_model_request; + image_model_request.id = id; + image_model_request.clipboard_history_item_ids.push_back(item.id()); + image_model_requests_.push_back(std::move(image_model_request)); + + // `image_model_factory` can be nullptr in tests. + auto* image_model_factory = ClipboardImageModelFactory::Get(); + if (!image_model_factory) { + return; + } // `text_input_client` can be nullptr in tests. const auto* text_input_client = @@ -202,23 +148,37 @@ display::Screen::GetScreen()->GetPrimaryDisplay().id()) ->GetInputMethod() ->GetTextInputClient(); - const gfx::Rect bounding_box = text_input_client ? text_input_client->GetSelectionBoundingBox() : gfx::Rect(); - ClipboardImageModelFactory::Get()->Render( + + image_model_factory->Render( id, item.data().markup_data(), IsRectContainedByAnyDisplay(bounding_box) ? bounding_box.size() : gfx::Size(), - base::BindOnce(&ClipboardHistoryResourceManager::CacheImageModel, + base::BindOnce(&ClipboardHistoryResourceManager::OnImageModelRendered, weak_factory_.GetWeakPtr(), id)); return; } - // If we do have an existing model, we need only to update its usages. - auto cached_image_model = base::ConstCastIterator( - cached_image_models_, FindCachedImageModelForItem(*it)); - DCHECK(cached_image_model != cached_image_models_.end()); - cached_image_model->clipboard_history_item_ids.push_back(item.id()); + + // If there is an existing item that will render the same as `item`, check + // whether the existing item's preview has rendered. + auto image_model_request = GetImageModelRequestForItem(*it); + if (image_model_request != image_model_requests_.end()) { + // If rendering is still in progress, just note that `item` will need to + // hear about the result as well. + image_model_request->clipboard_history_item_ids.push_back(item.id()); + } else { + // If rendering has finished, set `item` to have the same preview. + auto mutable_item = + base::ranges::find(items, item.id(), &ClipboardHistoryItem::id); + DCHECK(mutable_item != items.end()); + + const auto& existing_preview = it->html_preview(); + DCHECK(existing_preview.has_value()); + + mutable_item->set_html_preview(existing_preview.value()); + } } void ClipboardHistoryResourceManager::OnClipboardHistoryItemRemoved( @@ -228,30 +188,27 @@ return; } - // We should have an image model in the cache. - auto cached_image_model = base::ConstCastIterator( - cached_image_models_, FindCachedImageModelForItem(item)); - - DCHECK(cached_image_model != cached_image_models_.end()); - if (cached_image_model == cached_image_models_.end()) + // If the item's image model request has already finished, there is nothing + // more to do. + auto image_model_request = GetImageModelRequestForItem(item); + if (image_model_request == image_model_requests_.end()) { return; + } - // Update usages. - base::Erase(cached_image_model->clipboard_history_item_ids, item.id()); - if (!cached_image_model->clipboard_history_item_ids.empty()) - return; + // If `item` was attached to a pending request, make sure it is not updated + // when rendering finishes. + base::Erase(image_model_request->clipboard_history_item_ids, item.id()); - // If the ImageModel was never rendered, cancel the request. - if (cached_image_model->image_model.IsEmpty()) - ClipboardImageModelFactory::Get()->CancelRequest(cached_image_model->id); - - // If the cached image model is no longer in use, it can be erased. - cached_image_models_.erase(cached_image_model); + if (image_model_request->clipboard_history_item_ids.empty()) { + // If no more items are waiting on the image model, cancel the request. + ClipboardImageModelFactory::Get()->CancelRequest(image_model_request->id); + image_model_requests_.erase(image_model_request); + } } void ClipboardHistoryResourceManager::OnClipboardHistoryCleared() { CancelUnfinishedRequests(); - cached_image_models_ = std::vector<CachedImageModel>(); + image_model_requests_.clear(); } } // namespace ash
diff --git a/ash/clipboard/clipboard_history_resource_manager.h b/ash/clipboard/clipboard_history_resource_manager.h index f5183f2..9de15e1 100644 --- a/ash/clipboard/clipboard_history_resource_manager.h +++ b/ash/clipboard/clipboard_history_resource_manager.h
@@ -23,51 +23,44 @@ public: class Observer : public base::CheckedObserver { public: - // Called when the CachedImageModel that corresponds with 'menu_item_ids' - // has been updated. + // Called when a rendered image model is set on the clipboard history items + // specified by `menu_item_ids`. virtual void OnCachedImageModelUpdated( const std::vector<base::UnguessableToken>& menu_item_ids) = 0; }; - explicit ClipboardHistoryResourceManager( - const ClipboardHistory* clipboard_history); + explicit ClipboardHistoryResourceManager(ClipboardHistory* clipboard_history); ClipboardHistoryResourceManager(const ClipboardHistoryResourceManager&) = delete; ClipboardHistoryResourceManager& operator=( const ClipboardHistoryResourceManager&) = delete; ~ClipboardHistoryResourceManager() override; - // Returns the image to display for the specified clipboard history |item|. - ui::ImageModel GetImageModel(const ClipboardHistoryItem& item) const; - void AddObserver(Observer* observer) const; void RemoveObserver(Observer* observer) const; private: - struct CachedImageModel { - CachedImageModel(); - CachedImageModel(const CachedImageModel&); - CachedImageModel& operator=(const CachedImageModel&); - ~CachedImageModel(); + struct ImageModelRequest { + ImageModelRequest(); + ImageModelRequest(const ImageModelRequest&); + ImageModelRequest& operator=(const ImageModelRequest&); + ~ImageModelRequest(); + // Unique identifier. base::UnguessableToken id; - // ImageModel that was created by ClipboardImageModelFactory. - ui::ImageModel image_model; - // ClipboardHistoryItem id's which utilize this CachedImageModel. + + // IDs of items whose image model will be set to this request's result. std::vector<base::UnguessableToken> clipboard_history_item_ids; }; - // Caches the specified |image_model| with the specified |id|. - void CacheImageModel(const base::UnguessableToken& id, - ui::ImageModel image_model); + // Sets the result `image_model` on each `ClipboardHistoryItem` waiting on the + // `ImageModelRequest` specified by `id`. + void OnImageModelRendered(const base::UnguessableToken& id, + ui::ImageModel image_model); - // Finds the cached image model associated with the specified |id|. - std::vector<ClipboardHistoryResourceManager::CachedImageModel>::const_iterator - FindCachedImageModelForId(const base::UnguessableToken& id) const; - - // Finds the cached image model associated with the specified |item|. - std::vector<ClipboardHistoryResourceManager::CachedImageModel>::const_iterator - FindCachedImageModelForItem(const ClipboardHistoryItem& item) const; + // Finds the pending image model request that `item` is waiting on. + std::vector<ImageModelRequest>::iterator GetImageModelRequestForItem( + const ClipboardHistoryItem& item); // Cancels all unfinished requests. void CancelUnfinishedRequests(); @@ -78,16 +71,16 @@ void OnClipboardHistoryItemRemoved(const ClipboardHistoryItem& item) override; void OnClipboardHistoryCleared() override; - // Owned by ClipboardHistoryController. - const ClipboardHistory* const clipboard_history_; + // Owned by `ClipboardHistoryController`. + ClipboardHistory* const clipboard_history_; - std::vector<CachedImageModel> cached_image_models_; + // Pending requests for image models to be rendered. Once a request finishes, + // all of the clipboard history items waiting on that image model will be + // updated, and the request will be removed from this list. + std::vector<ImageModelRequest> image_model_requests_; - // Image used when the cached ImageModel has not yet been generated. - ui::ImageModel placeholder_image_model_; - - // Mutable to allow adding/removing from |observers_| through a const - // ClipboardHistoryResourceManager. + // Mutable to allow adding/removing from `observers_` through a const + // `ClipboardHistoryResourceManager`. mutable base::ObserverList<Observer> observers_; base::WeakPtrFactory<ClipboardHistoryResourceManager> weak_factory_{this};
diff --git a/ash/clipboard/clipboard_history_resource_manager_unittest.cc b/ash/clipboard/clipboard_history_resource_manager_unittest.cc index 1623b51..9978b0ebe 100644 --- a/ash/clipboard/clipboard_history_resource_manager_unittest.cc +++ b/ash/clipboard/clipboard_history_resource_manager_unittest.cc
@@ -5,16 +5,19 @@ #include "ash/clipboard/clipboard_history_resource_manager.h" #include <string> -#include <unordered_map> #include "ash/clipboard/clipboard_history.h" #include "ash/clipboard/clipboard_history_controller_impl.h" #include "ash/clipboard/clipboard_history_item.h" +#include "ash/clipboard/clipboard_history_util.h" #include "ash/public/cpp/clipboard_image_model_factory.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" #include "base/functional/callback.h" +#include "base/location.h" +#include "base/run_loop.h" #include "base/task/sequenced_task_runner.h" +#include "base/test/repeating_test_future.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/skia/include/core/SkBitmap.h" @@ -76,7 +79,8 @@ class ClipboardHistoryResourceManagerTest : public AshTestBase { public: - ClipboardHistoryResourceManagerTest() = default; + ClipboardHistoryResourceManagerTest() + : AshTestBase(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {} ClipboardHistoryResourceManagerTest( const ClipboardHistoryResourceManagerTest&) = delete; ClipboardHistoryResourceManagerTest& operator=( @@ -111,8 +115,7 @@ std::unique_ptr<MockClipboardImageModelFactory> mock_image_factory_; }; -// Tests that Render is called once when an eligible <img> is added -// to ClipboardHistory. +// Tests that an image model is rendered when HTML with an <img> tag is copied. TEST_F(ClipboardHistoryResourceManagerTest, BasicImgCachedImageModel) { ui::ImageModel expected_image_model = GetRandomImageModel(); ON_CALL(*mock_image_factory(), Render) @@ -123,21 +126,20 @@ EXPECT_CALL(*mock_image_factory(), CancelRequest).Times(0); EXPECT_CALL(*mock_image_factory(), Render).Times(1); - // Write a basic ClipboardData which is eligible to render HTML. { ui::ScopedClipboardWriter scw(ui::ClipboardBuffer::kCopyPaste); scw.WriteHTML(u"<img test>", "source_url", ui::ClipboardContentType::kSanitized); } - FlushMessageLoop(); - EXPECT_EQ(expected_image_model, resource_manager()->GetImageModel( - clipboard_history()->GetItems().front())); + ASSERT_EQ(clipboard_history()->GetItems().size(), 1u); + const auto& item = clipboard_history()->GetItems().front(); + ASSERT_TRUE(item.html_preview().has_value()); + EXPECT_EQ(item.html_preview().value(), expected_image_model); } -// Tests that Render is called once when an eligible <table> is added -// to ClipboardHistory. +// Tests that an image model is rendered when HTML with a <table> tag is copied. TEST_F(ClipboardHistoryResourceManagerTest, BasicTableCachedImageModel) { ui::ImageModel expected_image_model = GetRandomImageModel(); ON_CALL(*mock_image_factory(), Render) @@ -148,21 +150,21 @@ EXPECT_CALL(*mock_image_factory(), CancelRequest).Times(0); EXPECT_CALL(*mock_image_factory(), Render).Times(1); - // Write a basic ClipboardData which is eligible to render HTML. { ui::ScopedClipboardWriter scw(ui::ClipboardBuffer::kCopyPaste); scw.WriteHTML(u"<table test>", "source_url", ui::ClipboardContentType::kSanitized); } - FlushMessageLoop(); - EXPECT_EQ(expected_image_model, resource_manager()->GetImageModel( - clipboard_history()->GetItems().front())); + ASSERT_EQ(clipboard_history()->GetItems().size(), 1u); + const auto& item = clipboard_history()->GetItems().front(); + ASSERT_TRUE(item.html_preview().has_value()); + EXPECT_EQ(item.html_preview().value(), expected_image_model); } -// Tests that Render is not called when ineligble html is added to -// ClipboarHistory +// Tests that an image model is not rendered when HTML without render-eligible +// tags is copied. TEST_F(ClipboardHistoryResourceManagerTest, BasicIneligibleCachedImageModel) { ui::ImageModel expected_image_model = GetRandomImageModel(); ON_CALL(*mock_image_factory(), Render) @@ -173,21 +175,21 @@ EXPECT_CALL(*mock_image_factory(), CancelRequest).Times(0); EXPECT_CALL(*mock_image_factory(), Render).Times(0); - // Write a basic ClipboardData which is eligible to render HTML. { ui::ScopedClipboardWriter scw(ui::ClipboardBuffer::kCopyPaste); - scw.WriteHTML(u"html with no img or table tag", "source_url", + scw.WriteHTML(u"HTML with no img or table tag", "source_url", ui::ClipboardContentType::kSanitized); } - FlushMessageLoop(); + + ASSERT_EQ(clipboard_history()->GetItems().size(), 1u); + EXPECT_FALSE( + clipboard_history()->GetItems().front().html_preview().has_value()); } // Tests that copying duplicate HTML to the buffer results in only one render -// request, and that that request is canceled once when the item is forgotten. +// request. TEST_F(ClipboardHistoryResourceManagerTest, DuplicateHTML) { - // Write two duplicate ClipboardDatas. Two things should be in clipboard - // history, but they should share a CachedImageModel. ui::ImageModel expected_image_model = GetRandomImageModel(); ON_CALL(*mock_image_factory(), Render) .WillByDefault(testing::WithArg<3>( @@ -197,14 +199,15 @@ EXPECT_CALL(*mock_image_factory(), CancelRequest).Times(0); EXPECT_CALL(*mock_image_factory(), Render).Times(1); - // Use identical markup but differing source url so that both items are added - // to the clipboard history. + // Write identical markup from two different source URLs so that both items + // are added to the clipboard history. { ui::ScopedClipboardWriter scw(ui::ClipboardBuffer::kCopyPaste); scw.WriteHTML(u"<img test>", "source_url_1", ui::ClipboardContentType::kSanitized); } FlushMessageLoop(); + { ui::ScopedClipboardWriter scw(ui::ClipboardBuffer::kCopyPaste); scw.WriteHTML(u"<img test>", "source_url_2", @@ -212,16 +215,18 @@ } FlushMessageLoop(); + // Because the HTML for the two items renders to the same image, we should + // only try to render one time. auto items = clipboard_history()->GetItems(); - EXPECT_EQ(2u, items.size()); - for (const auto& item : items) - EXPECT_EQ(expected_image_model, resource_manager()->GetImageModel(item)); + EXPECT_EQ(items.size(), 2u); + for (const auto& item : items) { + ASSERT_TRUE(item.html_preview().has_value()); + EXPECT_EQ(item.html_preview().value(), expected_image_model); + } } -// Tests that two different eligible ClipboardData copied results in two calls -// to Render and Cancel. +// Tests that copying different HTML items results in each one being rendered. TEST_F(ClipboardHistoryResourceManagerTest, DifferentHTML) { - // Write two ClipboardData with different HTML. ui::ImageModel first_expected_image_model = GetRandomImageModel(); ui::ImageModel second_expected_image_model = GetRandomImageModel(); std::deque<ui::ImageModel> expected_image_models{first_expected_image_model, @@ -240,6 +245,7 @@ ui::ClipboardContentType::kSanitized); } FlushMessageLoop(); + { ui::ScopedClipboardWriter scw(ui::ClipboardBuffer::kCopyPaste); scw.WriteHTML(u"<img different>", "source_url", @@ -248,43 +254,101 @@ FlushMessageLoop(); std::list<ClipboardHistoryItem> items = clipboard_history()->GetItems(); - EXPECT_EQ(2u, items.size()); - EXPECT_EQ(second_expected_image_model, - resource_manager()->GetImageModel(items.front())); + ASSERT_EQ(items.size(), 2u); + ASSERT_TRUE(items.front().html_preview().has_value()); + EXPECT_EQ(items.front().html_preview().value(), second_expected_image_model); + items.pop_front(); - EXPECT_EQ(first_expected_image_model, - resource_manager()->GetImageModel(items.front())); + ASSERT_TRUE(items.front().html_preview().has_value()); + EXPECT_EQ(items.front().html_preview().value(), first_expected_image_model); } -// Tests that items that are ineligible for CachedImageModels (items with image -// representations, or no markup) do not request Render. -TEST_F(ClipboardHistoryResourceManagerTest, IneligibleItem) { - // Write a ClipboardData with an image, no CachedImageModel should be created. +// Tests that copying content with non-HTML display formats does not result in +// any render requests. +TEST_F(ClipboardHistoryResourceManagerTest, IneligibleDisplayTypes) { EXPECT_CALL(*mock_image_factory(), Render).Times(0); EXPECT_CALL(*mock_image_factory(), CancelRequest).Times(0); + + // Write clipboard data with what would otherwise be render-eligible markup, + // alongside an image. The image data format takes higher precedence, so no + // image model should be rendered. { ui::ScopedClipboardWriter scw(ui::ClipboardBuffer::kCopyPaste); - scw.WriteHTML(u"test", "source_url", ui::ClipboardContentType::kSanitized); + scw.WriteHTML(u"<img test>", "source_url", + ui::ClipboardContentType::kSanitized); scw.WriteImage(GetRandomBitmap()); } FlushMessageLoop(); - EXPECT_EQ(1u, clipboard_history()->GetItems().size()); + ASSERT_EQ(clipboard_history()->GetItems().size(), 1u); + EXPECT_FALSE( + clipboard_history()->GetItems().front().html_preview().has_value()); - // Write a ClipboardData with no markup and no image. No CachedImageModel - // should be created. + // Write clipboard data without an HTML format. No image model should be + // rendered. { ui::ScopedClipboardWriter scw(ui::ClipboardBuffer::kCopyPaste); - scw.WriteText(u"test"); - scw.WriteRTF("rtf"); - scw.WriteBookmark(u"bookmark_title", "test_url"); } FlushMessageLoop(); - EXPECT_EQ(2u, clipboard_history()->GetItems().size()); + ASSERT_EQ(clipboard_history()->GetItems().size(), 2u); + EXPECT_FALSE( + clipboard_history()->GetItems().front().html_preview().has_value()); +} + +// Tests that a placeholder image model is cached while rendering is ongoing. +TEST_F(ClipboardHistoryResourceManagerTest, PlaceholderDuringRender) { + constexpr const auto kRenderDelay = base::Seconds(1); + ui::ImageModel expected_image_model = GetRandomImageModel(); + ON_CALL(*mock_image_factory(), Render) + .WillByDefault(testing::WithArg<3>( + [&](ClipboardImageModelFactory::ImageModelCallback callback) { + // Delay the processing of the rendered image until after the + // clipboard history item has been created. + base::SequencedTaskRunner::GetCurrentDefault()->PostDelayedTask( + FROM_HERE, + base::BindOnce(std::move(callback), expected_image_model), + kRenderDelay); + })); + EXPECT_CALL(*mock_image_factory(), CancelRequest).Times(0); + EXPECT_CALL(*mock_image_factory(), Render).Times(1); + + base::test::RepeatingTestFuture<bool> operation_confirmed_future_; + Shell::Get() + ->clipboard_history_controller() + ->set_confirmed_operation_callback_for_test( + operation_confirmed_future_.GetCallback()); + + { + ui::ScopedClipboardWriter scw(ui::ClipboardBuffer::kCopyPaste); + scw.WriteHTML(u"<img test>", "source_url", + ui::ClipboardContentType::kSanitized); + } + + // Wait for the clipboard history item to be created. This allows us to check + // for the item's intermediate placeholder image model. + EXPECT_TRUE(operation_confirmed_future_.Take()); + + // Between the time a clipboard history item is first created and the time its + // image model finishes rendering, it should have a placeholder HTML preview. + ASSERT_EQ(clipboard_history()->GetItems().size(), 1u); + const auto& item = clipboard_history()->GetItems().front(); + ASSERT_TRUE(item.html_preview().has_value()); + EXPECT_NE(item.html_preview().value(), expected_image_model); + EXPECT_EQ(item.html_preview().value(), + clipboard_history_util::GetHtmlPreviewPlaceholder()); + + // Allow the resource manager to process the rendered image model. + task_environment()->FastForwardBy(kRenderDelay); + FlushMessageLoop(); + + // After the resource manager processes the rendered image, it should be + // cached in the clipboard history item. + ASSERT_TRUE(item.html_preview().has_value()); + EXPECT_EQ(item.html_preview().value(), expected_image_model); } } // namespace ash
diff --git a/ash/clipboard/clipboard_history_util.cc b/ash/clipboard/clipboard_history_util.cc index fc478c5..3e9b612 100644 --- a/ash/clipboard/clipboard_history_util.cc +++ b/ash/clipboard/clipboard_history_util.cc
@@ -13,13 +13,18 @@ #include "ash/shell.h" #include "ash/style/dark_light_mode_controller_impl.h" #include "base/files/file_path.h" +#include "base/no_destructor.h" #include "base/strings/string_split.h" #include "base/strings/utf_string_conversions.h" +#include "cc/paint/paint_flags.h" #include "chromeos/ui/base/file_icon_util.h" #include "ui/base/clipboard/clipboard_data.h" #include "ui/base/clipboard/custom_data_helper.h" #include "ui/base/models/image_model.h" #include "ui/chromeos/styles/cros_tokens_color_mappings.h" +#include "ui/gfx/canvas.h" +#include "ui/gfx/image/canvas_image_source.h" +#include "ui/gfx/paint_vector_icon.h" namespace ash::clipboard_history_util { @@ -27,6 +32,11 @@ constexpr char16_t kFileSystemSourcesType[] = u"fs/sources"; +constexpr int kPlaceholderImageWidth = 234; +constexpr int kPlaceholderImageHeight = 74; +constexpr int kPlaceholderImageOutlineCornerRadius = 8; +constexpr int kPlaceholderImageSVGSize = 32; + // The array of formats in order of decreasing priority. constexpr ui::ClipboardInternalFormat kPrioritizedFormats[] = { ui::ClipboardInternalFormat::kPng, @@ -38,6 +48,43 @@ ui::ClipboardInternalFormat::kWeb, ui::ClipboardInternalFormat::kCustom}; +// Used to draw a placeholder HTML preview to be shown while the real HTML is +// rendering. +class UnrenderedHtmlPlaceholderImage : public gfx::CanvasImageSource { + public: + UnrenderedHtmlPlaceholderImage() + : gfx::CanvasImageSource( + gfx::Size(kPlaceholderImageWidth, kPlaceholderImageHeight)) {} + UnrenderedHtmlPlaceholderImage(const UnrenderedHtmlPlaceholderImage&) = + delete; + UnrenderedHtmlPlaceholderImage& operator=( + const UnrenderedHtmlPlaceholderImage&) = delete; + ~UnrenderedHtmlPlaceholderImage() override = default; + + // gfx::CanvasImageSource: + void Draw(gfx::Canvas* canvas) override { + cc::PaintFlags flags; + flags.setStyle(cc::PaintFlags::kFill_Style); + flags.setAntiAlias(true); + // TODO(b/269680517): Update to use a semantic color token. + flags.setColor(gfx::kGoogleGrey100); + canvas->DrawRoundRect( + /*rect=*/{kPlaceholderImageWidth, kPlaceholderImageHeight}, + kPlaceholderImageOutlineCornerRadius, flags); + + flags = cc::PaintFlags(); + flags.setStyle(cc::PaintFlags::kFill_Style); + flags.setAntiAlias(true); + // TODO(b/269680517): Update to use a semantic color token. + const gfx::ImageSkia center_image = + gfx::CreateVectorIcon(kUnrenderedHtmlPlaceholderIcon, + kPlaceholderImageSVGSize, gfx::kGoogleGrey600); + canvas->DrawImageInt( + center_image, (size().width() - center_image.size().width()) / 2, + (size().height() - center_image.size().height()) / 2, flags); + } +}; + } // namespace absl::optional<ui::ClipboardInternalFormat> CalculateMainFormat( @@ -185,4 +232,10 @@ cros_tokens::kColorPrimary); } +ui::ImageModel GetHtmlPreviewPlaceholder() { + static base::NoDestructor<ui::ImageModel> model(ui::ImageModel::FromImageSkia( + gfx::CanvasImageSource::MakeImageSkia<UnrenderedHtmlPlaceholderImage>())); + return *model; +} + } // namespace ash::clipboard_history_util
diff --git a/ash/clipboard/clipboard_history_util.h b/ash/clipboard/clipboard_history_util.h index 9ac17a9..1fef00cb 100644 --- a/ash/clipboard/clipboard_history_util.h +++ b/ash/clipboard/clipboard_history_util.h
@@ -151,6 +151,10 @@ const ClipboardHistoryItem* item, const std::string& file_name); +// Returns a placeholder image to display for HTML items while their previews +// render. +ASH_EXPORT ui::ImageModel GetHtmlPreviewPlaceholder(); + } // namespace clipboard_history_util } // namespace ash
diff --git a/ash/clipboard/test_support/clipboard_history_item_builder.cc b/ash/clipboard/test_support/clipboard_history_item_builder.cc index f065c58..8d8febc 100644 --- a/ash/clipboard/test_support/clipboard_history_item_builder.cc +++ b/ash/clipboard/test_support/clipboard_history_item_builder.cc
@@ -9,11 +9,9 @@ #include "base/notreached.h" #include "base/pickle.h" #include "base/strings/string_util.h" -#include "base/strings/utf_string_conversions.h" #include "ui/base/clipboard/clipboard_data.h" #include "ui/base/clipboard/clipboard_format_type.h" #include "ui/base/clipboard/custom_data_helper.h" -#include "ui/gfx/codec/png_codec.h" #include "ui/gfx/image/image_unittest_util.h" namespace ash {
diff --git a/ash/clipboard/views/clipboard_history_bitmap_item_view.cc b/ash/clipboard/views/clipboard_history_bitmap_item_view.cc index 9a5c4469..dcd6745d 100644 --- a/ash/clipboard/views/clipboard_history_bitmap_item_view.cc +++ b/ash/clipboard/views/clipboard_history_bitmap_item_view.cc
@@ -16,7 +16,6 @@ #include "ui/base/l10n/l10n_util.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/compositor/layer.h" #include "ui/compositor/layer_animation_observer.h" #include "ui/compositor/scoped_layer_animation_settings.h" @@ -116,12 +115,9 @@ } void SetImageFromModel() { - // TODO(b/267677307): Make cached image an item field, set and updated - // directly by the resource manager. if (const auto* item = item_resolver_.Run()) { - const gfx::ImageSkia& image = - *(resource_manager_->GetImageModel(*item).GetImage().ToImageSkia()); - SetImage(image); + DCHECK(item->html_preview().has_value()); + SetImage(item->html_preview().value()); } // When fading in a new image, the ImageView's image has likely changed
diff --git a/ash/components/arc/memory/arc_memory_bridge.cc b/ash/components/arc/memory/arc_memory_bridge.cc index 1e1c33c9..8e5086cf6 100644 --- a/ash/components/arc/memory/arc_memory_bridge.cc +++ b/ash/components/arc/memory/arc_memory_bridge.cc
@@ -67,4 +67,14 @@ memory_instance->DropCaches(std::move(callback)); } +void ArcMemoryBridge::ReclaimAll(ReclaimAllCallback callback) { + auto* const memory_instance = + ARC_GET_INSTANCE_FOR_METHOD(arc_bridge_service_->memory(), ReclaimAll); + if (!memory_instance) { + std::move(callback).Run(0, 0); + return; + } + memory_instance->ReclaimAll(std::move(callback)); +} + } // namespace arc
diff --git a/ash/components/arc/memory/arc_memory_bridge.h b/ash/components/arc/memory/arc_memory_bridge.h index 15a08fc2..5b7c387 100644 --- a/ash/components/arc/memory/arc_memory_bridge.h +++ b/ash/components/arc/memory/arc_memory_bridge.h
@@ -37,6 +37,10 @@ using DropCachesCallback = base::OnceCallback<void(bool)>; void DropCaches(DropCachesCallback callback); + // Reclaims all pages from all processes. + using ReclaimAllCallback = base::OnceCallback<void(uint32_t, uint32_t)>; + void ReclaimAll(ReclaimAllCallback); + private: THREAD_CHECKER(thread_checker_);
diff --git a/ash/components/arc/memory/arc_memory_bridge_unittest.cc b/ash/components/arc/memory/arc_memory_bridge_unittest.cc index 8cc5526..811da3b 100644 --- a/ash/components/arc/memory/arc_memory_bridge_unittest.cc +++ b/ash/components/arc/memory/arc_memory_bridge_unittest.cc
@@ -82,5 +82,63 @@ EXPECT_FALSE(*opt_result); } +// Tests that ReclaimAll runs the callback with memory reclaimed from all +// processes successfully. +TEST_F(ArcMemoryBridgeTest, ReclaimAll_All_Success) { + memory_instance()->set_reclaim_all_result(100, 0); + + absl::optional<uint32_t> reclaimed_result; + absl::optional<uint32_t> unreclaimed_result; + bridge()->ReclaimAll( + base::BindLambdaForTesting([&](uint32_t reclaimed, uint32_t unreclaimed) { + reclaimed_result = reclaimed; + unreclaimed_result = unreclaimed; + })); + + ASSERT_TRUE(reclaimed_result); + EXPECT_EQ(*reclaimed_result, 100u); + ASSERT_TRUE(unreclaimed_result); + EXPECT_EQ(*unreclaimed_result, 0u); +} + +// Tests that ReclaimAll runs the callback with memory reclaimed from some +// processes successfully. +TEST_F(ArcMemoryBridgeTest, ReclaimAll_Partial_Success) { + memory_instance()->set_reclaim_all_result(50, 50); + + absl::optional<uint32_t> reclaimed_result; + absl::optional<uint32_t> unreclaimed_result; + bridge()->ReclaimAll( + base::BindLambdaForTesting([&](uint32_t reclaimed, uint32_t unreclaimed) { + reclaimed_result = reclaimed; + unreclaimed_result = unreclaimed; + })); + + ASSERT_TRUE(reclaimed_result); + EXPECT_EQ(*reclaimed_result, 50u); + ASSERT_TRUE(unreclaimed_result); + EXPECT_EQ(*unreclaimed_result, 50u); +} + +// Tests that ReclaimAll runs the callback with the instance not available. +TEST_F(ArcMemoryBridgeTest, ReclaimAll_NoInstance) { + // Inject failure. + ArcServiceManager::Get()->arc_bridge_service()->memory()->CloseInstance( + memory_instance()); + + absl::optional<uint32_t> reclaimed_result; + absl::optional<uint32_t> unreclaimed_result; + bridge()->ReclaimAll( + base::BindLambdaForTesting([&](uint32_t reclaimed, uint32_t unreclaimed) { + reclaimed_result = reclaimed; + unreclaimed_result = unreclaimed; + })); + + ASSERT_TRUE(reclaimed_result); + EXPECT_EQ(*reclaimed_result, 0u); + ASSERT_TRUE(unreclaimed_result); + EXPECT_EQ(*unreclaimed_result, 0u); +} + } // namespace } // namespace arc
diff --git a/ash/components/arc/mojom/memory.mojom b/ash/components/arc/mojom/memory.mojom index eacd8dd..9c589f2a 100644 --- a/ash/components/arc/mojom/memory.mojom +++ b/ash/components/arc/mojom/memory.mojom
@@ -1,12 +1,15 @@ // Copyright 2021 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Next MinVersion: 1 +// Next MinVersion: 2 module arc.mojom; -// Next method ID: 1 +// Next method ID: 2 interface MemoryInstance { // Drops the guest kernel's page caches. Returns true on success. DropCaches@0() => (bool result); + // Reclaims all pages from all guest processes. Returns the numbers of + // processes that were reclaimed successfully and unsuccessfully. + ReclaimAll@1() => (uint32 reclaimed, uint32 unreclaimed); };
diff --git a/ash/components/arc/session/arc_session_runner.h b/ash/components/arc/session/arc_session_runner.h index 8e53cdc..7ff11e5 100644 --- a/ash/components/arc/session/arc_session_runner.h +++ b/ash/components/arc/session/arc_session_runner.h
@@ -123,6 +123,7 @@ default_device_scale_factor_ = scale_factor; } + bool use_virtio_blk_data() { return use_virtio_blk_data_; } void set_use_virtio_blk_data(bool use_virtio_blk_data) { use_virtio_blk_data_ = use_virtio_blk_data; }
diff --git a/ash/components/arc/session/arc_vm_client_adapter.h b/ash/components/arc/session/arc_vm_client_adapter.h index 4ac62d5..8fc132f 100644 --- a/ash/components/arc/session/arc_vm_client_adapter.h +++ b/ash/components/arc/session/arc_vm_client_adapter.h
@@ -51,6 +51,7 @@ // The "_2d" in job names below corresponds to "-". Upstart escapes characters // that aren't valid in D-Bus object paths with underscore followed by its // ascii code in hex. So "arc_2dcreate_2ddata" becomes "arc-create-data". +constexpr char kArcVmDataMigratorJobName[] = "arcvm_2ddata_2dmigrator"; constexpr char kArcVmMediaSharingServicesJobName[] = "arcvm_2dmedia_2dsharing_2dservices"; constexpr const char kArcVmPerBoardFeaturesJobName[] = @@ -65,10 +66,9 @@ // List of Upstart jobs that can outlive ARC sessions (e.g. after Chrome crash, // Chrome restart on a feature flag change) and thus should be stopped at the // beginning of the ARCVM boot sequence. -constexpr std::array<const char*, 4> kArcVmUpstartJobsToBeStoppedOnRestart = { - kArcVmPreLoginServicesJobName, - kArcVmPostLoginServicesJobName, - kArcVmPostVmStartServicesJobName, +constexpr std::array<const char*, 5> kArcVmUpstartJobsToBeStoppedOnRestart = { + kArcVmDataMigratorJobName, kArcVmPreLoginServicesJobName, + kArcVmPostLoginServicesJobName, kArcVmPostVmStartServicesJobName, kArcVmMediaSharingServicesJobName, };
diff --git a/ash/components/arc/session/arc_vm_client_adapter_unittest.cc b/ash/components/arc/session/arc_vm_client_adapter_unittest.cc index e1a9daf3..336d2432 100644 --- a/ash/components/arc/session/arc_vm_client_adapter_unittest.cc +++ b/ash/components/arc/session/arc_vm_client_adapter_unittest.cc
@@ -753,6 +753,18 @@ StopArcInstance(); } +// Tests that StartMiniArc() still succeeds even when Upstart fails to stop +// arcvm-data-migrator. +TEST_F(ArcVmClientAdapterTest, StartMiniArc_StopArcVmDataMigratorJobFail) { + // Inject failure to FakeUpstartClient. + InjectUpstartStopJobFailure(kArcVmDataMigratorJobName); + + StartMiniArc(); + EXPECT_GE(GetTestConciergeClient()->start_arc_vm_call_count(), 1); + + StopArcInstance(); +} + // Tests that StartMiniArc() fails when Upstart fails to start the job. TEST_F(ArcVmClientAdapterTest, StartMiniArc_StartArcVmPerBoardFeaturesJobFail) { // Inject failure to FakeUpstartClient.
diff --git a/ash/components/arc/test/fake_memory_instance.cc b/ash/components/arc/test/fake_memory_instance.cc index 241d64b..dfd8b53 100644 --- a/ash/components/arc/test/fake_memory_instance.cc +++ b/ash/components/arc/test/fake_memory_instance.cc
@@ -15,4 +15,7 @@ std::move(callback).Run(drop_caches_result_); } +void FakeMemoryInstance::ReclaimAll(ReclaimAllCallback callback) { + std::move(callback).Run(reclaimed_process_count_, unreclaimed_process_count_); +} } // namespace arc
diff --git a/ash/components/arc/test/fake_memory_instance.h b/ash/components/arc/test/fake_memory_instance.h index 0266641..76a298b7 100644 --- a/ash/components/arc/test/fake_memory_instance.h +++ b/ash/components/arc/test/fake_memory_instance.h
@@ -19,11 +19,21 @@ void set_drop_caches_result(bool result) { drop_caches_result_ = result; } + void set_reclaim_all_result(uint32_t reclaimed, uint32_t unreclaimed) { + reclaimed_process_count_ = reclaimed; + unreclaimed_process_count_ = unreclaimed; + } + // mojom::MemoryInstance: void DropCaches(DropCachesCallback callback) override; + // mojom::MemoryInstance: + void ReclaimAll(ReclaimAllCallback callback) override; + private: bool drop_caches_result_ = true; + uint32_t reclaimed_process_count_ = 0; + uint32_t unreclaimed_process_count_ = 0; }; } // namespace arc
diff --git a/ash/quick_pair/pairing/fast_pair/fast_pair_pairer_impl.cc b/ash/quick_pair/pairing/fast_pair/fast_pair_pairer_impl.cc index 9b54cf3..3fbba7a5 100644 --- a/ash/quick_pair/pairing/fast_pair/fast_pair_pairer_impl.cc +++ b/ash/quick_pair/pairing/fast_pair/fast_pair_pairer_impl.cc
@@ -29,6 +29,7 @@ #include "chromeos/ash/services/quick_pair/public/cpp/fast_pair_message_type.h" #include "device/bluetooth/bluetooth_adapter.h" #include "device/bluetooth/bluetooth_device.h" +#include "device/bluetooth/floss/floss_features.h" #include "device/bluetooth/public/cpp/bluetooth_address.h" #include "third_party/boringssl/src/include/openssl/rand.h" @@ -263,6 +264,18 @@ void FastPairPairerImpl::OnConnectDevice(device::BluetoothDevice* device) { QP_LOG(VERBOSE) << __func__; + + if (floss::features::IsFlossEnabled()) { + // On Floss, ConnectDevice behaves like CreateDevice. It only creates + // a new device object so we have to follow up with actually Pair()-ing + // to it. + QP_LOG(INFO) << __func__ << " on Floss"; + device->Pair(/*pairing_delegate=*/this, + base::BindOnce(&FastPairPairerImpl::OnPairConnected, + weak_ptr_factory_.GetWeakPtr())); + return; + } + RecordProtocolPairingStep(FastPairProtocolPairingSteps::kDeviceConnected, *device_); RecordConnectDeviceResult(/*success=*/true); @@ -775,6 +788,14 @@ return; } + if (floss::features::IsFlossEnabled()) { + // On Floss, Pair is exactly the same as Connect. Therefore we skip calling + // Connect(). + QP_LOG(VERBOSE) << __func__ << ": Skipping Connect on Floss"; + OnConnected(absl::nullopt); + return; + } + // We must follow `Pair` with `Connect`. Not all Fast Pair devices initiate // a connection following pairing. For device that do initiate connecting // following pairing, this may result in `OnConnected` to return a failure,
diff --git a/ash/quick_pair/pairing/fast_pair/fast_pair_pairer_impl_unittest.cc b/ash/quick_pair/pairing/fast_pair/fast_pair_pairer_impl_unittest.cc index b72bd4a2..8aa6f1c 100644 --- a/ash/quick_pair/pairing/fast_pair/fast_pair_pairer_impl_unittest.cc +++ b/ash/quick_pair/pairing/fast_pair/fast_pair_pairer_impl_unittest.cc
@@ -42,6 +42,7 @@ #include "chromeos/ash/services/quick_pair/public/cpp/decrypted_passkey.h" #include "chromeos/ash/services/quick_pair/public/cpp/decrypted_response.h" #include "chromeos/ash/services/quick_pair/public/cpp/fast_pair_message_type.h" +#include "device/bluetooth/floss/floss_features.h" #include "device/bluetooth/test/mock_bluetooth_adapter.h" #include "device/bluetooth/test/mock_bluetooth_device.h" #include "testing/gtest/include/gtest/gtest.h" @@ -632,6 +633,28 @@ histogram_tester().ExpectTotalCount(kCreateBondTime, 1); } +TEST_F(FastPairPairerImplTest, PairByDeviceSuccess_Initial_Floss) { + base::test::ScopedFeatureList feature_list; + feature_list.InitWithFeatures( + /*enabled_features=*/ + {floss::features::kFlossEnabled}, + /*disabled_features=*/{}); + + Login(user_manager::UserType::USER_TYPE_REGULAR); + + CreateMockDevice(DeviceFastPairVersion::kHigherThanV1, + /*protocol=*/Protocol::kFastPairInitial); + AddConnectedHandshake(); + fake_fast_pair_handshake_->InvokeCallback(); + CreatePairer(); + fake_bluetooth_device_ptr_->TriggerPairCallback(); + EXPECT_EQ(GetPairFailure(), absl::nullopt); + ExpectStepMetrics(kProtocolPairingStepInitial, + {FastPairProtocolPairingSteps::kPairingStarted, + FastPairProtocolPairingSteps::kDeviceConnected}); + histogram_tester().ExpectTotalCount(kCreateBondTime, 1); +} + TEST_F(FastPairPairerImplTest, PairByDeviceSuccess_Initial_AlreadyClassicPaired) { Login(user_manager::UserType::USER_TYPE_REGULAR); @@ -1227,6 +1250,46 @@ FastPairProtocolPairingSteps::kDeviceConnected}); } +TEST_F(FastPairPairerImplTest, PairSuccess_Initial_Floss) { + base::test::ScopedFeatureList feature_list; + feature_list.InitWithFeatures( + /*enabled_features=*/ + {floss::features::kFlossEnabled}, + /*disabled_features=*/{}); + + Login(user_manager::UserType::USER_TYPE_REGULAR); + + CreateMockDevice(DeviceFastPairVersion::kHigherThanV1, + /*protocol=*/Protocol::kFastPairInitial); + + // When pairing starts, if the classic address can't be resolved to + // a device then we pair via address. 'SetGetDeviceNullptr' tells the adapter + // to return null when queried for the device to mock this behavior. + SetGetDeviceNullptr(); + AddConnectedHandshake(); + fake_fast_pair_handshake_->InvokeCallback(); + CreatePairer(); + EXPECT_EQ(GetPairFailure(), absl::nullopt); + EXPECT_CALL(paired_callback_, Run); + SetDecryptPasskeyForSuccess(); + NotifyConfirmPasskey(); + RunWritePasskeyCallback(kResponseBytes); + // Floss calls Pair instead of finishing after ConnectDevice. + fake_bluetooth_device_ptr_->TriggerPairCallback(); + EXPECT_EQ(GetPairFailure(), absl::nullopt); + EXPECT_TRUE(IsDevicePaired()); + EXPECT_EQ(DeviceFastPairVersion::kHigherThanV1, device_->version().value()); + adapter_->NotifyDevicePairedChanged(fake_bluetooth_device_ptr_, true); + ExpectStepMetrics(kProtocolPairingStepInitial, + {FastPairProtocolPairingSteps::kPairingStarted, + FastPairProtocolPairingSteps::kPairingComplete, + FastPairProtocolPairingSteps::kPasskeyNegotiated, + FastPairProtocolPairingSteps::kRecievedPasskeyResponse, + FastPairProtocolPairingSteps::kPasskeyValidated, + FastPairProtocolPairingSteps::kPasskeyConfirmed, + FastPairProtocolPairingSteps::kDeviceConnected}); +} + TEST_F(FastPairPairerImplTest, BleDeviceLostMidPair) { Login(user_manager::UserType::USER_TYPE_REGULAR);
diff --git a/ash/system/privacy/privacy_indicators_controller.cc b/ash/system/privacy/privacy_indicators_controller.cc index 9645290..b2f2ff2 100644 --- a/ash/system/privacy/privacy_indicators_controller.cc +++ b/ash/system/privacy/privacy_indicators_controller.cc
@@ -79,6 +79,17 @@ } } +void ASH_EXPORT UpdatePrivacyIndicators( + const std::string& app_id, + absl::optional<std::u16string> app_name, + bool is_camera_used, + bool is_microphone_used, + scoped_refptr<PrivacyIndicatorsNotificationDelegate> delegate) { + ModifyPrivacyIndicatorsNotification(app_id, app_name, is_camera_used, + is_microphone_used, delegate); + UpdatePrivacyIndicatorsView(app_id, is_camera_used, is_microphone_used); +} + std::string GetPrivacyIndicatorsNotificationId(const std::string& app_id) { return kPrivacyIndicatorsNotificationIdPrefix + app_id; }
diff --git a/ash/system/privacy/privacy_indicators_controller.h b/ash/system/privacy/privacy_indicators_controller.h index 242673d..28324cf 100644 --- a/ash/system/privacy/privacy_indicators_controller.h +++ b/ash/system/privacy/privacy_indicators_controller.h
@@ -19,7 +19,11 @@ namespace ash { // An interface for the delegate of the privacy indicators notification, -// handling launching the app and its settings. +// handling launching the app and its settings. Clients that use privacy +// indicators should provide this delegate when calling the privacy indicators +// controller API so that the API can add correct buttons to the notification +// based on the callbacks provided and appropriate actions are performed when +// clicking the buttons. class ASH_EXPORT PrivacyIndicatorsNotificationDelegate : public message_center::NotificationDelegate { public: @@ -69,6 +73,15 @@ absl::optional<int> launch_settings_button_index_; }; +// Updates privacy indicators, including the privacy indicators view and the +// privacy indicator notification(s). +void ASH_EXPORT UpdatePrivacyIndicators( + const std::string& app_id, + absl::optional<std::u16string> app_name, + bool is_camera_used, + bool is_microphone_used, + scoped_refptr<PrivacyIndicatorsNotificationDelegate> delegate); + // Get the id of the privacy indicators notification associated with `app_id`. std::string ASH_EXPORT GetPrivacyIndicatorsNotificationId(const std::string& app_id);
diff --git a/ash/system/privacy/privacy_indicators_tray_item_view.h b/ash/system/privacy/privacy_indicators_tray_item_view.h index 36ce04c..25f28f7 100644 --- a/ash/system/privacy/privacy_indicators_tray_item_view.h +++ b/ash/system/privacy/privacy_indicators_tray_item_view.h
@@ -74,6 +74,9 @@ ~PrivacyIndicatorsTrayItemView() override; + views::ImageView* camera_icon() { return camera_icon_; } + views::ImageView* microphone_icon() { return microphone_icon_; } + // Update the view according to the state of camara/microphone access. void Update(const std::string& app_id, bool is_camera_used,
diff --git a/ash/webui/personalization_app/resources/css/common.css b/ash/webui/personalization_app/resources/css/common.css index 3453957..79a3b88 100644 --- a/ash/webui/personalization_app/resources/css/common.css +++ b/ash/webui/personalization_app/resources/css/common.css
@@ -82,12 +82,6 @@ animation: 2210ms linear var(--animation-delay, 1s) infinite ripple; } -cr-button[aria-pressed=true], -cr-button[aria-selected=true] { - background-color: var(--cros-highlight-color); - border: 0; -} - .preview-container { border: 1px solid var(--cros-separator-color); border-radius: 16px;
diff --git a/ash/webui/personalization_app/resources/css/cros_button_style.css b/ash/webui/personalization_app/resources/css/cros_button_style.css index 3bf541e..dc0b8914 100644 --- a/ash/webui/personalization_app/resources/css/cros_button_style.css +++ b/ash/webui/personalization_app/resources/css/cros_button_style.css
@@ -12,43 +12,51 @@ } cr-button.primary { - background-color: var(--cros-button-background-color-primary); + background-color: var(--cros-sys-primary, var(--cros-button-background-color-primary)); border: 0; - --text-color: var(--cros-button-label-color-primary); - --ink-color: var(--cros-button-ripple-color-primary); - --hover-bg-color: var(--cros-button-background-color-primary-hover-preblended); - --disabled-bg: var(--cros-button-background-color-primary-disabled); - --disabled-text-color: var(--cros-button-label-color-primary-disabled); + --text-color: var(--cros-sys-on_primary, var(--cros-button-label-color-primary)); + --ink-color: var(--cros-sys-ripple_primary, var(--cros-button-ripple-color-primary)); + --hover-bg-color: var(--cros-sys-hover_on_prominent, var(--cros-button-background-color-primary-hover-preblended)); + --disabled-bg: var(--cros-sys-disabled_container, var(--cros-button-background-color-primary-disabled)); + --disabled-text-color: var(--cros-sys-disabled, var(--cros-button-label-color-primary-disabled)); } cr-button.primary:active { box-shadow: 0 1px 2px rgba(66, 133, 244, 0.3), 0 1px 3px rgba(66, 133, 244, 0.15); } +:host-context(body.jelly-enabled) cr-button.primary:active { + box-shadow: none; +} + cr-button.primary:hover { - background-color: var(--cros-button-background-color-primary-hover-preblended); + background-color: var(--cros-sys-hover_on_prominent, var(--cros-button-background-color-primary-hover-preblended)); } cr-button.secondary { + background-color: var(--cros-sys-primary_container, var(--cros-button-background-color-secondary)); border: 1px solid var(--cros-button-stroke-color-secondary); - --text-color: var(--cros-button-label-color-secondary); + --text-color: var(--cros-sys-on_primary_container, var(--cros-button-label-color-secondary)); --border-color: var(--cros-button-stroke-color-secondary); - --ink-color: var(--cros-button-ripple-color-secondary); + --ink-color: var(--cros-sys-ripple_primary, var(--cros-button-ripple-color-secondary)); --hover-border-color: var(--cros-button-stroke-color-secondary-hover); - --hover-bg-color: var(--cros-button-background-color-secondary-hover); - --disabled-text-color: var(--cros-button-label-color-secondary-disabled); + --hover-bg-color: var(--cros-sys-hover_on_subtle, var(--cros-button-background-color-secondary-hover)); + --disabled-text-color: var(--cros-sys-disabled, var(--cros-button-label-color-secondary-disabled)); --disabled-border-color: var(--cros-button-stroke-color-secondary-disabled); } +:host-context(body.jelly-enabled) cr-button.secondary { + border: none; +} + cr-button.secondary:hover { - background-color: var(--cros-button-background-color-secondary-hover); - border-color: var(--cros-button-stroke-color-secondary-hover); + background-color: var(--cros-sys-hover_on_subtle, var(--cros-button-background-color-secondary-hover)); } cr-icon-button:focus-visible, cr-button:focus-visible { box-shadow: none; - outline: 2px solid rgba(var(--cros-focus-ring-color-rgb), 0.8); + outline: 2px solid var(--cros-sys-focus_ring, rgba(var(--cros-focus-ring-color-rgb), 0.8)); } cr-icon-button:hover, @@ -59,17 +67,8 @@ cr-button[aria-pressed=true], cr-button[aria-selected=true] { - background-color: var(--cros-button-background-color-primary) !important; -} - -cr-button[aria-pressed=true] .text, -cr-button[aria-selected=true] .text { - color: var(--cros-button-label-color-primary) !important; -} - -cr-button[aria-pressed=true] iron-icon, -cr-button[aria-selected=true] iron-icon { - --iron-icon-fill-color: var(--cros-button-label-color-primary) !important; + background-color: var(--cros-sys-highlight_shape, var(--cros-highlight-color)); + border: none; } iron-icon {
diff --git a/ash/webui/personalization_app/resources/js/theme/personalization_theme_element.html b/ash/webui/personalization_app/resources/js/theme/personalization_theme_element.html index 1500082..521b835 100644 --- a/ash/webui/personalization_app/resources/js/theme/personalization_theme_element.html +++ b/ash/webui/personalization_app/resources/js/theme/personalization_theme_element.html
@@ -18,6 +18,16 @@ /* These cr-button styles are added here instead of cros-button-style because the specs for these buttons are different from others in the app. */ + cr-button[aria-pressed=true] .text, + cr-button[aria-selected=true] .text { + color: var(--cros-button-label-color-primary) !important; + } + + cr-button[aria-pressed=true] iron-icon, + cr-button[aria-selected=true] iron-icon { + --iron-icon-fill-color: var(--cros-button-label-color-primary) !important; + } + cr-button .text, cr-button:hover .text { color: var(--cros-text-color-secondary); @@ -35,6 +45,11 @@ var(--cros-button-primary-ripple-opacity)); } + cr-button[aria-pressed=true], + cr-button[aria-selected=true] { + background-color: var(--cros-button-background-color-primary) !important; + } + #selector { display: grid; gap: 8px;
diff --git a/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_selected_element.html b/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_selected_element.html index 3838cd3..711efa2 100644 --- a/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_selected_element.html +++ b/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_selected_element.html
@@ -60,11 +60,6 @@ --iron-icon-width: 20px; } - cr-button { - border-color: var(--cros-button-stroke-color-secondary); - border-radius: 16px; - } - cr-button + cr-button { margin-inline-start: 8px; } @@ -131,12 +126,14 @@ <template is="dom-if" if="[[shouldShowLayoutOptions_]]"> <div id="wallpaperOptions"> <cr-button id="fill" data-layout="FILL" on-click="onClickLayoutIcon_" + class="secondary" aria-pressed$="[[getFillAriaPressed_(image_)]]"> <iron-icon icon="[[fillIcon_]]"></iron-icon> <div class="text">$i18n{fill}</div> </cr-button> <cr-button id="center" data-layout="CENTER" on-click="onClickLayoutIcon_" + class="secondary" aria-pressed$="[[getCenterAriaPressed_(image_)]]"> <iron-icon icon="[[centerIcon_]]"></iron-icon> <div class="text">$i18n{center}</div> @@ -145,7 +142,7 @@ </template> <template is="dom-if" if="[[showCollectionOptions_]]"> <div id="collectionOptions"> - <cr-button id="dailyRefresh" + <cr-button id="dailyRefresh" class="secondary" aria-label="$i18n{ariaLabelChangeDaily}" aria-pressed$="[[ariaPressed_]]" on-click="onClickDailyRefreshToggle_" @@ -153,7 +150,7 @@ <iron-icon icon="[[dailyRefreshIcon_]]"></iron-icon> <div class="text">$i18n{changeDaily}</div> </cr-button> - <cr-button id="refreshWallpaper" + <cr-button id="refreshWallpaper" class="secondary" aria-label="$i18n{ariaLabelRefresh}" on-click="onClickUpdateDailyRefreshWallpaper_" hidden$="[[!showRefreshButton_]]">
diff --git a/ash/wm/collision_detection/collision_detection_utils.cc b/ash/wm/collision_detection/collision_detection_utils.cc index 2f06378..3171538 100644 --- a/ash/wm/collision_detection/collision_detection_utils.cc +++ b/ash/wm/collision_detection/collision_detection_utils.cc
@@ -5,15 +5,11 @@ #include "ash/wm/collision_detection/collision_detection_utils.h" #include "ash/app_list/app_list_controller_impl.h" -#include "ash/capture_mode/capture_mode_camera_controller.h" #include "ash/capture_mode/capture_mode_controller.h" -#include "ash/capture_mode/capture_mode_session.h" -#include "ash/constants/ash_features.h" #include "ash/keyboard/ui/keyboard_ui_controller.h" #include "ash/public/cpp/shelf_types.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/shelf/shelf.h" -#include "ash/shelf/shelf_layout_manager.h" #include "ash/shell.h" #include "ash/system/message_center/ash_message_popup_collection.h" #include "ash/wm/work_area_insets.h" @@ -178,26 +174,10 @@ /*parent=*/root_window)); } - // Check the capture bar if capture mode is active. - auto* capture_mode_controller = CaptureModeController::Get(); - if (capture_mode_controller->IsActive()) { - aura::Window* capture_bar_window = - capture_mode_controller->capture_mode_session() - ->capture_mode_bar_widget() - ->GetNativeWindow(); - rects.push_back(ComputeCollisionRectFromBounds( - capture_bar_window->GetTargetBounds(), capture_bar_window->parent())); - } - - // Check the camera preview if it exists. - auto* camera_preview_widget = - capture_mode_controller->camera_controller()->camera_preview_widget(); - if (camera_preview_widget && camera_preview_widget->IsVisible()) { - aura::Window* camera_preview_window = - camera_preview_widget->GetNativeWindow(); - rects.push_back( - ComputeCollisionRectFromBounds(camera_preview_window->GetTargetBounds(), - camera_preview_window->parent())); + for (auto* window : + CaptureModeController::Get()->GetWindowsForCollisionAvoidance()) { + rects.push_back(ComputeCollisionRectFromBounds(window->GetTargetBounds(), + window->parent())); } // Avoid clamshell-mode launcher bubble.
diff --git a/ash/wm/desks/desks_bar_view.cc b/ash/wm/desks/desks_bar_view.cc index 12317644..3258b44 100644 --- a/ash/wm/desks/desks_bar_view.cc +++ b/ash/wm/desks/desks_bar_view.cc
@@ -649,8 +649,8 @@ std::make_unique<CrOSNextDeskIconButton>( this, &kDesksTemplatesIcon, l10n_util::GetStringUTF16(button_text_id), - cros_tokens::kCrosSysOnPrimaryContainer, - cros_tokens::kCrosSysSystemPrimaryContainer, + cros_tokens::kCrosSysOnSecondaryContainer, + cros_tokens::kCrosSysInversePrimary, /*initially_enabled=*/true, base::BindRepeating(&DesksBarView::OnLibraryButtonPressed, base::Unretained(this))));
diff --git a/ash/wm/multitask_menu_nudge_controller_unittest.cc b/ash/wm/multitask_menu_nudge_controller_unittest.cc index 8343523..9019962e 100644 --- a/ash/wm/multitask_menu_nudge_controller_unittest.cc +++ b/ash/wm/multitask_menu_nudge_controller_unittest.cc
@@ -26,6 +26,7 @@ #include "chromeos/ui/frame/multitask_menu/multitask_button.h" #include "chromeos/ui/frame/multitask_menu/multitask_menu.h" #include "chromeos/ui/wm/features.h" +#include "ui/display/screen.h" #include "ui/gfx/geometry/size.h" #include "ui/views/widget/any_widget_observer.h" #include "ui/wm/core/window_util.h" @@ -192,6 +193,37 @@ EXPECT_FALSE(GetNudgeWidgetForWindow(window.get())); } +// Tests that the nudge bounds is within display bounds when the associated +// window is maximized. +TEST_F(MultitaskMenuNudgeControllerTest, ClamshellNudgeBounds) { + auto window = CreateAppWindow(gfx::Rect(300, 300)); + ASSERT_TRUE(GetNudgeWidgetForWindow(window.get())); + + WindowState::Get(window.get())->Maximize(); + auto* nudge_widget = GetNudgeWidgetForWindow(window.get()); + ASSERT_TRUE(nudge_widget); + EXPECT_TRUE(display::Screen::GetScreen() + ->GetDisplayNearestView(window.get()) + .work_area() + .Contains(nudge_widget->GetWindowBoundsInScreen())); + + // Cleanup some state for the next test. + FireDismissNudgeTimer(window.get()); + window.reset(); + test_clock_.Advance(base::Hours(26)); + + // Test the same thing in RTL. + base::i18n::SetRTLForTesting(true); + window = CreateAppWindow(gfx::Rect(300, 300)); + WindowState::Get(window.get())->Maximize(); + nudge_widget = GetNudgeWidgetForWindow(window.get()); + ASSERT_TRUE(nudge_widget); + EXPECT_TRUE(display::Screen::GetScreen() + ->GetDisplayNearestView(window.get()) + .work_area() + .Contains(nudge_widget->GetWindowBoundsInScreen())); +} + TEST_F(MultitaskMenuNudgeControllerTest, NudgeMultiDisplay) { UpdateDisplay("800x700,801+0-800x700"); ASSERT_EQ(2u, Shell::GetAllRootWindows().size()); @@ -199,27 +231,21 @@ auto window = CreateAppWindow(gfx::Rect(300, 300)); ASSERT_TRUE(GetNudgeWidgetForWindow(window.get())); + // Move the window using the shortcut. Test that the nudge is on the correct + // display. + display_move_window_util::HandleMoveActiveWindowBetweenDisplays(); + EXPECT_EQ(Shell::GetAllRootWindows()[1], GetNudgeWidgetForWindow(window.get()) + ->GetNativeWindow() + ->GetRootWindow()); + // Drag from the caption the window to the other display. The nudge should be - // on the other display, even though the window is not (the window stays - // offscreen and a mirrored version called the drag window is the one on the - // secondary display). + // gone, but there is no crash. + display_move_window_util::HandleMoveActiveWindowBetweenDisplays(); auto* event_generator = GetEventGenerator(); event_generator->set_current_screen_location(gfx::Point(150, 10)); event_generator->PressLeftButton(); - event_generator->MoveMouseTo(gfx::Point(900, 0)); - EXPECT_EQ(Shell::GetAllRootWindows()[1], GetNudgeWidgetForWindow(window.get()) - ->GetNativeWindow() - ->GetRootWindow()); - - event_generator->ReleaseLeftButton(); - EXPECT_EQ(Shell::GetAllRootWindows()[1], GetNudgeWidgetForWindow(window.get()) - ->GetNativeWindow() - ->GetRootWindow()); - - display_move_window_util::HandleMoveActiveWindowBetweenDisplays(); - EXPECT_EQ(Shell::GetAllRootWindows()[0], GetNudgeWidgetForWindow(window.get()) - ->GetNativeWindow() - ->GetRootWindow()); + event_generator->MoveMouseTo(gfx::Point(1200, 0)); + EXPECT_FALSE(GetNudgeWidgetForWindow(window.get())); } // Tests that based on preferences (shown count, and last shown time), the nudge
diff --git a/base/allocator/partition_alloc_support.cc b/base/allocator/partition_alloc_support.cc index d31d072..38b675d 100644 --- a/base/allocator/partition_alloc_support.cc +++ b/base/allocator/partition_alloc_support.cc
@@ -466,17 +466,30 @@ // are all the dangling raw_ptr occurrences in a table. std::string ExtractDanglingPtrSignature(std::string stacktrace) { std::vector<StringPiece> lines = SplitStringPiece( - stacktrace, "\r\n", TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY); + stacktrace, "\r\n", KEEP_WHITESPACE, SPLIT_WANT_NONEMPTY); // We are looking for the callers of the function releasing the raw_ptr and // freeing memory: const StringPiece callees[] = { + // Common signatures + "internal::PartitionFree", + "base::(anonymous namespace)::FreeFn", + + // Linux signatures "internal::RawPtrBackupRefImpl<>::ReleaseInternal()", - "internal::PartitionFree()", "base::RefCountedThreadSafe<>::Release()", - "base::(anonymous namespace)::FreeFn()", + + // Windows signatures + "internal::RawPtrBackupRefImpl<0>::ReleaseInternal", + "_free_base", + // Windows stack traces are prefixed with "Backtrace:" + "Backtrace:", + + // Mac signatures + "internal::RawPtrBackupRefImpl<false>::ReleaseInternal", + // Task traces are prefixed with "Task trace:" in - // https://crsrc.org/c/base/debug/task_trace.cc;drc=82fbec846172f4e7ea576ad4f2f7f3d082dcb13b;l=77 + // |TaskTrace::OutputToStream| "Task trace:", }; size_t caller_index = 0; @@ -492,20 +505,56 @@ } StringPiece caller = lines[caller_index]; - // |callers| follows the following format: - // - // #4 0x56051fe3404b content::GeneratedCodeCache::DidCreateBackend() - // -- -------------- ----------------------------------------------- - // Depth Address Function - - size_t address_start = caller.find(' '); - size_t function_start = caller.find(' ', address_start + 1); - - if (address_start == caller.npos || function_start == caller.npos) { + if (caller.empty()) { return "invalid_format"; } - return std::string(caller.substr(function_start + 1)); + // On Posix platforms |callers| follows the following format: + // + // #<index> <address> <symbol> + // + // See https://crsrc.org/c/base/debug/stack_trace_posix.cc + if (caller[0] == '#') { + const size_t address_start = caller.find(' '); + const size_t function_start = caller.find(' ', address_start + 1); + + if (address_start == caller.npos || function_start == caller.npos) { + return "invalid_format"; + } + + return std::string(caller.substr(function_start + 1)); + } + + // On Windows platforms |callers| follows the following format: + // + // \t<symbol> [0x<address>]+<displacement>(<filename>:<line>) + // + // See https://crsrc.org/c/base/debug/stack_trace_win.cc + if (caller[0] == '\t') { + const size_t symbol_start = 1; + const size_t symbol_end = caller.find(' '); + if (symbol_end == caller.npos) { + return "invalid_format"; + } + return std::string(caller.substr(symbol_start, symbol_end - symbol_start)); + } + + // On Mac platforms |callers| follows the following format: + // + // <index> <library> 0x<address> <symbol> + <line> + // + // See https://crsrc.org/c/base/debug/stack_trace_posix.cc + if (caller[0] >= '0' && caller[0] <= '9') { + const size_t address_start = caller.find("0x"); + const size_t symbol_start = caller.find(' ', address_start + 1) + 1; + const size_t symbol_end = caller.find(' ', symbol_start); + if (symbol_start == caller.npos || symbol_end == caller.npos) { + return "invalid_format"; + } + return std::string(caller.substr(symbol_start, symbol_end - symbol_start)); + } + + return "invalid_format"; } std::string ExtractDanglingPtrSignature(debug::TaskTrace task_trace) { @@ -1190,4 +1239,11 @@ // BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) } +#if BUILDFLAG(ENABLE_DANGLING_RAW_PTR_CHECKS) +std::string PartitionAllocSupport::ExtractDanglingPtrSignatureForTests( + std::string stacktrace) { + return ExtractDanglingPtrSignature(stacktrace); +} +#endif + } // namespace base::allocator
diff --git a/base/allocator/partition_alloc_support.h b/base/allocator/partition_alloc_support.h index ead3d47d..cd4ca93c 100644 --- a/base/allocator/partition_alloc_support.h +++ b/base/allocator/partition_alloc_support.h
@@ -75,6 +75,11 @@ void OnForegrounded(bool has_main_frame); void OnBackgrounded(); +#if BUILDFLAG(ENABLE_DANGLING_RAW_PTR_CHECKS) + static std::string ExtractDanglingPtrSignatureForTests( + std::string stacktrace); +#endif + static PartitionAllocSupport* Get() { static auto* singleton = new PartitionAllocSupport(); return singleton;
diff --git a/base/allocator/partition_alloc_support_unittest.cc b/base/allocator/partition_alloc_support_unittest.cc index 34b7b8bc..c1aa35b 100644 --- a/base/allocator/partition_alloc_support_unittest.cc +++ b/base/allocator/partition_alloc_support_unittest.cc
@@ -327,6 +327,57 @@ partition_alloc::GetDanglingRawPtrReleasedFn()(42); } +TEST(PartitionAllocDanglingPtrChecks, + ExtractDanglingPtrSignatureMacStackTrace) { + const std::string stack_trace_output = + "0 lib_1 0x0000000115fdfa12 base::F1(**) + 18\r\n" + "1 lib_1 0x0000000115ec0043 base::F2() + 19\r\n" + "2 lib_1 0x000000011601fb01 " + "allocator_shim::internal::PartitionFree(foo) + 13265\r\n" + "3 lib_1 0x0000000114831027 base::F3(bar) + 42\r\n" + "4 lib_2 0x00000001148eae35 base::F4() + 437\r\n"; + EXPECT_EQ("base::F3(bar)", + PartitionAllocSupport::ExtractDanglingPtrSignatureForTests( + stack_trace_output)); +} + +TEST(PartitionAllocDanglingPtrChecks, ExtractDanglingPtrSignatureMacTaskTrace) { + const std::string task_trace_output = + "Task trace:\r\n" + "0 lib_1 0x00000001161fd431 base::F1() + 257\r\n" + "1 lib_1 0x0000000115a49404 base::F2() + 68\r\n"; + EXPECT_EQ("base::F1()", + PartitionAllocSupport::ExtractDanglingPtrSignatureForTests( + task_trace_output)); +} + +TEST(PartitionAllocDanglingPtrChecks, + ExtractDanglingPtrSignatureWindowsStackTrace) { + const std::string stack_trace_output = + "Backtrace:\r\n" + "\tbase::F1 [0x055643C3+19] (o:\\base\\F1.cc:329)\r\n" + "\tallocator_shim::internal::PartitionFree [0x0648F87B+5243] " + "(o:\\path.cc:441)\r\n" + "\t_free_base [0x0558475D+29] (o:\\file_path.cc:142)\r\n" + "\tbase::F2 [0x04E5B317+23] (o:\\base\\F2.cc:91)\r\n" + "\tbase::F3 [0x04897800+544] (o:\\base\\F3.cc:638)\r\n"; + EXPECT_EQ("base::F2", + PartitionAllocSupport::ExtractDanglingPtrSignatureForTests( + stack_trace_output)); +} + +TEST(PartitionAllocDanglingPtrChecks, + ExtractDanglingPtrSignatureWindowsTaskTrace) { + const std::string task_trace_output = + "Task trace:\r\n" + "Backtrace:\r\n" + "\tbase::F1 [0x049068A3+813] (o:\\base\\F1.cc:207)\r\n" + "\tbase::F2 [0x0490614C+192] (o:\\base\\F2.cc:116)\r\n"; + EXPECT_EQ("base::F1", + PartitionAllocSupport::ExtractDanglingPtrSignatureForTests( + task_trace_output)); +} + #endif } // namespace allocator
diff --git a/base/feature_list.cc b/base/feature_list.cc index a924a1e..468b1974 100644 --- a/base/feature_list.cc +++ b/base/feature_list.cc
@@ -668,7 +668,12 @@ const Feature& feature) const { DCHECK(initialized_); DCHECK(IsValidFeatureOrFieldTrialName(feature.name)) << feature.name; - DCHECK(CheckFeatureIdentity(feature)) << feature.name; + DCHECK(CheckFeatureIdentity(feature)) + << feature.name + << " has multiple definitions. Either it is defined more than once in " + "code or (for component builds) the code is built into multiple " + "components (shared libraries) without a corresponding export " + "statement"; // If caching is disabled, always perform the full lookup. if (!g_cache_override_state)
diff --git a/base/test/data/activity_analyzer_fuzzer/9288a7d7d26f1cc5a3d0a62632827b3b6ade5206 b/base/test/data/activity_analyzer_fuzzer/9288a7d7d26f1cc5a3d0a62632827b3b6ade5206 deleted file mode 100644 index a87ef6b..0000000 --- a/base/test/data/activity_analyzer_fuzzer/9288a7d7d26f1cc5a3d0a62632827b3b6ade5206 +++ /dev/null Binary files differ
diff --git a/base/test/data/activity_analyzer_fuzzer/b115be9accdbf58ce8b1c951ac8a6376fdfc2b32 b/base/test/data/activity_analyzer_fuzzer/b115be9accdbf58ce8b1c951ac8a6376fdfc2b32 deleted file mode 100644 index 5aa8553..0000000 --- a/base/test/data/activity_analyzer_fuzzer/b115be9accdbf58ce8b1c951ac8a6376fdfc2b32 +++ /dev/null Binary files differ
diff --git a/base/test/data/activity_analyzer_fuzzer/cd42dd22f7cce7f6ca59be23d77c5eb749585641 b/base/test/data/activity_analyzer_fuzzer/cd42dd22f7cce7f6ca59be23d77c5eb749585641 deleted file mode 100644 index eb810b3..0000000 --- a/base/test/data/activity_analyzer_fuzzer/cd42dd22f7cce7f6ca59be23d77c5eb749585641 +++ /dev/null Binary files differ
diff --git a/base/test/data/activity_analyzer_fuzzer/ce037ea9196e360bf9be0a160c57f2c705d739c5 b/base/test/data/activity_analyzer_fuzzer/ce037ea9196e360bf9be0a160c57f2c705d739c5 deleted file mode 100644 index b6bf749..0000000 --- a/base/test/data/activity_analyzer_fuzzer/ce037ea9196e360bf9be0a160c57f2c705d739c5 +++ /dev/null Binary files differ
diff --git a/base/test/data/activity_analyzer_fuzzer/e3d08b4e17e3558cacddfe5f39565e5ed13a0159 b/base/test/data/activity_analyzer_fuzzer/e3d08b4e17e3558cacddfe5f39565e5ed13a0159 deleted file mode 100644 index 60db68e..0000000 --- a/base/test/data/activity_analyzer_fuzzer/e3d08b4e17e3558cacddfe5f39565e5ed13a0159 +++ /dev/null Binary files differ
diff --git a/build/fuchsia/gcs_download_test.py b/build/fuchsia/gcs_download_test.py index 3c5adaa..7aebe7d8 100755 --- a/build/fuchsia/gcs_download_test.py +++ b/build/fuchsia/gcs_download_test.py
@@ -3,6 +3,7 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import os import subprocess import sys import tarfile @@ -27,18 +28,23 @@ @mock.patch('tempfile.TemporaryDirectory') @mock.patch('subprocess.run') @mock.patch('tarfile.open') +@unittest.skipIf(os.name == 'nt', 'Fuchsia tests not supported on Windows') class TestDownloadAndUnpackFromCloudStorage(unittest.TestCase): def testHappyPath(self, mock_tarfile, mock_run, mock_tmp_dir): mock_run.return_value = _mock_task() - mock_tmp_dir.return_value.__enter__.return_value = '/some/tmp/dir' + + tmp_dir = os.path.join('some', 'tmp', 'dir') + mock_tmp_dir.return_value.__enter__.return_value = tmp_dir mock_seq = mock.Mock() mock_seq.attach_mock(mock_run, 'Run') mock_seq.attach_mock(mock_tarfile, 'Untar') mock_seq.attach_mock(mock_tmp_dir, 'MkTmpD') - DownloadAndUnpackFromCloudStorage('gs://some/url', 'output/dir') + output_dir = os.path.join('output', 'dir') + DownloadAndUnpackFromCloudStorage('gs://some/url', output_dir) + image_tgz_path = os.path.join(tmp_dir, 'image.tgz') mock_seq.assert_has_calls([ mock.call.MkTmpD(), mock.call.MkTmpD().__enter__(), @@ -47,8 +53,8 @@ stdout=subprocess.PIPE, check=True, encoding='utf-8'), - mock.call.Untar(name='/some/tmp/dir/image.tgz', mode='r|gz'), - mock.call.Untar().extractall(path='output/dir'), + mock.call.Untar(name=image_tgz_path, mode='r|gz'), + mock.call.Untar().extractall(path=output_dir), mock.call.MkTmpD().__exit__(None, None, None) ], any_order=False) @@ -56,8 +62,7 @@ # Verify cmd. cmd = ' '.join(mock_run.call_args[0][0]) self.assertRegex( - cmd, - r'.*python\s.*gsutil.py\s+cp\s+gs://some/url\s+/some/tmp/dir/image.tgz') + cmd, r'.*python\s.*gsutil.py\s+cp\s+gs://some/url\s+' + image_tgz_path) def testFailedTarOpen(self, mock_tarfile, mock_run, mock_tmp_dir): mock_run.return_value = _mock_task(stderr='some error')
diff --git a/cc/base/container_util.h b/cc/base/container_util.h index a7d8bdd..b53f2b6 100644 --- a/cc/base/container_util.h +++ b/cc/base/container_util.h
@@ -5,6 +5,7 @@ #ifndef CC_BASE_CONTAINER_UTIL_H_ #define CC_BASE_CONTAINER_UTIL_H_ +#include <utility> namespace cc {
diff --git a/cc/base/features.cc b/cc/base/features.cc index 865158f..59fe321 100644 --- a/cc/base/features.cc +++ b/cc/base/features.cc
@@ -44,9 +44,15 @@ "RemoveMobileViewportDoubleTap", base::FEATURE_ENABLED_BY_DEFAULT); +// Design doc: bit.ly/scrollunification +// Disabled on Windows due to crbug.com/1378021. BASE_FEATURE(kScrollUnification, "ScrollUnification", +#if BUILDFLAG(IS_WIN) base::FEATURE_DISABLED_BY_DEFAULT); +#else + base::FEATURE_ENABLED_BY_DEFAULT); +#endif BASE_FEATURE(kSchedulerSmoothnessForAnimatedScrolls, "SmoothnessModeForAnimatedScrolls",
diff --git a/cc/base/rolling_time_delta_history.cc b/cc/base/rolling_time_delta_history.cc index d967f94..429a125 100644 --- a/cc/base/rolling_time_delta_history.cc +++ b/cc/base/rolling_time_delta_history.cc
@@ -5,6 +5,7 @@ #include <stddef.h> #include <cmath> +#include <utility> #include "cc/base/rolling_time_delta_history.h"
diff --git a/cc/base/unique_notifier.cc b/cc/base/unique_notifier.cc index d714237..2717ab3 100644 --- a/cc/base/unique_notifier.cc +++ b/cc/base/unique_notifier.cc
@@ -4,6 +4,8 @@ #include "cc/base/unique_notifier.h" +#include <utility> + #include "base/functional/bind.h" #include "base/functional/callback_helpers.h" #include "base/location.h"
diff --git a/cc/benchmarks/micro_benchmark_controller_impl.cc b/cc/benchmarks/micro_benchmark_controller_impl.cc index fcaaeef..2250c2ac 100644 --- a/cc/benchmarks/micro_benchmark_controller_impl.cc +++ b/cc/benchmarks/micro_benchmark_controller_impl.cc
@@ -5,6 +5,7 @@ #include "cc/benchmarks/micro_benchmark_controller_impl.h" #include <string> +#include <utility> #include "base/containers/cxx20_erase.h" #include "base/functional/callback.h"
diff --git a/cc/benchmarks/micro_benchmark_controller_impl.h b/cc/benchmarks/micro_benchmark_controller_impl.h index 5cb033f..8a8f860 100644 --- a/cc/benchmarks/micro_benchmark_controller_impl.h +++ b/cc/benchmarks/micro_benchmark_controller_impl.h
@@ -5,6 +5,7 @@ #ifndef CC_BENCHMARKS_MICRO_BENCHMARK_CONTROLLER_IMPL_H_ #define CC_BENCHMARKS_MICRO_BENCHMARK_CONTROLLER_IMPL_H_ +#include <memory> #include <string> #include <vector>
diff --git a/cc/debug/rendering_stats.cc b/cc/debug/rendering_stats.cc index 4202758..fd36dc85 100644 --- a/cc/debug/rendering_stats.cc +++ b/cc/debug/rendering_stats.cc
@@ -4,6 +4,8 @@ #include "cc/debug/rendering_stats.h" +#include <utility> + namespace cc { RenderingStats::TimeDeltaList::TimeDeltaList() = default;
diff --git a/cc/input/layer_selection_bound.h b/cc/input/layer_selection_bound.h index 35a1301..87e04a6 100644 --- a/cc/input/layer_selection_bound.h +++ b/cc/input/layer_selection_bound.h
@@ -5,6 +5,8 @@ #ifndef CC_INPUT_LAYER_SELECTION_BOUND_H_ #define CC_INPUT_LAYER_SELECTION_BOUND_H_ +#include <string> + #include "cc/cc_export.h" #include "components/viz/common/quads/selection.h" #include "ui/gfx/geometry/point.h"
diff --git a/cc/layers/layer_list_iterator_unittest.cc b/cc/layers/layer_list_iterator_unittest.cc index acbba594..218e9bd 100644 --- a/cc/layers/layer_list_iterator_unittest.cc +++ b/cc/layers/layer_list_iterator_unittest.cc
@@ -5,6 +5,8 @@ #include "cc/layers/layer_list_iterator.h" #include <memory> +#include <unordered_map> +#include <utility> #include "base/containers/adapters.h" #include "cc/animation/animation_host.h"
diff --git a/cc/paint/decode_stashing_image_provider.cc b/cc/paint/decode_stashing_image_provider.cc index c1b58af..03e2c4f 100644 --- a/cc/paint/decode_stashing_image_provider.cc +++ b/cc/paint/decode_stashing_image_provider.cc
@@ -4,6 +4,8 @@ #include "cc/paint/decode_stashing_image_provider.h" +#include <utility> + namespace cc { DecodeStashingImageProvider::DecodeStashingImageProvider( ImageProvider* source_provider)
diff --git a/cc/paint/paint_image_generator.cc b/cc/paint/paint_image_generator.cc index 0ecaf26..890055c 100644 --- a/cc/paint/paint_image_generator.cc +++ b/cc/paint/paint_image_generator.cc
@@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <utility> #include <vector> #include "cc/paint/paint_image_generator.h"
diff --git a/cc/paint/transfer_cache_serialize_helper.h b/cc/paint/transfer_cache_serialize_helper.h index a4330ee..49c85792 100644 --- a/cc/paint/transfer_cache_serialize_helper.h +++ b/cc/paint/transfer_cache_serialize_helper.h
@@ -6,6 +6,7 @@ #define CC_PAINT_TRANSFER_CACHE_SERIALIZE_HELPER_H_ #include <set> +#include <utility> #include <vector> #include "cc/paint/paint_export.h"
diff --git a/cc/raster/tile_task.cc b/cc/raster/tile_task.cc index d5313ce..9312d7b9 100644 --- a/cc/raster/tile_task.cc +++ b/cc/raster/tile_task.cc
@@ -4,6 +4,8 @@ #include "cc/raster/tile_task.h" +#include <utility> + #include "base/check.h" namespace cc {
diff --git a/cc/resources/cross_thread_shared_bitmap.cc b/cc/resources/cross_thread_shared_bitmap.cc index ff957302..84a08f7 100644 --- a/cc/resources/cross_thread_shared_bitmap.cc +++ b/cc/resources/cross_thread_shared_bitmap.cc
@@ -4,6 +4,7 @@ #include "cc/resources/cross_thread_shared_bitmap.h" +#include <utility> namespace cc { CrossThreadSharedBitmap::CrossThreadSharedBitmap(const viz::SharedBitmapId& id,
diff --git a/cc/resources/shared_bitmap_id_registrar.cc b/cc/resources/shared_bitmap_id_registrar.cc index 839ee84..e6f43d2 100644 --- a/cc/resources/shared_bitmap_id_registrar.cc +++ b/cc/resources/shared_bitmap_id_registrar.cc
@@ -4,6 +4,8 @@ #include "cc/resources/shared_bitmap_id_registrar.h" +#include <utility> + #include "cc/layers/texture_layer.h" namespace cc {
diff --git a/cc/test/fake_layer_tree_frame_sink_client.h b/cc/test/fake_layer_tree_frame_sink_client.h index 2ea2dc86..0f16a23 100644 --- a/cc/test/fake_layer_tree_frame_sink_client.h +++ b/cc/test/fake_layer_tree_frame_sink_client.h
@@ -5,9 +5,10 @@ #ifndef CC_TEST_FAKE_LAYER_TREE_FRAME_SINK_CLIENT_H_ #define CC_TEST_FAKE_LAYER_TREE_FRAME_SINK_CLIENT_H_ +#include <vector> + #include "base/memory/raw_ptr.h" #include "cc/trees/layer_tree_frame_sink_client.h" - #include "cc/trees/managed_memory_policy.h" #include "components/viz/common/hit_test/hit_test_region_list.h"
diff --git a/cc/test/fake_mask_layer_impl.h b/cc/test/fake_mask_layer_impl.h index b564a1c1..b4c8984 100644 --- a/cc/test/fake_mask_layer_impl.h +++ b/cc/test/fake_mask_layer_impl.h
@@ -5,6 +5,8 @@ #ifndef CC_TEST_FAKE_MASK_LAYER_IMPL_H_ #define CC_TEST_FAKE_MASK_LAYER_IMPL_H_ +#include <memory> + #include "cc/layers/picture_layer_impl.h" #include "cc/raster/raster_source.h"
diff --git a/cc/test/fake_picture_layer_tiling_client.h b/cc/test/fake_picture_layer_tiling_client.h index f292d8d0..bb86cc6 100644 --- a/cc/test/fake_picture_layer_tiling_client.h +++ b/cc/test/fake_picture_layer_tiling_client.h
@@ -5,6 +5,8 @@ #ifndef CC_TEST_FAKE_PICTURE_LAYER_TILING_CLIENT_H_ #define CC_TEST_FAKE_PICTURE_LAYER_TILING_CLIENT_H_ +#include <memory> + #include "base/memory/raw_ptr.h" #include "cc/raster/raster_source.h" #include "cc/test/fake_tile_manager_client.h"
diff --git a/cc/test/fake_scoped_ui_resource.h b/cc/test/fake_scoped_ui_resource.h index e55b86b2..4d5cf2cc 100644 --- a/cc/test/fake_scoped_ui_resource.h +++ b/cc/test/fake_scoped_ui_resource.h
@@ -5,6 +5,8 @@ #ifndef CC_TEST_FAKE_SCOPED_UI_RESOURCE_H_ #define CC_TEST_FAKE_SCOPED_UI_RESOURCE_H_ +#include <memory> + #include "cc/resources/scoped_ui_resource.h" namespace cc {
diff --git a/cc/test/fake_video_frame_provider.h b/cc/test/fake_video_frame_provider.h index ce2544a..a7e8453 100644 --- a/cc/test/fake_video_frame_provider.h +++ b/cc/test/fake_video_frame_provider.h
@@ -5,6 +5,8 @@ #ifndef CC_TEST_FAKE_VIDEO_FRAME_PROVIDER_H_ #define CC_TEST_FAKE_VIDEO_FRAME_PROVIDER_H_ +#include <utility> + #include "base/memory/raw_ptr.h" #include "cc/layers/video_frame_provider.h" #include "media/base/video_frame.h"
diff --git a/cc/test/test_layer_tree_host_base.h b/cc/test/test_layer_tree_host_base.h index 12478798..ae72f96 100644 --- a/cc/test/test_layer_tree_host_base.h +++ b/cc/test/test_layer_tree_host_base.h
@@ -6,6 +6,7 @@ #define CC_TEST_TEST_LAYER_TREE_HOST_BASE_H_ #include <memory> +#include <utility> #include "base/memory/raw_ptr.h" #include "cc/test/fake_impl_task_runner_provider.h"
diff --git a/cc/test/test_paint_worklet_layer_painter.h b/cc/test/test_paint_worklet_layer_painter.h index 387f7f9..8084fb19 100644 --- a/cc/test/test_paint_worklet_layer_painter.h +++ b/cc/test/test_paint_worklet_layer_painter.h
@@ -5,6 +5,8 @@ #ifndef CC_TEST_TEST_PAINT_WORKLET_LAYER_PAINTER_H_ #define CC_TEST_TEST_PAINT_WORKLET_LAYER_PAINTER_H_ +#include <utility> + #include "cc/paint/paint_worklet_layer_painter.h" #include "testing/gmock/include/gmock/gmock.h"
diff --git a/cc/test/test_ukm_recorder_factory.h b/cc/test/test_ukm_recorder_factory.h index b1a76ad..0704485 100644 --- a/cc/test/test_ukm_recorder_factory.h +++ b/cc/test/test_ukm_recorder_factory.h
@@ -5,6 +5,8 @@ #ifndef CC_TEST_TEST_UKM_RECORDER_FACTORY_H_ #define CC_TEST_TEST_UKM_RECORDER_FACTORY_H_ +#include <memory> + #include "cc/trees/ukm_manager.h" namespace cc {
diff --git a/cc/tiles/eviction_tile_priority_queue.h b/cc/tiles/eviction_tile_priority_queue.h index b26ff4e2..a8c4749 100644 --- a/cc/tiles/eviction_tile_priority_queue.h +++ b/cc/tiles/eviction_tile_priority_queue.h
@@ -5,6 +5,7 @@ #ifndef CC_TILES_EVICTION_TILE_PRIORITY_QUEUE_H_ #define CC_TILES_EVICTION_TILE_PRIORITY_QUEUE_H_ +#include <memory> #include <set> #include <utility> #include <vector>
diff --git a/cc/tiles/frame_viewer_instrumentation.cc b/cc/tiles/frame_viewer_instrumentation.cc index 1f01c6e..e4a3d70 100644 --- a/cc/tiles/frame_viewer_instrumentation.cc +++ b/cc/tiles/frame_viewer_instrumentation.cc
@@ -4,6 +4,9 @@ #include "cc/tiles/frame_viewer_instrumentation.h" +#include <memory> +#include <utility> + #include "components/viz/common/traced_value.h" namespace cc {
diff --git a/cc/tiles/mipmap_util.cc b/cc/tiles/mipmap_util.cc index 47fd8c8..37779072 100644 --- a/cc/tiles/mipmap_util.cc +++ b/cc/tiles/mipmap_util.cc
@@ -4,6 +4,9 @@ #include "cc/tiles/mipmap_util.h" +#include <algorithm> +#include <limits> + #include "base/numerics/safe_math.h" namespace cc {
diff --git a/cc/tiles/raster_tile_priority_queue.cc b/cc/tiles/raster_tile_priority_queue.cc index 35b1580b..d51d9cf 100644 --- a/cc/tiles/raster_tile_priority_queue.cc +++ b/cc/tiles/raster_tile_priority_queue.cc
@@ -4,6 +4,8 @@ #include "cc/tiles/raster_tile_priority_queue.h" +#include <utility> + #include "base/notreached.h" #include "cc/tiles/raster_tile_priority_queue_all.h" #include "cc/tiles/raster_tile_priority_queue_required.h"
diff --git a/cc/tiles/raster_tile_priority_queue.h b/cc/tiles/raster_tile_priority_queue.h index e61a082..cca10301 100644 --- a/cc/tiles/raster_tile_priority_queue.h +++ b/cc/tiles/raster_tile_priority_queue.h
@@ -5,6 +5,7 @@ #ifndef CC_TILES_RASTER_TILE_PRIORITY_QUEUE_H_ #define CC_TILES_RASTER_TILE_PRIORITY_QUEUE_H_ +#include <memory> #include <vector> #include "cc/cc_export.h"
diff --git a/cc/tiles/raster_tile_priority_queue_required.cc b/cc/tiles/raster_tile_priority_queue_required.cc index f40e95a..a459eec 100644 --- a/cc/tiles/raster_tile_priority_queue_required.cc +++ b/cc/tiles/raster_tile_priority_queue_required.cc
@@ -4,6 +4,8 @@ #include "cc/tiles/raster_tile_priority_queue_required.h" +#include <utility> + #include "cc/tiles/tiling_set_raster_queue_required.h" namespace cc {
diff --git a/cc/tiles/raster_tile_priority_queue_required.h b/cc/tiles/raster_tile_priority_queue_required.h index b54a2ca..914a22a1 100644 --- a/cc/tiles/raster_tile_priority_queue_required.h +++ b/cc/tiles/raster_tile_priority_queue_required.h
@@ -5,6 +5,7 @@ #ifndef CC_TILES_RASTER_TILE_PRIORITY_QUEUE_REQUIRED_H_ #define CC_TILES_RASTER_TILE_PRIORITY_QUEUE_REQUIRED_H_ +#include <memory> #include <vector> #include "cc/layers/picture_layer_impl.h"
diff --git a/cc/tiles/tile_task_manager.h b/cc/tiles/tile_task_manager.h index 26487cb..441314f 100644 --- a/cc/tiles/tile_task_manager.h +++ b/cc/tiles/tile_task_manager.h
@@ -6,6 +6,7 @@ #define CC_TILES_TILE_TASK_MANAGER_H_ #include <stddef.h> +#include <memory> #include "base/memory/raw_ptr.h" #include "cc/raster/raster_buffer_provider.h"
diff --git a/cc/trees/frame_rate_estimator_unittest.cc b/cc/trees/frame_rate_estimator_unittest.cc index 93d0e0a6..ee4c755 100644 --- a/cc/trees/frame_rate_estimator_unittest.cc +++ b/cc/trees/frame_rate_estimator_unittest.cc
@@ -4,6 +4,8 @@ #include "cc/trees/frame_rate_estimator.h" +#include <memory> + #include "base/test/test_simple_task_runner.h" #include "base/time/time.h" #include "components/viz/common/frame_sinks/begin_frame_args.h"
diff --git a/chrome/app/os_settings_strings.grdp b/chrome/app/os_settings_strings.grdp index ca4bd30a..ce4bd906 100644 --- a/chrome/app/os_settings_strings.grdp +++ b/chrome/app/os_settings_strings.grdp
@@ -2478,6 +2478,15 @@ <message name="IDS_SETTINGS_AUDIO_INPUT_GAIN_TITLE" desc="In Device Settings, the title of the slider under the input section in audio settings subpage. This slider controls the microphone's gain setting." translateable="false"> Gain </message> + <message name="IDS_SETTINGS_AUDIO_INPUT_MUTE_BUTTON_ARIA_LABEL_NOT_MUTED" desc="In Device Settings, the aria label for the input mute button when not muted." translateable="false"> + Toggle mic. Mic is on, toggling will mute input. + </message> + <message name="IDS_SETTINGS_AUDIO_INPUT_MUTE_BUTTON_ARIA_LABEL_MUTED" desc="In Device Settings, the aria label for the input mute button when muted." translateable="false"> + Toggle mic. Mic is muted. + </message> + <message name="IDS_SETTINGS_AUDIO_INPUT_MUTE_BUTTON_ARIA_LABEL_MUTED_BY_HARDWARE_SWITCH" desc="In Device Settings, the aria label for the input mute button when microphone mute switch is turned on." translateable="false"> + Device's microphone button is turned off. + </message> <message name="IDS_SETTINGS_AUDIO_INPUT_NOISE_CANCELLATION_TITLE" desc="In Device Settings, the title of the noise cancellation toggle under the input section in audio settings subpage." translateable="false"> Noise Cancellation </message> @@ -2520,6 +2529,12 @@ <message name="IDS_SETTINGS_AUDIO_MUTED_EXTERNALLY_TOOLTIP" desc="In Device Settings, the tooltip used for the input and output mute buttons shown when the device is muted by hardware/switch." translateable="false"> Muted by hardware/switch </message> + <message name="IDS_SETTINGS_AUDIO_OUTPUT_MUTE_BUTTON_ARIA_LABEL_NOT_MUTED" desc="In Device Settings, the aria label for the output mute button when not muted." translateable="false"> + Toggle volume. Volume is on, toggling will mute audio. + </message> + <message name="IDS_SETTINGS_AUDIO_OUTPUT_MUTE_BUTTON_ARIA_LABEL_MUTED" desc="In Device Settings, the aria label for the output mute button when not muted." translateable="false"> + Toggle volume. Volume is muted. + </message> <!-- Device pointer page (OS settings) --> <message name="IDS_SETTINGS_MOUSE_TITLE" desc="In Device Settings, the title of the mouse settings subpage.">
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 842dc9d..716224e4 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -7569,12 +7569,6 @@ FEATURE_VALUE_TYPE(printing::features::kEnableOopPrintDrivers)}, #endif - {"enable-browsing-data-lifetime-manager", - flag_descriptions::kEnableBrowsingDataLifetimeManagerName, - flag_descriptions::kEnableBrowsingDataLifetimeManagerDescription, kOsAll, - FEATURE_VALUE_TYPE( - browsing_data::features::kEnableBrowsingDataLifetimeManager)}, - {"privacy-sandbox-ads-apis", flag_descriptions::kPrivacySandboxAdsAPIsOverrideName, flag_descriptions::kPrivacySandboxAdsAPIsOverrideDescription, kOsAll,
diff --git a/chrome/browser/ash/BUILD.gn b/chrome/browser/ash/BUILD.gn index c5afc286..e3343199 100644 --- a/chrome/browser/ash/BUILD.gn +++ b/chrome/browser/ash/BUILD.gn
@@ -552,6 +552,8 @@ "arc/session/arc_session_manager.cc", "arc/session/arc_session_manager.h", "arc/session/arc_session_manager_observer.h", + "arc/session/arc_vm_data_migration_necessity_checker.cc", + "arc/session/arc_vm_data_migration_necessity_checker.h", "arc/sharesheet/arc_sharesheet_bridge.cc", "arc/sharesheet/arc_sharesheet_bridge.h", "arc/survey/arc_survey_service.cc", @@ -3797,6 +3799,7 @@ "//chromeos/ash/components/dbus:vm_permission_service_proto", "//chromeos/ash/components/dbus:vm_sk_forwarding_proto", "//chromeos/ash/components/dbus/arc", + "//chromeos/ash/components/dbus/arc:arcvm_data_migrator_proto_lib", "//chromeos/ash/components/dbus/audio", "//chromeos/ash/components/dbus/biod", "//chromeos/ash/components/dbus/biod:biod_proto", @@ -4942,6 +4945,7 @@ "arc/session/arc_play_store_enabled_preference_handler_unittest.cc", "arc/session/arc_provisioning_result_unittest.cc", "arc/session/arc_session_manager_unittest.cc", + "arc/session/arc_vm_data_migration_necessity_checker_unittest.cc", "arc/sharesheet/arc_sharesheet_bridge_unittest.cc", "arc/survey/arc_survey_service_unittest.cc", "arc/tracing/arc_app_performance_tracing_unittest.cc", @@ -5790,6 +5794,7 @@ "//chromeos/ash/components/dbus", "//chromeos/ash/components/dbus:vm_applications_apps_proto", "//chromeos/ash/components/dbus/anomaly_detector", + "//chromeos/ash/components/dbus/arc", "//chromeos/ash/components/dbus/attestation", "//chromeos/ash/components/dbus/attestation:attestation_proto", "//chromeos/ash/components/dbus/audio",
diff --git a/chrome/browser/ash/arc/arc_util.cc b/chrome/browser/ash/arc/arc_util.cc index acd7f0ce..a9a220a 100644 --- a/chrome/browser/ash/arc/arc_util.cc +++ b/chrome/browser/ash/arc/arc_util.cc
@@ -146,6 +146,7 @@ break; case ArcSessionManager::State::CHECKING_REQUIREMENTS: case ArcSessionManager::State::REMOVING_DATA_DIR: + case ArcSessionManager::State::CHECKING_DATA_MIGRATION_NECESSITY: case ArcSessionManager::State::READY: case ArcSessionManager::State::ACTIVE: case ArcSessionManager::State::STOPPING:
diff --git a/chrome/browser/ash/arc/input_overlay/ui/edit_finish_view.cc b/chrome/browser/ash/arc/input_overlay/ui/edit_finish_view.cc index ea11b5b..4df2324 100644 --- a/chrome/browser/ash/arc/input_overlay/ui/edit_finish_view.cc +++ b/chrome/browser/ash/arc/input_overlay/ui/edit_finish_view.cc
@@ -16,7 +16,6 @@ #include "third_party/skia/include/core/SkColor.h" #include "ui/base/l10n/l10n_util.h" #include "ui/color/color_id.h" -#include "ui/compositor/layer.h" #include "ui/events/event.h" #include "ui/gfx/geometry/size.h" #include "ui/views/animation/flood_fill_ink_drop_ripple.h" @@ -36,7 +35,6 @@ constexpr int kViewCornerRadius = 16; constexpr int kViewBackgroundColor = SkColorSetA(SK_ColorBLACK, 0xCC /*80%*/); constexpr int kParentPadding = 16; -constexpr int kBackgroundBlur = 10; // Space between children. constexpr int kSpaceRow = 4; // Alpha view features. @@ -231,13 +229,6 @@ kViewCornerRadius) : views::CreateSolidBackground(SK_ColorTRANSPARENT)); - if (AllowReposition()) { - SetPaintToLayer(); - layer()->SetFillsBoundsOpaquely(false); - layer()->SetBackgroundBlur(kBackgroundBlur); - layer()->SetRoundedCornerRadius(gfx::RoundedCornersF(kViewCornerRadius)); - } - auto on_mouse_pressed_callback = base::BindRepeating( &EditFinishView::OnMousePressed, base::Unretained(this)); auto on_mouse_dragged_callback = base::BindRepeating(
diff --git a/chrome/browser/ash/arc/input_overlay/ui/menu_entry_view.cc b/chrome/browser/ash/arc/input_overlay/ui/menu_entry_view.cc index 26b658f..b55fbc7 100644 --- a/chrome/browser/ash/arc/input_overlay/ui/menu_entry_view.cc +++ b/chrome/browser/ash/arc/input_overlay/ui/menu_entry_view.cc
@@ -13,7 +13,6 @@ #include "chrome/browser/ash/arc/input_overlay/util.h" #include "components/vector_icons/vector_icons.h" #include "ui/color/color_id.h" -#include "ui/compositor/layer.h" #include "ui/events/event.h" #include "ui/events/types/event_type.h" #include "ui/gfx/color_utils.h" @@ -34,7 +33,6 @@ constexpr SkColor kHoverColor = SkColorSetA(gfx::kGoogleBlue600, 0x66 /*40%*/); constexpr int kParentPadding = 16; -constexpr int kBackgroundBlur = 20; constexpr int kMenuEntrySize = 48; constexpr int kMenuEntryIconSize = 24; constexpr int kMenuEntryCornerRadius = 8; @@ -67,10 +65,6 @@ SetImageModel(views::Button::STATE_NORMAL, game_icon); SetBackground(views::CreateRoundedRectBackground(kDefaultColor, kMenuEntryCornerRadius)); - SetPaintToLayer(); - layer()->SetFillsBoundsOpaquely(false); - layer()->SetBackgroundBlur(kBackgroundBlur); - layer()->SetRoundedCornerRadius(gfx::RoundedCornersF(kMenuEntryCornerRadius)); SetSize(allow_reposition_ ? gfx::Size(kMenuEntrySize, kMenuEntrySize)
diff --git a/chrome/browser/ash/arc/session/arc_session_manager.cc b/chrome/browser/ash/arc/session/arc_session_manager.cc index 3946995..0b3548f2 100644 --- a/chrome/browser/ash/arc/session/arc_session_manager.cc +++ b/chrome/browser/ash/arc/session/arc_session_manager.cc
@@ -22,6 +22,7 @@ #include "ash/components/arc/session/serial_number_util.h" #include "ash/constants/ash_switches.h" #include "base/command_line.h" +#include "base/feature_list.h" #include "base/functional/bind.h" #include "base/functional/callback_helpers.h" #include "base/logging.h" @@ -769,8 +770,6 @@ multi_user_util::GetAccountIdFromProfile(profile_)); data_remover_ = std::make_unique<ArcDataRemover>(prefs, cryptohome_id); - arc_session_runner_->set_use_virtio_blk_data(ShouldUseVirtioBlkData(prefs)); - // Chrome may be shut down before completing ARC data removal. // For such a case, start removing the data now, if necessary. MaybeStartArcDataRemoval(); @@ -810,6 +809,9 @@ case State::REMOVING_DATA_DIR: // When data removing is done, |state_| will be set to STOPPED. // Do nothing here. + case State::CHECKING_DATA_MIGRATION_NECESSITY: + // Checking whether /data migration is necessary. |state_| will be set to + // STOPPED when the check is done. Do nothing. case State::STOPPING: // Now ARC is stopping. Do nothing here. VLOG(1) << "Skipping session shutdown because state is: " << state_; @@ -973,7 +975,8 @@ DCHECK(profile_); DCHECK(enable_requested_); DCHECK(state_ == State::STOPPED || state_ == State::STOPPING || - state_ == State::REMOVING_DATA_DIR) + state_ == State::REMOVING_DATA_DIR || + state_ == State::CHECKING_DATA_MIGRATION_NECESSITY) << state_; if (state_ != State::STOPPED) { @@ -1455,12 +1458,75 @@ // We may have to avoid it. } - MaybeReenableArc(); + if (!base::FeatureList::IsEnabled(kEnableArcVmDataMigration) || + GetArcVmDataMigrationStatus(profile_->GetPrefs()) == + ArcVmDataMigrationStatus::kFinished) { + // No need to check the necessity of ARCVM /data migration. + MaybeReenableArc(); + return; + } + + if (GetArcVmDataMigrationStatus(profile_->GetPrefs()) == + ArcVmDataMigrationStatus::kStarted) { + VLOG(1) << "ARCVM /data migration is in progress. Restarting Chrome session" + << " to resume the migration"; + chrome::AttemptRestart(); + return; + } + + CheckArcVmDataMigrationNecessity(base::BindOnce( + &ArcSessionManager::MaybeReenableArc, weak_ptr_factory_.GetWeakPtr())); +} + +void ArcSessionManager::CheckArcVmDataMigrationNecessity( + base::OnceClosure callback) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + + DCHECK_EQ(state_, State::STOPPED); + state_ = State::CHECKING_DATA_MIGRATION_NECESSITY; + + DCHECK(profile_); + DCHECK(!arc_vm_data_migration_necessity_checker_); + arc_vm_data_migration_necessity_checker_ = + std::make_unique<ArcVmDataMigrationNecessityChecker>(profile_); + arc_vm_data_migration_necessity_checker_->Check( + base::BindOnce(&ArcSessionManager::OnArcVmDataMigrationNecessityChecked, + weak_ptr_factory_.GetWeakPtr(), std::move(callback))); +} + +void ArcSessionManager::OnArcVmDataMigrationNecessityChecked( + base::OnceClosure callback, + absl::optional<bool> result) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + + DCHECK_EQ(state_, State::CHECKING_DATA_MIGRATION_NECESSITY); + state_ = State::STOPPED; + + DCHECK(profile_); + DCHECK(arc_vm_data_migration_necessity_checker_); + arc_vm_data_migration_necessity_checker_.reset(); + + // We assume that the migration is needed when |result| has no value, i.e., + // when ArcVmDataMigrationNecessityChecker could not determine the necessity. + if (!result.value_or(true)) { + VLOG(1) << "No need to perform ARCVM /data migration. Marking the migration" + << " as finished"; + SetArcVmDataMigrationStatus(profile_->GetPrefs(), + ArcVmDataMigrationStatus::kFinished); + } + std::move(callback).Run(); } void ArcSessionManager::MaybeReenableArc() { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK_EQ(state_, State::STOPPED); + DCHECK(profile_); + + // Whether to use virtio-blk for /data depends on the status of ARCVM /data + // migration, which can be updated between Initialize() and MaybeReenableArc() + // by CheckArcVmDataMigrationNecessity(). Hence it should be set here. + arc_session_runner_->set_use_virtio_blk_data( + ShouldUseVirtioBlkData(profile_->GetPrefs())); if (!reenable_arc_) { // Re-enabling is not triggered. Do nothing. @@ -1706,6 +1772,7 @@ MAP_STATE(NOT_INITIALIZED); MAP_STATE(STOPPED); MAP_STATE(CHECKING_REQUIREMENTS); + MAP_STATE(CHECKING_DATA_MIGRATION_NECESSITY); MAP_STATE(REMOVING_DATA_DIR); MAP_STATE(READY); MAP_STATE(ACTIVE);
diff --git a/chrome/browser/ash/arc/session/arc_session_manager.h b/chrome/browser/ash/arc/session/arc_session_manager.h index 13027a5d..47d273dd 100644 --- a/chrome/browser/ash/arc/session/arc_session_manager.h +++ b/chrome/browser/ash/arc/session/arc_session_manager.h
@@ -24,6 +24,7 @@ #include "chrome/browser/ash/arc/session/arc_app_id_provider_impl.h" #include "chrome/browser/ash/arc/session/arc_requirement_checker.h" #include "chrome/browser/ash/arc/session/arc_session_manager_observer.h" +#include "chrome/browser/ash/arc/session/arc_vm_data_migration_necessity_checker.h" #include "chrome/browser/ash/guest_os/public/guest_os_mount_provider_registry.h" #include "chrome/browser/ash/policy/arc/android_management_client.h" #include "chromeos/ash/components/dbus/concierge/concierge_client.h" @@ -80,6 +81,10 @@ // State is ACTIVE, instead. // REMOVING_DATA_DIR: When ARC is disabled, the data directory is removed. // While removing is processed, ARC cannot be started. This is the state. + // CHECKING_DATA_MIGRATION_NECESSITY: When ARC /data migration is enabled but + // not started yet, we need to check whether the migration is necessary by + // inspecting the content of /data. ARC cannot be started while the check is + // being performed, which is indicated by this state. // READY: ARC is ready to run, but not running yet. This state is skipped on // the first boot case. // ACTIVE: ARC is running. @@ -109,6 +114,8 @@ // immediately. // REMOVING_DATA_DIR: Eventually state will become STOPPED. Do nothing // immediately. + // CHECKING_DATA_MIGRATION_NECESSITY: Eventually state will become STOPPED. + // Do nothing immediately. // // TODO(hidehiko): Fix the state machine, and update the comment including // relationship with |enable_requested_|. @@ -117,6 +124,7 @@ STOPPED, CHECKING_REQUIREMENTS, REMOVING_DATA_DIR, + CHECKING_DATA_MIGRATION_NECESSITY, READY, ACTIVE, STOPPING, @@ -407,10 +415,18 @@ // Starts to remove ARC data, if it is requested via RequestArcDataRemoval(). // On completion, OnArcDataRemoved() is called. // If not requested, just skipping the data removal, and moves to - // MaybeReenableArc() directly. + // MaybeReenableArc() or CheckArcVmDataMigrationNecessity() directly. void MaybeStartArcDataRemoval(); void OnArcDataRemoved(absl::optional<bool> success); + // Checks whether /data migration is needed for enabling virtio-blk /data. + // On completion, OnArcVmDataMigrationNecessityChecked() is called. + // ArcSessionRunner::set_use_virtio_blk_data() should be called after the + // check is finished but before ARC is enabled in MaybeReenableArc(). + void CheckArcVmDataMigrationNecessity(base::OnceClosure callback); + void OnArcVmDataMigrationNecessityChecked(base::OnceClosure callback, + absl::optional<bool> result); + // On ARC session stopped and/or data removal completion, this is called // so that, if necessary, ARC session is restarted. // TODO(hidehiko): This can be removed after the racy state machine @@ -465,6 +481,9 @@ std::unique_ptr<ArcSupportHost> support_host_; std::unique_ptr<ArcDataRemover> data_remover_; + std::unique_ptr<ArcVmDataMigrationNecessityChecker> + arc_vm_data_migration_necessity_checker_; + ArcRequirementChecker::AndroidManagementCheckerFactory android_management_checker_factory_; std::unique_ptr<ArcRequirementChecker> requirement_checker_;
diff --git a/chrome/browser/ash/arc/session/arc_session_manager_unittest.cc b/chrome/browser/ash/arc/session/arc_session_manager_unittest.cc index 4167df3..e9d2a77 100644 --- a/chrome/browser/ash/arc/session/arc_session_manager_unittest.cc +++ b/chrome/browser/ash/arc/session/arc_session_manager_unittest.cc
@@ -57,6 +57,8 @@ #include "chrome/browser/ui/webui/ash/login/arc_terms_of_service_screen_handler.h" #include "chrome/test/base/testing_browser_process.h" #include "chrome/test/base/testing_profile.h" +#include "chromeos/ash/components/dbus/arc/arcvm_data_migrator_client.h" +#include "chromeos/ash/components/dbus/arc/fake_arcvm_data_migrator_client.h" #include "chromeos/ash/components/dbus/concierge/concierge_client.h" #include "chromeos/ash/components/dbus/session_manager/session_manager_client.h" #include "chromeos/ash/components/dbus/upstart/upstart_client.h" @@ -286,6 +288,7 @@ } void SetUp() override { + ash::ArcVmDataMigratorClient::InitializeFake(); ash::ConciergeClient::InitializeFake(/*fake_cicerone_client=*/nullptr); chromeos::PowerManagerClient::InitializeFake(); ash::SessionManagerClient::InitializeFakeInMemory(); @@ -321,6 +324,7 @@ ash::SessionManagerClient::Shutdown(); chromeos::PowerManagerClient::Shutdown(); ash::ConciergeClient::Shutdown(); + ash::ArcVmDataMigratorClient::Shutdown(); } ash::FakeChromeUserManager* GetFakeUserManager() const { @@ -855,6 +859,70 @@ arc_session_manager()->Shutdown(); } +TEST_F(ArcSessionManagerTest, ArcVmDataMigrationNecessityChecker_Necessary) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature(kEnableArcVmDataMigration); + SetArcVmDataMigrationStatus(profile()->GetPrefs(), + ArcVmDataMigrationStatus::kUnnotified); + ash::FakeArcVmDataMigratorClient::Get()->set_has_data_to_migrate(true); + + arc_session_manager()->SetProfile(profile()); + arc_session_manager()->Initialize(); + arc_session_manager()->RequestEnable(); + base::RunLoop().RunUntilIdle(); + + EXPECT_FALSE(arc_session_manager() + ->GetArcSessionRunnerForTesting() + ->use_virtio_blk_data()); + EXPECT_EQ(GetArcVmDataMigrationStatus(profile()->GetPrefs()), + ArcVmDataMigrationStatus::kUnnotified); + + arc_session_manager()->Shutdown(); +} + +TEST_F(ArcSessionManagerTest, ArcVmDataMigrationNecessityChecker_Unnecessary) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature(kEnableArcVmDataMigration); + SetArcVmDataMigrationStatus(profile()->GetPrefs(), + ArcVmDataMigrationStatus::kUnnotified); + ash::FakeArcVmDataMigratorClient::Get()->set_has_data_to_migrate(false); + + arc_session_manager()->SetProfile(profile()); + arc_session_manager()->Initialize(); + arc_session_manager()->RequestEnable(); + base::RunLoop().RunUntilIdle(); + + EXPECT_TRUE(arc_session_manager() + ->GetArcSessionRunnerForTesting() + ->use_virtio_blk_data()); + EXPECT_EQ(GetArcVmDataMigrationStatus(profile()->GetPrefs()), + ArcVmDataMigrationStatus::kFinished); + + arc_session_manager()->Shutdown(); +} + +TEST_F(ArcSessionManagerTest, ArcVmDataMigrationNecessityChecker_Undetermined) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature(kEnableArcVmDataMigration); + SetArcVmDataMigrationStatus(profile()->GetPrefs(), + ArcVmDataMigrationStatus::kUnnotified); + ash::FakeArcVmDataMigratorClient::Get()->set_has_data_to_migrate( + absl::nullopt); + + arc_session_manager()->SetProfile(profile()); + arc_session_manager()->Initialize(); + arc_session_manager()->RequestEnable(); + base::RunLoop().RunUntilIdle(); + + EXPECT_FALSE(arc_session_manager() + ->GetArcSessionRunnerForTesting() + ->use_virtio_blk_data()); + EXPECT_EQ(GetArcVmDataMigrationStatus(profile()->GetPrefs()), + ArcVmDataMigrationStatus::kUnnotified); + + arc_session_manager()->Shutdown(); +} + TEST_F(ArcSessionManagerTest, RegularToChildTransition) { // Emulate the situation where a regular user has transitioned to a child // account.
diff --git a/chrome/browser/ash/arc/session/arc_vm_data_migration_necessity_checker.cc b/chrome/browser/ash/arc/session/arc_vm_data_migration_necessity_checker.cc new file mode 100644 index 0000000..28c0d91 --- /dev/null +++ b/chrome/browser/ash/arc/session/arc_vm_data_migration_necessity_checker.cc
@@ -0,0 +1,100 @@ +// Copyright 2023 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/arc/session/arc_vm_data_migration_necessity_checker.h" + +#include <string> +#include <vector> + +#include "ash/components/arc/arc_features.h" +#include "ash/components/arc/arc_prefs.h" +#include "ash/components/arc/arc_util.h" +#include "ash/components/arc/session/arc_vm_client_adapter.h" +#include "base/feature_list.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/ash/multi_user/multi_user_util.h" +#include "chromeos/ash/components/cryptohome/cryptohome_parameters.h" +#include "chromeos/ash/components/dbus/arc/arcvm_data_migrator_client.h" +#include "chromeos/ash/components/dbus/arcvm_data_migrator/arcvm_data_migrator.pb.h" +#include "components/account_id/account_id.h" + +namespace arc { + +namespace { + +std::string GetChromeOsUser(Profile* profile) { + const AccountId account(multi_user_util::GetAccountIdFromProfile(profile)); + return cryptohome::CreateAccountIdentifierFromAccountId(account).account_id(); +} + +} // namespace + +ArcVmDataMigrationNecessityChecker::ArcVmDataMigrationNecessityChecker( + Profile* profile) + : profile_(profile) { + DCHECK(profile_); +} + +ArcVmDataMigrationNecessityChecker::~ArcVmDataMigrationNecessityChecker() = + default; + +void ArcVmDataMigrationNecessityChecker::Check(CheckCallback callback) { + DCHECK(base::FeatureList::IsEnabled(kEnableArcVmDataMigration)); + if (base::FeatureList::IsEnabled(kEnableVirtioBlkForData)) { + // No migration needs to be performed if virtio-blk /data is forciblly + // enabled via a feature. + std::move(callback).Run(false); + return; + } + + if (GetArcVmDataMigrationStatus(profile_->GetPrefs()) == + ArcVmDataMigrationStatus::kFinished) { + // No migration needs to be performed if it's already finished. + std::move(callback).Run(false); + return; + } + + std::vector<std::string> environment = {"CHROMEOS_USER=" + + GetChromeOsUser(profile_)}; + std::deque<JobDesc> jobs{JobDesc{kArcVmDataMigratorJobName, + UpstartOperation::JOB_STOP_AND_START, + std::move(environment)}}; + ConfigureUpstartJobs( + std::move(jobs), + base::BindOnce( + &ArcVmDataMigrationNecessityChecker::OnArcVmDataMigratorStarted, + weak_ptr_factory_.GetWeakPtr(), std::move(callback))); +} + +void ArcVmDataMigrationNecessityChecker::OnArcVmDataMigratorStarted( + CheckCallback callback, + bool result) { + if (!result) { + LOG(ERROR) << "Failed to start arcvm-data-migrator"; + std::move(callback).Run(absl::nullopt); + return; + } + + DCHECK(ash::ArcVmDataMigratorClient::Get()); + data_migrator::HasDataToMigrateRequest request; + request.set_username(GetChromeOsUser(profile_)); + ash::ArcVmDataMigratorClient::Get()->HasDataToMigrate( + request, + base::BindOnce( + &ArcVmDataMigrationNecessityChecker::OnHasDataToMigrateResponse, + weak_ptr_factory_.GetWeakPtr(), std::move(callback))); +} + +void ArcVmDataMigrationNecessityChecker::OnHasDataToMigrateResponse( + CheckCallback callback, + absl::optional<bool> response) { + if (!response.has_value()) { + LOG(ERROR) << "Failed to check whether /data has any content: " + << "No valid D-Bus response"; + } + + std::move(callback).Run(response); +} + +} // namespace arc
diff --git a/chrome/browser/ash/arc/session/arc_vm_data_migration_necessity_checker.h b/chrome/browser/ash/arc/session/arc_vm_data_migration_necessity_checker.h new file mode 100644 index 0000000..1677447 --- /dev/null +++ b/chrome/browser/ash/arc/session/arc_vm_data_migration_necessity_checker.h
@@ -0,0 +1,49 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_ASH_ARC_SESSION_ARC_VM_DATA_MIGRATION_NECESSITY_CHECKER_H_ +#define CHROME_BROWSER_ASH_ARC_SESSION_ARC_VM_DATA_MIGRATION_NECESSITY_CHECKER_H_ + +#include "base/functional/callback.h" +#include "base/memory/weak_ptr.h" +#include "third_party/abseil-cpp/absl/types/optional.h" + +class Profile; + +namespace arc { + +// Class to check whether /data migration needs to be performed for enabling +// virtio-blk /data on ARCVM. +class ArcVmDataMigrationNecessityChecker { + public: + explicit ArcVmDataMigrationNecessityChecker(Profile* profile); + ArcVmDataMigrationNecessityChecker( + const ArcVmDataMigrationNecessityChecker&) = delete; + ArcVmDataMigrationNecessityChecker& operator=( + const ArcVmDataMigrationNecessityChecker&) = delete; + ~ArcVmDataMigrationNecessityChecker(); + + using CheckCallback = base::OnceCallback<void(absl::optional<bool> result)>; + + // Checks whether /data migration needs to be performed. When the migration is + // necessary/unnecessary, |callback| is called with true/false, respectively. + // On error, |callback| is called with absl::nullopt. + // Should be called when ARCVM /data migration is enabled. + void Check(CheckCallback callback); + + private: + void OnArcVmDataMigratorStarted(CheckCallback callback, bool result); + + void OnHasDataToMigrateResponse(CheckCallback callback, + absl::optional<bool> response); + + Profile* const profile_; + + base::WeakPtrFactory<ArcVmDataMigrationNecessityChecker> weak_ptr_factory_{ + this}; +}; + +} // namespace arc + +#endif // CHROME_BROWSER_ASH_ARC_SESSION_ARC_VM_DATA_MIGRATION_NECESSITY_CHECKER_H_
diff --git a/chrome/browser/ash/arc/session/arc_vm_data_migration_necessity_checker_unittest.cc b/chrome/browser/ash/arc/session/arc_vm_data_migration_necessity_checker_unittest.cc new file mode 100644 index 0000000..c08b3742 --- /dev/null +++ b/chrome/browser/ash/arc/session/arc_vm_data_migration_necessity_checker_unittest.cc
@@ -0,0 +1,144 @@ +// Copyright 2023 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/arc/session/arc_vm_data_migration_necessity_checker.h" + +#include "ash/components/arc/arc_features.h" +#include "ash/components/arc/arc_prefs.h" +#include "ash/components/arc/arc_util.h" +#include "ash/components/arc/session/arc_vm_client_adapter.h" +#include "base/test/bind.h" +#include "base/test/scoped_feature_list.h" +#include "chrome/test/base/testing_profile.h" +#include "chromeos/ash/components/dbus/arc/arcvm_data_migrator_client.h" +#include "chromeos/ash/components/dbus/arc/fake_arcvm_data_migrator_client.h" +#include "chromeos/ash/components/dbus/upstart/fake_upstart_client.h" +#include "chromeos/ash/components/dbus/upstart/upstart_client.h" +#include "content/public/test/browser_task_environment.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/abseil-cpp/absl/types/optional.h" + +namespace arc { +namespace { + +class ArcVmDataMigrationNecessityCheckerTest : public testing::Test { + public: + ArcVmDataMigrationNecessityCheckerTest() = default; + ~ArcVmDataMigrationNecessityCheckerTest() override = default; + + void SetUp() override { + ash::UpstartClient::InitializeFake(); + ash::ArcVmDataMigratorClient::InitializeFake(); + + profile_ = std::make_unique<TestingProfile>(); + checker_ = + std::make_unique<ArcVmDataMigrationNecessityChecker>(profile_.get()); + } + + void TearDown() override { + checker_.reset(); + profile_.reset(); + + ash::ArcVmDataMigratorClient::Shutdown(); + ash::UpstartClient::Shutdown(); + } + + protected: + content::BrowserTaskEnvironment task_environment_; + std::unique_ptr<TestingProfile> profile_; + std::unique_ptr<ArcVmDataMigrationNecessityChecker> checker_; +}; + +TEST_F(ArcVmDataMigrationNecessityCheckerTest, HasDataToMigrate) { + absl::optional<bool> migration_needed = false; + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature(kEnableArcVmDataMigration); + ash::FakeArcVmDataMigratorClient::Get()->set_has_data_to_migrate(true); + checker_->Check(base::BindLambdaForTesting( + [&migration_needed](absl::optional<bool> result) { + migration_needed = result; + })); + base::RunLoop().RunUntilIdle(); + EXPECT_TRUE(migration_needed.has_value()); + EXPECT_TRUE(migration_needed.value()); +} + +TEST_F(ArcVmDataMigrationNecessityCheckerTest, HasNoDataToMigrate) { + absl::optional<bool> migration_needed = true; + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature(kEnableArcVmDataMigration); + ash::FakeArcVmDataMigratorClient::Get()->set_has_data_to_migrate(false); + checker_->Check(base::BindLambdaForTesting( + [&migration_needed](absl::optional<bool> result) { + migration_needed = result; + })); + base::RunLoop().RunUntilIdle(); + EXPECT_TRUE(migration_needed.has_value()); + EXPECT_FALSE(migration_needed.value()); +} + +TEST_F(ArcVmDataMigrationNecessityCheckerTest, ForceVirtioBlkForData) { + absl::optional<bool> migration_needed = true; + base::test::ScopedFeatureList feature_list; + feature_list.InitWithFeatures( + {kEnableArcVmDataMigration, kEnableVirtioBlkForData}, {}); + ash::FakeArcVmDataMigratorClient::Get()->set_has_data_to_migrate(true); + checker_->Check(base::BindLambdaForTesting( + [&migration_needed](absl::optional<bool> result) { + migration_needed = result; + })); + base::RunLoop().RunUntilIdle(); + EXPECT_TRUE(migration_needed.has_value()); + EXPECT_FALSE(migration_needed.value()); +} + +TEST_F(ArcVmDataMigrationNecessityCheckerTest, MigrationFinished) { + absl::optional<bool> migration_needed = true; + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature(kEnableArcVmDataMigration); + SetArcVmDataMigrationStatus(profile_->GetPrefs(), + ArcVmDataMigrationStatus::kFinished); + ash::FakeArcVmDataMigratorClient::Get()->set_has_data_to_migrate(true); + checker_->Check(base::BindLambdaForTesting( + [&migration_needed](absl::optional<bool> result) { + migration_needed = result; + })); + base::RunLoop().RunUntilIdle(); + EXPECT_TRUE(migration_needed.has_value()); + EXPECT_FALSE(migration_needed.value()); +} + +TEST_F(ArcVmDataMigrationNecessityCheckerTest, StartJobFailed) { + absl::optional<bool> migration_needed = true; + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature(kEnableArcVmDataMigration); + ash::FakeArcVmDataMigratorClient::Get()->set_has_data_to_migrate(true); + ash::FakeUpstartClient::Get()->set_start_job_cb(base::BindLambdaForTesting( + [](const std::string& job_name, const std::vector<std::string>& env) { + return job_name != kArcVmDataMigratorJobName; + })); + checker_->Check(base::BindLambdaForTesting( + [&migration_needed](absl::optional<bool> result) { + migration_needed = result; + })); + base::RunLoop().RunUntilIdle(); + EXPECT_FALSE(migration_needed.has_value()); +} + +TEST_F(ArcVmDataMigrationNecessityCheckerTest, HasDataToMigrateFailed) { + absl::optional<bool> migration_needed = true; + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature(kEnableArcVmDataMigration); + ash::FakeArcVmDataMigratorClient::Get()->set_has_data_to_migrate( + absl::nullopt); + checker_->Check(base::BindLambdaForTesting( + [&migration_needed](absl::optional<bool> result) { + migration_needed = result; + })); + base::RunLoop().RunUntilIdle(); + EXPECT_FALSE(migration_needed.has_value()); +} + +} // namespace +} // namespace arc
diff --git a/chrome/browser/ash/crosapi/browser_data_back_migrator.cc b/chrome/browser/ash/crosapi/browser_data_back_migrator.cc index 93f8727b..60039240 100644 --- a/chrome/browser/ash/crosapi/browser_data_back_migrator.cc +++ b/chrome/browser/ash/crosapi/browser_data_back_migrator.cc
@@ -11,6 +11,7 @@ #include "ash/constants/ash_features.h" #include "ash/constants/ash_switches.h" #include "base/command_line.h" +#include "base/containers/contains.h" #include "base/files/file_enumerator.h" #include "base/files/file_path.h" #include "base/files/file_util.h" @@ -24,6 +25,7 @@ #include "base/path_service.h" #include "base/task/task_traits.h" #include "base/task/thread_pool.h" +#include "chrome/browser/ash/crosapi/browser_data_migrator_util.h" #include "chrome/browser/ash/profiles/profile_helper.h" #include "chrome/browser/lifetime/application_lifetime.h" #include "chrome/common/chrome_constants.h" @@ -94,6 +96,7 @@ crosapi::browser_util::PolicyInitState::kBeforeInit)); running_ = true; + migration_start_time_ = base::TimeTicks::Now(); const base::FilePath lacros_profile_dir = ash_profile_dir_.Append(browser_data_migrator_util::kLacrosDir); @@ -787,14 +790,8 @@ return false; } - // For preferences that were moved to Lacros, and deleted in Ash, copy them - // back to Ash. - for (const char* key : - browser_data_migrator_util::kLacrosOnlyPreferencesKeys) { - base::Value* lacros_value = lacros_root_dict->FindByDottedPath(key); - if (lacros_value) - ash_root_dict->SetByDottedPath(key, lacros_value->Clone()); - } + std::string current_path; + MergeLacrosPreferences(*ash_root_dict, current_path, lacros_root.value(), 0u); // Preferences that were split between Ash and Lacros relate to extensions. // Here we need to take the preferences from Lacros that were removed from @@ -856,6 +853,56 @@ } // static +bool BrowserDataBackMigrator::MergeLacrosPreferences( + base::Value::Dict& ash_root_dict, + std::string& current_dotted_path, + const base::Value& current_value, + unsigned int recursion_depth) { + if (recursion_depth >= kMaxRecursionDepth) { + LOG(WARNING) << "We have reached maximum recursion depth " + << kMaxRecursionDepth + << " and we are stopping MergeLacrosPreferences()"; + return false; + } + + // If the |current_dotted_path| was split or ash-only, then ignore it. + if (base::Contains(browser_data_migrator_util::kSplitPreferencesKeys, + current_dotted_path) || + base::Contains(browser_data_migrator_util::kAshOnlyPreferencesKeys, + current_dotted_path)) { + return true; + } + + // If current value is not a dictionary, then it is a final pref. + // Merge it into the |ash_root_dict|. + if (!current_value.is_dict()) { + ash_root_dict.SetByDottedPath(current_dotted_path, current_value.Clone()); + + return true; + } + // Otherwise, traverse all child elements of the current dictionary. + for (const auto child_entry : current_value.GetDict()) { + const std::string& child_entry_key = child_entry.first; + const base::Value* child_entry_value = &child_entry.second; + + std::string child_dotted_path; + // Can be empty if it is a root dictionary. + if (current_dotted_path.empty()) { + child_dotted_path = child_entry_key; + } else { + child_dotted_path = current_dotted_path + "." + child_entry_key; + } + + if (!MergeLacrosPreferences(ash_root_dict, child_dotted_path, + *child_entry_value, recursion_depth + 1u)) { + return false; + } + } + + return true; +} + +// static bool BrowserDataBackMigrator::IsLacrosOnlyExtension( const base::StringPiece extension_id) { return !base::Contains(browser_data_migrator_util::kExtensionsAshOnly, @@ -1274,6 +1321,7 @@ void BrowserDataBackMigrator::InvokeCallback(TaskResult result) { RecordFinalStatus(result); RecordPosixErrnoIfAvailable(result); + RecordMigrationTimeIfSuccessful(result, migration_start_time_); std::move(finished_callback_).Run(ToResult(result)); } @@ -1299,6 +1347,18 @@ } // static +void BrowserDataBackMigrator::RecordMigrationTimeIfSuccessful( + TaskResult result, + base::TimeTicks migration_start_time) { + if (result.status != TaskStatus::kSucceeded) { + return; + } + + base::UmaHistogramMediumTimes(kSuccessfulMigrationTimeUMA, + base::TimeTicks::Now() - migration_start_time); +} + +// static std::string BrowserDataBackMigrator::TaskStatusToString( TaskStatus task_status) { switch (task_status) {
diff --git a/chrome/browser/ash/crosapi/browser_data_back_migrator.h b/chrome/browser/ash/crosapi/browser_data_back_migrator.h index a1631ef..cd7ad6c 100644 --- a/chrome/browser/ash/crosapi/browser_data_back_migrator.h +++ b/chrome/browser/ash/crosapi/browser_data_back_migrator.h
@@ -25,6 +25,8 @@ constexpr char kFinalStatusUMA[] = "Ash.BrowserDataBackMigrator.FinalStatus"; constexpr char kPosixErrnoUMA[] = "Ash.BrowserDataBackMigrator.PosixErrno."; +constexpr char kSuccessfulMigrationTimeUMA[] = + "Ash.BrowserDataBackMigrator.SuccessfulMigrationTime"; // Injects the restart function called from // `BrowserDataBackMigrator::AttemptRestart()` in RAII manner. @@ -103,7 +105,17 @@ FRIEND_TEST_ALL_PREFIXES(BrowserDataBackMigratorUMATest, RecordFinalStatus); FRIEND_TEST_ALL_PREFIXES(BrowserDataBackMigratorUMATest, RecordPosixErrnoIfAvailable); + FRIEND_TEST_ALL_PREFIXES(BrowserDataBackMigratorUMATest, + RecordMigrationTimeIfSuccessful); FRIEND_TEST_ALL_PREFIXES(BrowserDataBackMigratorUMATest, TaskStatusToString); + FRIEND_TEST_ALL_PREFIXES(BrowserDataBackMigratorTest, + MergesAshOnlyPreferencesCorrectly); + FRIEND_TEST_ALL_PREFIXES(BrowserDataBackMigratorTest, + MergesDictSplitPreferencesCorrectly); + FRIEND_TEST_ALL_PREFIXES(BrowserDataBackMigratorTest, + MergesListSplitPreferencesCorrectly); + FRIEND_TEST_ALL_PREFIXES(BrowserDataBackMigratorTest, + MergesLacrosPreferencesCorrectly); // A list of all the possible results of migration, including success and all // failure types in each step of the migration. @@ -252,6 +264,15 @@ const base::FilePath& lacros_pref_path, const base::FilePath& tmp_pref_path); + // For Lacros preferences that were neither split nor ash-only, + // simply prefer them over the ones that are currently in Ash. + // Traverse all JSON dotted paths in Lacros preferences using + // depth-first search and merge them into |ash_root_dict|. + static bool MergeLacrosPreferences(base::Value::Dict& ash_root_dict, + std::string& current_path, + const base::Value& current_value, + unsigned int recursion_depth); + // Decides whether preferences for the given `extension_id` should be migrated // back from Lacros to Ash. static bool IsLacrosOnlyExtension(const base::StringPiece extension_id); @@ -309,11 +330,17 @@ // Records the final status of the migration in `kFinalStatusUMA`. static void RecordFinalStatus(TaskResult result); - // Record Ash.BrowserDataBackMigrator.PosixErrno.{result.status} UMA with the + // Records Ash.BrowserDataBackMigrator.PosixErrno.{result.status} UMA with the // value of `result.posix_errno` if the migration failed. static void RecordPosixErrnoIfAvailable(TaskResult result); - // Convert `TaskStatus` to string. + // Records `kSuccessfulMigrationTimeUMA` UMA with the elapsed time since + // starting backward migration. Only recorded if migration was successful. + static void RecordMigrationTimeIfSuccessful( + TaskResult result, + base::TimeTicks migration_start_time); + + // Converts `TaskStatus` to string. static std::string TaskStatusToString(TaskStatus task_status); // Path to the ash profile directory. @@ -325,6 +352,9 @@ // Local state prefs, not owned. PrefService* local_state_ = nullptr; + // Used to record how long the migration takes in UMA. + base::TimeTicks migration_start_time_; + base::WeakPtrFactory<BrowserDataBackMigrator> weak_factory_{this}; };
diff --git a/chrome/browser/ash/crosapi/browser_data_back_migrator_unittest.cc b/chrome/browser/ash/crosapi/browser_data_back_migrator_unittest.cc index a9e14731..654556b 100644 --- a/chrome/browser/ash/crosapi/browser_data_back_migrator_unittest.cc +++ b/chrome/browser/ash/crosapi/browser_data_back_migrator_unittest.cc
@@ -8,9 +8,12 @@ #include "ash/constants/ash_features.h" #include "base/files/file_enumerator.h" +#include "base/files/file_path.h" #include "base/files/file_util.h" #include "base/files/scoped_temp_dir.h" #include "base/test/metrics/histogram_tester.h" +#include "base/json/json_reader.h" +#include "base/json/json_writer.h" #include "base/test/scoped_feature_list.h" #include "chrome/browser/ash/crosapi/browser_data_migrator_util.h" #include "chrome/browser/ash/crosapi/browser_util.h" @@ -51,6 +54,16 @@ constexpr char kAshLevelDBMeta[] = "ash-meta"; constexpr char kLacrosLevelDBMeta[] = "lacros-meta"; +const int kAshPrefValue = 0; +const int kLacrosPrefValue = 1; +// Dotted paths of preferences not found in: +// - kAshOnlyPreferencesKeys +// - kLacrosOnlyPreferencesKeys +// - kSplitPreferencesKeys +constexpr char kOtherLacrosPreference[] = "xxx.xxx.xxx"; +constexpr char kOtherAshPreference[] = "yyy.xxx.xxx"; +constexpr char kOtherBothChromesPreference[] = "zzz.xxx.xxx"; + enum class FilesSetup { kAshOnly = 0, kLacrosOnly = 1, @@ -223,6 +236,27 @@ return db_map; } +bool WriteJSONDict(const base::Value::Dict& json_dict, + const base::FilePath& dest) { + std::string serialized_dict; + + if (!base::JSONWriter::Write(json_dict, &serialized_dict)) { + return false; + } + if (!base::WriteFile(dest, serialized_dict)) { + return false; + } + return true; +} + +size_t CountStringInList(const base::Value::List& list, + const std::string& value) { + return std::count_if(list.cbegin(), list.cend(), + [&](const base::Value& item) { + return item.is_string() && item.GetString() == value; + }); +} + class BrowserDataBackMigratorTest : public testing::Test { public: BrowserDataBackMigratorTest() { @@ -269,10 +303,20 @@ tmp_profile_dir_ = ash_profile_dir_.Append(browser_data_back_migrator::kTmpDir); + + merged_prefs_path_ = tmp_profile_dir_.Append("Preferences"); + lacros_prefs_path_ = lacros_profile_dir_.Append("Preferences"); + ash_prefs_path_ = ash_profile_dir_.Append("Preferences"); } void TearDown() override { EXPECT_TRUE(user_data_dir_.Delete()); } + void CreateDirectories() { + ASSERT_TRUE(base::CreateDirectory(ash_profile_dir_)); + ASSERT_TRUE(base::CreateDirectory(lacros_profile_dir_)); + CreateTemporaryDirectory(); + } + void CreateTemporaryDirectory() { // During backward migration, `tmp_profile_dir_` is created in // `MergeSplitItems`, but we don't want to call that in tests so we generate @@ -324,6 +368,22 @@ } } + void WritePrefs(const base::Value::Dict& ash_prefs, + const base::Value::Dict& lacros_prefs) { + ASSERT_TRUE(WriteJSONDict(ash_prefs, ash_prefs_path_)); + ASSERT_TRUE(WriteJSONDict(lacros_prefs, lacros_prefs_path_)); + } + + void ReadMergedPrefs(base::Value* prefs_out) { + std::string merged_contents; + ASSERT_TRUE(base::ReadFileToString(merged_prefs_path_, &merged_contents)); + absl::optional<base::Value> merged_prefs = + base::JSONReader::Read(merged_contents); + ASSERT_TRUE(merged_prefs.has_value()); + + *prefs_out = std::move(merged_prefs.value()); + } + void SetupStateStoreLevelDBFiles(const base::FilePath& ash_profile_dir, const base::FilePath& lacros_profile_dir, FilesSetup setup) { @@ -363,6 +423,10 @@ base::FilePath lacros_profile_dir_; base::FilePath tmp_profile_dir_; + base::FilePath merged_prefs_path_; + base::FilePath ash_prefs_path_; + base::FilePath lacros_prefs_path_; + std::string kAshOnlyMetaKey; std::string kAshOnlyValueKey; std::string kLacrosOnlyMetaKey; @@ -609,6 +673,263 @@ } } +TEST_F(BrowserDataBackMigratorTest, + MergesAshOnlyPreferencesCorrectly) { + // AshPrefs + // { + // kOtherAshPreference: kAshPrefValue, + // browser_data_migrator_util::kAshOnlyPreferencesKeys[0]: kAshPrefValue, + // } + // + // LacrosPrefs + // { + // browser_data_migrator_util::kAshOnlyPreferencesKeys[0]: kLacrosPrefValue, + // } + CreateDirectories(); + + base::Value::Dict ash_prefs; + ash_prefs.SetByDottedPath( + browser_data_migrator_util::kAshOnlyPreferencesKeys[0], kAshPrefValue); + ash_prefs.SetByDottedPath(kOtherAshPreference, kAshPrefValue); + + base::Value::Dict lacros_prefs; + lacros_prefs.SetByDottedPath( + browser_data_migrator_util::kAshOnlyPreferencesKeys[0], kLacrosPrefValue); + + WritePrefs(ash_prefs, lacros_prefs); + + ASSERT_TRUE(BrowserDataBackMigrator::MergePreferences( + ash_prefs_path_, lacros_prefs_path_, merged_prefs_path_)); + + // Expected MergedPrefs + // { + // kOtherAshPreference: kAshPrefValue, + // browser_data_migrator_util::kAshOnlyPreferencesKeys[0]: kAshPrefValue, + // } + base::Value merged_prefs; + ReadMergedPrefs(&merged_prefs); + + const base::Value* merged_ash_pref = merged_prefs.GetDict().FindByDottedPath( + browser_data_migrator_util::kAshOnlyPreferencesKeys[0]); + ASSERT_TRUE(merged_ash_pref); + ASSERT_EQ(merged_ash_pref->GetInt(), kAshPrefValue); + const base::Value* merged_other_ash_pref = + merged_prefs.GetDict().FindByDottedPath(kOtherAshPreference); + ASSERT_TRUE(merged_other_ash_pref); + ASSERT_EQ(merged_other_ash_pref->GetInt(), kAshPrefValue); +} + +TEST_F(BrowserDataBackMigratorTest, + MergesDictSplitPreferencesCorrectly) { + // AshPrefs + // { + // browser_data_migrator_util::kSplitPreferencesKeys[0]: { + // browser_data_migrator_util::kExtensionsAshOnly[0]: kAshPrefValue, + // browser_data_migrator_util::kExtensionsBothChromes[0]: kAshPrefValue, + // kLacrosOnlyExtensionId: kAshPrefValue + // } + // } + // + // LacrosPrefs + // { + // browser_data_migrator_util::kSplitPreferencesKeys[0]: { + // browser_data_migrator_util::kExtensionsAshOnly[0]: kLacrosPrefValue, + // browser_data_migrator_util::kExtensionsBothChromes[0]: kLacrosPrefValue, + // kLacrosOnlyExtensionId: kLacrosPrefValue + // } + // } + CreateDirectories(); + + base::Value::Dict ash_prefs; + base::Value::Dict ash_split_pref_dict; + ash_split_pref_dict.SetByDottedPath( + browser_data_migrator_util::kExtensionsAshOnly[0], kAshPrefValue); + ash_split_pref_dict.SetByDottedPath( + browser_data_migrator_util::kExtensionsBothChromes[0], kAshPrefValue); + ash_split_pref_dict.SetByDottedPath(kLacrosOnlyExtensionId, kAshPrefValue); + ash_prefs.SetByDottedPath( + browser_data_migrator_util::kSplitPreferencesKeys[0], + base::Value(std::move(ash_split_pref_dict))); + + base::Value::Dict lacros_prefs; + base::Value::Dict lacros_split_pref_dict; + lacros_split_pref_dict.SetByDottedPath( + browser_data_migrator_util::kExtensionsAshOnly[0], kLacrosPrefValue); + lacros_split_pref_dict.SetByDottedPath( + browser_data_migrator_util::kExtensionsBothChromes[0], kLacrosPrefValue); + lacros_split_pref_dict.SetByDottedPath(kLacrosOnlyExtensionId, + kLacrosPrefValue); + lacros_prefs.SetByDottedPath( + browser_data_migrator_util::kSplitPreferencesKeys[0], + base::Value(std::move(lacros_split_pref_dict))); + + WritePrefs(ash_prefs, lacros_prefs); + + ASSERT_TRUE(BrowserDataBackMigrator::MergePreferences( + ash_prefs_path_, lacros_prefs_path_, merged_prefs_path_)); + + // Expected MergedPrefs + // { + // browser_data_migrator_util::kSplitPreferencesKeys[0]: { + // browser_data_migrator_util::kExtensionsAshOnly[0]: kAshPrefValue, + // browser_data_migrator_util::kExtensionsBothChromes[0]: kAshPrefValue, + // kLacrosOnlyExtensionId: kLacrosPrefValue + // } + // } + base::Value merged_prefs; + ReadMergedPrefs(&merged_prefs); + + const base::Value* split_pref = merged_prefs.GetDict().FindByDottedPath( + browser_data_migrator_util::kSplitPreferencesKeys[0]); + ASSERT_TRUE(split_pref); + const base::Value::Dict* split_pref_dict = &split_pref->GetDict(); + const base::Value* ash_extension_value = split_pref_dict->FindByDottedPath( + browser_data_migrator_util::kExtensionsAshOnly[0]); + ASSERT_TRUE(ash_extension_value); + ASSERT_EQ(ash_extension_value->GetInt(), kAshPrefValue); + const base::Value* common_extension_value = split_pref_dict->FindByDottedPath( + browser_data_migrator_util::kExtensionsBothChromes[0]); + ASSERT_TRUE(common_extension_value); + ASSERT_EQ(common_extension_value->GetInt(), kAshPrefValue); + const base::Value* lacros_extension_value = + split_pref_dict->FindByDottedPath(kLacrosOnlyExtensionId); + ASSERT_TRUE(lacros_extension_value); + ASSERT_EQ(lacros_extension_value->GetInt(), kLacrosPrefValue); +} + +TEST_F(BrowserDataBackMigratorTest, + MergesListSplitPreferencesCorrectly) { + // AshPrefs + // { + // browser_data_migrator_util::kSplitPreferencesKeys[0]: [ + // browser_data_migrator_util::kExtensionsAshOnly[0], + // browser_data_migrator_util::kExtensionsBothChromes[0], + // kLacrosOnlyExtensionId + // ] + // } + // + // LacrosPrefs + // { + // browser_data_migrator_util::kSplitPreferencesKeys[0]: [ + // browser_data_migrator_util::kExtensionsAshOnly[0], + // browser_data_migrator_util::kExtensionsBothChromes[0], + // kLacrosOnlyExtensionId + // ] + // } + CreateDirectories(); + + base::Value::Dict ash_prefs; + base::Value::List ash_split_pref_list; + ash_split_pref_list.Append(browser_data_migrator_util::kExtensionsAshOnly[0]); + ash_split_pref_list.Append( + browser_data_migrator_util::kExtensionsBothChromes[0]); + ash_split_pref_list.Append(kLacrosOnlyExtensionId); + ash_prefs.SetByDottedPath( + browser_data_migrator_util::kSplitPreferencesKeys[0], + base::Value(std::move(ash_split_pref_list))); + + base::Value::Dict lacros_prefs; + base::Value::List lacros_split_pref_list; + lacros_split_pref_list.Append(kLacrosOnlyExtensionId); + lacros_prefs.SetByDottedPath( + browser_data_migrator_util::kSplitPreferencesKeys[0], + base::Value(std::move(lacros_split_pref_list))); + + WritePrefs(ash_prefs, lacros_prefs); + + ASSERT_TRUE(BrowserDataBackMigrator::MergePreferences( + ash_prefs_path_, lacros_prefs_path_, merged_prefs_path_)); + + // Expected MergedPrefs + // { + // browser_data_migrator_util::kSplitPreferencesKeys[0]: [ + // browser_data_migrator_util::kExtensionsAshOnly[0], + // browser_data_migrator_util::kExtensionsBothChromes[0], + // kLacrosOnlyExtensionId + // ] + // } + base::Value merged_prefs; + ReadMergedPrefs(&merged_prefs); + + const base::Value* split_pref = merged_prefs.GetDict().FindByDottedPath( + browser_data_migrator_util::kSplitPreferencesKeys[0]); + ASSERT_TRUE(split_pref); + const base::Value::List* split_pref_list = &split_pref->GetList(); + ASSERT_EQ( + CountStringInList(*split_pref_list, + browser_data_migrator_util::kExtensionsAshOnly[0]), + 1u); + ASSERT_EQ( + CountStringInList(*split_pref_list, + browser_data_migrator_util::kExtensionsBothChromes[0]), + 1u); + ASSERT_EQ(CountStringInList(*split_pref_list, kLacrosOnlyExtensionId), 1u); +} + +TEST_F(BrowserDataBackMigratorTest, + MergesLacrosPreferencesCorrectly) { + // AshPrefs + // { + // kOtherAshPreference: kAshPrefValue, + // browser_data_migrator_util::kLacrosOnlyPreferencesKeys[0]: kAshPrefValue, + // kOtherBothChromesPreference: kAshPrefValue, + // } + // + // LacrosPrefs + // { + // kOtherBothChromesPreference: kLacrosPrefValue, + // browser_data_migrator_util::kAshOnlyPreferencesKeys[0]: kLacrosPrefValue, + // kOtherLacrosPreference: kLacrosPrefValue, + // } + CreateDirectories(); + + base::Value::Dict ash_prefs; + ash_prefs.SetByDottedPath( + browser_data_migrator_util::kLacrosOnlyPreferencesKeys[0], kAshPrefValue); + ash_prefs.SetByDottedPath(kOtherAshPreference, kAshPrefValue); + ash_prefs.SetByDottedPath(kOtherBothChromesPreference, kAshPrefValue); + + base::Value::Dict lacros_prefs; + lacros_prefs.SetByDottedPath( + browser_data_migrator_util::kLacrosOnlyPreferencesKeys[0], + kLacrosPrefValue); + lacros_prefs.SetByDottedPath(kOtherBothChromesPreference, kLacrosPrefValue); + lacros_prefs.SetByDottedPath(kOtherLacrosPreference, kLacrosPrefValue); + + WritePrefs(ash_prefs, lacros_prefs); + + ASSERT_TRUE(BrowserDataBackMigrator::MergePreferences( + ash_prefs_path_, lacros_prefs_path_, merged_prefs_path_)); + + // Expected MergedPrefs + // { + // kOtherAshPreference: kAshPrefValue, + // browser_data_migrator_util::kLacrosOnlyPreferencesKeys[0]: kLacrosPrefValue, + // kOtherBothChromesPreference: kLacrosPrefValue, + // kOtherLacrosPreference: kLacrosPrefValue, + // } + base::Value merged_prefs; + ReadMergedPrefs(&merged_prefs); + + const base::Value* lacros_preference = + merged_prefs.GetDict().FindByDottedPath( + browser_data_migrator_util::kLacrosOnlyPreferencesKeys[0]); + ASSERT_TRUE(lacros_preference); + ASSERT_EQ(lacros_preference->GetInt(), kLacrosPrefValue); + const base::Value* other_ash_preference = + merged_prefs.GetDict().FindByDottedPath(kOtherAshPreference); + ASSERT_TRUE(other_ash_preference); + ASSERT_EQ(other_ash_preference->GetInt(), kAshPrefValue); + const base::Value* other_common_preference = + merged_prefs.GetDict().FindByDottedPath(kOtherBothChromesPreference); + ASSERT_TRUE(other_common_preference); + ASSERT_EQ(other_common_preference->GetInt(), kLacrosPrefValue); + const base::Value* other_lacros_preference = + merged_prefs.GetDict().FindByDottedPath(kOtherLacrosPreference); + ASSERT_TRUE(other_lacros_preference); + ASSERT_EQ(other_lacros_preference->GetInt(), kLacrosPrefValue); +} + TEST_P(BrowserDataBackMigratorFilesSetupTest, DeletesLacrosItemsFromAshDirCorrectly) { auto files_setup = GetParam(); @@ -805,4 +1126,22 @@ "Succeeded"); } +TEST(BrowserDataBackMigratorUMATest, RecordMigrationTimeIfSuccessful) { + base::HistogramTester histogram_tester; + + // No total time is recorded on failed migration. + BrowserDataBackMigrator::TaskResult failure = { + BrowserDataBackMigrator::TaskStatus::kDeleteTmpDirDeleteFailed, EPERM}; + BrowserDataBackMigrator::RecordMigrationTimeIfSuccessful( + failure, base::TimeTicks::Now()); + histogram_tester.ExpectTotalCount(kSuccessfulMigrationTimeUMA, 0); + + // When migration succeeds, total time is recorded. + BrowserDataBackMigrator::TaskResult success = { + BrowserDataBackMigrator::TaskStatus::kSucceeded}; + BrowserDataBackMigrator::RecordMigrationTimeIfSuccessful( + success, base::TimeTicks::Now()); + histogram_tester.ExpectTotalCount(kSuccessfulMigrationTimeUMA, 1); +} + } // namespace ash
diff --git a/chrome/browser/ash/login/gaia_reauth_token_fetcher.cc b/chrome/browser/ash/login/gaia_reauth_token_fetcher.cc index 6e9d2e6..b7afa64 100644 --- a/chrome/browser/ash/login/gaia_reauth_token_fetcher.cc +++ b/chrome/browser/ash/login/gaia_reauth_token_fetcher.cc
@@ -16,6 +16,7 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/net/system_network_context_manager.h" #include "chromeos/ash/components/login/auth/recovery/service_constants.h" +#include "google_apis/credentials_mode.h" #include "google_apis/google_api_keys.h" #include "net/base/load_flags.h" #include "net/base/url_util.h" @@ -59,7 +60,8 @@ resource_request->url = GetFetchReauthTokenUrl(); resource_request->load_flags = net::LOAD_DISABLE_CACHE | net::LOAD_DO_NOT_SAVE_COOKIES; - resource_request->credentials_mode = network::mojom::CredentialsMode::kOmit; + resource_request->credentials_mode = + google_apis::GetOmitCredentialsModeForGaiaRequests(); resource_request->method = "GET"; // TODO(b/197615068): Update the "policy" field in the traffic
diff --git a/chrome/browser/ash/login/marketing_backend_connector.cc b/chrome/browser/ash/login/marketing_backend_connector.cc index 5a05a5e..b97cd0b 100644 --- a/chrome/browser/ash/login/marketing_backend_connector.cc +++ b/chrome/browser/ash/login/marketing_backend_connector.cc
@@ -22,6 +22,7 @@ #include "components/signin/public/identity_manager/scope_set.h" #include "components/user_manager/user.h" #include "components/user_manager/user_manager.h" +#include "google_apis/credentials_mode.h" #include "net/base/load_flags.h" #include "net/http/http_request_headers.h" #include "net/http/http_status_code.h" @@ -65,7 +66,8 @@ auto resource_request = std::make_unique<network::ResourceRequest>(); resource_request->url = GetChromebookServiceEndpoint(); resource_request->load_flags = net::LOAD_DISABLE_CACHE; - resource_request->credentials_mode = network::mojom::CredentialsMode::kOmit; + resource_request->credentials_mode = + google_apis::GetOmitCredentialsModeForGaiaRequests(); resource_request->method = "POST"; return resource_request; }
diff --git a/chrome/browser/ash/login/saml/password_sync_token_fetcher.cc b/chrome/browser/ash/login/saml/password_sync_token_fetcher.cc index 70fd8ca..27c9874 100644 --- a/chrome/browser/ash/login/saml/password_sync_token_fetcher.cc +++ b/chrome/browser/ash/login/saml/password_sync_token_fetcher.cc
@@ -24,6 +24,7 @@ #include "components/user_manager/known_user.h" #include "content/public/browser/browser_context.h" #include "content/public/common/url_constants.h" +#include "google_apis/credentials_mode.h" #include "google_apis/gaia/gaia_auth_fetcher.h" #include "google_apis/gaia/gaia_constants.h" #include "google_apis/gaia/google_service_auth_error.h" @@ -241,7 +242,8 @@ } resource_request->load_flags = net::LOAD_DISABLE_CACHE | net::LOAD_BYPASS_CACHE; - resource_request->credentials_mode = network::mojom::CredentialsMode::kOmit; + resource_request->credentials_mode = + google_apis::GetOmitCredentialsModeForGaiaRequests(); if (request_type_ == RequestType::kCreateToken) { resource_request->method = net::HttpRequestHeaders::kPostMethod; } else {
diff --git a/chrome/browser/ash/login/users/avatar/user_image_loader.cc b/chrome/browser/ash/login/users/avatar/user_image_loader.cc index 5c450b1b..4bb3eed1 100644 --- a/chrome/browser/ash/login/users/avatar/user_image_loader.cc +++ b/chrome/browser/ash/login/users/avatar/user_image_loader.cc
@@ -21,6 +21,7 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/ui/ash/image_downloader_impl.h" #include "components/user_manager/user_image/user_image.h" +#include "google_apis/credentials_mode.h" #include "ipc/ipc_channel.h" #include "net/traffic_annotation/network_traffic_annotation.h" #include "services/data_decoder/public/cpp/data_decoder.h" @@ -438,7 +439,8 @@ auto request = std::make_unique<network::ResourceRequest>(); request->url = default_image_url; - request->credentials_mode = network::mojom::CredentialsMode::kOmit; + request->credentials_mode = + google_apis::GetOmitCredentialsModeForGaiaRequests(); auto loader = network::SimpleURLLoader::Create(std::move(request), kNetworkTrafficAnnotationTag);
diff --git a/chrome/browser/ash/printing/zeroconf_printer_detector.cc b/chrome/browser/ash/printing/zeroconf_printer_detector.cc index d7acd374..b457f6ad 100644 --- a/chrome/browser/ash/printing/zeroconf_printer_detector.cc +++ b/chrome/browser/ash/printing/zeroconf_printer_detector.cc
@@ -27,6 +27,7 @@ const char ZeroconfPrinterDetector::kIppsServiceName[] = "_ipps._tcp.local"; const char ZeroconfPrinterDetector::kSocketServiceName[] = "_pdl-datastream._tcp.local"; +const char ZeroconfPrinterDetector::kLpdServiceName[] = "_printer._tcp.local"; // IppEverywhere printers are also required to advertise these services. const char ZeroconfPrinterDetector::kIppEverywhereServiceName[] = @@ -36,12 +37,13 @@ // These service names are ordered in priority. In other words, earlier // service types in this list will be used preferentially over later ones. -constexpr std::array<const char*, 5> kServiceNames = { +constexpr std::array<const char*, 6> kServiceNames = { ZeroconfPrinterDetector::kIppsEverywhereServiceName, ZeroconfPrinterDetector::kIppEverywhereServiceName, ZeroconfPrinterDetector::kIppsServiceName, ZeroconfPrinterDetector::kIppServiceName, ZeroconfPrinterDetector::kSocketServiceName, + ZeroconfPrinterDetector::kLpdServiceName, }; namespace { @@ -186,6 +188,8 @@ // If the "rp" key is present in a Socket TXT record, the key/value MUST // be ignored. rp.clear(); + } else if (service_type == ZeroconfPrinterDetector::kLpdServiceName) { + uri.SetScheme("lpd"); } else { // Since we only register for these services, we should never get back // a service other than the ones above.
diff --git a/chrome/browser/ash/printing/zeroconf_printer_detector.h b/chrome/browser/ash/printing/zeroconf_printer_detector.h index 708c6e2..a5d0dfa 100644 --- a/chrome/browser/ash/printing/zeroconf_printer_detector.h +++ b/chrome/browser/ash/printing/zeroconf_printer_detector.h
@@ -26,6 +26,7 @@ static const char kIppEverywhereServiceName[]; static const char kIppsEverywhereServiceName[]; static const char kSocketServiceName[]; + static const char kLpdServiceName[]; ~ZeroconfPrinterDetector() override = default;
diff --git a/chrome/browser/ash/printing/zeroconf_printer_detector_unittest.cc b/chrome/browser/ash/printing/zeroconf_printer_detector_unittest.cc index 456992b2..41a7438 100644 --- a/chrome/browser/ash/printing/zeroconf_printer_detector_unittest.cc +++ b/chrome/browser/ash/printing/zeroconf_printer_detector_unittest.cc
@@ -64,6 +64,7 @@ kIppE, // IPP-Everywhere kIppsE, // IPPS-Everywhere kSocket, // Socket + kLpd, // LPD }; // This corresponds to MakeServiceDescription() below. Given the same name (and @@ -97,6 +98,9 @@ scheme = "socket"; rp = ""; break; + case ServiceType::kLpd: + scheme = "lpd"; + break; } printer.SetUri(base::StringPrintf("%s://%s.local:%d/%s", scheme.c_str(), name.c_str(), port, rp.c_str())); @@ -159,6 +163,9 @@ auto socket_lister = std::make_unique<FakeServiceDiscoveryDeviceLister>( runner, ZeroconfPrinterDetector::kSocketServiceName); socket_lister_ = socket_lister.get(); + auto lpd_lister = std::make_unique<FakeServiceDiscoveryDeviceLister>( + runner, ZeroconfPrinterDetector::kLpdServiceName); + lpd_lister_ = lpd_lister.get(); listers_[ZeroconfPrinterDetector::kIppServiceName] = std::move(ipp_lister); listers_[ZeroconfPrinterDetector::kIppsServiceName] = @@ -169,6 +176,7 @@ std::move(ippse_lister); listers_[ZeroconfPrinterDetector::kSocketServiceName] = std::move(socket_lister); + listers_[ZeroconfPrinterDetector::kLpdServiceName] = std::move(lpd_lister); } ~ZeroconfPrinterDetectorTest() override = default; @@ -187,6 +195,7 @@ ippe_lister_->SetDelegate(detector_.get()); ippse_lister_->SetDelegate(detector_.get()); socket_lister_->SetDelegate(detector_.get()); + lpd_lister_->SetDelegate(detector_.get()); } // Expect that the most up-to-date results from the detector match those @@ -278,6 +287,7 @@ FakeServiceDiscoveryDeviceLister* ippe_lister_; FakeServiceDiscoveryDeviceLister* ippse_lister_; FakeServiceDiscoveryDeviceLister* socket_lister_; + FakeServiceDiscoveryDeviceLister* lpd_lister_; // Detector under test. std::unique_ptr<ZeroconfPrinterDetector> detector_; @@ -334,6 +344,14 @@ ExpectPrintersAre({MakeExpectedPrinter("Printer5", ServiceType::kSocket)}); } +TEST_F(ZeroconfPrinterDetectorTest, SingleLpdPrinter) { + lpd_lister_->Announce(MakeServiceDescription( + "Printer6", ZeroconfPrinterDetector::kLpdServiceName)); + CreateDetector(); + CompleteTasks(); + ExpectPrintersAre({MakeExpectedPrinter("Printer6", ServiceType::kLpd)}); +} + // Test that an announce after the detector creation shows up as a printer. TEST_F(ZeroconfPrinterDetectorTest, AnnounceAfterDetectorCreation) { CreateDetector(); @@ -401,6 +419,17 @@ ASSERT_EQ(1U, printers_found_callbacks_.back().size()); // Id should be the same. ASSERT_EQ(id, printers_found_callbacks_.back()[0].printer.id()); + + // Remove it as a socket printer, add it as an LPD printer. + socket_lister_->Remove("Printer1"); + CompleteTasks(); + ASSERT_TRUE(printers_found_callbacks_.back().empty()); + lpd_lister_->Announce(MakeServiceDescription( + "Printer1", ZeroconfPrinterDetector::kLpdServiceName)); + CompleteTasks(); + ASSERT_EQ(1U, printers_found_callbacks_.back().size()); + // Id should be the same. + ASSERT_EQ(id, printers_found_callbacks_.back()[0].printer.id()); } // Test a basic removal. @@ -432,9 +461,9 @@ // Test that, when the same printer appears in multiple services, we // use the highest priority one. Priorities, from highest to lowest -// are IPPS-E, IPP-E, IPPS, IPP. +// are IPPS-E, IPP-E, IPPS, IPP, Socket, LPD. TEST_F(ZeroconfPrinterDetectorTest, ServiceTypePriorities) { - // Advertise on all 4 services. + // Advertise on all services. ipp_lister_->Announce(MakeServiceDescription( "Printer5", ZeroconfPrinterDetector::kIppServiceName)); ipps_lister_->Announce(MakeServiceDescription( @@ -445,6 +474,8 @@ "Printer5", ZeroconfPrinterDetector::kIppsEverywhereServiceName)); socket_lister_->Announce(MakeServiceDescription( "Printer5", ZeroconfPrinterDetector::kSocketServiceName)); + lpd_lister_->Announce(MakeServiceDescription( + "Printer5", ZeroconfPrinterDetector::kLpdServiceName)); CreateDetector(); CompleteTasks(); // IPPS-E is highest priority. @@ -466,11 +497,16 @@ ipp_lister_->Remove("Printer5"); CompleteTasks(); - // Socket is only remaining entry. + // Socket is highest remaining entry. ExpectPrintersAre({MakeExpectedPrinter("Printer5", ServiceType::kSocket)}); socket_lister_->Remove("Printer5"); CompleteTasks(); + // LPD is only remaining entry. + ExpectPrintersAre({MakeExpectedPrinter("Printer5", ServiceType::kLpd)}); + + lpd_lister_->Remove("Printer5"); + CompleteTasks(); // No entries left. ExpectPrintersEmpty(); } @@ -497,6 +533,10 @@ "Printer10", ZeroconfPrinterDetector::kSocketServiceName)); socket_lister_->Announce(MakeServiceDescription( "Printer11", ZeroconfPrinterDetector::kSocketServiceName)); + lpd_lister_->Announce(MakeServiceDescription( + "Printer11", ZeroconfPrinterDetector::kLpdServiceName)); + lpd_lister_->Announce(MakeServiceDescription( + "Printer12", ZeroconfPrinterDetector::kLpdServiceName)); CreateDetector(); CompleteTasks(); @@ -505,7 +545,8 @@ MakeExpectedPrinter("Printer8", ServiceType::kIppE), MakeExpectedPrinter("Printer9", ServiceType::kIppsE), MakeExpectedPrinter("Printer10", ServiceType::kIppsE), - MakeExpectedPrinter("Printer11", ServiceType::kSocket)}); + MakeExpectedPrinter("Printer11", ServiceType::kSocket), + MakeExpectedPrinter("Printer12", ServiceType::kLpd)}); ipps_lister_->Clear(); @@ -518,15 +559,15 @@ // Just for kicks, announce something new at this point. ipps_lister_->Announce(MakeServiceDescription( - "Printer12", ZeroconfPrinterDetector::kIppsServiceName)); + "Printer13", ZeroconfPrinterDetector::kIppsServiceName)); CompleteTasks(); - ExpectPrintersAre({MakeExpectedPrinter("Printer12", ServiceType::kIpps)}); + ExpectPrintersAre({MakeExpectedPrinter("Printer13", ServiceType::kIpps)}); // Clear out the IPPS lister, which will clear all printers too. ipps_lister_->Clear(); CompleteTasks(); - // With the IPPS lister cleared, Printer12 should disappear. + // With the IPPS lister cleared, Printer13 should disappear. ExpectPrintersEmpty(); EXPECT_TRUE(ippe_lister_->discovery_started()); } @@ -545,6 +586,8 @@ "Printer15", ZeroconfPrinterDetector::kIppsServiceName)); socket_lister_->Announce(MakeServiceDescription( "Printer16", ZeroconfPrinterDetector::kSocketServiceName)); + lpd_lister_->Announce(MakeServiceDescription( + "Printer17", ZeroconfPrinterDetector::kLpdServiceName)); CreateDetector(); CompleteTasks(); @@ -552,19 +595,21 @@ MakeExpectedPrinter("Printer13", ServiceType::kIpps), MakeExpectedPrinter("Printer14", ServiceType::kIppsE), MakeExpectedPrinter("Printer15", ServiceType::kIpps), - MakeExpectedPrinter("Printer16", ServiceType::kSocket)}); + MakeExpectedPrinter("Printer16", ServiceType::kSocket), + MakeExpectedPrinter("Printer17", ServiceType::kLpd)}); ippe_lister_->Announce(MakeServiceDescription( "Printer13", ZeroconfPrinterDetector::kIppEverywhereServiceName)); ipp_lister_->Announce(MakeServiceDescription( - "Printer17", ZeroconfPrinterDetector::kIppServiceName)); + "Printer18", ZeroconfPrinterDetector::kIppServiceName)); CompleteTasks(); ExpectPrintersAre({MakeExpectedPrinter("Printer12", ServiceType::kIpps), MakeExpectedPrinter("Printer13", ServiceType::kIppE), MakeExpectedPrinter("Printer14", ServiceType::kIppsE), MakeExpectedPrinter("Printer15", ServiceType::kIpps), MakeExpectedPrinter("Printer16", ServiceType::kSocket), - MakeExpectedPrinter("Printer17", ServiceType::kIpp)}); + MakeExpectedPrinter("Printer17", ServiceType::kLpd), + MakeExpectedPrinter("Printer18", ServiceType::kIpp)}); ipp_lister_->Remove("NonexistantPrinter"); ipps_lister_->Remove("Printer12");
diff --git a/chrome/browser/download/bubble/download_bubble_controller.cc b/chrome/browser/download/bubble/download_bubble_controller.cc index aeadb8a..c8a6c38 100644 --- a/chrome/browser/download/bubble/download_bubble_controller.cc +++ b/chrome/browser/download/bubble/download_bubble_controller.cc
@@ -36,6 +36,10 @@ namespace { constexpr int kShowDownloadsInBubbleForNumDays = 1; constexpr int kMaxDownloadsToShow = 100; +// Don't show the partial view more than once per 15 seconds, as this pops up +// automatically and may be annoying to the user. The time is reset when the +// user clicks on the button to open the main view. +constexpr base::TimeDelta kShowPartialViewMinInterval = base::Seconds(15); bool FindOfflineItemByContentId(const ContentId& to_find, const OfflineItem& candidate) { @@ -375,7 +379,12 @@ } std::vector<DownloadUIModelPtr> DownloadBubbleUIController::GetPartialView() { - last_partial_view_shown_time_ = absl::make_optional(base::Time::Now()); + base::Time now = base::Time::Now(); + if (last_partial_view_shown_time_.has_value() && + now - *last_partial_view_shown_time_ < kShowPartialViewMinInterval) { + return {}; + } + last_partial_view_shown_time_ = absl::make_optional(now); std::vector<DownloadUIModelPtr> list = GetDownloadUIModels(/*is_main_view=*/false); base::UmaHistogramCounts100("Download.Bubble.PartialViewSize", list.size());
diff --git a/chrome/browser/download/bubble/download_bubble_controller_unittest.cc b/chrome/browser/download/bubble/download_bubble_controller_unittest.cc index 05917ef..0cb357b 100644 --- a/chrome/browser/download/bubble/download_bubble_controller_unittest.cc +++ b/chrome/browser/download/bubble/download_bubble_controller_unittest.cc
@@ -387,6 +387,45 @@ EXPECT_EQ(second_controller().GetPartialView().size(), 0ul); } +// Tests that no items are returned (i.e. no partial view will be shown) if it +// is too soon since the last partial view has been shown. +TEST_F(DownloadBubbleUIControllerTest, NoItemsReturnedForPartialViewTooSoon) { + std::vector<std::string> ids = {"Download 1", "Download 2", "Download 3", + "Download 4"}; + + // First time showing the partial view should work. + EXPECT_CALL(display_controller(), OnNewItem(true, true)).Times(1); + InitDownloadItem(FILE_PATH_LITERAL("/foo/bar1.pdf"), + download::DownloadItem::IN_PROGRESS, ids[0]); + EXPECT_EQ(controller().GetPartialView().size(), 1u); + + // No items are returned for a partial view because it is too soon. + task_environment_.FastForwardBy(base::Seconds(14)); + EXPECT_CALL(display_controller(), OnNewItem(false, true)).Times(1); + InitDownloadItem(FILE_PATH_LITERAL("/foo/bar2.pdf"), + download::DownloadItem::COMPLETE, ids[1]); + EXPECT_EQ(controller().GetPartialView().size(), 0u); + + // Partial view can now be shown, and contains all the items. + task_environment_.FastForwardBy(base::Seconds(1)); + EXPECT_CALL(display_controller(), OnNewItem(false, true)).Times(1); + InitDownloadItem(FILE_PATH_LITERAL("/foo/bar3.pdf"), + download::DownloadItem::COMPLETE, ids[1]); + EXPECT_EQ(controller().GetPartialView().size(), 3u); + + // Showing the main view even before time is up should still work. + task_environment_.FastForwardBy(base::Seconds(14)); + EXPECT_EQ(controller().GetPartialView().size(), 0u); + EXPECT_EQ(controller().GetMainView().size(), 3u); + + // Main view resets the partial view time, so the partial view can now be + // shown. + EXPECT_CALL(display_controller(), OnNewItem(true, true)).Times(1); + InitDownloadItem(FILE_PATH_LITERAL("/foo/bar4.pdf"), + download::DownloadItem::IN_PROGRESS, ids[3]); + EXPECT_EQ(controller().GetPartialView().size(), 1u); +} + class DownloadBubbleUIControllerIncognitoTest : public DownloadBubbleUIControllerTest { public:
diff --git a/chrome/browser/extensions/BUILD.gn b/chrome/browser/extensions/BUILD.gn index a49bd4a..c5b695f 100644 --- a/chrome/browser/extensions/BUILD.gn +++ b/chrome/browser/extensions/BUILD.gn
@@ -1348,6 +1348,12 @@ } if (enable_pdf) { + sources += [ + "api/pdf_viewer_private/pdf_viewer_private_event_router.cc", + "api/pdf_viewer_private/pdf_viewer_private_event_router.h", + "api/pdf_viewer_private/pdf_viewer_private_event_router_factory.cc", + "api/pdf_viewer_private/pdf_viewer_private_event_router_factory.h", + ] deps += [ "//chrome/browser/pdf", "//components/pdf/browser",
diff --git a/chrome/browser/extensions/api/api_browser_context_keyed_service_factories.cc b/chrome/browser/extensions/api/api_browser_context_keyed_service_factories.cc index ebd92d3..271b1e6 100644 --- a/chrome/browser/extensions/api/api_browser_context_keyed_service_factories.cc +++ b/chrome/browser/extensions/api/api_browser_context_keyed_service_factories.cc
@@ -37,6 +37,7 @@ #include "chrome/browser/extensions/api/webrtc_audio_private/webrtc_audio_private_api.h" #include "chrome/browser/speech/extension_api/tts_extension_api.h" #include "chrome/common/buildflags.h" +#include "components/services/screen_ai/buildflags/buildflags.h" #include "extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_api.h" #include "extensions/browser/api/networking_private/networking_private_delegate_factory.h" @@ -50,6 +51,10 @@ #include "chrome/browser/extensions/api/terminal/terminal_private_api.h" #endif +#if BUILDFLAG(ENABLE_SCREEN_AI_SERVICE) +#include "chrome/browser/extensions/api/pdf_viewer_private/pdf_viewer_private_event_router_factory.h" +#endif // BUILDFLAG(ENABLE_SCREEN_AI_SERVICE) + #if BUILDFLAG(ENABLE_SERVICE_DISCOVERY) #include "chrome/browser/extensions/api/mdns/mdns_api.h" #endif @@ -85,6 +90,9 @@ #endif extensions::OmniboxAPI::GetFactoryInstance(); extensions::PasswordsPrivateEventRouterFactory::GetInstance(); +#if BUILDFLAG(ENABLE_SCREEN_AI_SERVICE) + extensions::PdfViewerPrivateEventRouterFactory::GetInstance(); +#endif // BUILDFLAG(ENABLE_SCREEN_AI_SERVICE) extensions::PreferenceAPI::GetFactoryInstance(); extensions::ProcessesAPI::GetFactoryInstance(); extensions::SafeBrowsingPrivateEventRouterFactory::GetInstance();
diff --git a/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc b/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc index 05085497..4a4c004e 100644 --- a/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc +++ b/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc
@@ -16,6 +16,7 @@ #include "base/stl_util.h" #include "base/strings/strcat.h" #include "base/strings/stringprintf.h" +#include "base/test/gtest_util.h" #include "base/test/values_test_util.h" #include "chrome/browser/extensions/chrome_test_extension_loader.h" #include "chrome/browser/extensions/error_console/error_console.h" @@ -1986,6 +1987,125 @@ // Test developerPrivate.getUserSiteSettings. TEST_F(DeveloperPrivateApiUnitTest, DeveloperPrivateGetUserSiteSettings) { PermissionsManager* manager = PermissionsManager::Get(browser_context()); + const url::Origin restricted_url = + url::Origin::Create(GURL("http://example.com")); + + manager->AddUserRestrictedSite(restricted_url); + + auto function = + base::MakeRefCounted<api::DeveloperPrivateGetUserSiteSettingsFunction>(); + + absl::optional<base::Value> result = + api_test_utils::RunFunctionAndReturnSingleResult( + function.get(), /*args=*/"[]", profile()); + ASSERT_TRUE(result.has_value()); + std::unique_ptr<api::developer_private::UserSiteSettings> settings = + api::developer_private::UserSiteSettings::FromValue(result.value()); + + ASSERT_TRUE(settings); + EXPECT_THAT(settings->permitted_sites, testing::IsEmpty()); + EXPECT_THAT(settings->restricted_sites, + testing::UnorderedElementsAre("http://example.com")); +} + +// Test developerPrivate.addUserSpecifiedSite and removeUserSpecifiedSite for +// restricted sites. +TEST_F(DeveloperPrivateApiUnitTest, DeveloperPrivateModifyUserSiteSettings) { + static constexpr char kExample[] = "http://example.com"; + static constexpr char kChromium[] = "http://chromium.org"; + + const url::Origin example_url = url::Origin::Create(GURL(kExample)); + const url::Origin chromium_url = url::Origin::Create(GURL(kChromium)); + + // Add restricted sites, and check that these sites are stored in the manager. + EXPECT_NO_FATAL_FAILURE(AddUserSpecifiedSites( + profile(), base::StringPrintf(R"(["%s","%s"])", kExample, kChromium), + /*restricted=*/true)); + + PermissionsManager* manager = PermissionsManager::Get(browser_context()); + EXPECT_THAT(manager->GetUserPermissionsSettings().permitted_sites, + testing::IsEmpty()); + EXPECT_THAT(manager->GetUserPermissionsSettings().restricted_sites, + testing::UnorderedElementsAre(example_url, chromium_url)); + + // Remove restricted site, and check that the site was removed in the manager. + EXPECT_NO_FATAL_FAILURE(RemoveUserSpecifiedSites( + profile(), base::StringPrintf(R"(["%s"])", kExample), + /*restricted=*/true)); + + EXPECT_THAT(manager->GetUserPermissionsSettings().permitted_sites, + testing::IsEmpty()); + EXPECT_THAT(manager->GetUserPermissionsSettings().restricted_sites, + testing::UnorderedElementsAre(chromium_url)); +} + +// Test that the OnUserSiteSettingsChanged event is fired whenever the user +// defined site settings update. +TEST_F(DeveloperPrivateApiUnitTest, OnUserSiteSettingsChanged) { + static constexpr char kExample[] = "http://example.com"; + + // We need to call DeveloperPrivateAPI::Get() in order to instantiate the + // keyed service, since it's not created by default in unit tests. + DeveloperPrivateAPI::Get(profile()); + EventRouter* event_router = EventRouter::Get(profile()); + + // The DeveloperPrivateEventRouter will only dispatch events if there's at + // least one listener to dispatch to. Create one. + const char* kEventName = + api::developer_private::OnUserSiteSettingsChanged::kEventName; + event_router->AddEventListener(kEventName, render_process_host(), + crx_file::id_util::GenerateId("listener")); + + TestEventRouterObserver test_observer(event_router); + + api::developer_private::UserSiteSettings settings; + EXPECT_FALSE( + WasUserSiteSettingsChangedEventDispatched(test_observer, &settings)); + + // Add a restricted site, and check the event that it's + // only contained in the restricted list. + const std::string kExampleArg = base::StringPrintf(R"(["%s"])", kExample); + EXPECT_NO_FATAL_FAILURE( + AddUserSpecifiedSites(profile(), kExampleArg, /*restricted=*/true)); + EXPECT_TRUE( + WasUserSiteSettingsChangedEventDispatched(test_observer, &settings)); + EXPECT_THAT(settings.permitted_sites, testing::IsEmpty()); + EXPECT_THAT(settings.restricted_sites, + testing::UnorderedElementsAre(kExample)); + + // Remove the site, and check the event that both lists are empty. + EXPECT_NO_FATAL_FAILURE( + RemoveUserSpecifiedSites(profile(), kExampleArg, /*restricted=*/true)); + EXPECT_TRUE( + WasUserSiteSettingsChangedEventDispatched(test_observer, &settings)); + EXPECT_THAT(settings.permitted_sites, testing::IsEmpty()); + EXPECT_THAT(settings.restricted_sites, testing::IsEmpty()); +} + +class DeveloperPrivateApiWithPermittedSitesUnitTest + : public DeveloperPrivateApiUnitTest { + public: + DeveloperPrivateApiWithPermittedSitesUnitTest(); + DeveloperPrivateApiWithPermittedSitesUnitTest( + const DeveloperPrivateApiWithPermittedSitesUnitTest&) = delete; + const DeveloperPrivateApiWithPermittedSitesUnitTest& operator=( + const DeveloperPrivateApiWithPermittedSitesUnitTest&) = delete; + ~DeveloperPrivateApiWithPermittedSitesUnitTest() override = default; + + private: + base::test::ScopedFeatureList feature_list_; +}; + +DeveloperPrivateApiWithPermittedSitesUnitTest:: + DeveloperPrivateApiWithPermittedSitesUnitTest() { + feature_list_.InitAndEnableFeature( + extensions_features::kExtensionsMenuAccessControlWithPermittedSites); +} + +// Test developerPrivate.getUserSiteSettings. +TEST_F(DeveloperPrivateApiWithPermittedSitesUnitTest, + DeveloperPrivateGetUserSiteSettings) { + PermissionsManager* manager = PermissionsManager::Get(browser_context()); const url::Origin permitted_url = url::Origin::Create(GURL("http://a.example.com")); const url::Origin restricted_url = @@ -2012,9 +2132,9 @@ testing::UnorderedElementsAre("http://b.example.com")); } -// Test developerPrivate.addUserPermittedSite, addUserRestrictedSite and -// removeUserSpecifiedSite. -TEST_F(DeveloperPrivateApiUnitTest, DeveloperPrivateModifyUserSiteSettings) { +// Test developerPrivate.addUserSpecifiedSite and removeUserSpecifiedSite. +TEST_F(DeveloperPrivateApiWithPermittedSitesUnitTest, + DeveloperPrivateModifyUserSiteSettings) { static constexpr char kExample[] = "http://example.com"; static constexpr char kChromium[] = "http://chromium.org"; static constexpr char kGoogle[] = "http://google.com"; @@ -2057,60 +2177,7 @@ EXPECT_TRUE(manager->GetUserPermissionsSettings().restricted_sites.empty()); } -// Test that the OnUserSiteSettingsChanged event is fired whenever the user -// defined site settings updates. -TEST_F(DeveloperPrivateApiUnitTest, OnUserSiteSettingsChanged) { - static constexpr char kExample[] = "http://example.com"; - - // We need to call DeveloperPrivateAPI::Get() in order to instantiate the - // keyed service, since it's not created by default in unit tests. - DeveloperPrivateAPI::Get(profile()); - EventRouter* event_router = EventRouter::Get(profile()); - - // The DeveloperPrivateEventRouter will only dispatch events if there's at - // least one listener to dispatch to. Create one. - const char* kEventName = - api::developer_private::OnUserSiteSettingsChanged::kEventName; - event_router->AddEventListener(kEventName, render_process_host(), - crx_file::id_util::GenerateId("listener")); - - TestEventRouterObserver test_observer(event_router); - - api::developer_private::UserSiteSettings settings; - EXPECT_FALSE( - WasUserSiteSettingsChangedEventDispatched(test_observer, &settings)); - - // Add a permitted site, and check that it is contained within the event's - // payload. - const std::string kExampleArg = base::StringPrintf(R"(["%s"])", kExample); - EXPECT_NO_FATAL_FAILURE( - AddUserSpecifiedSites(profile(), kExampleArg, /*restricted=*/false)); - EXPECT_TRUE( - WasUserSiteSettingsChangedEventDispatched(test_observer, &settings)); - EXPECT_THAT(settings.permitted_sites, - testing::UnorderedElementsAre(kExample)); - EXPECT_TRUE(settings.restricted_sites.empty()); - - // Add the same site to the restricted site, and check the event that it's - // only contained in the restricted list. - EXPECT_NO_FATAL_FAILURE( - AddUserSpecifiedSites(profile(), kExampleArg, /*restricted=*/true)); - EXPECT_TRUE( - WasUserSiteSettingsChangedEventDispatched(test_observer, &settings)); - EXPECT_TRUE(settings.permitted_sites.empty()); - EXPECT_THAT(settings.restricted_sites, - testing::UnorderedElementsAre(kExample)); - - // Remove the site, and check the event that both lists are empty. - EXPECT_NO_FATAL_FAILURE( - RemoveUserSpecifiedSites(profile(), kExampleArg, /*restricted=*/true)); - EXPECT_TRUE( - WasUserSiteSettingsChangedEventDispatched(test_observer, &settings)); - EXPECT_TRUE(settings.permitted_sites.empty()); - EXPECT_TRUE(settings.restricted_sites.empty()); -} - -TEST_F(DeveloperPrivateApiUnitTest, +TEST_F(DeveloperPrivateApiWithPermittedSitesUnitTest, DeveloperPrivateGetUserAndExtensionSitesByEtld_UserSites) { PermissionsManager* manager = PermissionsManager::Get(browser_context()); @@ -2151,7 +2218,7 @@ }])")); } -TEST_F(DeveloperPrivateApiUnitTest, +TEST_F(DeveloperPrivateApiWithPermittedSitesUnitTest, DeveloperPrivateGetUserAndExtensionSitesByEtld_UserAndExtensionSites) { PermissionsManager* manager = PermissionsManager::Get(browser_context()); manager->AddUserPermittedSite( @@ -2234,7 +2301,7 @@ }])")); } -TEST_F(DeveloperPrivateApiUnitTest, +TEST_F(DeveloperPrivateApiWithPermittedSitesUnitTest, DeveloperPrivateGetUserAndExtensionSitesByEtld_EffectiveAllHosts) { PermissionsManager* manager = PermissionsManager::Get(browser_context()); manager->AddUserPermittedSite( @@ -2263,8 +2330,8 @@ const base::Value::List* results = function->GetResultListForTest(); ASSERT_EQ(1u, results->size()); - // `extension_2` should not be counted for https://*.google.ca/* as it cannot - // run on .ca sites. + // `extension_2` should not be counted for https://*.google.ca/* as it + // cannot run on .ca sites. EXPECT_THAT((*results)[0], base::test::IsJson(R"([{ "etldPlusOne": "example.com", "numExtensions": 3,
diff --git a/chrome/browser/extensions/api/pdf_viewer_private/pdf_viewer_private_event_router.cc b/chrome/browser/extensions/api/pdf_viewer_private/pdf_viewer_private_event_router.cc new file mode 100644 index 0000000..fa93ed64 --- /dev/null +++ b/chrome/browser/extensions/api/pdf_viewer_private/pdf_viewer_private_event_router.cc
@@ -0,0 +1,90 @@ +// Copyright 2023 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/extensions/api/pdf_viewer_private/pdf_viewer_private_event_router.h" + +#include "base/functional/bind.h" +#include "chrome/common/extensions/api/pdf_viewer_private.h" +#include "chrome/common/pref_names.h" +#include "components/prefs/pref_service.h" + +namespace extensions { + +// static +PdfViewerPrivateEventRouter* PdfViewerPrivateEventRouter::Create( + content::BrowserContext* context) { + DCHECK(context); + Profile* profile = Profile::FromBrowserContext(context); + return new PdfViewerPrivateEventRouter(profile); +} + +PdfViewerPrivateEventRouter::PdfViewerPrivateEventRouter(Profile* profile) + : profile_(profile) { + DCHECK(profile_); + user_prefs_registrar_.Init(profile_->GetPrefs()); + EventRouter::Get(profile_)->RegisterObserver( + this, api::pdf_viewer_private::OnPdfOcrPrefChanged::kEventName); + StartOrStopListeningForPdfOcrPrefChanges(); +} + +PdfViewerPrivateEventRouter::~PdfViewerPrivateEventRouter() { + DCHECK(user_prefs_registrar_.IsEmpty()); +} + +void PdfViewerPrivateEventRouter::Shutdown() { + EventRouter::Get(profile_)->UnregisterObserver(this); + if (!user_prefs_registrar_.IsEmpty()) { + user_prefs_registrar_.Remove(prefs::kAccessibilityPdfOcrAlwaysActive); + } +} + +void PdfViewerPrivateEventRouter::OnListenerAdded( + const EventListenerInfo& details) { + // Start listening to events from the user registrar for the PDF OCR pref. + StartOrStopListeningForPdfOcrPrefChanges(); +} + +void PdfViewerPrivateEventRouter::OnListenerRemoved( + const EventListenerInfo& details) { + // Stop listening to events from the user registrar for the PDF OCR pref + // if there are no more listeners. + StartOrStopListeningForPdfOcrPrefChanges(); +} + +void PdfViewerPrivateEventRouter::StartOrStopListeningForPdfOcrPrefChanges() { + EventRouter* event_router = EventRouter::Get(profile_); + bool should_listen = event_router->HasEventListener( + api::pdf_viewer_private::OnPdfOcrPrefChanged::kEventName); + + if (should_listen && user_prefs_registrar_.IsEmpty()) { + // base::Unretained() is safe since `this` will be destroyed after this + // listener is removed. + user_prefs_registrar_.Add( + prefs::kAccessibilityPdfOcrAlwaysActive, + base::BindRepeating( + &PdfViewerPrivateEventRouter::OnPdfOcrPreferenceChanged, + base::Unretained(this))); + } else if (!should_listen && !user_prefs_registrar_.IsEmpty()) { + user_prefs_registrar_.Remove(prefs::kAccessibilityPdfOcrAlwaysActive); + } +} + +void PdfViewerPrivateEventRouter::OnPdfOcrPreferenceChanged() { + EventRouter* event_router = EventRouter::Get(profile_); + if (!event_router->HasEventListener( + api::pdf_viewer_private::OnPdfOcrPrefChanged::kEventName)) { + return; + } + // Send the changed value of the PDF OCR pref to observers. + base::Value::List event_arg; + bool is_pdf_ocr_always_active = + profile_->GetPrefs()->GetBoolean(prefs::kAccessibilityPdfOcrAlwaysActive); + event_arg.Append(is_pdf_ocr_always_active); + event_router->BroadcastEvent(std::make_unique<Event>( + events::PDF_VIEWER_PRIVATE_ON_PDF_OCR_PREF_CHANGED, + api::pdf_viewer_private::OnPdfOcrPrefChanged::kEventName, + std::move(event_arg))); +} + +} // namespace extensions
diff --git a/chrome/browser/extensions/api/pdf_viewer_private/pdf_viewer_private_event_router.h b/chrome/browser/extensions/api/pdf_viewer_private/pdf_viewer_private_event_router.h new file mode 100644 index 0000000..4035fac --- /dev/null +++ b/chrome/browser/extensions/api/pdf_viewer_private/pdf_viewer_private_event_router.h
@@ -0,0 +1,58 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_EXTENSIONS_API_PDF_VIEWER_PRIVATE_PDF_VIEWER_PRIVATE_EVENT_ROUTER_H_ +#define CHROME_BROWSER_EXTENSIONS_API_PDF_VIEWER_PRIVATE_PDF_VIEWER_PRIVATE_EVENT_ROUTER_H_ + +#include "base/memory/raw_ptr.h" +#include "chrome/browser/profiles/profile.h" +#include "components/keyed_service/core/keyed_service.h" +#include "components/prefs/pref_change_registrar.h" +#include "extensions/browser/event_router.h" + +namespace content { +class BrowserContext; +} + +namespace extensions { + +class PdfViewerPrivateEventRouter : public KeyedService, + public EventRouter::Observer { + public: + static PdfViewerPrivateEventRouter* Create(content::BrowserContext* context); + + explicit PdfViewerPrivateEventRouter(Profile* profile); + + PdfViewerPrivateEventRouter(const PdfViewerPrivateEventRouter&) = delete; + PdfViewerPrivateEventRouter& operator=(const PdfViewerPrivateEventRouter&) = + delete; + + ~PdfViewerPrivateEventRouter() override; + + // KeyedService overrides: + void Shutdown() override; + + // EventRouter::Observer overrides: + void OnListenerAdded(const EventListenerInfo& details) override; + void OnListenerRemoved(const EventListenerInfo& details) override; + + private: + // Decide if we should listen for pref changes or not. If there are any + // JavaScript listeners registered for the onPdfOcrPrefChanged event, then we + // want to register for change notification from the user registrar. + // Otherwise, we want to unregister and not be listening for pref changes. + void StartOrStopListeningForPdfOcrPrefChanges(); + + // Sends a pref change to any listeners (if they exist; no-ops otherwise). + void OnPdfOcrPreferenceChanged(); + + const raw_ptr<Profile> profile_ = nullptr; + + // This registrar monitors for user prefs changes. + PrefChangeRegistrar user_prefs_registrar_; +}; + +} // namespace extensions + +#endif // CHROME_BROWSER_EXTENSIONS_API_PDF_VIEWER_PRIVATE_PDF_VIEWER_PRIVATE_EVENT_ROUTER_H_
diff --git a/chrome/browser/extensions/api/pdf_viewer_private/pdf_viewer_private_event_router_factory.cc b/chrome/browser/extensions/api/pdf_viewer_private/pdf_viewer_private_event_router_factory.cc new file mode 100644 index 0000000..eb6e6abe --- /dev/null +++ b/chrome/browser/extensions/api/pdf_viewer_private/pdf_viewer_private_event_router_factory.cc
@@ -0,0 +1,53 @@ +// Copyright 2023 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/extensions/api/pdf_viewer_private/pdf_viewer_private_event_router_factory.h" + +#include "chrome/browser/extensions/api/pdf_viewer_private/pdf_viewer_private_event_router.h" +#include "content/public/browser/browser_context.h" +#include "extensions/browser/event_router_factory.h" +#include "extensions/browser/extension_system_provider.h" +#include "extensions/browser/extensions_browser_client.h" + +namespace extensions { + +// static +PdfViewerPrivateEventRouter* PdfViewerPrivateEventRouterFactory::GetForProfile( + content::BrowserContext* context) { + return static_cast<PdfViewerPrivateEventRouter*>( + GetInstance()->GetServiceForBrowserContext(context, true)); +} + +// static +PdfViewerPrivateEventRouterFactory* +PdfViewerPrivateEventRouterFactory::GetInstance() { + return base::Singleton<PdfViewerPrivateEventRouterFactory>::get(); +} + +PdfViewerPrivateEventRouterFactory::PdfViewerPrivateEventRouterFactory() + : ProfileKeyedServiceFactory( + "PdfViewerPrivateEventRouter", + ProfileSelections::BuildForRegularAndIncognito()) { + DependsOn(ExtensionsBrowserClient::Get()->GetExtensionSystemFactory()); + DependsOn(EventRouterFactory::GetInstance()); +} + +PdfViewerPrivateEventRouterFactory::~PdfViewerPrivateEventRouterFactory() = + default; + +KeyedService* PdfViewerPrivateEventRouterFactory::BuildServiceInstanceFor( + content::BrowserContext* context) const { + return PdfViewerPrivateEventRouter::Create(context); +} + +bool PdfViewerPrivateEventRouterFactory::ServiceIsCreatedWithBrowserContext() + const { + return true; +} + +bool PdfViewerPrivateEventRouterFactory::ServiceIsNULLWhileTesting() const { + return true; +} + +} // namespace extensions
diff --git a/chrome/browser/extensions/api/pdf_viewer_private/pdf_viewer_private_event_router_factory.h b/chrome/browser/extensions/api/pdf_viewer_private/pdf_viewer_private_event_router_factory.h new file mode 100644 index 0000000..faebd6c6 --- /dev/null +++ b/chrome/browser/extensions/api/pdf_viewer_private/pdf_viewer_private_event_router_factory.h
@@ -0,0 +1,52 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_EXTENSIONS_API_PDF_VIEWER_PRIVATE_PDF_VIEWER_PRIVATE_EVENT_ROUTER_FACTORY_H_ +#define CHROME_BROWSER_EXTENSIONS_API_PDF_VIEWER_PRIVATE_PDF_VIEWER_PRIVATE_EVENT_ROUTER_FACTORY_H_ + +#include "base/memory/singleton.h" +#include "chrome/browser/profiles/profile_keyed_service_factory.h" + +namespace extensions { + +class PdfViewerPrivateEventRouter; + +// This is a factory class used by the BrowserContextDependencyManager +// to instantiate the pdfViewerPrivate event router per profile (since the +// extension event router is per profile). +class PdfViewerPrivateEventRouterFactory : public ProfileKeyedServiceFactory { + public: + PdfViewerPrivateEventRouterFactory( + const PdfViewerPrivateEventRouterFactory&) = delete; + PdfViewerPrivateEventRouterFactory& operator=( + const PdfViewerPrivateEventRouterFactory&) = delete; + + // Returns the PdfViewerPrivateEventRouter for |profile|, creating it if + // it is not yet created. + static PdfViewerPrivateEventRouter* GetForProfile( + content::BrowserContext* context); + + // Returns the PdfViewerPrivateEventRouterFactory instance. + static PdfViewerPrivateEventRouterFactory* GetInstance(); + + protected: + // BrowserContextKeyedServiceFactory overrides: + bool ServiceIsCreatedWithBrowserContext() const override; + bool ServiceIsNULLWhileTesting() const override; + + private: + friend struct base::DefaultSingletonTraits< + PdfViewerPrivateEventRouterFactory>; + + PdfViewerPrivateEventRouterFactory(); + ~PdfViewerPrivateEventRouterFactory() override; + + // BrowserContextKeyedServiceFactory: + KeyedService* BuildServiceInstanceFor( + content::BrowserContext* profile) const override; +}; + +} // namespace extensions + +#endif // CHROME_BROWSER_EXTENSIONS_API_PDF_VIEWER_PRIVATE_PDF_VIEWER_PRIVATE_EVENT_ROUTER_FACTORY_H_
diff --git a/chrome/browser/extensions/corb_and_cors_extension_browsertest.cc b/chrome/browser/extensions/corb_and_cors_extension_browsertest.cc index f6e9a74..3a20d8c 100644 --- a/chrome/browser/extensions/corb_and_cors_extension_browsertest.cc +++ b/chrome/browser/extensions/corb_and_cors_extension_browsertest.cc
@@ -881,8 +881,10 @@ : public CorbAndCorsExtensionBrowserTest { public: CorbAndCorsUserHostRestrictionsBrowserTest() { - scoped_feature_list_.InitAndEnableFeature( - extensions_features::kExtensionsMenuAccessControl); + std::vector<base::test::FeatureRef> enabled_features = { + extensions_features::kExtensionsMenuAccessControl, + extensions_features::kExtensionsMenuAccessControlWithPermittedSites}; + scoped_feature_list_.InitWithFeatures(enabled_features, {}); } private: @@ -909,12 +911,15 @@ PermissionsManager* permissions_manager = PermissionsManager::Get(profile()); { + // Sites can be set as restricted iff the `host controls` flag is enabled. PermissionsManagerWaiter waiter(permissions_manager); permissions_manager->AddUserRestrictedSite( url::Origin::Create(policy_allowed_resource)); waiter.WaitForUserPermissionsSettingsChange(); } { + // Sites can be set as permitted iff the `host controls` and `permitted + // sites` flags are enabled. PermissionsManagerWaiter waiter(permissions_manager); permissions_manager->AddUserPermittedSite( url::Origin::Create(policy_restricted_resource));
diff --git a/chrome/browser/extensions/extension_action_runner.cc b/chrome/browser/extensions/extension_action_runner.cc index 4aade600..3fad63d 100644 --- a/chrome/browser/extensions/extension_action_runner.cc +++ b/chrome/browser/extensions/extension_action_runner.cc
@@ -43,6 +43,7 @@ #include "extensions/browser/permissions_manager.h" #include "extensions/common/api/extension_action/action_info.h" #include "extensions/common/extension.h" +#include "extensions/common/extension_features.h" #include "extensions/common/extension_id.h" #include "extensions/common/extension_set.h" #include "extensions/common/manifest.h" @@ -209,6 +210,13 @@ const base::flat_set<ToolbarActionsModel::ActionId>& action_ids, const url::Origin& origin, PermissionsManager::UserSiteSetting new_site_settings) { + // Granting access to all extensions is only allowed iff feature is enabled. + DCHECK( + new_site_settings != + PermissionsManager::UserSiteSetting::kGrantAllExtensions || + base::FeatureList::IsEnabled( + extensions_features::kExtensionsMenuAccessControlWithPermittedSites)); + auto* registry = ExtensionRegistry::Get(browser_context_); std::vector<const Extension*> extensions; extensions.reserve(action_ids.size());
diff --git a/chrome/browser/extensions/extension_action_runner_browsertest.cc b/chrome/browser/extensions/extension_action_runner_browsertest.cc index 6edae3d8..2e7c453c 100644 --- a/chrome/browser/extensions/extension_action_runner_browsertest.cc +++ b/chrome/browser/extensions/extension_action_runner_browsertest.cc
@@ -771,9 +771,134 @@ SiteAccess::kOnAllSites); EXPECT_TRUE(DidInjectScript(web_contents())); + // "customize by extension (on site)" -> "block all extensions": + // not accepting the page reload bubble maintains the same user site + // setting and keeps the script injected. + HandleUserSiteSettingModified(extension->id(), url_origin, + UserSiteSetting::kBlockAllExtensions, false); + EXPECT_EQ(permissions_manager()->GetUserSiteSetting(url_origin), + UserSiteSetting::kCustomizeByExtension); + EXPECT_TRUE(DidInjectScript(web_contents())); + + // "customize by extension (on site)" -> "block all extensions": + // accepting the page reload bubble revokes site access, refreshes the page + // and does not inject the script. (Note: we will accept all the next reload + // page bubbles since we previously checked the behavior of not accepting the + // dialog). + HandleUserSiteSettingModified(extension->id(), url_origin, + UserSiteSetting::kBlockAllExtensions, true); + EXPECT_EQ(permissions_manager()->GetUserSiteSetting(url_origin), + UserSiteSetting::kBlockAllExtensions); + EXPECT_FALSE(DidInjectScript(web_contents())); + + // "block all extensions" -> "customize by extension (on site)": + // grants site access, refreshes the page and injects the script. + HandleUserSiteSettingModified(extension->id(), url_origin, + UserSiteSetting::kCustomizeByExtension, true); + EXPECT_EQ(permissions_manager()->GetUserSiteSetting(url_origin), + UserSiteSetting::kCustomizeByExtension); + EXPECT_TRUE(DidInjectScript(web_contents())); +} + +// Tests changing user site settings when the extension does not have site +// access ('on click'). Note that we don't check if extension +// `WantsToRun` because on user-restricted sites, actions are blocked rather +// than withheld. +IN_PROC_BROWSER_TEST_F(ExtensionActionRunnerWithUserHostControlsBrowserTest, + HandleUserSiteSettingModified_ExtensionHasNoAccess) { + // Load an extension that wants to run on every page at document start. + const Extension* extension = LoadExtension( + test_data_dir_.AppendASCII("blocked_actions/content_scripts")); + ASSERT_TRUE(extension); + + // Withheld extension's host permission, so extension has "on click" site + // access. + ScriptingPermissionsModifier(profile(), extension) + .SetWithholdHostPermissions(true); + + // Navigate to a page where the extension wants to run. + const GURL url = embedded_test_server()->GetURL("/simple.html"); + const url::Origin url_origin = url::Origin::Create(url); + ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url)); + + // The page should have "customize by extension" user site setting and "on + // click" site access. The extension should not have injected. + EXPECT_EQ(permissions_manager()->GetUserSiteSetting(url_origin), + UserSiteSetting::kCustomizeByExtension); + EXPECT_EQ(SitePermissionsHelper(profile()).GetSiteAccess(*extension, url), + SiteAccess::kOnClick); + EXPECT_FALSE(DidInjectScript(web_contents())); + + // "customize by extension (on click)" -> "block all extensions": + // maintains current site access, and script is still not injected. No refresh + // is required. + HandleUserSiteSettingModified(extension->id(), url_origin, + UserSiteSetting::kBlockAllExtensions, false); + EXPECT_EQ(permissions_manager()->GetUserSiteSetting(url_origin), + UserSiteSetting::kBlockAllExtensions); + EXPECT_FALSE(DidInjectScript(web_contents())); + + // "block all extensions" -> "customize by extension (on click)": + // maintains current site access, refreshes the page and still does not inject + // the script. + HandleUserSiteSettingModified(extension->id(), url_origin, + UserSiteSetting::kCustomizeByExtension, true); + EXPECT_EQ(permissions_manager()->GetUserSiteSetting(url_origin), + UserSiteSetting::kCustomizeByExtension); + EXPECT_FALSE(DidInjectScript(web_contents())); +} + +class ExtensionActionRunnerWithUserHostControlsAndPermittedSitesBrowserTest + : public ExtensionActionRunnerWithUserHostControlsBrowserTest { + public: + ExtensionActionRunnerWithUserHostControlsAndPermittedSitesBrowserTest() { + feature_list_.InitAndEnableFeature( + extensions_features::kExtensionsMenuAccessControlWithPermittedSites); + } + ~ExtensionActionRunnerWithUserHostControlsAndPermittedSitesBrowserTest() + override = default; + + private: + base::test::ScopedFeatureList feature_list_; +}; + +// Tests changing user site settings when the extension has site access (which +// is either 'on all sites' or 'on site'). Note that we don't check if extension +// `WantsToRun` because on user-restricted sites, actions are blocked rather +// than withheld. +// TODO(crbug.com/1363781): Flaky on Win 7 and Mac 12. +#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) +#define MAYBE_HandleUserSiteSettingModified_ExtensionHasAccess \ + DISABLED_HandleUserSiteSettingModified_ExtensionHasAccess +#else +#define MAYBE_HandleUserSiteSettingModified_ExtensionHasAccess \ + HandleUserSiteSettingModified_ExtensionHasAccess +#endif +IN_PROC_BROWSER_TEST_F( + ExtensionActionRunnerWithUserHostControlsAndPermittedSitesBrowserTest, + MAYBE_HandleUserSiteSettingModified_ExtensionHasAccess) { + // Load an extension that wants to run on every page at document start. + const Extension* extension = LoadExtension( + test_data_dir_.AppendASCII("blocked_actions/content_scripts")); + ASSERT_TRUE(extension); + + // Navigate to a page where the extension can run. + const GURL url = embedded_test_server()->GetURL("/simple.html"); + const url::Origin url_origin = url::Origin::Create(url); + ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url)); + + // By default, the page should have "customize by extension" user site + // setting and the extensions should have "on all sites" site access. The + // extension should have injected. + EXPECT_EQ(permissions_manager()->GetUserSiteSetting(url_origin), + UserSiteSetting::kCustomizeByExtension); + EXPECT_EQ(SitePermissionsHelper(profile()).GetSiteAccess(*extension, url), + SiteAccess::kOnAllSites); + EXPECT_TRUE(DidInjectScript(web_contents())); + // "customize by extension (on site) -> "grant all extensions": - // maintains current site access and keeps the script injected. No refresh is - // required. + // maintains current site access and keeps the script injected. No refresh + // is required. HandleUserSiteSettingModified(extension->id(), url_origin, UserSiteSetting::kGrantAllExtensions, false); EXPECT_EQ(permissions_manager()->GetUserSiteSetting(url_origin), @@ -792,8 +917,8 @@ // "grant all extensions" -> "block all extensions": // accepting the page reload bubble revokes site access, refreshes the page // and does not inject the script. (Note: we will accept all the next reload - // page bubbles since we previously checked the behavior of not accepting the - // dialog). + // page bubbles since we previously checked the behavior of not accepting + // the dialog). HandleUserSiteSettingModified(extension->id(), url_origin, UserSiteSetting::kBlockAllExtensions, true); EXPECT_EQ(permissions_manager()->GetUserSiteSetting(url_origin), @@ -839,8 +964,9 @@ // access ('on click'). Note that we don't check if extension // `WantsToRun` because on user-restricted sites, actions are blocked rather // than withheld. -IN_PROC_BROWSER_TEST_F(ExtensionActionRunnerWithUserHostControlsBrowserTest, - HandleUserSiteSettingModified_ExtensionHasNoAccess) { +IN_PROC_BROWSER_TEST_F( + ExtensionActionRunnerWithUserHostControlsAndPermittedSitesBrowserTest, + HandleUserSiteSettingModified_ExtensionHasNoAccess) { // Load an extension that wants to run on every page at document start. const Extension* extension = LoadExtension( test_data_dir_.AppendASCII("blocked_actions/content_scripts"));
diff --git a/chrome/browser/extensions/extension_context_menu_model_unittest.cc b/chrome/browser/extensions/extension_context_menu_model_unittest.cc index 7307a7f..ae85701 100644 --- a/chrome/browser/extensions/extension_context_menu_model_unittest.cc +++ b/chrome/browser/extensions/extension_context_menu_model_unittest.cc
@@ -1923,12 +1923,8 @@ public testing::WithParamInterface<bool> { public: ExtensionContextMenuModelWithUserHostControlsTest() { - const base::Feature& feature = - extensions_features::kExtensionsMenuAccessControl; - if (GetParam()) - feature_list_.InitAndEnableFeature(feature); - else - feature_list_.InitAndDisableFeature(feature); + feature_list_.InitWithFeatureState( + extensions_features::kExtensionsMenuAccessControl, GetParam()); } ~ExtensionContextMenuModelWithUserHostControlsTest() override = default; @@ -1984,54 +1980,7 @@ auto* manager = extensions::PermissionsManager::Get(profile()); { - // Add site as a user permitted site. - extensions::PermissionsManagerWaiter manager_waiter(manager); - manager->AddUserPermittedSite(url::Origin::Create(url)); - manager_waiter.WaitForUserPermissionsSettingsChange(); - - ExtensionContextMenuModel menu(extension, GetBrowser(), - ExtensionContextMenuModel::PINNED, nullptr, - true, ContextMenuSource::kToolbarAction); - - if (GetParam()) { - // Verify "grant all extensions" item is visible and disabled, and the - // "learn more" and "permissions page" item are in the context menu. - EXPECT_EQ(GetCommandState(menu, kGrantAllExtensions), - CommandState::kDisabled); - EXPECT_EQ(GetCommandState(menu, kBlockAllExtensions), - CommandState::kAbsent); - EXPECT_EQ(GetCommandState(menu, kPageAccessSubmenu), - CommandState::kAbsent); - EXPECT_EQ(GetCommandState(menu, kLearnMore), CommandState::kEnabled); - EXPECT_EQ(GetPageAccessCommandState(menu, kLearnMore), - CommandState::kAbsent); - EXPECT_EQ(GetCommandState(menu, kPermissionsPage), - CommandState::kEnabled); - EXPECT_EQ(GetPageAccessCommandState(menu, kLearnMore), - CommandState::kAbsent); - } else { - // Even though we added a site as a user permitted site, the site - // permission behaves as "customize by extension". Verify page access - // submenu is visible and enabled, the "learn more" item is in in the - // submenu and the "permissions page" item is nowhere visible. - EXPECT_EQ(GetCommandState(menu, kGrantAllExtensions), - CommandState::kAbsent); - EXPECT_EQ(GetCommandState(menu, kBlockAllExtensions), - CommandState::kAbsent); - EXPECT_EQ(GetCommandState(menu, kPageAccessSubmenu), - CommandState::kEnabled); - EXPECT_EQ(GetCommandState(menu, kLearnMore), CommandState::kAbsent); - EXPECT_EQ(GetPageAccessCommandState(menu, kLearnMore), - CommandState::kEnabled); - EXPECT_EQ(GetCommandState(menu, kPermissionsPage), CommandState::kAbsent); - EXPECT_EQ(GetPageAccessCommandState(menu, kPermissionsPage), - CommandState::kAbsent); - } - } - - { - // Add site as a user restricted site. Note that adding a site as restricted - // site removes it from the permitted sites. + // Add site as a user restricted site. extensions::PermissionsManagerWaiter manager_waiter(manager); manager->AddUserRestrictedSite(url::Origin::Create(url)); manager_waiter.WaitForUserPermissionsSettingsChange(); @@ -2128,4 +2077,113 @@ GURL(chrome_extension_constants::kExtensionsSitePermissionsURL)); } +class ExtensionContextMenuModelWithUserHostControlsAndPermittedSitesTest + : public ExtensionContextMenuModelWithUserHostControlsTest { + public: + ExtensionContextMenuModelWithUserHostControlsAndPermittedSitesTest() { + feature_list_.InitAndEnableFeature( + extensions_features::kExtensionsMenuAccessControlWithPermittedSites); + } + ~ExtensionContextMenuModelWithUserHostControlsAndPermittedSitesTest() + override = default; + + private: + base::test::ScopedFeatureList feature_list_; +}; + +INSTANTIATE_TEST_SUITE_P( + All, + ExtensionContextMenuModelWithUserHostControlsAndPermittedSitesTest, + testing::Bool()); + +TEST_P(ExtensionContextMenuModelWithUserHostControlsAndPermittedSitesTest, + PageAccessItemsVisibilityBasedOnSiteSettings) { + InitializeEmptyExtensionService(); + + const Extension* extension = + AddExtensionWithHostPermission("extension", manifest_keys::kBrowserAction, + ManifestLocation::kInternal, "<all_urls>"); + + // Add a tab to the browser. + const GURL url("http://www.example.com/"); + AddTab(url); + + { + // By default, the site permission is set to "customize by extension". + // Verify page access submenu is visible and enabled, and the "learn more" + // item is in in the submenu. + ExtensionContextMenuModel menu(extension, GetBrowser(), + ExtensionContextMenuModel::PINNED, nullptr, + true, ContextMenuSource::kToolbarAction); + EXPECT_EQ(GetCommandState(menu, kGrantAllExtensions), + CommandState::kAbsent); + EXPECT_EQ(GetCommandState(menu, kBlockAllExtensions), + CommandState::kAbsent); + EXPECT_EQ(GetCommandState(menu, kPageAccessSubmenu), + CommandState::kEnabled); + EXPECT_EQ(GetCommandState(menu, kLearnMore), CommandState::kAbsent); + EXPECT_EQ(GetPageAccessCommandState(menu, kLearnMore), + CommandState::kEnabled); + // The "permissions page" item is in the submenu only if the feature is + // enabled. + EXPECT_EQ(GetCommandState(menu, kPermissionsPage), CommandState::kAbsent); + CommandState permission_page_state = + GetParam() ? CommandState::kEnabled : CommandState::kAbsent; + EXPECT_EQ(GetPageAccessCommandState(menu, kPermissionsPage), + permission_page_state); + } + + // User site settings are only taken into account for site access computations + // when the kExtensionsMenuAccessControl feature is enabled, even if they are + // added by the manager. Therefore, the context menu should not take into + // account user site settings when the feature is disabled. + auto* manager = extensions::PermissionsManager::Get(profile()); + + { + // Add site as a user permitted site. + extensions::PermissionsManagerWaiter manager_waiter(manager); + manager->AddUserPermittedSite(url::Origin::Create(url)); + manager_waiter.WaitForUserPermissionsSettingsChange(); + + ExtensionContextMenuModel menu(extension, GetBrowser(), + ExtensionContextMenuModel::PINNED, nullptr, + true, ContextMenuSource::kToolbarAction); + + if (GetParam()) { + // Verify "grant all extensions" item is visible and disabled, and the + // "learn more" and "permissions page" item are in the context menu. + EXPECT_EQ(GetCommandState(menu, kGrantAllExtensions), + CommandState::kDisabled); + EXPECT_EQ(GetCommandState(menu, kBlockAllExtensions), + CommandState::kAbsent); + EXPECT_EQ(GetCommandState(menu, kPageAccessSubmenu), + CommandState::kAbsent); + EXPECT_EQ(GetCommandState(menu, kLearnMore), CommandState::kEnabled); + EXPECT_EQ(GetPageAccessCommandState(menu, kLearnMore), + CommandState::kAbsent); + EXPECT_EQ(GetCommandState(menu, kPermissionsPage), + CommandState::kEnabled); + EXPECT_EQ(GetPageAccessCommandState(menu, kLearnMore), + CommandState::kAbsent); + } else { + // Even though we added a site as a user permitted site, the site + // permission behaves as "customize by extension". Verify page access + // submenu is visible and enabled, the "learn more" item is in in the + // submenu and the "permissions page" item is nowhere visible. + EXPECT_EQ(GetCommandState(menu, kGrantAllExtensions), + CommandState::kAbsent); + EXPECT_EQ(GetCommandState(menu, kBlockAllExtensions), + CommandState::kAbsent); + EXPECT_EQ(GetCommandState(menu, kPageAccessSubmenu), + CommandState::kEnabled); + EXPECT_EQ(GetCommandState(menu, kLearnMore), CommandState::kAbsent); + EXPECT_EQ(GetPageAccessCommandState(menu, kLearnMore), + CommandState::kEnabled); + EXPECT_EQ(GetCommandState(menu, kPermissionsPage), CommandState::kAbsent); + EXPECT_EQ(GetPageAccessCommandState(menu, kPermissionsPage), + CommandState::kAbsent); + } + } +} + } // namespace extensions
diff --git a/chrome/browser/extensions/permissions_manager_browsertest.cc b/chrome/browser/extensions/permissions_manager_browsertest.cc index 46e12cd..cb6303c 100644 --- a/chrome/browser/extensions/permissions_manager_browsertest.cc +++ b/chrome/browser/extensions/permissions_manager_browsertest.cc
@@ -5,67 +5,84 @@ #include "chrome/browser/extensions/extension_browsertest.h" #include "content/public/test/browser_test.h" #include "extensions/browser/permissions_manager.h" -#include "extensions/browser/state_store.h" +#include "extensions/common/extension_features.h" +#include "testing/gtest/include/gtest/gtest.h" namespace extensions { using PermissionsManagerBrowserTest = ExtensionBrowserTest; IN_PROC_BROWSER_TEST_F(PermissionsManagerBrowserTest, - PRE_UserPermissionsArePersisted) { + PRE_RestrictedSitesArePersisted) { auto* manager = PermissionsManager::Get(profile()); // Verify the restricted sites list is empty. EXPECT_EQ(manager->GetUserPermissionsSettings().restricted_sites, std::set<url::Origin>()); - { - // Add a url to restricted sites. Verify the site is stored as a restricted - // site. - const url::Origin url = - url::Origin::Create(GURL("http://restricted.example.com")); - std::set<url::Origin> set_with_url; - set_with_url.insert(url); - manager->AddUserRestrictedSite(url); - EXPECT_EQ(manager->GetUserPermissionsSettings().restricted_sites, - set_with_url); - } - - { - // Add a different url to permitted sites. Verify the site is stored as a - // permitted site. - const url::Origin url = - url::Origin::Create(GURL("http://permitted.example.com")); - std::set<url::Origin> set_with_url; - set_with_url.insert(url); - manager->AddUserPermittedSite(url); - EXPECT_EQ(manager->GetUserPermissionsSettings().permitted_sites, - set_with_url); - } + // Add a url to restricted sites. Verify the site is stored as a restricted + // site. + const url::Origin url = + url::Origin::Create(GURL("http://restricted.example.com")); + std::set<url::Origin> set_with_url; + set_with_url.insert(url); + manager->AddUserRestrictedSite(url); + EXPECT_EQ(manager->GetUserPermissionsSettings().restricted_sites, + set_with_url); } // Tests that user-level permissions are properly persisted across sessions. IN_PROC_BROWSER_TEST_F(PermissionsManagerBrowserTest, - UserPermissionsArePersisted) { + RestrictedSitesArePersisted) { auto* manager = PermissionsManager::Get(profile()); - { - // Verify the restricted site stored in previous session is persisted. - std::set<url::Origin> set_with_url; - set_with_url.insert( - url::Origin::Create(GURL("http://restricted.example.com"))); - EXPECT_EQ(manager->GetUserPermissionsSettings().restricted_sites, - set_with_url); - } + // Verify the restricted site stored in previous session is persisted. + std::set<url::Origin> set_with_url; + set_with_url.insert( + url::Origin::Create(GURL("http://restricted.example.com"))); + EXPECT_EQ(manager->GetUserPermissionsSettings().restricted_sites, + set_with_url); +} - { - // Verify the permitted site stored in previous session is persisted. - std::set<url::Origin> set_with_url; - set_with_url.insert( - url::Origin::Create(GURL("http://permitted.example.com"))); - EXPECT_EQ(manager->GetUserPermissionsSettings().permitted_sites, - set_with_url); +class PermissionsManagerWithPermittedSitesBrowserTest + : public ExtensionBrowserTest { + public: + PermissionsManagerWithPermittedSitesBrowserTest() { + scoped_feature_list_.InitAndEnableFeature( + extensions_features::kExtensionsMenuAccessControlWithPermittedSites); } + ~PermissionsManagerWithPermittedSitesBrowserTest() override = default; + + private: + base::test::ScopedFeatureList scoped_feature_list_; +}; + +IN_PROC_BROWSER_TEST_F(PermissionsManagerWithPermittedSitesBrowserTest, + PRE_PermittedSitesArePersisted) { + auto* manager = PermissionsManager::Get(profile()); + + // Add a url to permitted sites. Verify the site is stored as a permitted + // site. + const url::Origin url = + url::Origin::Create(GURL("http://permitted.example.com")); + std::set<url::Origin> set_with_url; + set_with_url.insert(url); + manager->AddUserPermittedSite(url); + EXPECT_EQ(manager->GetUserPermissionsSettings().permitted_sites, + set_with_url); +} + +// Tests that user-level permissions are properly persisted across sessions. +IN_PROC_BROWSER_TEST_F(PermissionsManagerWithPermittedSitesBrowserTest, + PermittedSitesArePersisted) { + auto* manager = PermissionsManager::Get(profile()); + + // Verify the permitted site stored in previous session is persisted. + std::set<url::Origin> set_with_url; + set_with_url.insert( + url::Origin::Create(GURL("http://permitted.example.com"))); + EXPECT_EQ(manager->GetUserPermissionsSettings().permitted_sites, + set_with_url); } } // namespace extensions
diff --git a/chrome/browser/extensions/permissions_updater_unittest.cc b/chrome/browser/extensions/permissions_updater_unittest.cc index 96304a6..e24e1c6 100644 --- a/chrome/browser/extensions/permissions_updater_unittest.cc +++ b/chrome/browser/extensions/permissions_updater_unittest.cc
@@ -937,16 +937,14 @@ } class PermissionsUpdaterTestWithEnhancedHostControls - : public PermissionsUpdaterTest, - public testing::WithParamInterface<bool> { + : public PermissionsUpdaterTest { public: PermissionsUpdaterTestWithEnhancedHostControls() { - const base::Feature& feature = - extensions_features::kExtensionsMenuAccessControl; - if (GetParam()) - feature_list_.InitAndEnableFeature(feature); - else - feature_list_.InitAndDisableFeature(feature); + std::vector<base::test::FeatureRef> enabled_features = { + extensions_features::kExtensionsMenuAccessControl, + extensions_features::kExtensionsMenuAccessControlWithPermittedSites}; + std::vector<base::test::FeatureRef> disabled_features = {}; + feature_list_.InitWithFeatures(enabled_features, disabled_features); } ~PermissionsUpdaterTestWithEnhancedHostControls() override = default; @@ -954,13 +952,9 @@ base::test::ScopedFeatureList feature_list_; }; -INSTANTIATE_TEST_SUITE_P(All, - PermissionsUpdaterTestWithEnhancedHostControls, - testing::Bool()); - // Tests the behavior of revoking permissions from the extension while the // user has specified a set of sites that all extensions are allowed to run on. -TEST_P(PermissionsUpdaterTestWithEnhancedHostControls, +TEST_F(PermissionsUpdaterTestWithEnhancedHostControls, RevokingPermissionsWithUserPermittedSites) { InitializeEmptyExtensionService(); @@ -1032,20 +1026,6 @@ ScriptingPermissionsModifier(profile(), extension) .SetWithholdHostPermissions(true); - // If the enhanced host controls feature is disabled, then both hosts are - // withheld. - if (!GetParam()) { - EXPECT_EQ(PermissionsData::PageAccess::kWithheld, - get_site_access(first_url)); - EXPECT_EQ(PermissionsData::PageAccess::kWithheld, - get_site_access(second_url)); - // There's nothing more we need to test in this case. - return; - } - - // Otherwise, the feature is enabled, and user host settings are considered - // in the permissions adjustment. - // The extension should be allowed to run on `first_url`, since the // user indicated all extensions can always run there. However, it should not // be allowed on `second_url`.
diff --git a/chrome/browser/extensions/site_permissions_helper_unittest.cc b/chrome/browser/extensions/site_permissions_helper_unittest.cc index c196cbb..9d3909f 100644 --- a/chrome/browser/extensions/site_permissions_helper_unittest.cc +++ b/chrome/browser/extensions/site_permissions_helper_unittest.cc
@@ -368,8 +368,11 @@ : public SitePermissionsHelperUnitTest { public: SitePermissionsHelperWithUserHostControlsUnitTest() { - feature_list_.InitAndEnableFeature( - extensions_features::kExtensionsMenuAccessControl); + std::vector<base::test::FeatureRef> enabled_features = { + extensions_features::kExtensionsMenuAccessControl, + extensions_features::kExtensionsMenuAccessControlWithPermittedSites}; + std::vector<base::test::FeatureRef> disabled_features; + feature_list_.InitWithFeatures(enabled_features, disabled_features); } ~SitePermissionsHelperWithUserHostControlsUnitTest() override = default;
diff --git a/chrome/browser/extensions/user_host_restrictions_browsertest.cc b/chrome/browser/extensions/user_host_restrictions_browsertest.cc index 38ff0f4..8d6a4a5 100644 --- a/chrome/browser/extensions/user_host_restrictions_browsertest.cc +++ b/chrome/browser/extensions/user_host_restrictions_browsertest.cc
@@ -21,6 +21,7 @@ #include "extensions/test/result_catcher.h" #include "extensions/test/test_extension_dir.h" #include "net/dns/mock_host_resolver.h" +#include "testing/gtest/include/gtest/gtest.h" namespace extensions { @@ -32,12 +33,8 @@ public testing::WithParamInterface<bool> { public: UserHostRestrictionsBrowserTest() { - const base::Feature& feature = - extensions_features::kExtensionsMenuAccessControl; - if (GetParam()) - feature_list_.InitAndEnableFeature(feature); - else - feature_list_.InitAndDisableFeature(feature); + feature_list_.InitWithFeatureState( + extensions_features::kExtensionsMenuAccessControl, GetParam()); } ~UserHostRestrictionsBrowserTest() override = default; @@ -67,16 +64,6 @@ waiter.WaitForExtensionPermissionsUpdate(); } - // Adds `url` as a new user-permitted site and waits for the change to take - // effect. - void AddUserPermittedSite(const GURL& url) { - PermissionsManager* permissions_manager = - PermissionsManager::Get(profile()); - PermissionsManagerWaiter waiter(permissions_manager); - permissions_manager->AddUserPermittedSite(url::Origin::Create(url)); - waiter.WaitForUserPermissionsSettingsChange(); - } - private: base::test::ScopedFeatureList feature_list_; }; @@ -279,9 +266,44 @@ } } +class UserHostRestrictionsWithPermittedSitesBrowserTest + : public UserHostRestrictionsBrowserTest { + public: + UserHostRestrictionsWithPermittedSitesBrowserTest(); + UserHostRestrictionsWithPermittedSitesBrowserTest( + const UserHostRestrictionsWithPermittedSitesBrowserTest&) = delete; + const UserHostRestrictionsWithPermittedSitesBrowserTest& operator=( + const UserHostRestrictionsWithPermittedSitesBrowserTest&) = delete; + ~UserHostRestrictionsWithPermittedSitesBrowserTest() override = default; + + // Adds `url` as a new user-permitted site and waits for the change to take + // effect. + void AddUserPermittedSite(const GURL& url) { + PermissionsManager* permissions_manager = + PermissionsManager::Get(profile()); + PermissionsManagerWaiter waiter(permissions_manager); + permissions_manager->AddUserPermittedSite(url::Origin::Create(url)); + waiter.WaitForUserPermissionsSettingsChange(); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + +UserHostRestrictionsWithPermittedSitesBrowserTest:: + UserHostRestrictionsWithPermittedSitesBrowserTest() { + feature_list_.InitAndEnableFeature( + extensions_features::kExtensionsMenuAccessControlWithPermittedSites); +} + +INSTANTIATE_TEST_SUITE_P(All, + UserHostRestrictionsWithPermittedSitesBrowserTest, + testing::Bool()); + // Tests that extensions with withheld host permissions are automatically // allowed to run on sites the user allows all extensions to run on. -IN_PROC_BROWSER_TEST_P(UserHostRestrictionsBrowserTest, UserPermittedSites) { +IN_PROC_BROWSER_TEST_P(UserHostRestrictionsWithPermittedSitesBrowserTest, + UserPermittedSites) { ASSERT_TRUE(StartEmbeddedTestServer()); static constexpr char kManifest[] = @@ -402,7 +424,7 @@ } // Tests that user permitted sites are persisted and granted on extension load. -IN_PROC_BROWSER_TEST_P(UserHostRestrictionsBrowserTest, +IN_PROC_BROWSER_TEST_P(UserHostRestrictionsWithPermittedSitesBrowserTest, PRE_UserPermittedSitesArePersisted) { // Note: We need a "real" extension here (instead of just a TestExtensionDir) // because it needs to persist for the next test. @@ -433,7 +455,7 @@ allowed_url, extension_misc::kUnknownTabId, nullptr)); } -IN_PROC_BROWSER_TEST_P(UserHostRestrictionsBrowserTest, +IN_PROC_BROWSER_TEST_P(UserHostRestrictionsWithPermittedSitesBrowserTest, UserPermittedSitesArePersisted) { const Extension* found_extension = nullptr; for (const auto& extension : @@ -446,9 +468,9 @@ ASSERT_TRUE(found_extension); const GURL example_com("https://example.com"); - // The user-permitted site should be allowed if and only if the feature is - // enabled (unlike the test above, our load-time granting *is* guarded behind - // the feature flag). + // The user-permitted site should be allowed iff the + // kExtensionsMenuAccessControl feature is enabled (unlike the test above, our + // load-time granting *is* guarded behind the feature flag). if (GetParam()) { EXPECT_EQ(PermissionsData::PageAccess::kAllowed, found_extension->permissions_data()->GetPageAccess( @@ -462,7 +484,7 @@ // Tests that sites the user indicated all extensions may run on are still // available to extensions after a permissions withholding change. -IN_PROC_BROWSER_TEST_P(UserHostRestrictionsBrowserTest, +IN_PROC_BROWSER_TEST_P(UserHostRestrictionsWithPermittedSitesBrowserTest, UserPermittedSitesAreAppliedOnWithholdingChange) { ASSERT_TRUE(StartEmbeddedTestServer()); @@ -495,9 +517,9 @@ WithholdExtensionPermissions(*extension); - // Once permissions are withheld, with the feature enabled, the extension may - // still run on the user-permitted site (without the feature enabled, the - // site is withheld). + // Once permissions are withheld, with the kExtensionsMenuAccessControl + // feature enabled, the extension may still run on the user-permitted site + // (without the feature enabled, the site is withheld). if (GetParam()) { EXPECT_EQ(PermissionsData::PageAccess::kAllowed, extension->permissions_data()->GetPageAccess( @@ -515,7 +537,7 @@ non_user_permitted_site, extension_misc::kUnknownTabId, nullptr)); } -IN_PROC_BROWSER_TEST_P(UserHostRestrictionsBrowserTest, +IN_PROC_BROWSER_TEST_P(UserHostRestrictionsWithPermittedSitesBrowserTest, UserPermittedSitesAndChromeFavicon) { ASSERT_TRUE(StartEmbeddedTestServer());
diff --git a/chrome/browser/fast_checkout/fast_checkout_client_impl.cc b/chrome/browser/fast_checkout/fast_checkout_client_impl.cc index 93a4e57b..7eeb8cf 100644 --- a/chrome/browser/fast_checkout/fast_checkout_client_impl.cc +++ b/chrome/browser/fast_checkout/fast_checkout_client_impl.cc
@@ -19,6 +19,7 @@ #include "components/autofill/core/browser/data_model/autofill_profile.h" #include "components/autofill/core/browser/data_model/credit_card.h" #include "components/autofill/core/common/dense_set.h" +#include "components/autofill/core/common/signatures.h" #include "content/public/browser/web_contents_user_data.h" #include "services/metrics/public/cpp/ukm_builders.h" #include "ui/base/l10n/l10n_util.h" @@ -171,11 +172,34 @@ void FastCheckoutClientImpl::OnRunComplete(FastCheckoutRunOutcome run_outcome, bool allow_further_runs) { - ukm::builders::Autofill_FastCheckoutRunOutcome builder( + ukm::builders::Autofill_FastCheckoutRunOutcome run_outcome_builder( GetWebContents().GetPrimaryMainFrame()->GetPageUkmSourceId()); - builder.SetRunOutcome(static_cast<int64_t>(run_outcome)); - builder.SetRunId(run_id_); - builder.Record(ukm::UkmRecorder::Get()); + run_outcome_builder.SetRunOutcome(static_cast<int64_t>(run_outcome)); + run_outcome_builder.SetRunId(run_id_); + run_outcome_builder.Record(ukm::UkmRecorder::Get()); + + if (autofill_manager_) { + for (auto [form_id, filling_state] : form_filling_states_) { + autofill::FormSignature form_signature = form_id.first; + autofill::DenseSet<autofill::FormType> form_types; + for (auto& [_, form] : autofill_manager_->form_structures()) { + if (form->form_signature() == form_signature) { + form_types = form->GetFormTypes(); + break; + } + } + ukm::builders::Autofill_FastCheckoutFormStatus form_status_builder( + GetWebContents().GetPrimaryMainFrame()->GetPageUkmSourceId()); + form_status_builder.SetFilled(filling_state == FillingState::kFilled); + form_status_builder.SetFormSignature( + autofill::HashFormSignature(form_signature)); + form_status_builder.SetRunId(run_id_); + form_status_builder.SetFormTypes( + autofill::AutofillMetrics::FormTypesToBitVector(form_types)); + form_status_builder.Record(ukm::UkmRecorder::Get()); + } + } + Stop(allow_further_runs); }
diff --git a/chrome/browser/fast_checkout/fast_checkout_client_impl_unittest.cc b/chrome/browser/fast_checkout/fast_checkout_client_impl_unittest.cc index 86af02c..2d9f8af 100644 --- a/chrome/browser/fast_checkout/fast_checkout_client_impl_unittest.cc +++ b/chrome/browser/fast_checkout/fast_checkout_client_impl_unittest.cc
@@ -46,6 +46,7 @@ using ::testing::Return; using ::testing::SaveArg; using ::testing::UnorderedElementsAre; +using ::ukm::builders::Autofill_FastCheckoutFormStatus; using ::ukm::builders::Autofill_FastCheckoutRunOutcome; namespace { @@ -686,6 +687,7 @@ {address_form->form_signature(), credit_card_form->form_signature()}); EXPECT_TRUE(fast_checkout_client()->IsRunning()); + int64_t run_id = fast_checkout_client()->run_id_; autofill::payments::FullCardRequest* full_card_request = autofill_client()->GetCvcAuthenticator()->GetFullCardRequest(); @@ -716,6 +718,32 @@ EXPECT_FALSE(fast_checkout_client()->IsRunning()); ExpectRunOutcomeUkm(FastCheckoutRunOutcome::kSuccess); + auto ukm_entries = ukm_recorder_.GetEntries( + Autofill_FastCheckoutFormStatus::kEntryName, + {Autofill_FastCheckoutFormStatus::kRunIdName, + Autofill_FastCheckoutFormStatus::kFilledName, + Autofill_FastCheckoutFormStatus::kFormSignatureName, + Autofill_FastCheckoutFormStatus::kFormTypesName}); + EXPECT_EQ(ukm_entries.size(), 2UL); + base::flat_set<ukm::TestAutoSetUkmRecorder::HumanReadableUkmMetrics> metrics; + metrics.emplace(ukm_entries[0].metrics); + metrics.emplace(ukm_entries[1].metrics); + EXPECT_THAT( + metrics, + UnorderedElementsAre( + UnorderedElementsAre( + Pair(Autofill_FastCheckoutFormStatus::kRunIdName, run_id), + Pair(Autofill_FastCheckoutFormStatus::kFilledName, 1), + Pair(Autofill_FastCheckoutFormStatus::kFormSignatureName, + autofill::HashFormSignature(address_form->form_signature())), + Pair(Autofill_FastCheckoutFormStatus::kFormTypesName, 3)), + UnorderedElementsAre( + Pair(Autofill_FastCheckoutFormStatus::kRunIdName, run_id), + Pair(Autofill_FastCheckoutFormStatus::kFilledName, 1), + Pair(Autofill_FastCheckoutFormStatus::kFormSignatureName, + autofill::HashFormSignature( + credit_card_form->form_signature())), + Pair(Autofill_FastCheckoutFormStatus::kFormTypesName, 5)))); } TEST_F(FastCheckoutClientImplTest, OnAutofillManagerReset_ResetsState) {
diff --git a/chrome/browser/feed/android/java/res/values/styles.xml b/chrome/browser/feed/android/java/res/values/styles.xml index f853ddd..0e626c60 100644 --- a/chrome/browser/feed/android/java/res/values/styles.xml +++ b/chrome/browser/feed/android/java/res/values/styles.xml
@@ -40,6 +40,14 @@ <item name="android:textColor">@color/tab_layout_text_color_list</item> </style> + <style name="TextAppearance.ClickableButton" parent="TextAppearance.Button.Text.Filled"> + <item name="android:textColor">@macro/default_text_color_on_accent1</item> + </style> + + <style name="TextAppearance.ClickableButtonInverse" parent="TextAppearance.Button.Text.Filled"> + <item name="android:textColor">@macro/default_text_color_accent1</item> + </style> + <style name="TextAppearance.HeaderTitle" parent="TextAppearance.TextAccentMediumThick"> <item name="android:textColor">@color/header_title_text_color_list</item> </style>
diff --git a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/webfeed/ShadowedClickableTextBubble.java b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/webfeed/ShadowedClickableTextBubble.java index cf2beba..67681c2 100644 --- a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/webfeed/ShadowedClickableTextBubble.java +++ b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/webfeed/ShadowedClickableTextBubble.java
@@ -7,11 +7,13 @@ import android.content.Context; import android.graphics.drawable.Drawable; import android.view.View; +import android.widget.TextView; import androidx.annotation.DrawableRes; import androidx.annotation.StringRes; import androidx.core.content.res.ResourcesCompat; +import org.chromium.base.ApiCompatibilityUtils; import org.chromium.chrome.browser.feed.R; import org.chromium.components.browser_ui.widget.textbubble.TextBubble; import org.chromium.ui.widget.LoadingView; @@ -98,6 +100,16 @@ return background; } + @Override + protected void updateTextStyle(TextView view, boolean isInverse) { + if (isInverse) { + ApiCompatibilityUtils.setTextAppearance( + view, R.style.TextAppearance_ClickableButtonInverse); + } else { + ApiCompatibilityUtils.setTextAppearance(view, R.style.TextAppearance_ClickableButton); + } + } + /** * Replaces image with loading spinner. Dismisses the entire button when loading spinner is * hidden.
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index 1cbbd58..e3032bd 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -820,7 +820,7 @@ { "name": "calculate-native-win-occlusion", "owners": [ "davidbienvenu", "fdoray" ], - "expiry_milestone": 112 + "expiry_milestone": 120 }, { "name": "calendar-jelly", @@ -1834,11 +1834,6 @@ "expiry_milestone": 120 }, { - "name": "enable-browsing-data-lifetime-manager", - "owners": ["ydago"], - "expiry_milestone": 106 - }, - { "name": "enable-cardboard", "owners": [ "alcooper", "chrome-xr-eng@google.com"], "expiry_milestone": 120
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index 4b7e6fb..3a7d803d 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -879,12 +879,6 @@ "Enables UI on chrome://settings/siteData to remove all third-party " "cookies and site data."; -const char kEnableBrowsingDataLifetimeManagerName[] = - "Enables the BrowsingDataLifetimeManager service to run."; -const char kEnableBrowsingDataLifetimeManagerDescription[] = - "Enables the BrowsingDataLifetimeManager service to run and periodically " - "delete browsing data as specified by the BrowsingDataLifetime policy."; - const char kDesktopPWAsAdditionalWindowingControlsName[] = "Desktop PWA Window Minimize/maximize/restore"; const char kDesktopPWAsAdditionalWindowingControlsDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index f5c20dc6..72833a2 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -499,9 +499,6 @@ extern const char kEnableRemovingAllThirdPartyCookiesName[]; extern const char kEnableRemovingAllThirdPartyCookiesDescription[]; -extern const char kEnableBrowsingDataLifetimeManagerName[]; -extern const char kEnableBrowsingDataLifetimeManagerDescription[]; - extern const char kDesktopPWAsAdditionalWindowingControlsName[]; extern const char kDesktopPWAsAdditionalWindowingControlsDescription[];
diff --git a/chrome/browser/media/cast_mirroring_performance_browsertest.cc b/chrome/browser/media/cast_mirroring_performance_browsertest.cc index 6af3633..d300f47 100644 --- a/chrome/browser/media/cast_mirroring_performance_browsertest.cc +++ b/chrome/browser/media/cast_mirroring_performance_browsertest.cc
@@ -893,7 +893,8 @@ mirroring::mojom::SessionType::AUDIO_AND_VIDEO, endpoint.address(), "model_name", "friendly_name", "sender-123", "receiver-456", base::Milliseconds(kTargetPlayoutDelayMs), - false /* is_remote_playback */, false /** force_letterboxing */); + false /* is_remote_playback */, false /** force_letterboxing */, + false /* should_enable_rtcp_reporting */); host_->Start(std::move(session_params), std::move(observer_remote), std::move(channel_remote), channel_to_service_.BindNewPipeAndPassReceiver(), "Sink Name");
diff --git a/chrome/browser/media/encrypted_media_supported_types_browsertest.cc b/chrome/browser/media/encrypted_media_supported_types_browsertest.cc index ca76cd25..45d902c 100644 --- a/chrome/browser/media/encrypted_media_supported_types_browsertest.cc +++ b/chrome/browser/media/encrypted_media_supported_types_browsertest.cc
@@ -603,6 +603,7 @@ EncryptedMediaSupportedTypesWidevineHwSecureForceClearLeadSupportTest() { enabled_features_.push_back({media::kHardwareSecureDecryption, {{"force_support_clear_lead", "true"}}}); + EnableFeature(media::kHardwareSecureDecryptionExperiment); } void SetUpCommandLine(base::CommandLine* command_line) override {
diff --git a/chrome/browser/media/router/providers/cast/mirroring_activity.cc b/chrome/browser/media/router/providers/cast/mirroring_activity.cc index 92b78ca..c21ce18 100644 --- a/chrome/browser/media/router/providers/cast/mirroring_activity.cc +++ b/chrome/browser/media/router/providers/cast/mirroring_activity.cc
@@ -36,7 +36,6 @@ #include "components/media_router/common/providers/cast/channel/cast_socket.h" #include "components/media_router/common/providers/cast/channel/enum_table.h" #include "components/media_router/common/route_request_result.h" -#include "components/mirroring/mojom/session_parameters.mojom-forward.h" #include "components/mirroring/mojom/session_parameters.mojom.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/browser_task_traits.h" @@ -188,6 +187,13 @@ base::TimeDelta(), incognito); } +bool IsRtcpReportingEnabled(int frame_tree_node_id) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + auto* debugger = MediaRouterDebugger::GetForFrameTreeNode(frame_tree_node_id); + + return debugger ? debugger->IsRtcpReportsEnabled() : false; +} + } // namespace MirroringActivity::MirroringActivity( @@ -305,8 +311,8 @@ // Record the error for access code discovery types. CastDiscoveryType discovery_type = cast_data_.discovery_type; if (discovery_type == CastDiscoveryType::kAccessCodeManualEntry) { - base::UmaHistogramEnumeration( - kHistogramStartFailureAccessCodeManualEntry, error); + base::UmaHistogramEnumeration(kHistogramStartFailureAccessCodeManualEntry, + error); } else if (discovery_type == CastDiscoveryType::kAccessCodeRememberedDevice) { base::UmaHistogramEnumeration( @@ -337,8 +343,7 @@ if (discovery_type == CastDiscoveryType::kAccessCodeManualEntry) { base::UmaHistogramEnumeration(kHistogramStartSuccessAccessCodeManualEntry, *mirroring_type_); - } else if (discovery_type == - CastDiscoveryType::kAccessCodeRememberedDevice) { + } else if (discovery_type == CastDiscoveryType::kAccessCodeRememberedDevice) { base::UmaHistogramEnumeration( kHistogramStartSuccessAccessCodeRememberedDevice, *mirroring_type_); } @@ -542,10 +547,10 @@ if (!has_audio && !has_video) { return; } - const SessionType session_type = - has_audio && has_video - ? SessionType::AUDIO_AND_VIDEO - : has_audio ? SessionType::AUDIO_ONLY : SessionType::VIDEO_ONLY; + const SessionType session_type = has_audio && has_video + ? SessionType::AUDIO_AND_VIDEO + : has_audio ? SessionType::AUDIO_ONLY + : SessionType::VIDEO_ONLY; will_start_mirroring_timestamp_ = base::Time::Now(); @@ -562,16 +567,41 @@ content::GetUIThreadTaskRunner({})->PostTask( FROM_HERE, base::BindOnce( - &mirroring::MirroringServiceHost::Start, host_->GetWeakPtr(), + &MirroringActivity::StartOnUiThread, weak_ptr_factory_.GetWeakPtr(), + host_->GetWeakPtr(), SessionParameters::New( session_type, cast_data_.ip_endpoint.address(), cast_data_.model_name, sink_.sink().name(), session.destination_id(), message_handler_->source_id(), cast_source->target_playout_delay(), route().media_source().IsRemotePlaybackSource(), - ShouldForceLetterboxing(cast_data_.model_name)), + ShouldForceLetterboxing(cast_data_.model_name), + false /* enable_rtcp_reporting */), std::move(observer_remote), std::move(channel_remote), - std::move(channel_to_service_receiver_), route_.media_sink_name())); + std::move(channel_to_service_receiver_), route_.media_sink_name(), + frame_tree_node_id_)); +} + +void MirroringActivity::StartOnUiThread( + base::WeakPtr<mirroring::MirroringServiceHost> host, + mirroring::mojom::SessionParametersPtr session_params, + mojo::PendingRemote<mirroring::mojom::SessionObserver> observer, + mojo::PendingRemote<mirroring::mojom::CastMessageChannel> outbound_channel, + mojo::PendingReceiver<mirroring::mojom::CastMessageChannel> inbound_channel, + const std::string& sink_name, + int frame_tree_node_id) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + + if (!host) { + return; + } + + session_params->enable_rtcp_reporting = + IsRtcpReportingEnabled(frame_tree_node_id); + + host->Start(std::move(session_params), std::move(observer), + std::move(outbound_channel), std::move(inbound_channel), + sink_name); } void MirroringActivity::StopMirroring() {
diff --git a/chrome/browser/media/router/providers/cast/mirroring_activity.h b/chrome/browser/media/router/providers/cast/mirroring_activity.h index 63946c4..3db8e930 100644 --- a/chrome/browser/media/router/providers/cast/mirroring_activity.h +++ b/chrome/browser/media/router/providers/cast/mirroring_activity.h
@@ -20,6 +20,7 @@ #include "components/media_router/common/providers/cast/channel/cast_message_handler.h" #include "components/mirroring/mojom/cast_message_channel.mojom.h" #include "components/mirroring/mojom/session_observer.mojom.h" +#include "components/mirroring/mojom/session_parameters.mojom-forward.h" #include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/cpp/bindings/pending_remote.h" #include "mojo/public/cpp/bindings/receiver.h" @@ -98,6 +99,19 @@ // Scrubs AES related data in messages with type "OFFER". static std::string GetScrubbedLogMessage(const base::Value::Dict& message); + // Starts the mirroring service via the Ui thread. Can only be called on the + // Ui thread. + void StartOnUiThread( + base::WeakPtr<mirroring::MirroringServiceHost> host, + mirroring::mojom::SessionParametersPtr session_params, + mojo::PendingRemote<mirroring::mojom::SessionObserver> observer, + mojo::PendingRemote<mirroring::mojom::CastMessageChannel> + outbound_channel, + mojo::PendingReceiver<mirroring::mojom::CastMessageChannel> + inbound_channel, + const std::string& sink_name, + int frame_tree_node_id); + std::unique_ptr<mirroring::MirroringServiceHost> host_; // Sends Cast messages from the mirroring receiver to the mirroring service.
diff --git a/chrome/browser/media/router/providers/dial/dial_internal_message_util_unittest.cc b/chrome/browser/media/router/providers/dial/dial_internal_message_util_unittest.cc index 5905699..0815d6e 100644 --- a/chrome/browser/media/router/providers/dial/dial_internal_message_util_unittest.cc +++ b/chrome/browser/media/router/providers/dial/dial_internal_message_util_unittest.cc
@@ -32,11 +32,10 @@ void ExpectMessagesEqual(const std::string& expected_message, const std::string& message) { - auto expected_message_value = - base::JSONReader::ReadDeprecated(expected_message); + auto expected_message_value = base::JSONReader::Read(expected_message); ASSERT_TRUE(expected_message_value); - auto message_value = base::JSONReader::ReadDeprecated(message); + auto message_value = base::JSONReader::Read(message); ASSERT_TRUE(message_value); EXPECT_EQ(*expected_message_value, *message_value);
diff --git a/chrome/browser/memory/memory_ablation_study_unittest.cc b/chrome/browser/memory/memory_ablation_study_unittest.cc index 059f903..e9d5da35 100644 --- a/chrome/browser/memory/memory_ablation_study_unittest.cc +++ b/chrome/browser/memory/memory_ablation_study_unittest.cc
@@ -25,13 +25,7 @@ }; // Tests basic functionality of the MemoryAblationStudy class. -#if BUILDFLAG(IS_WIN) -// TODO(https://crbug.com/1245173) Flaky on Win7 -#define MAYBE_Basic DISABLED_Basic -#else -#define MAYBE_Basic Basic -#endif -TEST_F(MemoryAblationStudyTest, MAYBE_Basic) { +TEST_F(MemoryAblationStudyTest, Basic) { // Ablate 137MB. base::FieldTrialParams params; params["ablation-size-mb"] = "137";
diff --git a/chrome/browser/policy/networking/device_network_configuration_updater_ash.cc b/chrome/browser/policy/networking/device_network_configuration_updater_ash.cc index 4997bc29..d63a071 100644 --- a/chrome/browser/policy/networking/device_network_configuration_updater_ash.cc +++ b/chrome/browser/policy/networking/device_network_configuration_updater_ash.cc
@@ -110,8 +110,8 @@ } void DeviceNetworkConfigurationUpdaterAsh::ApplyNetworkPolicy( - base::Value::List network_configs_onc, - base::Value::Dict global_network_config) { + const base::Value::List& network_configs_onc, + const base::Value::Dict& global_network_config) { // Ensure this is runnng on the UI thead because we're accessing global data // to populate the substitutions. DCHECK_CURRENTLY_ON(content::BrowserThread::UI); @@ -131,8 +131,8 @@ /*userhash=*/std::string(), std::move(substitutions)); network_config_handler_->SetPolicy( onc_source_, /*userhash=*/std::string(), - base::Value(std::move(network_configs_onc)), - base::Value(std::move(global_network_config))); + base::Value(network_configs_onc.Clone()), + base::Value(global_network_config.Clone())); } void DeviceNetworkConfigurationUpdaterAsh::OnDataRoamingSettingChanged() {
diff --git a/chrome/browser/policy/networking/device_network_configuration_updater_ash.h b/chrome/browser/policy/networking/device_network_configuration_updater_ash.h index 542210b..5ec91ec 100644 --- a/chrome/browser/policy/networking/device_network_configuration_updater_ash.h +++ b/chrome/browser/policy/networking/device_network_configuration_updater_ash.h
@@ -69,8 +69,9 @@ // NetworkConfigurationUpdater: void Init() override; void ImportClientCertificates() override; - void ApplyNetworkPolicy(base::Value::List network_configs_onc, - base::Value::Dict global_network_config) override; + void ApplyNetworkPolicy( + const base::Value::List& network_configs_onc, + const base::Value::Dict& global_network_config) override; void OnDataRoamingSettingChanged(); // Pointer to the global singleton or a test instance.
diff --git a/chrome/browser/policy/networking/network_configuration_updater.cc b/chrome/browser/policy/networking/network_configuration_updater.cc index dd287c6..7fe55125 100644 --- a/chrome/browser/policy/networking/network_configuration_updater.cc +++ b/chrome/browser/policy/networking/network_configuration_updater.cc
@@ -214,8 +214,7 @@ ImportCertificates(std::move(certificates)); MarkFieldsAsRecommendedForBackwardsCompatibility(network_configs); - ApplyNetworkPolicy(std::move(network_configs), - std::move(global_network_config)); + ApplyNetworkPolicy(network_configs, global_network_config); } void NetworkConfigurationUpdater::
diff --git a/chrome/browser/policy/networking/network_configuration_updater.h b/chrome/browser/policy/networking/network_configuration_updater.h index 9a529050..6abb79db 100644 --- a/chrome/browser/policy/networking/network_configuration_updater.h +++ b/chrome/browser/policy/networking/network_configuration_updater.h
@@ -84,8 +84,9 @@ // Parses the incoming policy, applies server and authority certificates. // Calls the specialized methods from subclasses to handle client certificates // and network configs. - virtual void ApplyNetworkPolicy(base::Value::List network_configs_onc, - base::Value::Dict global_network_config) = 0; + virtual void ApplyNetworkPolicy( + const base::Value::List& network_configs_onc, + const base::Value::Dict& global_network_config) = 0; // Parses the current value of the ONC policy. Clears |network_configs|, // |global_network_config| and |certificates| and fills them with the
diff --git a/chrome/browser/policy/networking/user_network_configuration_updater.h b/chrome/browser/policy/networking/user_network_configuration_updater.h index d436119b..1483448f 100644 --- a/chrome/browser/policy/networking/user_network_configuration_updater.h +++ b/chrome/browser/policy/networking/user_network_configuration_updater.h
@@ -29,8 +29,9 @@ // NetworkConfigurationUpdater void ImportClientCertificates() override {} - void ApplyNetworkPolicy(base::Value::List network_configs_onc, - base::Value::Dict global_network_config) override {} + void ApplyNetworkPolicy( + const base::Value::List& network_configs_onc, + const base::Value::Dict& global_network_config) override {} }; } // namespace policy
diff --git a/chrome/browser/policy/networking/user_network_configuration_updater_ash.cc b/chrome/browser/policy/networking/user_network_configuration_updater_ash.cc index 360c23d0..39ccc4d 100644 --- a/chrome/browser/policy/networking/user_network_configuration_updater_ash.cc +++ b/chrome/browser/policy/networking/user_network_configuration_updater_ash.cc
@@ -151,8 +151,8 @@ } void UserNetworkConfigurationUpdaterAsh::ApplyNetworkPolicy( - base::Value::List network_configs_onc, - base::Value::Dict global_network_config) { + const base::Value::List& network_configs_onc, + const base::Value::Dict& global_network_config) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(user_); @@ -166,8 +166,8 @@ network_config_handler_->SetPolicy( onc_source_, user_->username_hash(), - base::Value(std::move(network_configs_onc)), - base::Value(std::move(global_network_config))); + base::Value(network_configs_onc.Clone()), + base::Value(global_network_config.Clone())); } void UserNetworkConfigurationUpdaterAsh::OnProfileInitializationComplete(
diff --git a/chrome/browser/policy/networking/user_network_configuration_updater_ash.h b/chrome/browser/policy/networking/user_network_configuration_updater_ash.h index 7ce9165..e341bf2 100644 --- a/chrome/browser/policy/networking/user_network_configuration_updater_ash.h +++ b/chrome/browser/policy/networking/user_network_configuration_updater_ash.h
@@ -94,8 +94,9 @@ // NetworkConfigurationUpdater: void ImportClientCertificates() override; - void ApplyNetworkPolicy(base::Value::List network_configs_onc, - base::Value::Dict global_network_config) override; + void ApplyNetworkPolicy( + const base::Value::List& network_configs_onc, + const base::Value::Dict& global_network_config) override; // ProfileObserver implementation void OnProfileInitializationComplete(Profile* profile) override;
diff --git a/chrome/browser/preloading/prefetch/no_state_prefetch/prerender_nostate_prefetch_browsertest.cc b/chrome/browser/preloading/prefetch/no_state_prefetch/prerender_nostate_prefetch_browsertest.cc index 321bac79..ae84cc79 100644 --- a/chrome/browser/preloading/prefetch/no_state_prefetch/prerender_nostate_prefetch_browsertest.cc +++ b/chrome/browser/preloading/prefetch/no_state_prefetch/prerender_nostate_prefetch_browsertest.cc
@@ -481,9 +481,8 @@ void SetUp() override { bool split_cache_by_network_isolation_key = GetParam(); if (split_cache_by_network_isolation_key) { - feature_list_.InitWithFeatures( - {net::features::kSplitCacheByNetworkIsolationKey}, - {net::features::kForceIsolationInfoFrameOriginToTopLevelFrame}); + feature_list_.InitAndEnableFeature( + net::features::kSplitCacheByNetworkIsolationKey); } else { feature_list_.InitAndDisableFeature( net::features::kSplitCacheByNetworkIsolationKey);
diff --git a/chrome/browser/profiles/profile_keyed_service_browsertest.cc b/chrome/browser/profiles/profile_keyed_service_browsertest.cc index e281fcb..0c49c8a 100644 --- a/chrome/browser/profiles/profile_keyed_service_browsertest.cc +++ b/chrome/browser/profiles/profile_keyed_service_browsertest.cc
@@ -18,6 +18,7 @@ #include "components/keyed_service/core/keyed_service_base_factory.h" #include "components/supervised_user/core/common/buildflags.h" #include "content/public/test/browser_test.h" +#include "pdf/buildflags.h" #include "printing/buildflags/buildflags.h" #include "third_party/blink/public/common/features.h" @@ -236,6 +237,9 @@ "MediaRouterUIService", "NotificationDisplayService", "OptimizationGuideKeyedService", +#if BUILDFLAG(ENABLE_PDF) + "PdfViewerPrivateEventRouter", +#endif // BUILDFLAG(ENABLE_PDF) "PlatformNotificationService", "PrefWatcher", "PrivacySandboxSettings", @@ -415,6 +419,9 @@ "OptimizationGuideKeyedService", "PageContentAnnotationsService", "PasswordsPrivateEventRouter", +#if BUILDFLAG(ENABLE_PDF) + "PdfViewerPrivateEventRouter", +#endif // BUILDFLAG(ENABLE_PDF) "PermissionHelper", "PermissionsManager", "PermissionsUpdaterShutdownFactory",
diff --git a/chrome/browser/resources/new_tab_page/preprocess_if_expr_sourcemaps.gni b/chrome/browser/resources/new_tab_page/preprocess_if_expr_sourcemaps.gni deleted file mode 100644 index 114cd926..0000000 --- a/chrome/browser/resources/new_tab_page/preprocess_if_expr_sourcemaps.gni +++ /dev/null
@@ -1,55 +0,0 @@ -# Copyright 2022 The Chromium Authors -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import( - "//tools/code_coverage/js_source_maps/create_js_source_maps/create_js_source_maps.gni") -import("//tools/grit/preprocess_if_expr.gni") - -template("preprocess_if_expr_sourcemaps") { - _out_folder = target_gen_dir - if (defined(invoker.out_folder)) { - _out_folder = invoker.out_folder - } - - if (enable_webui_inline_sourcemaps) { - _preprocess_if_expr_target_name = "${target_name}__preprocess_if_expr" - _preprocess_if_expr_out_folder = "$_out_folder/preprocess_if_expr" - } else { - _preprocess_if_expr_target_name = target_name - _preprocess_if_expr_out_folder = _out_folder - } - - preprocess_if_expr(_preprocess_if_expr_target_name) { - forward_variables_from(invoker, - "*", - [ - "out_folder", - "enable_removal_comments", - ]) - out_folder = _preprocess_if_expr_out_folder - enable_removal_comments = enable_webui_inline_sourcemaps - } - - if (enable_webui_inline_sourcemaps) { - _in_folder = "." - if (defined(invoker.in_folder)) { - _in_folder = invoker.in_folder - } - - create_js_source_maps(target_name) { - inline_sourcemaps = true - originals = [] - sources = [] - outputs = [] - foreach(in_file, invoker.in_files) { - assert(get_path_info(in_file, "extension") == "ts" || - get_path_info(in_file, "extension") == "js") - originals += [ "$_in_folder/$in_file" ] - sources += [ "$_preprocess_if_expr_out_folder/" + in_file ] - outputs += [ "$_out_folder/" + in_file ] - } - deps = [ ":$_preprocess_if_expr_target_name" ] - } - } -}
diff --git a/chrome/browser/resources/new_tab_page/ts_library_sourcemaps.gni b/chrome/browser/resources/new_tab_page/ts_library_sourcemaps.gni deleted file mode 100644 index 483689c8..0000000 --- a/chrome/browser/resources/new_tab_page/ts_library_sourcemaps.gni +++ /dev/null
@@ -1,51 +0,0 @@ -# Copyright 2022 The Chromium Authors -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import( - "//tools/code_coverage/js_source_maps/merge_js_source_maps/merge_js_source_maps.gni") -import("//tools/typescript/ts_library.gni") - -template("ts_library_sourcemaps") { - _out_dir = target_gen_dir - if (defined(invoker.out_dir)) { - _out_dir = invoker.out_dir - } - - if (enable_webui_inline_sourcemaps) { - _ts_library_target_name = "${target_name}__ts_library" - _ts_library_out_dir = "$_out_dir/ts_library" - } else { - _ts_library_target_name = target_name - _ts_library_out_dir = _out_dir - } - - ts_library(_ts_library_target_name) { - forward_variables_from(invoker, "*", [ "out_dir" ]) - out_dir = _ts_library_out_dir - } - - if (enable_webui_inline_sourcemaps) { - merge_js_source_maps(target_name) { - deps = [ ":$_ts_library_target_name" ] - manifest_files = [] - sources = [] - outputs = [] - out_dir = _out_dir - foreach(_output, get_target_outputs(":$_ts_library_target_name")) { - if (get_path_info(_output, "extension") == "manifest") { - manifest_files += [ _output ] - } else if (get_path_info(_output, "extension") == "ts" || - get_path_info(_output, "extension") == "js") { - sources += [ _output ] - outputs += [ string_replace(_output, _ts_library_out_dir, _out_dir) ] - } else { - _ts_config = "$target_gen_dir/tsconfig_$_ts_library_target_name.json" - assert(_output == _ts_config) - sources += [ _ts_config ] - outputs += [ "$target_gen_dir/tsconfig_$target_name.json" ] - } - } - } - } -}
diff --git a/chrome/browser/resources/pdf/elements/viewer-toolbar.ts b/chrome/browser/resources/pdf/elements/viewer-toolbar.ts index 684b56a..4a3c978 100644 --- a/chrome/browser/resources/pdf/elements/viewer-toolbar.ts +++ b/chrome/browser/resources/pdf/elements/viewer-toolbar.ts
@@ -24,7 +24,7 @@ import {FittingType} from '../constants.js'; import {record, UserAction} from '../metrics.js'; // <if expr="enable_screen_ai_service"> -import {PdfViewerPrivateProxyImpl} from '../pdf_viewer_private_proxy.js'; +import {PdfOcrPrefCallback, PdfViewerPrivateProxyImpl} from '../pdf_viewer_private_proxy.js'; // </if> @@ -165,11 +165,22 @@ // <if expr="enable_screen_ai_service"> pdfOcrEnabled: boolean; private pdfOcrAlwaysActive_: boolean; + private pdfOcrPrefChanged_: PdfOcrPrefCallback = null; override async connectedCallback() { super.connectedCallback(); this.pdfOcrAlwaysActive_ = await PdfViewerPrivateProxyImpl.getInstance().isPdfOcrAlwaysActive(); + this.pdfOcrPrefChanged_ = this.onPdfOcrPrefChanged.bind(this); + PdfViewerPrivateProxyImpl.getInstance().addPdfOcrPrefChangedListener( + this.pdfOcrPrefChanged_); + } + + override disconnectedCallback() { + super.disconnectedCallback(); + PdfViewerPrivateProxyImpl.getInstance().removePdfOcrPrefChangedListener( + this.pdfOcrPrefChanged_); + this.pdfOcrPrefChanged_ = null; } // </if> @@ -394,6 +405,10 @@ // TODO(crbug.com/1393069): Start/stop PDF OCR accordingly. } } + + private onPdfOcrPrefChanged(isPdfOcrAlwaysActive: boolean) { + this.pdfOcrAlwaysActive_ = isPdfOcrAlwaysActive; + } // </if> }
diff --git a/chrome/browser/resources/pdf/pdf_viewer_private_proxy.ts b/chrome/browser/resources/pdf/pdf_viewer_private_proxy.ts index 19f7d07..d1f929f 100644 --- a/chrome/browser/resources/pdf/pdf_viewer_private_proxy.ts +++ b/chrome/browser/resources/pdf/pdf_viewer_private_proxy.ts
@@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +export type PdfOcrPrefCallback = chrome.pdfViewerPrivate.PdfOcrPrefCallback; + // TODO(crbug.com/1302465): Move the other chrome.pdfViewerPrivate calls across // the PDF UI under this proxy. // `chrome.pdfViewerPrivate.isAllowedLocalFileAccess` is currently located in @@ -9,6 +11,8 @@ interface PdfViewerPrivateProxy { isPdfOcrAlwaysActive(): Promise<boolean>; setPdfOcrPref(value: boolean): Promise<boolean>; + addPdfOcrPrefChangedListener(listener: PdfOcrPrefCallback): void; + removePdfOcrPrefChangedListener(listener: PdfOcrPrefCallback): void; } export class PdfViewerPrivateProxyImpl implements PdfViewerPrivateProxy { @@ -24,6 +28,14 @@ }); } + addPdfOcrPrefChangedListener(listener: PdfOcrPrefCallback): void { + chrome.pdfViewerPrivate.onPdfOcrPrefChanged.addListener(listener); + } + + removePdfOcrPrefChangedListener(listener: PdfOcrPrefCallback): void { + chrome.pdfViewerPrivate.onPdfOcrPrefChanged.removeListener(listener); + } + static getInstance(): PdfViewerPrivateProxy { return instance || (instance = new PdfViewerPrivateProxyImpl()); }
diff --git a/chrome/browser/resources/settings/autofill_page/passwords_device_section.ts b/chrome/browser/resources/settings/autofill_page/passwords_device_section.ts index c9e340c..1b23096 100644 --- a/chrome/browser/resources/settings/autofill_page/passwords_device_section.ts +++ b/chrome/browser/resources/settings/autofill_page/passwords_device_section.ts
@@ -26,7 +26,7 @@ import {WebUiListenerMixin} from 'chrome://resources/cr_elements/web_ui_listener_mixin.js'; import {OpenWindowProxyImpl} from 'chrome://resources/js/open_window_proxy.js'; import {PluralStringProxyImpl} from 'chrome://resources/js/plural_string_proxy.js'; -import {getDeepActiveElement} from 'chrome://resources/js/util_ts.js'; +import {getDeepActiveElement, isUndoKeyboardEvent} from 'chrome://resources/js/util_ts.js'; import {IronListElement} from 'chrome://resources/polymer/v3_0/iron-list/iron-list.js'; import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; @@ -241,17 +241,10 @@ override ready() { super.ready(); - document.addEventListener('keydown', keyboardEvent => { - // <if expr="is_macosx"> - if (keyboardEvent.metaKey && keyboardEvent.key === 'z') { + document.addEventListener('keydown', (keyboardEvent: KeyboardEvent) => { + if (isUndoKeyboardEvent(keyboardEvent)) { this.onUndoKeyBinding_(keyboardEvent); } - // </if> - // <if expr="not is_macosx"> - if (keyboardEvent.ctrlKey && keyboardEvent.key === 'z') { - this.onUndoKeyBinding_(keyboardEvent); - } - // </if> }); }
diff --git a/chrome/browser/resources/settings/autofill_page/passwords_section.ts b/chrome/browser/resources/settings/autofill_page/passwords_section.ts index 47fed02..796d4b3 100644 --- a/chrome/browser/resources/settings/autofill_page/passwords_section.ts +++ b/chrome/browser/resources/settings/autofill_page/passwords_section.ts
@@ -41,7 +41,7 @@ import {assert, assertNotReached} from 'chrome://resources/js/assert_ts.js'; import {focusWithoutInk} from 'chrome://resources/js/focus_without_ink.js'; import {OpenWindowProxyImpl} from 'chrome://resources/js/open_window_proxy.js'; -import {getDeepActiveElement} from 'chrome://resources/js/util_ts.js'; +import {getDeepActiveElement, isUndoKeyboardEvent} from 'chrome://resources/js/util_ts.js'; import {DomRepeat, DomRepeatEvent, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {SettingsToggleButtonElement} from '../controls/settings_toggle_button.js'; @@ -300,17 +300,10 @@ override ready() { super.ready(); - document.addEventListener('keydown', e => { - // <if expr="is_macosx"> - if (e.metaKey && e.key === 'z') { + document.addEventListener('keydown', (e: KeyboardEvent) => { + if (isUndoKeyboardEvent(e)) { this.onUndoKeyBinding_(e); } - // </if> - // <if expr="not is_macosx"> - if (e.ctrlKey && e.key === 'z') { - this.onUndoKeyBinding_(e); - } - // </if> }); // <if expr="is_win or is_macosx">
diff --git a/chrome/browser/resources/settings/chromeos/device_page/audio.html b/chrome/browser/resources/settings/chromeos/device_page/audio.html index a6a64674..bc640bc 100644 --- a/chrome/browser/resources/settings/chromeos/device_page/audio.html +++ b/chrome/browser/resources/settings/chromeos/device_page/audio.html
@@ -107,9 +107,14 @@ on-click="onOutputMuteButtonClicked" disabled="[[isOutputMutedByPolicy_( audioSystemProperties_.outputMuteState - )]]"> + )]]" + aria-description="[[getOutputMuteButtonAriaLabel( + isOutputMuted_ + )]]" + aria-labelledby="audioOutputVolumeLabel" + aria-pressed="[[isOutputMuted_]]"> </cr-icon-button> - <paper-tooltip id="audioOutputMuteButtonTooltip" + <paper-tooltip id="audioOutputMuteButtonTooltip" aria-hidden="true" for="audioOutputMuteButton"> [[getMuteTooltip_(audioSystemProperties_.outputMuteState)]] </paper-tooltip> @@ -159,9 +164,15 @@ iron-icon="[[getInputIcon_(isInputMuted_)]]" on-click="onInputMuteClicked" class="audio-mute-button" - disabled="[[shouldDisableInputGainControls(isInputMuted_)]]"> + disabled="[[shouldDisableInputGainControls(isInputMuted_)]]" + aria-description$="[[getInputMuteButtonAriaLabel( + audioSystemProperties_.inputMuteState, + isInputMuted_ + )]]" + aria-labelledby="audioInputGainLabel" + aria-pressed="[[isInputMuted_]]"> </cr-icon-button> - <paper-tooltip id="audioInputMuteButtonTooltip" + <paper-tooltip id="audioInputMuteButtonTooltip" aria-hidden="true" for="audioInputGainMuteButton"> [[getMuteTooltip_(audioSystemProperties_.inputMuteState)]] </paper-tooltip>
diff --git a/chrome/browser/resources/settings/chromeos/device_page/audio.ts b/chrome/browser/resources/settings/chromeos/device_page/audio.ts index ccb43f9..414c423 100644 --- a/chrome/browser/resources/settings/chromeos/device_page/audio.ts +++ b/chrome/browser/resources/settings/chromeos/device_page/audio.ts
@@ -339,6 +339,25 @@ return ''; } } + + /** Returns the appropriate aria-label for input mute button. */ + protected getInputMuteButtonAriaLabel(): string { + if (this.audioSystemProperties_.inputMuteState === + MuteState.kMutedExternally) { + return this.i18n('audioInputMuteButtonAriaLabelMutedByHardwareSwitch'); + } + + return this.isInputMuted_ ? + this.i18n('audioInputMuteButtonAriaLabelMuted') : + this.i18n('audioInputMuteButtonAriaLabelNotMuted'); + } + + /** Returns the appropriate aria-label for output mute button. */ + protected getOutputMuteButtonAriaLabel(): string { + return this.isOutputMuted_ ? + this.i18n('audioOutputMuteButtonAriaLabelMuted') : + this.i18n('audioOutputMuteButtonAriaLabelNotMuted'); + } } declare global {
diff --git a/chrome/browser/resources/settings/site_settings/review_notification_permissions.ts b/chrome/browser/resources/settings/site_settings/review_notification_permissions.ts index 295c510..c80ce89 100644 --- a/chrome/browser/resources/settings/site_settings/review_notification_permissions.ts +++ b/chrome/browser/resources/settings/site_settings/review_notification_permissions.ts
@@ -16,6 +16,7 @@ import {assert, assertNotReached} from 'chrome://resources/js/assert_ts.js'; import {EventTracker} from 'chrome://resources/js/event_tracker.js'; import {PluralStringProxyImpl} from 'chrome://resources/js/plural_string_proxy.js'; +import {isUndoKeyboardEvent} from 'chrome://resources/js/util_ts.js'; import {DomRepeatEvent, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {BaseMixin} from '../base_mixin.js'; @@ -305,10 +306,10 @@ private onUndoButtonClick_(e: Event) { e.stopPropagation(); - this.undoLastAction(); + this.undoLastAction_(); } - private undoLastAction() { + private undoLastAction_() { switch (this.lastUserAction_) { // As BLOCK and RESET actions just change the notification permission, // undoing them only requires allowing notification permissions again. @@ -350,28 +351,8 @@ return; } - /** - * TODO(crbug.com/1392664): Unify the implementation of ctrl+z that are in - * the current codebase. - * - * Undo should be done when ctrl+z (or meta+z on macOS) is pressed. No other - * modifier should be pressed simultaneously (alt, shift, meta on non-mac - * and ctrl on mac). - */ - if (e.key !== 'z') { - return; - } - const excludedModifiers = [e.altKey, e.shiftKey]; - // <if expr="is_macosx"> - let targetModifier = e.metaKey; - excludedModifiers.push(e.ctrlKey); - // </if> - // <if expr="not is_macosx"> - let targetModifier = e.ctrlKey; - excludedModifiers.push(e.metaKey); - // </if> - if (!excludedModifiers.some(Boolean) && targetModifier) { - this.undoLastAction(); + if (isUndoKeyboardEvent(e)) { + this.undoLastAction_(); } }
diff --git a/chrome/browser/safe_xml_parser_browsertest.cc b/chrome/browser/safe_xml_parser_browsertest.cc index 2a98f0b3..d6a7c58 100644 --- a/chrome/browser/safe_xml_parser_browsertest.cc +++ b/chrome/browser/safe_xml_parser_browsertest.cc
@@ -42,9 +42,9 @@ SCOPED_TRACE(xml); base::RunLoop run_loop; - std::unique_ptr<base::Value> expected_value; + absl::optional<base::Value> expected_value; if (!expected_json.empty()) { - expected_value = base::JSONReader::ReadDeprecated(expected_json); + expected_value = base::JSONReader::Read(expected_json); DCHECK(expected_value) << "Bad test, incorrect JSON: " << expected_json; } @@ -59,7 +59,7 @@ private: void XmlParsingDone(base::OnceClosure quit_loop_closure, - std::unique_ptr<base::Value> expected_value, + absl::optional<base::Value> expected_value, data_decoder::DataDecoder::ValueOrError result) { base::ScopedClosureRunner runner(std::move(quit_loop_closure)); if (!expected_value) {
diff --git a/chrome/browser/ssl/https_only_mode_tab_helper.cc b/chrome/browser/ssl/https_only_mode_tab_helper.cc index c8b81f2..817eabca 100644 --- a/chrome/browser/ssl/https_only_mode_tab_helper.cc +++ b/chrome/browser/ssl/https_only_mode_tab_helper.cc
@@ -4,29 +4,26 @@ #include "chrome/browser/ssl/https_only_mode_tab_helper.h" -#include "components/security_interstitials/content/https_only_mode_blocking_page.h" -#include "components/security_interstitials/content/security_interstitial_tab_helper.h" +#include "chrome/common/chrome_features.h" #include "content/public/browser/navigation_handle.h" HttpsOnlyModeTabHelper::~HttpsOnlyModeTabHelper() = default; -void HttpsOnlyModeTabHelper::ReadyToCommitNavigation( +void HttpsOnlyModeTabHelper::DidStartNavigation( content::NavigationHandle* navigation_handle) { - if (is_timer_interstitial()) { - set_is_timer_interstitial(false); - std::unique_ptr<security_interstitials::HttpsOnlyModeBlockingPage> - blocking_page = factory_->CreateHttpsOnlyModeBlockingPage( - navigation_handle->GetWebContents(), fallback_url()); - security_interstitials::SecurityInterstitialTabHelper:: - AssociateBlockingPage(navigation_handle, std::move(blocking_page)); + // The original HTTPS-First Mode implementation expects these to stay set + // across navigations and handles clearing them separately. Only reset if + // the HFMv2 implementation is being used to avoid interfering with HFMv1. + if (base::FeatureList::IsEnabled(features::kHttpsFirstModeV2)) { + set_fallback_url(GURL()); + set_is_navigation_fallback(false); + set_is_navigation_upgraded(false); } } HttpsOnlyModeTabHelper::HttpsOnlyModeTabHelper( content::WebContents* web_contents) : WebContentsObserver(web_contents), - content::WebContentsUserData<HttpsOnlyModeTabHelper>(*web_contents) { - factory_ = std::make_unique<ChromeSecurityBlockingPageFactory>(); -} + content::WebContentsUserData<HttpsOnlyModeTabHelper>(*web_contents) {} WEB_CONTENTS_USER_DATA_KEY_IMPL(HttpsOnlyModeTabHelper);
diff --git a/chrome/browser/ssl/https_only_mode_tab_helper.h b/chrome/browser/ssl/https_only_mode_tab_helper.h index 35166381a..fc3f8813 100644 --- a/chrome/browser/ssl/https_only_mode_tab_helper.h +++ b/chrome/browser/ssl/https_only_mode_tab_helper.h
@@ -5,7 +5,6 @@ #ifndef CHROME_BROWSER_SSL_HTTPS_ONLY_MODE_TAB_HELPER_H_ #define CHROME_BROWSER_SSL_HTTPS_ONLY_MODE_TAB_HELPER_H_ -#include "chrome/browser/ssl/chrome_security_blocking_page_factory.h" #include "content/public/browser/web_contents_observer.h" #include "content/public/browser/web_contents_user_data.h" @@ -15,8 +14,7 @@ } // namespace content // A short-lived, per-tab helper for tracking HTTPS-Only Mode data about the -// navigation and for creating the blocking page for the early-timeout code -// path. +// navigation. class HttpsOnlyModeTabHelper : public content::WebContentsObserver, public content::WebContentsUserData<HttpsOnlyModeTabHelper> { @@ -26,7 +24,7 @@ ~HttpsOnlyModeTabHelper() override; // content::WebContentsObserver: - void ReadyToCommitNavigation( + void DidStartNavigation( content::NavigationHandle* navigation_handle) override; // HTTPS-Only Mode metadata getters and setters: @@ -40,22 +38,20 @@ } bool is_navigation_fallback() const { return is_navigation_fallback_; } - void set_is_timer_interstitial(bool fallback) { - is_timer_interstitial_ = fallback; - } - bool is_timer_interstitial() const { return is_timer_interstitial_; } - void set_fallback_url(const GURL& fallback_url) { fallback_url_ = fallback_url; } GURL fallback_url() const { return fallback_url_; } + bool has_failed_upgrade(const GURL& url) { + return failed_upgrade_urls_.contains(url); + } + void add_failed_upgrade(const GURL& url) { failed_upgrade_urls_.insert(url); } + private: explicit HttpsOnlyModeTabHelper(content::WebContents* web_contents); friend class content::WebContentsUserData<HttpsOnlyModeTabHelper>; - std::unique_ptr<ChromeSecurityBlockingPageFactory> factory_; - // TODO(crbug.com/1218526): Track upgrade status per-navigation rather than // per-WebContents, in case multiple navigations occur in the WebContents and // the metadata is not cleared. This may be tricky however as the Interceptor @@ -67,13 +63,19 @@ // Set to true if the current navigation is a fallback to HTTP. bool is_navigation_fallback_ = false; - // Set to true if an interstitial triggered due to an HTTPS timeout is about - // to be shown. - bool is_timer_interstitial_ = false; - // HTTP URL that the current navigation should fall back to on failure. GURL fallback_url_; + // Holds the set of URLs that have failed to be upgraded to HTTPS in this + // WebContents. This is used to immediately show the HTTP interstitial without + // re-trying to upgrade the navigation -- currently this is only applied to + // back/forward navigations as they interact badly with interceptors, and this + // acts as the browser "remembering" the navigation state. + // + // In the case of HTTPS Upgrades, without HTTPS-First Mode enabled, these + // hostnames will also be on the HTTP allowlist, bypassing upgrade attempts. + std::set<GURL> failed_upgrade_urls_; + WEB_CONTENTS_USER_DATA_KEY_DECL(); };
diff --git a/chrome/browser/ssl/https_upgrades_browsertest.cc b/chrome/browser/ssl/https_upgrades_browsertest.cc index e805920..a82bba8 100644 --- a/chrome/browser/ssl/https_upgrades_browsertest.cc +++ b/chrome/browser/ssl/https_upgrades_browsertest.cc
@@ -1036,10 +1036,8 @@ // Regression test for crbug.com/1272781. Previously, performing back/forward // navigations around the HTTPS-First Mode interstitial could cause history // entries to dropped. -// TODO(crbug.com/1272781): Broken when BFCache is disabled (like on the -// linux-bfcache-rel bots). -IN_PROC_BROWSER_TEST_F(HttpsUpgradesBrowserTest, - DISABLED_InterstitialFallbackMaintainsHistory) { +IN_PROC_BROWSER_TEST_P(HttpsUpgradesBrowserTest, + InterstitialFallbackMaintainsHistory) { // This test only applies to HTTPS-First Mode. if (!IsHttpInterstitialEnabled()) { return; @@ -1088,18 +1086,16 @@ // upgraded to HTTPS and fail, triggering the HTTPS-First Mode // interstitial. content::NavigateToURLBlockUntilNavigationsComplete(contents, - downgrading_http_url, 2); + downgrading_http_url, 1); EXPECT_EQ(downgrading_http_url, contents->GetLastCommittedURL()); EXPECT_TRUE(chrome_browser_interstitials::IsShowingHttpsFirstModeInterstitial( contents)); // Simulate clicking the browser "back" button. - // TODO(crbug.com/1394910): The incorrect WARNING security state is retained - // from the interstitial page. EXPECT_TRUE(content::HistoryGoBack(contents)); EXPECT_EQ(good_https_url, contents->GetLastCommittedURL()); auto* helper = SecurityStateTabHelper::FromWebContents(contents); - EXPECT_EQ(security_state::WARNING, helper->GetSecurityLevel()); + EXPECT_EQ(security_state::SECURE, helper->GetSecurityLevel()); // Simulate clicking the browser "forward" button. The HistoryGoForward() // call returns `false` because it is an error page.
diff --git a/chrome/browser/ssl/https_upgrades_interceptor.cc b/chrome/browser/ssl/https_upgrades_interceptor.cc index 75bf497..1a21c97 100644 --- a/chrome/browser/ssl/https_upgrades_interceptor.cc +++ b/chrome/browser/ssl/https_upgrades_interceptor.cc
@@ -15,6 +15,7 @@ #include "components/prefs/pref_service.h" #include "components/security_interstitials/content/stateful_ssl_host_state_delegate.h" #include "components/security_interstitials/core/https_only_mode_metrics.h" +#include "content/public/browser/navigation_entry.h" #include "content/public/browser/storage_partition.h" #include "content/public/browser/url_loader_request_interceptor.h" #include "content/public/browser/web_contents.h" @@ -34,6 +35,7 @@ #include "services/network/public/mojom/network_context.mojom.h" #include "services/network/public/mojom/url_loader.mojom.h" #include "services/network/public/mojom/url_response_head.mojom.h" +#include "ui/base/page_transition_types.h" #include "url/gurl.h" #include "url/url_constants.h" @@ -85,8 +87,7 @@ if (resource_request.is_outermost_main_frame && resource_request.method == "GET" && !net::IsLocalhost(resource_request.url) && - resource_request.url.SchemeIs(url::kHttpScheme) && - !tab_helper->is_navigation_fallback()) { + resource_request.url.SchemeIs(url::kHttpScheme)) { return true; } return false; @@ -256,6 +257,30 @@ return; } + // If this is a back/forward navigation to a failed upgrade, then don't + // intercept to upgrade the navigation. Other forms of re-visiting a URL + // that previously failed to be upgraded to HTTPS *should* be intercepted so + // the upgrade can be attempted again (e.g., the user reloading the tab, the + // user navigating around and ending back on this URL in the same tab, etc.). + // + // This effectively "caches" the HTTPS-First Mode interstitial for the + // history entry of a failed upgrade for the lifetime of the tab. This means + // that it is possible for a user to come back much later (say, a week later), + // after a site has fixed its HTTPS configuration, and still see the + // interstitial for that URL. + // + // Without this check, resetting the HTTPS-Upgrades flags in + // HttpsOnlyModeTabHelper::DidStartNavigation() means the Interceptor would + // fire on back/forward navigation to the interstitial, which causes an + // "extra" interstitial entry to be added to the history list and lose other + // entries. + auto* entry = web_contents->GetController().GetPendingEntry(); + if (entry && entry->GetTransitionType() & ui::PAGE_TRANSITION_FORWARD_BACK && + tab_helper->has_failed_upgrade(tentative_resource_request.url)) { + std::move(callback).Run({}); + return; + } + if (!ShouldCreateLoader(tentative_resource_request, tab_helper)) { std::move(callback).Run({}); return; @@ -377,8 +402,9 @@ tab_helper->set_is_navigation_upgraded(false); tab_helper->set_is_navigation_fallback(true); + tab_helper->add_failed_upgrade(tab_helper->fallback_url()); - // `client_` may have been previously boudn from handling the initial upgrade + // `client_` may have been previously bound from handling the initial upgrade // in MaybeCreateLoader(), so reset it before re-binding it to handle this // response. client_.reset();
diff --git a/chrome/browser/ssl/https_upgrades_navigation_throttle.cc b/chrome/browser/ssl/https_upgrades_navigation_throttle.cc index c922b38f5..563e171e 100644 --- a/chrome/browser/ssl/https_upgrades_navigation_throttle.cc +++ b/chrome/browser/ssl/https_upgrades_navigation_throttle.cc
@@ -23,6 +23,7 @@ #include "content/public/browser/navigation_throttle.h" #include "content/public/browser/web_contents.h" #include "net/base/net_errors.h" +#include "ui/base/page_transition_types.h" using security_interstitials::https_only_mode::Event; @@ -91,6 +92,42 @@ content::NavigationThrottle::ThrottleCheckResult HttpsUpgradesNavigationThrottle::WillStartRequest() { + // If the navigation is fallback to HTTP, trigger the HTTP interstitial (if + // enabled). The interceptor creates a redirect for the fallback navigation, + // which will trigger MaybeCreateLoader() in the interceptor for the redirect + // but *doesn't* trigger WillStartRequest() because it's all part of the same + // request. Here, we skip directly to showing the HTTP interstitial if this + // is: + // (1) a back/forward navigation, and + // (2) the URL already failed upgrades before. + // This lets us avoid triggering the Interceptor during a back/forward + // navigation (which breaks history state) and acts like the browser + // "remembering" the state of the tab as being on the interstitial for that + // URL. + // + // Other cases for starting a navigation to a URL that previously failed + // to be upgraded should go through the full upgrade flow -- better to assume + // that something may have changed in the time since. For example: a user + // reloading the tab showing the interstitial should re-try the upgrade. + auto* handle = navigation_handle(); + auto* contents = handle->GetWebContents(); + auto* tab_helper = HttpsOnlyModeTabHelper::FromWebContents(contents); + if ((handle->GetPageTransition() & ui::PAGE_TRANSITION_FORWARD_BACK && + tab_helper->has_failed_upgrade(handle->GetURL())) && + !handle->GetURL().SchemeIsCryptographic() && http_interstitial_enabled_) { + // Mark this as a fallback HTTP navigation and trigger the interstitial. + tab_helper->set_is_navigation_fallback(true); + std::unique_ptr<security_interstitials::HttpsOnlyModeBlockingPage> + blocking_page = blocking_page_factory_->CreateHttpsOnlyModeBlockingPage( + contents, handle->GetURL()); + std::string interstitial_html = blocking_page->GetHTMLContents(); + security_interstitials::SecurityInterstitialTabHelper:: + AssociateBlockingPage(handle, std::move(blocking_page)); + return content::NavigationThrottle::ThrottleCheckResult( + content::NavigationThrottle::CANCEL, net::ERR_BLOCKED_BY_CLIENT, + interstitial_html); + } + // Navigation is HTTPS or an initial HTTP navigation (which will get // upgraded by the interceptor). Fallback HTTP navigations are handled in // WillRedirectRequest(). @@ -106,11 +143,11 @@ content::NavigationThrottle::ThrottleCheckResult HttpsUpgradesNavigationThrottle::WillRedirectRequest() { - // If the navigation is fallback to HTTP, trigger the HTTP interstitial (if - // enabled). The interceptor creates a redirect for the fallback navigation, - // which will trigger MaybeCreateLoader() in the interceptor for the redirect - // but *doesn't* trigger WillStartRequest() because it's all part of the same - // request. + // If the navigation is doing a fallback redirect to HTTP, trigger the HTTP + // interstitial (if enabled). The interceptor creates a redirect for the + // fallback navigation, which will trigger MaybeCreateLoader() in the + // interceptor for the redirect but *doesn't* trigger WillStartRequest() + // because it's all part of the same request. auto* handle = navigation_handle(); auto* contents = handle->GetWebContents(); auto* tab_helper = HttpsOnlyModeTabHelper::FromWebContents(contents);
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index 0b8ec41..f14b6fa 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -1525,8 +1525,6 @@ "webui/history/history_ui.h", "webui/history/navigation_handler.cc", "webui/history/navigation_handler.h", - "webui/history_clusters/history_cluster_type_utils.cc", - "webui/history_clusters/history_cluster_type_utils.h", "webui/history_clusters/history_clusters_handler.cc", "webui/history_clusters/history_clusters_handler.h", "webui/identity_internals_ui.cc", @@ -3983,11 +3981,11 @@ "views/apps/app_window_desktop_native_widget_aura_win.h", "views/apps/app_window_desktop_window_tree_host_win.cc", "views/apps/app_window_desktop_window_tree_host_win.h", + "views/apps/app_window_frame_view_win.cc", + "views/apps/app_window_frame_view_win.h", "views/apps/chrome_app_window_client_views_win.cc", "views/apps/chrome_native_app_window_views_win.cc", "views/apps/chrome_native_app_window_views_win.h", - "views/apps/glass_app_window_frame_view_win.cc", - "views/apps/glass_app_window_frame_view_win.h", "views/certificate_viewer_win.cc", "views/chrome_cleaner_dialog_win.cc", "views/chrome_cleaner_dialog_win.h",
diff --git a/chrome/browser/ui/android/fast_checkout/internal/BUILD.gn b/chrome/browser/ui/android/fast_checkout/internal/BUILD.gn index 5af7fc9..ea39c6e 100644 --- a/chrome/browser/ui/android/fast_checkout/internal/BUILD.gn +++ b/chrome/browser/ui/android/fast_checkout/internal/BUILD.gn
@@ -14,6 +14,7 @@ "java/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutMediator.java", "java/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutProperties.java", "java/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutSheetContent.java", + "java/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutSheetState.java", "java/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutUserActions.java", "java/src/org/chromium/chrome/browser/ui/fast_checkout/detail_screen/AutofillProfileItemProperties.java", "java/src/org/chromium/chrome/browser/ui/fast_checkout/detail_screen/AutofillProfileItemViewBinder.java", @@ -100,6 +101,7 @@ "junit/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutDetailScreenViewTest.java", "junit/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutHomeScreenViewTest.java", "junit/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutMediatorTest.java", + "junit/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutSheetContentTest.java", ] deps = [ ":java",
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/res/layout/fast_checkout_detail_screen_sheet.xml b/chrome/browser/ui/android/fast_checkout/internal/java/res/layout/fast_checkout_detail_screen_sheet.xml index 154c73c1..af23c79aa 100644 --- a/chrome/browser/ui/android/fast_checkout/internal/java/res/layout/fast_checkout_detail_screen_sheet.xml +++ b/chrome/browser/ui/android/fast_checkout/internal/java/res/layout/fast_checkout_detail_screen_sheet.xml
@@ -5,31 +5,28 @@ found in the LICENSE file. --> -<ScrollView +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" - android:layout_width="match_parent" android:layout_height="wrap_content" + android:layout_width="match_parent" + android:orientation="vertical" android:layout_marginTop="12dp"> - <LinearLayout - android:layout_height="wrap_content" - android:layout_width="match_parent" - android:orientation="vertical"> - <androidx.appcompat.widget.Toolbar - android:id="@+id/action_bar" - android:layout_gravity="center_horizontal" - android:layout_width="match_parent" - android:layout_height="?attr/actionBarSize" - android:focusable="true" - android:titleTextAppearance="@style/TextAppearance.Headline" - style="@style/ModernToolbar" /> + <androidx.appcompat.widget.Toolbar + android:id="@+id/action_bar" + android:layout_gravity="center_horizontal" + android:layout_width="match_parent" + android:layout_height="?attr/actionBarSize" + android:focusable="true" + android:titleTextAppearance="@style/TextAppearance.Headline" + style="@style/ModernToolbar" /> <FrameLayout android:id="@+id/sheet_item_list_container" android:layout_width="match_parent" - android:layout_height="match_parent"> + android:layout_height="wrap_content"> <androidx.recyclerview.widget.RecyclerView android:id="@+id/fast_checkout_detail_screen_recycler_view" android:layout_width="match_parent" @@ -40,4 +37,3 @@ </FrameLayout> </LinearLayout> -</ScrollView>
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/res/values/dimens.xml b/chrome/browser/ui/android/fast_checkout/internal/java/res/values/dimens.xml index 584e726..b18469b2 100644 --- a/chrome/browser/ui/android/fast_checkout/internal/java/res/values/dimens.xml +++ b/chrome/browser/ui/android/fast_checkout/internal/java/res/values/dimens.xml
@@ -34,4 +34,5 @@ <dimen name="fast_checkout_detail_sheet_selected_icon_margin_end">16dp</dimen> <dimen name="fast_checkout_detail_sheet_height_single_address">160dp</dimen> <dimen name="fast_checkout_detail_sheet_height_single_credit_card">92dp</dimen> + <dimen name="fast_checkout_detail_sheet_header_height">77dp</dimen> </resources>
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutCoordinator.java b/chrome/browser/ui/android/fast_checkout/internal/java/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutCoordinator.java index a69becb..d1b01e0 100644 --- a/chrome/browser/ui/android/fast_checkout/internal/java/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutCoordinator.java +++ b/chrome/browser/ui/android/fast_checkout/internal/java/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutCoordinator.java
@@ -28,15 +28,11 @@ public void initialize(Context context, BottomSheetController sheetController, FastCheckoutComponent.Delegate delegate) { mBottomSheetController = sheetController; - mMediator.initialize(delegate, mModel, mBottomSheetController, - context.getResources().getDimensionPixelSize( - R.dimen.fast_checkout_detail_sheet_height_single_address), - context.getResources().getDimensionPixelSize( - R.dimen.fast_checkout_detail_sheet_height_single_credit_card)); + mMediator.initialize(delegate, mModel, mBottomSheetController); LinearLayout rootView = (LinearLayout) LayoutInflater.from(context).inflate( R.layout.fast_checkout_bottom_sheet, null); - mContent = new FastCheckoutSheetContent(rootView); + mContent = new FastCheckoutSheetContent(mMediator, rootView); View homeScreenView = rootView.findViewById(R.id.fast_checkout_home_screen_sheet); HomeScreenCoordinator homeScreenCoordinator =
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutMediator.java b/chrome/browser/ui/android/fast_checkout/internal/java/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutMediator.java index cc304ec..64d196b 100644 --- a/chrome/browser/ui/android/fast_checkout/internal/java/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutMediator.java +++ b/chrome/browser/ui/android/fast_checkout/internal/java/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutMediator.java
@@ -5,10 +5,8 @@ package org.chromium.chrome.browser.ui.fast_checkout; import android.view.MenuItem; -import android.widget.FrameLayout; import androidx.annotation.MainThread; -import androidx.annotation.Px; import androidx.appcompat.widget.Toolbar.OnMenuItemClickListener; import org.chromium.chrome.browser.ui.fast_checkout.FastCheckoutProperties.DetailItemType; @@ -32,25 +30,17 @@ * Contains the logic for the FastCheckout component. It sets the state of the model and reacts * to events like clicks. */ -public class FastCheckoutMediator { - private static final float MAX_VISIBLE_ADDRESSES = 2.5f; - private static final float MAX_VISIBLE_CREDIT_CARDS = 3.5f; - +public class FastCheckoutMediator implements FastCheckoutSheetState { private PropertyModel mModel; private FastCheckoutComponent.Delegate mDelegate; private BottomSheetController mBottomSheetController; private BottomSheetObserver mBottomSheetDismissedObserver; - private @Px int mAddressItemHeight; - private @Px int mCreditCardItemHeight; void initialize(FastCheckoutComponent.Delegate delegate, PropertyModel model, - BottomSheetController bottomSheetController, @Px int addressItemHeight, - @Px int creditCardItemHeight) { + BottomSheetController bottomSheetController) { mModel = model; mDelegate = delegate; mBottomSheetController = bottomSheetController; - mAddressItemHeight = addressItemHeight; - mCreditCardItemHeight = creditCardItemHeight; mBottomSheetDismissedObserver = new EmptyBottomSheetObserver() { @Override @@ -322,8 +312,6 @@ })); mModel.set(FastCheckoutProperties.DETAIL_SCREEN_MODEL_LIST, mModel.get(FastCheckoutProperties.PROFILE_MODEL_LIST)); - mModel.set(FastCheckoutProperties.DETAIL_SCREEN_LIST_HEIGHT_IN_PX, - computeAddressListSheetHeight()); } else if (screenType == ScreenType.CREDIT_CARD_SCREEN) { mModel.set(FastCheckoutProperties.DETAIL_SCREEN_TITLE, R.string.fast_checkout_credit_card_sheet_title); @@ -338,48 +326,11 @@ })); mModel.set(FastCheckoutProperties.DETAIL_SCREEN_MODEL_LIST, mModel.get(FastCheckoutProperties.CREDIT_CARD_MODEL_LIST)); - mModel.set(FastCheckoutProperties.DETAIL_SCREEN_LIST_HEIGHT_IN_PX, - computeCreditCardListSheetHeight()); } mModel.set(FastCheckoutProperties.CURRENT_SCREEN, screenType); - } - - /** - * Computes the height of the detail address list. - * - * If there are 1 or 2 items, it shows all items fully. For 3+ suggestions, it shows the - * first 2.5 suggestions to encourage scrolling. - */ - private @Px int computeAddressListSheetHeight() { - // Remove the "Add item" button at the end of the list. - int numItems = mModel.get(FastCheckoutProperties.PROFILE_MODEL_LIST).size() - 1; - // When there are more than {@link MAX_VISIBLE_ADDRESSES} items, resize the list - // so that only {@link MAX_VISIBLE_ADDRESSES} items and part of the next one are visible. - if (numItems > MAX_VISIBLE_ADDRESSES) { - return Math.round((float) mAddressItemHeight * MAX_VISIBLE_ADDRESSES); - } - // Otherwise display all the items. - return FrameLayout.LayoutParams.WRAP_CONTENT; - } - - /** - * Computes the height of the detail credit card list. - * - * if there are less than 4 items, it shows all items fully. For 4+ suggestions, it shows the - * first 3.5 suggestions to encourage scrolling. - */ - private @Px int computeCreditCardListSheetHeight() { - // Remove the "Add item" button at the end of the list. - int numItems = mModel.get(FastCheckoutProperties.CREDIT_CARD_MODEL_LIST).size() - 1; - // When there are more than {@link MAX_VISIBLE_CREDIT_CARDS} items, resize the - // list so that only {@link MAX_VISIBLE_CREDIT_CARDS} items and part of the next one are - // visible. - if (numItems > MAX_VISIBLE_CREDIT_CARDS) { - return Math.round((float) mCreditCardItemHeight * MAX_VISIBLE_CREDIT_CARDS); - } - // Otherwise display all the items. - return FrameLayout.LayoutParams.WRAP_CONTENT; + // Sets bottom sheet to half height, if enabled. Otherwise to full. + mBottomSheetController.expandSheet(); } /** @@ -408,4 +359,28 @@ FastCheckoutUserActions.DESTROYED.log(); mModel.set(FastCheckoutProperties.VISIBLE, false); } + + @Override + public @ScreenType int getCurrentScreen() { + return mModel.get(FastCheckoutProperties.CURRENT_SCREEN); + } + + @Override + public int getNumOfAutofillProfiles() { + // The list contains Autofill profiles and one footer at the end. Subtracts 1 to not count + // the footer. + return mModel.get(FastCheckoutProperties.PROFILE_MODEL_LIST).size() - 1; + } + + @Override + public int getNumOfCreditCards() { + // The list contains credit cards and one footer at the end. Subtracts 1 to not count the + // footer. + return mModel.get(FastCheckoutProperties.CREDIT_CARD_MODEL_LIST).size() - 1; + } + + @Override + public int getContainerHeight() { + return mBottomSheetController.getContainerHeight(); + } }
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutProperties.java b/chrome/browser/ui/android/fast_checkout/internal/java/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutProperties.java index 21d29dd..35f4f44 100644 --- a/chrome/browser/ui/android/fast_checkout/internal/java/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutProperties.java +++ b/chrome/browser/ui/android/fast_checkout/internal/java/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutProperties.java
@@ -112,10 +112,6 @@ public static final WritableObjectPropertyKey<ModelList> DETAIL_SCREEN_MODEL_LIST = new WritableObjectPropertyKey<>("detail_screen_model_list"); - /** The height in px for the detail sheet item list. */ - public static final WritableIntPropertyKey DETAIL_SCREEN_LIST_HEIGHT_IN_PX = - new WritableIntPropertyKey("detail_screen_recycler_view_height"); - public static PropertyModel createDefaultModel() { return new PropertyModel.Builder(ALL_KEYS) .with(VISIBLE, false) @@ -130,6 +126,5 @@ SELECTED_PROFILE, PROFILE_MODEL_LIST, SELECTED_CREDIT_CARD, CREDIT_CARD_MODEL_LIST, HOME_SCREEN_DELEGATE, DETAIL_SCREEN_TITLE, DETAIL_SCREEN_TITLE_DESCRIPTION, DETAIL_SCREEN_SETTINGS_MENU_TITLE, DETAIL_SCREEN_BACK_CLICK_HANDLER, - DETAIL_SCREEN_SETTINGS_CLICK_HANDLER, DETAIL_SCREEN_MODEL_LIST, - DETAIL_SCREEN_LIST_HEIGHT_IN_PX}; + DETAIL_SCREEN_SETTINGS_CLICK_HANDLER, DETAIL_SCREEN_MODEL_LIST}; }
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutSheetContent.java b/chrome/browser/ui/android/fast_checkout/internal/java/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutSheetContent.java index c2955e7..dde21f6a8 100644 --- a/chrome/browser/ui/android/fast_checkout/internal/java/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutSheetContent.java +++ b/chrome/browser/ui/android/fast_checkout/internal/java/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutSheetContent.java
@@ -4,7 +4,13 @@ package org.chromium.chrome.browser.ui.fast_checkout; +import static org.chromium.chrome.browser.ui.fast_checkout.FastCheckoutProperties.ScreenType.AUTOFILL_PROFILE_SCREEN; +import static org.chromium.chrome.browser.ui.fast_checkout.FastCheckoutProperties.ScreenType.CREDIT_CARD_SCREEN; +import static org.chromium.chrome.browser.ui.fast_checkout.FastCheckoutProperties.ScreenType.HOME_SCREEN; + import android.view.View; +import android.view.View.MeasureSpec; +import android.view.ViewGroup; import androidx.annotation.Nullable; @@ -14,12 +20,17 @@ * The {@link BottomSheetContent} for Fast Checkout. */ public class FastCheckoutSheetContent implements BottomSheetContent { + private static final float MAX_VISIBLE_WHOLE_ADDRESSES = 2.5f; + private static final float MAX_VISIBLE_WHOLE_CREDIT_CARDS = 3.5f; + + private final FastCheckoutSheetState mState; private final View mContentView; /** * Constructs a FastCheckoutSheetContent which creates, modifies, and shows the bottom sheet. */ - FastCheckoutSheetContent(View contentView) { + FastCheckoutSheetContent(FastCheckoutSheetState state, View contentView) { + mState = state; mContentView = contentView; } @@ -63,8 +74,24 @@ } @Override + public float getHalfHeightRatio() { + if (shouldWrapContent()) { + return HeightMode.DISABLED; + } + return Math.min(getDesiredDetailSheetHeight(), mState.getContainerHeight()) + / (float) mState.getContainerHeight(); + } + + @Override public float getFullHeightRatio() { - return HeightMode.WRAP_CONTENT; + if (shouldWrapContent()) { + return HeightMode.WRAP_CONTENT; + } + // This would ideally also be `WRAP_CONTENT` but that disables half height mode. + // `mBottomSheetController.getContainerHeight()` is the height of the bottom sheet's + // container, i.e. the screen. + return Math.min(getBottomSheetHeight(), mState.getContainerHeight()) + / (float) mState.getContainerHeight(); } @Override @@ -86,4 +113,56 @@ public int getSheetFullHeightAccessibilityStringId() { return R.string.fast_checkout_content_description; } + + private boolean isHomeScreen() { + return mState.getCurrentScreen() == HOME_SCREEN; + } + + private boolean isAutofillProfileScreen() { + return mState.getCurrentScreen() == AUTOFILL_PROFILE_SCREEN; + } + + private boolean isCreditCardScreen() { + return mState.getCurrentScreen() == CREDIT_CARD_SCREEN; + } + + private float getBottomSheetHeight() { + ViewGroup parent = (ViewGroup) getContentView().getParent(); + getContentView().measure( + MeasureSpec.makeMeasureSpec(parent.getWidth(), MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(parent.getHeight(), MeasureSpec.AT_MOST)); + return getContentView().getMeasuredHeight(); + } + + private boolean shouldWrapContent() { + // If there are 1 or 2 Autofill profiles, it shows all items fully. For 3+ suggestions, it + // shows the first 2.5 suggestions to encourage scrolling. + boolean shouldWrapAutofillProfiles = isAutofillProfileScreen() + && mState.getNumOfAutofillProfiles() < MAX_VISIBLE_WHOLE_ADDRESSES; + // If there are less than 4 credit cards, it shows all items fully. For 4+ suggestions, it + // shows the first 3.5 suggestions to encourage scrolling. + boolean shouldWrapCreditCards = isCreditCardScreen() + && mState.getNumOfCreditCards() < MAX_VISIBLE_WHOLE_CREDIT_CARDS; + return isHomeScreen() || shouldWrapAutofillProfiles || shouldWrapCreditCards; + } + + private int getDesiredDetailSheetHeight() { + // TODO(crbug.com/1334642): Investigate measuring heights dynamically instead of using + // hard-coded values. + int height = getDimensionPixelSize(R.dimen.fast_checkout_detail_sheet_header_height); + if (isAutofillProfileScreen()) { + height += Math.round(MAX_VISIBLE_WHOLE_ADDRESSES + * getDimensionPixelSize( + R.dimen.fast_checkout_detail_sheet_height_single_address)); + } else { + height += Math.round(MAX_VISIBLE_WHOLE_CREDIT_CARDS + * getDimensionPixelSize( + R.dimen.fast_checkout_detail_sheet_height_single_credit_card)); + } + return height; + } + + private int getDimensionPixelSize(int id) { + return mContentView.getContext().getResources().getDimensionPixelSize(id); + } }
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutSheetState.java b/chrome/browser/ui/android/fast_checkout/internal/java/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutSheetState.java new file mode 100644 index 0000000..b7d670d --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/java/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutSheetState.java
@@ -0,0 +1,33 @@ +// Copyright 2023 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.ui.fast_checkout; + +import org.chromium.chrome.browser.ui.fast_checkout.FastCheckoutProperties.ScreenType; + +/** + * Provides read-only information about the state of the Fast Checkout bottomsheet. + */ +public interface FastCheckoutSheetState { + /** + * Returns the current screen type of the bottomsheet. + */ + @ScreenType + int getCurrentScreen(); + + /** + * Returns the number of Autofill profiles that would currently be displayed to the user. + */ + int getNumOfAutofillProfiles(); + + /** + * Returns the number of credit cards that would currently be displayed to the user. + */ + int getNumOfCreditCards(); + + /** + * Returns the height of the bottomsheet's container, i.e. the screen. + */ + int getContainerHeight(); +}
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/src/org/chromium/chrome/browser/ui/fast_checkout/detail_screen/DetailScreenViewBinder.java b/chrome/browser/ui/android/fast_checkout/internal/java/src/org/chromium/chrome/browser/ui/fast_checkout/detail_screen/DetailScreenViewBinder.java index 0a1127d..432c753 100644 --- a/chrome/browser/ui/android/fast_checkout/internal/java/src/org/chromium/chrome/browser/ui/fast_checkout/detail_screen/DetailScreenViewBinder.java +++ b/chrome/browser/ui/android/fast_checkout/internal/java/src/org/chromium/chrome/browser/ui/fast_checkout/detail_screen/DetailScreenViewBinder.java
@@ -5,7 +5,6 @@ package org.chromium.chrome.browser.ui.fast_checkout.detail_screen; import static org.chromium.chrome.browser.ui.fast_checkout.FastCheckoutProperties.DETAIL_SCREEN_BACK_CLICK_HANDLER; -import static org.chromium.chrome.browser.ui.fast_checkout.FastCheckoutProperties.DETAIL_SCREEN_LIST_HEIGHT_IN_PX; import static org.chromium.chrome.browser.ui.fast_checkout.FastCheckoutProperties.DETAIL_SCREEN_MODEL_LIST; import static org.chromium.chrome.browser.ui.fast_checkout.FastCheckoutProperties.DETAIL_SCREEN_SETTINGS_CLICK_HANDLER; import static org.chromium.chrome.browser.ui.fast_checkout.FastCheckoutProperties.DETAIL_SCREEN_SETTINGS_MENU_TITLE; @@ -82,9 +81,6 @@ adapter.registerType(DetailItemType.PROFILE, AutofillProfileItemViewBinder::create, AutofillProfileItemViewBinder::bind); view.setAdapter(adapter); - } else if (propertyKey == DETAIL_SCREEN_LIST_HEIGHT_IN_PX) { - view.mSheetItemListContainer.getLayoutParams().height = - model.get(DETAIL_SCREEN_LIST_HEIGHT_IN_PX); } } }
diff --git a/chrome/browser/ui/android/fast_checkout/internal/junit/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutMediatorTest.java b/chrome/browser/ui/android/fast_checkout/internal/junit/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutMediatorTest.java index 6d08e449..8db3860 100644 --- a/chrome/browser/ui/android/fast_checkout/internal/junit/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutMediatorTest.java +++ b/chrome/browser/ui/android/fast_checkout/internal/junit/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutMediatorTest.java
@@ -19,7 +19,6 @@ import static org.chromium.chrome.browser.ui.fast_checkout.FastCheckoutProperties.CREDIT_CARD_MODEL_LIST; import static org.chromium.chrome.browser.ui.fast_checkout.FastCheckoutProperties.CURRENT_SCREEN; import static org.chromium.chrome.browser.ui.fast_checkout.FastCheckoutProperties.DETAIL_SCREEN_BACK_CLICK_HANDLER; -import static org.chromium.chrome.browser.ui.fast_checkout.FastCheckoutProperties.DETAIL_SCREEN_LIST_HEIGHT_IN_PX; import static org.chromium.chrome.browser.ui.fast_checkout.FastCheckoutProperties.DETAIL_SCREEN_MODEL_LIST; import static org.chromium.chrome.browser.ui.fast_checkout.FastCheckoutProperties.DETAIL_SCREEN_SETTINGS_CLICK_HANDLER; import static org.chromium.chrome.browser.ui.fast_checkout.FastCheckoutProperties.DETAIL_SCREEN_SETTINGS_MENU_TITLE; @@ -31,7 +30,6 @@ import static org.chromium.chrome.browser.ui.fast_checkout.FastCheckoutProperties.VISIBLE; import android.view.MenuItem; -import android.widget.FrameLayout; import androidx.appcompat.widget.Toolbar.OnMenuItemClickListener; import androidx.recyclerview.widget.RecyclerView; @@ -112,7 +110,7 @@ public void setUp() { MockitoAnnotations.initMocks(this); mActionTester = new UserActionTester(); - mMediator.initialize(mMockDelegate, mModel, mMockBottomSheetController, 160, 92); + mMediator.initialize(mMockDelegate, mModel, mMockBottomSheetController); } @After @@ -428,38 +426,6 @@ assertActionRecorded(FastCheckoutUserActions.DESTROYED); } - @Test - public void testHeightOfAddressItemList() { - mMediator.showOptions( - DUMMY_PROFILES, DUMMY_CARDS); /* 3 addresses, should show 2 and a half items. */ - mMediator.setCurrentScreen(ScreenType.AUTOFILL_PROFILE_SCREEN); - assertThat(mModel.get(VISIBLE), is(true)); - assertThat(mModel.get(DETAIL_SCREEN_LIST_HEIGHT_IN_PX), is(400)); - - mMediator.showOptions( - new FastCheckoutAutofillProfile[] {DUMMY_PROFILES[0], DUMMY_PROFILES[1]}, - DUMMY_CARDS); /* 2 addresses, should show all items */ - mMediator.setCurrentScreen(ScreenType.AUTOFILL_PROFILE_SCREEN); - assertThat(mModel.get(DETAIL_SCREEN_LIST_HEIGHT_IN_PX), - is(FrameLayout.LayoutParams.WRAP_CONTENT)); - } - - @Test - public void testHeightOfCreditCardItemList() { - mMediator.showOptions( - DUMMY_PROFILES, DUMMY_CARDS); /* 4 credit cards, should show 3 and a half items. */ - mMediator.setCurrentScreen(ScreenType.CREDIT_CARD_SCREEN); - assertThat(mModel.get(VISIBLE), is(true)); - assertThat(mModel.get(DETAIL_SCREEN_LIST_HEIGHT_IN_PX), is(322)); - - mMediator.showOptions(DUMMY_PROFILES, - new FastCheckoutCreditCard[] {DUMMY_CARDS[0], DUMMY_CARDS[1], - DUMMY_CARDS[2]}); /* 3 addresses, should show all items */ - mMediator.setCurrentScreen(ScreenType.CREDIT_CARD_SCREEN); - assertThat(mModel.get(DETAIL_SCREEN_LIST_HEIGHT_IN_PX), - is(FrameLayout.LayoutParams.WRAP_CONTENT)); - } - private void assertActionRecorded(FastCheckoutUserActions action) { assertTrue(mActionTester.getActions().contains(action.getAction())); }
diff --git a/chrome/browser/ui/android/fast_checkout/internal/junit/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutSheetContentTest.java b/chrome/browser/ui/android/fast_checkout/internal/junit/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutSheetContentTest.java new file mode 100644 index 0000000..d3a3af81 --- /dev/null +++ b/chrome/browser/ui/android/fast_checkout/internal/junit/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutSheetContentTest.java
@@ -0,0 +1,146 @@ +// Copyright 2023 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.ui.fast_checkout; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.when; + +import static org.chromium.chrome.browser.ui.fast_checkout.FastCheckoutProperties.ScreenType.AUTOFILL_PROFILE_SCREEN; +import static org.chromium.chrome.browser.ui.fast_checkout.FastCheckoutProperties.ScreenType.CREDIT_CARD_SCREEN; +import static org.chromium.chrome.browser.ui.fast_checkout.FastCheckoutProperties.ScreenType.HOME_SCREEN; +import static org.chromium.components.browser_ui.bottomsheet.BottomSheetContent.HeightMode.DISABLED; +import static org.chromium.components.browser_ui.bottomsheet.BottomSheetContent.HeightMode.WRAP_CONTENT; + +import android.content.Context; +import android.content.res.Resources; +import android.view.View; +import android.view.ViewGroup; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.annotation.Config; + +import org.chromium.base.test.BaseRobolectricTestRunner; + +/** + * Unit tests for the `FastCheckoutSheetContent` class. + */ +@RunWith(BaseRobolectricTestRunner.class) +@Config(manifest = Config.NONE) +public class FastCheckoutSheetContentTest { + private static final double DELTA = 0.001; + private static final int HEADER_HEIGHT = 10; + private static final int PROFILE_HEIGHT = 15; + private static final int CREDIT_CARD_HEIGHT = 10; + private static final int CONTENT_VIEW_HEIGHT = 40; + private static final int CONTAINER_HEIGHT = 100; + + private FastCheckoutSheetContent mSheetContent; + @Mock + private View mContentView; + @Mock + private ViewGroup mContentViewParent; + @Mock + private Context mContext; + @Mock + private Resources mResources; + @Mock + private FastCheckoutSheetState mState; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mSheetContent = new FastCheckoutSheetContent(mState, mContentView); + + when(mResources.getDimensionPixelSize(R.dimen.fast_checkout_detail_sheet_header_height)) + .thenReturn(HEADER_HEIGHT); + when(mResources.getDimensionPixelSize( + R.dimen.fast_checkout_detail_sheet_height_single_address)) + .thenReturn(PROFILE_HEIGHT); + when(mResources.getDimensionPixelSize( + R.dimen.fast_checkout_detail_sheet_height_single_credit_card)) + .thenReturn(CREDIT_CARD_HEIGHT); + when(mContext.getResources()).thenReturn(mResources); + when(mContentView.getContext()).thenReturn(mContext); + when(mContentView.getParent()).thenReturn(mContentViewParent); + when(mContentView.getMeasuredHeight()).thenReturn(CONTENT_VIEW_HEIGHT); + when(mState.getContainerHeight()).thenReturn(CONTAINER_HEIGHT); + } + + @Test + public void getFullHeightRatio_HomeScreen_ReturnsWrapContent() { + when(mState.getCurrentScreen()).thenReturn(HOME_SCREEN); + assertEquals(WRAP_CONTENT, mSheetContent.getFullHeightRatio(), DELTA); + } + + @Test + public void getHalfHeightRatio_HomeScreen_ReturnsDisabled() { + when(mState.getCurrentScreen()).thenReturn(HOME_SCREEN); + assertEquals(DISABLED, mSheetContent.getHalfHeightRatio(), DELTA); + } + + @Test + public void + getFullHeightRatio_ProfileScreenAboveThreshold_ReturnsBottomsheetHeightByContainerHeight() { + when(mState.getCurrentScreen()).thenReturn(AUTOFILL_PROFILE_SCREEN); + when(mState.getNumOfAutofillProfiles()).thenReturn(3); + assertEquals(0.4f, mSheetContent.getFullHeightRatio(), DELTA); + } + + @Test + public void getFullHeightRatio_ProfileScreenBelowThreshold_ReturnsWrapContent() { + when(mState.getCurrentScreen()).thenReturn(AUTOFILL_PROFILE_SCREEN); + when(mState.getNumOfAutofillProfiles()).thenReturn(2); + assertEquals(WRAP_CONTENT, mSheetContent.getFullHeightRatio(), DELTA); + } + + @Test + public void + getHalfHeightRatio_ProfileScreenAboveThreshold_ReturnsDesiredHeightByContainerHeight() { + when(mState.getCurrentScreen()).thenReturn(AUTOFILL_PROFILE_SCREEN); + when(mState.getNumOfAutofillProfiles()).thenReturn(3); + assertEquals(0.48f, mSheetContent.getHalfHeightRatio(), DELTA); + } + + @Test + public void getHalfHeightRatio_ProfileScreenBelowThreshold_ReturnsDisabled() { + when(mState.getCurrentScreen()).thenReturn(AUTOFILL_PROFILE_SCREEN); + when(mState.getNumOfAutofillProfiles()).thenReturn(2); + assertEquals(DISABLED, mSheetContent.getHalfHeightRatio(), DELTA); + } + + @Test + public void + getFullHeightRatio_CreditCardScreenAboveThreshold_ReturnsBottomsheetHeightByContainerHeight() { + when(mState.getCurrentScreen()).thenReturn(CREDIT_CARD_SCREEN); + when(mState.getNumOfCreditCards()).thenReturn(4); + assertEquals(0.4f, mSheetContent.getFullHeightRatio(), DELTA); + } + + @Test + public void getFullHeightRatio_CreditCardScreenBelowThreshold_ReturnsWrapContent() { + when(mState.getCurrentScreen()).thenReturn(CREDIT_CARD_SCREEN); + when(mState.getNumOfCreditCards()).thenReturn(3); + assertEquals(WRAP_CONTENT, mSheetContent.getFullHeightRatio(), DELTA); + } + + @Test + public void + getHalfHeightRatio_CreditCardScreenAboveThreshold_ReturnsDesiredHeightByContainerHeight() { + when(mState.getCurrentScreen()).thenReturn(CREDIT_CARD_SCREEN); + when(mState.getNumOfCreditCards()).thenReturn(4); + assertEquals(0.45f, mSheetContent.getHalfHeightRatio(), DELTA); + } + + @Test + public void getHalfHeightRatio_CreditCardScreenBelowThreshold_ReturnsDisabled() { + when(mState.getCurrentScreen()).thenReturn(CREDIT_CARD_SCREEN); + when(mState.getNumOfCreditCards()).thenReturn(3); + assertEquals(DISABLED, mSheetContent.getHalfHeightRatio(), DELTA); + } +}
diff --git a/chrome/browser/ui/ash/app_access_notifier.cc b/chrome/browser/ui/ash/app_access_notifier.cc index fdd55f0..e02800a 100644 --- a/chrome/browser/ui/ash/app_access_notifier.cc +++ b/chrome/browser/ui/ash/app_access_notifier.cc
@@ -184,15 +184,13 @@ auto launch_app = absl::nullopt; auto launch_settings = base::BindRepeating(&AppAccessNotifier::LaunchAppSettings, app_id); - ash::ModifyPrivacyIndicatorsNotification( - app_id, GetAppShortNameFromAppId(app_id), is_camera_used, - is_microphone_used, + + ash::UpdatePrivacyIndicators( + app_id, /*app_name=*/GetAppShortNameFromAppId(app_id), is_camera_used, + is_microphone_used, /*delegate=*/ base::MakeRefCounted<ash::PrivacyIndicatorsNotificationDelegate>( launch_app, launch_settings)); - ash::UpdatePrivacyIndicatorsView(app_id, is_camera_used, - is_microphone_used); - auto* registry_cache = GetActiveUserAppRegistryCache(); if (registry_cache) { base::UmaHistogramEnumeration(
diff --git a/chrome/browser/ui/ash/app_access_notifier_unittest.cc b/chrome/browser/ui/ash/app_access_notifier_unittest.cc index 569e62c..b4d099b 100644 --- a/chrome/browser/ui/ash/app_access_notifier_unittest.cc +++ b/chrome/browser/ui/ash/app_access_notifier_unittest.cc
@@ -11,6 +11,7 @@ #include "ash/public/cpp/ash_prefs.h" #include "ash/root_window_controller.h" #include "ash/shell.h" +#include "ash/system/privacy/privacy_indicators_controller.h" #include "ash/system/privacy/privacy_indicators_tray_item_view.h" #include "ash/system/status_area_widget.h" #include "ash/system/unified/unified_system_tray.h" @@ -32,6 +33,7 @@ #include "components/user_manager/user.h" #include "content/public/test/browser_task_environment.h" #include "testing/gtest/include/gtest/gtest.h" +#include "ui/compositor/scoped_animation_duration_scale_mode.h" #include "ui/display/test/display_manager_test_api.h" #include "ui/message_center/message_center.h" @@ -42,9 +44,10 @@ constexpr char kPrivacyIndicatorsLaunchSettingsHistogramName[] = "Ash.PrivacyIndicators.LaunchSettings"; -// Check the visibility of privacy indicators in all displays. +// Check the visibility of privacy indicators and their camera/microphone icons +// in all displays. void ExpectPrivacyIndicatorsVisible(bool visible) { - for (ash::RootWindowController* root_window_controller : + for (auto* root_window_controller : ash::Shell::Get()->GetAllRootWindowControllers()) { EXPECT_EQ(root_window_controller->GetStatusAreaWidget() ->unified_system_tray() @@ -54,9 +57,31 @@ } } -} // namespace +void ExpectPrivacyIndicatorsCameraIconVisible(bool visible) { + for (auto* root_window_controller : + ash::Shell::Get()->GetAllRootWindowControllers()) { + EXPECT_EQ(root_window_controller->GetStatusAreaWidget() + ->unified_system_tray() + ->privacy_indicators_view() + ->camera_icon() + ->GetVisible(), + visible); + } +} -const char kPrivacyIndicatorsNotificationIdPrefix[] = "privacy-indicators"; +void ExpectPrivacyIndicatorsMicrophoneIconVisible(bool visible) { + for (auto* root_window_controller : + ash::Shell::Get()->GetAllRootWindowControllers()) { + EXPECT_EQ(root_window_controller->GetStatusAreaWidget() + ->unified_system_tray() + ->privacy_indicators_view() + ->microphone_icon() + ->GetVisible(), + visible); + } +} + +} // namespace class TestAppAccessNotifier : public AppAccessNotifier { public: @@ -529,32 +554,41 @@ // or microphone. const std::string id1 = "test_app_id_1"; const std::string id2 = "test_app_id_2"; + const std::string notification_id1 = + ash::GetPrivacyIndicatorsNotificationId(id1); + const std::string notification_id2 = + ash::GetPrivacyIndicatorsNotificationId(id2); LaunchAppUsingCameraOrMicrophone(id1, "test_app_name", /*use_camera=*/false, /*use_microphone=*/true); LaunchAppUsingCameraOrMicrophone(id2, "test_app_name", /*use_camera=*/true, /*use_microphone=*/false); EXPECT_TRUE(message_center::MessageCenter::Get()->FindNotificationById( - kPrivacyIndicatorsNotificationIdPrefix + id1)); + notification_id1)); EXPECT_TRUE(message_center::MessageCenter::Get()->FindNotificationById( - kPrivacyIndicatorsNotificationIdPrefix + id2)); + notification_id2)); LaunchAppUsingCameraOrMicrophone(id1, "test_app_name", /*use_camera=*/false, /*use_microphone=*/false); LaunchAppUsingCameraOrMicrophone(id2, "test_app_name", /*use_camera=*/false, /*use_microphone=*/false); EXPECT_FALSE(message_center::MessageCenter::Get()->FindNotificationById( - kPrivacyIndicatorsNotificationIdPrefix + id1)); + notification_id1)); EXPECT_FALSE(message_center::MessageCenter::Get()->FindNotificationById( - kPrivacyIndicatorsNotificationIdPrefix + id2)); + notification_id2)); LaunchAppUsingCameraOrMicrophone(id1, "test_app_name", /*use_camera=*/true, /*use_microphone=*/true); EXPECT_TRUE(message_center::MessageCenter::Get()->FindNotificationById( - kPrivacyIndicatorsNotificationIdPrefix + id1)); + notification_id1)); } TEST_F(AppAccessNotifierPrivacyIndicatorTest, PrivacyIndicatorsVisibility) { + // Uses normal animation duration so that the icons would not be immediately + // hidden after the animation. + ui::ScopedAnimationDurationScaleMode animation_scale( + ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION); + // Make sure privacy indicators work on multiple displays. display::test::DisplayManagerTestApi(ash::Shell::Get()->display_manager()) .UpdateDisplay("800x800,801+0-800x800"); @@ -562,11 +596,14 @@ ExpectPrivacyIndicatorsVisible(/*visible=*/false); // Privacy indicators should show up if at least camera or microphone is being - // accessed. + // accessed. The icons should show up accordingly (only at the start of the + // animation). LaunchAppUsingCameraOrMicrophone("test_app_id", "test_app_name", /*use_camera=*/true, /*use_microphone=*/true); ExpectPrivacyIndicatorsVisible(/*visible=*/true); + ExpectPrivacyIndicatorsCameraIconVisible(/*visible=*/true); + ExpectPrivacyIndicatorsMicrophoneIconVisible(/*visible=*/true); LaunchAppUsingCameraOrMicrophone("test_app_id", "test_app_name", /*use_camera=*/false, @@ -577,11 +614,15 @@ /*use_camera=*/true, /*use_microphone=*/false); ExpectPrivacyIndicatorsVisible(/*visible=*/true); + ExpectPrivacyIndicatorsCameraIconVisible(/*visible=*/true); + ExpectPrivacyIndicatorsMicrophoneIconVisible(/*visible=*/false); LaunchAppUsingCameraOrMicrophone("test_app_id", "test_app_name", /*use_camera=*/false, /*use_microphone=*/true); ExpectPrivacyIndicatorsVisible(/*visible=*/true); + ExpectPrivacyIndicatorsCameraIconVisible(/*visible=*/false); + ExpectPrivacyIndicatorsMicrophoneIconVisible(/*visible=*/true); } TEST_F(AppAccessNotifierPrivacyIndicatorTest, RecordAppType) {
diff --git a/chrome/browser/ui/extensions/extension_action_view_controller_unittest.cc b/chrome/browser/ui/extensions/extension_action_view_controller_unittest.cc index 1130aea3..6acdbea 100644 --- a/chrome/browser/ui/extensions/extension_action_view_controller_unittest.cc +++ b/chrome/browser/ui/extensions/extension_action_view_controller_unittest.cc
@@ -44,6 +44,7 @@ #include "extensions/common/extension_features.h" #include "extensions/common/mojom/run_location.mojom-shared.h" #include "extensions/test/test_extension_dir.h" +#include "testing/gtest/include/gtest/gtest.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/models/image_model.h" #include "ui/gfx/image/image_skia_rep.h" @@ -888,17 +889,6 @@ EXPECT_EQ(GetHoverCardSiteAccessState(controllerC, web_contents), HoverCardState::SiteAccess::kExtensionRequestsAccess); - // Grant all extensions site access. Verify extension A hover card state is - // "does not want access" and extensions B and C is "all extensions allowed". - permissions_manager->UpdateUserSiteSetting( - url, UserSiteSetting::kGrantAllExtensions); - EXPECT_EQ(GetHoverCardSiteAccessState(controllerA, web_contents), - HoverCardState::SiteAccess::kExtensionDoesNotWantAccess); - EXPECT_EQ(GetHoverCardSiteAccessState(controllerB, web_contents), - HoverCardState::SiteAccess::kAllExtensionsAllowed); - EXPECT_EQ(GetHoverCardSiteAccessState(controllerC, web_contents), - HoverCardState::SiteAccess::kAllExtensionsAllowed); - // Block all extensions site access. Verify all extensions appear as "all // extensions blocked" (even though extension A never requested access). permissions_manager->UpdateUserSiteSetting( @@ -922,3 +912,80 @@ EXPECT_EQ(GetHoverCardSiteAccessState(controllerC, web_contents), HoverCardState::SiteAccess::kExtensionRequestsAccess); } + +class ExtensionActionViewControllerFeatureWithPermittedSitesUnitTest + : public ExtensionActionViewControllerFeatureUnitTest { + public: + ExtensionActionViewControllerFeatureWithPermittedSitesUnitTest() { + scoped_feature_list_.InitAndEnableFeature( + extensions_features::kExtensionsMenuAccessControlWithPermittedSites); + } + ~ExtensionActionViewControllerFeatureWithPermittedSitesUnitTest() override = + default; + + private: + base::test::ScopedFeatureList scoped_feature_list_; +}; + +// Tests hover card status after changing user site settings and site access. +TEST_F(ExtensionActionViewControllerFeatureWithPermittedSitesUnitTest, + GetHoverCardStatus) { + std::string url_string = "https://example.com/"; + auto extensionA = + CreateAndAddExtension("Extension A", extensions::ActionInfo::TYPE_ACTION); + auto extensionB = CreateAndAddExtensionWithGrantedHostPermissions( + "Extension B", extensions::ActionInfo::TYPE_ACTION, {url_string}); + auto extensionC = CreateAndAddExtensionWithGrantedHostPermissions( + "Extension c", extensions::ActionInfo::TYPE_ACTION, {url_string}); + + AddTab(browser(), GURL(url_string)); + content::WebContents* web_contents = GetActiveWebContents(); + ASSERT_TRUE(web_contents); + auto url = url::Origin::Create(web_contents->GetLastCommittedURL()); + + ExtensionActionViewController* const controllerA = + GetViewControllerForId(extensionA->id()); + ASSERT_TRUE(controllerA); + ExtensionActionViewController* const controllerB = + GetViewControllerForId(extensionB->id()); + ASSERT_TRUE(controllerB); + ExtensionActionViewController* const controllerC = + GetViewControllerForId(extensionC->id()); + ASSERT_TRUE(controllerC); + + // By default, user site setting is "customize by extension" and site access + // is granted to every extension that requests them. Thus, verify extension A + // hover card state is "does not want access" and the rest is "have access". + auto* permissions_manager = + extensions::PermissionsManager::Get(browser()->profile()); + ASSERT_EQ(permissions_manager->GetUserSiteSetting(url), + UserSiteSetting::kCustomizeByExtension); + EXPECT_EQ(GetHoverCardSiteAccessState(controllerA, web_contents), + HoverCardState::SiteAccess::kExtensionDoesNotWantAccess); + EXPECT_EQ(GetHoverCardSiteAccessState(controllerB, web_contents), + HoverCardState::SiteAccess::kExtensionHasAccess); + EXPECT_EQ(GetHoverCardSiteAccessState(controllerC, web_contents), + HoverCardState::SiteAccess::kExtensionHasAccess); + + // Withhold extension C host permissions. Verify only extension C changed + // hover card state to "requests access". + extensions::ScriptingPermissionsModifier(profile(), extensionC) + .SetWithholdHostPermissions(true); + EXPECT_EQ(GetHoverCardSiteAccessState(controllerA, web_contents), + HoverCardState::SiteAccess::kExtensionDoesNotWantAccess); + EXPECT_EQ(GetHoverCardSiteAccessState(controllerB, web_contents), + HoverCardState::SiteAccess::kExtensionHasAccess); + EXPECT_EQ(GetHoverCardSiteAccessState(controllerC, web_contents), + HoverCardState::SiteAccess::kExtensionRequestsAccess); + + // Grant all extensions site access. Verify extension A hover card state is + // "does not want access" and extensions B and C is "all extensions allowed". + permissions_manager->UpdateUserSiteSetting( + url, UserSiteSetting::kGrantAllExtensions); + EXPECT_EQ(GetHoverCardSiteAccessState(controllerA, web_contents), + HoverCardState::SiteAccess::kExtensionDoesNotWantAccess); + EXPECT_EQ(GetHoverCardSiteAccessState(controllerB, web_contents), + HoverCardState::SiteAccess::kAllExtensionsAllowed); + EXPECT_EQ(GetHoverCardSiteAccessState(controllerC, web_contents), + HoverCardState::SiteAccess::kAllExtensionsAllowed); +}
diff --git a/chrome/browser/ui/layout_constants.cc b/chrome/browser/ui/layout_constants.cc index 959034f..ff1c5e53 100644 --- a/chrome/browser/ui/layout_constants.cc +++ b/chrome/browser/ui/layout_constants.cc
@@ -20,8 +20,6 @@ kBookmarkBarAttachedVerticalMargin; case BOOKMARK_BAR_BUTTON_HEIGHT: return touch_ui ? 36 : 28; - case BOOKMARK_BAR_NTP_HEIGHT: - return touch_ui ? GetLayoutConstant(BOOKMARK_BAR_HEIGHT) : 39; case WEB_APP_MENU_BUTTON_SIZE: return 24; case WEB_APP_PAGE_ACTION_ICON_SIZE:
diff --git a/chrome/browser/ui/layout_constants.h b/chrome/browser/ui/layout_constants.h index 335c7da..e8a41e9 100644 --- a/chrome/browser/ui/layout_constants.h +++ b/chrome/browser/ui/layout_constants.h
@@ -18,22 +18,6 @@ // The height of a button within the Bookmarks Bar. BOOKMARK_BAR_BUTTON_HEIGHT, -#if BUILDFLAG(IS_MAC) - // This is a little smaller than the bookmarkbar height because of the visual - // overlap with the main toolbar. This height should not be used when - // computing the height of the toolbar. - BOOKMARK_BAR_HEIGHT_NO_OVERLAP, -#endif - - // The height of Bookmarks Bar, when visible in "New Tab Page" mode. - BOOKMARK_BAR_NTP_HEIGHT, - -#if BUILDFLAG(IS_MAC) - // The amount of space between the inner bookmark bar and the outer toolbar on - // new tab pages. - BOOKMARK_BAR_NTP_PADDING, -#endif - // The size of icons used in Download bubbles. // TODO(crbug/1296323): We should be sourcing the size of the file icon from // the layout
diff --git a/chrome/browser/ui/views/apps/app_window_desktop_window_tree_host_win.cc b/chrome/browser/ui/views/apps/app_window_desktop_window_tree_host_win.cc index 93067da..367e9184 100644 --- a/chrome/browser/ui/views/apps/app_window_desktop_window_tree_host_win.cc +++ b/chrome/browser/ui/views/apps/app_window_desktop_window_tree_host_win.cc
@@ -7,8 +7,8 @@ #include <windows.h> #include "base/win/windows_version.h" +#include "chrome/browser/ui/views/apps/app_window_frame_view_win.h" #include "chrome/browser/ui/views/apps/chrome_native_app_window_views_win.h" -#include "chrome/browser/ui/views/apps/glass_app_window_frame_view_win.h" #include "ui/base/theme_provider.h" #include "ui/display/win/dpi.h" #include "ui/gfx/geometry/dip_util.h" @@ -32,28 +32,29 @@ // The inset added below is only necessary for the native glass frame, i.e. // not for colored frames drawn by Chrome, or when DWM is disabled. // In fullscreen the frame is not visible. - if (!app_window_->glass_frame_view() || IsFullscreen()) { + if (!app_window_->frame_view() || IsFullscreen()) { return false; } - *insets = app_window_->glass_frame_view()->GetClientAreaInsets(monitor); + *insets = app_window_->frame_view()->GetClientAreaInsets(monitor); return true; } bool AppWindowDesktopWindowTreeHostWin::GetDwmFrameInsetsInPixels( gfx::Insets* insets) const { - // If there's no glass view we never need to change DWM frame insets. - if (!GetWidget()->client_view() || !app_window_->glass_frame_view() || - !DesktopWindowTreeHostWin::ShouldUseNativeFrame()) + // If there's no frame view we never need to change DWM frame insets. + if (!GetWidget()->client_view() || !app_window_->frame_view() || + !DesktopWindowTreeHostWin::ShouldUseNativeFrame()) { return false; + } if (GetWidget()->IsFullscreen()) { *insets = gfx::Insets(); } else { // If the opaque frame is visible, we use the default (zero) margins. // Otherwise, we need to figure out how to extend the glass in. - *insets = app_window_->glass_frame_view()->GetGlassInsets(); + *insets = app_window_->frame_view()->GetInsets(); // The DWM API's expect values in pixels. We need to convert from DIP to // pixels here. *insets = gfx::ToFlooredInsets(
diff --git a/chrome/browser/ui/views/apps/glass_app_window_frame_view_win.cc b/chrome/browser/ui/views/apps/app_window_frame_view_win.cc similarity index 69% rename from chrome/browser/ui/views/apps/glass_app_window_frame_view_win.cc rename to chrome/browser/ui/views/apps/app_window_frame_view_win.cc index 321bd4e..16730d4 100644 --- a/chrome/browser/ui/views/apps/glass_app_window_frame_view_win.cc +++ b/chrome/browser/ui/views/apps/app_window_frame_view_win.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/ui/views/apps/glass_app_window_frame_view_win.h" +#include "chrome/browser/ui/views/apps/app_window_frame_view_win.h" #include <windows.h> @@ -23,13 +23,12 @@ } // namespace -GlassAppWindowFrameViewWin::GlassAppWindowFrameViewWin(views::Widget* widget) +AppWindowFrameViewWin::AppWindowFrameViewWin(views::Widget* widget) : widget_(widget) {} -GlassAppWindowFrameViewWin::~GlassAppWindowFrameViewWin() { -} +AppWindowFrameViewWin::~AppWindowFrameViewWin() {} -gfx::Insets GlassAppWindowFrameViewWin::GetGlassInsets() const { +gfx::Insets AppWindowFrameViewWin::GetFrameInsets() const { int caption_height = display::win::ScreenWin::GetSystemMetricsInDIP(SM_CYSIZEFRAME) + display::win::ScreenWin::GetSystemMetricsInDIP(SM_CYCAPTION); @@ -37,30 +36,30 @@ return gfx::Insets::TLBR(caption_height, 0, 0, 0); } -gfx::Insets GlassAppWindowFrameViewWin::GetClientAreaInsets( - HMONITOR monitor) const { +gfx::Insets AppWindowFrameViewWin::GetClientAreaInsets(HMONITOR monitor) const { const int frame_thickness = ui::GetFrameThickness(monitor); return gfx::Insets::TLBR(0, frame_thickness, frame_thickness, frame_thickness); } -gfx::Rect GlassAppWindowFrameViewWin::GetBoundsForClientView() const { - if (widget_->IsFullscreen()) +gfx::Rect AppWindowFrameViewWin::GetBoundsForClientView() const { + if (widget_->IsFullscreen()) { return bounds(); + } - gfx::Insets insets = GetGlassInsets(); - return gfx::Rect(insets.left(), - insets.top(), + gfx::Insets insets = GetFrameInsets(); + return gfx::Rect(insets.left(), insets.top(), std::max(0, width() - insets.left() - insets.right()), std::max(0, height() - insets.top() - insets.bottom())); } -gfx::Rect GlassAppWindowFrameViewWin::GetWindowBoundsForClientBounds( +gfx::Rect AppWindowFrameViewWin::GetWindowBoundsForClientBounds( const gfx::Rect& client_bounds) const { - if (widget_->IsFullscreen()) + if (widget_->IsFullscreen()) { return bounds(); + } - gfx::Insets insets = GetGlassInsets(); + gfx::Insets insets = GetFrameInsets(); insets += GetClientAreaInsets( MonitorFromWindow(HWNDForView(this), MONITOR_DEFAULTTONEAREST)); gfx::Rect window_bounds( @@ -73,12 +72,14 @@ return window_bounds; } -int GlassAppWindowFrameViewWin::NonClientHitTest(const gfx::Point& point) { - if (widget_->IsFullscreen()) +int AppWindowFrameViewWin::NonClientHitTest(const gfx::Point& point) { + if (widget_->IsFullscreen()) { return HTCLIENT; + } - if (!bounds().Contains(point)) + if (!bounds().Contains(point)) { return HTNOWHERE; + } // Check the frame first, as we allow a small area overlapping the contents // to be used for resize handles. @@ -92,23 +93,25 @@ int frame_component = GetHTComponentForFrame( point, gfx::Insets(resize_border), kResizeAreaCornerSize - resize_border, kResizeAreaCornerSize - resize_border, can_ever_resize); - if (frame_component != HTNOWHERE) + if (frame_component != HTNOWHERE) { return frame_component; + } int client_component = widget_->client_view()->NonClientHitTest(point); - if (client_component != HTNOWHERE) + if (client_component != HTNOWHERE) { return client_component; + } // Caption is a safe default. return HTCAPTION; } -void GlassAppWindowFrameViewWin::GetWindowMask(const gfx::Size& size, - SkPath* window_mask) { +void AppWindowFrameViewWin::GetWindowMask(const gfx::Size& size, + SkPath* window_mask) { // We got nothing to say about no window mask. } -gfx::Size GlassAppWindowFrameViewWin::CalculatePreferredSize() const { +gfx::Size AppWindowFrameViewWin::CalculatePreferredSize() const { gfx::Size pref = widget_->client_view()->GetPreferredSize(); gfx::Rect bounds(0, 0, pref.width(), pref.height()); return widget_->non_client_view() @@ -116,27 +119,29 @@ .size(); } -gfx::Size GlassAppWindowFrameViewWin::GetMinimumSize() const { +gfx::Size AppWindowFrameViewWin::GetMinimumSize() const { gfx::Size min_size = widget_->client_view()->GetMinimumSize(); - gfx::Insets insets = GetGlassInsets(); + gfx::Insets insets = GetFrameInsets(); min_size.Enlarge(insets.left() + insets.right(), insets.top() + insets.bottom()); return min_size; } -gfx::Size GlassAppWindowFrameViewWin::GetMaximumSize() const { +gfx::Size AppWindowFrameViewWin::GetMaximumSize() const { gfx::Size max_size = widget_->client_view()->GetMaximumSize(); - gfx::Insets insets = GetGlassInsets(); - if (max_size.width()) + gfx::Insets insets = GetFrameInsets(); + if (max_size.width()) { max_size.Enlarge(insets.left() + insets.right(), 0); - if (max_size.height()) + } + if (max_size.height()) { max_size.Enlarge(0, insets.top() + insets.bottom()); + } return max_size; } -BEGIN_METADATA(GlassAppWindowFrameViewWin, views::NonClientFrameView) +BEGIN_METADATA(AppWindowFrameViewWin, views::NonClientFrameView) END_METADATA
diff --git a/chrome/browser/ui/views/apps/glass_app_window_frame_view_win.h b/chrome/browser/ui/views/apps/app_window_frame_view_win.h similarity index 64% rename from chrome/browser/ui/views/apps/glass_app_window_frame_view_win.h rename to chrome/browser/ui/views/apps/app_window_frame_view_win.h index 50299479..bd6c0be 100644 --- a/chrome/browser/ui/views/apps/glass_app_window_frame_view_win.h +++ b/chrome/browser/ui/views/apps/app_window_frame_view_win.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_UI_VIEWS_APPS_GLASS_APP_WINDOW_FRAME_VIEW_WIN_H_ -#define CHROME_BROWSER_UI_VIEWS_APPS_GLASS_APP_WINDOW_FRAME_VIEW_WIN_H_ +#ifndef CHROME_BROWSER_UI_VIEWS_APPS_APP_WINDOW_FRAME_VIEW_WIN_H_ +#define CHROME_BROWSER_UI_VIEWS_APPS_APP_WINDOW_FRAME_VIEW_WIN_H_ #include "base/memory/raw_ptr.h" #include "ui/base/metadata/metadata_header_macros.h" @@ -11,18 +11,17 @@ #include "ui/views/metadata/view_factory.h" #include "ui/views/window/non_client_view.h" -// A glass style app window frame view. -class GlassAppWindowFrameViewWin : public views::NonClientFrameView { +// A Windows app window frame view. +class AppWindowFrameViewWin : public views::NonClientFrameView { public: - METADATA_HEADER(GlassAppWindowFrameViewWin); - explicit GlassAppWindowFrameViewWin(views::Widget* widget); - GlassAppWindowFrameViewWin(const GlassAppWindowFrameViewWin&) = delete; - GlassAppWindowFrameViewWin& operator=(const GlassAppWindowFrameViewWin&) = - delete; - ~GlassAppWindowFrameViewWin() override; + METADATA_HEADER(AppWindowFrameViewWin); + explicit AppWindowFrameViewWin(views::Widget* widget); + AppWindowFrameViewWin(const AppWindowFrameViewWin&) = delete; + AppWindowFrameViewWin& operator=(const AppWindowFrameViewWin&) = delete; + ~AppWindowFrameViewWin() override; - // The insets to the client area due to the glass frame. - gfx::Insets GetGlassInsets() const; + // The insets to the client area due to the frame. + gfx::Insets GetFrameInsets() const; // Additional insets to the client area. |monitor| is the monitor this // window is on. Normally that would be determined from the HWND, but @@ -51,10 +50,10 @@ }; BEGIN_VIEW_BUILDER(/* no export */, - GlassAppWindowFrameViewWin, + AppWindowFrameViewWin, views::NonClientFrameView) END_VIEW_BUILDER -DEFINE_VIEW_BUILDER(/* no export */, GlassAppWindowFrameViewWin) +DEFINE_VIEW_BUILDER(/* no export */, AppWindowFrameViewWin) -#endif // CHROME_BROWSER_UI_VIEWS_APPS_GLASS_APP_WINDOW_FRAME_VIEW_WIN_H_ +#endif // CHROME_BROWSER_UI_VIEWS_APPS_APP_WINDOW_FRAME_VIEW_WIN_H_
diff --git a/chrome/browser/ui/views/apps/chrome_native_app_window_views_win.cc b/chrome/browser/ui/views/apps/chrome_native_app_window_views_win.cc index a6e9da0..4db5703 100644 --- a/chrome/browser/ui/views/apps/chrome_native_app_window_views_win.cc +++ b/chrome/browser/ui/views/apps/chrome_native_app_window_views_win.cc
@@ -11,7 +11,7 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/browser/shell_integration_win.h" #include "chrome/browser/ui/views/apps/app_window_desktop_native_widget_aura_win.h" -#include "chrome/browser/ui/views/apps/glass_app_window_frame_view_win.h" +#include "chrome/browser/ui/views/apps/app_window_frame_view_win.h" #include "chrome/browser/web_applications/extensions/web_app_extension_shortcut.h" #include "chrome/browser/web_applications/web_app_helpers.h" #include "chrome/common/chrome_switches.h" @@ -77,10 +77,9 @@ std::unique_ptr<views::NonClientFrameView> ChromeNativeAppWindowViewsWin::CreateStandardDesktopAppFrame() { - auto glass_frame_view = - std::make_unique<GlassAppWindowFrameViewWin>(widget()); - glass_frame_view_ = glass_frame_view.get(); - return glass_frame_view; + auto frame_view = std::make_unique<AppWindowFrameViewWin>(widget()); + frame_view_ = frame_view.get(); + return frame_view; } bool ChromeNativeAppWindowViewsWin::CanMinimize() const {
diff --git a/chrome/browser/ui/views/apps/chrome_native_app_window_views_win.h b/chrome/browser/ui/views/apps/chrome_native_app_window_views_win.h index f6c82a03..f35610de 100644 --- a/chrome/browser/ui/views/apps/chrome_native_app_window_views_win.h +++ b/chrome/browser/ui/views/apps/chrome_native_app_window_views_win.h
@@ -12,7 +12,7 @@ struct ShortcutInfo; } -class GlassAppWindowFrameViewWin; +class AppWindowFrameViewWin; // Windows-specific parts of the views-backed native shell window implementation // for packaged apps. @@ -26,9 +26,7 @@ ~ChromeNativeAppWindowViewsWin() override; - GlassAppWindowFrameViewWin* glass_frame_view() { - return glass_frame_view_; - } + AppWindowFrameViewWin* frame_view() { return frame_view_; } private: void OnShortcutInfoLoaded( @@ -53,7 +51,7 @@ // Populated if there is a standard desktop app frame, which provides special // information to the native widget implementation. This will be NULL if the // frame is a non-standard app frame created by CreateNonStandardAppFrame. - raw_ptr<GlassAppWindowFrameViewWin> glass_frame_view_ = nullptr; + raw_ptr<AppWindowFrameViewWin> frame_view_ = nullptr; // The Windows Application User Model ID identifying the app. std::wstring app_model_id_;
diff --git a/chrome/browser/ui/views/extensions/extensions_toolbar_controls_unittest.cc b/chrome/browser/ui/views/extensions/extensions_toolbar_controls_unittest.cc index d04f4e1..c464a99 100644 --- a/chrome/browser/ui/views/extensions/extensions_toolbar_controls_unittest.cc +++ b/chrome/browser/ui/views/extensions/extensions_toolbar_controls_unittest.cc
@@ -238,15 +238,6 @@ EXPECT_TRUE(IsRequestAccessButtonVisible()); auto* manager = extensions::PermissionsManager::Get(profile()); - { - // Request access button is not visible in permitted sites. - extensions::PermissionsManagerWaiter manager_waiter( - extensions::PermissionsManager::Get(profile())); - manager->AddUserPermittedSite(url_origin); - manager_waiter.WaitForUserPermissionsSettingsChange(); - WaitForAnimation(); - EXPECT_FALSE(IsRequestAccessButtonVisible()); - } { // Request access button is not visible in restricted sites. @@ -259,7 +250,7 @@ } { - // Request acesss button is visible if site is not permitted or restricted, + // Request acesss button is visible if site is not restricted, // and at least one extension is requesting access. extensions::PermissionsManagerWaiter manager_waiter( extensions::PermissionsManager::Get(profile())); @@ -309,3 +300,59 @@ EXPECT_EQ(permissions.GetSiteAccess(*extension, url), extensions::SitePermissionsHelper::SiteAccess::kOnClick); } + +class ExtensionsToolbarControlsWithPermittedSitesUnitTest + : public ExtensionsToolbarControlsUnitTest { + public: + ExtensionsToolbarControlsWithPermittedSitesUnitTest() { + std::vector<base::test::FeatureRef> enabled_features = { + extensions_features::kExtensionsMenuAccessControl, + extensions_features::kExtensionsMenuAccessControlWithPermittedSites}; + std::vector<base::test::FeatureRef> disabled_features; + feature_list_.InitWithFeatures(enabled_features, disabled_features); + } + ExtensionsToolbarControlsWithPermittedSitesUnitTest( + const ExtensionsToolbarControlsWithPermittedSitesUnitTest&) = delete; + const ExtensionsToolbarControlsWithPermittedSitesUnitTest& operator=( + const ExtensionsToolbarControlsWithPermittedSitesUnitTest&) = delete; + ~ExtensionsToolbarControlsWithPermittedSitesUnitTest() override = default; + + private: + base::test::ScopedFeatureList feature_list_; +}; + +// Test that request access button is visible based on the user site setting +// selected. +TEST_F(ExtensionsToolbarControlsWithPermittedSitesUnitTest, + RequestAccessButtonVisibilityOnPermittedSites) { + content::WebContentsTester* web_contents_tester = + AddWebContentsAndGetTester(); + const GURL url("http://www.url.com"); + auto url_origin = url::Origin::Create(url); + + // Install an extension and withhold permissions so request access button can + // be visible. + auto extension = + InstallExtensionWithHostPermissions("Extension", {"<all_urls>"}); + WithholdHostPermissions(extension.get()); + + web_contents_tester->NavigateAndCommit(url); + WaitForAnimation(); + + // A site has "customize by extensions" site setting by default, + ASSERT_EQ( + GetUserSiteSetting(url), + extensions::PermissionsManager::UserSiteSetting::kCustomizeByExtension); + EXPECT_TRUE(IsRequestAccessButtonVisible()); + + // Request access button is not visible in permitted sites. + auto* manager = extensions::PermissionsManager::Get(profile()); + extensions::PermissionsManagerWaiter waiter(manager); + manager->AddUserPermittedSite(url_origin); + waiter.WaitForUserPermissionsSettingsChange(); + WaitForAnimation(); + + // Request access button visibility is the same for other site settings, which + // is already tested, regardless of whether permitted sites are supported or + // not. +}
diff --git a/chrome/browser/ui/views/web_apps/web_app_integration_test_driver.cc b/chrome/browser/ui/views/web_apps/web_app_integration_test_driver.cc index 5e47e60..4ef9a04 100644 --- a/chrome/browser/ui/views/web_apps/web_app_integration_test_driver.cc +++ b/chrome/browser/ui/views/web_apps/web_app_integration_test_driver.cc
@@ -483,10 +483,12 @@ for (auto it = browser_list->begin_browsers_ordered_by_activation(); it != browser_list->end_browsers_ordered_by_activation(); ++it) { Browser* browser = *it; - if (browser->profile() != profile) + if (browser->profile() != profile) { continue; - if (AppBrowserController::IsForWebApp(browser, app_id)) + } + if (AppBrowserController::IsForWebApp(browser, app_id)) { return browser; + } } return nullptr; } @@ -527,17 +529,20 @@ // WebAppInstallManagerObserver void OnWebAppUninstalled(const AppId& app_id) override { - if (app_id != app_id_) + if (app_id != app_id_) { return; + } uninstall_complete_ = true; MaybeFinishWaiting(); } void MaybeFinishWaiting() { - if (!uninstall_complete_) + if (!uninstall_complete_) { return; - if (AreAppBrowsersOpen(profile_, app_id_)) + } + if (AreAppBrowsersOpen(profile_, app_id_)) { return; + } BrowserList::RemoveObserver(this); observation_.Reset(); @@ -587,8 +592,9 @@ for (int size_px : sizes_px) { SkColor icon_pixel_color = IconManagerReadAppIconPixel(icon_manager, app_id, size_px, 0, 0); - if (icon_pixel_color != expected_icon_pixel_color) + if (icon_pixel_color != expected_icon_pixel_color) { return false; + } } return true; } @@ -866,12 +872,14 @@ in_tear_down_ = true; LOG(INFO) << "TearDownOnMainThread: Start."; observation_.Reset(); - if (delegate_->IsSyncTest()) + if (delegate_->IsSyncTest()) { SyncTurnOff(); + } for (auto* profile : GetAllProfiles()) { auto* provider = GetProviderForProfile(profile); - if (!provider) + if (!provider) { continue; + } std::vector<AppId> app_ids = provider->registrar_unsafe().GetAppIds(); for (auto& app_id : app_ids) { LOG(INFO) << "TearDownOnMainThread: Uninstalling " << app_id << "."; @@ -883,8 +891,9 @@ << " was already removed."; continue; } - if (app->IsPolicyInstalledApp()) + if (app->IsPolicyInstalledApp()) { UninstallPolicyAppById(app_id); + } if (provider->registrar_unsafe().IsInstalled(app_id)) { DCHECK(app->CanUserUninstallWebApp()); UninstallCompleteWaiter uninstall_waiter(profile, app_id); @@ -959,8 +968,9 @@ } void WebAppIntegrationTestDriver::AwaitManifestUpdate(Site site) { - if (!BeforeStateChangeAction(__FUNCTION__)) + if (!BeforeStateChangeAction(__FUNCTION__)) { return; + } AppId app_id = GetAppIdBySiteMode(site); ASSERT_TRUE(provider()->registrar_unsafe().GetAppById(app_id)); if (!previous_manifest_updates_.contains(app_id)) { @@ -993,8 +1003,9 @@ } void WebAppIntegrationTestDriver::CloseCustomToolbar() { - if (!BeforeStateChangeAction(__FUNCTION__)) + if (!BeforeStateChangeAction(__FUNCTION__)) { return; + } ASSERT_TRUE(app_browser()); BrowserView* app_view = BrowserView::GetBrowserViewForBrowser(app_browser()); content::WebContents* web_contents = app_view->GetActiveWebContents(); @@ -1035,37 +1046,42 @@ } void WebAppIntegrationTestDriver::DisableRunOnOsLogin(Site site) { - if (!BeforeStateChangeAction(__FUNCTION__)) + if (!BeforeStateChangeAction(__FUNCTION__)) { return; + } SetRunOnOsLoginMode(site, apps::RunOnOsLoginMode::kNotRun); AfterStateChangeAction(); } void WebAppIntegrationTestDriver::EnableRunOnOsLogin(Site site) { - if (!BeforeStateChangeAction(__FUNCTION__)) + if (!BeforeStateChangeAction(__FUNCTION__)) { return; + } SetRunOnOsLoginMode(site, apps::RunOnOsLoginMode::kWindowed); AfterStateChangeAction(); } void WebAppIntegrationTestDriver::DisableFileHandling(Site site) { - if (!BeforeStateChangeAction(__FUNCTION__)) + if (!BeforeStateChangeAction(__FUNCTION__)) { return; + } SetFileHandlingEnabled(site, false); AfterStateChangeAction(); } void WebAppIntegrationTestDriver::EnableFileHandling(Site site) { - if (!BeforeStateChangeAction(__FUNCTION__)) + if (!BeforeStateChangeAction(__FUNCTION__)) { return; + } SetFileHandlingEnabled(site, true); AfterStateChangeAction(); } void WebAppIntegrationTestDriver::CreateShortcut(Site site, WindowOptions options) { - if (!BeforeStateChangeAction(__FUNCTION__)) + if (!BeforeStateChangeAction(__FUNCTION__)) { return; + } MaybeNavigateTabbedBrowserInScope(site); bool open_in_window = options == WindowOptions::kWindowed; chrome::SetAutoAcceptWebAppDialogForTesting( @@ -1087,8 +1103,9 @@ } void WebAppIntegrationTestDriver::InstallMenuOption(InstallableSite site) { - if (!BeforeStateChangeAction(__FUNCTION__)) + if (!BeforeStateChangeAction(__FUNCTION__)) { return; + } MaybeNavigateTabbedBrowserInScope(InstallableSiteToSite(site)); BrowserAddedWaiter browser_added_waiter; WebAppTestInstallWithOsHooksObserver install_observer(profile()); @@ -1112,8 +1129,9 @@ #if !BUILDFLAG(IS_CHROMEOS) void WebAppIntegrationTestDriver::InstallLocally(Site site) { - if (!BeforeStateChangeAction(__FUNCTION__)) + if (!BeforeStateChangeAction(__FUNCTION__)) { return; + } AppId app_id = GetAppIdBySiteMode(site); ASSERT_TRUE(provider()->registrar_unsafe().GetAppById(app_id)) << "No app installed for site: " << static_cast<int>(site); @@ -1137,8 +1155,9 @@ #endif void WebAppIntegrationTestDriver::InstallOmniboxIcon(InstallableSite site) { - if (!BeforeStateChangeAction(__FUNCTION__)) + if (!BeforeStateChangeAction(__FUNCTION__)) { return; + } MaybeNavigateTabbedBrowserInScope(InstallableSiteToSite(site)); auto* app_banner_manager = @@ -1178,8 +1197,9 @@ ShortcutOptions shortcut, WindowOptions window, InstallMode mode) { - if (!BeforeStateChangeAction(__FUNCTION__)) + if (!BeforeStateChangeAction(__FUNCTION__)) { return; + } base::Value container = base::Value(window == WindowOptions::kWindowed ? kDefaultLaunchContainerWindowValue : kDefaultLaunchContainerTabValue); @@ -1243,8 +1263,9 @@ } void WebAppIntegrationTestDriver::EnableWindowControlsOverlay(Site site) { - if (!BeforeStateChangeAction(__FUNCTION__)) + if (!BeforeStateChangeAction(__FUNCTION__)) { return; + } ASSERT_TRUE(app_browser()); BrowserView* app_view = BrowserView::GetBrowserViewForBrowser(app_browser()); @@ -1261,8 +1282,9 @@ } void WebAppIntegrationTestDriver::DisableWindowControlsOverlay(Site site) { - if (!BeforeStateChangeAction(__FUNCTION__)) + if (!BeforeStateChangeAction(__FUNCTION__)) { return; + } ASSERT_TRUE(app_browser()); BrowserView* app_view = BrowserView::GetBrowserViewForBrowser(app_browser()); @@ -1279,30 +1301,34 @@ } void WebAppIntegrationTestDriver::ApplyRunOnOsLoginPolicyAllowed(Site site) { - if (!BeforeStateChangeAction(__FUNCTION__)) + if (!BeforeStateChangeAction(__FUNCTION__)) { return; + } ApplyRunOnOsLoginPolicy(site, kAllowed); AfterStateChangeAction(); } void WebAppIntegrationTestDriver::ApplyRunOnOsLoginPolicyBlocked(Site site) { - if (!BeforeStateChangeAction(__FUNCTION__)) + if (!BeforeStateChangeAction(__FUNCTION__)) { return; + } ApplyRunOnOsLoginPolicy(site, kBlocked); AfterStateChangeAction(); } void WebAppIntegrationTestDriver::ApplyRunOnOsLoginPolicyRunWindowed( Site site) { - if (!BeforeStateChangeAction(__FUNCTION__)) + if (!BeforeStateChangeAction(__FUNCTION__)) { return; + } ApplyRunOnOsLoginPolicy(site, kRunWindowed); AfterStateChangeAction(); } void WebAppIntegrationTestDriver::RemoveRunOnOsLoginPolicy(Site site) { - if (!BeforeStateChangeAction(__FUNCTION__)) + if (!BeforeStateChangeAction(__FUNCTION__)) { return; + } GURL url = GetUrlForSite(site); { ScopedListPrefUpdate update_list(profile()->GetPrefs(), @@ -1406,8 +1432,9 @@ } void WebAppIntegrationTestDriver::LaunchFromChromeApps(Site site) { - if (!BeforeStateChangeAction(__FUNCTION__)) + if (!BeforeStateChangeAction(__FUNCTION__)) { return; + } AppId app_id = GetAppIdBySiteMode(site); ASSERT_TRUE(provider()->registrar_unsafe().GetAppById(app_id)) << "No app installed for site: " << static_cast<int>(site); @@ -1428,8 +1455,9 @@ } void WebAppIntegrationTestDriver::LaunchFromLaunchIcon(Site site) { - if (!BeforeStateChangeAction(__FUNCTION__)) + if (!BeforeStateChangeAction(__FUNCTION__)) { return; + } base::AutoReset<bool> intent_picker_bubble_scope = IntentPickerBubbleView::SetAutoAcceptIntentPickerBubbleForTesting(); AppId app_id = GetAppIdBySiteMode(site); @@ -1463,8 +1491,9 @@ } void WebAppIntegrationTestDriver::LaunchFromMenuOption(Site site) { - if (!BeforeStateChangeAction(__FUNCTION__)) + if (!BeforeStateChangeAction(__FUNCTION__)) { return; + } AppId app_id = GetAppIdBySiteMode(site); ASSERT_TRUE(provider()->registrar_unsafe().GetAppById(app_id)) << "No app installed for site: " << static_cast<int>(site); @@ -1485,8 +1514,9 @@ void WebAppIntegrationTestDriver::LaunchFromPlatformShortcut(Site site) { #if !BUILDFLAG(IS_CHROMEOS) - if (!BeforeStateChangeAction(__FUNCTION__)) + if (!BeforeStateChangeAction(__FUNCTION__)) { return; + } AppId app_id = GetAppIdBySiteMode(site); ASSERT_TRUE(provider()->registrar_unsafe().GetAppById(app_id)) << "No app installed for site: " << static_cast<int>(site); @@ -1533,8 +1563,9 @@ #if BUILDFLAG(IS_MAC) void WebAppIntegrationTestDriver::LaunchFromAppShimFallback(Site site) { - if (!BeforeStateChangeAction(__FUNCTION__)) + if (!BeforeStateChangeAction(__FUNCTION__)) { return; + } AppId app_id = GetAppIdBySiteMode(site); ASSERT_TRUE(provider()->registrar_unsafe().GetAppById(app_id)) @@ -1574,8 +1605,9 @@ void WebAppIntegrationTestDriver::OpenAppSettingsFromAppMenu(Site site) { #if !BUILDFLAG(IS_CHROMEOS) - if (!BeforeStateChangeAction(__FUNCTION__)) + if (!BeforeStateChangeAction(__FUNCTION__)) { return; + } Browser* app_browser = GetAppBrowserForSite(site); ASSERT_TRUE(app_browser); @@ -1607,8 +1639,9 @@ void WebAppIntegrationTestDriver::OpenAppSettingsFromChromeApps(Site site) { #if !BUILDFLAG(IS_CHROMEOS) - if (!BeforeStateChangeAction(__FUNCTION__)) + if (!BeforeStateChangeAction(__FUNCTION__)) { return; + } AppId app_id = GetAppIdBySiteMode(site); ASSERT_TRUE(provider()->registrar_unsafe().GetAppById(app_id)) << "No app installed for site: " << static_cast<int>(site); @@ -1635,8 +1668,9 @@ void WebAppIntegrationTestDriver::CreateShortcutsFromList(Site site) { #if !BUILDFLAG(IS_CHROMEOS) - if (!BeforeStateChangeAction(__FUNCTION__)) + if (!BeforeStateChangeAction(__FUNCTION__)) { return; + } AppId app_id = GetAppIdBySiteMode(site); ASSERT_TRUE(provider()->registrar_unsafe().GetAppById(app_id)) << "No app installed for site: " << static_cast<int>(site); @@ -1669,10 +1703,12 @@ } void WebAppIntegrationTestDriver::DeletePlatformShortcut(Site site) { - if (!before_state_change_action_state_ && !after_state_change_action_state_) + if (!before_state_change_action_state_ && !after_state_change_action_state_) { return; - if (!BeforeStateChangeAction(__FUNCTION__)) + } + if (!BeforeStateChangeAction(__FUNCTION__)) { return; + } base::ScopedAllowBlockingForTesting allow_blocking; AppId app_id = GetAppIdBySiteMode(site); std::string app_name = provider()->registrar_unsafe().GetAppShortName(app_id); @@ -1715,13 +1751,15 @@ base::FilePath WebAppIntegrationTestDriver::GetResourceFile( base::FilePath::StringPieceType relative_path) { base::FilePath base_dir; - if (!base::PathService::Get(chrome::DIR_TEST_DATA, &base_dir)) + if (!base::PathService::Get(chrome::DIR_TEST_DATA, &base_dir)) { return base::FilePath(); + } base::FilePath full_path = base_dir.Append(relative_path); { base::ScopedAllowBlockingForTesting scoped_allow_blocking; - if (!PathExists(full_path)) + if (!PathExists(full_path)) { return base::FilePath(); + } } return full_path; } @@ -1757,15 +1795,17 @@ } void WebAppIntegrationTestDriver::NavigateBrowser(Site site) { - if (!BeforeStateChangeAction(__FUNCTION__)) + if (!BeforeStateChangeAction(__FUNCTION__)) { return; + } NavigateTabbedBrowserToSite(GetInScopeURL(site), NavigationMode::kCurrentTab); AfterStateChangeAction(); } void WebAppIntegrationTestDriver::NavigatePwa(Site pwa, Site to) { - if (!BeforeStateChangeAction(__FUNCTION__)) + if (!BeforeStateChangeAction(__FUNCTION__)) { return; + } app_browser_ = GetAppBrowserForSite(pwa); content::TestNavigationObserver url_observer(GetUrlForSite(to)); @@ -1777,8 +1817,9 @@ } void WebAppIntegrationTestDriver::NavigateNotfoundUrl() { - if (!BeforeStateChangeAction(__FUNCTION__)) + if (!BeforeStateChangeAction(__FUNCTION__)) { return; + } NavigateTabbedBrowserToSite( delegate_->EmbeddedTestServer()->GetURL("/non-existant/index.html"), NavigationMode::kCurrentTab); @@ -1788,8 +1829,9 @@ void WebAppIntegrationTestDriver::ManifestUpdateIcon( Site site, UpdateDialogResponse response) { - if (!BeforeStateChangeAction(__FUNCTION__)) + if (!BeforeStateChangeAction(__FUNCTION__)) { return; + } ASSERT_EQ(Site::kStandalone, site) << "Only site mode of 'Standalone' is supported"; @@ -1818,8 +1860,9 @@ Site site, Title title, UpdateDialogResponse response) { - if (!BeforeStateChangeAction(__FUNCTION__)) + if (!BeforeStateChangeAction(__FUNCTION__)) { return; + } ASSERT_EQ(Site::kStandalone, site) << "Only site mode of 'Standalone' is supported"; ASSERT_EQ(Title::kStandaloneUpdated, title) @@ -1840,8 +1883,9 @@ void WebAppIntegrationTestDriver::ManifestUpdateDisplay(Site site, Display display) { - if (!BeforeStateChangeAction(__FUNCTION__)) + if (!BeforeStateChangeAction(__FUNCTION__)) { return; + } std::string relative_url_path = GetSiteConfiguration(site).relative_url; std::string manifest_url_param = @@ -1854,8 +1898,9 @@ } void WebAppIntegrationTestDriver::ManifestUpdateScopeTo(Site app, Site scope) { - if (!BeforeStateChangeAction(__FUNCTION__)) + if (!BeforeStateChangeAction(__FUNCTION__)) { return; + } // The `scope_mode` would be changing the scope set in the manifest file. For // simplicity, right now only Standalone is supported, so that is just // hardcoded in manifest_scope_Standalone.json, which is specified in the URL. @@ -1868,8 +1913,9 @@ } void WebAppIntegrationTestDriver::OpenInChrome() { - if (!BeforeStateChangeAction(__FUNCTION__)) + if (!BeforeStateChangeAction(__FUNCTION__)) { return; + } ASSERT_TRUE(IsBrowserOpen(app_browser())) << "No current app browser."; AppId app_id = app_browser()->app_controller()->app_id(); GURL app_url = GetCurrentTab(app_browser())->GetURL(); @@ -1883,8 +1929,9 @@ } void WebAppIntegrationTestDriver::SetOpenInTab(Site site) { - if (!BeforeStateChangeAction(__FUNCTION__)) + if (!BeforeStateChangeAction(__FUNCTION__)) { return; + } AppId app_id = GetAppIdBySiteMode(site); ASSERT_TRUE(provider()->registrar_unsafe().GetAppById(app_id)) << "No app installed for site: " << static_cast<int>(site); @@ -1904,8 +1951,9 @@ } void WebAppIntegrationTestDriver::SetOpenInWindow(Site site) { - if (!BeforeStateChangeAction(__FUNCTION__)) + if (!BeforeStateChangeAction(__FUNCTION__)) { return; + } AppId app_id = GetAppIdBySiteMode(site); ASSERT_TRUE(provider()->registrar_unsafe().GetAppById(app_id)) << "No app installed for site: " << static_cast<int>(site); @@ -1939,8 +1987,9 @@ } void WebAppIntegrationTestDriver::SwitchProfileClients(ProfileClient client) { - if (!BeforeStateChangeAction(__FUNCTION__)) + if (!BeforeStateChangeAction(__FUNCTION__)) { return; + } DCHECK(active_profile_); active_profile_ = delegate_->GetProfileClient(client); DCHECK(active_profile_) @@ -1951,8 +2000,9 @@ void WebAppIntegrationTestDriver::SwitchActiveProfile( ProfileName profile_name) { - if (!BeforeStateChangeAction(__FUNCTION__)) + if (!BeforeStateChangeAction(__FUNCTION__)) { return; + } const char* profile_name_str = nullptr; switch (profile_name) { case ProfileName::kDefault: @@ -1978,22 +2028,25 @@ } void WebAppIntegrationTestDriver::SyncTurnOff() { - if (!BeforeStateChangeAction(__FUNCTION__)) + if (!BeforeStateChangeAction(__FUNCTION__)) { return; + } delegate_->SyncTurnOff(); AfterStateChangeAction(); } void WebAppIntegrationTestDriver::SyncTurnOn() { - if (!BeforeStateChangeAction(__FUNCTION__)) + if (!BeforeStateChangeAction(__FUNCTION__)) { return; + } delegate_->SyncTurnOn(); AfterStateChangeAction(); } void WebAppIntegrationTestDriver::UninstallFromList(Site site) { - if (!BeforeStateChangeAction(__FUNCTION__)) + if (!BeforeStateChangeAction(__FUNCTION__)) { return; + } AppId app_id = GetAppIdBySiteMode(site); ASSERT_TRUE(provider()->registrar_unsafe().GetAppById(app_id)) << "No app installed for site: " << static_cast<int>(site); @@ -2040,8 +2093,9 @@ void WebAppIntegrationTestDriver::UninstallFromAppSettings(Site site) { #if !BUILDFLAG(IS_CHROMEOS) - if (!BeforeStateChangeAction(__FUNCTION__)) + if (!BeforeStateChangeAction(__FUNCTION__)) { return; + } AppId app_id = GetAppIdBySiteMode(site); ASSERT_TRUE(provider()->registrar_unsafe().GetAppById(app_id)) << "No app installed for site: " << static_cast<int>(site); @@ -2077,8 +2131,9 @@ } void WebAppIntegrationTestDriver::UninstallFromMenu(Site site) { - if (!BeforeStateChangeAction(__FUNCTION__)) + if (!BeforeStateChangeAction(__FUNCTION__)) { return; + } AppId app_id = GetAppIdBySiteMode(site); ASSERT_TRUE(provider()->registrar_unsafe().GetAppById(app_id)) << "No app installed for site: " << static_cast<int>(site); @@ -2111,8 +2166,9 @@ } void WebAppIntegrationTestDriver::UninstallPolicyApp(Site site) { - if (!BeforeStateChangeAction(__FUNCTION__)) + if (!BeforeStateChangeAction(__FUNCTION__)) { return; + } GURL url = GetUrlForSite(site); auto policy_app = GetAppBySiteMode(before_state_change_action_state_.get(), profile(), site); @@ -2131,8 +2187,9 @@ // so this will listen for the removal of the policy install source. provider()->install_finalizer().SetRemoveManagementTypeCallbackForTesting( base::BindLambdaForTesting([&](const AppId& app_id) { - if (policy_app->id == app_id) + if (policy_app->id == app_id) { run_loop.Quit(); + } })); { ScopedListPrefUpdate update(profile()->GetPrefs(), @@ -2147,16 +2204,18 @@ const WebApp* app = provider()->registrar_unsafe().GetAppById(policy_app->id); // If the app was fully uninstalled, wait for the change to propagate through // App Service. - if (app == nullptr) + if (app == nullptr) { uninstall_waiter.Wait(); + } site_remember_deny_open_file_.erase(site); AfterStateChangeAction(); } void WebAppIntegrationTestDriver::UninstallFromOs(Site site) { #if BUILDFLAG(IS_WIN) - if (!BeforeStateChangeAction(__FUNCTION__)) + if (!BeforeStateChangeAction(__FUNCTION__)) { return; + } AppId app_id = GetAppIdBySiteMode(site); ASSERT_TRUE(provider()->registrar_unsafe().GetAppById(app_id)) << "No app installed for site: " << static_cast<int>(site); @@ -2182,8 +2241,9 @@ #if BUILDFLAG(IS_MAC) void WebAppIntegrationTestDriver::CorruptAppShim(Site site) { - if (!BeforeStateChangeAction(__FUNCTION__)) + if (!BeforeStateChangeAction(__FUNCTION__)) { return; + } base::ScopedAllowBlockingForTesting allow_blocking; AppId app_id = GetAppIdBySiteMode(site); std::string app_name = GetSiteConfiguration(site).app_name; @@ -2199,8 +2259,9 @@ #endif void WebAppIntegrationTestDriver::CheckAppListEmpty() { - if (!BeforeStateCheckAction(__FUNCTION__)) + if (!BeforeStateCheckAction(__FUNCTION__)) { return; + } absl::optional<ProfileState> state = GetStateForProfile(after_state_change_action_state_.get(), profile()); ASSERT_TRUE(state.has_value()); @@ -2244,8 +2305,9 @@ } void WebAppIntegrationTestDriver::CheckAppInListNotLocallyInstalled(Site site) { - if (!BeforeStateCheckAction(__FUNCTION__)) + if (!BeforeStateCheckAction(__FUNCTION__)) { return; + } // Note: This is a partially supported action. absl::optional<AppState> app_state = GetAppBySiteMode(after_state_change_action_state_.get(), profile(), site); @@ -2255,8 +2317,9 @@ } void WebAppIntegrationTestDriver::CheckAppInListTabbed(Site site) { - if (!BeforeStateCheckAction(__FUNCTION__)) + if (!BeforeStateCheckAction(__FUNCTION__)) { return; + } // Note: This is a partially supported action. absl::optional<AppState> app_state = GetAppBySiteMode(after_state_change_action_state_.get(), profile(), site); @@ -2266,8 +2329,9 @@ } void WebAppIntegrationTestDriver::CheckAppInListWindowed(Site site) { - if (!BeforeStateCheckAction(__FUNCTION__)) + if (!BeforeStateCheckAction(__FUNCTION__)) { return; + } // Note: This is a partially supported action. absl::optional<AppState> app_state = GetAppBySiteMode(after_state_change_action_state_.get(), profile(), site); @@ -2277,8 +2341,9 @@ } void WebAppIntegrationTestDriver::CheckAppNavigation(Site site) { - if (!BeforeStateCheckAction(__FUNCTION__)) + if (!BeforeStateCheckAction(__FUNCTION__)) { return; + } ASSERT_TRUE(app_browser()); GURL url = app_browser()->tab_strip_model()->GetActiveWebContents()->GetVisibleURL(); @@ -2287,8 +2352,9 @@ } void WebAppIntegrationTestDriver::CheckAppNavigationIsStartUrl() { - if (!BeforeStateCheckAction(__FUNCTION__)) + if (!BeforeStateCheckAction(__FUNCTION__)) { return; + } ASSERT_FALSE(active_app_id_.empty()); ASSERT_TRUE(app_browser()); GURL url = @@ -2298,8 +2364,9 @@ } void WebAppIntegrationTestDriver::CheckBrowserNavigation(Site site) { - if (!BeforeStateCheckAction(__FUNCTION__)) + if (!BeforeStateCheckAction(__FUNCTION__)) { return; + } ASSERT_TRUE(browser()); GURL url = browser()->tab_strip_model()->GetActiveWebContents()->GetURL(); EXPECT_EQ(url, GetUrlForSite(site)); @@ -2309,8 +2376,9 @@ void WebAppIntegrationTestDriver::CheckBrowserNavigationIsAppSettings( Site site) { #if !BUILDFLAG(IS_CHROMEOS) - if (!BeforeStateCheckAction(__FUNCTION__)) + if (!BeforeStateCheckAction(__FUNCTION__)) { return; + } AppId app_id = GetAppIdBySiteMode(site); ASSERT_TRUE(provider()->registrar_unsafe().GetAppById(app_id)) << "No app installed for site: " << static_cast<int>(site); @@ -2326,8 +2394,9 @@ } void WebAppIntegrationTestDriver::CheckAppNotInList(Site site) { - if (!BeforeStateCheckAction(__FUNCTION__)) + if (!BeforeStateCheckAction(__FUNCTION__)) { return; + } absl::optional<AppState> app_state = GetAppBySiteMode(after_state_change_action_state_.get(), profile(), site); EXPECT_FALSE(app_state.has_value()); @@ -2335,8 +2404,9 @@ } void WebAppIntegrationTestDriver::CheckPlatformShortcutAndIcon(Site site) { - if (!BeforeStateCheckAction(__FUNCTION__)) + if (!BeforeStateCheckAction(__FUNCTION__)) { return; + } absl::optional<AppState> app_state = GetAppBySiteMode(after_state_change_action_state_.get(), profile(), site); ASSERT_TRUE(app_state); @@ -2347,10 +2417,12 @@ void WebAppIntegrationTestDriver::CheckPlatformShortcutNotExists(Site site) { // This is to handle if the check happens at the very beginning of the test, // when no web app is installed (or any other action has happened yet). - if (!before_state_change_action_state_ && !after_state_change_action_state_) + if (!before_state_change_action_state_ && !after_state_change_action_state_) { return; - if (!BeforeStateCheckAction(__FUNCTION__)) + } + if (!BeforeStateCheckAction(__FUNCTION__)) { return; + } absl::optional<AppState> app_state = GetAppBySiteMode(after_state_change_action_state_.get(), profile(), site); if (!app_state) { @@ -2372,8 +2444,9 @@ } void WebAppIntegrationTestDriver::CheckAppIcon(Site site, Color color) { - if (!BeforeStateCheckAction(__FUNCTION__)) + if (!BeforeStateCheckAction(__FUNCTION__)) { return; + } absl::optional<AppState> app_state = GetAppBySiteMode(after_state_change_action_state_.get(), profile(), site); ASSERT_TRUE(app_state); @@ -2430,8 +2503,9 @@ } void WebAppIntegrationTestDriver::CheckAppTitle(Site site, Title title) { - if (!BeforeStateCheckAction(__FUNCTION__)) + if (!BeforeStateCheckAction(__FUNCTION__)) { return; + } absl::optional<AppState> app_state = GetAppBySiteMode(after_state_change_action_state_.get(), profile(), site); ASSERT_TRUE(app_state); @@ -2539,8 +2613,9 @@ void WebAppIntegrationTestDriver::CheckInstallIconShown() { // Currently this function does not support tests that check install icons // for sites that have a manifest but no service worker. - if (!BeforeStateCheckAction(__FUNCTION__)) + if (!BeforeStateCheckAction(__FUNCTION__)) { return; + } auto* app_banner_manager = webapps::TestAppBannerManagerDesktop::FromWebContents( GetCurrentTab(browser())); @@ -2552,8 +2627,9 @@ void WebAppIntegrationTestDriver::CheckInstallIconNotShown() { // Currently this function does not support tests that check install icons // for sites that have a manifest but no service worker. - if (!BeforeStateCheckAction(__FUNCTION__)) + if (!BeforeStateCheckAction(__FUNCTION__)) { return; + } auto* app_banner_manager = webapps::TestAppBannerManagerDesktop::FromWebContents( GetCurrentTab(browser())); @@ -2563,8 +2639,9 @@ } void WebAppIntegrationTestDriver::CheckLaunchIconShown() { - if (!BeforeStateCheckAction(__FUNCTION__)) + if (!BeforeStateCheckAction(__FUNCTION__)) { return; + } absl::optional<BrowserState> browser_state = GetStateForBrowser( after_state_change_action_state_.get(), profile(), browser()); ASSERT_TRUE(browser_state.has_value()); @@ -2573,8 +2650,9 @@ } void WebAppIntegrationTestDriver::CheckLaunchIconNotShown() { - if (!BeforeStateCheckAction(__FUNCTION__)) + if (!BeforeStateCheckAction(__FUNCTION__)) { return; + } absl::optional<BrowserState> browser_state = GetStateForBrowser( after_state_change_action_state_.get(), profile(), browser()); ASSERT_TRUE(browser_state.has_value()); @@ -2583,8 +2661,9 @@ } void WebAppIntegrationTestDriver::CheckTabCreated() { - if (!BeforeStateCheckAction(__FUNCTION__)) + if (!BeforeStateCheckAction(__FUNCTION__)) { return; + } DCHECK(before_state_change_action_state_); absl::optional<BrowserState> most_recent_browser_state = GetStateForBrowser( after_state_change_action_state_.get(), profile(), browser()); @@ -2611,8 +2690,9 @@ } void WebAppIntegrationTestDriver::CheckTabNotCreated() { - if (!BeforeStateCheckAction(__FUNCTION__)) + if (!BeforeStateCheckAction(__FUNCTION__)) { return; + } DCHECK(before_state_change_action_state_); absl::optional<BrowserState> most_recent_browser_state = GetStateForBrowser( after_state_change_action_state_.get(), profile(), browser()); @@ -2626,8 +2706,9 @@ } void WebAppIntegrationTestDriver::CheckCustomToolbar() { - if (!BeforeStateCheckAction(__FUNCTION__)) + if (!BeforeStateCheckAction(__FUNCTION__)) { return; + } ASSERT_TRUE(app_browser()); EXPECT_TRUE(app_browser()->app_controller()->ShouldShowCustomTabBar()); BrowserView* app_view = BrowserView::GetBrowserViewForBrowser(app_browser()); @@ -2639,8 +2720,9 @@ } void WebAppIntegrationTestDriver::CheckNoToolbar() { - if (!BeforeStateCheckAction(__FUNCTION__)) + if (!BeforeStateCheckAction(__FUNCTION__)) { return; + } ASSERT_TRUE(app_browser()); EXPECT_FALSE(app_browser()->app_controller()->ShouldShowCustomTabBar()); BrowserView* app_view = BrowserView::GetBrowserViewForBrowser(app_browser()); @@ -2649,8 +2731,9 @@ } void WebAppIntegrationTestDriver::CheckRunOnOsLoginEnabled(Site site) { - if (!BeforeStateCheckAction(__FUNCTION__)) + if (!BeforeStateCheckAction(__FUNCTION__)) { return; + } absl::optional<AppState> app_state = GetAppBySiteMode(after_state_change_action_state_.get(), profile(), site); ASSERT_TRUE(app_state); @@ -2674,8 +2757,9 @@ } void WebAppIntegrationTestDriver::CheckRunOnOsLoginDisabled(Site site) { - if (!BeforeStateCheckAction(__FUNCTION__)) + if (!BeforeStateCheckAction(__FUNCTION__)) { return; + } absl::optional<AppState> app_state = GetAppBySiteMode(after_state_change_action_state_.get(), profile(), site); ASSERT_TRUE(app_state); @@ -2691,8 +2775,9 @@ Site site, FileExtension file_extension) { #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) - if (!BeforeStateCheckAction(__FUNCTION__)) + if (!BeforeStateCheckAction(__FUNCTION__)) { return; + } ASSERT_TRUE(IsFileHandledBySite(site, file_extension)); AfterStateCheckAction(); #endif @@ -2702,8 +2787,9 @@ Site site, FileExtension file_extension) { #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) - if (!BeforeStateCheckAction(__FUNCTION__)) + if (!BeforeStateCheckAction(__FUNCTION__)) { return; + } ASSERT_FALSE(IsFileHandledBySite(site, file_extension)); AfterStateCheckAction(); #endif @@ -2711,8 +2797,9 @@ void WebAppIntegrationTestDriver::CheckUserCannotSetRunOnOsLogin(Site site) { #if !BUILDFLAG(IS_CHROMEOS) - if (!BeforeStateCheckAction(__FUNCTION__)) + if (!BeforeStateCheckAction(__FUNCTION__)) { return; + } absl::optional<AppState> app_state = GetAppBySiteMode(after_state_change_action_state_.get(), profile(), site); ASSERT_TRUE(app_state); @@ -2742,8 +2829,9 @@ void WebAppIntegrationTestDriver::CheckUserDisplayModeInternal( mojom::UserDisplayMode user_display_mode) { - if (!BeforeStateCheckAction(__FUNCTION__)) + if (!BeforeStateCheckAction(__FUNCTION__)) { return; + } absl::optional<AppState> app_state = GetStateForAppId( after_state_change_action_state_.get(), profile(), active_app_id_); ASSERT_TRUE(app_state.has_value()); @@ -2752,8 +2840,9 @@ } void WebAppIntegrationTestDriver::CheckWindowClosed() { - if (!BeforeStateCheckAction(__FUNCTION__)) + if (!BeforeStateCheckAction(__FUNCTION__)) { return; + } DCHECK(before_state_change_action_state_); absl::optional<ProfileState> after_action_profile = GetStateForProfile(after_state_change_action_state_.get(), profile()); @@ -2767,8 +2856,9 @@ } void WebAppIntegrationTestDriver::CheckWindowCreated() { - if (!BeforeStateCheckAction(__FUNCTION__)) + if (!BeforeStateCheckAction(__FUNCTION__)) { return; + } DCHECK(before_state_change_action_state_); absl::optional<ProfileState> after_action_profile = GetStateForProfile(after_state_change_action_state_.get(), profile()); @@ -2785,8 +2875,9 @@ } void WebAppIntegrationTestDriver::CheckWindowNotCreated() { - if (!BeforeStateCheckAction(__FUNCTION__)) + if (!BeforeStateCheckAction(__FUNCTION__)) { return; + } DCHECK(before_state_change_action_state_); absl::optional<ProfileState> after_action_profile = GetStateForProfile(after_state_change_action_state_.get(), profile()); @@ -2805,8 +2896,9 @@ void WebAppIntegrationTestDriver::CheckWindowControlsOverlayToggle( Site site, IsShown is_shown) { - if (!BeforeStateCheckAction(__FUNCTION__)) + if (!BeforeStateCheckAction(__FUNCTION__)) { return; + } ASSERT_TRUE(app_browser()); EXPECT_TRUE(AppBrowserController::IsForWebApp(app_browser(), GetAppIdBySiteMode(site))); @@ -2826,8 +2918,9 @@ void WebAppIntegrationTestDriver::CheckWindowControlsOverlay(Site site, IsOn is_on) { - if (!BeforeStateCheckAction(__FUNCTION__)) + if (!BeforeStateCheckAction(__FUNCTION__)) { return; + } ASSERT_TRUE(app_browser()); EXPECT_TRUE(AppBrowserController::IsForWebApp(app_browser(), GetAppIdBySiteMode(site))); @@ -2837,8 +2930,9 @@ } void WebAppIntegrationTestDriver::CheckWindowDisplayMinimal() { - if (!BeforeStateCheckAction(__FUNCTION__)) + if (!BeforeStateCheckAction(__FUNCTION__)) { return; + } DCHECK(app_browser()); web_app::AppBrowserController* app_controller = app_browser()->app_controller(); @@ -2891,8 +2985,9 @@ } void WebAppIntegrationTestDriver::CheckWindowDisplayStandalone() { - if (!BeforeStateCheckAction(__FUNCTION__)) + if (!BeforeStateCheckAction(__FUNCTION__)) { return; + } DCHECK(app_browser()); web_app::AppBrowserController* app_controller = @@ -2989,16 +3084,18 @@ // state. This is great, except for the manifest update edge case, which can // happen asynchronously outside of actions. In this case, re-grab the // snapshot after the update. - if (executing_action_level_ == 0 && after_state_change_action_state_) + if (executing_action_level_ == 0 && after_state_change_action_state_) { after_state_change_action_state_ = ConstructStateSnapshot(); + } } } bool WebAppIntegrationTestDriver::BeforeStateChangeAction( const char* function) { DCHECK(!base::StartsWith(function, "Check")); - if (testing::Test::HasFatalFailure() && !in_tear_down_) + if (testing::Test::HasFatalFailure() && !in_tear_down_) { return false; + } LOG(INFO) << "BeforeStateChangeAction: " << std::string(executing_action_level_, ' ') << function; ++executing_action_level_; @@ -3021,8 +3118,9 @@ std::map<AppId, size_t> open_browsers_per_app; for (auto* profile : GetAllProfiles()) { auto* provider = GetProviderForProfile(profile); - if (!provider) + if (!provider) { continue; + } std::vector<AppId> app_ids = provider->registrar_unsafe().GetAppIds(); for (auto& app_id : app_ids) { // Wait for any shims to finish connecting. @@ -3042,8 +3140,9 @@ } } for (const auto& [app_id, open_browsers] : open_browsers_per_app) { - if (open_browsers != 0) + if (open_browsers != 0) { continue; + } std::string app_name = provider()->registrar_unsafe().GetAppShortName(app_id); base::FilePath app_path = GetShortcutPath( @@ -3052,8 +3151,9 @@ WaitForShimToQuitForTesting(app_path, app_id); } #endif - if (delegate_->IsSyncTest()) + if (delegate_->IsSyncTest()) { delegate_->AwaitWebAppQuiescence(); + } FlushShortcutTasks(); provider()->command_manager().AwaitAllCommandsCompleteForTesting(); AwaitManifestSystemIdle(); @@ -3073,8 +3173,9 @@ bool WebAppIntegrationTestDriver::BeforeStateCheckAction(const char* function) { DCHECK(base::StartsWith(function, "Check")); - if (testing::Test::HasFatalFailure() && !in_tear_down_) + if (testing::Test::HasFatalFailure() && !in_tear_down_) { return false; + } ++executing_action_level_; provider()->command_manager().AwaitAllCommandsCompleteForTesting(); LOG(INFO) << "BeforeStateCheckAction: " @@ -3086,14 +3187,16 @@ void WebAppIntegrationTestDriver::AfterStateCheckAction() { DCHECK(executing_action_level_ > 0); --executing_action_level_; - if (!after_state_change_action_state_) + if (!after_state_change_action_state_) { return; + } DCHECK_EQ(*after_state_change_action_state_, *ConstructStateSnapshot()); } void WebAppIntegrationTestDriver::AwaitManifestSystemIdle() { - if (!is_performing_manifest_update_) + if (!is_performing_manifest_update_) { return; + } // Wait till pending manifest update processes have finished loading the page // to start the manifest update. @@ -3197,8 +3300,9 @@ launch_icon_shown = intent_picker_view()->GetVisible(); } AppId app_id; - if (AppBrowserController::IsWebApp(browser)) + if (AppBrowserController::IsWebApp(browser)) { app_id = browser->app_controller()->app_id(); + } browser_state.emplace( browser, BrowserState(browser, tab_state_map, active_tab, app_id, @@ -3231,11 +3335,11 @@ IsShortcutAndIconCreated(profile, registrar.GetAppShortName(app_id), app_id)); #if !BUILDFLAG(IS_CHROMEOS) - if (registrar.IsLocallyInstalled(app_id)) { - CheckAppSettingsAppState(profile->GetOriginalProfile(), state); - } + if (registrar.IsLocallyInstalled(app_id)) { + CheckAppSettingsAppState(profile->GetOriginalProfile(), state); + } #endif - app_state.emplace(app_id, state); + app_state.emplace(app_id, state); } } @@ -3321,8 +3425,9 @@ // so this will listen for the removal of the policy install source. provider()->install_finalizer().SetRemoveManagementTypeCallbackForTesting( base::BindLambdaForTesting([&](const AppId& app_id) { - if (id == app_id) + if (id == app_id) { run_loop.Quit(); + } })); const WebApp* web_app = provider()->registrar_unsafe().GetAppById(id); @@ -3350,10 +3455,12 @@ const WebApp* app = provider()->registrar_unsafe().GetAppById(id); // If the app was fully uninstalled, wait for the change to propagate through // App Service. - if (app == nullptr) + if (app == nullptr) { app_registration_waiter.Await(); - if (app == nullptr && active_app_id_ == id) + } + if (app == nullptr && active_app_id_ == id) { active_app_id_.clear(); + } } void WebAppIntegrationTestDriver::ForceUpdateManifestContents( @@ -3411,11 +3518,13 @@ auto profile_state = GetStateForProfile(state, profile()); DCHECK(profile_state); for (const auto& browser_state_pair : profile_state->browsers) { - if (browser_state_pair.second.app_id == app_state->id) + if (browser_state_pair.second.app_id == app_state->id) { return browser_state_pair.second.browser; + } } - if (!launch_if_not_open) + if (!launch_if_not_open) { return nullptr; + } Browser* browser = LaunchWebAppBrowserAndWait(profile(), app_state->id); provider()->manifest_update_manager().ResetManifestThrottleForTesting( GetAppIdBySiteMode(site)); @@ -3635,8 +3744,9 @@ } Profile* WebAppIntegrationTestDriver::profile() { - if (!active_profile_) + if (!active_profile_) { active_profile_ = delegate_->GetDefaultProfile(); + } return active_profile_; }
diff --git a/chrome/browser/ui/web_applications/web_app_browsertest.cc b/chrome/browser/ui/web_applications/web_app_browsertest.cc index 6760434..04c902e0 100644 --- a/chrome/browser/ui/web_applications/web_app_browsertest.cc +++ b/chrome/browser/ui/web_applications/web_app_browsertest.cc
@@ -58,10 +58,12 @@ #include "chrome/browser/ui/web_applications/web_app_menu_model.h" #include "chrome/browser/ui/web_applications/web_app_ui_utils.h" #include "chrome/browser/ui/window_sizer/window_sizer.h" +#include "chrome/browser/web_applications/commands/run_on_os_login_command.h" #include "chrome/browser/web_applications/external_install_options.h" #include "chrome/browser/web_applications/mojom/user_display_mode.mojom.h" #include "chrome/browser/web_applications/os_integration/os_integration_test_override.h" #include "chrome/browser/web_applications/os_integration/web_app_shortcut.h" +#include "chrome/browser/web_applications/test/web_app_install_test_utils.h" #include "chrome/browser/web_applications/test/web_app_test_observers.h" #include "chrome/browser/web_applications/test/web_app_test_utils.h" #include "chrome/browser/web_applications/web_app.h" @@ -1583,7 +1585,41 @@ provider->registrar_unsafe().GetAppShortName(app_id)); EXPECT_FALSE(base::PathExists(desktop_shortcut_path)); #endif -} // namespace web_app +} + +IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, RunOnOsLoginMetrics) { + os_hooks_suppress_.reset(); + GURL pwa_url("https://test-app.com"); + + base::ScopedAllowBlockingForTesting allow_blocking; + + std::unique_ptr<OsIntegrationTestOverride::BlockingRegistration> + registration = OsIntegrationTestOverride::OverrideForTesting(); + + auto* provider = WebAppProvider::GetForTest(profile()); + const AppId& app_id = InstallPWA(pwa_url); + + ASSERT_TRUE(provider->registrar_unsafe().IsInstalled(app_id)); + + base::HistogramTester tester; + base::RunLoop run_loop; + provider->scheduler().SetRunOnOsLoginMode( + app_id, RunOnOsLoginMode::kWindowed, base::BindLambdaForTesting([&]() { + EXPECT_THAT( + tester.GetAllSamples("WebApp.RunOnOsLogin.Registration.Result"), + BucketsAre(base::Bucket(true, 1))); + run_loop.Quit(); + })); + run_loop.Run(); + EXPECT_TRUE(GetOsIntegrationTestOverride()->IsRunOnOsLoginEnabled( + profile(), app_id, provider->registrar_unsafe().GetAppShortName(app_id))); + + test::UninstallAllWebApps(profile()); + EXPECT_FALSE(GetOsIntegrationTestOverride()->IsRunOnOsLoginEnabled( + profile(), app_id, provider->registrar_unsafe().GetAppShortName(app_id))); + EXPECT_THAT(tester.GetAllSamples("WebApp.RunOnOsLogin.Unregistration.Result"), + BucketsAre(base::Bucket(true, 1))); +} #endif // Tests that reparenting the last browser tab doesn't close the browser window.
diff --git a/chrome/browser/ui/webui/history_clusters/history_clusters_handler.cc b/chrome/browser/ui/webui/history_clusters/history_clusters_handler.cc index fe58ec21f..38894cc 100644 --- a/chrome/browser/ui/webui/history_clusters/history_clusters_handler.cc +++ b/chrome/browser/ui/webui/history_clusters/history_clusters_handler.cc
@@ -28,13 +28,13 @@ #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_commands.h" #include "chrome/browser/ui/browser_finder.h" -#include "chrome/browser/ui/webui/history_clusters/history_cluster_type_utils.h" #include "chrome/common/pref_names.h" #include "components/history/core/browser/history_service.h" #include "components/history/core/browser/history_types.h" #include "components/history_clusters/core/cluster_metrics_utils.h" #include "components/history_clusters/core/config.h" #include "components/history_clusters/core/features.h" +#include "components/history_clusters/core/history_cluster_type_utils.h" #include "components/history_clusters/core/history_clusters_prefs.h" #include "components/history_clusters/ui/query_clusters_state.h" #include "components/image_service/image_service.h" @@ -144,8 +144,10 @@ bool can_load_more, bool is_continuation) { std::vector<mojom::ClusterPtr> cluster_mojoms; + const TemplateURLService* template_url_service = + TemplateURLServiceFactory::GetForProfile(profile); for (const auto& cluster : clusters_batch) { - auto cluster_mojom = ClusterToMojom(profile, cluster); + auto cluster_mojom = ClusterToMojom(template_url_service, cluster); cluster_mojoms.emplace_back(std::move(cluster_mojom)); }
diff --git a/chrome/browser/ui/webui/settings/ash/device_section.cc b/chrome/browser/ui/webui/settings/ash/device_section.cc index 4ebc91a7..1cc87e5 100644 --- a/chrome/browser/ui/webui/settings/ash/device_section.cc +++ b/chrome/browser/ui/webui/settings/ash/device_section.cc
@@ -834,6 +834,12 @@ {"audioDeviceUsbLabel", IDS_SETTINGS_AUDIO_DEVICE_USB_LABEL}, {"audioInputDeviceTitle", IDS_SETTINGS_AUDIO_INPUT_DEVICE_TITLE}, {"audioInputGainTitle", IDS_SETTINGS_AUDIO_INPUT_GAIN_TITLE}, + {"audioInputMuteButtonAriaLabelMuted", + IDS_SETTINGS_AUDIO_INPUT_MUTE_BUTTON_ARIA_LABEL_MUTED}, + {"audioInputMuteButtonAriaLabelMutedByHardwareSwitch", + IDS_SETTINGS_AUDIO_INPUT_MUTE_BUTTON_ARIA_LABEL_MUTED_BY_HARDWARE_SWITCH}, + {"audioInputMuteButtonAriaLabelNotMuted", + IDS_SETTINGS_AUDIO_INPUT_MUTE_BUTTON_ARIA_LABEL_NOT_MUTED}, {"audioInputNoiseCancellationTitle", IDS_SETTINGS_AUDIO_INPUT_NOISE_CANCELLATION_TITLE}, {"audioInputTitle", IDS_SETTINGS_AUDIO_INPUT_TITLE}, @@ -842,6 +848,10 @@ IDS_SETTINGS_AUDIO_MUTED_EXTERNALLY_TOOLTIP}, {"audioOutputDeviceTitle", IDS_SETTINGS_AUDIO_OUTPUT_DEVICE_TITLE}, {"audioOutputTitle", IDS_SETTINGS_AUDIO_OUTPUT_TITLE}, + {"audioOutputMuteButtonAriaLabelMuted", + IDS_SETTINGS_AUDIO_OUTPUT_MUTE_BUTTON_ARIA_LABEL_MUTED}, + {"audioOutputMuteButtonAriaLabelNotMuted", + IDS_SETTINGS_AUDIO_OUTPUT_MUTE_BUTTON_ARIA_LABEL_NOT_MUTED}, {"audioTitle", IDS_SETTINGS_AUDIO_TITLE}, {"audioToggleToMuteTooltip", IDS_SETTINGS_AUDIO_TOGGLE_TO_MUTE_TOOLTIP}, {"audioToggleToUnmuteTooltip",
diff --git a/chrome/browser/usb/usb_chooser_context_unittest.cc b/chrome/browser/usb/usb_chooser_context_unittest.cc index 1a62387..8d0479e 100644 --- a/chrome/browser/usb/usb_chooser_context_unittest.cc +++ b/chrome/browser/usb/usb_chooser_context_unittest.cc
@@ -6,12 +6,12 @@ #include "base/containers/flat_map.h" #include "base/functional/callback_helpers.h" -#include "base/json/json_reader.h" #include "base/no_destructor.h" #include "base/run_loop.h" #include "base/strings/utf_string_conversions.h" #include "base/test/bind.h" #include "base/test/test_future.h" +#include "base/test/values_test_util.h" #include "base/values.h" #include "build/chromeos_buildflags.h" #include "chrome/browser/content_settings/host_content_settings_map_factory.h" @@ -493,7 +493,7 @@ prefs->SetManagedPref(prefs::kManagedDefaultWebUsbGuardSetting, std::make_unique<base::Value>(CONTENT_SETTING_BLOCK)); prefs->SetManagedPref(prefs::kManagedWebUsbAskForUrls, - base::JSONReader::ReadDeprecated(R"( + base::test::ParseJsonList(R"( [ "https://foo.origin" ] )")); @@ -525,7 +525,7 @@ auto* prefs = profile()->GetTestingPrefService(); prefs->SetManagedPref(prefs::kManagedWebUsbBlockedForUrls, - base::JSONReader::ReadDeprecated(R"( + base::test::ParseJsonList(R"( [ "https://foo.origin" ] )")); @@ -618,8 +618,8 @@ ExpectNoPermissions(store, *specific_device_info); - profile()->GetPrefs()->Set(prefs::kManagedWebUsbAllowDevicesForUrls, - *base::JSONReader::ReadDeprecated(kPolicySetting)); + profile()->GetPrefs()->SetList(prefs::kManagedWebUsbAllowDevicesForUrls, + base::test::ParseJsonList(kPolicySetting)); ExpectCorrectPermissions(store, kValidOrigins, kInvalidOrigins, *specific_device_info); @@ -640,8 +640,8 @@ ExpectNoPermissions(store, *vendor_related_device_info); - profile()->GetPrefs()->Set(prefs::kManagedWebUsbAllowDevicesForUrls, - *base::JSONReader::ReadDeprecated(kPolicySetting)); + profile()->GetPrefs()->SetList(prefs::kManagedWebUsbAllowDevicesForUrls, + base::test::ParseJsonList(kPolicySetting)); ExpectCorrectPermissions(store, kValidOrigins, kInvalidOrigins, *vendor_related_device_info); @@ -661,8 +661,8 @@ ExpectNoPermissions(store, *unrelated_device_info); - profile()->GetPrefs()->Set(prefs::kManagedWebUsbAllowDevicesForUrls, - *base::JSONReader::ReadDeprecated(kPolicySetting)); + profile()->GetPrefs()->SetList(prefs::kManagedWebUsbAllowDevicesForUrls, + base::test::ParseJsonList(kPolicySetting)); EXPECT_TRUE(store->HasDevicePermission(kCoolOrigin, *unrelated_device_info)); for (const auto& origin_url : PolicyOrigins()) { @@ -706,8 +706,8 @@ EXPECT_FALSE(store->HasDevicePermission(kCoolOrigin, *specific_device_info)); EXPECT_FALSE(store->HasDevicePermission(kCoolOrigin, *unrelated_device_info)); - profile()->GetPrefs()->Set(prefs::kManagedWebUsbAllowDevicesForUrls, - *base::JSONReader::ReadDeprecated(kPolicySetting)); + profile()->GetPrefs()->SetList(prefs::kManagedWebUsbAllowDevicesForUrls, + base::test::ParseJsonList(kPolicySetting)); EXPECT_TRUE( store->HasDevicePermission(kProductVendorOrigin, *specific_device_info)); @@ -753,9 +753,8 @@ ExpectNoPermissions(user_store, *specific_device_info); ExpectNoPermissions(signin_store, *specific_device_info); - user_profile->GetPrefs()->Set( - prefs::kManagedWebUsbAllowDevicesForUrls, - *base::JSONReader::ReadDeprecated(kPolicySetting)); + user_profile->GetPrefs()->SetList(prefs::kManagedWebUsbAllowDevicesForUrls, + base::test::ParseJsonList(kPolicySetting)); ExpectCorrectPermissions(user_store, kValidOrigins, kInvalidOrigins, *specific_device_info); @@ -780,9 +779,9 @@ ExpectNoPermissions(user_store, *specific_device_info); ExpectNoPermissions(signin_store, *specific_device_info); - signin_profile->GetPrefs()->Set( + signin_profile->GetPrefs()->SetList( prefs::kManagedWebUsbAllowDevicesForUrls, - *base::JSONReader::ReadDeprecated(kPolicySetting)); + base::test::ParseJsonList(kPolicySetting)); ExpectNoPermissions(user_store, *specific_device_info); ExpectCorrectPermissions(signin_store, kValidOrigins, kInvalidOrigins, @@ -829,8 +828,8 @@ TEST_F(UsbChooserContextTest, GetGrantedObjectsWithOnlyPolicyAllowedDevices) { auto* store = GetChooserContext(profile()); - profile()->GetPrefs()->Set(prefs::kManagedWebUsbAllowDevicesForUrls, - *base::JSONReader::ReadDeprecated(kPolicySetting)); + profile()->GetPrefs()->SetList(prefs::kManagedWebUsbAllowDevicesForUrls, + base::test::ParseJsonList(kPolicySetting)); const auto kVendorOrigin = url::Origin::Create(GURL(kVendorUrl)); auto objects = store->GetGrantedObjects(kVendorOrigin); @@ -847,8 +846,8 @@ TEST_F(UsbChooserContextTest, GetGrantedObjectsWithUserAndPolicyAllowedDevices) { - profile()->GetPrefs()->Set(prefs::kManagedWebUsbAllowDevicesForUrls, - *base::JSONReader::ReadDeprecated(kPolicySetting)); + profile()->GetPrefs()->SetList(prefs::kManagedWebUsbAllowDevicesForUrls, + base::test::ParseJsonList(kPolicySetting)); UsbDeviceInfoPtr persistent_device_info = device_manager_.CreateAndAddDevice(1000, 1, "Google", "Gizmo", "123ABC"); @@ -895,8 +894,8 @@ TEST_F(UsbChooserContextTest, GetGrantedObjectsWithUserGrantedDeviceAllowedBySpecificDevicePolicy) { - profile()->GetPrefs()->Set(prefs::kManagedWebUsbAllowDevicesForUrls, - *base::JSONReader::ReadDeprecated(kPolicySetting)); + profile()->GetPrefs()->SetList(prefs::kManagedWebUsbAllowDevicesForUrls, + base::test::ParseJsonList(kPolicySetting)); UsbDeviceInfoPtr persistent_device_info = device_manager_.CreateAndAddDevice( 6353, 5678, "Google", "Gizmo", "123ABC"); @@ -927,8 +926,8 @@ 6353, 1000, "Vendor", "Product", "123ABC"); auto* store = GetChooserContext(profile()); - profile()->GetPrefs()->Set(prefs::kManagedWebUsbAllowDevicesForUrls, - *base::JSONReader::ReadDeprecated(kPolicySetting)); + profile()->GetPrefs()->SetList(prefs::kManagedWebUsbAllowDevicesForUrls, + base::test::ParseJsonList(kPolicySetting)); const auto kVendorOrigin = url::Origin::Create(GURL(kVendorUrl)); store->GrantDevicePermission(kVendorOrigin, *persistent_device_info); @@ -953,8 +952,8 @@ 1123, 5813, "Some", "Product", "123ABC"); auto* store = GetChooserContext(profile()); - profile()->GetPrefs()->Set(prefs::kManagedWebUsbAllowDevicesForUrls, - *base::JSONReader::ReadDeprecated(kPolicySetting)); + profile()->GetPrefs()->SetList(prefs::kManagedWebUsbAllowDevicesForUrls, + base::test::ParseJsonList(kPolicySetting)); const auto kAnyDeviceOrigin = url::Origin::Create(GURL(kAnyDeviceUrl)); store->GrantDevicePermission(kAnyDeviceOrigin, *persistent_device_info); @@ -976,8 +975,8 @@ TEST_F(UsbChooserContextTest, GetAllGrantedObjectsWithOnlyPolicyAllowedDevices) { auto* store = GetChooserContext(profile()); - profile()->GetPrefs()->Set(prefs::kManagedWebUsbAllowDevicesForUrls, - *base::JSONReader::ReadDeprecated(kPolicySetting)); + profile()->GetPrefs()->SetList(prefs::kManagedWebUsbAllowDevicesForUrls, + base::test::ParseJsonList(kPolicySetting)); auto objects = store->GetAllGrantedObjects(); ASSERT_EQ(objects.size(), 4u); @@ -1017,8 +1016,8 @@ TEST_F(UsbChooserContextTest, GetAllGrantedObjectsWithUserAndPolicyAllowedDevices) { - profile()->GetPrefs()->Set(prefs::kManagedWebUsbAllowDevicesForUrls, - *base::JSONReader::ReadDeprecated(kPolicySetting)); + profile()->GetPrefs()->SetList(prefs::kManagedWebUsbAllowDevicesForUrls, + base::test::ParseJsonList(kPolicySetting)); const GURL kGoogleUrl("https://www.google.com"); const auto kGoogleOrigin = url::Origin::Create(kGoogleUrl); @@ -1094,8 +1093,8 @@ TEST_F(UsbChooserContextTest, GetAllGrantedObjectsWithSpecificPolicyAndUserGrantedDevice) { auto* store = GetChooserContext(profile()); - profile()->GetPrefs()->Set(prefs::kManagedWebUsbAllowDevicesForUrls, - *base::JSONReader::ReadDeprecated(kPolicySetting)); + profile()->GetPrefs()->SetList(prefs::kManagedWebUsbAllowDevicesForUrls, + base::test::ParseJsonList(kPolicySetting)); UsbDeviceInfoPtr persistent_device_info = device_manager_.CreateAndAddDevice( 6353, 5678, "Specific", "Product", "123ABC"); @@ -1154,8 +1153,8 @@ 6353, 1000, "Vendor", "Product", "123ABC"); auto* store = GetChooserContext(profile()); - profile()->GetPrefs()->Set(prefs::kManagedWebUsbAllowDevicesForUrls, - *base::JSONReader::ReadDeprecated(kPolicySetting)); + profile()->GetPrefs()->SetList(prefs::kManagedWebUsbAllowDevicesForUrls, + base::test::ParseJsonList(kPolicySetting)); EXPECT_CALL(*mock_permission_observers_[profile()], OnObjectPermissionChanged( @@ -1207,8 +1206,8 @@ 1123, 5813, "Some", "Product", "123ABC"); auto* store = GetChooserContext(profile()); - profile()->GetPrefs()->Set(prefs::kManagedWebUsbAllowDevicesForUrls, - *base::JSONReader::ReadDeprecated(kPolicySetting)); + profile()->GetPrefs()->SetList(prefs::kManagedWebUsbAllowDevicesForUrls, + base::test::ParseJsonList(kPolicySetting)); EXPECT_CALL(*mock_permission_observers_[profile()], OnObjectPermissionChanged(
diff --git a/chrome/browser/web_applications/BUILD.gn b/chrome/browser/web_applications/BUILD.gn index 620c7ae..622e692 100644 --- a/chrome/browser/web_applications/BUILD.gn +++ b/chrome/browser/web_applications/BUILD.gn
@@ -133,8 +133,6 @@ "os_integration/uninstallation_via_os_settings_sub_manager.h", "os_integration/url_handler_manager.cc", "os_integration/url_handler_manager.h", - "os_integration/url_handling_sub_manager.cc", - "os_integration/url_handling_sub_manager.h", "os_integration/web_app_file_handler_manager.cc", "os_integration/web_app_file_handler_manager.h", "os_integration/web_app_file_handler_registration.cc", @@ -626,7 +624,6 @@ "os_integration/run_on_os_login_sub_manager_unittest.cc", "os_integration/shortcut_menu_handling_sub_manager_unittest.cc", "os_integration/uninstallation_via_os_settings_sub_manager_unittest.cc", - "os_integration/url_handling_sub_manager_unittest.cc", "os_integration/web_app_file_handler_manager_unittest.cc", "os_integration/web_app_protocol_handler_manager_unittest.cc", "os_integration/web_app_shortcut_unittest.cc",
diff --git a/chrome/browser/web_applications/os_integration/os_integration_manager.cc b/chrome/browser/web_applications/os_integration/os_integration_manager.cc index 0bcee616..44e289d 100644 --- a/chrome/browser/web_applications/os_integration/os_integration_manager.cc +++ b/chrome/browser/web_applications/os_integration/os_integration_manager.cc
@@ -31,7 +31,6 @@ #include "chrome/browser/web_applications/os_integration/shortcut_menu_handling_sub_manager.h" #include "chrome/browser/web_applications/os_integration/shortcut_sub_manager.h" #include "chrome/browser/web_applications/os_integration/uninstallation_via_os_settings_sub_manager.h" -#include "chrome/browser/web_applications/os_integration/url_handling_sub_manager.h" #include "chrome/browser/web_applications/os_integration/web_app_shortcut.h" #include "chrome/browser/web_applications/os_integration/web_app_uninstallation_via_os_settings_registration.h" #include "chrome/browser/web_applications/proto/web_app_os_integration_state.pb.h" @@ -190,8 +189,6 @@ *profile_, *registrar, *sync_bridge); auto protocol_handling_sub_manager = std::make_unique<ProtocolHandlingSubManager>(profile_, *registrar); - auto url_handling_sub_manager = - std::make_unique<UrlHandlingSubManager>(*registrar); auto shortcut_menu_handling_sub_manager = std::make_unique<ShortcutMenuHandlingSubManager>( profile_->GetPath(), *icon_manager, *registrar); @@ -202,7 +199,6 @@ sub_managers_.push_back(std::move(shortcut_sub_manager)); sub_managers_.push_back(std::move(file_handling_sub_manager)); sub_managers_.push_back(std::move(protocol_handling_sub_manager)); - sub_managers_.push_back(std::move(url_handling_sub_manager)); sub_managers_.push_back(std::move(shortcut_menu_handling_sub_manager)); sub_managers_.push_back(std::move(run_on_os_login_sub_manager)); sub_managers_.push_back( @@ -234,6 +230,11 @@ return; } + if (sub_managers_.empty()) { + std::move(callback).Run(); + return; + } + if (!registrar_->GetAppById(app_id)) { std::move(callback).Run(); return; @@ -592,11 +593,18 @@ void OsIntegrationManager::RegisterRunOnOsLogin(const AppId& app_id, ResultCallback callback) { + ResultCallback metrics_callback = + base::BindOnce([](Result result) { + base::UmaHistogramBoolean("WebApp.RunOnOsLogin.Registration.Result", + (result == Result::kOk)); + return result; + }).Then(std::move(callback)); + GetShortcutInfoForApp( app_id, base::BindOnce( &OsIntegrationManager::OnShortcutInfoRetrievedRegisterRunOnOsLogin, - weak_ptr_factory_.GetWeakPtr(), std::move(callback))); + weak_ptr_factory_.GetWeakPtr(), std::move(metrics_callback))); } void OsIntegrationManager::MacAppShimOnAppInstalledForProfile( @@ -641,10 +649,17 @@ void OsIntegrationManager::UnregisterRunOnOsLogin(const AppId& app_id, ResultCallback callback) { + ResultCallback metrics_callback = + base::BindOnce([](Result result) { + base::UmaHistogramBoolean("WebApp.RunOnOsLogin.Unregistration.Result", + (result == Result::kOk)); + return result; + }).Then(std::move(callback)); + ScheduleUnregisterRunOnOsLogin( sync_bridge_, app_id, profile_->GetPath(), base::UTF8ToUTF16(registrar_->GetAppShortName(app_id)), - std::move(callback)); + std::move(metrics_callback)); } void OsIntegrationManager::DeleteShortcuts(
diff --git a/chrome/browser/web_applications/os_integration/url_handling_sub_manager.cc b/chrome/browser/web_applications/os_integration/url_handling_sub_manager.cc deleted file mode 100644 index c042d58..0000000 --- a/chrome/browser/web_applications/os_integration/url_handling_sub_manager.cc +++ /dev/null
@@ -1,65 +0,0 @@ -// Copyright 2023 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/web_applications/os_integration/url_handling_sub_manager.h" - -#include <utility> - -#include "chrome/browser/web_applications/proto/web_app_os_integration_state.pb.h" -#include "chrome/browser/web_applications/web_app.h" -#include "chrome/browser/web_applications/web_app_registrar.h" - -namespace web_app { - -UrlHandlingSubManager::UrlHandlingSubManager(WebAppRegistrar& registrar) - : registrar_(registrar) {} - -UrlHandlingSubManager::~UrlHandlingSubManager() = default; - -void UrlHandlingSubManager::Configure( - const AppId& app_id, - proto::WebAppOsIntegrationState& desired_state, - base::OnceClosure configure_done) { - DCHECK(!desired_state.has_url_handling()); - - if (!registrar_->IsLocallyInstalled(app_id)) { - std::move(configure_done).Run(); - return; - } - - const WebApp* web_app = registrar_->GetAppById(app_id); - - proto::UrlHandling* url_handling_proto = desired_state.mutable_url_handling(); - for (const auto& url_handler : web_app->url_handlers()) { - proto::UrlHandling::UrlHandler* url_handler_proto = - url_handling_proto->add_url_handlers(); - url_handler_proto->set_origin(url_handler.origin.Serialize()); - url_handler_proto->set_has_origin_wildcard(url_handler.has_origin_wildcard); - - for (const std::string& path : url_handler.paths) { - url_handler_proto->add_paths(path); - } - for (const std::string& exclude_path : url_handler.exclude_paths) { - url_handler_proto->add_exclude_paths(exclude_path); - } - } - - std::move(configure_done).Run(); -} - -void UrlHandlingSubManager::Start() {} - -void UrlHandlingSubManager::Shutdown() {} - -void UrlHandlingSubManager::Execute( - const AppId& app_id, - const absl::optional<SynchronizeOsOptions>& synchronize_options, - const proto::WebAppOsIntegrationState& desired_state, - const proto::WebAppOsIntegrationState& current_state, - base::OnceClosure callback) { - // Not implemented yet. - std::move(callback).Run(); -} - -} // namespace web_app
diff --git a/chrome/browser/web_applications/os_integration/url_handling_sub_manager.h b/chrome/browser/web_applications/os_integration/url_handling_sub_manager.h deleted file mode 100644 index ae972ad9..0000000 --- a/chrome/browser/web_applications/os_integration/url_handling_sub_manager.h +++ /dev/null
@@ -1,42 +0,0 @@ -// Copyright 2023 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_WEB_APPLICATIONS_OS_INTEGRATION_URL_HANDLING_SUB_MANAGER_H_ -#define CHROME_BROWSER_WEB_APPLICATIONS_OS_INTEGRATION_URL_HANDLING_SUB_MANAGER_H_ - -#include "base/functional/callback_forward.h" -#include "base/memory/raw_ref.h" -#include "chrome/browser/web_applications/os_integration/os_integration_sub_manager.h" -#include "chrome/browser/web_applications/proto/web_app_os_integration_state.pb.h" -#include "chrome/browser/web_applications/web_app_id.h" -#include "third_party/abseil-cpp/absl/types/optional.h" - -namespace web_app { - -class WebAppRegistrar; - -// Used to track updates to the URL handlers for a web app. -class UrlHandlingSubManager : public OsIntegrationSubManager { - public: - explicit UrlHandlingSubManager(WebAppRegistrar& registrar); - ~UrlHandlingSubManager() override; - void Start() override; - void Shutdown() override; - - void Configure(const AppId& app_id, - proto::WebAppOsIntegrationState& desired_state, - base::OnceClosure configure_done) override; - void Execute(const AppId& app_id, - const absl::optional<SynchronizeOsOptions>& synchronize_options, - const proto::WebAppOsIntegrationState& desired_state, - const proto::WebAppOsIntegrationState& current_state, - base::OnceClosure callback) override; - - private: - const raw_ref<WebAppRegistrar> registrar_; -}; - -} // namespace web_app - -#endif // CHROME_BROWSER_WEB_APPLICATIONS_OS_INTEGRATION_URL_HANDLING_SUB_MANAGER_H_
diff --git a/chrome/browser/web_applications/os_integration/url_handling_sub_manager_unittest.cc b/chrome/browser/web_applications/os_integration/url_handling_sub_manager_unittest.cc deleted file mode 100644 index 1abaa20..0000000 --- a/chrome/browser/web_applications/os_integration/url_handling_sub_manager_unittest.cc +++ /dev/null
@@ -1,201 +0,0 @@ -// Copyright 2023 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include <memory> -#include <utility> -#include <vector> - -#include "base/files/file_util.h" -#include "base/test/scoped_feature_list.h" -#include "base/test/test_future.h" -#include "chrome/browser/profiles/profile.h" -#include "chrome/browser/web_applications/os_integration/os_integration_manager.h" -#include "chrome/browser/web_applications/os_integration/os_integration_test_override.h" -#include "chrome/browser/web_applications/proto/web_app_os_integration_state.pb.h" -#include "chrome/browser/web_applications/test/fake_web_app_provider.h" -#include "chrome/browser/web_applications/test/web_app_install_test_utils.h" -#include "chrome/browser/web_applications/test/web_app_test.h" -#include "chrome/browser/web_applications/test/web_app_test_utils.h" -#include "chrome/browser/web_applications/web_app_command_scheduler.h" -#include "chrome/browser/web_applications/web_app_install_info.h" -#include "chrome/browser/web_applications/web_app_install_params.h" -#include "chrome/browser/web_applications/web_app_provider.h" -#include "chrome/common/chrome_features.h" -#include "components/services/app_service/public/cpp/url_handler_info.h" -#include "components/webapps/browser/install_result_code.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "url/gurl.h" - -namespace web_app { - -namespace { - -class UrlHandlingSubManagerTest - : public WebAppTest, - public ::testing::WithParamInterface<OsIntegrationSubManagersState> { - public: - const GURL kWebAppUrl = GURL("https://example.com/path/index.html"); - - UrlHandlingSubManagerTest() = default; - ~UrlHandlingSubManagerTest() override = default; - - void SetUp() override { - WebAppTest::SetUp(); - { - base::ScopedAllowBlockingForTesting allow_blocking; - test_override_ = - OsIntegrationTestOverride::OverrideForTesting(base::GetHomeDir()); - } - if (GetParam() == OsIntegrationSubManagersState::kSaveStateToDB) { - scoped_feature_list_.InitAndEnableFeatureWithParameters( - features::kOsIntegrationSubManagers, {{"stage", "write_config"}}); - } else { - scoped_feature_list_.InitWithFeatures( - /*enabled_features=*/{}, - /*disabled_features=*/{features::kOsIntegrationSubManagers}); - } - - provider_ = FakeWebAppProvider::Get(profile()); - - auto file_handler_manager = - std::make_unique<WebAppFileHandlerManager>(profile()); - auto protocol_handler_manager = - std::make_unique<WebAppProtocolHandlerManager>(profile()); - auto shortcut_manager = std::make_unique<WebAppShortcutManager>( - profile(), /*icon_manager=*/nullptr, file_handler_manager.get(), - protocol_handler_manager.get()); - auto os_integration_manager = std::make_unique<OsIntegrationManager>( - profile(), std::move(shortcut_manager), std::move(file_handler_manager), - std::move(protocol_handler_manager), /*url_handler_manager=*/nullptr); - - provider_->SetOsIntegrationManager(std::move(os_integration_manager)); - test::AwaitStartWebAppProviderAndSubsystems(profile()); - } - - void TearDown() override { - // Blocking required due to file operations in the shortcut override - // destructor. - test::UninstallAllWebApps(profile()); - { - base::ScopedAllowBlockingForTesting allow_blocking; - test_override_.reset(); - } - WebAppTest::TearDown(); - } - - web_app::AppId InstallWebApp(apps::UrlHandlers url_handlers) { - std::unique_ptr<WebAppInstallInfo> info = - std::make_unique<WebAppInstallInfo>(); - info->start_url = kWebAppUrl; - info->title = u"Test App"; - info->user_display_mode = web_app::mojom::UserDisplayMode::kStandalone; - info->url_handlers = url_handlers; - base::test::TestFuture<const AppId&, webapps::InstallResultCode> result; - // InstallFromInfoWithParams is used instead of InstallFromInfo, because - // InstallFromInfo doesn't register OS integration. - provider().scheduler().InstallFromInfoWithParams( - std::move(info), /*overwrite_existing_manifest_fields=*/true, - webapps::WebappInstallSource::OMNIBOX_INSTALL_ICON, - result.GetCallback(), WebAppInstallParams()); - bool success = result.Wait(); - EXPECT_TRUE(success); - if (!success) { - return AppId(); - } - EXPECT_EQ(result.Get<webapps::InstallResultCode>(), - webapps::InstallResultCode::kSuccessNewInstall); - return result.Get<AppId>(); - } - - protected: - WebAppProvider& provider() { return *provider_; } - - private: - raw_ptr<FakeWebAppProvider> provider_; - base::test::ScopedFeatureList scoped_feature_list_; - std::unique_ptr<OsIntegrationTestOverride::BlockingRegistration> - test_override_; -}; - -TEST_P(UrlHandlingSubManagerTest, TestConfig) { - apps::UrlHandlers url_handlers; - url::Origin foo_origin = url::Origin::Create(GURL("https://foo.com")); - url::Origin bar_origin = url::Origin::Create(GURL("https://bar.com")); - url_handlers.push_back(apps::UrlHandlerInfo(foo_origin, true, - /*paths*/ {"/include"}, - /*exclude_paths*/ {"/exclude"})); - url_handlers.push_back(apps::UrlHandlerInfo(bar_origin, false, /*paths*/ {}, - /*exclude_paths*/ {})); - - const AppId& app_id = InstallWebApp(url_handlers); - - auto state = - provider().registrar_unsafe().GetAppCurrentOsIntegrationState(app_id); - ASSERT_TRUE(state.has_value()); - const proto::WebAppOsIntegrationState& os_integration_state = state.value(); - if (AreOsIntegrationSubManagersEnabled()) { - EXPECT_TRUE(os_integration_state.has_url_handling()); - EXPECT_EQ(os_integration_state.url_handling().url_handlers_size(), 2); - - EXPECT_EQ(os_integration_state.url_handling().url_handlers(0).origin(), - "https://foo.com"); - EXPECT_TRUE(os_integration_state.url_handling() - .url_handlers(0) - .has_origin_wildcard()); - EXPECT_EQ(os_integration_state.url_handling().url_handlers(0).paths_size(), - 1); - EXPECT_EQ(os_integration_state.url_handling().url_handlers(0).paths()[0], - "/include"); - EXPECT_EQ(os_integration_state.url_handling() - .url_handlers(0) - .exclude_paths_size(), - 1); - EXPECT_EQ( - os_integration_state.url_handling().url_handlers(0).exclude_paths()[0], - "/exclude"); - - EXPECT_EQ(os_integration_state.url_handling().url_handlers(1).origin(), - "https://bar.com"); - EXPECT_FALSE(os_integration_state.url_handling() - .url_handlers(1) - .has_origin_wildcard()); - EXPECT_EQ(os_integration_state.url_handling().url_handlers(1).paths_size(), - 0); - EXPECT_EQ(os_integration_state.url_handling() - .url_handlers(1) - .exclude_paths_size(), - 0); - } else { - ASSERT_FALSE(os_integration_state.has_url_handling()); - } -} - -TEST_P(UrlHandlingSubManagerTest, TestUninstall) { - apps::UrlHandlers url_handlers; - url::Origin foo_origin = url::Origin::Create(GURL("https://foo.com")); - url::Origin bar_origin = url::Origin::Create(GURL("https://bar.com")); - url_handlers.push_back(apps::UrlHandlerInfo(foo_origin, true, - /*paths*/ {"/include"}, - /*exclude_paths*/ {"/exclude"})); - url_handlers.push_back(apps::UrlHandlerInfo(bar_origin, false, /*paths*/ {}, - /*exclude_paths*/ {})); - - const AppId& app_id = InstallWebApp(url_handlers); - test::UninstallAllWebApps(profile()); - - auto state = - provider().registrar_unsafe().GetAppCurrentOsIntegrationState(app_id); - ASSERT_FALSE(state.has_value()); -} - -INSTANTIATE_TEST_SUITE_P( - All, - UrlHandlingSubManagerTest, - ::testing::Values(OsIntegrationSubManagersState::kSaveStateToDB, - OsIntegrationSubManagersState::kDisabled), - test::GetOsIntegrationSubManagersTestName); - -} // namespace - -} // namespace web_app
diff --git a/chrome/browser/web_applications/proto/web_app_os_integration_state.proto b/chrome/browser/web_applications/proto/web_app_os_integration_state.proto index 5f6ecaf..11e3178 100644 --- a/chrome/browser/web_applications/proto/web_app_os_integration_state.proto +++ b/chrome/browser/web_applications/proto/web_app_os_integration_state.proto
@@ -76,27 +76,16 @@ repeated FileHandler file_handlers = 1; } -message UrlHandling { - message UrlHandler { - optional string origin = 1; - optional bool has_origin_wildcard = 2; - repeated string paths = 3; - repeated string exclude_paths = 4; - } - repeated UrlHandler url_handlers = 1; -} - // Represents all the common OS Integration states to be stored in the web_app // DB that matches the values in the OS. message WebAppOsIntegrationState { - reserved 2; + reserved 2, 8; optional ShortcutDescription shortcut = 1; optional ProtocolsHandled protocols_handled = 3; optional RunOnOsLogin run_on_os_login = 4; optional OsUninstallRegistration uninstall_registration = 5; optional ShortcutMenus shortcut_menus = 6; optional FileHandling file_handling = 7; - optional UrlHandling url_handling = 8; // Add data states for other OS integration hooks here. // New fields added to this message must also be added to: // OsStatesDebugValue()
diff --git a/chrome/browser/web_applications/web_app.cc b/chrome/browser/web_applications/web_app.cc index b443c08..7461deb 100644 --- a/chrome/browser/web_applications/web_app.cc +++ b/chrome/browser/web_applications/web_app.cc
@@ -182,31 +182,6 @@ debug_dict.Set("file_handling", std::move(file_handlers_list)); } - if (current_states.has_url_handling()) { - base::Value::List url_handlers; - for (const auto& url_handler : - current_states.url_handling().url_handlers()) { - base::Value::Dict url_handler_dict; - url_handler_dict.Set("origin", url_handler.origin()); - url_handler_dict.Set("has_origin_wildcard", - url_handler.has_origin_wildcard()); - base::Value::List paths; - for (auto path : url_handler.paths()) { - paths.Append(path); - } - url_handler_dict.Set("paths", std::move(paths)); - base::Value::List exclude_paths; - for (auto path : url_handler.exclude_paths()) { - exclude_paths.Append(path); - } - url_handler_dict.Set("exclude_paths", std::move(exclude_paths)); - url_handlers.Append(std::move(url_handler_dict)); - } - base::Value::Dict url_handling; - url_handling.Set("url_handlers", std::move(url_handlers)); - debug_dict.Set("url_handling", std::move(url_handling)); - } - return base::Value(std::move(debug_dict)); }
diff --git a/chrome/browser/webid/federated_identity_auto_reauthn_permission_context.cc b/chrome/browser/webid/federated_identity_auto_reauthn_permission_context.cc index a998049..4d18eed 100644 --- a/chrome/browser/webid/federated_identity_auto_reauthn_permission_context.cc +++ b/chrome/browser/webid/federated_identity_auto_reauthn_permission_context.cc
@@ -24,20 +24,26 @@ FederatedIdentityAutoReauthnPermissionContext:: ~FederatedIdentityAutoReauthnPermissionContext() = default; -bool FederatedIdentityAutoReauthnPermissionContext::HasAutoReauthnPermission( +bool FederatedIdentityAutoReauthnPermissionContext:: + HasAutoReauthnContentSetting() { + return host_content_settings_map_->GetDefaultContentSetting( + ContentSettingsType::FEDERATED_IDENTITY_AUTO_REAUTHN_PERMISSION, + /*provider_id=*/nullptr) != ContentSetting::CONTENT_SETTING_BLOCK; +} + +bool FederatedIdentityAutoReauthnPermissionContext::IsAutoReauthnEmbargoed( const url::Origin& relying_party_embedder) { - bool is_content_setting_allowed = - host_content_settings_map_->GetDefaultContentSetting( - ContentSettingsType::FEDERATED_IDENTITY_AUTO_REAUTHN_PERMISSION, - /*provider_id=*/nullptr) != ContentSetting::CONTENT_SETTING_BLOCK; - UMA_HISTOGRAM_BOOLEAN("Blink.FedCm.AutoReauthn.BlockedByContentSettings", - !is_content_setting_allowed); - bool is_embargoed = permission_autoblocker_->IsEmbargoed( + return permission_autoblocker_->IsEmbargoed( relying_party_embedder.GetURL(), ContentSettingsType::FEDERATED_IDENTITY_AUTO_REAUTHN_PERMISSION); - UMA_HISTOGRAM_BOOLEAN("Blink.FedCm.AutoReauthn.BlockedByEmbargo", - is_embargoed); - return is_content_setting_allowed && !is_embargoed; +} + +base::Time +FederatedIdentityAutoReauthnPermissionContext::GetAutoReauthnEmbargoStartTime( + const url::Origin& relying_party_embedder) { + return permission_autoblocker_->GetEmbargoStartTime( + relying_party_embedder.GetURL(), + ContentSettingsType::FEDERATED_IDENTITY_AUTO_REAUTHN_PERMISSION); } void FederatedIdentityAutoReauthnPermissionContext::RecordDisplayAndEmbargo(
diff --git a/chrome/browser/webid/federated_identity_auto_reauthn_permission_context.h b/chrome/browser/webid/federated_identity_auto_reauthn_permission_context.h index 73bc152..c6d163d 100644 --- a/chrome/browser/webid/federated_identity_auto_reauthn_permission_context.h +++ b/chrome/browser/webid/federated_identity_auto_reauthn_permission_context.h
@@ -34,7 +34,10 @@ const FederatedIdentityAutoReauthnPermissionContext&) = delete; // content::FederatedIdentityAutoReauthnPermissionContextDelegate: - bool HasAutoReauthnPermission( + bool HasAutoReauthnContentSetting() override; + bool IsAutoReauthnEmbargoed( + const url::Origin& relying_party_embedder) override; + base::Time GetAutoReauthnEmbargoStartTime( const url::Origin& relying_party_embedder) override; void RecordDisplayAndEmbargo( const url::Origin& relying_party_embedder) override;
diff --git a/chrome/browser/webid/federated_identity_auto_reauthn_permission_context_unittest.cc b/chrome/browser/webid/federated_identity_auto_reauthn_permission_context_unittest.cc index c0a7983..a053280 100644 --- a/chrome/browser/webid/federated_identity_auto_reauthn_permission_context_unittest.cc +++ b/chrome/browser/webid/federated_identity_auto_reauthn_permission_context_unittest.cc
@@ -52,8 +52,8 @@ TEST_F(FederatedIdentityAutoReauthnPermissionContextTest, AutoReauthnEnabledByDefault) { GURL rp_url("https://rp.com"); - EXPECT_EQ(true, - context_->HasAutoReauthnPermission(url::Origin::Create(rp_url))); + EXPECT_TRUE(context_->HasAutoReauthnContentSetting()); + EXPECT_FALSE(context_->IsAutoReauthnEmbargoed(url::Origin::Create(rp_url))); } // Test that
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt index 8d4d383c..670c1bc 100644 --- a/chrome/build/linux.pgo.txt +++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@ -chrome-linux-main-1676980367-ad7da12a7ad797e7820024f7fb3ecaafe86744f1.profdata +chrome-linux-main-1677002389-5e8b493cc771b62b8c22038ecef911a650be0be4.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt index 83334bd0b..637638c 100644 --- a/chrome/build/mac-arm.pgo.txt +++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@ -chrome-mac-arm-main-1676980367-21616960f10b88358395bf2911e6f3a88c674438.profdata +chrome-mac-arm-main-1677009458-7346edb3be6d91898fc7dc9ade06bb4e244fb600.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt index 3b57420..fc13fb7 100644 --- a/chrome/build/mac.pgo.txt +++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@ -chrome-mac-main-1676958321-3a15a6ea4903056f4c2154ff19b6ada3fe3697d8.profdata +chrome-mac-main-1677002389-c085779fc8798025d46f40a44faf7db0ca954d78.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt index 2ae7799..cf4498e8 100644 --- a/chrome/build/win32.pgo.txt +++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@ -chrome-win32-main-1676980367-5eeafc6931e2661f9793227292162a6a9894a260.profdata +chrome-win32-main-1677002389-aae805505c34a85fb8c880aed9e730c525c06114.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt index 50103367..e3c8f9f 100644 --- a/chrome/build/win64.pgo.txt +++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@ -chrome-win64-main-1676980367-f4f6f10748cab154e595d9943c12247067360c1a.profdata +chrome-win64-main-1677002389-9855de2516e5ab7c0d9b964eb2b999368b94955a.profdata
diff --git a/chrome/common/extensions/api/pdf_viewer_private.idl b/chrome/common/extensions/api/pdf_viewer_private.idl index 215fbb81..67eaab1 100644 --- a/chrome/common/extensions/api/pdf_viewer_private.idl +++ b/chrome/common/extensions/api/pdf_viewer_private.idl
@@ -30,4 +30,10 @@ [supportsPromises] static void setPdfOcrPref( boolean value, OnPdfOcrPrefSetCallback callback); }; + + interface Events { + // Fired when a pref value for PDF OCR has changed. + // |value| The pref value that changed. + static void onPdfOcrPrefChanged(boolean value); + }; };
diff --git a/chrome/test/base/extension_js_browser_test.cc b/chrome/test/base/extension_js_browser_test.cc index c00abad..15378717 100644 --- a/chrome/test/base/extension_js_browser_test.cc +++ b/chrome/test/base/extension_js_browser_test.cc
@@ -5,6 +5,7 @@ #include "chrome/test/base/extension_js_browser_test.h" #include <memory> +#include <vector> #include "base/functional/callback.h" #include "base/json/json_reader.h" @@ -14,6 +15,7 @@ #include "base/values.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" +#include "chrome/common/extensions/extension_constants.h" #include "chrome/test/base/javascript_browser_test.h" #include "content/public/browser/web_contents.h" #include "content/public/test/browser_test_utils.h" @@ -22,6 +24,23 @@ #include "extensions/browser/extension_host.h" #include "extensions/browser/extension_host_test_helper.h" #include "test_switches.h" +#include "ui/base/ime/ash/extension_ime_util.h" + +namespace { + +const std::vector<std::string>& GetExtensionIdsToCollectCoverage() { + static const std::vector<std::string> extensions_for_coverage = { + extension_misc::kChromeVoxExtensionId, + extension_misc::kSelectToSpeakExtensionId, + extension_misc::kSwitchAccessExtensionId, + extension_misc::kAccessibilityCommonExtensionId, + extension_misc::kEnhancedNetworkTtsExtensionId, + ash::extension_ime_util::kBrailleImeExtensionId, + }; + return extensions_for_coverage; +} + +} // namespace ExtensionJSBrowserTest::ExtensionJSBrowserTest() = default; @@ -37,8 +56,14 @@ command_line->GetSwitchValuePath(switches::kDevtoolsCodeCoverage); ShouldInspectDevToolsAgentHostCallback callback = base::BindRepeating([](content::DevToolsAgentHost* host) { - return base::StartsWith(host->GetTitle(), "ChromeVox") && - host->GetType() == "background_page"; + const auto& ext_ids = GetExtensionIdsToCollectCoverage(); + for (const auto& ext_id : ext_ids) { + if (base::Contains(host->GetURL().path(), ext_id) && + host->GetType() == "background_page") { + return true; + } + } + return false; }); coverage_handler_ = std::make_unique<DevToolsAgentCoverageObserver>( devtools_code_coverage_dir, std::move(callback));
diff --git a/chrome/test/data/extensions/api_test/pdf_viewer_private/background.js b/chrome/test/data/extensions/api_test/pdf_viewer_private/background.js index d62f16e8..163533b0 100644 --- a/chrome/test/data/extensions/api_test/pdf_viewer_private/background.js +++ b/chrome/test/data/extensions/api_test/pdf_viewer_private/background.js
@@ -76,5 +76,23 @@ await chrome.pdfViewerPrivate.isPdfOcrAlwaysActive(); chrome.test.assertFalse(isPdfOcrAlwaysActive); chrome.test.succeed(); + }, + /** + * Test that the onPdfOcrPrefChanged function can monitor changes in the PDF + * OCR pref correctly. It monitors the pref defined with the following name: + * `settings.a11y.pdf_ocr_always_active` + */ + async function testOnPdfOcrPrefChanged() { + const result = await chrome.pdfViewerPrivate.setPdfOcrPref(false); + chrome.test.assertTrue(result); + + chrome.pdfViewerPrivate.onPdfOcrPrefChanged.addListener(function local( + isPdfOcrAlwaysActive) { + chrome.pdfViewerPrivate.onPdfOcrPrefChanged.removeListener(local); + chrome.test.assertTrue(isPdfOcrAlwaysActive); + chrome.test.succeed(); + }); + + chrome.pdfViewerPrivate.setPdfOcrPref(true); } ]);
diff --git a/chrome/test/data/webui/settings/chromeos/device_page_tests.js b/chrome/test/data/webui/settings/chromeos/device_page_tests.js index 3644c9c..dfff6036 100644 --- a/chrome/test/data/webui/settings/chromeos/device_page_tests.js +++ b/chrome/test/data/webui/settings/chromeos/device_page_tests.js
@@ -1469,6 +1469,67 @@ loadTimeData.getString('audioMutedExternallyTooltip'), inputMuteTooltip.textContent.trim()); }); + + test( + 'mute state updates button aria-description and aria-pressed', + async function() { + const outputMuteButton = + audioPage.shadowRoot.querySelector('#audioOutputMuteButton'); + const inputMuteButton = + audioPage.shadowRoot.querySelector('#audioInputGainMuteButton'); + + // Default state should be unmuted so show the toggle mute tooltip. + assertEquals( + loadTimeData.getString('audioOutputMuteButtonAriaLabelNotMuted'), + outputMuteButton.ariaDescription.trim()); + assertEquals( + loadTimeData.getString('audioInputMuteButtonAriaLabelNotMuted'), + inputMuteButton.ariaDescription.trim()); + const ariaNotPressedValue = 'false'; + assertEquals(ariaNotPressedValue, outputMuteButton.ariaPressed); + assertEquals(ariaNotPressedValue, inputMuteButton.ariaPressed); + + // Test muted by user case. + crosAudioConfig.setAudioSystemProperties( + mutedByUserFakeAudioSystemProperties); + await flushTasks(); + assertEquals( + loadTimeData.getString('audioOutputMuteButtonAriaLabelMuted'), + outputMuteButton.ariaDescription.trim()); + assertEquals( + loadTimeData.getString('audioInputMuteButtonAriaLabelMuted'), + inputMuteButton.ariaDescription.trim()); + const ariaPressedValue = 'true'; + assertEquals(ariaPressedValue, outputMuteButton.ariaPressed); + assertEquals(ariaPressedValue, inputMuteButton.ariaPressed); + + // Test muted by policy case. + crosAudioConfig.setAudioSystemProperties( + mutedByPolicyFakeAudioSystemProperties); + await flushTasks(); + assertEquals( + loadTimeData.getString('audioOutputMuteButtonAriaLabelMuted'), + outputMuteButton.ariaDescription.trim()); + assertEquals( + loadTimeData.getString('audioInputMuteButtonAriaLabelMuted'), + inputMuteButton.ariaDescription.trim()); + assertEquals(ariaPressedValue, outputMuteButton.ariaPressed); + assertEquals(ariaPressedValue, inputMuteButton.ariaPressed); + + // Test muted externally case. + crosAudioConfig.setAudioSystemProperties( + mutedExternallyFakeAudioSystemProperties); + await flushTasks(); + assertEquals( + loadTimeData.getString('audioOutputMuteButtonAriaLabelMuted'), + outputMuteButton.ariaDescription.trim()); + assertEquals( + loadTimeData.getString( + 'audioInputMuteButtonAriaLabelMutedByHardwareSwitch'), + inputMuteButton.ariaDescription.trim()); + assertEquals(ariaPressedValue, outputMuteButton.ariaPressed); + assertEquals(ariaPressedValue, inputMuteButton.ariaPressed); + }); }); suite(assert(TestNames.PerDeviceMouse), function() {
diff --git a/chrome/updater/test/integration_tests.cc b/chrome/updater/test/integration_tests.cc index 26ed94b..ea09749 100644 --- a/chrome/updater/test/integration_tests.cc +++ b/chrome/updater/test/integration_tests.cc
@@ -95,13 +95,19 @@ ASSERT_NO_FATAL_FAILURE(EnterTestMode(GURL("http://localhost:1234"))); #if BUILDFLAG(IS_LINUX) - // On LUCI the XDG_RUNTIME_DIR environment variable may not be set. This is - // required for systemctl to connect to its bus in user mode. + // On LUCI the XDG_RUNTIME_DIR and DBUS_SESSION_BUS_ADDRESS environment + // variables may not be set. These are required for systemctl to connect to + // its bus in user mode. std::unique_ptr<base::Environment> env = base::Environment::Create(); + const std::string xdg_runtime_dir = + base::StrCat({"/run/user/", base::NumberToString(getuid())}); if (!env->HasVar("XDG_RUNTIME_DIR")) { - ASSERT_TRUE(env->SetVar( - "XDG_RUNTIME_DIR", - base::StrCat({"/run/user/", base::NumberToString(getuid())}))); + ASSERT_TRUE(env->SetVar("XDG_RUNTIME_DIR", xdg_runtime_dir)); + } + if (!env->HasVar("DBUS_SESSION_BUS_ADDRESS")) { + ASSERT_TRUE( + env->SetVar("DBUS_SESSION_BUS_ADDRESS", + base::StrCat({"unix:path=", xdg_runtime_dir, "/bus"}))); } #endif }
diff --git a/chromeos/ash/components/dbus/arc/fake_arcvm_data_migrator_client.cc b/chromeos/ash/components/dbus/arc/fake_arcvm_data_migrator_client.cc index da0398a..dc0c8b8 100644 --- a/chromeos/ash/components/dbus/arc/fake_arcvm_data_migrator_client.cc +++ b/chromeos/ash/components/dbus/arc/fake_arcvm_data_migrator_client.cc
@@ -36,7 +36,7 @@ const arc::data_migrator::HasDataToMigrateRequest& request, chromeos::DBusMethodCallback<bool> callback) { base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( - FROM_HERE, base::BindOnce(std::move(callback), true)); + FROM_HERE, base::BindOnce(std::move(callback), has_data_to_migrate_)); } void FakeArcVmDataMigratorClient::StartMigration(
diff --git a/chromeos/ash/components/dbus/arc/fake_arcvm_data_migrator_client.h b/chromeos/ash/components/dbus/arc/fake_arcvm_data_migrator_client.h index 778b7bd..1213435 100644 --- a/chromeos/ash/components/dbus/arc/fake_arcvm_data_migrator_client.h +++ b/chromeos/ash/components/dbus/arc/fake_arcvm_data_migrator_client.h
@@ -7,6 +7,7 @@ #include "chromeos/ash/components/dbus/arc/arcvm_data_migrator_client.h" #include "chromeos/ash/components/dbus/arcvm_data_migrator/arcvm_data_migrator.pb.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace ash { @@ -30,11 +31,18 @@ FakeArcVmDataMigratorClient& operator=(const FakeArcVmDataMigratorClient&) = delete; + void set_has_data_to_migrate(absl::optional<bool> has_data_to_migrate) { + has_data_to_migrate_ = has_data_to_migrate; + } + protected: friend class ArcVmDataMigratorClient; FakeArcVmDataMigratorClient(); ~FakeArcVmDataMigratorClient() override; + + private: + absl::optional<bool> has_data_to_migrate_ = true; }; } // namespace ash
diff --git a/chromeos/ash/components/device_activity/churn_cohort_use_case_impl_unittest.cc b/chromeos/ash/components/device_activity/churn_cohort_use_case_impl_unittest.cc index 4af28c7..062741f7 100644 --- a/chromeos/ash/components/device_activity/churn_cohort_use_case_impl_unittest.cc +++ b/chromeos/ash/components/device_activity/churn_cohort_use_case_impl_unittest.cc
@@ -36,14 +36,14 @@ // https://crsrc.org/o/src/third_party/chromiumos-overlay/chromeos-base/chromeos-activate-date/files/activate_date;l=67 const char kFakeFirstActivateDate[] = "2022-50"; -// The decimal representation of the bit string `100010001100000000000001101` +// The decimal representation of the bit string `0100010001 000000000000001101` // The first 10 bits represent the number of months since 2000 is 275, which // represents the 2022-12. // The right 18 bits represent the churn cohort active status for past 18 // months. The right most bit represents the status of previous active mont, // in this case, it represent 2022-12. And the second right most bit // represents 2022-11, etc. -const int kFakeChurnActiveStatus = 109450913; +const int kFakeChurnActiveStatus = 71565325; constexpr ChromeDeviceMetadataParameters kFakeChromeParameters = { version_info::Channel::STABLE /* chromeos_channel */,
diff --git a/chromeos/ash/components/device_activity/device_activity_client.cc b/chromeos/ash/components/device_activity/device_activity_client.cc index 773cfcc..2d90e3c 100644 --- a/chromeos/ash/components/device_activity/device_activity_client.cc +++ b/chromeos/ash/components/device_activity/device_activity_client.cc
@@ -1157,6 +1157,17 @@ // Update local state pref to record reporting device active. current_use_case->SetLastKnownPingTimestamp( last_transition_out_of_idle_time_); + + // Update the churn active status after churn cohort ping. + if (current_use_case->GetPsmUseCase() == + private_membership::rlwe::RlweUseCase:: + CROS_FRESNEL_CHURN_MONTHLY_COHORT) { + churn_active_status_ptr_->UpdateValue(last_transition_out_of_idle_time_); + // Update the active value in local_state_ as well. + int active_value = churn_active_status_ptr_->GetValueAsInt(); + local_state_->SetInteger(prefs::kDeviceActiveLastKnownChurnActiveStatus, + active_value); + } } RecordDurationStateMetric(state_, state_timer_.Elapsed());
diff --git a/chromeos/ash/components/device_activity/device_activity_client_unittest.cc b/chromeos/ash/components/device_activity/device_activity_client_unittest.cc index 3381a88..fb058bc 100644 --- a/chromeos/ash/components/device_activity/device_activity_client_unittest.cc +++ b/chromeos/ash/components/device_activity/device_activity_client_unittest.cc
@@ -50,7 +50,7 @@ // Set the current time to the following string. // Note that we use midnight PST (UTC-8) for the unit tests. -const char kFakeNowTimeString[] = "2000-01-01 08:00:00 GMT"; +const char kFakeNowTimeString[] = "2023-01-01 08:00:00 GMT"; // This value represents the UTC based activate date of the device formatted // YYYY-WW to reduce privacy granularity. @@ -1569,4 +1569,54 @@ use_cases.size()); } +TEST_F(DeviceActivityClientTest, + UpdateChurnActiveStatusAfterChurnCohortCheckIn) { + // The decimal representation of the bit string `100010001000000000000001101` + // The first 10 bits represent the number of months since 2000 is 273, which + // represents the 2022-10. + // The right 18 bits represent the churn cohort active status for past 18 + // months. The right most bit represents the status of previous active mont, + // in this case, it represent 2022-10. And the second right most bit + // represents 2022-09, etc. + int kFakeBeforeChurnActiveStatus = 71565325; + int kFakeAfterChurnActvieStatus = 72351849; + + // Set the past ping month to 2022-10. + base::Time new_daily_ts = base::Time::Now() - base::Days(70); + for (auto* use_case : device_activity_client_->GetUseCases()) { + use_case->SetLastKnownPingTimestamp(new_daily_ts); + } + + // Initialize the churn_active_value to kFakeBeforeChurnActiveStatus. + churn_active_status_->InitializeValue(kFakeBeforeChurnActiveStatus); + + // Last Churn Cohort month is: 2022-10, months is 273 + // Current Churn Cohort month is: 2023-01, months is 276 + // 273->276: 0100010001->0100010100 + // 2022-10 active value: 71565325 -> 0100010001 000000000000001101 + // 2023-01 active value: 72351849 -> 0100010100 000000000001101001 + + SetWifiNetworkState(shill::kStateOnline); + + for (auto* use_case : device_activity_client_->GetUseCases()) { + SCOPED_TRACE(testing::Message() + << "PSM use case: " + << psm_rlwe::RlweUseCase_Name(use_case->GetPsmUseCase())); + + EXPECT_TRUE(use_case->IsLastKnownPingTimestampSet()); + + EXPECT_EQ(device_activity_client_->GetState(), + DeviceActivityClient::State::kCheckingIn); + + SimulateImportResponse(std::string(), net::HTTP_OK); + task_environment_.RunUntilIdle(); + + EXPECT_GE(use_case->GetLastKnownPingTimestamp(), new_daily_ts); + } + + // Check the new churn active status after ping. + int updated_active_status_value = churn_active_status_->GetValueAsInt(); + EXPECT_EQ(updated_active_status_value, kFakeAfterChurnActvieStatus); +} + } // namespace ash::device_activity
diff --git a/chromeos/ui/frame/multitask_menu/multitask_menu_nudge_controller.cc b/chromeos/ui/frame/multitask_menu/multitask_menu_nudge_controller.cc index dfc8b36f..ae670c0 100644 --- a/chromeos/ui/frame/multitask_menu/multitask_menu_nudge_controller.cc +++ b/chromeos/ui/frame/multitask_menu/multitask_menu_nudge_controller.cc
@@ -387,14 +387,36 @@ } // The nudge is placed right below the anchor. - // TODO(crbug.com/1329233): Determine what to do if the nudge is offscreen. const gfx::Rect anchor_bounds_in_screen = anchor_view_->GetBoundsInScreen(); - const gfx::Rect bounds_in_screen( + gfx::Rect bounds_in_screen( anchor_bounds_in_screen.CenterPoint().x() - size.width() / 2, anchor_bounds_in_screen.bottom() + kNudgeDistanceFromAnchor, size.width(), size.height()); + bool adjust_to_fit = false; + const display::Display display = + display::Screen::GetScreen()->GetDisplayNearestView(window_); +#if BUILDFLAG(IS_CHROMEOS_LACROS) + // Lacros always needs adjustment since the child cannot go outside the + // parents bounds currently. See https://crbug.com/1416919. + adjust_to_fit = true; +#elif BUILDFLAG(IS_CHROMEOS_ASH) + // If the nudge is going to be offscreen, make sure it is within the window + // bounds. + adjust_to_fit = !display.work_area().Contains(bounds_in_screen); +#endif + if (adjust_to_fit) { + // The nudge should be within the window bounds. + bounds_in_screen.AdjustToFit(window_->GetBoundsInScreen()); + } nudge_widget_->SetBounds(bounds_in_screen); + // If setting bounds on the nudge causes it to move to another display (this + // can happen while dragging across displays), dismiss the nudge. + if (nudge_widget_->GetNativeWindow()->parent() != window_->parent()) { + DismissNudge(); + return; + } + // The circular pulse should be a square that matches the smaller dimension of // `anchor_view_`. We use rounded corners to make it look like a circle. gfx::Rect pulse_layer_bounds = anchor_bounds_in_screen;
diff --git a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/textbubble/TextBubble.java b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/textbubble/TextBubble.java index 5872bd2..3b77bb6 100644 --- a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/textbubble/TextBubble.java +++ b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/textbubble/TextBubble.java
@@ -540,7 +540,15 @@ */ private void setText(TextView view) { view.setText(mIsAccessibilityEnabled ? mAccessibilityString : mString); - if (mInverseColor) { + updateTextStyle(view, mInverseColor); + } + + /** + * @param isInverse Whether the color scheme is inversed or not. + * @param view The {@link TextView} to update the style for. + */ + protected void updateTextStyle(TextView view, boolean isInverse) { + if (isInverse) { ApiCompatibilityUtils.setTextAppearance( view, R.style.TextAppearance_TextMediumThick_Accent1); }
diff --git a/components/history_clusters/core/BUILD.gn b/components/history_clusters/core/BUILD.gn index 1af94ad..b2072d3a 100644 --- a/components/history_clusters/core/BUILD.gn +++ b/components/history_clusters/core/BUILD.gn
@@ -29,6 +29,8 @@ "file_clustering_backend.h", "full_membership_cluster_processor.cc", "full_membership_cluster_processor.h", + "history_cluster_type_utils.cc", + "history_cluster_type_utils.h", "history_clusters_db_tasks.cc", "history_clusters_db_tasks.h", "history_clusters_debug_jsons.cc", @@ -75,6 +77,7 @@ deps = [ "//base", "//components/history/core/browser", + "//components/history_clusters/public/mojom:mojo_bindings", "//components/keyed_service/core", "//components/optimization_guide/core", "//components/optimization_guide/core:entities",
diff --git a/chrome/browser/ui/webui/history_clusters/history_cluster_type_utils.cc b/components/history_clusters/core/history_cluster_type_utils.cc similarity index 87% rename from chrome/browser/ui/webui/history_clusters/history_cluster_type_utils.cc rename to components/history_clusters/core/history_cluster_type_utils.cc index 9ed0daf..229d5af 100644 --- a/chrome/browser/ui/webui/history_clusters/history_cluster_type_utils.cc +++ b/components/history_clusters/core/history_cluster_type_utils.cc
@@ -2,24 +2,23 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/ui/webui/history_clusters/history_cluster_type_utils.h" +#include "components/history_clusters/core/history_cluster_type_utils.h" #include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" #include "base/time/time.h" #include "base/time/time_to_iso8601.h" -#include "chrome/browser/profiles/profile.h" -#include "chrome/browser/search_engines/template_url_service_factory.h" #include "components/history/core/browser/history_types.h" #include "components/history_clusters/core/config.h" +#include "components/history_clusters/public/mojom/history_cluster_types.mojom.h" +#include "components/search_engines/template_url.h" #include "components/search_engines/template_url_service.h" #include "ui/base/l10n/time_format.h" -#include "ui/webui/resources/cr_components/history_clusters/history_clusters.mojom.h" namespace history_clusters { // Creates a `mojom::VisitPtr` from a `history_clusters::Visit`. -mojom::URLVisitPtr VisitToMojom(Profile* profile, +mojom::URLVisitPtr VisitToMojom(const TemplateURLService* template_url_service, const history::ClusterVisit& visit) { auto visit_mojom = mojom::URLVisit::New(); visit_mojom->visit_id = visit.annotated_visit.visit_row.visit_id; @@ -68,8 +67,6 @@ visit_mojom->annotations.push_back(mojom::Annotation::kBookmarked); } - const TemplateURLService* template_url_service = - TemplateURLServiceFactory::GetForProfile(profile); const TemplateURL* default_search_provider = template_url_service ? template_url_service->GetDefaultSearchProvider() : nullptr; @@ -97,10 +94,8 @@ // Creates a `mojom::SearchQueryPtr` from the given search query, if possible. absl::optional<mojom::SearchQueryPtr> SearchQueryToMojom( - Profile* profile, + const TemplateURLService* template_url_service, const std::string& search_query) { - const TemplateURLService* template_url_service = - TemplateURLServiceFactory::GetForProfile(profile); const TemplateURL* default_search_provider = template_url_service ? template_url_service->GetDefaultSearchProvider() : nullptr; @@ -121,7 +116,7 @@ return search_query_mojom; } -mojom::ClusterPtr ClusterToMojom(Profile* profile, +mojom::ClusterPtr ClusterToMojom(const TemplateURLService* template_url_service, const history::Cluster cluster) { auto cluster_mojom = mojom::Cluster::New(); cluster_mojom->id = cluster.cluster_id; @@ -143,11 +138,12 @@ } for (const auto& visit : cluster.visits) { - cluster_mojom->visits.push_back(VisitToMojom(profile, visit)); + cluster_mojom->visits.push_back(VisitToMojom(template_url_service, visit)); } for (const auto& related_search : cluster.related_searches) { - auto search_query_mojom = SearchQueryToMojom(profile, related_search); + auto search_query_mojom = + SearchQueryToMojom(template_url_service, related_search); if (search_query_mojom) { cluster_mojom->related_searches.emplace_back( std::move(*search_query_mojom));
diff --git a/chrome/browser/ui/webui/history_clusters/history_cluster_type_utils.h b/components/history_clusters/core/history_cluster_type_utils.h similarity index 60% rename from chrome/browser/ui/webui/history_clusters/history_cluster_type_utils.h rename to components/history_clusters/core/history_cluster_type_utils.h index 57d428b8..bd1f85f 100644 --- a/chrome/browser/ui/webui/history_clusters/history_cluster_type_utils.h +++ b/components/history_clusters/core/history_cluster_type_utils.h
@@ -2,12 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_UI_WEBUI_HISTORY_CLUSTERS_HISTORY_CLUSTER_TYPE_UTILS_H_ -#define CHROME_BROWSER_UI_WEBUI_HISTORY_CLUSTERS_HISTORY_CLUSTER_TYPE_UTILS_H_ +#ifndef COMPONENTS_HISTORY_CLUSTERS_CORE_HISTORY_CLUSTER_TYPE_UTILS_H_ +#define COMPONENTS_HISTORY_CLUSTERS_CORE_HISTORY_CLUSTER_TYPE_UTILS_H_ #include "components/history_clusters/public/mojom/history_cluster_types.mojom-forward.h" -class Profile; +class TemplateURLService; namespace history { struct Cluster; @@ -16,9 +16,9 @@ namespace history_clusters { // Creates a `mojom::Cluster` from a `history_clusters::Cluster`. -mojom::ClusterPtr ClusterToMojom(Profile* profile, +mojom::ClusterPtr ClusterToMojom(const TemplateURLService* template_url_service, const history::Cluster cluster); } // namespace history_clusters -#endif // CHROME_BROWSER_UI_WEBUI_HISTORY_CLUSTERS_HISTORY_CLUSTER_TYPE_UTILS_H_ +#endif // COMPONENTS_HISTORY_CLUSTERS_CORE_HISTORY_CLUSTER_TYPE_UTILS_H_
diff --git a/components/media_router/browser/BUILD.gn b/components/media_router/browser/BUILD.gn index b4ae651..4db9ab0 100644 --- a/components/media_router/browser/BUILD.gn +++ b/components/media_router/browser/BUILD.gn
@@ -7,8 +7,6 @@ "media_router.h", "media_router_base.cc", "media_router_base.h", - "media_router_debugger.cc", - "media_router_debugger.h", "media_router_dialog_controller.cc", "media_router_dialog_controller.h", "media_router_factory.cc", @@ -88,6 +86,8 @@ "log_util.h", "logger_impl.cc", "logger_impl.h", + "media_router_debugger.cc", + "media_router_debugger.h", "presentation/presentation_navigation_policy.cc", "presentation/presentation_navigation_policy.h", ] @@ -117,7 +117,6 @@ sources = [ "media_router_base_unittest.cc", - "media_router_debugger_unittest.cc", "media_router_dialog_controller_unittest.cc", "media_router_factory_unittest.cc", "media_router_metrics_unittest.cc", @@ -145,6 +144,7 @@ sources += [ "issue_manager_unittest.cc", "logger_impl_unittest.cc", + "media_router_debugger_unittest.cc", ] } }
diff --git a/components/media_router/browser/media_router_debugger.cc b/components/media_router/browser/media_router_debugger.cc index 2fc535d..a2f2481 100644 --- a/components/media_router/browser/media_router_debugger.cc +++ b/components/media_router/browser/media_router_debugger.cc
@@ -4,6 +4,10 @@ #include "components/media_router/browser/media_router_debugger.h" +#include "components/media_router/browser/media_router.h" +#include "components/media_router/browser/media_router_factory.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/web_contents.h" #include "media/base/media_switches.h" namespace media_router { @@ -11,6 +15,22 @@ MediaRouterDebugger::MediaRouterDebugger() = default; MediaRouterDebugger::~MediaRouterDebugger() = default; +// static. +MediaRouterDebugger* MediaRouterDebugger::GetForFrameTreeNode( + int frame_tree_node_id) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + auto* web_contents = + content::WebContents::FromFrameTreeNodeId(frame_tree_node_id); + if (!web_contents) { + return nullptr; + } + + auto* media_router = MediaRouterFactory::GetApiForBrowserContextIfExists( + web_contents->GetBrowserContext()); + + return media_router ? &media_router->GetDebugger() : nullptr; +} + void MediaRouterDebugger::EnableRtcpReports() { is_rtcp_reports_enabled_ = true; }
diff --git a/components/media_router/browser/media_router_debugger.h b/components/media_router/browser/media_router_debugger.h index b878705..cb14499 100644 --- a/components/media_router/browser/media_router_debugger.h +++ b/components/media_router/browser/media_router_debugger.h
@@ -10,6 +10,10 @@ // An interface for media router debugging and feedback. class MediaRouterDebugger { public: + // Fetches the MediaRouterDebugger from the media router fetched from the + // |frame_tree_node_id|. Must be called on the UiThread. May return a nullptr. + static MediaRouterDebugger* GetForFrameTreeNode(int frame_tree_node_id); + MediaRouterDebugger(); MediaRouterDebugger(const MediaRouterDebugger&) = delete;
diff --git a/components/metrics/metrics_log.cc b/components/metrics/metrics_log.cc index a5710fd..6daa396 100644 --- a/components/metrics/metrics_log.cc +++ b/components/metrics/metrics_log.cc
@@ -493,9 +493,11 @@ // call RecordEnvironment() in order to persist the system profile in the // persistent histograms .pma file. if (has_environment_) { + std::string client_uuid = uma_proto_.system_profile().client_uuid(); uma_proto_.clear_system_profile(); MetricsLog::RecordCoreSystemProfile(client_, uma_proto_.mutable_system_profile()); + uma_proto_.mutable_system_profile()->set_client_uuid(client_uuid); } has_environment_ = true;
diff --git a/components/metrics/metrics_log_unittest.cc b/components/metrics/metrics_log_unittest.cc index 423bfdca..7320f3a 100644 --- a/components/metrics/metrics_log_unittest.cc +++ b/components/metrics/metrics_log_unittest.cc
@@ -124,6 +124,7 @@ EXPECT_TRUE(system_profile.has_channel()); EXPECT_FALSE(system_profile.has_is_extended_stable_channel()); EXPECT_TRUE(system_profile.has_application_locale()); + EXPECT_TRUE(system_profile.has_client_uuid()); const SystemProfileProto::OS& os = system_profile.os(); EXPECT_TRUE(os.has_name());
diff --git a/components/mirroring/mojom/session_parameters.mojom b/components/mirroring/mojom/session_parameters.mojom index d9ef4b4..815d1055 100644 --- a/components/mirroring/mojom/session_parameters.mojom +++ b/components/mirroring/mojom/session_parameters.mojom
@@ -58,4 +58,8 @@ // // TODO(crbug.com/1363512): Remove support for sender side letterboxing. bool force_letterboxing; + + // If this is set to true, the Mirroring Service will fetch, analyze, and + // store information on the quality of the session using RTCP logs. + bool enable_rtcp_reporting; };
diff --git a/components/mirroring/service/BUILD.gn b/components/mirroring/service/BUILD.gn index c6f3d16ef..84d8a65 100644 --- a/components/mirroring/service/BUILD.gn +++ b/components/mirroring/service/BUILD.gn
@@ -36,6 +36,8 @@ "rtp_stream.h", "session.cc", "session.h", + "session_logger.cc", + "session_logger.h", "udp_socket_client.cc", "udp_socket_client.h", "value_util.cc", @@ -102,6 +104,7 @@ "receiver_response_unittest.cc", "remoting_sender_unittest.cc", "rtp_stream_unittest.cc", + "session_logger_unittest.cc", "session_unittest.cc", "udp_socket_client_unittest.cc", "video_capture_client_unittest.cc", @@ -115,6 +118,7 @@ "//components/mirroring/mojom:service", "//components/openscreen_platform", "//media", + "//media:test_support", "//media/capture/mojom:video_capture", "//media/cast:common", "//media/cast:net",
diff --git a/components/mirroring/service/session.cc b/components/mirroring/service/session.cc index 2e4d77b..c70b3e9 100644 --- a/components/mirroring/service/session.cc +++ b/components/mirroring/service/session.cc
@@ -466,6 +466,7 @@ audio_input_device_ = nullptr; } audio_capturing_callback_.reset(); + session_logger_.reset(); audio_stream_.reset(); video_stream_.reset(); cast_transport_.reset(); @@ -723,6 +724,10 @@ std::make_unique<TransportClient>(this), std::move(udp_client), base::SingleThreadTaskRunner::GetCurrentDefault()); + if (session_params_.enable_rtcp_reporting) { + session_logger_ = std::make_unique<SessionLogger>(cast_environment_); + } + if (state_ == REMOTING) { DCHECK(media_remoter_); DCHECK(!audio_config ||
diff --git a/components/mirroring/service/session.h b/components/mirroring/service/session.h index 2294d426..91ab702 100644 --- a/components/mirroring/service/session.h +++ b/components/mirroring/service/session.h
@@ -17,6 +17,7 @@ #include "components/mirroring/service/mirror_settings.h" #include "components/mirroring/service/rpc_dispatcher_impl.h" #include "components/mirroring/service/rtp_stream.h" +#include "components/mirroring/service/session_logger.h" #include "gpu/config/gpu_info.h" #include "media/capture/video/video_capture_feedback.h" #include "media/cast/cast_environment.h" @@ -206,6 +207,7 @@ std::unique_ptr<viz::Gpu> gpu_; SupportedProfiles supported_profiles_; mojo::Remote<media::mojom::VideoEncodeAcceleratorProvider> vea_provider_; + std::unique_ptr<SessionLogger> session_logger_; // A callback to call after initialization is completed AsyncInitializeDoneCB init_done_cb_;
diff --git a/components/mirroring/service/session_logger.cc b/components/mirroring/service/session_logger.cc new file mode 100644 index 0000000..ec983fe --- /dev/null +++ b/components/mirroring/service/session_logger.cc
@@ -0,0 +1,77 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/mirroring/service/session_logger.h" + +#include "media/cast/logging/receiver_time_offset_estimator_impl.h" + +namespace mirroring { + +SessionLogger::SessionLogger( + scoped_refptr<media::cast::CastEnvironment> cast_environment) + : SessionLogger( + cast_environment, + std::make_unique<media::cast::ReceiverTimeOffsetEstimatorImpl>()) {} + +SessionLogger::SessionLogger( + scoped_refptr<media::cast::CastEnvironment> cast_environment, + std::unique_ptr<media::cast::ReceiverTimeOffsetEstimator> offset_estimator) + : cast_environment_(cast_environment), + offset_estimator_(std::move(offset_estimator)), + video_stats_subscriber_(media::cast::VIDEO_EVENT, + cast_environment->Clock(), + offset_estimator_.get()), + audio_stats_subscriber_(media::cast::AUDIO_EVENT, + cast_environment->Clock(), + offset_estimator_.get()) { + auto* logger = cast_environment_->logger(); + if (logger) { + SubscribeToLoggingEvents(*logger); + } +} + +SessionLogger::~SessionLogger() { + auto* logger = cast_environment_->logger(); + if (logger) { + UnsubscribeFromLoggingEvents(*logger); + } +} + +base::Value::Dict SessionLogger::GetStats() const { + base::Value::Dict video_dict = video_stats_subscriber_.GetStats(); + base::Value::Dict audio_dict = audio_stats_subscriber_.GetStats(); + + base::Value::Dict combined_stats; + base::Value::Dict* audio_dict_value = audio_dict.FindDict( + media::cast::StatsEventSubscriber::kAudioStatsDictKey); + if (audio_dict_value) { + combined_stats.Set(media::cast::StatsEventSubscriber::kAudioStatsDictKey, + std::move(*audio_dict_value)); + } + + base::Value::Dict* video_dict_value = video_dict.FindDict( + media::cast::StatsEventSubscriber::kVideoStatsDictKey); + if (video_dict_value) { + combined_stats.Set(media::cast::StatsEventSubscriber::kVideoStatsDictKey, + std::move(*video_dict_value)); + } + + return combined_stats; +} + +void SessionLogger::SubscribeToLoggingEvents( + media::cast::LogEventDispatcher& logger) { + logger.Subscribe(offset_estimator_.get()); + logger.Subscribe(&video_stats_subscriber_); + logger.Subscribe(&audio_stats_subscriber_); +} + +void SessionLogger::UnsubscribeFromLoggingEvents( + media::cast::LogEventDispatcher& logger) { + logger.Unsubscribe(&video_stats_subscriber_); + logger.Unsubscribe(&audio_stats_subscriber_); + logger.Unsubscribe(offset_estimator_.get()); +} + +} // namespace mirroring
diff --git a/components/mirroring/service/session_logger.h b/components/mirroring/service/session_logger.h new file mode 100644 index 0000000..148cc64d --- /dev/null +++ b/components/mirroring/service/session_logger.h
@@ -0,0 +1,57 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_MIRRORING_SERVICE_SESSION_LOGGER_H_ +#define COMPONENTS_MIRRORING_SERVICE_SESSION_LOGGER_H_ + +#include "base/component_export.h" +#include "base/memory/raw_ptr.h" +#include "base/values.h" +#include "media/cast/cast_environment.h" +#include "media/cast/logging/log_event_dispatcher.h" +#include "media/cast/logging/receiver_time_offset_estimator.h" +#include "media/cast/logging/stats_event_subscriber.h" + +class LogEventDispatcher; + +namespace mirroring { + +// Handles logging and statistics of a mirroring session. +class COMPONENT_EXPORT(MIRRORING_SERVICE) SessionLogger { + public: + explicit SessionLogger( + scoped_refptr<media::cast::CastEnvironment> cast_environment); + + // Constructor used for testing. + SessionLogger(scoped_refptr<media::cast::CastEnvironment> cast_environment, + std::unique_ptr<media::cast::ReceiverTimeOffsetEstimator> + offset_estimator); + + SessionLogger(const SessionLogger&) = delete; + SessionLogger& operator=(const SessionLogger&) = delete; + + virtual ~SessionLogger(); + + // Returns a dictionary containing statistics for the current session. The + // dictionary contains two entries - "audio" or "video" pointing to an inner + // dictionary. The inner dictionary consists of string - double entries, where + // the string describes the name of the stat, and the double describes the + // value of the stat. See CastStat and StatsMap of the StatsEventSubscriber + // object for more details. + base::Value::Dict GetStats() const; + + protected: + void SubscribeToLoggingEvents(media::cast::LogEventDispatcher& logger); + void UnsubscribeFromLoggingEvents(media::cast::LogEventDispatcher& logger); + + scoped_refptr<media::cast::CastEnvironment> cast_environment_; + + std::unique_ptr<media::cast::ReceiverTimeOffsetEstimator> offset_estimator_; + media::cast::StatsEventSubscriber video_stats_subscriber_; + media::cast::StatsEventSubscriber audio_stats_subscriber_; +}; + +} // namespace mirroring + +#endif // COMPONENTS_MIRRORING_SERVICE_SESSION_LOGGER_H_
diff --git a/components/mirroring/service/session_logger_unittest.cc b/components/mirroring/service/session_logger_unittest.cc new file mode 100644 index 0000000..c304021 --- /dev/null +++ b/components/mirroring/service/session_logger_unittest.cc
@@ -0,0 +1,205 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/mirroring/service/session_logger.h" + +#include "base/base64.h" +#include "base/functional/bind.h" +#include "base/functional/callback.h" +#include "base/json/json_reader.h" +#include "base/logging.h" +#include "base/test/mock_callback.h" +#include "base/values.h" +#include "components/mirroring/service/value_util.h" +#include "media/base/fake_single_thread_task_runner.h" +#include "media/cast/cast_environment.h" +#include "media/cast/common/frame_id.h" +#include "media/cast/common/rtp_time.h" +#include "media/cast/logging/logging_defines.h" +#include "media/cast/logging/stats_event_subscriber.h" +#include "media/cast/test/fake_receiver_time_offset_estimator.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using ::media::FakeSingleThreadTaskRunner; +using ::media::cast::AUDIO_EVENT; +using ::media::cast::CastEnvironment; +using ::media::cast::EventMediaType; +using ::media::cast::FRAME_CAPTURE_BEGIN; +using ::media::cast::FRAME_CAPTURE_END; +using ::media::cast::FRAME_ENCODED; +using ::media::cast::FrameEvent; +using ::media::cast::FrameId; +using ::media::cast::RtpTimeDelta; +using ::media::cast::RtpTimeTicks; +using ::media::cast::StatsEventSubscriber; +using ::media::cast::VIDEO_EVENT; +using ::media::cast::test::FakeReceiverTimeOffsetEstimator; + +namespace mirroring { + +namespace { +const int kReceiverOffsetSecs = 100; +const size_t kMaxFrameInfoMapSize = 100UL; +} // namespace + +class SessionLoggerTest : public ::testing::Test { + public: + SessionLoggerTest() + : task_runner_(new FakeSingleThreadTaskRunner(&sender_clock_)), + cast_environment_(new CastEnvironment(&sender_clock_, + task_runner_, + task_runner_, + task_runner_)), + fake_offset_estimator_( + std::make_unique<FakeReceiverTimeOffsetEstimator>( + base::Seconds(kReceiverOffsetSecs))) { + receiver_clock_.Advance(base::Seconds(kReceiverOffsetSecs)); + } + + SessionLoggerTest(const SessionLoggerTest&) = delete; + SessionLoggerTest& operator=(const SessionLoggerTest&) = delete; + + ~SessionLoggerTest() override = default; + + protected: + void AdvanceClocks(base::TimeDelta delta) { + task_runner_->Sleep(delta); + receiver_clock_.Advance(delta); + } + + void Init() { + DCHECK(!session_logger_.get()); + session_logger_ = std::make_unique<SessionLogger>( + cast_environment_, std::move(fake_offset_estimator_)); + } + + void DispatchFrameEvent(std::unique_ptr<FrameEvent> frame_event) { + cast_environment_->logger()->DispatchFrameEvent(std::move(frame_event)); + } + + std::unique_ptr<FrameEvent> ConstructCaptureBeginEvent( + EventMediaType event_media_type, + RtpTimeTicks rtp_timestamp) { + std::unique_ptr<FrameEvent> capture_begin_event = + std::make_unique<FrameEvent>(); + capture_begin_event->timestamp = sender_clock_.NowTicks(); + capture_begin_event->type = FRAME_CAPTURE_BEGIN; + capture_begin_event->media_type = event_media_type; + capture_begin_event->rtp_timestamp = rtp_timestamp; + + return capture_begin_event; + } + + std::unique_ptr<FrameEvent> ConstructCaptureEndEvent( + EventMediaType event_media_type, + RtpTimeTicks rtp_timestamp) { + std::unique_ptr<FrameEvent> capture_end_event = + std::make_unique<FrameEvent>(); + capture_end_event->timestamp = sender_clock_.NowTicks(); + capture_end_event->type = FRAME_CAPTURE_END; + capture_end_event->media_type = event_media_type; + capture_end_event->rtp_timestamp = rtp_timestamp; + + return capture_end_event; + } + + std::unique_ptr<FrameEvent> ConstructEncodeEvent( + EventMediaType event_media_type, + RtpTimeTicks rtp_timestamp, + FrameId frame_id) { + std::unique_ptr<FrameEvent> encode_event = std::make_unique<FrameEvent>(); + encode_event->timestamp = sender_clock_.NowTicks(); + encode_event->type = FRAME_ENCODED; + encode_event->media_type = event_media_type; + encode_event->rtp_timestamp = rtp_timestamp; + encode_event->frame_id = frame_id; + encode_event->size = 1024; + encode_event->key_frame = true; + encode_event->target_bitrate = 5678; + encode_event->encoder_cpu_utilization = 9.10; + encode_event->idealized_bitrate_utilization = 11.12; + + return encode_event; + } + + base::SimpleTestTickClock sender_clock_; + base::SimpleTestTickClock receiver_clock_; + scoped_refptr<FakeSingleThreadTaskRunner> task_runner_; + scoped_refptr<CastEnvironment> cast_environment_; + std::unique_ptr<FakeReceiverTimeOffsetEstimator> fake_offset_estimator_; + std::unique_ptr<SessionLogger> session_logger_; +}; + +TEST_F(SessionLoggerTest, CaptureEncode) { + // Using RTP events, test that the StatEventSubscribers are parsing and + // storing statistics. + Init(); + + RtpTimeTicks rtp_timestamp; + FrameId frame_id = FrameId::first(); + + const int num_frames = kMaxFrameInfoMapSize + 50; + + // Drop half the frames during the encode step. + for (int i = 0; i < num_frames; i++) { + DispatchFrameEvent(ConstructCaptureBeginEvent(VIDEO_EVENT, rtp_timestamp)); + DispatchFrameEvent(ConstructCaptureBeginEvent(AUDIO_EVENT, rtp_timestamp)); + + AdvanceClocks(base::Microseconds(10)); + + DispatchFrameEvent(ConstructCaptureEndEvent(VIDEO_EVENT, rtp_timestamp)); + DispatchFrameEvent(ConstructCaptureEndEvent(AUDIO_EVENT, rtp_timestamp)); + + if (i % 2 == 0) { + AdvanceClocks(base::Microseconds(10)); + + DispatchFrameEvent( + ConstructEncodeEvent(VIDEO_EVENT, rtp_timestamp, frame_id)); + DispatchFrameEvent( + ConstructEncodeEvent(AUDIO_EVENT, rtp_timestamp, frame_id)); + } + AdvanceClocks(base::Microseconds(34567)); + rtp_timestamp += RtpTimeDelta::FromTicks(90); + frame_id++; + } + + auto stats_dict = session_logger_->GetStats(); + + // Check that the GetStats() dict has been populated with audio stats. + const base::Value::Dict* audio_dict = + stats_dict.FindDict(StatsEventSubscriber::kAudioStatsDictKey); + EXPECT_TRUE(audio_dict); + EXPECT_TRUE(audio_dict->contains("CAPTURE_FPS")); + EXPECT_TRUE(audio_dict->FindDouble("CAPTURE_FPS").has_value()); + + EXPECT_TRUE(audio_dict->contains("NUM_FRAMES_CAPTURED")); + EXPECT_TRUE(audio_dict->FindDouble("NUM_FRAMES_CAPTURED").has_value()); + + EXPECT_TRUE(audio_dict->contains("NUM_FRAMES_DROPPED_BY_ENCODER")); + EXPECT_TRUE( + audio_dict->FindDouble("NUM_FRAMES_DROPPED_BY_ENCODER").has_value()); + + EXPECT_TRUE(audio_dict->contains("AVG_CAPTURE_LATENCY_MS")); + EXPECT_TRUE(audio_dict->FindDouble("AVG_CAPTURE_LATENCY_MS").has_value()); + + // Check that the GetStats() dict has been populated with video stats. + const base::Value::Dict* video_dict = + stats_dict.FindDict(StatsEventSubscriber::kVideoStatsDictKey); + EXPECT_TRUE(video_dict); + EXPECT_TRUE(video_dict->contains("CAPTURE_FPS")); + EXPECT_TRUE(video_dict->FindDouble("CAPTURE_FPS").has_value()); + + EXPECT_TRUE(video_dict->contains("NUM_FRAMES_CAPTURED")); + EXPECT_TRUE(video_dict->FindDouble("NUM_FRAMES_CAPTURED").has_value()); + + EXPECT_TRUE(video_dict->contains("NUM_FRAMES_DROPPED_BY_ENCODER")); + EXPECT_TRUE( + video_dict->FindDouble("NUM_FRAMES_DROPPED_BY_ENCODER").has_value()); + + EXPECT_TRUE(video_dict->contains("AVG_CAPTURE_LATENCY_MS")); + EXPECT_TRUE(video_dict->FindDouble("AVG_CAPTURE_LATENCY_MS").has_value()); +} + +} // namespace mirroring
diff --git a/components/policy/core/common/features.cc b/components/policy/core/common/features.cc index b8996a3..d02a5bf 100644 --- a/components/policy/core/common/features.cc +++ b/components/policy/core/common/features.cc
@@ -28,7 +28,7 @@ BASE_FEATURE(kActivateMetricsReportingEnabledPolicyAndroid, "ActivateMetricsReportingEnabledPolicyAndroid", - base::FEATURE_DISABLED_BY_DEFAULT); + base::FEATURE_ENABLED_BY_DEFAULT); BASE_FEATURE(kDmTokenDeletion, "DmTokenDeletion",
diff --git a/components/security_state/core/security_state.cc b/components/security_state/core/security_state.cc index 5faa207..eb8f4e76b 100644 --- a/components/security_state/core/security_state.cc +++ b/components/security_state/core/security_state.cc
@@ -66,18 +66,18 @@ return DANGEROUS; } - // If the navigation was upgraded to HTTPS because of HTTPS-Only Mode, but did - // not succeed (either currently showing the HTTPS-Only Mode interstitial, or - // the navigation fell back to HTTP), set the security level to WARNING. The - // HTTPS-Only Mode interstitial warning is considered "less serious" than the - // general certificate error interstitials. + // If the navigation was upgraded to HTTPS because of HTTPS-First Mode, but + // did not succeed and is showing the HTTPS-First Mode interstitial, set the + // security level to WARNING. The HTTPS-First Mode interstitial warning is + // considered "less serious" than the general certificate error interstitials. // // This check must come before the checks for `connection_info_initialized` - // (because the HTTPS-Only Mode intersitital can trigger if the HTTPS version - // of the page does not commit) and certificate errors (because the HTTPS-Only - // Mode interstitial takes precedent if the certificate error occurred due to - // an upgraded main-frame navigation). - if (visible_security_state.is_https_only_mode_upgraded) { + // (because the HTTPS-First Mode intersitital can trigger if the HTTPS version + // of the page does not commit) and certificate errors (because the + // HTTPS-First Mode interstitial takes precedent if the certificate error + // occurred due to an upgraded main-frame navigation). + if (visible_security_state.is_https_only_mode_upgraded && + visible_security_state.is_error_page) { return WARNING; }
diff --git a/components/security_state/core/security_state_unittest.cc b/components/security_state/core/security_state_unittest.cc index 8c820cb..4c430395 100644 --- a/components/security_state/core/security_state_unittest.cc +++ b/components/security_state/core/security_state_unittest.cc
@@ -474,6 +474,7 @@ helper.set_cert_status(net::CERT_STATUS_SHA1_SIGNATURE_PRESENT | net::CERT_STATUS_UNABLE_TO_CHECK_REVOCATION); EXPECT_TRUE(helper.HasMajorCertificateError()); + helper.set_is_error_page(true); helper.set_is_https_only_mode_upgraded(true); EXPECT_EQ(SecurityLevel::WARNING, helper.GetSecurityLevel()); } @@ -483,6 +484,7 @@ TestSecurityStateHelper helper; helper.set_malicious_content_status( MALICIOUS_CONTENT_STATUS_SOCIAL_ENGINEERING); + helper.set_is_error_page(true); helper.set_is_https_only_mode_upgraded(true); EXPECT_EQ(DANGEROUS, helper.GetSecurityLevel()); }
diff --git a/components/signin/internal/identity_manager/DEPS b/components/signin/internal/identity_manager/DEPS index 4374378..b2b6d8c 100644 --- a/components/signin/internal/identity_manager/DEPS +++ b/components/signin/internal/identity_manager/DEPS
@@ -5,5 +5,6 @@ "+components/signin/public/webdata", "+components/signin/public/android/jni_headers", "+components/signin/public/android/test_support_jni_headers", + "+google_apis", "+mojo/public", ]
diff --git a/components/signin/internal/identity_manager/gaia_cookie_manager_service.cc b/components/signin/internal/identity_manager/gaia_cookie_manager_service.cc index 19a611cc..e64f7a6 100644 --- a/components/signin/internal/identity_manager/gaia_cookie_manager_service.cc +++ b/components/signin/internal/identity_manager/gaia_cookie_manager_service.cc
@@ -31,6 +31,7 @@ #include "components/signin/public/base/signin_metrics.h" #include "components/signin/public/base/signin_pref_names.h" #include "components/signin/public/identity_manager/set_accounts_in_cookie_result.h" +#include "google_apis/credentials_mode.h" #include "google_apis/gaia/gaia_constants.h" #include "google_apis/gaia/gaia_urls.h" #include "net/base/load_flags.h" @@ -347,7 +348,8 @@ auto request = std::make_unique<network::ResourceRequest>(); request->url = url; - request->credentials_mode = network::mojom::CredentialsMode::kOmit; + request->credentials_mode = + google_apis::GetOmitCredentialsModeForGaiaRequests(); std::unique_ptr<network::SimpleURLLoader> loader = network::SimpleURLLoader::Create(std::move(request), traffic_annotation);
diff --git a/components/sync/driver/sync_stopped_reporter.cc b/components/sync/driver/sync_stopped_reporter.cc index e388680..cebc3f35 100644 --- a/components/sync/driver/sync_stopped_reporter.cc +++ b/components/sync/driver/sync_stopped_reporter.cc
@@ -12,6 +12,7 @@ #include "base/metrics/histogram_functions.h" #include "base/strings/stringprintf.h" #include "components/sync/protocol/sync.pb.h" +#include "google_apis/credentials_mode.h" #include "net/base/load_flags.h" #include "net/http/http_status_code.h" #include "net/traffic_annotation/network_traffic_annotation.h" @@ -110,7 +111,8 @@ resource_request->url = sync_event_url_; resource_request->load_flags = net::LOAD_BYPASS_CACHE | net::LOAD_DISABLE_CACHE; - resource_request->credentials_mode = network::mojom::CredentialsMode::kOmit; + resource_request->credentials_mode = + google_apis::GetOmitCredentialsModeForGaiaRequests(); resource_request->method = "POST"; resource_request->headers.SetHeader( net::HttpRequestHeaders::kAuthorization,
diff --git a/components/sync/driver/trusted_vault_histograms.h b/components/sync/driver/trusted_vault_histograms.h index ba3dc6b..5a01b05 100644 --- a/components/sync/driver/trusted_vault_histograms.h +++ b/components/sync/driver/trusted_vault_histograms.h
@@ -27,7 +27,9 @@ kThrottledClientSide = 2, kAttemptingRegistrationWithNewKeyPair = 3, kAttemptingRegistrationWithExistingKeyPair = 4, - kAttemptingRegistrationWithPersistentAuthError = 5, + // Deprecated, replaced with more detailed + // TrustedVaultDeviceRegistrationOutcomeForUMA. + kDeprecatedAttemptingRegistrationWithPersistentAuthError = 5, kAlreadyRegisteredV1 = 6, kMaxValue = kAlreadyRegisteredV1, };
diff --git a/components/sync/engine/model_type_processor_metrics.cc b/components/sync/engine/model_type_processor_metrics.cc index 3cc6add1..92dcdfbf 100644 --- a/components/sync/engine/model_type_processor_metrics.cc +++ b/components/sync/engine/model_type_processor_metrics.cc
@@ -35,6 +35,13 @@ void LogNonReflectionUpdateFreshnessToUma(ModelType type, base::Time remote_modification_time) { + // TODO(crbug.com/1417105): This metric is only meaningful for incremental + // updates, and currently ApplyUpdatesImmediatelyTypes() don't properly + // distinguish incremental vs initial/full updates. + if (ApplyUpdatesImmediatelyTypes().Has(type)) { + return; + } + const base::TimeDelta freshness = base::Time::Now() - remote_modification_time;
diff --git a/components/sync/engine/net/http_bridge.cc b/components/sync/engine/net/http_bridge.cc index 8e5c296a..387aa93 100644 --- a/components/sync/engine/net/http_bridge.cc +++ b/components/sync/engine/net/http_bridge.cc
@@ -17,6 +17,7 @@ #include "base/task/thread_pool.h" #include "base/threading/thread_restrictions.h" #include "components/variations/net/variations_http_headers.h" +#include "google_apis/credentials_mode.h" #include "net/base/load_flags.h" #include "net/base/net_errors.h" #include "net/http/http_request_headers.h" @@ -242,7 +243,8 @@ resource_request->method = "POST"; resource_request->load_flags = net::LOAD_BYPASS_CACHE | net::LOAD_DISABLE_CACHE; - resource_request->credentials_mode = network::mojom::CredentialsMode::kOmit; + resource_request->credentials_mode = + google_apis::GetOmitCredentialsModeForGaiaRequests(); if (!extra_headers_.empty()) resource_request->headers.AddHeadersFromString(extra_headers_);
diff --git a/components/sync/trusted_vault/standalone_trusted_vault_backend.cc b/components/sync/trusted_vault/standalone_trusted_vault_backend.cc index aa45d56f..5548eb25 100644 --- a/components/sync/trusted_vault/standalone_trusted_vault_backend.cc +++ b/components/sync/trusted_vault/standalone_trusted_vault_backend.cc
@@ -875,10 +875,6 @@ } DCHECK(ongoing_device_registration_request_); - if (has_persistent_auth_error_) { - return TrustedVaultDeviceRegistrationStateForUMA:: - kAttemptingRegistrationWithPersistentAuthError; - } return had_generated_key_pair ? TrustedVaultDeviceRegistrationStateForUMA:: kAttemptingRegistrationWithExistingKeyPair
diff --git a/components/sync/trusted_vault/standalone_trusted_vault_backend_unittest.cc b/components/sync/trusted_vault/standalone_trusted_vault_backend_unittest.cc index e0fd3a79..af1c379 100644 --- a/components/sync/trusted_vault/standalone_trusted_vault_backend_unittest.cc +++ b/components/sync/trusted_vault/standalone_trusted_vault_backend_unittest.cc
@@ -950,7 +950,7 @@ } TEST_F(StandaloneTrustedVaultBackendTest, - ShouldRecordAuthErrorAndAttemptDeviceRegistration) { + ShouldRetryDeviceRegistrationWhenAuthErrorResolved) { const CoreAccountInfo account_info = MakeAccountInfoWithGaiaId("user"); const std::vector<uint8_t> kVaultKey = {1, 2, 3}; const int kLastKeyVersion = 1; @@ -970,7 +970,7 @@ "Sync.TrustedVaultDeviceRegistrationState", /*sample=*/ TrustedVaultDeviceRegistrationStateForUMA:: - kAttemptingRegistrationWithPersistentAuthError, + kAttemptingRegistrationWithNewKeyPair, /*expected_bucket_count=*/1); Mock::VerifyAndClearExpectations(connection()); @@ -989,7 +989,7 @@ // The second attempt should NOT have logged the histogram, following the // histogram's definition that it should be logged once. histogram_tester2.ExpectTotalCount("Sync.TrustedVaultDeviceRegistrationState", - /*count=*/0); + /*expected_count=*/0); } TEST_F(StandaloneTrustedVaultBackendTest,
diff --git a/components/sync/trusted_vault/trusted_vault_request.cc b/components/sync/trusted_vault/trusted_vault_request.cc index 26611a6..b62a69d1 100644 --- a/components/sync/trusted_vault/trusted_vault_request.cc +++ b/components/sync/trusted_vault/trusted_vault_request.cc
@@ -12,6 +12,7 @@ #include "components/sync/driver/trusted_vault_histograms.h" #include "components/sync/trusted_vault/trusted_vault_access_token_fetcher.h" #include "components/sync/trusted_vault/trusted_vault_server_constants.h" +#include "google_apis/credentials_mode.h" #include "net/base/url_util.h" #include "net/http/http_request_headers.h" #include "net/http/http_status_code.h" @@ -194,7 +195,8 @@ net::AppendQueryParameter(request_url_, kQueryParameterAlternateOutputKey, kQueryParameterAlternateOutputProto); request->method = GetHttpMethodString(http_method_); - request->credentials_mode = network::mojom::CredentialsMode::kOmit; + request->credentials_mode = + google_apis::GetOmitCredentialsModeForGaiaRequests(); request->headers.SetHeader( kAuthorizationHeader, /*value=*/base::StringPrintf("Bearer %s", access_token.c_str()));
diff --git a/content/browser/attribution_reporting/attribution_host.cc b/content/browser/attribution_reporting/attribution_host.cc index 952a56f2..c107f38e 100644 --- a/content/browser/attribution_reporting/attribution_host.cc +++ b/content/browser/attribution_reporting/attribution_host.cc
@@ -38,6 +38,7 @@ #include "third_party/blink/public/common/features.h" #include "third_party/blink/public/common/navigation/impression.h" #include "third_party/blink/public/mojom/conversions/attribution_data_host.mojom.h" +#include "third_party/blink/public/mojom/permissions_policy/permissions_policy.mojom-shared.h" #include "url/gurl.h" #include "url/origin.h" @@ -450,6 +451,11 @@ return; } + if (!initiator_frame_host->IsFeatureEnabled( + blink::mojom::PermissionsPolicyFeature::kAttributionReporting)) { + return; + } + AttributionManager* attribution_manager = AttributionManager::FromWebContents(web_contents()); if (!attribution_manager) {
diff --git a/content/browser/attribution_reporting/attribution_host.h b/content/browser/attribution_reporting/attribution_host.h index b0da1da..372a266 100644 --- a/content/browser/attribution_reporting/attribution_host.h +++ b/content/browser/attribution_reporting/attribution_host.h
@@ -64,6 +64,8 @@ // for reportEvent or for an automatic beacon. It may be cached and sent // later. This should be called before the navigation committed for a // navigation beacon. + // This function should only be invoked if Attribution Reporting API is + // enabled on the page. void NotifyFencedFrameReportingBeaconStarted( BeaconId beacon_id, RenderFrameHostImpl* initiator_frame_host);
diff --git a/content/browser/attribution_reporting/attribution_host_unittest.cc b/content/browser/attribution_reporting/attribution_host_unittest.cc index 70f42ac..97fea5e 100644 --- a/content/browser/attribution_reporting/attribution_host_unittest.cc +++ b/content/browser/attribution_reporting/attribution_host_unittest.cc
@@ -5,6 +5,7 @@ #include "content/browser/attribution_reporting/attribution_host.h" #include <memory> +#include <vector> #include "base/memory/raw_ptr.h" #include "base/test/metrics/histogram_tester.h" @@ -31,8 +32,11 @@ #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/public/common/features.h" +#include "third_party/blink/public/common/permissions_policy/origin_with_possible_wildcards.h" +#include "third_party/blink/public/common/permissions_policy/permissions_policy_declaration.h" #include "third_party/blink/public/common/tokens/tokens.h" #include "third_party/blink/public/mojom/conversions/conversions.mojom.h" +#include "third_party/blink/public/mojom/permissions_policy/permissions_policy.mojom-shared.h" #include "url/gurl.h" #include "url/origin.h" @@ -582,7 +586,7 @@ {kLocalHost, true}, {"http://127.0.0.1", true}, {"http://insecure.com", false}, - {"https:/secore.com", true}, + {"https:/secure.com", true}, }; NavigationBeaconId navigation_id(123); @@ -613,5 +617,45 @@ } } +TEST_F(AttributionHostTest, FencedFrameReportingBeacon_FeaturePolicyChecked) { + contents()->NavigateAndCommit(GURL("https://secure.com")); + + RenderFrameHost* fenced_frame = + RenderFrameHostTester::For(main_rfh()) + ->AppendFencedFrame(blink::mojom::FencedFrameMode::kOpaqueAds); + + static constexpr char kAllowedOriginUrl[] = "https://a.test"; + + const struct { + const char* fenced_frame_url; + bool expected; + } kTestCases[] = { + {kAllowedOriginUrl, true}, + {"https://b.test", false}, + }; + + for (const auto& test_case : kTestCases) { + EXPECT_CALL(*mock_data_host_manager(), + NotifyFencedFrameReportingBeaconStarted) + .Times(test_case.expected); + + auto simulator = NavigationSimulatorImpl::CreateRendererInitiated( + GURL(test_case.fenced_frame_url), fenced_frame); + simulator->SetPermissionsPolicyHeader( + {blink::ParsedPermissionsPolicyDeclaration( + blink::mojom::PermissionsPolicyFeature::kAttributionReporting, + /*allowed_origins=*/ + {blink::OriginWithPossibleWildcards( + url::Origin::Create(GURL(kAllowedOriginUrl)), + /*has_subdomain_wildcard=*/false)}, + /*matches_all_origins=*/false, /*matches_opaque_src=*/false)}); + simulator->Commit(); + fenced_frame = simulator->GetFinalRenderFrameHost(); + + conversion_host()->NotifyFencedFrameReportingBeaconStarted( + EventBeaconId(123), static_cast<RenderFrameHostImpl*>(fenced_frame)); + } +} + } // namespace } // namespace content
diff --git a/content/browser/child_process_launcher_helper_mac.cc b/content/browser/child_process_launcher_helper_mac.cc index 57a5e8af..27cfd07 100644 --- a/content/browser/child_process_launcher_helper_mac.cc +++ b/content/browser/child_process_launcher_helper_mac.cc
@@ -55,7 +55,8 @@ return *cache; } - sandbox::mac::SandboxPolicy* Query(sandbox::mojom::Sandbox sandbox_type) { + const sandbox::mac::SandboxPolicy* Query( + sandbox::mojom::Sandbox sandbox_type) { base::AutoLock lock(lock_); auto it = cache_.find(sandbox_type); if (it == cache_.end()) @@ -138,7 +139,7 @@ // problem. options->environment.insert(std::make_pair("OS_ACTIVITY_MODE", "disable")); - auto* cached_policy = SandboxProfileCache::Get().Query(sandbox_type); + const auto* cached_policy = SandboxProfileCache::Get().Query(sandbox_type); if (cached_policy) { policy_ = *cached_policy; } else {
diff --git a/content/browser/devtools/protocol/target_handler.cc b/content/browser/devtools/protocol/target_handler.cc index 3e49127d..2a4010833 100644 --- a/content/browser/devtools/protocol/target_handler.cc +++ b/content/browser/devtools/protocol/target_handler.cc
@@ -241,8 +241,7 @@ base::StringPiece message_sp(reinterpret_cast<const char*>(message.data()), message.size()); if (agent_host == page_host_.get()) { - std::unique_ptr<base::Value> value = - base::JSONReader::ReadDeprecated(message_sp); + absl::optional<base::Value> value = base::JSONReader::Read(message_sp); if (!value || !value->is_dict()) { return; }
diff --git a/content/browser/loader/navigation_early_hints_browsertest.cc b/content/browser/loader/navigation_early_hints_browsertest.cc index 0720a87..21f4950 100644 --- a/content/browser/loader/navigation_early_hints_browsertest.cc +++ b/content/browser/loader/navigation_early_hints_browsertest.cc
@@ -149,9 +149,8 @@ class NavigationEarlyHintsTest : public ContentBrowserTest { public: NavigationEarlyHintsTest() { - feature_list_.InitWithFeatures( - {net::features::kSplitCacheByNetworkIsolationKey}, - {net::features::kForceIsolationInfoFrameOriginToTopLevelFrame}); + feature_list_.InitAndEnableFeature( + net::features::kSplitCacheByNetworkIsolationKey); } ~NavigationEarlyHintsTest() override = default;
diff --git a/content/browser/navigation_browsertest.cc b/content/browser/navigation_browsertest.cc index 5fb1122f..11ed7e2 100644 --- a/content/browser/navigation_browsertest.cc +++ b/content/browser/navigation_browsertest.cc
@@ -349,24 +349,6 @@ } }; -class NetworkDoubleKeyIsolationNavigationBrowserTest - : public ContentBrowserTest { - public: - NetworkDoubleKeyIsolationNavigationBrowserTest() { - scoped_feature_list_.InitWithFeatures( - {net::features::kForceIsolationInfoFrameOriginToTopLevelFrame}, {}); - } - - protected: - void SetUpOnMainThread() override { - ASSERT_TRUE(embedded_test_server()->Start()); - ContentBrowserTest::SetUpOnMainThread(); - } - - private: - base::test::ScopedFeatureList scoped_feature_list_; -}; - class NavigationBrowserTestReferrerPolicy : public NavigationBrowserTest, public ::testing::WithParamInterface<network::mojom::ReferrerPolicy> { @@ -948,46 +930,6 @@ .IsEqualForTesting(iframe_request->trusted_params->isolation_info)); } -IN_PROC_BROWSER_TEST_F(NetworkDoubleKeyIsolationNavigationBrowserTest, - SubframeDoubleKeyNetworkIsolation) { - GURL url_top(embedded_test_server()->GetURL("/page_with_iframe.html")); - GURL url_iframe = embedded_test_server()->GetURL("/title1.html"); - url::Origin origin = url::Origin::Create(url_top); - URLLoaderMonitor monitor({url_iframe}); - EXPECT_TRUE(NavigateToURL(shell(), url_top)); - monitor.WaitForUrls(); - - absl::optional<network::ResourceRequest> main_frame_request = - monitor.GetRequestInfo(url_top); - ASSERT_TRUE(main_frame_request.has_value()); - ASSERT_TRUE(main_frame_request->trusted_params); - EXPECT_TRUE(net::IsolationInfo::Create( - net::IsolationInfo::RequestType::kMainFrame, origin, origin, - net::SiteForCookies::FromOrigin(origin), - std::set<net::SchemefulSite>()) - .IsEqualForTesting( - main_frame_request->trusted_params->isolation_info)); - - absl::optional<network::ResourceRequest> iframe_request = - monitor.GetRequestInfo(url_iframe); - ASSERT_TRUE(iframe_request->trusted_params); - - // IsolationInfo and NIK of subframe should only reflect the main_frame's - // origin when these flags are on because double key does not include the - // subframe's origin. - EXPECT_TRUE( - net::IsolationInfo::Create(net::IsolationInfo::RequestType::kSubFrame, - origin, origin, - net::SiteForCookies::FromOrigin(origin), - std::set<net::SchemefulSite>()) - .IsEqualForTesting(iframe_request->trusted_params->isolation_info)); - - EXPECT_EQ( - main_frame_request->trusted_params->isolation_info - .network_isolation_key(), - iframe_request->trusted_params->isolation_info.network_isolation_key()); -} - // Tests that the initiator is not set for a browser initiated top frame // navigation. IN_PROC_BROWSER_TEST_F(NavigationBrowserTest, BrowserNavigationInitiator) { @@ -4506,9 +4448,8 @@ : public NavigationBaseBrowserTest { public: NetworkIsolationSplitCacheAppendIframeOrigin() { - feature_list_.InitWithFeatures( - {net::features::kSplitCacheByNetworkIsolationKey}, - {net::features::kForceIsolationInfoFrameOriginToTopLevelFrame}); + feature_list_.InitAndEnableFeature( + net::features::kSplitCacheByNetworkIsolationKey); } private:
diff --git a/content/browser/network/split_cache_browsertest.cc b/content/browser/network/split_cache_browsertest.cc index 5a013e39..076cac8 100644 --- a/content/browser/network/split_cache_browsertest.cc +++ b/content/browser/network/split_cache_browsertest.cc
@@ -391,9 +391,8 @@ : public SplitCacheContentBrowserTest { public: SplitCacheRegistrableDomainContentBrowserTest() { - feature_list_.InitWithFeatures( - {net::features::kSplitCacheByNetworkIsolationKey}, - {net::features::kForceIsolationInfoFrameOriginToTopLevelFrame}); + feature_list_.InitAndEnableFeature( + net::features::kSplitCacheByNetworkIsolationKey); } private: @@ -406,11 +405,9 @@ public: SplitCacheContentBrowserTestEnabled() { std::vector<base::test::FeatureRef> enabled_features; + std::vector<base::test::FeatureRef> disabled_features; enabled_features.push_back(net::features::kSplitCacheByNetworkIsolationKey); - std::vector<base::test::FeatureRef> disabled_features; - disabled_features.push_back( - net::features::kForceIsolationInfoFrameOriginToTopLevelFrame); // When the test parameter is true, we test the split cache with // PlzDedicatedWorker enabled. if (GetParam())
diff --git a/content/browser/renderer_host/render_widget_host_view_ios.h b/content/browser/renderer_host/render_widget_host_view_ios.h index 4dfd088..4d72f14 100644 --- a/content/browser/renderer_host/render_widget_host_view_ios.h +++ b/content/browser/renderer_host/render_widget_host_view_ios.h
@@ -128,6 +128,10 @@ void SetCurrentDeviceScaleFactor(float device_scale_factor) override; void UpdateScreenInfo() override; void TransformPointToRootSurface(gfx::PointF* point) override; + bool TransformPointToCoordSpaceForView( + const gfx::PointF& point, + RenderWidgetHostViewBase* target_view, + gfx::PointF* transformed_point) override; void ProcessAckedTouchEvent( const TouchEventWithLatencyInfo& touch, blink::mojom::InputEventResultState ack_result) override;
diff --git a/content/browser/renderer_host/render_widget_host_view_ios.mm b/content/browser/renderer_host/render_widget_host_view_ios.mm index 93b58466..e270242 100644 --- a/content/browser/renderer_host/render_widget_host_view_ios.mm +++ b/content/browser/renderer_host/render_widget_host_view_ios.mm
@@ -499,6 +499,19 @@ browser_compositor_->TransformPointToRootSurface(point); } +bool RenderWidgetHostViewIOS::TransformPointToCoordSpaceForView( + const gfx::PointF& point, + RenderWidgetHostViewBase* target_view, + gfx::PointF* transformed_point) { + if (target_view == this) { + *transformed_point = point; + return true; + } + + return target_view->TransformPointToLocalCoordSpace( + point, GetCurrentSurfaceId(), transformed_point); +} + display::ScreenInfo RenderWidgetHostViewIOS::GetCurrentScreenInfo() const { return screen_infos_.current(); }
diff --git a/content/browser/web_package/signed_exchange_loader.cc b/content/browser/web_package/signed_exchange_loader.cc index a196ea04..240d70f5 100644 --- a/content/browser/web_package/signed_exchange_loader.cc +++ b/content/browser/web_package/signed_exchange_loader.cc
@@ -50,16 +50,10 @@ if (!outer_request.trusted_params || outer_request.trusted_params->isolation_info.IsEmpty()) return net::IsolationInfo(); - if (net::IsolationInfo::IsFrameSiteEnabled()) { - return net::IsolationInfo::Create( - net::IsolationInfo::RequestType::kOther, - *outer_request.trusted_params->isolation_info.top_frame_origin(), - *outer_request.trusted_params->isolation_info.frame_origin(), - net::SiteForCookies()); - } - return net::IsolationInfo::CreateDoubleKey( + return net::IsolationInfo::Create( net::IsolationInfo::RequestType::kOther, *outer_request.trusted_params->isolation_info.top_frame_origin(), + *outer_request.trusted_params->isolation_info.frame_origin(), net::SiteForCookies()); }
diff --git a/content/browser/webid/fedcm_metrics.cc b/content/browser/webid/fedcm_metrics.cc index 3e2dc0b..81b43c6e 100644 --- a/content/browser/webid/fedcm_metrics.cc +++ b/content/browser/webid/fedcm_metrics.cc
@@ -214,7 +214,10 @@ void FedCmMetrics::RecordAutoReauthnMetrics( bool has_single_returning_account, const IdentityRequestAccount* auto_signin_account, - bool auto_reauthn_success) { + bool auto_reauthn_success, + bool is_auto_reauthn_setting_blocked, + bool is_auto_reauthn_embargoed, + absl::optional<base::TimeDelta> time_from_embargo) { NumReturningAccounts num_returning_accounts = NumReturningAccounts::kZero; if (has_single_returning_account) { num_returning_accounts = NumReturningAccounts::kOne; @@ -226,11 +229,30 @@ num_returning_accounts); base::UmaHistogramBoolean("Blink.FedCm.AutoReauthn.Succeeded", auto_reauthn_success); - + base::UmaHistogramBoolean("Blink.FedCm.AutoReauthn.BlockedByContentSettings", + is_auto_reauthn_setting_blocked); + base::UmaHistogramBoolean("Blink.FedCm.AutoReauthn.BlockedByEmbargo", + is_auto_reauthn_embargoed); ukm::builders::Blink_FedCm ukm_builder(page_source_id_); + if (time_from_embargo) { + // Use a custom histogram with the default number of buckets so that we set + // the maximum to the permission embargo duration: 10 minutes. See + // `kFederatedIdentityAutoReauthnEmbargoDuration`. + base::UmaHistogramCustomTimes( + "Blink.FedCm.AutoReauthn.TimeFromEmbargoWhenBlocked", + *time_from_embargo, base::Milliseconds(10), base::Minutes(10), + /*buckets=*/50); + ukm_builder.SetAutoReauthn_TimeFromEmbargoWhenBlocked( + ukm::GetExponentialBucketMinForUserTiming( + time_from_embargo->InMilliseconds())); + } + ukm_builder.SetAutoReauthn_ReturningAccounts( static_cast<int>(num_returning_accounts)); ukm_builder.SetAutoReauthn_Succeeded(auto_reauthn_success); + ukm_builder.SetAutoReauthn_BlockedByContentSettings( + is_auto_reauthn_setting_blocked); + ukm_builder.SetAutoReauthn_BlockedByEmbargo(is_auto_reauthn_embargoed); ukm_builder.SetFedCmSessionID(session_id_); ukm_builder.Record(ukm::UkmRecorder::Get()); }
diff --git a/content/browser/webid/fedcm_metrics.h b/content/browser/webid/fedcm_metrics.h index e207e91d..fa985911 100644 --- a/content/browser/webid/fedcm_metrics.h +++ b/content/browser/webid/fedcm_metrics.h
@@ -153,11 +153,14 @@ kMaxValue = kMultiple }; - // Records some auto reauthn metrics. + // Records several auto reauthn metrics using the given parameters. void RecordAutoReauthnMetrics( bool has_single_returning_account, const IdentityRequestAccount* auto_signin_account, - bool auto_reauthn_success); + bool auto_reauthn_success, + bool is_auto_reauthn_setting_blocked, + bool is_auto_reauthn_embargoed, + absl::optional<base::TimeDelta> time_from_embargo); private: // The page's SourceId. Used to log the UKM event Blink.FedCm.
diff --git a/content/browser/webid/federated_auth_request_impl.cc b/content/browser/webid/federated_auth_request_impl.cc index 633fb15c..eafb8e0 100644 --- a/content/browser/webid/federated_auth_request_impl.cc +++ b/content/browser/webid/federated_auth_request_impl.cc
@@ -921,12 +921,23 @@ idp_enabled_auto_reauthn && IsFedCmAutoReauthnEnabled(); bool auto_reauthn = auto_reauthn_enabled; - if (auto_reauthn_enabled && - !auto_reauthn_permission_delegate_->HasAutoReauthnPermission( - GetEmbeddingOrigin())) { - // `auto_reauthn_permission_delegate_` will log the failure reason, so no - // need to log it here. - auto_reauthn = false; + bool has_auto_reauthn_content_setting = false; + bool is_auto_reauthn_embargoed = false; + absl::optional<base::TimeDelta> time_from_embargo; + if (auto_reauthn_enabled) { + has_auto_reauthn_content_setting = + auto_reauthn_permission_delegate_->HasAutoReauthnContentSetting(); + auto_reauthn &= has_auto_reauthn_content_setting; + is_auto_reauthn_embargoed = + auto_reauthn_permission_delegate_->IsAutoReauthnEmbargoed( + GetEmbeddingOrigin()); + if (is_auto_reauthn_embargoed) { + time_from_embargo = + base::Time::Now() - + auto_reauthn_permission_delegate_->GetAutoReauthnEmbargoStartTime( + GetEmbeddingOrigin()); + } + auto_reauthn &= !is_auto_reauthn_embargoed; } const IdentityProviderData* auto_reauthn_idp = nullptr; @@ -971,7 +982,9 @@ if (auto_reauthn_enabled) { fedcm_metrics_->RecordAutoReauthnMetrics( - has_single_returning_account, auto_reauthn_account, auto_reauthn); + has_single_returning_account, auto_reauthn_account, auto_reauthn, + !has_auto_reauthn_content_setting, is_auto_reauthn_embargoed, + time_from_embargo); } }
diff --git a/content/browser/webid/federated_auth_request_impl_unittest.cc b/content/browser/webid/federated_auth_request_impl_unittest.cc index 57d9ba6..f2821868 100644 --- a/content/browser/webid/federated_auth_request_impl_unittest.cc +++ b/content/browser/webid/federated_auth_request_impl_unittest.cc
@@ -974,9 +974,28 @@ EXPECT_TRUE(metric_found) << "No Status.SignInStateMatch was found"; } - void ExpectAutoReauthnUKM( + void ExpectAutoReauthnMetrics( FedCmMetrics::NumReturningAccounts expected_returning_accounts, - bool expected_succeeded) { + bool expected_succeeded, + bool expected_auto_reauthn_setting_blocked, + bool expected_auto_reauthn_embargoed) { + // UMA checks + histogram_tester_.ExpectUniqueSample("Blink.FedCm.AutoReauthn.Succeeded", + expected_succeeded, 1); + histogram_tester_.ExpectUniqueSample( + "Blink.FedCm.AutoReauthn.ReturningAccounts", + static_cast<int>(expected_returning_accounts), 1); + histogram_tester_.ExpectUniqueSample( + "Blink.FedCm.AutoReauthn.BlockedByContentSettings", + expected_auto_reauthn_setting_blocked, 1); + histogram_tester_.ExpectUniqueSample( + "Blink.FedCm.AutoReauthn.BlockedByEmbargo", + expected_auto_reauthn_embargoed, 1); + histogram_tester_.ExpectTotalCount( + "Blink.FedCm.AutoReauthn.TimeFromEmbargoWhenBlocked", + expected_auto_reauthn_embargoed ? 1 : 0); + + // UKM checks auto entries = ukm_recorder()->GetEntriesByName(FedCmEntry::kEntryName); ASSERT_FALSE(entries.empty()) << "No FedCM UKM entry was found!"; @@ -986,22 +1005,41 @@ ukm_recorder()->GetEntryMetric(entry, "AutoReauthn.Succeeded"); if (!metric) { EXPECT_FALSE(ukm_recorder()->GetEntryMetric( - entry, "AutoReauthn.ReturningAccounts")) - << "Found an entry with AutoReauthn.ReturningAccounts but without " - "AutoReauthn.Succeeded"; + entry, "AutoReauthn.ReturningAccounts")); + EXPECT_FALSE(ukm_recorder()->GetEntryMetric( + entry, "AutoReauthn.BlockedByContentSettings")); + EXPECT_FALSE(ukm_recorder()->GetEntryMetric( + entry, "AutoReauthn.BlockedByEmbargo")); + EXPECT_FALSE(ukm_recorder()->GetEntryMetric( + entry, "AutoReauthn.TimeFromEmbargoWhenBlocked")); continue; } EXPECT_FALSE(metric_found) << "Found more than one AutoReauthn entry"; metric_found = true; EXPECT_EQ(expected_succeeded, *metric); - const int64_t* returning_accounts_metric = ukm_recorder()->GetEntryMetric( - entry, "AutoReauthn.ReturningAccounts"); - ASSERT_TRUE(returning_accounts_metric) - << "AutoReauthn.ReturningAccounts was not found"; - EXPECT_EQ(static_cast<int>(expected_returning_accounts), - *returning_accounts_metric); + + metric = ukm_recorder()->GetEntryMetric(entry, + "AutoReauthn.ReturningAccounts"); + ASSERT_TRUE(metric) << "AutoReauthn.ReturningAccounts was not found"; + EXPECT_EQ(static_cast<int>(expected_returning_accounts), *metric); + + metric = ukm_recorder()->GetEntryMetric( + entry, "AutoReauthn.BlockedByContentSettings"); + ASSERT_TRUE(metric) + << "AutoReauthn.BlockedByContentSettings was not found"; + EXPECT_EQ(expected_auto_reauthn_setting_blocked, *metric); + + metric = + ukm_recorder()->GetEntryMetric(entry, "AutoReauthn.BlockedByEmbargo"); + ASSERT_TRUE(metric) << "AutoReauthn.BlockedByEmbargo was not found"; + EXPECT_EQ(expected_auto_reauthn_embargoed, *metric); + + metric = ukm_recorder()->GetEntryMetric( + entry, "AutoReauthn.TimeFromEmbargoWhenBlocked"); + EXPECT_EQ(expected_auto_reauthn_embargoed, !!metric); } EXPECT_TRUE(metric_found) << "Did not find AutoReauthn metrics"; + CheckAllFedCmSessionIDs(); } void CheckAllFedCmSessionIDs() { @@ -1382,8 +1420,11 @@ // Pretend the auto re-authn permission has been granted. EXPECT_CALL(*test_auto_reauthn_permission_delegate_, - HasAutoReauthnPermission(OriginFromString(kRpUrl))) + HasAutoReauthnContentSetting()) .WillOnce(Return(true)); + EXPECT_CALL(*test_auto_reauthn_permission_delegate_, + IsAutoReauthnEmbargoed(OriginFromString(kRpUrl))) + .WillOnce(Return(false)); RequestParameters request_parameters = kDefaultRequestParameters; request_parameters.auto_reauthn = true; @@ -1395,14 +1436,10 @@ EXPECT_TRUE(test_auto_reauthn_permission_delegate_->embargoed_origins_.count( OriginFromString(kRpUrl))); - histogram_tester_.ExpectUniqueSample("Blink.FedCm.AutoReauthn.Succeeded", - true, 1); - histogram_tester_.ExpectUniqueSample( - "Blink.FedCm.AutoReauthn.ReturningAccounts", - static_cast<int>(FedCmMetrics::NumReturningAccounts::kOne), 1); - ExpectAutoReauthnUKM(FedCmMetrics::NumReturningAccounts::kOne, - /*expected_succeeded=*/true); - CheckAllFedCmSessionIDs(); + ExpectAutoReauthnMetrics(FedCmMetrics::NumReturningAccounts::kOne, + /*expected_succeeded=*/true, + /*expected_auto_reauthn_setting_blocked=*/false, + /*expected_auto_reauthn_embargoed=*/false); } // Test that auto re-authn with a single account where the account is a @@ -1422,8 +1459,11 @@ // Pretend the auto re-authn permission has been granted. EXPECT_CALL(*test_auto_reauthn_permission_delegate_, - HasAutoReauthnPermission(OriginFromString(kRpUrl))) + HasAutoReauthnContentSetting()) .WillOnce(Return(true)); + EXPECT_CALL(*test_auto_reauthn_permission_delegate_, + IsAutoReauthnEmbargoed(OriginFromString(kRpUrl))) + .WillOnce(Return(false)); for (const auto& idp_info : kConfigurationValid.idp_info) { ASSERT_EQ(idp_info.second.accounts.size(), 1u); @@ -1436,14 +1476,10 @@ EXPECT_EQ(displayed_accounts()[0].login_state, LoginState::kSignIn); EXPECT_EQ(dialog_controller_state_.sign_in_mode, SignInMode::kAuto); - histogram_tester_.ExpectUniqueSample("Blink.FedCm.AutoReauthn.Succeeded", - true, 1); - histogram_tester_.ExpectUniqueSample( - "Blink.FedCm.AutoReauthn.ReturningAccounts", - static_cast<int>(FedCmMetrics::NumReturningAccounts::kOne), 1); - ExpectAutoReauthnUKM(FedCmMetrics::NumReturningAccounts::kOne, - /*expected_succeeded=*/true); - CheckAllFedCmSessionIDs(); + ExpectAutoReauthnMetrics(FedCmMetrics::NumReturningAccounts::kOne, + /*expected_succeeded=*/true, + /*expected_auto_reauthn_setting_blocked=*/false, + /*expected_auto_reauthn_embargoed=*/false); } // Test that auto re-authn with multiple accounts and a single returning user @@ -1477,8 +1513,11 @@ // Pretend the auto re-authn permission has been granted. EXPECT_CALL(*test_auto_reauthn_permission_delegate_, - HasAutoReauthnPermission(OriginFromString(kRpUrl))) + HasAutoReauthnContentSetting()) .WillOnce(Return(true)); + EXPECT_CALL(*test_auto_reauthn_permission_delegate_, + IsAutoReauthnEmbargoed(OriginFromString(kRpUrl))) + .WillOnce(Return(false)); RequestParameters request_parameters = kDefaultRequestParameters; request_parameters.auto_reauthn = true; @@ -1492,14 +1531,10 @@ EXPECT_EQ(CountNumLoginStateIsSignin(), 1); EXPECT_EQ(dialog_controller_state_.sign_in_mode, SignInMode::kAuto); - histogram_tester_.ExpectUniqueSample("Blink.FedCm.AutoReauthn.Succeeded", - true, 1); - histogram_tester_.ExpectUniqueSample( - "Blink.FedCm.AutoReauthn.ReturningAccounts", - static_cast<int>(FedCmMetrics::NumReturningAccounts::kOne), 1); - ExpectAutoReauthnUKM(FedCmMetrics::NumReturningAccounts::kOne, - /*expected_succeeded=*/true); - CheckAllFedCmSessionIDs(); + ExpectAutoReauthnMetrics(FedCmMetrics::NumReturningAccounts::kOne, + /*expected_succeeded=*/true, + /*expected_auto_reauthn_setting_blocked=*/false, + /*expected_auto_reauthn_embargoed=*/false); } // Test that auto re-authn with multiple accounts and multiple returning users @@ -1534,8 +1569,11 @@ // Pretend the auto re-authn permission has been granted. EXPECT_CALL(*test_auto_reauthn_permission_delegate_, - HasAutoReauthnPermission(OriginFromString(kRpUrl))) + HasAutoReauthnContentSetting()) .WillOnce(Return(true)); + EXPECT_CALL(*test_auto_reauthn_permission_delegate_, + IsAutoReauthnEmbargoed(OriginFromString(kRpUrl))) + .WillOnce(Return(false)); RequestParameters request_parameters = kDefaultRequestParameters; request_parameters.auto_reauthn = true; @@ -1550,14 +1588,10 @@ EXPECT_EQ(CountNumLoginStateIsSignin(), 2); EXPECT_EQ(dialog_controller_state_.sign_in_mode, SignInMode::kExplicit); - histogram_tester_.ExpectUniqueSample("Blink.FedCm.AutoReauthn.Succeeded", - false, 1); - histogram_tester_.ExpectUniqueSample( - "Blink.FedCm.AutoReauthn.ReturningAccounts", - static_cast<int>(FedCmMetrics::NumReturningAccounts::kMultiple), 1); - ExpectAutoReauthnUKM(FedCmMetrics::NumReturningAccounts::kMultiple, - /*expected_succeeded=*/false); - CheckAllFedCmSessionIDs(); + ExpectAutoReauthnMetrics(FedCmMetrics::NumReturningAccounts::kMultiple, + /*expected_succeeded=*/false, + /*expected_auto_reauthn_setting_blocked=*/false, + /*expected_auto_reauthn_embargoed=*/false); } // Test that auto re-authn with single non-returning account sets the sign-in @@ -1575,8 +1609,11 @@ // Pretend the auto re-authn permission has been granted. EXPECT_CALL(*test_auto_reauthn_permission_delegate_, - HasAutoReauthnPermission(OriginFromString(kRpUrl))) + HasAutoReauthnContentSetting()) .WillOnce(Return(true)); + EXPECT_CALL(*test_auto_reauthn_permission_delegate_, + IsAutoReauthnEmbargoed(OriginFromString(kRpUrl))) + .WillOnce(Return(false)); for (const auto& idp_info : kConfigurationValid.idp_info) { ASSERT_EQ(idp_info.second.accounts.size(), 1u); @@ -1589,14 +1626,10 @@ EXPECT_EQ(displayed_accounts()[0].login_state, LoginState::kSignUp); EXPECT_EQ(dialog_controller_state_.sign_in_mode, SignInMode::kExplicit); - histogram_tester_.ExpectUniqueSample("Blink.FedCm.AutoReauthn.Succeeded", - false, 1); - histogram_tester_.ExpectUniqueSample( - "Blink.FedCm.AutoReauthn.ReturningAccounts", - static_cast<int>(FedCmMetrics::NumReturningAccounts::kZero), 1); - ExpectAutoReauthnUKM(FedCmMetrics::NumReturningAccounts::kZero, - /*expected_succeeded=*/false); - CheckAllFedCmSessionIDs(); + ExpectAutoReauthnMetrics(FedCmMetrics::NumReturningAccounts::kZero, + /*expected_succeeded=*/false, + /*expected_auto_reauthn_setting_blocked=*/false, + /*expected_auto_reauthn_embargoed=*/false); } // Test that auto re-authn with multiple accounts and a single returning user @@ -1639,8 +1672,11 @@ // Pretend the auto re-authn permission has been granted. EXPECT_CALL(*test_auto_reauthn_permission_delegate_, - HasAutoReauthnPermission(OriginFromString(kRpUrl))) + HasAutoReauthnContentSetting()) .WillOnce(Return(true)); + EXPECT_CALL(*test_auto_reauthn_permission_delegate_, + IsAutoReauthnEmbargoed(OriginFromString(kRpUrl))) + .WillOnce(Return(false)); RequestParameters request_parameters = kDefaultRequestParameters; request_parameters.auto_reauthn = true; @@ -1665,8 +1701,11 @@ // Pretend the auto re-authn permission has been granted. EXPECT_CALL(*test_auto_reauthn_permission_delegate_, - HasAutoReauthnPermission(OriginFromString(kRpUrl))) + HasAutoReauthnContentSetting()) .WillOnce(Return(true)); + EXPECT_CALL(*test_auto_reauthn_permission_delegate_, + IsAutoReauthnEmbargoed(OriginFromString(kRpUrl))) + .WillOnce(Return(false)); RequestParameters request_parameters = kDefaultRequestParameters; request_parameters.auto_reauthn = true; @@ -1693,7 +1732,7 @@ // Pretend the auto re-authn permission has been blocked for this account. EXPECT_CALL(*test_auto_reauthn_permission_delegate_, - HasAutoReauthnPermission(OriginFromString(kRpUrl))) + HasAutoReauthnContentSetting()) .WillOnce(Return(false)); RequestParameters request_parameters = kDefaultRequestParameters; @@ -1703,6 +1742,47 @@ ASSERT_EQ(displayed_accounts().size(), 1u); EXPECT_EQ(displayed_accounts()[0].login_state, LoginState::kSignIn); EXPECT_EQ(dialog_controller_state_.sign_in_mode, SignInMode::kExplicit); + + ExpectAutoReauthnMetrics(FedCmMetrics::NumReturningAccounts::kOne, + /*expected_succeeded=*/false, + /*expected_auto_reauthn_setting_blocked=*/true, + /*expected_auto_reauthn_embargoed=*/false); +} + +// Test that auto re-authn where the auto re-authn cooldown is on sets +// the sign-in mode to explicit. +TEST_F(FederatedAuthRequestImplTest, AutoReauthnWithCooldown) { + base::test::ScopedFeatureList list; + list.InitAndEnableFeature(features::kFedCmAutoReauthn); + + // Pretend the sharing permission has been granted for this account. + EXPECT_CALL( + *test_permission_delegate_, + HasSharingPermission(OriginFromString(kRpUrl), OriginFromString(kRpUrl), + OriginFromString(kProviderUrlFull), kAccountId)) + .WillRepeatedly(Return(true)); + + // Pretend the auto re-authn permission has been granted for this account. + EXPECT_CALL(*test_auto_reauthn_permission_delegate_, + HasAutoReauthnContentSetting()) + .WillOnce(Return(true)); + // Pretend that auto re-authn is embargoed. + EXPECT_CALL(*test_auto_reauthn_permission_delegate_, + IsAutoReauthnEmbargoed(OriginFromString(kRpUrl))) + .WillOnce(Return(true)); + + RequestParameters request_parameters = kDefaultRequestParameters; + request_parameters.auto_reauthn = true; + RunAuthTest(request_parameters, kExpectationSuccess, kConfigurationValid); + + ASSERT_EQ(displayed_accounts().size(), 1u); + EXPECT_EQ(displayed_accounts()[0].login_state, LoginState::kSignIn); + EXPECT_EQ(dialog_controller_state_.sign_in_mode, SignInMode::kExplicit); + + ExpectAutoReauthnMetrics(FedCmMetrics::NumReturningAccounts::kOne, + /*expected_succeeded=*/false, + /*expected_auto_reauthn_setting_blocked=*/false, + /*expected_auto_reauthn_embargoed=*/true); } TEST_F(FederatedAuthRequestImplTest, MetricsForSuccessfulSignInCase) {
diff --git a/content/browser/webid/test/mock_auto_reauthn_permission_delegate.h b/content/browser/webid/test/mock_auto_reauthn_permission_delegate.h index 186f7e9..5816162 100644 --- a/content/browser/webid/test/mock_auto_reauthn_permission_delegate.h +++ b/content/browser/webid/test/mock_auto_reauthn_permission_delegate.h
@@ -22,7 +22,9 @@ MockAutoReauthnPermissionDelegate& operator=( const MockAutoReauthnPermissionDelegate&) = delete; - MOCK_METHOD1(HasAutoReauthnPermission, bool(const url::Origin&)); + MOCK_METHOD0(HasAutoReauthnContentSetting, bool()); + MOCK_METHOD1(IsAutoReauthnEmbargoed, bool(const url::Origin&)); + MOCK_METHOD1(GetAutoReauthnEmbargoStartTime, base::Time(const url::Origin&)); MOCK_METHOD1(RecordDisplayAndEmbargo, void(const url::Origin&)); };
diff --git a/content/gpu/gpu_sandbox_hook_linux.cc b/content/gpu/gpu_sandbox_hook_linux.cc index d93285a5..62712eee 100644 --- a/content/gpu/gpu_sandbox_hook_linux.cc +++ b/content/gpu/gpu_sandbox_hook_linux.cc
@@ -282,8 +282,11 @@ // To support threads in mesa we use --gpu-sandbox-start-early and // that requires the following libs and files to be accessible. "/usr/lib64/libEGL.so.1", "/usr/lib64/libGLESv2.so.2", - "/usr/lib64/libglapi.so.0", "/usr/lib64/dri/i965_dri.so", - "/usr/lib64/dri/iris_dri.so", + "/usr/lib64/libelf.so.1", "/usr/lib64/libglapi.so.0", + "/usr/lib64/libdrm_amdgpu.so.1", "/usr/lib64/libdrm_radeon.so.1", + "/usr/lib64/libdrm_nouveau.so.2", "/usr/lib64/dri/crocus_dri.so", + "/usr/lib64/dri/i965_dri.so", "/usr/lib64/dri/iris_dri.so", + "/usr/lib64/dri/swrast_dri.so", // Allow libglvnd files and libs. "/usr/share/glvnd/egl_vendor.d", "/usr/share/glvnd/egl_vendor.d/50_mesa.json",
diff --git a/content/public/browser/federated_identity_auto_reauthn_permission_context_delegate.h b/content/public/browser/federated_identity_auto_reauthn_permission_context_delegate.h index 907a01d..300c0c4 100644 --- a/content/public/browser/federated_identity_auto_reauthn_permission_context_delegate.h +++ b/content/public/browser/federated_identity_auto_reauthn_permission_context_delegate.h
@@ -5,6 +5,7 @@ #ifndef CONTENT_PUBLIC_BROWSER_FEDERATED_IDENTITY_AUTO_REAUTHN_PERMISSION_CONTEXT_DELEGATE_H_ #define CONTENT_PUBLIC_BROWSER_FEDERATED_IDENTITY_AUTO_REAUTHN_PERMISSION_CONTEXT_DELEGATE_H_ +#include "base/time/time.h" #include "content/common/content_export.h" namespace url { @@ -20,9 +21,22 @@ FederatedIdentityAutoReauthnPermissionContextDelegate() = default; virtual ~FederatedIdentityAutoReauthnPermissionContextDelegate() = default; - // Returns the permission status of the FedCM API's auto re-authn feature for - // the passed-in |relying_party_embedder|. - virtual bool HasAutoReauthnPermission( + // Returns whether the FedCM API's auto re-authn is unblocked based on content + // settings. A caller should also use `IsAutoReauthnEmbargoed()` to determine + // whether auto re-authn is allowed or not. + virtual bool HasAutoReauthnContentSetting() = 0; + + // Returns whether the FedCM API's auto re-authn feature is embargoed for the + // passed-in |relying_party_embedder|. A caller should also use + // `HasAutoReauthnContentSetting()` to determine whether auto re-authn is + // allowed or not. + virtual bool IsAutoReauthnEmbargoed( + const url::Origin& relying_party_embedder) = 0; + + // Returns the most recent recorded time an auto-reauthn embargo was started + // with the given |relying_party_embedder|. Returns base::Time() if no record + // is found. + virtual base::Time GetAutoReauthnEmbargoStartTime( const url::Origin& relying_party_embedder) = 0; // Records that an auto re-authn prompt was displayed to the user and places
diff --git a/content/shell/browser/shell_application_ios.mm b/content/shell/browser/shell_application_ios.mm index c92f702a..7592b83 100644 --- a/content/shell/browser/shell_application_ios.mm +++ b/content/shell/browser/shell_application_ios.mm
@@ -8,6 +8,7 @@ #error "This file requires ARC support." #endif +#include "base/command_line.h" #include "content/shell/browser/shell.h" #include "content/shell/browser/shell_browser_context.h" #include "content/shell/browser/shell_content_browser_client.h" @@ -27,10 +28,25 @@ // UIWindow* window = content::Shell::windows()[0]->window(); content::ShellBrowserContext* browserContext = content::ShellContentBrowserClient::Get()->browser_context(); - UIWindow* window = - content::Shell::CreateNewWindow(browserContext, GURL(url::kAboutBlankURL), - nullptr, gfx::Size()) - ->window(); + + GURL initial_url(url::kAboutBlankURL); + + // If a URL has been provided as an argument, use it. However, no attempt is + // made here to sanitize this input. + // TODO(crbug.com/1418123): usually this is done with GetStartupURL() and, + // ideally, we'd leverage that once the shell on ios shares more machinery. + base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); + const auto& args = command_line->GetArgs(); + if (!args.empty()) { + GURL candidate(args[0]); + if (candidate.is_valid()) { + initial_url = candidate; + } + } + + UIWindow* window = content::Shell::CreateNewWindow( + browserContext, initial_url, nullptr, gfx::Size()) + ->window(); self.window = window; return YES; }
diff --git a/content/shell/browser/shell_federated_permission_context.cc b/content/shell/browser/shell_federated_permission_context.cc index 2fb4520..a8e73fb 100644 --- a/content/shell/browser/shell_federated_permission_context.cc +++ b/content/shell/browser/shell_federated_permission_context.cc
@@ -34,11 +34,20 @@ } // FederatedIdentityAutoReauthnPermissionContextDelegate -bool ShellFederatedPermissionContext::HasAutoReauthnPermission( - const url::Origin& relying_party_embedder) { +bool ShellFederatedPermissionContext::HasAutoReauthnContentSetting() { return auto_reauthn_permission_; } +bool ShellFederatedPermissionContext::IsAutoReauthnEmbargoed( + const url::Origin& relying_party_embedder) { + return false; +} + +base::Time ShellFederatedPermissionContext::GetAutoReauthnEmbargoStartTime( + const url::Origin& relying_party_embedder) { + return base::Time(); +} + void ShellFederatedPermissionContext::RecordDisplayAndEmbargo( const url::Origin& relying_party_embedder) {}
diff --git a/content/shell/browser/shell_federated_permission_context.h b/content/shell/browser/shell_federated_permission_context.h index f550a413..5ae7e7f 100644 --- a/content/shell/browser/shell_federated_permission_context.h +++ b/content/shell/browser/shell_federated_permission_context.h
@@ -12,6 +12,7 @@ #include <vector> #include "base/functional/callback.h" +#include "base/time/time.h" #include "content/public/browser/federated_identity_api_permission_context_delegate.h" #include "content/public/browser/federated_identity_auto_reauthn_permission_context_delegate.h" #include "content/public/browser/federated_identity_permission_context_delegate.h" @@ -40,7 +41,10 @@ bool ShouldCompleteRequestImmediately() const override; // FederatedIdentityAutoReauthnPermissionContextDelegate - bool HasAutoReauthnPermission( + bool HasAutoReauthnContentSetting() override; + bool IsAutoReauthnEmbargoed( + const url::Origin& relying_party_embedder) override; + base::Time GetAutoReauthnEmbargoStartTime( const url::Origin& relying_party_embedder) override; void RecordDisplayAndEmbargo( const url::Origin& relying_party_embedder) override;
diff --git a/content/test/gpu/gpu_tests/trace_integration_test.py b/content/test/gpu/gpu_tests/trace_integration_test.py index 959db6e..171ec9c 100644 --- a/content/test/gpu/gpu_tests/trace_integration_test.py +++ b/content/test/gpu/gpu_tests/trace_integration_test.py
@@ -546,30 +546,18 @@ ]), ] for (name, first_load_page, cache_pages) in webgpu_xorigin_cache_miss_tests: - yield ( - 'WebGPUCachingTraceTest_' + name, - posixpath.join(gpu_data_relative_path, first_load_page), - [ - _CacheTraceTestArguments( - browser_args=webgpu_cache_test_browser_args + [ - # Currently it seems like this is not always the default - # yet. We may be able to remove this once it is defaulted. - # Without this flag, origin caching uses an isolation key - # that depends only on the top-level page, and hence these - # tests will fail. With the flag, the isolation key uses - # both the top-level page and the subpage. - # TODO(dawn:1568) Revisit whether this is necessary. - '--disable-features=' + - 'ForceIsolationInfoFrameOriginToTopLevelFrame' - ], - category='gpu', - test_harness_script=basic_test_harness_script, - finish_js_condition='domAutomationController._finished', - first_load_eval_func='CheckWebGPUFirstLoadCache', - cache_eval_func='CheckNoWebGPUCacheHits', - cache_pages=cache_pages, - test_renavigation=False) - ]) + yield ('WebGPUCachingTraceTest_' + name, + posixpath.join(gpu_data_relative_path, first_load_page), [ + _CacheTraceTestArguments( + browser_args=webgpu_cache_test_browser_args, + category='gpu', + test_harness_script=basic_test_harness_script, + finish_js_condition='domAutomationController._finished', + first_load_eval_func='CheckWebGPUFirstLoadCache', + cache_eval_func='CheckNoWebGPUCacheHits', + cache_pages=cache_pages, + test_renavigation=False) + ]) def _RunActualGpuTraceTest(self, test_path: str,
diff --git a/content/web_test/browser/web_test_browser_context.cc b/content/web_test/browser/web_test_browser_context.cc index 50cc205..48b12a49 100644 --- a/content/web_test/browser/web_test_browser_context.cc +++ b/content/web_test/browser/web_test_browser_context.cc
@@ -79,7 +79,7 @@ PermissionControllerDelegate* WebTestBrowserContext::GetPermissionControllerDelegate() { if (!permission_manager_.get()) - permission_manager_ = std::make_unique<WebTestPermissionManager>(); + permission_manager_ = std::make_unique<WebTestPermissionManager>(*this); return permission_manager_.get(); }
diff --git a/content/web_test/browser/web_test_control_host.cc b/content/web_test/browser/web_test_control_host.cc index 7f77d104..c58ad3d 100644 --- a/content/web_test/browser/web_test_control_host.cc +++ b/content/web_test/browser/web_test_control_host.cc
@@ -27,7 +27,6 @@ #include "base/logging.h" #include "base/path_service.h" #include "base/ranges/algorithm.h" -#include "base/run_loop.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" @@ -1470,7 +1469,8 @@ WebTestContentBrowserClient::Get() ->GetWebTestBrowserContext() ->GetWebTestPermissionManager() - ->SetPermission(type, status, origin, embedding_origin); + ->SetPermission(type, status, origin, embedding_origin, + base::DoNothing()); } void WebTestControlHost::GetWritableDirectory(
diff --git a/content/web_test/browser/web_test_permission_manager.cc b/content/web_test/browser/web_test_permission_manager.cc index 67ff4c7b..1d2bf2e 100644 --- a/content/web_test/browser/web_test_permission_manager.cc +++ b/content/web_test/browser/web_test_permission_manager.cc
@@ -10,11 +10,14 @@ #include "base/functional/bind.h" #include "base/functional/callback.h" +#include "components/content_settings/core/common/content_settings.h" #include "content/browser/permissions/permission_util.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/permission_controller.h" +#include "content/public/browser/storage_partition.h" #include "content/public/browser/web_contents.h" #include "content/web_test/browser/web_test_content_browser_client.h" +#include "services/network/public/mojom/cookie_manager.mojom.h" #include "third_party/blink/public/common/permissions/permission_utils.h" #include "third_party/blink/public/common/web_preferences/web_preferences.h" @@ -51,10 +54,11 @@ return hash; } -WebTestPermissionManager::WebTestPermissionManager() - : PermissionControllerDelegate() {} +WebTestPermissionManager::WebTestPermissionManager( + BrowserContext& browser_context) + : PermissionControllerDelegate(), browser_context_(browser_context) {} -WebTestPermissionManager::~WebTestPermissionManager() {} +WebTestPermissionManager::~WebTestPermissionManager() = default; void WebTestPermissionManager::RequestPermission( blink::PermissionType permission, @@ -247,7 +251,8 @@ blink::PermissionType permission, blink::mojom::PermissionStatus status, const GURL& url, - const GURL& embedding_url) { + const GURL& embedding_url, + blink::test::mojom::PermissionAutomation::SetPermissionCallback callback) { DCHECK_CURRENTLY_ON(BrowserThread::UI); PermissionDescription description(permission, url.DeprecatedGetOriginAsURL(), @@ -266,7 +271,7 @@ } } - OnPermissionChanged(description, status); + OnPermissionChanged(description, status, std::move(callback)); } void WebTestPermissionManager::SetPermission( @@ -287,8 +292,8 @@ applicable_permission_url = overridden_origin.GetURL(); } - SetPermission(*type, status, applicable_permission_url, embedding_url); - std::move(callback).Run(true); + SetPermission(*type, status, applicable_permission_url, embedding_url, + std::move(callback)); } void WebTestPermissionManager::ResetPermissions() { @@ -305,7 +310,9 @@ void WebTestPermissionManager::OnPermissionChanged( const PermissionDescription& permission, - blink::mojom::PermissionStatus status) { + blink::mojom::PermissionStatus status, + blink::test::mojom::PermissionAutomation::SetPermissionCallback + permission_callback) { std::vector<base::OnceClosure> callbacks; callbacks.reserve(subscriptions_.size()); @@ -327,6 +334,37 @@ for (auto& callback : callbacks) std::move(callback).Run(); + + if (permission.type != blink::PermissionType::STORAGE_ACCESS_GRANT) { + std::move(permission_callback).Run(true); + return; + } + + // The network service expects to hear about any new storage-access permission + // grants, so we have to inform it. + absl::optional<ContentSetting> setting; + switch (status) { + case blink::mojom::PermissionStatus::GRANTED: + setting = ContentSetting::CONTENT_SETTING_ALLOW; + break; + case blink::mojom::PermissionStatus::DENIED: + setting = ContentSetting::CONTENT_SETTING_BLOCK; + break; + case blink::mojom::PermissionStatus::ASK: + break; + } + std::vector<ContentSettingPatternSource> patterns; + if (setting) { + patterns.emplace_back( + ContentSettingsPattern::FromURL(permission.origin), + ContentSettingsPattern::FromURL(permission.embedding_origin), + base::Value(*setting), /*source=*/"", /*incognito=*/false); + } + browser_context_->GetDefaultStoragePartition() + ->GetCookieManagerForBrowserProcess() + ->SetStorageAccessGrantSettings( + patterns, + base::BindOnce(std::move(permission_callback), /*success=*/true)); } } // namespace content
diff --git a/content/web_test/browser/web_test_permission_manager.h b/content/web_test/browser/web_test_permission_manager.h index e35948ddf..82b5215 100644 --- a/content/web_test/browser/web_test_permission_manager.h +++ b/content/web_test/browser/web_test_permission_manager.h
@@ -10,6 +10,7 @@ #include "base/containers/id_map.h" #include "base/functional/callback_forward.h" #include "base/synchronization/lock.h" +#include "content/public/browser/browser_context.h" #include "content/public/browser/permission_controller_delegate.h" #include "content/public/browser/permission_result.h" #include "mojo/public/cpp/bindings/receiver_set.h" @@ -28,7 +29,8 @@ : public PermissionControllerDelegate, public blink::test::mojom::PermissionAutomation { public: - WebTestPermissionManager(); + // `browser_context` must outlive `this`. + explicit WebTestPermissionManager(BrowserContext& browser_context); WebTestPermissionManager(const WebTestPermissionManager&) = delete; WebTestPermissionManager& operator=(const WebTestPermissionManager&) = delete; @@ -85,10 +87,12 @@ void UnsubscribePermissionStatusChange( SubscriptionId subscription_id) override; - void SetPermission(blink::PermissionType permission, - blink::mojom::PermissionStatus status, - const GURL& url, - const GURL& embedding_url); + void SetPermission( + blink::PermissionType permission, + blink::mojom::PermissionStatus status, + const GURL& url, + const GURL& embedding_url, + blink::test::mojom::PermissionAutomation::SetPermissionCallback callback); void ResetPermissions(); // blink::test::mojom::PermissionAutomation @@ -131,8 +135,12 @@ using DefaultPermissionStatusMap = std::unordered_map<blink::PermissionType, blink::mojom::PermissionStatus>; - void OnPermissionChanged(const PermissionDescription& permission, - blink::mojom::PermissionStatus status); + void OnPermissionChanged( + const PermissionDescription& permission, + blink::mojom::PermissionStatus status, + blink::test::mojom::PermissionAutomation::SetPermissionCallback callback); + + raw_ref<BrowserContext> browser_context_; // Mutex for permissions access. Unfortunately, the permissions can be // accessed from the IO thread because of Notifications' synchronous IPC.
diff --git a/device/bluetooth/floss/bluetooth_adapter_floss.cc b/device/bluetooth/floss/bluetooth_adapter_floss.cc index 16adb06..297679a 100644 --- a/device/bluetooth/floss/bluetooth_adapter_floss.cc +++ b/device/bluetooth/floss/bluetooth_adapter_floss.cc
@@ -1062,7 +1062,9 @@ // createRfcommSocketToServiceRecord(UUID). This should be called after // ConnectDevice. Since all that is required on Floss for insecure connection // is an address, this function currently just creates a device pointer. - // TODO(b/259725491): This function should actually create an ACL connection. + // TODO(b/269500327): This behavior is actually a better design. We should + // rename this function to CreateDevice which does only device creation and + // let the caller decide what to do with it (Connect, Pair, etc). BluetoothDeviceFloss* device_ptr; std::string canonical_address = device::CanonicalizeBluetoothAddress(address);
diff --git a/device/bluetooth/floss/bluetooth_device_floss.cc b/device/bluetooth/floss/bluetooth_device_floss.cc index 9c9842d6..d25f44f1 100644 --- a/device/bluetooth/floss/bluetooth_device_floss.cc +++ b/device/bluetooth/floss/bluetooth_device_floss.cc
@@ -393,7 +393,9 @@ void BluetoothDeviceFloss::Pair( device::BluetoothDevice::PairingDelegate* pairing_delegate, ConnectCallback callback) { - NOTIMPLEMENTED(); + // Pair is the same as Connect due to influence from BlueZ. + // TODO(b/269516642): We should make distinction between them in the future. + Connect(pairing_delegate, std::move(callback)); } #if BUILDFLAG(IS_CHROMEOS)
diff --git a/docs/workflow/debugging-with-swarming.md b/docs/workflow/debugging-with-swarming.md index 6cbf6b62..3112f8eb 100644 --- a/docs/workflow/debugging-with-swarming.md +++ b/docs/workflow/debugging-with-swarming.md
@@ -173,7 +173,11 @@ $ tools/luci-go/isolate login ``` -Use your google.com account for this. +Use your google.com account for this. On Windows the command would be: + +``` +$ tools\luci-go\isolate.exe login +``` ## Uploading an isolate
diff --git a/extensions/browser/background_script_executor.cc b/extensions/browser/background_script_executor.cc index aa33e2c8..f83e3d62 100644 --- a/extensions/browser/background_script_executor.cc +++ b/extensions/browser/background_script_executor.cc
@@ -8,7 +8,6 @@ #include "base/json/json_reader.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/service_worker_context.h" -#include "content/public/browser/storage_partition.h" #include "content/public/test/browser_test_utils.h" #include "content/public/test/service_worker_test_helpers.h" #include "extensions/browser/extension_host.h" @@ -155,9 +154,8 @@ script_result_queue_ = std::make_unique<ScriptResultQueue>(); content::ServiceWorkerContext* service_worker_context = - util::GetStoragePartitionForExtensionId(extension_->id(), - browser_context_) - ->GetServiceWorkerContext(); + util::GetServiceWorkerContextForExtensionId(extension_->id(), + browser_context_); service_worker_context->ExecuteScriptForTest( // IN-TEST script_, worker_ids[0].version_id,
diff --git a/extensions/browser/event_router.h b/extensions/browser/event_router.h index 0e127bd..6f6e90d 100644 --- a/extensions/browser/event_router.h +++ b/extensions/browser/event_router.h
@@ -357,6 +357,8 @@ OnUserSiteSettingsChanged); FRIEND_TEST_ALL_PREFIXES(DeveloperPrivateApiAllowlistUnitTest, ExtensionUpdatedEventOnAllowlistWarningChange); + FRIEND_TEST_ALL_PREFIXES(DeveloperPrivateApiWithPermittedSitesUnitTest, + OnUserSiteSettingsChanged); FRIEND_TEST_ALL_PREFIXES(StorageApiUnittest, StorageAreaOnChanged); FRIEND_TEST_ALL_PREFIXES(StorageApiUnittest, StorageAreaOnChangedOtherListener);
diff --git a/extensions/browser/extension_event_histogram_value.h b/extensions/browser/extension_event_histogram_value.h index cb390b3..4ab4369 100644 --- a/extensions/browser/extension_event_histogram_value.h +++ b/extensions/browser/extension_event_histogram_value.h
@@ -523,6 +523,7 @@ SMART_CARD_PROVIDER_PRIVATE_ON_RELEASE_CONTEXT_REQUESTED = 501, SMART_CARD_PROVIDER_PRIVATE_ON_LIST_READERS_REQUESTED = 502, SMART_CARD_PROVIDER_PRIVATE_ON_GET_STATUS_CHANGE_REQUESTED = 503, + PDF_VIEWER_PRIVATE_ON_PDF_OCR_PREF_CHANGED = 504, // Last entry: Add new entries above, then run: // tools/metrics/histograms/update_extension_histograms.py ENUM_BOUNDARY
diff --git a/extensions/browser/extension_registrar.cc b/extensions/browser/extension_registrar.cc index df518a86..3fae9fb 100644 --- a/extensions/browser/extension_registrar.cc +++ b/extensions/browser/extension_registrar.cc
@@ -13,7 +13,6 @@ #include "content/public/browser/browser_context.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/devtools_agent_host.h" -#include "content/public/browser/storage_partition.h" #include "extensions/browser/blocklist_extension_prefs.h" #include "extensions/browser/extension_host.h" #include "extensions/browser/extension_prefs.h" @@ -284,9 +283,8 @@ } } else { content::ServiceWorkerContext* context = - util::GetStoragePartitionForExtensionId( - extension->id(), process_manager->browser_context()) - ->GetServiceWorkerContext(); + util::GetServiceWorkerContextForExtensionId( + extension->id(), process_manager->browser_context()); std::vector<WorkerId> service_worker_ids = process_manager->GetServiceWorkersForExtension(extension->id()); for (const auto& worker_id : service_worker_ids) { @@ -516,9 +514,8 @@ // extension ServiceWorkerTaskQueue and would prevent newer service worker // version from installing (crbug/1340341). content::ServiceWorkerContext* context = - util::GetStoragePartitionForExtensionId(new_extension->id(), - browser_context_) - ->GetServiceWorkerContext(); + util::GetServiceWorkerContextForExtensionId(new_extension->id(), + browser_context_); // Even though the unregistration process for a service worker is // asynchronous, we begin the process before the new extension is added, so // the old worker will be unregistered before the new one is registered.
diff --git a/extensions/browser/extension_util.cc b/extensions/browser/extension_util.cc index 06c313d..b0b0b815 100644 --- a/extensions/browser/extension_util.cc +++ b/extensions/browser/extension_util.cc
@@ -12,6 +12,7 @@ #include "content/public/browser/child_process_security_policy.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/site_instance.h" +#include "content/public/browser/storage_partition.h" #include "content/public/browser/storage_partition_config.h" #include "extensions/browser/extension_prefs.h" #include "extensions/browser/extension_registry.h" @@ -117,6 +118,13 @@ return storage_partition; } +content::ServiceWorkerContext* GetServiceWorkerContextForExtensionId( + const ExtensionId& extension_id, + content::BrowserContext* browser_context) { + return GetStoragePartitionForExtensionId(extension_id, browser_context) + ->GetServiceWorkerContext(); +} + // This function is security sensitive. Bugs could cause problems that break // restrictions on local file access or NaCl's validation caching. If you modify // this function, please get a security review from a NaCl person.
diff --git a/extensions/browser/extension_util.h b/extensions/browser/extension_util.h index f8705a6..04b1df9 100644 --- a/extensions/browser/extension_util.h +++ b/extensions/browser/extension_util.h
@@ -18,6 +18,7 @@ namespace content { class BrowserContext; +class ServiceWorkerContext; class SiteInstance; class StoragePartition; class StoragePartitionConfig; @@ -62,6 +63,11 @@ content::BrowserContext* browser_context, bool can_create = true); +// Returns the ServiceWorkerContext associated with the given `extension_id`. +content::ServiceWorkerContext* GetServiceWorkerContextForExtensionId( + const ExtensionId& extension_id, + content::BrowserContext* browser_context); + // Maps a |file_url| to a |file_path| on the local filesystem, including // resources in extensions. Returns true on success. See NaClBrowserDelegate for // full details. If |use_blocking_api| is false, only a subset of URLs will be
diff --git a/extensions/browser/permissions_manager.cc b/extensions/browser/permissions_manager.cc index 8e19db9..22cb518 100644 --- a/extensions/browser/permissions_manager.cc +++ b/extensions/browser/permissions_manager.cc
@@ -201,8 +201,12 @@ extension_prefs_(ExtensionPrefs::Get(browser_context)) { user_permissions_.restricted_sites = GetSitesFromPrefs(extension_prefs_, kRestrictedSites); - user_permissions_.permitted_sites = - GetSitesFromPrefs(extension_prefs_, kPermittedSites); + if (base::FeatureList::IsEnabled( + extensions_features:: + kExtensionsMenuAccessControlWithPermittedSites)) { + user_permissions_.permitted_sites = + GetSitesFromPrefs(extension_prefs_, kPermittedSites); + } } PermissionsManager::~PermissionsManager() { @@ -234,13 +238,21 @@ PermissionsManager::UserSiteSetting site_setting) { switch (site_setting) { case UserSiteSetting::kGrantAllExtensions: + // Granting access to all extensions is allowed iff feature is + // enabled. + DCHECK(base::FeatureList::IsEnabled( + extensions_features::kExtensionsMenuAccessControlWithPermittedSites)); AddUserPermittedSite(origin); break; case UserSiteSetting::kBlockAllExtensions: AddUserRestrictedSite(origin); break; case UserSiteSetting::kCustomizeByExtension: - RemoveUserPermittedSite(origin); + if (base::FeatureList::IsEnabled( + extensions_features:: + kExtensionsMenuAccessControlWithPermittedSites)) { + RemoveUserPermittedSite(origin); + } RemoveUserRestrictedSite(origin); break; } @@ -264,8 +276,12 @@ } void PermissionsManager::AddUserPermittedSite(const url::Origin& origin) { - if (base::Contains(user_permissions_.permitted_sites, origin)) + DCHECK(base::FeatureList::IsEnabled( + extensions_features::kExtensionsMenuAccessControlWithPermittedSites)); + + if (base::Contains(user_permissions_.permitted_sites, origin)) { return; + } // Origin cannot be both restricted and permitted. RemoveRestrictedSiteAndUpdatePrefs(origin); @@ -306,6 +322,9 @@ } void PermissionsManager::RemoveUserPermittedSite(const url::Origin& origin) { + DCHECK(base::FeatureList::IsEnabled( + extensions_features::kExtensionsMenuAccessControlWithPermittedSites)); + if (RemovePermittedSiteAndUpdatePrefs(origin)) OnUserPermissionsSettingsChanged(); }
diff --git a/extensions/browser/permissions_manager_unittest.cc b/extensions/browser/permissions_manager_unittest.cc index d163aeb88..7c4f573 100644 --- a/extensions/browser/permissions_manager_unittest.cc +++ b/extensions/browser/permissions_manager_unittest.cc
@@ -4,14 +4,15 @@ #include "extensions/browser/permissions_manager.h" #include "base/memory/raw_ptr.h" +#include "base/test/gtest_util.h" +#include "base/test/scoped_feature_list.h" #include "extensions/browser/extension_prefs.h" #include "extensions/browser/extension_registry.h" #include "extensions/browser/extension_util.h" #include "extensions/browser/extensions_test.h" #include "extensions/browser/pref_types.h" #include "extensions/common/extension_builder.h" -#include "extensions/common/extension_icon_set.h" -#include "extensions/common/extensions_client.h" +#include "extensions/common/extension_features.h" #include "extensions/common/permissions/permissions_data.h" #include "extensions/common/url_pattern_set.h" #include "testing/gmock/include/gmock/gmock.h" @@ -186,90 +187,16 @@ } TEST_F(PermissionsManagerUnittest, AddAndRemovePermittedSite) { - const url::Origin url = url::Origin::Create(GURL("http://a.example.com")); - const std::string expected_url_pattern = "http://a.example.com/*"; - std::set<url::Origin> set_with_url; - set_with_url.insert(url); - base::Value::List value_with_url; - value_with_url.Append(url.Serialize()); - // Verify the permitted sites list is empty. EXPECT_EQ(GetPermittedSitesFromManager(), std::set<url::Origin>()); EXPECT_EQ(GetPermittedSitesFromPrefs(), nullptr); EXPECT_THAT(GetPermittedSitesFromPermissionsData(), testing::IsEmpty()); - EXPECT_EQ(manager_->GetUserSiteSetting(url), - PermissionsManager::UserSiteSetting::kCustomizeByExtension); - // Add `url` to permitted sites. Verify the site is stored both in manager - // and prefs permitted sites. - manager_->AddUserPermittedSite(url); - EXPECT_EQ(GetPermittedSitesFromManager(), set_with_url); - EXPECT_EQ(*GetPermittedSitesFromPrefs(), value_with_url); - EXPECT_THAT(GetPermittedSitesFromPermissionsData(), - testing::UnorderedElementsAre(expected_url_pattern)); - EXPECT_EQ(manager_->GetUserSiteSetting(url), - PermissionsManager::UserSiteSetting::kGrantAllExtensions); - - // Adding an existent permitted site. Verify the entry is not duplicated. - manager_->AddUserPermittedSite(url); - EXPECT_EQ(GetPermittedSitesFromManager(), set_with_url); - EXPECT_EQ(*GetPermittedSitesFromPrefs(), value_with_url); - EXPECT_THAT(GetPermittedSitesFromPermissionsData(), - testing::UnorderedElementsAre(expected_url_pattern)); - - // Remove `url` from permitted sites. Verify the site is removed from both - // manager and prefs permitted sites. - manager_->RemoveUserPermittedSite(url); - EXPECT_EQ(GetPermittedSitesFromManager(), std::set<url::Origin>()); - EXPECT_EQ(*GetPermittedSitesFromPrefs(), - base::Value(base::Value::Type::LIST)); - EXPECT_THAT(GetPermittedSitesFromPermissionsData(), testing::IsEmpty()); - EXPECT_EQ(manager_->GetUserSiteSetting(url), - PermissionsManager::UserSiteSetting::kCustomizeByExtension); -} - -TEST_F(PermissionsManagerUnittest, - RestrictedAndPermittedSitesAreMutuallyExclusive) { + // Adding or removing a permitted site is only supported when + // kExtensionsMenuAccessControlWithPermittedSites is enabled. const url::Origin url = url::Origin::Create(GURL("http://a.example.com")); - std::set<url::Origin> empty_set; - std::set<url::Origin> set_with_url; - set_with_url.insert(url); - - { - manager_->AddUserRestrictedSite(url); - const PermissionsManager::UserPermissionsSettings& actual_permissions = - manager_->GetUserPermissionsSettings(); - EXPECT_EQ(actual_permissions.restricted_sites, set_with_url); - EXPECT_EQ(actual_permissions.permitted_sites, empty_set); - EXPECT_EQ(manager_->GetUserSiteSetting(url), - PermissionsManager::UserSiteSetting::kBlockAllExtensions); - } - - { - // Adding an url to the permitted sites that is already in the restricted - // sites should remove it from restricted sites and add it to permitted - // sites. - manager_->AddUserPermittedSite(url); - const PermissionsManager::UserPermissionsSettings& actual_permissions = - manager_->GetUserPermissionsSettings(); - EXPECT_EQ(actual_permissions.restricted_sites, empty_set); - EXPECT_EQ(actual_permissions.permitted_sites, set_with_url); - EXPECT_EQ(manager_->GetUserSiteSetting(url), - PermissionsManager::UserSiteSetting::kGrantAllExtensions); - } - - { - // Adding an url to the restricted sites that is already in the permitted - // sites should remove it from permitted sites and add it to restricted - // sites. - manager_->AddUserRestrictedSite(url); - const PermissionsManager::UserPermissionsSettings& actual_permissions = - manager_->GetUserPermissionsSettings(); - EXPECT_EQ(actual_permissions.restricted_sites, set_with_url); - EXPECT_EQ(actual_permissions.permitted_sites, empty_set); - EXPECT_EQ(manager_->GetUserSiteSetting(url), - PermissionsManager::UserSiteSetting::kBlockAllExtensions); - } + EXPECT_DCHECK_DEATH(manager_->AddUserPermittedSite(url)); + EXPECT_DCHECK_DEATH(manager_->RemoveUserPermittedSite(url)); } TEST_F(PermissionsManagerUnittest, UpdateUserSiteSetting) { @@ -279,14 +206,10 @@ set_with_url.insert(url); { - manager_->UpdateUserSiteSetting( - url, PermissionsManager::UserSiteSetting::kGrantAllExtensions); - const PermissionsManager::UserPermissionsSettings& actual_permissions = - manager_->GetUserPermissionsSettings(); - EXPECT_EQ(actual_permissions.restricted_sites, empty_set); - EXPECT_EQ(actual_permissions.permitted_sites, set_with_url); - EXPECT_EQ(manager_->GetUserSiteSetting(url), - PermissionsManager::UserSiteSetting::kGrantAllExtensions); + // Granting all extensions is only supported when + // kExtensionsMenuAccessControlWithPermittedSites flag is enabled. + EXPECT_DCHECK_DEATH(manager_->UpdateUserSiteSetting( + url, PermissionsManager::UserSiteSetting::kGrantAllExtensions)); } { @@ -448,4 +371,130 @@ } } +class PermissionsManagerWithPermittedSitesUnitTest + : public PermissionsManagerUnittest { + public: + PermissionsManagerWithPermittedSitesUnitTest(); + PermissionsManagerWithPermittedSitesUnitTest( + const PermissionsManagerWithPermittedSitesUnitTest&) = delete; + const PermissionsManagerWithPermittedSitesUnitTest& operator=( + const PermissionsManagerWithPermittedSitesUnitTest&) = delete; + ~PermissionsManagerWithPermittedSitesUnitTest() override = default; + + private: + base::test::ScopedFeatureList feature_list_; +}; + +PermissionsManagerWithPermittedSitesUnitTest:: + PermissionsManagerWithPermittedSitesUnitTest() { + feature_list_.InitAndEnableFeature( + extensions_features::kExtensionsMenuAccessControlWithPermittedSites); +} + +TEST_F(PermissionsManagerWithPermittedSitesUnitTest, + AddAndRemovePermittedSite) { + const url::Origin url = url::Origin::Create(GURL("http://a.example.com")); + const std::string expected_url_pattern = "http://a.example.com/*"; + std::set<url::Origin> set_with_url; + set_with_url.insert(url); + base::Value::List value_with_url; + value_with_url.Append(url.Serialize()); + + // Verify the permitted sites list is empty. + EXPECT_EQ(GetPermittedSitesFromManager(), std::set<url::Origin>()); + EXPECT_EQ(GetPermittedSitesFromPrefs(), nullptr); + EXPECT_THAT(GetPermittedSitesFromPermissionsData(), testing::IsEmpty()); + EXPECT_EQ(manager_->GetUserSiteSetting(url), + PermissionsManager::UserSiteSetting::kCustomizeByExtension); + + manager_->AddUserPermittedSite(url); + + // Verify the site is stored both in manager and prefs permitted sites. + EXPECT_EQ(GetPermittedSitesFromManager(), set_with_url); + EXPECT_EQ(*GetPermittedSitesFromPrefs(), value_with_url); + EXPECT_THAT(GetPermittedSitesFromPermissionsData(), + testing::UnorderedElementsAre(expected_url_pattern)); + EXPECT_EQ(manager_->GetUserSiteSetting(url), + PermissionsManager::UserSiteSetting::kGrantAllExtensions); + + // Adding an existent permitted site. + manager_->AddUserPermittedSite(url); + + // Verify the entry is not duplicated. + EXPECT_EQ(GetPermittedSitesFromManager(), set_with_url); + EXPECT_EQ(*GetPermittedSitesFromPrefs(), value_with_url); + EXPECT_THAT(GetPermittedSitesFromPermissionsData(), + testing::UnorderedElementsAre(expected_url_pattern)); + + // Remove `url` from permitted sites. Verify the site is removed from both + // manager and prefs permitted sites. + manager_->RemoveUserPermittedSite(url); + EXPECT_EQ(GetPermittedSitesFromManager(), std::set<url::Origin>()); + EXPECT_EQ(*GetPermittedSitesFromPrefs(), + base::Value(base::Value::Type::LIST)); + EXPECT_THAT(GetPermittedSitesFromPermissionsData(), testing::IsEmpty()); + EXPECT_EQ(manager_->GetUserSiteSetting(url), + PermissionsManager::UserSiteSetting::kCustomizeByExtension); +} + +TEST_F(PermissionsManagerWithPermittedSitesUnitTest, GrantAllExtensionsAccess) { + const url::Origin url = url::Origin::Create(GURL("http://a.example.com")); + std::set<url::Origin> empty_set; + std::set<url::Origin> set_with_url; + set_with_url.insert(url); + + manager_->UpdateUserSiteSetting( + url, PermissionsManager::UserSiteSetting::kGrantAllExtensions); + const PermissionsManager::UserPermissionsSettings& actual_permissions = + manager_->GetUserPermissionsSettings(); + EXPECT_EQ(actual_permissions.restricted_sites, empty_set); + EXPECT_EQ(actual_permissions.permitted_sites, set_with_url); + EXPECT_EQ(manager_->GetUserSiteSetting(url), + PermissionsManager::UserSiteSetting::kGrantAllExtensions); +} + +TEST_F(PermissionsManagerWithPermittedSitesUnitTest, + RestrictedAndPermittedSitesAreMutuallyExclusive) { + const url::Origin url = url::Origin::Create(GURL("http://a.example.com")); + std::set<url::Origin> empty_set; + std::set<url::Origin> set_with_url; + set_with_url.insert(url); + + { + manager_->AddUserRestrictedSite(url); + const PermissionsManager::UserPermissionsSettings& actual_permissions = + manager_->GetUserPermissionsSettings(); + EXPECT_EQ(actual_permissions.restricted_sites, set_with_url); + EXPECT_EQ(actual_permissions.permitted_sites, empty_set); + EXPECT_EQ(manager_->GetUserSiteSetting(url), + PermissionsManager::UserSiteSetting::kBlockAllExtensions); + } + + { + // Adding an url to the permitted sites that is already in the restricted + // sites should remove it from restricted sites and add it to permitted + // sites. + manager_->AddUserPermittedSite(url); + const PermissionsManager::UserPermissionsSettings& actual_permissions = + manager_->GetUserPermissionsSettings(); + EXPECT_EQ(actual_permissions.restricted_sites, empty_set); + EXPECT_EQ(actual_permissions.permitted_sites, set_with_url); + EXPECT_EQ(manager_->GetUserSiteSetting(url), + PermissionsManager::UserSiteSetting::kGrantAllExtensions); + } + + { + // Adding an url to the restricted sites that is already in the permitted + // sites should remove it from permitted sites and add it to restricted + // sites. + manager_->AddUserRestrictedSite(url); + const PermissionsManager::UserPermissionsSettings& actual_permissions = + manager_->GetUserPermissionsSettings(); + EXPECT_EQ(actual_permissions.restricted_sites, set_with_url); + EXPECT_EQ(actual_permissions.permitted_sites, empty_set); + EXPECT_EQ(manager_->GetUserSiteSetting(url), + PermissionsManager::UserSiteSetting::kBlockAllExtensions); + } +} + } // namespace extensions
diff --git a/extensions/browser/process_manager.cc b/extensions/browser/process_manager.cc index 3baf99b..115f31f 100644 --- a/extensions/browser/process_manager.cc +++ b/extensions/browser/process_manager.cc
@@ -33,7 +33,6 @@ #include "content/public/browser/service_worker_context.h" #include "content/public/browser/service_worker_external_request_result.h" #include "content/public/browser/site_instance.h" -#include "content/public/browser/storage_partition.h" #include "content/public/browser/web_contents.h" #include "content/public/common/url_constants.h" #include "extensions/browser/extension_host.h" @@ -767,8 +766,8 @@ std::string request_uuid = base::GenerateGUID(); content::ServiceWorkerContext* service_worker_context = - util::GetStoragePartitionForExtensionId(extension->id(), browser_context_) - ->GetServiceWorkerContext(); + util::GetServiceWorkerContextForExtensionId(extension->id(), + browser_context_); service_worker_context->StartingExternalRequest(service_worker_version_id, timeout_type, request_uuid); @@ -824,8 +823,8 @@ int64_t service_worker_version_id = worker_id.version_id; content::ServiceWorkerContext* service_worker_context = - util::GetStoragePartitionForExtensionId(extension->id(), browser_context_) - ->GetServiceWorkerContext(); + util::GetServiceWorkerContextForExtensionId(extension->id(), + browser_context_); content::ServiceWorkerExternalRequestResult result = service_worker_context->FinishedExternalRequest(service_worker_version_id,
diff --git a/extensions/browser/service_worker_manager.cc b/extensions/browser/service_worker_manager.cc index a186054..d229678 100644 --- a/extensions/browser/service_worker_manager.cc +++ b/extensions/browser/service_worker_manager.cc
@@ -8,7 +8,6 @@ #include "base/functional/callback_helpers.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/service_worker_context.h" -#include "content/public/browser/storage_partition.h" #include "extensions/browser/extension_util.h" #include "third_party/blink/public/common/storage_key/storage_key.h" @@ -26,8 +25,7 @@ content::BrowserContext* browser_context, const Extension* extension, UnloadedExtensionReason reason) { - util::GetStoragePartitionForExtensionId(extension->id(), browser_context_) - ->GetServiceWorkerContext() + util::GetServiceWorkerContextForExtensionId(extension->id(), browser_context_) ->StopAllServiceWorkersForStorageKey( blink::StorageKey::CreateFirstParty(extension->origin())); } @@ -40,8 +38,7 @@ // a) Keep track of extensions with registered service workers. // b) Add a callback to the (Un)SuspendServiceWorkersOnOrigin() method. // c) Check for any orphaned workers. - util::GetStoragePartitionForExtensionId(extension->id(), browser_context_) - ->GetServiceWorkerContext() + util::GetServiceWorkerContextForExtensionId(extension->id(), browser_context_) ->DeleteForStorageKey( blink::StorageKey::CreateFirstParty(extension->origin()), base::DoNothing());
diff --git a/extensions/browser/service_worker_task_queue.cc b/extensions/browser/service_worker_task_queue.cc index 67e355ba..5afd0990 100644 --- a/extensions/browser/service_worker_task_queue.cc +++ b/extensions/browser/service_worker_task_queue.cc
@@ -490,12 +490,8 @@ WorkerState* worker_state = GetWorkerState(context_id); DCHECK_NE(BrowserState::kStarted, worker_state->browser_state_); - content::StoragePartition* partition = - util::GetStoragePartitionForExtensionId( - lazy_context_id.extension_id(), lazy_context_id.browser_context()); - content::ServiceWorkerContext* service_worker_context = - partition->GetServiceWorkerContext(); + GetServiceWorkerContext(lazy_context_id.extension_id()); const GURL& scope = context_id.first.service_worker_scope(); service_worker_context->StartWorkerForScope( @@ -720,8 +716,8 @@ content::ServiceWorkerContext* ServiceWorkerTaskQueue::GetServiceWorkerContext( const ExtensionId& extension_id) { - return util::GetStoragePartitionForExtensionId(extension_id, browser_context_) - ->GetServiceWorkerContext(); + return util::GetServiceWorkerContextForExtensionId(extension_id, + browser_context_); } void ServiceWorkerTaskQueue::StartObserving(
diff --git a/extensions/common/extension_features.cc b/extensions/common/extension_features.cc index 17f65053..a3a4115 100644 --- a/extensions/common/extension_features.cc +++ b/extensions/common/extension_features.cc
@@ -156,4 +156,11 @@ "TelemetryExtensionPendingApprovalApi", base::FEATURE_DISABLED_BY_DEFAULT); +// If enabled, user permitted sites are granted access. This should only happen +// if kExtensionsMenuAccessControl is enabled, since it's the only entry point +// where user could set permitted sites. +BASE_FEATURE(kExtensionsMenuAccessControlWithPermittedSites, + "ExtensionsMenuAccessControlWithPermittedSitesName", + base::FEATURE_DISABLED_BY_DEFAULT); + } // namespace extensions_features
diff --git a/extensions/common/extension_features.h b/extensions/common/extension_features.h index 6cf4433..22aff15f 100644 --- a/extensions/common/extension_features.h +++ b/extensions/common/extension_features.h
@@ -54,6 +54,8 @@ BASE_DECLARE_FEATURE(kTelemetryExtensionPendingApprovalApi); +BASE_DECLARE_FEATURE(kExtensionsMenuAccessControlWithPermittedSites); + } // namespace extensions_features #endif // EXTENSIONS_COMMON_EXTENSION_FEATURES_H_
diff --git a/extensions/renderer/bindings/api_binding_test_util.cc b/extensions/renderer/bindings/api_binding_test_util.cc index 84d5759..d2d8651 100644 --- a/extensions/renderer/bindings/api_binding_test_util.cc +++ b/extensions/renderer/bindings/api_binding_test_util.cc
@@ -91,13 +91,6 @@ return std::move(value).TakeDict(); } -std::unique_ptr<base::Value> DeprecatedValueFromString(base::StringPiece str) { - std::unique_ptr<base::Value> value = - base::JSONReader::ReadDeprecated(ReplaceSingleQuotes(str)); - EXPECT_TRUE(value) << str; - return value; -} - std::string ValueToString(const base::ValueView& value_view) { std::string json; EXPECT_TRUE(base::JSONWriter::Write(value_view, &json));
diff --git a/extensions/renderer/bindings/api_binding_test_util.h b/extensions/renderer/bindings/api_binding_test_util.h index 0da018a4..2b4395a 100644 --- a/extensions/renderer/bindings/api_binding_test_util.h +++ b/extensions/renderer/bindings/api_binding_test_util.h
@@ -28,10 +28,6 @@ // As above, but returning a Value::Dict. base::Value::Dict DictValueFromString(base::StringPiece str); -// Returns a base::Value parsed from |str|. EXPECTs the conversion to succeed. -// DEPRECATED: prefer `ValueFromString`. -std::unique_ptr<base::Value> DeprecatedValueFromString(base::StringPiece str); - // Converts the given |value| to a JSON string. EXPECTs the conversion to // succeed. std::string ValueToString(const base::ValueView&);
diff --git a/extensions/renderer/bindings/argument_spec_unittest.cc b/extensions/renderer/bindings/argument_spec_unittest.cc index f364d8c..99a563f 100644 --- a/extensions/renderer/bindings/argument_spec_unittest.cc +++ b/extensions/renderer/bindings/argument_spec_unittest.cc
@@ -194,7 +194,7 @@ TEST_F(ArgumentSpecUnitTest, Test) { { - ArgumentSpec spec(*DeprecatedValueFromString("{'type': 'integer'}")); + ArgumentSpec spec(ValueFromString("{'type': 'integer'}")); ExpectSuccess(spec, "1", "1"); ExpectSuccess(spec, "-1", "-1"); ExpectSuccess(spec, "0", "0"); @@ -215,7 +215,7 @@ } { - ArgumentSpec spec(*DeprecatedValueFromString("{'type': 'number'}")); + ArgumentSpec spec(ValueFromString("{'type': 'number'}")); ExpectSuccess(spec, "1", "1.0"); ExpectSuccess(spec, "-1", "-1.0"); ExpectSuccess(spec, "0", "0.0"); @@ -233,8 +233,7 @@ } { - ArgumentSpec spec( - *DeprecatedValueFromString("{'type': 'integer', 'minimum': 1}")); + ArgumentSpec spec(ValueFromString("{'type': 'integer', 'minimum': 1}")); ExpectSuccess(spec, "2", "2"); ExpectSuccess(spec, "1", "1"); ExpectFailure(spec, "0", api_errors::NumberTooSmall(1)); @@ -242,15 +241,14 @@ } { - ArgumentSpec spec( - *DeprecatedValueFromString("{'type': 'integer', 'maximum': 10}")); + ArgumentSpec spec(ValueFromString("{'type': 'integer', 'maximum': 10}")); ExpectSuccess(spec, "10", "10"); ExpectSuccess(spec, "1", "1"); ExpectFailure(spec, "11", api_errors::NumberTooLarge(10)); } { - ArgumentSpec spec(*DeprecatedValueFromString("{'type': 'string'}")); + ArgumentSpec spec(ValueFromString("{'type': 'string'}")); ExpectSuccess(spec, "'foo'", "'foo'"); ExpectSuccess(spec, "''", "''"); ExpectFailure(spec, "1", InvalidType(kTypeString, kTypeInteger)); @@ -259,8 +257,8 @@ } { - ArgumentSpec spec(*DeprecatedValueFromString( - "{'type': 'string', 'enum': ['foo', 'bar']}")); + ArgumentSpec spec( + ValueFromString("{'type': 'string', 'enum': ['foo', 'bar']}")); std::set<std::string> valid_enums = {"foo", "bar"}; ExpectSuccess(spec, "'foo'", "'foo'"); ExpectSuccess(spec, "'bar'", "'bar'"); @@ -272,7 +270,7 @@ } { - ArgumentSpec spec(*DeprecatedValueFromString( + ArgumentSpec spec(ValueFromString( "{'type': 'string', 'enum': [{'name': 'foo'}, {'name': 'bar'}]}")); std::set<std::string> valid_enums = {"foo", "bar"}; ExpectSuccess(spec, "'foo'", "'foo'"); @@ -285,7 +283,7 @@ } { - ArgumentSpec spec(*DeprecatedValueFromString("{'type': 'boolean'}")); + ArgumentSpec spec(ValueFromString("{'type': 'boolean'}")); ExpectSuccess(spec, "true", "true"); ExpectSuccess(spec, "false", "false"); ExpectFailure(spec, "1", InvalidType(kTypeBoolean, kTypeInteger)); @@ -294,8 +292,8 @@ } { - ArgumentSpec spec(*DeprecatedValueFromString( - "{'type': 'array', 'items': {'type': 'string'}}")); + ArgumentSpec spec( + ValueFromString("{'type': 'array', 'items': {'type': 'string'}}")); ExpectSuccess(spec, "[]", "[]"); ExpectSuccess(spec, "['foo']", "['foo']"); ExpectSuccess(spec, "['foo', 'bar']", "['foo','bar']"); @@ -329,7 +327,7 @@ " 'prop2': {'type': 'integer', 'optional': true}" " }" "}"; - ArgumentSpec spec(*DeprecatedValueFromString(kObjectSpec)); + ArgumentSpec spec(ValueFromString(kObjectSpec)); ExpectSuccess(spec, "({prop1: 'foo', prop2: 2})", "{'prop1':'foo','prop2':2}"); ExpectSuccess(spec, "({prop1: 'foo'})", "{'prop1':'foo'}"); @@ -390,7 +388,7 @@ { const char kFunctionSpec[] = "{ 'type': 'function' }"; - ArgumentSpec spec(*DeprecatedValueFromString(kFunctionSpec)); + ArgumentSpec spec(ValueFromString(kFunctionSpec)); // Functions are serialized as empty dictionaries. ExpectSuccess(spec, "(function() {})", "{}"); ExpectSuccessWithNoConversion(spec, "(function() {})"); @@ -406,7 +404,7 @@ { const char kBinarySpec[] = "{ 'type': 'binary' }"; - ArgumentSpec spec(*DeprecatedValueFromString(kBinarySpec)); + ArgumentSpec spec(ValueFromString(kBinarySpec)); // Simple case: empty ArrayBuffer -> empty BinaryValue. ExpectSuccess(spec, "(new ArrayBuffer())", base::Value(base::Value::Type::BINARY)); @@ -432,7 +430,7 @@ } { const char kAnySpec[] = "{ 'type': 'any' }"; - ArgumentSpec spec(*DeprecatedValueFromString(kAnySpec)); + ArgumentSpec spec(ValueFromString(kAnySpec)); ExpectSuccess(spec, "42", "42"); ExpectSuccess(spec, "'foo'", "'foo'"); ExpectSuccess(spec, "({prop1:'bar'})", "{'prop1':'bar'}"); @@ -469,10 +467,10 @@ "}"; const char kEnumType[] = "{'id': 'refEnum', 'type': 'string', 'enum': ['alpha', 'beta']}"; - AddTypeRef("refObj", std::make_unique<ArgumentSpec>( - *DeprecatedValueFromString(kObjectType))); - AddTypeRef("refEnum", std::make_unique<ArgumentSpec>( - *DeprecatedValueFromString(kEnumType))); + AddTypeRef("refObj", + std::make_unique<ArgumentSpec>(ValueFromString(kObjectType))); + AddTypeRef("refEnum", + std::make_unique<ArgumentSpec>(ValueFromString(kEnumType))); std::set<std::string> valid_enums = {"alpha", "beta"}; { @@ -485,7 +483,7 @@ " 'sub': {'type': 'integer'}" " }" "}"; - ArgumentSpec spec(*DeprecatedValueFromString(kObjectWithRefEnumSpec)); + ArgumentSpec spec(ValueFromString(kObjectWithRefEnumSpec)); ExpectSuccess(spec, "({e: 'alpha', sub: 1})", "{'e':'alpha','sub':1}"); ExpectSuccess(spec, "({e: 'beta', sub: 1})", "{'e':'beta','sub':1}"); ExpectFailure(spec, "({e: 'gamma', sub: 1})", @@ -503,7 +501,7 @@ " 'o': {'$ref': 'refObj'}" " }" "}"; - ArgumentSpec spec(*DeprecatedValueFromString(kObjectWithRefObjectSpec)); + ArgumentSpec spec(ValueFromString(kObjectWithRefObjectSpec)); ExpectSuccess(spec, "({o: {prop1: 'foo'}})", "{'o':{'prop1':'foo'}}"); ExpectSuccess(spec, "({o: {prop1: 'foo', prop2: 2}})", "{'o':{'prop1':'foo','prop2':2}}"); @@ -517,7 +515,7 @@ { const char kRefEnumListSpec[] = "{'type': 'array', 'items': {'$ref': 'refEnum'}}"; - ArgumentSpec spec(*DeprecatedValueFromString(kRefEnumListSpec)); + ArgumentSpec spec(ValueFromString(kRefEnumListSpec)); ExpectSuccess(spec, "['alpha']", "['alpha']"); ExpectSuccess(spec, "['alpha', 'alpha']", "['alpha','alpha']"); ExpectSuccess(spec, "['alpha', 'beta']", "['alpha','beta']"); @@ -530,7 +528,7 @@ { const char kSimpleChoices[] = "{'choices': [{'type': 'string'}, {'type': 'integer'}]}"; - ArgumentSpec spec(*DeprecatedValueFromString(kSimpleChoices)); + ArgumentSpec spec(ValueFromString(kSimpleChoices)); ExpectSuccess(spec, "'alpha'", "'alpha'"); ExpectSuccess(spec, "42", "42"); const char kChoicesType[] = "[string|integer]"; @@ -545,7 +543,7 @@ " {'type': 'object', 'properties': {'prop1': {'type': 'string'}}}" " ]" "}"; - ArgumentSpec spec(*DeprecatedValueFromString(kComplexChoices)); + ArgumentSpec spec(ValueFromString(kComplexChoices)); ExpectSuccess(spec, "['alpha']", "['alpha']"); ExpectSuccess(spec, "['alpha', 'beta']", "['alpha','beta']"); ExpectSuccess(spec, "({prop1: 'alpha'})", "{'prop1':'alpha'}"); @@ -564,7 +562,7 @@ " 'type': 'object'," " 'additionalProperties': {'type': 'any'}" "}"; - ArgumentSpec spec(*DeprecatedValueFromString(kOnlyAnyAdditionalProperties)); + ArgumentSpec spec(ValueFromString(kOnlyAnyAdditionalProperties)); ExpectSuccess(spec, "({prop1: 'alpha', prop2: 42, prop3: {foo: 'bar'}})", "{'prop1':'alpha','prop2':42,'prop3':{'foo':'bar'}}"); ExpectSuccess(spec, "({})", "{}"); @@ -633,8 +631,7 @@ " }," " 'additionalProperties': {'type': 'any'}" "}"; - ArgumentSpec spec( - *DeprecatedValueFromString(kPropertiesAndAnyAdditionalProperties)); + ArgumentSpec spec(ValueFromString(kPropertiesAndAnyAdditionalProperties)); ExpectSuccess(spec, "({prop1: 'alpha', prop2: 42, prop3: {foo: 'bar'}})", "{'prop1':'alpha','prop2':42,'prop3':{'foo':'bar'}}"); // Additional properties are optional. @@ -651,7 +648,7 @@ " 'type': 'object'," " 'additionalProperties': {'type': 'string'}" "}"; - ArgumentSpec spec(*DeprecatedValueFromString(kTypedAdditionalProperties)); + ArgumentSpec spec(ValueFromString(kTypedAdditionalProperties)); ExpectSuccess(spec, "({prop1: 'alpha', prop2: 'beta', prop3: 'gamma'})", "{'prop1':'alpha','prop2':'beta','prop3':'gamma'}"); ExpectFailure(spec, "({prop1: 'alpha', prop2: 42})", @@ -667,7 +664,7 @@ " 'type': 'object'," " 'isInstanceOf': 'RegExp'" "}"; - ArgumentSpec spec(*DeprecatedValueFromString(kInstanceOfRegExp)); + ArgumentSpec spec(ValueFromString(kInstanceOfRegExp)); ExpectSuccess(spec, "(new RegExp())", "{}"); ExpectSuccess(spec, "({ __proto__: RegExp.prototype })", "{}"); ExpectSuccess(spec, @@ -696,7 +693,7 @@ " 'type': 'object'," " 'isInstanceOf': 'customClass'" "}"; - ArgumentSpec spec(*DeprecatedValueFromString(kInstanceOfCustomClass)); + ArgumentSpec spec(ValueFromString(kInstanceOfCustomClass)); ExpectSuccess(spec, "(function() {\n" " function customClass() {}\n" @@ -725,7 +722,7 @@ TEST_F(ArgumentSpecUnitTest, MinAndMaxLengths) { { const char kMinLengthString[] = "{'type': 'string', 'minLength': 3}"; - ArgumentSpec spec(*DeprecatedValueFromString(kMinLengthString)); + ArgumentSpec spec(ValueFromString(kMinLengthString)); ExpectSuccess(spec, "'aaa'", "'aaa'"); ExpectSuccess(spec, "'aaaa'", "'aaaa'"); ExpectFailure(spec, "'aa'", api_errors::TooFewStringChars(3, 2)); @@ -734,7 +731,7 @@ { const char kMaxLengthString[] = "{'type': 'string', 'maxLength': 3}"; - ArgumentSpec spec(*DeprecatedValueFromString(kMaxLengthString)); + ArgumentSpec spec(ValueFromString(kMaxLengthString)); ExpectSuccess(spec, "'aaa'", "'aaa'"); ExpectSuccess(spec, "'aa'", "'aa'"); ExpectSuccess(spec, "''", "''"); @@ -744,7 +741,7 @@ { const char kMinLengthArray[] = "{'type': 'array', 'items': {'type': 'integer'}, 'minItems': 3}"; - ArgumentSpec spec(*DeprecatedValueFromString(kMinLengthArray)); + ArgumentSpec spec(ValueFromString(kMinLengthArray)); ExpectSuccess(spec, "[1, 2, 3]", "[1,2,3]"); ExpectSuccess(spec, "[1, 2, 3, 4]", "[1,2,3,4]"); ExpectFailure(spec, "[1, 2]", api_errors::TooFewArrayItems(3, 2)); @@ -754,7 +751,7 @@ { const char kMaxLengthArray[] = "{'type': 'array', 'items': {'type': 'integer'}, 'maxItems': 3}"; - ArgumentSpec spec(*DeprecatedValueFromString(kMaxLengthArray)); + ArgumentSpec spec(ValueFromString(kMaxLengthArray)); ExpectSuccess(spec, "[1, 2, 3]", "[1,2,3]"); ExpectSuccess(spec, "[1, 2]", "[1,2]"); ExpectSuccess(spec, "[]", "[]"); @@ -770,7 +767,7 @@ " 'additionalProperties': {'type': 'any'}," " 'preserveNull': true" "}"; - ArgumentSpec spec(*DeprecatedValueFromString(kObjectSpec)); + ArgumentSpec spec(ValueFromString(kObjectSpec)); ExpectSuccess(spec, "({foo: 1, bar: null})", "{'bar':null,'foo':1}"); // Subproperties shouldn't preserve null (if not specified). ExpectSuccess(spec, "({prop: {subprop1: 'foo', subprop2: null}})", @@ -784,7 +781,7 @@ " 'additionalProperties': {'type': 'any', 'preserveNull': true}," " 'preserveNull': true" "}"; - ArgumentSpec spec(*DeprecatedValueFromString(kObjectSpec)); + ArgumentSpec spec(ValueFromString(kObjectSpec)); ExpectSuccess(spec, "({foo: 1, bar: null})", "{'bar':null,'foo':1}"); // Here, subproperties should preserve null. ExpectSuccess(spec, "({prop: {subprop1: 'foo', subprop2: null}})", @@ -798,7 +795,7 @@ " 'properties': {'prop1': {'type': 'string', 'optional': true}}," " 'preserveNull': true" "}"; - ArgumentSpec spec(*DeprecatedValueFromString(kObjectSpec)); + ArgumentSpec spec(ValueFromString(kObjectSpec)); ExpectSuccess(spec, "({})", "{}"); ExpectSuccess(spec, "({prop1: null})", "{'prop1':null}"); ExpectSuccess(spec, "({prop1: 'foo'})", "{'prop1':'foo'}"); @@ -814,14 +811,14 @@ TEST_F(ArgumentSpecUnitTest, NaNFun) { { const char kAnySpec[] = "{'type': 'any'}"; - ArgumentSpec spec(*DeprecatedValueFromString(kAnySpec)); + ArgumentSpec spec(ValueFromString(kAnySpec)); ExpectFailure(spec, "NaN", api_errors::UnserializableValue()); } { const char kObjectWithAnyPropertiesSpec[] = "{'type': 'object', 'additionalProperties': {'type': 'any'}}"; - ArgumentSpec spec(*DeprecatedValueFromString(kObjectWithAnyPropertiesSpec)); + ArgumentSpec spec(ValueFromString(kObjectWithAnyPropertiesSpec)); ExpectSuccess(spec, "({foo: NaN, bar: 'baz'})", "{'bar':'baz'}"); } } @@ -1033,7 +1030,7 @@ "type": "function", "serializableFunction": true })"; - ArgumentSpec spec(*DeprecatedValueFromString(kFunctionSpec)); + ArgumentSpec spec(ValueFromString(kFunctionSpec)); constexpr char kExpectedSerialization[] = R"("function() { }")"; ExpectSuccess(spec, "(function() { })", kExpectedSerialization);
diff --git a/google_apis/BUILD.gn b/google_apis/BUILD.gn index 04ef849a..a177cc2b 100644 --- a/google_apis/BUILD.gn +++ b/google_apis/BUILD.gn
@@ -110,100 +110,90 @@ } } -# Variables: -# deps: Extra dependencies -template("google_apis_tmpl") { - source_set(target_name) { - sources = [ - "gaia/core_account_id.cc", - "gaia/core_account_id.h", - "gaia/gaia_access_token_fetcher.cc", - "gaia/gaia_access_token_fetcher.h", - "gaia/gaia_auth_consumer.cc", - "gaia/gaia_auth_consumer.h", - "gaia/gaia_auth_fetcher.cc", - "gaia/gaia_auth_fetcher.h", - "gaia/gaia_auth_util.cc", - "gaia/gaia_auth_util.h", - "gaia/gaia_config.cc", - "gaia/gaia_config.h", - "gaia/gaia_constants.cc", - "gaia/gaia_constants.h", - "gaia/gaia_oauth_client.cc", - "gaia/gaia_oauth_client.h", - "gaia/gaia_switches.cc", - "gaia/gaia_switches.h", - "gaia/gaia_urls.cc", - "gaia/gaia_urls.h", - "gaia/google_service_auth_error.cc", - "gaia/google_service_auth_error.h", - "gaia/oauth2_access_token_consumer.cc", - "gaia/oauth2_access_token_consumer.h", - "gaia/oauth2_access_token_fetcher.cc", - "gaia/oauth2_access_token_fetcher.h", - "gaia/oauth2_access_token_fetcher_immediate_error.cc", - "gaia/oauth2_access_token_fetcher_immediate_error.h", - "gaia/oauth2_access_token_fetcher_impl.cc", - "gaia/oauth2_access_token_fetcher_impl.h", - "gaia/oauth2_access_token_manager.cc", - "gaia/oauth2_access_token_manager.h", - "gaia/oauth2_api_call_flow.cc", - "gaia/oauth2_api_call_flow.h", - "gaia/oauth2_id_token_decoder.cc", - "gaia/oauth2_id_token_decoder.h", - "gaia/oauth2_mint_token_flow.cc", - "gaia/oauth2_mint_token_flow.h", - "gaia/oauth_multilogin_result.cc", - "gaia/oauth_multilogin_result.h", - "gaia/oauth_request_signer.cc", - "gaia/oauth_request_signer.h", - "google_api_keys.cc", - "google_api_keys.h", - ] +component("google_apis") { + sources = [ + "credentials_mode.cc", + "credentials_mode.h", + "gaia/core_account_id.cc", + "gaia/core_account_id.h", + "gaia/gaia_access_token_fetcher.cc", + "gaia/gaia_access_token_fetcher.h", + "gaia/gaia_auth_consumer.cc", + "gaia/gaia_auth_consumer.h", + "gaia/gaia_auth_fetcher.cc", + "gaia/gaia_auth_fetcher.h", + "gaia/gaia_auth_util.cc", + "gaia/gaia_auth_util.h", + "gaia/gaia_config.cc", + "gaia/gaia_config.h", + "gaia/gaia_constants.cc", + "gaia/gaia_constants.h", + "gaia/gaia_oauth_client.cc", + "gaia/gaia_oauth_client.h", + "gaia/gaia_switches.cc", + "gaia/gaia_switches.h", + "gaia/gaia_urls.cc", + "gaia/gaia_urls.h", + "gaia/google_service_auth_error.cc", + "gaia/google_service_auth_error.h", + "gaia/oauth2_access_token_consumer.cc", + "gaia/oauth2_access_token_consumer.h", + "gaia/oauth2_access_token_fetcher.cc", + "gaia/oauth2_access_token_fetcher.h", + "gaia/oauth2_access_token_fetcher_immediate_error.cc", + "gaia/oauth2_access_token_fetcher_immediate_error.h", + "gaia/oauth2_access_token_fetcher_impl.cc", + "gaia/oauth2_access_token_fetcher_impl.h", + "gaia/oauth2_access_token_manager.cc", + "gaia/oauth2_access_token_manager.h", + "gaia/oauth2_api_call_flow.cc", + "gaia/oauth2_api_call_flow.h", + "gaia/oauth2_id_token_decoder.cc", + "gaia/oauth2_id_token_decoder.h", + "gaia/oauth2_mint_token_flow.cc", + "gaia/oauth2_mint_token_flow.h", + "gaia/oauth_multilogin_result.cc", + "gaia/oauth_multilogin_result.h", + "gaia/oauth_request_signer.cc", + "gaia/oauth_request_signer.h", + "google_api_keys.cc", + "google_api_keys.h", + ] - configs += [ ":key_defines" ] + configs += [ ":key_defines" ] - public_deps = [ - ":buildflags", - "//build:chromeos_buildflags", - ] - - deps = [ - ":oauth2_mint_token_consent_result_proto", - "//base", - "//base/third_party/dynamic_annotations", - "//build:branding_buildflags", - "//build:chromeos_buildflags", - "//crypto", - "//mojo/public/cpp/bindings:struct_traits", - "//services/network/public/cpp", - ] - - if (_use_official_google_keys_and_generate_metrics_key_header) { - deps += [ "internal:generate_metrics_key_header" ] - } - - if (defined(invoker.deps)) { - deps += invoker.deps - } - - if (is_apple) { - sources += [ - "google_api_keys_mac.h", - "google_api_keys_mac.mm", - ] - - frameworks = [ "Foundation.framework" ] - } - } -} - -google_apis_tmpl("google_apis") { - deps = [ - "//net", + public_deps = [ + ":buildflags", + "//base", + "//build:chromeos_buildflags", "//services/network/public/cpp", + ] + + deps = [ + ":oauth2_mint_token_consent_result_proto", + "//base/third_party/dynamic_annotations", + "//build:branding_buildflags", + "//build:chromeos_buildflags", + "//crypto", + "//mojo/public/cpp/bindings:struct_traits", + "//net", "//services/network/public/mojom", ] + + if (_use_official_google_keys_and_generate_metrics_key_header) { + deps += [ "internal:generate_metrics_key_header" ] + } + + if (is_apple) { + sources += [ + "google_api_keys_mac.h", + "google_api_keys_mac.mm", + ] + + frameworks = [ "Foundation.framework" ] + } + + defines = [ "IS_GOOGLE_APIS_IMPL" ] } proto_library("oauth2_mint_token_consent_result_proto") {
diff --git a/google_apis/common/base_requests.cc b/google_apis/common/base_requests.cc index c37149b..741aa2fd 100644 --- a/google_apis/common/base_requests.cc +++ b/google_apis/common/base_requests.cc
@@ -20,6 +20,7 @@ #include "base/values.h" #include "google_apis/common/request_sender.h" #include "google_apis/common/task_util.h" +#include "google_apis/credentials_mode.h" #include "net/base/load_flags.h" #include "net/http/http_util.h" #include "services/network/public/cpp/resource_request.h" @@ -174,7 +175,7 @@ request->url = url; request->method = GetRequestType(); request->load_flags = net::LOAD_DISABLE_CACHE; - request->credentials_mode = network::mojom::CredentialsMode::kOmit; + request->credentials_mode = GetOmitCredentialsModeForGaiaRequests(); // Add request headers. // Note that SetHeader clears the current headers and sets it to the passed-in
diff --git a/google_apis/credentials_mode.cc b/google_apis/credentials_mode.cc new file mode 100644 index 0000000..54cf67c4 --- /dev/null +++ b/google_apis/credentials_mode.cc
@@ -0,0 +1,27 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "google_apis/credentials_mode.h" + +#include "base/feature_list.h" +#include "services/network/public/mojom/fetch_api.mojom.h" + +namespace google_apis { + +namespace { + +BASE_FEATURE(kGaiaCredentialsModeOmitBug_775438_Workaround, + "GaiaCredentialsModeOmitBug_775438_Workaround", + base::FEATURE_ENABLED_BY_DEFAULT); + +} // namespace + +network::mojom::CredentialsMode GetOmitCredentialsModeForGaiaRequests() { + return base::FeatureList::IsEnabled( + kGaiaCredentialsModeOmitBug_775438_Workaround) + ? network::mojom::CredentialsMode::kOmitBug_775438_Workaround + : network::mojom::CredentialsMode::kOmit; +} + +} // namespace google_apis
diff --git a/google_apis/credentials_mode.h b/google_apis/credentials_mode.h new file mode 100644 index 0000000..132f857 --- /dev/null +++ b/google_apis/credentials_mode.h
@@ -0,0 +1,21 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef GOOGLE_APIS_CREDENTIALS_MODE_H_ +#define GOOGLE_APIS_CREDENTIALS_MODE_H_ + +#include "base/component_export.h" +#include "services/network/public/mojom/fetch_api.mojom-forward.h" + +namespace google_apis { + +// Returns the CredentialsMode that should be used for requests to Gaia. It +// returns kCredentialsMode::kOmit or kOmitBug_775438_Workaround depending on a +// variations-controlled feature toggle. +COMPONENT_EXPORT(GOOGLE_APIS) +network::mojom::CredentialsMode GetOmitCredentialsModeForGaiaRequests(); + +} // namespace google_apis + +#endif // GOOGLE_APIS_CREDENTIALS_MODE_H_
diff --git a/google_apis/gaia/core_account_id.h b/google_apis/gaia/core_account_id.h index ae75a8f..f8f7e48 100644 --- a/google_apis/gaia/core_account_id.h +++ b/google_apis/gaia/core_account_id.h
@@ -9,6 +9,7 @@ #include <string> #include <vector> +#include "base/component_export.h" #include "build/build_config.h" #include "build/chromeos_buildflags.h" @@ -24,7 +25,7 @@ // change on start-up. // -------------------------------------------------------------------------- -struct CoreAccountId { +struct COMPONENT_EXPORT(GOOGLE_APIS) CoreAccountId { CoreAccountId(); CoreAccountId(const CoreAccountId&); CoreAccountId(CoreAccountId&&) noexcept; @@ -96,16 +97,21 @@ std::string id_; }; +COMPONENT_EXPORT(GOOGLE_APIS) bool operator<(const CoreAccountId& lhs, const CoreAccountId& rhs); +COMPONENT_EXPORT(GOOGLE_APIS) bool operator==(const CoreAccountId& lhs, const CoreAccountId& rhs); +COMPONENT_EXPORT(GOOGLE_APIS) bool operator!=(const CoreAccountId& lhs, const CoreAccountId& rhs); +COMPONENT_EXPORT(GOOGLE_APIS) std::ostream& operator<<(std::ostream& out, const CoreAccountId& a); // Returns the values of the account ids in a vector. Useful especially for // logs. +COMPONENT_EXPORT(GOOGLE_APIS) std::vector<std::string> ToStringList( const std::vector<CoreAccountId>& account_ids);
diff --git a/google_apis/gaia/gaia_access_token_fetcher.h b/google_apis/gaia/gaia_access_token_fetcher.h index b2d4db9e..571cffb4 100644 --- a/google_apis/gaia/gaia_access_token_fetcher.h +++ b/google_apis/gaia/gaia_access_token_fetcher.h
@@ -8,6 +8,7 @@ #include <memory> #include <string> +#include "base/component_export.h" #include "base/memory/ref_counted.h" #include "google_apis/gaia/oauth2_access_token_fetcher_impl.h" @@ -21,7 +22,8 @@ // tokens from Google's authorization server. See "Refreshing an access token" // for more Google specific info: // https://developers.google.com/identity/protocols/oauth2/web-server?csw=1#obtainingaccesstokens -class GaiaAccessTokenFetcher : public OAuth2AccessTokenFetcherImpl { +class COMPONENT_EXPORT(GOOGLE_APIS) GaiaAccessTokenFetcher + : public OAuth2AccessTokenFetcherImpl { public: static const char kOAuth2NetResponseCodeHistogramName[]; static const char kOAuth2ResponseHistogramName[];
diff --git a/google_apis/gaia/gaia_auth_consumer.h b/google_apis/gaia/gaia_auth_consumer.h index 0cc2391..17cc45d 100644 --- a/google_apis/gaia/gaia_auth_consumer.h +++ b/google_apis/gaia/gaia_auth_consumer.h
@@ -9,14 +9,16 @@ #include <string> #include <vector> +#include "base/component_export.h" + class GoogleServiceAuthError; class OAuthMultiloginResult; // An interface that defines the callbacks for objects that // GaiaAuthFetcher can return data to. -class GaiaAuthConsumer { +class COMPONENT_EXPORT(GOOGLE_APIS) GaiaAuthConsumer { public: - struct ClientOAuthResult { + struct COMPONENT_EXPORT(GOOGLE_APIS) ClientOAuthResult { ClientOAuthResult(const std::string& new_refresh_token, const std::string& new_access_token, int new_expires_in_secs,
diff --git a/google_apis/gaia/gaia_auth_fetcher.cc b/google_apis/gaia/gaia_auth_fetcher.cc index 51faad8..24f3b12 100644 --- a/google_apis/gaia/gaia_auth_fetcher.cc +++ b/google_apis/gaia/gaia_auth_fetcher.cc
@@ -22,6 +22,7 @@ #include "base/system/sys_info.h" #include "base/types/optional_util.h" #include "base/values.h" +#include "google_apis/credentials_mode.h" #include "google_apis/gaia/gaia_auth_consumer.h" #include "google_apis/gaia/gaia_auth_util.h" #include "google_apis/gaia/gaia_constants.h" @@ -266,7 +267,9 @@ resource_request->url = gaia_gurl; original_url_ = gaia_gurl; - if (credentials_mode != network::mojom::CredentialsMode::kOmit) { + if (credentials_mode != network::mojom::CredentialsMode::kOmit && + credentials_mode != + network::mojom::CredentialsMode::kOmitBug_775438_Workaround) { CHECK(gaia::HasGaiaSchemeHostPort(gaia_gurl)) << gaia_gurl; url::Origin origin = GaiaUrls::GetInstance()->gaia_origin(); @@ -410,10 +413,10 @@ } } })"); - CreateAndStartGaiaFetcher(request_body_, kFormEncodedContentType, - std::string(), oauth2_revoke_gurl_, - network::mojom::CredentialsMode::kOmit, - traffic_annotation); + CreateAndStartGaiaFetcher( + request_body_, kFormEncodedContentType, std::string(), + oauth2_revoke_gurl_, google_apis::GetOmitCredentialsModeForGaiaRequests(), + traffic_annotation); } void GaiaAuthFetcher::StartAuthCodeForOAuth2TokenExchange( @@ -458,7 +461,7 @@ })"); CreateAndStartGaiaFetcher( request_body_, kFormEncodedContentType, std::string(), oauth2_token_gurl_, - network::mojom::CredentialsMode::kOmit, traffic_annotation); + google_apis::GetOmitCredentialsModeForGaiaRequests(), traffic_annotation); } void GaiaAuthFetcher::StartMergeSession(const std::string& uber_token, @@ -549,7 +552,7 @@ })"); CreateAndStartGaiaFetcher( std::string(), std::string(), authentication_header, uberauth_token_gurl_, - network::mojom::CredentialsMode::kOmit, traffic_annotation); + google_apis::GetOmitCredentialsModeForGaiaRequests(), traffic_annotation); } void GaiaAuthFetcher::StartListAccounts() { @@ -747,9 +750,9 @@ DCHECK(reauth_url.is_valid()); // Start the request. - CreateAndStartGaiaFetcher(post_body, kJsonContentType, headers, reauth_url, - network::mojom::CredentialsMode::kOmit, - traffic_annotation); + CreateAndStartGaiaFetcher( + post_body, kJsonContentType, headers, reauth_url, + google_apis::GetOmitCredentialsModeForGaiaRequests(), traffic_annotation); } void GaiaAuthFetcher::StartGetCheckConnectionInfo() { @@ -780,10 +783,10 @@ } } })"); - CreateAndStartGaiaFetcher(std::string(), std::string(), std::string(), - get_check_connection_info_url_, - network::mojom::CredentialsMode::kOmit, - traffic_annotation); + CreateAndStartGaiaFetcher( + std::string(), std::string(), std::string(), + get_check_connection_info_url_, + google_apis::GetOmitCredentialsModeForGaiaRequests(), traffic_annotation); } // static
diff --git a/google_apis/gaia/gaia_auth_fetcher.h b/google_apis/gaia/gaia_auth_fetcher.h index 9016c95..992bbb3 100644 --- a/google_apis/gaia/gaia_auth_fetcher.h +++ b/google_apis/gaia/gaia_auth_fetcher.h
@@ -9,6 +9,7 @@ #include <string> #include <vector> +#include "base/component_export.h" #include "base/gtest_prod_util.h" #include "base/memory/raw_ptr.h" #include "base/memory/ref_counted.h" @@ -43,7 +44,7 @@ }; // Specifies the "source" parameter for Gaia calls. -class GaiaSource { +class COMPONENT_EXPORT(GOOGLE_APIS) GaiaSource { public: enum Type { kChrome, @@ -72,9 +73,9 @@ class SharedURLLoaderFactory; } // namespace network -class GaiaAuthFetcher { +class COMPONENT_EXPORT(GOOGLE_APIS) GaiaAuthFetcher { public: - struct MultiloginTokenIDPair { + struct COMPONENT_EXPORT(GOOGLE_APIS) MultiloginTokenIDPair { std::string token_; std::string gaia_id_;
diff --git a/google_apis/gaia/gaia_auth_fetcher_unittest.cc b/google_apis/gaia/gaia_auth_fetcher_unittest.cc index e7d9e62..43e264e 100644 --- a/google_apis/gaia/gaia_auth_fetcher_unittest.cc +++ b/google_apis/gaia/gaia_auth_fetcher_unittest.cc
@@ -17,6 +17,7 @@ #include "base/test/task_environment.h" #include "base/values.h" #include "build/build_config.h" +#include "google_apis/credentials_mode.h" #include "google_apis/gaia/gaia_auth_consumer.h" #include "google_apis/gaia/gaia_constants.h" #include "google_apis/gaia/gaia_urls.h" @@ -255,7 +256,7 @@ TestGaiaAuthFetcher auth(&consumer, GetURLLoaderFactory()); auth.StartAuthCodeForOAuth2TokenExchange("auth_code"); ASSERT_EQ(received_requests_.size(), 1U); - EXPECT_EQ(network::mojom::CredentialsMode::kOmit, + EXPECT_EQ(google_apis::GetOmitCredentialsModeForGaiaRequests(), received_requests_.at(0).credentials_mode); std::string body = GetRequestBodyAsString(&received_requests_.at(0)); EXPECT_EQ(std::string::npos, body.find("device_type=chrome")); @@ -274,7 +275,7 @@ "device_ABCDE_1"); ASSERT_EQ(1U, received_requests_.size()); - EXPECT_EQ(network::mojom::CredentialsMode::kOmit, + EXPECT_EQ(google_apis::GetOmitCredentialsModeForGaiaRequests(), received_requests_.at(0).credentials_mode); std::string body = GetRequestBodyAsString(&received_requests_.at(0)); EXPECT_NE(std::string::npos, body.find("device_type=chrome")); @@ -625,7 +626,8 @@ TestGaiaAuthFetcher auth(&consumer, GetURLLoaderFactory()); auth.CreateAndStartGaiaFetcherForTesting( /*body=*/"", /*headers=*/"", GaiaUrls::GetInstance()->reauth_api_url(), - network::mojom::CredentialsMode ::kOmit, TRAFFIC_ANNOTATION_FOR_TESTS); + google_apis::GetOmitCredentialsModeForGaiaRequests(), + TRAFFIC_ANNOTATION_FOR_TESTS); auth.TestOnURLLoadCompleteInternal(net::OK, net::HTTP_OK, data); } @@ -640,7 +642,8 @@ TestGaiaAuthFetcher auth(&consumer, GetURLLoaderFactory()); auth.CreateAndStartGaiaFetcherForTesting( /*body=*/"", /*headers=*/"", GaiaUrls::GetInstance()->reauth_api_url(), - network::mojom::CredentialsMode ::kOmit, TRAFFIC_ANNOTATION_FOR_TESTS); + google_apis::GetOmitCredentialsModeForGaiaRequests(), + TRAFFIC_ANNOTATION_FOR_TESTS); auth.TestOnURLLoadCompleteInternal(net::OK, net::HTTP_BAD_REQUEST, data); } @@ -655,7 +658,8 @@ TestGaiaAuthFetcher auth(&consumer, GetURLLoaderFactory()); auth.CreateAndStartGaiaFetcherForTesting( /*body=*/"", /*headers=*/"", GaiaUrls::GetInstance()->reauth_api_url(), - network::mojom::CredentialsMode ::kOmit, TRAFFIC_ANNOTATION_FOR_TESTS); + google_apis::GetOmitCredentialsModeForGaiaRequests(), + TRAFFIC_ANNOTATION_FOR_TESTS); auth.TestOnURLLoadCompleteInternal(net::OK, net::HTTP_BAD_REQUEST, data); } @@ -671,7 +675,8 @@ TestGaiaAuthFetcher auth(&consumer, GetURLLoaderFactory()); auth.CreateAndStartGaiaFetcherForTesting( /*body=*/"", /*headers=*/"", GaiaUrls::GetInstance()->reauth_api_url(), - network::mojom::CredentialsMode ::kOmit, TRAFFIC_ANNOTATION_FOR_TESTS); + google_apis::GetOmitCredentialsModeForGaiaRequests(), + TRAFFIC_ANNOTATION_FOR_TESTS); auth.TestOnURLLoadCompleteInternal(net::OK, net::HTTP_FORBIDDEN, data); } @@ -686,7 +691,8 @@ TestGaiaAuthFetcher auth(&consumer, GetURLLoaderFactory()); auth.CreateAndStartGaiaFetcherForTesting( /*body=*/"", /*headers=*/"", GaiaUrls::GetInstance()->reauth_api_url(), - network::mojom::CredentialsMode ::kOmit, TRAFFIC_ANNOTATION_FOR_TESTS); + google_apis::GetOmitCredentialsModeForGaiaRequests(), + TRAFFIC_ANNOTATION_FOR_TESTS); auth.TestOnURLLoadCompleteInternal(net::OK, net::HTTP_FORBIDDEN, data); } @@ -701,6 +707,7 @@ TestGaiaAuthFetcher auth(&consumer, GetURLLoaderFactory()); auth.CreateAndStartGaiaFetcherForTesting( /*body=*/"", /*headers=*/"", GaiaUrls::GetInstance()->reauth_api_url(), - network::mojom::CredentialsMode ::kOmit, TRAFFIC_ANNOTATION_FOR_TESTS); + google_apis::GetOmitCredentialsModeForGaiaRequests(), + TRAFFIC_ANNOTATION_FOR_TESTS); auth.TestOnURLLoadCompleteInternal(net::OK, net::HTTP_FORBIDDEN, data); }
diff --git a/google_apis/gaia/gaia_auth_util.h b/google_apis/gaia/gaia_auth_util.h index 2c36ac9..58a2696 100644 --- a/google_apis/gaia/gaia_auth_util.h +++ b/google_apis/gaia/gaia_auth_util.h
@@ -9,13 +9,14 @@ #include <utility> #include <vector> +#include "base/component_export.h" #include "google_apis/gaia/core_account_id.h" class GURL; namespace gaia { -struct ListedAccount { +struct COMPONENT_EXPORT(GOOGLE_APIS) ListedAccount { // The account's ID, as per Chrome, will be determined in the // CookieManagerService. CoreAccountId id; @@ -35,34 +36,41 @@ // gmail does not consider '.' or caps inside a username to matter. // If |email_address| is not a valid, returns it in lower case without // additional canonicalization. +COMPONENT_EXPORT(GOOGLE_APIS) std::string CanonicalizeEmail(const std::string& email_address); // Returns the canonical form of the given domain. +COMPONENT_EXPORT(GOOGLE_APIS) std::string CanonicalizeDomain(const std::string& domain); // Sanitize emails. Currently, it only ensures all emails have a domain by // adding gmail.com if no domain is present. +COMPONENT_EXPORT(GOOGLE_APIS) std::string SanitizeEmail(const std::string& email_address); // Returns true if the two specified email addresses are the same. Both // addresses are first sanitized and then canonicalized before comparing. +COMPONENT_EXPORT(GOOGLE_APIS) bool AreEmailsSame(const std::string& email1, const std::string& email2); // Extract the domain part from the canonical form of the given email. +COMPONENT_EXPORT(GOOGLE_APIS) std::string ExtractDomainName(const std::string& email); // Returns whether the user's email is Google internal. This check is meant // to be used sparingly since it ship Googler-only code to all users. +COMPONENT_EXPORT(GOOGLE_APIS) bool IsGoogleInternalAccountEmail(const std::string& email); // Returns true if |email| correspnds to the email of a robot account. +COMPONENT_EXPORT(GOOGLE_APIS) bool IsGoogleRobotAccountEmail(const std::string& email); // Mechanically compares the scheme, host, and port of the |url| against the // GAIA url in GaiaUrls. This means that this function will *not* work for // determining whether a frame with an "about:blank" URL or "blob:..." URL has // a GAIA origin and will in that case return false. -bool HasGaiaSchemeHostPort(const GURL& url); +COMPONENT_EXPORT(GOOGLE_APIS) bool HasGaiaSchemeHostPort(const GURL& url); // Parses JSON data returned by /ListAccounts call, returning a vector of // email/valid pairs. An email addresses is considered valid if a passive @@ -70,6 +78,7 @@ // If there an error parsing the JSON, then false is returned. // If either |accounts| or |signed_out_accounts| is null, the corresponding // accounts returned from /ListAccounts will be ignored. +COMPONENT_EXPORT(GOOGLE_APIS) bool ParseListAccountsData(const std::string& data, std::vector<ListedAccount>* accounts, std::vector<ListedAccount>* signed_out_accounts); @@ -79,6 +88,7 @@ // that was shown the consent page. // Returns false if the method failed to decode the protobuf. // |approved| and |gaia_id| must not be null. +COMPONENT_EXPORT(GOOGLE_APIS) bool ParseOAuth2MintTokenConsentResult(const std::string& consent_result, bool* approved, std::string* gaia_id);
diff --git a/google_apis/gaia/gaia_config.h b/google_apis/gaia/gaia_config.h index ec4b212..5dd7a6f9 100644 --- a/google_apis/gaia/gaia_config.h +++ b/google_apis/gaia/gaia_config.h
@@ -8,6 +8,7 @@ #include <memory> #include <string> +#include "base/component_export.h" #include "base/gtest_prod_util.h" #include "base/strings/string_piece_forward.h" #include "base/values.h" @@ -38,7 +39,7 @@ // ... // } // } -class GaiaConfig { +class COMPONENT_EXPORT(GOOGLE_APIS) GaiaConfig { public: // Returns a global instance of GaiaConfig. // This may return nullptr if the config file was not specified by a command
diff --git a/google_apis/gaia/gaia_constants.h b/google_apis/gaia/gaia_constants.h index 5e403ac..8809748 100644 --- a/google_apis/gaia/gaia_constants.h +++ b/google_apis/gaia/gaia_constants.h
@@ -7,68 +7,79 @@ #ifndef GOOGLE_APIS_GAIA_GAIA_CONSTANTS_H_ #define GOOGLE_APIS_GAIA_GAIA_CONSTANTS_H_ +#include "base/component_export.h" + namespace GaiaConstants { // Gaia sources for accounting -extern const char kChromeOSSource[]; -extern const char kChromeSource[]; +COMPONENT_EXPORT(GOOGLE_APIS) extern const char kChromeOSSource[]; +COMPONENT_EXPORT(GOOGLE_APIS) extern const char kChromeSource[]; // Used as Gaia source suffix to detect retry requests because of // |GoogleServiceAuthError::UNEXPECTED_SERVICE_RESPONSE|. -extern const char kUnexpectedServiceResponse[]; +COMPONENT_EXPORT(GOOGLE_APIS) extern const char kUnexpectedServiceResponse[]; // OAuth2 scopes. -extern const char kOAuth1LoginScope[]; -extern const char kDeviceManagementServiceOAuth[]; -extern const char kAnyApiOAuth2Scope[]; -extern const char kChromeSyncOAuth2Scope[]; +COMPONENT_EXPORT(GOOGLE_APIS) extern const char kOAuth1LoginScope[]; +COMPONENT_EXPORT(GOOGLE_APIS) extern const char kDeviceManagementServiceOAuth[]; +COMPONENT_EXPORT(GOOGLE_APIS) extern const char kAnyApiOAuth2Scope[]; +COMPONENT_EXPORT(GOOGLE_APIS) extern const char kChromeSyncOAuth2Scope[]; +COMPONENT_EXPORT(GOOGLE_APIS) extern const char kChromeSyncSupervisedOAuth2Scope[]; +COMPONENT_EXPORT(GOOGLE_APIS) extern const char kKidManagementPrivilegedOAuth2Scope[]; +COMPONENT_EXPORT(GOOGLE_APIS) extern const char kKidsSupervisionSetupChildOAuth2Scope[]; -extern const char kGoogleTalkOAuth2Scope[]; -extern const char kGoogleUserInfoEmail[]; -extern const char kGoogleUserInfoProfile[]; -extern const char kParentApprovalOAuth2Scope[]; -extern const char kPeopleApiReadOnlyOAuth2Scope[]; +COMPONENT_EXPORT(GOOGLE_APIS) extern const char kGoogleTalkOAuth2Scope[]; +COMPONENT_EXPORT(GOOGLE_APIS) extern const char kGoogleUserInfoEmail[]; +COMPONENT_EXPORT(GOOGLE_APIS) extern const char kGoogleUserInfoProfile[]; +COMPONENT_EXPORT(GOOGLE_APIS) extern const char kParentApprovalOAuth2Scope[]; +COMPONENT_EXPORT(GOOGLE_APIS) extern const char kPeopleApiReadOnlyOAuth2Scope[]; +COMPONENT_EXPORT(GOOGLE_APIS) extern const char kProgrammaticChallengeOAuth2Scope[]; -extern const char kAccountsReauthOAuth2Scope[]; -extern const char kAuditRecordingOAuth2Scope[]; -extern const char kClearCutOAuth2Scope[]; -extern const char kFCMOAuthScope[]; -extern const char kTachyonOAuthScope[]; -extern const char kPhotosOAuth2Scope[]; -extern const char kCastBackdropOAuth2Scope[]; -extern const char kCloudTranslationOAuth2Scope[]; +COMPONENT_EXPORT(GOOGLE_APIS) extern const char kAccountsReauthOAuth2Scope[]; +COMPONENT_EXPORT(GOOGLE_APIS) extern const char kAuditRecordingOAuth2Scope[]; +COMPONENT_EXPORT(GOOGLE_APIS) extern const char kClearCutOAuth2Scope[]; +COMPONENT_EXPORT(GOOGLE_APIS) extern const char kFCMOAuthScope[]; +COMPONENT_EXPORT(GOOGLE_APIS) extern const char kTachyonOAuthScope[]; +COMPONENT_EXPORT(GOOGLE_APIS) extern const char kPhotosOAuth2Scope[]; +COMPONENT_EXPORT(GOOGLE_APIS) extern const char kCastBackdropOAuth2Scope[]; +COMPONENT_EXPORT(GOOGLE_APIS) extern const char kCloudTranslationOAuth2Scope[]; +COMPONENT_EXPORT(GOOGLE_APIS) extern const char kPasswordsLeakCheckOAuth2Scope[]; +COMPONENT_EXPORT(GOOGLE_APIS) extern const char kChromeSafeBrowsingOAuth2Scope[]; +COMPONENT_EXPORT(GOOGLE_APIS) extern const char kClassifyUrlKidPermissionOAuth2Scope[]; -extern const char kKidFamilyReadonlyOAuth2Scope[]; -extern const char kPaymentsOAuth2Scope[]; -extern const char kCryptAuthOAuth2Scope[]; -extern const char kDriveOAuth2Scope[]; -extern const char kDriveReadOnlyOAuth2Scope[]; -extern const char kAssistantOAuth2Scope[]; +COMPONENT_EXPORT(GOOGLE_APIS) extern const char kKidFamilyReadonlyOAuth2Scope[]; +COMPONENT_EXPORT(GOOGLE_APIS) extern const char kPaymentsOAuth2Scope[]; +COMPONENT_EXPORT(GOOGLE_APIS) extern const char kCryptAuthOAuth2Scope[]; +COMPONENT_EXPORT(GOOGLE_APIS) extern const char kDriveOAuth2Scope[]; +COMPONENT_EXPORT(GOOGLE_APIS) extern const char kDriveReadOnlyOAuth2Scope[]; +COMPONENT_EXPORT(GOOGLE_APIS) extern const char kAssistantOAuth2Scope[]; +COMPONENT_EXPORT(GOOGLE_APIS) extern const char kCloudPlatformProjectsOAuth2Scope[]; -extern const char kNearbyShareOAuth2Scope[]; -extern const char kGCMGroupServerOAuth2Scope[]; -extern const char kGCMCheckinServerOAuth2Scope[]; -extern const char kChromeWebstoreOAuth2Scope[]; +COMPONENT_EXPORT(GOOGLE_APIS) extern const char kNearbyShareOAuth2Scope[]; +COMPONENT_EXPORT(GOOGLE_APIS) extern const char kGCMGroupServerOAuth2Scope[]; +COMPONENT_EXPORT(GOOGLE_APIS) extern const char kGCMCheckinServerOAuth2Scope[]; +COMPONENT_EXPORT(GOOGLE_APIS) extern const char kChromeWebstoreOAuth2Scope[]; +COMPONENT_EXPORT(GOOGLE_APIS) extern const char kAccountCapabilitiesOAuth2Scope[]; -extern const char kSupportContentOAuth2Scope[]; -extern const char kPhotosModuleOAuth2Scope[]; -extern const char kPhotosModuleImageOAuth2Scope[]; -extern const char kSecureConnectOAuth2Scope[]; -extern const char kFeedOAuth2Scope[]; -extern const char kKAnonymityServiceOAuth2Scope[]; -extern const char kCalendarReadOnlyOAuth2Scope[]; +COMPONENT_EXPORT(GOOGLE_APIS) extern const char kSupportContentOAuth2Scope[]; +COMPONENT_EXPORT(GOOGLE_APIS) extern const char kPhotosModuleOAuth2Scope[]; +COMPONENT_EXPORT(GOOGLE_APIS) extern const char kPhotosModuleImageOAuth2Scope[]; +COMPONENT_EXPORT(GOOGLE_APIS) extern const char kSecureConnectOAuth2Scope[]; +COMPONENT_EXPORT(GOOGLE_APIS) extern const char kFeedOAuth2Scope[]; +COMPONENT_EXPORT(GOOGLE_APIS) extern const char kKAnonymityServiceOAuth2Scope[]; +COMPONENT_EXPORT(GOOGLE_APIS) extern const char kCalendarReadOnlyOAuth2Scope[]; // Used by wallet sign in helper. -extern const char kClientOAuthEmailKey[]; +COMPONENT_EXPORT(GOOGLE_APIS) extern const char kClientOAuthEmailKey[]; // Refresh token that is guaranteed to be invalid. -extern const char kInvalidRefreshToken[]; +COMPONENT_EXPORT(GOOGLE_APIS) extern const char kInvalidRefreshToken[]; // Name of the Google authentication cookie. -extern const char kGaiaSigninCookieName[]; +COMPONENT_EXPORT(GOOGLE_APIS) extern const char kGaiaSigninCookieName[]; } // namespace GaiaConstants #endif // GOOGLE_APIS_GAIA_GAIA_CONSTANTS_H_
diff --git a/google_apis/gaia/gaia_oauth_client.cc b/google_apis/gaia/gaia_oauth_client.cc index 502ba94..4f64f84 100644 --- a/google_apis/gaia/gaia_oauth_client.cc +++ b/google_apis/gaia/gaia_oauth_client.cc
@@ -19,6 +19,7 @@ #include "base/strings/string_util.h" #include "base/task/single_thread_task_runner.h" #include "base/values.h" +#include "google_apis/credentials_mode.h" #include "google_apis/gaia/gaia_auth_util.h" #include "google_apis/gaia/gaia_urls.h" #include "net/base/backoff_entry.h" @@ -460,7 +461,8 @@ auto resource_request = std::make_unique<network::ResourceRequest>(); resource_request->url = url_; resource_request->method = post_body_.empty() ? "GET" : "POST"; - resource_request->credentials_mode = network::mojom::CredentialsMode::kOmit; + resource_request->credentials_mode = + google_apis::GetOmitCredentialsModeForGaiaRequests(); if (!authorization_header_.empty()) resource_request->headers.SetHeader("Authorization", authorization_header_); if (!http_method_override_header_.empty()) {
diff --git a/google_apis/gaia/gaia_oauth_client.h b/google_apis/gaia/gaia_oauth_client.h index a15211b..1b3176a 100644 --- a/google_apis/gaia/gaia_oauth_client.h +++ b/google_apis/gaia/gaia_oauth_client.h
@@ -9,6 +9,7 @@ #include <string> #include <vector> +#include "base/component_export.h" #include "base/memory/ref_counted.h" #include "base/values.h" @@ -23,15 +24,15 @@ // instances. namespace gaia { -struct OAuthClientInfo { +struct COMPONENT_EXPORT(GOOGLE_APIS) OAuthClientInfo { std::string client_id; std::string client_secret; std::string redirect_uri; }; -class GaiaOAuthClient { +class COMPONENT_EXPORT(GOOGLE_APIS) GaiaOAuthClient { public: - class Delegate { + class COMPONENT_EXPORT(GOOGLE_APIS) Delegate { public: // Invoked on a successful response to the GetTokensFromAuthCode request. virtual void OnGetTokensResponse(const std::string& refresh_token, @@ -154,6 +155,7 @@ class Core; scoped_refptr<Core> core_; }; -} + +} // namespace gaia #endif // GOOGLE_APIS_GAIA_GAIA_OAUTH_CLIENT_H_
diff --git a/google_apis/gaia/gaia_switches.h b/google_apis/gaia/gaia_switches.h index ca8b737..7ac4bcd 100644 --- a/google_apis/gaia/gaia_switches.h +++ b/google_apis/gaia/gaia_switches.h
@@ -5,42 +5,44 @@ #ifndef GOOGLE_APIS_GAIA_GAIA_SWITCHES_H_ #define GOOGLE_APIS_GAIA_GAIA_SWITCHES_H_ +#include "base/component_export.h" + namespace switches { // Specifies the path to a config file containing GAIA urls. // See "google_apis/test/data/gaia/all_urls.json" for a format example. -extern const char kGaiaConfigPath[]; +COMPONENT_EXPORT(GOOGLE_APIS) extern const char kGaiaConfigPath[]; // Specifies a string containing the JSON config for GAIA urls. This is // equivalent to pointing to a file with the same content via kGaiaConfigPath. // See "google_apis/test/data/gaia/all_urls.json" for a format example. -extern const char kGaiaConfigContents[]; +COMPONENT_EXPORT(GOOGLE_APIS) extern const char kGaiaConfigContents[]; // Specifies the domain of the SAPISID cookie. The default value is // "http://.google.com". -extern const char kGoogleUrl[]; +COMPONENT_EXPORT(GOOGLE_APIS) extern const char kGoogleUrl[]; // Specifies the path for GAIA authentication URL. The default value is // "https://accounts.google.com". -extern const char kGaiaUrl[]; +COMPONENT_EXPORT(GOOGLE_APIS) extern const char kGaiaUrl[]; // Specifies the backend server used for Google API calls. // "https://www.googleapis.com". -extern const char kGoogleApisUrl[]; +COMPONENT_EXPORT(GOOGLE_APIS) extern const char kGoogleApisUrl[]; // Specifies the backend server used for lso authentication calls. // "https://accounts.google.com". -extern const char kLsoUrl[]; +COMPONENT_EXPORT(GOOGLE_APIS) extern const char kLsoUrl[]; // Specifies the backend server used for OAuth issue token calls. // "https://oauthaccountmanager.googleapis.com". -extern const char kOAuthAccountManagerUrl[]; +COMPONENT_EXPORT(GOOGLE_APIS) extern const char kOAuthAccountManagerUrl[]; // Specifies custom OAuth2 client id for testing purposes. -extern const char kOAuth2ClientID[]; +COMPONENT_EXPORT(GOOGLE_APIS) extern const char kOAuth2ClientID[]; // Specifies custom OAuth2 client secret for testing purposes. -extern const char kOAuth2ClientSecret[]; +COMPONENT_EXPORT(GOOGLE_APIS) extern const char kOAuth2ClientSecret[]; } // namespace switches
diff --git a/google_apis/gaia/gaia_urls.h b/google_apis/gaia/gaia_urls.h index f720aad..a608c6d 100644 --- a/google_apis/gaia/gaia_urls.h +++ b/google_apis/gaia/gaia_urls.h
@@ -7,6 +7,7 @@ #include <string> +#include "base/component_export.h" #include "base/memory/singleton.h" #include "url/gurl.h" #include "url/origin.h" @@ -14,7 +15,7 @@ // A singleton that provides all the URLs that are used for connecting to GAIA. // // Please update InitializeFromConfig() when adding new URLs. -class GaiaUrls { +class COMPONENT_EXPORT(GOOGLE_APIS) GaiaUrls { public: static GaiaUrls* GetInstance();
diff --git a/google_apis/gaia/google_service_auth_error.h b/google_apis/gaia/google_service_auth_error.h index 5f913ef..27dba23 100644 --- a/google_apis/gaia/google_service_auth_error.h +++ b/google_apis/gaia/google_service_auth_error.h
@@ -13,9 +13,10 @@ #include <string> +#include "base/component_export.h" #include "url/gurl.h" -class GoogleServiceAuthError { +class COMPONENT_EXPORT(GOOGLE_APIS) GoogleServiceAuthError { public: // // These enumerations are referenced by integer value in HTML login code and
diff --git a/google_apis/gaia/oauth2_access_token_consumer.h b/google_apis/gaia/oauth2_access_token_consumer.h index 3dad545..b7bce19 100644 --- a/google_apis/gaia/oauth2_access_token_consumer.h +++ b/google_apis/gaia/oauth2_access_token_consumer.h
@@ -7,16 +7,17 @@ #include <string> +#include "base/component_export.h" #include "base/time/time.h" class GoogleServiceAuthError; // An interface that defines the callbacks for consumers to which // OAuth2AccessTokenFetcher can return results. -class OAuth2AccessTokenConsumer { +class COMPONENT_EXPORT(GOOGLE_APIS) OAuth2AccessTokenConsumer { public: // Structure representing information contained in OAuth2 access token. - struct TokenResponse { + struct COMPONENT_EXPORT(GOOGLE_APIS) TokenResponse { TokenResponse(); TokenResponse(const TokenResponse& response); TokenResponse(TokenResponse&& response); @@ -39,7 +40,7 @@ std::string id_token; // Helper class to make building TokenResponse objects clearer. - class Builder { + class COMPONENT_EXPORT(GOOGLE_APIS) Builder { public: Builder(); ~Builder();
diff --git a/google_apis/gaia/oauth2_access_token_fetcher.h b/google_apis/gaia/oauth2_access_token_fetcher.h index 585611d..29db3b4 100644 --- a/google_apis/gaia/oauth2_access_token_fetcher.h +++ b/google_apis/gaia/oauth2_access_token_fetcher.h
@@ -8,6 +8,7 @@ #include <string> #include <vector> +#include "base/component_export.h" #include "base/memory/raw_ptr.h" #include "google_apis/gaia/oauth2_access_token_consumer.h" @@ -21,7 +22,7 @@ // // This class can handle one request at a time. To parallelize requests, // create multiple instances. -class OAuth2AccessTokenFetcher { +class COMPONENT_EXPORT(GOOGLE_APIS) OAuth2AccessTokenFetcher { public: explicit OAuth2AccessTokenFetcher(OAuth2AccessTokenConsumer* consumer);
diff --git a/google_apis/gaia/oauth2_access_token_fetcher_immediate_error.h b/google_apis/gaia/oauth2_access_token_fetcher_immediate_error.h index 1dba817..ddb17a9 100644 --- a/google_apis/gaia/oauth2_access_token_fetcher_immediate_error.h +++ b/google_apis/gaia/oauth2_access_token_fetcher_immediate_error.h
@@ -5,6 +5,7 @@ #ifndef GOOGLE_APIS_GAIA_OAUTH2_ACCESS_TOKEN_FETCHER_IMMEDIATE_ERROR_H_ #define GOOGLE_APIS_GAIA_OAUTH2_ACCESS_TOKEN_FETCHER_IMMEDIATE_ERROR_H_ +#include "base/component_export.h" #include "base/memory/raw_ptr.h" #include "base/memory/ref_counted.h" #include "google_apis/gaia/google_service_auth_error.h" @@ -28,7 +29,8 @@ // // This class can handle one request at a time. To parallelize requests, // create multiple instances. -class OAuth2AccessTokenFetcherImmediateError : public OAuth2AccessTokenFetcher { +class COMPONENT_EXPORT(GOOGLE_APIS) OAuth2AccessTokenFetcherImmediateError + : public OAuth2AccessTokenFetcher { public: OAuth2AccessTokenFetcherImmediateError(OAuth2AccessTokenConsumer* consumer, const GoogleServiceAuthError& error); @@ -47,7 +49,8 @@ void CancelRequest() override; private: - class FailCaller : public base::RefCounted<FailCaller> { + class COMPONENT_EXPORT(GOOGLE_APIS) FailCaller + : public base::RefCounted<FailCaller> { public: FailCaller(OAuth2AccessTokenFetcherImmediateError* fetcher);
diff --git a/google_apis/gaia/oauth2_access_token_fetcher_impl.cc b/google_apis/gaia/oauth2_access_token_fetcher_impl.cc index 4a3c42a..c3fcb30 100644 --- a/google_apis/gaia/oauth2_access_token_fetcher_impl.cc +++ b/google_apis/gaia/oauth2_access_token_fetcher_impl.cc
@@ -16,6 +16,7 @@ #include "base/strings/stringprintf.h" #include "base/time/time.h" #include "base/values.h" +#include "google_apis/credentials_mode.h" #include "google_apis/gaia/gaia_auth_util.h" #include "google_apis/gaia/google_service_auth_error.h" #include "net/http/http_status_code.h" @@ -95,7 +96,8 @@ const net::NetworkTrafficAnnotationTag& traffic_annotation) { auto resource_request = std::make_unique<network::ResourceRequest>(); resource_request->url = url; - resource_request->credentials_mode = network::mojom::CredentialsMode::kOmit; + resource_request->credentials_mode = + google_apis::GetOmitCredentialsModeForGaiaRequests(); if (!body.empty()) resource_request->method = "POST";
diff --git a/google_apis/gaia/oauth2_access_token_fetcher_impl.h b/google_apis/gaia/oauth2_access_token_fetcher_impl.h index 8570a3a..1372527 100644 --- a/google_apis/gaia/oauth2_access_token_fetcher_impl.h +++ b/google_apis/gaia/oauth2_access_token_fetcher_impl.h
@@ -9,6 +9,7 @@ #include <string> #include <vector> +#include "base/component_export.h" #include "base/gtest_prod_util.h" #include "base/memory/ref_counted.h" #include "google_apis/gaia/oauth2_access_token_consumer.h" @@ -39,7 +40,8 @@ // This class can handle one request at a time. To parallelize requests, // create multiple instances. Prefer `GaiaAccessTokenFetcher` over this class // while talking to Google's OAuth servers. -class OAuth2AccessTokenFetcherImpl : public OAuth2AccessTokenFetcher { +class COMPONENT_EXPORT(GOOGLE_APIS) OAuth2AccessTokenFetcherImpl + : public OAuth2AccessTokenFetcher { public: // Enumerated constants of server responses, matching RFC 6749. // These values are persisted to logs. Entries should not be renumbered and
diff --git a/google_apis/gaia/oauth2_access_token_manager.h b/google_apis/gaia/oauth2_access_token_manager.h index ba1b0793..f787f48 100644 --- a/google_apis/gaia/oauth2_access_token_manager.h +++ b/google_apis/gaia/oauth2_access_token_manager.h
@@ -8,6 +8,7 @@ #include <map> #include <set> +#include "base/component_export.h" #include "base/gtest_prod_util.h" #include "base/memory/raw_ptr.h" #include "base/observer_list.h" @@ -24,13 +25,13 @@ class OAuth2AccessTokenFetcher; // Class that manages requests for OAuth2 access tokens. -class OAuth2AccessTokenManager { +class COMPONENT_EXPORT(GOOGLE_APIS) OAuth2AccessTokenManager { public: // A set of scopes in OAuth2 authentication. typedef std::set<std::string> ScopeSet; class RequestImpl; - class Delegate { + class COMPONENT_EXPORT(GOOGLE_APIS) Delegate { public: Delegate(); virtual ~Delegate(); @@ -79,7 +80,7 @@ }; // Class representing a request that fetches an OAuth2 access token. - class Request { + class COMPONENT_EXPORT(GOOGLE_APIS) Request { public: virtual ~Request(); virtual CoreAccountId GetAccountId() const = 0; @@ -90,7 +91,7 @@ // Class representing the consumer of a Request passed to |StartRequest|, // which will be called back when the request completes. - class Consumer { + class COMPONENT_EXPORT(GOOGLE_APIS) Consumer { public: explicit Consumer(const std::string& id); virtual ~Consumer(); @@ -112,8 +113,9 @@ // Implements a cancelable |OAuth2AccessTokenManager::Request|, which should // be operated on the UI thread. // TODO(davidroche): move this out of header file. - class RequestImpl : public base::SupportsWeakPtr<RequestImpl>, - public Request { + class COMPONENT_EXPORT(GOOGLE_APIS) RequestImpl + : public base::SupportsWeakPtr<RequestImpl>, + public Request { public: // |consumer| is required to outlive this. RequestImpl(const CoreAccountId& account_id, Consumer* consumer); @@ -140,7 +142,7 @@ // Classes that want to monitor status of access token and access token // request should implement this interface and register with the // AddDiagnosticsObserver() call. - class DiagnosticsObserver { + class COMPONENT_EXPORT(GOOGLE_APIS) DiagnosticsObserver { public: // Called when receiving request for access token. virtual void OnAccessTokenRequested(const CoreAccountId& account_id, @@ -162,7 +164,7 @@ }; // The parameters used to fetch an OAuth2 access token. - struct RequestParameters { + struct COMPONENT_EXPORT(GOOGLE_APIS) RequestParameters { RequestParameters(const std::string& client_id, const CoreAccountId& account_id, const ScopeSet& scopes);
diff --git a/google_apis/gaia/oauth2_api_call_flow.cc b/google_apis/gaia/oauth2_api_call_flow.cc index 37a1b34..b9f28b94 100644 --- a/google_apis/gaia/oauth2_api_call_flow.cc +++ b/google_apis/gaia/oauth2_api_call_flow.cc
@@ -10,6 +10,7 @@ #include "base/functional/bind.h" #include "base/strings/escape.h" #include "base/strings/stringprintf.h" +#include "google_apis/credentials_mode.h" #include "google_apis/gaia/gaia_auth_util.h" #include "google_apis/gaia/gaia_urls.h" #include "net/base/load_flags.h" @@ -98,7 +99,8 @@ auto request = std::make_unique<network::ResourceRequest>(); request->url = CreateApiCallUrl(); request->method = request_type; - request->credentials_mode = network::mojom::CredentialsMode::kOmit; + request->credentials_mode = + google_apis::GetOmitCredentialsModeForGaiaRequests(); request->headers = CreateApiCallHeaders(); request->headers.SetHeader("Authorization", MakeAuthorizationValue(access_token));
diff --git a/google_apis/gaia/oauth2_api_call_flow.h b/google_apis/gaia/oauth2_api_call_flow.h index c194eeb..9e8b075a 100644 --- a/google_apis/gaia/oauth2_api_call_flow.h +++ b/google_apis/gaia/oauth2_api_call_flow.h
@@ -8,6 +8,7 @@ #include <memory> #include <string> +#include "base/component_export.h" #include "base/memory/scoped_refptr.h" #include "net/traffic_annotation/network_traffic_annotation.h" #include "services/network/public/mojom/url_response_head.mojom-forward.h" @@ -26,7 +27,7 @@ // given an access token to the service. This class abstracts the basic steps // and exposes template methods for sub-classes to implement for API specific // details. -class OAuth2ApiCallFlow { +class COMPONENT_EXPORT(GOOGLE_APIS) OAuth2ApiCallFlow { public: OAuth2ApiCallFlow();
diff --git a/google_apis/gaia/oauth2_id_token_decoder.h b/google_apis/gaia/oauth2_id_token_decoder.h index d7bdfa4..64a9c6b 100644 --- a/google_apis/gaia/oauth2_id_token_decoder.h +++ b/google_apis/gaia/oauth2_id_token_decoder.h
@@ -8,6 +8,8 @@ #include <string> #include <vector> +#include "base/component_export.h" + // This file holds methods decodes the id token received for OAuth2 token // endpoint, and derive useful information from it, such as whether the account // is a child account, and whether this account is under advanced protection. @@ -15,12 +17,13 @@ namespace gaia { // Service flags extracted from ID token. -struct TokenServiceFlags { +struct COMPONENT_EXPORT(GOOGLE_APIS) TokenServiceFlags { bool is_child_account = false; bool is_under_advanced_protection = false; }; // Parses service flag from ID token. +COMPONENT_EXPORT(GOOGLE_APIS) TokenServiceFlags ParseServiceFlags(const std::string& id_token); } // namespace gaia
diff --git a/google_apis/gaia/oauth2_mint_token_flow.h b/google_apis/gaia/oauth2_mint_token_flow.h index fe633950..ef861fe 100644 --- a/google_apis/gaia/oauth2_mint_token_flow.h +++ b/google_apis/gaia/oauth2_mint_token_flow.h
@@ -9,6 +9,7 @@ #include <string> #include <vector> +#include "base/component_export.h" #include "base/gtest_prod_util.h" #include "base/memory/raw_ptr.h" #include "base/memory/weak_ptr.h" @@ -21,6 +22,7 @@ class GoogleServiceAuthError; class OAuth2MintTokenFlowTest; +COMPONENT_EXPORT(GOOGLE_APIS) extern const char kOAuth2MintTokenApiCallResultHistogram[]; // Values carrying the result of processing a successful API call. @@ -48,7 +50,7 @@ // Data for the remote consent resolution: // - URL of the consent page to be displayed to the user. // - Cookies that should be set before navigating to that URL. -struct RemoteConsentResolutionData { +struct COMPONENT_EXPORT(GOOGLE_APIS) RemoteConsentResolutionData { RemoteConsentResolutionData(); ~RemoteConsentResolutionData(); @@ -65,7 +67,8 @@ // This class implements the OAuth2 flow to Google to mint an OAuth2 access // token for the given client and the given set of scopes from the OAuthLogin // scoped "master" OAuth2 token for the user logged in to Chrome. -class OAuth2MintTokenFlow : public OAuth2ApiCallFlow { +class COMPONENT_EXPORT(GOOGLE_APIS) OAuth2MintTokenFlow + : public OAuth2ApiCallFlow { public: // There are four different modes when minting a token to grant // access to third-party app for a user. @@ -81,7 +84,7 @@ }; // Parameters needed to mint a token. - struct Parameters { + struct COMPONENT_EXPORT(GOOGLE_APIS) Parameters { public: Parameters(); Parameters(const std::string& eid, @@ -109,7 +112,7 @@ Mode mode; }; - class Delegate { + class COMPONENT_EXPORT(GOOGLE_APIS) Delegate { public: virtual void OnMintTokenSuccess(const std::string& access_token, const std::set<std::string>& granted_scopes,
diff --git a/google_apis/gaia/oauth_multilogin_result.h b/google_apis/gaia/oauth_multilogin_result.h index bd1e024..0e219a3 100644 --- a/google_apis/gaia/oauth_multilogin_result.h +++ b/google_apis/gaia/oauth_multilogin_result.h
@@ -7,6 +7,7 @@ #include <string> +#include "base/component_export.h" #include "base/gtest_prod_util.h" #include "base/values.h" #include "google_apis/gaia/gaia_auth_util.h" @@ -49,10 +50,11 @@ }; // Parses the status field of the response. +COMPONENT_EXPORT(GOOGLE_APIS) OAuthMultiloginResponseStatus ParseOAuthMultiloginResponseStatus( const std::string& status); -class OAuthMultiloginResult { +class COMPONENT_EXPORT(GOOGLE_APIS) OAuthMultiloginResult { public: // Parses cookies and status from JSON response. Maps status to // GoogleServiceAuthError::State values or sets error to
diff --git a/google_apis/gaia/oauth_request_signer.h b/google_apis/gaia/oauth_request_signer.h index 06789733..5926cc8 100644 --- a/google_apis/gaia/oauth_request_signer.h +++ b/google_apis/gaia/oauth_request_signer.h
@@ -8,13 +8,15 @@ #include <map> #include <string> +#include "base/component_export.h" + class GURL; // Implements the OAuth request signing process as described here: // http://oauth.net/core/1.0/#signing_process // // NOTE: Currently the only supported SignatureMethod is HMAC_SHA1_SIGNATURE -class OAuthRequestSigner { +class COMPONENT_EXPORT(GOOGLE_APIS) OAuthRequestSigner { public: enum SignatureMethod { HMAC_SHA1_SIGNATURE,
diff --git a/google_apis/gcm/engine/checkin_request.cc b/google_apis/gcm/engine/checkin_request.cc index 544bdca..ff40cfa 100644 --- a/google_apis/gcm/engine/checkin_request.cc +++ b/google_apis/gcm/engine/checkin_request.cc
@@ -9,6 +9,7 @@ #include "base/metrics/histogram_functions.h" #include "base/task/sequenced_task_runner.h" #include "build/chromeos_buildflags.h" +#include "google_apis/credentials_mode.h" #include "google_apis/gcm/monitoring/gcm_stats_recorder.h" #include "google_apis/gcm/protocol/checkin.pb.h" #include "net/base/load_flags.h" @@ -193,7 +194,8 @@ auto resource_request = std::make_unique<network::ResourceRequest>(); resource_request->url = checkin_url_; resource_request->method = "POST"; - resource_request->credentials_mode = network::mojom::CredentialsMode::kOmit; + resource_request->credentials_mode = + google_apis::GetOmitCredentialsModeForGaiaRequests(); DVLOG(1) << "Performing check-in request with android id: " << request_info_.android_id
diff --git a/google_apis/gcm/engine/registration_request.cc b/google_apis/gcm/engine/registration_request.cc index 50d754d9..36adf30 100644 --- a/google_apis/gcm/engine/registration_request.cc +++ b/google_apis/gcm/engine/registration_request.cc
@@ -14,6 +14,7 @@ #include "base/strings/string_number_conversions.h" #include "base/task/sequenced_task_runner.h" #include "base/values.h" +#include "google_apis/credentials_mode.h" #include "google_apis/gcm/base/gcm_util.h" #include "google_apis/gcm/monitoring/gcm_stats_recorder.h" #include "net/base/load_flags.h" @@ -176,7 +177,8 @@ auto request = std::make_unique<network::ResourceRequest>(); request->url = registration_url_; request->method = "POST"; - request->credentials_mode = network::mojom::CredentialsMode::kOmit; + request->credentials_mode = + google_apis::GetOmitCredentialsModeForGaiaRequests(); BuildRequestHeaders(&request->headers); std::string body;
diff --git a/google_apis/gcm/engine/registration_request_unittest.cc b/google_apis/gcm/engine/registration_request_unittest.cc index 7dc1cb8..ec5ce5b 100644 --- a/google_apis/gcm/engine/registration_request_unittest.cc +++ b/google_apis/gcm/engine/registration_request_unittest.cc
@@ -15,6 +15,7 @@ #include "base/strings/string_number_conversions.h" #include "base/strings/string_tokenizer.h" #include "base/task/single_thread_task_runner.h" +#include "google_apis/credentials_mode.h" #include "google_apis/gcm/engine/gcm_registration_request_handler.h" #include "google_apis/gcm/engine/gcm_request_test_base.h" #include "google_apis/gcm/engine/instance_id_get_token_request_handler.h" @@ -459,7 +460,7 @@ const network::ResourceRequest* pending_request; ASSERT_TRUE( test_url_loader_factory()->IsPending(kRegistrationURL, &pending_request)); - EXPECT_EQ(network::mojom::CredentialsMode::kOmit, + EXPECT_EQ(google_apis::GetOmitCredentialsModeForGaiaRequests(), pending_request->credentials_mode); // Verify that authorization header was put together properly.
diff --git a/google_apis/gcm/engine/unregistration_request.cc b/google_apis/gcm/engine/unregistration_request.cc index 3782675..195f5a97 100644 --- a/google_apis/gcm/engine/unregistration_request.cc +++ b/google_apis/gcm/engine/unregistration_request.cc
@@ -13,6 +13,7 @@ #include "base/strings/string_piece.h" #include "base/task/sequenced_task_runner.h" #include "base/values.h" +#include "google_apis/credentials_mode.h" #include "google_apis/gcm/base/gcm_util.h" #include "google_apis/gcm/monitoring/gcm_stats_recorder.h" #include "net/base/load_flags.h" @@ -163,7 +164,8 @@ auto request = std::make_unique<network::ResourceRequest>(); request->url = registration_url_; request->method = "POST"; - request->credentials_mode = network::mojom::CredentialsMode::kOmit; + request->credentials_mode = + google_apis::GetOmitCredentialsModeForGaiaRequests(); BuildRequestHeaders(&request->headers); std::string body;
diff --git a/google_apis/gcm/engine/unregistration_request_unittest.cc b/google_apis/gcm/engine/unregistration_request_unittest.cc index 760ea34..d4637128 100644 --- a/google_apis/gcm/engine/unregistration_request_unittest.cc +++ b/google_apis/gcm/engine/unregistration_request_unittest.cc
@@ -14,6 +14,7 @@ #include "base/strings/string_number_conversions.h" #include "base/strings/string_tokenizer.h" #include "base/task/single_thread_task_runner.h" +#include "google_apis/credentials_mode.h" #include "google_apis/gcm/engine/gcm_request_test_base.h" #include "google_apis/gcm/engine/gcm_unregistration_request_handler.h" #include "google_apis/gcm/engine/instance_id_delete_token_request_handler.h" @@ -118,7 +119,7 @@ const network::ResourceRequest* pending_request; ASSERT_TRUE( test_url_loader_factory()->IsPending(kRegistrationURL, &pending_request)); - EXPECT_EQ(network::mojom::CredentialsMode::kOmit, + EXPECT_EQ(google_apis::GetOmitCredentialsModeForGaiaRequests(), pending_request->credentials_mode); // Verify that authorization header was put together properly.
diff --git a/google_apis/google_api_keys.h b/google_apis/google_api_keys.h index 4275578d..ba958fc 100644 --- a/google_apis/google_api_keys.h +++ b/google_apis/google_api_keys.h
@@ -9,6 +9,7 @@ // google_api_keys_unittest.cc. #include <string> +#include "base/component_export.h" #include "build/build_config.h" #include "build/chromeos_buildflags.h" #include "google_apis/buildflags.h" @@ -61,47 +62,47 @@ namespace google_apis { -extern const char kAPIKeysDevelopersHowToURL[]; +COMPONENT_EXPORT(GOOGLE_APIS) extern const char kAPIKeysDevelopersHowToURL[]; // Returns true if no dummy API key is set. -bool HasAPIKeyConfigured(); +COMPONENT_EXPORT(GOOGLE_APIS) bool HasAPIKeyConfigured(); // Retrieves the API key, a.k.a. developer key, or a dummy string // if not set. // // Note that the key should be escaped for the context you use it in, // e.g. URL-escaped if you use it in a URL. -std::string GetAPIKey(); +COMPONENT_EXPORT(GOOGLE_APIS) std::string GetAPIKey(); // Non-stable channels may have a different Google API key. -std::string GetNonStableAPIKey(); +COMPONENT_EXPORT(GOOGLE_APIS) std::string GetNonStableAPIKey(); // Retrieves the Chrome Remote Desktop API key. -std::string GetRemotingAPIKey(); +COMPONENT_EXPORT(GOOGLE_APIS) std::string GetRemotingAPIKey(); // Retrieves the Speech On-Device API (SODA) API Key. -std::string GetSodaAPIKey(); +COMPONENT_EXPORT(GOOGLE_APIS) std::string GetSodaAPIKey(); #if BUILDFLAG(IS_CHROMEOS_ASH) // Retrieves the Sharing API Key. -std::string GetSharingAPIKey(); +COMPONENT_EXPORT(GOOGLE_APIS) std::string GetSharingAPIKey(); // Retrieves the ReadAloud API Key. -std::string GetReadAloudAPIKey(); +COMPONENT_EXPORT(GOOGLE_APIS) std::string GetReadAloudAPIKey(); // Retrieves the Fresnel API Key. -std::string GetFresnelAPIKey(); +COMPONENT_EXPORT(GOOGLE_APIS) std::string GetFresnelAPIKey(); #endif #if BUILDFLAG(SUPPORT_EXTERNAL_GOOGLE_API_KEY) // Sets the API key. This should be called as early as possible before this // API key is even accessed. It must be called before GetAPIKey. // TODO(https://crbug.com/1166007): Enforce this is called before GetAPIKey. -void SetAPIKey(const std::string& api_key); +COMPONENT_EXPORT(GOOGLE_APIS) void SetAPIKey(const std::string& api_key); #endif // Retrieves the key used to sign metrics (UMA/UKM) uploads. -std::string GetMetricsKey(); +COMPONENT_EXPORT(GOOGLE_APIS) std::string GetMetricsKey(); // Represents the different sets of client IDs and secrets in use. enum OAuth2Client { @@ -113,13 +114,14 @@ }; // Returns true if no dummy OAuth2 client ID and secret are set. -bool HasOAuthClientConfigured(); +COMPONENT_EXPORT(GOOGLE_APIS) bool HasOAuthClientConfigured(); // Retrieves the OAuth2 client ID for the specified client, or the // empty string if not set. // // Note that the ID should be escaped for the context you use it in, // e.g. URL-escaped if you use it in a URL. +COMPONENT_EXPORT(GOOGLE_APIS) std::string GetOAuth2ClientID(OAuth2Client client); // Retrieves the OAuth2 client secret for the specified client, or the @@ -127,22 +129,25 @@ // // Note that the secret should be escaped for the context you use it // in, e.g. URL-escaped if you use it in a URL. +COMPONENT_EXPORT(GOOGLE_APIS) std::string GetOAuth2ClientSecret(OAuth2Client client); #if BUILDFLAG(IS_IOS) // Sets the client id for the specified client. Should be called as early as // possible before these ids are accessed. +COMPONENT_EXPORT(GOOGLE_APIS) void SetOAuth2ClientID(OAuth2Client client, const std::string& client_id); // Sets the client secret for the specified client. Should be called as early as // possible before these secrets are accessed. +COMPONENT_EXPORT(GOOGLE_APIS) void SetOAuth2ClientSecret(OAuth2Client client, const std::string& client_secret); #endif // Returns if the API key using in the current build is the one for official // Google Chrome. -bool IsGoogleChromeAPIKeyUsed(); +COMPONENT_EXPORT(GOOGLE_APIS) bool IsGoogleChromeAPIKeyUsed(); } // namespace google_apis
diff --git a/google_apis/google_api_keys_mac.h b/google_apis/google_api_keys_mac.h index 8c1fc8a..efc03a6 100644 --- a/google_apis/google_api_keys_mac.h +++ b/google_apis/google_api_keys_mac.h
@@ -7,8 +7,11 @@ #include <string> +#include "base/component_export.h" + namespace google_apis { +COMPONENT_EXPORT(GOOGLE_APIS) std::string GetAPIKeyFromInfoPlist(const std::string& key_name); } // namespace google_apis
diff --git a/gpu/command_buffer/service/abstract_texture_android.h b/gpu/command_buffer/service/abstract_texture_android.h index 2cfc335e..9e97d63 100644 --- a/gpu/command_buffer/service/abstract_texture_android.h +++ b/gpu/command_buffer/service/abstract_texture_android.h
@@ -71,7 +71,7 @@ bool have_context_ = true; std::unique_ptr<TextureBase> texture_for_testing_; - raw_ptr<gles2::Texture, DanglingUntriaged> texture_; + raw_ptr<gles2::Texture, DanglingUntriaged> texture_ = nullptr; scoped_refptr<gles2::TexturePassthrough> texture_passthrough_; raw_ptr<gl::GLApi, DanglingUntriaged> api_ = nullptr; };
diff --git a/gpu/command_buffer/service/webgpu_decoder_impl.cc b/gpu/command_buffer/service/webgpu_decoder_impl.cc index 8cc325d2..d819846 100644 --- a/gpu/command_buffer/service/webgpu_decoder_impl.cc +++ b/gpu/command_buffer/service/webgpu_decoder_impl.cc
@@ -1532,8 +1532,17 @@ swiftShaderOptions.forceSwiftShader = true; dawn_instance_->DiscoverAdapters(&swiftShaderOptions); #endif // BUILDFLAG(ENABLE_VULKAN) -#endif // BUILDFLAG(IS_WIN) + if (use_webgpu_adapter_ == WebGPUAdapterName::kCompat) { + // On compat, discover default adapters to also discover the compat adapter. + // TODO(senorblanco): This may incorrectly discover a compat adapter that + // does not match the one ANGLE is using. + dawn_instance_->DiscoverDefaultAdapters(); + } +#else // BUILDFLAG(IS_WIN) + // Only discover default adapters on non-Windows. Windows requires + // compatibility with ANGLE. Other adapters will not be compatible. dawn_instance_->DiscoverDefaultAdapters(); +#endif // BUILDFLAG(IS_WIN) std::vector<dawn::native::Adapter> adapters = dawn_instance_->GetAdapters(); for (dawn::native::Adapter& adapter : adapters) {
diff --git a/headless/lib/browser/devtools_api/domain_types_cc.template b/headless/lib/browser/devtools_api/domain_types_cc.template index abedb81..c6a2f78 100644 --- a/headless/lib/browser/devtools_api/domain_types_cc.template +++ b/headless/lib/browser/devtools_api/domain_types_cc.template
@@ -31,9 +31,12 @@ std::unique_ptr<{{type.id}}> result(new {{type.id}}()); errors->Push(); errors->SetName("{{type.id}}"); + {% if type.properties %} + const base::Value::Dict& dict = value.GetDict(); + {% endif %} {% for property in type.properties %} {% set value_name = property.name | camelcase_to_hacker_style + "_value" %} - const base::Value* {{value_name}} = value.FindKey("{{property.name}}"); + const base::Value* {{value_name}} = dict.Find("{{property.name}}"); if ({{value_name}}) { errors->SetName("{{property.name}}"); {% if property.optional %}
diff --git a/headless/lib/browser/headless_browser_main_parts_linux.cc b/headless/lib/browser/headless_browser_main_parts_linux.cc index 0a4264c2..89e4640 100644 --- a/headless/lib/browser/headless_browser_main_parts_linux.cc +++ b/headless/lib/browser/headless_browser_main_parts_linux.cc
@@ -4,26 +4,129 @@ #include "headless/lib/browser/headless_browser_main_parts.h" +#include <signal.h> +#include <unistd.h> + +#include "base/functional/bind.h" +#include "base/functional/callback.h" +#include "base/logging.h" +#include "base/memory/scoped_refptr.h" +#include "base/no_destructor.h" +#include "base/task/single_thread_task_runner.h" #include "build/build_config.h" #include "build/chromeos_buildflags.h" -#include "device/bluetooth/dbus/bluez_dbus_manager.h" +#include "content/public/browser/browser_task_traits.h" +#include "content/public/browser/browser_thread.h" +#include "headless/lib/browser/headless_browser_impl.h" #if !BUILDFLAG(IS_CHROMEOS) #include "base/command_line.h" #include "components/os_crypt/key_storage_config_linux.h" #include "components/os_crypt/os_crypt.h" -#include "content/public/browser/browser_task_traits.h" -#include "content/public/browser/browser_thread.h" #include "headless/public/switches.h" #endif +#if defined(USE_DBUS) && !BUILDFLAG(IS_CHROMEOS_ASH) +#include "device/bluetooth/dbus/bluez_dbus_manager.h" +#endif + namespace headless { +namespace { + +class BrowserShutdownHandler { + public: + BrowserShutdownHandler(const BrowserShutdownHandler&) = delete; + BrowserShutdownHandler& operator=(const BrowserShutdownHandler&) = delete; + + static void Install(base::OnceClosure shutdown_callback) { + GetInstance().Init(content::GetUIThreadTaskRunner({}), + std::move(shutdown_callback)); + + // We need to handle SIGTERM, because that is how many POSIX-based distros + // ask processes to quit gracefully at shutdown time. + struct sigaction action; + memset(&action, 0, sizeof(action)); + action.sa_handler = SIGTERMHandler; + PCHECK(sigaction(SIGTERM, &action, nullptr) == 0); + + // Also handle SIGINT - when the user terminates the browser via Ctrl+C. If + // the browser process is being debugged, GDB will catch the SIGINT first. + action.sa_handler = SIGINTHandler; + PCHECK(sigaction(SIGINT, &action, nullptr) == 0); + + // And SIGHUP, for when the terminal disappears. On shutdown, many Linux + // distros send SIGHUP, SIGTERM, and then SIGKILL. + action.sa_handler = SIGHUPHandler; + PCHECK(sigaction(SIGHUP, &action, nullptr) == 0); + } + + private: + friend class base::NoDestructor<BrowserShutdownHandler>; + + BrowserShutdownHandler() = default; + ~BrowserShutdownHandler() = default; + + static BrowserShutdownHandler& GetInstance() { + static base::NoDestructor<BrowserShutdownHandler> instance; + return *instance; + } + + void Init(scoped_refptr<base::SingleThreadTaskRunner> task_runner, + base::OnceClosure shutdown_callback) { + task_runner_ = std::move(task_runner); + shutdown_callback_ = std::move(shutdown_callback); + } + + void Shutdown(int signal) { + if (shutdown_callback_) { + if (!task_runner_->PostTask(FROM_HERE, std::move(shutdown_callback_))) { + RAW_LOG(WARNING, "No valid task runner, exiting ungracefully."); + kill(getpid(), signal); + } + } + } + + static void SIGHUPHandler(int signal) { + RAW_CHECK(signal == SIGHUP); + ShutdownHandler(signal); + } + + static void SIGINTHandler(int signal) { + RAW_CHECK(signal == SIGINT); + ShutdownHandler(signal); + } + + static void SIGTERMHandler(int signal) { + RAW_CHECK(signal == SIGTERM); + ShutdownHandler(signal); + } + + static void ShutdownHandler(int signal) { + // Reinstall the default handler. We have only one shot at graceful + // shutdown. + struct sigaction action; + memset(&action, 0, sizeof(action)); + action.sa_handler = SIG_DFL; + RAW_CHECK(sigaction(signal, &action, nullptr) == 0); + + GetInstance().Shutdown(signal); + } + + scoped_refptr<base::SingleThreadTaskRunner> task_runner_; + base::OnceClosure shutdown_callback_; +}; + +} // namespace + #if !BUILDFLAG(IS_CHROMEOS) constexpr char kProductName[] = "HeadlessChrome"; #endif void HeadlessBrowserMainParts::PostCreateMainMessageLoop() { + BrowserShutdownHandler::Install( + base::BindOnce(&HeadlessBrowserImpl::Shutdown, browser_->GetWeakPtr())); + #if defined(USE_DBUS) && !BUILDFLAG(IS_CHROMEOS_ASH) bluez::BluezDBusManager::Initialize(/*system_bus=*/nullptr); #endif
diff --git a/infra/config/dev.star b/infra/config/dev.star index aaf286a0..4a17e62 100755 --- a/infra/config/dev.star +++ b/infra/config/dev.star
@@ -37,9 +37,10 @@ data = io.read_file("luci-analysis-dev.cfg"), ) -lucicfg.emit( - dest = "luci/chops-weetbix-dev.cfg", - data = io.read_file("chops-weetbix-dev.cfg"), -) +# TODO(b/270163072): Re-emit after staging is fixed. +# lucicfg.emit( +# dest = "luci/chops-weetbix-dev.cfg", +# data = io.read_file("chops-weetbix-dev.cfg"), +# ) branches.exec("//dev/dev.star")
diff --git a/infra/config/generated/luci/chops-weetbix-dev.cfg b/infra/config/generated/luci/chops-weetbix-dev.cfg deleted file mode 100644 index 07e05c1..0000000 --- a/infra/config/generated/luci/chops-weetbix-dev.cfg +++ /dev/null
@@ -1,77 +0,0 @@ -# Schema for this config file: ProjectConfig in: -# https://luci-config.appspot.com/schemas/projects:luci-analysis.cfg - -bug_filing_threshold { - # Do not file bugs for now. -} - -clustering { - test_name_rules { - name: "Blink Web Tests" - # To match blink_web_tests as well as webgpu_blink_web_tests and any others. - pattern: "^ninja://:(?P<target>\\w*blink_web_tests)/(virtual/[^/]+/)?(?P<test>([^/]+/)+[^/]+\\.[a-zA-Z]+).*$" - like_template: "ninja://:${target}/%${test}%" - } - test_name_rules { - name: "Google Test (Value-parameterized)" - pattern: "^ninja:(?P<target>[\\w/]+:\\w+)/(\\w+/)?(?P<suite>\\w+)\\.(?P<test>\\w+)/[\\w.]+$" - like_template: "ninja:${target}/%${suite}.${test}%" - } - test_name_rules { - name: "Google Test (Type-parameterized)" - pattern: "^ninja:(?P<target>[\\w/]+:\\w+)/(\\w+/)?(?P<suite>\\w+)/\\w+\\.(?P<test>\\w+)$" - like_template: "ninja:${target}/%${suite}/%.${test}" - } - test_name_rules { - name: "JUnit Test (Parameterized)" - # Matches parameterized JUnit tests like: - # ninja://android_webview/test:webview_instrumentation_test_apk/org.chromium.android_webview.test.MyTest#testFoo__parameter1 - # Also matches tests parameterized with different command line flags, - # as constructed by https://source.chromium.org/chromium/chromium/src/+/main:build/android/pylib/instrumentation/instrumentation_test_instance.py?q=%22def%20GetUniqueTestName(%22 - # E.g. ninja://chrome/android:chrome_public_test_apk/org.chromium.chrome.browser.omnibox.OmniboxTest#testDefaultText_with___disable_features=SpannableInlineAutocomplete - pattern: "^ninja:(?P<target>[\\w/]+:\\w+)/(?P<class>[\\w$.]+)#(?P<test>\\w+?)(?P<sep>__|_with_)[\\w.=,]+$" - like_template: "ninja:${target}/${class}#${test}${sep}%" - } -} - -monorail { - project: "chromium" - default_field_values { - # Type field. - field_id: 10 - value: "Bug" - } - priority_field_id: 11 - priorities { - priority: "0" - threshold { - presubmit_runs_failed { - one_day: 20 - } - } - } - priorities { - priority: "1" - threshold { - presubmit_runs_failed { - one_day: 10 - } - } - } - priorities { - priority: "2" - threshold { - # Clusters which fail to meet this threshold will be closed. - presubmit_runs_failed { - seven_day: 1 - } - critical_failures_exonerated { - seven_day: 1 - } - } - } - priority_hysteresis_percent: 50 - monorail_hostname: "monorail-staging.appspot.com" - display_prefix: "crbug.com" -} -
diff --git a/ios/chrome/browser/signin/gaia_auth_fetcher_ios.mm b/ios/chrome/browser/signin/gaia_auth_fetcher_ios.mm index 2c42335d..49ffe7f 100644 --- a/ios/chrome/browser/signin/gaia_auth_fetcher_ios.mm +++ b/ios/chrome/browser/signin/gaia_auth_fetcher_ios.mm
@@ -37,7 +37,10 @@ DCHECK(!HasPendingFetch()) << "Tried to fetch two things at once!"; bool cookies_required = - credentials_mode != network::mojom::CredentialsMode::kOmit; + credentials_mode != network::mojom::CredentialsMode::kOmit && + credentials_mode != + network::mojom::CredentialsMode::kOmitBug_775438_Workaround; + if (!cookies_required) { GaiaAuthFetcher::CreateAndStartGaiaFetcher(body, body_content_type, headers, gaia_gurl, credentials_mode,
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.h b/ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.h index a453ff9..e9576b0 100644 --- a/ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.h +++ b/ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.h
@@ -24,6 +24,11 @@ class BookmarkNode; } // namespace bookmarks +enum class BookmarkModelType { + kProfile, + kAccount, +}; + namespace bookmark_utils_ios { typedef std::vector<const bookmarks::BookmarkNode*> NodeVector; @@ -47,6 +52,20 @@ // to display a slighly different wording for the default folders. NSString* TitleForBookmarkNode(const bookmarks::BookmarkNode* node); +// Returns the model type for a node, based on profile model and account model, +// based on the root node. +// `bookmark_node` is the bookmark to query. It can not be null. +// `profile_model` is the profile mode. It can not be null. +// `account_model` is the account mode. It can be null. +// The node must belongs to one of the two models. +// This function is linear in time in the depth of the bookmark_node. +// TODO(crbug.com/1417992): once the bookmark nodes has access to its model, +// rewrite the function to be constant time. +BookmarkModelType GetBookmarkModelType( + const bookmarks::BookmarkNode* bookmark_node, + bookmarks::BookmarkModel* profile_model, + bookmarks::BookmarkModel* account_model); + #pragma mark - Updating Bookmarks // Creates the bookmark if `node` is NULL. Otherwise updates `node`.
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.mm b/ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.mm index 82f36a3..e22cdad5 100644 --- a/ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.mm +++ b/ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.mm
@@ -16,6 +16,7 @@ #import "base/hash/hash.h" #import "base/i18n/string_compare.h" #import "base/metrics/user_metrics_action.h" +#import "base/notreached.h" #import "base/ranges/algorithm.h" #import "base/strings/string_number_conversions.h" #import "base/strings/sys_string_conversions.h" @@ -108,6 +109,19 @@ return title; } +BookmarkModelType GetBookmarkModelType( + const bookmarks::BookmarkNode* bookmark_node, + bookmarks::BookmarkModel* profile_model, + bookmarks::BookmarkModel* account_model) { + DCHECK(profile_model); + if (bookmark_node->HasAncestor(profile_model->root_node())) { + return BookmarkModelType::kProfile; + } + DCHECK(account_model && + bookmark_node->HasAncestor(account_model->root_node())); + return BookmarkModelType::kAccount; +} + #pragma mark - Updating Bookmarks // Deletes all subnodes of `node`, including `node`, that are in `bookmarks`.
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_constants.h b/ios/chrome/browser/ui/content_suggestions/content_suggestions_constants.h index a51650d..19b0d01 100644 --- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_constants.h +++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_constants.h
@@ -37,4 +37,25 @@ // TrendingQueryIndex enum so it can capture a higher max value. const int kMaxTrendingQueries = 4; +// Tile Ablation constants. +// The amount of time between two tile ablation NTP impressions. (User opens +// NTP, 1 impression. If user goes back to NTP within +// `kTileAblationImpressionThresholdMinutes` don't count that as an NTP +// impression. +extern const int kTileAblationImpressionThresholdMinutes; +// Minimum and Maximum amount of days the Tile Ablation experiment can run for. +extern const int kTileAblationMinimumUseThresholdInDays; +extern const int kTileAblationMaximumUseThresholdInDays; +// Minimum an Maximum number of impressions until the Tile Ablation experiment +// ends before the NTP goes back to the normal state. +extern const int kMinimumImpressionThresholdTileAblation; +extern const int kMaximumImpressionThresholdTileAblation; +// Stores the last time an NTP impression was recorded. +extern NSString* const kLastNTPImpressionRecordedKey; +// Stores the number of NTP impressions over a period of time. +extern NSString* const kNumberOfNTPImpressionsRecordedKey; +// Stores the first NTP impression for the MVT experiment. +extern NSString* const kFirstImpressionRecordedTileAblationKey; +extern NSString* const kDoneWithTileAblationKey; + #endif // IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CONTENT_SUGGESTIONS_CONSTANTS_H_
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_constants.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_constants.mm index 6735d01..fb4d580 100644 --- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_constants.mm +++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_constants.mm
@@ -20,3 +20,15 @@ @"contentSuggestionsShortcutsAccessibilityIdentifierPrefix"; const CGFloat kMostVisitedBottomMargin = 13; + +const int kTileAblationImpressionThresholdMinutes = 5; +const int kTileAblationMinimumUseThresholdInDays = 7; +const int kTileAblationMaximumUseThresholdInDays = 14; +const int kMinimumImpressionThresholdTileAblation = 10; +const int kMaximumImpressionThresholdTileAblation = 20; +NSString* const kLastNTPImpressionRecordedKey = @"LastNTPImpressionRecorded"; +NSString* const kNumberOfNTPImpressionsRecordedKey = + @"NumberOfNTPImpressionsRecorded"; +NSString* const kFirstImpressionRecordedTileAblationKey = + @"kFirstImpressionRecordedTileAblationKey"; +NSString* const kDoneWithTileAblationKey = @"DoneWithTileAblation";
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.mm index ac615bb..5d48b11 100644 --- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.mm +++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.mm
@@ -222,6 +222,7 @@ } - (void)reloadAllData { + BOOL isTileAblationComplete = [self isTileAblationComplete]; if (!self.consumer) { return; } @@ -229,10 +230,12 @@ [self.consumer showReturnToRecentTabTileWithConfig:self.returnToRecentTabItem]; } - if ([self.mostVisitedItems count] && !ShouldHideMostVisited()) { + if ([self.mostVisitedItems count] && + (!ShouldHideMostVisited() || isTileAblationComplete)) { [self.consumer setMostVisitedTilesWithConfigs:self.mostVisitedItems]; } - if (!ShouldHideShortcutsForTrendingQueries() && !ShouldHideShortcuts()) { + if (!ShouldHideShortcutsForTrendingQueries() && + (!ShouldHideShortcuts() || isTileAblationComplete)) { [self.consumer setShortcutTilesWithConfigs:self.actionButtonItems]; } if (IsTrendingQueriesModuleEnabled()) { @@ -479,7 +482,7 @@ - (void)onMostVisitedURLsAvailable: (const ntp_tiles::NTPTilesVector&)mostVisited { - if (ShouldHideMostVisited()) { + if (ShouldHideMostVisited() && ![self isTileAblationComplete]) { return; } @@ -529,7 +532,7 @@ // Replaces the Most Visited items currently displayed by the most recent ones. - (void)useFreshMostVisited { - if (ShouldHideMostVisited()) { + if (ShouldHideMostVisited() && ![self isTileAblationComplete]) { return; } self.mostVisitedItems = self.freshMostVisitedItems; @@ -641,6 +644,52 @@ return !isSignedIn; } +// Checks if users have met conditions to drop from the experiment to hide the +// Most Visited Tiles and Shortcuts from the NTP. +- (BOOL)isTileAblationComplete { + // Conditions: + // MVT/Shortcuts Should be shown again if: + // 1. User has used Bling < `kTileAblationMinimumUseThresholdInDays` days AND + // NTP Impressions > `kMinimumImpressionThresholdTileAblation`; or + // 2. User has used Bling >= `kTileAblationMaximumUseThresholdInDays` days + // or + // 3. NTP Impressions > `kMaximumImpressionThresholdTileAblation`; + // NTP impression time threshold is >= + // `kTileAblationImpressionThresholdMinutes` minutes per impression. + // (eg. 2 NTP impressions within <5 minutes of each other will count as 1 NTP + // impression for the purposes of this test. + + // Return early if ablation was already complete. + NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; + if ([defaults boolForKey:kDoneWithTileAblationKey]) { + return YES; + } + + int impressions = [defaults integerForKey:kNumberOfNTPImpressionsRecordedKey]; + NSDate* firstImpressionDate = base::mac::ObjCCast<NSDate>( + [defaults objectForKey:kFirstImpressionRecordedTileAblationKey]); + // Return early if no NTP impression has been recorded. + if (firstImpressionDate == nil) { + return NO; + } + base::Time firstImpressionTime = base::Time::FromNSDate(firstImpressionDate); + + if ( // User has used Bling < `kTileAblationMinimumUseThresholdInDays` days + // AND NTP Impressions > `kMinimumImpressionThresholdTileAblation`; or + (base::Time::Now() - firstImpressionTime >= + base::Days(kTileAblationMinimumUseThresholdInDays) && + impressions >= kMinimumImpressionThresholdTileAblation) || + // User has used Bling >= `kTileAblationMaximumUseThresholdInDays` days + (base::Time::Now() - firstImpressionTime >= + base::Days(kTileAblationMaximumUseThresholdInDays)) || + // NTP Impressions >= `kMaximumImpressionThresholdTileAblation`; + (impressions >= kMaximumImpressionThresholdTileAblation)) { + [defaults setBool:YES forKey:kDoneWithTileAblationKey]; + return YES; + } + return NO; +} + #pragma mark - Properties - (NSArray<ContentSuggestionsMostVisitedActionItem*>*)actionButtonItems {
diff --git a/ios/chrome/browser/ui/content_suggestions/ntp_home_metrics.h b/ios/chrome/browser/ui/content_suggestions/ntp_home_metrics.h index 5266330..ea206ed 100644 --- a/ios/chrome/browser/ui/content_suggestions/ntp_home_metrics.h +++ b/ios/chrome/browser/ui/content_suggestions/ntp_home_metrics.h
@@ -19,7 +19,8 @@ // Records an NTP impression of type `impression_type`. void RecordNTPImpression(ntp_home::IOSNTPImpression impression_type); - +// Records when an NTP impression has occurred for Tile Ablation. +void NTPImpressionHasOccurred(); } // namespace ntp_home // These values are persisted to IOS.ContentSuggestions.ActionOn* histograms.
diff --git a/ios/chrome/browser/ui/content_suggestions/ntp_home_metrics.mm b/ios/chrome/browser/ui/content_suggestions/ntp_home_metrics.mm index ebe0de2..b6a543a0 100644 --- a/ios/chrome/browser/ui/content_suggestions/ntp_home_metrics.mm +++ b/ios/chrome/browser/ui/content_suggestions/ntp_home_metrics.mm
@@ -4,9 +4,11 @@ #import "ios/chrome/browser/ui/content_suggestions/ntp_home_metrics.h" +#import "base/mac/foundation_util.h" #import "base/metrics/histogram_macros.h" #import "base/metrics/user_metrics.h" #import "base/metrics/user_metrics_action.h" +#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_constants.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." @@ -14,8 +16,41 @@ namespace ntp_home { +// Records when an NTP impression has occurred for purposes of Tile Ablation. +void NTPImpressionHasOccurred() { + base::Time now = base::Time::Now(); + NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; + if ([defaults boolForKey:kDoneWithTileAblationKey]) { + return; + } + // Find/Set first NTP impression ever. + NSDate* firstImpressionRecordedTileAblationExperiment = + base::mac::ObjCCast<NSDate>( + [defaults objectForKey:kFirstImpressionRecordedTileAblationKey]); + int impressions = [defaults integerForKey:kNumberOfNTPImpressionsRecordedKey]; + // Record first NTP impression. + if (firstImpressionRecordedTileAblationExperiment == nil) { + [defaults setObject:now.ToNSDate() + forKey:kFirstImpressionRecordedTileAblationKey]; + [defaults setObject:now.ToNSDate() forKey:kLastNTPImpressionRecordedKey]; + [defaults setInteger:1 forKey:kNumberOfNTPImpressionsRecordedKey]; + return; + } + NSDate* lastImpressionTileAblation = base::mac::ObjCCast<NSDate>( + [defaults objectForKey:kLastNTPImpressionRecordedKey]); + // Check when the last impression happened. + if (now - base::Time::FromNSDate(lastImpressionTileAblation) >= + base::Minutes(kTileAblationImpressionThresholdMinutes)) { + // Count impression for MVT/Shortcuts Experiment. + [defaults setObject:now.ToNSDate() forKey:kLastNTPImpressionRecordedKey]; + [defaults setInteger:impressions + 1 + forKey:kNumberOfNTPImpressionsRecordedKey]; + } +} + void RecordNTPImpression(IOSNTPImpression impression_type) { UMA_HISTOGRAM_ENUMERATION("IOS.NTP.Impression", impression_type, COUNT); + NTPImpressionHasOccurred(); } } // namespace ntp_home
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_view_controller.mm b/ios/chrome/browser/ui/ntp/new_tab_page_view_controller.mm index edf2d11..0078f5c 100644 --- a/ios/chrome/browser/ui/ntp/new_tab_page_view_controller.mm +++ b/ios/chrome/browser/ui/ntp/new_tab_page_view_controller.mm
@@ -214,7 +214,6 @@ self.headerController.showing = YES; - [self applyCollectionViewConstraints]; [self updateNTPLayout]; // Scroll to the top before coming into view to minimize sudden visual jerking @@ -435,14 +434,15 @@ // changes in feed visibility. [self applyCollectionViewConstraints]; + // Force relayout so that the views added in this method are rendered ASAP, + // ensuring it is showing in the new tab animation. + [self.view setNeedsLayout]; + [self.view layoutIfNeeded]; + // If the feed is not visible, we control the delegate ourself (since it is - // otherwise controlled by the feed service). The view is also layed out - // so that we can correctly calculate the minimum height. + // otherwise controlled by the feed service). if (!self.isFeedVisible) { self.feedWrapperViewController.contentCollectionView.delegate = self; - - [self.view setNeedsLayout]; - [self.view layoutIfNeeded]; [self setMinimumHeight]; } }
diff --git a/ios/chrome/browser/ui/overlays/infobar_banner/passwords/password_infobar_banner_overlay_mediator_unittest.mm b/ios/chrome/browser/ui/overlays/infobar_banner/passwords/password_infobar_banner_overlay_mediator_unittest.mm index 6870893..0b3ee77c 100644 --- a/ios/chrome/browser/ui/overlays/infobar_banner/passwords/password_infobar_banner_overlay_mediator_unittest.mm +++ b/ios/chrome/browser/ui/overlays/infobar_banner/passwords/password_infobar_banner_overlay_mediator_unittest.mm
@@ -98,7 +98,7 @@ InfoBarIOS infobar(InfobarType::kInfobarTypePasswordSave, MockIOSChromeSavePasswordInfoBarDelegate::Create( kUsername, kPassword, GURL::EmptyGURL(), - /*account_store_password=*/absl::nullopt)); + /*account_to_store_password=*/absl::nullopt)); // Package the infobar into an OverlayRequest, then create a mediator that // uses this request in order to set up a fake consumer. std::unique_ptr<OverlayRequest> request = OverlayRequest::CreateWithConfig<
diff --git a/ios/chrome/browser/ui/settings/password/password_checkup/BUILD.gn b/ios/chrome/browser/ui/settings/password/password_checkup/BUILD.gn index cc86d72..a757337 100644 --- a/ios/chrome/browser/ui/settings/password/password_checkup/BUILD.gn +++ b/ios/chrome/browser/ui/settings/password/password_checkup/BUILD.gn
@@ -15,6 +15,8 @@ deps = [ ":password_checkup_ui", "//components/password_manager/core/browser", + "//ios/chrome/browser/main:public", + "//ios/chrome/browser/passwords", "//ios/chrome/browser/ui/coordinators:chrome_coordinators", "//ios/chrome/browser/ui/table_view:utils", ]
diff --git a/ios/chrome/browser/ui/settings/password/password_checkup/password_checkup_coordinator.mm b/ios/chrome/browser/ui/settings/password/password_checkup/password_checkup_coordinator.mm index 8751e960..933bf226 100644 --- a/ios/chrome/browser/ui/settings/password/password_checkup/password_checkup_coordinator.mm +++ b/ios/chrome/browser/ui/settings/password/password_checkup/password_checkup_coordinator.mm
@@ -4,6 +4,9 @@ #import "ios/chrome/browser/ui/settings/password/password_checkup/password_checkup_coordinator.h" +#import "ios/chrome/browser/main/browser.h" +#import "ios/chrome/browser/passwords/ios_chrome_password_check_manager.h" +#import "ios/chrome/browser/passwords/ios_chrome_password_check_manager_factory.h" #import "ios/chrome/browser/ui/settings/password/password_checkup/password_checkup_commands.h" #import "ios/chrome/browser/ui/settings/password/password_checkup/password_checkup_mediator.h" #import "ios/chrome/browser/ui/settings/password/password_checkup/password_checkup_view_controller.h" @@ -43,13 +46,17 @@ self.viewController = [[PasswordCheckupViewController alloc] initWithStyle:ChromeTableViewStyle()]; self.viewController.handler = self; - self.mediator = [[PasswordCheckupMediator alloc] init]; + self.mediator = [[PasswordCheckupMediator alloc] + initWithPasswordCheckManager:IOSChromePasswordCheckManagerFactory:: + GetForBrowserState( + self.browser->GetBrowserState())]; self.mediator.consumer = self.viewController; [self.baseNavigationController pushViewController:self.viewController animated:YES]; } - (void)stop { + [self.mediator disconnect]; self.mediator = nil; self.viewController.handler = nil; self.viewController = nil;
diff --git a/ios/chrome/browser/ui/settings/password/password_checkup/password_checkup_mediator.h b/ios/chrome/browser/ui/settings/password/password_checkup/password_checkup_mediator.h index 0ceb72d0..026bcce 100644 --- a/ios/chrome/browser/ui/settings/password/password_checkup/password_checkup_mediator.h +++ b/ios/chrome/browser/ui/settings/password/password_checkup/password_checkup_mediator.h
@@ -7,15 +7,26 @@ #import <Foundation/Foundation.h> +#import "ios/chrome/browser/passwords/ios_chrome_password_check_manager.h" + @protocol PasswordCheckupConsumer; // This mediator fetches and organises the insecure credentials for its // consumer. @interface PasswordCheckupMediator : NSObject +- (instancetype)initWithPasswordCheckManager: + (scoped_refptr<IOSChromePasswordCheckManager>)passwordCheckManager + NS_DESIGNATED_INITIALIZER; + +- (instancetype)init NS_UNAVAILABLE; + // Consumer of this mediator. @property(nonatomic, weak) id<PasswordCheckupConsumer> consumer; +// Disconnect the observers. +- (void)disconnect; + @end #endif // IOS_CHROME_BROWSER_UI_SETTINGS_PASSWORD_PASSWORD_CHECKUP_PASSWORD_CHECKUP_MEDIATOR_H_
diff --git a/ios/chrome/browser/ui/settings/password/password_checkup/password_checkup_mediator.mm b/ios/chrome/browser/ui/settings/password/password_checkup/password_checkup_mediator.mm index eb16435..d860ad7 100644 --- a/ios/chrome/browser/ui/settings/password/password_checkup/password_checkup_mediator.mm +++ b/ios/chrome/browser/ui/settings/password/password_checkup/password_checkup_mediator.mm
@@ -4,12 +4,38 @@ #import "ios/chrome/browser/ui/settings/password/password_checkup/password_checkup_mediator.h" +#import "ios/chrome/browser/passwords/ios_chrome_password_check_manager.h" +#import "ios/chrome/browser/passwords/password_check_observer_bridge.h" +#import "ios/chrome/browser/ui/settings/password/password_checkup/password_checkup_consumer.h" + #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." #endif +@interface PasswordCheckupMediator () <PasswordCheckObserver> { + // The service responsible for password check feature. + scoped_refptr<IOSChromePasswordCheckManager> _passwordCheckManager; + + // A helper object for passing data about changes in password check status + // and changes to compromised credentials list. + std::unique_ptr<PasswordCheckObserverBridge> _passwordCheckObserver; +} + +@end + @implementation PasswordCheckupMediator +- (instancetype)initWithPasswordCheckManager: + (scoped_refptr<IOSChromePasswordCheckManager>)passwordCheckManager { + self = [super init]; + if (self) { + _passwordCheckManager = passwordCheckManager; + _passwordCheckObserver = std::make_unique<PasswordCheckObserverBridge>( + self, _passwordCheckManager.get()); + } + return self; +} + - (void)setConsumer:(id<PasswordCheckupConsumer>)consumer { if (_consumer == consumer) { return; @@ -17,4 +43,19 @@ _consumer = consumer; } +- (void)disconnect { + _passwordCheckObserver.reset(); + _passwordCheckManager.reset(); +} + +#pragma mark - PasswordCheckObserver + +- (void)passwordCheckStateDidChange:(PasswordCheckState)state { + // TODO(crbug.com/1406540): Add method's body. +} + +- (void)insecureCredentialsDidChange { + // TODO(crbug.com/1406540): Add method's body. +} + @end
diff --git a/ios/chrome/browser/ui/settings/password/password_details/BUILD.gn b/ios/chrome/browser/ui/settings/password/password_details/BUILD.gn index 931aca06..49a25bc3 100644 --- a/ios/chrome/browser/ui/settings/password/password_details/BUILD.gn +++ b/ios/chrome/browser/ui/settings/password/password_details/BUILD.gn
@@ -35,6 +35,7 @@ "//ios/chrome/browser/ui/alert_coordinator", "//ios/chrome/browser/ui/commands", "//ios/chrome/browser/ui/coordinators:chrome_coordinators", + "//ios/chrome/browser/ui/settings/password:common", "//ios/chrome/browser/ui/settings/utils", "//ios/chrome/browser/ui/table_view", "//ios/chrome/browser/ui/util",
diff --git a/ios/chrome/browser/ui/settings/password/password_details/password_details_coordinator.h b/ios/chrome/browser/ui/settings/password/password_details/password_details_coordinator.h index 42bd0d76..6c0b403 100644 --- a/ios/chrome/browser/ui/settings/password/password_details/password_details_coordinator.h +++ b/ios/chrome/browser/ui/settings/password/password_details/password_details_coordinator.h
@@ -48,11 +48,6 @@ // Displays the password data in edit mode without requiring any authentication. - (void)showPasswordDetailsInEditModeWithoutAuthentication; -// Remove the credential from the cache and reload password details view -// controller after a change was made. -- (void)removeCredentialFromCacheAndRefreshTableView: - (const password_manager::CredentialUIEntry&)credential; - // Delegate. @property(nonatomic, weak) id<PasswordDetailsCoordinatorDelegate> delegate;
diff --git a/ios/chrome/browser/ui/settings/password/password_details/password_details_coordinator.mm b/ios/chrome/browser/ui/settings/password/password_details/password_details_coordinator.mm index b1e6798..f2922520 100644 --- a/ios/chrome/browser/ui/settings/password/password_details/password_details_coordinator.mm +++ b/ios/chrome/browser/ui/settings/password/password_details/password_details_coordinator.mm
@@ -326,15 +326,6 @@ [self.viewController showEditViewWithoutAuthentication]; } -- (void)removeCredentialFromCacheAndRefreshTableView: - (const password_manager::CredentialUIEntry&)credential { - // Remove credential from the credentials cache of the password details - // manager. - [self.mediator removeCredential:credential]; - - [self.mediator didFinishEditingPasswordDetails]; -} - - (void)onPasswordCopiedByUser { if (IsCredentialProviderExtensionPromoEnabledOnPasswordCopied()) { DCHECK(_credentialProviderPromoHandler); @@ -344,6 +335,12 @@ } } +- (void)onAllPasswordsDeleted { + DCHECK_EQ(self.baseNavigationController.topViewController, + self.viewController); + [self.baseNavigationController popViewControllerAnimated:YES]; +} + #pragma mark - Private // Notifies delegate about password deletion and records metric if needed. @@ -369,9 +366,7 @@ return; } - [self.delegate passwordDetailsCoordinator:self - deleteCredential:*it - shouldDismissView:(credentials.size() - 1 == 0)]; + [self.mediator removeCredential:*it]; if (compromised) { base::UmaHistogramEnumeration( "PasswordManager.BulkCheck.UserAction",
diff --git a/ios/chrome/browser/ui/settings/password/password_details/password_details_coordinator_delegate.h b/ios/chrome/browser/ui/settings/password/password_details/password_details_coordinator_delegate.h index ccc6011..1b0aacde 100644 --- a/ios/chrome/browser/ui/settings/password/password_details/password_details_coordinator_delegate.h +++ b/ios/chrome/browser/ui/settings/password/password_details/password_details_coordinator_delegate.h
@@ -5,10 +5,6 @@ #ifndef IOS_CHROME_BROWSER_UI_SETTINGS_PASSWORD_PASSWORD_DETAILS_PASSWORD_DETAILS_COORDINATOR_DELEGATE_H_ #define IOS_CHROME_BROWSER_UI_SETTINGS_PASSWORD_PASSWORD_DETAILS_PASSWORD_DETAILS_COORDINATOR_DELEGATE_H_ -namespace password_manager { -struct CredentialUIEntry; -} // namespace password_manager - @class PasswordDetailsCoordinator; // Delegate for PasswordIssuesCoordinator. @@ -18,15 +14,6 @@ - (void)passwordDetailsCoordinatorDidRemove: (PasswordDetailsCoordinator*)coordinator; -// Called when user deleted password. This action should be handled outside to -// update the list of passwords immediately. Callers should pass YES for -// `shouldDismiss` if this is the last password on the page, to ensure the view -// controller gets dismissed. -- (void)passwordDetailsCoordinator:(PasswordDetailsCoordinator*)coordinator - deleteCredential: - (const password_manager::CredentialUIEntry&)credential - shouldDismissView:(BOOL)shouldDismiss; - @end #endif // IOS_CHROME_BROWSER_UI_SETTINGS_PASSWORD_PASSWORD_DETAILS_PASSWORD_DETAILS_COORDINATOR_DELEGATE_H_
diff --git a/ios/chrome/browser/ui/settings/password/password_details/password_details_handler.h b/ios/chrome/browser/ui/settings/password/password_details/password_details_handler.h index 0ab08eb..f9c1972 100644 --- a/ios/chrome/browser/ui/settings/password/password_details/password_details_handler.h +++ b/ios/chrome/browser/ui/settings/password/password_details/password_details_handler.h
@@ -33,6 +33,9 @@ // Called by the view controller when the user successfully copied a password. - (void)onPasswordCopiedByUser; +// Called when all passwords were deleted, in order to close the view. +- (void)onAllPasswordsDeleted; + @end #endif // IOS_CHROME_BROWSER_UI_SETTINGS_PASSWORD_PASSWORD_DETAILS_PASSWORD_DETAILS_HANDLER_H_
diff --git a/ios/chrome/browser/ui/settings/password/password_details/password_details_mediator.mm b/ios/chrome/browser/ui/settings/password/password_details/password_details_mediator.mm index b3052ae..bb75de9 100644 --- a/ios/chrome/browser/ui/settings/password/password_details/password_details_mediator.mm +++ b/ios/chrome/browser/ui/settings/password/password_details/password_details_mediator.mm
@@ -9,6 +9,7 @@ #import <vector> #import "base/containers/contains.h" +#import "base/containers/cxx20_erase.h" #import "base/memory/raw_ptr.h" #import "base/strings/sys_string_conversions.h" #import "components/password_manager/core/browser/move_password_to_account_store_helper.h" @@ -127,10 +128,16 @@ - (void)removeCredential: (const password_manager::CredentialUIEntry&)credential { - auto it = base::ranges::find(_credentials, credential); - if (it != _credentials.end()) { - _credentials.erase(it); - } + // TODO(crbug.com/1359392). Once kPasswordsGrouping launches, the mediator + // should update the passwords model and receive the updates via + // SavedPasswordsPresenterObserver, instead of replicating the updates to its + // own copy and calling [self providePasswordsToConsumer:]. Today when the + // flag is disabled and the password is edited, it's impossible to identify + // the new object to show (sign-on realm can't be used as an id, there might + // be multiple credentials; nor username/password since the values changed). + base::Erase(_credentials, credential); + _manager->GetSavedPasswordsPresenter()->RemoveCredential(credential); + [self providePasswordsToConsumer]; } - (void)moveCredentialToAccountStore:
diff --git a/ios/chrome/browser/ui/settings/password/password_details/password_details_table_view_controller.mm b/ios/chrome/browser/ui/settings/password/password_details/password_details_table_view_controller.mm index 933563b..770d87b 100644 --- a/ios/chrome/browser/ui/settings/password/password_details/password_details_table_view_controller.mm +++ b/ios/chrome/browser/ui/settings/password/password_details/password_details_table_view_controller.mm
@@ -570,15 +570,18 @@ - (void)setPasswords:(NSArray<PasswordDetails*>*)passwords andTitle:(NSString*)title { - if (IsPasswordGroupingEnabled()) { - DCHECK(passwords.count > 0); - } else { - DCHECK(passwords.count == 1); - } - + BOOL hadPasswords = [_passwords count]; _passwords = passwords; _pageTitle = title; + if (![passwords count]) { + // onAllPasswordsDeleted() mustn't be called twice. + if (hadPasswords) { + [self.handler onAllPasswordsDeleted]; + } + return; + } + [self updateNavigationTitle]; [self reloadData];
diff --git a/ios/chrome/browser/ui/settings/password/password_details/password_details_table_view_controller_unittest.mm b/ios/chrome/browser/ui/settings/password/password_details/password_details_table_view_controller_unittest.mm index 5bf8469..b6d3d747 100644 --- a/ios/chrome/browser/ui/settings/password/password_details/password_details_table_view_controller_unittest.mm +++ b/ios/chrome/browser/ui/settings/password/password_details/password_details_table_view_controller_unittest.mm
@@ -93,6 +93,9 @@ self.passwordCopiedByUserCalled = YES; } +- (void)onAllPasswordsDeleted { +} + @end // Test class that conforms to PasswordDetailsViewControllerDelegate in order
diff --git a/ios/chrome/browser/ui/settings/password/password_issues_coordinator.h b/ios/chrome/browser/ui/settings/password/password_issues_coordinator.h index f9dce71..fef9f22 100644 --- a/ios/chrome/browser/ui/settings/password/password_issues_coordinator.h +++ b/ios/chrome/browser/ui/settings/password/password_issues_coordinator.h
@@ -7,10 +7,6 @@ #import "ios/chrome/browser/ui/coordinators/chrome_coordinator.h" -namespace password_manager { -struct CredentialUIEntry; -} // namespace password_manager - @protocol ApplicationCommands; class Browser; class IOSChromePasswordCheckManager; @@ -24,11 +20,6 @@ - (void)passwordIssuesCoordinatorDidRemove: (PasswordIssuesCoordinator*)coordinator; -// Called when the user deleted password. Returns whether presenter will -// handle it or not. -- (BOOL)willHandlePasswordDeletion: - (const password_manager::CredentialUIEntry&)credential; - @end // This coordinator presents a list of compromised credentials for the user.
diff --git a/ios/chrome/browser/ui/settings/password/password_issues_coordinator.mm b/ios/chrome/browser/ui/settings/password/password_issues_coordinator.mm index 9c6251a6..4e7aea0 100644 --- a/ios/chrome/browser/ui/settings/password/password_issues_coordinator.mm +++ b/ios/chrome/browser/ui/settings/password/password_issues_coordinator.mm
@@ -138,14 +138,4 @@ self.passwordDetails = nil; } -- (void)passwordDetailsCoordinator:(PasswordDetailsCoordinator*)coordinator - deleteCredential: - (const password_manager::CredentialUIEntry&)credential - shouldDismissView:(BOOL)shouldDismiss { - if (![self.delegate willHandlePasswordDeletion:credential]) { - [self.mediator deleteCredential:credential]; - } - [self.baseNavigationController popViewControllerAnimated:YES]; -} - @end
diff --git a/ios/chrome/browser/ui/settings/password/password_issues_mediator.h b/ios/chrome/browser/ui/settings/password/password_issues_mediator.h index bc10781..dca1c31d1 100644 --- a/ios/chrome/browser/ui/settings/password/password_issues_mediator.h +++ b/ios/chrome/browser/ui/settings/password/password_issues_mediator.h
@@ -36,9 +36,6 @@ @property(nonatomic, weak) id<PasswordIssuesConsumer> consumer; -// Deletes password from the password store. -- (void)deleteCredential:(const password_manager::CredentialUIEntry&)credential; - @end #endif // IOS_CHROME_BROWSER_UI_SETTINGS_PASSWORD_PASSWORD_ISSUES_MEDIATOR_H_
diff --git a/ios/chrome/browser/ui/settings/password/password_issues_mediator.mm b/ios/chrome/browser/ui/settings/password/password_issues_mediator.mm index dc3d207..1bf26be7 100644 --- a/ios/chrome/browser/ui/settings/password/password_issues_mediator.mm +++ b/ios/chrome/browser/ui/settings/password/password_issues_mediator.mm
@@ -9,23 +9,30 @@ #import "base/memory/raw_ptr.h" #import "components/password_manager/core/browser/ui/insecure_credentials_manager.h" +#import "components/password_manager/core/browser/ui/saved_passwords_presenter.h" #import "components/sync/driver/sync_service.h" #import "ios/chrome/browser/favicon/favicon_loader.h" #import "ios/chrome/browser/net/crurl.h" +#import "ios/chrome/browser/passwords/ios_chrome_password_check_manager.h" #import "ios/chrome/browser/passwords/password_check_observer_bridge.h" #import "ios/chrome/browser/passwords/password_manager_util_ios.h" #import "ios/chrome/browser/ui/settings/password/password_issues_consumer.h" +#import "ios/chrome/browser/ui/settings/password/saved_passwords_presenter_observer.h" #import "ios/chrome/common/ui/favicon/favicon_constants.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." #endif -@interface PasswordIssuesMediator () <PasswordCheckObserver> { +@interface PasswordIssuesMediator () <PasswordCheckObserver, + SavedPasswordsPresenterObserver> { raw_ptr<IOSChromePasswordCheckManager> _manager; std::unique_ptr<PasswordCheckObserverBridge> _passwordCheckObserver; + std::unique_ptr<SavedPasswordsPresenterObserverBridge> + _passwordsPresenterObserver; + std::vector<password_manager::CredentialUIEntry> _insecureCredentials; // Object storing the time of the previous successful re-authentication. @@ -57,12 +64,16 @@ _manager = manager; _passwordCheckObserver = std::make_unique<PasswordCheckObserverBridge>(self, manager); + _passwordsPresenterObserver = + std::make_unique<SavedPasswordsPresenterObserverBridge>( + self, _manager->GetSavedPasswordsPresenter()); } return self; } - (void)disconnect { _passwordCheckObserver.reset(); + _passwordsPresenterObserver.reset(); _manager = nullptr; _faviconLoader = nullptr; @@ -76,13 +87,6 @@ [self providePasswordsToConsumer]; } -- (void)deleteCredential: - (const password_manager::CredentialUIEntry&)credential { - _manager->GetSavedPasswordsPresenter()->RemoveCredential(credential); - // TODO:(crbug.com/1075494) - Update list of compromised passwords without - // awaiting insecureCredentialsDidChange. -} - #pragma mark - PasswordCheckObserver - (void)passwordCheckStateDidChange:(PasswordCheckState)state { @@ -93,6 +97,12 @@ [self providePasswordsToConsumer]; } +#pragma mark - SavedPasswordsPresenterObserver + +- (void)savedPasswordsDidChange { + [self providePasswordsToConsumer]; +} + #pragma mark - Private Methods - (void)providePasswordsToConsumer {
diff --git a/ios/chrome/browser/ui/settings/password/password_issues_mediator_unittest.mm b/ios/chrome/browser/ui/settings/password/password_issues_mediator_unittest.mm index b132831..344bbe8f 100644 --- a/ios/chrome/browser/ui/settings/password/password_issues_mediator_unittest.mm +++ b/ios/chrome/browser/ui/settings/password/password_issues_mediator_unittest.mm
@@ -159,19 +159,6 @@ EXPECT_NSEQ(@"example.com", password.website); } -// Tests that mediator deletes password from the store. -TEST_F(PasswordIssuesMediatorTest, TestPasswordDeletion) { - MakeTestPasswordIssue(); - RunUntilIdle(); - - EXPECT_EQ(1u, [[consumer() passwords] count]); - - auto password = store()->stored_passwords().at(kExampleCom).at(0); - [mediator() deleteCredential:password_manager::CredentialUIEntry(password)]; - RunUntilIdle(); - EXPECT_EQ(0u, [[consumer() passwords] count]); -} - // Tests that passwords are sorted properly. TEST_F(PasswordIssuesMediatorTest, TestPasswordSorting) { EXPECT_EQ(0u, [[consumer() passwords] count]);
diff --git a/ios/chrome/browser/ui/settings/password/password_manager_egtest.mm b/ios/chrome/browser/ui/settings/password/password_manager_egtest.mm index 6b78d0a4a..2c57a2f 100644 --- a/ios/chrome/browser/ui/settings/password/password_manager_egtest.mm +++ b/ios/chrome/browser/ui/settings/password/password_manager_egtest.mm
@@ -2855,11 +2855,10 @@ OpenPasswordManager(); OpenSettingsSubmenu(); - [EarlGrey - selectElementWithMatcher: - grey_allOf(grey_accessibilityID( - kPasswordSettingsAccountStorageSwitchTableViewId), - grey_notVisible(), nil)]; + [[EarlGrey selectElementWithMatcher: + grey_accessibilityID( + kPasswordSettingsAccountStorageSwitchTableViewId)] + assertWithMatcher:grey_nil()]; } - (void)testAccountStorageSwitchShownIfSignedInAndFlagEnabled { @@ -2875,32 +2874,32 @@ chrome_test_util::TableViewSwitchCell( kPasswordSettingsAccountStorageSwitchTableViewId, /*is_toggled_on=*/YES)]; + [accountStorageSwitch assertWithMatcher:grey_sufficientlyVisible()]; // The toggle text must contain the signed-in account. - [EarlGrey - selectElementWithMatcher: - grey_allOf( - grey_descendant(grey_accessibilityID( - kPasswordSettingsAccountStorageSwitchTableViewId)), - ElementWithAccessibilityLabelSubstring(fakeIdentity.userEmail), - nil)]; + [[EarlGrey + selectElementWithMatcher:grey_accessibilityLabel(l10n_util::GetNSStringF( + IDS_IOS_ACCOUNT_STORAGE_OPT_IN_SUBLABEL, + base::SysNSStringToUTF16( + fakeIdentity.userEmail)))] + assertWithMatcher:grey_sufficientlyVisible()]; [accountStorageSwitch performAction:TurnTableViewSwitchOn(NO)]; - [EarlGrey selectElementWithMatcher: - chrome_test_util::TableViewSwitchCell( - kPasswordSettingsAccountStorageSwitchTableViewId, - /*is_toggled_on=*/NO)]; + [[EarlGrey selectElementWithMatcher: + chrome_test_util::TableViewSwitchCell( + kPasswordSettingsAccountStorageSwitchTableViewId, + /*is_toggled_on=*/NO)] + assertWithMatcher:grey_sufficientlyVisible()]; } - (void)testAccountStorageSwitchHiddenIfSignedOut { OpenPasswordManager(); OpenSettingsSubmenu(); - [EarlGrey - selectElementWithMatcher: - grey_allOf(grey_accessibilityID( - kPasswordSettingsAccountStorageSwitchTableViewId), - grey_notVisible(), nil)]; + [[EarlGrey selectElementWithMatcher: + grey_accessibilityID( + kPasswordSettingsAccountStorageSwitchTableViewId)] + assertWithMatcher:grey_nil()]; } - (void)testAccountStorageSwitchHiddenIfSyncing { @@ -2912,11 +2911,10 @@ OpenPasswordManager(); OpenSettingsSubmenu(); - [EarlGrey - selectElementWithMatcher: - grey_allOf(grey_accessibilityID( - kPasswordSettingsAccountStorageSwitchTableViewId), - grey_notVisible(), nil)]; + [[EarlGrey selectElementWithMatcher: + grey_accessibilityID( + kPasswordSettingsAccountStorageSwitchTableViewId)] + assertWithMatcher:grey_nil()]; } @end
diff --git a/ios/chrome/browser/ui/settings/password/passwords_coordinator.mm b/ios/chrome/browser/ui/settings/password/passwords_coordinator.mm index 3db3b054..52e07eb 100644 --- a/ios/chrome/browser/ui/settings/password/passwords_coordinator.mm +++ b/ios/chrome/browser/ui/settings/password/passwords_coordinator.mm
@@ -315,12 +315,6 @@ self.passwordIssuesCoordinator = nil; } -- (BOOL)willHandlePasswordDeletion: - (const password_manager::CredentialUIEntry&)credential { - [self.mediator deleteCredential:credential]; - return YES; -} - #pragma mark - PasswordCheckupCoordinatorDelegate - (void)passwordCheckupCoordinatorDidRemove: @@ -341,21 +335,6 @@ self.passwordDetailsCoordinator = nil; } -- (void)passwordDetailsCoordinator:(PasswordDetailsCoordinator*)coordinator - deleteCredential: - (const password_manager::CredentialUIEntry&)credential - shouldDismissView:(BOOL)shouldDismiss { - DCHECK_EQ(self.passwordDetailsCoordinator, coordinator); - [self.mediator deleteCredential:credential]; - - if (shouldDismiss) { - [self.baseNavigationController popViewControllerAnimated:YES]; - } else { - [self.passwordDetailsCoordinator - removeCredentialFromCacheAndRefreshTableView:credential]; - } -} - #pragma mark AddPasswordDetailsCoordinatorDelegate - (void)passwordDetailsTableViewControllerDidFinish:
diff --git a/ios/chrome/browser/ui/settings/password/passwords_mediator.h b/ios/chrome/browser/ui/settings/password/passwords_mediator.h index 9258a23e..6d2be2a0 100644 --- a/ios/chrome/browser/ui/settings/password/passwords_mediator.h +++ b/ios/chrome/browser/ui/settings/password/passwords_mediator.h
@@ -41,9 +41,6 @@ - (instancetype)init NS_UNAVAILABLE; -// Deletes 'form' and its duplicates. -- (void)deleteCredential:(const password_manager::CredentialUIEntry&)credential; - // Disconnect the observers. - (void)disconnect;
diff --git a/ios/chrome/browser/ui/settings/password/passwords_mediator.mm b/ios/chrome/browser/ui/settings/password/passwords_mediator.mm index 45186aa4..43e2b6ed 100644 --- a/ios/chrome/browser/ui/settings/password/passwords_mediator.mm +++ b/ios/chrome/browser/ui/settings/password/passwords_mediator.mm
@@ -143,11 +143,6 @@ [self updateConsumerPasswordCheckState:_currentState]; } -- (void)deleteCredential: - (const password_manager::CredentialUIEntry&)credential { - _savedPasswordsPresenter->RemoveCredential(credential); -} - - (void)disconnect { _identityManagerObserver.reset(); _syncObserver.reset();
diff --git a/ios/chrome/browser/ui/settings/password/passwords_mediator_unittest.mm b/ios/chrome/browser/ui/settings/password/passwords_mediator_unittest.mm index d83374d9..2bc1d85 100644 --- a/ios/chrome/browser/ui/settings/password/passwords_mediator_unittest.mm +++ b/ios/chrome/browser/ui/settings/password/passwords_mediator_unittest.mm
@@ -209,23 +209,6 @@ EXPECT_THAT([consumer() passwords], testing::IsEmpty()); } -// Duplicates of a form should be removed as well. -TEST_F(PasswordsMediatorTest, DeleteFormWithDuplicates) { - PasswordForm form = CreatePasswordForm(); - PasswordForm duplicate = form; - duplicate.username_element = u"element"; - - store()->AddLogin(form); - store()->AddLogin(duplicate); - RunUntilIdle(); - ASSERT_THAT([consumer() passwords], - testing::ElementsAre(password_manager::CredentialUIEntry(form))); - - [mediator() deleteCredential:password_manager::CredentialUIEntry(form)]; - RunUntilIdle(); - EXPECT_THAT([consumer() passwords], testing::IsEmpty()); -} - // Mediator should update consumer password autofill state. TEST_F(PasswordsMediatorTest, TestPasswordAutoFillDidChangeToStatusMethod) { ASSERT_EQ([consumer() detailedText], nil);
diff --git a/ios/chrome/browser/ui/settings/safety_check/safety_check_coordinator.mm b/ios/chrome/browser/ui/settings/safety_check/safety_check_coordinator.mm index bdb4728..2fd1b9a 100644 --- a/ios/chrome/browser/ui/settings/safety_check/safety_check_coordinator.mm +++ b/ios/chrome/browser/ui/settings/safety_check/safety_check_coordinator.mm
@@ -252,11 +252,6 @@ self.passwordIssuesCoordinator = nil; } -- (BOOL)willHandlePasswordDeletion: - (const password_manager::CredentialUIEntry&)credential { - return NO; -} - #pragma mark - PrivacySafeBrowsingCoordinatorDelegate - (void)privacySafeBrowsingCoordinatorDidRemove:
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/BUILD.gn b/ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/BUILD.gn index 2b67f27..1cd9894 100644 --- a/ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/BUILD.gn +++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/BUILD.gn
@@ -13,14 +13,18 @@ deps = [ ":inactive_tabs_ui", "//base", + "//components/favicon/ios", "//ios/chrome/browser/main:public", + "//ios/chrome/browser/snapshots", "//ios/chrome/browser/tabs/inactive_tabs:features", "//ios/chrome/browser/ui/coordinators:chrome_coordinators", "//ios/chrome/browser/ui/tab_switcher", "//ios/chrome/browser/ui/tab_switcher:tab_utils", "//ios/chrome/browser/ui/tab_switcher/tab_grid/grid:grid_ui", + "//ios/chrome/browser/url", "//ios/chrome/browser/web_state_list", "//ios/web/public", + "//ui/gfx", ] }
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/inactive_tabs_coordinator.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/inactive_tabs_coordinator.mm index eeeaaa3..33d81db 100644 --- a/ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/inactive_tabs_coordinator.mm +++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/inactive_tabs_coordinator.mm
@@ -59,6 +59,7 @@ self.mediator = [[InactiveTabsMediator alloc] initWithConsumer:self.viewController.gridViewController]; self.mediator.inactiveBrowser = self.browser; + self.viewController.gridViewController.imageDataSource = self.mediator; // Add the view controller to the hierarchy. UIView* baseView = self.baseViewController.view;
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/inactive_tabs_mediator.h b/ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/inactive_tabs_mediator.h index fe1c255..6b8d97e 100644 --- a/ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/inactive_tabs_mediator.h +++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/inactive_tabs_mediator.h
@@ -7,10 +7,12 @@ #import <Foundation/Foundation.h> +#import "ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_image_data_source.h" + class Browser; @protocol TabCollectionConsumer; -@interface InactiveTabsMediator : NSObject +@interface InactiveTabsMediator : NSObject <GridImageDataSource> // The inactive browser reference. @property(nonatomic, assign) Browser* inactiveBrowser;
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/inactive_tabs_mediator.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/inactive_tabs_mediator.mm index 0c36e49e..f4b470b 100644 --- a/ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/inactive_tabs_mediator.mm +++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/inactive_tabs_mediator.mm
@@ -6,10 +6,16 @@ #import "base/notreached.h" #import "base/scoped_multi_source_observation.h" +#import "components/favicon/ios/web_favicon_driver.h" #import "ios/chrome/browser/main/browser.h" +#import "ios/chrome/browser/snapshots/snapshot_browser_agent.h" +#import "ios/chrome/browser/snapshots/snapshot_cache.h" +#import "ios/chrome/browser/snapshots/snapshot_cache_observer.h" +#import "ios/chrome/browser/snapshots/snapshot_tab_helper.h" #import "ios/chrome/browser/tabs/inactive_tabs/features.h" #import "ios/chrome/browser/ui/tab_switcher/tab_collection_consumer.h" #import "ios/chrome/browser/ui/tab_switcher/tab_utils.h" +#import "ios/chrome/browser/url/url_util.h" #import "ios/chrome/browser/web_state_list/web_state_list.h" #import "ios/chrome/browser/web_state_list/web_state_list_observer_bridge.h" #import "ios/web/public/web_state.h" @@ -25,6 +31,7 @@ base::ScopedMultiSourceObservation<web::WebState, web::WebStateObserver>; @interface InactiveTabsMediator () <CRWWebStateObserver, + SnapshotCacheObserver, WebStateListObserving> { // Observers for WebStateList. std::unique_ptr<WebStateListObserverBridge> _webStateListObserverBridge; @@ -38,6 +45,11 @@ @property(nonatomic, weak, readonly) id<TabCollectionConsumer> consumer; // The list of inactive tabs. @property(nonatomic, assign, readonly) WebStateList* webStateList; +// The snapshot cache of `webStateList`. +@property(nonatomic, weak, readonly) SnapshotCache* snapshotCache; +// The short-term cache for grid thumbnails. +@property(nonatomic, strong, readonly) + NSMutableDictionary<NSString*, UIImage*>* appearanceCache; @end @@ -56,19 +68,26 @@ std::make_unique<web::WebStateObserverBridge>(self); _scopedWebStateObservation = std::make_unique<ScopedWebStateObservation>( _webStateObserverBridge.get()); + _appearanceCache = [[NSMutableDictionary alloc] init]; } return self; } +- (void)dealloc { + [_snapshotCache removeObserver:self]; +} + #pragma mark - Public properties - (void)setInactiveBrowser:(Browser*)inactiveBrowser { + [_snapshotCache removeObserver:self]; _scopedWebStateListObservation->RemoveAllObservations(); _scopedWebStateObservation->RemoveAllObservations(); _inactiveBrowser = inactiveBrowser; _webStateList = inactiveBrowser->GetWebStateList(); + [_snapshotCache addObserver:self]; if (_webStateList) { _scopedWebStateListObservation->AddObservation(_webStateList); [self addWebStateObservations]; @@ -95,6 +114,86 @@ withItem:GetTabSwitcherItem(webState)]; } +#pragma mark - GridImageDataSource + +- (void)snapshotForIdentifier:(NSString*)identifier + completion:(void (^)(UIImage*))completion { + if (_appearanceCache[identifier]) { + completion(_appearanceCache[identifier]); + return; + } + web::WebState* webState = + GetWebState(_webStateList, identifier, /*pinned=*/NO); + if (webState) { + SnapshotTabHelper::FromWebState(webState)->RetrieveColorSnapshot( + ^(UIImage* image) { + completion(image); + }); + } +} + +- (void)faviconForIdentifier:(NSString*)identifier + completion:(void (^)(UIImage*))completion { + web::WebState* webState = + GetWebState(_webStateList, identifier, /*pinned=*/NO); + if (!webState) { + return; + } + // NTP tabs get no favicon. + if (IsURLNtp(webState->GetVisibleURL())) { + return; + } + completion([UIImage imageNamed:@"default_world_favicon_regular"]); + + favicon::FaviconDriver* faviconDriver = + favicon::WebFaviconDriver::FromWebState(webState); + if (faviconDriver) { + gfx::Image favicon = faviconDriver->GetFavicon(); + if (!favicon.IsEmpty()) { + completion(favicon.ToUIImage()); + } + } +} + +- (void)preloadSnapshotsForVisibleGridItems: + (NSSet<NSString*>*)visibleGridItems { + for (int i = 0; i <= self.webStateList->count() - 1; i++) { + web::WebState* web_state = _webStateList->GetWebStateAt(i); + NSString* identifier = web_state->GetStableIdentifier(); + + BOOL isWebStateHidden = ![visibleGridItems containsObject:identifier]; + if (isWebStateHidden) { + continue; + } + + __weak __typeof(self) weakSelf = self; + auto cacheImage = ^(UIImage* image) { + weakSelf.appearanceCache[identifier] = image; + }; + + [self snapshotForIdentifier:identifier completion:cacheImage]; + } +} + +- (void)clearPreloadedSnapshots { + [_appearanceCache removeAllObjects]; +} + +#pragma mark - SnapshotCacheObserver + +- (void)snapshotCache:(SnapshotCache*)snapshotCache + didUpdateSnapshotForIdentifier:(NSString*)identifier { + [_appearanceCache removeObjectForKey:identifier]; + web::WebState* webState = + GetWebState(_webStateList, identifier, /*pinned=*/NO); + if (webState) { + // It is possible to observe an updated snapshot for a WebState before + // observing that the WebState has been added to the WebStateList. It is the + // consumer's responsibility to ignore any updates before inserts. + [_consumer replaceItemID:identifier withItem:GetTabSwitcherItem(webState)]; + } +} + #pragma mark - WebStateListObserving - (void)webStateList:(WebStateList*)webStateList
diff --git a/ios/web_view/BUILD.gn b/ios/web_view/BUILD.gn index a1bbbcf..7be5eeee 100644 --- a/ios/web_view/BUILD.gn +++ b/ios/web_view/BUILD.gn
@@ -333,6 +333,7 @@ "//components/services/unzip:in_process", "//components/signin/core/browser", "//components/signin/ios/browser", + "//components/signin/public/base", "//components/signin/public/identity_manager", "//components/signin/public/identity_manager/ios", "//components/signin/public/webdata",
diff --git a/ios/web_view/internal/sync/cwv_trusted_vault_utils.mm b/ios/web_view/internal/sync/cwv_trusted_vault_utils.mm index 34ac7e2..cbfd6ac 100644 --- a/ios/web_view/internal/sync/cwv_trusted_vault_utils.mm +++ b/ios/web_view/internal/sync/cwv_trusted_vault_utils.mm
@@ -30,8 +30,9 @@ return syncer::TrustedVaultDeviceRegistrationStateForUMA:: kAttemptingRegistrationWithExistingKeyPair; case CWVTrustedVaultStateAttemptingRegistrationWithPersistentAuthError: + // TODO(crbug.com/1418027): remove CWV version of this bucket. return syncer::TrustedVaultDeviceRegistrationStateForUMA:: - kAttemptingRegistrationWithPersistentAuthError; + kDeprecatedAttemptingRegistrationWithPersistentAuthError; case CWVTrustedVaultStateAlreadyRegisteredV1: return syncer::TrustedVaultDeviceRegistrationStateForUMA:: kAlreadyRegisteredV1;
diff --git a/ios/web_view/internal/web_view_web_main_parts.mm b/ios/web_view/internal/web_view_web_main_parts.mm index 714e16ba..03284c6 100644 --- a/ios/web_view/internal/web_view_web_main_parts.mm +++ b/ios/web_view/internal/web_view_web_main_parts.mm
@@ -13,6 +13,7 @@ #include "components/autofill/core/common/autofill_payments_features.h" #include "components/component_updater/installer_policies/safety_tips_component_installer.h" #include "components/password_manager/core/common/password_manager_features.h" +#import "components/signin/public/base/signin_switches.h" #include "components/sync/base/features.h" #include "components/variations/variations_ids_provider.h" #include "ios/web/public/webui/web_ui_ios_controller_factory.h" @@ -76,6 +77,7 @@ ","); std::string disabled_features = base::JoinString( { + switches::kEnableFetchingAccountCapabilities.name, }, ","); feature_list->InitializeFromCommandLine(
diff --git a/media/base/android/java/src/org/chromium/media/VideoEncodeAcceleratorUtil.java b/media/base/android/java/src/org/chromium/media/VideoEncodeAcceleratorUtil.java index 4acee26..9dae41b 100644 --- a/media/base/android/java/src/org/chromium/media/VideoEncodeAcceleratorUtil.java +++ b/media/base/android/java/src/org/chromium/media/VideoEncodeAcceleratorUtil.java
@@ -351,9 +351,7 @@ supportedProfiles.add(VideoCodecProfile.H264PROFILE_MAIN); break; case VideoCodec.AV1: - if (isAtLeastQ) { - supportedProfiles.add(VideoCodecProfile.AV1PROFILE_PROFILE_MAIN); - } + supportedProfiles.add(VideoCodecProfile.AV1PROFILE_PROFILE_MAIN); break; } }
diff --git a/media/cast/logging/stats_event_subscriber.cc b/media/cast/logging/stats_event_subscriber.cc index 3a6dd99..490294d 100644 --- a/media/cast/logging/stats_event_subscriber.cc +++ b/media/cast/logging/stats_event_subscriber.cc
@@ -237,7 +237,9 @@ stats.Set(CastStatToString(it->first), it->second->GetHistogram()); } - ret.Set(event_media_type_ == AUDIO_EVENT ? "audio" : "video", + ret.Set(event_media_type_ == AUDIO_EVENT + ? StatsEventSubscriber::kAudioStatsDictKey + : StatsEventSubscriber::kVideoStatsDictKey, std::move(stats)); return ret;
diff --git a/media/cast/logging/stats_event_subscriber.h b/media/cast/logging/stats_event_subscriber.h index fd095b35..c5a7ff0 100644 --- a/media/cast/logging/stats_event_subscriber.h +++ b/media/cast/logging/stats_event_subscriber.h
@@ -55,7 +55,12 @@ // Resets stats in this object. void Reset(); + static constexpr char kAudioStatsDictKey[] = "audio"; + static constexpr char kVideoStatsDictKey[] = "video"; + private: + // TODO(b/268543775): Replace friend class declarations with public getters + // for tests. friend class StatsEventSubscriberTest; FRIEND_TEST_ALL_PREFIXES(StatsEventSubscriberTest, EmptyStats); FRIEND_TEST_ALL_PREFIXES(StatsEventSubscriberTest, CaptureEncode);
diff --git a/media/gpu/android/media_codec_video_decoder_unittest.cc b/media/gpu/android/media_codec_video_decoder_unittest.cc index c058ecc7..4d2d2dc 100644 --- a/media/gpu/android/media_codec_video_decoder_unittest.cc +++ b/media/gpu/android/media_codec_video_decoder_unittest.cc
@@ -31,6 +31,7 @@ #include "media/gpu/android/fake_codec_allocator.h" #include "media/gpu/android/mock_android_video_surface_chooser.h" #include "media/gpu/android/mock_device_info.h" +#include "media/gpu/android/video_accelerator_util.h" #include "media/gpu/android/video_frame_factory.h" #include "testing/gtest/include/gtest/gtest.h" @@ -57,6 +58,22 @@ return nullptr; } +// Tests require the presence of a software AV1 decoder, which isn't required +// by Android at this time. +bool HasAv1Decoder() { + if (!MediaCodecUtil::IsAv1DecoderAvailable()) { + return false; + } + + for (const auto& info : GetDecoderInfoCache()) { + if (info.profile >= AV1PROFILE_MIN && info.profile <= AV1PROFILE_MAX) { + return true; + } + } + + return false; +} + } // namespace class MockVideoFrameFactory : public VideoFrameFactory { @@ -294,9 +311,9 @@ scoped_refptr<DecoderBuffer> fake_decoder_buffer_; std::unique_ptr<MockDeviceInfo> device_info_; std::unique_ptr<FakeCodecAllocator> codec_allocator_; - raw_ptr<MockAndroidVideoSurfaceChooser> surface_chooser_; - raw_ptr<gpu::MockTextureOwner> texture_owner_; - raw_ptr<MockVideoFrameFactory> video_frame_factory_; + raw_ptr<MockAndroidVideoSurfaceChooser> surface_chooser_ = nullptr; + raw_ptr<gpu::MockTextureOwner> texture_owner_ = nullptr; + raw_ptr<MockVideoFrameFactory> video_frame_factory_ = nullptr; NiceMock<base::MockCallback<VideoDecoder::DecodeCB>> decode_cb_; ProvideOverlayInfoCB provide_overlay_info_cb_; bool restart_for_transitions_; @@ -339,6 +356,9 @@ } TEST_P(MediaCodecVideoDecoderAV1Test, Av1IsSupported) { + if (!HasAv1Decoder()) { + return; + } EXPECT_CALL(*device_info_, IsAv1DecoderAvailable()).WillOnce(Return(true)); ASSERT_TRUE(Initialize(TestVideoConfig::Normal(VideoCodec::kAV1))); } @@ -1039,8 +1059,9 @@ test_codecs.push_back(VideoCodec::kVP8); if (MediaCodecUtil::IsVp9DecoderAvailable()) test_codecs.push_back(VideoCodec::kVP9); - if (MediaCodecUtil::IsAv1DecoderAvailable()) + if (HasAv1Decoder()) { test_codecs.push_back(VideoCodec::kAV1); + } return test_codecs; } @@ -1065,9 +1086,8 @@ // } static std::vector<VideoCodec> GetAv1IfAvailable() { - return MediaCodecUtil::IsAv1DecoderAvailable() - ? std::vector<VideoCodec>(1, VideoCodec::kAV1) - : std::vector<VideoCodec>(); + return HasAv1Decoder() ? std::vector<VideoCodec>(1, VideoCodec::kAV1) + : std::vector<VideoCodec>(); } INSTANTIATE_TEST_SUITE_P(MediaCodecVideoDecoderTest,
diff --git a/media/gpu/android/video_accelerator_util.cc b/media/gpu/android/video_accelerator_util.cc index 970e6da2..a6a8431 100644 --- a/media/gpu/android/video_accelerator_util.cc +++ b/media/gpu/android/video_accelerator_util.cc
@@ -77,8 +77,6 @@ CHECK(env); auto java_profiles = Java_VideoEncodeAcceleratorUtil_getSupportedDecoderProfiles(env); - std::vector<MediaCodecDecoderInfo> cpp_infos; - constexpr char kHasMediaCodecDecoderInfo[] = "Media.Android.MediaCodecInfo.HasDecoderInfo"; if (!java_profiles) { @@ -93,27 +91,19 @@ constexpr auto kDefaultSize = gfx::Size(4096, 4096); constexpr auto kSoftwareCodec = true; constexpr auto kHardwareCodec = false; - cpp_infos.insert( - cpp_infos.end(), - { - {H264PROFILE_BASELINE, gfx::Size(), kDefaultSize, kHardwareCodec}, - {H264PROFILE_MAIN, gfx::Size(), kDefaultSize, kHardwareCodec}, - {H264PROFILE_HIGH, gfx::Size(), kDefaultSize, kHardwareCodec}, - {HEVCPROFILE_MAIN, gfx::Size(), kDefaultSize, kHardwareCodec}, + return std::vector<MediaCodecDecoderInfo>({ + {H264PROFILE_BASELINE, gfx::Size(), kDefaultSize, kHardwareCodec}, + {H264PROFILE_MAIN, gfx::Size(), kDefaultSize, kHardwareCodec}, + {H264PROFILE_HIGH, gfx::Size(), kDefaultSize, kHardwareCodec}, + {HEVCPROFILE_MAIN, gfx::Size(), kDefaultSize, kHardwareCodec}, - // Report codecs as software where we have a bundled decoder. - {VP8PROFILE_ANY, gfx::Size(), kDefaultSize, kSoftwareCodec}, - {VP9PROFILE_PROFILE0, gfx::Size(), kDefaultSize, kSoftwareCodec}, - }); - - if (base::android::BuildInfo::GetInstance()->sdk_int() >= - base::android::SDK_VERSION_Q) { - cpp_infos.emplace_back(AV1PROFILE_PROFILE_MAIN, gfx::Size(), - kDefaultSize, kSoftwareCodec); - } - return cpp_infos; + // Report codecs as software where we have a bundled decoder. + {VP8PROFILE_ANY, gfx::Size(), kDefaultSize, kSoftwareCodec}, + {VP9PROFILE_PROFILE0, gfx::Size(), kDefaultSize, kSoftwareCodec}, + }); } + std::vector<MediaCodecDecoderInfo> cpp_infos; for (auto java_profile : java_profiles.ReadElements<jobject>()) { MediaCodecDecoderInfo info; info.profile = static_cast<VideoCodecProfile>(
diff --git a/media/gpu/video_encode_accelerator_perf_tests.cc b/media/gpu/video_encode_accelerator_perf_tests.cc index b8ca24d..e8406a21 100644 --- a/media/gpu/video_encode_accelerator_perf_tests.cc +++ b/media/gpu/video_encode_accelerator_perf_tests.cc
@@ -635,7 +635,7 @@ get_model_frame_cb, /*corrupt_frame_processor=*/nullptr, VideoFrameValidator::ValidationMode::kAverage, - /*tolerance=*/0.0); + /*tolerance=*/100.0); LOG_ASSERT(log_likelihood_validator); quality_metrics_.push_back(BitstreamQualityMetrics( psnr_validator.get(), ssim_validator.get(),
diff --git a/net/base/features.cc b/net/base/features.cc index 73d56b3..9a8a4ef 100644 --- a/net/base/features.cc +++ b/net/base/features.cc
@@ -93,10 +93,6 @@ "PartitionConnectionsByNetworkIsolationKey", base::FEATURE_DISABLED_BY_DEFAULT); -BASE_FEATURE(kForceIsolationInfoFrameOriginToTopLevelFrame, - "ForceIsolationInfoFrameOriginToTopLevelFrame", - base::FEATURE_DISABLED_BY_DEFAULT); - BASE_FEATURE(kPartitionHttpServerPropertiesByNetworkIsolationKey, "PartitionHttpServerPropertiesByNetworkIsolationKey", base::FEATURE_DISABLED_BY_DEFAULT);
diff --git a/net/base/features.h b/net/base/features.h index 25f94ac9..3ee5b6c 100644 --- a/net/base/features.h +++ b/net/base/features.h
@@ -114,11 +114,6 @@ // request. NET_EXPORT BASE_DECLARE_FEATURE(kPartitionConnectionsByNetworkIsolationKey); -// Forces the `frame_origin` value in IsolationInfo to the `top_level_origin` -// value when an IsolationInfo instance is created. This is to enable -// expirimenting with double keyed network partitions. -NET_EXPORT BASE_DECLARE_FEATURE(kForceIsolationInfoFrameOriginToTopLevelFrame); - // Partitions HttpServerProperties based on the NetworkIsolationKey associated // with a request. NET_EXPORT BASE_DECLARE_FEATURE(
diff --git a/net/base/isolation_info.cc b/net/base/isolation_info.cc index 52cd760..668610a 100644 --- a/net/base/isolation_info.cc +++ b/net/base/isolation_info.cc
@@ -155,18 +155,6 @@ std::move(party_context), nullptr); } -IsolationInfo IsolationInfo::CreateDoubleKey( - RequestType request_type, - const url::Origin& top_frame_origin, - const SiteForCookies& site_for_cookies, - absl::optional<std::set<SchemefulSite>> party_context, - const base::UnguessableToken* nonce) { - // This should only be used when the frame site is disabled for double keying. - DCHECK(!IsFrameSiteEnabled()); - return IsolationInfo(request_type, top_frame_origin, absl::nullopt, - site_for_cookies, nonce, std::move(party_context)); -} - IsolationInfo IsolationInfo::Create( RequestType request_type, const url::Origin& top_frame_origin, @@ -305,8 +293,9 @@ } bool IsolationInfo::IsFrameSiteEnabled() { - return !base::FeatureList::IsEnabled( - net::features::kForceIsolationInfoFrameOriginToTopLevelFrame); + // NIKs, and thus IsolationInfo's, are currently always triple-keyed, but we + // will experiment with 2.5-keying in crbug.com/1414808. + return true; } std::string IsolationInfo::DebugString() const {
diff --git a/net/base/isolation_info.h b/net/base/isolation_info.h index 6fa7c4a..f2c52b0 100644 --- a/net/base/isolation_info.h +++ b/net/base/isolation_info.h
@@ -121,16 +121,6 @@ absl::optional<std::set<SchemefulSite>> party_context = absl::nullopt, const base::UnguessableToken* nonce = nullptr); - // Create and IsolationInfo from the context of a double key. This should only - // be used when we don't have access to the frame_origin because the - // IsolationInfo is being created from an existing double keyed IsolationInfo. - static IsolationInfo CreateDoubleKey( - RequestType request_type, - const url::Origin& top_frame_origin, - const SiteForCookies& site_for_cookies, - absl::optional<std::set<SchemefulSite>> party_context = absl::nullopt, - const base::UnguessableToken* nonce = nullptr); - // TODO(crbug/1372769): Remove this and create a safer way to ensure NIKs // created from NAKs aren't used by accident. static IsolationInfo DoNotUseCreatePartialFromNak( @@ -195,9 +185,7 @@ // policy. It MUST NEVER be used for any kind of SECURITY check. const SiteForCookies& site_for_cookies() const { return site_for_cookies_; } - // Do not use outside of testing. Returns the `frame_origin_` if - // `kForceIsolationInfoFrameOriginToTopLevelFrame` is disabled. Else it - // returns the `top_frame_origin_` value. + // Do not use outside of testing. Returns the `frame_origin_`. const absl::optional<url::Origin>& frame_origin_for_testing() const; // Return |party_context| which exclude the top frame origin and the frame
diff --git a/net/base/isolation_info_unittest.cc b/net/base/isolation_info_unittest.cc index d8802c3..3d26824 100644 --- a/net/base/isolation_info_unittest.cc +++ b/net/base/isolation_info_unittest.cc
@@ -24,34 +24,20 @@ namespace net { // `IsolationInfoEnabledFeatureFlagsTestingParam ` allows enabling and disabling -// the feature flags that control the key schemes for IsolationInfo, -// NetworkIsolationKey and Network AnonymizationKey. This allows us to test the -// possible combinations of flags that will be allowed for experimentation. -// Those possible combinations are outlined below. When a property is `true` the -// flag that enables this scheme will be enabled for testing. When the bool -// parameter is `false` the flag that enables the scheme will be disabled. +// the feature flags that control the key schemes for NetworkAnonymizationKey. +// This allows us to test the possible combinations of flags that will be +// allowed for experimentation. +// +// Presently, only one flag is used, but future experiments will add more. struct IsolationInfoEnabledFeatureFlagsTestingParam { - const bool enableDoubleKeyIsolationInfo; const bool enableDoubleKeyAndCrossSiteBitNetworkAnonymizationKey; }; -// The three cases we need to account for: -// 0. Double-keying is enabled for both IsolationInfo and -// NetworkAnonymizationKey. -// 1. Triple-keying is enabled for IsolationInfo and double-keying is enabled -// for NetworkAnonymizationKey. -// 2. Triple-keying is enabled for IsolationInfo and double-keying + -// cross-site-bit is enabled for NetworkAnonymizationKey. -// Note: At the current time double-keyed IsolationInfo is only supported when -// double-keying or double-keying + is cross site bit are enabled for -// NetworkAnonymizationKey. const IsolationInfoEnabledFeatureFlagsTestingParam kFlagsParam[] = { - {/*enableDoubleKeyIsolationInfo=*/true, - /*enableDoubleKeyAndCrossSiteBitNetworkAnonymizationKey=*/false}, - {/*enableDoubleKeyIsolationInfo=*/false, - /*enableDoubleKeyAndCrossSiteBitNetworkAnonymizationKey=*/false}, - {/*enableDoubleKeyIsolationInfo=*/false, - /*enableDoubleKeyAndCrossSiteBitNetworkAnonymizationKey=*/true}}; + // 0. Double-keying is enabled for NetworkAnonymizationKey. + {/*enableDoubleKeyAndCrossSiteBitNetworkAnonymizationKey=*/false}, + // 1. Double-keying + cross-site-bit is enabled for NetworkAnonymizationKey. + {/*enableDoubleKeyAndCrossSiteBitNetworkAnonymizationKey=*/true}}; namespace { @@ -63,14 +49,6 @@ std::vector<base::test::FeatureRef> enabled_features = {}; std::vector<base::test::FeatureRef> disabled_features = {}; - if (IsDoubleKeyIsolationInfoEnabled()) { - enabled_features.push_back( - net::features::kForceIsolationInfoFrameOriginToTopLevelFrame); - } else { - disabled_features.push_back( - net::features::kForceIsolationInfoFrameOriginToTopLevelFrame); - } - if (IsDoubleKeyAndCrossSiteBitNetworkAnonymizationKeyEnabled()) { enabled_features.push_back( net::features::kEnableCrossSiteFlagNetworkAnonymizationKey); @@ -82,10 +60,6 @@ scoped_feature_list_.InitWithFeatures(enabled_features, disabled_features); } - static bool IsDoubleKeyIsolationInfoEnabled() { - return GetParam().enableDoubleKeyIsolationInfo; - } - static bool IsDoubleKeyAndCrossSiteBitNetworkAnonymizationKeyEnabled() { return GetParam().enableDoubleKeyAndCrossSiteBitNetworkAnonymizationKey; } @@ -139,11 +113,7 @@ } TEST_P(IsolationInfoTest, IsFrameSiteEnabled) { - if (IsDoubleKeyIsolationInfoEnabled()) { - EXPECT_FALSE(IsolationInfo::IsFrameSiteEnabled()); - } else { - EXPECT_TRUE(IsolationInfo::IsFrameSiteEnabled()); - } + EXPECT_TRUE(IsolationInfo::IsFrameSiteEnabled()); } TEST_P(IsolationInfoTest, DebugString) { @@ -192,18 +162,10 @@ kNonce1); EXPECT_EQ(isolation_info.nonce().value(), kNonce1); - if (!IsDoubleKeyAndCrossSiteBitNetworkAnonymizationKeyEnabled() && - IsDoubleKeyIsolationInfoEnabled()) { - // Double-keyed IsolationInfo + double-keyed NetworkAnonymizationKey case. - EXPECT_EQ(kOrigin1, isolation_info.top_frame_origin()); - EXPECT_DEATH_IF_SUPPORTED(isolation_info.frame_origin(), ""); - EXPECT_EQ(absl::nullopt, isolation_info.frame_origin_for_testing()); - } else if (!IsDoubleKeyIsolationInfoEnabled() && - !IsDoubleKeyAndCrossSiteBitNetworkAnonymizationKeyEnabled()) { + if (!IsDoubleKeyAndCrossSiteBitNetworkAnonymizationKeyEnabled()) { // Triple-keyed IsolationInfo + double-keyed NetworkAnonymizationKey case. EXPECT_EQ(isolation_info.frame_origin(), kOrigin2); - } else if (!IsDoubleKeyIsolationInfoEnabled() && - IsDoubleKeyAndCrossSiteBitNetworkAnonymizationKeyEnabled()) { + } else { // Triple-keyed IsolationInfo + double-keyed + cross site bit // NetworkAnonymizationKey case. EXPECT_EQ(isolation_info.frame_origin(), kOrigin2); @@ -215,50 +177,6 @@ } } -TEST_P(IsolationInfoTest, CreateDoubleKey) { - IsolationInfo isolation_info = IsolationInfo::Create( - IsolationInfo::RequestType::kMainFrame, kOrigin1, kOrigin1, - SiteForCookies::FromOrigin(kOrigin1), kPartyContextEmpty); - - if (IsDoubleKeyIsolationInfoEnabled()) { - IsolationInfo double_key_isolation_info = IsolationInfo::CreateDoubleKey( - IsolationInfo::RequestType::kMainFrame, kOrigin1, - SiteForCookies::FromOrigin(kOrigin1), kPartyContextEmpty); - - EXPECT_EQ(IsolationInfo::RequestType::kMainFrame, - double_key_isolation_info.request_type()); - EXPECT_EQ(kOrigin1, double_key_isolation_info.top_frame_origin()); - EXPECT_DEATH_IF_SUPPORTED(double_key_isolation_info.frame_origin(), ""); - EXPECT_EQ(absl::nullopt, - double_key_isolation_info.frame_origin_for_testing()); - EXPECT_EQ( - "https://foo.test https://foo.test", - double_key_isolation_info.network_isolation_key().ToCacheKeyString()); - EXPECT_EQ(kPartyContextEmpty, double_key_isolation_info.party_context()); - EXPECT_FALSE(double_key_isolation_info.nonce().has_value()); - - // When double keying is enabled Create and CreateDoubleKey should - // create the same key. - EXPECT_EQ(isolation_info.top_frame_origin(), - double_key_isolation_info.top_frame_origin()); - EXPECT_EQ(isolation_info.request_type(), - double_key_isolation_info.request_type()); - EXPECT_EQ(isolation_info.network_isolation_key(), - double_key_isolation_info.network_isolation_key()); - EXPECT_EQ(isolation_info.party_context(), - double_key_isolation_info.party_context()); - EXPECT_EQ(isolation_info.nonce(), double_key_isolation_info.nonce()); - } else { - // Creating double keyed IsolationInfos is not allowed when frame site is - // enabled. - EXPECT_DEATH_IF_SUPPORTED( - IsolationInfo::CreateDoubleKey( - IsolationInfo::RequestType::kMainFrame, kOrigin1, - SiteForCookies::FromOrigin(kOrigin1), kPartyContextEmpty), - ""); - } -} - TEST_P(IsolationInfoTest, RequestTypeMainFrame) { IsolationInfo isolation_info = IsolationInfo::Create( IsolationInfo::RequestType::kMainFrame, kOrigin1, kOrigin1, @@ -267,16 +185,9 @@ isolation_info.request_type()); EXPECT_EQ(kOrigin1, isolation_info.top_frame_origin()); - if (IsDoubleKeyIsolationInfoEnabled()) { - EXPECT_DEATH_IF_SUPPORTED(isolation_info.frame_origin(), ""); - EXPECT_EQ(absl::nullopt, isolation_info.frame_origin_for_testing()); - EXPECT_EQ("https://foo.test https://foo.test", - isolation_info.network_isolation_key().ToCacheKeyString()); - } else { - EXPECT_EQ(kOrigin1, isolation_info.frame_origin()); - EXPECT_EQ("https://foo.test https://foo.test", - isolation_info.network_isolation_key().ToCacheKeyString()); - } + EXPECT_EQ(kOrigin1, isolation_info.frame_origin()); + EXPECT_EQ("https://foo.test https://foo.test", + isolation_info.network_isolation_key().ToCacheKeyString()); EXPECT_TRUE(isolation_info.network_isolation_key().IsFullyPopulated()); EXPECT_FALSE(isolation_info.network_isolation_key().IsTransient()); EXPECT_TRUE( @@ -291,25 +202,13 @@ EXPECT_EQ(IsolationInfo::RequestType::kMainFrame, redirected_isolation_info.request_type()); EXPECT_EQ(kOrigin3, redirected_isolation_info.top_frame_origin()); - if (IsDoubleKeyIsolationInfoEnabled()) { - EXPECT_DEATH_IF_SUPPORTED(redirected_isolation_info.frame_origin(), ""); - EXPECT_EQ(absl::nullopt, - redirected_isolation_info.frame_origin_for_testing()); - } else { - EXPECT_EQ(kOrigin3, redirected_isolation_info.frame_origin()); - } + EXPECT_EQ(kOrigin3, redirected_isolation_info.frame_origin()); EXPECT_TRUE( redirected_isolation_info.network_isolation_key().IsFullyPopulated()); EXPECT_FALSE(redirected_isolation_info.network_isolation_key().IsTransient()); - if (IsDoubleKeyIsolationInfoEnabled()) { - EXPECT_EQ( - "https://baz.test https://baz.test", - redirected_isolation_info.network_isolation_key().ToCacheKeyString()); - } else { - EXPECT_EQ( - "https://baz.test https://baz.test", - redirected_isolation_info.network_isolation_key().ToCacheKeyString()); - } + EXPECT_EQ( + "https://baz.test https://baz.test", + redirected_isolation_info.network_isolation_key().ToCacheKeyString()); EXPECT_TRUE(redirected_isolation_info.site_for_cookies().IsFirstParty( kOrigin3.GetURL())); EXPECT_EQ(kPartyContextEmpty, redirected_isolation_info.party_context()); @@ -323,16 +222,9 @@ EXPECT_EQ(IsolationInfo::RequestType::kSubFrame, isolation_info.request_type()); EXPECT_EQ(kOrigin1, isolation_info.top_frame_origin()); - if (IsDoubleKeyIsolationInfoEnabled()) { - EXPECT_DEATH_IF_SUPPORTED(isolation_info.frame_origin(), ""); - EXPECT_EQ(absl::nullopt, isolation_info.frame_origin_for_testing()); - EXPECT_EQ("https://foo.test https://foo.test", - isolation_info.network_isolation_key().ToCacheKeyString()); - } else { - EXPECT_EQ(kOrigin2, isolation_info.frame_origin()); - EXPECT_EQ("https://foo.test https://bar.test", - isolation_info.network_isolation_key().ToCacheKeyString()); - } + EXPECT_EQ(kOrigin2, isolation_info.frame_origin()); + EXPECT_EQ("https://foo.test https://bar.test", + isolation_info.network_isolation_key().ToCacheKeyString()); EXPECT_TRUE(isolation_info.network_isolation_key().IsFullyPopulated()); EXPECT_FALSE(isolation_info.network_isolation_key().IsTransient()); EXPECT_TRUE( @@ -348,19 +240,10 @@ redirected_isolation_info.request_type()); EXPECT_EQ(kOrigin1, redirected_isolation_info.top_frame_origin()); - if (IsDoubleKeyIsolationInfoEnabled()) { - EXPECT_DEATH_IF_SUPPORTED(redirected_isolation_info.frame_origin(), ""); - EXPECT_EQ(absl::nullopt, - redirected_isolation_info.frame_origin_for_testing()); - EXPECT_EQ( - "https://foo.test https://foo.test", - redirected_isolation_info.network_isolation_key().ToCacheKeyString()); - } else { - EXPECT_EQ(kOrigin3, redirected_isolation_info.frame_origin()); - EXPECT_EQ( - "https://foo.test https://baz.test", - redirected_isolation_info.network_isolation_key().ToCacheKeyString()); - } + EXPECT_EQ(kOrigin3, redirected_isolation_info.frame_origin()); + EXPECT_EQ( + "https://foo.test https://baz.test", + redirected_isolation_info.network_isolation_key().ToCacheKeyString()); EXPECT_TRUE( redirected_isolation_info.network_isolation_key().IsFullyPopulated()); EXPECT_FALSE(redirected_isolation_info.network_isolation_key().IsTransient()); @@ -377,12 +260,7 @@ EXPECT_EQ(IsolationInfo::RequestType::kMainFrame, isolation_info.request_type()); EXPECT_EQ(kOrigin1, isolation_info.top_frame_origin()); - if (IsDoubleKeyIsolationInfoEnabled()) { - EXPECT_DEATH_IF_SUPPORTED(isolation_info.frame_origin(), ""); - EXPECT_EQ(absl::nullopt, isolation_info.frame_origin_for_testing()); - } else { - EXPECT_EQ(kOrigin1, isolation_info.frame_origin()); - } + EXPECT_EQ(kOrigin1, isolation_info.frame_origin()); EXPECT_TRUE(isolation_info.network_isolation_key().IsFullyPopulated()); EXPECT_TRUE(isolation_info.network_isolation_key().IsTransient()); EXPECT_EQ(absl::nullopt, @@ -399,13 +277,7 @@ EXPECT_EQ(IsolationInfo::RequestType::kMainFrame, redirected_isolation_info.request_type()); EXPECT_EQ(kOrigin3, redirected_isolation_info.top_frame_origin()); - if (IsDoubleKeyIsolationInfoEnabled()) { - EXPECT_DEATH_IF_SUPPORTED(redirected_isolation_info.frame_origin(), ""); - EXPECT_EQ(absl::nullopt, - redirected_isolation_info.frame_origin_for_testing()); - } else { - EXPECT_EQ(kOrigin3, redirected_isolation_info.frame_origin()); - } + EXPECT_EQ(kOrigin3, redirected_isolation_info.frame_origin()); EXPECT_TRUE( redirected_isolation_info.network_isolation_key().IsFullyPopulated()); EXPECT_TRUE(redirected_isolation_info.network_isolation_key().IsTransient()); @@ -425,12 +297,7 @@ EXPECT_EQ(IsolationInfo::RequestType::kSubFrame, isolation_info.request_type()); EXPECT_EQ(kOrigin1, isolation_info.top_frame_origin()); - if (IsDoubleKeyIsolationInfoEnabled()) { - EXPECT_DEATH_IF_SUPPORTED(isolation_info.frame_origin(), ""); - EXPECT_EQ(absl::nullopt, isolation_info.frame_origin_for_testing()); - } else { - EXPECT_EQ(kOrigin2, isolation_info.frame_origin()); - } + EXPECT_EQ(kOrigin2, isolation_info.frame_origin()); EXPECT_TRUE(isolation_info.network_isolation_key().IsFullyPopulated()); EXPECT_TRUE(isolation_info.network_isolation_key().IsTransient()); EXPECT_EQ(absl::nullopt, @@ -447,13 +314,7 @@ EXPECT_EQ(IsolationInfo::RequestType::kSubFrame, redirected_isolation_info.request_type()); EXPECT_EQ(kOrigin1, redirected_isolation_info.top_frame_origin()); - if (IsDoubleKeyIsolationInfoEnabled()) { - EXPECT_DEATH_IF_SUPPORTED(redirected_isolation_info.frame_origin(), ""); - EXPECT_EQ(absl::nullopt, - redirected_isolation_info.frame_origin_for_testing()); - } else { - EXPECT_EQ(kOrigin3, redirected_isolation_info.frame_origin()); - } + EXPECT_EQ(kOrigin3, redirected_isolation_info.frame_origin()); EXPECT_TRUE( redirected_isolation_info.network_isolation_key().IsFullyPopulated()); EXPECT_TRUE(redirected_isolation_info.network_isolation_key().IsTransient()); @@ -470,12 +331,7 @@ IsolationInfo isolation_info; EXPECT_EQ(IsolationInfo::RequestType::kOther, isolation_info.request_type()); EXPECT_FALSE(isolation_info.top_frame_origin()); - if (IsDoubleKeyIsolationInfoEnabled()) { - EXPECT_DEATH_IF_SUPPORTED(isolation_info.frame_origin(), ""); - EXPECT_FALSE(isolation_info.frame_origin_for_testing()); - } else { - EXPECT_FALSE(isolation_info.frame_origin()); - } + EXPECT_FALSE(isolation_info.frame_origin()); EXPECT_TRUE(isolation_info.network_isolation_key().IsEmpty()); EXPECT_TRUE(isolation_info.site_for_cookies().IsNull()); EXPECT_FALSE(isolation_info.party_context()); @@ -494,16 +350,9 @@ SiteForCookies::FromOrigin(kOrigin1), kPartyContextEmpty); EXPECT_EQ(IsolationInfo::RequestType::kOther, isolation_info.request_type()); EXPECT_EQ(kOrigin1, isolation_info.top_frame_origin()); - if (IsDoubleKeyIsolationInfoEnabled()) { - EXPECT_DEATH_IF_SUPPORTED(isolation_info.frame_origin(), ""); - EXPECT_EQ(absl::nullopt, isolation_info.frame_origin_for_testing()); - EXPECT_EQ("https://foo.test https://foo.test", - isolation_info.network_isolation_key().ToCacheKeyString()); - } else { - EXPECT_EQ(kOrigin1, isolation_info.frame_origin()); - EXPECT_EQ("https://foo.test https://foo.test", - isolation_info.network_isolation_key().ToCacheKeyString()); - } + EXPECT_EQ(kOrigin1, isolation_info.frame_origin()); + EXPECT_EQ("https://foo.test https://foo.test", + isolation_info.network_isolation_key().ToCacheKeyString()); EXPECT_TRUE(isolation_info.network_isolation_key().IsFullyPopulated()); EXPECT_FALSE(isolation_info.network_isolation_key().IsTransient()); EXPECT_TRUE( @@ -526,16 +375,9 @@ kOrigin2, SiteForCookies(), kPartyContext2); EXPECT_EQ(IsolationInfo::RequestType::kOther, isolation_info.request_type()); EXPECT_EQ(kOrigin1, isolation_info.top_frame_origin()); - if (IsDoubleKeyIsolationInfoEnabled()) { - EXPECT_DEATH_IF_SUPPORTED(isolation_info.frame_origin(), ""); - EXPECT_EQ(absl::nullopt, isolation_info.frame_origin_for_testing()); - EXPECT_EQ("https://foo.test https://foo.test", - isolation_info.network_isolation_key().ToCacheKeyString()); - } else { - EXPECT_EQ(kOrigin2, isolation_info.frame_origin()); - EXPECT_EQ("https://foo.test https://bar.test", - isolation_info.network_isolation_key().ToCacheKeyString()); - } + EXPECT_EQ(kOrigin2, isolation_info.frame_origin()); + EXPECT_EQ("https://foo.test https://bar.test", + isolation_info.network_isolation_key().ToCacheKeyString()); EXPECT_TRUE(isolation_info.network_isolation_key().IsFullyPopulated()); EXPECT_FALSE(isolation_info.network_isolation_key().IsTransient()); EXPECT_TRUE(isolation_info.site_for_cookies().IsNull()); @@ -553,12 +395,7 @@ IsolationInfo isolation_info = IsolationInfo::CreateTransient(); EXPECT_EQ(IsolationInfo::RequestType::kOther, isolation_info.request_type()); EXPECT_TRUE(isolation_info.top_frame_origin()->opaque()); - if (IsDoubleKeyIsolationInfoEnabled()) { - EXPECT_DEATH_IF_SUPPORTED(isolation_info.frame_origin(), ""); - EXPECT_FALSE(isolation_info.frame_origin_for_testing().has_value()); - } else { - EXPECT_TRUE(isolation_info.frame_origin()->opaque()); - } + EXPECT_TRUE(isolation_info.frame_origin()->opaque()); EXPECT_TRUE(isolation_info.network_isolation_key().IsFullyPopulated()); EXPECT_TRUE(isolation_info.network_isolation_key().IsTransient()); EXPECT_TRUE(isolation_info.site_for_cookies().IsNull()); @@ -577,16 +414,9 @@ IsolationInfo::CreateForInternalRequest(kOrigin1); EXPECT_EQ(IsolationInfo::RequestType::kOther, isolation_info.request_type()); EXPECT_EQ(kOrigin1, isolation_info.top_frame_origin()); - if (IsDoubleKeyIsolationInfoEnabled()) { - EXPECT_DEATH_IF_SUPPORTED(isolation_info.frame_origin(), ""); - EXPECT_EQ(absl::nullopt, isolation_info.frame_origin_for_testing()); - EXPECT_EQ("https://foo.test https://foo.test", - isolation_info.network_isolation_key().ToCacheKeyString()); - } else { - EXPECT_EQ(kOrigin1, isolation_info.frame_origin()); - EXPECT_EQ("https://foo.test https://foo.test", - isolation_info.network_isolation_key().ToCacheKeyString()); - } + EXPECT_EQ(kOrigin1, isolation_info.frame_origin()); + EXPECT_EQ("https://foo.test https://foo.test", + isolation_info.network_isolation_key().ToCacheKeyString()); EXPECT_TRUE(isolation_info.network_isolation_key().IsFullyPopulated()); EXPECT_FALSE(isolation_info.network_isolation_key().IsTransient()); EXPECT_TRUE( @@ -617,16 +447,9 @@ SiteForCookies::FromOrigin(kCustomOrigin), kPartyContext1); EXPECT_EQ(IsolationInfo::RequestType::kOther, isolation_info.request_type()); EXPECT_EQ(kCustomOrigin, isolation_info.top_frame_origin()); - if (IsDoubleKeyIsolationInfoEnabled()) { - EXPECT_DEATH_IF_SUPPORTED(isolation_info.frame_origin(), ""); - EXPECT_EQ(absl::nullopt, isolation_info.frame_origin_for_testing()); - EXPECT_EQ("foo://a.foo.com foo://a.foo.com", - isolation_info.network_isolation_key().ToCacheKeyString()); - } else { - EXPECT_EQ(kOrigin1, isolation_info.frame_origin()); - EXPECT_EQ("foo://a.foo.com https://foo.test", - isolation_info.network_isolation_key().ToCacheKeyString()); - } + EXPECT_EQ(kOrigin1, isolation_info.frame_origin()); + EXPECT_EQ("foo://a.foo.com https://foo.test", + isolation_info.network_isolation_key().ToCacheKeyString()); EXPECT_TRUE(isolation_info.network_isolation_key().IsFullyPopulated()); EXPECT_FALSE(isolation_info.network_isolation_key().IsTransient()); EXPECT_TRUE(isolation_info.site_for_cookies().IsFirstParty(kCustomOriginUrl)); @@ -673,32 +496,20 @@ EXPECT_FALSE(IsolationInfo::CreateIfConsistent( IsolationInfo::RequestType::kSubFrame, absl::nullopt, kOrigin2, SiteForCookies())); - // Empty frame origins are ok when double keying is enabled but incorrect - // when triple key is enabled. - if (IsDoubleKeyIsolationInfoEnabled()) { - EXPECT_TRUE(IsolationInfo::CreateIfConsistent( - IsolationInfo::RequestType::kOther, kOrigin1, absl::nullopt, - SiteForCookies())); - EXPECT_TRUE(IsolationInfo::CreateIfConsistent( - IsolationInfo::RequestType::kSubFrame, kOrigin1, absl::nullopt, - SiteForCookies())); - EXPECT_TRUE(IsolationInfo::CreateIfConsistent( - IsolationInfo::RequestType::kMainFrame, kOrigin1, absl::nullopt, - SiteForCookies::FromOrigin(kOrigin1))); - } else { - EXPECT_FALSE(IsolationInfo::CreateIfConsistent( - IsolationInfo::RequestType::kOther, kOrigin1, absl::nullopt, - SiteForCookies())); - EXPECT_FALSE(IsolationInfo::CreateIfConsistent( - IsolationInfo::RequestType::kSubFrame, kOrigin1, absl::nullopt, - SiteForCookies())); - EXPECT_FALSE(IsolationInfo::CreateIfConsistent( - IsolationInfo::RequestType::kMainFrame, kOrigin1, absl::nullopt, - SiteForCookies::FromOrigin(kOrigin1))); - EXPECT_FALSE(IsolationInfo::CreateIfConsistent( - IsolationInfo::RequestType::kOther, kOrigin1, kOrigin2, - SiteForCookies::FromOrigin(kOrigin1))); - } + + // Empty frame origins are incorrect. + EXPECT_FALSE(IsolationInfo::CreateIfConsistent( + IsolationInfo::RequestType::kOther, kOrigin1, absl::nullopt, + SiteForCookies())); + EXPECT_FALSE(IsolationInfo::CreateIfConsistent( + IsolationInfo::RequestType::kSubFrame, kOrigin1, absl::nullopt, + SiteForCookies())); + EXPECT_FALSE(IsolationInfo::CreateIfConsistent( + IsolationInfo::RequestType::kMainFrame, kOrigin1, absl::nullopt, + SiteForCookies::FromOrigin(kOrigin1))); + EXPECT_FALSE(IsolationInfo::CreateIfConsistent( + IsolationInfo::RequestType::kOther, kOrigin1, kOrigin2, + SiteForCookies::FromOrigin(kOrigin1))); // No origins with non-null SiteForCookies. EXPECT_FALSE(IsolationInfo::CreateIfConsistent( @@ -811,15 +622,8 @@ kOrigin2, SiteForCookies::FromOrigin(kOrigin1), kPartyContext1, &kNonce1), }; - if (IsDoubleKeyIsolationInfoEnabled()) { - for (const auto& info : kNegativeWhenDoubleKeyEnabledTestCases) { - EXPECT_TRUE(info.Serialize().empty()); - } - - } else { - for (const auto& info : kNegativeTestCases) { - EXPECT_TRUE(info.Serialize().empty()); - } + for (const auto& info : kNegativeTestCases) { + EXPECT_TRUE(info.Serialize().empty()); } }
diff --git a/net/base/network_anonymization_key_unittest.cc b/net/base/network_anonymization_key_unittest.cc index f885273..bc35e88 100644 --- a/net/base/network_anonymization_key_unittest.cc +++ b/net/base/network_anonymization_key_unittest.cc
@@ -18,25 +18,20 @@ namespace net { +// `EnabledFeatureFlagsTestingParam ` allows enabling and disabling +// the feature flags that control the key schemes for NetworkAnonymizationKey. +// This allows us to test the possible combinations of flags that will be +// allowed for experimentation. struct EnabledFeatureFlagsTestingParam { // True = 2.5-keyed NAK, false = double-keyed NAK. const bool enableCrossSiteFlagNetworkAnonymizationKey; - const bool enableDoubleKeyNetworkIsolationKey; }; -// 0. Double-keying is enabled for both IsolationInfo and -// NetworkAnonymizationKey. -// 1. Triple-keying is enabled for IsolationInfo and double-keying is enabled -// for NetworkAnonymizationKey. -// 2. Triple-keying is enabled for IsolationInfo and double-keying + -// cross-site-bit is enabled for NetworkAnonymizationKey. const EnabledFeatureFlagsTestingParam kFlagsParam[] = { - {/*enableCrossSiteFlagNetworkAnonymizationKey=*/false, - /*enableDoubleKeyNetworkIsolationKey=*/true}, - {/*enableCrossSiteFlagNetworkAnonymizationKey=*/false, - /*enableDoubleKeyNetworkIsolationKey=*/false}, - {/*enableCrossSiteFlagNetworkAnonymizationKey=*/true, - /*enableDoubleKeyNetworkIsolationKey=*/false}}; + // 0. Double-keying is enabled for NetworkAnonymizationKey. + {/*enableCrossSiteFlagNetworkAnonymizationKey=*/false}, + // 1. Double-keying + cross-site-bit is enabled for NetworkAnonymizationKey. + {/*enableCrossSiteFlagNetworkAnonymizationKey=*/true}}; class NetworkAnonymizationKeyTest : public testing::Test, @@ -46,14 +41,6 @@ std::vector<base::test::FeatureRef> enabled_features = {}; std::vector<base::test::FeatureRef> disabled_features = {}; - if (IsDoubleKeyNetworkIsolationKeyEnabled()) { - enabled_features.push_back( - net::features::kForceIsolationInfoFrameOriginToTopLevelFrame); - } else { - disabled_features.push_back( - net::features::kForceIsolationInfoFrameOriginToTopLevelFrame); - } - if (IsCrossSiteFlagEnabled()) { enabled_features.push_back( net::features::kEnableCrossSiteFlagNetworkAnonymizationKey); @@ -65,10 +52,6 @@ scoped_feature_list_.InitWithFeatures(enabled_features, disabled_features); } - static bool IsDoubleKeyNetworkIsolationKeyEnabled() { - return GetParam().enableDoubleKeyNetworkIsolationKey; - } - bool IsCrossSiteFlagEnabled() { return GetParam().enableCrossSiteFlagNetworkAnonymizationKey; } @@ -128,25 +111,8 @@ // empty NAK. EXPECT_TRUE(nak_from_empty_nik.IsEmpty()); - // Double-keyed NetworkIsolationKey + double-keyed NetworkAnonymizationKey - // case. - if (IsDoubleKeyNetworkIsolationKeyEnabled() && !IsCrossSiteFlagEnabled()) { - // Top site should be populated. - EXPECT_EQ(nak_from_cross_site_nik.GetTopFrameSite(), site_a); - EXPECT_EQ(nak_from_same_site_nik.GetTopFrameSite(), site_a); - - // Nonce should be populated. - EXPECT_EQ(nak_from_same_site_nik.GetNonce(), nik_nonce); - EXPECT_EQ(nak_from_cross_site_nik.GetNonce(), nik_nonce); - - // Double-keyed NAKs created from different third party cross site contexts - // should be equal. - EXPECT_TRUE(nak_from_same_site_nik == nak_from_cross_site_nik); - } - - // Triple-keyed NetworkIsolationKey + double-keyed NetworkAnonymizationKey - // case. - if (!IsDoubleKeyNetworkIsolationKeyEnabled() && !IsCrossSiteFlagEnabled()) { + // Double-keyed NetworkAnonymizationKey case. + if (!IsCrossSiteFlagEnabled()) { // Top site should be populated correctly. EXPECT_EQ(nak_from_cross_site_nik.GetTopFrameSite(), site_a); EXPECT_EQ(nak_from_same_site_nik.GetTopFrameSite(), site_a); @@ -160,9 +126,8 @@ EXPECT_TRUE(nak_from_same_site_nik == nak_from_cross_site_nik); } - // Triple-keyed NetworkIsolationKey + double-keyed + cross site bit - // NetworkAnonymizationKey case. - if (!IsDoubleKeyNetworkIsolationKeyEnabled() && IsCrossSiteFlagEnabled()) { + // Double-keyed + cross site bit NetworkAnonymizationKey case. + if (IsCrossSiteFlagEnabled()) { // Top site should be populated correctly. EXPECT_EQ(nak_from_cross_site_nik.GetTopFrameSite(), site_a); EXPECT_EQ(nak_from_same_site_nik.GetTopFrameSite(), site_a);
diff --git a/net/base/network_isolation_key.cc b/net/base/network_isolation_key.cc index 0000f73..d0ff1ba 100644 --- a/net/base/network_isolation_key.cc +++ b/net/base/network_isolation_key.cc
@@ -215,8 +215,9 @@ } bool NetworkIsolationKey::IsFrameSiteEnabled() { - return !base::FeatureList::IsEnabled( - net::features::kForceIsolationInfoFrameOriginToTopLevelFrame); + // NIKs are currently always triple-keyed, but we will experiment with + // 2.5-keying in crbug.com/1414808. + return true; } bool NetworkIsolationKey::IsOpaque() const {
diff --git a/net/base/network_isolation_key.h b/net/base/network_isolation_key.h index 049f4a3..77193f0 100644 --- a/net/base/network_isolation_key.h +++ b/net/base/network_isolation_key.h
@@ -121,9 +121,7 @@ const absl::optional<SchemefulSite>& GetFrameSite() const; - // Do not use outside of testing. Returns the `frame_site_` if - // `kForceIsolationInfoFrameOriginToTopLevelFrame` is disabled. Else it - // returns nullopt. + // Do not use outside of testing. Returns the `frame_site_`. const absl::optional<SchemefulSite>& GetFrameSiteForTesting() const { return frame_site_; }
diff --git a/net/base/network_isolation_key_unittest.cc b/net/base/network_isolation_key_unittest.cc index 919720f..a764a73 100644 --- a/net/base/network_isolation_key_unittest.cc +++ b/net/base/network_isolation_key_unittest.cc
@@ -4,7 +4,6 @@ #include "net/base/network_isolation_key.h" -#include "base/test/scoped_feature_list.h" #include "base/unguessable_token.h" #include "base/values.h" #include "net/base/features.h" @@ -19,40 +18,11 @@ namespace { const char kDataUrl[] = "data:text/html,<body>Hello World</body>"; -class NetworkIsolationKeyTest : public testing::Test, - public testing::WithParamInterface<bool> { - public: - void SetUp() override { - if (ForceIsolationInfoFrameOriginToTopLevelFrameEnabled()) { - scoped_feature_list_.InitAndEnableFeature( - net::features::kForceIsolationInfoFrameOriginToTopLevelFrame); - } else { - scoped_feature_list_.InitAndDisableFeature( - net::features::kForceIsolationInfoFrameOriginToTopLevelFrame); - } - } - static bool ForceIsolationInfoFrameOriginToTopLevelFrameEnabled() { - return GetParam(); - } - - private: - base::test::ScopedFeatureList scoped_feature_list_; -}; - -INSTANTIATE_TEST_SUITE_P( - All, - NetworkIsolationKeyTest, - /*force_isolation_info_frame_origin_to_top_level_frame*/ testing::Bool()); - -TEST_P(NetworkIsolationKeyTest, IsFrameSiteEnabled) { - if (ForceIsolationInfoFrameOriginToTopLevelFrameEnabled()) { - EXPECT_FALSE(NetworkIsolationKey::IsFrameSiteEnabled()); - } else { - EXPECT_TRUE(NetworkIsolationKey::IsFrameSiteEnabled()); - } +TEST(NetworkIsolationKeyTest, IsFrameSiteEnabled) { + EXPECT_TRUE(NetworkIsolationKey::IsFrameSiteEnabled()); } -TEST_P(NetworkIsolationKeyTest, EmptyKey) { +TEST(NetworkIsolationKeyTest, EmptyKey) { NetworkIsolationKey key; EXPECT_FALSE(key.IsFullyPopulated()); EXPECT_EQ(absl::nullopt, key.ToCacheKeyString()); @@ -60,25 +30,19 @@ EXPECT_EQ("null null", key.ToDebugString()); } -TEST_P(NetworkIsolationKeyTest, NonEmptyKey) { +TEST(NetworkIsolationKeyTest, NonEmptyKey) { SchemefulSite site1 = SchemefulSite(GURL("http://a.test/")); SchemefulSite site2 = SchemefulSite(GURL("http://b.test/")); NetworkIsolationKey key(site1, site2); EXPECT_TRUE(key.IsFullyPopulated()); - if (ForceIsolationInfoFrameOriginToTopLevelFrameEnabled()) { - EXPECT_EQ(site1.Serialize() + " " + site1.Serialize(), - key.ToCacheKeyString()); - EXPECT_EQ(site1.GetDebugString() + " null", key.ToDebugString()); - } else { - EXPECT_EQ(site1.Serialize() + " " + site2.Serialize(), - key.ToCacheKeyString()); - EXPECT_EQ(site1.GetDebugString() + " " + site2.GetDebugString(), - key.ToDebugString()); - } + EXPECT_EQ(site1.Serialize() + " " + site2.Serialize(), + key.ToCacheKeyString()); + EXPECT_EQ(site1.GetDebugString() + " " + site2.GetDebugString(), + key.ToDebugString()); EXPECT_FALSE(key.IsTransient()); } -TEST_P(NetworkIsolationKeyTest, KeyWithNonce) { +TEST(NetworkIsolationKeyTest, KeyWithNonce) { SchemefulSite site1 = SchemefulSite(GURL("http://a.test/")); SchemefulSite site2 = SchemefulSite(GURL("http://b.test/")); base::UnguessableToken nonce = base::UnguessableToken::Create(); @@ -86,15 +50,9 @@ EXPECT_TRUE(key.IsFullyPopulated()); EXPECT_EQ(absl::nullopt, key.ToCacheKeyString()); EXPECT_TRUE(key.IsTransient()); - if (ForceIsolationInfoFrameOriginToTopLevelFrameEnabled()) { - EXPECT_EQ(site1.GetDebugString() + " null" + " (with nonce " + - nonce.ToString() + ")", - key.ToDebugString()); - } else { - EXPECT_EQ(site1.GetDebugString() + " " + site2.GetDebugString() + - " (with nonce " + nonce.ToString() + ")", - key.ToDebugString()); - } + EXPECT_EQ(site1.GetDebugString() + " " + site2.GetDebugString() + + " (with nonce " + nonce.ToString() + ")", + key.ToDebugString()); // Create another NetworkIsolationKey with the same input parameters, and // check that it is equal. @@ -109,7 +67,7 @@ EXPECT_NE(key.ToDebugString(), key2.ToDebugString()); } -TEST_P(NetworkIsolationKeyTest, OpaqueOriginKey) { +TEST(NetworkIsolationKeyTest, OpaqueOriginKey) { SchemefulSite site_data = SchemefulSite(GURL(kDataUrl)); NetworkIsolationKey key(site_data, site_data); EXPECT_TRUE(key.IsFullyPopulated()); @@ -124,7 +82,7 @@ EXPECT_NE(key.ToDebugString(), other_key.ToDebugString()); } -TEST_P(NetworkIsolationKeyTest, Operators) { +TEST(NetworkIsolationKeyTest, Operators) { base::UnguessableToken nonce1 = base::UnguessableToken::Create(); base::UnguessableToken nonce2 = base::UnguessableToken::Create(); if (nonce2 < nonce1) @@ -176,7 +134,7 @@ } } -TEST_P(NetworkIsolationKeyTest, UniqueOriginOperators) { +TEST(NetworkIsolationKeyTest, UniqueOriginOperators) { const auto kSite1 = SchemefulSite(GURL(kDataUrl)); const auto kSite2 = SchemefulSite(GURL(kDataUrl)); NetworkIsolationKey key1(kSite1, kSite1); @@ -197,38 +155,26 @@ EXPECT_TRUE(!(key1 < key2) || !(key2 < key1)); } -TEST_P(NetworkIsolationKeyTest, KeyWithOneOpaqueOrigin) { +TEST(NetworkIsolationKeyTest, KeyWithOneOpaqueOrigin) { SchemefulSite site = SchemefulSite(GURL("http://a.test")); SchemefulSite opaque_site = SchemefulSite(GURL(kDataUrl)); NetworkIsolationKey key1(site, opaque_site); EXPECT_TRUE(key1.IsFullyPopulated()); - if (ForceIsolationInfoFrameOriginToTopLevelFrameEnabled()) { - EXPECT_FALSE(key1.IsTransient()); - EXPECT_EQ(site.GetDebugString() + " " + site.GetDebugString(), - key1.ToCacheKeyString()); - - EXPECT_EQ(site.GetDebugString() + " null", key1.ToDebugString()); - } else { - EXPECT_TRUE(key1.IsTransient()); - EXPECT_EQ(absl::nullopt, key1.ToCacheKeyString()); - EXPECT_EQ(site.GetDebugString() + " " + opaque_site.GetDebugString(), - key1.ToDebugString()); - } + EXPECT_TRUE(key1.IsTransient()); + EXPECT_EQ(absl::nullopt, key1.ToCacheKeyString()); + EXPECT_EQ(site.GetDebugString() + " " + opaque_site.GetDebugString(), + key1.ToDebugString()); NetworkIsolationKey key2(opaque_site, site); EXPECT_TRUE(key2.IsFullyPopulated()); EXPECT_TRUE(key2.IsTransient()); EXPECT_EQ(absl::nullopt, key2.ToCacheKeyString()); - if (ForceIsolationInfoFrameOriginToTopLevelFrameEnabled()) { - EXPECT_EQ(opaque_site.GetDebugString() + " null", key2.ToDebugString()); - } else { - EXPECT_EQ(opaque_site.GetDebugString() + " " + site.GetDebugString(), - key2.ToDebugString()); - } + EXPECT_EQ(opaque_site.GetDebugString() + " " + site.GetDebugString(), + key2.ToDebugString()); } -TEST_P(NetworkIsolationKeyTest, ValueRoundTripEmpty) { +TEST(NetworkIsolationKeyTest, ValueRoundTripEmpty) { const SchemefulSite kJunkSite = SchemefulSite(GURL("data:text/html,junk")); // Convert empty key to value and back, expecting the same value. @@ -242,7 +188,7 @@ EXPECT_EQ(no_frame_site_key, out_key); } -TEST_P(NetworkIsolationKeyTest, ValueRoundTripNonEmpty) { +TEST(NetworkIsolationKeyTest, ValueRoundTripNonEmpty) { const SchemefulSite kJunkSite = SchemefulSite(GURL("data:text/html,junk")); NetworkIsolationKey key1(SchemefulSite(GURL("https://foo.test/")), @@ -256,7 +202,7 @@ EXPECT_EQ(key1, key2); } -TEST_P(NetworkIsolationKeyTest, ToValueTransientSite) { +TEST(NetworkIsolationKeyTest, ToValueTransientSite) { const SchemefulSite kSiteWithTransientOrigin = SchemefulSite(GURL("data:text/html,transient")); NetworkIsolationKey key(kSiteWithTransientOrigin, kSiteWithTransientOrigin); @@ -265,7 +211,7 @@ EXPECT_FALSE(key.ToValue(&value)); } -TEST_P(NetworkIsolationKeyTest, FromValueBadData) { +TEST(NetworkIsolationKeyTest, FromValueBadData) { base::Value::List not_a_url_list; not_a_url_list.Append("not-a-url"); @@ -297,70 +243,47 @@ NetworkIsolationKey key; base::Value triple_key_case(std::move(triple_key_list)); - // When double key is enabled top_level_site must equal frame_site. - bool expect_fail_on_different_sites = - ForceIsolationInfoFrameOriginToTopLevelFrameEnabled(); - - if (expect_fail_on_different_sites) { - EXPECT_FALSE(NetworkIsolationKey::FromValue(triple_key_case, &key)) - << triple_key_case; - } + EXPECT_FALSE(NetworkIsolationKey::FromValue(triple_key_case, &key)) + << triple_key_case; } -TEST_P(NetworkIsolationKeyTest, WithFrameSite) { +TEST(NetworkIsolationKeyTest, WithFrameSite) { NetworkIsolationKey key(SchemefulSite(GURL("http://b.test")), SchemefulSite(GURL("http://a.test/"))); EXPECT_TRUE(key.IsFullyPopulated()); EXPECT_FALSE(key.IsTransient()); - if (ForceIsolationInfoFrameOriginToTopLevelFrameEnabled()) { - EXPECT_EQ("http://b.test http://b.test", key.ToCacheKeyString()); - EXPECT_EQ("http://b.test null", key.ToDebugString()); - } else { - EXPECT_EQ("http://b.test http://a.test", key.ToCacheKeyString()); - EXPECT_EQ("http://b.test http://a.test", key.ToDebugString()); - } + EXPECT_EQ("http://b.test http://a.test", key.ToCacheKeyString()); + EXPECT_EQ("http://b.test http://a.test", key.ToDebugString()); EXPECT_TRUE(key == key); EXPECT_FALSE(key != key); EXPECT_FALSE(key < key); } -TEST_P(NetworkIsolationKeyTest, OpaqueSiteKey) { +TEST(NetworkIsolationKeyTest, OpaqueSiteKey) { SchemefulSite site_data = SchemefulSite(GURL(kDataUrl)); SchemefulSite site_data2 = SchemefulSite(GURL(kDataUrl)); SchemefulSite site_a = SchemefulSite(GURL("http://a.test")); NetworkIsolationKey key1(site_a, site_data); EXPECT_TRUE(key1.IsFullyPopulated()); - if (ForceIsolationInfoFrameOriginToTopLevelFrameEnabled()) { - EXPECT_FALSE(key1.IsTransient()); + EXPECT_TRUE(key1.IsTransient()); - EXPECT_EQ(NetworkIsolationKey(site_a, site_data2), key1); - EXPECT_EQ("http://a.test http://a.test", key1.ToCacheKeyString()); - EXPECT_EQ("http://a.test null", key1.ToDebugString()); - } else { - EXPECT_TRUE(key1.IsTransient()); - - EXPECT_EQ(absl::nullopt, key1.ToCacheKeyString()); - EXPECT_EQ("http://a.test " + site_data.GetDebugString(), - key1.ToDebugString()); - EXPECT_NE(NetworkIsolationKey(site_a, site_data2), key1); - } + EXPECT_EQ(absl::nullopt, key1.ToCacheKeyString()); + EXPECT_EQ("http://a.test " + site_data.GetDebugString(), + key1.ToDebugString()); + EXPECT_NE(NetworkIsolationKey(site_a, site_data2), key1); NetworkIsolationKey key2(site_data, site_a); EXPECT_TRUE(key2.IsFullyPopulated()); EXPECT_TRUE(key2.IsTransient()); EXPECT_EQ(absl::nullopt, key2.ToCacheKeyString()); - if (ForceIsolationInfoFrameOriginToTopLevelFrameEnabled()) { - EXPECT_EQ(site_data.GetDebugString() + " null", key2.ToDebugString()); - } else { - EXPECT_EQ(site_data.GetDebugString() + " http://a.test", - key2.ToDebugString()); - } + EXPECT_EQ(site_data.GetDebugString() + " http://a.test", + key2.ToDebugString()); EXPECT_NE(NetworkIsolationKey(site_data2, site_a), key2); } -TEST_P(NetworkIsolationKeyTest, OpaqueSiteKeyBoth) { +TEST(NetworkIsolationKeyTest, OpaqueSiteKeyBoth) { SchemefulSite site_data_1 = SchemefulSite(GURL(kDataUrl)); SchemefulSite site_data_2 = SchemefulSite(GURL(kDataUrl)); SchemefulSite site_data_3 = SchemefulSite(GURL(kDataUrl)); @@ -379,15 +302,9 @@ // Test the equality/comparisons of the various keys EXPECT_TRUE(key1 == key2); - if (ForceIsolationInfoFrameOriginToTopLevelFrameEnabled()) { - EXPECT_TRUE(key1 == key3); - EXPECT_FALSE(key1 < key3 || key3 < key1); - EXPECT_EQ(key1.ToDebugString(), key3.ToDebugString()); - } else { - EXPECT_FALSE(key1 == key3); - EXPECT_TRUE(key1 < key3 || key3 < key1); - EXPECT_NE(key1.ToDebugString(), key3.ToDebugString()); - } + EXPECT_FALSE(key1 == key3); + EXPECT_TRUE(key1 < key3 || key3 < key1); + EXPECT_NE(key1.ToDebugString(), key3.ToDebugString()); EXPECT_FALSE(key1 < key2 || key2 < key1); // Test the ToString and ToDebugString @@ -399,7 +316,7 @@ // Make sure that the logic to extract the registerable domain from an origin // does not affect the host when using a non-standard scheme. -TEST_P(NetworkIsolationKeyTest, NonStandardScheme) { +TEST(NetworkIsolationKeyTest, NonStandardScheme) { // Have to register the scheme, or SchemefulSite() will return an opaque // origin. url::ScopedSchemeRegistryForTests scoped_registry; @@ -411,22 +328,18 @@ EXPECT_EQ("foo://a.foo.com foo://a.foo.com", key.ToCacheKeyString()); } -TEST_P(NetworkIsolationKeyTest, CreateWithNewFrameSite) { +TEST(NetworkIsolationKeyTest, CreateWithNewFrameSite) { SchemefulSite site_a = SchemefulSite(GURL("http://a.com")); SchemefulSite site_b = SchemefulSite(GURL("http://b.com")); SchemefulSite site_c = SchemefulSite(GURL("http://c.com")); net::NetworkIsolationKey key(site_a, site_b); NetworkIsolationKey key_c = key.CreateWithNewFrameSite(site_c); - if (ForceIsolationInfoFrameOriginToTopLevelFrameEnabled()) { - EXPECT_DEATH_IF_SUPPORTED(key_c.GetFrameSite(), ""); - } else { - EXPECT_EQ(site_c, key_c.GetFrameSite()); - } + EXPECT_EQ(site_c, key_c.GetFrameSite()); EXPECT_EQ(site_a, key_c.GetTopFrameSite()); } -TEST_P(NetworkIsolationKeyTest, CreateTransient) { +TEST(NetworkIsolationKeyTest, CreateTransient) { NetworkIsolationKey transient_key = NetworkIsolationKey::CreateTransient(); EXPECT_TRUE(transient_key.IsFullyPopulated()); EXPECT_TRUE(transient_key.IsTransient()); @@ -443,13 +356,9 @@ } } -TEST(NetworkIsolationKeyFeatureShiftTest, ValueRoundTripDoubleToTriple) { - base::test::ScopedFeatureList scoped_feature_list_; +TEST(NetworkIsolationKeyFeatureShiftTest, ValueRoundTrip) { const SchemefulSite kJunkSite = SchemefulSite(GURL("data:text/html,junk")); - // Turn double keying off. - scoped_feature_list_.InitAndDisableFeature( - net::features::kForceIsolationInfoFrameOriginToTopLevelFrame); // Create a triple key. NetworkIsolationKey created_triple_key( SchemefulSite(GURL("https://foo.test/")), @@ -468,37 +377,6 @@ // Serialize a triple key value with frame site enabled. base::Value created_triple_key_value2; ASSERT_TRUE(created_triple_key.ToValue(&created_triple_key_value2)); - - // Turn double keying on. - scoped_feature_list_.Reset(); - scoped_feature_list_.InitAndEnableFeature( - net::features::kForceIsolationInfoFrameOriginToTopLevelFrame); - - // Create a key and confirm the frame site is correctly set to nullopt rather - // than https://bar.test/. - NetworkIsolationKey created_double_key( - SchemefulSite(GURL("https://foo.test/")), - SchemefulSite(GURL("https://bar.test/"))); - EXPECT_DEATH_IF_SUPPORTED(created_double_key.GetFrameSite(), ""); - - // Test round trip of key created when frame site was disabled. - base::Value created_double_key_value; - ASSERT_TRUE(created_double_key.ToValue(&created_double_key_value)); - // Fill initial value with junk data, to make sure it's overwritten. - NetworkIsolationKey created_double_key2(kJunkSite, kJunkSite); - EXPECT_TRUE(NetworkIsolationKey::FromValue(created_double_key_value, - &created_double_key2)); - EXPECT_EQ(created_double_key, created_double_key2); - - // Test round trip of key created with frame site enabled is now formed - // correctly as a double key. This key was serialized to value when frame site - // was enabled and should be able to be created from value without error. - NetworkIsolationKey created_triple_key3(kJunkSite, kJunkSite); - EXPECT_TRUE(NetworkIsolationKey::FromValue(created_triple_key_value2, - &created_triple_key3)); - // Triple key should be in a double key form with the frame site an empty - // optional. - EXPECT_EQ(created_double_key, created_triple_key3); } } // namespace
diff --git a/net/http/http_request_info_unittest.cc b/net/http/http_request_info_unittest.cc index bdffaa0..a144364 100644 --- a/net/http/http_request_info_unittest.cc +++ b/net/http/http_request_info_unittest.cc
@@ -25,27 +25,8 @@ // Triple key NIK and double key NAK. base::test::ScopedFeatureList scoped_feature_list_; scoped_feature_list_.Reset(); - std::vector<base::test::FeatureRef> enabled_features_3 = {}; - std::vector<base::test::FeatureRef> disabled_features_3 = {}; - disabled_features_3.push_back( - net::features::kForceIsolationInfoFrameOriginToTopLevelFrame); - disabled_features_3.push_back( + scoped_feature_list_.InitAndDisableFeature( net::features::kEnableCrossSiteFlagNetworkAnonymizationKey); - scoped_feature_list_.InitWithFeatures(enabled_features_3, - disabled_features_3); - - EXPECT_FALSE(triple_nik_double_nak_request_info.IsConsistent()); - - // Triple key NIK and double key with cross site flag NAK. - scoped_feature_list_.Reset(); - std::vector<base::test::FeatureRef> enabled_features_4 = {}; - std::vector<base::test::FeatureRef> disabled_features_4 = {}; - disabled_features_3.push_back( - net::features::kForceIsolationInfoFrameOriginToTopLevelFrame); - enabled_features_4.push_back( - net::features::kEnableCrossSiteFlagNetworkAnonymizationKey); - scoped_feature_list_.InitWithFeatures(enabled_features_4, - disabled_features_4); EXPECT_FALSE(triple_nik_double_nak_request_info.IsConsistent());
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc index f601bc32..d8a684f 100644 --- a/net/url_request/url_request_unittest.cc +++ b/net/url_request/url_request_unittest.cc
@@ -12886,11 +12886,8 @@ TEST_F(URLRequestTest, SetIsolationInfoFromNakTripleNikDoublePlusCrossSiteBitNak) { base::test::ScopedFeatureList scoped_feature_list_; - std::vector<base::test::FeatureRef> enabled_features = { - net::features::kEnableCrossSiteFlagNetworkAnonymizationKey}; - std::vector<base::test::FeatureRef> disabled_features = { - net::features::kForceIsolationInfoFrameOriginToTopLevelFrame}; - scoped_feature_list_.InitWithFeatures(enabled_features, disabled_features); + scoped_feature_list_.InitAndEnableFeature( + net::features::kEnableCrossSiteFlagNetworkAnonymizationKey); TestDelegate d; SchemefulSite site_a = SchemefulSite(GURL("https://a.com/")); @@ -12948,70 +12945,11 @@ r->Start(); d.RunUntilComplete(); } -TEST_F(URLRequestTest, SetIsolationInfoFromNakDoubleNikDoubleNak) { - base::test::ScopedFeatureList scoped_feature_list_; - std::vector<base::test::FeatureRef> enabled_features = { - net::features::kForceIsolationInfoFrameOriginToTopLevelFrame}; - std::vector<base::test::FeatureRef> disabled_features = { - net::features::kEnableCrossSiteFlagNetworkAnonymizationKey}; - scoped_feature_list_.InitWithFeatures(enabled_features, disabled_features); - - TestDelegate d; - SchemefulSite site_a = SchemefulSite(GURL("https://a.com/")); - SchemefulSite site_b = SchemefulSite(GURL("https://b.com/")); - base::UnguessableToken nak_nonce = base::UnguessableToken::Create(); - NetworkAnonymizationKey populated_cross_site_nak(site_a, site_b, true, - nak_nonce); - NetworkAnonymizationKey populated_same_site_nak(site_a, site_a, false, - nak_nonce); - // Frame site should be set to the top level sites value even though NAK is - // double keyed. - IsolationInfo expected_isolation_info_populated_same_site_nak = - IsolationInfo::Create(IsolationInfo::RequestType::kOther, - url::Origin::Create(GURL("https://a.com/")), - url::Origin::Create(GURL("https://a.com/")), - SiteForCookies(), - /*party_context=*/absl::nullopt, &nak_nonce); - NetworkAnonymizationKey empty_nak; - - GURL original_url("http://localhost"); - std::unique_ptr<URLRequest> r(default_context().CreateRequest( - original_url, DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS)); - - r->set_isolation_info_from_network_anonymization_key( - populated_cross_site_nak); - r->SetLoadFlags(LOAD_DISABLE_CACHE); - r->set_allow_credentials(false); - EXPECT_TRUE(r->is_created_from_network_anonymization_key()); - EXPECT_EQ(r->isolation_info().network_anonymization_key(), - populated_cross_site_nak); - // We do not know the frame_site other than that it will be cross site. - EXPECT_EQ(r->isolation_info().top_frame_origin(), - url::Origin::Create(GURL("https://a.com/"))); - - r->set_isolation_info_from_network_anonymization_key(populated_same_site_nak); - EXPECT_TRUE(r->is_created_from_network_anonymization_key()); - EXPECT_EQ(r->isolation_info().network_anonymization_key(), - populated_same_site_nak); - EXPECT_TRUE(r->isolation_info().IsEqualForTesting( - expected_isolation_info_populated_same_site_nak)); - - r->set_isolation_info_from_network_anonymization_key(empty_nak); - EXPECT_TRUE(r->is_created_from_network_anonymization_key()); - EXPECT_TRUE(r->load_flags() & LOAD_DISABLE_CACHE); - EXPECT_EQ(r->isolation_info().network_anonymization_key(), empty_nak); - EXPECT_TRUE(r->isolation_info().IsEqualForTesting(net::IsolationInfo())); - r->Start(); - d.RunUntilComplete(); -} TEST_F(URLRequestTest, SetIsolationInfoFromNakTripleNikDoubleNak) { base::test::ScopedFeatureList scoped_feature_list_; - std::vector<base::test::FeatureRef> enabled_features = {}; - std::vector<base::test::FeatureRef> disabled_features = { - net::features::kForceIsolationInfoFrameOriginToTopLevelFrame, - net::features::kEnableCrossSiteFlagNetworkAnonymizationKey}; - scoped_feature_list_.InitWithFeatures(enabled_features, disabled_features); + scoped_feature_list_.InitAndDisableFeature( + net::features::kEnableCrossSiteFlagNetworkAnonymizationKey); TestDelegate d; SchemefulSite site_a = SchemefulSite(GURL("https://a.com/")); @@ -13068,11 +13006,8 @@ TEST_F(URLRequestTest, SetIsolationInfoFromNakTripleNikDoubleWithCrossSiteFlagNak) { base::test::ScopedFeatureList scoped_feature_list_; - std::vector<base::test::FeatureRef> enabled_features = { - net::features::kEnableCrossSiteFlagNetworkAnonymizationKey}; - std::vector<base::test::FeatureRef> disabled_features = { - net::features::kForceIsolationInfoFrameOriginToTopLevelFrame}; - scoped_feature_list_.InitWithFeatures(enabled_features, disabled_features); + scoped_feature_list_.InitAndEnableFeature( + net::features::kEnableCrossSiteFlagNetworkAnonymizationKey); TestDelegate d; SchemefulSite site_a = SchemefulSite(GURL("https://a.com/")); @@ -13239,26 +13174,23 @@ namespace { +// `EnabledFeatureFlagsTestingParam ` allows enabling and disabling +// the feature flags that control the key schemes for NetworkAnonymizationKey. +// This allows us to test the possible combinations of flags that will be +// allowed for experimentation. +// +// Presently, only one flag is used, but future experiments will add more. struct EnabledFeatureFlagsTestingParam { + // True = 2.5-keyed NAK, false = double-keyed NAK. const bool enable_cross_site_flag_network_anonymization_key; - const bool enable_double_key_network_isolation_key; }; const EnabledFeatureFlagsTestingParam kFlagsParam[] = { - // 0. Double-keying is enabled for both IsolationInfo and - // NetworkAnonymizationKey. - {/*enable_cross_site_flag_network_anonymization_key=*/false, - /*enable_double_key_network_isolation_key=*/true}, + // 0. Double-keying is enabled for NetworkAnonymizationKey. + {/*enable_cross_site_flag_network_anonymization_key=*/false}, - // 1. Triple-keying is enabled for IsolationInfo and double-keying is - // enabled for NetworkAnonymizationKey. - {/*enable_cross_site_flag_network_anonymization_key=*/false, - /*enable_double_key_network_isolation_key=*/false}, - - // 2. Triple-keying is enabled for IsolationInfo and double-keying + - // cross-site-bit is enabled for NetworkAnonymizationKey. - {/*enable_cross_site_flag_network_anonymization_key=*/true, - /*enable_double_key_network_isolation_key=*/false}}; + // 1. Double-keying + cross-site-bit is enabled for NetworkAnonymizationKey. + {/*enable_cross_site_flag_network_anonymization_key=*/true}}; } // namespace @@ -13272,14 +13204,6 @@ net::features::kPartitionSSLSessionsByNetworkIsolationKey}; std::vector<base::test::FeatureRef> disabled_features = {}; - if (IsDoubleKeyNetworkIsolationKeyEnabled()) { - enabled_features.push_back( - net::features::kForceIsolationInfoFrameOriginToTopLevelFrame); - } else { - disabled_features.push_back( - net::features::kForceIsolationInfoFrameOriginToTopLevelFrame); - } - if (IsCrossSiteFlagEnabled()) { enabled_features.push_back( net::features::kEnableCrossSiteFlagNetworkAnonymizationKey); @@ -13291,10 +13215,6 @@ scoped_feature_list_.InitWithFeatures(enabled_features, disabled_features); } - bool IsDoubleKeyNetworkIsolationKeyEnabled() const { - return GetParam().enable_double_key_network_isolation_key; - } - bool IsCrossSiteFlagEnabled() const { return GetParam().enable_cross_site_flag_network_anonymization_key; }
diff --git a/remoting/base/BUILD.gn b/remoting/base/BUILD.gn index d31748c..e390acc5 100644 --- a/remoting/base/BUILD.gn +++ b/remoting/base/BUILD.gn
@@ -166,6 +166,7 @@ if (is_mac) { sources += [ "breakpad_mac.mm" ] deps += [ "//third_party/breakpad" ] + frameworks = [ "Foundation.framework" ] } if (is_win) {
diff --git a/sandbox/policy/features.cc b/sandbox/policy/features.cc index 00bf6861..b060d9d 100644 --- a/sandbox/policy/features.cc +++ b/sandbox/policy/features.cc
@@ -74,7 +74,7 @@ // as controlled by CanCacheSandboxPolicy(). BASE_FEATURE(kCacheMacSandboxProfiles, "CacheMacSandboxProfiles", - base::FEATURE_DISABLED_BY_DEFAULT); + base::FEATURE_ENABLED_BY_DEFAULT); #endif // BUILDFLAG(IS_MAC) bool IsNetworkSandboxEnabled() {
diff --git a/services/network/public/cpp/isolation_info_mojom_traits.h b/services/network/public/cpp/isolation_info_mojom_traits.h index a3173d52..376c5cea 100644 --- a/services/network/public/cpp/isolation_info_mojom_traits.h +++ b/services/network/public/cpp/isolation_info_mojom_traits.h
@@ -44,10 +44,10 @@ static const absl::optional<url::Origin>& frame_origin( const net::IsolationInfo& input) { - return base::FeatureList::IsEnabled( - net::features::kForceIsolationInfoFrameOriginToTopLevelFrame) - ? input.top_frame_origin() - : input.frame_origin(); + // This is trivially true right now, but crbug.com/1414808 will involve + // an experiment where this may be false. + CHECK(net::IsolationInfo::IsFrameSiteEnabled()); + return input.frame_origin(); } static const absl::optional<base::UnguessableToken>& nonce(
diff --git a/services/network/public/cpp/network_switches.cc b/services/network/public/cpp/network_switches.cc index f774c06a8..718d5eb 100644 --- a/services/network/public/cpp/network_switches.cc +++ b/services/network/public/cpp/network_switches.cc
@@ -17,6 +17,8 @@ // causing them to attempt an unauthenticated SSL/TLS session. This is intended // for use when testing various service URLs (eg: kPromoServerURL, kSbURLPrefix, // kSyncServiceURL, etc). +// TODO(crbug.com/1417189): Remove this flag if the alternative solution +// implemented for crbug.com/1221565 covers all needs. const char kIgnoreUrlFetcherCertRequests[] = "ignore-urlfetcher-cert-requests"; // A set of public key hashes for which to ignore certificate-related errors.
diff --git a/sql/README.md b/sql/README.md index 999ad05..1423bee3 100644 --- a/sql/README.md +++ b/sql/README.md
@@ -151,7 +151,7 @@ storage costs. This is because indexes for `WITHOUT ROWID` tables enjoy [a space optimization](https://sqlite.org/fileformat2.html#representation_of_sql_indices) where columns in both the primary key and the index key are not stored twice in -B-tree nodes. +B-tree nodes. Note that data in such tables cannot be recovered by `sql::Recovery`. ### Statement execution model {#query-model}
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json index 76b4a0a..676de0d9 100644 --- a/testing/buildbot/chromium.chromiumos.json +++ b/testing/buildbot/chromium.chromiumos.json
@@ -5818,9 +5818,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v112.0.5609.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v112.0.5610.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 112.0.5609.0", + "description": "Run with ash-chrome version 112.0.5610.0", "isolate_profile_data": true, "merge": { "args": [], @@ -5832,8 +5832,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v112.0.5609.0", - "revision": "version:112.0.5609.0" + "location": "lacros_version_skew_tests_v112.0.5610.0", + "revision": "version:112.0.5610.0" } ], "dimension_sets": [ @@ -5989,9 +5989,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v112.0.5609.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v112.0.5610.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 112.0.5609.0", + "description": "Run with ash-chrome version 112.0.5610.0", "isolate_profile_data": true, "merge": { "args": [], @@ -6003,8 +6003,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v112.0.5609.0", - "revision": "version:112.0.5609.0" + "location": "lacros_version_skew_tests_v112.0.5610.0", + "revision": "version:112.0.5610.0" } ], "dimension_sets": [ @@ -6141,9 +6141,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v112.0.5609.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v112.0.5610.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 112.0.5609.0", + "description": "Run with ash-chrome version 112.0.5610.0", "isolate_profile_data": true, "merge": { "args": [], @@ -6155,8 +6155,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v112.0.5609.0", - "revision": "version:112.0.5609.0" + "location": "lacros_version_skew_tests_v112.0.5610.0", + "revision": "version:112.0.5610.0" } ], "dimension_sets": [
diff --git a/testing/buildbot/chromium.coverage.json b/testing/buildbot/chromium.coverage.json index 256dabe..890832a 100644 --- a/testing/buildbot/chromium.coverage.json +++ b/testing/buildbot/chromium.coverage.json
@@ -20507,9 +20507,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v112.0.5609.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v112.0.5610.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 112.0.5609.0", + "description": "Run with ash-chrome version 112.0.5610.0", "isolate_profile_data": true, "merge": { "args": [], @@ -20521,8 +20521,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v112.0.5609.0", - "revision": "version:112.0.5609.0" + "location": "lacros_version_skew_tests_v112.0.5610.0", + "revision": "version:112.0.5610.0" } ], "dimension_sets": [ @@ -20678,9 +20678,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v112.0.5609.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v112.0.5610.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 112.0.5609.0", + "description": "Run with ash-chrome version 112.0.5610.0", "isolate_profile_data": true, "merge": { "args": [], @@ -20692,8 +20692,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v112.0.5609.0", - "revision": "version:112.0.5609.0" + "location": "lacros_version_skew_tests_v112.0.5610.0", + "revision": "version:112.0.5610.0" } ], "dimension_sets": [ @@ -20830,9 +20830,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v112.0.5609.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v112.0.5610.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 112.0.5609.0", + "description": "Run with ash-chrome version 112.0.5610.0", "isolate_profile_data": true, "merge": { "args": [], @@ -20844,8 +20844,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v112.0.5609.0", - "revision": "version:112.0.5609.0" + "location": "lacros_version_skew_tests_v112.0.5610.0", + "revision": "version:112.0.5610.0" } ], "dimension_sets": [
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json index 28ddee73..304d551 100644 --- a/testing/buildbot/chromium.fyi.json +++ b/testing/buildbot/chromium.fyi.json
@@ -57176,9 +57176,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v112.0.5609.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v112.0.5610.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 112.0.5609.0", + "description": "Run with ash-chrome version 112.0.5610.0", "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -57189,8 +57189,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v112.0.5609.0", - "revision": "version:112.0.5609.0" + "location": "lacros_version_skew_tests_v112.0.5610.0", + "revision": "version:112.0.5610.0" } ], "dimension_sets": [ @@ -57347,9 +57347,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v112.0.5609.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v112.0.5610.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 112.0.5609.0", + "description": "Run with ash-chrome version 112.0.5610.0", "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -57360,8 +57360,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v112.0.5609.0", - "revision": "version:112.0.5609.0" + "location": "lacros_version_skew_tests_v112.0.5610.0", + "revision": "version:112.0.5610.0" } ], "dimension_sets": [ @@ -57499,9 +57499,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v112.0.5609.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v112.0.5610.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 112.0.5609.0", + "description": "Run with ash-chrome version 112.0.5610.0", "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -57512,8 +57512,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v112.0.5609.0", - "revision": "version:112.0.5609.0" + "location": "lacros_version_skew_tests_v112.0.5610.0", + "revision": "version:112.0.5610.0" } ], "dimension_sets": [ @@ -59037,9 +59037,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v112.0.5609.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v112.0.5610.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 112.0.5609.0", + "description": "Run with ash-chrome version 112.0.5610.0", "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -59050,8 +59050,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v112.0.5609.0", - "revision": "version:112.0.5609.0" + "location": "lacros_version_skew_tests_v112.0.5610.0", + "revision": "version:112.0.5610.0" } ], "dimension_sets": [ @@ -59208,9 +59208,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v112.0.5609.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v112.0.5610.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 112.0.5609.0", + "description": "Run with ash-chrome version 112.0.5610.0", "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -59221,8 +59221,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v112.0.5609.0", - "revision": "version:112.0.5609.0" + "location": "lacros_version_skew_tests_v112.0.5610.0", + "revision": "version:112.0.5610.0" } ], "dimension_sets": [ @@ -59360,9 +59360,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v112.0.5609.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v112.0.5610.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 112.0.5609.0", + "description": "Run with ash-chrome version 112.0.5610.0", "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -59373,8 +59373,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v112.0.5609.0", - "revision": "version:112.0.5609.0" + "location": "lacros_version_skew_tests_v112.0.5610.0", + "revision": "version:112.0.5610.0" } ], "dimension_sets": [ @@ -60146,9 +60146,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v112.0.5609.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v112.0.5610.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 112.0.5609.0", + "description": "Run with ash-chrome version 112.0.5610.0", "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -60159,8 +60159,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v112.0.5609.0", - "revision": "version:112.0.5609.0" + "location": "lacros_version_skew_tests_v112.0.5610.0", + "revision": "version:112.0.5610.0" } ], "dimension_sets": [
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json index 445204e..121f628 100644 --- a/testing/buildbot/chromium.memory.json +++ b/testing/buildbot/chromium.memory.json
@@ -18533,12 +18533,12 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v112.0.5609.0/test_ash_chrome", + "--ash-chrome-path-override=../../lacros_version_skew_tests_v112.0.5610.0/test_ash_chrome", "--test-launcher-print-test-stdio=always", "--combine-ash-logs-on-bots", "--asan-symbolize-output" ], - "description": "Run with ash-chrome version 112.0.5609.0", + "description": "Run with ash-chrome version 112.0.5610.0", "isolate_profile_data": true, "merge": { "args": [], @@ -18550,8 +18550,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v112.0.5609.0", - "revision": "version:112.0.5609.0" + "location": "lacros_version_skew_tests_v112.0.5610.0", + "revision": "version:112.0.5610.0" } ], "dimension_sets": [ @@ -18724,12 +18724,12 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v112.0.5609.0/test_ash_chrome", + "--ash-chrome-path-override=../../lacros_version_skew_tests_v112.0.5610.0/test_ash_chrome", "--test-launcher-print-test-stdio=always", "--combine-ash-logs-on-bots", "--asan-symbolize-output" ], - "description": "Run with ash-chrome version 112.0.5609.0", + "description": "Run with ash-chrome version 112.0.5610.0", "isolate_profile_data": true, "merge": { "args": [], @@ -18741,8 +18741,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v112.0.5609.0", - "revision": "version:112.0.5609.0" + "location": "lacros_version_skew_tests_v112.0.5610.0", + "revision": "version:112.0.5610.0" } ], "dimension_sets": [ @@ -18891,12 +18891,12 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v112.0.5609.0/test_ash_chrome", + "--ash-chrome-path-override=../../lacros_version_skew_tests_v112.0.5610.0/test_ash_chrome", "--test-launcher-print-test-stdio=always", "--combine-ash-logs-on-bots", "--asan-symbolize-output" ], - "description": "Run with ash-chrome version 112.0.5609.0", + "description": "Run with ash-chrome version 112.0.5610.0", "isolate_profile_data": true, "merge": { "args": [], @@ -18908,8 +18908,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v112.0.5609.0", - "revision": "version:112.0.5609.0" + "location": "lacros_version_skew_tests_v112.0.5610.0", + "revision": "version:112.0.5610.0" } ], "dimension_sets": [
diff --git a/testing/buildbot/variants.pyl b/testing/buildbot/variants.pyl index be7c7d3..9bde9c7 100644 --- a/testing/buildbot/variants.pyl +++ b/testing/buildbot/variants.pyl
@@ -22,16 +22,16 @@ }, 'LACROS_VERSION_SKEW_CANARY': { 'args': [ - '--ash-chrome-path-override=../../lacros_version_skew_tests_v112.0.5609.0/test_ash_chrome', + '--ash-chrome-path-override=../../lacros_version_skew_tests_v112.0.5610.0/test_ash_chrome', ], - 'description': 'Run with ash-chrome version 112.0.5609.0', + 'description': 'Run with ash-chrome version 112.0.5610.0', 'identifier': 'Lacros version skew testing ash canary', 'swarming': { 'cipd_packages': [ { 'cipd_package': 'chromium/testing/linux-ash-chromium/x86_64/ash.zip', - 'location': 'lacros_version_skew_tests_v112.0.5609.0', - 'revision': 'version:112.0.5609.0', + 'location': 'lacros_version_skew_tests_v112.0.5610.0', + 'revision': 'version:112.0.5610.0', }, ], },
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index a2941ac..83748b8 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -8690,9 +8690,7 @@ "PartitionSSLSessionsByNetworkIsolationKey", "SplitHostCacheByNetworkIsolationKey" ], - "disable_features": [ - "ForceIsolationInfoFrameOriginToTopLevelFrame" - ] + "disable_features": [] } ] }
diff --git a/third_party/blink/tools/blinkpy/tool/commands/update_metadata.py b/third_party/blink/tools/blinkpy/tool/commands/update_metadata.py index d25361100..58956b7 100644 --- a/third_party/blink/tools/blinkpy/tool/commands/update_metadata.py +++ b/third_party/blink/tools/blinkpy/tool/commands/update_metadata.py
@@ -48,6 +48,7 @@ path_finder.bootstrap_wpt_imports() from manifest import manifest as wptmanifest from wptrunner import manifestupdate, metadata, testloader, wpttest +from wptrunner.wptmanifest import node as wptnode from wptrunner.wptmanifest.backends import conditional from wptrunner.wptmanifest.parser import ParseError @@ -738,6 +739,7 @@ if modified: if self._bug: self._add_bug_url(expected) + sort_metadata_ast(expected.node) if not self._dry_run: metadata.write_new_expected(test_file.metadata_path, expected) return modified @@ -748,6 +750,29 @@ test_id_section.set('bug', 'crbug.com/%d' % self._bug) +def sort_metadata_ast(node: wptnode.DataNode) -> None: + """Sort the metadata abstract syntax tree to create a stable rendering. + + Since keys/sections are identified by unique names within their block, their + ordering within the file do not matter. Sorting avoids creating spurious + diffs after serialization. + + Note: + This mutates the given node. Create a copy with `node.copy()` if you + wish to keep the original. + """ + assert all( + isinstance(child, (wptnode.DataNode, wptnode.KeyValueNode)) + for child in node.children), node + # Put keys first, then child sections. Keys and child sections are sorted + # alphabetically within their respective groups. + node.children.sort(key=lambda child: (bool( + isinstance(child, wptnode.DataNode)), child.data or '')) + for child in node.children: + if isinstance(child, wptnode.DataNode): + sort_metadata_ast(child) + + def _compose(f, g): return lambda *args, **kwargs: f(g(*args, **kwargs))
diff --git a/third_party/blink/tools/blinkpy/tool/commands/update_metadata_unittest.py b/third_party/blink/tools/blinkpy/tool/commands/update_metadata_unittest.py index 776ccc2..5d24ab6 100644 --- a/third_party/blink/tools/blinkpy/tool/commands/update_metadata_unittest.py +++ b/third_party/blink/tools/blinkpy/tool/commands/update_metadata_unittest.py
@@ -19,12 +19,13 @@ UpdateMetadata, MetadataUpdater, load_and_update_manifests, + sort_metadata_ast, ) from blinkpy.web_tests.builder_list import BuilderList path_finder.bootstrap_wpt_imports() from manifest.manifest import Manifest -from wptrunner import metadata +from wptrunner import metadata, wptmanifest class BaseUpdateMetadataTest(LoggingTestCase): @@ -1107,6 +1108,43 @@ expected: FAIL """) + def test_stable_rendering(self): + buf = io.BytesIO( + textwrap.dedent("""\ + [variant.html?foo=baz] + [subtest 2] + expected: + if os == "win": FAIL + if os == "mac": FAIL + disabled: @False + [subtest 1] + expected: [OK, CRASH] + + bug: crbug.com/123 + + [variant.html?foo=bar/abc] + """).encode()) + ast = wptmanifest.parse(buf) + sort_metadata_ast(ast) + # Unlike keys/sections, the ordering of conditions is significant, so + # they should not be sorted. + self.assertEqual( + wptmanifest.serialize(ast), + textwrap.dedent("""\ + bug: crbug.com/123 + [variant.html?foo=bar/abc] + + [variant.html?foo=baz] + expected: [OK, CRASH] + [subtest 1] + + [subtest 2] + disabled: @False + expected: + if os == "win": FAIL + if os == "mac": FAIL + """)) + class UpdateMetadataArgumentParsingTest(unittest.TestCase): def setUp(self):
diff --git a/third_party/blink/tools/run_wpt_tests.py b/third_party/blink/tools/run_wpt_tests.py index dcf2f340f..470c209 100755 --- a/third_party/blink/tools/run_wpt_tests.py +++ b/third_party/blink/tools/run_wpt_tests.py
@@ -15,6 +15,7 @@ import re import shutil import sys +import warnings from typing import List, Optional, Tuple from blinkpy.common import exit_codes @@ -32,9 +33,9 @@ import mozlog from scripts import common -from wptrunner import wptcommandline +from wptrunner import wptcommandline, wptlogging -logger = logging.getLogger(__name__) +logger = logging.getLogger('run_wpt_tests') UPSTREAM_GIT_URL = 'https://github.com/web-platform-tests/wpt.git' @@ -50,10 +51,44 @@ from pylib.local.emulator import avd _ANDROID_ENABLED = True except ImportError: - logger.warning('Android tools not found') _ANDROID_ENABLED = False +def _make_log_enabled_grouping_formatter(): + # Make a grouping log formatter that shows regular log messages: + # WARNING Unsupported test type wdspec for product content_shell + # + # Activating logs dynamically with: + # StructuredLogger.send_message('show_logs', 'on') + # appears buggy. This factory exists as a workaround. + grouping_formatter = mozlog.formatters.GroupingFormatter() + grouping_formatter.message_handler.handle_message('show_logs', 'on') + return grouping_formatter + + +mozlog.commandline.log_formatters['grouped'] = ( + _make_log_enabled_grouping_formatter, + mozlog.commandline.log_formatters['grouped'][1], +) + + +class StructuredLogAdapter(logging.Handler): + def __init__(self, logger, *args, **kwargs): + super().__init__(*args, **kwargs) + self._logger = logger + self._fallback_handler = logging.StreamHandler() + self._fallback_handler.setFormatter( + logging.Formatter('%(name)s %(levelname)s %(message)s')) + + def emit(self, record): + log = getattr(self._logger, record.levelname.lower(), + self._logger.debug) + try: + log(record.getMessage(), component=record.name) + except mozlog.structuredlog.LoggerShutdownError: + self._fallback_handler.emit(record) + + PARAMETER_DENYLIST = { # Parameters specific to non-Chromium vendors. '--prefs-root', @@ -184,6 +219,8 @@ self.add_configuration_arguments(parser) if _ANDROID_ENABLED: self.add_android_arguments(parser) + else: + warnings.warn('Android tools not found') # Nightly installation is not supported, so just add defaults. parser.set_defaults( prompt=False, @@ -196,8 +233,9 @@ def _check_and_update_options(self, options): """Postprocess options, some of which can depend on each other.""" - self._check_and_update_upstream_options(options) + # Set up logging as early as possible. self._check_and_update_output_options(options) + self._check_and_update_upstream_options(options) self._check_and_update_config_options(options) self._check_and_update_sharding_options(options) # TODO(crbug/1316055): Enable tombstone with '--stackwalk-binary' and @@ -213,25 +251,17 @@ options.manifest_download = False def _check_and_update_output_options(self, options): - if options.verbose >= 2: + if options.verbose >= 1: options.log_mach = '-' options.log_mach_level = 'info' options.log_mach_verbose = True - if options.verbose >= 3: + if options.verbose >= 2: options.log_mach_level = 'debug' - if options.verbose >= 4: + if options.verbose >= 3: options.webdriver_args.extend([ '--verbose', '--log-path=-', ]) - # Set up logging within `run_wpt_tests` as soon as possible. - # TODO(crbug.com/1356318): Pipe stdlib `logging` records into `mozlog` - # for a unified output format. - logging.basicConfig( - level=self.log_level(options), - # Align level name for easier reading. - format='%(asctime)s [%(levelname)-8s] %(name)s: %(message)s', - force=True) output_dir = self.path_from_output_dir(options.target) if not self.fs.isdir(output_dir): @@ -252,6 +282,11 @@ filename = self.fs.abspath(filename) setattr(options, dest, [mozlog.commandline.log_file(filename)]) + options.log = wptlogging.setup(dict(vars(options)), + {'grouped': sys.stdout}) + logging.root.handlers.clear() + logging.root.addHandler(StructuredLogAdapter(options.log)) + def _check_and_update_config_options(self, options: argparse.Namespace): options.webdriver_args.extend([ '--enable-chrome-logs', @@ -269,8 +304,15 @@ '--force-fieldtrial-params=' 'DownloadServiceStudy.Enabled:start_up_delay_ms/0', ]) - if _has_explicit_tests(options): - options.retry_unexpected = 0 + if options.retry_unexpected is None: + if _has_explicit_tests(options): + options.retry_unexpected = 0 + logger.warning('Tests explicitly specified; disabling retries') + else: + options.retry_unexpected = 3 + logger.warning( + 'Tests not explicitly specified; ' + 'using %d retries', options.retry_unexpected) if not options.mojojs_path: options.mojojs_path = self.path_from_output_dir( options.target, 'gen') @@ -280,10 +322,19 @@ if options.flag_specific: configs = self.port.flag_specific_configs() args, smoke_file_name = configs[options.flag_specific] + logger.info('Running with flag-specific arguments: "%s"', + ' '.join(args)) options.binary_args.extend(args) if smoke_file_name and not _has_explicit_tests(options): options.include_file = self.path_finder.path_from_web_tests( smoke_file_name) + logger.info( + 'Tests not explicitly specified; ' + 'running tests from web_tests/%s', smoke_file_name) + elif smoke_file_name: + logger.warning( + 'Tests explicitly specified; ' + 'not running tests from web_tests/%s', smoke_file_name) def _check_and_update_upstream_options(self, options: argparse.Namespace): if options.use_upstream_wpt: @@ -312,9 +363,8 @@ options.this_chunk = self._shard_index + 1 if self._total_shards is not None: options.total_chunks = self._total_shards - if options.this_chunk and options.total_chunks: - logger.info('Selecting tests for shard %d/%d', options.this_chunk, - options.total_chunks) + logger.info('Selecting tests for shard %d/%d', options.this_chunk, + options.total_chunks) # The default sharding strategy is to shard by directory. But # we want to hash each test to determine which shard runs it. # This allows running individual directories that have few @@ -324,13 +374,6 @@ def path_from_output_dir(self, *parts): return self.path_finder.path_from_chromium_base('out', *parts) - def log_level(self, options): - if options.verbose >= 2: - return logging.DEBUG - if options.verbose >= 1: - return logging.INFO - return logging.WARNING - def run_tests(self, options: argparse.Namespace) -> int: with contextlib.ExitStack() as stack: tmp_dir = stack.enter_context(self.fs.mkdtemp()) @@ -500,7 +543,7 @@ '--isolated-script-test-launcher-retry-limit', metavar='RETRIES', type=lambda value: max(0, int(value)), - default=3, + default=None, help=( 'Maximum number of times to rerun unexpectedly failed tests. ' 'Defaults to 3 unless given an explicit list of tests to run.'
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index d588c9da..35b157e3 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -6742,6 +6742,8 @@ # Test is flaky because of test_driver.bless, see crbug.com/1066891 crbug.com/1382865 external/wpt/storage-access-api/requestStorageAccess-cross-origin-iframe.sub.https.window.html [ Failure Pass ] crbug.com/1382865 external/wpt/storage-access-api/requestStorageAccess-nested-cross-origin-iframe.sub.https.window.html [ Failure Pass ] +crbug.com/1382865 external/wpt/storage-access-api/requestStorageAccess-cross-site-iframe.sub.https.window.html [ Failure Pass ] +crbug.com/1382865 external/wpt/storage-access-api/requestStorageAccess-nested-cross-site-iframe.sub.https.window.html [ Failure Pass ] # Test is not yet supported in Chrome. crbug.com/1382865 external/wpt/storage-access-api/requestStorageAccess-cross-origin-sibling-iframes.sub.https.window.html [ Failure Pass ]
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json index 9b54939..aafc75b 100644 --- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json +++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
@@ -264645,16 +264645,6 @@ } }, "support": { - ".cache": { - "gitignore2.json": [ - "24658fcbb8b2f7366ccd91bb977cd3be4719da28", - [] - ], - "mtime.json": [ - "9e6b268c357c24b113ae363db36beb76cb116c89", - [] - ] - }, ".gitignore": [ "d93e645d547894b50149d3726de2654957b6e06f", [] @@ -299309,43 +299299,11 @@ ], "image-set": { "image-set-computed.sub-expected.txt": [ - "78e0027cb8765b6d52250a4a0700b59c112c12b2", - [] - ], - "image-set-computed.sub.html.ini": [ - "f98353bade16d7c70dcaff09ac065b2ec1a928c5", - [] - ], - "image-set-conic-gradient-rendering.html.ini": [ - "95d9cf7bd8d5a0a27d177bc66e8c7c684deabb3d", - [] - ], - "image-set-linear-gradient-rendering.html.ini": [ - "b58c2976a5926a55ad3f1b4c57155c33405f8b0e", + "dfc5f32b1eb39996c178765b273c0c6a496dc9c7", [] ], "image-set-parsing-expected.txt": [ - "d2f52d3a8f54a0348c315c04a131391304492c8d", - [] - ], - "image-set-parsing.html.ini": [ - "936aabcf464f334c39966c22ce9863502b5fb42e", - [] - ], - "image-set-radial-gradient-rendering.html.ini": [ - "3fcaf7fed895cbcb82a8a8a3082a86283464619e", - [] - ], - "image-set-repeating-conic-gradient-rendering.html.ini": [ - "f18e1ef9a009dd1d0eb1c76f73654ab469925435", - [] - ], - "image-set-repeating-linear-gradient-rendering.html.ini": [ - "be70642abe0de6d1f01e5cea728d0475998f7177", - [] - ], - "image-set-repeating-radial-gradient-rendering.html.ini": [ - "cfb95cb1d12971431322dce97fd519cbf8c3d8b1", + "52390b2af587cee70e05b57e9800bf3e21c8bd3b", [] ], "image-set-resolution-001-ref.html": [ @@ -370882,7 +370840,7 @@ [] ], "mock-direct-sockets.js": [ - "0752850c8a383353c39320da4dc0d3b3df257129", + "e2e02453f7f4d446c528051fc44974878150b809", [] ], "mock-facedetection.js": [ @@ -659100,7 +659058,7 @@ }, "get_active_element": { "get.py": [ - "2b79ebd58485156573d5369372bfe6a8a1587a9f", + "1d2960c88c5f587bf2dea86f5b97ad1e5fae9b5c", [ null, {}
diff --git a/third_party/blink/web_tests/external/wpt/cookies/resources/set-cookie.py b/third_party/blink/web_tests/external/wpt/cookies/resources/set-cookie.py index 839f350c..b184087 100644 --- a/third_party/blink/web_tests/external/wpt/cookies/resources/set-cookie.py +++ b/third_party/blink/web_tests/external/wpt/cookies/resources/set-cookie.py
@@ -21,8 +21,14 @@ name = request.GET[b'name'] path = request.GET[b'path'] + samesite = request.GET.get(b'samesite') + secure = b'secure' in request.GET expiry_year = date.today().year + 1 cookie = b"%s=1; Path=%s; Expires=09 Jun %d 10:18:14 GMT" % (name, path, expiry_year) + if samesite: + cookie += b";SameSite=%s" % samesite + if secure: + cookie += b";Secure" headers = [ (b"Content-Type", b"application/json"),
diff --git a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/__dir__.ini b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/__dir__.ini deleted file mode 100644 index ff88b1e..0000000 --- a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/__dir__.ini +++ /dev/null
@@ -1,3 +0,0 @@ -bug: crbug.com/1309178 -disabled: - if flag_specific == "disable-layout-ng": CSS Anchor Positioning is only implemented in ng.
diff --git a/third_party/blink/web_tests/external/wpt/css/css-contain/container-queries/__dir__.ini b/third_party/blink/web_tests/external/wpt/css/css-contain/container-queries/__dir__.ini deleted file mode 100644 index 298ed18..0000000 --- a/third_party/blink/web_tests/external/wpt/css/css-contain/container-queries/__dir__.ini +++ /dev/null
@@ -1,3 +0,0 @@ -bug: crbug.com/1145970 -disabled: - if flag_specific == "disable-layout-ng": Container Queries tests require enabled LayoutNG
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/subgrid/__dir__.ini b/third_party/blink/web_tests/external/wpt/css/css-grid/subgrid/__dir__.ini deleted file mode 100644 index 2e8253ea..0000000 --- a/third_party/blink/web_tests/external/wpt/css/css-grid/subgrid/__dir__.ini +++ /dev/null
@@ -1,3 +0,0 @@ -bug: crbug.com/618969 -disabled: - if flag_specific == "disable-layout-ng": Subgrid will not be implemented in legacy.
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/__dir__.ini b/third_party/blink/web_tests/external/wpt/css/css-layout-api/__dir__.ini deleted file mode 100644 index 4a9d009..0000000 --- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/__dir__.ini +++ /dev/null
@@ -1,3 +0,0 @@ -bug: crbug.com/591099 -disabled: - if flag_specific == "disable-layout-ng": external/wpt/css/css-layout-api/
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/popovers/popover-attribute-basic.html b/third_party/blink/web_tests/external/wpt/html/semantics/popovers/popover-attribute-basic.html index 0abba9c4..e9167aae 100644 --- a/third_party/blink/web_tests/external/wpt/html/semantics/popovers/popover-attribute-basic.html +++ b/third_party/blink/web_tests/external/wpt/html/semantics/popovers/popover-attribute-basic.html
@@ -237,15 +237,6 @@ assert_false(popover.matches(':open'),'From "auto" to "invalid" (which is interpreted as "manual") should close the popover'); },'Changing attribute values should close open popovers'); - function modalPseudoSupported() { - try { - document.createElement('dialog').matches(':modal'); - return true; // No exception means :modal is supported. - } catch(e) { - return false; - } - } - const validTypes = ["auto","manual"]; validTypes.forEach(type => { test((t) => { @@ -259,16 +250,14 @@ assert_false(popover.matches(':open')); },`Removing a visible popover=${type} element from the document should close the popover`); - if (modalPseudoSupported()) { - test((t) => { - const popover = createPopover(t); - popover.setAttribute('popover',type); - popover.showPopover(); - assert_true(popover.matches(':open')); - assert_false(popover.matches(':modal')); - popover.hidePopover(); - },`A showing popover=${type} does not match :modal`); - } + test((t) => { + const popover = createPopover(t); + popover.setAttribute('popover',type); + popover.showPopover(); + assert_true(popover.matches(':open')); + assert_false(popover.matches(':modal')); + popover.hidePopover(); + },`A showing popover=${type} does not match :modal`); }); test((t) => {
diff --git a/third_party/blink/web_tests/external/wpt/mathml/__dir__.ini b/third_party/blink/web_tests/external/wpt/mathml/__dir__.ini deleted file mode 100644 index d5dc646..0000000 --- a/third_party/blink/web_tests/external/wpt/mathml/__dir__.ini +++ /dev/null
@@ -1,3 +0,0 @@ -bug: crbug.com/6606 -disabled: - if flag_specific == "disable-layout-ng": MathML depends on LayoutNG.
diff --git a/third_party/blink/web_tests/external/wpt/storage-access-api/requestStorageAccess-cross-site-iframe.sub.https.window-expected.txt b/third_party/blink/web_tests/external/wpt/storage-access-api/requestStorageAccess-cross-site-iframe.sub.https.window-expected.txt new file mode 100644 index 0000000..6046805 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/storage-access-api/requestStorageAccess-cross-site-iframe.sub.https.window-expected.txt
@@ -0,0 +1,8 @@ +This is a testharness.js-based test. +PASS [cross-site-frame] document.requestStorageAccess() should exist on the document interface +PASS [cross-site-frame] document.requestStorageAccess() should resolve in top-level frame or otherwise reject with a NotAllowedError with no user gesture +FAIL [cross-site-frame] document.requestStorageAccess() should be resolved when called properly with a user gesture, and should allow cookie access assert_true: After obtaining storage access, subresource requests from the frame should send and set cookies. expected true got false +FAIL [cross-site-frame] document.requestStorageAccess() should be rejected with a NotAllowedError without permission grant assert_unreached: Should have rejected: document.requestStorageAccess() call without permission Reached unreachable code +PASS [cross-site-frame] document.requestStorageAccess() should be rejected with a NotAllowedError with denied permission +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/storage-access-api/requestStorageAccess-cross-site-iframe.sub.https.window.js b/third_party/blink/web_tests/external/wpt/storage-access-api/requestStorageAccess-cross-site-iframe.sub.https.window.js new file mode 100644 index 0000000..f7c35ca2 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/storage-access-api/requestStorageAccess-cross-site-iframe.sub.https.window.js
@@ -0,0 +1,9 @@ +// META: script=helpers.js +// META: script=/resources/testdriver.js +// META: script=/resources/testdriver-vendor.js +'use strict'; + +(async function() { + // Create a test with a single-child cross-site iframe. + RunTestsInIFrame('https://{{hosts[alt][www]}}:{{ports[https][0]}}/storage-access-api/resources/requestStorageAccess-iframe.https.html?testCase=cross-site-frame&rootdocument=false'); +})();
diff --git a/third_party/blink/web_tests/external/wpt/storage-access-api/requestStorageAccess-nested-cross-site-iframe.sub.https.window-expected.txt b/third_party/blink/web_tests/external/wpt/storage-access-api/requestStorageAccess-nested-cross-site-iframe.sub.https.window-expected.txt new file mode 100644 index 0000000..dd76957 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/storage-access-api/requestStorageAccess-nested-cross-site-iframe.sub.https.window-expected.txt
@@ -0,0 +1,8 @@ +This is a testharness.js-based test. +PASS [nested-cross-site-frame] document.requestStorageAccess() should exist on the document interface +PASS [nested-cross-site-frame] document.requestStorageAccess() should resolve in top-level frame or otherwise reject with a NotAllowedError with no user gesture +FAIL [nested-cross-site-frame] document.requestStorageAccess() should be resolved when called properly with a user gesture, and should allow cookie access assert_true: After obtaining storage access, subresource requests from the frame should send and set cookies. expected true got false +FAIL [nested-cross-site-frame] document.requestStorageAccess() should be rejected with a NotAllowedError without permission grant assert_unreached: Should have rejected: document.requestStorageAccess() call without permission Reached unreachable code +PASS [nested-cross-site-frame] document.requestStorageAccess() should be rejected with a NotAllowedError with denied permission +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/storage-access-api/requestStorageAccess-nested-cross-site-iframe.sub.https.window.js b/third_party/blink/web_tests/external/wpt/storage-access-api/requestStorageAccess-nested-cross-site-iframe.sub.https.window.js new file mode 100644 index 0000000..f3ac0e8 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/storage-access-api/requestStorageAccess-nested-cross-site-iframe.sub.https.window.js
@@ -0,0 +1,10 @@ +// META: script=helpers.js +// META: script=/resources/testdriver.js +// META: script=/resources/testdriver-vendor.js +'use strict'; + +(async function() { + // Validate the nested-iframe scenario where the cross-site frame + // containing the tests is not the first child. + RunTestsInNestedIFrame('https://{{hosts[alt][www]}}:{{ports[https][0]}}/storage-access-api/resources/requestStorageAccess-iframe.https.html?testCase=nested-cross-site-frame&rootdocument=false'); +})();
diff --git a/third_party/blink/web_tests/external/wpt/storage-access-api/requestStorageAccess.sub.https.window.js b/third_party/blink/web_tests/external/wpt/storage-access-api/requestStorageAccess.sub.https.window.js index d673ed3..07fa29d 100644 --- a/third_party/blink/web_tests/external/wpt/storage-access-api/requestStorageAccess.sub.https.window.js +++ b/third_party/blink/web_tests/external/wpt/storage-access-api/requestStorageAccess.sub.https.window.js
@@ -40,16 +40,27 @@ }, "[" + testPrefix + "] document.requestStorageAccess() should resolve in top-level frame or otherwise reject with a NotAllowedError with no user gesture"); promise_test( - async () => { - await test_driver.set_permission( - {name: 'storage-access'}, 'granted'); + async (t) => { + await MaybeSetStorageAccess("*", "*", "blocked"); + await test_driver.set_permission({name: 'storage-access'}, 'granted'); + t.add_cleanup(async () => { + await test_driver.delete_all_cookies(); + }); await RunCallbackWithGesture(() => document.requestStorageAccess()); + + await fetch(`${window.location.origin}/cookies/resources/set-cookie.py?name=cookie&path=/&samesite=None&secure=`) + .then((resp) => resp.text()); + const httpCookies = await fetch(`${window.location.origin}/storage-access-api/resources/echo-cookie-header.py`) + .then((resp) => resp.text()); + assert_true(httpCookies.includes('cookie=1'), + 'After obtaining storage access, subresource requests from the frame should send and set cookies.'); }, '[' + testPrefix + - '] document.requestStorageAccess() should be resolved when called properly with a user gesture'); + '] document.requestStorageAccess() should be resolved when called properly with a user gesture, and ' + + 'should allow cookie access'); -if (testPrefix == 'cross-origin-frame' || testPrefix == 'nested-cross-origin-frame') { +if (!topLevelDocument && !testPrefix.includes('same-origin')) { promise_test( async t => { await RunCallbackWithGesture(() => {
diff --git a/third_party/blink/web_tests/external/wpt/storage-access-api/resources/echo-cookie-header.py b/third_party/blink/web_tests/external/wpt/storage-access-api/resources/echo-cookie-header.py new file mode 100644 index 0000000..546e76e --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/storage-access-api/resources/echo-cookie-header.py
@@ -0,0 +1,4 @@ +def main(request, response): + cookie_header = request.headers.get(b"Cookie", b"") + + return (200, [], cookie_header)
diff --git a/third_party/blink/web_tests/external/wpt/storage-access-api/resources/embedded_responder.js b/third_party/blink/web_tests/external/wpt/storage-access-api/resources/embedded_responder.js index 8d27dd39..86319b9d 100644 --- a/third_party/blink/web_tests/external/wpt/storage-access-api/resources/embedded_responder.js +++ b/third_party/blink/web_tests/external/wpt/storage-access-api/resources/embedded_responder.js
@@ -23,6 +23,7 @@ case "write document.cookie": document.cookie = event.data.cookie; reply(undefined); + break; case "document.cookie": reply(document.cookie); break;
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/get_active_element/get.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/get_active_element/get.py index 2b79ebd..1d2960c8 100644 --- a/third_party/blink/web_tests/external/wpt/webdriver/tests/get_active_element/get.py +++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/get_active_element/get.py
@@ -57,6 +57,17 @@ <p>Another element</p> </body>""") + # Per spec, autofocus candidates will be + # flushed by next paint, so we use rAF here to + # ensure the candidates are flushed. + session.execute_async_script( + """ + const resolve = arguments[0]; + window.requestAnimationFrame(function() { + window.requestAnimationFrame(resolve); + }); + """ + ) response = get_active_element(session) element = assert_success(response) assert_is_active_element(session, element) @@ -71,6 +82,17 @@ <p>Another element</p> </body>""") + # Per spec, autofocus candidates will be + # flushed by next paint, so we use rAF here to + # ensure the candidates are flushed. + session.execute_async_script( + """ + const resolve = arguments[0]; + window.requestAnimationFrame(function() { + window.requestAnimationFrame(resolve); + }); + """ + ) response = get_active_element(session) element = assert_success(response) assert_is_active_element(session, element)
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/__dir__.ini b/third_party/blink/web_tests/external/wpt/webrtc/__dir__.ini deleted file mode 100644 index 8a6d4ac2..0000000 --- a/third_party/blink/web_tests/external/wpt/webrtc/__dir__.ini +++ /dev/null
@@ -1,3 +0,0 @@ -bug: crbug.com/840659 -disabled: - if flag_specific == "disable-layout-ng": No H.264 decoder support in bot - just skip all webrtc tests.
diff --git a/third_party/blink/web_tests/resources/gesture-util.js b/third_party/blink/web_tests/resources/gesture-util.js index 5fc7bc4..61a99fff 100644 --- a/third_party/blink/web_tests/resources/gesture-util.js +++ b/third_party/blink/web_tests/resources/gesture-util.js
@@ -766,9 +766,11 @@ scroller.scrollLeft == 0) { resolve(); } else { + const eventTarget = + scroller == document.scrollingElement ? document : scroller; scroller.scrollTop = 0; scroller.scrollLeft = 0; - waitForScrollendEvent(document).then(resolve()); + waitForScrollendEvent(eventTarget).then(resolve); } }); }
diff --git a/third_party/blink/web_tests/wpt_internal/formatted-text/__dir__.ini b/third_party/blink/web_tests/wpt_internal/formatted-text/__dir__.ini deleted file mode 100644 index 58a48d5..0000000 --- a/third_party/blink/web_tests/wpt_internal/formatted-text/__dir__.ini +++ /dev/null
@@ -1,3 +0,0 @@ -bug: crbug.com/1176933 -disabled: - if flag_specific == "disable-layout-ng": was skipped in 'FlagExpectations/disable-layout-ng'
diff --git a/third_party/dom_distiller_js/protoc_plugins/json_values_converter.py b/third_party/dom_distiller_js/protoc_plugins/json_values_converter.py index b09240d4..86b9c96 100755 --- a/third_party/dom_distiller_js/protoc_plugins/json_values_converter.py +++ b/third_party/dom_distiller_js/protoc_plugins/json_values_converter.py
@@ -65,8 +65,9 @@ # Nothing to write for enums. self.Output( - 'static bool ReadFromValue(const base::Value& dict, {generated_class_name}* message) {{\n' - ' if (!dict.is_dict()) goto error;\n' + 'static bool ReadFromValue(const base::Value& dict_value, {generated_class_name}* message) {{\n' + ' const base::Value::Dict* dict = dict_value.GetIfDict();\n' + ' if (!dict) goto error;\n' '', generated_class_name=generated_class_name) @@ -82,7 +83,7 @@ '}}\n' '\n' 'static base::Value WriteToValue(const {generated_class_name}& message) {{\n' - ' base::Value dict(base::Value::Type::DICT);\n' + ' base::Value::Dict dict;\n' '', generated_class_name=generated_class_name) @@ -91,7 +92,7 @@ self.FieldWriteToValue(field_proto) self.Output( - ' return dict;\n' + ' return base::Value(std::move(dict));\n' '', generated_class_name=generated_class_name) self.Output('}}') @@ -123,8 +124,7 @@ ' field_list.Append(\n' ' {inner_class_converter}::WriteToValue(element));\n' '}}\n' - 'dict.SetKey("{field_number}",\n' - ' base::Value(std::move(field_list)));\n', + 'dict.Set("{field_number}", std::move(field_list));\n', field_number=field.JavascriptIndex(), field_name=field.name, inner_class_converter=field.CppConverterType() @@ -137,8 +137,7 @@ 'for (const auto& element : repeated_field) {{\n' ' field_list.Append(element);\n' '}}\n' - 'dict.SetKey("{field_number}",\n' - ' base::Value(std::move(field_list)));\n', + 'dict.Set("{field_number}", std::move(field_list));\n', field_number=field.JavascriptIndex(), field_name=field.name ) @@ -146,23 +145,23 @@ def OptionalMemberFieldWriteToValue(self, field): if field.IsClassType(): self.Output( - 'dict.SetKey("{field_number}",\n' - ' {inner_class_converter}::WriteToValue(\n' - ' message.{field_name}()));\n', + 'dict.Set("{field_number}",\n' + ' {inner_class_converter}::WriteToValue(\n' + ' message.{field_name}()));\n', field_number=field.JavascriptIndex(), field_name=field.name, inner_class_converter=field.CppConverterType() ) else: self.Output( - 'dict.Set{value_type}Key("{field_number}", message.{field_name}());\n', + 'dict.Set("{field_number}", message.{field_name}());\n', field_number=field.JavascriptIndex(), field_name=field.name, value_type=field.CppValueType() ) def WriteFieldRead(self, field): - self.Output('if (const auto* value = dict.FindKey("{field_number}")) {{', + self.Output('if (const auto* value = dict->Find("{field_number}")) {{', field_number=field.JavascriptIndex()) with self.AddIndent():
diff --git a/third_party/dom_distiller_js/test_sample_json_converter.h.golden b/third_party/dom_distiller_js/test_sample_json_converter.h.golden index 1c44aac..9ea16e3 100644 --- a/third_party/dom_distiller_js/test_sample_json_converter.h.golden +++ b/third_party/dom_distiller_js/test_sample_json_converter.h.golden
@@ -17,9 +17,10 @@ public: class Message { public: - static bool ReadFromValue(const base::Value& dict, dom_distiller::test_sample::proto::TypeTest::Message* message) { - if (!dict.is_dict()) goto error; - if (const auto* value = dict.FindKey("1")) { + static bool ReadFromValue(const base::Value& dict_value, dom_distiller::test_sample::proto::TypeTest::Message* message) { + const base::Value::Dict* dict = dict_value.GetIfDict(); + if (!dict) goto error; + if (const auto* value = dict->Find("1")) { if (!(*value).is_bool()) { goto error; } @@ -32,47 +33,48 @@ } static base::Value WriteToValue(const dom_distiller::test_sample::proto::TypeTest::Message& message) { - base::Value dict(base::Value::Type::DICT); + base::Value::Dict dict; if (message.has_dummy()) { - dict.SetBoolKey("1", message.dummy()); + dict.Set("1", message.dummy()); } - return dict; + return base::Value(std::move(dict)); } }; - static bool ReadFromValue(const base::Value& dict, dom_distiller::test_sample::proto::TypeTest* message) { - if (!dict.is_dict()) goto error; - if (const auto* value = dict.FindKey("1")) { + static bool ReadFromValue(const base::Value& dict_value, dom_distiller::test_sample::proto::TypeTest* message) { + const base::Value::Dict* dict = dict_value.GetIfDict(); + if (!dict) goto error; + if (const auto* value = dict->Find("1")) { if (!((*value).is_int() || (*value).is_double())) { goto error; } message->set_float_value(value->GetDouble()); } - if (const auto* value = dict.FindKey("2")) { + if (const auto* value = dict->Find("2")) { if (!((*value).is_int() || (*value).is_double())) { goto error; } message->set_double_value(value->GetDouble()); } - if (const auto* value = dict.FindKey("3")) { + if (const auto* value = dict->Find("3")) { if (!(*value).is_int()) { goto error; } message->set_int32_value(value->GetInt()); } - if (const auto* value = dict.FindKey("4")) { + if (const auto* value = dict->Find("4")) { if (!(*value).is_bool()) { goto error; } message->set_bool_value(value->GetBool()); } - if (const auto* value = dict.FindKey("5")) { + if (const auto* value = dict->Find("5")) { if (!(*value).is_string()) { goto error; } message->set_string_value(value->GetString()); } - if (const auto* value = dict.FindKey("6")) { + if (const auto* value = dict->Find("6")) { if (!dom_distiller::test_sample::proto::json::TypeTest::Message::ReadFromValue(*value, message->mutable_message_value())) { goto error; } @@ -84,28 +86,28 @@ } static base::Value WriteToValue(const dom_distiller::test_sample::proto::TypeTest& message) { - base::Value dict(base::Value::Type::DICT); + base::Value::Dict dict; if (message.has_float_value()) { - dict.SetDoubleKey("1", message.float_value()); + dict.Set("1", message.float_value()); } if (message.has_double_value()) { - dict.SetDoubleKey("2", message.double_value()); + dict.Set("2", message.double_value()); } if (message.has_int32_value()) { - dict.SetIntKey("3", message.int32_value()); + dict.Set("3", message.int32_value()); } if (message.has_bool_value()) { - dict.SetBoolKey("4", message.bool_value()); + dict.Set("4", message.bool_value()); } if (message.has_string_value()) { - dict.SetStringKey("5", message.string_value()); + dict.Set("5", message.string_value()); } if (message.has_message_value()) { - dict.SetKey("6", - dom_distiller::test_sample::proto::json::TypeTest::Message::WriteToValue( - message.message_value())); + dict.Set("6", + dom_distiller::test_sample::proto::json::TypeTest::Message::WriteToValue( + message.message_value())); } - return dict; + return base::Value(std::move(dict)); } }; @@ -113,9 +115,10 @@ public: class Message { public: - static bool ReadFromValue(const base::Value& dict, dom_distiller::test_sample::proto::Repeated::Message* message) { - if (!dict.is_dict()) goto error; - if (const auto* value = dict.FindKey("1")) { + static bool ReadFromValue(const base::Value& dict_value, dom_distiller::test_sample::proto::Repeated::Message* message) { + const base::Value::Dict* dict = dict_value.GetIfDict(); + if (!dict) goto error; + if (const auto* value = dict->Find("1")) { if (!value->is_list()) { goto error; } @@ -133,7 +136,7 @@ } static base::Value WriteToValue(const dom_distiller::test_sample::proto::Repeated::Message& message) { - base::Value dict(base::Value::Type::DICT); + base::Value::Dict dict; { const auto& repeated_field = message.dummy(); base::Value::List field_list; @@ -141,16 +144,16 @@ for (const auto& element : repeated_field) { field_list.Append(element); } - dict.SetKey("1", - base::Value(std::move(field_list))); + dict.Set("1", std::move(field_list)); } - return dict; + return base::Value(std::move(dict)); } }; - static bool ReadFromValue(const base::Value& dict, dom_distiller::test_sample::proto::Repeated* message) { - if (!dict.is_dict()) goto error; - if (const auto* value = dict.FindKey("1")) { + static bool ReadFromValue(const base::Value& dict_value, dom_distiller::test_sample::proto::Repeated* message) { + const base::Value::Dict* dict = dict_value.GetIfDict(); + if (!dict) goto error; + if (const auto* value = dict->Find("1")) { if (!value->is_list()) { goto error; } @@ -161,7 +164,7 @@ message->add_float_value(element.GetDouble()); } } - if (const auto* value = dict.FindKey("2")) { + if (const auto* value = dict->Find("2")) { if (!value->is_list()) { goto error; } @@ -172,7 +175,7 @@ message->add_double_value(element.GetDouble()); } } - if (const auto* value = dict.FindKey("3")) { + if (const auto* value = dict->Find("3")) { if (!value->is_list()) { goto error; } @@ -183,7 +186,7 @@ message->add_int32_value(element.GetInt()); } } - if (const auto* value = dict.FindKey("4")) { + if (const auto* value = dict->Find("4")) { if (!value->is_list()) { goto error; } @@ -194,7 +197,7 @@ message->add_bool_value(element.GetBool()); } } - if (const auto* value = dict.FindKey("5")) { + if (const auto* value = dict->Find("5")) { if (!value->is_list()) { goto error; } @@ -205,7 +208,7 @@ message->add_string_value(element.GetString()); } } - if (const auto* value = dict.FindKey("6")) { + if (const auto* value = dict->Find("6")) { if (!value->is_list()) { goto error; } @@ -222,7 +225,7 @@ } static base::Value WriteToValue(const dom_distiller::test_sample::proto::Repeated& message) { - base::Value dict(base::Value::Type::DICT); + base::Value::Dict dict; { const auto& repeated_field = message.float_value(); base::Value::List field_list; @@ -230,8 +233,7 @@ for (const auto& element : repeated_field) { field_list.Append(element); } - dict.SetKey("1", - base::Value(std::move(field_list))); + dict.Set("1", std::move(field_list)); } { const auto& repeated_field = message.double_value(); @@ -240,8 +242,7 @@ for (const auto& element : repeated_field) { field_list.Append(element); } - dict.SetKey("2", - base::Value(std::move(field_list))); + dict.Set("2", std::move(field_list)); } { const auto& repeated_field = message.int32_value(); @@ -250,8 +251,7 @@ for (const auto& element : repeated_field) { field_list.Append(element); } - dict.SetKey("3", - base::Value(std::move(field_list))); + dict.Set("3", std::move(field_list)); } { const auto& repeated_field = message.bool_value(); @@ -260,8 +260,7 @@ for (const auto& element : repeated_field) { field_list.Append(element); } - dict.SetKey("4", - base::Value(std::move(field_list))); + dict.Set("4", std::move(field_list)); } { const auto& repeated_field = message.string_value(); @@ -270,8 +269,7 @@ for (const auto& element : repeated_field) { field_list.Append(element); } - dict.SetKey("5", - base::Value(std::move(field_list))); + dict.Set("5", std::move(field_list)); } { const auto& repeated_field = message.message_value(); @@ -281,10 +279,9 @@ field_list.Append( dom_distiller::test_sample::proto::json::Repeated::Message::WriteToValue(element)); } - dict.SetKey("6", - base::Value(std::move(field_list))); + dict.Set("6", std::move(field_list)); } - return dict; + return base::Value(std::move(dict)); } };
diff --git a/third_party/nearby/README.chromium b/third_party/nearby/README.chromium index e90c961..75a3a247 100644 --- a/third_party/nearby/README.chromium +++ b/third_party/nearby/README.chromium
@@ -1,7 +1,7 @@ Name: Nearby Connections Library Short Name: Nearby URL: https://github.com/google/nearby -Version: a977a6bd7c85b417919111bf98c139be782ce6cc +Version: b59ed0b70f86c0dc1496c3145fa114bc38965f51 License: Apache 2.0 License File: LICENSE Security Critical: yes
diff --git a/tools/boilerplate.py b/tools/boilerplate.py index 5808c75..cdf09b5 100755 --- a/tools/boilerplate.py +++ b/tools/boilerplate.py
@@ -28,18 +28,19 @@ ] EXTENSIONS_TO_COMMENTS = { - 'h': '//', 'cc': '//', - 'nc': '//', - 'mm': '//', - 'js': '//', - 'py': '#', 'gn': '#', 'gni': '#', + 'h': '//', + 'js': '//', + 'mm': '//', 'mojom': '//', + 'nc': '//', + 'proto': '//', + 'py': '#', + 'swift': '//', 'ts': '//', 'typemap': '#', - "swift": "//", }
diff --git a/tools/grit/preprocess_if_expr.gni b/tools/grit/preprocess_if_expr.gni index 450071f8..850bff9a 100644 --- a/tools/grit/preprocess_if_expr.gni +++ b/tools/grit/preprocess_if_expr.gni
@@ -37,6 +37,14 @@ foreach(in_file, invoker.in_files) { inputs += [ "$in_folder/" + in_file ] outputs += [ "$out_folder/" + in_file ] + + if (defined(invoker.enable_removal_comments) && + invoker.enable_removal_comments) { + extension = get_path_info(in_file, "extension") + assert( + extension == "js" || extension == "ts", + "enable_removal_comments requires .js or .ts input files. Found ${in_file}") + } } args = [
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 61596d56..b0a82fd 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -34194,6 +34194,7 @@ label="SMART_CARD_PROVIDER_PRIVATE_ON_LIST_READERS_REQUESTED"/> <int value="503" label="SMART_CARD_PROVIDER_PRIVATE_ON_GET_STATUS_CHANGE_REQUESTED"/> + <int value="504" label="PDF_VIEWER_PRIVATE_ON_PDF_OCR_PREF_CHANGED"/> </enum> <enum name="ExtensionFileWriteResult"> @@ -103050,7 +103051,7 @@ <int value="4" label="Attempting registration with preexisting keys"/> <int value="5" label="Attempting registration while having persistent authentication - error"/> + error (deprecated)"/> <int value="6" label="Already registered V1"/> </enum>
diff --git a/tools/metrics/histograms/metadata/arc/histograms.xml b/tools/metrics/histograms/metadata/arc/histograms.xml index b8679e8..f61e615 100644 --- a/tools/metrics/histograms/metadata/arc/histograms.xml +++ b/tools/metrics/histograms/metadata/arc/histograms.xml
@@ -259,7 +259,7 @@ </summary> </histogram> -<histogram name="Arc.AndroidBootTime" units="ms" expires_after="2023-07-02"> +<histogram name="Arc.AndroidBootTime" units="ms" expires_after="2023-09-01"> <owner>khmel@google.com</owner> <owner>arc-performance@google.com</owner> <summary>The time elapsed for booting up the ARC instance.</summary> @@ -329,7 +329,7 @@ </summary> </histogram> -<histogram name="Arc.Anr.{AnrPeriod}" units="ANRs" expires_after="2023-03-01"> +<histogram name="Arc.Anr.{AnrPeriod}" units="ANRs" expires_after="2023-09-01"> <owner>khmel@google.com</owner> <owner>alanding@google.com</owner> <owner>arc-performance@google.com</owner> @@ -340,7 +340,7 @@ </histogram> <histogram name="Arc.Anr.{AnrPeriod}.{ArcBootType}" units="ANRs" - expires_after="2023-03-01"> + expires_after="2023-09-01"> <owner>khmel@google.com</owner> <owner>arc-performance@google.com</owner> <summary> @@ -351,7 +351,7 @@ <token key="ArcBootType" variants="ArcBootTypes"/> </histogram> -<histogram name="Arc.Anr.{AnrSource}" enum="ArcAnr" expires_after="2023-03-01"> +<histogram name="Arc.Anr.{AnrSource}" enum="ArcAnr" expires_after="2023-09-01"> <owner>khmel@google.com</owner> <owner>alanding@google.com</owner> <owner>arc-performance@google.com</owner> @@ -981,7 +981,7 @@ </histogram> <histogram name="Arc.CpuRestrictionDisabled{ArcThrottleObservers}" units="ms" - expires_after="2023-03-01"> + expires_after="2023-09-01"> <owner>khmel@google.com</owner> <owner>alanding@google.com</owner> <owner>arc-performance@google.com</owner> @@ -1008,7 +1008,7 @@ </histogram> <histogram name="Arc.CpuRestrictionVmResult" enum="ArcCpuRestrictionVmResult" - expires_after="2023-03-01"> + expires_after="2023-09-01"> <owner>khmel@google.com</owner> <owner>alanding@google.com</owner> <owner>arc-performance@google.com</owner> @@ -1206,7 +1206,7 @@ </histogram> <histogram name="Arc.FirstAppLaunchDelay.TimeDelta" units="ms" - expires_after="2023-07-02"> + expires_after="2023-09-01"> <owner>khmel@google.com</owner> <owner>arc-performance@google.com</owner> <summary> @@ -1220,7 +1220,7 @@ </histogram> <histogram name="Arc.FirstAppLaunchDelay.TimeDeltaUntilAppLaunch" units="ms" - expires_after="2023-07-02"> + expires_after="2023-09-01"> <owner>khmel@google.com</owner> <owner>alanding@google.com</owner> <summary> @@ -1233,7 +1233,7 @@ </histogram> <histogram name="Arc.FirstAppLaunchRequest.TimeDelta" units="ms" - expires_after="2023-03-01"> + expires_after="2023-09-01"> <owner>khmel@google.com</owner> <owner>arc-performance@google.com</owner> <summary> @@ -1780,7 +1780,7 @@ </histogram> <histogram name="Arc.PlayStoreLaunch.TimeDelta" units="ms" - expires_after="2023-03-01"> + expires_after="2023-09-01"> <owner>khmel@google.com</owner> <owner>arc-performance@google.com</owner> <summary> @@ -1857,7 +1857,7 @@ </histogram> <histogram name="Arc.PlayStoreShown.TimeDelta{ArcUserTypes}" units="ms" - expires_after="2023-03-01"> + expires_after="2023-09-01"> <owner>khmel@google.com</owner> <owner>arc-performance@google.com</owner> <summary> @@ -2021,7 +2021,7 @@ <histogram name="Arc.Runtime.Performance.CommitDeviation2{ArcPerformanceAppCategories}" - units="microseconds" expires_after="2023-03-01"> + units="microseconds" expires_after="2023-09-01"> <owner>khmel@google.com</owner> <owner>alanding@google.com</owner> <summary> @@ -2036,7 +2036,7 @@ </histogram> <histogram name="Arc.Runtime.Performance.FPS2{ArcPerformanceAppCategories}" - units="fps" expires_after="2023-03-01"> + units="fps" expires_after="2023-09-01"> <owner>khmel@google.com</owner> <owner>alanding@google.com</owner> <summary> @@ -2050,7 +2050,7 @@ </histogram> <histogram name="Arc.Runtime.Performance.Generic.FirstFrameRendered" units="ms" - expires_after="2023-07-02"> + expires_after="2023-09-01"> <owner>khmel@google.com</owner> <owner>alanding@google.com</owner> <summary> @@ -2061,7 +2061,7 @@ </histogram> <histogram name="Arc.Runtime.Performance.Generic.FrameTime" units="ms" - expires_after="2023-04-30"> + expires_after="2023-09-01"> <owner>khmel@google.com</owner> <owner>alanding@google.com</owner> <summary> @@ -2071,7 +2071,7 @@ </histogram> <histogram name="Arc.Runtime.Performance.Generic.Jankiness" units="%" - expires_after="2023-07-02"> + expires_after="2023-09-01"> <owner>khmel@google.com</owner> <owner>alanding@google.com</owner> <summary> @@ -2082,7 +2082,7 @@ <histogram name="Arc.Runtime.Performance.RenderQuality2{ArcPerformanceAppCategories}" - units="%" expires_after="2023-03-01"> + units="%" expires_after="2023-09-01"> <owner>khmel@google.com</owner> <owner>alanding@google.com</owner> <summary> @@ -2249,7 +2249,7 @@ </histogram> <histogram name="Arc.UiAvailable.AlreadyProvisioned.TimeDelta{ArcUserTypes}" - units="ms" expires_after="2023-03-01"> + units="ms" expires_after="2023-09-01"> <owner>khmel@google.com</owner> <owner>arc-performance@google.com</owner> <summary> @@ -2262,7 +2262,7 @@ </histogram> <histogram name="Arc.UiAvailable.InSessionProvisioning.TimeDelta{ArcUserTypes}" - units="ms" expires_after="2023-03-01"> + units="ms" expires_after="2023-09-01"> <owner>khmel@google.com</owner> <owner>arc-performance@google.com</owner> <summary> @@ -2275,7 +2275,7 @@ </histogram> <histogram name="Arc.UiAvailable.OobeProvisioning.TimeDelta{ArcUserTypes}" - units="ms" expires_after="2023-03-01"> + units="ms" expires_after="2023-09-01"> <owner>khmel@google.com</owner> <owner>arc-performance@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/ash/histograms.xml b/tools/metrics/histograms/metadata/ash/histograms.xml index 18936ca..b3ec20e 100644 --- a/tools/metrics/histograms/metadata/ash/histograms.xml +++ b/tools/metrics/histograms/metadata/ash/histograms.xml
@@ -488,6 +488,16 @@ </token> </histogram> +<histogram name="Ash.BrowserDataBackMigrator.SuccessfulMigrationTime" + units="ms" expires_after="2023-12-01"> + <owner>janagrill@google.com</owner> + <owner>artyomchen@google.com</owner> + <summary> + How long the backward migration took to complete in ms. Only recorded if + migration succeeds. + </summary> +</histogram> + <histogram name="Ash.BrowserDataMigrator.AshDataSizeMB" units="MB" expires_after="M121"> <owner>ythjkt@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/blink/histograms.xml b/tools/metrics/histograms/metadata/blink/histograms.xml index 12808ad8..7af4929 100644 --- a/tools/metrics/histograms/metadata/blink/histograms.xml +++ b/tools/metrics/histograms/metadata/blink/histograms.xml
@@ -916,7 +916,7 @@ <owner>web-identity-eng@google.com</owner> <summary> Records whether the FedCM auto re-authn call is blocked because the auto - re-auth content settings permission is disabled. Records at most one sample + re-authn content settings permission is disabled. Records at most one sample per FedCM API with auto re-authn enabled: some failures could occur before this metric is recorded. </summary> @@ -964,6 +964,21 @@ </summary> </histogram> +<histogram name="Blink.FedCm.AutoReauthn.TimeFromEmbargoWhenBlocked" units="ms" + expires_after="2023-08-09"> + <owner>npm@chromium.org</owner> + <owner>yigu@chromium.org</owner> + <owner>web-identity-eng@google.com</owner> + <summary> + Records the amount of time that has passed from the time the FedCM auto + re-authn API was embargoed to the time in which the next call occurs. Only + records a sample when there is an auto re-authn FedCM API call which is + blocked due to embargo. Samples are exponentially bucketed, with a max + bucket of 10 minutes, the embargo duration (see + `kFederatedIdentityAutoReauthnEmbargoDuration`). + </summary> +</histogram> + <histogram name="Blink.FedCm.CancelReason" enum="FedCmCancelReason" expires_after="2023-07-23"> <owner>pkotwicz@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/holding_space/histograms.xml b/tools/metrics/histograms/metadata/holding_space/histograms.xml index 3deb8a66..9b81a87b 100644 --- a/tools/metrics/histograms/metadata/holding_space/histograms.xml +++ b/tools/metrics/histograms/metadata/holding_space/histograms.xml
@@ -62,7 +62,7 @@ </variants> <histogram name="HoldingSpace.Animation.BubbleResize.Smoothness" units="%" - expires_after="2023-04-01"> + expires_after="2023-08-08"> <owner>dmblack@google.com</owner> <owner>gzadina@google.com</owner> <summary> @@ -74,7 +74,7 @@ </histogram> <histogram name="HoldingSpace.Animation.PodResize.Smoothness" units="%" - expires_after="2023-04-01"> + expires_after="2023-08-08"> <owner>dmblack@google.com</owner> <owner>gzadina@google.com</owner> <summary> @@ -96,7 +96,7 @@ </histogram> <histogram name="HoldingSpace.FilesAppChip.Action.All" - enum="HoldingSpaceFilesAppChipAction" expires_after="2023-04-01"> + enum="HoldingSpaceFilesAppChipAction" expires_after="2023-08-08"> <owner>dmblack@google.com</owner> <owner>gzadina@google.com</owner> <summary> @@ -106,7 +106,7 @@ </histogram> <histogram name="HoldingSpace.Item.Action.All" enum="HoldingSpaceItemAction" - expires_after="2023-08-06"> + expires_after="2023-08-08"> <owner>dmblack@google.com</owner> <owner>gzadina@google.com</owner> <summary> @@ -116,7 +116,7 @@ </histogram> <histogram name="HoldingSpace.Item.Action.{action}" enum="HoldingSpaceItemType" - expires_after="2023-04-01"> + expires_after="2023-08-08"> <owner>dmblack@google.com</owner> <owner>gzadina@google.com</owner> <summary> @@ -127,7 +127,7 @@ </histogram> <histogram name="HoldingSpace.Item.Action.{action}.Extension" - enum="HoldingSpaceExtension" expires_after="2023-04-01"> + enum="HoldingSpaceExtension" expires_after="2023-08-08"> <owner>dmblack@google.com</owner> <owner>gzadina@google.com</owner> <summary> @@ -138,7 +138,7 @@ </histogram> <histogram name="HoldingSpace.Item.Count.{type}" units="items" - expires_after="2023-04-01"> + expires_after="2023-08-08"> <owner>dmblack@google.com</owner> <owner>gzadina@google.com</owner> <summary> @@ -149,7 +149,7 @@ </histogram> <histogram name="HoldingSpace.Item.FailureToLaunch" enum="HoldingSpaceItemType" - expires_after="2023-04-01"> + expires_after="2023-08-08"> <owner>dmblack@google.com</owner> <owner>gzadina@google.com</owner> <summary> @@ -159,7 +159,7 @@ </histogram> <histogram name="HoldingSpace.Item.FailureToLaunch.Extension" - enum="HoldingSpaceExtension" expires_after="2023-04-01"> + enum="HoldingSpaceExtension" expires_after="2023-08-08"> <owner>dmblack@google.com</owner> <owner>gzadina@google.com</owner> <summary> @@ -169,7 +169,7 @@ </histogram> <histogram name="HoldingSpace.Item.FailureToLaunch.Reason" - enum="HoldingSpaceItemFailureToLaunchReason" expires_after="2023-04-01"> + enum="HoldingSpaceItemFailureToLaunchReason" expires_after="2023-08-08"> <owner>dmblack@google.com</owner> <owner>gzadina@google.com</owner> <summary> @@ -179,7 +179,7 @@ </histogram> <histogram name="HoldingSpace.Item.TotalCount.{type}" units="items" - expires_after="2023-04-01"> + expires_after="2023-08-08"> <owner>dmblack@google.com</owner> <owner>gzadina@google.com</owner> <summary> @@ -191,7 +191,7 @@ </histogram> <histogram name="HoldingSpace.Pod.Action.All" enum="HoldingSpacePodAction" - expires_after="2023-08-06"> + expires_after="2023-08-08"> <owner>dmblack@google.com</owner> <owner>gzadina@google.com</owner> <summary> @@ -211,7 +211,7 @@ </histogram> <histogram name="HoldingSpace.TimeFromFirstAvailabilityToFirstAdd" units="ms" - expires_after="2023-04-01"> + expires_after="2023-08-08"> <owner>dmblack@google.com</owner> <owner>gzadina@google.com</owner> <summary> @@ -242,7 +242,7 @@ </histogram> <histogram name="HoldingSpace.UserPreferences.PreviewsEnabled" - enum="BooleanEnabled" expires_after="2023-08-06"> + enum="BooleanEnabled" expires_after="2023-08-08"> <owner>dmblack@google.com</owner> <owner>gzadina@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/webapps/histograms.xml b/tools/metrics/histograms/metadata/webapps/histograms.xml index 8a55e95b..d313bf48d 100644 --- a/tools/metrics/histograms/metadata/webapps/histograms.xml +++ b/tools/metrics/histograms/metadata/webapps/histograms.xml
@@ -1109,6 +1109,31 @@ </summary> </histogram> +<histogram name="WebApp.RunOnOsLogin.Registration.Result" enum="BooleanSuccess" + expires_after="2024-03-01"> + <owner>dibyapal@chromium.org</owner> + <owner>desktop-pwas-team@google.com</owner> + <summary> + Records the result of registering Run On OS Login with the OS. This is + triggered during OS integration whenever an app is being installed or the + run on OS login state is being updated by the user from various UI surfaces + like the chrome://apps context menu or from the app settings page for an + app. + </summary> +</histogram> + +<histogram name="WebApp.RunOnOsLogin.Unregistration.Result" + enum="BooleanSuccess" expires_after="2024-03-01"> + <owner>dibyapal@chromium.org</owner> + <owner>desktop-pwas-team@google.com</owner> + <summary> + Records the result of unregistering Run On OS Login with the OS. This is + triggered during OS integration whenever an app is being uninstalled or the + user is modifying the app preferences to not have it run on startup from the + chrome://apps context menu or app settings page. + </summary> +</histogram> + <histogram name="WebApp.Shortcuts.Creation.Result" enum="ShortcutsCreationResult" expires_after="2023-08-20"> <owner>phillis@chromium.org</owner>
diff --git a/tools/metrics/ukm/ukm.xml b/tools/metrics/ukm/ukm.xml index 59090b8..b71151bd 100644 --- a/tools/metrics/ukm/ukm.xml +++ b/tools/metrics/ukm/ukm.xml
@@ -2070,6 +2070,36 @@ </metric> </event> +<event name="Autofill.FastCheckoutFormStatus"> + <owner>bwolfgang@google.com</owner> + <owner>jkeitel@google.com</owner> + <owner>vizcay@google.com</owner> + <summary> + Recorded at the end of a Fast Checkout run. + </summary> + <metric name="Filled" enum="Boolean"> + <summary> + 1 if the form was filled by Fast Checkout, 0 otherwise. + </summary> + </metric> + <metric name="FormSignature"> + <summary> + An approximately 10-bit hash of the form's actual signature. + </summary> + </metric> + <metric name="FormTypes"> + <summary> + Type of form. Stored as bitvector. A set i-th bit implies enum FormType's + i-th type was detected. Multiple types are possible. + </summary> + </metric> + <metric name="RunId"> + <summary> + Unique run ID for linking to other UKM events. + </summary> + </metric> +</event> + <event name="Autofill.FastCheckoutRunOutcome"> <owner>bwolfgang@google.com</owner> <owner>jkeitel@google.com</owner> @@ -3258,6 +3288,22 @@ <summary> Records performance metrics for FedCM(Federated Credential Management) API. </summary> + <metric name="AutoReauthn.BlockedByContentSettings" enum="Boolean"> + <summary> + Records whether the FedCM auto re-authn call is blocked because the auto + re-authn content settings permission is disabled. Records at most one + sample per FedCM API with auto re-authn enabled: some failures could occur + before this metric is recorded. + </summary> + </metric> + <metric name="AutoReauthn.BlockedByEmbargo" enum="Boolean"> + <summary> + Records whether the FedCM auto re-authn call is blocked because the auto + re-authn is under embargo, i.e. due to cooldown. Records at most one + sample per FedCM API with auto re-authn enabled: some failures could occur + before this metric is recorded. + </summary> + </metric> <metric name="AutoReauthn.ReturningAccounts" enum="FedCmReturningAccounts"> <summary> Records whether there was zero, one, or multiple returning accounts when a @@ -3277,6 +3323,16 @@ occur before this metric is recorded. </summary> </metric> + <metric name="AutoReauthn.TimeFromEmbargoWhenBlocked"> + <summary> + Records the amount of time that has passed from the time the FedCM auto + re-authn API was embargoed to the time in which the next call occurs. Only + records a sample when there is an auto re-authn FedCM API call which is + blocked due to embargo. Samples are exponentially bucketed, with a max + bucket of 10 minutes, the embargo duration (see + `kFederatedIdentityAutoReauthnEmbargoDuration`). + </summary> + </metric> <metric name="FedCmSessionID"> <summary> Records the session ID associated to the FedCM call for which this event
diff --git a/tools/perf/benchmark.csv b/tools/perf/benchmark.csv index 1e19649..647593c 100644 --- a/tools/perf/benchmark.csv +++ b/tools/perf/benchmark.csv
@@ -67,7 +67,6 @@ speedometer,"cbruni@chromium.org, vahl@chromium.org",Blink>JavaScript,,all speedometer-future,"cbruni@chromium.org, vahl@chromium.org",Blink>JavaScript,,all speedometer2,"cbruni@chromium.org, vahl@chromium.org",Blink>JavaScript,,all -speedometer2-chrome-health,"cbruni@chromium.org, vahl@chromium.org",Blink>JavaScript,,all speedometer2-future,"cbruni@chromium.org, vahl@chromium.org",Blink>JavaScript,,all speedometer2-minormc,omerkatz@chromium.org,Blink>JavaScript>GarbageCollection,,all speedometer2-pcscan,tmrts@chromium.org,Blink>JavaScript,,all
diff --git a/tools/perf/benchmarks/speedometer2.py b/tools/perf/benchmarks/speedometer2.py index 15afd1a..2fdf3a3 100644 --- a/tools/perf/benchmarks/speedometer2.py +++ b/tools/perf/benchmarks/speedometer2.py
@@ -173,20 +173,3 @@ def SetExtraBrowserOptions(self, options): options.AppendExtraBrowserArgs('--js-flags=--minor-mc') - - -@benchmark.Info(emails=['cbruni@chromium.org', 'vahl@chromium.org'], - component='Blink>JavaScript') -class Speedometer2ChromeHealth(Speedometer2): - """Speedometer2 benchmark, but run for only one iteration. - - For use with the Chrome Health Project. - """ - - @classmethod - def Name(cls): - return 'speedometer2-chrome-health' - - def CreateStorySet(self, options): - self.iteration_count = 1 - return super(Speedometer2ChromeHealth, self).CreateStorySet(options)
diff --git a/tools/perf/chrome-health-presets.yaml b/tools/perf/chrome-health-presets.yaml index dde6251..a576def 100644 --- a/tools/perf/chrome-health-presets.yaml +++ b/tools/perf/chrome-health-presets.yaml
@@ -7,7 +7,7 @@ presets: chrome_health: telemetry_batch_experiment: - - benchmark: speedometer2-chrome-health + - benchmark: speedometer2 configs: - mac-laptop_low_end-perf - mac-m1_mini_2020-perf @@ -69,7 +69,7 @@ - JetStream2 chrome_health_pgo: telemetry_batch_experiment: - - benchmark: speedometer2-chrome-health + - benchmark: speedometer2 configs: - mac-laptop_low_end-perf-pgo - mac-m1_mini_2020-perf-pgo @@ -140,7 +140,7 @@ - Speedometer2 speedometer2_pgo: telemetry_batch_experiment: - - benchmark: speedometer2-chrome-health + - benchmark: speedometer2 configs: - mac-laptop_low_end-perf-pgo - mac-m1_mini_2020-perf-pgo
diff --git a/tools/perf/core/bot_platforms.py b/tools/perf/core/bot_platforms.py index e503a96..fd0dc20 100644 --- a/tools/perf/core/bot_platforms.py +++ b/tools/perf/core/bot_platforms.py
@@ -224,11 +224,9 @@ [_GetBenchmarkConfig(b.Name()) for b in OFFICIAL_BENCHMARKS]) # power.mobile requires special hardware. # only run blink_perf.sanitizer-api on linux-perf. -# speedometer2-chrome-health is only for use with the Chrome Health pipeline OFFICIAL_BENCHMARK_CONFIGS = OFFICIAL_BENCHMARK_CONFIGS.Remove([ 'power.mobile', 'blink_perf.sanitizer-api', - 'speedometer2-chrome-health', 'speedometer2-minormc', ]) # TODO(crbug.com/965158): Remove OFFICIAL_BENCHMARK_NAMES once sharding
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json index 9df6486..e26c888 100644 --- a/tools/perf/core/perfetto_binary_roller/binary_deps.json +++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -22,7 +22,7 @@ }, "linux": { "hash": "53030fbc3d6d2485ec35eb072492d32edf0cde5a", - "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/f396a983fe100dec36e2c7d9285ca8a74e0ade91/trace_processor_shell" + "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/e85c60ec550a5b4f09e5e8efcad6b355f5a7c52d/trace_processor_shell" } }, "power_profile.sql": {
diff --git a/tools/perf/core/undocumented_benchmarks.py b/tools/perf/core/undocumented_benchmarks.py index 3bbb5f0..5564cd5 100644 --- a/tools/perf/core/undocumented_benchmarks.py +++ b/tools/perf/core/undocumented_benchmarks.py
@@ -18,7 +18,6 @@ 'speedometer', 'speedometer-future', 'speedometer2', - 'speedometer2-chrome-health', 'speedometer2-future', 'speedometer2-minormc', 'speedometer2-pcscan',
diff --git a/tools/run-swarmed.py b/tools/run-swarmed.py index e9b697a..565c2a9 100755 --- a/tools/run-swarmed.py +++ b/tools/run-swarmed.py
@@ -285,9 +285,7 @@ elif args.target_os == 'android': args.arch = gn_args.get('target_cpu', 'detect') - # TODO(crbug.com/1268955): Use sys.executable and remove os-specific logic - # once mb.py is in python3 - mb_cmd = ['tools/mb/mb', 'isolate'] + mb_cmd = [sys.executable, 'tools/mb/mb.py', 'isolate'] if not args.build: mb_cmd.append('--no-build') if args.isolate_map_file: @@ -310,9 +308,9 @@ with open(archive_json) as f: cas_digest = json.load(f).get(args.target_name) - # TODO(crbug.com/1268955): Use sys.executable and remove os-specific logic - # once mb.py is in python3 - mb_cmd = ['tools/mb/mb', 'get-swarming-command', '--as-list'] + mb_cmd = [ + sys.executable, 'tools/mb/mb.py', 'get-swarming-command', '--as-list' + ] if not args.build: mb_cmd.append('--no-build') if args.isolate_map_file:
diff --git a/tools/typescript/definitions/i18n.d.ts b/tools/typescript/definitions/i18n.d.ts deleted file mode 100644 index 22d7d11..0000000 --- a/tools/typescript/definitions/i18n.d.ts +++ /dev/null
@@ -1,30 +0,0 @@ -// Copyright 2023 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -/** @fileoverview Definitions for chrome.i18n API */ -// TODO(crbug.com/1203307): Auto-generate this file. -declare namespace chrome { - export namespace i18n { - - export function getAcceptLanguages(callback: (languages: string[]) => void): - void; - - export function getMessage( - messageName: string, args?: string|string[], - options?: {escapeLt: boolean}): string; - - export function getUILanguage(): string; - - interface DetectLanguageResult { - isReliable: boolean; - languages: Array<{ - language: string, - percentage: number, - }>; - } - - export function detectLanguage( - text: string, callback: (result: DetectLanguageResult) => void): void; - } -}
diff --git a/tools/typescript/definitions/pdf_viewer_private.d.ts b/tools/typescript/definitions/pdf_viewer_private.d.ts index 746c6430..0f0668c 100644 --- a/tools/typescript/definitions/pdf_viewer_private.d.ts +++ b/tools/typescript/definitions/pdf_viewer_private.d.ts
@@ -5,14 +5,21 @@ /** @fileoverview Definitions for chrome.pdfViewerPrivate API. */ // TODO(crbug.com/1203307): Auto-generate this file. -declare namespace chrome { - export namespace pdfViewerPrivate { +import {ChromeEvent} from './chrome_event.js'; - export function isAllowedLocalFileAccess( - url: string, callback: (isAllowed: boolean) => void): void; - export function isPdfOcrAlwaysActive( - callback: (isAlwaysActive: boolean) => void): void; - export function setPdfOcrPref( - isAlwaysActive: boolean, callback: (isSet: boolean) => void): void; +declare global { + export namespace chrome { + export namespace pdfViewerPrivate { + + export function isAllowedLocalFileAccess( + url: string, callback: (isAllowed: boolean) => void): void; + export function isPdfOcrAlwaysActive( + callback: (isAlwaysActive: boolean) => void): void; + export function setPdfOcrPref( + isAlwaysActive: boolean, callback: (isSet: boolean) => void): void; + + type PdfOcrPrefCallback = ((isPdfOcrAlwaysActive: boolean) => void)|null; + export const onPdfOcrPrefChanged: ChromeEvent<PdfOcrPrefCallback>; + } } }
diff --git a/tools/typescript/definitions/settings_private_mv2.d.ts b/tools/typescript/definitions/settings_private_mv2.d.ts deleted file mode 100644 index 142a5c2..0000000 --- a/tools/typescript/definitions/settings_private_mv2.d.ts +++ /dev/null
@@ -1,84 +0,0 @@ -// Copyright 2023 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -/** @fileoverview Definitions for chrome.settingsPrivate API in Manifest V2 */ -// This file exists because MV3 supports promises and MV2 does not. -// TODO(b/260590502): Delete this after MV3 migration. -// TODO(crbug.com/1203307): Auto-generate this file. - -import {ChromeEvent} from './chrome_event.js'; - -declare global { - export namespace chrome { - export namespace settingsPrivate { - export enum PrefType { - BOOLEAN = 'BOOLEAN', - NUMBER = 'NUMBER', - STRING = 'STRING', - URL = 'URL', - LIST = 'LIST', - DICTIONARY = 'DICTIONARY', - } - - export enum ControlledBy { - DEVICE_POLICY = 'DEVICE_POLICY', - USER_POLICY = 'USER_POLICY', - OWNER = 'OWNER', - PRIMARY_USER = 'PRIMARY_USER', - EXTENSION = 'EXTENSION', - PARENT = 'PARENT', - CHILD_RESTRICTION = 'CHILD_RESTRICTION', - } - - export enum Enforcement { - ENFORCED = 'ENFORCED', - RECOMMENDED = 'RECOMMENDED', - PARENT_SUPERVISED = 'PARENT_SUPERVISED', - } - - // Callback Types - type GetAllPrefsCallback = (prefs: PrefObject[]) => void; - type OnPrefSetCallback = (success: boolean) => void; - type GetPrefCallback = (pref: PrefObject) => void; - // TODO(crbug/1373934) Update existing usages of PrefObject to be typed, - // removing the need to use any here. - export interface PrefObject<T = any> { - key: string; - type: - // clang-format off - T extends boolean ? PrefType.BOOLEAN : - T extends number ? PrefType.NUMBER : - T extends string ? PrefType.STRING | PrefType.URL : - T extends unknown[] ? PrefType.LIST : - T extends Record<string|number, unknown> ? PrefType.DICTIONARY : - never; - // clang-format on - value: T; - controlledBy?: ControlledBy; - controlledByName?: string; - enforcement?: Enforcement; - recommendedValue?: T; - userSelectableValues?: T[]; - userControlDisabled?: boolean; - extensionId?: string; - extensionCanBeDisabled?: boolean; - } - - export function getAllPrefs(callback: GetAllPrefsCallback): void; - export function getPref(name: string, callback: GetPrefCallback): void; - - export function setPref( - name: string, value: any, pageId?: string, - callback?: OnPrefSetCallback): void; - - export function getDefaultZoom(callback: (arg: number) => void): void; - export function setDefaultZoom( - zoom: number, callback?: (arg: boolean) => void): void; - - type PrefsCallback = (prefs: PrefObject[]) => void; - - export const onPrefsChanged: ChromeEvent<PrefsCallback>; - } - } -}
diff --git a/tools/typescript/definitions/storage_mv2.d.ts b/tools/typescript/definitions/storage_mv2.d.ts deleted file mode 100644 index eea979c..0000000 --- a/tools/typescript/definitions/storage_mv2.d.ts +++ /dev/null
@@ -1,47 +0,0 @@ -// Copyright 2023 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -/** @fileoverview Definitions for chrome.storage API in Manifest V2 */ -// This file exists because MV3 supports promises and MV2 does not. -// TODO(b/260590502): Delete this after MV3 migration. -// TODO(crbug.com/1203307): Auto-generate this file. - -import {ChromeEvent} from './chrome_event'; - -declare global { - export namespace chrome { - export namespace storage { - export const sync: StorageArea; - export const local: StorageArea; - export const managed: StorageArea; - export const onChanged: StorageChangeEvent; - - export type StorageChangeEvent = ChromeEvent< - (changes: {[x: string]: StorageChange}, areaName: string) => void>; - - export type StorageAreaChangeEvent = - ChromeEvent<(changes: {[x: string]: StorageChange}) => void>; - - export interface StorageChange { - oldValue?: any; - newValue?: any; - } - - export class StorageArea { - public get( - keysOrCallback?: string|string[]|object|((obj: any) => void), - callback?: (obj: any) => void): void; - - public getBytesInUse( - keysOrCallback?: string|string[]|((obj: any) => void), - callback?: (num: number) => void): void; - - public set(items: {[x: string]: any}, callback?: () => void): void; - public remove(keys: string|string[], callback?: () => void): void; - public clear(callback?: () => void): void; - public onChanged: StorageAreaChangeEvent; - } - } - } -}
diff --git a/tools/typescript/definitions/tts.d.ts b/tools/typescript/definitions/tts.d.ts deleted file mode 100644 index 4192d28..0000000 --- a/tools/typescript/definitions/tts.d.ts +++ /dev/null
@@ -1,72 +0,0 @@ -// Copyright 2023 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import {ChromeEvent} from './chrome_event.js'; - -// TODO(crbug.com/1203307): Auto-generate this file. - -declare global { - namespace chrome { - export namespace tts { - - export enum EventType { - START = 'start', - END = 'end', - WORD = 'word', - SENTENCE = 'sentence', - MARKER = 'marker', - INTERRUPTED = 'interrupted', - CANCELLED = 'cancelled', - ERROR = 'error', - PAUSE = 'pause', - RESUME = 'resume', - } - - export class TtsOptions { - enqueue?: boolean; - voiceName?: string; - extensionId?: string; - lang?: string; - rate: number; - pitch?: number; - volume?: number; - requiredEventTypes?: string[]; - desiredEventTypes?: string[]; - onEvent(event: TtsEvent): void; - } - - export interface TtsEvent { - type: EventType; - charIndex?: number; - errorMessage?: string; - srcId?: number; - isFinalEvent?: boolean; - length?: number; - } - - export interface TtsVoice { - voiceName?: string; - lang?: string; - remote?: boolean; - extensionId?: string; - eventTypes?: EventType[]; - } - - export function speak( - utterance: string, options: TtsOptions, callback?: () => void): void; - - export function stop(): void; - - export function pause(): void; - - export function resume(): void; - - export function isSpeaking(callback?: (param: boolean) => void): void; - - export function getVoices(callback?: (param: TtsVoice[]) => void): void; - - export const onEvent: ChromeEvent<(event: TtsEvent) => void>; - } - } -}
diff --git a/ui/gl/test/gl_surface_test_support.cc b/ui/gl/test/gl_surface_test_support.cc index 4674dad..998fb7a 100644 --- a/ui/gl/test/gl_surface_test_support.cc +++ b/ui/gl/test/gl_surface_test_support.cc
@@ -49,8 +49,8 @@ use_software_gl = false; } -#if BUILDFLAG(IS_ANDROID) - // On Android we always use hardware GL. +#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS) + // On Android and iOS we always use hardware GL. use_software_gl = false; #endif
diff --git a/ui/views/controls/button/md_text_button.cc b/ui/views/controls/button/md_text_button.cc index 3c24862..bb470a4 100644 --- a/ui/views/controls/button/md_text_button.cc +++ b/ui/views/controls/button/md_text_button.cc
@@ -53,6 +53,9 @@ if (features::IsChromeRefresh2023()) { constexpr int kImageSpacing = 8; SetImageLabelSpacing(kImageSpacing); + } else { + SetCornerRadius(LayoutProvider::Get()->GetCornerRadiusMetric( + ShapeContextTokens::kButtonRadius)); } SetHorizontalAlignment(gfx::ALIGN_CENTER);
diff --git a/ui/views/examples/checkbox_example.cc b/ui/views/examples/checkbox_example.cc index 4ca56414..51e0d480 100644 --- a/ui/views/examples/checkbox_example.cc +++ b/ui/views/examples/checkbox_example.cc
@@ -4,14 +4,10 @@ #include "ui/views/examples/checkbox_example.h" -#include <memory> - #include "base/functional/bind.h" -#include "base/strings/utf_string_conversions.h" #include "ui/views/controls/button/checkbox.h" -#include "ui/views/controls/button/radio_button.h" #include "ui/views/examples/examples_window.h" -#include "ui/views/layout/fill_layout.h" +#include "ui/views/layout/flex_layout_view.h" namespace views::examples { @@ -20,14 +16,27 @@ CheckboxExample::~CheckboxExample() = default; void CheckboxExample::CreateExampleView(View* container) { - container->SetLayoutManager(std::make_unique<FillLayout>()); - container->AddChildView( - views::Builder<Checkbox>() - .SetText(u"Checkbox") - .SetCallback(base::BindRepeating( - [](int* count) { PrintStatus("Pressed! count: %d", ++(*count)); }, - &count_)) - .Build()); + Builder<View>(container) + .SetUseDefaultFillLayout(true) + .AddChild(Builder<FlexLayoutView>() + .SetOrientation(LayoutOrientation::kVertical) + .SetMainAxisAlignment(views::LayoutAlignment::kCenter) + .AddChildren(Builder<Checkbox>() + .SetText(u"Checkbox") + .SetCallback(base::BindRepeating( + [](int* count) { + PrintStatus("Pressed! count: %d", + ++(*count)); + }, + &count_)), + Builder<Checkbox>() + .SetText(u"Disabled Unchecked") + .SetState(Button::STATE_DISABLED), + Builder<Checkbox>() + .SetText(u"Disabled Checked") + .SetChecked(true) + .SetState(Button::STATE_DISABLED))) + .BuildChildren(); } } // namespace views::examples
diff --git a/ui/webui/resources/tools/generate_grd_test.py b/ui/webui/resources/tools/generate_grd_test.py index 6d0daba..d55b8c97 100755 --- a/ui/webui/resources/tools/generate_grd_test.py +++ b/ui/webui/resources/tools/generate_grd_test.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright 2019 The Chromium Authors # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file.
diff --git a/ui/webui/resources/tools/tests/test_manifest_1.json b/ui/webui/resources/tools/tests/test_manifest_1.json index d1144ddb..2fd9426 100644 --- a/ui/webui/resources/tools/tests/test_manifest_1.json +++ b/ui/webui/resources/tools/tests/test_manifest_1.json
@@ -1 +1 @@ -{"files": ["test.html", "test.rollup.js", "shared.rollup.js", "dir/element_in_dir.js", "dir/test_svg.svg"], "base_dir": "tools/tests/preprocessed" } +{"files": ["test.html", "test.rollup.js", "shared.rollup.js", "dir/element_in_dir.js", "dir/test_svg.svg"], "base_dir": "tests/preprocessed" }
diff --git a/ui/webui/resources/tools/tests/test_manifest_2.json b/ui/webui/resources/tools/tests/test_manifest_2.json index 4abc6b5a..5f72562 100644 --- a/ui/webui/resources/tools/tests/test_manifest_2.json +++ b/ui/webui/resources/tools/tests/test_manifest_2.json
@@ -1 +1 @@ -{"files": ["test_ui.js", "test_proxy.js", "file-with-dashes.js", "dir/another_element_in_dir.js"], "base_dir": "tools/tests/preprocessed" } +{"files": ["test_ui.js", "test_proxy.js", "file-with-dashes.js", "dir/another_element_in_dir.js"], "base_dir": "tests/preprocessed" }
diff --git a/weblayer/public/java/org/chromium/webengine/TabNavigationController.java b/weblayer/public/java/org/chromium/webengine/TabNavigationController.java index 8e91ab10..d7e5551 100644 --- a/weblayer/public/java/org/chromium/webengine/TabNavigationController.java +++ b/weblayer/public/java/org/chromium/webengine/TabNavigationController.java
@@ -93,6 +93,32 @@ } /** + * Reloads this Tab. Does nothing if there are no navigations. + */ + public void reload() { + if (mTabNavigationControllerProxy == null) { + throw new IllegalStateException("WebSandbox has been destroyed"); + } + try { + mTabNavigationControllerProxy.reload(); + } catch (RemoteException e) { + } + } + + /** + * Stops in progress loading. Does nothing if not in the process of loading. + */ + public void stop() { + if (mTabNavigationControllerProxy == null) { + throw new IllegalStateException("WebSandbox has been destroyed"); + } + try { + mTabNavigationControllerProxy.stop(); + } catch (RemoteException e) { + } + } + + /** * Returns true if there is a navigation before the current one. * * @return ListenableFuture with a Boolean stating if there is a navigation before the current
diff --git a/weblayer/public/java/org/chromium/webengine/interfaces/ITabNavigationControllerProxy.aidl b/weblayer/public/java/org/chromium/webengine/interfaces/ITabNavigationControllerProxy.aidl index 3be1ebd..d717dce 100644 --- a/weblayer/public/java/org/chromium/webengine/interfaces/ITabNavigationControllerProxy.aidl +++ b/weblayer/public/java/org/chromium/webengine/interfaces/ITabNavigationControllerProxy.aidl
@@ -13,6 +13,8 @@ void goForward() = 3; void canGoBack(IBooleanCallback callback) = 4; void canGoForward(IBooleanCallback callback) = 5; + void reload() = 7; + void stop() = 8; void setNavigationObserverDelegate(INavigationObserverDelegate tabNavigationDelegate) = 6; } \ No newline at end of file
diff --git a/weblayer/public/java/org/chromium/weblayer/TabNavigationControllerProxy.java b/weblayer/public/java/org/chromium/weblayer/TabNavigationControllerProxy.java index 3496816..b839db88 100644 --- a/weblayer/public/java/org/chromium/weblayer/TabNavigationControllerProxy.java +++ b/weblayer/public/java/org/chromium/weblayer/TabNavigationControllerProxy.java
@@ -66,6 +66,16 @@ } @Override + public void reload() { + mHandler.post(() -> { mNavigationController.reload(); }); + } + + @Override + public void stop() { + mHandler.post(() -> { mNavigationController.stop(); }); + } + + @Override public void setNavigationObserverDelegate(INavigationObserverDelegate navigationDelegate) { mNavigationObserverDelegate.setObserver(navigationDelegate); }