diff --git a/DEPS b/DEPS index f803c7d..ecb4e18 100644 --- a/DEPS +++ b/DEPS
@@ -297,15 +297,15 @@ # 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': 'da1c56b693348ac18187a7f72233ec3971319f2b', + 'skia_revision': '88d90928a76f91472d26cb3b2da3dd404ecf7115', # 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': '5275adc18e435dd1efd80736f0a463b4babe47bf', + 'v8_revision': '8e78df1eec463194449a74c4a34f4eceecaa138d', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ANGLE # and whatever else without interference from each other. - 'angle_revision': '05d86e06003bc9bcfdf62d769d6c6229e7680f5e', + 'angle_revision': '0b7e347a60ddfed8a4e77f2779d071f64cd9605a', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. @@ -368,7 +368,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling catapult # and whatever else without interference from each other. - 'catapult_revision': '2a52133e52c1fd021510b0b474d11676a680856f', + 'catapult_revision': '7f8536d0bbce1a7b63c5091f2baecaee56687a2f', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other. @@ -376,7 +376,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling devtools-frontend # and whatever else without interference from each other. - 'devtools_frontend_revision': '28c01320c79b22a767ce51339a0626abde8b3446', + 'devtools_frontend_revision': '5dc24542f6ff222f655d88200a903a5cb8378bc6', # 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. @@ -412,7 +412,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'dawn_revision': 'ce6246502c4d4e43b158bd161859179ba606bf75', + 'dawn_revision': '6f8d945dd6ce5d786530c1b2b8bdb2140616cbed', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -792,7 +792,7 @@ }, 'src/ios/third_party/material_components_ios/src': { - 'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + '9ff4459c2738fed6a8248a6aaafa595883093967', + 'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + '9100ba8f35c6184bdefd3551f09b179d678d09c9', 'condition': 'checkout_ios', }, @@ -1573,7 +1573,7 @@ }, 'src/third_party/perfetto': - Var('android_git') + '/platform/external/perfetto.git' + '@' + 'f8af68b97235247620b9b52d2c3369192684214f', + Var('android_git') + '/platform/external/perfetto.git' + '@' + 'ce19ce7576b6563e5344885ab151cad5089da9e7', 'src/third_party/perl': { 'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3', @@ -1805,7 +1805,7 @@ Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'), 'src-internal': { - 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@7541357ca26c5a3172c642ba27d081a8e10c09d8', + 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@861ce8cae3001c04dddbd738017bd63813420f21', 'condition': 'checkout_src_internal', }, @@ -1835,7 +1835,7 @@ 'packages': [ { 'package': 'chromeos_internal/apps/help_app/app', - 'version': '4mU5xSfqzZRdzqHfg-a_LNopmnrV8acGo-EjkY4CND4C', + 'version': '1pnKTN657Ssn-miDFzA1W7pMXuTroUpqKFGw2oShTrMC', }, ], 'condition': 'checkout_chromeos and checkout_src_internal', @@ -1846,7 +1846,7 @@ 'packages': [ { 'package': 'chromeos_internal/apps/media_app/app', - 'version': 'Mel72U4wXnVKhzK77ZLyxSpHoeelA8yxqOKeRzf8nkMC', + 'version': 'pGfZwUD7R0xpwgfDWKat7tEqV1y19uulGcf60FiAQ-4C', }, ], 'condition': 'checkout_chromeos and checkout_src_internal', @@ -1857,7 +1857,7 @@ 'packages': [ { 'package': 'chromeos_internal/apps/projector_app/app', - 'version': 'hkxJY91p1OSrQy88P4fPDCR-CpqvY7IAHhQ7KXjU4vUC', + 'version': 'rxMZUoSzn5bPwQ_1ZR1RDfWFcxwE-Nt-zYkx0mpyvMgC', }, ], 'condition': 'checkout_chromeos and checkout_src_internal',
diff --git a/ash/BUILD.gn b/ash/BUILD.gn index d2f0b3f..cbe1049 100644 --- a/ash/BUILD.gn +++ b/ash/BUILD.gn
@@ -1099,6 +1099,15 @@ "system/camera/autozoom_controller_impl.h", "system/camera/autozoom_feature_pod_controller.cc", "system/camera/autozoom_feature_pod_controller.h", + "system/camera/autozoom_nudge.cc", + "system/camera/autozoom_nudge.h", + "system/camera/autozoom_nudge_controller.cc", + "system/camera/autozoom_nudge_controller.h", + "system/camera/autozoom_observer.h", + "system/camera/autozoom_toast_controller.cc", + "system/camera/autozoom_toast_controller.h", + "system/camera/autozoom_toast_view.cc", + "system/camera/autozoom_toast_view.h", "system/caps_lock_notification_controller.cc", "system/caps_lock_notification_controller.h", "system/cast/cast_feature_pod_controller.cc", @@ -2752,6 +2761,7 @@ "system/bluetooth/fake_bluetooth_device_list_controller.h", "system/bluetooth/tray_bluetooth_helper_legacy_unittest.cc", "system/bluetooth/unified_bluetooth_detailed_view_controller_unittest.cc", + "system/camera/autozoom_toast_controller_unittest.cc", "system/caps_lock_notification_controller_unittest.cc", "system/channel_indicator/channel_indicator_quick_settings_view_unittest.cc", "system/channel_indicator/channel_indicator_unittest.cc",
diff --git a/ash/accessibility/autoclick/autoclick_drag_event_rewriter_unittest.cc b/ash/accessibility/autoclick/autoclick_drag_event_rewriter_unittest.cc index 168e384..a350b05 100644 --- a/ash/accessibility/autoclick/autoclick_drag_event_rewriter_unittest.cc +++ b/ash/accessibility/autoclick/autoclick_drag_event_rewriter_unittest.cc
@@ -28,7 +28,7 @@ // EventSink override: ui::EventDispatchDetails OnEventFromSource(ui::Event* event) override { - last_event_ = ui::Event::Clone(*event); + last_event_ = event->Clone(); return ui::EventDispatchDetails(); }
diff --git a/ash/accessibility/chromevox/touch_exploration_controller_unittest.cc b/ash/accessibility/chromevox/touch_exploration_controller_unittest.cc index d3d149b..66027fc 100644 --- a/ash/accessibility/chromevox/touch_exploration_controller_unittest.cc +++ b/ash/accessibility/chromevox/touch_exploration_controller_unittest.cc
@@ -50,7 +50,7 @@ void OnEvent(ui::Event* event) override { if (event->IsMouseEvent() || event->IsTouchEvent() || event->IsGestureEvent() || event->IsKeyEvent()) { - events_.push_back(ui::Event::Clone(*event)); + events_.push_back(event->Clone()); } else { return; }
diff --git a/ash/accessibility/sticky_keys/sticky_keys_controller.cc b/ash/accessibility/sticky_keys/sticky_keys_controller.cc index 62c0d117..a40575e 100644 --- a/ash/accessibility/sticky_keys/sticky_keys_controller.cc +++ b/ash/accessibility/sticky_keys/sticky_keys_controller.cc
@@ -40,7 +40,7 @@ if (!released && !flags_rewritten) return ui::EVENT_REWRITE_CONTINUE; - *rewritten_event = ui::Event::Clone(event); + *rewritten_event = event.Clone(); if (mod_down_flags & ~event.flags()) { (*rewritten_event)->set_flags(event.flags() | mod_down_flags); }
diff --git a/ash/ash_prefs.cc b/ash/ash_prefs.cc index 2aa3f05..784ef01f 100644 --- a/ash/ash_prefs.cc +++ b/ash/ash_prefs.cc
@@ -30,6 +30,7 @@ #include "ash/style/dark_light_mode_controller_impl.h" #include "ash/system/bluetooth/bluetooth_power_controller.h" #include "ash/system/camera/autozoom_controller_impl.h" +#include "ash/system/camera/autozoom_nudge_controller.h" #include "ash/system/caps_lock_notification_controller.h" #include "ash/system/gesture_education/gesture_education_notification_controller.h" #include "ash/system/human_presence/snooping_protection_controller.h" @@ -72,6 +73,7 @@ AppListControllerImpl::RegisterProfilePrefs(registry); AssistantControllerImpl::RegisterProfilePrefs(registry); AutozoomControllerImpl::RegisterProfilePrefs(registry); + AutozoomNudgeController::RegisterProfilePrefs(registry); AmbientController::RegisterProfilePrefs(registry); if (!ash::features::IsBluetoothRevampEnabled()) BluetoothPowerController::RegisterProfilePrefs(registry);
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd index ec01aea3..495fea1 100644 --- a/ash/ash_strings.grd +++ b/ash/ash_strings.grd
@@ -336,6 +336,12 @@ <message name="IDS_ASH_STATUS_TRAY_AUTOZOOM_ON_STATE" desc="Button label for the Autozoom feature." meaning="Autozoom feature is on. [CHAR_LIMIT=14]"> On </message> + <message name="IDS_ASH_STATUS_TRAY_AUTOZOOM_TOAST_ON_STATE" desc="The text for the toast after autozoom centers the camera."> + Autozoom centered the camera + </message> + <message name="IDS_ASH_STATUS_TRAY_AUTOZOOM_EDUCATIONAL_NUDGE_TEXT" desc="The text for the educational nudge for autozoom."> + Try autozoom so you'll be in the center of the screen. Turn it on in Quick Settings. + </message> <message name="IDS_ASH_STATUS_TRAY_BRAILLE_DISPLAY_CONNECTED" desc="The message shown on a notification when a braille display is connected"> Braille display connected. </message>
diff --git a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_AUTOZOOM_EDUCATIONAL_NUDGE_TEXT.png.sha1 b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_AUTOZOOM_EDUCATIONAL_NUDGE_TEXT.png.sha1 new file mode 100644 index 0000000..4f2d227c --- /dev/null +++ b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_AUTOZOOM_EDUCATIONAL_NUDGE_TEXT.png.sha1
@@ -0,0 +1 @@ +2c18373a0c261b25e04cc78c329ec314cd2ddc0f \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_AUTOZOOM_TOAST_ON_STATE.png.sha1 b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_AUTOZOOM_TOAST_ON_STATE.png.sha1 new file mode 100644 index 0000000..dbbcb92 --- /dev/null +++ b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_AUTOZOOM_TOAST_ON_STATE.png.sha1
@@ -0,0 +1 @@ +11762a1304bd9c29bcc1759fbec3b19a25b8cbc8 \ No newline at end of file
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc index d2fde842..34d2b39 100644 --- a/ash/constants/ash_features.cc +++ b/ash/constants/ash_features.cc
@@ -218,6 +218,11 @@ const base::Feature kAutocorrectParamsTuning{"AutocorrectParamsTuning", base::FEATURE_DISABLED_BY_DEFAULT}; +// If enabled, the autozoom nudge shown prefs will be reset at the start of +// each new user session. +const base::Feature kAutozoomNudgeSessionReset{ + "AutozoomNudgeSessionReset", base::FEATURE_DISABLED_BY_DEFAULT}; + // Enables the persistent desks bar at the top of the screen in clamshell mode // when there are more than one desk. const base::Feature kBentoBar{"BentoBar", base::FEATURE_DISABLED_BY_DEFAULT}; @@ -279,6 +284,10 @@ const base::Feature kCalendarModelDebugMode{"CalendarModelDebugMode", base::FEATURE_DISABLED_BY_DEFAULT}; +// Enables to allow using document scanning feature via DLC in the camera app. +const base::Feature kCameraAppDocScanDlc{"CameraAppDocScanDlc", + base::FEATURE_DISABLED_BY_DEFAULT}; + // Controls whether the camera privacy switch toasts and notification should be // displayed. const base::Feature kCameraPrivacySwitchNotifications{
diff --git a/ash/constants/ash_features.h b/ash/constants/ash_features.h index 32715959..53cfdc0 100644 --- a/ash/constants/ash_features.h +++ b/ash/constants/ash_features.h
@@ -100,6 +100,8 @@ extern const base::Feature kAutocompleteExtendedSuggestions; COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kAutocorrectParamsTuning; +COMPONENT_EXPORT(ASH_CONSTANTS) +extern const base::Feature kAutozoomNudgeSessionReset; COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kBentoBar; COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kBluetoothFixA2dpPacketSize; @@ -122,6 +124,8 @@ COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kCalendarModelDebugMode; COMPONENT_EXPORT(ASH_CONSTANTS) +extern const base::Feature kCameraAppDocScanDlc; +COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kCameraPrivacySwitchNotifications; COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kCellularBypassESimInstallationConnectivityCheck;
diff --git a/ash/constants/ash_pref_names.cc b/ash/constants/ash_pref_names.cc index dca3d94..68c49b07 100644 --- a/ash/constants/ash_pref_names.cc +++ b/ash/constants/ash_pref_names.cc
@@ -1058,6 +1058,10 @@ // cros::mojom::CameraAutoFramingState. const char kAutozoomState[] = "ash.camera.autozoom_state"; +// A dictionary storing the number of times and most recent time the autozoom +// nudge was shown. +const char kAutozoomNudges[] = "ash.camera.autozoom_nudges"; + // NOTE: New prefs should start with the "ash." prefix. Existing prefs moved // into this file should not be renamed, since they may be synced.
diff --git a/ash/constants/ash_pref_names.h b/ash/constants/ash_pref_names.h index f549cdb..b3b2d4d 100644 --- a/ash/constants/ash_pref_names.h +++ b/ash/constants/ash_pref_names.h
@@ -485,6 +485,8 @@ COMPONENT_EXPORT(ASH_CONSTANTS) extern const char kAutozoomState[]; +COMPONENT_EXPORT(ASH_CONSTANTS) extern const char kAutozoomNudges[]; + } // namespace prefs } // namespace ash
diff --git a/ash/drag_drop/drag_drop_controller.cc b/ash/drag_drop/drag_drop_controller.cc index ce0ae87..161166a3 100644 --- a/ash/drag_drop/drag_drop_controller.cc +++ b/ash/drag_drop/drag_drop_controller.cc
@@ -469,7 +469,7 @@ static_cast<aura::Window*>(capture_delegate_->capture_window()), static_cast<aura::Window*>(drag_source_window_)); } else { - pending_long_tap_ = ui::Event::Clone(*event); + pending_long_tap_ = event->Clone(); } DoDragCancel(kTouchCancelAnimationDuration); break;
diff --git a/ash/events/accessibility_event_rewriter.cc b/ash/events/accessibility_event_rewriter.cc index 8c5f7fe8..772fdb6d 100644 --- a/ash/events/accessibility_event_rewriter.cc +++ b/ash/events/accessibility_event_rewriter.cc
@@ -164,8 +164,8 @@ if (rewritten_key_event->GetDomKey() == ui::DomKey::TAB) capture = false; - delegate_->DispatchKeyEventToChromeVox( - ui::Event::Clone(*rewritten_key_event), capture); + delegate_->DispatchKeyEventToChromeVox(rewritten_key_event->Clone(), + capture); return capture; } @@ -310,7 +310,7 @@ .enabled() || Shell::Get()->accessibility_controller()->docked_magnifier().enabled() || Shell::Get()->accessibility_controller()->spoken_feedback().enabled())) { - delegate_->DispatchMouseEvent(ui::Event::Clone(event)); + delegate_->DispatchMouseEvent(event.Clone()); } }
diff --git a/ash/events/keyboard_driven_event_rewriter_unittest.cc b/ash/events/keyboard_driven_event_rewriter_unittest.cc index a7e580f..c8fd0d7 100644 --- a/ash/events/keyboard_driven_event_rewriter_unittest.cc +++ b/ash/events/keyboard_driven_event_rewriter_unittest.cc
@@ -28,12 +28,12 @@ ~TestEventRewriterContinuation() override = default; ui::EventDispatchDetails SendEvent(const ui::Event* event) override { - passthrough_event = ui::Event::Clone(*event); + passthrough_event = event->Clone(); return ui::EventDispatchDetails(); } ui::EventDispatchDetails SendEventFinally(const ui::Event* event) override { - rewritten_event = ui::Event::Clone(*event); + rewritten_event = event->Clone(); return ui::EventDispatchDetails(); }
diff --git a/ash/frame/default_frame_header_unittest.cc b/ash/frame/default_frame_header_unittest.cc index 0d7d2c4a..dc38c094 100644 --- a/ash/frame/default_frame_header_unittest.cc +++ b/ash/frame/default_frame_header_unittest.cc
@@ -175,7 +175,8 @@ FrameHeader* frame_header_ = nullptr; }; -TEST_F(DefaultFrameHeaderTest, DeleteDuringAnimation) { +// TODO(crbug.com/1349573): Revive this test. +TEST_F(DefaultFrameHeaderTest, DISABLED_DeleteDuringAnimation) { const auto bounds = gfx::Rect(100, 100); auto win0 = CreateAppWindow(bounds, AppType::BROWSER); auto win1 = CreateAppWindow(bounds, AppType::BROWSER); @@ -213,8 +214,9 @@ EXPECT_TRUE(checker.destroyed()); } +// TODO(crbug.com/1349633): Revive this test. // Make sure that the animation is canceled when resized. -TEST_F(DefaultFrameHeaderTest, ResizeAndReorderDuringAnimation) { +TEST_F(DefaultFrameHeaderTest, DISABLED_ResizeAndReorderDuringAnimation) { const auto bounds = gfx::Rect(100, 100); auto win_0 = CreateAppWindow(bounds, AppType::BROWSER); auto win_1 = CreateAppWindow(bounds, AppType::BROWSER);
diff --git a/ash/public/cpp/app_list/app_list_features.h b/ash/public/cpp/app_list/app_list_features.h index 0c82cfb2..8cbea5f2 100644 --- a/ash/public/cpp/app_list/app_list_features.h +++ b/ash/public/cpp/app_list/app_list_features.h
@@ -74,7 +74,6 @@ ASH_PUBLIC_EXPORT bool IsAppRankerEnabled(); ASH_PUBLIC_EXPORT bool IsZeroStateAppsRankerEnabled(); -ASH_PUBLIC_EXPORT bool IsQueryBasedMixedTypesRankerEnabled(); ASH_PUBLIC_EXPORT bool IsZeroStateMixedTypesRankerEnabled(); ASH_PUBLIC_EXPORT bool IsAppReinstallZeroStateEnabled(); ASH_PUBLIC_EXPORT bool IsAppListLaunchRecordingEnabled(); @@ -92,8 +91,6 @@ ASH_PUBLIC_EXPORT bool IsCompactBubbleLauncherEnabled(); ASH_PUBLIC_EXPORT bool IsLauncherPlayStoreSearchEnabled(); -ASH_PUBLIC_EXPORT std::string AnswerServerUrl(); -ASH_PUBLIC_EXPORT std::string AnswerServerQuerySuffix(); ASH_PUBLIC_EXPORT std::string AppSearchResultRankerPredictorName(); ASH_PUBLIC_EXPORT std::string CategoricalSearchType();
diff --git a/ash/shelf/shelf_view.cc b/ash/shelf/shelf_view.cc index 6676c7cb..87d97101 100644 --- a/ash/shelf/shelf_view.cc +++ b/ash/shelf/shelf_view.cc
@@ -795,17 +795,17 @@ // Run AfterItemSelected directly if the item has no delegate (ie. in tests). const ShelfItem& item = model_->items()[last_pressed_index_.value()]; if (!model_->GetShelfItemDelegate(item.id)) { - AfterItemSelected(item, sender, ui::Event::Clone(event), ink_drop, - SHELF_ACTION_NONE, {}); + AfterItemSelected(item, sender, event.Clone(), ink_drop, SHELF_ACTION_NONE, + {}); return; } // Notify the item of its selection; handle the result in AfterItemSelected. item_awaiting_response_ = item.id; model_->GetShelfItemDelegate(item.id)->ItemSelected( - ui::Event::Clone(event), GetDisplayIdForView(this), LAUNCH_FROM_SHELF, + event.Clone(), GetDisplayIdForView(this), LAUNCH_FROM_SHELF, base::BindOnce(&ShelfView::AfterItemSelected, weak_factory_.GetWeakPtr(), - item, sender, ui::Event::Clone(event), ink_drop), + item, sender, event.Clone(), ink_drop), base::BindRepeating(&ShouldIncludeMenuItem)); }
diff --git a/ash/system/camera/autozoom_controller_impl.cc b/ash/system/camera/autozoom_controller_impl.cc index 76477e1..8020b05 100644 --- a/ash/system/camera/autozoom_controller_impl.cc +++ b/ash/system/camera/autozoom_controller_impl.cc
@@ -12,7 +12,8 @@ namespace ash { -AutozoomControllerImpl::AutozoomControllerImpl() { +AutozoomControllerImpl::AutozoomControllerImpl() + : nudge_controller_(std::make_unique<AutozoomNudgeController>(this)) { Shell::Get()->session_controller()->AddObserver(this); } @@ -38,6 +39,14 @@ : cros::mojom::CameraAutoFramingState::OFF); } +void AutozoomControllerImpl::AddObserver(AutozoomObserver* observer) { + observers_.AddObserver(observer); +} + +void AutozoomControllerImpl::RemoveObserver(AutozoomObserver* observer) { + observers_.RemoveObserver(observer); +} + void AutozoomControllerImpl::OnActiveUserPrefServiceChanged( PrefService* pref_service) { if (pref_service == active_user_pref_service_) @@ -62,8 +71,11 @@ auto* camera_hal_dispatcher = media::CameraHalDispatcherImpl::GetInstance(); if (camera_hal_dispatcher) { - camera_hal_dispatcher->SetAutoFramingState(GetState()); + camera_hal_dispatcher->SetAutoFramingState(state_); } + + for (auto& observer : observers_) + observer.OnAutozoomStateChanged(state_); } void AutozoomControllerImpl::StartWatchingPrefsChanges() {
diff --git a/ash/system/camera/autozoom_controller_impl.h b/ash/system/camera/autozoom_controller_impl.h index ece5f19..16bf9870 100644 --- a/ash/system/camera/autozoom_controller_impl.h +++ b/ash/system/camera/autozoom_controller_impl.h
@@ -8,6 +8,9 @@ #include "ash/ash_export.h" #include "ash/public/cpp/session/session_observer.h" +#include "ash/system/camera/autozoom_nudge_controller.h" +#include "ash/system/camera/autozoom_observer.h" +#include "base/observer_list.h" #include "components/prefs/pref_change_registrar.h" #include "components/prefs/pref_registry_simple.h" #include "components/prefs/pref_service.h" @@ -35,6 +38,9 @@ void Toggle(); + void AddObserver(AutozoomObserver* observer); + void RemoveObserver(AutozoomObserver* observer); + // SessionObserver: void OnActiveUserPrefServiceChanged(PrefService* pref_service) override; @@ -59,6 +65,10 @@ std::unique_ptr<PrefChangeRegistrar> pref_change_registrar_; cros::mojom::CameraAutoFramingState state_; + + base::ObserverList<AutozoomObserver> observers_; + + std::unique_ptr<AutozoomNudgeController> nudge_controller_; }; } // namespace ash
diff --git a/ash/system/camera/autozoom_feature_pod_controller.cc b/ash/system/camera/autozoom_feature_pod_controller.cc index a9cf626..d913d1b 100644 --- a/ash/system/camera/autozoom_feature_pod_controller.cc +++ b/ash/system/camera/autozoom_feature_pod_controller.cc
@@ -20,9 +20,13 @@ if (camera_hal_dispatcher) { camera_hal_dispatcher->AddActiveClientObserver(this); } + + Shell::Get()->autozoom_controller()->AddObserver(this); } AutozoomFeaturePodController::~AutozoomFeaturePodController() { + Shell::Get()->autozoom_controller()->RemoveObserver(this); + auto* camera_hal_dispatcher = media::CameraHalDispatcherImpl::GetInstance(); if (camera_hal_dispatcher) { camera_hal_dispatcher->RemoveActiveClientObserver(this); @@ -42,7 +46,7 @@ description); button_->label_button()->GetViewAccessibility().OverrideDescription( description); - UpdateButton(); + UpdateButton(Shell::Get()->autozoom_controller()->GetState()); return button_; } @@ -50,19 +54,12 @@ return SystemTrayItemUmaType::UMA_AUTOZOOM; } -void AutozoomFeaturePodController::OnToggled() { - Shell::Get()->autozoom_controller()->Toggle(); - UpdateButton(); -} - void AutozoomFeaturePodController::OnLabelPressed() { - if (!button_->GetEnabled()) - return; - OnToggled(); + Shell::Get()->autozoom_controller()->Toggle(); } void AutozoomFeaturePodController::OnIconPressed() { - OnToggled(); + Shell::Get()->autozoom_controller()->Toggle(); } void AutozoomFeaturePodController::UpdateButtonVisibility() { @@ -74,8 +71,15 @@ active_camera_client_count_ > 0); } -void AutozoomFeaturePodController::UpdateButton() { - auto state = Shell::Get()->autozoom_controller()->GetState(); +void AutozoomFeaturePodController::OnAutozoomStateChanged( + cros::mojom::CameraAutoFramingState state) { + UpdateButton(state); +} + +void AutozoomFeaturePodController::UpdateButton( + cros::mojom::CameraAutoFramingState state) { + if (!button_) + return; button_->SetToggled(state != cros::mojom::CameraAutoFramingState::OFF); UpdateButtonVisibility();
diff --git a/ash/system/camera/autozoom_feature_pod_controller.h b/ash/system/camera/autozoom_feature_pod_controller.h index 8f42e72..ebe7840 100644 --- a/ash/system/camera/autozoom_feature_pod_controller.h +++ b/ash/system/camera/autozoom_feature_pod_controller.h
@@ -5,6 +5,7 @@ #ifndef ASH_SYSTEM_CAMERA_AUTOZOOM_FEATURE_POD_CONTROLLER_H_ #define ASH_SYSTEM_CAMERA_AUTOZOOM_FEATURE_POD_CONTROLLER_H_ +#include "ash/system/camera/autozoom_observer.h" #include "ash/system/unified/feature_pod_controller_base.h" #include "media/capture/video/chromeos/camera_hal_dispatcher_impl.h" @@ -12,7 +13,8 @@ // Controller of a feature pod button that toggles autozoom. class AutozoomFeaturePodController : public FeaturePodControllerBase, - public media::CameraActiveClientObserver { + public media::CameraActiveClientObserver, + public AutozoomObserver { public: AutozoomFeaturePodController(); @@ -28,9 +30,12 @@ void OnLabelPressed() override; SystemTrayItemUmaType GetUmaType() const override; + // AutozoomObserver: + void OnAutozoomStateChanged( + cros::mojom::CameraAutoFramingState state) override; + private: - void OnToggled(); - void UpdateButton(); + void UpdateButton(cros::mojom::CameraAutoFramingState state); void UpdateButtonVisibility();
diff --git a/ash/system/camera/autozoom_nudge.cc b/ash/system/camera/autozoom_nudge.cc new file mode 100644 index 0000000..b63279b0 --- /dev/null +++ b/ash/system/camera/autozoom_nudge.cc
@@ -0,0 +1,64 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/system/camera/autozoom_nudge.h" + +#include <memory> + +#include "ash/resources/vector_icons/vector_icons.h" +#include "ash/strings/grit/ash_strings.h" +#include "ash/style/ash_color_provider.h" +#include "ash/system/tray/system_nudge_label.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/gfx/paint_vector_icon.h" + +namespace ash { + +namespace { + +// The size of the autozoom icon. +constexpr int kAutozoomIconSize = 20; + +// The minimum width of the label. +constexpr int kMinLabelWidth = 220; + +// The spacing between the icon and label in the nudge view. +constexpr int kIconLabelSpacing = 16; + +// The padding which separates the nudge's border with its inner contents. +constexpr int kNudgePadding = 16; + +constexpr char kAutozoomNudgeName[] = "AutozoomNudge"; + +} // namespace + +AutozoomNudge::AutozoomNudge() + : SystemNudge(kAutozoomNudgeName, + kAutozoomIconSize, + kIconLabelSpacing, + kNudgePadding, + /*anchor_status_area=*/true, + AshColorProvider::ContentLayerType::kIconColorProminent) {} + +AutozoomNudge::~AutozoomNudge() = default; + +std::unique_ptr<SystemNudgeLabel> AutozoomNudge::CreateLabelView() const { + std::u16string label_text = l10n_util::GetStringUTF16( + IDS_ASH_STATUS_TRAY_AUTOZOOM_EDUCATIONAL_NUDGE_TEXT); + // Set the label's text. + auto label = std::make_unique<SystemNudgeLabel>(label_text, kMinLabelWidth); + label->set_font_size_delta(2); + return label; +} + +const gfx::VectorIcon& AutozoomNudge::GetIcon() const { + return kUnifiedMenuAutozoomIcon; +} + +std::u16string AutozoomNudge::GetAccessibilityText() const { + return l10n_util::GetStringUTF16( + IDS_ASH_STATUS_TRAY_AUTOZOOM_EDUCATIONAL_NUDGE_TEXT); +} + +} // namespace ash
diff --git a/ash/system/camera/autozoom_nudge.h b/ash/system/camera/autozoom_nudge.h new file mode 100644 index 0000000..6e204414 --- /dev/null +++ b/ash/system/camera/autozoom_nudge.h
@@ -0,0 +1,31 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_SYSTEM_CAMERA_AUTOZOOM_NUDGE_H_ +#define ASH_SYSTEM_CAMERA_AUTOZOOM_NUDGE_H_ + +#include "ash/ash_export.h" +#include "ash/system/tray/system_nudge.h" +#include "ui/gfx/paint_vector_icon.h" + +namespace ash { + +// Implements a contextual nudge for multipaste. +class ASH_EXPORT AutozoomNudge : public SystemNudge { + public: + AutozoomNudge(); + AutozoomNudge(const AutozoomNudge&) = delete; + AutozoomNudge& operator=(const AutozoomNudge&) = delete; + ~AutozoomNudge() override; + + protected: + // SystemNudge: + std::unique_ptr<SystemNudgeLabel> CreateLabelView() const override; + const gfx::VectorIcon& GetIcon() const override; + std::u16string GetAccessibilityText() const override; +}; + +} // namespace ash + +#endif // ASH_SYSTEM_CAMERA_AUTOZOOM_NUDGE_H_
diff --git a/ash/system/camera/autozoom_nudge_controller.cc b/ash/system/camera/autozoom_nudge_controller.cc new file mode 100644 index 0000000..6391d432 --- /dev/null +++ b/ash/system/camera/autozoom_nudge_controller.cc
@@ -0,0 +1,162 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/system/camera/autozoom_nudge_controller.h" + +#include "ash/constants/ash_features.h" +#include "ash/constants/ash_pref_names.h" +#include "ash/session/session_controller_impl.h" +#include "ash/shell.h" +#include "ash/system/camera/autozoom_controller_impl.h" +#include "ash/system/camera/autozoom_nudge.h" +#include "base/json/values_util.h" +#include "components/prefs/pref_registry_simple.h" +#include "components/prefs/pref_service.h" +#include "components/prefs/scoped_user_pref_update.h" + +namespace ash { +namespace { +// Keys for autozoom nudge sub-preferences for shown count and last time shown. +constexpr char kShownCount[] = "shown_count"; +constexpr char kLastTimeShown[] = "last_time_shown"; +constexpr char kHadEnabled[] = "had_enabled"; +constexpr int kNotificationLimit = 3; +constexpr base::TimeDelta kMinInterval = base::Days(1); +} // namespace + +AutozoomNudgeController::AutozoomNudgeController( + AutozoomControllerImpl* autozoom_controller) + : autozoom_controller_(autozoom_controller) { + autozoom_controller_->AddObserver(this); + + auto* camera_hal_dispatcher = media::CameraHalDispatcherImpl::GetInstance(); + if (camera_hal_dispatcher) + camera_hal_dispatcher->AddActiveClientObserver(this); + + if (base::FeatureList::IsEnabled(features::kAutozoomNudgeSessionReset)) + Shell::Get()->session_controller()->AddObserver(this); +} + +AutozoomNudgeController::~AutozoomNudgeController() { + autozoom_controller_->RemoveObserver(this); + + auto* camera_hal_dispatcher = media::CameraHalDispatcherImpl::GetInstance(); + if (camera_hal_dispatcher) + camera_hal_dispatcher->RemoveActiveClientObserver(this); + + if (base::FeatureList::IsEnabled(features::kAutozoomNudgeSessionReset)) + Shell::Get()->session_controller()->RemoveObserver(this); +} + +// static +void AutozoomNudgeController::RegisterProfilePrefs( + PrefRegistrySimple* registry) { + registry->RegisterDictionaryPref(prefs::kAutozoomNudges); +} + +void AutozoomNudgeController::OnActiveUserPrefServiceChanged( + PrefService* prefs) { + // Reset the nudge prefs so that the nudge can be shown again. This observer + // callback is only registered and called when + // features::kAutozoomNudgeSessionReset is enabled. + DictionaryPrefUpdate update(prefs, prefs::kAutozoomNudges); + update->SetIntPath(kShownCount, 0); + update->SetPath(kLastTimeShown, base::TimeToValue(base::Time())); + update->SetBoolPath(kHadEnabled, false); +} + +base::Time AutozoomNudgeController::GetTime() { + return base::Time::Now(); +} + +void AutozoomNudgeController::HandleNudgeShown() { + PrefService* prefs = + Shell::Get()->session_controller()->GetLastActiveUserPrefService(); + if (!prefs) + return; + const int shown_count = GetShownCount(prefs); + DictionaryPrefUpdate update(prefs, prefs::kAutozoomNudges); + update->SetIntPath(kShownCount, shown_count + 1); + update->SetPath(kLastTimeShown, base::TimeToValue(GetTime())); +} + +bool AutozoomNudgeController::GetHadEnabled(PrefService* prefs) { + const base::Value* dictionary = prefs->GetDictionary(prefs::kAutozoomNudges); + if (!dictionary) + return false; + return dictionary->FindBoolPath(kHadEnabled).value_or(false); +} + +int AutozoomNudgeController::GetShownCount(PrefService* prefs) { + const base::Value* dictionary = prefs->GetDictionary(prefs::kAutozoomNudges); + if (!dictionary) + return 0; + return dictionary->FindIntPath(kShownCount).value_or(0); +} + +base::Time AutozoomNudgeController::GetLastShownTime(PrefService* prefs) { + const base::Value* dictionary = prefs->GetDictionary(prefs::kAutozoomNudges); + if (!dictionary) + return base::Time(); + absl::optional<base::Time> last_shown_time = + base::ValueToTime(dictionary->FindPath(kLastTimeShown)); + return last_shown_time.value_or(base::Time()); +} + +bool AutozoomNudgeController::ShouldShowNudge(PrefService* prefs) { + if (!prefs) + return false; + + bool had_enabled = GetHadEnabled(prefs); + // We should not show more nudge after user had enabled autozoom before. + if (had_enabled) + return false; + + int nudge_shown_count = GetShownCount(prefs); + // We should not show more nudges after hitting the limit. + if (nudge_shown_count >= kNotificationLimit) + return false; + + base::Time last_shown_time = GetLastShownTime(prefs); + // If the nudge has yet to be shown, we should return true. + if (last_shown_time.is_null()) + return true; + + // We should show the nudge if enough time has passed since the nudge was last + // shown. + return (base::Time::Now() - last_shown_time) > kMinInterval; +} + +void AutozoomNudgeController::OnActiveClientChange( + cros::mojom::CameraClientType type, + bool is_active) { + if (!is_active) + return; + + PrefService* prefs = + Shell::Get()->session_controller()->GetLastActiveUserPrefService(); + if (!ShouldShowNudge(prefs)) + return; + + ShowNudge(); + HandleNudgeShown(); +} + +void AutozoomNudgeController::OnAutozoomStateChanged( + cros::mojom::CameraAutoFramingState state) { + if (state != cros::mojom::CameraAutoFramingState::OFF) { + PrefService* prefs = + Shell::Get()->session_controller()->GetLastActiveUserPrefService(); + if (!prefs) + return; + DictionaryPrefUpdate update(prefs, prefs::kAutozoomNudges); + update->SetBoolPath(kHadEnabled, true); + } +} + +std::unique_ptr<SystemNudge> AutozoomNudgeController::CreateSystemNudge() { + return std::make_unique<AutozoomNudge>(); +} + +} // namespace ash
diff --git a/ash/system/camera/autozoom_nudge_controller.h b/ash/system/camera/autozoom_nudge_controller.h new file mode 100644 index 0000000..10d78a5 --- /dev/null +++ b/ash/system/camera/autozoom_nudge_controller.h
@@ -0,0 +1,71 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_SYSTEM_CAMERA_AUTOZOOM_NUDGE_CONTROLLER_H_ +#define ASH_SYSTEM_CAMERA_AUTOZOOM_NUDGE_CONTROLLER_H_ + +#include "ash/ash_export.h" +#include "ash/public/cpp/session/session_observer.h" +#include "ash/system/camera/autozoom_observer.h" +#include "ash/system/tray/system_nudge_controller.h" +#include "base/time/time.h" +#include "media/capture/video/chromeos/camera_hal_dispatcher_impl.h" + +class PrefService; +class PrefRegistrySimple; + +namespace ash { + +class AutozoomControllerImpl; + +class ASH_EXPORT AutozoomNudgeController + : public SystemNudgeController, + public AutozoomObserver, + public SessionObserver, + public media::CameraActiveClientObserver { + public: + explicit AutozoomNudgeController(AutozoomControllerImpl* controller); + AutozoomNudgeController(const AutozoomNudgeController&) = delete; + AutozoomNudgeController& operator=(const AutozoomNudgeController&) = delete; + ~AutozoomNudgeController() override; + + // SessionObserver: + void OnActiveUserPrefServiceChanged(PrefService* prefs) override; + + // Registers profile prefs. + static void RegisterProfilePrefs(PrefRegistrySimple* registry); + + protected: + // SystemNudgeController: + std::unique_ptr<SystemNudge> CreateSystemNudge() override; + + private: + // Gets whether the user had enabled autozoom before. + bool GetHadEnabled(PrefService* prefs); + // Gets the number of times the nudge has been shown. + int GetShownCount(PrefService* prefs); + // Gets the last time the nudge was shown. + base::Time GetLastShownTime(PrefService* prefs); + // Checks whether another nudge can be shown. + bool ShouldShowNudge(PrefService* prefs); + // Gets the current time. + base::Time GetTime(); + // Resets nudge state and show nudge timer. + void HandleNudgeShown(); + + // AutozoomObserver: + void OnAutozoomStateChanged( + cros::mojom::CameraAutoFramingState state) override; + + // CameraActiveClientObserver: + void OnActiveClientChange(cros::mojom::CameraClientType type, + bool is_active) override; + + // Owned by ash/Shell. + AutozoomControllerImpl* const autozoom_controller_; +}; + +} // namespace ash + +#endif // ASH_SYSTEM_CAMERA_AUTOZOOM_NUDGE_CONTROLLER_H_
diff --git a/ash/system/camera/autozoom_observer.h b/ash/system/camera/autozoom_observer.h new file mode 100644 index 0000000..6dd5430 --- /dev/null +++ b/ash/system/camera/autozoom_observer.h
@@ -0,0 +1,22 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_SYSTEM_CAMERA_AUTOZOOM_OBSERVER_H_ +#define ASH_SYSTEM_CAMERA_AUTOZOOM_OBSERVER_H_ + +#include "base/observer_list_types.h" +#include "media/capture/video/chromeos/mojom/cros_camera_service.mojom.h" + +namespace ash { + +class AutozoomObserver : public base::CheckedObserver { + public: + // Called when the autozoom state has changed. + virtual void OnAutozoomStateChanged( + cros::mojom::CameraAutoFramingState state) {} +}; + +} // namespace ash + +#endif // ASH_SYSTEM_CAMERA_AUTOZOOM_OBSERVER_H_
diff --git a/ash/system/camera/autozoom_toast_controller.cc b/ash/system/camera/autozoom_toast_controller.cc new file mode 100644 index 0000000..e79ff77 --- /dev/null +++ b/ash/system/camera/autozoom_toast_controller.cc
@@ -0,0 +1,191 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/system/camera/autozoom_toast_controller.h" + +#include "ash/accessibility/accessibility_controller_impl.h" +#include "ash/shelf/shelf.h" +#include "ash/shell.h" +#include "ash/system/camera/autozoom_controller_impl.h" +#include "ash/system/tray/tray_constants.h" +#include "ash/system/tray/tray_utils.h" +#include "ash/system/unified/unified_system_tray.h" +#include "base/cxx17_backports.h" + +namespace ash { + +AutozoomToastController::Delegate::Delegate() = default; + +void AutozoomToastController::Delegate::AddAutozoomObserver( + AutozoomObserver* observer) { + Shell::Get()->autozoom_controller()->AddObserver(observer); +} + +void AutozoomToastController::Delegate::RemoveAutozoomObserver( + AutozoomObserver* observer) { + Shell::Get()->autozoom_controller()->RemoveObserver(observer); +} + +void AutozoomToastController::Delegate::AddCameraActiveClientObserver( + media::CameraActiveClientObserver* observer) { + auto* camera_hal_dispatcher = media::CameraHalDispatcherImpl::GetInstance(); + if (camera_hal_dispatcher) { + camera_hal_dispatcher->AddActiveClientObserver(observer); + } +} + +void AutozoomToastController::Delegate::RemoveCameraActiveClientObserver( + media::CameraActiveClientObserver* observer) { + auto* camera_hal_dispatcher = media::CameraHalDispatcherImpl::GetInstance(); + if (camera_hal_dispatcher) { + camera_hal_dispatcher->RemoveActiveClientObserver(observer); + } +} + +bool AutozoomToastController::Delegate::AutozoomEnabled() { + return Shell::Get()->autozoom_controller()->GetState() != + cros::mojom::CameraAutoFramingState::OFF; +} + +AutozoomToastController::AutozoomToastController( + UnifiedSystemTray* tray, + std::unique_ptr<Delegate> delegate) + : tray_(tray), delegate_(std::move(delegate)) { + delegate_->AddAutozoomObserver(this); + delegate_->AddCameraActiveClientObserver(this); +} + +AutozoomToastController::~AutozoomToastController() { + if (bubble_widget_ && !bubble_widget_->IsClosed()) + bubble_widget_->CloseNow(); + delegate_->RemoveCameraActiveClientObserver(this); + delegate_->RemoveAutozoomObserver(this); +} + +void AutozoomToastController::ShowToast() { + // If the bubble already exists, update the content of the bubble and extend + // the autoclose timer. + if (bubble_widget_) { + UpdateToastView(); + if (!mouse_hovered_) + StartAutoCloseTimer(); + return; + } + + tray_->CloseSecondaryBubbles(); + + TrayBubbleView::InitParams init_params; + init_params.shelf_alignment = tray_->shelf()->alignment(); + init_params.preferred_width = kAutozoomToastMinWidth; + init_params.delegate = GetWeakPtr(); + init_params.parent_window = tray_->GetBubbleWindowContainer(); + init_params.anchor_view = nullptr; + init_params.anchor_mode = TrayBubbleView::AnchorMode::kRect; + init_params.anchor_rect = tray_->shelf()->GetSystemTrayAnchorRect(); + // Decrease bottom and right insets to compensate for the adjustment of + // the respective edges in Shelf::GetSystemTrayAnchorRect(). + init_params.insets = GetTrayBubbleInsets(); + init_params.translucent = true; + + auto bubble_view = std::make_unique<TrayBubbleView>(init_params); + // bubble_view_ is owned by the view hierarchy and not by this class. + bubble_view_ = bubble_view.get(); + toast_view_ = + bubble_view->AddChildView(std::make_unique<AutozoomToastView>(this)); + + bubble_widget_ = + views::BubbleDialogDelegateView::CreateBubble(std::move(bubble_view)); + + TrayBackgroundView::InitializeBubbleAnimations(bubble_widget_); + bubble_view_->InitializeAndShowBubble(); + + StartAutoCloseTimer(); + UpdateToastView(); + + tray_->SetTrayBubbleHeight( + bubble_widget_->GetWindowBoundsInScreen().height()); +} + +void AutozoomToastController::HideToast() { + close_timer_.Stop(); + if (!bubble_widget_ || bubble_widget_->IsClosed()) + return; + bubble_widget_->Close(); + tray_->SetTrayBubbleHeight(0); +} + +void AutozoomToastController::BubbleViewDestroyed() { + close_timer_.Stop(); + bubble_view_ = nullptr; + bubble_widget_ = nullptr; +} + +void AutozoomToastController::OnMouseEnteredView() { + close_timer_.Stop(); + mouse_hovered_ = true; +} + +void AutozoomToastController::OnMouseExitedView() { + StartAutoCloseTimer(); + mouse_hovered_ = false; +} + +std::u16string AutozoomToastController::GetAccessibleNameForBubble() { + if (!toast_view_) + return std::u16string(); + return toast_view_->GetAccessibleName(); +} + +void AutozoomToastController::StartAutoCloseTimer() { + close_timer_.Stop(); + + // Don't start the timer if the toast is focused. + if (toast_view_ && toast_view_->IsButtonFocused()) + return; + + int autoclose_delay = kTrayPopupAutoCloseDelayInSeconds; + if (Shell::Get()->accessibility_controller()->spoken_feedback().enabled()) + autoclose_delay = kTrayPopupAutoCloseDelayInSecondsWithSpokenFeedback; + + close_timer_.Start(FROM_HERE, base::Seconds(autoclose_delay), this, + &AutozoomToastController::HideToast); +} + +void AutozoomToastController::OnAutozoomStateChanged( + cros::mojom::CameraAutoFramingState state) { + if (state == cros::mojom::CameraAutoFramingState::OFF) { + // TODO(pihsun): Should we hide toast immediately when the autozoom is + // toggled off while the toast is showing? Or should there be a "Autozoom + // is off" toast? + HideToast(); + } +} + +void AutozoomToastController::UpdateToastView() { + if (toast_view_) { + toast_view_->SetAutozoomEnabled(/*enabled=*/delegate_->AutozoomEnabled()); + int width = base::clamp(toast_view_->GetPreferredSize().width(), + kAutozoomToastMinWidth, kAutozoomToastMaxWidth); + bubble_view_->SetPreferredWidth(width); + } +} + +void AutozoomToastController::StopAutocloseTimer() { + close_timer_.Stop(); +} + +void AutozoomToastController::OnActiveClientChange( + cros::mojom::CameraClientType type, + bool is_active) { + // TODO(pihsun): Should this only be shown for some client type? + if (is_active) { + if (delegate_->AutozoomEnabled()) { + ShowToast(); + } else { + HideToast(); + } + } +} + +} // namespace ash
diff --git a/ash/system/camera/autozoom_toast_controller.h b/ash/system/camera/autozoom_toast_controller.h new file mode 100644 index 0000000..6048fe9 --- /dev/null +++ b/ash/system/camera/autozoom_toast_controller.h
@@ -0,0 +1,105 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_SYSTEM_CAMERA_AUTOZOOM_TOAST_CONTROLLER_H_ +#define ASH_SYSTEM_CAMERA_AUTOZOOM_TOAST_CONTROLLER_H_ + +#include "ash/ash_export.h" +#include "ash/system/camera/autozoom_observer.h" +#include "ash/system/camera/autozoom_toast_view.h" +#include "ash/system/tray/tray_bubble_view.h" +#include "base/timer/timer.h" +#include "media/capture/video/chromeos/camera_hal_dispatcher_impl.h" + +namespace ash { + +class UnifiedSystemTray; + +// Controller class for the autozoom toast, which is shown when the autozoom is +// on and camera is opened. +class ASH_EXPORT AutozoomToastController + : public TrayBubbleView::Delegate, + public AutozoomObserver, + public media::CameraActiveClientObserver { + public: + // The Delegate interface handles adding and removing observers on behalf of + // AutozoomToastController. This is used for unit tests. + class ASH_EXPORT Delegate { + public: + Delegate(); + + Delegate(const Delegate&) = delete; + Delegate& operator=(const Delegate&) = delete; + + virtual ~Delegate() = default; + + virtual void AddAutozoomObserver(AutozoomObserver* observer); + + virtual void RemoveAutozoomObserver(AutozoomObserver* observer); + + virtual void AddCameraActiveClientObserver( + media::CameraActiveClientObserver* observer); + + virtual void RemoveCameraActiveClientObserver( + media::CameraActiveClientObserver* observer); + + virtual bool AutozoomEnabled(); + }; + + AutozoomToastController(UnifiedSystemTray* tray, + std::unique_ptr<Delegate> delegate); + AutozoomToastController(AutozoomToastController&) = delete; + AutozoomToastController operator=(AutozoomToastController&) = delete; + ~AutozoomToastController() override; + + // Shows the toast explicitly. Normally this is shown when there's a new + // active camera client and autozoom is enabled. + void ShowToast(); + + // Hides the toast if it is shown. Normally, it times out and automatically + // closes. + void HideToast(); + + // Stops the timer to autoclose the toast. + void StopAutocloseTimer(); + + // Triggers a timer to automatically close the toast. + void StartAutoCloseTimer(); + + protected: + views::Widget* bubble_widget_for_test() { return bubble_widget_; } + + private: + friend class AutozoomToastControllerTest; + + // AutozoomObserver: + void OnAutozoomStateChanged( + cros::mojom::CameraAutoFramingState state) override; + + // CameraActiveClientObserver: + void OnActiveClientChange(cros::mojom::CameraClientType type, + bool is_active) override; + + // Updates the toast UI with the current privacy screen state. + void UpdateToastView(); + + // TrayBubbleView::Delegate: + void BubbleViewDestroyed() override; + void OnMouseEnteredView() override; + void OnMouseExitedView() override; + std::u16string GetAccessibleNameForBubble() override; + + UnifiedSystemTray* const tray_; + TrayBubbleView* bubble_view_ = nullptr; + views::Widget* bubble_widget_ = nullptr; + AutozoomToastView* toast_view_ = nullptr; + bool mouse_hovered_ = false; + base::OneShotTimer close_timer_; + + const std::unique_ptr<Delegate> delegate_; +}; + +} // namespace ash + +#endif // ASH_SYSTEM_CAMERA_AUTOZOOM_TOAST_CONTROLLER_H_
diff --git a/ash/system/camera/autozoom_toast_controller_unittest.cc b/ash/system/camera/autozoom_toast_controller_unittest.cc new file mode 100644 index 0000000..930b74c --- /dev/null +++ b/ash/system/camera/autozoom_toast_controller_unittest.cc
@@ -0,0 +1,110 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/system/camera/autozoom_toast_controller.h" + +#include "ash/system/unified/unified_system_tray.h" +#include "ash/test/ash_test_base.h" + +namespace ash { + +class TestDelegate : public AutozoomToastController::Delegate { + public: + void AddAutozoomObserver(AutozoomObserver* observer) override { + ASSERT_EQ(autozoom_observer, nullptr); + autozoom_observer = observer; + } + + void RemoveAutozoomObserver(AutozoomObserver* observer) override { + ASSERT_EQ(autozoom_observer, observer); + autozoom_observer = nullptr; + } + + void AddCameraActiveClientObserver( + media::CameraActiveClientObserver* observer) override { + ASSERT_EQ(camera_observer, nullptr); + camera_observer = observer; + } + + void RemoveCameraActiveClientObserver( + media::CameraActiveClientObserver* observer) override { + ASSERT_EQ(camera_observer, observer); + camera_observer = nullptr; + } + + bool AutozoomEnabled() override { return autozoom_enabled_; } + + void SetAutozoomEnabled(bool autozoom_enabled) { + autozoom_enabled_ = autozoom_enabled; + if (autozoom_observer != nullptr) { + autozoom_observer->OnAutozoomStateChanged( + autozoom_enabled_ ? cros::mojom::CameraAutoFramingState::ON_SINGLE + : cros::mojom::CameraAutoFramingState::OFF); + } + } + + void SetCameraActive(bool is_active) { + ASSERT_NE(camera_observer, nullptr); + camera_observer->OnActiveClientChange( + cros::mojom::CameraClientType::ASH_CHROME, is_active); + } + + AutozoomObserver* autozoom_observer = nullptr; + media::CameraActiveClientObserver* camera_observer = nullptr; + + private: + bool autozoom_enabled_ = false; +}; + +class AutozoomToastControllerTest : public AshTestBase { + public: + AutozoomToastControllerTest() = default; + ~AutozoomToastControllerTest() override = default; + + AutozoomToastControllerTest(const AutozoomToastControllerTest&) = delete; + AutozoomToastControllerTest& operator=(const AutozoomToastControllerTest&) = + delete; + + // AshTestBase: + void SetUp() override { + AshTestBase::SetUp(); + auto delegate = std::make_unique<TestDelegate>(); + delegate_ = delegate.get(); + controller_ = std::make_unique<AutozoomToastController>( + GetPrimaryUnifiedSystemTray(), std::move(delegate)); + } + + void TearDown() override { + controller_ = nullptr; + delegate_ = nullptr; + AshTestBase::TearDown(); + } + + views::Widget* bubble_widget() { + return controller_->bubble_widget_for_test(); + } + + std::unique_ptr<AutozoomToastController> controller_; + TestDelegate* delegate_; +}; + +TEST_F(AutozoomToastControllerTest, ShowToastWhenCameraActive) { + EXPECT_EQ(bubble_widget(), nullptr); + + // No toast when enabling camera when autozoom is disabled. + delegate_->SetCameraActive(true); + EXPECT_EQ(bubble_widget(), nullptr); + + // No toast when enabling autozoom when camera is already active. + delegate_->SetAutozoomEnabled(true); + EXPECT_EQ(bubble_widget(), nullptr); + + // Toast is shown when autozoom is enabled when camera become active. + delegate_->SetCameraActive(false); + delegate_->SetCameraActive(true); + ASSERT_NE(bubble_widget(), nullptr); + EXPECT_TRUE(bubble_widget()->IsVisible()); +} + +} // namespace ash
diff --git a/ash/system/camera/autozoom_toast_view.cc b/ash/system/camera/autozoom_toast_view.cc new file mode 100644 index 0000000..807f415 --- /dev/null +++ b/ash/system/camera/autozoom_toast_view.cc
@@ -0,0 +1,73 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/system/camera/autozoom_toast_view.h" + +#include "ash/resources/vector_icons/vector_icons.h" +#include "ash/strings/grit/ash_strings.h" +#include "ash/system/camera/autozoom_toast_controller.h" +#include "ash/system/tray/tray_constants.h" +#include "ash/system/unified/feature_pod_button.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/views/controls/button/button.h" +#include "ui/views/controls/label.h" +#include "ui/views/layout/box_layout.h" +#include "ui/views/style/typography.h" + +namespace ash { + +AutozoomToastView::AutozoomToastView(AutozoomToastController* controller) + : controller_(controller) { + auto* layout = SetLayoutManager(std::make_unique<views::BoxLayout>( + views::BoxLayout::Orientation::kHorizontal, kAutozoomToastInsets, + kAutozoomToastSpacing)); + layout->set_cross_axis_alignment( + views::BoxLayout::CrossAxisAlignment::kCenter); + + button_ = AddChildView(std::make_unique<FeaturePodIconButton>( + FeaturePodIconButton::PressedCallback(), + /*is_togglable=*/true)); + button_->SetVectorIcon(kUnifiedMenuAutozoomIcon); + button_->SetToggled(false); + button_->AddObserver(this); + + label_ = AddChildView(std::make_unique<views::Label>()); + label_->SetText( + l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_AUTOZOOM_TOAST_ON_STATE)); + label_->SetFontList( + views::style::GetFont(views::style::TextContext::CONTEXT_DIALOG_TITLE, + views::style::TextStyle::STYLE_PRIMARY)); +} + +AutozoomToastView::~AutozoomToastView() { + button_->RemoveObserver(this); +} + +void AutozoomToastView::SetAutozoomEnabled(bool enabled) { + button_->SetToggled(enabled); + button_->SetTooltipText( + l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_AUTOZOOM_TOAST_ON_STATE)); + + InvalidateLayout(); +} + +std::u16string AutozoomToastView::GetAccessibleName() { + return l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_AUTOZOOM_TOAST_ON_STATE); +} + +bool AutozoomToastView::IsButtonFocused() const { + return button_->HasFocus(); +} + +void AutozoomToastView::OnViewFocused(views::View* observed_view) { + DCHECK(observed_view == button_); + controller_->StopAutocloseTimer(); +} + +void AutozoomToastView::OnViewBlurred(views::View* observed_view) { + DCHECK(observed_view == button_); + controller_->StartAutoCloseTimer(); +} + +} // namespace ash
diff --git a/ash/system/camera/autozoom_toast_view.h b/ash/system/camera/autozoom_toast_view.h new file mode 100644 index 0000000..b498eef --- /dev/null +++ b/ash/system/camera/autozoom_toast_view.h
@@ -0,0 +1,48 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_SYSTEM_CAMERA_AUTOZOOM_TOAST_VIEW_H_ +#define ASH_SYSTEM_CAMERA_AUTOZOOM_TOAST_VIEW_H_ + +#include "ash/ash_export.h" +#include "ui/views/controls/label.h" +#include "ui/views/view.h" +#include "ui/views/view_observer.h" + +namespace ash { + +class FeaturePodIconButton; +class AutozoomToastController; + +// The view shown inside the autozoom toast bubble. +class ASH_EXPORT AutozoomToastView : public views::View, + public views::ViewObserver { + public: + explicit AutozoomToastView(AutozoomToastController* controller); + AutozoomToastView(AutozoomToastView&) = delete; + AutozoomToastView operator=(AutozoomToastView&) = delete; + ~AutozoomToastView() override; + + // Updates the toast with whether autozoom is enabled. + void SetAutozoomEnabled(bool enabled); + + // Returns the accessible name for the view. + std::u16string GetAccessibleName(); + + // Returns true if the toggle button is focused. + bool IsButtonFocused() const; + + private: + // views::ViewObserver: + void OnViewFocused(views::View* observed_view) override; + void OnViewBlurred(views::View* observed_view) override; + + AutozoomToastController* controller_ = nullptr; + FeaturePodIconButton* button_ = nullptr; + views::Label* label_ = nullptr; +}; + +} // namespace ash + +#endif // ASH_SYSTEM_CAMERA_AUTOZOOM_TOAST_VIEW_H_
diff --git a/ash/system/tray/tray_constants.h b/ash/system/tray/tray_constants.h index ccc15cc..b8a6b58 100644 --- a/ash/system/tray/tray_constants.h +++ b/ash/system/tray/tray_constants.h
@@ -250,6 +250,13 @@ // dark mode. Sets the icon color to be constant. constexpr SkColor kIconColorInOobe = gfx::kGoogleGrey700; +// Constants used for the autozoom toast. +constexpr int kAutozoomToastMinWidth = 160; +constexpr int kAutozoomToastMaxWidth = 320; +constexpr int kAutozoomToastMainLabelFontSize = 14; +constexpr auto kAutozoomToastInsets = gfx::Insets::VH(10, 16); +constexpr int kAutozoomToastSpacing = 16; + } // namespace ash #endif // ASH_SYSTEM_TRAY_TRAY_CONSTANTS_H_
diff --git a/ash/system/unified/unified_system_tray.cc b/ash/system/unified/unified_system_tray.cc index 952e84f..c6930e2 100644 --- a/ash/system/unified/unified_system_tray.cc +++ b/ash/system/unified/unified_system_tray.cc
@@ -12,6 +12,7 @@ #include "ash/shell.h" #include "ash/shell_delegate.h" #include "ash/strings/grit/ash_strings.h" +#include "ash/system/camera/autozoom_toast_controller.h" #include "ash/system/channel_indicator/channel_indicator.h" #include "ash/system/human_presence/snooping_protection_view.h" #include "ash/system/message_center/ash_message_popup_collection.h" @@ -51,6 +52,7 @@ #include "base/strings/string_util.h" #include "base/time/time.h" #include "base/timer/timer.h" +#include "media/capture/video/chromeos/video_capture_features_chromeos.h" #include "ui/base/l10n/l10n_util.h" #include "ui/compositor/presentation_time_recorder.h" #include "ui/display/display.h" @@ -189,6 +191,11 @@ mic_view_( new CameraMicTrayItemView(shelf, CameraMicTrayItemView::Type::kMic)), time_view_(new TimeTrayItemView(shelf, TimeView::Type::kTime)) { + if (media::ShouldEnableAutoFraming()) { + autozoom_toast_controller_ = std::make_unique<AutozoomToastController>( + this, std::make_unique<AutozoomToastController::Delegate>()); + } + tray_container()->SetMargin( kUnifiedTrayContentPadding - ShelfConfig::Get()->status_area_hit_region_padding(), @@ -336,6 +343,8 @@ void UnifiedSystemTray::CloseSecondaryBubbles() { slider_bubble_controller_->CloseBubble(); privacy_screen_toast_controller_->HideToast(); + if (autozoom_toast_controller_) + autozoom_toast_controller_->HideToast(); } void UnifiedSystemTray::CollapseMessageCenter() {
diff --git a/ash/system/unified/unified_system_tray.h b/ash/system/unified/unified_system_tray.h index 03670504..0424830 100644 --- a/ash/system/unified/unified_system_tray.h +++ b/ash/system/unified/unified_system_tray.h
@@ -29,6 +29,7 @@ namespace ash { +class AutozoomToastController; class AshMessagePopupCollection; class CameraMicTrayItemView; class ChannelIndicatorView; @@ -280,6 +281,8 @@ const std::unique_ptr<PrivacyScreenToastController> privacy_screen_toast_controller_; + std::unique_ptr<AutozoomToastController> autozoom_toast_controller_; + // Manages showing notification icons in the tray. const std::unique_ptr<NotificationIconsController> notification_icons_controller_;
diff --git a/ash/webui/camera_app_ui/BUILD.gn b/ash/webui/camera_app_ui/BUILD.gn index 499c5ca..82def91 100644 --- a/ash/webui/camera_app_ui/BUILD.gn +++ b/ash/webui/camera_app_ui/BUILD.gn
@@ -82,6 +82,7 @@ public_deps = [ "//dbus" ] deps = [ + "//ash/constants", "//base", "//chromeos/dbus/dlcservice", "//chromeos/dbus/dlcservice:dlcservice_proto",
diff --git a/ash/webui/camera_app_ui/document_scanner_service_client.cc b/ash/webui/camera_app_ui/document_scanner_service_client.cc index af18616..5d15cc9 100644 --- a/ash/webui/camera_app_ui/document_scanner_service_client.cc +++ b/ash/webui/camera_app_ui/document_scanner_service_client.cc
@@ -4,6 +4,7 @@ #include "ash/webui/camera_app_ui/document_scanner_service_client.h" +#include "ash/constants/ash_features.h" #include "ash/webui/camera_app_ui/document_scanner_installer.h" #include "base/command_line.h" #include "base/memory/ptr_util.h" @@ -42,6 +43,9 @@ // Returns true if switch kOndeviceDocumentScanner is set to use_dlc. bool IsEnabledOnDlc() { + if (!base::FeatureList::IsEnabled(chromeos::features::kCameraAppDocScanDlc)) { + return false; + } return HasCommandLineSwitch(kOndeviceDocumentScanner, "use_dlc"); }
diff --git a/ash/webui/camera_app_ui/resources/css/custom_toast.css b/ash/webui/camera_app_ui/resources/css/custom_toast.css index a99da978..9521954 100644 --- a/ash/webui/camera_app_ui/resources/css/custom_toast.css +++ b/ash/webui/camera_app_ui/resources/css/custom_toast.css
@@ -27,13 +27,13 @@ } @property --toast-element-ref-x { - syntax: 'left | right'; + syntax: 'left | right | center'; inherits: false; initial-value: right; } @property --toast-element-ref-y { - syntax: 'bottom | top'; + syntax: 'bottom | top | middle'; inherits: false; initial-value: top; } @@ -63,13 +63,13 @@ } @property --indicator-dot-element-ref-x { - syntax: 'left | right'; + syntax: 'left | right | center'; inherits: false; initial-value: right; } @property --indicator-dot-element-ref-y { - syntax: 'bottom | top'; + syntax: 'bottom | top | middle'; inherits: false; initial-value: top; } @@ -205,10 +205,41 @@ --toast-ref-y: bottom; --toast-element-ref-y: top; --toast-offset-y: -23px; +} - --indicator-dot-ref-x: right; - --indicator-dot-element-ref-x: right; - --indicator-dot-offset-x: -16px; +#modes-group .mode-item input { + --ripple-start-height: 20px; + --ripple-start-width: 54px; + + --toast-ref-x: right; + --toast-element-ref-x: right; + --toast-offset-x: 0; + + --toast-ref-y: bottom; + --toast-element-ref-y: top; + --toast-offset-y: -30px; + + --indicator-dot-ref-x: left; + --indicator-dot-element-ref-x: center; + --indicator-dot-offset-x: 0px; + + --indicator-dot-ref-y: bottom; + --indicator-dot-element-ref-y: top; + --indicator-dot-offset-y: -14px; +} + +.mode-subgroup .item { + --toast-ref-x: right; + --toast-element-ref-x: right; + --toast-offset-x: 0; + + --toast-ref-y: bottom; + --toast-element-ref-y: top; + --toast-offset-y: -16px; + + --indicator-dot-ref-x: left; + --indicator-dot-element-ref-x: center; + --indicator-dot-offset-x: 0px; --indicator-dot-ref-y: bottom; --indicator-dot-element-ref-y: top;
diff --git a/ash/webui/camera_app_ui/resources/css/main.css b/ash/webui/camera_app_ui/resources/css/main.css index fb6c9d4c..29126b2 100644 --- a/ash/webui/camera_app_ui/resources/css/main.css +++ b/ash/webui/camera_app_ui/resources/css/main.css
@@ -1388,6 +1388,10 @@ visibility: hidden; } +.disabled { + opacity: 0.38; +} + .panel { backdrop-filter: blur(10px); background: rgba(var(--grey-900-rgb), 0.9);
diff --git a/ash/webui/camera_app_ui/resources/js/custom_effect.ts b/ash/webui/camera_app_ui/resources/js/custom_effect.ts index 6a50bdc..c1574ae8e5 100644 --- a/ash/webui/camera_app_ui/resources/js/custom_effect.ts +++ b/ash/webui/camera_app_ui/resources/js/custom_effect.ts
@@ -3,10 +3,12 @@ // found in the LICENSE file. import * as animation from './animation.js'; -import {assertExists, assertInstanceof, assertNotReached} from './assert.js'; +import {assertExists, assertNotReached} from './assert.js'; import * as dom from './dom.js'; import {I18nString} from './i18n_string.js'; import * as loadTimeData from './models/load_time_data.js'; +import {ChromeHelper} from './mojo/chrome_helper.js'; +import * as state from './state.js'; import * as util from './util.js'; /** @@ -77,7 +79,9 @@ enum PositionProperty { BOTTOM = 'bottom', + CENTER = 'center', LEFT = 'left', + MIDDLE = 'middle', RIGHT = 'right', TOP = 'top', } @@ -95,12 +99,32 @@ export enum IndicatorType { DOWNLOAD_DOCUMENT_SCANNER = 'download_document_scanner', + DOC_SCAN_AVAILABLE = 'doc_scan_available', +} + +/** + * Setup the required state observers to dismiss toasts when changing + * modes/cameras. + */ +export function setup(): void { + state.addObserver(state.State.CAMERA_SWITCHING, (val) => { + if (val) { + hide(); + } + }); + state.addObserver(state.State.MODE_SWITCHING, (val) => { + if (val) { + hide(); + } + }); } function getIndicatorI18nStringId(indicatorType: IndicatorType): I18nString { switch (indicatorType) { case IndicatorType.DOWNLOAD_DOCUMENT_SCANNER: return I18nString.DOWNLOADING_DOCUMENT_SCANNING_FEATURE; + case IndicatorType.DOC_SCAN_AVAILABLE: + return I18nString.NEW_DOCUMENT_SCAN_TOAST; default: assertNotReached(); } @@ -110,6 +134,8 @@ switch (indicatorType) { case IndicatorType.DOWNLOAD_DOCUMENT_SCANNER: return '/images/download_dlc_toast_icon.svg'; + case IndicatorType.DOC_SCAN_AVAILABLE: + return '/images/new_feature_toast_icon.svg'; default: return null; } @@ -151,7 +177,15 @@ } style.clear(); for (const {elProperty, toastProperty, offset} of properties) { - let value = rect[elProperty] + offset; + let value; + if (elProperty === PositionProperty.CENTER) { + value = rect.left + offset + rect.width / 2; + } else if (elProperty === PositionProperty.MIDDLE) { + value = rect.top + offset + rect.height / 2; + } else { + value = rect[elProperty] + offset; + } + if (toastProperty === PositionProperty.RIGHT) { value = window.innerWidth - value; } else if (toastProperty === PositionProperty.BOTTOM) { @@ -191,7 +225,7 @@ this.anchor.removeAttribute('aria-owns'); clearInterval(this.cancelHandle); for (const {target} of this.positionInfos) { - document.body.removeChild(target); + target.remove(); } } } @@ -366,27 +400,21 @@ } /** - * Shows feature visual effect for document mode entry. + * Shows document scan feature is available indicator on the scan mode button. */ -export function showDocToast(): void { +export function showDocScanAvailableIndicator(): void { const scanModeButton = dom.get('input[data-mode="scan"]', HTMLInputElement); - const scanModeItem = - assertInstanceof(scanModeButton.parentElement, HTMLDivElement); - // aria-owns don't work on HTMLInputElement, show toast on parent div - // instead. - const {hide} = showNewFeature(scanModeItem); - scanModeButton.addEventListener('click', hide, {once: true}); + showIndicator(scanModeButton, IndicatorType.DOC_SCAN_AVAILABLE); } /** * Shows loading indicator toast for document mode when it's supported but not * yet ready. */ -export function showDocIndicator(): void { - const scanModeButton = dom.get('input[data-mode="scan"]', HTMLInputElement); - const scanModeItem = - assertInstanceof(scanModeButton.parentElement, HTMLDivElement); +export async function showDownloadingDocScanIndicator(): Promise<void> { + const docModeButton = dom.get('#scan-document-option', HTMLDivElement); const {hide} = - showIndicator(scanModeItem, IndicatorType.DOWNLOAD_DOCUMENT_SCANNER); - scanModeButton.addEventListener('click', hide, {once: true}); + showIndicator(docModeButton, IndicatorType.DOWNLOAD_DOCUMENT_SCANNER); + await ChromeHelper.getInstance().waitUntilDocumentModeReady(); + hide(); }
diff --git a/ash/webui/camera_app_ui/resources/js/main.ts b/ash/webui/camera_app_ui/resources/js/main.ts index b462e9f..0223a38d 100644 --- a/ash/webui/camera_app_ui/resources/js/main.ts +++ b/ash/webui/camera_app_ui/resources/js/main.ts
@@ -114,6 +114,7 @@ window.addEventListener('resize', () => nav.layoutShownViews()); windowController.addListener(() => nav.layoutShownViews()); + customEffect.setup(); util.setupI18nElements(document.body); this.setupToggles(); localStorage.cleanup(); @@ -190,13 +191,23 @@ * Sets up visual effects, toasts, and dialogs for the new features. */ async setupFeatureEffectsAndDialogs(): Promise<void> { - const registerDocDialog = () => { + const registerDocScanIntroductionDialog = () => { this.cameraManager.registerCameraUI({ - onUpdateConfig: () => { + onUpdateConfig: async () => { if (localStorage.getBool(LocalStorageKey.DOC_MODE_DIALOG_SHOWN) || !state.get(Mode.SCAN)) { return; } + + const {ready} = + await ChromeHelper.getInstance().getDocumentScannerReadyState(); + if (!ready) { + return; + } + // No need to show doc scan feature toast if the user has already seen + // the doc scan mode. + localStorage.set(LocalStorageKey.DOC_MODE_TOAST_SHOWN, true); + localStorage.set(LocalStorageKey.DOC_MODE_DIALOG_SHOWN, true); const message = loadTimeData.getI18nMessage( I18nString.DOCUMENT_MODE_DIALOG_INTRO_TITLE); @@ -204,6 +215,20 @@ }, }); }; + const registerDownloadingDocScanIndicator = () => { + let hasShownDocIndicator = false; + this.cameraManager.registerCameraUI({ + onUpdateConfig: async () => { + const {ready} = + await ChromeHelper.getInstance().getDocumentScannerReadyState(); + if (ready || !state.get(Mode.SCAN) || hasShownDocIndicator) { + return; + } + customEffect.showDownloadingDocScanIndicator(); + hasShownDocIndicator = true; + }, + }); + }; const registerPtzToast = () => { this.cameraManager.registerCameraUI({ onUpdateConfig: () => { @@ -218,26 +243,15 @@ const {supported, ready} = await ChromeHelper.getInstance().getDocumentScannerReadyState(); - // TODO(chuhsuan): Separate loading indicators and feature toasts in - // order to provide more control like showing them at the same time. - if (supported) { - if (!ready) { - customEffect.showDocIndicator(); - } - const loaded = - await ChromeHelper.getInstance().waitUntilDocumentModeReady(); - if (loaded) { - if (!localStorage.getBool(LocalStorageKey.DOC_MODE_DIALOG_SHOWN)) { - registerDocDialog(); - } - if (!localStorage.getBool(LocalStorageKey.DOC_MODE_TOAST_SHOWN)) { - localStorage.set(LocalStorageKey.DOC_MODE_TOAST_SHOWN, true); - customEffect.showDocToast(); - return; - } - } - } - if (!localStorage.getBool(LocalStorageKey.PTZ_TOAST_SHOWN)) { + + // Handling logic for new feature toast. + if (supported && ready && + !localStorage.getBool(LocalStorageKey.DOC_MODE_TOAST_SHOWN)) { + // Only show new feature indicator for doc scan if it is ready when + // starting the app. + localStorage.set(LocalStorageKey.DOC_MODE_TOAST_SHOWN, true); + customEffect.showDocScanAvailableIndicator(); + } else if (!localStorage.getBool(LocalStorageKey.PTZ_TOAST_SHOWN)) { if (state.get(state.State.ENABLE_PTZ)) { localStorage.set(LocalStorageKey.PTZ_TOAST_SHOWN, true); customEffect.showPtzToast(); @@ -245,6 +259,18 @@ registerPtzToast(); } } + + + // TODO(chuhsuan): Separate loading indicators and feature toasts in + // order to provide more control like showing them at the same time. + if (supported) { + if (!localStorage.getBool(LocalStorageKey.DOC_MODE_DIALOG_SHOWN)) { + registerDocScanIntroductionDialog(); + } + if (!ready) { + registerDownloadingDocScanIndicator(); + } + } } /**
diff --git a/ash/webui/camera_app_ui/resources/js/views/camera/scan_options.ts b/ash/webui/camera_app_ui/resources/js/views/camera/scan_options.ts index d723fff..7d24363f 100644 --- a/ash/webui/camera_app_ui/resources/js/views/camera/scan_options.ts +++ b/ash/webui/camera_app_ui/resources/js/views/camera/scan_options.ts
@@ -67,6 +67,12 @@ // ready. dom.get('#scan-barcode', HTMLInputElement).checked = true; + (async () => { + const {supported} = + await ChromeHelper.getInstance().getDocumentScannerReadyState(); + dom.get('#scan-document-option', HTMLElement).hidden = !supported; + })(); + for (const option of this.scanOptions) { option.addEventListener('click', (evt) => { if (state.get(state.State.CAMERA_CONFIGURING)) { @@ -81,11 +87,6 @@ } } - setDocumentModeEnabled(enabled: boolean): void { - const documentModeBtn = dom.get('#scan-document-option', HTMLDivElement); - documentModeBtn.hidden = !enabled; - } - async waitUntilDocumentModeReady(): Promise<boolean> { const isLoaded = await ChromeHelper.getInstance().waitUntilDocumentModeReady(); @@ -96,10 +97,14 @@ } onDocumentModeReady(): void { + const docModeOption = dom.get('#scan-document-option', HTMLDivElement); + docModeOption.classList.remove('disabled'); + + const docBtn = dom.get('#scan-document', HTMLInputElement); + docBtn.disabled = false; if (!state.get(Mode.SCAN)) { - dom.get('#scan-document', HTMLInputElement).checked = true; + docBtn.checked = true; } - this.setDocumentModeEnabled(true); } /**
diff --git a/ash/webui/camera_app_ui/resources/strings/camera_strings.grd b/ash/webui/camera_app_ui/resources/strings/camera_strings.grd index cb4bccf84..99d0fac 100644 --- a/ash/webui/camera_app_ui/resources/strings/camera_strings.grd +++ b/ash/webui/camera_app_ui/resources/strings/camera_strings.grd
@@ -205,7 +205,7 @@ Pan tilt zoom </message> <message desc="Toast message notifying user about new document scanning feature is available" name="IDS_NEW_DOCUMENT_SCAN_TOAST"> - Document scanning now available + Document scan available </message> <message desc="Toast message notifying user about new controls available" name="IDS_NEW_CONTROL_TOAST"> Additional camera controls available @@ -696,7 +696,7 @@ Toggle microphone mute. Mute is on </message> <message desc="Toast message notifying user about the document scanner feature is currently downloading" name="IDS_DOWNLOADING_DOCUMENT_SCANNING_FEATURE"> - Downloading document scanning feature + Downloading updates for document scanning </message> </messages> </release>
diff --git a/ash/webui/camera_app_ui/resources/strings/camera_strings_grd/IDS_DOWNLOADING_DOCUMENT_SCANNING_FEATURE.png.sha1 b/ash/webui/camera_app_ui/resources/strings/camera_strings_grd/IDS_DOWNLOADING_DOCUMENT_SCANNING_FEATURE.png.sha1 index e5d73d1..33e1b0ec 100644 --- a/ash/webui/camera_app_ui/resources/strings/camera_strings_grd/IDS_DOWNLOADING_DOCUMENT_SCANNING_FEATURE.png.sha1 +++ b/ash/webui/camera_app_ui/resources/strings/camera_strings_grd/IDS_DOWNLOADING_DOCUMENT_SCANNING_FEATURE.png.sha1
@@ -1 +1 @@ -fe44e7853755d47f1aa443edba1dfd719c8295cc \ No newline at end of file +58533ed43ca74551145ca407233995f481a4cc0b \ No newline at end of file
diff --git a/ash/webui/camera_app_ui/resources/strings/camera_strings_grd/IDS_NEW_DOCUMENT_SCAN_TOAST.png.sha1 b/ash/webui/camera_app_ui/resources/strings/camera_strings_grd/IDS_NEW_DOCUMENT_SCAN_TOAST.png.sha1 index cbebc148..cbacb88 100644 --- a/ash/webui/camera_app_ui/resources/strings/camera_strings_grd/IDS_NEW_DOCUMENT_SCAN_TOAST.png.sha1 +++ b/ash/webui/camera_app_ui/resources/strings/camera_strings_grd/IDS_NEW_DOCUMENT_SCAN_TOAST.png.sha1
@@ -1 +1 @@ -de621e91ebb96e729b1f763fcc42b59c5fdffcfc \ No newline at end of file +4a2a10148926a071e0e583796a2f238c546927a3 \ No newline at end of file
diff --git a/ash/webui/camera_app_ui/resources/views/main.html b/ash/webui/camera_app_ui/resources/views/main.html index 4ef1df6..9fbdd74 100644 --- a/ash/webui/camera_app_ui/resources/views/main.html +++ b/ash/webui/camera_app_ui/resources/views/main.html
@@ -140,10 +140,10 @@ </div> <div id="scan-modes-group" class="mode-subgroup" role="radiogroup" i18n-aria="aria_scan_type_group"> - <div id="scan-document-option" class="item" hidden> + <div id="scan-document-option" class="item disabled"> <input id="scan-document" type="radio" tabindex="0" name="scan-type" data-scantype="document" - i18n-aria="scan_document_option"> + i18n-aria="scan_document_option" disabled> <div class="label" i18n-text="label_scan_document_option" aria-hidden="true"></div> </div> @@ -218,7 +218,7 @@ <span i18n-text="label_switch_take_photo_button" aria-hidden="true"></span> </div> - <div class="mode-item" i18n-new-feature="new_document_scan_toast"> + <div class="mode-item"> <input type="radio" name="mode" data-mode="scan" tabindex="0" i18n-aria="switch_scan_mode_button">
diff --git a/ash/wm/window_positioning_utils.cc b/ash/wm/window_positioning_utils.cc index c40d016..152d6242 100644 --- a/ash/wm/window_positioning_utils.cc +++ b/ash/wm/window_positioning_utils.cc
@@ -210,7 +210,7 @@ const display::Display& display) { // This function is used by `GetSnappedWindowBounds()` for clamshell mode // only. Tablet mode uses a different function - // `SplitViewController::GetSnappedWindowBoundsInScreen()`. + // `SplitViewController::GetSnappedWindowBoundsInScreen()`1. auto* tablet_mode_controller = Shell::Get()->tablet_mode_controller(); DCHECK(!tablet_mode_controller || !tablet_mode_controller->InTabletMode()); @@ -232,7 +232,6 @@ void SetBoundsInScreen(aura::Window* window, const gfx::Rect& bounds_in_screen, const display::Display& display) { - DCHECK_NE(display::kInvalidDisplayId, display.id()); // Don't move a window to other root window if: // a) the window is a transient window. It moves when its // transient parent moves. @@ -277,11 +276,15 @@ gfx::Rect new_bounds = gfx::Rect(origin, bounds_in_screen.size()); // Set new bounds now so that the container's layout manager can adjust // the bounds if necessary. + if (window_state) + window_state->set_is_moving_to_another_display(true); window->SetBounds(new_bounds); } - dst_container->AddChild(window); + if (window_state) + window_state->set_is_moving_to_another_display(false); + // Restore focused/active window. if (focused && tracker.Contains(focused)) { aura::client::GetFocusClient(focused)->FocusWindow(focused);
diff --git a/ash/wm/window_state.h b/ash/wm/window_state.h index 0332cd4a..428adbf 100644 --- a/ash/wm/window_state.h +++ b/ash/wm/window_state.h
@@ -173,6 +173,14 @@ // Returns true if the window's location can be controlled by the user. bool IsUserPositionable() const; + bool is_moving_to_another_display() const { + return is_moving_to_another_display_; + } + void set_is_moving_to_another_display(bool moving) { + is_moving_to_another_display_ = moving; + } + bool is_moving_to_another_display_ = false; + // Checks if the window can change its state accordingly. bool CanMaximize() const; bool CanMinimize() const;
diff --git a/base/time/time.cc b/base/time/time.cc index 92e2c1a..6c58068 100644 --- a/base/time/time.cc +++ b/base/time/time.cc
@@ -28,6 +28,8 @@ const char kMonthName[12][4] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; +TimeTicks g_shared_time_ticks_at_unix_epoch; + } // namespace namespace internal { @@ -324,12 +326,32 @@ } // static +// This method should be called once at process start and before +// TimeTicks::UnixEpoch is accessed. It is intended to make the offset between +// unix time and monotonic time consistent across processes. +void TimeTicks::SetSharedUnixEpoch(TimeTicks ticks_at_epoch) { + DCHECK(g_shared_time_ticks_at_unix_epoch.is_null()); + g_shared_time_ticks_at_unix_epoch = ticks_at_epoch; +} + +// static TimeTicks TimeTicks::UnixEpoch() { - static const TimeTicks epoch([]() { - return subtle::TimeTicksNowIgnoringOverride() - - (subtle::TimeNowIgnoringOverride() - Time::UnixEpoch()); - }()); - return epoch; + struct StaticUnixEpoch { + StaticUnixEpoch() + : epoch( + g_shared_time_ticks_at_unix_epoch.is_null() + ? subtle::TimeTicksNowIgnoringOverride() - + (subtle::TimeNowIgnoringOverride() - Time::UnixEpoch()) + : g_shared_time_ticks_at_unix_epoch) { + // Prevent future usage of `g_shared_time_ticks_at_unix_epoch`. + g_shared_time_ticks_at_unix_epoch = TimeTicks::Max(); + } + + const TimeTicks epoch; + }; + + static StaticUnixEpoch static_epoch; + return static_epoch.epoch; } TimeTicks TimeTicks::SnappedToNextTick(TimeTicks tick_phase,
diff --git a/base/time/time.h b/base/time/time.h index 4cfa619a1..3f906ed 100644 --- a/base/time/time.h +++ b/base/time/time.h
@@ -1084,6 +1084,8 @@ // in future application runs. static TimeTicks UnixEpoch(); + static void SetSharedUnixEpoch(TimeTicks); + // Returns |this| snapped to the next tick, given a |tick_phase| and // repeating |tick_interval| in both directions. |this| may be before, // after, or equal to the |tick_phase|.
diff --git a/base/values.cc b/base/values.cc index 0cbe888..d0d3ce2 100644 --- a/base/values.cc +++ b/base/values.cc
@@ -1705,26 +1705,6 @@ const_cast<const ListValue**>(out_value)); } -bool DictionaryValue::GetDictionaryWithoutPathExpansion( - StringPiece key, - const DictionaryValue** out_value) const { - const Value* value = FindKey(key); - if (!value || !value->is_dict()) - return false; - - if (out_value) - *out_value = static_cast<const DictionaryValue*>(value); - - return true; -} - -bool DictionaryValue::GetDictionaryWithoutPathExpansion( - StringPiece key, - DictionaryValue** out_value) { - return as_const(*this).GetDictionaryWithoutPathExpansion( - key, const_cast<const DictionaryValue**>(out_value)); -} - std::unique_ptr<DictionaryValue> DictionaryValue::DeepCopyWithoutEmptyChildren() const { std::unique_ptr<DictionaryValue> copy =
diff --git a/base/values.h b/base/values.h index d58dd5f..0c37db302 100644 --- a/base/values.h +++ b/base/values.h
@@ -1353,16 +1353,6 @@ bool GetList(StringPiece path, const ListValue** out_value) const; bool GetList(StringPiece path, ListValue** out_value); - // Like `Get()`, but without special treatment of '.'. This allows e.g. URLs - // to be used as paths. - // DEPRECATED, use `Value::FindDictKey(key)` instead. - bool GetDictionaryWithoutPathExpansion( - StringPiece key, - const DictionaryValue** out_value) const; - // DEPRECATED, use `Value::FindDictKey(key)` instead. - bool GetDictionaryWithoutPathExpansion(StringPiece key, - DictionaryValue** out_value); - // Makes a copy of `this` but doesn't include empty dictionaries and lists in // the copy. This never returns NULL, even if `this` itself is empty. std::unique_ptr<DictionaryValue> DeepCopyWithoutEmptyChildren() const;
diff --git a/base/values_unittest.cc b/base/values_unittest.cc index e03c839..1a24c2f1 100644 --- a/base/values_unittest.cc +++ b/base/values_unittest.cc
@@ -561,6 +561,36 @@ EXPECT_TRUE(value->GetBool()); } +TEST(ValuesTest, DictSetByDottedPath) { + Value::Dict dict; + + Value* c = dict.SetByDottedPath("a.b.c", Value()); + ASSERT_TRUE(c); + + Value::Dict* a = dict.FindDict("a"); + ASSERT_TRUE(a); + EXPECT_EQ(1U, a->size()); + + Value::Dict* b = a->FindDict("b"); + ASSERT_TRUE(b); + EXPECT_EQ(1U, b->size()); + + EXPECT_EQ(c, b->Find("c")); +} + +TEST(ValuesTest, DictSetWithDottedKey) { + Value::Dict dict; + + Value* abc = dict.Set("a.b.c", Value()); + ASSERT_TRUE(abc); + + EXPECT_FALSE(dict.FindByDottedPath("a")); + EXPECT_FALSE(dict.FindByDottedPath("a.b")); + EXPECT_FALSE(dict.FindByDottedPath("a.b.c")); + + EXPECT_EQ(abc, dict.Find("a.b.c")); +} + TEST(ValuesTest, ListFront) { Value::List list; const Value::List& const_list = list; @@ -1607,28 +1637,6 @@ } } -TEST(ValuesTest, DictionaryWithoutPathExpansion) { - DictionaryValue dict; - dict.Set("this.is.expanded", std::make_unique<Value>()); - dict.SetKey("this.isnt.expanded", Value()); - - EXPECT_FALSE(dict.FindKey("this.is.expanded")); - EXPECT_TRUE(dict.FindKey("this")); - Value* value1; - EXPECT_TRUE(dict.Get("this", &value1)); - DictionaryValue* value2; - ASSERT_TRUE(dict.GetDictionaryWithoutPathExpansion("this", &value2)); - EXPECT_EQ(value1, value2); - EXPECT_EQ(1U, value2->DictSize()); - - EXPECT_TRUE(dict.FindKey("this.isnt.expanded")); - Value* value3; - EXPECT_FALSE(dict.Get("this.isnt.expanded", &value3)); - Value* value4 = dict.FindKey("this.isnt.expanded"); - ASSERT_TRUE(value4); - EXPECT_EQ(Value::Type::NONE, value4->type()); -} - // Tests the deprecated version of SetWithoutPathExpansion. // TODO(estade): remove. TEST(ValuesTest, DictionaryWithoutPathExpansionDeprecated) { @@ -1640,8 +1648,10 @@ EXPECT_TRUE(dict.FindKey("this")); Value* value1; EXPECT_TRUE(dict.Get("this", &value1)); - DictionaryValue* value2; - ASSERT_TRUE(dict.GetDictionaryWithoutPathExpansion("this", &value2)); + ASSERT_TRUE(dict.GetDict().FindDict("this")); + DictionaryValue* value2 = + static_cast<DictionaryValue*>(dict.GetDict().Find("this")); + ASSERT_TRUE(value2); EXPECT_EQ(value1, value2); EXPECT_EQ(1U, value2->DictSize()); @@ -2370,18 +2380,6 @@ EXPECT_FALSE(main_dict.GetList("dict", nullptr)); EXPECT_TRUE(main_dict.GetList("list", nullptr)); EXPECT_FALSE(main_dict.GetList("DNE", nullptr)); - - // There is no GetBinaryWithoutPathExpansion for some reason, but if there - // were it should be tested here... - - EXPECT_FALSE(main_dict.GetDictionaryWithoutPathExpansion("bool", nullptr)); - EXPECT_FALSE(main_dict.GetDictionaryWithoutPathExpansion("int", nullptr)); - EXPECT_FALSE(main_dict.GetDictionaryWithoutPathExpansion("double", nullptr)); - EXPECT_FALSE(main_dict.GetDictionaryWithoutPathExpansion("string", nullptr)); - EXPECT_FALSE(main_dict.GetDictionaryWithoutPathExpansion("binary", nullptr)); - EXPECT_TRUE(main_dict.GetDictionaryWithoutPathExpansion("dict", nullptr)); - EXPECT_FALSE(main_dict.GetDictionaryWithoutPathExpansion("list", nullptr)); - EXPECT_FALSE(main_dict.GetDictionaryWithoutPathExpansion("DNE", nullptr)); } TEST(ValuesTest, SelfSwap) {
diff --git a/build/fuchsia/linux_internal.sdk.sha1 b/build/fuchsia/linux_internal.sdk.sha1 index 68e22d64..fb02c42 100644 --- a/build/fuchsia/linux_internal.sdk.sha1 +++ b/build/fuchsia/linux_internal.sdk.sha1
@@ -1 +1 @@ -9.20220802.3.1 +9.20220803.1.1
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index db5d426..e25cb729 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -406,6 +406,7 @@ "defaults.h", "device_reauth/chrome_biometric_authenticator_common.cc", "device_reauth/chrome_biometric_authenticator_common.h", + "device_reauth/chrome_biometric_authenticator_factory.cc", "device_reauth/chrome_biometric_authenticator_factory.h", "dips/cookie_access_filter.cc", "dips/cookie_access_filter.h", @@ -2939,8 +2940,6 @@ "crash_upload_list/crash_upload_list_android.h", "device_reauth/android/biometric_authenticator_android.cc", "device_reauth/android/biometric_authenticator_android.h", - "device_reauth/android/biometric_authenticator_android_factory.cc", - "device_reauth/android/biometric_authenticator_android_factory.h", "device_reauth/android/biometric_authenticator_bridge.h", "device_reauth/android/biometric_authenticator_bridge_impl.cc", "device_reauth/android/biometric_authenticator_bridge_impl.h",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 2c28bb9..9c6d6db 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -3320,6 +3320,12 @@ flag_descriptions::kWebKioskEnableLacrosDescription, kOsCrOS, FEATURE_VALUE_TYPE(features::kWebKioskEnableLacros)}, #endif // BUILDFLAG(IS_CHROMEOS_ASH) +#if BUILDFLAG(IS_CHROMEOS) + {"enable-app-service-in-kiosk", + flag_descriptions::kKioskEnableAppServiceName, + flag_descriptions::kKioskEnableAppServiceDescription, kOsCrOS, + FEATURE_VALUE_TYPE(features::kKioskEnableAppService)}, +#endif // BUILDFLAG(IS_CHROMEOS) #if !BUILDFLAG(IS_ANDROID) {"enable-webrtc-remote-event-log", flag_descriptions::kWebRtcRemoteEventLogName, @@ -5024,6 +5030,9 @@ {"auto-framing-override", flag_descriptions::kAutoFramingOverrideName, flag_descriptions::kAutoFramingOverrideDescription, kOsCrOS, MULTI_VALUE_TYPE(kAutoFramingOverrideChoices)}, + {"camera-app-doc-scan-dlc", flag_descriptions::kCameraAppDocScanDlcName, + flag_descriptions::kCameraAppDocScanDlcDescription, kOsCrOS, + FEATURE_VALUE_TYPE(chromeos::features::kCameraAppDocScanDlc)}, {"crostini-gpu-support", flag_descriptions::kCrostiniGpuSupportName, flag_descriptions::kCrostiniGpuSupportDescription, kOsCrOS, FEATURE_VALUE_TYPE(chromeos::features::kCrostiniGpuSupport)}, @@ -7486,11 +7495,6 @@ {"quick-commands", flag_descriptions::kQuickCommandsName, flag_descriptions::kQuickCommandsDescription, kOsDesktop, FEATURE_VALUE_TYPE(features::kQuickCommands)}, - - {"desktop-detailed-language-settings", - flag_descriptions::kDesktopDetailedLanguageSettingsName, - flag_descriptions::kDesktopDetailedLanguageSettingsDescription, kOsDesktop, - FEATURE_VALUE_TYPE(language::kDesktopDetailedLanguageSettings)}, #endif {"pwa-update-dialog-for-icon", @@ -7794,6 +7798,11 @@ kOsWin | kOsLinux | kOsLacros | kOsMac | kOsFuchsia, FEATURE_VALUE_TYPE(features::kUIDebugTools), }, + {"desktop-detailed-language-settings", + flag_descriptions::kDesktopDetailedLanguageSettingsName, + flag_descriptions::kDesktopDetailedLanguageSettingsDescription, + kOsWin | kOsLinux | kOsLacros | kOsMac | kOsFuchsia, + FEATURE_VALUE_TYPE(language::kDesktopDetailedLanguageSettings)}, #endif {"http-cache-partitioning", flag_descriptions::kSplitCacheByNetworkIsolationKeyName,
diff --git a/chrome/browser/android/contextualsearch/contextual_search_manager.cc b/chrome/browser/android/contextualsearch/contextual_search_manager.cc index 1431402..8197d9d 100644 --- a/chrome/browser/android/contextualsearch/contextual_search_manager.cc +++ b/chrome/browser/android/contextualsearch/contextual_search_manager.cc
@@ -43,7 +43,13 @@ Profile* profile = ProfileManager::GetActiveUserProfile(); delegate_ = std::make_unique<ContextualSearchDelegate>( profile->GetURLLoaderFactory(), - TemplateURLServiceFactory::GetForProfile(profile)); + TemplateURLServiceFactory::GetForProfile(profile), + base::BindRepeating( + &ContextualSearchManager::OnSearchTermResolutionResponse, + base::Unretained(this)), + base::BindRepeating( + &ContextualSearchManager::OnTextSurroundingSelectionAvailable, + base::Unretained(this))); } ContextualSearchManager::~ContextualSearchManager() { @@ -68,11 +74,8 @@ NativeContextualSearchContext::FromJavaContextualSearchContext( j_contextual_search_context); // Calls back to OnSearchTermResolutionResponse. - delegate_->StartSearchTermResolutionRequest( - contextual_search_context, base_web_contents, - base::BindRepeating( - &ContextualSearchManager::OnSearchTermResolutionResponse, - base::Unretained(this))); + delegate_->StartSearchTermResolutionRequest(contextual_search_context, + base_web_contents); } void ContextualSearchManager::GatherSurroundingText( @@ -86,11 +89,8 @@ base::WeakPtr<NativeContextualSearchContext> contextual_search_context = NativeContextualSearchContext::FromJavaContextualSearchContext( j_contextual_search_context); - delegate_->GatherAndSaveSurroundingText( - contextual_search_context, base_web_contents, - base::BindRepeating( - &ContextualSearchManager::OnTextSurroundingSelectionAvailable, - base::Unretained(this))); + delegate_->GatherAndSaveSurroundingText(contextual_search_context, + base_web_contents); } void ContextualSearchManager::OnSearchTermResolutionResponse(
diff --git a/chrome/browser/apps/app_service/intent_util.cc b/chrome/browser/apps/app_service/intent_util.cc index b8dfbde..506054d 100644 --- a/chrome/browser/apps/app_service/intent_util.cc +++ b/chrome/browser/apps/app_service/intent_util.cc
@@ -172,8 +172,7 @@ if (!content_types.empty()) { const std::vector<std::string> intent_actions( {kIntentActionSend, kIntentActionSendMultiple}); - filters.push_back(apps::ConvertMojomIntentFilterToIntentFilter( - CreateFileFilter(intent_actions, content_types, {}))); + filters.push_back(CreateFileFilter(intent_actions, content_types, {})); } return filters; @@ -205,7 +204,8 @@ if (!content_types.empty()) { const std::vector<std::string> intent_actions( {kIntentActionSend, kIntentActionSendMultiple}); - filters.push_back(CreateFileFilter(intent_actions, content_types, {})); + filters.push_back(apps::ConvertIntentFilterToMojomIntentFilter( + CreateFileFilter(intent_actions, content_types, {}))); } return filters; @@ -226,9 +226,8 @@ file_extensions.push_back(extension); } } - filters.push_back( - apps::ConvertMojomIntentFilterToIntentFilter(CreateFileFilter( - {kIntentActionView}, mime_types, file_extensions, action_url))); + filters.push_back(CreateFileFilter({kIntentActionView}, mime_types, + file_extensions, action_url)); } return filters; @@ -250,8 +249,9 @@ file_extensions.push_back(extension); } } - filters.push_back(CreateFileFilter({kIntentActionView}, mime_types, - file_extensions, action_url)); + filters.push_back( + apps::ConvertIntentFilterToMojomIntentFilter(CreateFileFilter( + {kIntentActionView}, mime_types, file_extensions, action_url))); } return filters; @@ -364,48 +364,47 @@ } // namespace -apps::mojom::IntentFilterPtr CreateFileFilter( +apps::IntentFilterPtr CreateFileFilter( const std::vector<std::string>& intent_actions, const std::vector<std::string>& mime_types, const std::vector<std::string>& file_extensions, const std::string& activity_name, bool include_directories) { DCHECK(!mime_types.empty() || !file_extensions.empty()); - auto intent_filter = apps::mojom::IntentFilter::New(); + auto intent_filter = std::make_unique<apps::IntentFilter>(); // kAction == View, Share etc. - std::vector<apps::mojom::ConditionValuePtr> action_condition_values; + apps::ConditionValues action_condition_values; for (auto& action : intent_actions) { - action_condition_values.push_back( - MakeConditionValue(action, apps::mojom::PatternMatchType::kLiteral)); + action_condition_values.push_back(std::make_unique<apps::ConditionValue>( + action, apps::PatternMatchType::kLiteral)); } if (!action_condition_values.empty()) { - auto action_condition = MakeCondition(apps::mojom::ConditionType::kAction, - std::move(action_condition_values)); - intent_filter->conditions.push_back(std::move(action_condition)); + intent_filter->conditions.push_back(std::make_unique<apps::Condition>( + apps::ConditionType::kAction, std::move(action_condition_values))); } - std::vector<apps::mojom::ConditionValuePtr> condition_values; + apps::ConditionValues file_condition_values; + // Mime types. for (auto& mime_type : mime_types) { - condition_values.push_back(MakeConditionValue( - mime_type, apps::mojom::PatternMatchType::kMimeType)); + file_condition_values.push_back(std::make_unique<apps::ConditionValue>( + mime_type, apps::PatternMatchType::kMimeType)); } // And file extensions. for (const std::string& extension : file_extensions) { - condition_values.push_back(MakeConditionValue( - extension, apps::mojom::PatternMatchType::kFileExtension)); + file_condition_values.push_back(std::make_unique<apps::ConditionValue>( + extension, apps::PatternMatchType::kFileExtension)); } if (include_directories) { - condition_values.push_back( - MakeConditionValue("", apps::mojom::PatternMatchType::kIsDirectory)); + file_condition_values.push_back(std::make_unique<apps::ConditionValue>( + "", apps::PatternMatchType::kIsDirectory)); } - DCHECK(!condition_values.empty()); - if (!condition_values.empty()) { - auto file_condition = MakeCondition(apps::mojom::ConditionType::kFile, - std::move(condition_values)); - intent_filter->conditions.push_back(std::move(file_condition)); + DCHECK(!file_condition_values.empty()); + if (!file_condition_values.empty()) { + intent_filter->conditions.push_back(std::make_unique<apps::Condition>( + apps::ConditionType::kFile, std::move(file_condition_values))); } if (!activity_name.empty()) { @@ -528,9 +527,9 @@ handler.types.end()); std::vector<std::string> file_extensions(handler.extensions.begin(), handler.extensions.end()); - filters.push_back(apps::ConvertMojomIntentFilterToIntentFilter( - CreateFileFilter({kIntentActionView}, mime_types, file_extensions, - handler.id, handler.include_directories))); + filters.push_back(CreateFileFilter({kIntentActionView}, mime_types, + file_extensions, handler.id, + handler.include_directories)); filters.back()->activity_label = extension->name(); } @@ -567,9 +566,9 @@ handler.types.end()); std::vector<std::string> file_extensions(handler.extensions.begin(), handler.extensions.end()); - filters.push_back(CreateFileFilter({kIntentActionView}, mime_types, - file_extensions, handler.id, - handler.include_directories)); + filters.push_back(apps::ConvertIntentFilterToMojomIntentFilter( + CreateFileFilter({kIntentActionView}, mime_types, file_extensions, + handler.id, handler.include_directories))); filters.back()->activity_label = extension->name(); }
diff --git a/chrome/browser/apps/app_service/intent_util.h b/chrome/browser/apps/app_service/intent_util.h index 415c4bc..6cd7843 100644 --- a/chrome/browser/apps/app_service/intent_util.h +++ b/chrome/browser/apps/app_service/intent_util.h
@@ -49,7 +49,7 @@ namespace apps_util { // Creates a file filter. -apps::mojom::IntentFilterPtr CreateFileFilter( +apps::IntentFilterPtr CreateFileFilter( const std::vector<std::string>& intent_actions, const std::vector<std::string>& mime_types, const std::vector<std::string>& file_extensions,
diff --git a/chrome/browser/apps/app_service/publishers/crostini_apps.cc b/chrome/browser/apps/app_service/publishers/crostini_apps.cc index 6d87fe92..14d0c83 100644 --- a/chrome/browser/apps/app_service/publishers/crostini_apps.cc +++ b/chrome/browser/apps/app_service/publishers/crostini_apps.cc
@@ -12,6 +12,7 @@ #include "chrome/browser/apps/app_service/app_icon/dip_px_util.h" #include "chrome/browser/apps/app_service/app_launch_params.h" #include "chrome/browser/apps/app_service/app_service_proxy.h" +#include "chrome/browser/apps/app_service/intent_util.h" #include "chrome/browser/apps/app_service/launch_utils.h" #include "chrome/browser/apps/app_service/menu_util.h" #include "chrome/browser/ash/crostini/crostini_features.h" @@ -27,6 +28,8 @@ #include "components/prefs/pref_service.h" #include "components/services/app_service/public/cpp/app_types.h" #include "components/services/app_service/public/cpp/intent.h" +#include "components/services/app_service/public/cpp/intent_filter.h" +#include "components/services/app_service/public/cpp/intent_util.h" #include "components/services/app_service/public/mojom/types.mojom.h" #include "mojo/public/cpp/bindings/callback_helpers.h" #include "ui/display/display.h" @@ -57,6 +60,23 @@ return d.device_scale_factor() != 1.0; } +// Create a file intent filter with mime type conditions for App Service. +apps::IntentFilters CreateIntentFilterForCrostini( + const std::set<std::string>& mime_types) { + apps::IntentFilters intent_filters; + + if (mime_types.empty()) { + return intent_filters; + } + + std::vector<std::string> mime_types_vector(mime_types.begin(), + mime_types.end()); + apps::IntentFilterPtr intent_filter = apps_util::CreateFileFilter( + {apps_util::kIntentActionView}, mime_types_vector, {}); + intent_filters.push_back(std::move(intent_filter)); + return intent_filters; +} + } // namespace namespace apps { @@ -334,6 +354,9 @@ app->allow_uninstall = crostini::IsUninstallable(profile_, registration.app_id()); + app->handles_intents = show; + app->intent_filters = CreateIntentFilterForCrostini(registration.MimeTypes()); + // TODO(crbug.com/1253250): Add other fields for the App struct. return app; } @@ -379,6 +402,10 @@ ? apps::mojom::OptionalBool::kTrue : apps::mojom::OptionalBool::kFalse; + app->handles_intents = show; + app->intent_filters = ConvertIntentFiltersToMojomIntentFilters( + CreateIntentFilterForCrostini(registration.MimeTypes())); + return app; }
diff --git a/chrome/browser/apps/app_service/publishers/crostini_apps_unittest.cc b/chrome/browser/apps/app_service/publishers/crostini_apps_unittest.cc new file mode 100644 index 0000000..4424801c --- /dev/null +++ b/chrome/browser/apps/app_service/publishers/crostini_apps_unittest.cc
@@ -0,0 +1,110 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/apps/app_service/publishers/crostini_apps.h" + +#include <vector> + +#include "chrome/browser/apps/app_service/app_service_proxy.h" +#include "chrome/browser/apps/app_service/app_service_proxy_factory.h" +#include "chrome/browser/ash/crostini/crostini_test_helper.h" +#include "chrome/browser/web_applications/test/web_app_install_test_utils.h" +#include "chrome/test/base/testing_profile.h" +#include "chromeos/dbus/dbus_thread_manager.h" +#include "components/services/app_service/public/cpp/app_registry_cache.h" +#include "components/services/app_service/public/cpp/app_update.h" +#include "components/services/app_service/public/cpp/intent_filter.h" +#include "components/services/app_service/public/cpp/intent_util.h" +#include "content/public/test/browser_task_environment.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace apps { + +class CrostiniAppsTest : public testing::Test { + public: + CrostiniAppsTest() + : task_environment_(content::BrowserTaskEnvironment::REAL_IO_THREAD) {} + + crostini::CrostiniTestHelper* test_helper() { return test_helper_.get(); } + + AppServiceProxy* app_service_proxy() { return app_service_proxy_; } + + void SetUp() override { + chromeos::DBusThreadManager::Initialize(); + profile_ = std::make_unique<TestingProfile>(); + app_service_proxy_ = AppServiceProxyFactory::GetForProfile(profile_.get()); + web_app::test::AwaitStartWebAppProviderAndSubsystems(profile_.get()); + test_helper_ = + std::make_unique<crostini::CrostiniTestHelper>(profile_.get()); + test_helper()->ReInitializeAppServiceIntegration(); + } + + void TearDown() override { + test_helper_.reset(); + profile_.reset(); + chromeos::DBusThreadManager::Shutdown(); + } + + private: + content::BrowserTaskEnvironment task_environment_; + std::unique_ptr<TestingProfile> profile_; + std::unique_ptr<crostini::CrostiniTestHelper> test_helper_; + AppServiceProxy* app_service_proxy_ = nullptr; +}; + +TEST_F(CrostiniAppsTest, AppServiceHasCrostiniIntentFilters) { + std::vector<std::string> mime_types = {"text/csv", "text/plain"}; + + // Set up the test Crostini app for our desired mime types. + vm_tools::apps::App app; + for (std::string mime_type : mime_types) { + app.add_mime_types(mime_type); + } + app.set_desktop_file_id("app_id"); + vm_tools::apps::App::LocaleString::Entry* entry = + app.mutable_name()->add_values(); + entry->set_locale(std::string()); + entry->set_value("app_name"); + test_helper()->AddApp(app); + + // Get the app ID so that we can find the Crostini app in App Service later. + std::string app_service_id = crostini::CrostiniTestHelper::GenerateAppId( + app.desktop_file_id(), crostini::kCrostiniDefaultVmName, + crostini::kCrostiniDefaultContainerName); + + // Retrieve the registered intent filter for the app in App Service. + std::vector<std::unique_ptr<IntentFilter>> intent_filters; + app_service_proxy()->AppRegistryCache().ForOneApp( + app_service_id, [&intent_filters](const AppUpdate& update) { + for (auto& intent_filter : update.IntentFilters()) { + intent_filters.push_back(std::move(intent_filter)); + } + }); + + EXPECT_EQ(intent_filters.size(), 1U); + std::unique_ptr<IntentFilter> intent_filter = std::move(intent_filters[0]); + EXPECT_EQ(intent_filter->conditions.size(), 2U); + + // Check that the filter has the correct action type. + { + const Condition* condition = intent_filter->conditions[0].get(); + ASSERT_EQ(condition->condition_type, ConditionType::kAction); + EXPECT_EQ(condition->condition_values.size(), 1U); + ASSERT_EQ(condition->condition_values[0]->match_type, + PatternMatchType::kLiteral); + ASSERT_EQ(condition->condition_values[0]->value, + apps_util::kIntentActionView); + } + + // Check that the filter has all our mime types. + { + const Condition* condition = intent_filter->conditions[1].get(); + ASSERT_EQ(condition->condition_type, ConditionType::kFile); + EXPECT_EQ(condition->condition_values.size(), 2U); + ASSERT_EQ(condition->condition_values[0]->value, mime_types[0]); + ASSERT_EQ(condition->condition_values[1]->value, mime_types[1]); + } +} + +} // namespace apps
diff --git a/chrome/browser/apps/platform_apps/app_browsertest_util.cc b/chrome/browser/apps/platform_apps/app_browsertest_util.cc index 21ab6f1a..792f120 100644 --- a/chrome/browser/apps/platform_apps/app_browsertest_util.cc +++ b/chrome/browser/apps/platform_apps/app_browsertest_util.cc
@@ -250,7 +250,8 @@ ProcessManager* process_manager = ProcessManager::Get(context); ExtensionHost* background_host = process_manager->GetBackgroundHostForExtension(extension->id()); - window->Init(GURL(std::string()), new AppWindowContentsImpl(window), + window->Init(GURL(std::string()), + std::make_unique<AppWindowContentsImpl>(window), background_host->host_contents()->GetPrimaryMainFrame(), params); return window; }
diff --git a/chrome/browser/ash/accessibility/accessibility_event_rewriter_delegate_impl.cc b/chrome/browser/ash/accessibility/accessibility_event_rewriter_delegate_impl.cc index 1dc80790..75fc7d3 100644 --- a/chrome/browser/ash/accessibility/accessibility_event_rewriter_delegate_impl.cc +++ b/chrome/browser/ash/accessibility/accessibility_event_rewriter_delegate_impl.cc
@@ -171,7 +171,7 @@ bool AccessibilityEventRewriterDelegateImpl::HandleKeyboardEvent( content::WebContents* source, const content::NativeWebKeyboardEvent& event) { - OnUnhandledSpokenFeedbackEvent(ui::Event::Clone(*event.os_event)); + OnUnhandledSpokenFeedbackEvent(event.os_event->Clone()); return true; }
diff --git a/chrome/browser/ash/app_mode/startup_app_launcher_unittest.cc b/chrome/browser/ash/app_mode/startup_app_launcher_unittest.cc index 5046e11..790abfe 100644 --- a/chrome/browser/ash/app_mode/startup_app_launcher_unittest.cc +++ b/chrome/browser/ash/app_mode/startup_app_launcher_unittest.cc
@@ -353,7 +353,7 @@ extensions::AppWindow::CreateParams params; params.content_spec.bounds = bounds; - app_window->Init(GURL(), app_window_contents.release(), main_frame, params); + app_window->Init(GURL(), std::move(app_window_contents), main_frame, params); } extensions::AppWindow* CreateAppWindow(Profile* profile,
diff --git a/chrome/browser/ash/child_accounts/child_status_reporting_service.cc b/chrome/browser/ash/child_accounts/child_status_reporting_service.cc index 1f375ea..1c33ee4 100644 --- a/chrome/browser/ash/child_accounts/child_status_reporting_service.cc +++ b/chrome/browser/ash/child_accounts/child_status_reporting_service.cc
@@ -65,10 +65,10 @@ void ChildStatusReportingService::CreateStatusUploaderIfNeeded( policy::CloudPolicyClient* client) { - const base::Value* time_limit = - pref_change_registrar_->prefs()->GetDictionary(prefs::kUsageTimeLimit); + const base::Value::Dict& time_limit = + pref_change_registrar_->prefs()->GetValueDict(prefs::kUsageTimeLimit); const base::TimeDelta new_day_reset_time = - usage_time_limit::GetTimeUsageLimitResetTime(*time_limit); + usage_time_limit::GetTimeUsageLimitResetTime(time_limit); // Day reset time did not change, there is no need to re-create StatusUploader // if it already exists.
diff --git a/chrome/browser/ash/child_accounts/child_user_service.cc b/chrome/browser/ash/child_accounts/child_user_service.cc index 564ae83..2597aa0 100644 --- a/chrome/browser/ash/child_accounts/child_user_service.cc +++ b/chrome/browser/ash/child_accounts/child_user_service.cc
@@ -138,12 +138,11 @@ } void ChildUserService ::ReportTimeLimitPolicy() const { - const base::Value* time_limit_prefs = - profile_->GetPrefs()->GetDictionary(prefs::kUsageTimeLimit); - DCHECK(time_limit_prefs); + const base::Value::Dict& time_limit_prefs = + profile_->GetPrefs()->GetValueDict(prefs::kUsageTimeLimit); std::set<usage_time_limit::PolicyType> enabled_policies = - usage_time_limit::GetEnabledTimeLimitPolicies(*time_limit_prefs); + usage_time_limit::GetEnabledTimeLimitPolicies(time_limit_prefs); for (const auto& policy_type : enabled_policies) { TimeLimitPolicyType time_limit_policy = GetTimeLimitPolicyType(policy_type);
diff --git a/chrome/browser/ash/child_accounts/family_user_parental_control_metrics_unittest.cc b/chrome/browser/ash/child_accounts/family_user_parental_control_metrics_unittest.cc index 6f89f45..31c7fc7 100644 --- a/chrome/browser/ash/child_accounts/family_user_parental_control_metrics_unittest.cc +++ b/chrome/browser/ash/child_accounts/family_user_parental_control_metrics_unittest.cc
@@ -125,7 +125,7 @@ TEST_F(FamilyUserParentalControlMetricsTest, BedAndScreenTimeLimitMetrics) { ASSERT_TRUE(ChildUserServiceFactory::GetForBrowserContext(profile_.get())); - base::Value policy_content = + base::Value::Dict policy_content = utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); // Adds bedtime policy: @@ -140,7 +140,7 @@ /*quota*/ kOneHour, /*last_updated=*/base::Time::Now()); - GetPrefs()->Set(prefs::kUsageTimeLimit, policy_content); + GetPrefs()->SetDict(prefs::kUsageTimeLimit, policy_content.Clone()); histogram_tester_.ExpectBucketCount( ChildUserService::GetTimeLimitPolicyTypesHistogramNameForTest(), @@ -180,7 +180,7 @@ ASSERT_TRUE(ChildUserServiceFactory::GetForBrowserContext(profile_.get())); // Adds override time policy created at 1 day ago. - base::Value policy_content = + base::Value::Dict policy_content = utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); utils::AddOverrideWithDuration( @@ -188,7 +188,7 @@ /*action=*/usage_time_limit::TimeLimitOverride::Action::kLock, /*created_at=*/base::Time::Now() - kOneDay, /*duration=*/base::Hours(2)); - GetPrefs()->Set(prefs::kUsageTimeLimit, policy_content); + GetPrefs()->SetDict(prefs::kUsageTimeLimit, policy_content.Clone()); // The override time limit policy would not get reported since the difference // between reported and created time are greater than 1 day. @@ -209,7 +209,7 @@ /*action=*/usage_time_limit::TimeLimitOverride::Action::kLock, /*created_at=*/base::Time::Now() - base::Hours(23), /*duration=*/base::Hours(2)); - GetPrefs()->Set(prefs::kUsageTimeLimit, policy_content); + GetPrefs()->SetDict(prefs::kUsageTimeLimit, policy_content.Clone()); // The override time limit policy would get reported since the created // time and reported time are within 1 day.
diff --git a/chrome/browser/ash/child_accounts/screen_time_controller.cc b/chrome/browser/ash/child_accounts/screen_time_controller.cc index 2bdb885..fb8849b 100644 --- a/chrome/browser/ash/child_accounts/screen_time_controller.cc +++ b/chrome/browser/ash/child_accounts/screen_time_controller.cc
@@ -76,8 +76,7 @@ clock_(base::DefaultClock::GetInstance()), next_state_timer_(std::make_unique<base::OneShotTimer>()), usage_time_limit_warning_timer_(std::make_unique<base::OneShotTimer>()), - last_policy_( - pref_service_->GetDictionary(prefs::kUsageTimeLimit)->Clone()), + last_policy_(pref_service_->GetValueDict(prefs::kUsageTimeLimit).Clone()), time_limit_notifier_(context) { session_manager::SessionManager::Get()->AddObserver(this); UsageTimeStateNotifier::GetInstance()->AddObserver(this); @@ -147,14 +146,14 @@ const icu::TimeZone& time_zone = system::TimezoneSettings::GetInstance()->GetTimezone(); absl::optional<usage_time_limit::State> last_state = GetLastStateFromPref(); - const base::Value* time_limit = - pref_service_->GetDictionary(prefs::kUsageTimeLimit); - const base::Value* local_override = - pref_service_->GetDictionary(prefs::kTimeLimitLocalOverride); + const base::Value::Dict& time_limit = + pref_service_->GetValueDict(prefs::kUsageTimeLimit); + const base::Value::Dict& local_override = + pref_service_->GetValueDict(prefs::kTimeLimitLocalOverride); // TODO(agawronska): Usage timestamp should be passed instead of second |now|. usage_time_limit::State state = usage_time_limit::GetState( - *time_limit, local_override, GetScreenTimeDuration(), now, now, + time_limit, &local_override, GetScreenTimeDuration(), now, now, &time_zone, last_state); SaveCurrentStateToPref(state); @@ -182,9 +181,8 @@ } // Trigger policy update notifications. - DCHECK(last_policy_.is_dict()); auto updated_policy_types = - usage_time_limit::UpdatedPolicyTypes(last_policy_, *time_limit); + usage_time_limit::UpdatedPolicyTypes(last_policy_, time_limit); for (const auto& policy_type : updated_policy_types) { absl::optional<base::Time> lock_time; if (policy_type == usage_time_limit::PolicyType::kOverride) @@ -196,14 +194,14 @@ time_limit_notifier_.ShowPolicyUpdateNotification(notification_type.value(), lock_time); } - last_policy_ = time_limit->Clone(); + last_policy_ = time_limit.Clone(); // TODO(agawronska): We are creating UsageTimeLimitProcessor second time in // this method. Could expected reset time be returned as a part of the state? base::Time next_get_state_time = std::min(state.next_state_change_time, usage_time_limit::GetExpectedResetTime( - *time_limit, local_override, now, &time_zone)); + time_limit, &local_override, now, &time_zone)); if (!next_get_state_time.is_null()) { VLOG(1) << "Scheduling state change timer in " << next_get_state_time - now; next_state_timer_->Start( @@ -249,8 +247,8 @@ absl::nullopt); // Replace previous local override stored in pref, because PAC can only be // entered if previous override is not active anymore. - pref_service_->Set(prefs::kTimeLimitLocalOverride, - local_override.ToDictionary()); + pref_service_->SetDict(prefs::kTimeLimitLocalOverride, + local_override.ToDictionary()); pref_service_->CommitPendingWrite(); CheckTimeLimit("OnAccessCodeValidation"); @@ -362,21 +360,21 @@ absl::optional<usage_time_limit::State> ScreenTimeController::GetLastStateFromPref() { - const base::Value* last_state = - pref_service_->GetDictionary(prefs::kScreenTimeLastState); + const base::Value::Dict& last_state = + pref_service_->GetValueDict(prefs::kScreenTimeLastState); usage_time_limit::State result; - if (last_state->DictEmpty()) + if (last_state.empty()) return absl::nullopt; // Verify is_locked from the pref is a boolean value. - const base::Value* is_locked = last_state->FindKey(kScreenStateLocked); + const base::Value* is_locked = last_state.Find(kScreenStateLocked); if (!is_locked || !is_locked->is_bool()) return absl::nullopt; result.is_locked = is_locked->GetBool(); // Verify active policy type is a value of usage_time_limit::PolicyType. const base::Value* active_policy = - last_state->FindKey(kScreenStateCurrentPolicyType); + last_state.Find(kScreenStateCurrentPolicyType); // TODO(crbug.com/823536): Add kCount in usage_time_limit::PolicyType // instead of checking kUsageLimit here. if (!active_policy || !active_policy->is_int() || @@ -390,21 +388,21 @@ // Verify time_usage_limit_enabled from the pref is a boolean value. const base::Value* time_usage_limit_enabled = - last_state->FindKey(kScreenStateTimeUsageLimitEnabled); + last_state.Find(kScreenStateTimeUsageLimitEnabled); if (!time_usage_limit_enabled || !time_usage_limit_enabled->is_bool()) return absl::nullopt; result.is_time_usage_limit_enabled = time_usage_limit_enabled->GetBool(); // Verify remaining_usage from the pref is a int value. const base::Value* remaining_usage = - last_state->FindKey(kScreenStateRemainingUsage); + last_state.Find(kScreenStateRemainingUsage); if (!remaining_usage || !remaining_usage->is_int()) return absl::nullopt; result.remaining_usage = base::Milliseconds(remaining_usage->GetInt()); // Verify time_usage_limit_started from the pref is a double value. const base::Value* time_usage_limit_started = - last_state->FindKey(kScreenStateUsageLimitStarted); + last_state.Find(kScreenStateUsageLimitStarted); if (!time_usage_limit_started || !time_usage_limit_started->is_double()) return absl::nullopt; result.time_usage_limit_started = @@ -412,7 +410,7 @@ // Verify next_state_change_time from the pref is a double value. const base::Value* next_state_change_time = - last_state->FindKey(kScreenStateNextStateChangeTime); + last_state.Find(kScreenStateNextStateChangeTime); if (!next_state_change_time || !next_state_change_time->is_double()) return absl::nullopt; result.next_state_change_time = @@ -420,7 +418,7 @@ // Verify next policy type is a value of usage_time_limit::PolicyType. const base::Value* next_active_policy = - last_state->FindKey(kScreenStateNextPolicyType); + last_state.Find(kScreenStateNextPolicyType); if (!next_active_policy || !next_active_policy->is_int() || next_active_policy->GetInt() < 0 || next_active_policy->GetInt() > @@ -432,7 +430,7 @@ // Verify next_unlock_time from the pref is a double value. const base::Value* next_unlock_time = - last_state->FindKey(kScreenStateNextUnlockTime); + last_state.Find(kScreenStateNextUnlockTime); if (!next_unlock_time || !next_unlock_time->is_double()) return absl::nullopt; result.next_unlock_time = @@ -444,13 +442,13 @@ base::Time now = clock_->Now(); const icu::TimeZone& time_zone = system::TimezoneSettings::GetInstance()->GetTimezone(); - const base::Value* time_limit = - pref_service_->GetDictionary(prefs::kUsageTimeLimit); - const base::Value* local_override = - pref_service_->GetDictionary(prefs::kTimeLimitLocalOverride); + const base::Value::Dict& time_limit = + pref_service_->GetValueDict(prefs::kUsageTimeLimit); + const base::Value::Dict& local_override = + pref_service_->GetValueDict(prefs::kTimeLimitLocalOverride); absl::optional<base::TimeDelta> remaining_usage = - usage_time_limit::GetRemainingTimeUsage(*time_limit, local_override, now, + usage_time_limit::GetRemainingTimeUsage(time_limit, &local_override, now, GetScreenTimeDuration(), &time_zone);
diff --git a/chrome/browser/ash/child_accounts/screen_time_controller.h b/chrome/browser/ash/child_accounts/screen_time_controller.h index 139948e..5c0b193 100644 --- a/chrome/browser/ash/child_accounts/screen_time_controller.h +++ b/chrome/browser/ash/child_accounts/screen_time_controller.h
@@ -170,7 +170,7 @@ // Contains the last time limit policy processed by this class. Used to // generate notifications when the policy changes. - base::Value last_policy_{base::Value::Type::DICTIONARY}; + base::Value::Dict last_policy_; // Used to set up timers when a time limit is approaching. TimeLimitNotifier time_limit_notifier_;
diff --git a/chrome/browser/ash/child_accounts/screen_time_controller_browsertest.cc b/chrome/browser/ash/child_accounts/screen_time_controller_browsertest.cc index 6b95eae..0659d47 100644 --- a/chrome/browser/ash/child_accounts/screen_time_controller_browsertest.cc +++ b/chrome/browser/ash/child_accounts/screen_time_controller_browsertest.cc
@@ -73,7 +73,7 @@ void SetUpInProcessBrowserTestFixture() override { MixinBasedInProcessBrowserTest::SetUpInProcessBrowserTestFixture(); // A basic starting policy. - base::Value policy_content = + base::Value::Dict policy_content = utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); logged_in_user_mixin_.GetUserPolicyMixin() ->RequestPolicyUpdate() @@ -128,7 +128,7 @@ return session_manager::SessionManager::Get()->IsScreenLocked(); } - void SetUsageTimeLimitPolicy(const base::Value& policy_content) { + void SetUsageTimeLimitPolicy(const base::Value::Dict& policy_content) { logged_in_user_mixin_.GetUserPolicyMixin() ->RequestPolicyUpdate() ->policy_payload() @@ -165,7 +165,7 @@ EXPECT_TRUE(IsAuthEnabled()); // Set new policy. - base::Value policy_content = + base::Value::Dict policy_content = utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); utils::AddOverride(&policy_content, usage_time_limit::TimeLimitOverride::Action::kLock, @@ -184,7 +184,7 @@ // Set new policy. base::Time last_updated = utils::TimeFromString("1 Jan 2018 0:00 BRT"); - base::Value policy_content = + base::Value::Dict policy_content = utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); utils::AddTimeWindowLimit(&policy_content, utils::kFriday, utils::CreateTime(21, 0), utils::CreateTime(7, 0), @@ -224,7 +224,7 @@ // Set new policy. base::Time last_updated = utils::TimeFromString("1 Jan 2018 0:00 PST"); - base::Value policy_content = + base::Value::Dict policy_content = utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); utils::AddTimeWindowLimit(&policy_content, utils::kFriday, utils::CreateTime(21, 0), utils::CreateTime(7, 0), @@ -282,7 +282,7 @@ // Set new policy. base::Time last_updated = utils::TimeFromString("1 Jan 2018 0:00 BRT"); - base::Value policy_content = + base::Value::Dict policy_content = utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); utils::AddTimeUsageLimit(&policy_content, utils::kMonday, base::Hours(2), last_updated); @@ -334,7 +334,7 @@ // Set new policy. base::Time last_updated = utils::TimeFromString("1 Jan 2018 0:00 GMT"); - base::Value policy_content = + base::Value::Dict policy_content = utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); utils::AddTimeWindowLimit(&policy_content, utils::kFriday, utils::CreateTime(21, 0), utils::CreateTime(7, 0), @@ -388,7 +388,7 @@ // Set new policy. base::Time last_updated = utils::TimeFromString("1 Jan 2018 0:00 PST"); - base::Value policy_content = + base::Value::Dict policy_content = utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); utils::AddTimeUsageLimit(&policy_content, utils::kMonday, base::Hours(2), last_updated); @@ -440,7 +440,7 @@ // Set new policy. base::Time last_updated = utils::TimeFromString("1 Jan 2018 0:00 GMT"); - base::Value policy_content = + base::Value::Dict policy_content = utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); utils::AddTimeWindowLimit(&policy_content, utils::kMonday, utils::CreateTime(21, 0), utils::CreateTime(7, 0), @@ -496,7 +496,7 @@ // Set new policy. base::Time last_updated = utils::TimeFromString("1 Jan 2018 0:00 GMT"); - base::Value policy_content = + base::Value::Dict policy_content = utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); utils::AddTimeUsageLimit(&policy_content, utils::kMonday, base::Hours(3), last_updated); @@ -554,7 +554,7 @@ // Set new policy. base::Time last_updated = utils::TimeFromString("1 Jan 2018 0:00 PST"); - base::Value policy_content = + base::Value::Dict policy_content = utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); utils::AddTimeWindowLimit(&policy_content, utils::kMonday, utils::CreateTime(23, 0), utils::CreateTime(8, 0), @@ -585,7 +585,7 @@ // Set new policy. base::Time last_updated = utils::TimeFromString("1 Jan 2018 0:00 PST"); - base::Value policy_content = + base::Value::Dict policy_content = utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); utils::AddTimeUsageLimit(&policy_content, utils::kMonday, base::Hours(1), last_updated); @@ -615,7 +615,7 @@ // Set new policy. base::Time last_updated = utils::TimeFromString("3 Jan 2018 0:00 GMT-0600"); - base::Value policy_content = + base::Value::Dict policy_content = utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); utils::AddTimeWindowLimit(&policy_content, utils::kWednesday, utils::CreateTime(19, 0), utils::CreateTime(7, 0), @@ -660,7 +660,7 @@ // Set new policy. base::Time last_updated = utils::TimeFromString("1 Jan 2018 0:00 GMT"); - base::Value policy_content = + base::Value::Dict policy_content = utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); utils::AddTimeWindowLimit(&policy_content, utils::kMonday, utils::CreateTime(21, 0), utils::CreateTime(17, 0), @@ -684,7 +684,7 @@ // Set new policy. base::Time last_updated = utils::TimeFromString("3 Jan 2018 0:00 GMT+1300"); - base::Value policy_content = + base::Value::Dict policy_content = utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); utils::AddTimeWindowLimit(&policy_content, utils::kTuesday, utils::CreateTime(20, 0), utils::CreateTime(7, 0), @@ -718,7 +718,7 @@ // Set new policy with 3 hours of time usage limit. base::Time last_updated = utils::TimeFromString("1 Jan 2018 0:00 PST"); - base::Value policy_content = + base::Value::Dict policy_content = utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); utils::AddTimeUsageLimit(&policy_content, utils::kMonday, base::Hours(3), last_updated);
diff --git a/chrome/browser/ash/child_accounts/time_limit_consistency_test/consistency_golden_converter.cc b/chrome/browser/ash/child_accounts/time_limit_consistency_test/consistency_golden_converter.cc index ed41fb8..5c1bccd 100644 --- a/chrome/browser/ash/child_accounts/time_limit_consistency_test/consistency_golden_converter.cc +++ b/chrome/browser/ash/child_accounts/time_limit_consistency_test/consistency_golden_converter.cc
@@ -63,7 +63,7 @@ } // namespace -base::Value ConvertGoldenInputToProcessorInput( +base::Value::Dict ConvertGoldenInputToProcessorInput( const ConsistencyGoldenInput& input) { // Random date representing the last time the policies were updated, // used whenever the last_updated field is not specified in the input proto. @@ -75,7 +75,7 @@ input.usage_limit_resets_at().minute()) : kDefaultResetsAt; - base::Value policy = utils::CreateTimeLimitPolicy(resets_at); + base::Value::Dict policy = utils::CreateTimeLimitPolicy(resets_at); /* Begin Window Limits data */
diff --git a/chrome/browser/ash/child_accounts/time_limit_consistency_test/consistency_golden_converter.h b/chrome/browser/ash/child_accounts/time_limit_consistency_test/consistency_golden_converter.h index 5793f6d9..417fa9f 100644 --- a/chrome/browser/ash/child_accounts/time_limit_consistency_test/consistency_golden_converter.h +++ b/chrome/browser/ash/child_accounts/time_limit_consistency_test/consistency_golden_converter.h
@@ -21,7 +21,7 @@ // Converts the input part of a consistency golden case to the structure used by // the time limit processor. -base::Value ConvertGoldenInputToProcessorInput( +base::Value::Dict ConvertGoldenInputToProcessorInput( const ConsistencyGoldenInput& input); // Converts the output struct generated by the time limit processor to the
diff --git a/chrome/browser/ash/child_accounts/time_limit_consistency_test/consistency_golden_converter_unittest.cc b/chrome/browser/ash/child_accounts/time_limit_consistency_test/consistency_golden_converter_unittest.cc index ba1fd31..cad971a 100644 --- a/chrome/browser/ash/child_accounts/time_limit_consistency_test/consistency_golden_converter_unittest.cc +++ b/chrome/browser/ash/child_accounts/time_limit_consistency_test/consistency_golden_converter_unittest.cc
@@ -32,16 +32,18 @@ TEST_F(ConsistencyGoldenConverterTest, ConvertInputWhenEmpty) { ConsistencyGoldenInput input; - base::Value actual_output = ConvertGoldenInputToProcessorInput(input); + base::Value::Dict actual_output = ConvertGoldenInputToProcessorInput(input); - base::Value expected_output = utils::CreateTimeLimitPolicy(base::Hours(6)); + base::Value::Dict expected_output = + utils::CreateTimeLimitPolicy(base::Hours(6)); EXPECT_TRUE(actual_output == expected_output); } TEST_F(ConsistencyGoldenConverterTest, ConvertInputWithBedtimes) { ConsistencyGoldenInput input; - base::Value expected_output = utils::CreateTimeLimitPolicy(base::Hours(6)); + base::Value::Dict expected_output = + utils::CreateTimeLimitPolicy(base::Hours(6)); // First window: Wednesday, 22:30 to 8:00 consistency_utils::AddWindowLimitEntryToGoldenInput( @@ -59,14 +61,15 @@ utils::CreateTime(18, 45), utils::CreateTime(22, 30), kTestLastUpdated); - base::Value actual_output = ConvertGoldenInputToProcessorInput(input); + base::Value::Dict actual_output = ConvertGoldenInputToProcessorInput(input); EXPECT_TRUE(actual_output == expected_output); } TEST_F(ConsistencyGoldenConverterTest, ConvertInputWithBedtimesLastUpdated) { ConsistencyGoldenInput input; - base::Value expected_output = utils::CreateTimeLimitPolicy(base::Hours(6)); + base::Value::Dict expected_output = + utils::CreateTimeLimitPolicy(base::Hours(6)); // First window: Wednesday, 22:30 to 8:00 consistency_utils::AddWindowLimitEntryToGoldenInput( @@ -76,14 +79,14 @@ utils::CreateTime(22, 30), utils::CreateTime(8, 0), base::Time::FromJavaTime(kTestTimestamp)); - base::Value actual_output = ConvertGoldenInputToProcessorInput(input); + base::Value::Dict actual_output = ConvertGoldenInputToProcessorInput(input); EXPECT_TRUE(actual_output == expected_output); } TEST_F(ConsistencyGoldenConverterTest, ConvertInputWithUsageLimit) { ConsistencyGoldenInput input; - base::Value expected_output = + base::Value::Dict expected_output = utils::CreateTimeLimitPolicy(utils::CreateTime(17, 30)); input.mutable_usage_limit_resets_at()->set_hour(17); @@ -101,14 +104,15 @@ utils::AddTimeUsageLimit(&expected_output, utils::kFriday, base::Minutes(30), kTestLastUpdated); - base::Value actual_output = ConvertGoldenInputToProcessorInput(input); + base::Value::Dict actual_output = ConvertGoldenInputToProcessorInput(input); EXPECT_TRUE(actual_output == expected_output); } TEST_F(ConsistencyGoldenConverterTest, ConvertInputWithUsageLimitDefaultReset) { ConsistencyGoldenInput input; - base::Value expected_output = utils::CreateTimeLimitPolicy(base::Hours(6)); + base::Value::Dict expected_output = + utils::CreateTimeLimitPolicy(base::Hours(6)); // First quota: Tuesday, 60 minutes consistency_utils::AddUsageLimitEntryToGoldenInput(&input, TUESDAY, 60, @@ -122,14 +126,15 @@ utils::AddTimeUsageLimit(&expected_output, utils::kFriday, base::Minutes(30), kTestLastUpdated); - base::Value actual_output = ConvertGoldenInputToProcessorInput(input); + base::Value::Dict actual_output = ConvertGoldenInputToProcessorInput(input); EXPECT_TRUE(actual_output == expected_output); } TEST_F(ConsistencyGoldenConverterTest, ConvertInputWithUsageLimitLastUpdated) { ConsistencyGoldenInput input; - base::Value expected_output = utils::CreateTimeLimitPolicy(base::Hours(6)); + base::Value::Dict expected_output = + utils::CreateTimeLimitPolicy(base::Hours(6)); // First quota: Tuesday, 60 minutes consistency_utils::AddUsageLimitEntryToGoldenInput(&input, TUESDAY, 60, @@ -137,14 +142,15 @@ utils::AddTimeUsageLimit(&expected_output, utils::kTuesday, base::Minutes(60), base::Time::FromJavaTime(kTestTimestamp)); - base::Value actual_output = ConvertGoldenInputToProcessorInput(input); + base::Value::Dict actual_output = ConvertGoldenInputToProcessorInput(input); EXPECT_TRUE(actual_output == expected_output); } TEST_F(ConsistencyGoldenConverterTest, ConvertInputWithOverride) { ConsistencyGoldenInput input; - base::Value expected_output = utils::CreateTimeLimitPolicy(base::Hours(6)); + base::Value::Dict expected_output = + utils::CreateTimeLimitPolicy(base::Hours(6)); // Override: Unlock bedtime consistency_utils::AddOverrideToGoldenInput(&input, UNLOCK_WINDOW_LIMIT, @@ -153,14 +159,15 @@ usage_time_limit::TimeLimitOverride::Action::kUnlock, base::Time::FromJavaTime(kTestTimestamp)); - base::Value actual_output = ConvertGoldenInputToProcessorInput(input); + base::Value::Dict actual_output = ConvertGoldenInputToProcessorInput(input); EXPECT_TRUE(actual_output == expected_output); } TEST_F(ConsistencyGoldenConverterTest, ConvertInputWithTimedOverride) { ConsistencyGoldenInput input; - base::Value expected_output = utils::CreateTimeLimitPolicy(base::Hours(6)); + base::Value::Dict expected_output = + utils::CreateTimeLimitPolicy(base::Hours(6)); const int64_t override_duration_millis = 10000; // Override: Grant more time @@ -171,7 +178,7 @@ base::Time::FromJavaTime(kTestTimestamp), base::Milliseconds(override_duration_millis)); - base::Value actual_output = ConvertGoldenInputToProcessorInput(input); + base::Value::Dict actual_output = ConvertGoldenInputToProcessorInput(input); EXPECT_TRUE(actual_output == expected_output); }
diff --git a/chrome/browser/ash/child_accounts/time_limit_consistency_test/consistency_test.cc b/chrome/browser/ash/child_accounts/time_limit_consistency_test/consistency_test.cc index 65e89f4..7855072 100644 --- a/chrome/browser/ash/child_accounts/time_limit_consistency_test/consistency_test.cc +++ b/chrome/browser/ash/child_accounts/time_limit_consistency_test/consistency_test.cc
@@ -39,7 +39,8 @@ absl::optional<usage_time_limit::State> previous_state = GenerateUnlockUsageLimitOverrideStateFromInput(golden_case.input()); - base::Value policy = ConvertGoldenInputToProcessorInput(golden_case.input()); + base::Value::Dict policy = + ConvertGoldenInputToProcessorInput(golden_case.input()); usage_time_limit::State state = usage_time_limit::GetState( policy, /* local_override */ nullptr, base::Milliseconds(current_state.usage_millis()), usage_timestamp,
diff --git a/chrome/browser/ash/child_accounts/time_limit_override.cc b/chrome/browser/ash/child_accounts/time_limit_override.cc index 80a1c8a..1e38a81 100644 --- a/chrome/browser/ash/child_accounts/time_limit_override.cc +++ b/chrome/browser/ash/child_accounts/time_limit_override.cc
@@ -46,20 +46,20 @@ // static absl::optional<TimeLimitOverride> TimeLimitOverride::FromDictionary( - const base::Value* dict) { - if (!dict || !dict->is_dict()) { + const base::Value::Dict* dict) { + if (!dict) { DLOG(ERROR) << "Override entry is not a dictionary"; return absl::nullopt; } - const std::string* action_string = dict->FindStringKey(kOverrideAction); + const std::string* action_string = dict->FindString(kOverrideAction); if (!action_string || action_string->empty()) { DLOG(ERROR) << "Invalid override action."; return absl::nullopt; } const std::string* creation_time_string = - dict->FindStringKey(kOverrideActionCreatedAt); + dict->FindString(kOverrideActionCreatedAt); int64_t creation_time_millis; if (!creation_time_string || creation_time_string->empty() || !base::StringToInt64(*creation_time_string, &creation_time_millis)) { @@ -73,8 +73,10 @@ base::Time creation_time = base::Time::UnixEpoch() + base::Milliseconds(creation_time_millis); - const base::Value* duration_value = dict->FindPath( - {kOverrideActionSpecificData, kOverrideActionDurationMins}); + const base::Value::Dict* action_dict = + dict->FindDict(kOverrideActionSpecificData); + const base::Value* duration_value = + action_dict ? action_dict->Find(kOverrideActionDurationMins) : nullptr; absl::optional<base::TimeDelta> duration = duration_value ? base::Minutes(duration_value->GetInt()) : absl::optional<base::TimeDelta>(); @@ -94,7 +96,7 @@ absl::optional<TimeLimitOverride> last_override; for (const base::Value& override_value : list->GetListDeprecated()) { absl::optional<TimeLimitOverride> current_override = - FromDictionary(&override_value); + FromDictionary(&override_value.GetDict()); if (!current_override.has_value()) { DLOG(ERROR) << "Invalid override entry"; continue; @@ -128,16 +130,15 @@ return action_ == Action::kLock; } -base::Value TimeLimitOverride::ToDictionary() const { - base::Value dict(base::Value::Type::DICTIONARY); - dict.SetKey(kOverrideAction, base::Value(ActionToString(action_))); - dict.SetKey(kOverrideActionCreatedAt, - base::Value(PolicyTimestamp(created_at_))); +base::Value::Dict TimeLimitOverride::ToDictionary() const { + base::Value::Dict dict; + dict.Set(kOverrideAction, base::Value(ActionToString(action_))); + dict.Set(kOverrideActionCreatedAt, base::Value(PolicyTimestamp(created_at_))); if (duration_.has_value()) { - base::Value duration_dict(base::Value::Type::DICTIONARY); - duration_dict.SetKey(kOverrideActionDuration, - base::Value(duration_->InMinutes())); - dict.SetKey(kOverrideActionSpecificData, std::move(duration_dict)); + base::Value::Dict duration_dict; + duration_dict.Set(kOverrideActionDuration, + base::Value(duration_->InMinutes())); + dict.Set(kOverrideActionSpecificData, std::move(duration_dict)); } return dict; }
diff --git a/chrome/browser/ash/child_accounts/time_limit_override.h b/chrome/browser/ash/child_accounts/time_limit_override.h index 599cd71..b2cf08db 100644 --- a/chrome/browser/ash/child_accounts/time_limit_override.h +++ b/chrome/browser/ash/child_accounts/time_limit_override.h
@@ -8,12 +8,9 @@ #include <string> #include "base/time/time.h" +#include "base/values.h" #include "third_party/abseil-cpp/absl/types/optional.h" -namespace base { -class Value; -} // namespace base - namespace ash { namespace usage_time_limit { @@ -36,7 +33,7 @@ // Factory method. Creates TimeLimitOverride from a |dict|. Returns nullopt if // |dict| could not be parsed. static absl::optional<TimeLimitOverride> FromDictionary( - const base::Value* dict); + const base::Value::Dict* dict); // Factory method. Creates TimeLimitOverride from the most recent override in // the list of overrides passed in |list|. Returns nullopt if |list| could not @@ -72,7 +69,7 @@ bool IsLock() const; // Serializes TimeLimitOverride to a dictionary. - base::Value ToDictionary() const; + base::Value::Dict ToDictionary() const; private: Action action_;
diff --git a/chrome/browser/ash/child_accounts/time_limit_test_utils.cc b/chrome/browser/ash/child_accounts/time_limit_test_utils.cc index 6b41d89..036a9de 100644 --- a/chrome/browser/ash/child_accounts/time_limit_test_utils.cc +++ b/chrome/browser/ash/child_accounts/time_limit_test_utils.cc
@@ -99,17 +99,17 @@ return time_usage; } -base::Value CreateTimeLimitPolicy(base::TimeDelta reset_time) { - base::Value time_usage_limit = base::Value(base::Value::Type::DICTIONARY); - time_usage_limit.SetKey(kUsageLimitResetAt, CreatePolicyTime(reset_time)); +base::Value::Dict CreateTimeLimitPolicy(base::TimeDelta reset_time) { + base::Value::Dict time_usage_limit; + time_usage_limit.Set(kUsageLimitResetAt, CreatePolicyTime(reset_time)); - base::Value time_limit = base::Value(base::Value::Type::DICTIONARY); - time_limit.SetKey(kTimeUsageLimit, std::move(time_usage_limit)); + base::Value::Dict time_limit; + time_limit.Set(kTimeUsageLimit, std::move(time_usage_limit)); return time_limit; } -void AddTimeUsageLimit(base::Value* policy, +void AddTimeUsageLimit(base::Value::Dict* policy, std::string day, base::TimeDelta quota, base::Time last_updated) { @@ -119,66 +119,66 @@ DCHECK_LT(quota, base::Hours(24)); std::transform(day.begin(), day.end(), day.begin(), ::tolower); - policy->FindKey(kTimeUsageLimit) + policy->Find(kTimeUsageLimit) ->SetKey(day, CreateTimeUsage(quota, last_updated)); } -void AddTimeWindowLimit(base::Value* policy, +void AddTimeWindowLimit(base::Value::Dict* policy, const std::string& day, base::TimeDelta start_time, base::TimeDelta end_time, base::Time last_updated) { - base::Value* time_window_limit = policy->FindKey(kTimeWindowLimit); + base::Value::Dict* time_window_limit = policy->FindDict(kTimeWindowLimit); if (!time_window_limit) { - time_window_limit = policy->SetKey( - kTimeWindowLimit, base::Value(base::Value::Type::DICTIONARY)); + time_window_limit = + &policy->Set(kTimeWindowLimit, base::Value::Dict())->GetDict(); } base::Value* window_limit_entries = - time_window_limit->FindKey(kWindowLimitEntries); + time_window_limit->Find(kWindowLimitEntries); if (!window_limit_entries) { - window_limit_entries = time_window_limit->SetKey( - kWindowLimitEntries, base::Value(base::Value::Type::LIST)); + window_limit_entries = + time_window_limit->Set(kWindowLimitEntries, base::Value::List()); } window_limit_entries->Append( CreateTimeWindow(day, start_time, end_time, last_updated)); } -void AddOverride(base::Value* policy, +void AddOverride(base::Value::Dict* policy, usage_time_limit::TimeLimitOverride::Action action, base::Time created_at) { base::Value* overrides = - policy->FindKey(usage_time_limit::TimeLimitOverride::kOverridesDictKey); + policy->Find(usage_time_limit::TimeLimitOverride::kOverridesDictKey); if (!overrides) { overrides = - policy->SetKey(usage_time_limit::TimeLimitOverride::kOverridesDictKey, - base::Value(base::Value::Type::LIST)); + policy->Set(usage_time_limit::TimeLimitOverride::kOverridesDictKey, + base::Value::List()); } usage_time_limit::TimeLimitOverride new_override(action, created_at, absl::nullopt); - overrides->Append(new_override.ToDictionary()); + overrides->Append(base::Value(new_override.ToDictionary())); } -void AddOverrideWithDuration(base::Value* policy, +void AddOverrideWithDuration(base::Value::Dict* policy, usage_time_limit::TimeLimitOverride::Action action, base::Time created_at, base::TimeDelta duration) { base::Value* overrides = - policy->FindKey(usage_time_limit::TimeLimitOverride::kOverridesDictKey); + policy->Find(usage_time_limit::TimeLimitOverride::kOverridesDictKey); if (!overrides) { overrides = - policy->SetKey(usage_time_limit::TimeLimitOverride::kOverridesDictKey, - base::Value(base::Value::Type::LIST)); + policy->Set(usage_time_limit::TimeLimitOverride::kOverridesDictKey, + base::Value::List()); } usage_time_limit::TimeLimitOverride new_override(action, created_at, duration); - overrides->Append(new_override.ToDictionary()); + overrides->Append(base::Value(new_override.ToDictionary())); } -std::string PolicyToString(const base::Value& policy) { +std::string PolicyToString(const base::Value::Dict& policy) { std::string json_string; base::JSONWriter::Write(policy, &json_string); return json_string;
diff --git a/chrome/browser/ash/child_accounts/time_limit_test_utils.h b/chrome/browser/ash/child_accounts/time_limit_test_utils.h index e33ff15..e211985 100644 --- a/chrome/browser/ash/child_accounts/time_limit_test_utils.h +++ b/chrome/browser/ash/child_accounts/time_limit_test_utils.h
@@ -55,39 +55,35 @@ // Creates dictionary with a minimalist Time Limit policy, containing only the // time usage limit reset time. -base::Value CreateTimeLimitPolicy(base::TimeDelta reset_time); +base::Value::Dict CreateTimeLimitPolicy(base::TimeDelta reset_time); // Adds a time usage limit dictionary to the provided Time Limit policy. -// |policy| needs to be a dictionary. -void AddTimeUsageLimit(base::Value* policy, +void AddTimeUsageLimit(base::Value::Dict* policy, std::string day, base::TimeDelta quota, base::Time last_updated); // Adds a time window limit dictionary to the provided Time Limit policy. -// |policy| needs to be a dictionary. -void AddTimeWindowLimit(base::Value* policy, +void AddTimeWindowLimit(base::Value::Dict* policy, const std::string& day, base::TimeDelta start_time, base::TimeDelta end_time, base::Time last_updated); // Adds a time limit override dictionary to the provided Time Limit policy. -// |policy| needs to be a dictionary. -void AddOverride(base::Value* policy, +void AddOverride(base::Value::Dict* policy, usage_time_limit::TimeLimitOverride::Action action, base::Time created_at); // Adds a time limit override with duration dictionary to the provided -// Time Limit policy. |policy| needs to be a dictionary. -void AddOverrideWithDuration(base::Value* policy, +// Time Limit policy. +void AddOverrideWithDuration(base::Value::Dict* policy, usage_time_limit::TimeLimitOverride::Action action, base::Time created_at, base::TimeDelta duration); -// Converts the Time Limit policy to a string. |policy| needs to be a -// dictionary. -std::string PolicyToString(const base::Value& policy); +// Converts the Time Limit policy to a string. +std::string PolicyToString(const base::Value::Dict& policy); } // namespace time_limit_test_utils } // namespace ash
diff --git a/chrome/browser/ash/child_accounts/time_limits/app_time_controller.cc b/chrome/browser/ash/child_accounts/time_limits/app_time_controller.cc index 898d832..e82d9185 100644 --- a/chrome/browser/ash/child_accounts/time_limits/app_time_controller.cc +++ b/chrome/browser/ash/child_accounts/time_limits/app_time_controller.cc
@@ -319,22 +319,18 @@ void AppTimeController::TimeLimitsPolicyUpdated(const std::string& pref_name) { DCHECK_EQ(pref_name, prefs::kPerAppTimeLimitsPolicy); - const base::Value* policy = - pref_registrar_->prefs()->GetDictionary(prefs::kPerAppTimeLimitsPolicy); + const base::Value::Dict& policy = + pref_registrar_->prefs()->GetValueDict(prefs::kPerAppTimeLimitsPolicy); - if (!policy || !policy->is_dict()) { - LOG(WARNING) << "Invalid PerAppTimeLimits policy."; - return; - } - std::map<AppId, AppLimit> app_limits = policy::AppLimitsFromDict(*policy); + std::map<AppId, AppLimit> app_limits = policy::AppLimitsFromDict(policy); bool updated = app_registry_->UpdateAppLimits(app_limits); app_registry_->SetReportingEnabled( - policy::ActivityReportingEnabledFromDict(*policy)); + policy::ActivityReportingEnabledFromDict(policy)); absl::optional<base::TimeDelta> new_reset_time = - policy::ResetTimeFromDict(*policy); + policy::ResetTimeFromDict(policy); // TODO(agawronska): Propagate the information about reset time change. if (new_reset_time && *new_reset_time != limits_reset_time_) limits_reset_time_ = *new_reset_time; @@ -417,16 +413,11 @@ LOG(WARNING) << " Invalid PerAppTimeLimitAllowlist policy"; } - const base::Value* policy = - pref_registrar_->prefs()->GetDictionary(prefs::kPerAppTimeLimitsPolicy); - - if (!policy || !policy->is_dict()) { - LOG(WARNING) << "Invalid PerAppTimeLimits policy."; - return; - } + const base::Value::Dict& policy = + pref_registrar_->prefs()->GetValueDict(prefs::kPerAppTimeLimitsPolicy); // Update the application's time limit. - const std::map<AppId, AppLimit> limits = policy::AppLimitsFromDict(*policy); + const std::map<AppId, AppLimit> limits = policy::AppLimitsFromDict(policy); // Update the limit for newly installed app, if it exists. auto result = limits.find(app_id); if (result == limits.end())
diff --git a/chrome/browser/ash/child_accounts/time_limits/app_time_policy_helpers.cc b/chrome/browser/ash/child_accounts/time_limits/app_time_policy_helpers.cc index 18d97da..073d620 100644 --- a/chrome/browser/ash/child_accounts/time_limits/app_time_policy_helpers.cc +++ b/chrome/browser/ash/child_accounts/time_limits/app_time_policy_helpers.cc
@@ -133,11 +133,8 @@ return AppIdFromDict(*app_info); } -absl::optional<AppLimit> AppLimitFromDict(const base::Value& dict) { - if (!dict.is_dict()) - return absl::nullopt; - - const std::string* restriction_string = dict.FindStringKey(kRestrictionEnum); +absl::optional<AppLimit> AppLimitFromDict(const base::Value::Dict& dict) { + const std::string* restriction_string = dict.FindString(kRestrictionEnum); if (!restriction_string || restriction_string->empty()) { DLOG(ERROR) << "Invalid restriction."; return absl::nullopt; @@ -145,7 +142,7 @@ const AppRestriction restriction = PolicyStringToAppRestriction(*restriction_string); - absl::optional<int> daily_limit_mins = dict.FindIntKey(kDailyLimitInt); + absl::optional<int> daily_limit_mins = dict.FindInt(kDailyLimitInt); if ((restriction == AppRestriction::kTimeLimit && !daily_limit_mins) || (restriction == AppRestriction::kBlocked && daily_limit_mins)) { DLOG(ERROR) << "Invalid restriction."; @@ -162,8 +159,7 @@ } } - const std::string* last_updated_string = - dict.FindStringKey(kLastUpdatedString); + const std::string* last_updated_string = dict.FindString(kLastUpdatedString); int64_t last_updated_millis; if (!last_updated_string || last_updated_string->empty() || !base::StringToInt64(*last_updated_string, &last_updated_millis)) { @@ -190,11 +186,9 @@ return value; } -absl::optional<base::TimeDelta> ResetTimeFromDict(const base::Value& dict) { - if (!dict.is_dict()) - return absl::nullopt; - - const base::Value* reset_dict = dict.FindKey(kResetAtDict); +absl::optional<base::TimeDelta> ResetTimeFromDict( + const base::Value::Dict& dict) { + const base::Value* reset_dict = dict.Find(kResetAtDict); if (!reset_dict || !reset_dict->is_dict()) { DLOG(ERROR) << "Invalid reset time dictionary."; return absl::nullopt; @@ -224,23 +218,21 @@ return value; } -absl::optional<bool> ActivityReportingEnabledFromDict(const base::Value& dict) { - if (!dict.is_dict()) - return absl::nullopt; - return dict.FindBoolPath(kActivityReportingEnabled); +absl::optional<bool> ActivityReportingEnabledFromDict( + const base::Value::Dict& dict) { + return dict.FindBool(kActivityReportingEnabled); } -std::map<AppId, AppLimit> AppLimitsFromDict(const base::Value& dict) { +std::map<AppId, AppLimit> AppLimitsFromDict(const base::Value::Dict& dict) { std::map<AppId, AppLimit> app_limits; - const base::Value* limits_array = dict.FindListKey(kAppLimitsArray); + const base::Value::List* limits_array = dict.FindList(kAppLimitsArray); if (!limits_array) { DLOG(ERROR) << "Invalid app limits list."; return app_limits; } - base::Value::ConstListView list_view = limits_array->GetListDeprecated(); - for (const base::Value& dict : list_view) { + for (const base::Value& dict : *limits_array) { if (!dict.is_dict()) { DLOG(ERROR) << "Invalid app limits entry. "; continue; @@ -252,7 +244,7 @@ continue; } - absl::optional<AppLimit> app_limit = AppLimitFromDict(dict); + absl::optional<AppLimit> app_limit = AppLimitFromDict(dict.GetDict()); if (!app_limit) { DLOG(ERROR) << "Invalid app limit."; continue;
diff --git a/chrome/browser/ash/child_accounts/time_limits/app_time_policy_helpers.h b/chrome/browser/ash/child_accounts/time_limits/app_time_policy_helpers.h index 2ae68c31..e3669a7 100644 --- a/chrome/browser/ash/child_accounts/time_limits/app_time_policy_helpers.h +++ b/chrome/browser/ash/child_accounts/time_limits/app_time_policy_helpers.h
@@ -8,12 +8,12 @@ #include <map> #include <string> +#include "base/values.h" #include "components/services/app_service/public/cpp/app_types.h" #include "third_party/abseil-cpp/absl/types/optional.h" namespace base { class TimeDelta; -class Value; } // namespace base namespace ash { @@ -62,25 +62,27 @@ // Deserializes AppLimit from |dict|. // Returns value if |dict| contains valid app limit information. -absl::optional<AppLimit> AppLimitFromDict(const base::Value& dict); +absl::optional<AppLimit> AppLimitFromDict(const base::Value::Dict& dict); // Serializes AppLimit to the dictionary. base::Value AppLimitToDict(const AppLimit& limit); // Deserializes daily limits reset time from |dict|. // Returns value if |dict| contains valid reset time information. -absl::optional<base::TimeDelta> ResetTimeFromDict(const base::Value& dict); +absl::optional<base::TimeDelta> ResetTimeFromDict( + const base::Value::Dict& dict); // Serializes daily limits reset to the dictionary. base::Value ResetTimeToDict(int hour, int minutes); // Deserializes activity reporting enabled boolean from |dict|. // Returns value if |dict| contains a valid entry. -absl::optional<bool> ActivityReportingEnabledFromDict(const base::Value& dict); +absl::optional<bool> ActivityReportingEnabledFromDict( + const base::Value::Dict& dict); // Deserializes app limits data from the |dict|. // Will return empty map if |dict| is invalid. -std::map<AppId, AppLimit> AppLimitsFromDict(const base::Value& dict); +std::map<AppId, AppLimit> AppLimitsFromDict(const base::Value::Dict& dict); } // namespace policy } // namespace app_time
diff --git a/chrome/browser/ash/child_accounts/usage_time_limit_processor.cc b/chrome/browser/ash/child_accounts/usage_time_limit_processor.cc index 52a86c31..1ac0204 100644 --- a/chrome/browser/ash/child_accounts/usage_time_limit_processor.cc +++ b/chrome/browser/ash/child_accounts/usage_time_limit_processor.cc
@@ -1199,41 +1199,37 @@ } // namespace internal absl::optional<internal::TimeWindowLimit> TimeWindowLimitFromPolicy( - const base::Value& time_limit) { - DCHECK(time_limit.is_dict()); + const base::Value::Dict& time_limit) { const base::Value* time_window_limit_value = - time_limit.FindKey(internal::kTimeWindowLimit); + time_limit.Find(internal::kTimeWindowLimit); if (!time_window_limit_value) return absl::nullopt; return internal::TimeWindowLimit(*time_window_limit_value); } absl::optional<internal::TimeUsageLimit> TimeUsageLimitFromPolicy( - const base::Value& time_limit) { - DCHECK(time_limit.is_dict()); + const base::Value::Dict& time_limit) { const base::Value* time_usage_limit_value = - time_limit.FindKey(internal::kTimeUsageLimit); + time_limit.Find(internal::kTimeUsageLimit); if (!time_usage_limit_value) return absl::nullopt; return internal::TimeUsageLimit(*time_usage_limit_value); } absl::optional<TimeLimitOverride> OverrideFromPolicy( - const base::Value& time_limit) { - DCHECK(time_limit.is_dict()); + const base::Value::Dict& time_limit) { const base::Value* override_value = - time_limit.FindKey(TimeLimitOverride::kOverridesDictKey); + time_limit.Find(TimeLimitOverride::kOverridesDictKey); return TimeLimitOverride::MostRecentFromList(override_value); } -State GetState(const base::Value& time_limit, - const base::Value* local_override, +State GetState(const base::Value::Dict& time_limit, + const base::Value::Dict* local_override, const base::TimeDelta& used_time, const base::Time& usage_timestamp, const base::Time& current_time, const icu::TimeZone* const time_zone, const absl::optional<State>& previous_state) { - DCHECK(time_limit.is_dict()); absl::optional<internal::TimeWindowLimit> time_window_limit = TimeWindowLimitFromPolicy(time_limit); absl::optional<internal::TimeUsageLimit> time_usage_limit = @@ -1251,11 +1247,10 @@ .GetState(); } -base::Time GetExpectedResetTime(const base::Value& time_limit, - const base::Value* local_override, +base::Time GetExpectedResetTime(const base::Value::Dict& time_limit, + const base::Value::Dict* local_override, const base::Time current_time, const icu::TimeZone* const time_zone) { - DCHECK(time_limit.is_dict()); absl::optional<internal::TimeWindowLimit> time_window_limit = TimeWindowLimitFromPolicy(time_limit); absl::optional<internal::TimeUsageLimit> time_usage_limit = @@ -1273,12 +1268,11 @@ } absl::optional<base::TimeDelta> GetRemainingTimeUsage( - const base::Value& time_limit, - const base::Value* local_override, + const base::Value::Dict& time_limit, + const base::Value::Dict* local_override, const base::Time current_time, const base::TimeDelta& used_time, const icu::TimeZone* const time_zone) { - DCHECK(time_limit.is_dict()); absl::optional<internal::TimeWindowLimit> time_window_limit = TimeWindowLimitFromPolicy(time_limit); absl::optional<internal::TimeUsageLimit> time_usage_limit = @@ -1295,16 +1289,13 @@ .GetRemainingTimeUsage(); } -base::TimeDelta GetTimeUsageLimitResetTime(const base::Value& time_limit) { - DCHECK(time_limit.is_dict()); +base::TimeDelta GetTimeUsageLimitResetTime( + const base::Value::Dict& time_limit) { return internal::GetUsageLimitResetTime(TimeUsageLimitFromPolicy(time_limit)); } -std::set<PolicyType> UpdatedPolicyTypes(const base::Value& old_policy, - const base::Value& new_policy) { - DCHECK(old_policy.is_dict()); - DCHECK(new_policy.is_dict()); - +std::set<PolicyType> UpdatedPolicyTypes(const base::Value::Dict& old_policy, + const base::Value::Dict& new_policy) { std::set<PolicyType> updated_policies; if (TimeUsageLimitFromPolicy(old_policy) != TimeUsageLimitFromPolicy(new_policy)) { @@ -1328,8 +1319,7 @@ } std::set<PolicyType> GetEnabledTimeLimitPolicies( - const base::Value& time_limit_prefs) { - DCHECK(time_limit_prefs.is_dict()); + const base::Value::Dict& time_limit_prefs) { std::set<PolicyType> enabled_policies; absl::optional<internal::TimeWindowLimit> time_window_limit =
diff --git a/chrome/browser/ash/child_accounts/usage_time_limit_processor.h b/chrome/browser/ash/child_accounts/usage_time_limit_processor.h index af9810d..f6aedc6 100644 --- a/chrome/browser/ash/child_accounts/usage_time_limit_processor.h +++ b/chrome/browser/ash/child_accounts/usage_time_limit_processor.h
@@ -15,12 +15,9 @@ #include "ash/components/settings/timezone_settings.h" #include "base/time/time.h" +#include "base/values.h" #include "third_party/abseil-cpp/absl/types/optional.h" -namespace base { -class Value; -} // namespace base - namespace ash { namespace usage_time_limit { namespace internal { @@ -161,8 +158,8 @@ // |usage_timestamp| when was |used_time| data collected. Usually differs from // |current_time| by milliseconds. // |previous_state| state previously returned by UsageTimeLimitProcessor. -State GetState(const base::Value& time_limit, - const base::Value* local_override, +State GetState(const base::Value::Dict& time_limit, + const base::Value::Dict* local_override, const base::TimeDelta& used_time, const base::Time& usage_timestamp, const base::Time& current_time, @@ -173,8 +170,8 @@ // |time_limit| dictionary with UsageTimeLimit policy data. // |local_override| dictionary with data of the last local override (authorized // by parent access code). -base::Time GetExpectedResetTime(const base::Value& time_limit, - const base::Value* local_override, +base::Time GetExpectedResetTime(const base::Value::Dict& time_limit, + const base::Value::Dict* local_override, base::Time current_time, const icu::TimeZone* const time_zone); @@ -184,30 +181,29 @@ // by parent access code). // |used_time| time used in the current day. absl::optional<base::TimeDelta> GetRemainingTimeUsage( - const base::Value& time_limit, - const base::Value* local_override, + const base::Value::Dict& time_limit, + const base::Value::Dict* local_override, const base::Time current_time, const base::TimeDelta& used_time, const icu::TimeZone* const time_zone); // Returns time of the day when TimeUsageLimit policy is reset, represented by -// the distance from midnight. |time_limit| needs to be a dictionary. -base::TimeDelta GetTimeUsageLimitResetTime(const base::Value& time_limit); +// the distance from midnight. +base::TimeDelta GetTimeUsageLimitResetTime(const base::Value::Dict& time_limit); // Compares two Usage Time Limit policy dictionaries and returns which // PolicyTypes changed between the two versions. Changes on simple overrides are // not reported, but changes on override with durations are, the reason is that // this method is intended for notifications, and the former does not trigger -// those while the latter does. |old_policy| and |new_policy| need to be -// dictionaries. -std::set<PolicyType> UpdatedPolicyTypes(const base::Value& old_policy, - const base::Value& new_policy); +// those while the latter does. +std::set<PolicyType> UpdatedPolicyTypes(const base::Value::Dict& old_policy, + const base::Value::Dict& new_policy); // Returns the active time limit polices in `time_limit_prefs`. // `time_limit_prefs` is the value of prefs::kUsageTimeLimit which stores the // usage time limit preference of a user. std::set<PolicyType> GetEnabledTimeLimitPolicies( - const base::Value& time_limit_prefs); + const base::Value::Dict& time_limit_prefs); } // namespace usage_time_limit } // namespace ash
diff --git a/chrome/browser/ash/child_accounts/usage_time_limit_processor_unittest.cc b/chrome/browser/ash/child_accounts/usage_time_limit_processor_unittest.cc index 9b2bd0b..699e9ea 100644 --- a/chrome/browser/ash/child_accounts/usage_time_limit_processor_unittest.cc +++ b/chrome/browser/ash/child_accounts/usage_time_limit_processor_unittest.cc
@@ -291,7 +291,8 @@ // Set up policy. base::Time last_updated = utils::TimeFromString("1 Jan 2018 10:00 GMT+0300"); - base::Value policy = utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); + base::Value::Dict policy = + utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); utils::AddTimeWindowLimit(&policy, utils::kSunday, utils::CreateTime(22, 0), utils::CreateTime(7, 30), last_updated); @@ -365,7 +366,8 @@ // Set up policy. base::Time last_updated = utils::TimeFromString("1 Jan 2018 8:00"); - base::Value policy = utils::CreateTimeLimitPolicy(utils::CreateTime(8, 0)); + base::Value::Dict policy = + utils::CreateTimeLimitPolicy(utils::CreateTime(8, 0)); utils::AddTimeUsageLimit(&policy, utils::kTuesday, base::Hours(2), last_updated); @@ -433,7 +435,8 @@ // Setup policy. base::Time last_updated = utils::TimeFromString("1 Jan 2018 8:00"); - base::Value policy = utils::CreateTimeLimitPolicy(utils::CreateTime(8, 0)); + base::Value::Dict policy = + utils::CreateTimeLimitPolicy(utils::CreateTime(8, 0)); utils::AddTimeWindowLimit(&policy, utils::kMonday, utils::CreateTime(21, 0), utils::CreateTime(8, 30), last_updated); @@ -524,7 +527,8 @@ // Setup policy. base::Time last_updated = utils::TimeFromString("5 Jan 2018 8:00 PST"); - base::Value policy = utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); + base::Value::Dict policy = + utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); utils::AddTimeUsageLimit(&policy, utils::kFriday, base::Hours(1), last_updated); @@ -552,7 +556,7 @@ TEST_F(UsageTimeLimitProcessorTest, GetStateWithOverrideLock) { std::unique_ptr<icu::TimeZone> timezone(icu::TimeZone::createTimeZone("GMT")); - base::Value policy = base::Value(base::Value::Type::DICTIONARY); + base::Value::Dict policy; utils::AddOverride(&policy, TimeLimitOverride::Action::kLock, utils::TimeFromString("Mon, 1 Jan 2018 15:00")); @@ -580,7 +584,8 @@ GetStateWithOverrideLockFollowedByWindowLimit) { std::unique_ptr<icu::TimeZone> timezone(icu::TimeZone::createTimeZone("GMT")); - base::Value policy = utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); + base::Value::Dict policy = + utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); utils::AddTimeWindowLimit(&policy, utils::kMonday, utils::CreateTime(22, 0), utils::CreateTime(9, 0), utils::TimeFromString("Mon, 1 Jan 2018 00:00")); @@ -633,7 +638,7 @@ // Setup policy. base::Time last_updated = utils::TimeFromString("Mon, 1 Jan 2018 8:00 GMT+0800"); - base::Value policy = base::Value(base::Value::Type::DICTIONARY); + base::Value::Dict policy; utils::AddTimeWindowLimit(&policy, utils::kMonday, utils::CreateTime(18, 0), utils::CreateTime(7, 30), last_updated); utils::AddOverride(&policy, TimeLimitOverride::Action::kUnlock, @@ -687,7 +692,8 @@ // Setup policy. base::Time last_updated = utils::TimeFromString("1 Jan 2018 8:00 PST"); - base::Value policy = utils::CreateTimeLimitPolicy(utils::CreateTime(8, 0)); + base::Value::Dict policy = + utils::CreateTimeLimitPolicy(utils::CreateTime(8, 0)); utils::AddTimeWindowLimit(&policy, utils::kMonday, utils::CreateTime(21, 0), utils::CreateTime(10, 0), last_updated); utils::AddTimeUsageLimit(&policy, utils::kMonday, base::Hours(1), @@ -740,7 +746,8 @@ // Setup policy. base::Time last_updated = utils::TimeFromString("1 Jan 2018 8:00 PST"); - base::Value policy = utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); + base::Value::Dict policy = + utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); utils::AddTimeUsageLimit(&policy, utils::kSunday, base::Minutes(60), last_updated); @@ -809,7 +816,8 @@ std::unique_ptr<icu::TimeZone> timezone(icu::TimeZone::createTimeZone("PST")); // Setup policy. - base::Value policy = utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); + base::Value::Dict policy = + utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); utils::AddOverride(&policy, TimeLimitOverride::Action::kLock, utils::TimeFromString("Mon, 1 Jan 2018 21:00 PST")); @@ -872,7 +880,8 @@ // Setup policy. base::Time last_updated = utils::TimeFromString("1 Jan 2018 8:00 PST"); - base::Value policy = utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); + base::Value::Dict policy = + utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); utils::AddTimeWindowLimit(&policy, utils::kMonday, utils::CreateTime(21, 0), utils::CreateTime(7, 0), last_updated); utils::AddTimeWindowLimit(&policy, utils::kTuesday, utils::CreateTime(21, 0), @@ -942,7 +951,8 @@ // Setup policy. base::Time last_updated = utils::TimeFromString("1 Jan 2018 8:00 PST"); - base::Value policy = utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); + base::Value::Dict policy = + utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); utils::AddTimeUsageLimit(&policy, utils::kMonday, base::Hours(3), last_updated); utils::AddTimeUsageLimit(&policy, utils::kTuesday, base::Hours(3), @@ -1012,7 +1022,8 @@ // Setup policy. base::Time last_updated = utils::TimeFromString("1 Jan 2018 8:00 GMT"); - base::Value policy = utils::CreateTimeLimitPolicy(utils::CreateTime(8, 0)); + base::Value::Dict policy = + utils::CreateTimeLimitPolicy(utils::CreateTime(8, 0)); utils::AddTimeWindowLimit(&policy, utils::kSaturday, utils::CreateTime(21, 0), utils::CreateTime(8, 30), last_updated); @@ -1041,7 +1052,8 @@ // Setup policy. base::Time last_updated = utils::TimeFromString("1 Jan 2018 8:00 GMT"); - base::Value policy = utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); + base::Value::Dict policy = + utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); utils::AddTimeUsageLimit(&policy, utils::kSaturday, base::Hours(2), last_updated); @@ -1072,7 +1084,8 @@ // Setup policy. base::Time last_updated = utils::TimeFromString("1 Jan 2018 8:00 PST"); - base::Value policy = utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); + base::Value::Dict policy = + utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); utils::AddTimeUsageLimit(&policy, utils::kSaturday, base::Hours(2), last_updated); @@ -1104,7 +1117,8 @@ // Setup policy. base::Time last_updated = utils::TimeFromString("1 Jan 2018 8:00 PST"); - base::Value policy = utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); + base::Value::Dict policy = + utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); utils::AddTimeWindowLimit(&policy, utils::kMonday, utils::CreateTime(18, 0), utils::CreateTime(20, 0), last_updated); utils::AddOverride(&policy, TimeLimitOverride::Action::kLock, @@ -1169,7 +1183,8 @@ // Setup policy. base::Time last_updated = utils::TimeFromString("1 Jan 2018 8:00 PST"); - base::Value policy = utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); + base::Value::Dict policy = + utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); utils::AddTimeWindowLimit(&policy, utils::kMonday, utils::CreateTime(10, 0), utils::CreateTime(20, 0), last_updated); utils::AddOverride(&policy, TimeLimitOverride::Action::kUnlock, @@ -1237,7 +1252,8 @@ // Setup policy. base::Time last_updated = utils::TimeFromString("1 Jan 2018 8:00 PST"); - base::Value policy = utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); + base::Value::Dict policy = + utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); utils::AddTimeWindowLimit(&policy, utils::kMonday, utils::CreateTime(22, 0), utils::CreateTime(10, 0), last_updated); utils::AddOverrideWithDuration( @@ -1286,7 +1302,8 @@ // Setup policy. base::Time last_updated = utils::TimeFromString("1 Jan 2018 8:00 GMT"); - base::Value policy = utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); + base::Value::Dict policy = + utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); utils::AddTimeWindowLimit(&policy, utils::kMonday, utils::CreateTime(22, 0), utils::CreateTime(5, 0), last_updated); utils::AddOverrideWithDuration( @@ -1319,7 +1336,8 @@ // Setup policy. base::Time last_updated = utils::TimeFromString("1 Jan 2018 8:00 PST"); - base::Value policy = utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); + base::Value::Dict policy = + utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); utils::AddTimeWindowLimit(&policy, utils::kMonday, utils::CreateTime(22, 0), utils::CreateTime(10, 0), last_updated); utils::AddTimeWindowLimit(&policy, utils::kTuesday, utils::CreateTime(10, 0), @@ -1390,7 +1408,8 @@ // Setup policy. base::Time last_updated = utils::TimeFromString("1 Jan 2018 8:00 GMT"); - base::Value policy = utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); + base::Value::Dict policy = + utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); utils::AddTimeUsageLimit(&policy, utils::kThursday, base::Hours(2), last_updated); @@ -1461,7 +1480,8 @@ // Setup policy. base::Time last_updated = utils::TimeFromString("1 Jan 2018 8:00 PST"); - base::Value policy = utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); + base::Value::Dict policy = + utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); utils::AddTimeUsageLimit(&policy, utils::kMonday, base::Hours(2), last_updated); @@ -1532,7 +1552,8 @@ // Setup policy. base::Time last_updated = utils::TimeFromString("1 Jan 2018 8:00 GMT"); - base::Value policy = utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); + base::Value::Dict policy = + utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); utils::AddTimeWindowLimit(&policy, utils::kSaturday, utils::CreateTime(10, 0), utils::CreateTime(4, 0), last_updated); utils::AddTimeUsageLimit(&policy, utils::kSaturday, base::Hours(2), @@ -1605,7 +1626,8 @@ // Setup policy. base::Time last_updated = utils::TimeFromString("1 Jan 2018 8:00 BRT"); - base::Value policy = utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); + base::Value::Dict policy = + utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); utils::AddTimeWindowLimit(&policy, utils::kWednesday, utils::CreateTime(22, 0), utils::CreateTime(10, 0), last_updated); @@ -1679,7 +1701,8 @@ // Setup policy. base::Time last_updated = utils::TimeFromString("2 Jan 2018 8:00 BRT"); - base::Value policy = utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); + base::Value::Dict policy = + utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); utils::AddTimeWindowLimit(&policy, utils::kTuesday, utils::CreateTime(22, 0), utils::CreateTime(10, 0), last_updated); utils::AddOverrideWithDuration( @@ -1729,7 +1752,8 @@ // Setup policy. base::Time last_updated = utils::TimeFromString("1 Jan 2018 8:00 PST"); - base::Value policy = utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); + base::Value::Dict policy = + utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); utils::AddTimeUsageLimit(&policy, utils::kMonday, base::Hours(2), last_updated); @@ -1801,7 +1825,8 @@ // Setup policy. base::Time last_updated = utils::TimeFromString("1 Jan 2018 8:00 BRT"); - base::Value policy = utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); + base::Value::Dict policy = + utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); utils::AddTimeUsageLimit(&policy, utils::kSaturday, base::Hours(2), last_updated); @@ -1873,7 +1898,8 @@ // Setup policy. base::Time last_updated = utils::TimeFromString("1 Jan 2018 8:00 GMT"); - base::Value policy = utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); + base::Value::Dict policy = + utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); utils::AddTimeWindowLimit(&policy, utils::kWednesday, utils::CreateTime(22, 0), utils::CreateTime(10, 0), last_updated); @@ -1925,7 +1951,8 @@ // Setup policy. base::Time last_updated = utils::TimeFromString("1 Jan 2018 8:00 PST"); - base::Value policy = utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); + base::Value::Dict policy = + utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); utils::AddTimeUsageLimit(&policy, utils::kSunday, base::Hours(2), last_updated); @@ -1994,7 +2021,8 @@ // Setup policy. base::Time last_updated = utils::TimeFromString("1 Jan 2018 8:00 PST"); - base::Value policy = utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); + base::Value::Dict policy = + utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); utils::AddTimeWindowLimit(&policy, utils::kMonday, utils::CreateTime(22, 0), utils::CreateTime(10, 0), last_updated); utils::AddOverrideWithDuration( @@ -2046,7 +2074,8 @@ // Setup policy. base::Time last_updated = utils::TimeFromString("1 Jan 2018 8:00 PST"); - base::Value policy = utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); + base::Value::Dict policy = + utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); utils::AddTimeUsageLimit(&policy, utils::kFriday, base::Hours(2), last_updated); @@ -2115,7 +2144,8 @@ // Setup policy. base::Time last_updated = utils::TimeFromString("1 Jan 2018 8:00 GMT"); - base::Value policy = utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); + base::Value::Dict policy = + utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); utils::AddTimeWindowLimit(&policy, utils::kWednesday, utils::CreateTime(22, 0), utils::CreateTime(10, 0), last_updated); @@ -2185,7 +2215,8 @@ // Setup policy. base::Time last_updated = utils::TimeFromString("1 Jan 2018 8:00 BRT"); - base::Value policy = utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); + base::Value::Dict policy = + utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); utils::AddTimeUsageLimit(&policy, utils::kThursday, base::Hours(2), last_updated); @@ -2260,7 +2291,8 @@ // Setup policy. base::Time last_updated = utils::TimeFromString("1 Jan 2018 8:00 BRT"); - base::Value policy = utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); + base::Value::Dict policy = + utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); utils::AddTimeUsageLimit(&policy, utils::kWednesday, base::Hours(2), last_updated); @@ -2359,7 +2391,8 @@ // Setup policy. base::Time last_updated = utils::TimeFromString("1 Jan 2018 8:00 BRT"); - base::Value policy = utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); + base::Value::Dict policy = + utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); utils::AddTimeUsageLimit(&policy, utils::kWednesday, base::Hours(0), last_updated); utils::AddTimeUsageLimit(&policy, utils::kThursday, base::Hours(0), @@ -2471,7 +2504,8 @@ // Setup policy. base::Time last_updated = utils::TimeFromString("1 Jan 2018 8:00 BRT"); - base::Value policy = utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); + base::Value::Dict policy = + utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); utils::AddTimeUsageLimit(&policy, utils::kWednesday, base::Hours(0), last_updated); utils::AddTimeUsageLimit(&policy, utils::kThursday, base::Hours(0), @@ -2553,7 +2587,7 @@ base::Time::FromString("Mon, 1 Jan 2018 19:00 GMT", ¤t_time)); const base::Time last_updated = current_time - base::Hours(4); - auto policy = base::Value(base::Value::Type::DICTIONARY); + base::Value::Dict policy; utils::AddTimeWindowLimit(&policy, utils::kMonday, utils::CreateTime(kWindowStart, 0), utils::CreateTime(kWindowEnd, 0), last_updated); @@ -2562,7 +2596,7 @@ utils::CreateTime(kWindowEnd, 0), last_updated); // Local override started before latest policy update - should be ignored. - base::Value inactive_local_override = + base::Value::Dict inactive_local_override = usage_time_limit::TimeLimitOverride( usage_time_limit::TimeLimitOverride::Action::kUnlock, last_updated - base::Minutes(5), absl::nullopt /* duration */) @@ -2583,7 +2617,7 @@ EXPECT_EQ(monday_bedtime_end, state.next_unlock_time); // Local override started after last policy update - should take effect. - base::Value active_local_override = + base::Value::Dict active_local_override = usage_time_limit::TimeLimitOverride( usage_time_limit::TimeLimitOverride::Action::kUnlock, current_time - base::Minutes(5), absl::nullopt /* duration */) @@ -2616,7 +2650,8 @@ ASSERT_TRUE(base::Time::FromString("Mon, 1 Jan 2018 15:00 GMT", ×tamp)); const base::Time last_updated = timestamp - base::Hours(4); - base::Value policy = utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); + base::Value::Dict policy = + utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); utils::AddTimeUsageLimit(&policy, utils::kMonday, kDailyLimit, last_updated); utils::AddTimeUsageLimit(&policy, utils::kTuesday, kDailyLimit, last_updated); @@ -2636,7 +2671,7 @@ usage_limit_lock_state.next_state_change_time = next_day_reset; // Local override started before usage time limit - should be ignored. - base::Value inactive_local_override = + base::Value::Dict inactive_local_override = usage_time_limit::TimeLimitOverride( usage_time_limit::TimeLimitOverride::Action::kUnlock, timestamp - base::Minutes(5), absl::nullopt /* duration */) @@ -2652,7 +2687,7 @@ AssertEqState(usage_limit_lock_state, state); // Local override that started after usage time limit - should take effect. - base::Value active_local_override = + base::Value::Dict active_local_override = usage_time_limit::TimeLimitOverride( usage_time_limit::TimeLimitOverride::Action::kUnlock, current_time, absl::nullopt /* duration */) @@ -2679,12 +2714,12 @@ ASSERT_TRUE( base::Time::FromString("Mon, 1 Jan 2018 15:00 GMT", ¤t_time)); - base::Value policy = base::Value(base::Value::Type::DICTIONARY); + base::Value::Dict policy; utils::AddOverride(&policy, TimeLimitOverride::Action::kLock, current_time - base::Hours(1)); // Local override started before latest policy update - should be ignored. - base::Value inactive_local_override = + base::Value::Dict inactive_local_override = usage_time_limit::TimeLimitOverride( usage_time_limit::TimeLimitOverride::Action::kUnlock, current_time - base::Hours(2), absl::nullopt /* duration */) @@ -2704,7 +2739,7 @@ EXPECT_EQ(next_day, state.next_unlock_time); // Local override started after last policy update - should take effect. - base::Value active_local_override = + base::Value::Dict active_local_override = usage_time_limit::TimeLimitOverride( usage_time_limit::TimeLimitOverride::Action::kUnlock, current_time - base::Minutes(5), absl::nullopt /* duration */) @@ -2728,7 +2763,7 @@ std::unique_ptr<icu::TimeZone> timezone(icu::TimeZone::createTimeZone("GMT")); // Setup policy. - base::Value policy = base::Value(base::Value::Type::DICTIONARY); + base::Value::Dict policy; base::Time time_one = utils::TimeFromString("Mon, 1 Jan 2018 22:00"); base::Time reset_time = GetExpectedResetTime( @@ -2742,7 +2777,8 @@ std::unique_ptr<icu::TimeZone> timezone(icu::TimeZone::createTimeZone("EST")); // Setup policy. - base::Value policy = utils::CreateTimeLimitPolicy(utils::CreateTime(8, 0)); + base::Value::Dict policy = + utils::CreateTimeLimitPolicy(utils::CreateTime(8, 0)); // Check that it resets in the same day. base::Time time_one = utils::TimeFromString("Tue, 2 Jan 2018 6:00 EST"); @@ -2762,7 +2798,7 @@ TEST_F(UsageTimeLimitProcessorTest, GetTimeUsageLimitResetTime) { // If there is no valid time usage limit in the policy, default value // (midnight) should be returned. - auto empty_time_limit_dictionary = base::Value(base::Value::Type::DICTIONARY); + base::Value::Dict empty_time_limit_dictionary; EXPECT_EQ(base::Hours(0), GetTimeUsageLimitResetTime(empty_time_limit_dictionary)); @@ -2774,8 +2810,8 @@ auto time_usage_limit = base::Value(base::Value::Type::DICTIONARY); time_usage_limit.SetKey( "reset_at", utils::CreatePolicyTime(utils::CreateTime(kHour, kMinutes))); - auto time_limit_dictionary = base::Value(base::Value::Type::DICTIONARY); - time_limit_dictionary.SetKey("time_usage_limit", std::move(time_usage_limit)); + base::Value::Dict time_limit_dictionary; + time_limit_dictionary.Set("time_usage_limit", std::move(time_usage_limit)); EXPECT_EQ(base::Hours(kHour) + base::Minutes(kMinutes), GetTimeUsageLimitResetTime(time_limit_dictionary)); @@ -2786,7 +2822,7 @@ std::unique_ptr<icu::TimeZone> timezone(icu::TimeZone::createTimeZone("BRT")); // Setup policy. - base::Value policy = base::Value(base::Value::Type::DICTIONARY); + base::Value::Dict policy; base::Time time_one = utils::TimeFromString("Mon, 1 Jan 2018 22:00"); absl::optional<base::TimeDelta> remaining_usage = GetRemainingTimeUsage(policy, nullptr /* local_override */, time_one, @@ -2801,7 +2837,8 @@ // Setup policy with a time usage of 2 hours. base::Time last_updated = utils::TimeFromString("1 Jan 2018 8:00 BRT"); - base::Value policy = utils::CreateTimeLimitPolicy(utils::CreateTime(8, 0)); + base::Value::Dict policy = + utils::CreateTimeLimitPolicy(utils::CreateTime(8, 0)); utils::AddTimeUsageLimit(&policy, utils::kTuesday, base::Hours(2), last_updated); utils::AddTimeUsageLimit(&policy, utils::kWednesday, base::Hours(2), @@ -2828,20 +2865,20 @@ // Tests UpdatedPolicyTypes with no polcies. TEST_F(UsageTimeLimitProcessorTest, UpdatedPolicyTypesEmptyPolicies) { - auto old_policy = base::Value(base::Value::Type::DICTIONARY); - auto new_policy = base::Value(base::Value::Type::DICTIONARY); + base::Value::Dict old_policy; + base::Value::Dict new_policy; EXPECT_TRUE(UpdatedPolicyTypes(old_policy, new_policy).empty()); } // Tests UpdatedPolicyTypes with different simple overrides. TEST_F(UsageTimeLimitProcessorTest, UpdatedPolicyTypesDifferentSimpleOverrides) { - base::Value old_policy = + base::Value::Dict old_policy = utils::CreateTimeLimitPolicy(utils::CreateTime(8, 0)); utils::AddOverride(&old_policy, TimeLimitOverride::Action::kUnlock, utils::TimeFromString("Wed, 3 Jan 2019 12:30 GMT")); - base::Value new_policy = + base::Value::Dict new_policy = utils::CreateTimeLimitPolicy(utils::CreateTime(8, 0)); // New override was created on 4 Jan instead of 3 Jan. utils::AddOverride(&new_policy, TimeLimitOverride::Action::kUnlock, @@ -2854,7 +2891,7 @@ TEST_F(UsageTimeLimitProcessorTest, UpdatedPolicyTypesEquivalentPolicies) { base::Time last_updated = utils::TimeFromString("1 Jan 2019 8:00 BRT"); - base::Value old_policy = + base::Value::Dict old_policy = utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); utils::AddTimeUsageLimit(&old_policy, utils::kWednesday, base::Hours(2), last_updated); @@ -2865,7 +2902,7 @@ &old_policy, TimeLimitOverride::Action::kUnlock, utils::TimeFromString("Mon, 1 Jan 2019 10:30 PST"), base::Hours(2)); - base::Value new_policy = old_policy.Clone(); + base::Value::Dict new_policy = old_policy.Clone(); EXPECT_TRUE(UpdatedPolicyTypes(old_policy, new_policy).empty()); } @@ -2874,7 +2911,7 @@ TEST_F(UsageTimeLimitProcessorTest, UpdatedPolicyTypesDifferentUsageLimit) { base::Time last_updated = utils::TimeFromString("1 Jan 2019 8:00 PST"); - base::Value old_policy = + base::Value::Dict old_policy = utils::CreateTimeLimitPolicy(utils::CreateTime(7, 0)); utils::AddTimeUsageLimit(&old_policy, utils::kSaturday, base::Hours(2), last_updated); @@ -2885,7 +2922,7 @@ &old_policy, TimeLimitOverride::Action::kUnlock, utils::TimeFromString("Wed, 3 Jan 2019 10:30 PST"), base::Hours(3)); - base::Value new_policy = + base::Value::Dict new_policy = utils::CreateTimeLimitPolicy(utils::CreateTime(7, 0)); // New usage limit has a 3-hour duration instead of 2. utils::AddTimeUsageLimit(&new_policy, utils::kSaturday, base::Hours(3), @@ -2907,7 +2944,7 @@ TEST_F(UsageTimeLimitProcessorTest, UpdatedPolicyTypesDifferentWindowLimit) { base::Time last_updated = utils::TimeFromString("1 Jan 2019 8:00 GMT"); - base::Value old_policy = + base::Value::Dict old_policy = utils::CreateTimeLimitPolicy(utils::CreateTime(8, 0)); utils::AddTimeUsageLimit(&old_policy, utils::kTuesday, base::Hours(3), last_updated); @@ -2918,7 +2955,7 @@ &old_policy, TimeLimitOverride::Action::kUnlock, utils::TimeFromString("Wed, 3 Jan 2019 12:30 GMT"), base::Hours(3)); - base::Value new_policy = + base::Value::Dict new_policy = utils::CreateTimeLimitPolicy(utils::CreateTime(8, 0)); utils::AddTimeUsageLimit(&new_policy, utils::kTuesday, base::Hours(3), last_updated); @@ -2941,7 +2978,7 @@ UpdatedPolicyTypesDifferentOverridesWithDuration) { base::Time last_updated = utils::TimeFromString("1 Jan 2019 8:00 GMT"); - base::Value old_policy = + base::Value::Dict old_policy = utils::CreateTimeLimitPolicy(utils::CreateTime(8, 0)); utils::AddTimeUsageLimit(&old_policy, utils::kTuesday, base::Hours(3), last_updated); @@ -2952,7 +2989,7 @@ &old_policy, TimeLimitOverride::Action::kUnlock, utils::TimeFromString("Wed, 3 Jan 2019 12:30 GMT"), base::Hours(3)); - base::Value new_policy = + base::Value::Dict new_policy = utils::CreateTimeLimitPolicy(utils::CreateTime(8, 0)); utils::AddTimeUsageLimit(&new_policy, utils::kTuesday, base::Hours(3), last_updated); @@ -2976,7 +3013,7 @@ UpdatedPolicyTypesDifferentWindowAndUsageLimits) { base::Time last_updated = utils::TimeFromString("1 Jan 2019 8:00 KST"); - base::Value old_policy = + base::Value::Dict old_policy = utils::CreateTimeLimitPolicy(utils::CreateTime(8, 0)); utils::AddTimeUsageLimit(&old_policy, utils::kMonday, base::Hours(3), last_updated); @@ -2987,7 +3024,7 @@ &old_policy, TimeLimitOverride::Action::kUnlock, utils::TimeFromString("Wed, 3 Jan 2019 12:30 GMT"), base::Hours(3)); - base::Value new_policy = + base::Value::Dict new_policy = utils::CreateTimeLimitPolicy(utils::CreateTime(8, 0)); // New usage limit is applied to Tuesdays not Mondays. utils::AddTimeUsageLimit(&new_policy, utils::kTuesday, base::Hours(3),
diff --git a/chrome/browser/ash/crostini/ansible/ansible_management_service.cc b/chrome/browser/ash/crostini/ansible/ansible_management_service.cc index be425e0..cdd20ba 100644 --- a/chrome/browser/ash/crostini/ansible/ansible_management_service.cc +++ b/chrome/browser/ash/crostini/ansible/ansible_management_service.cc
@@ -225,7 +225,12 @@ OnConfigurationFinished(container_id, false); break; case vm_tools::cicerone::ApplyAnsiblePlaybookProgressSignal::IN_PROGRESS: - // TODO(okalitova): Report Ansible playbook application progress. + for (auto& observer : observers_) { + observer.OnAnsibleSoftwareConfigurationProgress( + container_id, + std::vector<std::string>(signal.status_string().begin(), + signal.status_string().end())); + } break; default: NOTREACHED();
diff --git a/chrome/browser/ash/crostini/ansible/ansible_management_service.h b/chrome/browser/ash/crostini/ansible/ansible_management_service.h index b05400e..aa1cddd 100644 --- a/chrome/browser/ash/crostini/ansible/ansible_management_service.h +++ b/chrome/browser/ash/crostini/ansible/ansible_management_service.h
@@ -43,6 +43,9 @@ ~Observer() override = default; virtual void OnAnsibleSoftwareConfigurationStarted( const guest_os::GuestId& container_id) = 0; + virtual void OnAnsibleSoftwareConfigurationProgress( + const guest_os::GuestId& container_id, + const std::vector<std::string>& status_lines) {} virtual void OnAnsibleSoftwareConfigurationFinished( const guest_os::GuestId& container_id, bool success) = 0;
diff --git a/chrome/browser/ash/events/event_rewriter_unittest.cc b/chrome/browser/ash/events/event_rewriter_unittest.cc index 688beaf..5a69be6 100644 --- a/chrome/browser/ash/events/event_rewriter_unittest.cc +++ b/chrome/browser/ash/events/event_rewriter_unittest.cc
@@ -93,12 +93,12 @@ const TestEventRewriterContinuation&) = delete; ui::EventDispatchDetails SendEvent(const ui::Event* event) override { - passthrough_events.push_back(ui::Event::Clone(*event)); + passthrough_events.push_back(event->Clone()); return ui::EventDispatchDetails(); } ui::EventDispatchDetails SendEventFinally(const ui::Event* event) override { - rewritten_events.push_back(ui::Event::Clone(*event)); + rewritten_events.push_back(event->Clone()); return ui::EventDispatchDetails(); } @@ -3754,7 +3754,7 @@ private: // ui::EventSink overrides: ui::EventDispatchDetails OnEventFromSource(ui::Event* event) override { - events_.push_back(ui::Event::Clone(*event)); + events_.push_back(event->Clone()); return ui::EventDispatchDetails(); }
diff --git a/chrome/browser/ash/guest_os/guest_id.cc b/chrome/browser/ash/guest_os/guest_id.cc index 8a004ca..e2b70d4 100644 --- a/chrome/browser/ash/guest_os/guest_id.cc +++ b/chrome/browser/ash/guest_os/guest_id.cc
@@ -110,7 +110,7 @@ std::vector<GuestId> GetContainers(Profile* profile, VmType vm_type) { std::vector<GuestId> result; const base::Value::List& container_list = - profile->GetPrefs()->GetList(prefs::kGuestOsContainers)->GetList(); + profile->GetPrefs()->GetValueList(prefs::kGuestOsContainers); for (const auto& container : container_list) { guest_os::GuestId id(container); if (id.vm_type == vm_type) {
diff --git a/chrome/browser/ash/guest_os/guest_os_mime_types_service.cc b/chrome/browser/ash/guest_os/guest_os_mime_types_service.cc index 8400f39..2ad1348 100644 --- a/chrome/browser/ash/guest_os/guest_os_mime_types_service.cc +++ b/chrome/browser/ash/guest_os/guest_os_mime_types_service.cc
@@ -94,28 +94,28 @@ const base::FilePath& file_path, const std::string& vm_name, const std::string& container_name) const { - const base::Value* vm = - prefs_->GetDictionary(prefs::kGuestOsMimeTypes)->FindDictKey(vm_name); + const base::Value::Dict* vm = + prefs_->GetValueDict(prefs::kGuestOsMimeTypes).FindDict(vm_name); if (vm) { - const base::Value* container = vm->FindDictKey(container_name); + const base::Value::Dict* container = vm->FindDict(container_name); if (container) { // Try Extension() which may be a double like ".tar.gz". std::string extension = file_path.Extension(); // Remove leading dot. extension.erase(0, 1); - const std::string* result = container->FindStringKey(extension); + const std::string* result = container->FindString(extension); if (!result) { // Try lowercase. - result = container->FindStringKey(base::ToLowerASCII(extension)); + result = container->FindString(base::ToLowerASCII(extension)); } // If this was a double extension, then try FinalExtension(). if (!result && extension.find('.') != std::string::npos) { extension = file_path.FinalExtension(); extension.erase(0, 1); - result = container->FindStringKey(extension); + result = container->FindString(extension); if (!result) { // Try lowercase. - result = container->FindStringKey(base::ToLowerASCII(extension)); + result = container->FindString(base::ToLowerASCII(extension)); } } if (result) {
diff --git a/chrome/browser/ash/guest_os/guest_os_registry_service.cc b/chrome/browser/ash/guest_os/guest_os_registry_service.cc index 7ab6e8e..596c9cdb 100644 --- a/chrome/browser/ash/guest_os/guest_os_registry_service.cc +++ b/chrome/browser/ash/guest_os/guest_os_registry_service.cc
@@ -536,10 +536,10 @@ std::map<std::string, GuestOsRegistryService::Registration> GuestOsRegistryService::GetAllRegisteredApps() const { - const base::Value* apps = - prefs_->GetDictionary(guest_os::prefs::kGuestOsRegistry); + const base::Value::Dict& apps = + prefs_->GetValueDict(guest_os::prefs::kGuestOsRegistry); std::map<std::string, GuestOsRegistryService::Registration> result; - for (const auto item : apps->DictItems()) { + for (const auto item : apps) { result.emplace(item.first, Registration(item.first, item.second.Clone())); } return result; @@ -599,24 +599,24 @@ absl::optional<GuestOsRegistryService::Registration> GuestOsRegistryService::GetRegistration(const std::string& app_id) const { - const base::Value* apps = - prefs_->GetDictionary(guest_os::prefs::kGuestOsRegistry); + const base::Value::Dict& apps = + prefs_->GetValueDict(guest_os::prefs::kGuestOsRegistry); - const base::Value* pref_registration = - apps->FindKeyOfType(app_id, base::Value::Type::DICTIONARY); + const base::Value::Dict* pref_registration = apps.FindDict(app_id); if (!pref_registration) { return absl::nullopt; } - return absl::make_optional<Registration>(app_id, pref_registration->Clone()); + return absl::make_optional<Registration>( + app_id, base::Value(pref_registration->Clone())); } void GuestOsRegistryService::RecordStartupMetrics() { - const base::Value* apps = - prefs_->GetDictionary(guest_os::prefs::kGuestOsRegistry); + const base::Value::Dict& apps = + prefs_->GetValueDict(guest_os::prefs::kGuestOsRegistry); base::flat_map<int, int> num_apps; - for (const auto item : apps->DictItems()) { + for (const auto item : apps) { absl::optional<bool> no_display = item.second.FindBoolKey(guest_os::prefs::kAppNoDisplayKey); if (no_display && no_display.value()) {
diff --git a/chrome/browser/ash/guest_os/guest_os_terminal.cc b/chrome/browser/ash/guest_os/guest_os_terminal.cc index 2b976da..064da28 100644 --- a/chrome/browser/ash/guest_os/guest_os_terminal.cc +++ b/chrome/browser/ash/guest_os/guest_os_terminal.cc
@@ -403,9 +403,9 @@ {"theme-variations", TerminalSetting::kThemeVariations}, }); - const base::Value* settings = profile->GetPrefs()->GetDictionary( + const base::Value::Dict& settings = profile->GetPrefs()->GetValueDict( guest_os::prefs::kGuestOsTerminalSettings); - for (const auto item : settings->DictItems()) { + for (const auto item : settings) { // Only record settings for /hterm/profiles/default/. if (!base::StartsWith(item.first, kSettingPrefix, base::CompareCase::SENSITIVE)) { @@ -427,13 +427,13 @@ return GetSettingsKey(kSettingsPrefixHterm, profile, kSettingsKeyBackgroundColor); }; - const base::Value* settings = profile->GetPrefs()->GetDictionary( + const base::Value::Dict& settings = profile->GetPrefs()->GetValueDict( guest_os::prefs::kGuestOsTerminalSettings); // 1. Use 'settings_profile' url param. std::string settings_profile; if (net::GetValueForKeyInQuery(url, kSettingsProfileUrlParam, &settings_profile)) { - const std::string* result = settings->FindStringKey(key(settings_profile)); + const std::string* result = settings.FindString(key(settings_profile)); if (result) { return *result; } @@ -445,15 +445,14 @@ } // 3. Use 'default' profile color, or default color. - const std::string* result = - settings->FindStringKey(key(kSettingsProfileDefault)); + const std::string* result = settings.FindString(key(kSettingsProfileDefault)); return result ? *result : kDefaultBackgroundColor; } bool GetTerminalSettingPassCtrlW(Profile* profile) { - const base::Value* value = profile->GetPrefs()->GetDictionary( + const base::Value::Dict& value = profile->GetPrefs()->GetValueDict( guest_os::prefs::kGuestOsTerminalSettings); - return value->FindBoolKey(kSettingPassCtrlW).value_or(kDefaultPassCtrlW); + return value.FindBool(kSettingPassCtrlW).value_or(kDefaultPassCtrlW); } std::string ShortcutIdForSSH(const std::string& profileId) { @@ -471,10 +470,8 @@ dict.Set(kShortcutKey, base::Value(kShortcutValueTerminal)); // Find terminal profile from prefs. - const base::Value::Dict& settings = - profile->GetPrefs() - ->GetDictionary(guest_os::prefs::kGuestOsTerminalSettings) - ->GetDict(); + const base::Value::Dict& settings = profile->GetPrefs()->GetValueDict( + guest_os::prefs::kGuestOsTerminalSettings); const base::Value::List* vsh_ids = settings.FindList("/vsh/profile-ids"); if (vsh_ids) { for (const auto& vsh_id : *vsh_ids) { @@ -513,10 +510,8 @@ std::vector<std::pair<std::string, std::string>> GetSSHConnections( Profile* profile) { std::vector<std::pair<std::string, std::string>> result; - const base::Value::Dict& settings = - profile->GetPrefs() - ->GetDictionary(guest_os::prefs::kGuestOsTerminalSettings) - ->GetDict(); + const base::Value::Dict& settings = profile->GetPrefs()->GetValueDict( + guest_os::prefs::kGuestOsTerminalSettings); const base::Value::List* ids = settings.FindList("/nassh/profile-ids"); if (!ids) { return result; @@ -597,11 +592,10 @@ if (!profileId) { return false; } - const base::Value* settings = profile->GetPrefs()->GetDictionary( + const base::Value::Dict& settings = profile->GetPrefs()->GetValueDict( guest_os::prefs::kGuestOsTerminalSettings); - const std::string* settings_profile = - settings->FindStringKey(GetSettingsKey(kSettingsPrefixNassh, *profileId, - kSettingsKeyTerminalProfile)); + const std::string* settings_profile = settings.FindString(GetSettingsKey( + kSettingsPrefixNassh, *profileId, kSettingsKeyTerminalProfile)); auto escape = [](const std::string& v) { return base::EscapeQueryParamValue(v, /*use_plus=*/true); };
diff --git a/chrome/browser/ash/lock_screen_apps/state_controller_unittest.cc b/chrome/browser/ash/lock_screen_apps/state_controller_unittest.cc index ff4568180..c03c6e49 100644 --- a/chrome/browser/ash/lock_screen_apps/state_controller_unittest.cc +++ b/chrome/browser/ash/lock_screen_apps/state_controller_unittest.cc
@@ -344,7 +344,8 @@ extensions::AppWindow::CreateParams params; params.hidden = !shown; - window_->Init(GURL(), new extensions::AppWindowContentsImpl(window_), + window_->Init(GURL(), + std::make_unique<extensions::AppWindowContentsImpl>(window_), web_contents_->GetPrimaryMainFrame(), params); Observe(window_->web_contents()); }
diff --git a/chrome/browser/ash/policy/dlp/dlp_content_manager_ash_browsertest.cc b/chrome/browser/ash/policy/dlp/dlp_content_manager_ash_browsertest.cc index 4d88119f..fe59255 100644 --- a/chrome/browser/ash/policy/dlp/dlp_content_manager_ash_browsertest.cc +++ b/chrome/browser/ash/policy/dlp/dlp_content_manager_ash_browsertest.cc
@@ -1776,8 +1776,36 @@ ASSERT_TRUE(events_.empty()); } -IN_PROC_BROWSER_TEST_F(DlpContentManagerAshScreenShareBrowserTest, - NavigateWebContents) { +struct ScreenshareNavigateTestParams { + ScreenshareNavigateTestParams(std::string test_name, + DlpRulesManager::Level level, + std::string histogram_suffix) + : test_name(std::move(test_name)), + level(level), + restriction_set(DlpContentRestriction::kScreenShare, level), + histogram_suffix(histogram_suffix) {} + + ~ScreenshareNavigateTestParams() = default; + + std::string test_name; + DlpRulesManager::Level level; + DlpContentRestrictionSet restriction_set; + std::string histogram_suffix; +}; + +class ScreenShareNavigateWebContentsTest + : public DlpContentManagerAshScreenShareBrowserTest, + public testing::WithParamInterface<ScreenshareNavigateTestParams> { + public: + ScreenShareNavigateWebContentsTest() = default; + ~ScreenShareNavigateWebContentsTest() override = default; +}; + +// Tests that navigating between unrestricted, restricted, and only reported +// content during a tab share emits the correct number of reporting events. +IN_PROC_BROWSER_TEST_P(ScreenShareNavigateWebContentsTest, Reporting) { + const ScreenshareNavigateTestParams& param = GetParam(); + SetupReporting(); const GURL restricted_url(kGoogleUrl); const GURL reported_url(kExampleUrl); @@ -1831,33 +1859,41 @@ GetDlpHistogramPrefix() + dlp::kScreenShareBlockedUMA, false), 0); - // Navigate to restricted content. Should emit a block event. - helper_->UpdateConfidentiality(web_contents, kScreenShareRestricted); + // Navigate to restricted content. Should emit a corresponding event. + helper_->UpdateConfidentiality(web_contents, param.restriction_set); ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), restricted_url)); helper_->CheckRunningScreenShares(); ASSERT_EQ(events_.size(), 2u); EXPECT_THAT(events_[1], IsDlpPolicyEvent(CreateDlpPolicyEvent( kSrcPattern, DlpRulesManager::Restriction::kScreenShare, - DlpRulesManager::Level::kBlock))); - EXPECT_TRUE( - display_service_tester.GetNotification(kScreenSharePausedNotificationId)); + param.level))); + if (param.level == DlpRulesManager::Level::kWarn) { + // Proceed, as otherwise the screen share would be stopped. + DismissDialog(/*allow=*/true); + } else { + // Paused notification is only shown in block mode. + EXPECT_TRUE(display_service_tester.GetNotification( + kScreenSharePausedNotificationId)); + } histogram_tester_.ExpectBucketCount( - GetDlpHistogramPrefix() + dlp::kScreenShareBlockedUMA, true, 1); + GetDlpHistogramPrefix() + param.histogram_suffix, true, 1); - // Navigate to the previous reported content. Should not emit any report + // Remember current number of reporting events: further navigation should not + // emit any new events. + auto prev_events_size = events_.size(); + // Navigate to the previous reported content. Should not emit any reporting // event. helper_->UpdateConfidentiality(web_contents, kScreenShareReported); ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), reported_url)); helper_->CheckRunningScreenShares(); - EXPECT_EQ(events_.size(), 2u); + EXPECT_EQ(events_.size(), prev_events_size); - // Expect resume notification. Screen share should be paused, not blocked, - // when navigating to restricted content. + // Expect resume notification. EXPECT_TRUE(display_service_tester.GetNotification( kScreenShareResumedNotificationId)); histogram_tester_.ExpectBucketCount( - GetDlpHistogramPrefix() + dlp::kScreenShareBlockedUMA, true, 1); + GetDlpHistogramPrefix() + param.histogram_suffix, true, 1); } INSTANTIATE_TEST_SUITE_P( @@ -1996,4 +2032,20 @@ return info.param.test_name; }); +INSTANTIATE_TEST_SUITE_P( + DlpContentManagerAsh, + ScreenShareNavigateWebContentsTest, + testing::ValuesIn<ScreenshareNavigateTestParams>( + {ScreenshareNavigateTestParams( + /*test_name=*/"Restricted", + /*level=*/DlpRulesManager::Level::kBlock, + /*histogram_suffix=*/dlp::kScreenShareBlockedUMA), + ScreenshareNavigateTestParams( + /*test_name=*/"Warned", + /*level=*/DlpRulesManager::Level::kWarn, + /*histogram_suffix=*/dlp::kScreenShareWarnedUMA)}), + [](const testing::TestParamInfo<ScreenshareNavigateTestParams>& info) { + return info.param.test_name; + }); + } // namespace policy
diff --git a/chrome/browser/ash/policy/enrollment/auto_enrollment_client_impl.cc b/chrome/browser/ash/policy/enrollment/auto_enrollment_client_impl.cc index 8da7e81..b6623a68 100644 --- a/chrome/browser/ash/policy/enrollment/auto_enrollment_client_impl.cc +++ b/chrome/browser/ash/policy/enrollment/auto_enrollment_client_impl.cc
@@ -787,11 +787,11 @@ AutoEnrollmentClientImpl::AutoEnrollmentClientImpl( ProgressCallback callback, std::unique_ptr<ServerStateAvailabilityRequester> - server_state_avalability_requester, + server_state_availability_requester, std::unique_ptr<ServerStateRetriever> server_state_retriever) : progress_callback_(std::move(callback)), - server_state_avalability_requester_( - std::move(server_state_avalability_requester)), + server_state_availability_requester_( + std::move(server_state_availability_requester)), server_state_retriever_(std::move(server_state_retriever)) { DCHECK(progress_callback_); } @@ -852,14 +852,14 @@ state_ == State::kRequestServerStateAvailabilityServerError); state_ = State::kRequestingServerStateAvailability; - if (server_state_avalability_requester_->GetServerStateIfObtained()) { + if (server_state_availability_requester_->GetServerStateIfObtained()) { OnServerStateAvailabilityCompleted(ServerStateAvailabilityResult::kSuccess); return; } ReportProgress(AUTO_ENROLLMENT_STATE_PENDING); - server_state_avalability_requester_->Start(base::BindOnce( + server_state_availability_requester_->Start(base::BindOnce( &AutoEnrollmentClientImpl::OnServerStateAvailabilityCompleted, base::Unretained(this))); } @@ -870,8 +870,8 @@ switch (result) { case ServerStateAvailabilityResult::kSuccess: - DCHECK(server_state_avalability_requester_->GetServerStateIfObtained()); - if (server_state_avalability_requester_->GetServerStateIfObtained() + DCHECK(server_state_availability_requester_->GetServerStateIfObtained()); + if (server_state_availability_requester_->GetServerStateIfObtained() .value()) { state_ = State::kRequestServerStateAvailabilitySuccess; RequestStateRetrieval(); @@ -893,7 +893,7 @@ Retry(); break; case ServerStateAvailabilityResult::kPsmInternalError: - DCHECK(!server_state_avalability_requester_->GetServerStateIfObtained()); + DCHECK(!server_state_availability_requester_->GetServerStateIfObtained()); state_ = State::kFinished; ReportFinished(); break; @@ -904,9 +904,9 @@ DCHECK(state_ == State::kRequestServerStateAvailabilitySuccess || state_ == State::kRequestStateRetrievalConnectionError || state_ == State::kRequestStateRetrievalServerError); - DCHECK(server_state_avalability_requester_->GetServerStateIfObtained()); + DCHECK(server_state_availability_requester_->GetServerStateIfObtained()); DCHECK( - server_state_avalability_requester_->GetServerStateIfObtained().value()); + server_state_availability_requester_->GetServerStateIfObtained().value()); DCHECK(!server_state_retriever_->GetAutoEnrollmentStateIfObtained()); state_ = State::kRequestingStateRetrieval;
diff --git a/chrome/browser/ash/policy/enrollment/auto_enrollment_client_impl.h b/chrome/browser/ash/policy/enrollment/auto_enrollment_client_impl.h index 820844f..7cc8799 100644 --- a/chrome/browser/ash/policy/enrollment/auto_enrollment_client_impl.h +++ b/chrome/browser/ash/policy/enrollment/auto_enrollment_client_impl.h
@@ -196,7 +196,7 @@ // Sends server state availability request and parses response. Reports // results. std::unique_ptr<ServerStateAvailabilityRequester> - server_state_avalability_requester_; + server_state_availability_requester_; // Sends server state retrieval request and parses response. Reports results. std::unique_ptr<ServerStateRetriever> server_state_retriever_;
diff --git a/chrome/browser/ash/system_extensions/BUILD.gn b/chrome/browser/ash/system_extensions/BUILD.gn index 8c9235fe..0228f47c 100644 --- a/chrome/browser/ash/system_extensions/BUILD.gn +++ b/chrome/browser/ash/system_extensions/BUILD.gn
@@ -17,12 +17,17 @@ "system_extensions_install_status.h", "system_extensions_internals_page_handler.cc", "system_extensions_internals_page_handler.h", + "system_extensions_mutable_registry.cc", + "system_extensions_mutable_registry.h", "system_extensions_profile_utils.cc", "system_extensions_profile_utils.h", "system_extensions_provider.cc", "system_extensions_provider.h", "system_extensions_provider_factory.cc", "system_extensions_provider_factory.h", + "system_extensions_registry.h", + "system_extensions_registry_manager.cc", + "system_extensions_registry_manager.h", "system_extensions_sandboxed_unpacker.cc", "system_extensions_sandboxed_unpacker.h", "system_extensions_status_or.h",
diff --git a/chrome/browser/ash/system_extensions/api/window_management/cros_window_management_context.cc b/chrome/browser/ash/system_extensions/api/window_management/cros_window_management_context.cc index d322d94..7df90df 100644 --- a/chrome/browser/ash/system_extensions/api/window_management/cros_window_management_context.cc +++ b/chrome/browser/ash/system_extensions/api/window_management/cros_window_management_context.cc
@@ -38,8 +38,8 @@ CrosWindowManagementContext::CrosWindowManagementContext(Profile* profile) : profile_(*profile), - install_manager_( - SystemExtensionsProvider::Get(profile).install_manager()) {} + system_extensions_registry_( + SystemExtensionsProvider::Get(profile).registry()) {} CrosWindowManagementContext::~CrosWindowManagementContext() = default; @@ -58,8 +58,7 @@ cros_window_management_instances_.Add(std::move(cros_window_management), std::move(pending_receiver)); - auto* system_extension = - install_manager_->GetSystemExtensionByURL(info.scope); + auto* system_extension = system_extensions_registry_->GetByUrl(info.scope); if (!system_extension) return;
diff --git a/chrome/browser/ash/system_extensions/api/window_management/cros_window_management_context.h b/chrome/browser/ash/system_extensions/api/window_management/cros_window_management_context.h index 424ca5ec..12ff4879 100644 --- a/chrome/browser/ash/system_extensions/api/window_management/cros_window_management_context.h +++ b/chrome/browser/ash/system_extensions/api/window_management/cros_window_management_context.h
@@ -65,8 +65,8 @@ // Safe because this KeyedService is marked as depending on the // SystemExtensionsProvider keyed service which owns - // SystemExtensionsInstallManager. - const raw_ref<SystemExtensionsInstallManager> install_manager_; + // SystemExtensionsRegistry. + const raw_ref<SystemExtensionsRegistry> system_extensions_registry_; mojo::ReceiverSet<blink::mojom::CrosWindowManagementFactory, content::ServiceWorkerVersionBaseInfo>
diff --git a/chrome/browser/ash/system_extensions/system_extensions_browsertest.cc b/chrome/browser/ash/system_extensions/system_extensions_browsertest.cc index 80fab9e..6cfcf25 100644 --- a/chrome/browser/ash/system_extensions/system_extensions_browsertest.cc +++ b/chrome/browser/ash/system_extensions/system_extensions_browsertest.cc
@@ -100,12 +100,12 @@ void TestInstalledTestExtensionWorks() { auto& provider = SystemExtensionsProvider::Get(browser()->profile()); - auto& install_manager = provider.install_manager(); + auto& registry = provider.registry(); - auto extension_ids = install_manager.GetSystemExtensionIds(); + auto extension_ids = registry.GetIds(); EXPECT_EQ(std::vector<SystemExtensionId>({kTestSystemExtensionId}), extension_ids); - EXPECT_TRUE(install_manager.GetSystemExtensionById(kTestSystemExtensionId)); + EXPECT_TRUE(registry.GetById(kTestSystemExtensionId)); auto* tab = browser()->tab_strip_model()->GetActiveWebContents(); {
diff --git a/chrome/browser/ash/system_extensions/system_extensions_install_manager.cc b/chrome/browser/ash/system_extensions/system_extensions_install_manager.cc index 7335755..87ab146 100644 --- a/chrome/browser/ash/system_extensions/system_extensions_install_manager.cc +++ b/chrome/browser/ash/system_extensions/system_extensions_install_manager.cc
@@ -18,6 +18,7 @@ #include "base/values.h" #include "chrome/browser/ash/system_extensions/system_extension.h" #include "chrome/browser/ash/system_extensions/system_extensions_profile_utils.h" +#include "chrome/browser/ash/system_extensions/system_extensions_registry_manager.h" #include "chrome/browser/ash/system_extensions/system_extensions_webui_config.h" #include "chrome/browser/profiles/profile.h" #include "chrome/common/chrome_paths.h" @@ -34,30 +35,18 @@ namespace ash { -SystemExtensionsInstallManager::SystemExtensionsInstallManager(Profile* profile) - : profile_(profile) { +SystemExtensionsInstallManager::SystemExtensionsInstallManager( + Profile* profile, + SystemExtensionsRegistryManager& registry_manager, + SystemExtensionsRegistry& registry) + : profile_(profile), + registry_manager_(registry_manager), + registry_(registry) { InstallFromCommandLineIfNecessary(); } SystemExtensionsInstallManager::~SystemExtensionsInstallManager() = default; -std::vector<SystemExtensionId> -SystemExtensionsInstallManager::GetSystemExtensionIds() { - std::vector<SystemExtensionId> extension_ids; - for (const auto& id_and_extension : system_extensions_) { - extension_ids.emplace_back(id_and_extension.first); - } - return extension_ids; -} - -const SystemExtension* SystemExtensionsInstallManager::GetSystemExtensionById( - const SystemExtensionId& id) { - const auto it = system_extensions_.find(id); - if (it == system_extensions_.end()) - return nullptr; - return &it->second; -} - void SystemExtensionsInstallManager::InstallUnpackedExtensionFromDir( const base::FilePath& unpacked_system_extension_dir, OnceInstallCallback final_callback) { @@ -138,7 +127,7 @@ content::WebUIConfigMap::GetInstance().AddUntrustedWebUIConfig( std::move(config)); - system_extensions_[{1, 2, 3, 4}] = std::move(system_extension); + registry_manager_->AddSystemExtension(std::move(system_extension)); std::move(final_callback).Run(std::move(id)); base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, @@ -148,16 +137,14 @@ void SystemExtensionsInstallManager::RegisterServiceWorker( const SystemExtensionId& system_extension_id) { - auto it = system_extensions_.find(system_extension_id); - if (it == system_extensions_.end()) { + auto* system_extension = registry_->GetById(system_extension_id); + if (!system_extension) { LOG(ERROR) << "Tried to install service worker for non-existent extension"; return; } - const SystemExtension& system_extension = it->second; - blink::mojom::ServiceWorkerRegistrationOptions options( - system_extension.base_url, blink::mojom::ScriptType::kClassic, + system_extension->base_url, blink::mojom::ScriptType::kClassic, blink::mojom::ServiceWorkerUpdateViaCache::kImports); blink::StorageKey key(url::Origin::Create(options.scope)); @@ -166,7 +153,7 @@ auto* worker_context = profile_->GetDefaultStoragePartition()->GetServiceWorkerContext(); worker_context->RegisterServiceWorker( - system_extension.service_worker_url, key, options, + system_extension->service_worker_url, key, options, base::BindOnce(&SystemExtensionsInstallManager::OnRegisterServiceWorker, weak_ptr_factory_.GetWeakPtr(), system_extension_id)); } @@ -218,13 +205,4 @@ return true; } -const SystemExtension* SystemExtensionsInstallManager::GetSystemExtensionByURL( - const GURL& url) { - for (const auto& id_and_system_extension : system_extensions_) { - if (url::IsSameOriginWith(id_and_system_extension.second.base_url, url)) - return &id_and_system_extension.second; - } - return nullptr; -} - } // namespace ash
diff --git a/chrome/browser/ash/system_extensions/system_extensions_install_manager.h b/chrome/browser/ash/system_extensions/system_extensions_install_manager.h index ec76073..7678282c 100644 --- a/chrome/browser/ash/system_extensions/system_extensions_install_manager.h +++ b/chrome/browser/ash/system_extensions/system_extensions_install_manager.h
@@ -8,6 +8,7 @@ #include <map> #include "base/files/file_path.h" +#include "base/memory/raw_ref.h" #include "base/memory/weak_ptr.h" #include "base/observer_list.h" #include "base/one_shot_event.h" @@ -21,6 +22,9 @@ namespace ash { +class SystemExtensionsRegistry; +class SystemExtensionsRegistryManager; + class SystemExtensionsInstallManager { public: class Observer : public base::CheckedObserver { @@ -30,7 +34,10 @@ blink::ServiceWorkerStatusCode status_code) {} }; - explicit SystemExtensionsInstallManager(Profile* profile); + SystemExtensionsInstallManager( + Profile* profile, + SystemExtensionsRegistryManager& registry_manager, + SystemExtensionsRegistry& registry); SystemExtensionsInstallManager(const SystemExtensionsInstallManager&) = delete; SystemExtensionsInstallManager& operator=( @@ -53,14 +60,6 @@ observers_.RemoveObserver(observer); } - // TODO(ortuno): Move these to a Registrar or Database. - std::vector<SystemExtensionId> GetSystemExtensionIds(); - const SystemExtension* GetSystemExtensionById(const SystemExtensionId& id); - - // Return the system extension that runs on |url|. Returns nullptr if |url| - // doesn't belong to any system extension. - const SystemExtension* GetSystemExtensionByURL(const GURL& url); - private: // Helper class to run blocking IO operations on a separate thread. class IOHelper { @@ -91,15 +90,22 @@ int process_id, int thread_id); - Profile* profile_; + // Safe because this class is owned by SystemExtensionsProvider which is owned + // by the profile. + raw_ptr<Profile> profile_; + + // Safe to hold references because the parent class, + // SystemExtensionsProvider, ensures this class is constructed after and + // destroyed before the classes below. + const raw_ref<SystemExtensionsRegistryManager> registry_manager_; + const raw_ref<SystemExtensionsRegistry> registry_; + + std::map<SystemExtensionId, SystemExtension> system_extensions_; base::OneShotEvent on_command_line_install_finished_; SystemExtensionsSandboxedUnpacker sandboxed_unpacker_; - // TODO(ortuno): Move this to a Registrar or Database. - std::map<SystemExtensionId, SystemExtension> system_extensions_; - base::ObserverList<Observer> observers_; base::SequenceBound<IOHelper> io_helper_{
diff --git a/chrome/browser/ash/system_extensions/system_extensions_mutable_registry.cc b/chrome/browser/ash/system_extensions/system_extensions_mutable_registry.cc new file mode 100644 index 0000000..4f284e6 --- /dev/null +++ b/chrome/browser/ash/system_extensions/system_extensions_mutable_registry.cc
@@ -0,0 +1,51 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ash/system_extensions/system_extensions_mutable_registry.h" + +#include "chrome/browser/ash/system_extensions/system_extension.h" +#include "url/gurl.h" +#include "url/origin.h" + +namespace ash { + +SystemExtensionsMutableRegistry::SystemExtensionsMutableRegistry() = default; + +SystemExtensionsMutableRegistry::~SystemExtensionsMutableRegistry() = default; + +void SystemExtensionsMutableRegistry::AddSystemExtension( + SystemExtension system_extension) { + SystemExtensionId id = system_extension.id; + system_extensions_[id] = std::move(system_extension); +} + +std::vector<SystemExtensionId> SystemExtensionsMutableRegistry::GetIds() { + std::vector<SystemExtensionId> extension_ids; + for (const auto& [id, system_extension] : system_extensions_) { + extension_ids.push_back(id); + } + return extension_ids; +} + +const SystemExtension* SystemExtensionsMutableRegistry::GetById( + const SystemExtensionId& system_extension_id) { + auto it = system_extensions_.find(system_extension_id); + if (it == system_extensions_.end()) { + return nullptr; + } + return &it->second; +} + +const SystemExtension* SystemExtensionsMutableRegistry::GetByUrl( + const GURL& url) { + for (auto& [id, system_extension] : system_extensions_) { + if (url::IsSameOriginWith(system_extension.base_url, url)) { + return &system_extension; + } + } + + return nullptr; +} + +} // namespace ash
diff --git a/chrome/browser/ash/system_extensions/system_extensions_mutable_registry.h b/chrome/browser/ash/system_extensions/system_extensions_mutable_registry.h new file mode 100644 index 0000000..87c00dc --- /dev/null +++ b/chrome/browser/ash/system_extensions/system_extensions_mutable_registry.h
@@ -0,0 +1,44 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_ASH_SYSTEM_EXTENSIONS_SYSTEM_EXTENSIONS_MUTABLE_REGISTRY_H_ +#define CHROME_BROWSER_ASH_SYSTEM_EXTENSIONS_SYSTEM_EXTENSIONS_MUTABLE_REGISTRY_H_ + +#include <map> + +#include "chrome/browser/ash/system_extensions/system_extension.h" +#include "chrome/browser/ash/system_extensions/system_extensions_registry.h" + +namespace ash { + +struct SystemExtension; + +// SystemExtensionsMutableRegistry implements SystemExtensionsRegistry but +// exposes methods to modify the registry. It's owned by and should only be +// used by SystemExtensionsRegistryManager. +class SystemExtensionsMutableRegistry : public SystemExtensionsRegistry { + public: + SystemExtensionsMutableRegistry(); + SystemExtensionsMutableRegistry(const SystemExtensionsMutableRegistry&) = + delete; + SystemExtensionsMutableRegistry& operator=( + const SystemExtensionsMutableRegistry&) = delete; + ~SystemExtensionsMutableRegistry(); + + // Adds |system_extension| to the map of installed System Extensions. + void AddSystemExtension(SystemExtension system_extension); + + // SystemExtensionsRegistry + std::vector<SystemExtensionId> GetIds() override; + const SystemExtension* GetById( + const SystemExtensionId& system_extension_id) override; + const SystemExtension* GetByUrl(const GURL& url) override; + + private: + std::map<SystemExtensionId, SystemExtension> system_extensions_; +}; + +} // namespace ash + +#endif // CHROME_BROWSER_ASH_SYSTEM_EXTENSIONS_SYSTEM_EXTENSIONS_MUTABLE_REGISTRY_H_
diff --git a/chrome/browser/ash/system_extensions/system_extensions_provider.cc b/chrome/browser/ash/system_extensions/system_extensions_provider.cc index e5c0730..9bbbf107 100644 --- a/chrome/browser/ash/system_extensions/system_extensions_provider.cc +++ b/chrome/browser/ash/system_extensions/system_extensions_provider.cc
@@ -12,6 +12,7 @@ #include "chrome/browser/ash/system_extensions/system_extensions_install_manager.h" #include "chrome/browser/ash/system_extensions/system_extensions_profile_utils.h" #include "chrome/browser/ash/system_extensions/system_extensions_provider_factory.h" +#include "chrome/browser/ash/system_extensions/system_extensions_registry_manager.h" #include "content/public/browser/render_process_host.h" #include "content/public/common/url_constants.h" @@ -34,9 +35,13 @@ } SystemExtensionsProvider::SystemExtensionsProvider(Profile* profile) { - install_manager_ = std::make_unique<SystemExtensionsInstallManager>(profile); + registry_manager_ = std::make_unique<SystemExtensionsRegistryManager>(); + install_manager_ = std::make_unique<SystemExtensionsInstallManager>( + profile, *registry_manager_, registry_manager_->registry()); } +SystemExtensionsProvider::~SystemExtensionsProvider() = default; + void SystemExtensionsProvider:: UpdateEnabledBlinkRuntimeFeaturesInIsolatedWorker( const GURL& script_url, @@ -44,8 +49,7 @@ if (!script_url.SchemeIs(kSystemExtensionScheme)) return; - auto* system_extension = - install_manager_->GetSystemExtensionByURL(script_url); + auto* system_extension = registry().GetByUrl(script_url); if (!system_extension) return; @@ -58,6 +62,4 @@ } } -SystemExtensionsProvider::~SystemExtensionsProvider() = default; - } // namespace ash
diff --git a/chrome/browser/ash/system_extensions/system_extensions_provider.h b/chrome/browser/ash/system_extensions/system_extensions_provider.h index e2c5cc9..7dfbf49 100644 --- a/chrome/browser/ash/system_extensions/system_extensions_provider.h +++ b/chrome/browser/ash/system_extensions/system_extensions_provider.h
@@ -8,10 +8,10 @@ #include <memory> #include "chrome/browser/ash/system_extensions/system_extensions_install_manager.h" +#include "chrome/browser/ash/system_extensions/system_extensions_registry_manager.h" #include "components/keyed_service/core/keyed_service.h" class Profile; -class SystemExtensionsInstallManager; namespace ash { @@ -37,6 +37,12 @@ SystemExtensionsProvider& operator=(const SystemExtensionsProvider&) = delete; ~SystemExtensionsProvider() override; + SystemExtensionsRegistry& registry() { return registry_manager_->registry(); } + + SystemExtensionsRegistryManager& registry_manager() { + return *registry_manager_; + } + SystemExtensionsInstallManager& install_manager() { return *install_manager_; } @@ -50,6 +56,7 @@ std::vector<std::string>& out_forced_enabled_runtime_features); private: + std::unique_ptr<SystemExtensionsRegistryManager> registry_manager_; std::unique_ptr<SystemExtensionsInstallManager> install_manager_; };
diff --git a/chrome/browser/ash/system_extensions/system_extensions_registry.h b/chrome/browser/ash/system_extensions/system_extensions_registry.h new file mode 100644 index 0000000..648b4c0 --- /dev/null +++ b/chrome/browser/ash/system_extensions/system_extensions_registry.h
@@ -0,0 +1,33 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_ASH_SYSTEM_EXTENSIONS_SYSTEM_EXTENSIONS_REGISTRY_H_ +#define CHROME_BROWSER_ASH_SYSTEM_EXTENSIONS_SYSTEM_EXTENSIONS_REGISTRY_H_ + +#include <map> + +#include "chrome/browser/ash/system_extensions/system_extension.h" + +namespace ash { + +struct SystemExtension; + +// SystemExtensionsRegistry holds the set of the installed system extensions. +// Exposes methods clients can use to get SystemExtensions. +class SystemExtensionsRegistry { + public: + // Returns the ids of all installed System Extensions. + virtual std::vector<SystemExtensionId> GetIds() = 0; + + // Returns the SystemExtension with `system_extension_id`. + virtual const SystemExtension* GetById( + const SystemExtensionId& system_extension_id) = 0; + + // Returns the SystemExtension that has the same origin as `url`. + virtual const SystemExtension* GetByUrl(const GURL& url) = 0; +}; + +} // namespace ash + +#endif // CHROME_BROWSER_ASH_SYSTEM_EXTENSIONS_SYSTEM_EXTENSIONS_REGISTRY_H_
diff --git a/chrome/browser/ash/system_extensions/system_extensions_registry_manager.cc b/chrome/browser/ash/system_extensions/system_extensions_registry_manager.cc new file mode 100644 index 0000000..26d7e434b --- /dev/null +++ b/chrome/browser/ash/system_extensions/system_extensions_registry_manager.cc
@@ -0,0 +1,20 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ash/system_extensions/system_extensions_registry_manager.h" + +#include "chrome/browser/ash/system_extensions/system_extension.h" + +namespace ash { + +SystemExtensionsRegistryManager::SystemExtensionsRegistryManager() = default; + +SystemExtensionsRegistryManager::~SystemExtensionsRegistryManager() = default; + +void SystemExtensionsRegistryManager::AddSystemExtension( + SystemExtension system_extension) { + registry_.AddSystemExtension(std::move(system_extension)); +} + +} // namespace ash
diff --git a/chrome/browser/ash/system_extensions/system_extensions_registry_manager.h b/chrome/browser/ash/system_extensions/system_extensions_registry_manager.h new file mode 100644 index 0000000..4dbadf2 --- /dev/null +++ b/chrome/browser/ash/system_extensions/system_extensions_registry_manager.h
@@ -0,0 +1,40 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_ASH_SYSTEM_EXTENSIONS_SYSTEM_EXTENSIONS_REGISTRY_MANAGER_H_ +#define CHROME_BROWSER_ASH_SYSTEM_EXTENSIONS_SYSTEM_EXTENSIONS_REGISTRY_MANAGER_H_ + +#include "chrome/browser/ash/system_extensions/system_extensions_mutable_registry.h" + +namespace ash { + +struct SystemExtension; + +// SystemExtensionsRegistryManager drives the stages of registering and +// unregistering system extensions in memory. It uses +// SystemExtensionsMutableRegistry to store the SystemExtension instances. Other +// classes may query the registry directly, but only +// SystemExtensionsRegistryManager is able to make changes to it. +class SystemExtensionsRegistryManager { + public: + SystemExtensionsRegistryManager(); + SystemExtensionsRegistryManager(const SystemExtensionsRegistryManager&) = + delete; + SystemExtensionsRegistryManager& operator=( + const SystemExtensionsRegistryManager&) = delete; + ~SystemExtensionsRegistryManager(); + + // Adds the `system_extension` to the SystemExtensionRegistry. + void AddSystemExtension(SystemExtension system_extension); + + // Returns the registry this class uses to store SystemExtension instances. + SystemExtensionsRegistry& registry() { return registry_; } + + private: + SystemExtensionsMutableRegistry registry_; +}; + +} // namespace ash + +#endif // CHROME_BROWSER_ASH_SYSTEM_EXTENSIONS_SYSTEM_EXTENSIONS_REGISTRY_MANAGER_H_
diff --git a/chrome/browser/ash/telemetry_extension/BUILD.gn b/chrome/browser/ash/telemetry_extension/BUILD.gn index ba60e68..636c4607 100644 --- a/chrome/browser/ash/telemetry_extension/BUILD.gn +++ b/chrome/browser/ash/telemetry_extension/BUILD.gn
@@ -8,8 +8,8 @@ source_set("telemetry_extension") { sources = [ - "probe_service.cc", - "probe_service.h", + "probe_service_ash.cc", + "probe_service_ash.h", "probe_service_converters.cc", "probe_service_converters.h", ] @@ -29,6 +29,8 @@ sources = [ "fake_probe_service.cc", "fake_probe_service.h", + "fake_probe_service_factory.cc", + "fake_probe_service_factory.h", ] deps = [ @@ -42,8 +44,8 @@ source_set("unit_tests") { testonly = true sources = [ + "probe_service_ash_unittest.cc", "probe_service_converters_unittest.cc", - "probe_service_unittest.cc", ] deps = [ ":telemetry_extension",
diff --git a/chrome/browser/ash/telemetry_extension/fake_probe_service.cc b/chrome/browser/ash/telemetry_extension/fake_probe_service.cc index d511243..db26893 100644 --- a/chrome/browser/ash/telemetry_extension/fake_probe_service.cc +++ b/chrome/browser/ash/telemetry_extension/fake_probe_service.cc
@@ -17,27 +17,17 @@ namespace ash { -void FakeProbeService::Factory::SetCreateInstanceResponse( - std::unique_ptr<FakeProbeService> fake_service) { - fake_service_ = std::move(fake_service); -} - -std::unique_ptr<crosapi::mojom::ProbeService> -FakeProbeService::Factory::CreateInstance( - mojo::PendingReceiver<crosapi::mojom::ProbeService> receiver) { - fake_service_->BindPendingReceiver(std::move(receiver)); - return std::move(fake_service_); -} - -FakeProbeService::Factory::Factory() = default; -FakeProbeService::Factory::~Factory() = default; - FakeProbeService::FakeProbeService() : receiver_(this) {} FakeProbeService::~FakeProbeService() { // Assert on the expectations. EXPECT_EQ(actual_requested_categories_, expected_requested_categories_); } +void FakeProbeService::BindPendingReceiver( + mojo::PendingReceiver<crosapi::mojom::ProbeService> receiver) { + receiver_.Bind(std::move(receiver)); +} + void FakeProbeService::ProbeTelemetryInfo( const std::vector<crosapi::mojom::ProbeCategoryEnum>& categories, ProbeTelemetryInfoCallback callback) { @@ -70,9 +60,4 @@ oem_data_ = std::move(oem_data); } -void FakeProbeService::BindPendingReceiver( - mojo::PendingReceiver<crosapi::mojom::ProbeService> receiver) { - receiver_.Bind(std::move(receiver)); -} - } // namespace ash
diff --git a/chrome/browser/ash/telemetry_extension/fake_probe_service.h b/chrome/browser/ash/telemetry_extension/fake_probe_service.h index 67a2c83..745682d 100644 --- a/chrome/browser/ash/telemetry_extension/fake_probe_service.h +++ b/chrome/browser/ash/telemetry_extension/fake_probe_service.h
@@ -8,7 +8,6 @@ #include <memory> #include <vector> -#include "chrome/browser/ash/telemetry_extension/probe_service.h" #include "chromeos/crosapi/mojom/probe_service.mojom.h" #include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/cpp/bindings/receiver.h" @@ -17,37 +16,14 @@ class FakeProbeService : public crosapi::mojom::ProbeService { public: - class Factory : public ash::ProbeService::Factory { - public: - Factory(); - ~Factory() override; - - void SetCreateInstanceResponse( - std::unique_ptr<FakeProbeService> fake_service); - - protected: - // ProbeService::Factory: - std::unique_ptr<crosapi::mojom::ProbeService> CreateInstance( - mojo::PendingReceiver<crosapi::mojom::ProbeService> receiver) override; - - private: - crosapi::mojom::ProbeTelemetryInfoPtr telem_info_{ - crosapi::mojom::ProbeTelemetryInfo::New()}; - - crosapi::mojom::ProbeOemDataPtr oem_data_{ - crosapi::mojom::ProbeOemData::New()}; - - std::vector<crosapi::mojom::ProbeCategoryEnum> requested_categories_; - - private: - std::unique_ptr<FakeProbeService> fake_service_; - }; - FakeProbeService(); FakeProbeService(const FakeProbeService&) = delete; FakeProbeService& operator=(const FakeProbeService&) = delete; ~FakeProbeService() override; + void BindPendingReceiver( + mojo::PendingReceiver<crosapi::mojom::ProbeService> receiver); + // crosapi::mojom::ProbeService overrides. void ProbeTelemetryInfo( const std::vector<crosapi::mojom::ProbeCategoryEnum>& categories, @@ -68,9 +44,6 @@ expected_requested_categories); private: - void BindPendingReceiver( - mojo::PendingReceiver<crosapi::mojom::ProbeService> receiver); - mojo::Receiver<crosapi::mojom::ProbeService> receiver_; // Response for a call to |ProbeTelemetryInfo|.
diff --git a/chrome/browser/ash/telemetry_extension/fake_probe_service_factory.cc b/chrome/browser/ash/telemetry_extension/fake_probe_service_factory.cc new file mode 100644 index 0000000..d308f00 --- /dev/null +++ b/chrome/browser/ash/telemetry_extension/fake_probe_service_factory.cc
@@ -0,0 +1,30 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ash/telemetry_extension/fake_probe_service_factory.h" + +#include <memory> +#include <utility> + +#include "chromeos/crosapi/mojom/probe_service.mojom.h" +#include "mojo/public/cpp/bindings/pending_receiver.h" + +namespace ash { + +FakeProbeServiceFactory::FakeProbeServiceFactory() = default; +FakeProbeServiceFactory::~FakeProbeServiceFactory() = default; + +void FakeProbeServiceFactory::SetCreateInstanceResponse( + std::unique_ptr<FakeProbeService> fake_service) { + fake_service_ = std::move(fake_service); +} + +std::unique_ptr<crosapi::mojom::ProbeService> +FakeProbeServiceFactory::CreateInstance( + mojo::PendingReceiver<crosapi::mojom::ProbeService> receiver) { + fake_service_->BindPendingReceiver(std::move(receiver)); + return std::move(fake_service_); +} + +} // namespace ash
diff --git a/chrome/browser/ash/telemetry_extension/fake_probe_service_factory.h b/chrome/browser/ash/telemetry_extension/fake_probe_service_factory.h new file mode 100644 index 0000000..8f0ad28 --- /dev/null +++ b/chrome/browser/ash/telemetry_extension/fake_probe_service_factory.h
@@ -0,0 +1,36 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_ASH_TELEMETRY_EXTENSION_FAKE_PROBE_SERVICE_FACTORY_H_ +#define CHROME_BROWSER_ASH_TELEMETRY_EXTENSION_FAKE_PROBE_SERVICE_FACTORY_H_ + +#include <memory> + +#include "chrome/browser/ash/telemetry_extension/fake_probe_service.h" +#include "chrome/browser/ash/telemetry_extension/probe_service_ash.h" +#include "chromeos/crosapi/mojom/probe_service.mojom.h" +#include "mojo/public/cpp/bindings/pending_receiver.h" + +namespace ash { + +class FakeProbeServiceFactory : public ash::ProbeServiceAsh::Factory { + public: + FakeProbeServiceFactory(); + ~FakeProbeServiceFactory() override; + + void SetCreateInstanceResponse( + std::unique_ptr<FakeProbeService> fake_service); + + protected: + // ProbeServiceAsh::Factory: + std::unique_ptr<crosapi::mojom::ProbeService> CreateInstance( + mojo::PendingReceiver<crosapi::mojom::ProbeService> receiver) override; + + private: + std::unique_ptr<FakeProbeService> fake_service_; +}; + +} // namespace ash + +#endif // CHROME_BROWSER_ASH_TELEMETRY_EXTENSION_FAKE_PROBE_SERVICE_FACTORY_H_
diff --git a/chrome/browser/ash/telemetry_extension/probe_service.cc b/chrome/browser/ash/telemetry_extension/probe_service_ash.cc similarity index 69% rename from chrome/browser/ash/telemetry_extension/probe_service.cc rename to chrome/browser/ash/telemetry_extension/probe_service_ash.cc index 71d0e27..a3208fe 100644 --- a/chrome/browser/ash/telemetry_extension/probe_service.cc +++ b/chrome/browser/ash/telemetry_extension/probe_service_ash.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/ash/telemetry_extension/probe_service.h" +#include "chrome/browser/ash/telemetry_extension/probe_service_ash.h" #include <utility> @@ -22,32 +22,34 @@ } // namespace // static -ProbeService::Factory* ProbeService::Factory::test_factory_ = nullptr; +ProbeServiceAsh::Factory* ProbeServiceAsh::Factory::test_factory_ = nullptr; // static -std::unique_ptr<crosapi::mojom::ProbeService> ProbeService::Factory::Create( +std::unique_ptr<crosapi::mojom::ProbeService> ProbeServiceAsh::Factory::Create( mojo::PendingReceiver<crosapi::mojom::ProbeService> receiver) { if (test_factory_) { return test_factory_->CreateInstance(std::move(receiver)); } - return base::WrapUnique<ProbeService>(new ProbeService(std::move(receiver))); + return base::WrapUnique<ProbeService>( + new ProbeServiceAsh(std::move(receiver))); } // static -void ProbeService::Factory::SetForTesting(ProbeService::Factory* test_factory) { +void ProbeServiceAsh::Factory::SetForTesting( + ProbeServiceAsh::Factory* test_factory) { test_factory_ = test_factory; } -ProbeService::Factory::~Factory() = default; +ProbeServiceAsh::Factory::~Factory() = default; -ProbeService::ProbeService( +ProbeServiceAsh::ProbeServiceAsh( mojo::PendingReceiver<crosapi::mojom::ProbeService> receiver) : receiver_(this, std::move(receiver)) {} -ProbeService::~ProbeService() = default; +ProbeServiceAsh::~ProbeServiceAsh() = default; -void ProbeService::ProbeTelemetryInfo( +void ProbeServiceAsh::ProbeTelemetryInfo( const std::vector<crosapi::mojom::ProbeCategoryEnum>& categories, ProbeTelemetryInfoCallback callback) { GetService()->ProbeTelemetryInfo( @@ -61,8 +63,10 @@ std::move(callback))); } -void ProbeService::GetOemData(GetOemDataCallback callback) { - DebugDaemonClient::Get()->GetLog( +void ProbeServiceAsh::GetOemData(GetOemDataCallback callback) { + DebugDaemonClient* debugd_client = DebugDaemonClient::Get(); + + debugd_client->GetLog( kOemDataLogName, base::BindOnce( [](GetOemDataCallback callback, @@ -73,17 +77,17 @@ std::move(callback))); } -cros_healthd::mojom::CrosHealthdProbeService* ProbeService::GetService() { +cros_healthd::mojom::CrosHealthdProbeService* ProbeServiceAsh::GetService() { if (!service_ || !service_.is_connected()) { cros_healthd::ServiceConnection::GetInstance()->GetProbeService( service_.BindNewPipeAndPassReceiver()); service_.set_disconnect_handler( - base::BindOnce(&ProbeService::OnDisconnect, base::Unretained(this))); + base::BindOnce(&ProbeServiceAsh::OnDisconnect, base::Unretained(this))); } return service_.get(); } -void ProbeService::OnDisconnect() { +void ProbeServiceAsh::OnDisconnect() { service_.reset(); }
diff --git a/chrome/browser/ash/telemetry_extension/probe_service.h b/chrome/browser/ash/telemetry_extension/probe_service_ash.h similarity index 81% rename from chrome/browser/ash/telemetry_extension/probe_service.h rename to chrome/browser/ash/telemetry_extension/probe_service_ash.h index edd3ec8..d548844 100644 --- a/chrome/browser/ash/telemetry_extension/probe_service.h +++ b/chrome/browser/ash/telemetry_extension/probe_service_ash.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_ASH_TELEMETRY_EXTENSION_PROBE_SERVICE_H_ -#define CHROME_BROWSER_ASH_TELEMETRY_EXTENSION_PROBE_SERVICE_H_ +#ifndef CHROME_BROWSER_ASH_TELEMETRY_EXTENSION_PROBE_SERVICE_ASH_H_ +#define CHROME_BROWSER_ASH_TELEMETRY_EXTENSION_PROBE_SERVICE_ASH_H_ #include <memory> #include <vector> @@ -21,7 +21,7 @@ namespace mojom = ::chromeos::cros_healthd::mojom; } // namespace cros_healthd -class ProbeService : public crosapi::mojom::ProbeService { +class ProbeServiceAsh : public crosapi::mojom::ProbeService { public: class Factory { public: @@ -39,12 +39,12 @@ static Factory* test_factory_; }; - ProbeService(const ProbeService&) = delete; - ProbeService& operator=(const ProbeService&) = delete; - ~ProbeService() override; + ProbeServiceAsh(const ProbeServiceAsh&) = delete; + ProbeServiceAsh& operator=(const ProbeServiceAsh&) = delete; + ~ProbeServiceAsh() override; private: - explicit ProbeService( + explicit ProbeServiceAsh( mojo::PendingReceiver<crosapi::mojom::ProbeService> receiver); // crosapi::mojom::ProbeService override @@ -71,9 +71,4 @@ } // namespace ash -// TODO(https://crbug.com/1164001): remove when ChromeOS code migration is done. -namespace chromeos { -using ::ash::ProbeService; -} // namespace chromeos - -#endif // CHROME_BROWSER_ASH_TELEMETRY_EXTENSION_PROBE_SERVICE_H_ +#endif // CHROME_BROWSER_ASH_TELEMETRY_EXTENSION_PROBE_SERVICE_ASH_H_
diff --git a/chrome/browser/ash/telemetry_extension/probe_service_unittest.cc b/chrome/browser/ash/telemetry_extension/probe_service_ash_unittest.cc similarity index 91% rename from chrome/browser/ash/telemetry_extension/probe_service_unittest.cc rename to chrome/browser/ash/telemetry_extension/probe_service_ash_unittest.cc index 8b01c09d..b549bcb 100644 --- a/chrome/browser/ash/telemetry_extension/probe_service_unittest.cc +++ b/chrome/browser/ash/telemetry_extension/probe_service_ash_unittest.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/ash/telemetry_extension/probe_service.h" +#include "chrome/browser/ash/telemetry_extension/probe_service_ash.h" #include <cstdint> #include <utility> @@ -21,7 +21,7 @@ namespace cros_healthd = ::ash::cros_healthd; } // namespace -class ProbeServiceTest : public testing::Test { +class ProbeServieAshTest : public testing::Test { public: void SetUp() override { DebugDaemonClient::InitializeFake(); @@ -42,13 +42,13 @@ mojo::Remote<crosapi::mojom::ProbeService> remote_probe_service_; std::unique_ptr<crosapi::mojom::ProbeService> probe_service_{ - ProbeService::Factory::Create( + ProbeServiceAsh::Factory::Create( remote_probe_service_.BindNewPipeAndPassReceiver())}; }; // Tests that ProbeTelemetryInfo requests telemetry info in cros_healthd and // forwards response via callback. -TEST_F(ProbeServiceTest, ProbeTelemetryInfoSuccess) { +TEST_F(ProbeServieAshTest, ProbeTelemetryInfoSuccess) { constexpr int64_t kCycleCount = 512; { @@ -84,7 +84,7 @@ // Tests that GetOemData requests OEM data in debugd and // forwards response via callback. -TEST_F(ProbeServiceTest, GetOemDataSuccess) { +TEST_F(ProbeServieAshTest, GetOemDataSuccess) { base::RunLoop run_loop; probe_service()->GetOemData( base::BindLambdaForTesting([&](crosapi::mojom::ProbeOemDataPtr ptr) {
diff --git a/chrome/browser/ash/web_applications/terminal_system_web_app_info.cc b/chrome/browser/ash/web_applications/terminal_system_web_app_info.cc index a035125..0acd0b2 100644 --- a/chrome/browser/ash/web_applications/terminal_system_web_app_info.cc +++ b/chrome/browser/ash/web_applications/terminal_system_web_app_info.cc
@@ -7,14 +7,18 @@ #include <memory> #include "base/strings/strcat.h" +#include "chrome/browser/ash/crostini/crostini_pref_names.h" #include "chrome/browser/ash/guest_os/guest_os_terminal.h" +#include "chrome/browser/ash/guest_os/virtual_machines/virtual_machines_util.h" #include "chrome/browser/ash/web_applications/system_web_app_install_utils.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/browser/web_applications/web_app_install_info.h" #include "chrome/common/webui_url_constants.h" #include "chrome/grit/chrome_unscaled_resources.h" #include "chrome/grit/generated_resources.h" +#include "components/prefs/pref_service.h" #include "extensions/common/constants.h" #include "third_party/blink/public/mojom/manifest/display_mode.mojom.h" #include "ui/base/l10n/l10n_util.h" @@ -76,6 +80,13 @@ return true; } +bool TerminalSystemAppDelegate::ShouldShowInLauncher() const { + // Hide from launcher if VMs disabled, and SSH disabled. + return virtual_machines::AreVirtualMachinesAllowedByPolicy() || + profile()->GetPrefs()->GetBoolean( + crostini::prefs::kTerminalSshAllowedByPolicy); +} + bool TerminalSystemAppDelegate::ShouldHaveTabStrip() const { return true; }
diff --git a/chrome/browser/ash/web_applications/terminal_system_web_app_info.h b/chrome/browser/ash/web_applications/terminal_system_web_app_info.h index 6449f5e..123373f 100644 --- a/chrome/browser/ash/web_applications/terminal_system_web_app_info.h +++ b/chrome/browser/ash/web_applications/terminal_system_web_app_info.h
@@ -23,6 +23,7 @@ std::unique_ptr<WebAppInstallInfo> GetWebAppInfo() const override; bool ShouldReuseExistingWindow() const override; bool ShouldShowNewWindowMenuOption() const override; + bool ShouldShowInLauncher() const override; bool ShouldHaveTabStrip() const override; gfx::Rect GetDefaultBounds(Browser* browser) const override; bool HasCustomTabMenuModel() const override;
diff --git a/chrome/browser/autofill_assistant/password_change/apc_client_impl.cc b/chrome/browser/autofill_assistant/password_change/apc_client_impl.cc index e057d52..7bb52c29 100644 --- a/chrome/browser/autofill_assistant/password_change/apc_client_impl.cc +++ b/chrome/browser/autofill_assistant/password_change/apc_client_impl.cc
@@ -128,8 +128,15 @@ return; } - side_panel_coordinator_ = CreateSidePanel(); - side_panel_coordinator_->AddObserver(this); + // Only create a new sidepanel coordinator if there is not one already shown. + if (!side_panel_coordinator_) { + side_panel_coordinator_ = CreateSidePanel(); + if (!side_panel_coordinator_) { + Stop(/*success=*/false); + return; + } + side_panel_coordinator_->AddObserver(this); + } base::flat_map<std::string, std::string> params_map = { {autofill_assistant::public_script_parameters::
diff --git a/chrome/browser/chromeos/app_mode/chrome_kiosk_app_launcher_unittest.cc b/chrome/browser/chromeos/app_mode/chrome_kiosk_app_launcher_unittest.cc index cc1c7f0..f974819 100644 --- a/chrome/browser/chromeos/app_mode/chrome_kiosk_app_launcher_unittest.cc +++ b/chrome/browser/chromeos/app_mode/chrome_kiosk_app_launcher_unittest.cc
@@ -99,7 +99,7 @@ extensions::AppWindow::CreateParams params; params.content_spec.bounds = bounds; - app_window->Init(GURL(), app_window_contents.release(), main_frame, params); + app_window->Init(GURL(), std::move(app_window_contents), main_frame, params); } extensions::AppWindow* CreateAppWindow(Profile* profile,
diff --git a/chrome/browser/chromeos/extensions/telemetry/api/remote_probe_service_strategy.cc b/chrome/browser/chromeos/extensions/telemetry/api/remote_probe_service_strategy.cc index 0dc62a4..55e24db 100644 --- a/chrome/browser/chromeos/extensions/telemetry/api/remote_probe_service_strategy.cc +++ b/chrome/browser/chromeos/extensions/telemetry/api/remote_probe_service_strategy.cc
@@ -6,7 +6,7 @@ #include <memory> -#include "chrome/browser/ash/telemetry_extension/probe_service.h" +#include "chrome/browser/ash/telemetry_extension/probe_service_ash.h" #include "chromeos/crosapi/mojom/probe_service.mojom.h" #include "mojo/public/cpp/bindings/remote.h" @@ -17,7 +17,7 @@ class RemoteProbeServiceStrategyAsh : public RemoteProbeServiceStrategy { public: RemoteProbeServiceStrategyAsh() - : probe_service_(ash::ProbeService::Factory::Create( + : probe_service_(ash::ProbeServiceAsh::Factory::Create( remote_probe_service_.BindNewPipeAndPassReceiver())) {} ~RemoteProbeServiceStrategyAsh() override = default;
diff --git a/chrome/browser/chromeos/extensions/telemetry/api/telemetry_api_browsertest.cc b/chrome/browser/chromeos/extensions/telemetry/api/telemetry_api_browsertest.cc index 4a9369f..271d25d 100644 --- a/chrome/browser/chromeos/extensions/telemetry/api/telemetry_api_browsertest.cc +++ b/chrome/browser/chromeos/extensions/telemetry/api/telemetry_api_browsertest.cc
@@ -7,7 +7,8 @@ #include <utility> #include "chrome/browser/ash/telemetry_extension/fake_probe_service.h" -#include "chrome/browser/ash/telemetry_extension/probe_service.h" +#include "chrome/browser/ash/telemetry_extension/fake_probe_service_factory.h" +#include "chrome/browser/ash/telemetry_extension/probe_service_ash.h" #include "chrome/browser/chromeos/extensions/telemetry/api/base_telemetry_extension_browser_test.h" #include "content/public/test/browser_test.h" #include "testing/gtest/include/gtest/gtest.h" @@ -18,7 +19,7 @@ : public BaseTelemetryExtensionBrowserTest { public: TelemetryExtensionTelemetryApiBrowserTest() { - ash::ProbeService::Factory::SetForTesting(&fake_probe_factory_); + ash::ProbeServiceAsh::Factory::SetForTesting(&fake_probe_factory_); } ~TelemetryExtensionTelemetryApiBrowserTest() override = default; @@ -34,7 +35,7 @@ std::move(fake_diagnostics_service_impl)); } - ash::FakeProbeService::Factory fake_probe_factory_; + ash::FakeProbeServiceFactory fake_probe_factory_; }; IN_PROC_BROWSER_TEST_F(TelemetryExtensionTelemetryApiBrowserTest,
diff --git a/chrome/browser/device_reauth/android/biometric_authenticator_android.h b/chrome/browser/device_reauth/android/biometric_authenticator_android.h index ec9f4c1..f74b431 100644 --- a/chrome/browser/device_reauth/android/biometric_authenticator_android.h +++ b/chrome/browser/device_reauth/android/biometric_authenticator_android.h
@@ -83,7 +83,7 @@ std::unique_ptr<BiometricAuthenticatorBridge> bridge); private: - friend class BiometricAuthenticatorAndroidFactory; + friend class ChromeBiometricAuthenticatorFactory; explicit BiometricAuthenticatorAndroid( std::unique_ptr<BiometricAuthenticatorBridge> bridge);
diff --git a/chrome/browser/device_reauth/android/biometric_authenticator_android_factory.cc b/chrome/browser/device_reauth/android/biometric_authenticator_android_factory.cc deleted file mode 100644 index f37960813..0000000 --- a/chrome/browser/device_reauth/android/biometric_authenticator_android_factory.cc +++ /dev/null
@@ -1,42 +0,0 @@ -// Copyright 2021 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/device_reauth/android/biometric_authenticator_android_factory.h" - -#include "base/memory/scoped_refptr.h" -#include "base/no_destructor.h" - -#include "chrome/browser/device_reauth/android/biometric_authenticator_android.h" -#include "chrome/browser/device_reauth/android/biometric_authenticator_bridge_impl.h" -#include "chrome/browser/device_reauth/chrome_biometric_authenticator_factory.h" - -// static -scoped_refptr<device_reauth::BiometricAuthenticator> -ChromeBiometricAuthenticatorFactory::GetBiometricAuthenticator() { - return BiometricAuthenticatorAndroidFactory::GetInstance() - ->GetOrCreateBiometricAuthenticator(); -} - -BiometricAuthenticatorAndroidFactory::~BiometricAuthenticatorAndroidFactory() = - default; - -// static -BiometricAuthenticatorAndroidFactory* -BiometricAuthenticatorAndroidFactory::GetInstance() { - static base::NoDestructor<BiometricAuthenticatorAndroidFactory> instance; - return instance.get(); -} - -scoped_refptr<device_reauth::BiometricAuthenticator> -BiometricAuthenticatorAndroidFactory::GetOrCreateBiometricAuthenticator() { - if (!biometric_authenticator_) { - biometric_authenticator_ = - base::WrapRefCounted(new BiometricAuthenticatorAndroid( - std::make_unique<BiometricAuthenticatorBridgeImpl>())); - } - return biometric_authenticator_; -} - -BiometricAuthenticatorAndroidFactory::BiometricAuthenticatorAndroidFactory() = - default;
diff --git a/chrome/browser/device_reauth/android/biometric_authenticator_android_factory.h b/chrome/browser/device_reauth/android/biometric_authenticator_android_factory.h deleted file mode 100644 index 62d5e53d..0000000 --- a/chrome/browser/device_reauth/android/biometric_authenticator_android_factory.h +++ /dev/null
@@ -1,39 +0,0 @@ -// Copyright 2021 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_DEVICE_REAUTH_ANDROID_BIOMETRIC_AUTHENTICATOR_ANDROID_FACTORY_H_ -#define CHROME_BROWSER_DEVICE_REAUTH_ANDROID_BIOMETRIC_AUTHENTICATOR_ANDROID_FACTORY_H_ - -#include "base/no_destructor.h" -#include "chrome/browser/device_reauth/chrome_biometric_authenticator_factory.h" - -// A singleton factory that is responsible for creating and providing a shared -// instance of BiometricAuthenticator in Android. -class BiometricAuthenticatorAndroidFactory - : public ChromeBiometricAuthenticatorFactory { - public: - BiometricAuthenticatorAndroidFactory( - const BiometricAuthenticatorAndroidFactory& other) = delete; - BiometricAuthenticatorAndroidFactory& operator=( - const BiometricAuthenticatorAndroidFactory&) = delete; - ~BiometricAuthenticatorAndroidFactory(); - - static BiometricAuthenticatorAndroidFactory* GetInstance(); - - scoped_refptr<device_reauth::BiometricAuthenticator> - GetOrCreateBiometricAuthenticator(); - - private: - friend class base::NoDestructor<BiometricAuthenticatorAndroidFactory>; - - BiometricAuthenticatorAndroidFactory(); - - // The BiometricAuthenticator instance which holds the actual logic for - // re-authentication. This factory is responsible for creating and owning this - // instance. Clients can get access to it via - // ChromeBiometricAuthenticatorFactory::GetBiometricAuthenticator method. - scoped_refptr<device_reauth::BiometricAuthenticator> biometric_authenticator_; -}; - -#endif // CHROME_BROWSER_DEVICE_REAUTH_ANDROID_BIOMETRIC_AUTHENTICATOR_ANDROID_FACTORY_H_
diff --git a/chrome/browser/device_reauth/chrome_biometric_authenticator_factory.cc b/chrome/browser/device_reauth/chrome_biometric_authenticator_factory.cc new file mode 100644 index 0000000..e5ba4b7e --- /dev/null +++ b/chrome/browser/device_reauth/chrome_biometric_authenticator_factory.cc
@@ -0,0 +1,48 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/device_reauth/chrome_biometric_authenticator_factory.h" + +#include "base/notreached.h" + +#if BUILDFLAG(IS_ANDROID) +#include "chrome/browser/device_reauth/android/biometric_authenticator_android.h" +#include "chrome/browser/device_reauth/android/biometric_authenticator_bridge_impl.h" +#endif + +// static +scoped_refptr<device_reauth::BiometricAuthenticator> +ChromeBiometricAuthenticatorFactory::GetBiometricAuthenticator() { + return ChromeBiometricAuthenticatorFactory::GetInstance() + ->GetOrCreateBiometricAuthenticator(); +} + +// static +ChromeBiometricAuthenticatorFactory* +ChromeBiometricAuthenticatorFactory::GetInstance() { + static base::NoDestructor<ChromeBiometricAuthenticatorFactory> instance; + return instance.get(); +} + +scoped_refptr<device_reauth::BiometricAuthenticator> +ChromeBiometricAuthenticatorFactory::GetOrCreateBiometricAuthenticator() { + if (!biometric_authenticator_) { +#if BUILDFLAG(IS_ANDROID) + biometric_authenticator_ = + (new BiometricAuthenticatorAndroid( + std::make_unique<BiometricAuthenticatorBridgeImpl>())) + ->GetWeakPtr(); +#else + NOTREACHED(); +#endif + } + + return base::WrapRefCounted(biometric_authenticator_.get()); +} + +ChromeBiometricAuthenticatorFactory::ChromeBiometricAuthenticatorFactory() = + default; + +ChromeBiometricAuthenticatorFactory::~ChromeBiometricAuthenticatorFactory() = + default;
diff --git a/chrome/browser/device_reauth/chrome_biometric_authenticator_factory.h b/chrome/browser/device_reauth/chrome_biometric_authenticator_factory.h index 070a4c7..bc3f70cc 100644 --- a/chrome/browser/device_reauth/chrome_biometric_authenticator_factory.h +++ b/chrome/browser/device_reauth/chrome_biometric_authenticator_factory.h
@@ -6,22 +6,48 @@ #define CHROME_BROWSER_DEVICE_REAUTH_CHROME_BIOMETRIC_AUTHENTICATOR_FACTORY_H_ #include "base/memory/scoped_refptr.h" +#include "base/memory/weak_ptr.h" +#include "base/no_destructor.h" +#include "components/device_reauth/biometric_authenticator.h" -namespace device_reauth { -class BiometricAuthenticator; -} - -// Subclasses are expected to provide an implementation for -// GetBiometricAuthenticator(), instantiating authenticators for a given -// platform. They would also be responsible for deciding whether to create -// multiple/single instances of BiometricAuthenticator. +// Implementation for every OS will be in the same file, as the only thing +// different will be the way of creating a BiometricAuthenticator object, and +// that part will be hidden behind a BUILDFLAG. class ChromeBiometricAuthenticatorFactory { public: + ChromeBiometricAuthenticatorFactory( + const ChromeBiometricAuthenticatorFactory& other) = delete; + ChromeBiometricAuthenticatorFactory& operator=( + const ChromeBiometricAuthenticatorFactory&) = delete; + // Get or create an instance of the BiometricAuthenticator. Trying to use this // API on platforms that do not provide an implementation will result in a // link error. So far only Android provides an implementation. + // TODO(crbug.com/1349717): Change way of obtaining BiometricAuthenticator + // from factory. static scoped_refptr<device_reauth::BiometricAuthenticator> GetBiometricAuthenticator(); + + static ChromeBiometricAuthenticatorFactory* GetInstance(); + + scoped_refptr<device_reauth::BiometricAuthenticator> + GetOrCreateBiometricAuthenticator(); + + private: + friend class base::NoDestructor<ChromeBiometricAuthenticatorFactory>; + + ChromeBiometricAuthenticatorFactory(); + + ~ChromeBiometricAuthenticatorFactory(); + + // The BiometricAuthenticator instance which holds the actual logic for + // re-authentication. This factory is responsible for creating this instance. + // Clients can get access to it via + // ChromeBiometricAuthenticatorFactory::GetBiometricAuthenticator method. + // Factory doesn't own that object so if there are no references to it and + // more than 60 seconds have passed since last successful authentication, + // the authenticator will be destroyed. + base::WeakPtr<device_reauth::BiometricAuthenticator> biometric_authenticator_; }; #endif // CHROME_BROWSER_DEVICE_REAUTH_CHROME_BIOMETRIC_AUTHENTICATOR_FACTORY_H_
diff --git a/chrome/browser/extensions/api/passwords_private/password_check_delegate.cc b/chrome/browser/extensions/api/passwords_private/password_check_delegate.cc index df8c9f7..debfa02 100644 --- a/chrome/browser/extensions/api/passwords_private/password_check_delegate.cc +++ b/chrome/browser/extensions/api/passwords_private/password_check_delegate.cc
@@ -75,8 +75,6 @@ using password_manager::metrics_util::PasswordCheckScriptsCacheState; using ui::TimeFormat; -using InsecureCredentialsView = - password_manager::InsecureCredentialsManager::CredentialsView; using SavedPasswordsView = password_manager::SavedPasswordsPresenter::SavedPasswordsView; using State = password_manager::BulkLeakCheckService::State; @@ -282,12 +280,6 @@ &insecure_credentials_manager_); observed_bulk_leak_check_service_.Observe( BulkLeakCheckServiceFactory::GetForProfile(profile_)); - - // Instructs the provider to initialize and build its cache. - // This will soon after invoke OnCompromisedCredentialsChanged(). Calls to - // GetCompromisedCredentials() that might happen until then will return an - // empty list. - insecure_credentials_manager_.Init(); } PasswordCheckDelegate::~PasswordCheckDelegate() = default; @@ -385,8 +377,8 @@ return; } - // Also return early if the check is already running. - if (is_check_running_ || + // Also return early if the check is already running or scripts are fetching. + if (are_scripts_fetching_ || bulk_leak_check_service_adapter_.GetBulkLeakCheckState() == State::kRunning) { std::move(callback).Run(State::kRunning); @@ -395,10 +387,10 @@ // If automated password change from password check in settings is enabled, // we make sure that the cache is warm prior to analyzing passwords. - is_check_running_ = true; if (base::FeatureList::IsEnabled( password_manager::features::kPasswordChange)) { if (GetPasswordScriptsFetcher()->IsCacheStale()) { + are_scripts_fetching_ = true; // The UMA metric for a stale cache is recorded on callback. GetPasswordScriptsFetcher()->RefreshScriptsIfNecessary( base::BindOnce(&PasswordCheckDelegate::OnPasswordScriptsFetched, @@ -415,6 +407,8 @@ void PasswordCheckDelegate::OnPasswordScriptsFetched( StartPasswordCheckCallback callback) { + DCHECK(are_scripts_fetching_); + are_scripts_fetching_ = false; if (PasswordsPrivateEventRouter* event_router = PasswordsPrivateEventRouterFactory::GetForProfile(profile_)) { // Only update if at least one credential now has a startable script. @@ -438,9 +432,6 @@ void PasswordCheckDelegate::StartPasswordAnalyses( StartPasswordCheckCallback callback) { - // This is set as soon as the script availability fetching is started. - DCHECK(is_check_running_); - // Start the weakness check, and notify observers once done. insecure_credentials_manager_.StartWeakCheck(base::BindOnce( &PasswordCheckDelegate::RecordAndNotifyAboutCompletedWeakPasswordCheck,
diff --git a/chrome/browser/extensions/api/passwords_private/password_check_delegate.h b/chrome/browser/extensions/api/passwords_private/password_check_delegate.h index e171781..42ba7b46 100644 --- a/chrome/browser/extensions/api/passwords_private/password_check_delegate.h +++ b/chrome/browser/extensions/api/passwords_private/password_check_delegate.h
@@ -201,6 +201,9 @@ // running. base::WeakPtr<PasswordCheckProgress> password_check_progress_; + // Remembers whether scripts are fetching right now. + bool are_scripts_fetching_ = false; + // Remembers whether a password check is running right now. bool is_check_running_ = false;
diff --git a/chrome/browser/extensions/api/passwords_private/password_check_delegate_unittest.cc b/chrome/browser/extensions/api/passwords_private/password_check_delegate_unittest.cc index 925b23a..57fe6200 100644 --- a/chrome/browser/extensions/api/passwords_private/password_check_delegate_unittest.cc +++ b/chrome/browser/extensions/api/passwords_private/password_check_delegate_unittest.cc
@@ -90,7 +90,6 @@ using api::passwords_private::UrlCollection; using password_manager::BulkLeakCheckDelegateInterface; using password_manager::BulkLeakCheckService; -using password_manager::InsecureCredentialTypeFlags; using password_manager::InsecureType; using password_manager::InsecurityMetadata; using password_manager::IsLeaked; @@ -361,27 +360,6 @@ } // namespace -TEST_F(PasswordCheckDelegateTest, VerifyCastingOfCompromisedCredentialTypes) { - static_assert( - static_cast<int>(api::passwords_private::COMPROMISE_TYPE_NONE) == - static_cast<int>(InsecureCredentialTypeFlags::kSecure), - ""); - static_assert( - static_cast<int>(api::passwords_private::COMPROMISE_TYPE_LEAKED) == - static_cast<int>(InsecureCredentialTypeFlags::kCredentialLeaked), - ""); - static_assert( - static_cast<int>(api::passwords_private::COMPROMISE_TYPE_PHISHED) == - static_cast<int>(InsecureCredentialTypeFlags::kCredentialPhished), - ""); - static_assert( - static_cast<int>( - api::passwords_private::COMPROMISE_TYPE_PHISHED_AND_LEAKED) == - static_cast<int>(InsecureCredentialTypeFlags::kCredentialLeaked | - InsecureCredentialTypeFlags::kCredentialPhished), - ""); -} - // Verify that GetWeakCredentials() correctly represents weak credentials. TEST_F(PasswordCheckDelegateTest, GetWeakCredentialsFillsFieldsCorrectly) { store().AddLogin(MakeSavedPassword(kExampleCom, kUsername1, kWeakPassword1));
diff --git a/chrome/browser/external_protocol/external_protocol_handler_unittest.cc b/chrome/browser/external_protocol/external_protocol_handler_unittest.cc index 700300d..8c09d0d 100644 --- a/chrome/browser/external_protocol/external_protocol_handler_unittest.cc +++ b/chrome/browser/external_protocol/external_protocol_handler_unittest.cc
@@ -334,8 +334,8 @@ EXPECT_EQ(ExternalProtocolHandler::UNKNOWN, block_state); EXPECT_TRUE( profile_->GetPrefs() - ->GetDictionary(prefs::kProtocolHandlerPerOriginAllowedProtocols) - ->DictEmpty()); + ->GetValueDict(prefs::kProtocolHandlerPerOriginAllowedProtocols) + .empty()); } TEST_F(ExternalProtocolHandlerTest, TestGetBlockStateDefaultBlock) { @@ -354,8 +354,8 @@ EXPECT_EQ(ExternalProtocolHandler::BLOCK, block_state); EXPECT_TRUE( profile_->GetPrefs() - ->GetDictionary(prefs::kProtocolHandlerPerOriginAllowedProtocols) - ->DictEmpty()); + ->GetValueDict(prefs::kProtocolHandlerPerOriginAllowedProtocols) + .empty()); } TEST_F(ExternalProtocolHandlerTest, TestGetBlockStateDefaultDontBlock) { @@ -364,8 +364,8 @@ EXPECT_EQ(ExternalProtocolHandler::DONT_BLOCK, block_state); EXPECT_TRUE( profile_->GetPrefs() - ->GetDictionary(prefs::kProtocolHandlerPerOriginAllowedProtocols) - ->DictEmpty()); + ->GetValueDict(prefs::kProtocolHandlerPerOriginAllowedProtocols) + .empty()); } TEST_F(ExternalProtocolHandlerTest, TestSetBlockState) { @@ -390,8 +390,8 @@ EXPECT_EQ(ExternalProtocolHandler::UNKNOWN, block_state); EXPECT_TRUE( profile_->GetPrefs() - ->GetDictionary(prefs::kProtocolHandlerPerOriginAllowedProtocols) - ->DictEmpty()); + ->GetValueDict(prefs::kProtocolHandlerPerOriginAllowedProtocols) + .empty()); // Set to DONT_BLOCK for {kScheme_1, example_origin_1}, and make sure it is // written to prefs. @@ -429,23 +429,19 @@ kScheme_2, &example_origin_2, profile_.get()); EXPECT_EQ(ExternalProtocolHandler::DONT_BLOCK, block_state); - const base::Value* protocol_origin_pairs = - profile_->GetPrefs()->GetDictionary( + const base::Value::Dict& protocol_origin_pairs = + profile_->GetPrefs()->GetValueDict( prefs::kProtocolHandlerPerOriginAllowedProtocols); - base::Value expected_allowed_protocols_for_example_origin_1( - base::Value::Type::DICTIONARY); - expected_allowed_protocols_for_example_origin_1.SetKey(kScheme_1, - base::Value(true)); - const base::Value* allowed_protocols_for_example_origin_1 = - protocol_origin_pairs->FindDictKey(example_origin_1.Serialize()); + base::Value::Dict expected_allowed_protocols_for_example_origin_1; + expected_allowed_protocols_for_example_origin_1.Set(kScheme_1, true); + const base::Value::Dict* allowed_protocols_for_example_origin_1 = + protocol_origin_pairs.FindDict(example_origin_1.Serialize()); EXPECT_EQ(expected_allowed_protocols_for_example_origin_1, *allowed_protocols_for_example_origin_1); - base::Value expected_allowed_protocols_for_example_origin_2( - base::Value::Type::DICTIONARY); - expected_allowed_protocols_for_example_origin_2.SetKey(kScheme_2, - base::Value(true)); - const base::Value* allowed_protocols_for_example_origin_2 = - protocol_origin_pairs->FindDictKey(example_origin_2.Serialize()); + base::Value::Dict expected_allowed_protocols_for_example_origin_2; + expected_allowed_protocols_for_example_origin_2.Set(kScheme_2, true); + const base::Value::Dict* allowed_protocols_for_example_origin_2 = + protocol_origin_pairs.FindDict(example_origin_2.Serialize()); EXPECT_EQ(expected_allowed_protocols_for_example_origin_2, *allowed_protocols_for_example_origin_2); @@ -467,8 +463,8 @@ EXPECT_EQ(ExternalProtocolHandler::UNKNOWN, block_state); EXPECT_TRUE( profile_->GetPrefs() - ->GetDictionary(prefs::kProtocolHandlerPerOriginAllowedProtocols) - ->DictEmpty()); + ->GetValueDict(prefs::kProtocolHandlerPerOriginAllowedProtocols) + .empty()); } TEST_F(ExternalProtocolHandlerTest, TestSetBlockStateWithUntrustowrthyOrigin) { @@ -483,8 +479,8 @@ EXPECT_EQ(ExternalProtocolHandler::UNKNOWN, block_state); EXPECT_TRUE( profile_->GetPrefs() - ->GetDictionary(prefs::kProtocolHandlerPerOriginAllowedProtocols) - ->DictEmpty()); + ->GetValueDict(prefs::kProtocolHandlerPerOriginAllowedProtocols) + .empty()); // Set to DONT_BLOCK for {kScheme, untrustworthy_origin}, and make sure it is // not written to prefs. Calling SetBlockState with a non-trustworthy origin @@ -497,8 +493,8 @@ EXPECT_EQ(ExternalProtocolHandler::UNKNOWN, block_state); EXPECT_TRUE( profile_->GetPrefs() - ->GetDictionary(prefs::kProtocolHandlerPerOriginAllowedProtocols) - ->DictEmpty()); + ->GetValueDict(prefs::kProtocolHandlerPerOriginAllowedProtocols) + .empty()); } // Test that an opaque initiating origin gets transformed to its precursor
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index 0c10751..8a50f81 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -764,6 +764,11 @@ "expiry_milestone": 113 }, { + "name": "camera-app-doc-scan-dlc", + "owners": [ "wtlee" ], + "expiry_milestone": 110 + }, + { "name": "canvas-2d-layers", "owners": [ "alisalin", "fserb", "juanmihd", "yiyix" ], "expiry_milestone": 100 @@ -984,11 +989,21 @@ "expiry_milestone": 110 }, { + "name": "content-suggestions-header-migration", + "owners": [ "thegreenfrog@google.com", "adamta@google.com" ], + "expiry_milestone": 105 + }, + { "name": "content-suggestions-ui-module-refresh", "owners": [ "thegreenfrog@google.com", "bling-flags@google.com" ], "expiry_milestone": 108 }, { + "name": "content-suggestions-uiviewcontroller-migration", + "owners": [ "thegreenfrog@google.com", "adamta@google.com" ], + "expiry_milestone": 106 + }, + { "name": "context-menu-popup-style", "owners": [ "wenyufu", "clank-app-team@google.com" ], "expiry_milestone": 108 @@ -1569,6 +1584,11 @@ "expiry_milestone": 110 }, { + "name": "enable-app-service-in-kiosk", + "owners": ["yixie", "chromeos-kiosk-eng@google.com"], + "expiry_milestone": 130 + }, + { "name": "enable-aria-element-reflection", "owners": [ "aleventhal", "//third_party/blink/renderer/modules/accessibility/OWNERS" ], "expiry_milestone": 105 @@ -5821,6 +5841,11 @@ "expiry_milestone": 106 }, { + "name": "single-cell-content-suggestions", + "owners": [ "thegreenfrog@google.com", "sczs@google.com"], + "expiry_milestone": 106 + }, + { "name": "single-ntp", "owners": [ "thegreenfrog@google.com", "sczs@google.com"], "expiry_milestone": 106
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index 4372567..b5b175a4 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -4741,6 +4741,11 @@ const char kBruschettaDescription[] = "Enables UI support for third party/generic VMs"; +const char kCameraAppDocScanDlcName[] = "Camera App Doc Scan DLC"; +const char kCameraAppDocScanDlcDescription[] = + "Enables this flag to allow downloading document scanning feature via DLC " + "and use it in the camera app"; + const char kCompactBubbleLauncherName[] = "Make bubble launcher more compact"; const char kCompactBubbleLauncherDescription[] = @@ -5956,6 +5961,11 @@ "When enabled, the intent chip in the Omnibox will show the app icon for " "the app which can handle the current URL."; +const char kKioskEnableAppServiceName[] = "Enable App Service in Kiosk."; +const char kKioskEnableAppServiceDescription[] = + "Uses App Service to install web apps and launch both Chrome apps and web " + "apps in Kiosk sessions."; + const char kLinkCapturingAutoDisplayIntentPickerName[] = "Enable auto-display of intent picker bubble"; const char kLinkCapturingAutoDisplayIntentPickerDescription[] = @@ -6050,12 +6060,6 @@ #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || \ BUILDFLAG(IS_FUCHSIA) - -const char kDesktopDetailedLanguageSettingsName[] = - "Detailed Language Settings (Desktop)"; -const char kDesktopDetailedLanguageSettingsDescription[] = - "Enable the new detailed language settings page"; - const char kQuickCommandsName[] = "Quick Commands"; const char kQuickCommandsDescription[] = "Enable a text interface to browser features. Invoke with Ctrl-Space."; @@ -6221,6 +6225,11 @@ const char kUIDebugToolsName[] = "Debugging tools for UI"; const char kUIDebugToolsDescription[] = "Enables additional keyboard shortcuts to help debugging."; + +const char kDesktopDetailedLanguageSettingsName[] = + "Detailed Language Settings (Desktop)"; +const char kDesktopDetailedLanguageSettingsDescription[] = + "Enable the new detailed language settings page"; #endif #if defined(WEBRTC_USE_PIPEWIRE)
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index 59e4537..d918a6e 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -2720,6 +2720,9 @@ extern const char kBruschettaName[]; extern const char kBruschettaDescription[]; +extern const char kCameraAppDocScanDlcName[]; +extern const char kCameraAppDocScanDlcDescription[]; + extern const char kCompactBubbleLauncherName[]; extern const char kCompactBubbleLauncherDescription[]; @@ -3419,6 +3422,9 @@ extern const char kIntentChipAppIconName[]; extern const char kIntentChipAppIconDescription[]; +extern const char kKioskEnableAppServiceName[]; +extern const char kKioskEnableAppServiceDescription[]; + extern const char kLinkCapturingAutoDisplayIntentPickerName[]; extern const char kLinkCapturingAutoDisplayIntentPickerDescription[]; @@ -3476,10 +3482,6 @@ #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || \ BUILDFLAG(IS_FUCHSIA) - -extern const char kDesktopDetailedLanguageSettingsName[]; -extern const char kDesktopDetailedLanguageSettingsDescription[]; - extern const char kQuickCommandsName[]; extern const char kQuickCommandsDescription[]; @@ -3596,6 +3598,9 @@ BUILDFLAG(IS_MAC) || BUILDFLAG(IS_FUCHSIA) extern const char kUIDebugToolsName[]; extern const char kUIDebugToolsDescription[]; + +extern const char kDesktopDetailedLanguageSettingsName[]; +extern const char kDesktopDetailedLanguageSettingsDescription[]; #endif #if defined(WEBRTC_USE_PIPEWIRE)
diff --git a/chrome/browser/media/router/providers/dial/dial_activity_manager.cc b/chrome/browser/media/router/providers/dial/dial_activity_manager.cc index 9ecfa0db..0621440 100644 --- a/chrome/browser/media/router/providers/dial/dial_activity_manager.cc +++ b/chrome/browser/media/router/providers/dial/dial_activity_manager.cc
@@ -226,7 +226,7 @@ if (record_it->second->pending_stop_request) { return {"A pending request already exists", - mojom::RouteRequestResultCode::UNKNOWN_ERROR}; + mojom::RouteRequestResultCode::REDUNDANT_REQUEST}; } return {absl::nullopt, mojom::RouteRequestResultCode::OK}; }
diff --git a/chrome/browser/media/router/providers/dial/dial_media_route_provider.cc b/chrome/browser/media/router/providers/dial/dial_media_route_provider.cc index b99ebfae..0c9ab5c 100644 --- a/chrome/browser/media/router/providers/dial/dial_media_route_provider.cc +++ b/chrome/browser/media/router/providers/dial/dial_media_route_provider.cc
@@ -181,8 +181,6 @@ MediaRoute::GetPresentationIdFromMediaRouteId(route_id)); std::move(callback).Run("Activity not found", mojom::RouteRequestResultCode::ROUTE_NOT_FOUND); - DialMediaRouteProviderMetrics::RecordTerminateRouteResult( - DialTerminateRouteResult::kRouteNotFound); return; } @@ -197,8 +195,6 @@ MediaRoute::GetPresentationIdFromMediaRouteId(route_id)); std::move(callback).Run("Sink not found", mojom::RouteRequestResultCode::SINK_NOT_FOUND); - DialMediaRouteProviderMetrics::RecordTerminateRouteResult( - DialTerminateRouteResult::kSinkNotFound); return; } @@ -469,16 +465,12 @@ mojom::RouteRequestResultCode result_code) { switch (result_code) { case mojom::RouteRequestResultCode::OK: - DialMediaRouteProviderMetrics::RecordTerminateRouteResult( - DialTerminateRouteResult::kSuccess); logger_->LogInfo(mojom::LogCategory::kRoute, kLoggerComponent, "Successfully terminated route.", "", MediaRoute::GetMediaSourceIdFromMediaRouteId(route_id), MediaRoute::GetPresentationIdFromMediaRouteId(route_id)); break; case mojom::RouteRequestResultCode::ROUTE_ALREADY_TERMINATED: - DialMediaRouteProviderMetrics::RecordTerminateRouteResult( - DialTerminateRouteResult::kRouteAlreadyTerminated); logger_->LogInfo(mojom::LogCategory::kRoute, kLoggerComponent, "Tried to stop a session that no longer exists.", "", MediaRoute::GetMediaSourceIdFromMediaRouteId(route_id), @@ -489,8 +481,6 @@ // controller with the OnPresentationConnectionStateChanged() call // below. This results in a local MediaRoute that is not associated with a // PresentationConnection. - DialMediaRouteProviderMetrics::RecordTerminateRouteResult( - DialTerminateRouteResult::kStopAppFailed); logger_->LogError( mojom::LogCategory::kRoute, kLoggerComponent, base::StringPrintf(
diff --git a/chrome/browser/media/router/providers/dial/dial_media_route_provider_metrics.cc b/chrome/browser/media/router/providers/dial/dial_media_route_provider_metrics.cc index a76ae668a..cb180b5 100644 --- a/chrome/browser/media/router/providers/dial/dial_media_route_provider_metrics.cc +++ b/chrome/browser/media/router/providers/dial/dial_media_route_provider_metrics.cc
@@ -16,13 +16,6 @@ } // static -void DialMediaRouteProviderMetrics::RecordTerminateRouteResult( - DialTerminateRouteResult result) { - UMA_HISTOGRAM_ENUMERATION(kHistogramDialTerminateRouteResult, result, - DialTerminateRouteResult::kCount); -} - -// static void DialMediaRouteProviderMetrics::RecordParseMessageResult( DialParseMessageResult result) { UMA_HISTOGRAM_ENUMERATION(kHistogramDialParseMessageResult, result,
diff --git a/chrome/browser/media/router/providers/dial/dial_media_route_provider_metrics.h b/chrome/browser/media/router/providers/dial/dial_media_route_provider_metrics.h index 2054057..d9fe1aa 100644 --- a/chrome/browser/media/router/providers/dial/dial_media_route_provider_metrics.h +++ b/chrome/browser/media/router/providers/dial/dial_media_route_provider_metrics.h
@@ -9,8 +9,6 @@ static constexpr char kHistogramDialCreateRouteResult[] = "MediaRouter.Dial.CreateRoute"; -static constexpr char kHistogramDialTerminateRouteResult[] = - "MediaRouter.Dial.TerminateRoute"; static constexpr char kHistogramDialParseMessageResult[] = "MediaRouter.Dial.ParseMessage"; @@ -29,15 +27,6 @@ kCount }; -enum class DialTerminateRouteResult { - kSuccess = 0, - kRouteNotFound = 1, - kSinkNotFound = 2, - kStopAppFailed = 3, - kRouteAlreadyTerminated = 4, - kCount -}; - enum class DialParseMessageResult { kSuccess = 0, kParseError = 1, @@ -48,7 +37,6 @@ class DialMediaRouteProviderMetrics { public: static void RecordCreateRouteResult(DialCreateRouteResult result); - static void RecordTerminateRouteResult(DialTerminateRouteResult result); static void RecordParseMessageResult(DialParseMessageResult result); };
diff --git a/chrome/browser/metrics/variations/variations_http_headers_browsertest.cc b/chrome/browser/metrics/variations/variations_http_headers_browsertest.cc index 8c26679..0957d0f 100644 --- a/chrome/browser/metrics/variations/variations_http_headers_browsertest.cc +++ b/chrome/browser/metrics/variations/variations_http_headers_browsertest.cc
@@ -621,8 +621,9 @@ local_state->SetInteger(metrics::prefs::kMetricsLowEntropySource, 5); } +// TODO(crbug.com/1349693): Re-enable this test IN_PROC_BROWSER_TEST_F(VariationsHttpHeadersBrowserTest, - CheckLowEntropySourceValue) { + DISABLED_CheckLowEntropySourceValue) { std::unique_ptr<const base::FieldTrial::EntropyProvider> low_entropy_provider = g_browser_process->GetMetricsServicesManager() ->CreateEntropyProviderForTesting();
diff --git a/chrome/browser/notifications/notification_platform_bridge_linux.cc b/chrome/browser/notifications/notification_platform_bridge_linux.cc index 5f281b5..98431e0d 100644 --- a/chrome/browser/notifications/notification_platform_bridge_linux.cc +++ b/chrome/browser/notifications/notification_platform_bridge_linux.cc
@@ -289,9 +289,9 @@ std::unique_ptr<dbus::Response> name_has_owner_response = dbus_proxy->CallMethodAndBlock(&name_has_owner_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT); - dbus::MessageReader reader(name_has_owner_response.get()); + dbus::MessageReader owner_reader(name_has_owner_response.get()); bool owned = false; - if (name_has_owner_response && reader.PopBool(&owned) && owned) + if (name_has_owner_response && owner_reader.PopBool(&owned) && owned) return true; // If the service currently isn't running, maybe it is activatable. @@ -702,14 +702,14 @@ if (notification->type() == message_center::NOTIFICATION_TYPE_MULTIPLE) { for (const auto& item : notification->items()) { - const std::string title = base::UTF16ToUTF8(item.title); - const std::string message = base::UTF16ToUTF8(item.message); + const std::string item_title = base::UTF16ToUTF8(item.title); + const std::string item_message = base::UTF16ToUTF8(item.message); // TODO(peter): Figure out the right way to internationalize // this for RTL languages. if (body_markup) - body << "<b>" << title << "</b> " << message << "\n"; + body << "<b>" << item_title << "</b> " << item_message << "\n"; else - body << title << " - " << message << "\n"; + body << item_title << " - " << item_message << "\n"; } } else if (notification->type() == message_center::NOTIFICATION_TYPE_IMAGE &&
diff --git a/chrome/browser/notifications/notification_platform_bridge_linux_unittest.cc b/chrome/browser/notifications/notification_platform_bridge_linux_unittest.cc index 9327c47..90d8dd3 100644 --- a/chrome/browser/notifications/notification_platform_bridge_linux_unittest.cc +++ b/chrome/browser/notifications/notification_platform_bridge_linux_unittest.cc
@@ -149,38 +149,39 @@ expect_shutdown(true), connect_signals(true) {} - TestParams& SetNameHasOwner(bool name_has_owner) { - this->name_has_owner = name_has_owner; + TestParams& SetNameHasOwner(bool new_name_has_owner) { + this->name_has_owner = new_name_has_owner; return *this; } - TestParams& SetCapabilities(const std::vector<std::string>& capabilities) { - this->capabilities = capabilities; + TestParams& SetCapabilities( + const std::vector<std::string>& new_capabilities) { + this->capabilities = new_capabilities; return *this; } - TestParams& SetServerName(const std::string& server_name) { - this->server_name = server_name; + TestParams& SetServerName(const std::string& new_server_name) { + this->server_name = new_server_name; return *this; } - TestParams& SetServerVersion(const std::string& server_version) { - this->server_version = server_version; + TestParams& SetServerVersion(const std::string& new_server_version) { + this->server_version = new_server_version; return *this; } - TestParams& SetExpectInitSuccess(bool expect_init_success) { - this->expect_init_success = expect_init_success; + TestParams& SetExpectInitSuccess(bool new_expect_init_success) { + this->expect_init_success = new_expect_init_success; return *this; } - TestParams& SetExpectShutdown(bool expect_shutdown) { - this->expect_shutdown = expect_shutdown; + TestParams& SetExpectShutdown(bool new_expect_shutdown) { + this->expect_shutdown = new_expect_shutdown; return *this; } - TestParams& SetConnectSignals(bool connect_signals) { - this->connect_signals = connect_signals; + TestParams& SetConnectSignals(bool new_connect_signals) { + this->connect_signals = new_connect_signals; return *this; }
diff --git a/chrome/browser/password_check/android/password_check_bridge.cc b/chrome/browser/password_check/android/password_check_bridge.cc index 2d198c7..253c565 100644 --- a/chrome/browser/password_check/android/password_check_bridge.cc +++ b/chrome/browser/password_check/android/password_check_bridge.cc
@@ -21,7 +21,7 @@ namespace { -password_manager::CredentialView ConvertJavaObjectToCredentialView( +password_manager::CredentialUIEntry ConvertJavaObjectToCredential( JNIEnv* env, const base::android::JavaParamRef<jobject>& credential) { std::string signon_realm = ConvertJavaStringToUTF8( @@ -36,14 +36,16 @@ : *url::GURLAndroid::ToNativeGURL( env, Java_CompromisedCredential_getAssociatedUrl( env, credential)); - return password_manager::CredentialView( - std::move(signon_realm), std::move(url), - ConvertJavaStringToUTF16( - env, Java_CompromisedCredential_getUsername(env, credential)), - ConvertJavaStringToUTF16( - env, Java_CompromisedCredential_getPassword(env, credential)), - base::Time::FromJavaTime( - Java_CompromisedCredential_getLastUsedTime(env, credential))); + password_manager::CredentialUIEntry entry; + entry.signon_realm = std::move(signon_realm); + entry.url = std::move(url); + entry.username = ConvertJavaStringToUTF16( + env, Java_CompromisedCredential_getUsername(env, credential)); + entry.password = ConvertJavaStringToUTF16( + env, Java_CompromisedCredential_getPassword(env, credential)); + entry.last_used_time = base::Time::FromJavaTime( + Java_CompromisedCredential_getLastUsedTime(env, credential)); + return entry; } // Checks whether the credential is leaked but not phished. Other compromising @@ -136,7 +138,7 @@ const base::android::JavaParamRef<jobject>& credential, const base::android::JavaParamRef<jstring>& new_password) { check_manager_.UpdateCredential( - ConvertJavaObjectToCredentialView(env, credential), + ConvertJavaObjectToCredential(env, credential), base::android::ConvertJavaStringToUTF8(new_password)); } @@ -146,7 +148,7 @@ const base::android::JavaParamRef<jobject>& context, const base::android::JavaParamRef<jobject>& settings_launcher) { check_manager_.OnEditCredential( - ConvertJavaObjectToCredentialView(env, credential), context, + ConvertJavaObjectToCredential(env, credential), context, settings_launcher); } @@ -154,7 +156,7 @@ JNIEnv* env, const base::android::JavaParamRef<jobject>& credential) { check_manager_.RemoveCredential( - ConvertJavaObjectToCredentialView(env, credential)); + ConvertJavaObjectToCredential(env, credential)); } void PasswordCheckBridge::Destroy(JNIEnv* env) {
diff --git a/chrome/browser/password_check/android/password_check_manager.cc b/chrome/browser/password_check/android/password_check_manager.cc index 4c3a2bc..8d7c92b 100644 --- a/chrome/browser/password_check/android/password_check_manager.cc +++ b/chrome/browser/password_check/android/password_check_manager.cc
@@ -37,8 +37,6 @@ } // namespace -using CredentialsView = - password_manager::InsecureCredentialsManager::CredentialsView; using PasswordCheckUIStatus = password_manager::PasswordCheckUIStatus; using State = password_manager::BulkLeakCheckService::State; using SyncState = password_manager::SyncState; @@ -73,7 +71,6 @@ // GetCompromisedCredentials() that might happen until then will return an // empty list. saved_passwords_presenter_.Init(); - insecure_credentials_manager_.Init(); if (!ShouldFetchPasswordScripts()) { // Ensure that scripts are treated as initialized if they are unnecessary. @@ -130,26 +127,27 @@ } void PasswordCheckManager::UpdateCredential( - const password_manager::CredentialView& credential, + const password_manager::CredentialUIEntry& credential, base::StringPiece new_password) { - insecure_credentials_manager_.UpdateCredential(credential, new_password); + CredentialUIEntry updated_credential = credential; + updated_credential.password = base::UTF8ToUTF16(new_password); + saved_passwords_presenter_.EditSavedCredentials(credential, + updated_credential); } void PasswordCheckManager::OnEditCredential( - const password_manager::CredentialView& credential, + const password_manager::CredentialUIEntry& credential, const base::android::JavaParamRef<jobject>& context, const base::android::JavaParamRef<jobject>& settings_launcher) { - password_manager::SavedPasswordsPresenter::SavedPasswordsView forms = - insecure_credentials_manager_.GetSavedPasswordsFor(credential); + std::vector<password_manager::PasswordForm> forms = + saved_passwords_presenter_.GetCorrespondingPasswordForms(credential); if (forms.empty() || credential_edit_bridge_) return; - const PasswordForm form = - insecure_credentials_manager_.GetSavedPasswordsFor(credential)[0]; - bool is_using_account_store = form.IsUsingAccountStore(); + bool is_using_account_store = forms[0].IsUsingAccountStore(); credential_edit_bridge_ = CredentialEditBridge::MaybeCreate( - password_manager::CredentialUIEntry(form), + password_manager::CredentialUIEntry(forms[0]), CredentialEditBridge::IsInsecureCredential(true), GetUsernamesForRealm(saved_passwords_presenter_.GetSavedCredentials(), credential.signon_realm, is_using_account_store), @@ -160,8 +158,8 @@ } void PasswordCheckManager::RemoveCredential( - const password_manager::CredentialView& credential) { - insecure_credentials_manager_.RemoveCredential(credential); + const password_manager::CredentialUIEntry& credential) { + saved_passwords_presenter_.RemoveCredential(credential); } PasswordCheckManager::PasswordCheckProgress::PasswordCheckProgress() = default;
diff --git a/chrome/browser/password_check/android/password_check_manager.h b/chrome/browser/password_check/android/password_check_manager.h index 8ba7feb..3ee3b69 100644 --- a/chrome/browser/password_check/android/password_check_manager.h +++ b/chrome/browser/password_check/android/password_check_manager.h
@@ -86,18 +86,18 @@ // Called by java to update the given compromised `credential` and set its // password to `new_password`. - void UpdateCredential(const password_manager::CredentialView& credential, + void UpdateCredential(const password_manager::CredentialUIEntry& credential, base::StringPiece new_password); // Called by java to launch the edit credential UI for `credential`. void OnEditCredential( - const password_manager::CredentialView& credential, + const password_manager::CredentialUIEntry& credential, const base::android::JavaParamRef<jobject>& context, const base::android::JavaParamRef<jobject>& settings_launcher); // Called by java to remove the given compromised `credential` and trigger a // UI update on completion. - void RemoveCredential(const password_manager::CredentialView& credential); + void RemoveCredential(const password_manager::CredentialUIEntry& credential); // Invokes `PasswordScriptsFetcher`'s scripts refreshment. void RefreshScripts();
diff --git a/chrome/browser/password_check/android/password_check_manager_unittest.cc b/chrome/browser/password_check/android/password_check_manager_unittest.cc index f71c776..d9464c8 100644 --- a/chrome/browser/password_check/android/password_check_manager_unittest.cc +++ b/chrome/browser/password_check/android/password_check_manager_unittest.cc
@@ -43,8 +43,6 @@ #include "third_party/abseil-cpp/absl/types/optional.h" using password_manager::BulkLeakCheckService; -using password_manager::InsecureCredential; -using password_manager::InsecureCredentialTypeFlags; using password_manager::InsecureType; using password_manager::MockPasswordScriptsFetcher; using password_manager::PasswordCheckUIStatus; @@ -80,26 +78,10 @@ constexpr char kTestEmail[] = "user@gmail.com"; -InsecureCredentialTypeFlags InsecureTypeFlagFromInsecureType( - InsecureType type) { - switch (type) { - case InsecureType::kLeaked: - return InsecureCredentialTypeFlags::kCredentialLeaked; - case InsecureType::kPhished: - return InsecureCredentialTypeFlags::kCredentialPhished; - case InsecureType::kWeak: - return InsecureCredentialTypeFlags::kWeakCredential; - case InsecureType::kReused: - return InsecureCredentialTypeFlags::kReusedCredential; - } - NOTREACHED() << "Unexpected InsecureType value"; -} - -MATCHER_P(MatchInsecureTypeFlag, - insecure_type_flag, +MATCHER_P(MatchInsecureType, + insecure_type, base::StrCat({negation ? "does not " : "", "match the type flag"})) { - return ((insecure_type_flag & InsecureTypeFlagFromInsecureType(arg)) != - InsecureCredentialTypeFlags::kSecure); + return arg.contains(insecure_type); } class MockPasswordCheckManagerObserver : public PasswordCheckManager::Observer { @@ -189,7 +171,7 @@ const GURL& url, const absl::optional<std::string>& package_name, const absl::optional<std::string>& change_password_url, - InsecureCredentialTypeFlags insecure_type, + InsecureType insecure_type, bool has_startable_script, bool has_auto_change_button) { auto package_name_field_matcher = @@ -208,12 +190,11 @@ Field(&CompromisedCredentialForUI::url, url), package_name_field_matcher, change_password_url_field_matcher, Field(&CompromisedCredentialForUI::password_issues, - Each(Key(MatchInsecureTypeFlag(insecure_type)))), + MatchInsecureType(insecure_type)), Property(&CompromisedCredentialForUI::IsLeaked, - insecure_type == InsecureCredentialTypeFlags::kCredentialLeaked), - Property( - &CompromisedCredentialForUI::IsPhished, - insecure_type == InsecureCredentialTypeFlags::kCredentialPhished), + insecure_type == InsecureType::kLeaked), + Property(&CompromisedCredentialForUI::IsPhished, + insecure_type == InsecureType::kPhished), Field(&CompromisedCredentialForUI::has_startable_script, has_startable_script), Field(&CompromisedCredentialForUI::has_auto_change_button, @@ -365,7 +346,7 @@ ElementsAre(ExpectCompromisedCredentialForUI( kUsername1, u"example.com", GURL(kExampleCom), absl::nullopt, "https://example.com/.well-known/change-password", - InsecureCredentialTypeFlags::kCredentialLeaked, + InsecureType::kLeaked, /*has_startable_script=*/false, /*has_auto_change_button=*/false))); } @@ -396,20 +377,18 @@ store().AddLogin(MakeSavedAndroidPassword(kExampleOrg, kUsername2)); EXPECT_THAT(manager().GetCompromisedCredentialsCount(), 2); - EXPECT_THAT( - manager().GetCompromisedCredentials(), - UnorderedElementsAre( - ExpectCompromisedCredentialForUI( - kUsername1, u"App (com.example.app)", GURL::EmptyGURL(), - "com.example.app", absl::nullopt, - InsecureCredentialTypeFlags::kCredentialLeaked, - /*has_startable_script=*/false, - /*has_auto_change_button=*/false), - ExpectCompromisedCredentialForUI( - kUsername2, u"Example App", GURL(kExampleCom), "com.example.app", - absl::nullopt, InsecureCredentialTypeFlags::kCredentialLeaked, - /*has_startable_script=*/false, - /*has_auto_change_button=*/false))); + EXPECT_THAT(manager().GetCompromisedCredentials(), + UnorderedElementsAre( + ExpectCompromisedCredentialForUI( + kUsername1, u"App (com.example.app)", GURL::EmptyGURL(), + "com.example.app", absl::nullopt, InsecureType::kLeaked, + /*has_startable_script=*/false, + /*has_auto_change_button=*/false), + ExpectCompromisedCredentialForUI( + kUsername2, u"Example App", GURL(kExampleCom), + "com.example.app", absl::nullopt, InsecureType::kLeaked, + /*has_startable_script=*/false, + /*has_auto_change_button=*/false))); } TEST_F(PasswordCheckManagerTest, SetsTimestampOnSuccessfulCheck) { @@ -466,7 +445,7 @@ ElementsAre(ExpectCompromisedCredentialForUI( kUsername1, u"example.com", GURL(kExampleCom), absl::nullopt, "https://example.com/.well-known/change-password", - InsecureCredentialTypeFlags::kCredentialLeaked, + InsecureType::kLeaked, /*has_startable_script=*/false, /*has_auto_change_button=*/false))); } @@ -497,7 +476,7 @@ ElementsAre(ExpectCompromisedCredentialForUI( kUsername1, u"example.com", GURL(kExampleCom), absl::nullopt, "https://example.com/.well-known/change-password", - InsecureCredentialTypeFlags::kCredentialLeaked, + InsecureType::kLeaked, /*has_startable_script=*/true, /*has_auto_change_button=*/true))); } @@ -532,7 +511,7 @@ ElementsAre(ExpectCompromisedCredentialForUI( u"No username", u"example.com", GURL(kExampleCom), absl::nullopt, "https://example.com/.well-known/change-password", - InsecureCredentialTypeFlags::kCredentialLeaked, + InsecureType::kLeaked, /*has_startable_script=*/false, /*has_auto_change_button=*/false))); } @@ -567,7 +546,7 @@ ElementsAre(ExpectCompromisedCredentialForUI( kUsername1, u"example.com", GURL(kExampleCom), absl::nullopt, "https://example.com/.well-known/change-password", - InsecureCredentialTypeFlags::kCredentialLeaked, + InsecureType::kLeaked, /*has_startable_script=*/true, /*has_auto_change_button=*/false))); } @@ -600,7 +579,7 @@ ElementsAre(ExpectCompromisedCredentialForUI( kUsername1, u"example.com", GURL(kExampleCom), absl::nullopt, "https://example.com/.well-known/change-password", - InsecureCredentialTypeFlags::kCredentialLeaked, + InsecureType::kLeaked, /*has_startable_script=*/false, /*has_auto_change_button=*/false))); }
diff --git a/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/PasswordManagerAndroidBackendUtil.java b/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/PasswordManagerAndroidBackendUtil.java index 8b537cd..e1144cf 100644 --- a/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/PasswordManagerAndroidBackendUtil.java +++ b/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/PasswordManagerAndroidBackendUtil.java
@@ -7,6 +7,9 @@ import android.app.PendingIntent; +import androidx.annotation.Nullable; + +import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.api.ApiException; import com.google.android.gms.common.api.ResolvableApiException; @@ -50,6 +53,17 @@ return 0; // '0' means SUCCESS. } + @Nullable + static Integer getConnectionResultCode(Exception exception) { + if (!(exception instanceof ApiException)) return null; + + ConnectionResult connectionResult = + ((ApiException) exception).getStatus().getConnectionResult(); + if (connectionResult == null) return null; + + return connectionResult.getErrorCode(); + } + static void handleResolvableApiException(ResolvableApiException exception) { if (!usesUnifiedPasswordManagerUI()) return;
diff --git a/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/PasswordStoreAndroidBackendBridgeImpl.java b/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/PasswordStoreAndroidBackendBridgeImpl.java index e2586c35..367f32d 100644 --- a/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/PasswordStoreAndroidBackendBridgeImpl.java +++ b/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/PasswordStoreAndroidBackendBridgeImpl.java
@@ -122,9 +122,12 @@ @AndroidBackendErrorType int error = PasswordManagerAndroidBackendUtil.getBackendError(exception); int apiErrorCode = PasswordManagerAndroidBackendUtil.getApiErrorCode(exception); + Integer connectionResultCode = + PasswordManagerAndroidBackendUtil.getConnectionResultCode(exception); - PasswordStoreAndroidBackendBridgeImplJni.get().onError( - mNativeBackendBridge, jobId, error, apiErrorCode); + PasswordStoreAndroidBackendBridgeImplJni.get().onError(mNativeBackendBridge, jobId, error, + apiErrorCode, connectionResultCode != null, + connectionResultCode == null ? -1 : connectionResultCode.intValue()); } private Optional<Account> getAccount(String syncingAccount) { @@ -169,6 +172,7 @@ @JobId int jobId, byte[] passwords); void onLoginChanged(long nativePasswordStoreAndroidBackendBridgeImpl, @JobId int jobId); void onError(long nativePasswordStoreAndroidBackendBridgeImpl, @JobId int jobId, - int errorType, int apiErrorCode); + int errorType, int apiErrorCode, boolean hasConnectionResult, + int connectionResultStatusCode); } }
diff --git a/chrome/browser/password_manager/android/junit/src/org/chromium/chrome/browser/password_manager/PasswordManagerAndroidBackendUtilTest.java b/chrome/browser/password_manager/android/junit/src/org/chromium/chrome/browser/password_manager/PasswordManagerAndroidBackendUtilTest.java index 5de634dc..350eddf 100644 --- a/chrome/browser/password_manager/android/junit/src/org/chromium/chrome/browser/password_manager/PasswordManagerAndroidBackendUtilTest.java +++ b/chrome/browser/password_manager/android/junit/src/org/chromium/chrome/browser/password_manager/PasswordManagerAndroidBackendUtilTest.java
@@ -11,6 +11,7 @@ import android.app.PendingIntent; import android.app.PendingIntent.CanceledException; +import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.api.ApiException; import com.google.android.gms.common.api.CommonStatusCodes; import com.google.android.gms.common.api.ResolvableApiException; @@ -58,6 +59,26 @@ PasswordManagerAndroidBackendUtil.getBackendError(apiException)); Assert.assertEquals(CommonStatusCodes.ERROR, PasswordManagerAndroidBackendUtil.getApiErrorCode(apiException)); + Assert.assertNull(PasswordManagerAndroidBackendUtil.getConnectionResultCode(apiException)); + } + + @Test + public void testUtilsForApiExceptionWithConnectionResult() { + ApiException apiException = new ApiException( + new Status(new ConnectionResult(ConnectionResult.API_UNAVAILABLE), "")); + Assert.assertEquals(AndroidBackendErrorType.EXTERNAL_ERROR, + PasswordManagerAndroidBackendUtil.getBackendError(apiException)); + Assert.assertEquals(CommonStatusCodes.API_NOT_CONNECTED, + PasswordManagerAndroidBackendUtil.getApiErrorCode(apiException)); + Assert.assertEquals(ConnectionResult.API_UNAVAILABLE, + PasswordManagerAndroidBackendUtil.getConnectionResultCode(apiException).intValue()); + } + + @Test + public void testUtilsReturnNullConnectionResultForNonApiException() { + BackendException exception = new BackendException( + "Cannot call API without context.", AndroidBackendErrorType.NO_CONTEXT); + Assert.assertNull(PasswordManagerAndroidBackendUtil.getConnectionResultCode(exception)); } @Test
diff --git a/chrome/browser/password_manager/android/junit/src/org/chromium/chrome/browser/password_manager/PasswordStoreAndroidBackendBridgeTest.java b/chrome/browser/password_manager/android/junit/src/org/chromium/chrome/browser/password_manager/PasswordStoreAndroidBackendBridgeTest.java index dc1a55ae..f2c55ec 100644 --- a/chrome/browser/password_manager/android/junit/src/org/chromium/chrome/browser/password_manager/PasswordStoreAndroidBackendBridgeTest.java +++ b/chrome/browser/password_manager/android/junit/src/org/chromium/chrome/browser/password_manager/PasswordStoreAndroidBackendBridgeTest.java
@@ -14,6 +14,7 @@ import android.accounts.Account; import android.app.PendingIntent; +import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.api.ApiException; import com.google.android.gms.common.api.CommonStatusCodes; import com.google.android.gms.common.api.ResolvableApiException; @@ -118,8 +119,8 @@ Exception kExpectedException = new Exception("Sample failure"); failureCallback.getValue().onResult(kExpectedException); verify(mBridgeJniMock) - .onError( - sDummyNativePointer, kTestTaskId, AndroidBackendErrorType.UNCATEGORIZED, 0); + .onError(sDummyNativePointer, kTestTaskId, AndroidBackendErrorType.UNCATEGORIZED, 0, + false, -1); } @Test @@ -137,7 +138,8 @@ "Sample failure", AndroidBackendErrorType.NO_ACCOUNT); failureCallback.getValue().onResult(kExpectedException); verify(mBridgeJniMock) - .onError(sDummyNativePointer, kTestTaskId, AndroidBackendErrorType.NO_ACCOUNT, 0); + .onError(sDummyNativePointer, kTestTaskId, AndroidBackendErrorType.NO_ACCOUNT, 0, + false, -1); } @Test @@ -151,11 +153,13 @@ verify(mBackendMock).getAllLogins(eq(Optional.absent()), any(), failureCallback.capture()); assertNotNull(failureCallback.getValue()); - Exception kExpectedException = new ApiException(new Status(CommonStatusCodes.ERROR, "")); + Exception kExpectedException = new ApiException( + new Status(new ConnectionResult(ConnectionResult.API_UNAVAILABLE), "")); failureCallback.getValue().onResult(kExpectedException); verify(mBridgeJniMock) .onError(sDummyNativePointer, kTestTaskId, AndroidBackendErrorType.EXTERNAL_ERROR, - CommonStatusCodes.ERROR); + CommonStatusCodes.API_NOT_CONNECTED, true, + ConnectionResult.API_UNAVAILABLE); } @Test @@ -176,7 +180,7 @@ verify(pendingIntentMock, never()).send(); verify(mBridgeJniMock) .onError(sDummyNativePointer, kTestTaskId, AndroidBackendErrorType.EXTERNAL_ERROR, - CommonStatusCodes.RESOLUTION_REQUIRED); + CommonStatusCodes.RESOLUTION_REQUIRED, false, -1); } @Test @@ -211,8 +215,8 @@ Exception kExpectedException = new Exception("Sample failure"); failureCallback.getValue().onResult(kExpectedException); verify(mBridgeJniMock) - .onError( - sDummyNativePointer, kTestTaskId, AndroidBackendErrorType.UNCATEGORIZED, 0); + .onError(sDummyNativePointer, kTestTaskId, AndroidBackendErrorType.UNCATEGORIZED, 0, + false, -1); } @Test @@ -249,8 +253,8 @@ Exception kExpectedException = new Exception("Sample failure"); failureCallback.getValue().onResult(kExpectedException); verify(mBridgeJniMock) - .onError( - sDummyNativePointer, kTestTaskId, AndroidBackendErrorType.UNCATEGORIZED, 0); + .onError(sDummyNativePointer, kTestTaskId, AndroidBackendErrorType.UNCATEGORIZED, 0, + false, -1); } @Test @@ -284,8 +288,8 @@ Exception kExpectedException = new Exception("Sample failure"); failureCallback.getValue().onResult(kExpectedException); verify(mBridgeJniMock) - .onError( - sDummyNativePointer, kTestTaskId, AndroidBackendErrorType.UNCATEGORIZED, 0); + .onError(sDummyNativePointer, kTestTaskId, AndroidBackendErrorType.UNCATEGORIZED, 0, + false, -1); } @Test @@ -319,8 +323,8 @@ Exception kExpectedException = new Exception("Sample failure"); failureCallback.getValue().onResult(kExpectedException); verify(mBridgeJniMock) - .onError( - sDummyNativePointer, kTestTaskId, AndroidBackendErrorType.UNCATEGORIZED, 0); + .onError(sDummyNativePointer, kTestTaskId, AndroidBackendErrorType.UNCATEGORIZED, 0, + false, -1); } @Test @@ -354,7 +358,7 @@ Exception kExpectedException = new Exception("Sample failure"); failureCallback.getValue().onResult(kExpectedException); verify(mBridgeJniMock) - .onError( - sDummyNativePointer, kTestTaskId, AndroidBackendErrorType.UNCATEGORIZED, 0); + .onError(sDummyNativePointer, kTestTaskId, AndroidBackendErrorType.UNCATEGORIZED, 0, + false, -1); } }
diff --git a/chrome/browser/password_manager/android/password_store_android_backend_bridge_impl.cc b/chrome/browser/password_manager/android/password_store_android_backend_bridge_impl.cc index 5aa0f34..c7149fa5 100644 --- a/chrome/browser/password_manager/android/password_store_android_backend_bridge_impl.cc +++ b/chrome/browser/password_manager/android/password_store_android_backend_bridge_impl.cc
@@ -96,10 +96,13 @@ consumer_->OnCompleteWithLogins(JobId(job_id), CreateFormsVector(passwords)); } -void PasswordStoreAndroidBackendBridgeImpl::OnError(JNIEnv* env, - jint job_id, - jint error_type, - jint api_error_code) { +void PasswordStoreAndroidBackendBridgeImpl::OnError( + JNIEnv* env, + jint job_id, + jint error_type, + jint api_error_code, + jboolean has_connection_result, + jint connection_result_code) { DCHECK(consumer_); // Posting the tasks to the same sequence prevents that synchronous responses // try to finish tasks before their registration was completed. @@ -110,6 +113,10 @@ error.api_error_code = static_cast<int>(api_error_code); } + if (has_connection_result) { + error.connection_result_code = static_cast<int>(connection_result_code); + } + base::SequencedTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::BindOnce(&PasswordStoreAndroidBackendBridge::Consumer::OnError,
diff --git a/chrome/browser/password_manager/android/password_store_android_backend_bridge_impl.h b/chrome/browser/password_manager/android/password_store_android_backend_bridge_impl.h index 35b2261e..118bcaaa 100644 --- a/chrome/browser/password_manager/android/password_store_android_backend_bridge_impl.h +++ b/chrome/browser/password_manager/android/password_store_android_backend_bridge_impl.h
@@ -40,7 +40,12 @@ // Called via JNI. Called when the api call with `job_id` finished with // an exception. - void OnError(JNIEnv* env, jint job_id, jint error_type, jint api_error_code); + void OnError(JNIEnv* env, + jint job_id, + jint error_type, + jint api_error_code, + jboolean has_connection_result, + jint connection_result_code); private: // Implements PasswordStoreAndroidBackendBridge interface.
diff --git a/chrome/browser/password_manager/android/password_store_bridge.cc b/chrome/browser/password_manager/android/password_store_bridge.cc index d4914d8b..465ca06 100644 --- a/chrome/browser/password_manager/android/password_store_bridge.cc +++ b/chrome/browser/password_manager/android/password_store_bridge.cc
@@ -63,9 +63,13 @@ JNIEnv* env, const base::android::JavaParamRef<jobject>& credential, const base::android::JavaParamRef<jstring>& new_password) { - return saved_passwords_presenter_.EditPassword( - ConvertJavaObjectToPasswordForm(env, credential), - ConvertJavaStringToUTF16(env, new_password)); + password_manager::CredentialUIEntry original_credential( + ConvertJavaObjectToPasswordForm(env, credential)); + password_manager::CredentialUIEntry updated_credential = original_credential; + updated_credential.password = ConvertJavaStringToUTF16(env, new_password); + return saved_passwords_presenter_.EditSavedCredentials(original_credential, + updated_credential) == + password_manager::SavedPasswordsPresenter::EditResult::kSuccess; } jint PasswordStoreBridge::GetPasswordStoreCredentialsCount(JNIEnv* env) const {
diff --git a/chrome/browser/profile_resetter/profile_resetter_unittest.cc b/chrome/browser/profile_resetter/profile_resetter_unittest.cc index e5e53ba..bfdf05c3 100644 --- a/chrome/browser/profile_resetter/profile_resetter_unittest.cc +++ b/chrome/browser/profile_resetter/profile_resetter_unittest.cc
@@ -941,7 +941,7 @@ MOCK_METHOD0(OnUpdatedList, void(void)); - std::unique_ptr<base::ListValue> list_; + base::Value::List list_; }; // Make sure GetReadableFeedback handles non-ascii letters. @@ -980,12 +980,11 @@ ::testing::Mock::VerifyAndClearExpectations(&capture); // The homepage and the startup page are in punycode. They are unreadable. // Trying to find the extension name. - std::unique_ptr<base::ListValue> list = std::move(capture.list_); - ASSERT_TRUE(list); + base::Value::List list = std::move(capture.list_); bool checked_extensions = false; bool checked_shortcuts = false; - for (size_t i = 0; i < list->GetListDeprecated().size(); ++i) { - const base::Value& dict = list->GetListDeprecated()[i]; + for (size_t i = 0; i < list.size(); ++i) { + const base::Value& dict = list[i]; ASSERT_TRUE(dict.is_dict()); const std::string* value = dict.FindStringKey("key"); ASSERT_TRUE(value);
diff --git a/chrome/browser/profile_resetter/resettable_settings_snapshot.cc b/chrome/browser/profile_resetter/resettable_settings_snapshot.cc index 77489de..f0aaa61 100644 --- a/chrome/browser/profile_resetter/resettable_settings_snapshot.cc +++ b/chrome/browser/profile_resetter/resettable_settings_snapshot.cc
@@ -41,13 +41,13 @@ namespace { template <class StringType> -void AddPair(base::ListValue* list, +void AddPair(base::Value::List& list, const std::u16string& key, const StringType& value) { base::Value::Dict results; results.Set("key", key); results.Set("value", value); - list->GetList().Append(std::move(results)); + list.Append(std::move(results)); } } // namespace @@ -233,20 +233,20 @@ ->DispatchReport(report); } -std::unique_ptr<base::ListValue> GetReadableFeedbackForSnapshot( +base::Value::List GetReadableFeedbackForSnapshot( Profile* profile, const ResettableSettingsSnapshot& snapshot) { DCHECK(profile); DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - std::unique_ptr<base::ListValue> list(new base::ListValue); - AddPair(list.get(), + base::Value::List list; + AddPair(list, l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_LOCALE), g_browser_process->GetApplicationLocale()); - AddPair(list.get(), l10n_util::GetStringUTF16(IDS_VERSION_UI_USER_AGENT), + AddPair(list, l10n_util::GetStringUTF16(IDS_VERSION_UI_USER_AGENT), embedder_support::GetUserAgent()); std::string version = version_info::GetVersionNumber(); version += chrome::GetChannelName(chrome::WithExtendedStable(true)); - AddPair(list.get(), + AddPair(list, l10n_util::GetStringUTF16(IDS_PRODUCT_NAME), version); @@ -259,7 +259,7 @@ startup_urls += i->host(); } if (!startup_urls.empty()) { - AddPair(list.get(), + AddPair(list, l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_STARTUP_URLS), startup_urls); } @@ -285,12 +285,12 @@ default: break; } - AddPair(list.get(), + AddPair(list, l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_STARTUP_TYPE), startup_type); if (!snapshot.homepage().empty()) { - AddPair(list.get(), + AddPair(list, l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_HOMEPAGE), snapshot.homepage()); } @@ -298,7 +298,7 @@ int is_ntp_message_id = snapshot.homepage_is_ntp() ? IDS_RESET_PROFILE_SETTINGS_YES : IDS_RESET_PROFILE_SETTINGS_NO; - AddPair(list.get(), + AddPair(list, l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_HOMEPAGE_IS_NTP), l10n_util::GetStringUTF16(is_ntp_message_id)); @@ -306,7 +306,7 @@ ? IDS_RESET_PROFILE_SETTINGS_YES : IDS_RESET_PROFILE_SETTINGS_NO; AddPair( - list.get(), + list, l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_SHOW_HOME_BUTTON), l10n_util::GetStringUTF16(show_home_button_id)); @@ -315,7 +315,7 @@ DCHECK(service); const TemplateURL* dse = service->GetDefaultSearchProvider(); if (dse) { - AddPair(list.get(), + AddPair(list, l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_DSE), dse->GenerateSearchURL(service->search_terms_data()).host()); } @@ -330,12 +330,12 @@ shortcut_targets += base::WideToUTF16(i->second); } if (!shortcut_targets.empty()) { - AddPair(list.get(), + AddPair(list, l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_SHORTCUTS), shortcut_targets); } } else { - AddPair(list.get(), + AddPair(list, l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_SHORTCUTS), l10n_util::GetStringUTF16( IDS_RESET_PROFILE_SETTINGS_PROCESSING_SHORTCUTS)); @@ -350,7 +350,7 @@ extension_names += i->second; } if (!extension_names.empty()) { - AddPair(list.get(), + AddPair(list, l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_EXTENSIONS), extension_names); }
diff --git a/chrome/browser/profile_resetter/resettable_settings_snapshot.h b/chrome/browser/profile_resetter/resettable_settings_snapshot.h index 2b715ba..b6f0fe4b 100644 --- a/chrome/browser/profile_resetter/resettable_settings_snapshot.h +++ b/chrome/browser/profile_resetter/resettable_settings_snapshot.h
@@ -137,7 +137,7 @@ // Returns list of key/value pairs for all available reported information // from the |profile| and some additional fields. -std::unique_ptr<base::ListValue> GetReadableFeedbackForSnapshot( +base::Value::List GetReadableFeedbackForSnapshot( Profile* profile, const ResettableSettingsSnapshot& snapshot);
diff --git a/chrome/browser/resources/BUILD.gn b/chrome/browser/resources/BUILD.gn index abaa1be..cda4bcc 100644 --- a/chrome/browser/resources/BUILD.gn +++ b/chrome/browser/resources/BUILD.gn
@@ -31,7 +31,7 @@ "commander:resources", "downloads:resources", "feed:resources", - "feedback_webui:resources", + "feedback:resources", "gaia_auth_host:resources", "history:resources", "image_editor:trusted_resources",
diff --git a/chrome/browser/resources/chromeos/login/oobe_auto_imports.gni b/chrome/browser/resources/chromeos/login/oobe_auto_imports.gni index c62e3e54..c5e4016 100644 --- a/chrome/browser/resources/chromeos/login/oobe_auto_imports.gni +++ b/chrome/browser/resources/chromeos/login/oobe_auto_imports.gni
@@ -91,5 +91,8 @@ "cr.login.Authenticator|Authenticator", ] -oobe_migrated_imports = - [ "ui/webui/resources/cr_elements/cr_lazy_render/cr_lazy_render.html" ] +oobe_migrated_imports = [ + "ui/webui/resources/cr_elements/cr_lazy_render/cr_lazy_render.html", + "ui/webui/resources/cr_elements/cr_fingerprint/cr_fingerprint_progress_arc.html", + "ui/webui/resources/cr_elements/cr_fingerprint/cr_fingerprint_icon.html", +]
diff --git a/chrome/browser/resources/chromeos/login/screens/common/BUILD.gn b/chrome/browser/resources/chromeos/login/screens/common/BUILD.gn index e0cebfd7..9aab714 100644 --- a/chrome/browser/resources/chromeos/login/screens/common/BUILD.gn +++ b/chrome/browser/resources/chromeos/login/screens/common/BUILD.gn
@@ -261,7 +261,7 @@ "../../components/buttons:oobe_text_button.m", "../../components/dialogs:oobe_adaptive_dialog.m", "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", - "//ui/webui/resources/cr_elements/cr_fingerprint:cr_fingerprint_progress_arc.m", + "//ui/webui/resources/cr_elements/cr_fingerprint:cr_fingerprint_progress_arc", "//ui/webui/resources/js:load_time_data.m", ] extra_deps = [ ":fingerprint_setup_module" ] @@ -746,6 +746,7 @@ html_file = "fingerprint_setup.html" html_type = "dom-module" auto_imports = oobe_auto_imports + migrated_imports = oobe_migrated_imports namespace_rewrites = oobe_namespace_rewrites }
diff --git a/chrome/browser/resources/feedback_webui/BUILD.gn b/chrome/browser/resources/feedback/BUILD.gn similarity index 97% rename from chrome/browser/resources/feedback_webui/BUILD.gn rename to chrome/browser/resources/feedback/BUILD.gn index 88f8a8f..201c354 100644 --- a/chrome/browser/resources/feedback_webui/BUILD.gn +++ b/chrome/browser/resources/feedback/BUILD.gn
@@ -9,7 +9,7 @@ assert(!is_android) build_webui("build") { - grd_prefix = "feedback_webui" + grd_prefix = "feedback" static_files = [ "css/common.css",
diff --git a/chrome/browser/resources/feedback_webui/DIR_METADATA b/chrome/browser/resources/feedback/DIR_METADATA similarity index 100% rename from chrome/browser/resources/feedback_webui/DIR_METADATA rename to chrome/browser/resources/feedback/DIR_METADATA
diff --git a/chrome/browser/resources/feedback_webui/OWNERS b/chrome/browser/resources/feedback/OWNERS similarity index 100% rename from chrome/browser/resources/feedback_webui/OWNERS rename to chrome/browser/resources/feedback/OWNERS
diff --git a/chrome/browser/resources/feedback_webui/css/assistant_logs_info.css b/chrome/browser/resources/feedback/css/assistant_logs_info.css similarity index 100% rename from chrome/browser/resources/feedback_webui/css/assistant_logs_info.css rename to chrome/browser/resources/feedback/css/assistant_logs_info.css
diff --git a/chrome/browser/resources/feedback_webui/css/common.css b/chrome/browser/resources/feedback/css/common.css similarity index 100% rename from chrome/browser/resources/feedback_webui/css/common.css rename to chrome/browser/resources/feedback/css/common.css
diff --git a/chrome/browser/resources/feedback_webui/css/feedback.css b/chrome/browser/resources/feedback/css/feedback.css similarity index 100% rename from chrome/browser/resources/feedback_webui/css/feedback.css rename to chrome/browser/resources/feedback/css/feedback.css
diff --git a/chrome/browser/resources/feedback_webui/css/feedback_shared_styles.css b/chrome/browser/resources/feedback/css/feedback_shared_styles.css similarity index 100% rename from chrome/browser/resources/feedback_webui/css/feedback_shared_styles.css rename to chrome/browser/resources/feedback/css/feedback_shared_styles.css
diff --git a/chrome/browser/resources/feedback_webui/css/feedback_shared_vars.css b/chrome/browser/resources/feedback/css/feedback_shared_vars.css similarity index 100% rename from chrome/browser/resources/feedback_webui/css/feedback_shared_vars.css rename to chrome/browser/resources/feedback/css/feedback_shared_vars.css
diff --git a/chrome/browser/resources/feedback_webui/css/sys_info.css b/chrome/browser/resources/feedback/css/sys_info.css similarity index 100% rename from chrome/browser/resources/feedback_webui/css/sys_info.css rename to chrome/browser/resources/feedback/css/sys_info.css
diff --git a/chrome/browser/resources/feedback_webui/html/assistant_logs_info.html b/chrome/browser/resources/feedback/html/assistant_logs_info.html similarity index 100% rename from chrome/browser/resources/feedback_webui/html/assistant_logs_info.html rename to chrome/browser/resources/feedback/html/assistant_logs_info.html
diff --git a/chrome/browser/resources/feedback_webui/html/bluetooth_logs_info.html b/chrome/browser/resources/feedback/html/bluetooth_logs_info.html similarity index 100% rename from chrome/browser/resources/feedback_webui/html/bluetooth_logs_info.html rename to chrome/browser/resources/feedback/html/bluetooth_logs_info.html
diff --git a/chrome/browser/resources/feedback_webui/html/default.html b/chrome/browser/resources/feedback/html/default.html similarity index 100% rename from chrome/browser/resources/feedback_webui/html/default.html rename to chrome/browser/resources/feedback/html/default.html
diff --git a/chrome/browser/resources/feedback_webui/html/sys_info.html b/chrome/browser/resources/feedback/html/sys_info.html similarity index 100% rename from chrome/browser/resources/feedback_webui/html/sys_info.html rename to chrome/browser/resources/feedback/html/sys_info.html
diff --git a/chrome/browser/resources/feedback_webui/images/2x/button_butter_bar_close.png b/chrome/browser/resources/feedback/images/2x/button_butter_bar_close.png similarity index 100% rename from chrome/browser/resources/feedback_webui/images/2x/button_butter_bar_close.png rename to chrome/browser/resources/feedback/images/2x/button_butter_bar_close.png Binary files differ
diff --git a/chrome/browser/resources/feedback_webui/images/2x/button_butter_bar_close_hover.png b/chrome/browser/resources/feedback/images/2x/button_butter_bar_close_hover.png similarity index 100% rename from chrome/browser/resources/feedback_webui/images/2x/button_butter_bar_close_hover.png rename to chrome/browser/resources/feedback/images/2x/button_butter_bar_close_hover.png Binary files differ
diff --git a/chrome/browser/resources/feedback_webui/images/2x/button_butter_bar_close_pressed.png b/chrome/browser/resources/feedback/images/2x/button_butter_bar_close_pressed.png similarity index 100% rename from chrome/browser/resources/feedback_webui/images/2x/button_butter_bar_close_pressed.png rename to chrome/browser/resources/feedback/images/2x/button_butter_bar_close_pressed.png Binary files differ
diff --git a/chrome/browser/resources/feedback_webui/images/button_butter_bar_close.png b/chrome/browser/resources/feedback/images/button_butter_bar_close.png similarity index 100% rename from chrome/browser/resources/feedback_webui/images/button_butter_bar_close.png rename to chrome/browser/resources/feedback/images/button_butter_bar_close.png Binary files differ
diff --git a/chrome/browser/resources/feedback_webui/images/button_butter_bar_close_hover.png b/chrome/browser/resources/feedback/images/button_butter_bar_close_hover.png similarity index 100% rename from chrome/browser/resources/feedback_webui/images/button_butter_bar_close_hover.png rename to chrome/browser/resources/feedback/images/button_butter_bar_close_hover.png Binary files differ
diff --git a/chrome/browser/resources/feedback_webui/images/button_butter_bar_close_pressed.png b/chrome/browser/resources/feedback/images/button_butter_bar_close_pressed.png similarity index 100% rename from chrome/browser/resources/feedback_webui/images/button_butter_bar_close_pressed.png rename to chrome/browser/resources/feedback/images/button_butter_bar_close_pressed.png Binary files differ
diff --git a/chrome/browser/resources/feedback_webui/js/feedback.ts b/chrome/browser/resources/feedback/js/feedback.ts similarity index 99% rename from chrome/browser/resources/feedback_webui/js/feedback.ts rename to chrome/browser/resources/feedback/js/feedback.ts index 820a7f64..d0f1653 100644 --- a/chrome/browser/resources/feedback_webui/js/feedback.ts +++ b/chrome/browser/resources/feedback/js/feedback.ts
@@ -6,9 +6,7 @@ import {$} from 'chrome://resources/js/util.m.js'; import {FEEDBACK_LANDING_PAGE, FEEDBACK_LANDING_PAGE_TECHSTOP, FEEDBACK_LEGAL_HELP_URL, FEEDBACK_PRIVACY_POLICY_URL, FEEDBACK_TERM_OF_SERVICE_URL, openUrlInAppWindow} from './feedback_util.js'; -import {domainQuestions} from './questionnaire.js'; -import {questionnaireBegin} from './questionnaire.js'; -import {questionnaireNotification} from './questionnaire.js'; +import {domainQuestions, questionnaireBegin, questionnaireNotification} from './questionnaire.js'; import {takeScreenshot} from './take_screenshot.js'; const formOpenTime: number = new Date().getTime();
diff --git a/chrome/browser/resources/feedback_webui/js/feedback_util.ts b/chrome/browser/resources/feedback/js/feedback_util.ts similarity index 100% rename from chrome/browser/resources/feedback_webui/js/feedback_util.ts rename to chrome/browser/resources/feedback/js/feedback_util.ts
diff --git a/chrome/browser/resources/feedback_webui/js/questionnaire.ts b/chrome/browser/resources/feedback/js/questionnaire.ts similarity index 100% rename from chrome/browser/resources/feedback_webui/js/questionnaire.ts rename to chrome/browser/resources/feedback/js/questionnaire.ts
diff --git a/chrome/browser/resources/feedback_webui/js/sys_info.ts b/chrome/browser/resources/feedback/js/sys_info.ts similarity index 100% rename from chrome/browser/resources/feedback_webui/js/sys_info.ts rename to chrome/browser/resources/feedback/js/sys_info.ts
diff --git a/chrome/browser/resources/feedback_webui/js/take_screenshot.ts b/chrome/browser/resources/feedback/js/take_screenshot.ts similarity index 100% rename from chrome/browser/resources/feedback_webui/js/take_screenshot.ts rename to chrome/browser/resources/feedback/js/take_screenshot.ts
diff --git a/chrome/browser/resources/settings/BUILD.gn b/chrome/browser/resources/settings/BUILD.gn index fa23f4a..de17653 100644 --- a/chrome/browser/resources/settings/BUILD.gn +++ b/chrome/browser/resources/settings/BUILD.gn
@@ -3,85 +3,15 @@ # found in the LICENSE file. import("//build/config/chromeos/ui_mode.gni") +import("//chrome/browser/resources/tools/build_webui.gni") import("//chrome/common/features.gni") import("//crypto/features.gni") import("//third_party/closure_compiler/compile_js.gni") -import("//tools/grit/grit_rule.gni") -import("//tools/grit/preprocess_if_expr.gni") -import("//tools/polymer/css_to_wrapper.gni") -import("//tools/polymer/html_to_wrapper.gni") -import("//tools/typescript/ts_library.gni") -import("//ui/webui/resources/tools/generate_grd.gni") import("//ui/webui/webui_features.gni") -import("../tools/optimize_webui.gni") -import("settings.gni") +import("./settings.gni") assert(!is_android, "Android does not use these settings") -preprocess_folder = "preprocessed" - -if (optimize_webui) { - build_manifest = "build_manifest.json" - - optimize_webui("build") { - host = "settings" - input = rebase_path("$target_gen_dir/tsc", root_build_dir) - js_module_in_files = [ - "settings.js", - "lazy_load.js", - ] - js_out_files = [ - "settings.rollup.js", - "lazy_load.rollup.js", - "shared.rollup.js", - ] - out_manifest = "$target_gen_dir/$build_manifest" - - deps = [ - ":build_ts", - "//ui/webui/resources:preprocess", - ] - - if (!is_chromeos_ash) { - deps += [ "//ui/webui/resources/cr_components/customize_themes:build_ts" ] - } - - if (use_nss_certs) { - deps += - [ "//ui/webui/resources/cr_components/certificate_manager:build_ts" ] - } - - excludes = [ - "chrome://resources/js/cr.m.js", - "chrome://resources/mojo/mojo/public/js/bindings.js", - "chrome://resources/mojo/skia/public/mojom/skcolor.mojom-webui.js", - ] - } -} - -preprocess_if_expr("preprocess") { - defines = chrome_grit_defines - out_folder = "$target_gen_dir/$preprocess_folder" - in_files = ts_files + html_files + icons_html_files + css_files -} - -grit("resources") { - defines = chrome_grit_defines - - # These arguments are needed since the grd is generated at build time. - enable_input_discovery_for_gn_analyze = false - source = "$target_gen_dir/settings_resources.grd" - deps = [ ":build_grd" ] - - outputs = [ - "grit/settings_resources.h", - "grit/settings_resources_map.cc", - "grit/settings_resources_map.h", - "settings_resources.pak", - ] - output_dir = "$root_gen_dir/chrome" -} - if (is_chromeos_ash) { group("closure_compile") { deps = [ @@ -105,75 +35,10 @@ } } -html_to_wrapper("html_wrapper_files") { - deps = [ ":preprocess" ] - in_folder = "$target_gen_dir/$preprocess_folder" - out_folder = "$target_gen_dir/$preprocess_folder" - in_files = html_files + icons_html_files - minify = optimize_webui -} - -css_to_wrapper("css_wrapper_files") { - deps = [ ":preprocess" ] - in_folder = "$target_gen_dir/$preprocess_folder" - out_folder = "$target_gen_dir/$preprocess_folder" - in_files = css_files - minify = optimize_webui -} - -ts_library("build_ts") { - root_dir = "$target_gen_dir/$preprocess_folder" - out_dir = "$target_gen_dir/tsc" - composite = true - tsconfig_base = "tsconfig_base.json" - in_files = ts_files + css_wrapper_files + html_wrapper_files - - deps = [ - "//third_party/polymer/v3_0:library", - "//ui/webui/resources:library", - "//ui/webui/resources/cr_components/customize_themes:build_ts", - ] - - if (use_nss_certs) { - deps += - [ "//ui/webui/resources/cr_components/certificate_manager:build_ts" ] - } - - definitions = [ - "//tools/typescript/definitions/autofill_private.d.ts", - "//tools/typescript/definitions/chrome_send.d.ts", - "//tools/typescript/definitions/language_settings_private.d.ts", - "//tools/typescript/definitions/management.d.ts", - "//tools/typescript/definitions/metrics_private.d.ts", - "//tools/typescript/definitions/passwords_private.d.ts", - "//tools/typescript/definitions/pending.d.ts", - "//tools/typescript/definitions/runtime.d.ts", - "//tools/typescript/definitions/settings_private.d.ts", - ] - if (is_chromeos) { - definitions += - [ "//tools/typescript/definitions/quick_unlock_private.d.ts" ] - } - - extra_deps = [ - ":css_wrapper_files", - ":html_wrapper_files", - ":preprocess", - ] - - if (is_chromeos_ash) { - # TODO(crbug.com/1013466): Browser Settings should not depend on ash/webui/ - # code. The codepath needing this (in people_page.ts) should be removed when - # the SplitSettings effort makes progress (unclear status as of this - # writing, unfortunately). - extra_deps += [ "//ash/webui/common/resources:generate_definitions" ] - } -} - -generate_grd("build_grd") { +build_webui("build") { grd_prefix = "settings" - out_grd = "$target_gen_dir/${grd_prefix}_resources.grd" - input_files = [ + + static_files = [ "images/cookies_banner_dark.svg", "images/cookies_banner.svg", "images/googleg_standard_clr_32px.svg", @@ -238,22 +103,375 @@ "privacy_sandbox/privacy_sandbox.html", "settings.html", ] - input_files_base_dir = rebase_path(".", "//") + + # -----------------web_component_files start --------------------------------- + web_component_files = [ + "a11y_page/a11y_page.ts", + "a11y_page/live_caption_section.ts", + "about_page/about_page.ts", + "appearance_page/appearance_fonts_page.ts", + "appearance_page/appearance_page.ts", + "appearance_page/home_url_input.ts", + "autofill_page/address_edit_dialog.ts", + "autofill_page/address_remove_confirmation_dialog.ts", + "autofill_page/autofill_page.ts", + "autofill_page/autofill_section.ts", + "autofill_page/avatar_icon.ts", + "autofill_page/credit_card_edit_dialog.ts", + "autofill_page/credit_card_list_entry.ts", + "autofill_page/password_check_edit_dialog.ts", + "autofill_page/password_check_edit_disclaimer_dialog.ts", + "autofill_page/password_check_list_item.ts", + "autofill_page/password_check.ts", + "autofill_page/password_edit_dialog.ts", + "autofill_page/password_list_item.ts", + "autofill_page/password_move_multiple_passwords_to_account_dialog.ts", + "autofill_page/password_move_to_account_dialog.ts", + "autofill_page/password_remove_confirmation_dialog.ts", + "autofill_page/password_remove_dialog.ts", + "autofill_page/password_view.ts", + "autofill_page/passwords_device_section.ts", + "autofill_page/passwords_export_dialog.ts", + "autofill_page/passwords_import_dialog.ts", + "autofill_page/passwords_list_handler.ts", + "autofill_page/passwords_section.ts", + "autofill_page/payments_list.ts", + "autofill_page/payments_section.ts", + "autofill_page/upi_id_list_entry.ts", + "autofill_page/virtual_card_unenroll_dialog.ts", + "basic_page/basic_page.ts", + "clear_browsing_data_dialog/clear_browsing_data_dialog.ts", + "clear_browsing_data_dialog/history_deletion_dialog.ts", + "clear_browsing_data_dialog/installed_app_checkbox.ts", + "clear_browsing_data_dialog/passwords_deletion_dialog.ts", + "controls/controlled_button.ts", + "controls/controlled_radio_button.ts", + "controls/extension_controlled_indicator.ts", + "controls/settings_checkbox.ts", + "controls/settings_dropdown_menu.ts", + "controls/settings_radio_group.ts", + "controls/settings_slider.ts", + "controls/settings_textarea.ts", + "controls/settings_toggle_button.ts", + "downloads_page/downloads_page.ts", + "on_startup_page/on_startup_page.ts", + "on_startup_page/startup_url_dialog.ts", + "on_startup_page/startup_url_entry.ts", + "on_startup_page/startup_urls_page.ts", + "people_page/people_page.ts", + "people_page/signout_dialog.ts", + "people_page/sync_account_control.ts", + "people_page/sync_controls.ts", + "people_page/sync_encryption_options.ts", + "people_page/sync_page.ts", + "privacy_page/collapse_radio_button.ts", + "privacy_page/cookies_page.ts", + "privacy_page/disable_safebrowsing_dialog.ts", + "privacy_page/do_not_track_toggle.ts", + "privacy_page/personalization_options.ts", + "privacy_page/privacy_guide_promo.ts", + "privacy_page/privacy_guide/privacy_guide_clear_on_exit_fragment.ts", + "privacy_page/privacy_guide/privacy_guide_completion_fragment.ts", + "privacy_page/privacy_guide/privacy_guide_completion_link_row.ts", + "privacy_page/privacy_guide/privacy_guide_cookies_fragment.ts", + "privacy_page/privacy_guide/privacy_guide_description_item.ts", + "privacy_page/privacy_guide/privacy_guide_dialog.ts", + "privacy_page/privacy_guide/privacy_guide_history_sync_fragment.ts", + "privacy_page/privacy_guide/privacy_guide_msbb_fragment.ts", + "privacy_page/privacy_guide/privacy_guide_page.ts", + "privacy_page/privacy_guide/privacy_guide_safe_browsing_fragment.ts", + "privacy_page/privacy_guide/privacy_guide_welcome_fragment.ts", + "privacy_page/privacy_guide/step_indicator.ts", + "privacy_page/privacy_page.ts", + "privacy_page/secure_dns.ts", + "privacy_page/secure_dns_input.ts", + "privacy_page/security_keys_bio_enroll_dialog.ts", + "privacy_page/security_keys_credential_management_dialog.ts", + "privacy_page/security_keys_pin_field.ts", + "privacy_page/security_keys_reset_dialog.ts", + "privacy_page/security_keys_set_pin_dialog.ts", + "privacy_page/security_keys_subpage.ts", + "privacy_page/security_keys_phones_subpage.ts", + "privacy_page/security_keys_phones_list.ts", + "privacy_page/security_keys_phones_dialog.ts", + "privacy_page/security_page.ts", + "privacy_sandbox/app.ts", + "privacy_sandbox/interest_item.ts", + "reset_page/reset_page.ts", + "reset_page/reset_profile_banner.ts", + "reset_page/reset_profile_dialog.ts", + "safety_check_page/safety_check_child.ts", + "safety_check_page/safety_check_extensions_child.ts", + "safety_check_page/safety_check_page.ts", + "safety_check_page/safety_check_passwords_child.ts", + "safety_check_page/safety_check_safe_browsing_child.ts", + "safety_check_page/safety_check_updates_child.ts", + "search_engines_page/omnibox_extension_entry.ts", + "search_engines_page/search_engine_delete_confirmation_dialog.ts", + "search_engines_page/search_engine_edit_dialog.ts", + "search_engines_page/search_engine_entry.ts", + "search_engines_page/search_engines_list.ts", + "search_engines_page/search_engines_page.ts", + "search_page/search_page.ts", + "settings_main/settings_main.ts", + "settings_menu/settings_menu.ts", + "settings_page/settings_animated_pages.ts", + "settings_page/settings_section.ts", + "settings_page/settings_subpage.ts", + "settings_ui/settings_ui.ts", + "site_favicon.ts", + "site_settings/add_site_dialog.ts", + "site_settings/all_sites.ts", + "site_settings/category_default_setting.ts", + "site_settings/category_setting_exceptions.ts", + "site_settings/chooser_exception_list_entry.ts", + "site_settings/chooser_exception_list.ts", + "site_settings/edit_exception_dialog.ts", + "site_settings/media_picker.ts", + "site_settings_page/recent_site_permissions.ts", + "site_settings_page/site_settings_list.ts", + "site_settings_page/site_settings_page.ts", + "site_settings/pdf_documents.ts", + "site_settings/protocol_handlers.ts", + "site_settings/settings_category_default_radio_group.ts", + "site_settings/site_data_details_subpage.ts", + "site_settings/site_data_entry.ts", + "site_settings/site_data.ts", + "site_settings/site_details_permission.ts", + "site_settings/site_details.ts", + "site_settings/site_entry.ts", + "site_settings/site_list_entry.ts", + "site_settings/site_list.ts", + "site_settings/zoom_levels.ts", + ] + + if (!is_chromeos_ash) { + web_component_files += [ + "people_page/manage_profile.ts", + "relaunch_confirmation_dialog.ts", + "languages_page/add_languages_dialog.ts", + "languages_page/languages_page.ts", + "languages_page/spell_check_page.ts", + "system_page/system_page.ts", + ] + } + + if (!is_chromeos) { + web_component_files += [ + "default_browser_page/default_browser_page.ts", + "people_page/import_data_dialog.ts", + ] + } + + if (!is_chromeos_ash && !is_mac) { + web_component_files += [ "languages_page/edit_dictionary_page.ts" ] + } + + if (!is_mac) { + web_component_files += [ "a11y_page/captions_subpage.ts" ] + } + + if (is_win) { + web_component_files += [ + "autofill_page/passkeys_subpage.ts", + "safety_check_page/safety_check_chrome_cleaner_child.ts", + "chrome_cleanup_page/chrome_cleanup_page.ts", + "chrome_cleanup_page/items_to_remove_list.ts", + "incompatible_applications_page/incompatible_application_item.ts", + "incompatible_applications_page/incompatible_applications_page.ts", + ] + } + + if (is_chromeos) { + web_component_files += [ "controls/password_prompt_dialog.ts" ] + } + + # -----------------web_component_files end ---------------------------------- + + # -----------------non_web_component_files start ---------------------------- + + non_web_component_files = [ + "a11y_page/captions_browser_proxy.ts", + "about_page/about_page_browser_proxy.ts", + "appearance_page/appearance_browser_proxy.ts", + "appearance_page/fonts_browser_proxy.ts", + "autofill_page/autofill_manager_proxy.ts", + "autofill_page/merge_passwords_store_copies_mixin.ts", + "autofill_page/password_check_mixin.ts", + "autofill_page/password_manager_proxy.ts", + "autofill_page/password_removal_mixin.ts", + "autofill_page/password_requestor_mixin.ts", + "autofill_page/payments_manager_proxy.ts", + "autofill_page/show_password_mixin.ts", + "base_mixin.ts", + "clear_browsing_data_dialog/clear_browsing_data_browser_proxy.ts", + "controls/cr_policy_pref_mixin.ts", + "controls/pref_control_mixin.ts", + "controls/settings_boolean_control_mixin.ts", + "controls/settings_idle_load.ts", + "downloads_page/downloads_browser_proxy.ts", + "ensure_lazy_loaded.ts", + "extension_control_browser_proxy.ts", + "focus_config.ts", + "global_scroll_target_mixin.ts", + "hats_browser_proxy.ts", + "i18n_setup.ts", + "lazy_load.ts", + "lifetime_browser_proxy.ts", + "metrics_browser_proxy.ts", + "on_startup_page/on_startup_browser_proxy.ts", + "on_startup_page/startup_urls_page_browser_proxy.ts", + "open_window_proxy.ts", + "page_visibility.ts", + "people_page/sync_browser_proxy.ts", + "people_page/profile_info_browser_proxy.ts", + "prefs/prefs_mixin.ts", + "prefs/prefs.ts", + "prefs/prefs_types.ts", + "prefs/pref_util.ts", + "privacy_page/privacy_guide/constants.ts", + "privacy_page/privacy_guide/privacy_guide_browser_proxy.ts", + "privacy_page/privacy_page_browser_proxy.ts", + "privacy_page/security_keys_browser_proxy.ts", + "privacy_sandbox/icons.html.ts", + "privacy_sandbox/privacy_sandbox_browser_proxy.ts", + "relaunch_mixin.ts", + "reset_page/reset_browser_proxy.ts", + "route.ts", + "router.js", + "safety_check_page/safety_check_browser_proxy.ts", + "search_engines_page/search_engines_browser_proxy.ts", + "search_settings.ts", + "setting_id_param_util.ts", + "settings.ts", + "settings_page/main_page_mixin.ts", + "settings_routes.ts", + "site_settings/constants.ts", + "site_settings/cookie_info.ts", + "site_settings/local_data_browser_proxy.ts", + "site_settings/site_settings_mixin.ts", + "site_settings/site_settings_prefs_browser_proxy.ts", + "site_settings/website_usage_browser_proxy.ts", + ] + + if (is_chromeos) { + non_web_component_files += [ "autofill_page/blocking_request_manager.ts" ] + } + + if (is_chromeos_ash) { + non_web_component_files += [ + "people_page/account_manager_browser_proxy.ts", + "site_settings/android_info_browser_proxy.ts", + ] + } else { + if (!is_chromeos_lacros) { + non_web_component_files += [ + "default_browser_page/default_browser_browser_proxy.ts", + "people_page/import_data_browser_proxy.ts", + ] + } + non_web_component_files += [ + "languages_page/languages.ts", + "languages_page/languages_browser_proxy.ts", + "languages_page/languages_settings_metrics_proxy.ts", + "languages_page/languages_types.ts", + "people_page/manage_profile_browser_proxy.ts", + "system_page/system_page_browser_proxy.ts", + ] + } + + if (is_win) { + non_web_component_files += [ + "autofill_page/passkeys_browser_proxy.ts", + "chrome_cleanup_page/chrome_cleanup_proxy.ts", + "incompatible_applications_page/incompatible_applications_browser_proxy.ts", + ] + } + + # -----------------non_web_component_files end ------------------------------- + + icons_html_files = [ + "icons.html", + "site_settings/all_sites_icons.html", + ] + + css_files = [ + "settings_page_styles.css", + "settings_shared.css", + "settings_vars.css", + + # subfolder files + "autofill_page/passwords_shared.css", + "search_engines_page/search_engine_entry.css", + "site_settings/clear_storage_dialog_shared.css", + "privacy_page/privacy_guide/privacy_guide_fragment_shared.css", + ] + + ts_composite = true + ts_definitions = [ + "//tools/typescript/definitions/autofill_private.d.ts", + "//tools/typescript/definitions/chrome_send.d.ts", + "//tools/typescript/definitions/language_settings_private.d.ts", + "//tools/typescript/definitions/management.d.ts", + "//tools/typescript/definitions/metrics_private.d.ts", + "//tools/typescript/definitions/passwords_private.d.ts", + "//tools/typescript/definitions/pending.d.ts", + "//tools/typescript/definitions/runtime.d.ts", + "//tools/typescript/definitions/settings_private.d.ts", + ] + if (is_chromeos) { + ts_definitions += + [ "//tools/typescript/definitions/quick_unlock_private.d.ts" ] + } + + ts_deps = [ + "//third_party/polymer/v3_0:library", + "//ui/webui/resources:library", + ] + + if (!is_chromeos_ash) { + ts_deps += + [ "//ui/webui/resources/cr_components/customize_themes:build_ts" ] + } + + if (use_nss_certs) { + ts_deps += + [ "//ui/webui/resources/cr_components/certificate_manager:build_ts" ] + } + + if (is_chromeos_ash) { + # TODO(crbug.com/1013466): Browser Settings should not depend on ash/webui/ + # code. The codepath needing this (in people_page.ts) should be removed when + # the SplitSettings effort makes progress (unclear status as of this + # writing, unfortunately). + ts_extra_deps = [ "//ash/webui/common/resources:generate_definitions" ] + } if (optimize_webui) { - deps = [ - ":build", - "privacy_sandbox:build_grdp", + extra_grdp_deps = [ "privacy_sandbox:build_grdp" ] + extra_grdp_files = [ "$target_gen_dir/privacy_sandbox/resources.grdp" ] + } + + optimize = optimize_webui + if (optimize) { + optimize_webui_host = "settings" + optimize_webui_in_files = [ + "settings.js", + "lazy_load.js", ] - manifest_files = [ "$target_gen_dir/$build_manifest" ] - resource_path_rewrites = [ + optimize_webui_out_files = [ + "settings.rollup.js", + "lazy_load.rollup.js", + "shared.rollup.js", + ] + optimize_webui_excludes = [ + "chrome://resources/js/cr.m.js", + "chrome://resources/mojo/mojo/public/js/bindings.js", + "chrome://resources/mojo/skia/public/mojom/skcolor.mojom-webui.js", + ] + optimize_webui_resource_paths_rewrites = [ "settings.rollup.js|settings.js", "lazy_load.rollup.js|lazy_load.js", ] - grdp_files = [ "$target_gen_dir/privacy_sandbox/resources.grdp" ] - } else { - deps = [ ":build_ts" ] - manifest_files = - filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ]) } }
diff --git a/chrome/browser/resources/settings/autofill_page/password_check.ts b/chrome/browser/resources/settings/autofill_page/password_check.ts index ee4538ef..bf6ec76 100644 --- a/chrome/browser/resources/settings/autofill_page/password_check.ts +++ b/chrome/browser/resources/settings/autofill_page/password_check.ts
@@ -122,7 +122,8 @@ canUsePasswordCheckup_: { type: Boolean, - computed: 'computeCanUsePasswordCheckup_(syncPrefs_, syncStatus_)', + computed: 'computeCanUsePasswordCheckup_(syncPrefs_,' + + 'isSyncingPasswords_)', }, isButtonHidden_: { @@ -166,7 +167,7 @@ showNoCompromisedPasswordsLabel_: { type: Boolean, computed: 'computeShowNoCompromisedPasswordsLabel_(' + - 'syncStatus_, prefs.*, status, leakedPasswords)', + 'isSignedOut_, prefs.*, status, leakedPasswords)', }, showHideMenuTitle_: { @@ -820,7 +821,7 @@ * @return whether the user can use the online Password Checkup. */ private computeCanUsePasswordCheckup_(): boolean { - return !!this.syncStatus_ && !!this.syncStatus_.signedIn && + return this.isSyncingPasswords_ && (!this.syncPrefs_ || !this.syncPrefs_.encryptAllData); } @@ -832,7 +833,7 @@ private computeShowNoCompromisedPasswordsLabel_(): boolean { // Check if user isn't signed in. - if (!this.syncStatus_ || !this.syncStatus_.signedIn) { + if (this.isSignedOut_) { return false; }
diff --git a/chrome/browser/resources/settings/chromeos/BUILD.gn b/chrome/browser/resources/settings/chromeos/BUILD.gn index 37ae13f..1f3cdd92 100644 --- a/chrome/browser/resources/settings/chromeos/BUILD.gn +++ b/chrome/browser/resources/settings/chromeos/BUILD.gn
@@ -762,10 +762,6 @@ "parental_controls_page:web_components", "personalization_page:web_components", "settings_scheduler_slider:web_components", - - # Shared with browser settings - "..:css_wrapper_files", - "..:html_wrapper_files", ] }
diff --git a/chrome/browser/resources/settings/chromeos/os_people_page/BUILD.gn b/chrome/browser/resources/settings/chromeos/os_people_page/BUILD.gn index 21a5605..7dec4b6 100644 --- a/chrome/browser/resources/settings/chromeos/os_people_page/BUILD.gn +++ b/chrome/browser/resources/settings/chromeos/os_people_page/BUILD.gn
@@ -175,7 +175,7 @@ ":fingerprint_browser_proxy", "..:metrics_recorder", "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", - "//ui/webui/resources/cr_elements/cr_fingerprint:cr_fingerprint_progress_arc.m", + "//ui/webui/resources/cr_elements/cr_fingerprint:cr_fingerprint_progress_arc", "//ui/webui/resources/cr_elements/cr_lottie:cr_lottie.m", "//ui/webui/resources/js:i18n_behavior.m", "//ui/webui/resources/js:web_ui_listener_behavior.m",
diff --git a/chrome/browser/resources/settings/chromeos/os_people_page/setup_fingerprint_dialog.js b/chrome/browser/resources/settings/chromeos/os_people_page/setup_fingerprint_dialog.js index 73c153a..c32770d8 100644 --- a/chrome/browser/resources/settings/chromeos/os_people_page/setup_fingerprint_dialog.js +++ b/chrome/browser/resources/settings/chromeos/os_people_page/setup_fingerprint_dialog.js
@@ -3,7 +3,7 @@ // found in the LICENSE file. import 'chrome://resources/cr_elements/cr_lottie/cr_lottie.m.js'; -import 'chrome://resources/cr_elements/cr_fingerprint/cr_fingerprint_progress_arc.m.js'; +import 'chrome://resources/cr_elements/cr_fingerprint/cr_fingerprint_progress_arc.js'; import 'chrome://resources/cr_elements/cr_button/cr_button.m.js'; import 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js'; import '../../settings_shared.css.js';
diff --git a/chrome/browser/resources/settings/languages_page/languages_page.ts b/chrome/browser/resources/settings/languages_page/languages_page.ts index c4eda808..3f60cb8 100644 --- a/chrome/browser/resources/settings/languages_page/languages_page.ts +++ b/chrome/browser/resources/settings/languages_page/languages_page.ts
@@ -125,12 +125,8 @@ enableDesktopDetailedLanguageSettings_: { type: Boolean, value: function() { - let enabled = false; - // <if expr="not chromeos_lacros"> - enabled = - loadTimeData.getBoolean('enableDesktopDetailedLanguageSettings'); - // </if> - return enabled; + return loadTimeData.getBoolean( + 'enableDesktopDetailedLanguageSettings'); }, }, };
diff --git a/chrome/browser/resources/settings/languages_page/languages_settings_metrics_proxy.ts b/chrome/browser/resources/settings/languages_page/languages_settings_metrics_proxy.ts index f7b0281..c97be945 100644 --- a/chrome/browser/resources/settings/languages_page/languages_settings_metrics_proxy.ts +++ b/chrome/browser/resources/settings/languages_page/languages_settings_metrics_proxy.ts
@@ -23,6 +23,13 @@ ENABLE_TRANSLATE_FOR_SINGLE_LANGUAGE = 7, LANGUAGE_LIST_REORDERED = 8, CHANGE_CHROME_LANGUAGE = 9, + // 10-16 are Android only + ENABLE_SPELL_CHECK_GLOBALLY = 17, + DISABLE_SPELL_CHECK_GLOBALLY = 18, + ENABLE_SPELL_CHECK_FOR_LANGUAGE = 19, + DISABLE_SPELL_CHECK_FOR_LANGUAGE = 20, + SELECT_BASIC_SPELL_CHECK = 21, + SELECT_ENHANCED_SPELL_CHECK = 22, } /**
diff --git a/chrome/browser/resources/settings/languages_page/spell_check_page.html b/chrome/browser/resources/settings/languages_page/spell_check_page.html index 95115f35..8099d8d 100644 --- a/chrome/browser/resources/settings/languages_page/spell_check_page.html +++ b/chrome/browser/resources/settings/languages_page/spell_check_page.html
@@ -61,7 +61,8 @@ label="$i18n{offerToEnableSpellCheck}" sub-label="[[getSpellCheckSubLabel_(spellCheckLanguages_)]]" pref="{{prefs.browser.enable_spellchecking}}" - disabled="[[!spellCheckLanguages_.length]]"> + disabled="[[!spellCheckLanguages_.length]]" + on-settings-boolean-control-change="onSpellCheckToggleChange_"> </settings-toggle-button> <if expr="_google_chrome or not is_macosx"> <iron-collapse id="spellCheckCollapse" @@ -69,7 +70,8 @@ <if expr="_google_chrome"> <div class="cr-row continuation spell-check-radio-group"> <settings-radio-group class="flex" - pref="{{prefs.spellcheck.use_spelling_service}}"> + pref="{{prefs.spellcheck.use_spelling_service}}" + on-change="onSelectedSpellingServiceChange_"> <controlled-radio-button class="spell-check-radio-button" id="spellingServiceDisable" label="$i18n{spellCheckBasicLabel}" name="false"
diff --git a/chrome/browser/resources/settings/languages_page/spell_check_page.ts b/chrome/browser/resources/settings/languages_page/spell_check_page.ts index e998c4d..91c72817b 100644 --- a/chrome/browser/resources/settings/languages_page/spell_check_page.ts +++ b/chrome/browser/resources/settings/languages_page/spell_check_page.ts
@@ -32,6 +32,8 @@ // <if expr="not is_macosx"> import './edit_dictionary_page.js'; // </if> + +import {SettingsToggleButtonElement} from '../controls/settings_toggle_button.js'; import {assert} from 'chrome://resources/js/assert_ts.js'; import {focusWithoutInk} from 'chrome://resources/js/cr/ui/focus_without_ink.m.js'; import {I18nMixin} from 'chrome://resources/js/i18n_mixin.js'; @@ -43,6 +45,7 @@ import {routes} from '../route.js'; import {Router} from '../router.js'; +import {LanguageSettingsActionType, LanguageSettingsMetricsProxy, LanguageSettingsMetricsProxyImpl} from './languages_settings_metrics_proxy.js'; import {LanguageHelper, LanguagesModel, LanguageState, SpellCheckLanguageState} from './languages_types.js'; import {getTemplate} from './spell_check_page.html.js'; @@ -124,6 +127,22 @@ private spellCheckLanguages_: Array<LanguageState|SpellCheckLanguageState>; private hideSpellCheckLanguages_: boolean; private focusConfig_: FocusConfig; + private languageSettingsMetricsProxy_: LanguageSettingsMetricsProxy = + LanguageSettingsMetricsProxyImpl.getInstance(); + + private onSpellCheckToggleChange_(e: Event) { + this.languageSettingsMetricsProxy_.recordSettingsMetric( + (e.target as SettingsToggleButtonElement).checked ? + LanguageSettingsActionType.ENABLE_SPELL_CHECK_GLOBALLY : + LanguageSettingsActionType.DISABLE_SPELL_CHECK_GLOBALLY); + } + + private onSelectedSpellingServiceChange_() { + this.languageSettingsMetricsProxy_.recordSettingsMetric( + this.prefs.spellcheck.use_spelling_service ? + LanguageSettingsActionType.SELECT_ENHANCED_SPELL_CHECK : + LanguageSettingsActionType.SELECT_BASIC_SPELL_CHECK); + } // <if expr="not is_macosx"> /** @@ -248,6 +267,11 @@ this.languageHelper.toggleSpellCheck( item.language.code, !item.spellCheckEnabled); + + this.languageSettingsMetricsProxy_.recordSettingsMetric( + item.spellCheckEnabled ? + LanguageSettingsActionType.ENABLE_SPELL_CHECK_FOR_LANGUAGE : + LanguageSettingsActionType.DISABLE_SPELL_CHECK_FOR_LANGUAGE); } /**
diff --git a/chrome/browser/resources/settings/privacy_page/security_keys_bio_enroll_dialog.ts b/chrome/browser/resources/settings/privacy_page/security_keys_bio_enroll_dialog.ts index bf9e1d66..17cb6d1 100644 --- a/chrome/browser/resources/settings/privacy_page/security_keys_bio_enroll_dialog.ts +++ b/chrome/browser/resources/settings/privacy_page/security_keys_bio_enroll_dialog.ts
@@ -11,7 +11,7 @@ import 'chrome://resources/cr_elements/cr_button/cr_button.m.js'; import 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js'; import 'chrome://resources/cr_elements/cr_input/cr_input.m.js'; -import 'chrome://resources/cr_elements/cr_fingerprint/cr_fingerprint_progress_arc.m.js'; +import 'chrome://resources/cr_elements/cr_fingerprint/cr_fingerprint_progress_arc.js'; import 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.m.js'; import 'chrome://resources/polymer/v3_0/iron-icon/iron-icon.js'; import 'chrome://resources/polymer/v3_0/iron-list/iron-list.js'; @@ -24,7 +24,7 @@ import {getInstance as getAnnouncerInstance} from 'chrome://resources/cr_elements/cr_a11y_announcer/cr_a11y_announcer.js'; import {CrButtonElement} from 'chrome://resources/cr_elements/cr_button/cr_button.m.js'; import {CrDialogElement} from 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js'; -import {CrFingerprintProgressArcElement} from 'chrome://resources/cr_elements/cr_fingerprint/cr_fingerprint_progress_arc.m.js'; +import {CrFingerprintProgressArcElement} from 'chrome://resources/cr_elements/cr_fingerprint/cr_fingerprint_progress_arc.js'; import {CrInputElement} from 'chrome://resources/cr_elements/cr_input/cr_input.m.js'; import {assert, assertNotReached} from 'chrome://resources/js/assert_ts.js'; import {I18nMixin} from 'chrome://resources/js/i18n_mixin.js';
diff --git a/chrome/browser/resources/settings/settings.gni b/chrome/browser/resources/settings/settings.gni index 02714af..d0d9bcc 100644 --- a/chrome/browser/resources/settings/settings.gni +++ b/chrome/browser/resources/settings/settings.gni
@@ -2,7 +2,6 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -import("//build/config/chromeos/ui_mode.gni") import("//third_party/closure_compiler/compile_js.gni") assert(!is_android, "Android does not use these settings") @@ -12,329 +11,3 @@ "js_module_root=../../chrome/browser/resources/settings/", "js_module_root=./gen/chrome/browser/resources/settings/", ] - -# -----------------web_component_files start ----------------------------------- - -# Files holding a Polymer element definition and have an equivalent .html file. -web_component_files = [ - "a11y_page/a11y_page.ts", - "a11y_page/live_caption_section.ts", - "about_page/about_page.ts", - "appearance_page/appearance_fonts_page.ts", - "appearance_page/appearance_page.ts", - "appearance_page/home_url_input.ts", - "autofill_page/address_edit_dialog.ts", - "autofill_page/address_remove_confirmation_dialog.ts", - "autofill_page/autofill_page.ts", - "autofill_page/autofill_section.ts", - "autofill_page/avatar_icon.ts", - "autofill_page/credit_card_edit_dialog.ts", - "autofill_page/credit_card_list_entry.ts", - "autofill_page/password_check_edit_dialog.ts", - "autofill_page/password_check_edit_disclaimer_dialog.ts", - "autofill_page/password_check_list_item.ts", - "autofill_page/password_check.ts", - "autofill_page/password_edit_dialog.ts", - "autofill_page/password_list_item.ts", - "autofill_page/password_move_multiple_passwords_to_account_dialog.ts", - "autofill_page/password_move_to_account_dialog.ts", - "autofill_page/password_remove_confirmation_dialog.ts", - "autofill_page/password_remove_dialog.ts", - "autofill_page/password_view.ts", - "autofill_page/passwords_device_section.ts", - "autofill_page/passwords_export_dialog.ts", - "autofill_page/passwords_import_dialog.ts", - "autofill_page/passwords_list_handler.ts", - "autofill_page/passwords_section.ts", - "autofill_page/payments_list.ts", - "autofill_page/payments_section.ts", - "autofill_page/upi_id_list_entry.ts", - "autofill_page/virtual_card_unenroll_dialog.ts", - "basic_page/basic_page.ts", - "clear_browsing_data_dialog/clear_browsing_data_dialog.ts", - "clear_browsing_data_dialog/history_deletion_dialog.ts", - "clear_browsing_data_dialog/installed_app_checkbox.ts", - "clear_browsing_data_dialog/passwords_deletion_dialog.ts", - "controls/controlled_button.ts", - "controls/controlled_radio_button.ts", - "controls/extension_controlled_indicator.ts", - "controls/settings_checkbox.ts", - "controls/settings_dropdown_menu.ts", - "controls/settings_radio_group.ts", - "controls/settings_slider.ts", - "controls/settings_textarea.ts", - "controls/settings_toggle_button.ts", - "downloads_page/downloads_page.ts", - "on_startup_page/on_startup_page.ts", - "on_startup_page/startup_url_dialog.ts", - "on_startup_page/startup_url_entry.ts", - "on_startup_page/startup_urls_page.ts", - "people_page/people_page.ts", - "people_page/signout_dialog.ts", - "people_page/sync_account_control.ts", - "people_page/sync_controls.ts", - "people_page/sync_encryption_options.ts", - "people_page/sync_page.ts", - "privacy_page/collapse_radio_button.ts", - "privacy_page/cookies_page.ts", - "privacy_page/disable_safebrowsing_dialog.ts", - "privacy_page/do_not_track_toggle.ts", - "privacy_page/personalization_options.ts", - "privacy_page/privacy_guide_promo.ts", - "privacy_page/privacy_guide/privacy_guide_clear_on_exit_fragment.ts", - "privacy_page/privacy_guide/privacy_guide_completion_fragment.ts", - "privacy_page/privacy_guide/privacy_guide_completion_link_row.ts", - "privacy_page/privacy_guide/privacy_guide_cookies_fragment.ts", - "privacy_page/privacy_guide/privacy_guide_description_item.ts", - "privacy_page/privacy_guide/privacy_guide_dialog.ts", - "privacy_page/privacy_guide/privacy_guide_history_sync_fragment.ts", - "privacy_page/privacy_guide/privacy_guide_msbb_fragment.ts", - "privacy_page/privacy_guide/privacy_guide_page.ts", - "privacy_page/privacy_guide/privacy_guide_safe_browsing_fragment.ts", - "privacy_page/privacy_guide/privacy_guide_welcome_fragment.ts", - "privacy_page/privacy_guide/step_indicator.ts", - "privacy_page/privacy_page.ts", - "privacy_page/secure_dns.ts", - "privacy_page/secure_dns_input.ts", - "privacy_page/security_keys_bio_enroll_dialog.ts", - "privacy_page/security_keys_credential_management_dialog.ts", - "privacy_page/security_keys_pin_field.ts", - "privacy_page/security_keys_reset_dialog.ts", - "privacy_page/security_keys_set_pin_dialog.ts", - "privacy_page/security_keys_subpage.ts", - "privacy_page/security_keys_phones_subpage.ts", - "privacy_page/security_keys_phones_list.ts", - "privacy_page/security_keys_phones_dialog.ts", - "privacy_page/security_page.ts", - "privacy_sandbox/app.ts", - "privacy_sandbox/interest_item.ts", - "reset_page/reset_page.ts", - "reset_page/reset_profile_banner.ts", - "reset_page/reset_profile_dialog.ts", - "safety_check_page/safety_check_child.ts", - "safety_check_page/safety_check_extensions_child.ts", - "safety_check_page/safety_check_page.ts", - "safety_check_page/safety_check_passwords_child.ts", - "safety_check_page/safety_check_safe_browsing_child.ts", - "safety_check_page/safety_check_updates_child.ts", - "search_engines_page/omnibox_extension_entry.ts", - "search_engines_page/search_engine_delete_confirmation_dialog.ts", - "search_engines_page/search_engine_edit_dialog.ts", - "search_engines_page/search_engine_entry.ts", - "search_engines_page/search_engines_list.ts", - "search_engines_page/search_engines_page.ts", - "search_page/search_page.ts", - "settings_main/settings_main.ts", - "settings_menu/settings_menu.ts", - "settings_page/settings_animated_pages.ts", - "settings_page/settings_section.ts", - "settings_page/settings_subpage.ts", - "settings_ui/settings_ui.ts", - "site_favicon.ts", - "site_settings/add_site_dialog.ts", - "site_settings/all_sites.ts", - "site_settings/category_default_setting.ts", - "site_settings/category_setting_exceptions.ts", - "site_settings/chooser_exception_list_entry.ts", - "site_settings/chooser_exception_list.ts", - "site_settings/edit_exception_dialog.ts", - "site_settings/media_picker.ts", - "site_settings_page/recent_site_permissions.ts", - "site_settings_page/site_settings_list.ts", - "site_settings_page/site_settings_page.ts", - "site_settings/pdf_documents.ts", - "site_settings/protocol_handlers.ts", - "site_settings/settings_category_default_radio_group.ts", - "site_settings/site_data_details_subpage.ts", - "site_settings/site_data_entry.ts", - "site_settings/site_data.ts", - "site_settings/site_details_permission.ts", - "site_settings/site_details.ts", - "site_settings/site_entry.ts", - "site_settings/site_list_entry.ts", - "site_settings/site_list.ts", - "site_settings/zoom_levels.ts", -] - -if (!is_chromeos_ash) { - web_component_files += [ - "people_page/manage_profile.ts", - "relaunch_confirmation_dialog.ts", - "languages_page/add_languages_dialog.ts", - "languages_page/languages_page.ts", - "languages_page/spell_check_page.ts", - "system_page/system_page.ts", - ] -} - -if (!is_chromeos) { - web_component_files += [ - "default_browser_page/default_browser_page.ts", - "people_page/import_data_dialog.ts", - ] -} - -if (!is_chromeos_ash && !is_mac) { - web_component_files += [ "languages_page/edit_dictionary_page.ts" ] -} - -if (!is_mac) { - web_component_files += [ "a11y_page/captions_subpage.ts" ] -} - -if (is_win) { - web_component_files += [ - "autofill_page/passkeys_subpage.ts", - "safety_check_page/safety_check_chrome_cleaner_child.ts", - "chrome_cleanup_page/chrome_cleanup_page.ts", - "chrome_cleanup_page/items_to_remove_list.ts", - "incompatible_applications_page/incompatible_application_item.ts", - "incompatible_applications_page/incompatible_applications_page.ts", - ] -} - -if (is_chromeos) { - web_component_files += [ "controls/password_prompt_dialog.ts" ] -} - -# -----------------web_component_files end ------------------------------------ - -# Files that are passed as input to html_to_wrapper(). -html_files = [] -foreach(f, web_component_files) { - html_files += [ string_replace(f, ".ts", ".html") ] -} - -icons_html_files = [ - "icons.html", - "site_settings/all_sites_icons.html", -] - -# Files that are generated by html_to_wrapper(). -html_wrapper_files = [] -foreach(f, html_files + icons_html_files) { - html_wrapper_files += [ f + ".ts" ] -} - -# -----------------non_web_component_files start ------------------------------ - -non_web_component_files = [ - "a11y_page/captions_browser_proxy.ts", - "about_page/about_page_browser_proxy.ts", - "appearance_page/appearance_browser_proxy.ts", - "appearance_page/fonts_browser_proxy.ts", - "autofill_page/autofill_manager_proxy.ts", - "autofill_page/merge_passwords_store_copies_mixin.ts", - "autofill_page/password_check_mixin.ts", - "autofill_page/password_manager_proxy.ts", - "autofill_page/password_removal_mixin.ts", - "autofill_page/password_requestor_mixin.ts", - "autofill_page/payments_manager_proxy.ts", - "autofill_page/show_password_mixin.ts", - "base_mixin.ts", - "clear_browsing_data_dialog/clear_browsing_data_browser_proxy.ts", - "controls/cr_policy_pref_mixin.ts", - "controls/pref_control_mixin.ts", - "controls/settings_boolean_control_mixin.ts", - "controls/settings_idle_load.ts", - "downloads_page/downloads_browser_proxy.ts", - "ensure_lazy_loaded.ts", - "extension_control_browser_proxy.ts", - "focus_config.ts", - "global_scroll_target_mixin.ts", - "hats_browser_proxy.ts", - "i18n_setup.ts", - "lazy_load.ts", - "lifetime_browser_proxy.ts", - "metrics_browser_proxy.ts", - "on_startup_page/on_startup_browser_proxy.ts", - "on_startup_page/startup_urls_page_browser_proxy.ts", - "open_window_proxy.ts", - "page_visibility.ts", - "people_page/sync_browser_proxy.ts", - "people_page/profile_info_browser_proxy.ts", - "prefs/prefs_mixin.ts", - "prefs/prefs.ts", - "prefs/prefs_types.ts", - "prefs/pref_util.ts", - "privacy_page/privacy_guide/constants.ts", - "privacy_page/privacy_guide/privacy_guide_browser_proxy.ts", - "privacy_page/privacy_page_browser_proxy.ts", - "privacy_page/security_keys_browser_proxy.ts", - "privacy_sandbox/icons.html.ts", - "privacy_sandbox/privacy_sandbox_browser_proxy.ts", - "relaunch_mixin.ts", - "reset_page/reset_browser_proxy.ts", - "route.ts", - "router.js", - "safety_check_page/safety_check_browser_proxy.ts", - "search_engines_page/search_engines_browser_proxy.ts", - "search_settings.ts", - "setting_id_param_util.ts", - "settings.ts", - "settings_page/main_page_mixin.ts", - "settings_routes.ts", - "site_settings/constants.ts", - "site_settings/cookie_info.ts", - "site_settings/local_data_browser_proxy.ts", - "site_settings/site_settings_mixin.ts", - "site_settings/site_settings_prefs_browser_proxy.ts", - "site_settings/website_usage_browser_proxy.ts", -] - -if (is_chromeos) { - non_web_component_files += [ "autofill_page/blocking_request_manager.ts" ] -} - -if (is_chromeos_ash) { - non_web_component_files += [ - "people_page/account_manager_browser_proxy.ts", - "site_settings/android_info_browser_proxy.ts", - ] -} else { - if (!is_chromeos_lacros) { - non_web_component_files += [ - "default_browser_page/default_browser_browser_proxy.ts", - "people_page/import_data_browser_proxy.ts", - ] - } - non_web_component_files += [ - "languages_page/languages.ts", - "languages_page/languages_browser_proxy.ts", - "languages_page/languages_settings_metrics_proxy.ts", - "languages_page/languages_types.ts", - "people_page/manage_profile_browser_proxy.ts", - "system_page/system_page_browser_proxy.ts", - ] -} - -if (is_win) { - non_web_component_files += [ - "autofill_page/passkeys_browser_proxy.ts", - "chrome_cleanup_page/chrome_cleanup_proxy.ts", - "incompatible_applications_page/incompatible_applications_browser_proxy.ts", - ] -} - -# -----------------non_web_component_files end --------------------------------- - -ts_files = web_component_files + non_web_component_files - -# Files that are passed as input to css_to_wrapper(). -css_files = [ - "settings_page_styles.css", - "settings_shared.css", - "settings_vars.css", - - # subfolder files - "autofill_page/passwords_shared.css", - "search_engines_page/search_engine_entry.css", - "site_settings/clear_storage_dialog_shared.css", - "privacy_page/privacy_guide/privacy_guide_fragment_shared.css", -] - -# Files that are generated by css_to_wrapper(). -css_wrapper_files = [] -foreach(f, css_files) { - css_wrapper_files += [ f + ".ts" ] -}
diff --git a/chrome/browser/safe_browsing/chrome_password_protection_service.cc b/chrome/browser/safe_browsing/chrome_password_protection_service.cc index 054d748c..b9a5b49e 100644 --- a/chrome/browser/safe_browsing/chrome_password_protection_service.cc +++ b/chrome/browser/safe_browsing/chrome_password_protection_service.cc
@@ -373,14 +373,12 @@ password_type == PasswordType::OTHER_GAIA_PASSWORD); // Otherwise, checks if there's any unhandled sync password reuses matches // this origin. - auto* unhandled_sync_password_reuses = profile->GetPrefs()->GetDictionary( - prefs::kSafeBrowsingUnhandledGaiaPasswordReuses); - return unhandled_sync_password_reuses - ? (unhandled_sync_password_reuses->FindKey( - web_contents->GetPrimaryMainFrame() - ->GetLastCommittedOrigin() - .Serialize()) != nullptr) - : false; + const auto& unhandled_sync_password_reuses = + profile->GetPrefs()->GetValueDict( + prefs::kSafeBrowsingUnhandledGaiaPasswordReuses); + return unhandled_sync_password_reuses.Find(web_contents->GetPrimaryMainFrame() + ->GetLastCommittedOrigin() + .Serialize()); } safe_browsing::LoginReputationClientRequest::UrlDisplayExperiment @@ -1212,10 +1210,10 @@ } void ChromePasswordProtectionService::OnWarningTriggerChanged() { - const base::Value* pref_value = pref_change_registrar_->prefs()->Get( + const base::Value& pref_value = pref_change_registrar_->prefs()->GetValue( prefs::kPasswordProtectionWarningTrigger); // If password protection is not turned off, do nothing. - if (static_cast<PasswordProtectionTrigger>(pref_value->GetInt()) != + if (static_cast<PasswordProtectionTrigger>(pref_value.GetInt()) != PASSWORD_PROTECTION_OFF) { return; }
diff --git a/chrome/browser/segmentation_platform/segmentation_platform_config.cc b/chrome/browser/segmentation_platform/segmentation_platform_config.cc index 8c4d7eb..e9b9aa1 100644 --- a/chrome/browser/segmentation_platform/segmentation_platform_config.cc +++ b/chrome/browser/segmentation_platform/segmentation_platform_config.cc
@@ -11,11 +11,10 @@ #include "base/time/time.h" #include "build/build_config.h" #include "chrome/browser/metrics/chrome_metrics_service_accessor.h" +#include "components/commerce/core/commerce_feature_list.h" #include "components/segmentation_platform/embedder/default_model/feed_user_segment.h" #include "components/segmentation_platform/embedder/default_model/low_user_engagement_model.h" #include "components/segmentation_platform/embedder/default_model/price_tracking_action_model.h" -#include "components/segmentation_platform/internal/config_parser.h" -#include "components/segmentation_platform/internal/stats.h" #include "components/segmentation_platform/public/config.h" #include "components/segmentation_platform/public/features.h" #include "components/segmentation_platform/public/model_provider.h" @@ -27,7 +26,6 @@ #include "chrome/browser/flags/android/chrome_feature_list.h" #include "chrome/browser/segmentation_platform/default_model/chrome_start_model_android.h" #include "chrome/browser/ui/android/start_surface/start_surface_android.h" -#include "components/commerce/core/commerce_feature_list.h" #include "components/query_tiles/switches.h" #include "components/segmentation_platform/embedder/default_model/query_tiles_model.h" #endif @@ -68,19 +66,10 @@ constexpr int kQueryTilesDefaultUnknownTTLDays = 7; #endif // BUILDFLAG(IS_ANDROID) -#define SEGMENT_ID_ENTRY(segment) \ - { \ - segment, Config::SegmentMetadata { \ - stats::OptimizationTargetToHistogramVariant(segment) \ - } \ - } - #if BUILDFLAG(IS_ANDROID) std::unique_ptr<Config> GetConfigForAdaptiveToolbar() { auto config = std::make_unique<Config>(); config->segmentation_key = kAdaptiveToolbarSegmentationKey; - config->segmentation_uma_name = - stats::SegmentationKeyToUmaName(config->segmentation_key); int segment_selection_ttl_days = base::GetFieldTrialParamByFeatureAsInt( chrome::android::kAdaptiveButtonInTopToolbarCustomizationV2, @@ -89,10 +78,10 @@ // Do not set unknown TTL so that the platform ignores unknown results. // A hardcoded list of segment IDs known to the segmentation platform. - config->segments = { - SEGMENT_ID_ENTRY(SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_NEW_TAB), - SEGMENT_ID_ENTRY(SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_SHARE), - SEGMENT_ID_ENTRY(SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_VOICE), + config->segment_ids = { + SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_NEW_TAB, + SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_SHARE, + SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_VOICE, }; return config; @@ -102,10 +91,8 @@ std::unique_ptr<Config> GetConfigForDummyFeature() { auto config = std::make_unique<Config>(); config->segmentation_key = kDummySegmentationKey; - config->segmentation_uma_name = - stats::SegmentationKeyToUmaName(config->segmentation_key); - config->segments = { - SEGMENT_ID_ENTRY(SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_DUMMY), + config->segment_ids = { + SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_DUMMY, }; config->segment_selection_ttl = base::Days(kDummyFeatureSelectionTTLDays); config->unknown_selection_ttl = base::Days(kDummyFeatureSelectionTTLDays); @@ -125,11 +112,8 @@ std::unique_ptr<Config> GetConfigForChromeStartAndroid() { auto config = std::make_unique<Config>(); config->segmentation_key = kChromeStartAndroidSegmentationKey; - config->segmentation_uma_name = - stats::SegmentationKeyToUmaName(config->segmentation_key); - config->segments = { - SEGMENT_ID_ENTRY( - SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_CHROME_START_ANDROID), + config->segment_ids = { + SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_CHROME_START_ANDROID, }; int segment_selection_ttl_days = base::GetFieldTrialParamByFeatureAsInt( @@ -156,10 +140,8 @@ std::unique_ptr<Config> GetConfigForQueryTiles() { auto config = std::make_unique<Config>(); config->segmentation_key = kQueryTilesSegmentationKey; - config->segmentation_uma_name = - stats::SegmentationKeyToUmaName(config->segmentation_key); - config->segments = { - SEGMENT_ID_ENTRY(SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_QUERY_TILES), + config->segment_ids = { + SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_QUERY_TILES, }; int segment_selection_ttl_days = base::GetFieldTrialParamByFeatureAsInt( @@ -185,13 +167,11 @@ std::unique_ptr<Config> GetConfigForContextualPageActions() { auto config = std::make_unique<Config>(); config->segmentation_key = kContextualPageActionsKey; - config->segmentation_uma_name = - stats::SegmentationKeyToUmaName(config->segmentation_key); if (base::FeatureList::IsEnabled( features::kContextualPageActionPriceTracking) && base::FeatureList::IsEnabled(commerce::kShoppingList)) { - config->segments.insert(SEGMENT_ID_ENTRY( - SegmentId::OPTIMIZATION_TARGET_CONTEXTUAL_PAGE_ACTION_PRICE_TRACKING)); + config->segment_ids.push_back( + SegmentId::OPTIMIZATION_TARGET_CONTEXTUAL_PAGE_ACTION_PRICE_TRACKING); } config->on_demand_execution = true; return config; @@ -224,12 +204,8 @@ std::unique_ptr<Config> GetConfigForChromeLowUserEngagement() { auto config = std::make_unique<Config>(); config->segmentation_key = kChromeLowUserEngagementSegmentationKey; - config->segmentation_uma_name = - stats::SegmentationKeyToUmaName(config->segmentation_key); - config->segments = { - SEGMENT_ID_ENTRY( - SegmentId:: - OPTIMIZATION_TARGET_SEGMENTATION_CHROME_LOW_USER_ENGAGEMENT), + config->segment_ids = { + SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_CHROME_LOW_USER_ENGAGEMENT, }; #if BUILDFLAG(IS_ANDROID) @@ -250,10 +226,8 @@ std::unique_ptr<Config> GetConfigForFeedSegments() { auto config = std::make_unique<Config>(); config->segmentation_key = kFeedUserSegmentationKey; - config->segmentation_uma_name = - stats::SegmentationKeyToUmaName(config->segmentation_key); - config->segments = { - SEGMENT_ID_ENTRY(SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_FEED_USER), + config->segment_ids = { + SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_FEED_USER, }; config->segment_selection_ttl = base::Days(base::GetFieldTrialParamByFeatureAsInt( @@ -280,19 +254,6 @@ return std::make_unique<PriceTrackingActionModel>(); } -void AppendConfigsFromExperiments( - std::vector<std::unique_ptr<Config>>& out_configs) { - // TODO(crbug.com/1346389): Add logic to find segmentation param from field - // trials. - std::vector<std::string> params; - for (const std::string& param : params) { - auto config = ParseConfigFromString(param); - if (config) { - out_configs.push_back(std::move(config)); - } - } -} - } // namespace std::vector<std::unique_ptr<Config>> GetSegmentationPlatformConfig() { @@ -325,8 +286,6 @@ features::kSegmentationPlatformFeedSegmentFeature)) { configs.emplace_back(GetConfigForFeedSegments()); } - - AppendConfigsFromExperiments(configs); return configs; }
diff --git a/chrome/browser/signin/services/android/java/src/org/chromium/chrome/browser/signin/services/SigninMetricsUtils.java b/chrome/browser/signin/services/android/java/src/org/chromium/chrome/browser/signin/services/SigninMetricsUtils.java index 1f018a3b..ed8d7073 100644 --- a/chrome/browser/signin/services/android/java/src/org/chromium/chrome/browser/signin/services/SigninMetricsUtils.java +++ b/chrome/browser/signin/services/android/java/src/org/chromium/chrome/browser/signin/services/SigninMetricsUtils.java
@@ -49,7 +49,11 @@ * Logs signin user action for a given {@link SigninAccessPoint}. */ public static void logSigninUserActionForAccessPoint(@SigninAccessPoint int accessPoint) { - SigninMetricsUtilsJni.get().logSigninUserActionForAccessPoint(accessPoint); + // TODO(https://crbug.com/1349700): Remove this check when user action checks are removed + // from native code. + if (accessPoint != SigninAccessPoint.SETTINGS_SYNC_OFF_ROW) { + SigninMetricsUtilsJni.get().logSigninUserActionForAccessPoint(accessPoint); + } } @VisibleForTesting
diff --git a/chrome/browser/sync/test/integration/single_client_sessions_sync_test.cc b/chrome/browser/sync/test/integration/single_client_sessions_sync_test.cc index af4cf4ca2..d0328e18 100644 --- a/chrome/browser/sync/test/integration/single_client_sessions_sync_test.cc +++ b/chrome/browser/sync/test/integration/single_client_sessions_sync_test.cc
@@ -824,7 +824,7 @@ sync_pb::ClientToServerMessage first_commit; ASSERT_TRUE(GetFakeServer()->GetLastCommitMessage(&first_commit)); EXPECT_TRUE(first_commit.commit().config_params().cookie_jar_mismatch()) - << *syncer::ClientToServerMessageToValue(first_commit, true); + << *syncer::ClientToServerMessageToValue(first_commit, /*options=*/{}); // Avoid interferences from actual IdentityManager trying to fetch gaia // account information, which would exercise @@ -848,7 +848,7 @@ sync_pb::ClientToServerMessage second_commit; ASSERT_TRUE(GetFakeServer()->GetLastCommitMessage(&second_commit)); EXPECT_FALSE(second_commit.commit().config_params().cookie_jar_mismatch()) - << *syncer::ClientToServerMessageToValue(second_commit, true); + << *syncer::ClientToServerMessageToValue(second_commit, /*options=*/{}); } IN_PROC_BROWSER_TEST_F(SingleClientSessionsSyncTest,
diff --git a/chrome/browser/ui/app_list/search/games/game_provider.cc b/chrome/browser/ui/app_list/search/games/game_provider.cc index 71eb57b..4d01d68 100644 --- a/chrome/browser/ui/app_list/search/games/game_provider.cc +++ b/chrome/browser/ui/app_list/search/games/game_provider.cc
@@ -4,11 +4,13 @@ #include "chrome/browser/ui/app_list/search/games/game_provider.h" +#include <algorithm> #include <utility> #include "ash/constants/ash_pref_names.h" #include "base/metrics/field_trial_params.h" #include "base/metrics/histogram_functions.h" +#include "base/rand_util.h" #include "base/strings/strcat.h" #include "base/task/task_traits.h" #include "base/task/thread_pool.h" @@ -41,6 +43,7 @@ constexpr double kPartialMatchPenaltyRate = 0.9; constexpr size_t kMaxResults = 3u; +constexpr double kEpsilon = 1e-5; // Outcome of a call to GameSearchProvider::Start. These values persist to logs. // Entries should not be renumbered and numeric values should not be reused. @@ -187,6 +190,14 @@ std::vector<std::pair<const apps::Result*, double>> matches) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + // Shuffle the matches and use the resulting order to slightly modify all + // scores. When the results are sorted, this will have the effect of + // randomizing the order of cloud providers given the same game title. + base::RandomShuffle(matches.begin(), matches.end()); + for (size_t i = 0; i < matches.size(); ++i) { + matches[i].second = std::max(0.0, matches[i].second - i * kEpsilon); + } + // Sort matches by descending relevance score. std::sort(matches.begin(), matches.end(), [](const auto& a, const auto& b) { return a.second > b.second; });
diff --git a/chrome/browser/ui/app_list/search/games/game_provider_unittest.cc b/chrome/browser/ui/app_list/search/games/game_provider_unittest.cc index fabe7a2..6c86c173 100644 --- a/chrome/browser/ui/app_list/search/games/game_provider_unittest.cc +++ b/chrome/browser/ui/app_list/search/games/game_provider_unittest.cc
@@ -34,14 +34,33 @@ return arg->title() == title; } -apps::Result MakeAppsResult(const std::u16string& title) { +apps::Result MakeAppsResult(const std::u16string& title, + const std::u16string& source) { return apps::Result( apps::AppSource::kGames, "12345", title, std::make_unique<apps::GameExtras>( absl::make_optional(std::vector<std::u16string>({u"A", u"B", u"C"})), - u"SourceName", u"TestGamePublisher", - base::FilePath("/icons/test.png"), /*is_icon_masking_allowed=*/false, - GURL("https://game.com/game"))); + source, u"TestGamePublisher", base::FilePath("/icons/test.png"), + /*is_icon_masking_allowed=*/false, GURL("https://game.com/game"))); +} + +apps::Result MakeAppsResult(const std::u16string& title) { + return MakeAppsResult(title, u"SourceName"); +} + +// Checks that the result's details text vector contains exactly one text item +// with the given text. +bool DetailsEquals(const std::unique_ptr<ChromeSearchResult>& result, + const std::u16string& details) { + const auto& details_vector = result->details_text_vector(); + + if (details_vector.size() != 1) + return false; + + if (details_vector[0].GetType() != ash::SearchResultTextItemType::kString) + return false; + + return details_vector[0].GetText() == details; } } // namespace @@ -87,12 +106,13 @@ provider_->SetGameIndexForTest(std::move(index)); } - void Wait() { task_environment_.RunUntilIdle(); } - void StartSearch(const std::u16string& query) { search_controller_->StartSearch(query); + task_environment_.RunUntilIdle(); } + GameProvider* provider() const { return provider_; } + ScopedFeatureList feature_list_; content::BrowserTaskEnvironment task_environment_; ::test::TestAppListControllerDelegate list_controller_; @@ -110,11 +130,9 @@ SetUpTestingIndex(); StartSearch(u"first"); - Wait(); EXPECT_THAT(LastResults(), ElementsAre(Title(u"First Title"))); StartSearch(u"title"); - Wait(); EXPECT_THAT(LastResults(), UnorderedElementsAre(Title(u"First Title"), Title(u"Second Title"), Title(u"Third Title"))); @@ -127,14 +145,12 @@ profile_->GetPrefs()->SetBoolean(chromeos::prefs::kSuggestedContentEnabled, true); StartSearch(u"first"); - Wait(); EXPECT_THAT(LastResults(), ElementsAre(Title(u"First Title"))); // If Suggested Content is disabled, only show results if the override is on. profile_->GetPrefs()->SetBoolean(chromeos::prefs::kSuggestedContentEnabled, false); StartSearch(u"first"); - Wait(); bool enabled_override = GetParam(); if (enabled_override) { EXPECT_THAT(LastResults(), ElementsAre(Title(u"First Title"))); @@ -143,4 +159,36 @@ } } +// Tests that games with the same title but different sources appear in a random +// order across different queries. +TEST_P(GameProviderTest, RandomizeSourceOrder) { + // Create two games with the same name but different sources. + GameProvider::GameIndex index; + index.push_back(MakeAppsResult(u"title", u"source_a")); + index.push_back(MakeAppsResult(u"title", u"source_b")); + provider()->SetGameIndexForTest(std::move(index)); + + int a_first = 0; + int b_first = 0; + for (int i = 0; i < 1000; ++i) { + StartSearch(u"title"); + ASSERT_EQ(LastResults().size(), 2); + + // The source name is set into the result details, so use the result details + // to identify which source it came from. + if (DetailsEquals(LastResults()[0], u"source_a")) { + a_first++; + } else if (DetailsEquals(LastResults()[0], u"source_b")) { + b_first++; + } + } + ASSERT_EQ(a_first + b_first, 1000); + + // We expect a and b each to be first about ~half the time, but this will vary + // randomly across test runs. To avoid flakiness, only expect here that they + // each happen at least 10 times, which has a very high chance of being true. + EXPECT_GE(a_first, 10); + EXPECT_GE(b_first, 10); +} + } // namespace app_list
diff --git a/chrome/browser/ui/ash/shelf/chrome_shelf_controller_unittest.cc b/chrome/browser/ui/ash/shelf/chrome_shelf_controller_unittest.cc index f4751b7..c6f1b61 100644 --- a/chrome/browser/ui/ash/shelf/chrome_shelf_controller_unittest.cc +++ b/chrome/browser/ui/ash/shelf/chrome_shelf_controller_unittest.cc
@@ -714,7 +714,8 @@ void AppendPrefValue(base::ListValue* pref_value, const std::string& extension_id) { base::DictionaryValue entry; - entry.SetKey(ChromeShelfPrefs::kPinnedAppsPrefAppIDKey, base::Value(extension_id)); + entry.SetKey(ChromeShelfPrefs::kPinnedAppsPrefAppIDKey, + base::Value(extension_id)); pref_value->Append(std::move(entry)); } @@ -1358,7 +1359,7 @@ // calling chrome.app.window.create. For unit testing purposes, just passing // in a random RenderFrameHost is Good Enough™. window_->Init(GURL(std::string()), - new extensions::AppWindowContentsImpl(window_), + std::make_unique<extensions::AppWindowContentsImpl>(window_), creator_web_contents_->GetPrimaryMainFrame(), params); }
diff --git a/chrome/browser/ui/page_info/chrome_page_info_delegate.cc b/chrome/browser/ui/page_info/chrome_page_info_delegate.cc index 86672f4..18706b7 100644 --- a/chrome/browser/ui/page_info/chrome_page_info_delegate.cc +++ b/chrome/browser/ui/page_info/chrome_page_info_delegate.cc
@@ -180,6 +180,11 @@ chrome::ShowSiteSettings(browser, site_url); } +void ChromePageInfoDelegate::ShowCookiesSettings() { + Browser* browser = chrome::FindBrowserWithWebContents(web_contents_); + chrome::ShowSettingsSubPage(browser, chrome::kCookieSettingsSubPage); +} + void ChromePageInfoDelegate::OpenCookiesDialog() { TabDialogs::FromWebContents(web_contents_)->ShowCollectedCookies(); }
diff --git a/chrome/browser/ui/page_info/chrome_page_info_delegate.h b/chrome/browser/ui/page_info/chrome_page_info_delegate.h index 9aab22f..5e719b7 100644 --- a/chrome/browser/ui/page_info/chrome_page_info_delegate.h +++ b/chrome/browser/ui/page_info/chrome_page_info_delegate.h
@@ -57,6 +57,7 @@ // In Chrome's case, this may show the site settings page or an app settings // page, depending on context. void ShowSiteSettings(const GURL& site_url) override; + void ShowCookiesSettings() override; void OpenCookiesDialog() override; void OpenCertificateDialog(net::X509Certificate* certificate) override; void OpenConnectionHelpCenterPage(const ui::Event& event) override;
diff --git a/chrome/browser/ui/quick_answers/ui/quick_answers_pre_target_handler.cc b/chrome/browser/ui/quick_answers/ui/quick_answers_pre_target_handler.cc index b716051..2ee7a7b5 100644 --- a/chrome/browser/ui/quick_answers/ui/quick_answers_pre_target_handler.cc +++ b/chrome/browser/ui/quick_answers/ui/quick_answers_pre_target_handler.cc
@@ -59,7 +59,7 @@ return; // Clone event to forward down the view-hierarchy. - auto clone = ui::Event::Clone(*event); + auto clone = event->Clone(); ui::Event::DispatcherApi(clone.get()).set_target(event->target()); auto* to_dispatch = clone->AsLocatedEvent(); auto location = to_dispatch->target()->GetScreenLocation(*to_dispatch);
diff --git a/chrome/browser/ui/views/crostini/crostini_ansible_software_config_view.cc b/chrome/browser/ui/views/crostini/crostini_ansible_software_config_view.cc index 0607b8f..9eb4f90 100644 --- a/chrome/browser/ui/views/crostini/crostini_ansible_software_config_view.cc +++ b/chrome/browser/ui/views/crostini/crostini_ansible_software_config_view.cc
@@ -6,6 +6,7 @@ #include "base/callback_helpers.h" #include "base/logging.h" +#include "base/strings/utf_string_conversions.h" #include "chrome/browser/ash/crostini/crostini_pref_names.h" #include "chrome/browser/ash/crostini/crostini_util.h" #include "chrome/browser/profiles/profile.h" @@ -82,6 +83,19 @@ void CrostiniAnsibleSoftwareConfigView::OnAnsibleSoftwareConfigurationStarted( const guest_os::GuestId& container_id) {} +void CrostiniAnsibleSoftwareConfigView::OnAnsibleSoftwareConfigurationProgress( + const guest_os::GuestId& container_id, + const std::vector<std::string>& status_lines) { + std::u16string status_string; + if (!base::UTF8ToUTF16(status_lines.back().c_str(), + status_lines.back().size(), &status_string)) { + LOG(ERROR) << "Failed to convert status line into a UTF16 string: " + << status_lines.back(); + } else { + progress_label_->SetText(status_string); + } +} + void CrostiniAnsibleSoftwareConfigView::OnAnsibleSoftwareConfigurationFinished( const guest_os::GuestId& container_id, bool success) { @@ -106,6 +120,11 @@ return subtext_label_->GetText(); } +std::u16string +CrostiniAnsibleSoftwareConfigView::GetProgressLabelStringForTesting() { + return progress_label_->GetText(); +} + // static CrostiniAnsibleSoftwareConfigView* CrostiniAnsibleSoftwareConfigView::GetActiveViewForTesting() { @@ -135,13 +154,19 @@ subtext_label_ = AddChildView(std::move(subtext_label)); // Add infinite progress bar. - // TODO(crbug.com/1000173): add progress reporting and display text above - // progress bar indicating current process. auto progress_bar = std::make_unique<views::ProgressBar>(); // Values outside the range [0,1] display an infinite loading animation. progress_bar->SetValue(-1); progress_bar_ = AddChildView(std::move(progress_bar)); + // Adds text below the infinite progress bar stating the last action. + // Currently can't really display the full progress since Ansible doesn't + // expose this by default w/o specific playbook hacks. + auto progress_label = std::make_unique<views::Label>(); + progress_label->SetMultiLine(true); + progress_label->SetHorizontalAlignment(gfx::ALIGN_LEFT); + progress_label_ = AddChildView(std::move(progress_label)); + default_container_ansible_filepath_ = profile->GetPrefs()->GetFilePath( crostini::prefs::kCrostiniAnsiblePlaybookFilePath);
diff --git a/chrome/browser/ui/views/crostini/crostini_ansible_software_config_view.h b/chrome/browser/ui/views/crostini/crostini_ansible_software_config_view.h index c91a776..dcfa1ca 100644 --- a/chrome/browser/ui/views/crostini/crostini_ansible_software_config_view.h +++ b/chrome/browser/ui/views/crostini/crostini_ansible_software_config_view.h
@@ -35,11 +35,15 @@ // crostini::AnsibleManagementService::Observer: void OnAnsibleSoftwareConfigurationStarted( const guest_os::GuestId& container_id) override; + void OnAnsibleSoftwareConfigurationProgress( + const guest_os::GuestId& container_id, + const std::vector<std::string>& status_lines) override; void OnAnsibleSoftwareConfigurationFinished( const guest_os::GuestId& container_id, bool success) override; std::u16string GetSubtextLabelStringForTesting(); + std::u16string GetProgressLabelStringForTesting(); static CrostiniAnsibleSoftwareConfigView* GetActiveViewForTesting(); @@ -61,6 +65,7 @@ crostini::AnsibleManagementService* ansible_management_service_ = nullptr; views::Label* subtext_label_ = nullptr; + views::Label* progress_label_ = nullptr; views::ProgressBar* progress_bar_ = nullptr; base::FilePath default_container_ansible_filepath_;
diff --git a/chrome/browser/ui/views/crostini/crostini_ansible_software_config_view_browsertest.cc b/chrome/browser/ui/views/crostini/crostini_ansible_software_config_view_browsertest.cc index 55da189f..9a68a0b 100644 --- a/chrome/browser/ui/views/crostini/crostini_ansible_software_config_view_browsertest.cc +++ b/chrome/browser/ui/views/crostini/crostini_ansible_software_config_view_browsertest.cc
@@ -4,7 +4,10 @@ #include "chrome/browser/ui/views/crostini/crostini_ansible_software_config_view.h" +#include <string> + #include "base/callback_helpers.h" +#include "base/strings/utf_string_conversions.h" #include "base/test/bind.h" #include "chrome/browser/ash/crostini/ansible/ansible_management_service.h" #include "chrome/browser/ash/crostini/ansible/ansible_management_test_helper.h" @@ -23,6 +26,8 @@ #include "ui/base/l10n/l10n_util.h" #include "ui/chromeos/devicetype_utils.h" +constexpr char kProgressString[] = "Yesh milord. More work?"; + class CrostiniAnsibleSoftwareConfigViewBrowserTest : public CrostiniDialogBrowserTest, public crostini::AnsibleManagementService::Observer { @@ -48,11 +53,27 @@ // crostini::AnsibleManagementService::Observer void OnAnsibleSoftwareConfigurationStarted( const guest_os::GuestId& container_id) override {} + + void OnAnsibleSoftwareConfigurationProgress( + const guest_os::GuestId& container_id, + const std::vector<std::string>& status_lines) override {} + void OnAnsibleSoftwareConfigurationFinished( const guest_os::GuestId& container_id, bool success) override {} void OnApplyAnsiblePlaybook(const guest_os::GuestId& container_id) override { + if (send_ansible_progress_) { + EXPECT_NE(nullptr, ActiveView()); + vm_tools::cicerone::ApplyAnsiblePlaybookProgressSignal signal; + signal.set_status( + vm_tools::cicerone::ApplyAnsiblePlaybookProgressSignal::IN_PROGRESS); + signal.set_vm_name(crostini::DefaultContainerId().vm_name); + signal.set_container_name(crostini::DefaultContainerId().container_name); + signal.add_status_string(kProgressString); + ansible_management_service()->OnApplyAnsiblePlaybookProgress(signal); + status_string_ = ActiveView()->GetProgressLabelStringForTesting(); + } if (is_apply_ansible_success_) { EXPECT_NE(nullptr, ActiveView()); vm_tools::cicerone::ApplyAnsiblePlaybookProgressSignal signal; @@ -108,6 +129,7 @@ // Set sensible defaults. is_install_ansible_success_ = true; is_apply_ansible_success_ = true; + send_ansible_progress_ = false; } void TearDownOnMainThread() override { @@ -154,7 +176,12 @@ is_install_ansible_success_ = success; } + void SetSendAnsibleProgress(bool show_progress) { + send_ansible_progress_ = show_progress; + } + guest_os::GuestId container_id_; + std::u16string status_string_; private: bool HasAcceptButton() { return ActiveView()->GetOkButton() != nullptr; } @@ -190,6 +217,7 @@ bool is_install_ansible_success_; bool is_apply_ansible_success_; + bool send_ansible_progress_; std::unique_ptr<network::TestNetworkConnectionTracker> network_connection_tracker_; std::unique_ptr<crostini::AnsibleManagementTestHelper> test_helper_; @@ -297,6 +325,25 @@ } IN_PROC_BROWSER_TEST_F(CrostiniAnsibleSoftwareConfigViewBrowserTest, + AnsibleConfigFlowWithProgress_Successful) { + SetSendAnsibleProgress(true); + ansible_management_service()->ConfigureContainer( + crostini::DefaultContainerId(), + browser()->profile()->GetPrefs()->GetFilePath( + crostini::prefs::kCrostiniAnsiblePlaybookFilePath), + base::BindLambdaForTesting([&](bool success) { run_loop()->Quit(); })); + + run_loop()->Run(); + std::u16string expected; + // -1 to anti the null at the end of the string. + ASSERT_TRUE(base::UTF8ToUTF16(kProgressString, sizeof(kProgressString) - 1, + &expected)); + EXPECT_EQ(status_string_, expected); + + EXPECT_TRUE(HasNoView()); +} + +IN_PROC_BROWSER_TEST_F(CrostiniAnsibleSoftwareConfigViewBrowserTest, AnsibleConfigFlow_InstallationFailed) { // Set install failure. No need to set apply because it should never reach // there.
diff --git a/chrome/browser/ui/views/omnibox/rounded_omnibox_results_frame.cc b/chrome/browser/ui/views/omnibox/rounded_omnibox_results_frame.cc index 8a3625d2..95690cbe 100644 --- a/chrome/browser/ui/views/omnibox/rounded_omnibox_results_frame.cc +++ b/chrome/browser/ui/views/omnibox/rounded_omnibox_results_frame.cc
@@ -48,7 +48,7 @@ views::Widget* this_widget = this_view->GetWidget(); views::Widget* parent_widget = this_widget->parent(); std::unique_ptr<ui::MouseEvent> event( - static_cast<ui::MouseEvent*>(ui::Event::Clone(*this_event).release())); + static_cast<ui::MouseEvent*>(this_event->Clone().release())); if (!parent_widget) return {nullptr, std::move(event)};
diff --git a/chrome/browser/ui/views/page_info/page_info_cookies_content_view.cc b/chrome/browser/ui/views/page_info/page_info_cookies_content_view.cc index eedf3eb..d64b9dd 100644 --- a/chrome/browser/ui/views/page_info/page_info_cookies_content_view.cc +++ b/chrome/browser/ui/views/page_info/page_info_cookies_content_view.cc
@@ -96,7 +96,5 @@ void PageInfoCookiesContentView::CookiesSettingsLinkClicked( const ui::Event& event) { - // TODO(crbug.com/1346305): Add a new function to PageInfo for opening cookies - // settings. - presenter_->OpenSiteSettingsView(); + presenter_->OpenCookiesSettingsView(); }
diff --git a/chrome/browser/ui/webui/chromeos/login/base_webui_handler.h b/chrome/browser/ui/webui/chromeos/login/base_webui_handler.h index b7343ed..b694f3c 100644 --- a/chrome/browser/ui/webui/chromeos/login/base_webui_handler.h +++ b/chrome/browser/ui/webui/chromeos/login/base_webui_handler.h
@@ -71,7 +71,7 @@ // All CallJS invocations can be recorded for tests if CallJS recording is // enabled. template <typename... Args> - void CallJS(const std::string& function_name, Args... args) { + void CallJS(base::StringPiece function_name, Args... args) { if (IsJavascriptAllowed()) { CallJavascriptFunction(function_name, base::Value(std::move(args))...); return; @@ -79,11 +79,12 @@ deferred_calls_.push_back(base::BindOnce( &BaseWebUIHandler::CallJS<Args...>, base::Unretained(this), - function_name, std::move(args)...)); + std::string(function_name.data(), function_name.length()), + std::move(args)...)); } template <typename... Args> - void FireWebUIListenerWhenAllowed(const std::string& event_name, + void FireWebUIListenerWhenAllowed(base::StringPiece event_name, Args... args) { if (IsJavascriptAllowed()) { FireWebUIListener(event_name, args...); @@ -92,11 +93,13 @@ deferred_calls_.push_back( base::BindOnce(&BaseWebUIHandler::FireWebUIListenerWhenAllowed<Args...>, - base::Unretained(this), event_name, std::move(args)...)); + base::Unretained(this), + std::string(event_name.data(), event_name.length()), + std::move(args)...)); } template <typename T, typename... Args> - void AddCallback(const std::string& function_name, + void AddCallback(base::StringPiece function_name, void (T::*method)(Args...)) { base::RepeatingCallback<void(Args...)> callback = base::BindRepeating(method, base::Unretained(static_cast<T*>(this)));
diff --git a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc index 0044a93f..f50903c 100644 --- a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
@@ -941,11 +941,17 @@ CreateSamlChallengeKeyHandler(); saml_challenge_key_handler_->Run( Profile::FromWebUI(web_ui()), - base::BindOnce(&GaiaScreenHandler::ResolveJavascriptCallback, + base::BindOnce(&GaiaScreenHandler::HandleSamlChallengeMachineKeyResult, weak_factory_.GetWeakPtr(), base::Value(callback_id)), GURL(url), challenge); } +void GaiaScreenHandler::HandleSamlChallengeMachineKeyResult( + base::Value callback_id, + base::Value::Dict result) { + ResolveJavascriptCallback(callback_id, result); +} + void GaiaScreenHandler::HandleGaiaUIReady() { VLOG(1) << "Gaia is loaded";
diff --git a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h index 4139525f..62c2fa5d 100644 --- a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h +++ b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h
@@ -227,6 +227,8 @@ void HandleSamlChallengeMachineKey(const std::string& callback_id, const std::string& url, const std::string& challenge); + void HandleSamlChallengeMachineKeyResult(base::Value callback_id, + base::Value::Dict result); void HandleGaiaUIReady();
diff --git a/chrome/browser/ui/webui/chromeos/login/saml_challenge_key_handler.cc b/chrome/browser/ui/webui/chromeos/login/saml_challenge_key_handler.cc index 0f4cf9ce..f76621b 100644 --- a/chrome/browser/ui/webui/chromeos/login/saml_challenge_key_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/saml_challenge_key_handler.cc
@@ -137,7 +137,7 @@ void SamlChallengeKeyHandler::ReturnResult( const attestation::TpmChallengeKeyResult& result) { - base::Value js_result(base::Value::Type::DICTIONARY); + base::Value::Dict js_result; if (!result.IsSuccess()) { LOG(WARNING) << "Device attestation error: " << result.GetErrorMessage(); } @@ -145,8 +145,8 @@ std::string encoded_result_data; base::Base64Encode(result.challenge_response, &encoded_result_data); - js_result.SetKey(kSuccessField, base::Value(result.IsSuccess())); - js_result.SetKey(kResponseField, base::Value(encoded_result_data)); + js_result.Set(kSuccessField, result.IsSuccess()); + js_result.Set(kResponseField, encoded_result_data); std::move(callback_).Run(std::move(js_result)); tpm_key_challenger_.reset();
diff --git a/chrome/browser/ui/webui/chromeos/login/saml_challenge_key_handler.h b/chrome/browser/ui/webui/chromeos/login/saml_challenge_key_handler.h index 49665ff..e9697a0 100644 --- a/chrome/browser/ui/webui/chromeos/login/saml_challenge_key_handler.h +++ b/chrome/browser/ui/webui/chromeos/login/saml_challenge_key_handler.h
@@ -22,7 +22,8 @@ // attestation during SAML authentication. class SamlChallengeKeyHandler final { public: - using CallbackType = base::OnceCallback<void(const base::Value& response)>; + using CallbackType = + base::OnceCallback<void(const base::Value::Dict response)>; SamlChallengeKeyHandler(); SamlChallengeKeyHandler(const SamlChallengeKeyHandler&) = delete;
diff --git a/chrome/browser/ui/webui/feedback/feedback_ui.cc b/chrome/browser/ui/webui/feedback/feedback_ui.cc index df24fd6..38b93f0 100644 --- a/chrome/browser/ui/webui/feedback/feedback_ui.cc +++ b/chrome/browser/ui/webui/feedback/feedback_ui.cc
@@ -8,8 +8,8 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/common/webui_url_constants.h" #include "chrome/grit/browser_resources.h" -#include "chrome/grit/feedback_webui_resources.h" -#include "chrome/grit/feedback_webui_resources_map.h" +#include "chrome/grit/feedback_resources.h" +#include "chrome/grit/feedback_resources_map.h" #include "chrome/grit/generated_resources.h" #include "components/strings/grit/components_strings.h" #include "content/public/browser/web_ui.h" @@ -72,8 +72,8 @@ content::WebUIDataSource* source = content::WebUIDataSource::Create(chrome::kChromeUIFeedbackHost); source->AddResourcePaths( - base::make_span(kFeedbackWebuiResources, kFeedbackWebuiResourcesSize)); - source->AddResourcePath("", IDR_FEEDBACK_WEBUI_HTML_DEFAULT_HTML); + base::make_span(kFeedbackResources, kFeedbackResourcesSize)); + source->AddResourcePath("", IDR_FEEDBACK_HTML_DEFAULT_HTML); // Register the CSS file from chrome://system manually as that style is // re-used by chrome://feedback/html/sys_info.html.
diff --git a/chrome/browser/ui/webui/ntp_tiles_internals_ui.cc b/chrome/browser/ui/webui/ntp_tiles_internals_ui.cc index 9fb89db..f1cafb15 100644 --- a/chrome/browser/ui/webui/ntp_tiles_internals_ui.cc +++ b/chrome/browser/ui/webui/ntp_tiles_internals_ui.cc
@@ -57,11 +57,11 @@ std::unique_ptr<ntp_tiles::MostVisitedSites> MakeMostVisitedSites() override; PrefService* GetPrefs() override; void RegisterMessageCallback( - const std::string& message, + base::StringPiece message, base::RepeatingCallback<void(const base::Value::List&)> callback) override; void CallJavascriptFunctionSpan( - const std::string& name, + base::StringPiece name, base::span<const base::ValueView> values) override; ntp_tiles::NTPTilesInternalsMessageHandler handler_; @@ -113,13 +113,13 @@ } void ChromeNTPTilesInternalsMessageHandlerClient::RegisterMessageCallback( - const std::string& message, + base::StringPiece message, base::RepeatingCallback<void(const base::Value::List&)> callback) { web_ui()->RegisterMessageCallback(message, std::move(callback)); } void ChromeNTPTilesInternalsMessageHandlerClient::CallJavascriptFunctionSpan( - const std::string& name, + base::StringPiece name, base::span<const base::ValueView> values) { web_ui()->CallJavascriptFunctionUnsafe(name, values); }
diff --git a/chrome/browser/ui/webui/print_preview/local_printer_handler_chromeos.cc b/chrome/browser/ui/webui/print_preview/local_printer_handler_chromeos.cc index a096d3b..2ee9d56 100644 --- a/chrome/browser/ui/webui/print_preview/local_printer_handler_chromeos.cc +++ b/chrome/browser/ui/webui/print_preview/local_printer_handler_chromeos.cc
@@ -121,20 +121,20 @@ } // static -base::Value LocalPrinterHandlerChromeos::StatusToValue( +base::Value::Dict LocalPrinterHandlerChromeos::StatusToValue( const crosapi::mojom::PrinterStatus& status) { - base::Value dict(base::Value::Type::DICTIONARY); - dict.SetStringKey("printerId", status.printer_id); - dict.SetDoubleKey("timestamp", status.timestamp.ToJsTimeIgnoringNull()); - base::Value status_reasons(base::Value::Type::LIST); + base::Value::Dict dict; + dict.Set("printerId", status.printer_id); + dict.Set("timestamp", status.timestamp.ToJsTimeIgnoringNull()); + base::Value::List status_reasons; for (const crosapi::mojom::StatusReasonPtr& reason_ptr : status.status_reasons) { - base::Value status_reason(base::Value::Type::DICTIONARY); - status_reason.SetIntKey("reason", static_cast<int>(reason_ptr->reason)); - status_reason.SetIntKey("severity", static_cast<int>(reason_ptr->severity)); + base::Value::Dict status_reason; + status_reason.Set("reason", static_cast<int>(reason_ptr->reason)); + status_reason.Set("severity", static_cast<int>(reason_ptr->severity)); status_reasons.Append(std::move(status_reason)); } - dict.SetKey("statusReasons", std::move(status_reasons)); + dict.Set("statusReasons", std::move(status_reasons)); return dict; } @@ -241,7 +241,7 @@ if (!local_printer_) { PRINTER_LOG(ERROR) << "Local printer not available (StartPrinterStatusRequest)"; - std::move(callback).Run(base::Value()); + std::move(callback).Run(absl::nullopt); return; } local_printer_->GetStatus(
diff --git a/chrome/browser/ui/webui/print_preview/local_printer_handler_chromeos.h b/chrome/browser/ui/webui/print_preview/local_printer_handler_chromeos.h index d893989..741c9605 100644 --- a/chrome/browser/ui/webui/print_preview/local_printer_handler_chromeos.h +++ b/chrome/browser/ui/webui/print_preview/local_printer_handler_chromeos.h
@@ -59,7 +59,8 @@ // Returns a PrinterStatus object (defined in // chrome/browser/resources/print_preview/data/printer_status_cros.js). - static base::Value StatusToValue(const crosapi::mojom::PrinterStatus& status); + static base::Value::Dict StatusToValue( + const crosapi::mojom::PrinterStatus& status); // PrinterHandler implementation. void Reset() override;
diff --git a/chrome/browser/ui/webui/print_preview/local_printer_handler_chromeos_unittest.cc b/chrome/browser/ui/webui/print_preview/local_printer_handler_chromeos_unittest.cc index be74129..e9619b6 100644 --- a/chrome/browser/ui/webui/print_preview/local_printer_handler_chromeos_unittest.cc +++ b/chrome/browser/ui/webui/print_preview/local_printer_handler_chromeos_unittest.cc
@@ -80,13 +80,13 @@ TEST_F(LocalPrinterHandlerChromeosTest, PrinterStatusRequestNoAsh_ProvidesDefaultValue) { - base::Value printer_status("unset"); + absl::optional<base::Value::Dict> printer_status = base::Value::Dict(); local_printer_handler()->StartPrinterStatusRequest( - "printer1", - base::BindOnce(base::BindLambdaForTesting([&](const base::Value& status) { - printer_status = status.Clone(); - }))); - EXPECT_EQ(base::Value(), printer_status); + "printer1", base::BindOnce(base::BindLambdaForTesting( + [&](absl::optional<base::Value::Dict> status) { + printer_status = std::move(status); + }))); + EXPECT_EQ(absl::nullopt, printer_status); } TEST_F(LocalPrinterHandlerChromeosTest, GetPrintersNoAsh_ProvidesDefaultValue) {
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_handler.cc b/chrome/browser/ui/webui/print_preview/print_preview_handler.cc index 69c0bdd..94ee1b5 100644 --- a/chrome/browser/ui/webui/print_preview/print_preview_handler.cc +++ b/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
@@ -231,166 +231,159 @@ } #if BUILDFLAG(IS_CHROMEOS) -base::Value PoliciesToValue(crosapi::mojom::PoliciesPtr ptr) { - base::Value policies(base::Value::Type::DICTIONARY); +base::Value::Dict PoliciesToValue(crosapi::mojom::PoliciesPtr ptr) { + base::Value::Dict policies; - base::Value header_footer_policy(base::Value::Type::DICTIONARY); + base::Value::Dict header_footer_policy; if (ptr->print_header_footer_allowed != crosapi::mojom::Policies::OptionalBool::kUnset) { - header_footer_policy.SetBoolKey( - kAllowedMode, ptr->print_header_footer_allowed == - crosapi::mojom::Policies::OptionalBool::kTrue); + header_footer_policy.Set(kAllowedMode, + ptr->print_header_footer_allowed == + crosapi::mojom::Policies::OptionalBool::kTrue); } if (ptr->print_header_footer_default != crosapi::mojom::Policies::OptionalBool::kUnset) { - header_footer_policy.SetBoolKey( - kDefaultMode, ptr->print_header_footer_default == - crosapi::mojom::Policies::OptionalBool::kTrue); + header_footer_policy.Set(kDefaultMode, + ptr->print_header_footer_default == + crosapi::mojom::Policies::OptionalBool::kTrue); } - if (!header_footer_policy.DictEmpty()) - policies.SetKey(kHeaderFooter, std::move(header_footer_policy)); + if (!header_footer_policy.empty()) + policies.Set(kHeaderFooter, std::move(header_footer_policy)); - base::Value background_graphics_policy(base::Value::Type::DICTIONARY); + base::Value::Dict background_graphics_policy; int value = static_cast<int>(ptr->allowed_background_graphics_modes); if (value) - background_graphics_policy.SetIntKey(kAllowedMode, value); + background_graphics_policy.Set(kAllowedMode, value); value = static_cast<int>(ptr->background_graphics_default); if (value) - background_graphics_policy.SetIntKey(kDefaultMode, value); - if (!background_graphics_policy.DictEmpty()) - policies.SetKey(kCssBackground, std::move(background_graphics_policy)); + background_graphics_policy.Set(kDefaultMode, value); + if (!background_graphics_policy.empty()) + policies.Set(kCssBackground, std::move(background_graphics_policy)); - base::Value paper_size_policy(base::Value::Type::DICTIONARY); + base::Value::Dict paper_size_policy; const absl::optional<gfx::Size>& default_paper_size = ptr->paper_size_default; if (default_paper_size.has_value()) { - base::Value default_paper_size_value(base::Value::Type::DICTIONARY); - default_paper_size_value.SetIntKey(kPaperSizeWidth, - default_paper_size.value().width()); - default_paper_size_value.SetIntKey(kPaperSizeHeight, - default_paper_size.value().height()); - paper_size_policy.SetKey(kDefaultMode, std::move(default_paper_size_value)); + base::Value::Dict default_paper_size_value; + default_paper_size_value.Set(kPaperSizeWidth, + default_paper_size.value().width()); + default_paper_size_value.Set(kPaperSizeHeight, + default_paper_size.value().height()); + paper_size_policy.Set(kDefaultMode, std::move(default_paper_size_value)); } - if (!paper_size_policy.DictEmpty()) - policies.SetKey(kMediaSize, std::move(paper_size_policy)); + if (!paper_size_policy.empty()) + policies.Set(kMediaSize, std::move(paper_size_policy)); if (ptr->max_sheets_allowed_has_value) { - base::Value sheets_policy(base::Value::Type::DICTIONARY); - sheets_policy.SetIntKey(kValue, ptr->max_sheets_allowed); - policies.SetKey(kSheets, std::move(sheets_policy)); + base::Value::Dict sheets_policy; + sheets_policy.Set(kValue, static_cast<int>(ptr->max_sheets_allowed)); + policies.Set(kSheets, std::move(sheets_policy)); } - base::Value color_policy(base::Value::Type::DICTIONARY); + base::Value::Dict color_policy; if (ptr->allowed_color_modes) - color_policy.SetIntKey(kAllowedMode, - static_cast<int>(ptr->allowed_color_modes)); + color_policy.Set(kAllowedMode, static_cast<int>(ptr->allowed_color_modes)); if (ptr->default_color_mode != printing::mojom::ColorModeRestriction::kUnset) - color_policy.SetIntKey(kDefaultMode, - static_cast<int>(ptr->default_color_mode)); - if (!color_policy.DictEmpty()) - policies.SetKey(kColor, std::move(color_policy)); + color_policy.Set(kDefaultMode, static_cast<int>(ptr->default_color_mode)); + if (!color_policy.empty()) + policies.Set(kColor, std::move(color_policy)); - base::Value duplex_policy(base::Value::Type::DICTIONARY); + base::Value::Dict duplex_policy; if (ptr->allowed_duplex_modes) - duplex_policy.SetIntKey(kAllowedMode, - static_cast<int>(ptr->allowed_duplex_modes)); + duplex_policy.Set(kAllowedMode, + static_cast<int>(ptr->allowed_duplex_modes)); if (ptr->default_duplex_mode != printing::mojom::DuplexModeRestriction::kUnset) - duplex_policy.SetIntKey(kDefaultMode, - static_cast<int>(ptr->default_duplex_mode)); - if (!duplex_policy.DictEmpty()) - policies.SetKey(kDuplex, std::move(duplex_policy)); + duplex_policy.Set(kDefaultMode, static_cast<int>(ptr->default_duplex_mode)); + if (!duplex_policy.empty()) + policies.Set(kDuplex, std::move(duplex_policy)); - base::Value pin_policy(base::Value::Type::DICTIONARY); + base::Value::Dict pin_policy; if (ptr->allowed_pin_modes != printing::mojom::PinModeRestriction::kUnset) - pin_policy.SetIntKey(kAllowedMode, - static_cast<int>(ptr->allowed_pin_modes)); + pin_policy.Set(kAllowedMode, static_cast<int>(ptr->allowed_pin_modes)); if (ptr->default_pin_mode != printing::mojom::PinModeRestriction::kUnset) - pin_policy.SetIntKey(kDefaultMode, static_cast<int>(ptr->default_pin_mode)); - if (!pin_policy.DictEmpty()) - policies.SetKey(kPin, std::move(pin_policy)); + pin_policy.Set(kDefaultMode, static_cast<int>(ptr->default_pin_mode)); + if (!pin_policy.empty()) + policies.Set(kPin, std::move(pin_policy)); - base::Value print_as_image_for_pdf_default_policy( - base::Value::Type::DICTIONARY); + base::Value::Dict print_as_image_for_pdf_default_policy; if (ptr->default_print_pdf_as_image != crosapi::mojom::Policies::OptionalBool::kUnset) { - print_as_image_for_pdf_default_policy.SetBoolKey( + print_as_image_for_pdf_default_policy.Set( kDefaultMode, ptr->default_print_pdf_as_image == crosapi::mojom::Policies::OptionalBool::kTrue); } - if (!print_as_image_for_pdf_default_policy.DictEmpty()) { - policies.SetKey(kPrintPdfAsImage, - std::move(print_as_image_for_pdf_default_policy)); + if (!print_as_image_for_pdf_default_policy.empty()) { + policies.Set(kPrintPdfAsImage, + std::move(print_as_image_for_pdf_default_policy)); } return policies; } #else -base::Value GetPolicies(const PrefService& prefs) { - base::Value policies(base::Value::Type::DICTIONARY); +base::Value::Dict GetPolicies(const PrefService& prefs) { + base::Value::Dict policies; - base::Value header_footer_policy(base::Value::Type::DICTIONARY); + base::Value::Dict header_footer_policy; if (prefs.HasPrefPath(prefs::kPrintHeaderFooter)) { if (prefs.IsManagedPreference(prefs::kPrintHeaderFooter)) { - header_footer_policy.SetBoolKey( - kAllowedMode, prefs.GetBoolean(prefs::kPrintHeaderFooter)); + header_footer_policy.Set(kAllowedMode, + prefs.GetBoolean(prefs::kPrintHeaderFooter)); } else { - header_footer_policy.SetBoolKey( - kDefaultMode, prefs.GetBoolean(prefs::kPrintHeaderFooter)); + header_footer_policy.Set(kDefaultMode, + prefs.GetBoolean(prefs::kPrintHeaderFooter)); } } - if (!header_footer_policy.DictEmpty()) - policies.SetKey(kHeaderFooter, std::move(header_footer_policy)); + if (!header_footer_policy.empty()) + policies.Set(kHeaderFooter, std::move(header_footer_policy)); - base::Value background_graphics_policy(base::Value::Type::DICTIONARY); + base::Value::Dict background_graphics_policy; if (prefs.HasPrefPath(prefs::kPrintingAllowedBackgroundGraphicsModes)) { - background_graphics_policy.SetIntKey( + background_graphics_policy.Set( kAllowedMode, prefs.GetInteger(prefs::kPrintingAllowedBackgroundGraphicsModes)); } if (prefs.HasPrefPath(prefs::kPrintingBackgroundGraphicsDefault)) { - background_graphics_policy.SetIntKey( + background_graphics_policy.Set( kDefaultMode, prefs.GetInteger(prefs::kPrintingBackgroundGraphicsDefault)); } - if (!background_graphics_policy.DictEmpty()) - policies.SetKey(kCssBackground, std::move(background_graphics_policy)); + if (!background_graphics_policy.empty()) + policies.Set(kCssBackground, std::move(background_graphics_policy)); - base::Value paper_size_policy(base::Value::Type::DICTIONARY); + base::Value::Dict paper_size_policy; absl::optional<gfx::Size> default_paper_size = ParsePaperSizeDefault(prefs); if (default_paper_size.has_value()) { - base::Value default_paper_size_value(base::Value::Type::DICTIONARY); - default_paper_size_value.SetIntKey(kPaperSizeWidth, - default_paper_size.value().width()); - default_paper_size_value.SetIntKey(kPaperSizeHeight, - default_paper_size.value().height()); - paper_size_policy.SetKey(kDefaultMode, std::move(default_paper_size_value)); + base::Value::Dict default_paper_size_value; + default_paper_size_value.Set(kPaperSizeWidth, + default_paper_size.value().width()); + default_paper_size_value.Set(kPaperSizeHeight, + default_paper_size.value().height()); + paper_size_policy.Set(kDefaultMode, std::move(default_paper_size_value)); } - if (!paper_size_policy.DictEmpty()) - policies.SetKey(kMediaSize, std::move(paper_size_policy)); + if (!paper_size_policy.empty()) + policies.Set(kMediaSize, std::move(paper_size_policy)); #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) - base::Value print_as_image_available_for_pdf_policy( - base::Value::Type::DICTIONARY); + base::Value::Dict print_as_image_available_for_pdf_policy; if (prefs.HasPrefPath(prefs::kPrintPdfAsImageAvailability)) { - print_as_image_available_for_pdf_policy.SetBoolKey( + print_as_image_available_for_pdf_policy.Set( kAllowedMode, prefs.GetBoolean(prefs::kPrintPdfAsImageAvailability)); } - if (!print_as_image_available_for_pdf_policy.DictEmpty()) { - policies.SetKey(kPrintPdfAsImageAvailability, - std::move(print_as_image_available_for_pdf_policy)); + if (!print_as_image_available_for_pdf_policy.empty()) { + policies.Set(kPrintPdfAsImageAvailability, + std::move(print_as_image_available_for_pdf_policy)); } #endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) - base::Value print_as_image_for_pdf_default_policy( - base::Value::Type::DICTIONARY); + base::Value::Dict print_as_image_for_pdf_default_policy; if (prefs.HasPrefPath(prefs::kPrintPdfAsImageDefault)) { - print_as_image_for_pdf_default_policy.SetBoolKey( + print_as_image_for_pdf_default_policy.Set( kDefaultMode, prefs.GetBoolean(prefs::kPrintPdfAsImageDefault)); } - if (!print_as_image_for_pdf_default_policy.DictEmpty()) { - policies.SetKey(kPrintPdfAsImage, - std::move(print_as_image_for_pdf_default_policy)); + if (!print_as_image_for_pdf_default_policy.empty()) { + policies.Set(kPrintPdfAsImage, + std::move(print_as_image_for_pdf_default_policy)); } return policies; @@ -519,12 +512,12 @@ if (!prefs->HasPrefPath(prefs::kPrinterTypeDenyList)) return; - const base::Value& deny_list_from_prefs = - prefs->GetValue(prefs::kPrinterTypeDenyList); + const base::Value::List& deny_list_from_prefs = + prefs->GetValueList(prefs::kPrinterTypeDenyList); std::vector<mojom::PrinterType> deny_list; - deny_list.reserve(deny_list_from_prefs.GetList().size()); - for (const base::Value& deny_list_value : deny_list_from_prefs.GetList()) { + deny_list.reserve(deny_list_from_prefs.size()); + for (const base::Value& deny_list_value : deny_list_from_prefs) { const std::string& deny_list_str = deny_list_value.GetString(); mojom::PrinterType printer_type; if (deny_list_str == "extension") @@ -820,11 +813,11 @@ regenerate_preview_request_count_); } -void PrintPreviewHandler::GetLocaleInformation(base::Value* settings) { +void PrintPreviewHandler::GetLocaleInformation(base::Value::Dict* settings) { // Getting the measurement system based on the locale. UErrorCode errorCode = U_ZERO_ERROR; const char* locale = g_browser_process->GetApplicationLocale().c_str(); - settings->SetStringKey(kUiLocale, std::string(locale)); + settings->Set(kUiLocale, std::string(locale)); UMeasurementSystem system = ulocdata_getMeasurementSystem(locale, &errorCode); // On error, assume the units are SI. // Since the only measurement units print preview's WebUI cares about are @@ -842,9 +835,9 @@ size_t decimal_pos = number_format.find('6') + 1; DCHECK_NE(number_format[decimal_pos], '7'); std::u16string decimal_delimiter = number_format.substr(decimal_pos, 1); - settings->SetStringKey(kDecimalDelimiter, decimal_delimiter); - settings->SetStringKey(kThousandsDelimiter, thousands_delimiter); - settings->SetIntKey(kUnitType, system); + settings->Set(kDecimalDelimiter, decimal_delimiter); + settings->Set(kThousandsDelimiter, thousands_delimiter); + settings->Set(kUnitType, system); } void PrintPreviewHandler::HandleGetInitialSettings( @@ -856,20 +849,22 @@ AllowJavascript(); PrinterHandler* handler = GetPrinterHandler(mojom::PrinterType::kLocal); - base::OnceCallback<void(base::Value, const std::string&)> cb = + base::OnceCallback<void(base::Value::Dict, const std::string&)> cb = base::BindOnce(&PrintPreviewHandler::SendInitialSettings, weak_factory_.GetWeakPtr(), callback_id); #if BUILDFLAG(IS_CHROMEOS) if (!local_printer_) { LOG(ERROR) << "Local printer not available"; - handler->GetDefaultPrinter(base::BindOnce(std::move(cb), base::Value())); + handler->GetDefaultPrinter( + base::BindOnce(std::move(cb), base::Value::Dict())); return; } local_printer_->GetPolicies( base::BindOnce(PoliciesToValue) .Then(base::BindOnce( - [](base::OnceCallback<void(base::Value, const std::string&)> cb, - PrinterHandler* handler, base::Value policies) { + [](base::OnceCallback<void(base::Value::Dict, const std::string&)> + cb, + PrinterHandler* handler, base::Value::Dict policies) { handler->GetDefaultPrinter( base::BindOnce(std::move(cb), std::move(policies))); }, @@ -882,58 +877,55 @@ void PrintPreviewHandler::SendInitialSettings( const std::string& callback_id, - base::Value policies, + base::Value::Dict policies, const std::string& default_printer) { - base::Value initial_settings(base::Value::Type::DICTIONARY); - initial_settings.SetStringKey(kDocumentTitle, - print_preview_ui()->initiator_title()); - initial_settings.SetBoolKey(kSettingPreviewModifiable, - print_preview_ui()->source_is_modifiable()); + base::Value::Dict initial_settings; + initial_settings.Set(kDocumentTitle, print_preview_ui()->initiator_title()); + initial_settings.Set(kSettingPreviewModifiable, + print_preview_ui()->source_is_modifiable()); #if BUILDFLAG(IS_CHROMEOS_ASH) bool source_is_arc = print_preview_ui()->source_is_arc(); #else bool source_is_arc = false; #endif - initial_settings.SetBoolKey(kSettingPreviewIsFromArc, source_is_arc); - initial_settings.SetStringKey(kSettingPrinterName, default_printer); - initial_settings.SetBoolKey(kDocumentHasSelection, - print_preview_ui()->source_has_selection()); - initial_settings.SetBoolKey(kSettingShouldPrintSelectionOnly, - print_preview_ui()->print_selection_only()); + initial_settings.Set(kSettingPreviewIsFromArc, source_is_arc); + initial_settings.Set(kSettingPrinterName, default_printer); + initial_settings.Set(kDocumentHasSelection, + print_preview_ui()->source_has_selection()); + initial_settings.Set(kSettingShouldPrintSelectionOnly, + print_preview_ui()->print_selection_only()); PrefService* prefs = GetPrefs(); PrintPreviewStickySettings* sticky_settings = PrintPreviewStickySettings::GetInstance(); sticky_settings->RestoreFromPrefs(prefs); if (sticky_settings->printer_app_state()) { - initial_settings.SetStringKey(kAppState, - *sticky_settings->printer_app_state()); + initial_settings.Set(kAppState, *sticky_settings->printer_app_state()); } else { - initial_settings.SetKey(kAppState, base::Value()); + initial_settings.Set(kAppState, base::Value()); } - if (policies.is_dict() && !policies.DictEmpty()) - initial_settings.SetKey(kPolicies, std::move(policies)); + if (!policies.empty()) + initial_settings.Set(kPolicies, std::move(policies)); - initial_settings.SetBoolKey( + initial_settings.Set( kPdfPrinterDisabled, base::Contains(printer_type_deny_list_, mojom::PrinterType::kPdf)); const bool destinations_managed = !printer_type_deny_list_.empty() && prefs->IsManagedPreference(prefs::kPrinterTypeDenyList); - initial_settings.SetBoolKey(kDestinationsManaged, destinations_managed); + initial_settings.Set(kDestinationsManaged, destinations_managed); base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess(); - initial_settings.SetBoolKey(kIsInKioskAutoPrintMode, - cmdline->HasSwitch(switches::kKioskModePrinting)); - initial_settings.SetBoolKey(kIsInAppKioskMode, - chrome::IsRunningInForcedAppMode()); + initial_settings.Set(kIsInKioskAutoPrintMode, + cmdline->HasSwitch(switches::kKioskModePrinting)); + initial_settings.Set(kIsInAppKioskMode, chrome::IsRunningInForcedAppMode()); const std::string rules_str = prefs->GetString(prefs::kPrintPreviewDefaultDestinationSelectionRules); if (rules_str.empty()) { - initial_settings.SetKey(kDefaultDestinationSelectionRules, base::Value()); + initial_settings.Set(kDefaultDestinationSelectionRules, base::Value()); } else { - initial_settings.SetStringKey(kDefaultDestinationSelectionRules, rules_str); + initial_settings.Set(kDefaultDestinationSelectionRules, rules_str); } GetLocaleInformation(&initial_settings); @@ -942,8 +934,8 @@ drive::DriveIntegrationService* drive_service = drive::DriveIntegrationServiceFactory::GetForProfile( Profile::FromWebUI(web_ui())); - initial_settings.SetBoolKey(kIsDriveMounted, - drive_service && drive_service->IsMounted()); + initial_settings.Set(kIsDriveMounted, + drive_service && drive_service->IsMounted()); #elif BUILDFLAG(IS_CHROMEOS_LACROS) if (drive_integration_service_) { drive_integration_service_->GetMountPointPath(base::BindOnce( @@ -957,10 +949,10 @@ } #if BUILDFLAG(IS_CHROMEOS_LACROS) -void PrintPreviewHandler::OnDrivePathReady(base::Value initial_settings, +void PrintPreviewHandler::OnDrivePathReady(base::Value::Dict initial_settings, const std::string& callback_id, const base::FilePath& drive_path) { - initial_settings.SetBoolKey(kIsDriveMounted, !drive_path.empty()); + initial_settings.Set(kIsDriveMounted, !drive_path.empty()); ResolveJavascriptCallback(base::Value(callback_id), initial_settings); } #endif @@ -975,8 +967,7 @@ // Check that |settings_info| is valid. if (settings_info.FindDict(kSettingCapabilities)) { VLOG(1) << "Get printer capabilities finished"; - ResolveJavascriptCallback(base::Value(callback_id), - base::Value(std::move(settings_info))); + ResolveJavascriptCallback(base::Value(callback_id), settings_info); return; } @@ -1147,8 +1138,7 @@ const size_t printer_count = printers.size(); DCHECK(printer_count); FireWebUIListener("printers-added", - base::Value(static_cast<int>(printer_type)), - base::Value(std::move(printers))); + base::Value(static_cast<int>(printer_type)), printers); if (printer_type == mojom::PrinterType::kLocal && !has_logged_printers_count_) {
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_handler.h b/chrome/browser/ui/webui/print_preview/print_preview_handler.h index ecfcd52..7e54b4e 100644 --- a/chrome/browser/ui/webui/print_preview/print_preview_handler.h +++ b/chrome/browser/ui/webui/print_preview/print_preview_handler.h
@@ -213,12 +213,12 @@ void HandleManagePrinters(const base::Value::List& args); void SendInitialSettings(const std::string& callback_id, - base::Value policies, + base::Value::Dict policies, const std::string& default_printer); #if BUILDFLAG(IS_CHROMEOS_LACROS) // Sets |kIsDriveMounted| for Lacros chrome then returns the initial settings. - void OnDrivePathReady(base::Value initial_settings, + void OnDrivePathReady(base::Value::Dict initial_settings, const std::string& callback_id, const base::FilePath& drive_path); #endif @@ -236,10 +236,10 @@ void ClearInitiatorDetails(); // Populates |settings| according to the current locale. - void GetLocaleInformation(base::Value* settings); + void GetLocaleInformation(base::Value::Dict* settings); // Populates |settings| with the list of logged in accounts. - void GetUserAccountList(base::Value* settings); + void GetUserAccountList(base::Value::Dict* settings); PdfPrinterHandler* GetPdfPrinterHandler();
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_handler_chromeos.cc b/chrome/browser/ui/webui/print_preview/print_preview_handler_chromeos.cc index 47f9e3f..0ecc9a59 100644 --- a/chrome/browser/ui/webui/print_preview/print_preview_handler_chromeos.cc +++ b/chrome/browser/ui/webui/print_preview/print_preview_handler_chromeos.cc
@@ -259,10 +259,20 @@ PrinterHandler* handler = GetPrinterHandler(mojom::PrinterType::kLocal); handler->StartPrinterStatusRequest( printer_id, - base::BindOnce(&PrintPreviewHandlerChromeOS::ResolveJavascriptCallback, + base::BindOnce(&PrintPreviewHandlerChromeOS:: + HandleRequestPrinterStatusUpdateCompletion, weak_factory_.GetWeakPtr(), base::Value(callback_id))); } +void PrintPreviewHandlerChromeOS::HandleRequestPrinterStatusUpdateCompletion( + base::Value callback_id, + absl::optional<base::Value::Dict> result) { + if (result) + ResolveJavascriptCallback(callback_id, *result); + else + ResolveJavascriptCallback(callback_id, base::Value()); +} + void PrintPreviewHandlerChromeOS::HandleChoosePrintServers( const base::Value::List& args) { CHECK_EQ(1U, args.size());
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_handler_chromeos.h b/chrome/browser/ui/webui/print_preview/print_preview_handler_chromeos.h index cb80912c..9e1d3c3e 100644 --- a/chrome/browser/ui/webui/print_preview/print_preview_handler_chromeos.h +++ b/chrome/browser/ui/webui/print_preview/print_preview_handler_chromeos.h
@@ -93,6 +93,9 @@ // Called to initiate a status request for a printer. void HandleRequestPrinterStatusUpdate(const base::Value::List& args); + void HandleRequestPrinterStatusUpdateCompletion( + base::Value callback_id, + absl::optional<base::Value::Dict> result); // crosapi::mojom::PrintServerObserver Implementation void OnPrintServersChanged(
diff --git a/chrome/browser/ui/webui/print_preview/printer_handler.h b/chrome/browser/ui/webui/print_preview/printer_handler.h index 17b57dbe..2738254 100644 --- a/chrome/browser/ui/webui/print_preview/printer_handler.h +++ b/chrome/browser/ui/webui/print_preview/printer_handler.h
@@ -52,8 +52,8 @@ #if BUILDFLAG(IS_CHROMEOS) using GetEulaUrlCallback = base::OnceCallback<void(const std::string& license)>; - using PrinterStatusRequestCallback = - base::OnceCallback<void(const base::Value& cups_printer_status)>; + using PrinterStatusRequestCallback = base::OnceCallback<void( + absl::optional<base::Value::Dict> cups_printer_status)>; #endif // Creates an instance of a PrinterHandler for extension printers.
diff --git a/chrome/browser/ui/webui/settings/chromeos/privacy_hub_handler_unittest.cc b/chrome/browser/ui/webui/settings/chromeos/privacy_hub_handler_unittest.cc index 6143c823..28d3016 100644 --- a/chrome/browser/ui/webui/settings/chromeos/privacy_hub_handler_unittest.cc +++ b/chrome/browser/ui/webui/settings/chromeos/privacy_hub_handler_unittest.cc
@@ -77,8 +77,8 @@ // Assume that the data is stored in the last valid arg. for (const auto& arg : base::Reversed(data->args())) { - if (arg && arg.get() != data->arg1()) - return arg->Clone(); + if (&arg != data->arg1()) + return arg.Clone(); } }
diff --git a/chrome/browser/ui/webui/settings/reset_settings_handler.cc b/chrome/browser/ui/webui/settings/reset_settings_handler.cc index 0e5399aa..f1c21916a 100644 --- a/chrome/browser/ui/webui/settings/reset_settings_handler.cc +++ b/chrome/browser/ui/webui/settings/reset_settings_handler.cc
@@ -186,9 +186,9 @@ } void ResetSettingsHandler::OnGetReportedSettingsDone(std::string callback_id) { - std::unique_ptr<base::ListValue> list = + base::Value::List list = GetReadableFeedbackForSnapshot(profile_, *setting_snapshot_); - ResolveJavascriptCallback(base::Value(callback_id), *list); + ResolveJavascriptCallback(base::Value(callback_id), list); } void ResetSettingsHandler::OnShowResetProfileDialog(
diff --git a/chrome/browser/ui/webui/settings/settings_ui.cc b/chrome/browser/ui/webui/settings/settings_ui.cc index 692727a..2166675c 100644 --- a/chrome/browser/ui/webui/settings/settings_ui.cc +++ b/chrome/browser/ui/webui/settings/settings_ui.cc
@@ -94,9 +94,9 @@ #include "chrome/browser/ui/webui/settings/languages_handler.h" #endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_CHROMEOS_ASH) -#if !BUILDFLAG(IS_CHROMEOS) +#if !BUILDFLAG(IS_CHROMEOS_ASH) #include "components/language/core/common/language_experiments.h" -#endif // !BUILDFLAG(IS_CHROMEOS) +#endif // !BUILDFLAG(IS_CHROMEOS_ASH) #if BUILDFLAG(IS_CHROMEOS_ASH) #include "ash/components/account_manager/account_manager_factory.h" @@ -301,11 +301,11 @@ base::FeatureList::IsEnabled( password_manager::features::kPasswordChangeInSettings)); -#if !BUILDFLAG(IS_CHROMEOS) +#if !BUILDFLAG(IS_CHROMEOS_ASH) html_source->AddBoolean( "enableDesktopDetailedLanguageSettings", base::FeatureList::IsEnabled(language::kDesktopDetailedLanguageSettings)); -#endif // !BUILDFLAG(IS_CHROMEOS) +#endif // !BUILDFLAG(IS_CHROMEOS_ASH) #if BUILDFLAG(IS_CHROMEOS_ASH) html_source->AddBoolean(
diff --git a/chrome/browser/ui/webui/signin/signin_url_utils.h b/chrome/browser/ui/webui/signin/signin_url_utils.h index aa4c86e..4f78f488 100644 --- a/chrome/browser/ui/webui/signin/signin_url_utils.h +++ b/chrome/browser/ui/webui/signin/signin_url_utils.h
@@ -9,10 +9,11 @@ #include "components/signin/public/base/signin_metrics.h" #include "url/gurl.h" +// Keep enum values in sync with the JS tests defined in signin_browsertest.js. enum class SyncConfirmationStyle { - kDefaultModal, - kSigninInterceptModal, - kWindow + kDefaultModal = 0, + kSigninInterceptModal = 1, + kWindow = 2 }; // Returns which style the sync confirmation page is using, as a default modal
diff --git a/chrome/browser/ui/webui/translate_internals/chrome_translate_internals_handler.cc b/chrome/browser/ui/webui/translate_internals/chrome_translate_internals_handler.cc index 828ab97..1a316a7 100644 --- a/chrome/browser/ui/webui/translate_internals/chrome_translate_internals_handler.cc +++ b/chrome/browser/ui/webui/translate_internals/chrome_translate_internals_handler.cc
@@ -50,13 +50,13 @@ } void ChromeTranslateInternalsHandler::RegisterMessageCallback( - const std::string& message, + base::StringPiece message, MessageCallback callback) { web_ui()->RegisterMessageCallback(message, std::move(callback)); } void ChromeTranslateInternalsHandler::CallJavascriptFunction( - const std::string& function_name, + base::StringPiece function_name, base::span<const base::ValueView> args) { web_ui()->CallJavascriptFunctionUnsafe(function_name, args); }
diff --git a/chrome/browser/ui/webui/translate_internals/chrome_translate_internals_handler.h b/chrome/browser/ui/webui/translate_internals/chrome_translate_internals_handler.h index 40191f0..0b80e2a 100644 --- a/chrome/browser/ui/webui/translate_internals/chrome_translate_internals_handler.h +++ b/chrome/browser/ui/webui/translate_internals/chrome_translate_internals_handler.h
@@ -5,8 +5,6 @@ #ifndef CHROME_BROWSER_UI_WEBUI_TRANSLATE_INTERNALS_CHROME_TRANSLATE_INTERNALS_HANDLER_H_ #define CHROME_BROWSER_UI_WEBUI_TRANSLATE_INTERNALS_CHROME_TRANSLATE_INTERNALS_HANDLER_H_ -#include <string> - #include "base/callback_list.h" #include "components/translate/translate_internals/translate_internals_handler.h" #include "content/public/browser/web_ui_message_handler.h" @@ -28,9 +26,9 @@ // translate::TranslateInternalsHandler. translate::TranslateClient* GetTranslateClient() override; variations::VariationsService* GetVariationsService() override; - void RegisterMessageCallback(const std::string& message, + void RegisterMessageCallback(base::StringPiece message, MessageCallback callback) override; - void CallJavascriptFunction(const std::string& function_name, + void CallJavascriptFunction(base::StringPiece function_name, base::span<const base::ValueView> args) override; // content::WebUIMessageHandler methods:
diff --git a/chrome/browser/web_applications/app_service/web_app_publisher_helper.cc b/chrome/browser/web_applications/app_service/web_app_publisher_helper.cc index d5b20c3f..3247edc 100644 --- a/chrome/browser/web_applications/app_service/web_app_publisher_helper.cc +++ b/chrome/browser/web_applications/app_service/web_app_publisher_helper.cc
@@ -600,12 +600,11 @@ if (all_file_handlers && !all_file_handlers->empty()) { std::set<std::string> extensions_set = apps::GetFileExtensionsFromFileHandlers(*all_file_handlers); - app->intent_filters.push_back(apps::ConvertMojomIntentFilterToIntentFilter( - apps_util::CreateFileFilter( - {apps_util::kIntentActionPotentialFileHandler}, - /*mime_types=*/{}, - /*file_extensions=*/ - {extensions_set.begin(), extensions_set.end()}))); + app->intent_filters.push_back(apps_util::CreateFileFilter( + {apps_util::kIntentActionPotentialFileHandler}, + /*mime_types=*/{}, + /*file_extensions=*/ + {extensions_set.begin(), extensions_set.end()})); } if (IsNoteTakingWebApp(*web_app)) @@ -616,12 +615,11 @@ #if BUILDFLAG(IS_CHROMEOS_ASH) if (web_app->app_id() == guest_os::kTerminalSystemAppId) { - app->intent_filters.push_back(apps::ConvertMojomIntentFilterToIntentFilter( - apps_util::CreateFileFilter( - {apps_util::kIntentActionView}, - /*mime_types=*/ - {extensions::app_file_handler_util::kMimeTypeInodeDirectory}, - /*file_extensions=*/{}))); + app->intent_filters.push_back(apps_util::CreateFileFilter( + {apps_util::kIntentActionView}, + /*mime_types=*/ + {extensions::app_file_handler_util::kMimeTypeInodeDirectory}, + /*file_extensions=*/{})); } #endif
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt index c1ea4be..30e2fd1 100644 --- a/chrome/build/linux.pgo.txt +++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@ -chrome-linux-main-1659484575-aa21dd6c3c2af862c5f0f8787701a08eec85a7c3.profdata +chrome-linux-main-1659505904-cb9abb091024ee19865c95d562f565a4ed60f6da.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt index 6f63074..ddb13b6 100644 --- a/chrome/build/mac-arm.pgo.txt +++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@ -chrome-mac-arm-main-1659484575-8635c2ba0f24232a06db0b706ec75bb9e41f9480.profdata +chrome-mac-arm-main-1659505904-89e971e3c599a012db0555602c13bc00bddf6a33.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt index 404552d..1fce8da 100644 --- a/chrome/build/mac.pgo.txt +++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@ -chrome-mac-main-1659484575-37bf97f4195514edfb49b625a622265894788433.profdata +chrome-mac-main-1659505904-90cd344349313ba7965827550accab4af50c8300.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt index f5c27fb..5de04ee 100644 --- a/chrome/build/win32.pgo.txt +++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@ -chrome-win32-main-1659462943-7492dd0f78b6af43a1eeadd05f98b57f42975de8.profdata +chrome-win32-main-1659505904-83e0fdaf4082098625a4e221f09c10556f9d6c2f.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt index 558a937..c6e1e91 100644 --- a/chrome/build/win64.pgo.txt +++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@ -chrome-win64-main-1659473906-e142187540b19655958f4ad02997f41054724f8f.profdata +chrome-win64-main-1659505904-f391b83b373a0e16fcf7d6f7f71e33eefc87dab9.profdata
diff --git a/chrome/chrome_paks.gni b/chrome/chrome_paks.gni index 67ac969..66ce488 100644 --- a/chrome/chrome_paks.gni +++ b/chrome/chrome_paks.gni
@@ -147,7 +147,7 @@ "$root_gen_dir/chrome/dev_ui_resources.pak", "$root_gen_dir/chrome/downloads_resources.pak", "$root_gen_dir/chrome/feed_resources.pak", - "$root_gen_dir/chrome/feedback_webui_resources.pak", + "$root_gen_dir/chrome/feedback_resources.pak", "$root_gen_dir/chrome/gaia_auth_host_resources.pak", "$root_gen_dir/chrome/history_resources.pak", "$root_gen_dir/chrome/identity_internals_resources.pak", @@ -181,7 +181,7 @@ "//chrome/browser/resources/commander:resources", "//chrome/browser/resources/downloads:resources", "//chrome/browser/resources/feed:resources", - "//chrome/browser/resources/feedback_webui:resources", + "//chrome/browser/resources/feedback:resources", "//chrome/browser/resources/gaia_auth_host:resources", "//chrome/browser/resources/history:resources", "//chrome/browser/resources/identity_internals:resources",
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc index 182fbb5..965fa32 100644 --- a/chrome/common/chrome_features.cc +++ b/chrome/common/chrome_features.cc
@@ -584,6 +584,11 @@ const base::Feature kIncognitoNtpRevamp{"IncognitoNtpRevamp", base::FEATURE_DISABLED_BY_DEFAULT}; +#if BUILDFLAG(IS_CHROMEOS) +const base::Feature kKioskEnableAppService("KioskEnableAppService", + base::FEATURE_DISABLED_BY_DEFAULT); +#endif // BUILDFLAG(IS_CHROMEOS) + // When enabled, removes any entry points to the history UI from Incognito mode. const base::Feature kUpdateHistoryEntryPointsInIncognito{ "UpdateHistoryEntryPointsInIncognito", base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h index 6472420..38f02a5 100644 --- a/chrome/common/chrome_features.h +++ b/chrome/common/chrome_features.h
@@ -412,6 +412,11 @@ COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kIncognitoNtpRevamp; +#if BUILDFLAG(IS_CHROMEOS) +COMPONENT_EXPORT(CHROME_FEATURES) +extern const base::Feature kKioskEnableAppService; +#endif + COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kUpdateHistoryEntryPointsInIncognito;
diff --git a/chrome/installer/util/shell_util_interactive_uitest.cc b/chrome/installer/util/shell_util_interactive_uitest.cc index 3af0f07..e8b3b10 100644 --- a/chrome/installer/util/shell_util_interactive_uitest.cc +++ b/chrome/installer/util/shell_util_interactive_uitest.cc
@@ -15,12 +15,14 @@ #include "base/strings/strcat.h" #include "base/strings/utf_string_conversions.h" #include "base/test/test_reg_util_win.h" +#include "base/types/pass_key.h" #include "base/win/com_init_util.h" #include "base/win/registry.h" #include "base/win/scoped_co_mem.h" #include "base/win/windows_version.h" #include "chrome/installer/util/util_constants.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace { @@ -41,34 +43,46 @@ // restoring it at destruction. class ScopedCopyRegKey { public: - // |to| must outlive this object. - ScopedCopyRegKey(const base::win::RegKey& from, - base::win::RegKey& to, - const wchar_t* key) - : to_(to), key_(key) { - base::win::RegKey exists_key(to_.Handle(), key_.c_str(), - KEY_READ | KEY_WRITE); + // absl::optional requires a public constructor, so the constructor requires + // a passkey to ensure callers use Create() to create this object. + using ConstructorPassKey = base::PassKey<ScopedCopyRegKey>; + + // Copies |from|\|key| to |to|\|key|, preserving |to|\|key| and restoring it + // at destruction. Returns nullopt upon failure of preserving |to|. |to| must + // outlive this object. + static absl::optional<ScopedCopyRegKey> Create(const base::win::RegKey& from, + base::win::RegKey& to, + const std::wstring& key) { + absl::optional<ScopedCopyRegKey> copy_regkey; + std::wstring temp_key_name; + base::win::RegKey exists_key(to.Handle(), key.c_str(), KEY_READ); if (exists_key.Valid()) { - temp_key_name_ = + temp_key_name = base::StrCat({L"Temp-", base::ASCIIToWide(base::GenerateGUID())}); LONG result = - RegRenameKey(to_.Handle(), key_.c_str(), temp_key_name_.c_str()); + RegRenameKey(to.Handle(), key.c_str(), temp_key_name.c_str()); if (result != ERROR_SUCCESS) { ADD_FAILURE() << "Registry Initial Rename Failed " << result; - temp_key_name_.clear(); - return; + return copy_regkey; } } - base::win::RegKey orig_key(from.Handle(), key_.c_str(), KEY_READ); - base::win::RegKey dest_key(to_.Handle(), key_.c_str(), KEY_WRITE); + base::win::RegKey orig_key(from.Handle(), key.c_str(), KEY_READ); + base::win::RegKey dest_key(to.Handle(), key.c_str(), KEY_WRITE); CopyRecursively(orig_key, dest_key); - copied_ = true; + copy_regkey.emplace(to, key, temp_key_name, ConstructorPassKey()); + return copy_regkey; } + // |to| must outlive this object. + ScopedCopyRegKey(base::win::RegKey& to, + const std::wstring& key, + const std::wstring& temp_key_name, + ConstructorPassKey passkey) + : to_(to), key_(key), temp_key_name_(temp_key_name) {} + ~ScopedCopyRegKey() { - if (copied_) - to_.DeleteKey(key_.c_str()); + to_.DeleteKey(key_.c_str()); if (!temp_key_name_.empty()) { LONG result = @@ -98,9 +112,8 @@ // This RegKey must outlive this class. base::win::RegKey& to_; - std::wstring key_; - std::wstring temp_key_name_; - bool copied_ = false; + const std::wstring key_; + const std::wstring temp_key_name_; }; } // namespace @@ -163,8 +176,9 @@ // to the underlying HKCU if necessary for correct functionality. base::win::RegKey redirected_hkcu_classes(HKEY_CURRENT_USER, L"Software\\Classes", KEY_READ); - ScopedCopyRegKey copy_regkey(redirected_hkcu_classes, original_hkcu_classes, - prog_id.c_str()); + absl::optional<ScopedCopyRegKey> copy_regkey = ScopedCopyRegKey::Create( + redirected_hkcu_classes, original_hkcu_classes, prog_id.c_str()); + ASSERT_TRUE(copy_regkey); // If the expectations fail below, the default browser mechanism has changed // and will need to be reexamined.
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 0119e51..5dd2bc55 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -7069,6 +7069,7 @@ "../browser/apps/app_service/file_utils_unittest.cc", "../browser/apps/app_service/metrics/app_platform_metrics_service_unittest.cc", "../browser/apps/app_service/publishers/arc_apps_unittest.cc", + "../browser/apps/app_service/publishers/crostini_apps_unittest.cc", "../browser/apps/app_service/webapk/webapk_install_task_unittest.cc", "../browser/apps/app_service/webapk/webapk_manager_unittest.cc", "../browser/ash/attestation/attestation_policy_unittest.cc",
diff --git a/chrome/test/data/extensions/api_test/terminal/component_extension/test.js b/chrome/test/data/extensions/api_test/terminal/component_extension/test.js index d501436c..55ab612 100644 --- a/chrome/test/data/extensions/api_test/terminal/component_extension/test.js +++ b/chrome/test/data/extensions/api_test/terminal/component_extension/test.js
@@ -9,8 +9,6 @@ // Ensure this has all distinct characters. var testLine = 'abcdefgh\n'; -var startChar = '#'; - var croshName = 'crosh'; var invalidName = 'some name'; @@ -28,8 +26,15 @@ this.id_ = id; this.type_= type; - // Text received before we start matching lines. + // Start text to receive before we start matching lines. + // We receive 2x each of: + // type=stdout | type=stderr + // shell\r\n 7 | shell\r\n 7 + // cat\r\n 5 | cat 1>&2\r\n 10 + // --------------------------------- + // 2 x SUM: 24 | 34 this.startText_ = ''; + this.startTextLength_ = type === 'stdout' ? 24 : 34; this.lineExpectation_ = ''; this.linesLeftToCheck_ = -1; @@ -50,13 +55,13 @@ // algorithm to work. TestProcess.prototype.testExpectation = function(text) { chrome.test.assertTrue(this.linesLeftToCheck_ >= 0, - "Test expectations not set.") + 'Test expectations not set.') for (var i = 0; i < text.length; i++) { if (this.processReceivedCharacter_(text[i], 0)) continue; if (this.processReceivedCharacter_(text[i], 1)) continue; - chrome.test.fail("Received: [" + text + "]"); + chrome.test.fail('Received: [' + text + ']'); } }; @@ -108,24 +113,23 @@ }; TestProcess.prototype.getCatCommand = function() { - if (this.type_ == "stdout") + if (this.type_ == 'stdout') return catCommand; return catErrCommand; }; TestProcess.prototype.addLineExpectation = function(line, times) { - this.lineExpectation_ = line.replace(/\n/g, "\r\n"); + this.lineExpectation_ = line.replace(/\n/g, '\r\n'); this.linesLeftToCheck_ = times - 2; }; -// Set of commands we use to setup terminal for testing (start cat) will produce -// some output. We don't care about that output, to avoid having to set that -// output in test expectations, we will send |startChar| right after cat is -// started. After we detect `${startChar}\r\n${startChar}\r\n` in output, we -// know process won't produce any output by itself, so it is safe to start test. +// We first call 'shell' and 'cat' (stdout) / 'cat 1>&2' (stderr) to set up the +// terminal. We start testing once we have received this text. TestProcess.prototype.maybeKickOffTest = function(text) { this.startText_ += text; - if (this.startText_.indexOf(`${startChar}\r\n${startChar}\r\n`) !== -1) { + if (this.startText_.length > this.startTextLength_) { + chrome.test.fail('Unexpected start text: [' + this.startText_ + ']'); + } else if (this.startText_.length === this.startTextLength_) { this.kickOffTest_(testLine, testLineNum); } }; @@ -196,23 +200,12 @@ }; function initTest(process) { - var sendStartChar = function() { - chrome.terminalPrivate.sendInput( - process.id(), - startChar + '\n', - function(result) { - chrome.test.assertTrue(result); - } - ); - }; - var startCat = function() { chrome.terminalPrivate.sendInput( process.id(), process.getCatCommand(), function(result) { chrome.test.assertTrue(result); - sendStartChar(); } ); };
diff --git a/chrome/test/data/webui/cr_elements/cr_fingerprint_progress_arc_tests.ts b/chrome/test/data/webui/cr_elements/cr_fingerprint_progress_arc_tests.ts index 628ea6e..fe5ffe7 100644 --- a/chrome/test/data/webui/cr_elements/cr_fingerprint_progress_arc_tests.ts +++ b/chrome/test/data/webui/cr_elements/cr_fingerprint_progress_arc_tests.ts
@@ -4,7 +4,7 @@ import 'chrome://resources/cr_elements/cr_lottie/cr_lottie.m.js'; -import {CrFingerprintProgressArcElement, FINGERPRINT_CHECK_DARK_URL, FINGERPRINT_CHECK_LIGHT_URL, FINGERPRINT_SCANNED_ICON_DARK, FINGERPRINT_SCANNED_ICON_LIGHT, PROGRESS_CIRCLE_BACKGROUND_COLOR_DARK, PROGRESS_CIRCLE_BACKGROUND_COLOR_LIGHT, PROGRESS_CIRCLE_FILL_COLOR_DARK, PROGRESS_CIRCLE_FILL_COLOR_LIGHT} from 'chrome://resources/cr_elements/cr_fingerprint/cr_fingerprint_progress_arc.m.js'; +import {CrFingerprintProgressArcElement, FINGERPRINT_CHECK_DARK_URL, FINGERPRINT_CHECK_LIGHT_URL, FINGERPRINT_SCANNED_ICON_DARK, FINGERPRINT_SCANNED_ICON_LIGHT, PROGRESS_CIRCLE_BACKGROUND_COLOR_DARK, PROGRESS_CIRCLE_BACKGROUND_COLOR_LIGHT, PROGRESS_CIRCLE_FILL_COLOR_DARK, PROGRESS_CIRCLE_FILL_COLOR_LIGHT} from 'chrome://resources/cr_elements/cr_fingerprint/cr_fingerprint_progress_arc.js'; import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {assertEquals} from 'chrome://webui-test/chai_assert.js'; import {MockController} from 'chrome://webui-test/mock_controller.js';
diff --git a/chrome/test/data/webui/settings/BUILD.gn b/chrome/test/data/webui/settings/BUILD.gn index 9f533df..cec9d13 100644 --- a/chrome/test/data/webui/settings/BUILD.gn +++ b/chrome/test/data/webui/settings/BUILD.gn
@@ -37,6 +37,7 @@ "test_languages_browser_proxy.ts", "spell_check_page_tests.ts", "languages_page_metrics_test_browser.ts", + "spell_check_page_metrics_test_browser.ts", ] }
diff --git a/chrome/test/data/webui/settings/cr_settings_browsertest.js b/chrome/test/data/webui/settings/cr_settings_browsertest.js index 3fc8c84..3cd5106 100644 --- a/chrome/test/data/webui/settings/cr_settings_browsertest.js +++ b/chrome/test/data/webui/settings/cr_settings_browsertest.js
@@ -127,7 +127,6 @@ mocha.grep(languages_page_tests.TestNames.LanguageMenu).run(); }); -GEN('#if !BUILDFLAG(IS_CHROMEOS_LACROS)'); var CrSettingsLanguagesPageDetailedTest = class extends CrSettingsBrowserTest { /** @override */ @@ -150,7 +149,6 @@ mocha.grep(languages_page_details_tests.TestNames.NeverTranslateDialog) .run(); }); -GEN('#endif'); var CrSettingsLanguagesPageMetricsTest = class extends CrSettingsBrowserTest { /** @override */ @@ -165,6 +163,29 @@ runMochaSuite('LanguagesPageMetricsBrowser'); }); +var CrSettingsSpellCheckPageMetricsTest = class extends CrSettingsBrowserTest { + /** @override */ + get browsePreload() { + return 'chrome://settings/test_loader.html?module=settings/spell_check_page_metrics_test_browser.js'; + } +}; + +TEST_F('CrSettingsSpellCheckPageMetricsTest', 'SpellCheckMetrics', function() { + mocha.grep(spell_check_page_metrics_test_browser.TestNames.SpellCheckMetrics).run(); +}); + +GEN('#if BUILDFLAG(GOOGLE_CHROME_BRANDING)'); +TEST_F('CrSettingsSpellCheckPageMetricsTest', 'SpellCheckMetricsOfficialBuild', function() { + mocha.grep(spell_check_page_metrics_test_browser.TestNames.SpellCheckMetricsOfficialBuild).run(); +}); +GEN('#endif'); + +GEN('#if !BUILDFLAG(IS_MAC)'); +TEST_F('CrSettingsSpellCheckPageMetricsTest', 'SpellCheckMetricsNotMacOSx', function() { + mocha.grep(spell_check_page_metrics_test_browser.TestNames.SpellCheckMetricsNotMacOSx).run(); +}); +GEN('#endif'); + GEN('#endif // !BUILDFLAG(IS_CHROMEOS_ASH)'); var CrSettingsClearBrowsingDataTest = class extends CrSettingsBrowserTest {
diff --git a/chrome/test/data/webui/settings/spell_check_page_metrics_test_browser.ts b/chrome/test/data/webui/settings/spell_check_page_metrics_test_browser.ts new file mode 100644 index 0000000..9902d56 --- /dev/null +++ b/chrome/test/data/webui/settings/spell_check_page_metrics_test_browser.ts
@@ -0,0 +1,209 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {LanguageHelper, LanguagesBrowserProxyImpl, LanguageSettingsActionType, LanguageSettingsMetricsProxy, LanguageSettingsMetricsProxyImpl, LanguageSettingsPageImpressionType, SettingsSpellCheckPageElement} from 'chrome://settings/lazy_load.js'; +import {CrSettingsPrefs} from 'chrome://settings/settings.js'; +import {assertEquals, assertTrue} from 'chrome://webui-test/chai_assert.js'; +import {TestBrowserProxy} from 'chrome://webui-test/test_browser_proxy.js'; +import {fakeDataBind} from 'chrome://webui-test/test_util.js'; + +import {FakeLanguageSettingsPrivate, getFakeLanguagePrefs} from './fake_language_settings_private.js'; +import {FakeSettingsPrivate} from './fake_settings_private.js'; +import {TestLanguagesBrowserProxy} from './test_languages_browser_proxy.js'; + +const spell_check_page_metrics_test_browser = { + TestNames: { + SpellCheckMetrics: 'spell_check_metrics_all', + // <if expr="_google_chrome"> + SpellCheckMetricsOfficialBuild: 'spell_check_metrics_official', + // </if> + // <if expr="not is_macosx"> + SpellCheckMetricsNotMacOSx: 'spell_check_not_macosx', + // </if> + }, +}; + +Object.assign(window, {spell_check_page_metrics_test_browser}); + +/** + * A test version of LanguageSettingsMetricsProxy. + */ +class TestSpellCheckSettingsMetricsProxy extends TestBrowserProxy implements + LanguageSettingsMetricsProxy { + constructor() { + super(['recordSettingsMetric', 'recordPageImpressionMetric']); + } + + recordSettingsMetric(interaction: LanguageSettingsActionType) { + this.methodCalled('recordSettingsMetric', interaction); + } + + recordPageImpressionMetric(interaction: LanguageSettingsPageImpressionType) { + this.methodCalled('recordPageImpressionMetric', interaction); + } +} + +suite('SpellCheckPageMetricsBrowser', function() { + let languageHelper: LanguageHelper; + let spellCheckPage: SettingsSpellCheckPageElement; + let browserProxy: TestLanguagesBrowserProxy; + let languageSettingsMetricsProxy: TestSpellCheckSettingsMetricsProxy; + + suiteSetup(function() { + CrSettingsPrefs.deferInitialization = true; + }); + + setup(function() { + document.body.innerHTML = ''; + const settingsPrefs = document.createElement('settings-prefs'); + const settingsPrivate = new FakeSettingsPrivate(getFakeLanguagePrefs()) as + unknown as typeof chrome.settingsPrivate; + settingsPrefs.initialize(settingsPrivate); + document.body.appendChild(settingsPrefs); + return CrSettingsPrefs.initialized.then(function() { + // Sets up test browser proxy. + browserProxy = new TestLanguagesBrowserProxy(); + LanguagesBrowserProxyImpl.setInstance(browserProxy); + + // Sets up test browser proxy. + languageSettingsMetricsProxy = new TestSpellCheckSettingsMetricsProxy(); + LanguageSettingsMetricsProxyImpl.setInstance( + languageSettingsMetricsProxy); + + // Sets up fake languageSettingsPrivate API. + const languageSettingsPrivate = browserProxy.getLanguageSettingsPrivate(); + (languageSettingsPrivate as unknown as FakeLanguageSettingsPrivate) + .setSettingsPrefs(settingsPrefs); + + const settingsLanguages = document.createElement('settings-languages'); + settingsLanguages.prefs = settingsPrefs.prefs; + fakeDataBind(settingsPrefs, settingsLanguages, 'prefs'); + document.body.appendChild(settingsLanguages); + + spellCheckPage = document.createElement('settings-spell-check-page'); + + // Prefs would normally be data-bound to settings-languages-page. + spellCheckPage.prefs = settingsLanguages.prefs; + fakeDataBind(settingsLanguages, spellCheckPage, 'prefs'); + + spellCheckPage.languageHelper = settingsLanguages.languageHelper; + fakeDataBind(settingsLanguages, spellCheckPage, 'language-helper'); + + spellCheckPage.languages = settingsLanguages.languages; + fakeDataBind(settingsLanguages, spellCheckPage, 'languages'); + + document.body.appendChild(spellCheckPage); + languageHelper = spellCheckPage.languageHelper; + return languageHelper.whenReady(); + }); + }); + + teardown(function() { + document.body.innerHTML = ''; + }); + + suite(spell_check_page_metrics_test_browser.TestNames.SpellCheckMetrics, function() { + test('records when disabling spellCheck globally', async () => { + spellCheckPage.setPrefValue('browser.enable_spellchecking', true); + const spellCheckToggle = spellCheckPage.shadowRoot! + .querySelector<HTMLElement>('#enableSpellcheckingToggle'); + assertTrue(!!spellCheckToggle, 'no spellCheckToggle'); + spellCheckToggle.click(); + flush(); + + assertEquals( + LanguageSettingsActionType.DISABLE_SPELL_CHECK_GLOBALLY, + await languageSettingsMetricsProxy.whenCalled('recordSettingsMetric')); + }); + + test('records when enabling spellCheck globally', async () => { + spellCheckPage.setPrefValue('browser.enable_spellchecking', false); + + const spellCheckToggle = spellCheckPage.shadowRoot! + .querySelector<HTMLElement>('#enableSpellcheckingToggle'); + assertTrue(!!spellCheckToggle); + spellCheckToggle.click(); + flush(); + + assertEquals( + LanguageSettingsActionType.ENABLE_SPELL_CHECK_GLOBALLY, + await languageSettingsMetricsProxy.whenCalled('recordSettingsMetric')); + }); + }); + + // <if expr="_google_chrome"> + suite(spell_check_page_metrics_test_browser.TestNames.SpellCheckMetricsOfficialBuild, function() { + test('records when selecing basic spell check', async () => { + spellCheckPage.setPrefValue('spellcheck.use_spelling_service', true); + const basicServiceSelect = spellcheckPage.shadowRoot! + .querySelector<HTMLElement>('#spellingServiceDisable'); + assertTrue(!!basicServiceSelect); + basicServiceSelect.click(); + flush(); + + assertEquals( + LanguageSettingsActionType.SELECT_BASIC_SPELL_CHECK, + await languageSettingsMetricsProxy.whenCalled('recordSettingsMetric')); + }); + + test('records when selecing enhanced spell check', async () => { + spellCheckPage.setPrefValue('spellcheck.use_spelling_service', false); + const enhancedServiceSelect = spellcheckPage.shadowRoot! + .querySelector<HTMLElement>('#spellingServiceEnable'); + assertTrue(!!enhancedServiceSelect); + enhancedServiceSelect.click(); + flush(); + + assertEquals( + LanguageSettingsActionType.SELECT_ENHANCED_SPELL_CHECK, + await languageSettingsMetricsProxy.whenCalled('recordSettingsMetric')); + }); + }); + // </if> + + // <if expr="not is_macosx"> + suite(spell_check_page_metrics_test_browser.TestNames.SpellCheckMetricsNotMacOSx, function() { + test('records when enabling spellCheck for a language', async () => { + spellCheckPage.setPrefValue('browser.enable_spellchecking', true); + // enable language with support for spell check + spellCheckPage.setPrefValue('spellcheck.dictionaries', ['en']); + spellCheckPage.setPrefValue('spellcheck.dictionaries', ['nb']); + + const spellCheckLanguagesList = spellCheckPage.shadowRoot! + .querySelector<HTMLElement>('#spellCheckLanguagesList'); + assertTrue(!!spellCheckLanguagesList); + const spellCheckLanguageItem = spellCheckLanguagesList + .querySelectorAll<HTMLElement>('.list-item')[1]; + assertTrue(!!spellCheckLanguageItem); + spellCheckLanguageItem.querySelector('cr-toggle')!.click(); + flush(); + + assertEquals( + LanguageSettingsActionType.ENABLE_SPELL_CHECK_FOR_LANGUAGE, + await languageSettingsMetricsProxy.whenCalled('recordSettingsMetric')); + }); + + test('records when disabling spellCheck for a language', async () => { + spellCheckPage.setPrefValue('browser.enable_spellchecking', true); + // enable language with support for spell check + languageHelper.enableLanguage('en'); + languageHelper.enableLanguage('af'); + + const spellCheckLanguagesList = spellCheckPage.shadowRoot! + .querySelector<HTMLElement>('#spellCheckLanguagesList'); + assertTrue(!!spellCheckLanguagesList); + const spellCheckLanguageItem = spellCheckLanguagesList + .querySelectorAll<HTMLElement>('.list-item')[1]; + assertTrue(!!spellCheckLanguageItem); + spellCheckLanguageItem.querySelector('cr-toggle')!.click(); + flush(); + + assertEquals( + LanguageSettingsActionType.DISABLE_SPELL_CHECK_FOR_LANGUAGE, + await languageSettingsMetricsProxy.whenCalled('recordSettingsMetric')); + }); + }); + // </if> +});
diff --git a/chrome/test/data/webui/signin/BUILD.gn b/chrome/test/data/webui/signin/BUILD.gn index eacfab3..6feebb54 100644 --- a/chrome/test/data/webui/signin/BUILD.gn +++ b/chrome/test/data/webui/signin/BUILD.gn
@@ -15,6 +15,7 @@ "profile_card_menu_test.ts", "profile_picker_app_test.ts", "profile_picker_main_view_test.ts", + "sync_confirmation_test.ts", "test_manage_profiles_browser_proxy.ts", ] @@ -27,7 +28,6 @@ "profile_customization_test.ts", "profile_switch_test.ts", "profile_type_choice_test.ts", - "sync_confirmation_test.ts", "test_enterprise_profile_welcome_browser_proxy.ts", "test_profile_customization_browser_proxy.ts", "test_sync_confirmation_browser_proxy.ts",
diff --git a/chrome/test/data/webui/signin/signin_browsertest.js b/chrome/test/data/webui/signin/signin_browsertest.js index 4e82b64..275bb49 100644 --- a/chrome/test/data/webui/signin/signin_browsertest.js +++ b/chrome/test/data/webui/signin/signin_browsertest.js
@@ -10,12 +10,21 @@ GEN('#include "base/command_line.h"'); GEN('#include "build/branding_buildflags.h"'); GEN('#include "build/chromeos_buildflags.h"'); +GEN('#include "chrome/browser/signin/signin_features.h"'); GEN('#include "chrome/browser/ui/ui_features.h"'); GEN('#include "components/signin/public/base/signin_buildflags.h"'); GEN('#include "content/public/test/browser_test.h"'); /* eslint-disable no-var */ +// Keep enum values in sync with the SyncConfirmationStyle enum class defined in +// signin_url_utils.h. +const SyncConfirmationStyle = { + DEFAULT_MODAL: 0, + SIGNIN_INTERCEPT_MODAL: 1, + WINDOW: 2, +}; + class SigninBrowserTest extends PolymerTest { /** @override */ get browsePreload() { @@ -24,18 +33,61 @@ } /** - * Test fixture for + * Test fixture for the default modal dialog version of * chrome/browser/resources/signin/sync_confirmation/sync_confirmation.html. * This has to be declared as a variable for TEST_F to find it correctly. */ -var SigninSyncConfirmationTest = class extends SigninBrowserTest { +var SigninSyncConfirmationDefaultModalTest = class extends SigninBrowserTest { /** @override */ get browsePreload() { - return 'chrome://sync-confirmation/test_loader.html?module=signin/sync_confirmation_test.js'; + return 'chrome://sync-confirmation/test_loader.html?module=' + + 'signin/sync_confirmation_test.js'; } }; -TEST_F('SigninSyncConfirmationTest', 'Dialog', function() { +TEST_F('SigninSyncConfirmationDefaultModalTest', 'Dialog', function() { + mocha.run(); +}); + +/** + * Test fixture for the Signin Intercept modal dialog version of + * chrome/browser/resources/signin/sync_confirmation/sync_confirmation.html. + * This has to be declared as a variable for TEST_F to find it correctly. + */ +var SigninSyncConfirmationSigninInterceptModalTest = + class extends SigninBrowserTest { + /** @override */ + get browsePreload() { + return `chrome://sync-confirmation/test_loader.html?module=` + + `signin/sync_confirmation_test.js&style=` + + `${SyncConfirmationStyle.SIGNIN_INTERCEPT_MODAL}`; + } + + /** @override */ + get featureList() { + return {enabled: ['kSyncPromoAfterSigninIntercept']}; + } +}; + +TEST_F('SigninSyncConfirmationSigninInterceptModalTest', 'Dialog', function() { + mocha.run(); +}); + +/** + * Test fixture for the window version of + * chrome/browser/resources/signin/sync_confirmation/sync_confirmation.html. + * This has to be declared as a variable for TEST_F to find it correctly. + */ +var SigninSyncConfirmationWindowTest = class extends SigninBrowserTest { + /** @override */ + get browsePreload() { + return `chrome://sync-confirmation/test_loader.html?module=` + + `signin/sync_confirmation_test.js&style=` + + `${SyncConfirmationStyle.WINDOW}`; + } +}; + +TEST_F('SigninSyncConfirmationWindowTest', 'Window', function() { mocha.run(); });
diff --git a/chrome/test/data/webui/signin/sync_confirmation_test.ts b/chrome/test/data/webui/signin/sync_confirmation_test.ts index 5c1f2d0..1d82e2f 100644 --- a/chrome/test/data/webui/signin/sync_confirmation_test.ts +++ b/chrome/test/data/webui/signin/sync_confirmation_test.ts
@@ -8,128 +8,157 @@ import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js'; import {SyncConfirmationAppElement} from 'chrome://sync-confirmation/sync_confirmation_app.js'; import {SyncConfirmationBrowserProxyImpl} from 'chrome://sync-confirmation/sync_confirmation_browser_proxy.js'; -import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js'; +import {assertArrayEquals, assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js'; import {TestSyncConfirmationBrowserProxy} from './test_sync_confirmation_browser_proxy.js'; -[true, false].forEach(isModalDialogDesignEnabled => { - const suiteDesignSuffix = isModalDialogDesignEnabled ? 'Modal' : 'NonModal'; +const isModalDialogDesignEnabled = loadTimeData.getBoolean('isModalDialog'); +const isSigninInterceptFreEnabled = + loadTimeData.getBoolean('isSigninInterceptFre'); - const STANDARD_CONSENT_CONFIRMATION = 'Yes, I\'m in'; +const STANDARD_CONSENT_CONFIRMATION = 'Yes, I\'m in'; +const SIGNIN_INTERCEPT_CONSENT_CONFIRMATION = 'Turn on sync'; - suite(`SigninSyncConfirmationTest${suiteDesignSuffix}`, function() { - let app: SyncConfirmationAppElement; - let browserProxy: TestSyncConfirmationBrowserProxy; +const SETTINGS_CONSENT_CONFIRMATION = 'Settings'; +const MANAGE_SYNC_CONSENT_CONFIRMATION = 'Manage sync'; +const SYNC_SETTINGS_CONSENT_CONFIRMATION = 'Sync settings'; - function testButtonClick(buttonSelector: string) { - const allButtons = - Array.from(app.shadowRoot!.querySelectorAll('cr-button')) as - CrButtonElement[]; - const actionButton = - app.shadowRoot!.querySelector(buttonSelector) as CrButtonElement; - const spinner = app.shadowRoot!.querySelector('paper-spinner-lite'); +const CONSENT_DESCRIPTION_TEXTS = [ + 'Turn on sync?', + 'Sync your bookmarks, passwords, history, and more on all your devices', + 'Google may use your history to personalize Search and other Google services', +]; +const CONSENT_DESCRIPTION_SIGNIN_INTERCEPT_TEXTS = [ + 'Welcome, Person 1', + 'Turn on sync to get your bookmarks, passwords, history, and more on this device and anywhere else you\'re syncing.', + 'Google may use your history to personalize Search and other Google services', +]; - allButtons.forEach(button => assertFalse(button.disabled)); - assertFalse(spinner!.active); +// <if expr="chromeos_lacros"> +CONSENT_DESCRIPTION_TEXTS[0] = 'Turn on Chrome browser sync?'; +// </if> - actionButton.click(); +suite(`SigninSyncConfirmationTest`, function() { + let app: SyncConfirmationAppElement; + let browserProxy: TestSyncConfirmationBrowserProxy; - allButtons.forEach(button => assertTrue(button.disabled)); - assertTrue(spinner!.active); - } + function testButtonClick(buttonSelector: string) { + const allButtons = + Array.from(app.shadowRoot!.querySelectorAll('cr-button')) as + CrButtonElement[]; + const actionButton = + app.shadowRoot!.querySelector(buttonSelector) as CrButtonElement; + const spinner = app.shadowRoot!.querySelector('paper-spinner-lite'); - setup(async function() { - browserProxy = new TestSyncConfirmationBrowserProxy(); - SyncConfirmationBrowserProxyImpl.setInstance(browserProxy); - loadTimeData.overrideValues({ - isModalDialog: isModalDialogDesignEnabled, - }); - document.body.innerHTML = ''; - app = document.createElement('sync-confirmation-app'); - document.body.append(app); - // Check that the account image is requested when the app element is - // attached to the document. - await browserProxy.whenCalled('requestAccountInfo'); - }); + allButtons.forEach(button => assertFalse(button.disabled)); + assertFalse(spinner!.active); - // Tests that no DCHECKS are thrown during initialization of the UI. - test('LoadPage', function() { - const cancelButton = - app.shadowRoot!.querySelector( - isModalDialogDesignEnabled ? '#cancelButton' : '#notNowButton') as - HTMLElement; - assertFalse(cancelButton!.hidden); - }); + actionButton.click(); - // Tests clicking on confirm button. - test('ConfirmClicked', async function() { - testButtonClick('#confirmButton'); - await browserProxy.whenCalled('confirm'); - }); + allButtons.forEach(button => assertTrue(button.disabled)); + assertTrue(spinner!.active); + } - // Tests clicking on cancel button. - test('CancelClicked', async function() { - testButtonClick( - isModalDialogDesignEnabled ? '#cancelButton' : '#notNowButton'); - await browserProxy.whenCalled('undo'); - }); - - // Tests clicking on settings button. - test('SettingsClicked', async function() { - testButtonClick('#settingsButton'); - await browserProxy.whenCalled('goToSettings'); - }); + setup(async function() { + browserProxy = new TestSyncConfirmationBrowserProxy(); + SyncConfirmationBrowserProxyImpl.setInstance(browserProxy); + document.body.innerHTML = ''; + app = document.createElement('sync-confirmation-app'); + document.body.append(app); + // Check that the account image is requested when the app element is + // attached to the document. + await browserProxy.whenCalled('requestAccountInfo'); }); - // This test suite verifies that the consent strings recorded in various - // scenarios are as expected. If the corresponding HTML file was updated - // without also updating the attributes referring to consent strings, - // this test will break. - suite( - `SigninSyncConfirmationConsentRecordingTest${suiteDesignSuffix}`, - function() { - let app: SyncConfirmationAppElement; - let browserProxy: TestSyncConfirmationBrowserProxy; + // Tests that no DCHECKS are thrown during initialization of the UI. + test('LoadPage', function() { + const cancelButton = + app.shadowRoot!.querySelector( + isModalDialogDesignEnabled ? '#cancelButton' : '#notNowButton') as + HTMLElement; + assertFalse(cancelButton!.hidden); + }); - setup(async function() { - // This test suite makes comparisons with strings in their default - // locale, which is en-US. - assertEquals( - 'en-US', navigator.language, - 'Cannot verify strings for the ' + navigator.language + - 'locale.'); + // Tests clicking on confirm button. + test('ConfirmClicked', async function() { + testButtonClick('#confirmButton'); + await browserProxy.whenCalled('confirm'); + }); - browserProxy = new TestSyncConfirmationBrowserProxy(); - SyncConfirmationBrowserProxyImpl.setInstance(browserProxy); - loadTimeData.overrideValues( - {isModalDialog: isModalDialogDesignEnabled}); + // Tests clicking on cancel button. + test('CancelClicked', async function() { + testButtonClick( + isModalDialogDesignEnabled ? '#cancelButton' : '#notNowButton'); + await browserProxy.whenCalled('undo'); + }); - document.body.innerHTML = ''; - app = document.createElement('sync-confirmation-app'); - document.body.append(app); - // Wait for the app element to get attached to the document (which is - // when the account image gets requested). - await browserProxy.whenCalled('requestAccountInfo'); - }); + // Tests clicking on settings button. + test('SettingsClicked', async function() { + testButtonClick('#settingsButton'); + await browserProxy.whenCalled('goToSettings'); + }); +}); - // Tests that the expected strings are recorded when clicking the - // Confirm button. - test('recordConsentOnConfirm', async function() { - app.shadowRoot!.querySelector<HTMLElement>('#confirmButton')!.click(); - const [_, confirmation] = await browserProxy.whenCalled('confirm'); - assertEquals(STANDARD_CONSENT_CONFIRMATION, confirmation); - }); +// This test suite verifies that the consent strings recorded in various +// scenarios are as expected. If the corresponding HTML file was updated +// without also updating the attributes referring to consent strings, +// this test will break. +suite(`SigninSyncConfirmationConsentRecordingTest`, function() { + let app: SyncConfirmationAppElement; + let browserProxy: TestSyncConfirmationBrowserProxy; - // Tests that the expected strings are recorded when clicking the - // Confirm button. - test('recordConsentOnSettingsLink', async function() { - app.shadowRoot!.querySelector<HTMLElement>( - '#settingsButton')!.click(); - const [_, confirmation] = - await browserProxy.whenCalled('goToSettings'); - // 'Sync settings' is recorded for non-modal design but this is passed - // from the UI class so overriding loadTimeData does not help here. - assertEquals('Settings', confirmation); - }); - }); + setup(async function() { + // This test suite makes comparisons with strings in their default + // locale, which is en-US. + assertEquals( + 'en-US', navigator.language, + 'Cannot verify strings for the ' + navigator.language + 'locale.'); + + browserProxy = new TestSyncConfirmationBrowserProxy(); + SyncConfirmationBrowserProxyImpl.setInstance(browserProxy); + + document.body.innerHTML = ''; + app = document.createElement('sync-confirmation-app'); + document.body.append(app); + // Wait for the app element to get attached to the document (which is + // when the account image gets requested). + await browserProxy.whenCalled('requestAccountInfo'); + }); + + // Tests that the expected strings are recorded when clicking the + // Confirm button. + test('recordConsentOnConfirm', async function() { + app.shadowRoot!.querySelector<HTMLElement>('#confirmButton')!.click(); + const [description, confirmation] = + await browserProxy.whenCalled('confirm'); + assertEquals( + isSigninInterceptFreEnabled ? SIGNIN_INTERCEPT_CONSENT_CONFIRMATION : + STANDARD_CONSENT_CONFIRMATION, + confirmation); + assertArrayEquals( + isSigninInterceptFreEnabled ? + CONSENT_DESCRIPTION_SIGNIN_INTERCEPT_TEXTS : + CONSENT_DESCRIPTION_TEXTS, + description); + }); + + // Tests that the expected strings are recorded when clicking the + // Settings button. + test('recordConsentOnSettingsLink', async function() { + app.shadowRoot!.querySelector<HTMLElement>('#settingsButton')!.click(); + const [description, confirmation] = + await browserProxy.whenCalled('goToSettings'); + if (isSigninInterceptFreEnabled) { + assertEquals(MANAGE_SYNC_CONSENT_CONFIRMATION, confirmation); + } else if (isModalDialogDesignEnabled) { + assertEquals(SETTINGS_CONSENT_CONFIRMATION, confirmation); + } else { + assertEquals(SYNC_SETTINGS_CONSENT_CONFIRMATION, confirmation); + } + assertArrayEquals( + isSigninInterceptFreEnabled ? + CONSENT_DESCRIPTION_SIGNIN_INTERCEPT_TEXTS : + CONSENT_DESCRIPTION_TEXTS, + description); + }); });
diff --git a/chromecast/browser/webui/cast_webui.cc b/chromecast/browser/webui/cast_webui.cc index fcd22fb..e17ed99 100644 --- a/chromecast/browser/webui/cast_webui.cc +++ b/chromecast/browser/webui/cast_webui.cc
@@ -70,7 +70,8 @@ void CastWebUI::CallJavascriptFunction(const std::string& function, std::vector<base::Value> args) { - message_handler_->CallJavascriptFunction(function, std::move(args)); + message_handler_->CallJavascriptFunction( + function, std::vector<const base::ValueView>(args.begin(), args.end())); } } // namespace chromecast
diff --git a/chromecast/browser/webui/cast_webui_message_handler.cc b/chromecast/browser/webui/cast_webui_message_handler.cc index 0b6bd5f..603e1314 100644 --- a/chromecast/browser/webui/cast_webui_message_handler.cc +++ b/chromecast/browser/webui/cast_webui_message_handler.cc
@@ -22,12 +22,11 @@ } void CastWebUIMessageHandler::CallJavascriptFunction( - const std::string& function, - std::vector<base::Value> args) { + base::StringPiece function, + base::span<const base::ValueView> args) { AllowJavascript(); javascript_called_ = true; - WebUIMessageHandler::CallJavascriptFunction( - function, std::vector<base::ValueView>(args.begin(), args.end())); + WebUIMessageHandler::CallJavascriptFunction(function, args); } } // namespace chromecast
diff --git a/chromecast/browser/webui/cast_webui_message_handler.h b/chromecast/browser/webui/cast_webui_message_handler.h index 7bfd3af9..e9932f2b 100644 --- a/chromecast/browser/webui/cast_webui_message_handler.h +++ b/chromecast/browser/webui/cast_webui_message_handler.h
@@ -6,8 +6,8 @@ #define CHROMECAST_BROWSER_WEBUI_CAST_WEBUI_MESSAGE_HANDLER_H_ #include <string> -#include <vector> +#include "base/containers/span.h" #include "base/values.h" #include "content/public/browser/web_ui_message_handler.h" @@ -26,8 +26,8 @@ void OnJavascriptDisallowed() override; // Invoke a JS function in the Web UI. - void CallJavascriptFunction(const std::string& function, - std::vector<base::Value> args); + void CallJavascriptFunction(base::StringPiece function, + base::span<const base::ValueView> args); private: bool javascript_called_ = false;
diff --git a/chromecast/cast_core/runtime/browser/grpc_webui_controller.cc b/chromecast/cast_core/runtime/browser/grpc_webui_controller.cc index c3b859d..f891d197b 100644 --- a/chromecast/cast_core/runtime/browser/grpc_webui_controller.cc +++ b/chromecast/cast_core/runtime/browser/grpc_webui_controller.cc
@@ -123,8 +123,8 @@ } void GrpcWebUIController::CallJavascriptFunction( - const std::string& function, - std::vector<base::Value> args) { + base::StringPiece function, + base::span<const base::ValueView> args) { message_handler_->CallJavascriptFunction(function, std::move(args)); }
diff --git a/chromecast/cast_core/runtime/browser/grpc_webui_controller.h b/chromecast/cast_core/runtime/browser/grpc_webui_controller.h index 86ee3cd..1f2b74c0 100644 --- a/chromecast/cast_core/runtime/browser/grpc_webui_controller.h +++ b/chromecast/cast_core/runtime/browser/grpc_webui_controller.h
@@ -6,9 +6,9 @@ #define CHROMECAST_CAST_CORE_RUNTIME_BROWSER_GRPC_WEBUI_CONTROLLER_H_ #include <memory> -#include <vector> #include "base/containers/flat_map.h" +#include "base/containers/span.h" #include "base/values.h" #include "content/public/browser/web_ui_controller.h" #include "third_party/cast_core/public/src/proto/v2/core_application_service.castcore.pb.h" @@ -60,8 +60,8 @@ void RecordAction(const base::Value::List& args); void LaunchTutorial(const base::Value::List& args); void GetQRCode(const base::Value::List& args); - void CallJavascriptFunction(const std::string& function, - std::vector<base::Value> args); + void CallJavascriptFunction(base::StringPiece function, + base::span<const base::ValueView> args); // Pointer to the generic message handler owned by the ctor provided|webui|. // The message handler is guaranteed to outlive GrpcWebUIController since
diff --git a/components/contextual_search/core/browser/contextual_search_delegate.cc b/components/contextual_search/core/browser/contextual_search_delegate.cc index 71cf0636..15d41df 100644 --- a/components/contextual_search/core/browser/contextual_search_delegate.cc +++ b/components/contextual_search/core/browser/contextual_search_delegate.cc
@@ -102,65 +102,67 @@ // Handles tasks for the ContextualSearchManager in a separable, testable way. ContextualSearchDelegate::ContextualSearchDelegate( scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, - TemplateURLService* template_url_service) + TemplateURLService* template_url_service, + ContextualSearchDelegate::SearchTermResolutionCallback search_term_callback, + ContextualSearchDelegate::SurroundingTextCallback surrounding_text_callback) : url_loader_factory_(std::move(url_loader_factory)), template_url_service_(template_url_service), - field_trial_(std::make_unique<ContextualSearchFieldTrial>()) {} + field_trial_(std::make_unique<ContextualSearchFieldTrial>()), + search_term_callback_(std::move(search_term_callback)), + surrounding_text_callback_(std::move(surrounding_text_callback)) {} ContextualSearchDelegate::~ContextualSearchDelegate() = default; void ContextualSearchDelegate::GatherAndSaveSurroundingText( - base::WeakPtr<ContextualSearchContext> context, - content::WebContents* web_contents, - SurroundingTextCallback callback) { + base::WeakPtr<ContextualSearchContext> contextual_search_context, + content::WebContents* web_contents) { DCHECK(web_contents); - blink::mojom::LocalFrame::GetTextSurroundingSelectionCallback - get_text_callback = base::BindOnce( + blink::mojom::LocalFrame::GetTextSurroundingSelectionCallback callback = + base::BindOnce( &ContextualSearchDelegate::OnTextSurroundingSelectionAvailable, - AsWeakPtr(), context, callback); - if (!context) + AsWeakPtr()); + context_ = contextual_search_context; + if (context_ == nullptr) return; - context->SetBasePageEncoding(web_contents->GetEncoding()); - int surroundingTextSize = context->CanResolve() + context_->SetBasePageEncoding(web_contents->GetEncoding()); + int surroundingTextSize = context_->CanResolve() ? field_trial_->GetResolveSurroundingSize() : field_trial_->GetSampleSurroundingSize(); RenderFrameHost* focused_frame = web_contents->GetFocusedFrame(); if (focused_frame) { - focused_frame->RequestTextSurroundingSelection(std::move(get_text_callback), + focused_frame->RequestTextSurroundingSelection(std::move(callback), surroundingTextSize); } else { - std::move(get_text_callback).Run(std::u16string(), 0, 0); + std::move(callback).Run(std::u16string(), 0, 0); } } void ContextualSearchDelegate::StartSearchTermResolutionRequest( - base::WeakPtr<ContextualSearchContext> context, - content::WebContents* web_contents, - SearchTermResolutionCallback callback) { + base::WeakPtr<ContextualSearchContext> contextual_search_context, + content::WebContents* web_contents) { DCHECK(web_contents); - if (!context) + if (context_ == nullptr) return; - DCHECK(context->CanResolve()); + DCHECK(context_.get() == contextual_search_context.get()); + DCHECK(context_->CanResolve()); // Immediately cancel any request that's in flight, since we're building a new // context (and the response disposes of any existing context). url_loader_.reset(); // Decide if the URL should be sent with the context. - if (context->CanSendBasePageUrl()) - context->SetBasePageUrl(web_contents->GetLastCommittedURL()); + if (context_->CanSendBasePageUrl()) + context_->SetBasePageUrl(web_contents->GetLastCommittedURL()); // Issue the resolve request. - ResolveSearchTermFromContext(context, std::move(callback)); + ResolveSearchTermFromContext(); } -void ContextualSearchDelegate::ResolveSearchTermFromContext( - base::WeakPtr<ContextualSearchContext> context, - SearchTermResolutionCallback callback) { - DCHECK(context); - GURL request_url(BuildRequestUrl(context.get())); +void ContextualSearchDelegate::ResolveSearchTermFromContext() { + DCHECK(context_ != nullptr); + GURL request_url(BuildRequestUrl(context_.get())); DCHECK(request_url.is_valid()); auto resource_request = std::make_unique<network::ResourceRequest>(); @@ -168,7 +170,7 @@ // Populates the discourse context and adds it to the HTTP header of the // search term resolution request. - resource_request->headers.CopyFrom(GetDiscourseContext(*context)); + resource_request->headers.CopyFrom(GetDiscourseContext(*context_)); // Disable cookies for this request. resource_request->credentials_mode = network::mojom::CredentialsMode::kOmit; @@ -216,14 +218,12 @@ url_loader_->DownloadToStringOfUnboundedSizeUntilCrashAndDie( url_loader_factory_.get(), base::BindOnce(&ContextualSearchDelegate::OnUrlLoadComplete, - base::Unretained(this), context, std::move(callback))); + base::Unretained(this))); } void ContextualSearchDelegate::OnUrlLoadComplete( - base::WeakPtr<ContextualSearchContext> context, - SearchTermResolutionCallback callback, std::unique_ptr<std::string> response_body) { - if (!context) + if (!context_) return; int response_code = ResolvedSearchTerm::kResponseCodeUninitialized; @@ -235,16 +235,16 @@ std::make_unique<ResolvedSearchTerm>(response_code); if (response_body && response_code == net::HTTP_OK) { resolved_search_term = - GetResolvedSearchTermFromJson(*context, response_code, *response_body); + GetResolvedSearchTermFromJson(response_code, *response_body); } - callback.Run(*resolved_search_term); + search_term_callback_.Run(*resolved_search_term); } std::unique_ptr<ResolvedSearchTerm> ContextualSearchDelegate::GetResolvedSearchTermFromJson( - const ContextualSearchContext& context, int response_code, const std::string& json_string) { + DCHECK(context_ != nullptr); std::string search_term; std::string display_text; std::string alternate_term; @@ -277,13 +277,13 @@ // the new and old selection. if (mention_start >= mention_end || (mention_end - mention_start) > kContextualSearchMaxSelection || - mention_end <= context.GetStartOffset() || - mention_start >= context.GetEndOffset()) { + mention_end <= context_->GetStartOffset() || + mention_start >= context_->GetEndOffset()) { start_adjust = 0; end_adjust = 0; } else { - start_adjust = mention_start - context.GetStartOffset(); - end_adjust = mention_end - context.GetEndOffset(); + start_adjust = mention_start - context_->GetStartOffset(); + end_adjust = mention_end - context_->GetEndOffset(); } } bool is_invalid = @@ -324,7 +324,7 @@ } int mainFunctionVersion = kContextualSearchRequestVersion; - if (context->GetRelatedSearches()) + if (context_->GetRelatedSearches()) mainFunctionVersion = kRelatedSearchesVersion; TemplateURLRef::SearchTermsArgs::ContextualSearchParams params( @@ -357,18 +357,16 @@ } void ContextualSearchDelegate::OnTextSurroundingSelectionAvailable( - base::WeakPtr<ContextualSearchContext> context, - SurroundingTextCallback callback, const std::u16string& surrounding_text, uint32_t start_offset, uint32_t end_offset) { - if (!context) + if (context_ == nullptr) return; // Sometimes the surroundings are 0, 0, '', so run the callback with empty // data in that case. See https://crbug.com/393100. if (start_offset == 0 && end_offset == 0 && surrounding_text.length() == 0) { - callback.Run(std::string(), std::u16string(), 0, 0); + surrounding_text_callback_.Run(std::string(), std::u16string(), 0, 0); return; } @@ -379,7 +377,8 @@ start_offset = std::min(surrounding_length, start_offset); end_offset = std::min(surrounding_length, end_offset); - context->SetSelectionSurroundings(start_offset, end_offset, surrounding_text); + context_->SetSelectionSurroundings(start_offset, end_offset, + surrounding_text); // Call the Java surrounding callback with a shortened copy of the // surroundings to use as a sample of the surrounding text. @@ -393,8 +392,9 @@ SampleSurroundingText(surrounding_text, sample_padding_each_side, &selection_start, &selection_end); DCHECK(selection_start <= selection_end); - callback.Run(context->GetBasePageEncoding(), sample_surrounding_text, - selection_start, selection_end); + surrounding_text_callback_.Run(context_->GetBasePageEncoding(), + sample_surrounding_text, selection_start, + selection_end); } // Decodes the given response from the search term resolution request and sets @@ -530,7 +530,7 @@ void ContextualSearchDelegate::ExtractMentionsStartEnd( const base::Value::List& mentions_list, int* start_result, - int* end_result) const { + int* end_result) { if (mentions_list.size() >= 1 && mentions_list[0].is_int()) *start_result = std::max(0, mentions_list[0].GetInt()); if (mentions_list.size() >= 2 && mentions_list[1].is_int()) @@ -541,7 +541,7 @@ const std::u16string& surrounding_text, int padding_each_side, size_t* start, - size_t* end) const { + size_t* end) { std::u16string result_text = surrounding_text; size_t start_offset = *start; size_t end_offset = *end;
diff --git a/components/contextual_search/core/browser/contextual_search_delegate.h b/components/contextual_search/core/browser/contextual_search_delegate.h index a13b252..6cbdfc7 100644 --- a/components/contextual_search/core/browser/contextual_search_delegate.h +++ b/components/contextual_search/core/browser/contextual_search_delegate.h
@@ -44,32 +44,32 @@ void(const std::string&, const std::u16string&, size_t, size_t)> SurroundingTextCallback; - // Constructs a delegate that uses the given url_loader_factory and - // template_url_service for all contextual search requests. + // Constructs a delegate that will always call back to the given callbacks + // when search term resolution or surrounding text responses are available. ContextualSearchDelegate( scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, - TemplateURLService* template_url_service); + TemplateURLService* template_url_service, + SearchTermResolutionCallback search_term_callback, + SurroundingTextCallback surrounding_callback); ContextualSearchDelegate(const ContextualSearchDelegate&) = delete; ContextualSearchDelegate& operator=(const ContextualSearchDelegate&) = delete; virtual ~ContextualSearchDelegate(); - // Gathers surrounding text and saves it in the given context. The given - // callback will be run when the surrounding text becomes available. + // Gathers surrounding text and saves it locally in the given context. void GatherAndSaveSurroundingText( base::WeakPtr<ContextualSearchContext> contextual_search_context, - content::WebContents* web_contents, - SurroundingTextCallback callback); + content::WebContents* web_contents); // Starts an asynchronous search term resolution request. - // The given context may include some content from a web page and must be able + // The given context includes some content from a web page and must be able // to resolve. - // When the response is available the given callback will be run. + // When the response is available the callback specified in the constructor + // is run. void StartSearchTermResolutionRequest( base::WeakPtr<ContextualSearchContext> contextual_search_context, - content::WebContents* web_contents, - SearchTermResolutionCallback callback); + content::WebContents* web_contents); private: // Friend our test which allows our private methods to be used in helper @@ -95,31 +95,23 @@ FRIEND_TEST_ALL_PREFIXES(ContextualSearchDelegateTest, DecodeSearchTermFromJsonResponse); - // Resolves the search term specified by the current context. - void ResolveSearchTermFromContext( - base::WeakPtr<ContextualSearchContext> context, - SearchTermResolutionCallback callback); + void OnUrlLoadComplete(std::unique_ptr<std::string> response_body); - // Handles the contextual search response included in |response_body|. Calls - // |callback| with the resulting ResolvedSearchTerm. - void OnUrlLoadComplete(base::WeakPtr<ContextualSearchContext> context, - SearchTermResolutionCallback callback, - std::unique_ptr<std::string> response_body); + // Resolves the search term specified by the current context. + // Only needed for tests. TODO(donnd): make private and friend? + void ResolveSearchTermFromContext(); // Builds and returns the search term resolution request URL. // |context| is used to help build the query. std::string BuildRequestUrl(ContextualSearchContext* context); void OnTextSurroundingSelectionAvailable( - base::WeakPtr<ContextualSearchContext> context, - SurroundingTextCallback callback, const std::u16string& surrounding_text, uint32_t start_offset, uint32_t end_offset); // Builds a Resolved Search Term by decoding the given JSON string. std::unique_ptr<ResolvedSearchTerm> GetResolvedSearchTermFromJson( - const ContextualSearchContext& context, int response_code, const std::string& json_string); @@ -148,7 +140,7 @@ // |mentions_list| must be a list. void ExtractMentionsStartEnd(const base::Value::List& mentions_list, int* start_result, - int* end_result) const; + int* end_result); // Generates a subset of the given surrounding_text string, for usage from // Java. @@ -165,7 +157,13 @@ std::u16string SampleSurroundingText(const std::u16string& surrounding_text, int padding_each_side, size_t* start, - size_t* end) const; + size_t* end); + + // For testing. + void SetContextForTesting( + const base::WeakPtr<ContextualSearchContext>& context) { + context_ = context; + } // The current request in progress, or NULL. std::unique_ptr<network::SimpleURLLoader> url_loader_; @@ -178,6 +176,16 @@ // The field trial helper instance, always set up by the constructor. std::unique_ptr<ContextualSearchFieldTrial> field_trial_; + + // The callback for notifications of completed URL fetches. + SearchTermResolutionCallback search_term_callback_; + + // The callback for notifications of surrounding text being available. + SurroundingTextCallback surrounding_text_callback_; + + // Used to hold the context until an upcoming search term request is started. + // Owned by the Java ContextualSearchContext. + base::WeakPtr<ContextualSearchContext> context_; }; #endif // COMPONENTS_CONTEXTUAL_SEARCH_CORE_BROWSER_CONTEXTUAL_SEARCH_DELEGATE_H_
diff --git a/components/contextual_search/core/browser/contextual_search_delegate_unittest.cc b/components/contextual_search/core/browser/contextual_search_delegate_unittest.cc index d909e172..914d00b 100644 --- a/components/contextual_search/core/browser/contextual_search_delegate_unittest.cc +++ b/components/contextual_search/core/browser/contextual_search_delegate_unittest.cc
@@ -14,7 +14,6 @@ #include "base/bind.h" #include "base/command_line.h" #include "base/memory/raw_ptr.h" -#include "base/memory/weak_ptr.h" #include "base/strings/escape.h" #include "base/strings/utf_string_conversions.h" #include "base/test/scoped_feature_list.h" @@ -74,7 +73,13 @@ &test_url_loader_factory_); template_url_service_.reset(CreateTemplateURLService()); delegate_ = std::make_unique<ContextualSearchDelegate>( - test_shared_url_loader_factory_, template_url_service_.get()); + test_shared_url_loader_factory_, template_url_service_.get(), + base::BindRepeating( + &ContextualSearchDelegateTest::recordSearchTermResolutionResponse, + base::Unretained(this)), + base::BindRepeating( + &ContextualSearchDelegateTest::recordSampleSelectionAvailable, + base::Unretained(this))); } void TearDown() override { @@ -112,13 +117,12 @@ int end_offset) { test_context_ = std::make_unique<WeakContextualSearchContext>( std::string(), GURL(kSomeSpecificBasePage), "utf-8"); + // ContextualSearchDelegate class takes ownership of the context. + delegate_->SetContextForTesting(test_context_->GetWeakPtr()); + test_context_->SetSelectionSurroundings(start_offset, end_offset, surrounding_text); - delegate_->ResolveSearchTermFromContext( - test_context_->GetWeakPtr(), - base::BindRepeating( - &ContextualSearchDelegateTest::recordSearchTermResolutionResponse, - base::Unretained(this))); + delegate_->ResolveSearchTermFromContext(); ASSERT_TRUE(test_url_loader_factory_.GetPendingRequest(0)); } @@ -150,6 +154,7 @@ void CreateTestContext() { test_context_ = std::make_unique<WeakContextualSearchContext>( std::string(), GURL(kSomeSpecificBasePage), "utf-8"); + delegate_->SetContextForTesting(test_context_->GetWeakPtr()); } void DestroyTestContext() { test_context_.reset(); } @@ -157,23 +162,12 @@ // Call the OnTextSurroundingSelectionAvailable. // Cannot be in an actual test because OnTextSurroundingSelectionAvailable // is private. - void CallOnTextSurroundingSelectionAvailable( - base::WeakPtr<ContextualSearchContext> context) { - delegate_->OnTextSurroundingSelectionAvailable( - context, - base::BindRepeating( - &ContextualSearchDelegateTest::recordSampleSelectionAvailable, - base::Unretained(this)), - std::u16string(), 1, 2); + void CallOnTextSurroundingSelectionAvailable() { + delegate_->OnTextSurroundingSelectionAvailable(std::u16string(), 1, 2); } - void CallResolveSearchTermFromContext( - base::WeakPtr<ContextualSearchContext> context) { - delegate_->ResolveSearchTermFromContext( - context, - base::BindRepeating( - &ContextualSearchDelegateTest::recordSearchTermResolutionResponse, - base::Unretained(this))); + void CallResolveSearchTermFromContext() { + delegate_->ResolveSearchTermFromContext(); } void SetResponseStringAndSimulateResponse(const std::string& selected_text, @@ -204,6 +198,7 @@ std::string(), GURL(kSomeSpecificBasePage), "utf-8"); test_context_->SetSelectionSurroundings(start_offset, end_offset, surrounding_text); + delegate_->SetContextForTesting(test_context_->GetWeakPtr()); } // Gets the Client Discourse Context proto from the request header. @@ -265,7 +260,6 @@ // The delegate under test. std::unique_ptr<ContextualSearchDelegate> delegate_; - std::unique_ptr<WeakContextualSearchContext> test_context_; network::TestURLLoaderFactory test_url_loader_factory_; @@ -327,6 +321,8 @@ scoped_refptr<network::SharedURLLoaderFactory> test_shared_url_loader_factory_; + std::unique_ptr<WeakContextualSearchContext> test_context_; + // Features to enable base::test::ScopedFeatureList feature_list_; }; @@ -679,11 +675,9 @@ // Test that we can destroy the context while resolving without a crash. // Test is flaky: https://crbug.com/890427 -TEST_F(ContextualSearchDelegateTest, DestroyContextDuringResolve) { +TEST_F(ContextualSearchDelegateTest, DISABLED_DestroyContextDuringResolve) { CreateTestContext(); - base::WeakPtr<ContextualSearchContext> weak_context = - test_context_->GetWeakPtr(); - CallResolveSearchTermFromContext(weak_context); + CallResolveSearchTermFromContext(); DestroyTestContext(); std::string response("Any response as it does not matter here."); @@ -695,10 +689,8 @@ // Test that we can destroy the context while gathering surrounding text. TEST_F(ContextualSearchDelegateTest, DestroyContextDuringGatherSurroundings) { CreateTestContext(); - base::WeakPtr<ContextualSearchContext> weak_context = - test_context_->GetWeakPtr(); DestroyTestContext(); - CallOnTextSurroundingSelectionAvailable(weak_context); + CallOnTextSurroundingSelectionAvailable(); } TEST_F(ContextualSearchDelegateTest, ResponseWithCocaCardTag) {
diff --git a/components/exo/extended_drag_source_unittest.cc b/components/exo/extended_drag_source_unittest.cc index c7c9030..b234641 100644 --- a/components/exo/extended_drag_source_unittest.cc +++ b/components/exo/extended_drag_source_unittest.cc
@@ -688,29 +688,46 @@ #endif // BUILDFLAG(IS_CHROMEOS_ASH) TEST_F(ExtendedDragSourceTest, DragToAnotherDisplay) { - UpdateDisplay("800x600,800x600"); + UpdateDisplay("400x300,800x600"); + const gfx::Rect original_window_bounds(410, 10, 500, 200); - // Create and map a toplevel shell surface. + // Create and map a toplevel shell surface, with the size larger than 2nd + // display to test if configure uses the adjusted size. auto shell_surface = - exo::test::ShellSurfaceBuilder({32, 32}).BuildShellSurface(); + exo::test::ShellSurfaceBuilder(original_window_bounds.size()) + .SetOrigin(original_window_bounds.origin()) + .BuildShellSurface(); auto* surface = shell_surface->root_surface(); - - shell_surface->GetWidget()->SetBounds({810, 10, 32, 32}); - + EXPECT_EQ(original_window_bounds, + shell_surface->GetWidget()->GetWindowBoundsInScreen()); auto display = display::Screen::GetScreen()->GetDisplayNearestWindow( shell_surface->GetWidget()->GetNativeWindow()); - EXPECT_EQ(gfx::Rect(800, 0, 800, 600), display.bounds()); + EXPECT_EQ(gfx::Rect(400, 0, 800, 600), display.bounds()); - gfx::Rect expected_bounds = - shell_surface->GetWidget()->GetWindowBoundsInScreen(); + uint32_t serial = 0; + gfx::Rect drop_bounds; + auto configure_callback = base::BindLambdaForTesting( + [&](const gfx::Rect& bounds, chromeos::WindowStateType state_type, + bool resizing, bool activated, const gfx::Vector2d& origin_offset) { + drop_bounds = bounds; + return ++serial; + }); + std::vector<gfx::Point> origins; + auto origin_change_callback = base::BindLambdaForTesting( + [&](const gfx::Point& point) { origins.push_back(point); }); - constexpr int kDragOffset = 10; + // Map shell surface. + // surface->Attach(buffer.get()); + shell_surface->set_configure_callback(configure_callback); + shell_surface->set_origin_change_callback(origin_change_callback); + + constexpr int kDragOffset = 100; extended_drag_source_->Drag(surface, gfx::Vector2d(kDragOffset, 0)); // Start the DND + extended-drag session. // Creates a mouse-pressed event before starting the drag session. ui::test::EventGenerator* generator = GetEventGenerator(); - generator->MoveMouseTo({810 + kDragOffset, 10}); + generator->MoveMouseTo({410 + kDragOffset, 10}); generator->PressLeftButton(); // Start a DragDropOperation. @@ -718,23 +735,24 @@ seat_->StartDrag(data_source_.get(), surface, /*icon=*/nullptr, ui::mojom::DragEventSource::kMouse); // Just move to the middle to avoid snapping. - int x_movement = 500; - expected_bounds.set_x(310); + int x_movement = 300; constexpr int kXDragDelta = 20; auto* toplevel_handler = ash::Shell::Get()->toplevel_window_event_handler(); base::RunLoop loop; + size_t move_count = 0; drag_drop_controller_->SetLoopClosureForTesting( base::BindLambdaForTesting([&]() { - if (x_movement == 500) { + if (x_movement == 300) { auto* window_state = ash::WindowState::Get( shell_surface->GetWidget()->GetNativeWindow()); - EXPECT_EQ(gfx::PointF(20, 10), + EXPECT_EQ(gfx::PointF(110, 10), window_state->drag_details()->initial_location_in_parent); } if (x_movement > 0) { x_movement -= kXDragDelta; + move_count++; generator->MoveMouseBy(-kXDragDelta, 0); EXPECT_TRUE(toplevel_handler->is_drag_in_progress()); } else { @@ -744,11 +762,34 @@ loop.QuitClosure()); loop.Run(); EXPECT_FALSE(toplevel_handler->is_drag_in_progress()); - EXPECT_EQ(expected_bounds, - shell_surface->GetWidget()->GetWindowBoundsInScreen()); + EXPECT_FALSE(shell_surface->GetWidget()->IsMaximized()); display = display::Screen::GetScreen()->GetDisplayNearestWindow( shell_surface->GetWidget()->GetNativeWindow()); - EXPECT_EQ(gfx::Rect(0, 0, 800, 600), display.bounds()); + + gfx::Size secondary_display_size(400, 300); + EXPECT_EQ(gfx::Rect(secondary_display_size), display.bounds()); + EXPECT_EQ(move_count, origins.size()); + + // Configure when dropped. + EXPECT_EQ(1u, serial); + // Upon drop, the window is shrunk horizontally. + gfx::Rect expected_drop_bounds = + gfx::Rect(origins.back(), original_window_bounds.size()); + expected_drop_bounds.set_width(secondary_display_size.width()); + int offset = + (original_window_bounds.width() - expected_drop_bounds.width()) / 2; + expected_drop_bounds.set_x(expected_drop_bounds.x() + offset); + EXPECT_EQ(expected_drop_bounds, drop_bounds); + EXPECT_EQ(expected_drop_bounds, + shell_surface->GetWidget()->GetWindowBoundsInScreen()); + + // Make sure all origins are kXDragDelta apart. + for (size_t i = 1; origins.size() < i; i++) { + EXPECT_EQ(origins[i - 1].x() + kXDragDelta, origins[i].x()); + } + + // The size will be adjusted when dropped. + EXPECT_EQ(gfx::Size(400, 200), drop_bounds.size()); } } // namespace exo
diff --git a/components/exo/shell_surface.cc b/components/exo/shell_surface.cc index 67837d67..21b4a36 100644 --- a/components/exo/shell_surface.cc +++ b/components/exo/shell_surface.cc
@@ -408,6 +408,14 @@ return; if (window == widget_->GetNativeWindow()) { + auto* window_state = ash::WindowState::Get(window); + if (window_state && window_state->is_moving_to_another_display()) { + old_screen_bounds_for_pending_move_ = old_bounds; + wm::ConvertRectToScreen(window->parent(), + &old_screen_bounds_for_pending_move_); + return; + } + if (new_bounds.size() == old_bounds.size()) { if (!origin_change_callback_.is_null()) origin_change_callback_.Run(GetClientBoundsInScreen(widget_).origin()); @@ -439,8 +447,28 @@ ShellSurfaceBase::OnWindowAddedToRootWindow(window); if (window != widget_->GetNativeWindow()) return; - if (!origin_change_callback_.is_null()) - origin_change_callback_.Run(GetClientBoundsInScreen(widget_).origin()); + auto* window_state = ash::WindowState::Get(window); + if (window_state && window_state->is_moving_to_another_display()) { + DCHECK(!old_screen_bounds_for_pending_move_.IsEmpty()); + + gfx::Rect new_bounds_in_screen = window->bounds(); + wm::ConvertRectToScreen(window->parent(), &new_bounds_in_screen); + + gfx::Vector2d delta = new_bounds_in_screen.origin() - + old_screen_bounds_for_pending_move_.origin(); + old_screen_bounds_for_pending_move_ = gfx::Rect(); + origin_offset_ -= delta; + pending_origin_offset_accumulator_ += delta; + UpdateSurfaceBounds(); + UpdateShadow(); + + if (!window_state_is_changing_) + Configure(); + + } else { + if (!origin_change_callback_.is_null()) + origin_change_callback_.Run(GetClientBoundsInScreen(widget_).origin()); + } } //////////////////////////////////////////////////////////////////////////////// @@ -533,6 +561,8 @@ DCHECK(!ignore_window_bounds_changes_); ignore_window_bounds_changes_ = true; + // TODO(oshima): Probably ignore while dragging. + widget_->SetBounds(bounds); UpdateSurfaceBounds();
diff --git a/components/exo/shell_surface.h b/components/exo/shell_surface.h index 7a29462..eeb5518 100644 --- a/components/exo/shell_surface.h +++ b/components/exo/shell_surface.h
@@ -201,6 +201,7 @@ gfx::Vector2d origin_offset_; gfx::Vector2d pending_origin_offset_; gfx::Vector2d pending_origin_offset_accumulator_; + gfx::Rect old_screen_bounds_for_pending_move_; int resize_component_ = HTCAPTION; // HT constant (see ui/base/hit_test.h) int pending_resize_component_ = HTCAPTION;
diff --git a/components/exo/shell_surface_presentation_time_recorder_unittest.cc b/components/exo/shell_surface_presentation_time_recorder_unittest.cc index 0edf1ad..8136793 100644 --- a/components/exo/shell_surface_presentation_time_recorder_unittest.cc +++ b/components/exo/shell_surface_presentation_time_recorder_unittest.cc
@@ -134,7 +134,9 @@ EXPECT_TRUE(recorder_->RequestNext()); } -TEST_F(ShellSurfacePresentationTimeRecorderTest, AckSkippedOrOutOfOrder) { +// TODO(crbug.com/1349591): Revive this test. +TEST_F(ShellSurfacePresentationTimeRecorderTest, + DISABLED_AckSkippedOrOutOfOrder) { // Issue 4 requests with configure serial 1-5. for (size_t i = 1u; i <= 5u; ++i) { recorder_->PrepareToRecord();
diff --git a/components/exo/shell_surface_util.cc b/components/exo/shell_surface_util.cc index bfe162f..3282728e 100644 --- a/components/exo/shell_surface_util.cc +++ b/components/exo/shell_surface_util.cc
@@ -223,7 +223,7 @@ // Create a clone of the event as targeter may update it during the // search. - auto cloned = ui::Event::Clone(*original_event); + auto cloned = original_event->Clone(); ui::LocatedEvent* event = cloned->AsLocatedEvent(); while (true) {
diff --git a/components/media_router/common/mojom/route_request_result_code.mojom b/components/media_router/common/mojom/route_request_result_code.mojom index 7f2db31..33ac1b22 100644 --- a/components/media_router/common/mojom/route_request_result_code.mojom +++ b/components/media_router/common/mojom/route_request_result_code.mojom
@@ -18,6 +18,7 @@ CANCELLED, ROUTE_ALREADY_EXISTS, DESKTOP_PICKER_FAILED, - ROUTE_ALREADY_TERMINATED + ROUTE_ALREADY_TERMINATED, + REDUNDANT_REQUEST, // New values must be added here. };
diff --git a/components/ntp_tiles/webui/ntp_tiles_internals_message_handler_client.h b/components/ntp_tiles/webui/ntp_tiles_internals_message_handler_client.h index 18306006..1f4219e 100644 --- a/components/ntp_tiles/webui/ntp_tiles_internals_message_handler_client.h +++ b/components/ntp_tiles/webui/ntp_tiles_internals_message_handler_client.h
@@ -43,17 +43,17 @@ // Registers a callback in Javascript. See content::WebUI and web::WebUIIOS. virtual void RegisterMessageCallback( - const std::string& message, + base::StringPiece message, base::RepeatingCallback<void(const base::Value::List&)> callback) = 0; // Invokes a function in Javascript. See content::WebUI and web::WebUIIOS. virtual void CallJavascriptFunctionSpan( - const std::string& name, + base::StringPiece name, base::span<const base::ValueView> values) = 0; // Convenience function for CallJavascriptFunctionSpan(). template <typename... Arg> - void CallJavascriptFunction(const std::string& name, const Arg&... arg) { + void CallJavascriptFunction(base::StringPiece name, const Arg&... arg) { base::ValueView args[] = {arg...}; CallJavascriptFunctionSpan(name, args); }
diff --git a/components/page_info/page_info.cc b/components/page_info/page_info.cc index 6b0a71b..7d37631 100644 --- a/components/page_info/page_info.cc +++ b/components/page_info/page_info.cc
@@ -551,6 +551,9 @@ case PAGE_INFO_COOKIES_PAGE_OPENED: // TODO(crbug.com/1346305) Add recording action. break; + case PAGE_INFO_COOKIES_SETTINGS_OPENED: + // TODO(crbug.com/1346305) Add recording action. + break; } } @@ -674,6 +677,15 @@ #endif } +void PageInfo::OpenCookiesSettingsView() { +#if BUILDFLAG(IS_ANDROID) + NOTREACHED(); +#else + RecordPageInfoAction(PAGE_INFO_COOKIES_SETTINGS_OPENED); + delegate_->ShowCookiesSettings(); +#endif +} + void PageInfo::OpenCookiesDialog() { #if BUILDFLAG(IS_ANDROID) NOTREACHED();
diff --git a/components/page_info/page_info.h b/components/page_info/page_info.h index b538bf1..f2548f2 100644 --- a/components/page_info/page_info.h +++ b/components/page_info/page_info.h
@@ -152,7 +152,8 @@ PAGE_INFO_AD_PERSONALIZATION_SETTINGS_OPENED = 31, PAGE_INFO_ABOUT_THIS_SITE_MORE_ABOUT_CLICKED = 32, PAGE_INFO_COOKIES_PAGE_OPENED = 33, - kMaxValue = PAGE_INFO_COOKIES_PAGE_OPENED + PAGE_INFO_COOKIES_SETTINGS_OPENED = 34, + kMaxValue = PAGE_INFO_COOKIES_SETTINGS_OPENED }; struct ChooserUIInfo { @@ -237,6 +238,9 @@ // Handles opening the link to show more site settings and records the event. void OpenSiteSettingsView(); + // Handles opening the link to show cookies settings and records the event. + void OpenCookiesSettingsView(); + // Handles opening the cookies dialog and records the event. void OpenCookiesDialog();
diff --git a/components/page_info/page_info_delegate.h b/components/page_info/page_info_delegate.h index 66c065eb..ee85dc55 100644 --- a/components/page_info/page_info_delegate.h +++ b/components/page_info/page_info_delegate.h
@@ -64,6 +64,7 @@ virtual bool CreateInfoBarDelegate() = 0; virtual void ShowSiteSettings(const GURL& site_url) = 0; + virtual void ShowCookiesSettings() = 0; virtual void OpenCookiesDialog() = 0; virtual void OpenCertificateDialog(net::X509Certificate* certificate) = 0; virtual void OpenConnectionHelpCenterPage(const ui::Event& event) = 0;
diff --git a/components/password_manager/core/browser/android_backend_error.h b/components/password_manager/core/browser/android_backend_error.h index 3227ae5..baf2641c7 100644 --- a/components/password_manager/core/browser/android_backend_error.h +++ b/components/password_manager/core/browser/android_backend_error.h
@@ -45,6 +45,10 @@ // Numeric error code returned by the GMS Core API, only available if 'type' // is kExternalError. absl::optional<int> api_error_code; + + // Numeric connection result status code returned by the GMS Core API, only + // available if ConnectionResult was set on the returned exception. + absl::optional<int> connection_result_code; }; } // namespace password_manager
diff --git a/components/password_manager/core/browser/password_store_backend_metrics_recorder.cc b/components/password_manager/core/browser/password_store_backend_metrics_recorder.cc index a2f00dd..e886ba93 100644 --- a/components/password_manager/core/browser/password_store_backend_metrics_recorder.cc +++ b/components/password_manager/core/browser/password_store_backend_metrics_recorder.cc
@@ -83,6 +83,11 @@ base::UmaHistogramSparse(BuildMetricName("UnenrolledFromUPM.APIError"), error->api_error_code.value()); } + if (error->connection_result_code.has_value()) { + base::UmaHistogramSparse( + BuildMetricName("UnenrolledFromUPM.ConnectionResultCode"), + error->connection_result_code.value()); + } } base::TimeDelta @@ -118,6 +123,9 @@ << " failed with error code: " << backend_error.api_error_code.value(); } + if (backend_error.connection_result_code.has_value()) { + RecordConnectionResultCode(backend_error.connection_result_code.value()); + } } void PasswordStoreBackendMetricsRecorder::RecordLatency() const { @@ -133,6 +141,15 @@ base::UmaHistogramSparse(BuildMetricName("APIError"), api_error_code); } +void PasswordStoreBackendMetricsRecorder::RecordConnectionResultCode( + int connection_result_code) const { + base::UmaHistogramSparse( + base::StrCat({kMetricPrefix, "AndroidBackend.ConnectionResultCode"}), + connection_result_code); + base::UmaHistogramSparse(BuildMetricName("ConnectionResultCode"), + connection_result_code); +} + std::string PasswordStoreBackendMetricsRecorder::GetBackendMetricName() const { return base::StrCat({kMetricPrefix, *backend_infix_, ".", *metric_infix_}); }
diff --git a/components/password_manager/core/browser/password_store_backend_metrics_recorder.h b/components/password_manager/core/browser/password_store_backend_metrics_recorder.h index 1f6250a..254dc3c6 100644 --- a/components/password_manager/core/browser/password_store_backend_metrics_recorder.h +++ b/components/password_manager/core/browser/password_store_backend_metrics_recorder.h
@@ -91,6 +91,12 @@ // - "PasswordManager.PasswordStoreAndroidBackend.<metric_infix_>.APIError" void RecordApiErrorCode(int api_error_code) const; + // Records the following metrics: + // - "PasswordManager.PasswordStoreAndroidBackend.ConnectionResultCode" + // - "PasswordManager.PasswordStoreAndroidBackend.<metric_infix_> + // .ConnectionResultCode" + void RecordConnectionResultCode(int connection_result_code) const; + std::string GetBackendMetricName() const; std::string BuildMetricName(base::StringPiece suffix) const; std::string GetOverallMetricName() const;
diff --git a/components/password_manager/core/browser/password_store_backend_metrics_recorder_unittest.cc b/components/password_manager/core/browser/password_store_backend_metrics_recorder_unittest.cc index 8a1c6cf4..47e9c40 100644 --- a/components/password_manager/core/browser/password_store_backend_metrics_recorder_unittest.cc +++ b/components/password_manager/core/browser/password_store_backend_metrics_recorder_unittest.cc
@@ -15,6 +15,7 @@ namespace { using testing::ElementsAre; +using testing::IsEmpty; using SuccessStatus = PasswordStoreBackendMetricsRecorder::SuccessStatus; @@ -32,6 +33,8 @@ "PasswordManager.PasswordStoreSomeBackend.MethodName.ErrorCode"; constexpr char kApiErrorMetric[] = "PasswordManager.PasswordStoreSomeBackend.MethodName.APIError"; +constexpr char kConnectionResultMetric[] = + "PasswordManager.PasswordStoreSomeBackend.MethodName.ConnectionResultCode"; constexpr char kOverallMetric[] = "PasswordManager.PasswordStoreBackend.MethodName"; constexpr char kDurationOverallMetric[] = @@ -42,6 +45,8 @@ "PasswordManager.PasswordStoreAndroidBackend.ErrorCode"; constexpr char kApiErrorOverallMetric[] = "PasswordManager.PasswordStoreAndroidBackend.APIError"; +constexpr char kConnectionResultOverallMetric[] = + "PasswordManager.PasswordStoreAndroidBackend.ConnectionResultCode"; } // anonymous namespace class PasswordStoreBackendMetricsRecorderTest : public testing::Test { @@ -124,6 +129,8 @@ ElementsAre(Bucket(7, 1))); // External EXPECT_THAT(histogram_tester.GetAllSamples(kApiErrorMetric), ElementsAre(Bucket(11010, 1))); // No access. + EXPECT_THAT(histogram_tester.GetAllSamples(kConnectionResultMetric), + IsEmpty()); // Checking records in the overall histogram histogram_tester.ExpectTotalCount(kDurationOverallMetric, 1); @@ -135,6 +142,60 @@ ElementsAre(Bucket(7, 1))); EXPECT_THAT(histogram_tester.GetAllSamples(kApiErrorOverallMetric), ElementsAre(Bucket(11010, 1))); + EXPECT_THAT(histogram_tester.GetAllSamples(kConnectionResultOverallMetric), + IsEmpty()); + + // Checking completed requests in the overall and backend-specific histogram. + EXPECT_THAT( + histogram_tester.GetAllSamples(kSpecificMetric), + ElementsAre(Bucket(/* Requested */ 0, 1), Bucket(/* Completed */ 2, 1))); + EXPECT_THAT( + histogram_tester.GetAllSamples(kOverallMetric), + ElementsAre(Bucket(/* Requested */ 0, 1), Bucket(/* Completed */ 2, 1))); +} + +TEST_F(PasswordStoreBackendMetricsRecorderTest, + RecordMetrics_ExternalErrorWithConnectionResult) { + using base::Bucket; + base::HistogramTester histogram_tester; + + const int kApiUnavailableConnectionResult = 16; + + PasswordStoreBackendMetricsRecorder metrics_recorder = + PasswordStoreBackendMetricsRecorder(BackendInfix(kSomeBackend), + MetricInfix(kSomeMethod)); + + AdvanceClock(kLatencyDelta); + + AndroidBackendError error(AndroidBackendErrorType::kExternalError); + error.api_error_code = 11010; + error.connection_result_code = kApiUnavailableConnectionResult; + metrics_recorder.RecordMetrics(SuccessStatus::kError, std::move(error)); + + // Checking records in the backend-specific histogram + histogram_tester.ExpectTotalCount(kDurationMetric, 1); + histogram_tester.ExpectTimeBucketCount(kDurationMetric, kLatencyDelta, 1); + EXPECT_THAT(histogram_tester.GetAllSamples(kSuccessMetric), + ElementsAre(Bucket(false, 1))); + EXPECT_THAT(histogram_tester.GetAllSamples(kErrorCodeMetric), + ElementsAre(Bucket(7, 1))); // External + EXPECT_THAT(histogram_tester.GetAllSamples(kApiErrorMetric), + ElementsAre(Bucket(11010, 1))); // No access. + EXPECT_THAT(histogram_tester.GetAllSamples(kConnectionResultMetric), + ElementsAre(Bucket(kApiUnavailableConnectionResult, 1))); + + // Checking records in the overall histogram + histogram_tester.ExpectTotalCount(kDurationOverallMetric, 1); + histogram_tester.ExpectTimeBucketCount(kDurationOverallMetric, kLatencyDelta, + 1); + EXPECT_THAT(histogram_tester.GetAllSamples(kSuccessOverallMetric), + ElementsAre(Bucket(false, 1))); + EXPECT_THAT(histogram_tester.GetAllSamples(kErrorCodeOverallMetric), + ElementsAre(Bucket(7, 1))); + EXPECT_THAT(histogram_tester.GetAllSamples(kApiErrorOverallMetric), + ElementsAre(Bucket(11010, 1))); + EXPECT_THAT(histogram_tester.GetAllSamples(kConnectionResultOverallMetric), + ElementsAre(Bucket(kApiUnavailableConnectionResult, 1))); // Checking completed requests in the overall and backend-specific histogram. EXPECT_THAT(
diff --git a/components/password_manager/core/browser/ui/bulk_leak_check_service_adapter_unittest.cc b/components/password_manager/core/browser/ui/bulk_leak_check_service_adapter_unittest.cc index 41558a4..90433cc2 100644 --- a/components/password_manager/core/browser/ui/bulk_leak_check_service_adapter_unittest.cc +++ b/components/password_manager/core/browser/ui/bulk_leak_check_service_adapter_unittest.cc
@@ -264,7 +264,10 @@ RunUntilIdle(); EXPECT_CALL(factory(), TryCreateBulkLeakCheck).Times(0); - presenter().EditPassword(password, kPassword2); + CredentialUIEntry original_credential(password), + updated_credential = original_credential; + updated_credential.password = kPassword2; + presenter().EditSavedCredentials(original_credential, updated_credential); } // Tests that editing a password through the presenter will result in another @@ -288,7 +291,10 @@ CheckCredentials(CredentialsAre(std::cref(expected)))); EXPECT_CALL(factory(), TryCreateBulkLeakCheck) .WillOnce(Return(ByMove(std::move(leak_check)))); - presenter().EditPassword(password, kPassword2); + CredentialUIEntry original_credential(password), + updated_credential = original_credential; + updated_credential.password = kPassword2; + presenter().EditSavedCredentials(original_credential, updated_credential); } } // namespace password_manager
diff --git a/components/password_manager/core/browser/ui/insecure_credentials_manager.cc b/components/password_manager/core/browser/ui/insecure_credentials_manager.cc index 9e24f8d..075fc2a2 100644 --- a/components/password_manager/core/browser/ui/insecure_credentials_manager.cc +++ b/components/password_manager/core/browser/ui/insecure_credentials_manager.cc
@@ -34,143 +34,13 @@ namespace password_manager { -// Extra information about InsecureCredential which is required by UI. -struct CredentialMetadata { - std::vector<PasswordForm> forms; - InsecureCredentialTypeFlags type = InsecureCredentialTypeFlags::kSecure; - base::Time latest_time; - IsMuted is_muted; -}; - namespace { -using CredentialPasswordsMap = - std::map<CredentialView, CredentialMetadata, PasswordCredentialLess>; - -// Transparent comparator that can compare InsecureCredential and -// PasswordForm. -struct CredentialWithoutPasswordLess { - template <typename T, typename U> - bool operator()(const T& lhs, const U& rhs) const { - return CredentialOriginAndUsernameAndStore(lhs) < - CredentialOriginAndUsernameAndStore(rhs); - } - - using is_transparent = void; - - private: - static auto CredentialOriginAndUsernameAndStore(const PasswordForm& form) { - return std::tie(form.signon_realm, form.username_value, form.in_store); - } - - static auto CredentialOriginAndUsernameAndStore(const InsecureCredential& c) { - return std::tie(c.signon_realm, c.username, c.in_store); - } -}; - -InsecureCredentialTypeFlags ConvertInsecureType(InsecureType type) { - switch (type) { - case InsecureType::kLeaked: - return InsecureCredentialTypeFlags::kCredentialLeaked; - case InsecureType::kPhished: - return InsecureCredentialTypeFlags::kCredentialPhished; - case InsecureType::kWeak: - return InsecureCredentialTypeFlags::kWeakCredential; - case InsecureType::kReused: - return InsecureCredentialTypeFlags::kReusedCredential; - } - NOTREACHED(); -} - -bool IsPasswordFormLeaked(const PasswordForm& form) { - return form.password_issues.find(InsecureType::kLeaked) != - form.password_issues.end(); -} - -bool IsPasswordFormPhished(const PasswordForm& form) { - return form.password_issues.find(InsecureType::kPhished) != - form.password_issues.end(); -} - bool SupportsMuteOperation(InsecureType insecure_type) { return (insecure_type == InsecureType::kLeaked || insecure_type == InsecureType::kPhished); } -// This function takes two lists: weak passwords and saved passwords and joins -// them, producing a map that contains CredentialWithPassword as keys and -// vector<PasswordForm> as values. -CredentialPasswordsMap GetInsecureCredentialsFromPasswords( - const base::flat_set<std::u16string>& weak_passwords, - SavedPasswordsPresenter::SavedPasswordsView saved_passwords) { - CredentialPasswordsMap credentials_to_forms; - - bool mark_all_credentials_leaked_for_testing = - base::GetFieldTrialParamByFeatureAsBool( - password_manager::features::kPasswordChangeInSettings, - password_manager::features:: - kPasswordChangeInSettingsWithForcedWarningForEverySite, - false); - if (mark_all_credentials_leaked_for_testing) { - for (const auto& form : saved_passwords) { - CredentialView insecure_credential(form); - auto& credential_to_form = credentials_to_forms[insecure_credential]; - credential_to_form.type = InsecureCredentialTypeFlags::kCredentialLeaked; - credential_to_form.forms.push_back(form); - credential_to_form.latest_time = form.date_created; - } - return credentials_to_forms; - } - - for (const auto& form : saved_passwords) { - if (IsPasswordFormLeaked(form) || IsPasswordFormPhished(form)) { - CredentialView insecure_credential(form); - auto& credential_to_form = credentials_to_forms[insecure_credential]; - for (const auto& pair : form.password_issues) { - credential_to_form.type |= ConvertInsecureType(pair.first); - credential_to_form.latest_time = - std::max(credential_to_form.latest_time, pair.second.create_time); - if (SupportsMuteOperation(pair.first)) - credential_to_form.is_muted = pair.second.is_muted; - } - // Populate the map. The values are vectors, because it is - // possible that multiple saved passwords match to the same - // insecure credential. - credential_to_form.forms.push_back(form); - } - if (weak_passwords.contains(form.password_value)) { - CredentialView weak_credential(form); - auto& credential_to_form = credentials_to_forms[weak_credential]; - credential_to_form.type |= InsecureCredentialTypeFlags::kWeakCredential; - - // This helps not to create a copy of the |form| in case the credential - // has also been insecure. This is important because we don't want to - // delete the form twice in the RemoveCredential. - if (!IsInsecure(credential_to_form.type)) { - credential_to_form.forms.push_back(form); - } - } - } - - return credentials_to_forms; -} - -std::vector<CredentialWithPassword> ExtractInsecureCredentials( - const CredentialPasswordsMap& credentials_to_forms, - bool (*condition)(const InsecureCredentialTypeFlags&)) { - std::vector<CredentialWithPassword> credentials; - for (const auto& credential_to_forms : credentials_to_forms) { - if (condition(credential_to_forms.second.type)) { - CredentialWithPassword credential(credential_to_forms.first); - credential.insecure_type = credential_to_forms.second.type; - credential.create_time = credential_to_forms.second.latest_time; - credential.is_muted = credential_to_forms.second.is_muted; - credentials.push_back(std::move(credential)); - } - } - return credentials; -} - // The function is only used by the weak check. #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) base::flat_set<std::u16string> ExtractPasswords( @@ -182,56 +52,6 @@ } // namespace -CredentialView::CredentialView(std::string signon_realm, - GURL url, - std::u16string username, - std::u16string password, - base::Time last_used_time) - : signon_realm(std::move(signon_realm)), - url(std::move(url)), - username(std::move(username)), - password(std::move(password)), - last_used_time(last_used_time) {} - -CredentialView::CredentialView(const PasswordForm& form) - : signon_realm(form.signon_realm), - url(form.url), - username(form.username_value), - password(form.password_value), - last_used_time(form.date_last_used) {} - -CredentialView::CredentialView(const CredentialView& credential) = default; -CredentialView::CredentialView(CredentialView&& credential) = default; -CredentialView& CredentialView::operator=(const CredentialView& credential) = - default; -CredentialView& CredentialView::operator=(CredentialView&& credential) = - default; -CredentialView::~CredentialView() = default; - -CredentialWithPassword::CredentialWithPassword(const CredentialView& credential) - : CredentialView(credential) {} -CredentialWithPassword::~CredentialWithPassword() = default; -CredentialWithPassword::CredentialWithPassword( - const CredentialWithPassword& other) = default; - -CredentialWithPassword::CredentialWithPassword(CredentialWithPassword&& other) = - default; -CredentialWithPassword::CredentialWithPassword( - const InsecureCredential& credential) - : CredentialView(credential.signon_realm, - GURL(credential.signon_realm), - credential.username, - /*password=*/{}, - /*last_used_time=*/base::Time()), - create_time(credential.create_time), - insecure_type(ConvertInsecureType(credential.insecure_type)), - is_muted(credential.is_muted) {} - -CredentialWithPassword& CredentialWithPassword::operator=( - const CredentialWithPassword& other) = default; -CredentialWithPassword& CredentialWithPassword::operator=( - CredentialWithPassword&& other) = default; - InsecureCredentialsManager::InsecureCredentialsManager( SavedPasswordsPresenter* presenter, scoped_refptr<PasswordStoreInterface> profile_store, @@ -244,8 +64,6 @@ InsecureCredentialsManager::~InsecureCredentialsManager() = default; -void InsecureCredentialsManager::Init() {} - #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) void InsecureCredentialsManager::StartWeakCheck( base::OnceClosure on_check_done) { @@ -305,47 +123,6 @@ SavedPasswordsPresenter::EditResult::kSuccess; } -bool InsecureCredentialsManager::UpdateCredential( - const CredentialView& credential, - const base::StringPiece password) { - auto it = credentials_to_forms_.find(credential); - if (it == credentials_to_forms_.end()) - return false; - - // Make sure there are matching password forms. Also erase duplicates if there - // are any. - const auto& forms = it->second.forms; - if (forms.empty()) - return false; - - for (size_t i = 1; i < forms.size(); ++i) - GetStoreFor(forms[i]).RemoveLogin(forms[i]); - - // Note: We Invoke EditPassword on the presenter rather than UpdateLogin() on - // the store, so that observers of the presenter get notified of this event. - return presenter_->EditPassword(forms[0], base::UTF8ToUTF16(password)); -} - -bool InsecureCredentialsManager::RemoveCredential( - const CredentialView& credential) { - auto it = credentials_to_forms_.find(credential); - if (it == credentials_to_forms_.end()) - return false; - - // Erase all matching credentials from the store. Return whether any - // credentials were deleted. - const auto& saved_passwords = it->second.forms; - for (const PasswordForm& saved_password : saved_passwords) - GetStoreFor(saved_password).RemoveLogin(saved_password); - - return !saved_passwords.empty(); -} - -std::vector<CredentialWithPassword> -InsecureCredentialsManager::GetInsecureCredentials() const { - return ExtractInsecureCredentials(credentials_to_forms_, &IsInsecure); -} - std::vector<CredentialUIEntry> InsecureCredentialsManager::GetInsecureCredentialEntries() const { DCHECK(presenter_); @@ -374,19 +151,6 @@ return credentials; } -std::vector<CredentialWithPassword> -InsecureCredentialsManager::GetWeakCredentials() const { - std::vector<CredentialWithPassword> weak_credentials = - ExtractInsecureCredentials(credentials_to_forms_, &IsWeak); - - auto get_sort_key = [this](const CredentialWithPassword& credential) { - return CreateSortKey(GetSavedPasswordsFor(credential)[0], - IgnoreStore(true)); - }; - base::ranges::sort(weak_credentials, {}, get_sort_key); - return weak_credentials; -} - std::vector<CredentialUIEntry> InsecureCredentialsManager::GetWeakCredentialEntries() const { DCHECK(presenter_); @@ -398,15 +162,6 @@ return credentials; } -SavedPasswordsPresenter::SavedPasswordsView -InsecureCredentialsManager::GetSavedPasswordsFor( - const CredentialView& credential) const { - auto it = credentials_to_forms_.find(credential); - return it != credentials_to_forms_.end() - ? it->second.forms - : SavedPasswordsPresenter::SavedPasswordsView(); -} - void InsecureCredentialsManager::AddObserver(Observer* observer) { observers_.AddObserver(observer); } @@ -415,18 +170,12 @@ observers_.RemoveObserver(observer); } -void InsecureCredentialsManager::UpdateInsecureCredentials() { - credentials_to_forms_ = GetInsecureCredentialsFromPasswords( - weak_passwords_, presenter_->GetSavedPasswords()); -} - void InsecureCredentialsManager::OnWeakCheckDone( base::ElapsedTimer timer_since_weak_check_start, base::flat_set<std::u16string> weak_passwords) { base::UmaHistogramTimes("PasswordManager.WeakCheck.Time", timer_since_weak_check_start.Elapsed()); weak_passwords_ = std::move(weak_passwords); - UpdateInsecureCredentials(); NotifyWeakCredentialsChanged(); } @@ -442,7 +191,6 @@ } weak_passwords_.insert(password); - UpdateInsecureCredentials(); NotifyWeakCredentialsChanged(); #endif } @@ -451,8 +199,6 @@ // new list of saved passwords. void InsecureCredentialsManager::OnSavedPasswordsChanged( SavedPasswordsPresenter::SavedPasswordsView saved_passwords) { - credentials_to_forms_ = - GetInsecureCredentialsFromPasswords(weak_passwords_, saved_passwords); NotifyInsecureCredentialsChanged(); NotifyWeakCredentialsChanged(); }
diff --git a/components/password_manager/core/browser/ui/insecure_credentials_manager.h b/components/password_manager/core/browser/ui/insecure_credentials_manager.h index dfb24e4b..df85c13 100644 --- a/components/password_manager/core/browser/ui/insecure_credentials_manager.h +++ b/components/password_manager/core/browser/ui/insecure_credentials_manager.h
@@ -33,114 +33,6 @@ struct CredentialUIEntry; class LeakCheckCredential; -enum class InsecureCredentialTypeFlags { - kSecure = 0, - // If the credential was leaked by a data breach. - kCredentialLeaked = 1 << 0, - // If the credential was reused on a phishing site. - kCredentialPhished = 1 << 1, - // If the credential has a weak password. - kWeakCredential = 1 << 2, - // If the credentials has the same password as another credentials. - kReusedCredential = 1 << 3, -}; - -constexpr InsecureCredentialTypeFlags operator&( - InsecureCredentialTypeFlags lhs, - InsecureCredentialTypeFlags rhs) { - return static_cast<InsecureCredentialTypeFlags>(static_cast<int>(lhs) & - static_cast<int>(rhs)); -} - -constexpr InsecureCredentialTypeFlags operator|( - InsecureCredentialTypeFlags lhs, - InsecureCredentialTypeFlags rhs) { - return static_cast<InsecureCredentialTypeFlags>(static_cast<int>(lhs) | - static_cast<int>(rhs)); -} - -constexpr InsecureCredentialTypeFlags& operator|=( - InsecureCredentialTypeFlags& lhs, - InsecureCredentialTypeFlags rhs) { - lhs = lhs | rhs; - return lhs; -} - -// Unsets the bits responsible for the reused and weak credential in the |flag|. -constexpr InsecureCredentialTypeFlags UnsetWeakAndReusedCredentialTypeFlags( - InsecureCredentialTypeFlags flag) { - return static_cast<InsecureCredentialTypeFlags>( - static_cast<int>(flag) & - ~(static_cast<int>(InsecureCredentialTypeFlags::kWeakCredential | - InsecureCredentialTypeFlags::kReusedCredential))); -} - -// Checks that |flag| contains at least one of insecure types. -constexpr bool IsInsecure(const InsecureCredentialTypeFlags& flag) { - return (flag & (InsecureCredentialTypeFlags::kCredentialLeaked | - InsecureCredentialTypeFlags::kCredentialPhished)) != - InsecureCredentialTypeFlags::kSecure; -} - -// Checks that |flag| contains weak type. -constexpr bool IsWeak(const InsecureCredentialTypeFlags& flag) { - return (flag & InsecureCredentialTypeFlags::kWeakCredential) != - InsecureCredentialTypeFlags::kSecure; -} - -// Simple struct that augments key values of InsecureCredential and a password. -struct CredentialView { - CredentialView(std::string signon_realm, - GURL url, - std::u16string username, - std::u16string password, - base::Time last_used_time); - // Enable explicit construction from PasswordForm for convenience. - explicit CredentialView(const PasswordForm& form); - CredentialView(const CredentialView& credential); - CredentialView(CredentialView&& credential); - CredentialView& operator=(const CredentialView& credential); - CredentialView& operator=(CredentialView&& credential); - ~CredentialView(); - - std::string signon_realm; - GURL url; - std::u16string username; - std::u16string password; - base::Time last_used_time; -}; - -// All information needed by UI to represent InsecureCredential. It's a result -// of deduplicating InsecureCredential to have single entity for phished, -// leaked and weak credentials with latest |create_time|, and after that joining -// with autofill::PasswordForms to get passwords. If the credential is only -// weak, |create_time| will be unset. -struct CredentialWithPassword : CredentialView { - explicit CredentialWithPassword(const CredentialView& credential); - explicit CredentialWithPassword(const InsecureCredential& credential); - CredentialWithPassword(const CredentialWithPassword& other); - CredentialWithPassword(CredentialWithPassword&& other); - ~CredentialWithPassword(); - - CredentialWithPassword& operator=(const CredentialWithPassword& other); - CredentialWithPassword& operator=(CredentialWithPassword&& other); - base::Time create_time; - InsecureCredentialTypeFlags insecure_type = - InsecureCredentialTypeFlags::kSecure; - IsMuted is_muted{false}; -}; - -// Comparator that can compare CredentialView or CredentialsWithPasswords. -struct PasswordCredentialLess { - bool operator()(const CredentialView& lhs, const CredentialView& rhs) const { - return std::tie(lhs.signon_realm, lhs.username, lhs.password) < - std::tie(rhs.signon_realm, rhs.username, rhs.password); - } -}; - -// Extra information about InsecureCredential which is required by UI. -struct CredentialMetadata; - // This class provides clients with saved insecure credentials and possibility // to save new LeakedCredentials, edit/delete/[un]mute insecure credentials and // match insecure credentials with corresponding autofill::PasswordForms. It @@ -148,8 +40,6 @@ // notified about changes to the list. class InsecureCredentialsManager : public SavedPasswordsPresenter::Observer { public: - using CredentialsView = base::span<const CredentialWithPassword>; - // Observer interface. Clients can implement this to get notified about // changes to the list of insecure and weak credentials. Clients can register // and de-register themselves, and are expected to do so before the provider @@ -166,8 +56,6 @@ scoped_refptr<PasswordStoreInterface> account_store = nullptr); ~InsecureCredentialsManager() override; - void Init(); - #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) // Computes weak credentials in a separate thread and then passes the result // to OnWeakCheckDone. @@ -178,15 +66,6 @@ // insecure. void SaveInsecureCredential(const LeakCheckCredential& credential); - // Attempts to change the stored password of |credential| to |new_password|. - // Returns whether the change succeeded. - bool UpdateCredential(const CredentialView& credential, - const base::StringPiece password); - - // Attempts to remove |credential| from the password store. Returns whether - // the remove succeeded. - bool RemoveCredential(const CredentialView& credential); - // Attempts to mute |credential| from the password store. // Returns whether the mute succeeded. bool MuteCredential(const CredentialUIEntry& credential); @@ -196,34 +75,16 @@ bool UnmuteCredential(const CredentialUIEntry& credential); // Returns a vector of currently insecure credentials. - // TODO(crbug.com/1330549): Use CredentialUIEntry only. - std::vector<CredentialWithPassword> GetInsecureCredentials() const; std::vector<CredentialUIEntry> GetInsecureCredentialEntries() const; // Returns a vector of currently weak credentials. - // TODO(crbug.com/1330549): Use CredentialUIEntry only. - std::vector<CredentialWithPassword> GetWeakCredentials() const; std::vector<CredentialUIEntry> GetWeakCredentialEntries() const; - // Returns password forms which map to provided insecure credential. - // In most of the cases vector will have 1 element only. - SavedPasswordsPresenter::SavedPasswordsView GetSavedPasswordsFor( - const CredentialView& credential) const; - // Allows clients and register and de-register themselves. void AddObserver(Observer* observer); void RemoveObserver(Observer* observer); private: - using CredentialPasswordsMap = - std::map<CredentialView, CredentialMetadata, PasswordCredentialLess>; - - // Recomputes the insecure credentials by making use of information stored in - // `insecure_credentials_`, `weak_passwords_` and `presenter_`. - // This does not invoke either `NotifyInsecureCredentialsChanged` or - // `NotifyWeakCredentialsChanged`, so that it can be used more generally. - void UpdateInsecureCredentials(); - // Updates |weak_passwords| set and notifies observers that weak credentials // were changed. void OnWeakCheckDone(base::ElapsedTimer timer_since_weak_check_start, @@ -252,16 +113,9 @@ scoped_refptr<PasswordStoreInterface> profile_store_; scoped_refptr<PasswordStoreInterface> account_store_; - // Cache of the most recently obtained insecure credentials. - std::vector<InsecureCredential> insecure_credentials_; - // Cache of the most recently obtained weak passwords. base::flat_set<std::u16string> weak_passwords_; - // A map that matches CredentialView to corresponding PasswordForms, latest - // create_type and combined insecure type. - CredentialPasswordsMap credentials_to_forms_; - // A scoped observer for |presenter_|. base::ScopedObservation<SavedPasswordsPresenter, SavedPasswordsPresenter::Observer>
diff --git a/components/password_manager/core/browser/ui/insecure_credentials_manager_unittest.cc b/components/password_manager/core/browser/ui/insecure_credentials_manager_unittest.cc index 17875bf..7e6e1709 100644 --- a/components/password_manager/core/browser/ui/insecure_credentials_manager_unittest.cc +++ b/components/password_manager/core/browser/ui/insecure_credentials_manager_unittest.cc
@@ -33,16 +33,12 @@ constexpr char16_t kUsername2[] = u"bob"; constexpr char16_t kPassword1[] = u"f00b4r"; -constexpr char kPassword2[] = "s3cr3t"; constexpr char16_t kPassword216[] = u"s3cr3t"; -constexpr char16_t kPassword3[] = u"484her"; #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) constexpr char16_t kWeakPassword1[] = u"123456"; -constexpr char kWeakPassword2[] = "abcdabcdabcdabcdabcdabcdabcdabcdabcdabcda"; constexpr char16_t kWeakPassword216[] = u"abcdabcdabcdabcdabcdabcdabcdabcdabcdabcda"; -constexpr char kStrongPassword1[] = "fnlsr4@cm^mdls@fkspnsg3d"; constexpr char16_t kStrongPassword116[] = u"fnlsr4@cm^mdls@fkspnsg3d"; constexpr char16_t kStrongPassword2[] = u"pmsFlsnoab4nsl#losb@skpfnsbkjb^klsnbs!cns"; @@ -84,34 +80,6 @@ std::u16string(password)); } -CredentialWithPassword MakeCompromisedCredential( - const PasswordForm& form, - const InsecureCredentialTypeFlags type = - InsecureCredentialTypeFlags::kCredentialLeaked, - const bool is_muted = false) { - CredentialWithPassword credential_with_password((CredentialView(form))); - credential_with_password.insecure_type = type; - credential_with_password.is_muted = IsMuted(is_muted); - return credential_with_password; -} - -#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) -CredentialWithPassword MakeWeakCredential(const PasswordForm& form) { - CredentialWithPassword weak_credential{CredentialView(form)}; - weak_credential.insecure_type = InsecureCredentialTypeFlags::kWeakCredential; - return weak_credential; -} - -CredentialWithPassword MakeWeakAndCompromisedCredential( - const PasswordForm& form) { - CredentialWithPassword credential_with_password = - MakeCompromisedCredential(form); - credential_with_password.insecure_type |= - InsecureCredentialTypeFlags::kWeakCredential; - return credential_with_password; -} -#endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) - class InsecureCredentialsManagerTest : public ::testing::Test { protected: InsecureCredentialsManagerTest() { @@ -124,6 +92,7 @@ } TestPasswordStore& store() { return *store_; } + SavedPasswordsPresenter& presenter() { return presenter_; } InsecureCredentialsManager& provider() { return provider_; } void RunUntilIdle() { task_env_.RunUntilIdle(); } @@ -160,23 +129,6 @@ } // namespace -bool operator==(const CredentialWithPassword& lhs, - const CredentialWithPassword& rhs) { - return lhs.signon_realm == rhs.signon_realm && lhs.username == rhs.username && - lhs.create_time == rhs.create_time && lhs.is_muted == rhs.is_muted && - lhs.insecure_type == rhs.insecure_type && lhs.password == rhs.password; -} - -std::ostream& operator<<(std::ostream& out, - const CredentialWithPassword& credential) { - return out << "{ signon_realm: " << credential.signon_realm - << ", username: " << credential.username - << ", create_time: " << credential.create_time - << ", is_muted: " << credential.is_muted << ", insecure_type: " - << static_cast<int>(credential.insecure_type) - << ", password: " << credential.password << " }"; -} - // Tests whether adding and removing an observer works as expected. TEST_F(InsecureCredentialsManagerTest, NotifyObserversAboutCompromisedCredentialChanges) { @@ -204,7 +156,7 @@ store().UpdateLogin(password_form); RunUntilIdle(); - EXPECT_THAT(provider().GetInsecureCredentials(), IsEmpty()); + EXPECT_THAT(provider().GetInsecureCredentialEntries(), IsEmpty()); // After an observer is removed it should no longer receive notifications. provider().RemoveObserver(&observer); @@ -213,8 +165,8 @@ {InsecureType::kLeaked, InsecurityMetadata()}); store().UpdateLogin(password_form); RunUntilIdle(); - EXPECT_THAT(provider().GetInsecureCredentials(), - ElementsAre(MakeCompromisedCredential(password_form))); + EXPECT_THAT(provider().GetInsecureCredentialEntries(), + ElementsAre(CredentialUIEntry(password_form))); } // Tests whether adding and removing an observer works as expected. @@ -264,8 +216,8 @@ store().AddLogin(password); RunUntilIdle(); - EXPECT_THAT(provider().GetInsecureCredentials(), - ElementsAre(MakeCompromisedCredential(password))); + EXPECT_THAT(provider().GetInsecureCredentialEntries(), + ElementsAre(CredentialUIEntry(password))); } // Tests that the provider is able to join a password with a credential that was @@ -282,11 +234,8 @@ store().AddLogin(password); RunUntilIdle(); - CredentialWithPassword expected = MakeCompromisedCredential(password); - expected.insecure_type = (InsecureCredentialTypeFlags::kCredentialLeaked | - InsecureCredentialTypeFlags::kCredentialPhished); - - EXPECT_THAT(provider().GetInsecureCredentials(), ElementsAre(expected)); + EXPECT_THAT(provider().GetInsecureCredentialEntries(), + ElementsAre(CredentialUIEntry(password))); } // Tests that the provider reacts whenever the saved passwords or the @@ -299,37 +248,36 @@ store().AddLogin(password1); RunUntilIdle(); - EXPECT_THAT(provider().GetInsecureCredentials(), IsEmpty()); + EXPECT_THAT(provider().GetInsecureCredentialEntries(), IsEmpty()); password1.password_issues.insert( {InsecureType::kLeaked, InsecurityMetadata()}); store().UpdateLogin(password1); RunUntilIdle(); - EXPECT_THAT(provider().GetInsecureCredentials(), - ElementsAre(MakeCompromisedCredential(password1))); + EXPECT_THAT(provider().GetInsecureCredentialEntries(), + ElementsAre(CredentialUIEntry(password1))); store().AddLogin(password2); RunUntilIdle(); - EXPECT_THAT(provider().GetInsecureCredentials(), - ElementsAre(MakeCompromisedCredential(password1))); + EXPECT_THAT(provider().GetInsecureCredentialEntries(), + ElementsAre(CredentialUIEntry(password1))); password2.password_issues.insert( {InsecureType::kLeaked, InsecurityMetadata()}); store().UpdateLogin(password2); RunUntilIdle(); - EXPECT_THAT( - provider().GetInsecureCredentials(), - testing::UnorderedElementsAre(MakeCompromisedCredential(password1), - MakeCompromisedCredential(password2))); + EXPECT_THAT(provider().GetInsecureCredentialEntries(), + testing::UnorderedElementsAre(CredentialUIEntry(password1), + CredentialUIEntry(password2))); store().RemoveLogin(password1); RunUntilIdle(); - EXPECT_THAT(provider().GetInsecureCredentials(), - ElementsAre(MakeCompromisedCredential(password2))); + EXPECT_THAT(provider().GetInsecureCredentialEntries(), + ElementsAre(CredentialUIEntry(password2))); store().RemoveLogin(password2); RunUntilIdle(); - EXPECT_THAT(provider().GetInsecureCredentials(), IsEmpty()); + EXPECT_THAT(provider().GetInsecureCredentialEntries(), IsEmpty()); } // Tests that the provider is able to join multiple passwords with compromised @@ -349,10 +297,9 @@ store().AddLogin(password2); RunUntilIdle(); - EXPECT_THAT( - provider().GetInsecureCredentials(), - testing::UnorderedElementsAre(MakeCompromisedCredential(password1), - MakeCompromisedCredential(password2))); + EXPECT_THAT(provider().GetInsecureCredentialEntries(), + testing::UnorderedElementsAre(CredentialUIEntry(password1), + CredentialUIEntry(password2))); } // Tests that joining a compromised credential with multiple saved passwords for @@ -371,42 +318,8 @@ store().AddLogin(password2); RunUntilIdle(); - EXPECT_THAT(provider().GetInsecureCredentials(), - ElementsAre(MakeCompromisedCredential(password1))); -} - -// Tests that verifies mapping compromised credentials to passwords works -// correctly. -TEST_F(InsecureCredentialsManagerTest, MapCompromisedPasswordsToPasswords) { - std::vector<PasswordForm> passwords = { - MakeSavedPassword(kExampleCom, kUsername1, kPassword1, u"element_1"), - MakeSavedPassword(kExampleCom, kUsername1, kPassword1, u"element_2"), - MakeSavedPassword(kExampleOrg, kUsername2, kPassword216)}; - - passwords.at(0).password_issues.insert( - {InsecureType::kLeaked, InsecurityMetadata()}); - passwords.at(1).password_issues.insert( - {InsecureType::kLeaked, InsecurityMetadata()}); - passwords.at(2).password_issues.insert( - {InsecureType::kLeaked, InsecurityMetadata()}); - - std::vector<CredentialWithPassword> credentials_with_password = { - MakeCompromisedCredential(passwords[0]), - MakeCompromisedCredential(passwords[1]), - MakeCompromisedCredential(passwords[2])}; - - for (const auto& form : passwords) - store().AddLogin(form); - - RunUntilIdle(); - EXPECT_THAT(provider().GetSavedPasswordsFor(credentials_with_password[0]), - ElementsAreArray(store().stored_passwords().at(kExampleCom))); - - EXPECT_THAT(provider().GetSavedPasswordsFor(credentials_with_password[1]), - ElementsAreArray(store().stored_passwords().at(kExampleCom))); - - EXPECT_THAT(provider().GetSavedPasswordsFor(credentials_with_password[2]), - ElementsAreArray(store().stored_passwords().at(kExampleOrg))); + EXPECT_THAT(provider().GetInsecureCredentialEntries(), + ElementsAre(CredentialUIEntry(password1))); } #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) @@ -427,7 +340,7 @@ AdvanceClock(base::Milliseconds(kDelay)); RunUntilIdle(); - EXPECT_THAT(provider().GetWeakCredentials(), IsEmpty()); + EXPECT_THAT(provider().GetWeakCredentialEntries(), IsEmpty()); histogram_tester().ExpectUniqueSample( "PasswordManager.WeakCheck.CheckedPasswords", 0, 1); @@ -453,7 +366,7 @@ AdvanceClock(base::Milliseconds(2 * kDelay)); RunUntilIdle(); - EXPECT_THAT(provider().GetWeakCredentials(), IsEmpty()); + EXPECT_THAT(provider().GetWeakCredentialEntries(), IsEmpty()); histogram_tester().ExpectUniqueSample( "PasswordManager.WeakCheck.CheckedPasswords", 2, 1); @@ -481,12 +394,8 @@ AdvanceClock(base::Milliseconds(kDelay)); RunUntilIdle(); - std::vector<CredentialWithPassword> weak_credentials = - provider().GetWeakCredentials(); - - ASSERT_EQ(weak_credentials.size(), 1u); - EXPECT_EQ(weak_credentials[0].password, kWeakPassword1); - EXPECT_TRUE(IsWeak(weak_credentials[0].insecure_type)); + EXPECT_THAT(provider().GetWeakCredentialEntries(), + ElementsAre(CredentialUIEntry(passwords[0]))); histogram_tester().ExpectUniqueSample( "PasswordManager.WeakCheck.CheckedPasswords", 2, 1); @@ -499,7 +408,7 @@ } // Tests that credentials with the same signon_realm and username, but different -// passwords will be both returned by GetWeakCredentials(). +// passwords will be both returned by GetWeakCredentialEntries(). TEST_F(InsecureCredentialsManagerTest, FindBothWeakCredentialsWithDifferentPasswords) { std::vector<PasswordForm> passwords = { @@ -515,12 +424,9 @@ AdvanceClock(base::Milliseconds(kDelay)); RunUntilIdle(); - std::vector<CredentialWithPassword> weak_credentials = - provider().GetWeakCredentials(); - - ASSERT_EQ(weak_credentials.size(), 2u); - EXPECT_TRUE(IsWeak(weak_credentials[0].insecure_type)); - EXPECT_TRUE(IsWeak(weak_credentials[1].insecure_type)); + EXPECT_THAT(provider().GetWeakCredentialEntries(), + ElementsAre(CredentialUIEntry(passwords[0]), + CredentialUIEntry(passwords[1]))); histogram_tester().ExpectUniqueSample( "PasswordManager.WeakCheck.CheckedPasswords", 2, 1); @@ -533,7 +439,7 @@ } // Tests that credentials with the same signon_realm, username and passwords -// will be joind and GetWeakCredentials() will return one credential. +// will be joind and GetWeakCredentialEntries() will return one credential. TEST_F(InsecureCredentialsManagerTest, JoinWeakCredentialsWithTheSamePasswords) { std::vector<PasswordForm> passwords = { @@ -548,12 +454,8 @@ AdvanceClock(base::Milliseconds(kDelay)); RunUntilIdle(); - std::vector<CredentialWithPassword> weak_credentials = - provider().GetWeakCredentials(); - - ASSERT_EQ(weak_credentials.size(), 1u); - EXPECT_EQ(weak_credentials[0].password, kWeakPassword1); - EXPECT_TRUE(IsWeak(weak_credentials[0].insecure_type)); + EXPECT_THAT(provider().GetWeakCredentialEntries(), + ElementsAre(CredentialUIEntry(passwords[0]))); histogram_tester().ExpectUniqueSample( "PasswordManager.WeakCheck.CheckedPasswords", 1, 1); @@ -582,18 +484,11 @@ AdvanceClock(base::Milliseconds(kDelay)); RunUntilIdle(); - std::vector<CredentialWithPassword> returned_weak_credentials = - provider().GetWeakCredentials(); - std::vector<CredentialWithPassword> returned_compromised_credentials = - provider().GetInsecureCredentials(); - - ASSERT_EQ(returned_weak_credentials.size(), 1u); - EXPECT_EQ(returned_weak_credentials[0].password, kWeakPassword1); - EXPECT_TRUE(IsWeak(returned_weak_credentials[0].insecure_type)); - - ASSERT_EQ(returned_compromised_credentials.size(), 2u); - EXPECT_TRUE(IsInsecure(returned_compromised_credentials[0].insecure_type)); - EXPECT_TRUE(IsInsecure(returned_compromised_credentials[1].insecure_type)); + EXPECT_THAT(provider().GetWeakCredentialEntries(), + ElementsAre(CredentialUIEntry(passwords[0]))); + EXPECT_THAT(provider().GetInsecureCredentialEntries(), + ElementsAre(CredentialUIEntry(passwords[0]), + CredentialUIEntry(passwords[1]))); histogram_tester().ExpectUniqueSample( "PasswordManager.WeakCheck.CheckedPasswords", 2, 1); @@ -606,8 +501,8 @@ } // Checks that for a credential that is both weak and compromised, -// getWeakCredentials and GetInsecureCredentials will return this credential -// in one instance. +// GetWeakCredentialEntries and GetInsecureCredentials will return this +// credential in one instance. TEST_F(InsecureCredentialsManagerTest, SingleCredentialIsWeakAndCompromised) { std::vector<PasswordForm> passwords = { MakeSavedPassword(kExampleCom, kUsername1, kWeakPassword1)}; @@ -622,23 +517,10 @@ AdvanceClock(base::Milliseconds(kDelay)); RunUntilIdle(); - std::vector<CredentialWithPassword> returned_weak_credentials = - provider().GetWeakCredentials(); - std::vector<CredentialWithPassword> returned_compromised_credentials = - provider().GetInsecureCredentials(); - - // Since the credential is weak and compromised, the |insecure_type| should be - // weak and compromised for elements from |returned_weak_credentials| and - // |returned_compromised_credentials|. - ASSERT_EQ(returned_weak_credentials.size(), 1u); - EXPECT_EQ(returned_weak_credentials[0].password, kWeakPassword1); - EXPECT_TRUE(IsWeak(returned_weak_credentials[0].insecure_type)); - EXPECT_TRUE(IsInsecure(returned_weak_credentials[0].insecure_type)); - - ASSERT_EQ(returned_compromised_credentials.size(), 1u); - EXPECT_EQ(returned_compromised_credentials[0].password, kWeakPassword1); - EXPECT_TRUE(IsWeak(returned_compromised_credentials[0].insecure_type)); - EXPECT_TRUE(IsInsecure(returned_compromised_credentials[0].insecure_type)); + EXPECT_THAT(provider().GetWeakCredentialEntries(), + ElementsAre(CredentialUIEntry(passwords[0]))); + EXPECT_THAT(provider().GetInsecureCredentialEntries(), + ElementsAre(CredentialUIEntry(passwords[0]))); histogram_tester().ExpectUniqueSample( "PasswordManager.WeakCheck.CheckedPasswords", 1, 1); @@ -661,13 +543,15 @@ store().AddLogin(password_form); RunUntilIdle(); - CredentialWithPassword expected = MakeCompromisedCredential(password_form); - expected.create_time = base::Time::Now(); + EXPECT_THAT(provider().GetInsecureCredentialEntries(), IsEmpty()); + password_form.password_issues[InsecureType::kLeaked].create_time = + base::Time::Now(); provider().SaveInsecureCredential(credential); RunUntilIdle(); - EXPECT_THAT(provider().GetInsecureCredentials(), ElementsAre(expected)); + EXPECT_THAT(provider().GetInsecureCredentialEntries(), + ElementsAre(CredentialUIEntry(password_form))); } // Test verifies that saving LeakCheckCredential doesn't occur for already @@ -1111,51 +995,48 @@ EXPECT_THAT(provider().GetInsecureCredentialEntries(), SizeIs(1u)); } -// Test verifies that editing Compromised Credential via provider change the -// original password form. +// Test verifies that editing Compromised Credential makes it secure. TEST_F(InsecureCredentialsManagerTest, UpdateCompromisedPassword) { PasswordForm password_form = MakeSavedPassword(kExampleCom, kUsername1, kPassword1); password_form.password_issues.insert( {InsecureType::kLeaked, InsecurityMetadata()}); - store().AddLogin(password_form); - RunUntilIdle(); - CredentialWithPassword expected = -#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) - MakeWeakAndCompromisedCredential(password_form); -#else - MakeCompromisedCredential(password_form); -#endif - EXPECT_TRUE(provider().UpdateCredential(expected, kPassword2)); + EXPECT_THAT(provider().GetInsecureCredentialEntries(), SizeIs(1u)); + + CredentialUIEntry original_credential(password_form), + updated_credential = original_credential; + updated_credential.password = kPassword216; + presenter().EditSavedCredentials(original_credential, updated_credential); RunUntilIdle(); - expected.password = kPassword216; - EXPECT_TRUE(provider().GetInsecureCredentials().empty()); + EXPECT_TRUE(provider().GetInsecureCredentialEntries().empty()); } #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) -// Test verifies that editing weak credential via provider has affect on weak -// credentials and updates password in the store. -TEST_F(InsecureCredentialsManagerTest, UpdateWeakPassword) { +// Test verifies that editing a weak credential to another weak credential +// continues to be treated weak. +TEST_F(InsecureCredentialsManagerTest, UpdatedWeakPasswordBecomesStrong) { PasswordForm password_form = MakeSavedPassword(kExampleCom, kUsername1, kWeakPassword1); store().AddLogin(password_form); RunUntilIdle(); + provider().StartWeakCheck(); RunUntilIdle(); + EXPECT_THAT(provider().GetWeakCredentialEntries(), + ElementsAre(CredentialUIEntry(password_form))); - EXPECT_EQ(provider().GetWeakCredentials().size(), 1u); - EXPECT_TRUE(provider().UpdateCredential(CredentialView(password_form), - kStrongPassword1)); + CredentialUIEntry original_credential(password_form), + updated_credential = original_credential; + updated_credential.password = kStrongPassword116; + presenter().EditSavedCredentials(original_credential, updated_credential); RunUntilIdle(); - EXPECT_THAT(provider().GetWeakCredentials(), IsEmpty()); - EXPECT_EQ(GetSavedPasswordForUsername(kExampleCom, kUsername1), - kStrongPassword116); + EXPECT_THAT(provider().GetWeakCredentialEntries(), IsEmpty()); } // Test verifies that editing a weak credential to another weak credential @@ -1169,101 +1050,21 @@ provider().StartWeakCheck(); RunUntilIdle(); + EXPECT_THAT(provider().GetWeakCredentialEntries(), + ElementsAre(CredentialUIEntry(password_form))); - CredentialWithPassword expected = MakeWeakCredential(password_form); - EXPECT_THAT(provider().GetWeakCredentials(), ElementsAre(expected)); - - EXPECT_TRUE(provider().UpdateCredential(expected, kWeakPassword2)); + CredentialUIEntry original_credential(password_form), + updated_credential = original_credential; + updated_credential.password = kWeakPassword216; + presenter().EditSavedCredentials(original_credential, updated_credential); RunUntilIdle(); - expected.password = kWeakPassword216; - EXPECT_THAT(provider().GetWeakCredentials(), ElementsAre(expected)); + EXPECT_THAT(provider().GetWeakCredentialEntries(), + ElementsAre(updated_credential)); } -// Test verifies that editing credential that is weak and compromised via -// provider change the saved password. -TEST_F(InsecureCredentialsManagerTest, UpdateInsecurePassword) { - PasswordForm password_form = - MakeSavedPassword(kExampleCom, kUsername1, kWeakPassword1); - password_form.password_issues.insert( - {InsecureType::kLeaked, InsecurityMetadata()}); - - store().AddLogin(password_form); - RunUntilIdle(); - provider().StartWeakCheck(); - RunUntilIdle(); - - CredentialWithPassword expected = - MakeWeakAndCompromisedCredential(password_form); - EXPECT_THAT(provider().GetWeakCredentials(), ElementsAre(expected)); - EXPECT_THAT(provider().GetInsecureCredentials(), ElementsAre(expected)); - - EXPECT_TRUE(provider().UpdateCredential(expected, kStrongPassword1)); - RunUntilIdle(); - - EXPECT_EQ(GetSavedPasswordForUsername(kExampleCom, kUsername1), - kStrongPassword116); -} -#endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) - -TEST_F(InsecureCredentialsManagerTest, RemoveCompromisedCredential) { - PasswordForm password = - MakeSavedPassword(kExampleCom, kUsername1, kPassword1); - password.password_issues.insert( - {InsecureType::kLeaked, InsecurityMetadata()}); - - store().AddLogin(password); - RunUntilIdle(); - - CredentialWithPassword expected = MakeCompromisedCredential(password); - expected.password = password.password_value; - - EXPECT_THAT(provider().GetInsecureCredentials(), ElementsAre(expected)); - - EXPECT_TRUE(provider().RemoveCredential(expected)); - RunUntilIdle(); - EXPECT_THAT(provider().GetInsecureCredentials(), IsEmpty()); -} - -#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) -TEST_F(InsecureCredentialsManagerTest, RemoveWeakCredential) { - PasswordForm password = - MakeSavedPassword(kExampleCom, kUsername1, kWeakPassword1); - - store().AddLogin(password); - RunUntilIdle(); - provider().StartWeakCheck(); - RunUntilIdle(); - - EXPECT_EQ(provider().GetWeakCredentials().size(), 1u); - EXPECT_TRUE(provider().RemoveCredential(CredentialView(password))); - RunUntilIdle(); - EXPECT_THAT(GetSavedPasswordForUsername(kExampleCom, kUsername1), IsEmpty()); -} - -TEST_F(InsecureCredentialsManagerTest, RemoveInsecureCredential) { - PasswordForm password_form = - MakeSavedPassword(kExampleCom, kUsername1, kWeakPassword1); - password_form.password_issues.insert( - {InsecureType::kLeaked, InsecurityMetadata()}); - - store().AddLogin(password_form); - RunUntilIdle(); - provider().StartWeakCheck(); - RunUntilIdle(); - - CredentialWithPassword expected = - MakeWeakAndCompromisedCredential(password_form); - EXPECT_THAT(provider().GetWeakCredentials(), ElementsAre(expected)); - EXPECT_THAT(provider().GetInsecureCredentials(), ElementsAre(expected)); - - EXPECT_TRUE(provider().RemoveCredential(expected)); - RunUntilIdle(); - EXPECT_THAT(GetSavedPasswordForUsername(kExampleCom, kUsername1), IsEmpty()); -} - -// Verifues that GetWeakCredentials() returns sorted weak credentials by using -// CreateSortKey. +// Verifues that GetWeakCredentialEntries() returns sorted weak credentials by +// using CreateSortKey. TEST_F(InsecureCredentialsManagerTest, GetWeakCredentialsReturnsSortedData) { const std::vector<PasswordForm> password_forms = { MakeSavedPassword("http://example-a.com", u"user_a1", u"pwd"), @@ -1279,15 +1080,15 @@ provider().StartWeakCheck(); RunUntilIdle(); - EXPECT_THAT(provider().GetWeakCredentials(), - ElementsAre(MakeWeakCredential(password_forms[0]), - MakeWeakCredential(password_forms[1]), - MakeWeakCredential(password_forms[2]), - MakeWeakCredential(password_forms[3]))); + EXPECT_THAT(provider().GetWeakCredentialEntries(), + ElementsAre(CredentialUIEntry(password_forms[0]), + CredentialUIEntry(password_forms[1]), + CredentialUIEntry(password_forms[2]), + CredentialUIEntry(password_forms[3]))); } -// Verifues that GetWeakCredentials() returns sorted weak credentials by using -// CreateSortKey. +// Verifues that GetWeakCredentialEntries() returns sorted weak credentials by +// using CreateSortKey. TEST_F(InsecureCredentialsManagerTest, GetWeakCredentialEntries) { const std::vector<PasswordForm> password_forms = { MakeSavedPassword("http://example-a.com", u"user_a1", u"pwd"), @@ -1379,58 +1180,6 @@ }; } // namespace -// Tests that verifies mapping compromised credentials to passwords works -// correctly. -TEST_F(InsecureCredentialsManagerWithTwoStoresTest, - MapCompromisedPasswordsToPasswords) { - // Add credentials for both `kExampleCom` and `kExampleOrg` in both stores - // with the same username and difference passwords. For `kUsername1`, the - // `kPassword1` are `kPassword2` are compromised while - // `kPassword3` is safe. - std::vector<PasswordForm> profile_store_passwords = { - MakeSavedPassword(kExampleCom, kUsername1, kPassword1), - MakeSavedPassword(kExampleOrg, kUsername1, kPassword3)}; - for (const PasswordForm& profile_password : profile_store_passwords) - profile_store().AddLogin(profile_password); - - std::vector<PasswordForm> account_store_passwords = { - MakeSavedPassword(kExampleCom, kUsername1, kPassword3), - MakeSavedPassword(kExampleOrg, kUsername1, kPassword216)}; - for (const PasswordForm& account_password : account_store_passwords) - account_store().AddLogin(account_password); - - RunUntilIdle(); - - LeakCheckCredential credential = MakeLeakCredential(kUsername1, kPassword3); - - // Mark `kUsername1` and `kPassword3` to be compromised. - provider().SaveInsecureCredential(credential); - - RunUntilIdle(); - - // Each password should be joined only with compromised credential from - // their store. - EXPECT_THAT(provider().GetSavedPasswordsFor(CredentialView( - kExampleCom, GURL(), kUsername1, kPassword1, base::Time())), - IsEmpty()); - - EXPECT_EQ(provider() - .GetSavedPasswordsFor(CredentialView( - kExampleOrg, GURL(), kUsername1, kPassword3, base::Time())) - .size(), - 1u); - - EXPECT_EQ(provider() - .GetSavedPasswordsFor(CredentialView( - kExampleCom, GURL(), kUsername1, kPassword3, base::Time())) - .size(), - 1u); - - EXPECT_THAT(provider().GetSavedPasswordsFor(CredentialView( - kExampleOrg, GURL(), kUsername1, kPassword216, base::Time())), - IsEmpty()); -} - // Test verifies that saving LeakCheckCredential via provider adds expected // compromised credential to the correct store. TEST_F(InsecureCredentialsManagerWithTwoStoresTest, SaveCompromisedPassword) { @@ -1453,7 +1202,7 @@ provider().SaveInsecureCredential(MakeLeakCredential(kUsername1, kPassword1)); RunUntilIdle(); - EXPECT_EQ(2U, provider().GetInsecureCredentials().size()); + EXPECT_EQ(2U, provider().GetInsecureCredentialEntries().size()); EXPECT_EQ(1U, profile_store() .stored_passwords() .at(kExampleCom) @@ -1476,7 +1225,7 @@ MakeLeakCredential(kUsername1, kPassword216)); RunUntilIdle(); - EXPECT_EQ(3U, provider().GetInsecureCredentials().size()); + EXPECT_EQ(3U, provider().GetInsecureCredentialEntries().size()); EXPECT_EQ(1U, profile_store() .stored_passwords() .at(kExampleCom) @@ -1494,52 +1243,7 @@ .password_issues.size()); } -TEST_F(InsecureCredentialsManagerWithTwoStoresTest, - RemoveCompromisedCredential) { - // Add `kUsername1`,`kPassword1` to both stores. - PasswordForm profile_form = - MakeSavedPassword(kExampleCom, kUsername1, kPassword1); - profile_form.password_issues.insert( - {InsecureType::kLeaked, InsecurityMetadata()}); - PasswordForm account_form = - MakeSavedPassword(kExampleCom, kUsername1, kPassword1); - account_form.password_issues.insert( - {InsecureType::kLeaked, InsecurityMetadata()}); - profile_store().AddLogin(profile_form); - account_store().AddLogin(account_form); - RunUntilIdle(); - - // Now remove the compromised credentials - EXPECT_TRUE(provider().RemoveCredential(CredentialView( - kExampleCom, GURL(), kUsername1, kPassword1, base::Time()))); - RunUntilIdle(); - - // It should have been removed from both stores. - EXPECT_TRUE(profile_store().stored_passwords().at(kExampleCom).empty()); - EXPECT_TRUE(account_store().stored_passwords().at(kExampleCom).empty()); -} - #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) -TEST_F(InsecureCredentialsManagerWithTwoStoresTest, RemoveWeakCredential) { - // Add `kUsername1`,`kPassword1` to both stores. - profile_store().AddLogin( - MakeSavedPassword(kExampleCom, kUsername1, kWeakPassword1)); - account_store().AddLogin( - MakeSavedPassword(kExampleCom, kUsername1, kWeakPassword1)); - RunUntilIdle(); - provider().StartWeakCheck(); - RunUntilIdle(); - - // Now remove the weak credential - EXPECT_TRUE(provider().RemoveCredential(CredentialView( - kExampleCom, GURL(), kUsername1, kWeakPassword1, base::Time()))); - RunUntilIdle(); - - // It should have been removed from both stores. - EXPECT_THAT(profile_store().stored_passwords().at(kExampleCom), IsEmpty()); - EXPECT_THAT(account_store().stored_passwords().at(kExampleCom), IsEmpty()); -} - TEST_F(InsecureCredentialsManagerWithTwoStoresTest, GetInsecureCredentialsWeak) { profile_store().AddLogin(
diff --git a/components/password_manager/core/browser/ui/saved_passwords_presenter.cc b/components/password_manager/core/browser/ui/saved_passwords_presenter.cc index a69f1b0..20f63e3 100644 --- a/components/password_manager/core/browser/ui/saved_passwords_presenter.cc +++ b/components/password_manager/core/browser/ui/saved_passwords_presenter.cc
@@ -130,10 +130,6 @@ } } -void SavedPasswordsPresenter::RemovePassword(const PasswordForm& form) { - RemoveCredential(CredentialUIEntry(form)); -} - bool SavedPasswordsPresenter::RemoveCredential( const CredentialUIEntry& credential) { const auto range = @@ -200,27 +196,6 @@ return true; } -bool SavedPasswordsPresenter::EditPassword(const PasswordForm& form, - std::u16string new_password) { - CredentialUIEntry updated_credential(form); - updated_credential.password = new_password; - return EditSavedCredentials(CredentialUIEntry(form), updated_credential) == - EditResult::kSuccess; -} - -bool SavedPasswordsPresenter::EditSavedPasswords( - const PasswordForm& form, - const std::u16string& new_username, - const std::u16string& new_password) { - // TODO(crbug.com/1184691): Change desktop settings and maybe iOS to use this - // presenter for updating the duplicates. - CredentialUIEntry updated_credential(form); - updated_credential.password = new_password; - updated_credential.username = new_username; - return EditSavedCredentials(CredentialUIEntry(form), updated_credential) == - EditResult::kSuccess; -} - SavedPasswordsPresenter::EditResult SavedPasswordsPresenter::EditSavedCredentials( const CredentialUIEntry& original_credential, @@ -300,14 +275,13 @@ return EditResult::kSuccess; } -SavedPasswordsPresenter::SavedPasswordsView -SavedPasswordsPresenter::GetSavedPasswords() const { +SavedPasswordsView SavedPasswordsPresenter::GetSavedPasswords() const { return passwords_; } -std::vector<PasswordForm> SavedPasswordsPresenter::GetUniquePasswordForms() +std::vector<CredentialUIEntry> SavedPasswordsPresenter::GetSavedCredentials() const { - std::vector<PasswordForm> forms; + std::vector<CredentialUIEntry> credentials; auto it = sort_key_to_password_forms_.begin(); std::string current_key; @@ -315,24 +289,14 @@ while (it != sort_key_to_password_forms_.end()) { if (current_key != it->first) { current_key = it->first; - forms.push_back(it->second); + credentials.emplace_back(it->second); } else { - forms.back().in_store = forms.back().in_store | it->second.in_store; + // Aggregates store information which might be different across copies. + credentials.back().stored_in.insert(it->second.in_store); } ++it; } - return forms; -} - -std::vector<CredentialUIEntry> SavedPasswordsPresenter::GetSavedCredentials() - const { - std::vector<PasswordForm> forms = GetUniquePasswordForms(); - std::vector<CredentialUIEntry> credentials; - credentials.reserve(forms.size()); - base::ranges::transform( - forms, std::back_inserter(credentials), - [](const PasswordForm& form) { return CredentialUIEntry(form); }); return credentials; }
diff --git a/components/password_manager/core/browser/ui/saved_passwords_presenter.h b/components/password_manager/core/browser/ui/saved_passwords_presenter.h index ecee0f95..79ff12c 100644 --- a/components/password_manager/core/browser/ui/saved_passwords_presenter.h +++ b/components/password_manager/core/browser/ui/saved_passwords_presenter.h
@@ -83,8 +83,6 @@ void Init(); // Removes the credential and all its duplicates from the store. - // TODO(crbug.com/1330906): Remove in favor of EditSavedCredentials. - void RemovePassword(const PasswordForm& form); bool RemoveCredential(const CredentialUIEntry& credential); // Cancels the last removal operation. @@ -98,23 +96,6 @@ password_manager::PasswordForm::Type type = password_manager::PasswordForm::Type::kManuallyAdded); - // Tries to edit |password|. After checking whether |form| is present in - // |passwords_|, this will ask the password store to change the underlying - // password_value to |new_password| in case it was found. This will also - // notify clients that an edit event happened in case |form| was present - // in |passwords_|. - // TODO(crbug.com/1330906): Remove in favor of EditSavedCredentials. - bool EditPassword(const PasswordForm& form, std::u16string new_password); - - // Modifies the provided password form and its duplicates - // with `new_username` and `new_password`. - // - // Note: this will also change duplicates of 'form' in all stores. - // TODO(crbug.com/1330906): Remove in favor of EditSavedCredentials. - bool EditSavedPasswords(const PasswordForm& form, - const std::u16string& new_username, - const std::u16string& new_password); - // Modifies all the saved credentials matching |original_credential| to // |updated_credential|. Only username, password, notes and password issues // are modifiable. @@ -130,8 +111,6 @@ // Uniqueness is determined using site name, username, password. For Android // credentials package name is also taken into account and for Federated // credentials federation origin. - // TODO(crbug.com/1330906): Replace all API to work with CredentialUIEntry. - std::vector<PasswordForm> GetUniquePasswordForms() const; std::vector<CredentialUIEntry> GetSavedCredentials() const; // Returns PasswordForms corresponding to |credential|.
diff --git a/components/password_manager/core/browser/ui/saved_passwords_presenter_unittest.cc b/components/password_manager/core/browser/ui/saved_passwords_presenter_unittest.cc index 6e1b2c28..d818328 100644 --- a/components/password_manager/core/browser/ui/saved_passwords_presenter_unittest.cc +++ b/components/password_manager/core/browser/ui/saved_passwords_presenter_unittest.cc
@@ -190,7 +190,8 @@ // Blocklist some origin. store().AddLogin(blocked_form); RunUntilIdle(); - ASSERT_THAT(presenter().GetUniquePasswordForms(), ElementsAre(blocked_form)); + ASSERT_THAT(presenter().GetSavedCredentials(), + ElementsAre(CredentialUIEntry(blocked_form))); // Add a new entry with the same origin. EXPECT_TRUE(presenter().AddCredential(CredentialUIEntry(form_to_add))); @@ -201,7 +202,8 @@ store().stored_passwords(), ElementsAre(Pair(form_to_add.signon_realm, ElementsAre(form_to_add)))); // The origin should be no longer blocklisted. - EXPECT_THAT(presenter().GetUniquePasswordForms(), ElementsAre(form_to_add)); + EXPECT_THAT(presenter().GetSavedCredentials(), + ElementsAre(CredentialUIEntry(form_to_add))); } // Tests whether editing a password works and results in the right @@ -228,17 +230,21 @@ form.in_store = PasswordForm::Store::kProfileStore; const std::u16string new_password = u"new_password"; - // The expected updated form should have a new password and no password - // issues. + PasswordForm updated = form; updated.password_value = new_password; + CredentialUIEntry updated_credential(updated); + // The expected updated form should have a new password and no password + // issues. updated.date_password_modified = base::Time::Now(); updated.password_issues.clear(); // Verify that editing a password triggers the right notifications. EXPECT_CALL(observer, OnEdited(updated)); EXPECT_CALL(observer, OnSavedPasswordsChanged(ElementsAre(updated))); - EXPECT_TRUE(presenter().EditPassword(form, new_password)); + EXPECT_EQ(SavedPasswordsPresenter::EditResult::kSuccess, + presenter().EditSavedCredentials(CredentialUIEntry(form), + updated_credential)); RunUntilIdle(); EXPECT_THAT(store().stored_passwords(), ElementsAre(Pair(updated.signon_realm, ElementsAre(updated)))); @@ -248,7 +254,9 @@ form.username_value = u"another_username"; EXPECT_CALL(observer, OnEdited).Times(0); EXPECT_CALL(observer, OnSavedPasswordsChanged).Times(0); - EXPECT_FALSE(presenter().EditPassword(form, new_password)); + EXPECT_EQ(SavedPasswordsPresenter::EditResult::kNotFound, + presenter().EditSavedCredentials(CredentialUIEntry(form), + updated_credential)); RunUntilIdle(); presenter().RemoveObserver(&observer); @@ -696,9 +704,11 @@ const std::u16string new_password = u"new_password"; PasswordForm updated_form = form; + updated_form.password_value = new_password; + CredentialUIEntry updated_credential(updated_form); + // The result of the update should have a new password and no password_issues. // The same is valid for the duplicate form. - updated_form.password_value = new_password; updated_form.date_password_modified = base::Time::Now(); updated_form.password_issues.clear(); @@ -716,8 +726,9 @@ EXPECT_CALL(observer, OnSavedPasswordsChanged( ElementsAre(updated_form, updated_duplicate_form))) .Times(2); - EXPECT_TRUE( - presenter().EditSavedPasswords(form, form.username_value, new_password)); + EXPECT_EQ(SavedPasswordsPresenter::EditResult::kSuccess, + presenter().EditSavedCredentials(CredentialUIEntry(form), + updated_credential)); RunUntilIdle(); EXPECT_THAT(store().stored_passwords(), ElementsAre(Pair(form.signon_realm, ElementsAre(updated_form)), @@ -727,7 +738,7 @@ } TEST_F(SavedPasswordsPresenterTest, - GetUniquePasswordFormsShouldReturnBlockedAndFederatedForms) { + GetSavedCredentialsReturnsBlockedAndFederatedForms) { PasswordForm form = CreateTestPasswordForm(PasswordForm::Store::kProfileStore); @@ -754,8 +765,6 @@ Pair(form.signon_realm, UnorderedElementsAre(form, blocked_form)), Pair(federated_form.signon_realm, ElementsAre(federated_form)))); - EXPECT_THAT(presenter().GetUniquePasswordForms(), - UnorderedElementsAre(form, blocked_form, federated_form)); EXPECT_THAT(presenter().GetSavedCredentials(), UnorderedElementsAre(CredentialUIEntry(form), CredentialUIEntry(blocked_form), @@ -1009,7 +1018,8 @@ // Blocklist some origin in the account store. account_store().AddLogin(blocked_form); RunUntilIdle(); - ASSERT_THAT(presenter().GetUniquePasswordForms(), ElementsAre(blocked_form)); + ASSERT_THAT(presenter().GetSavedCredentials(), + ElementsAre(CredentialUIEntry(blocked_form))); // Add a new entry with the same origin to the profile store. EXPECT_TRUE(presenter().AddCredential(CredentialUIEntry(form_to_add))); @@ -1021,7 +1031,8 @@ ElementsAre(Pair(form_to_add.signon_realm, ElementsAre(form_to_add)))); // The origin should be no longer blocklisted irrespective of which store the // form was added to. - EXPECT_THAT(presenter().GetUniquePasswordForms(), ElementsAre(form_to_add)); + EXPECT_THAT(presenter().GetSavedCredentials(), + ElementsAre(CredentialUIEntry(form_to_add))); } // This tests changing the username of a credentials stored in the profile store @@ -1090,7 +1101,7 @@ ElementsAre(Pair(account_store_form.signon_realm, ElementsAre(account_store_form)))); - presenter().RemovePassword(profile_store_form); + presenter().RemoveCredential(CredentialUIEntry(profile_store_form)); RunUntilIdle(); EXPECT_TRUE(profile_store().IsEmpty()); @@ -1124,7 +1135,7 @@ Pair(duplicate_account_store_form.signon_realm, ElementsAre(duplicate_account_store_form)))); - presenter().RemovePassword(account_store_form); + presenter().RemoveCredential(CredentialUIEntry(account_store_form)); RunUntilIdle(); EXPECT_THAT(profile_store().stored_passwords(), @@ -1162,7 +1173,7 @@ form_to_delete.in_store = PasswordForm::Store::kProfileStore | PasswordForm::Store::kAccountStore; - presenter().RemovePassword(form_to_delete); + presenter().RemoveCredential(CredentialUIEntry(form_to_delete)); RunUntilIdle(); // All credentials which are considered duplicates of a 'form_to_delete' @@ -1171,7 +1182,7 @@ EXPECT_TRUE(account_store().IsEmpty()); } -TEST_F(SavedPasswordsPresenterWithTwoStoresTest, GetUniquePasswords) { +TEST_F(SavedPasswordsPresenterWithTwoStoresTest, GetSavedCredentials) { PasswordForm profile_store_form = CreateTestPasswordForm(PasswordForm::Store::kProfileStore); @@ -1193,13 +1204,13 @@ expected_form.in_store = PasswordForm::Store::kProfileStore | PasswordForm::Store::kAccountStore; - EXPECT_THAT(presenter().GetUniquePasswordForms(), ElementsAre(expected_form)); EXPECT_THAT(presenter().GetSavedCredentials(), ElementsAre(CredentialUIEntry(expected_form))); } // Prefixes like [m, mobile, www] are considered as "same-site". -TEST_F(SavedPasswordsPresenterWithTwoStoresTest, GetUniquePasswords2) { +TEST_F(SavedPasswordsPresenterWithTwoStoresTest, + GetSavedCredentialsGroupsSameSites) { PasswordForm profile_store_form = CreateTestPasswordForm(PasswordForm::Store::kProfileStore); profile_store_form.signon_realm = "https://example.com"; @@ -1231,7 +1242,8 @@ expected_form.in_store = PasswordForm::Store::kProfileStore | PasswordForm::Store::kAccountStore; - EXPECT_THAT(presenter().GetUniquePasswordForms(), ElementsAre(expected_form)); + EXPECT_THAT(presenter().GetSavedCredentials(), + ElementsAre(CredentialUIEntry(expected_form))); } TEST_F(SavedPasswordsPresenterWithTwoStoresTest, EditPasswordBothStores) { @@ -1263,8 +1275,12 @@ std::u16string new_username = u"new_test@gmail.com"; std::u16string new_password = u"new_password"; - EXPECT_TRUE(presenter().EditSavedPasswords(profile_store_form, new_username, - new_password)); + CredentialUIEntry updated_credential(profile_store_form); + updated_credential.username = new_username; + updated_credential.password = new_password; + EXPECT_EQ(SavedPasswordsPresenter::EditResult::kSuccess, + presenter().EditSavedCredentials( + CredentialUIEntry(profile_store_form), updated_credential)); RunUntilIdle();
diff --git a/components/policy/test_support/BUILD.gn b/components/policy/test_support/BUILD.gn index f95f9bb..ed22aed 100644 --- a/components/policy/test_support/BUILD.gn +++ b/components/policy/test_support/BUILD.gn
@@ -51,6 +51,12 @@ "test_server_helpers.cc", "test_server_helpers.h", ] + if (is_chromeos) { + sources += [ + "fake_dmserver.cc", + "fake_dmserver.h", + ] + } public_deps = [ "//net:test_support" ] deps = [ @@ -66,6 +72,23 @@ ] } +if (is_chromeos) { + executable("fake_dmserver") { + testonly = true + output_name = "fake_dmserver" + sources = [ "fake_dmserver_main.cc" ] + public_deps = [ "//net:test_support" ] + deps = [ + ":test_support", + "//base", + "//google_apis:google_apis", + "//net", + "//third_party/private_membership:private_membership_proto", + "//third_party/re2:re2", + ] + } +} + source_set("unittests") { testonly = true @@ -95,6 +118,10 @@ "signature_provider_unittest.cc", ] + if (is_chromeos) { + sources += [ "fake_dmserver_unittest.cc" ] + } + deps = [ ":test_support", "//components/policy/core/common:common_constants",
diff --git a/components/policy/test_support/embedded_policy_test_server.h b/components/policy/test_support/embedded_policy_test_server.h index 46c721a7..84b86c0 100644 --- a/components/policy/test_support/embedded_policy_test_server.h +++ b/components/policy/test_support/embedded_policy_test_server.h
@@ -68,7 +68,7 @@ virtual ~EmbeddedPolicyTestServer(); // Initializes and waits until the server is ready to accept requests. - bool Start(); + virtual bool Start(); ClientStorage* client_storage() const { return client_storage_.get(); } @@ -100,11 +100,12 @@ const std::string& raw_policy); #endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) - private: + protected: // Default request handler. - std::unique_ptr<net::test_server::HttpResponse> HandleRequest( + virtual std::unique_ptr<net::test_server::HttpResponse> HandleRequest( const net::test_server::HttpRequest& request); + private: // Request handler for external policy data. std::unique_ptr<net::test_server::HttpResponse> HandleExternalPolicyDataRequest(const GURL& request);
diff --git a/components/policy/test_support/fake_dmserver.cc b/components/policy/test_support/fake_dmserver.cc new file mode 100644 index 0000000..6bde386 --- /dev/null +++ b/components/policy/test_support/fake_dmserver.cc
@@ -0,0 +1,374 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/policy/test_support/fake_dmserver.h" + +#include <vector> + +#include "base/base64.h" +#include "base/files/file_util.h" +#include "base/json/json_file_value_serializer.h" +#include "base/logging.h" +#include "base/strings/stringprintf.h" +#include "components/policy/test_support/client_storage.h" +#include "components/policy/test_support/embedded_policy_test_server.h" +#include "components/policy/test_support/policy_storage.h" +#include "components/policy/test_support/request_handler_for_policy.h" +#include "components/policy/test_support/test_server_helpers.h" + +namespace fakedms { + +namespace { + +constexpr char kPolicyTypeKey[] = "policy_type"; +constexpr char kEntityIdKey[] = "entity_id"; +constexpr char kPolicyValueKey[] = "value"; +constexpr char kDeviceIdKey[] = "device_id"; +constexpr char kDeviceTokenKey[] = "device_token"; +constexpr char kMachineNameKey[] = "machine_name"; +constexpr char kUsernameKey[] = "username"; +constexpr char kStateKeysKey[] = "state_keys"; +constexpr char kAllowedPolicyTypesKey[] = "allowed_policy_types"; +constexpr char kPoliciesKey[] = "policies"; +constexpr char kManagedUsersKey[] = "managed_users"; +constexpr char kPolicyUserKey[] = "policy_user"; + +constexpr char kDefaultPolicyBlobFilename[] = "policy.json"; +constexpr char kDefaultClientStateFilename[] = "state.json"; + +constexpr char kPolicyBlobPathSwitch[] = "policy-blob-path"; +constexpr char kClientStatePathSwitch[] = "client-state-path"; +constexpr char kLogPathSwitch[] = "log-path"; +constexpr char kStartupPipeSwitch[] = "startup-pipe"; + +} // namespace + +void InitLogging(const std::string& log_path) { + logging::LoggingSettings settings; + settings.log_file_path = log_path.c_str(); + settings.logging_dest = logging::LOG_TO_ALL; + logging::InitLogging(settings); +} + +void ParseFlags(const base::CommandLine& command_line, + std::string& policy_blob_path, + std::string& client_state_path, + absl::optional<std::string>& log_path, + base::ScopedFD& startup_pipe) { + policy_blob_path = kDefaultPolicyBlobFilename; + client_state_path = kDefaultClientStateFilename; + + if (command_line.HasSwitch(kPolicyBlobPathSwitch)) { + policy_blob_path = command_line.GetSwitchValueASCII(kPolicyBlobPathSwitch); + } + + if (command_line.HasSwitch(kLogPathSwitch)) { + log_path = command_line.GetSwitchValueASCII(kLogPathSwitch); + } + + if (command_line.HasSwitch(kClientStatePathSwitch)) { + client_state_path = + command_line.GetSwitchValueASCII(kClientStatePathSwitch); + } + + if (command_line.HasSwitch(kStartupPipeSwitch)) { + std::string pipe_str = command_line.GetSwitchValueASCII(kStartupPipeSwitch); + int pipe_val; + CHECK(base::StringToInt(pipe_str, &pipe_val)) + << "Expected an int value for --startup-pipe switch, but got: " + << pipe_str; + startup_pipe = base::ScopedFD(pipe_val); + } +} + +FakeDMServer::FakeDMServer(const std::string& policy_blob_path, + const std::string& client_state_path, + base::OnceClosure shutdown_cb) + : policy_blob_path_(policy_blob_path), + client_state_path_(client_state_path), + shutdown_cb_(std::move(shutdown_cb)) {} + +FakeDMServer::~FakeDMServer() = default; + +bool FakeDMServer::Start() { + LOG(INFO) << "Starting the FakeDMServer with args policy_blob_path=" + << policy_blob_path_ << " client_state_path=" << client_state_path_; + + if (!policy::EmbeddedPolicyTestServer::Start()) { + LOG(ERROR) << "Failed to start the EmbeddedPolicyTestServer"; + return false; + } + LOG(INFO) << "Server started running on URL: " + << EmbeddedPolicyTestServer::GetServiceURL(); + return true; +} + +bool FakeDMServer::WriteURLToPipe(const base::ScopedFD& startup_pipe) { + GURL server_url = EmbeddedPolicyTestServer::GetServiceURL(); + std::string server_data = + base::StringPrintf("{\"host\": \"%s\", \"port\": %s}", + server_url.host().c_str(), server_url.port().c_str()); + + base::PlatformFile fd(startup_pipe.get()); + base::File pipe_writer(fd); + if (!pipe_writer.WriteAtCurrentPosAndCheck( + base::as_bytes(base::make_span(server_data)))) { + LOG(ERROR) << "Failed to write the server url data to the pipe, data: " + << server_data; + return false; + } + pipe_writer.Close(); + return true; +} + +std::unique_ptr<net::test_server::HttpResponse> FakeDMServer::HandleRequest( + const net::test_server::HttpRequest& request) { + GURL url = request.GetURL(); + + if (url.path() == "/test/exit") { + LOG(INFO) << "Stopping the FakeDMServer"; + CHECK(shutdown_cb_); + std::move(shutdown_cb_).Run(); + return policy::CreateHttpResponse(net::HTTP_OK, "Policy Server exited."); + } + + if (url.path() == "/test/ping") + return policy::CreateHttpResponse(net::HTTP_OK, "Pong."); + + if (!ReadPolicyBlobFile()) { + return policy::CreateHttpResponse(net::HTTP_INTERNAL_SERVER_ERROR, + "Failed to read policy blob file."); + } + + if (!ReadClientStateFile()) { + return policy::CreateHttpResponse(net::HTTP_INTERNAL_SERVER_ERROR, + "Failed to read client state file."); + } + auto resp = policy::EmbeddedPolicyTestServer::HandleRequest(request); + if (!WriteClientStateFile()) { + return policy::CreateHttpResponse(net::HTTP_INTERNAL_SERVER_ERROR, + "Failed to write client state file."); + } + return resp; +} + +bool FakeDMServer::SetPolicyPayload(const std::string* policy_type, + const std::string* entity_id, + const std::string* serialized_proto) { + if (!policy_type || !serialized_proto) { + LOG(ERROR) << "Coudln't find the policy type or value fields"; + return false; + } + std::string decoded_proto; + if (!base::Base64Decode(*serialized_proto, &decoded_proto)) { + LOG(ERROR) << "Unable to base64 decode validation value from " + << *serialized_proto; + return false; + } + if (entity_id) { + policy_storage()->SetPolicyPayload(*policy_type, *entity_id, decoded_proto); + } else { + policy_storage()->SetPolicyPayload(*policy_type, decoded_proto); + } + return true; +} + +bool FakeDMServer::ReadPolicyBlobFile() { + base::FilePath policy_blob_file(policy_blob_path_); + if (!base::PathExists(policy_blob_file)) { + LOG(INFO) << "Policy blob file doesn't exist yet."; + return true; + } + EmbeddedPolicyTestServer::ResetPolicyStorage(); + JSONFileValueDeserializer deserializer(policy_blob_file); + int error_code = 0; + std::string error_msg; + std::unique_ptr<base::Value> value = + deserializer.Deserialize(&error_code, &error_msg); + if (!value) { + LOG(ERROR) << "Failed to read the policy blob file " + << policy_blob_file.value() << ": " << error_msg; + return false; + } + LOG(INFO) << "Deserialized value of the policy blob: " << *value; + if (!value->is_dict()) { + LOG(ERROR) << "Policy blob isn't a dict"; + return false; + } + base::Value::Dict& dict = value->GetDict(); + + std::string* policy_user = dict.FindString(kPolicyUserKey); + if (policy_user) { + LOG(INFO) << "Adding " << *policy_user << " as a policy user"; + policy_storage()->set_policy_user(*policy_user); + } else { + LOG(INFO) << "The policy_user key isn't found and the default policy " + "user " + << policy::kDefaultUsername << " will be used"; + } + + base::Value::List* managed_users = dict.FindList(kManagedUsersKey); + if (managed_users) { + for (const base::Value& managed_user : *managed_users) { + const std::string* managed_val = managed_user.GetIfString(); + if (managed_val) { + LOG(INFO) << "Adding " << *managed_val << " as a managed user"; + policy_storage()->add_managed_user(*managed_val); + } + } + } + + base::Value::List* policies = dict.FindList(kPoliciesKey); + if (policies) { + for (const base::Value& policy : *policies) { + if (!policy.is_dict()) { + LOG(ERROR) << "The current policy isn't dict"; + return false; + } + if (!SetPolicyPayload(policy.GetDict().FindString(kPolicyTypeKey), + policy.GetDict().FindString(kEntityIdKey), + policy.GetDict().FindString(kPolicyValueKey))) { + LOG(ERROR) << "Failed to set the policy"; + return false; + } + } + } + + return true; +} + +base::Value::Dict FakeDMServer::GetValueFromClient( + const policy::ClientStorage::ClientInfo& c) { + base::Value::Dict dict; + dict.Set(kDeviceIdKey, c.device_id); + dict.Set(kDeviceTokenKey, c.device_token); + dict.Set(kMachineNameKey, c.machine_name); + dict.Set(kUsernameKey, c.username.value_or("")); + base::Value::List state_keys, allowed_policy_types; + for (auto& key : c.state_keys) + state_keys.Append(key); + dict.Set(kStateKeysKey, std::move(state_keys)); + for (auto& policy_type : c.allowed_policy_types) + allowed_policy_types.Append(policy_type); + dict.Set(kAllowedPolicyTypesKey, std::move(allowed_policy_types)); + return dict; +} + +bool FakeDMServer::WriteClientStateFile() { + base::FilePath client_state_file(client_state_path_); + std::vector<policy::ClientStorage::ClientInfo> clients = + client_storage()->GetAllClients(); + base::Value::Dict dict_clients; + for (auto& c : clients) + dict_clients.Set(c.device_id, GetValueFromClient(c)); + + JSONFileValueSerializer serializer(client_state_file); + return serializer.Serialize(base::ValueView(dict_clients)); +} + +bool FakeDMServer::FindKey(const base::Value::Dict& dict, + const std::string& key, + base::Value::Type type) { + switch (type) { + case base::Value::Type::STRING: { + const std::string* str_val = dict.FindString(key); + if (!str_val) { + LOG(ERROR) << "Key `" << key << "` is missing or not a string."; + return false; + } + return true; + } + case base::Value::Type::LIST: { + const base::Value::List* list_val = dict.FindList(key); + if (!list_val) { + LOG(ERROR) << "Key `" << key << "` is missing or not a list."; + return false; + } + return true; + } + default: { + NOTREACHED() << "Unsupported type for client file key"; + return false; + } + } +} + +absl::optional<policy::ClientStorage::ClientInfo> +FakeDMServer::GetClientFromValue(const base::Value& v) { + policy::ClientStorage::ClientInfo client_info; + if (!v.is_dict()) { + LOG(ERROR) << "Client value isn't a dict"; + return absl::nullopt; + } + + const base::Value::Dict& dict = v.GetDict(); + if (!FindKey(dict, kDeviceIdKey, base::Value::Type::STRING) || + !FindKey(dict, kDeviceTokenKey, base::Value::Type::STRING) || + !FindKey(dict, kMachineNameKey, base::Value::Type::STRING) || + !FindKey(dict, kUsernameKey, base::Value::Type::STRING) || + !FindKey(dict, kStateKeysKey, base::Value::Type::LIST) || + !FindKey(dict, kAllowedPolicyTypesKey, base::Value::Type::LIST)) { + return absl::nullopt; + } + + client_info.device_id = *dict.FindString(kDeviceIdKey); + client_info.device_token = *dict.FindString(kDeviceTokenKey); + client_info.machine_name = *dict.FindString(kMachineNameKey); + client_info.username = *dict.FindString(kUsernameKey); + const base::Value::List* state_keys = dict.FindList(kStateKeysKey); + for (const auto& it : *state_keys) { + const std::string* key = it.GetIfString(); + if (!key) { + LOG(ERROR) << "State key list entry is not a string: " << it; + return absl::nullopt; + } + client_info.state_keys.emplace_back(*key); + } + const base::Value::List* policy_types = dict.FindList(kAllowedPolicyTypesKey); + for (const auto& it : *policy_types) { + const std::string* key = it.GetIfString(); + if (!key) { + LOG(ERROR) << "Policy type list entry is not a string: " << it; + return absl::nullopt; + } + client_info.allowed_policy_types.insert(*key); + } + return client_info; +} + +bool FakeDMServer::ReadClientStateFile() { + base::FilePath client_state_file(client_state_path_); + if (!base::PathExists(client_state_file)) { + LOG(INFO) << "Client state file doesn't exist yet."; + return true; + } + EmbeddedPolicyTestServer::ResetClientStorage(); + JSONFileValueDeserializer deserializer(client_state_file); + int error_code = 0; + std::string error_msg; + std::unique_ptr<base::Value> value = + deserializer.Deserialize(&error_code, &error_msg); + if (!value) { + LOG(ERROR) << "Failed to read client state file " + << client_state_file.value() << ": " << error_msg; + return false; + } + if (!value->is_dict()) { + LOG(ERROR) << "The client state file isn't dict."; + return false; + } + base::Value::Dict& dict = value->GetDict(); + for (auto it : dict) { + absl::optional<policy::ClientStorage::ClientInfo> c = + GetClientFromValue(it.second); + if (!c.has_value()) { + LOG(ERROR) << "The client isn't configured correctly."; + return false; + } + client_storage()->RegisterClient(c.value()); + } + return true; +} + +} // namespace fakedms
diff --git a/components/policy/test_support/fake_dmserver.h b/components/policy/test_support/fake_dmserver.h new file mode 100644 index 0000000..b19fe72 --- /dev/null +++ b/components/policy/test_support/fake_dmserver.h
@@ -0,0 +1,125 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/* +A bare-bones test server for testing cloud policy support. + +This implements a simple cloud policy test server that can be used to test +Chrome's device management service client. The policy information is read from +the file named policy.json in the server's data directory. It contains +policies for the device and user scope, and a list of managed users. The format +of the file is JSON. +The root dictionary contains a list under the key +"managed_users". It contains auth tokens for which the server will claim that +the user is managed. The token string "*" indicates that all users are claimed +to be managed. +The root dictionary also contains a list under the key "policies". It contains +all the policies to be set, each policy has 3 fields, "policy_type" is the type +or scope of the policy (user, device or publicaccount), "entity_id" is the +account id used for public account policies, "value" is the seralized proto +message of the policies value encoded in base64. +The root dictionary also contains a "policy_user" key which indicates the +current user. + +Example: +{ + "policies" : [ + { + "policy_type" : "google/chromeos/user", + "value" : "base64 encoded proto message", + }, + { + "policy_type" : "google/chromeos/device", + "value" : "base64 encoded proto message", + }, + { + "policy_type" : "google/chromeos/publicaccount", + "entity_id" : "accountid@managedchrome.com", + "value" : "base64 encoded proto message", + } + ], + "managed_users" : [ + "secret123456" + ], + "policy_user" : "tast-user@managedchrome.com", +} +*/ + +#ifndef COMPONENTS_POLICY_TEST_SUPPORT_FAKE_DMSERVER_H_ +#define COMPONENTS_POLICY_TEST_SUPPORT_FAKE_DMSERVER_H_ + +#include <string> + +#include "base/command_line.h" +#include "base/values.h" +#include "components/policy/test_support/client_storage.h" +#include "components/policy/test_support/embedded_policy_test_server.h" + +namespace fakedms { + +void InitLogging(const std::string& log_path); +void ParseFlags(const base::CommandLine& command_line, + std::string& policy_blob_path, + std::string& client_state_path, + absl::optional<std::string>& log_path, + base::ScopedFD& startup_pipe); + +class FakeDMServer : public policy::EmbeddedPolicyTestServer { + public: + FakeDMServer(const std::string& policy_blob_path, + const std::string& client_state_path, + base::OnceClosure shutdown_cb = base::DoNothing()); + ~FakeDMServer() override; + // Starts the FakeDMServer and EmbeddedPolicyTestServer, it will return true + // if it's able to start the server successfully, and false otherwise. + bool Start() override; + + // Writes the host and port of the EmbeddedPolicyTestServer to the given pipe + // in a json format {"host": "localhost", "port": 1234}, it will return true + // if it's able to write the URL to the pipe, and false otherwise. + bool WriteURLToPipe(const base::ScopedFD& startup_pipe); + + // Overrides the EmbeddedPolicyTestServer request handler. + std::unique_ptr<net::test_server::HttpResponse> HandleRequest( + const net::test_server::HttpRequest& request) override; + + private: + // Sets the policy payload in the policy storage, it will return true if it's + // able to set the policy and false otherwise. + bool SetPolicyPayload(const std::string* policy_type, + const std::string* entity_id, + const std::string* serialized_proto); + // Reads and sets the values in the policy blob file, it will return true if + // the policy blob file doesn't exist yet or all the values are read + // correctly, and false otherwise. + bool ReadPolicyBlobFile(); + + // Writes all the clients to the client state file, it will return true if + // it's able to write the client storage to the state file, and false + // otherwise. + bool WriteClientStateFile(); + // Reads the client state file and registers the clients, it will return true + // if the state file doesn't exist yet or all the values are read + // correctly, and false otherwise. + bool ReadClientStateFile(); + + // Returns true if the key of the specific type is in the dictionary. + static bool FindKey(const base::Value::Dict& dict, + const std::string& key, + base::Value::Type type); + + // Converts the client to Dictionary. + static base::Value::Dict GetValueFromClient( + const policy::ClientStorage::ClientInfo& c); + // Converts the value to Client. + static absl::optional<policy::ClientStorage::ClientInfo> GetClientFromValue( + const base::Value& v); + + std::string policy_blob_path_, client_state_path_; + base::OnceClosure shutdown_cb_; +}; + +} // namespace fakedms + +#endif // COMPONENTS_POLICY_TEST_SUPPORT_FAKE_DMSERVER_H_
diff --git a/components/policy/test_support/fake_dmserver_main.cc b/components/policy/test_support/fake_dmserver_main.cc new file mode 100644 index 0000000..e1086906 --- /dev/null +++ b/components/policy/test_support/fake_dmserver_main.cc
@@ -0,0 +1,35 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/command_line.h" +#include "base/run_loop.h" +#include "base/task/single_thread_task_executor.h" +#include "components/policy/test_support/fake_dmserver.h" + +int main(int argc, char** argv) { + base::SingleThreadTaskExecutor io_task_executor(base::MessagePumpType::IO); + base::CommandLine::Init(argc, argv); + + std::string policy_blob_path, client_state_path; + absl::optional<std::string> log_path; + base::ScopedFD startup_pipe; + + base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); + fakedms::ParseFlags(*command_line, policy_blob_path, client_state_path, + log_path, startup_pipe); + if (log_path.has_value()) + fakedms::InitLogging(log_path.value()); + + base::RunLoop run_loop; + fakedms::FakeDMServer policy_test_server(policy_blob_path, client_state_path, + run_loop.QuitClosure()); + if (!policy_test_server.Start()) + return 1; + if (startup_pipe.is_valid()) { + if (!policy_test_server.WriteURLToPipe(startup_pipe)) + return 1; + } + run_loop.Run(); + return 0; +}
diff --git a/components/policy/test_support/fake_dmserver_unittest.cc b/components/policy/test_support/fake_dmserver_unittest.cc new file mode 100644 index 0000000..c0ef43d --- /dev/null +++ b/components/policy/test_support/fake_dmserver_unittest.cc
@@ -0,0 +1,478 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <set> +#include <string> +#include <vector> + +#include "base/base64.h" +#include "base/bind.h" +#include "base/callback.h" +#include "base/callback_forward.h" +#include "base/check.h" +#include "base/files/file.h" +#include "base/files/file_enumerator.h" +#include "base/files/file_util.h" +#include "base/files/scoped_temp_dir.h" +#include "base/json/json_file_value_serializer.h" +#include "base/memory/scoped_refptr.h" +#include "base/run_loop.h" +#include "base/strings/stringprintf.h" +#include "base/test/mock_callback.h" +#include "base/test/task_environment.h" +#include "components/policy/core/common/cloud/cloud_policy_constants.h" +#include "components/policy/proto/device_management_backend.pb.h" +#include "components/policy/test_support/client_storage.h" +#include "components/policy/test_support/embedded_policy_test_server.h" +#include "components/policy/test_support/embedded_policy_test_server_test_base.h" +#include "components/policy/test_support/fake_dmserver.h" +#include "components/policy/test_support/policy_storage.h" +#include "net/base/url_util.h" +#include "net/http/http_request_headers.h" +#include "net/http/http_status_code.h" +#include "net/traffic_annotation/network_traffic_annotation_test_helper.h" +#include "services/network/public/cpp/resource_request.h" +#include "services/network/public/cpp/shared_url_loader_factory.h" +#include "services/network/public/cpp/simple_url_loader.h" +#include "services/network/public/mojom/url_response_head.mojom.h" +#include "services/network/test/test_shared_url_loader_factory.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace fakedms { + +namespace { + +void DownloadedToString(base::OnceClosure callback, + std::unique_ptr<std::string> response_body) { + CHECK(callback); + if (response_body) + LOG(INFO) << "response body: " << *response_body; + std::move(callback).Run(); +} + +} // namespace + +// TODO(b/239676448): Add missing unittest for Writing to Pipe. +class FakeDMServerTest : public testing::Test { + public: + FakeDMServerTest() + : task_environment_(base::test::TaskEnvironment::MainThreadType::IO) {} + + void SetUp() override { + ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); + policy_blob_path_ = temp_dir_.GetPath().Append( + base::FilePath(FILE_PATH_LITERAL("policy.json"))); + ASSERT_FALSE(PathExists(policy_blob_path_)); + client_state_path_ = temp_dir_.GetPath().Append( + base::FilePath(FILE_PATH_LITERAL("state.json"))); + ASSERT_FALSE(PathExists(client_state_path_)); + } + + // TODO(b/240445061): Check response content to verify the returned policy. + int SendRequest(const GURL& server_url, const std::string& request_path) { + std::string request_url = + base::StringPrintf("http://%s:%s%s", server_url.host().c_str(), + server_url.port().c_str(), request_path.c_str()); + std::unique_ptr<network::ResourceRequest> resource_request = + std::make_unique<network::ResourceRequest>(); + resource_request->method = net::HttpRequestHeaders::kPostMethod; + resource_request->url = GURL(request_url); + resource_request->headers.SetHeader( + "Authorization", "GoogleDMToken token=fake_device_token"); + + std::unique_ptr<network::SimpleURLLoader> url_loader = + network::SimpleURLLoader::Create(std::move(resource_request), + TRAFFIC_ANNOTATION_FOR_TESTS); + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory = + base::MakeRefCounted<network::TestSharedURLLoaderFactory>(); + + base::RunLoop run_loop; + url_loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie( + url_loader_factory.get(), + base::BindOnce(&DownloadedToString, run_loop.QuitClosure())); + run_loop.Run(); + return url_loader->ResponseInfo()->headers->response_code(); + } + + protected: + base::FilePath policy_blob_path_, client_state_path_; + + private: + base::ScopedTempDir temp_dir_; + base::test::TaskEnvironment task_environment_; +}; + +TEST_F(FakeDMServerTest, HandleExitRequest_Succeeds) { + base::MockOnceCallback<void()> callback; + FakeDMServer fake_dmserver(policy_blob_path_.MaybeAsASCII(), + client_state_path_.MaybeAsASCII(), callback.Get()); + EXPECT_TRUE(fake_dmserver.Start()); + + EXPECT_CALL(callback, Run()).Times(1); + EXPECT_EQ(SendRequest(fake_dmserver.GetServiceURL(), "/test/exit"), + net::HTTP_OK); +} + +TEST_F(FakeDMServerTest, HandlePingRequest_Succeeds) { + FakeDMServer fake_dmserver(policy_blob_path_.MaybeAsASCII(), + client_state_path_.MaybeAsASCII()); + EXPECT_TRUE(fake_dmserver.Start()); + + EXPECT_EQ(SendRequest(fake_dmserver.GetServiceURL(), "/test/ping"), + net::HTTP_OK); +} + +TEST_F(FakeDMServerTest, HandleRegisterRequest_Succeeds) { + FakeDMServer fake_dmserver(policy_blob_path_.MaybeAsASCII(), + client_state_path_.MaybeAsASCII()); + EXPECT_TRUE(fake_dmserver.Start()); + + ASSERT_TRUE(base::WriteFile(policy_blob_path_, R"( + { + "managed_users" : [ "*" ], + "policy_user" : "tast-user@managedchrome.com" + } + )")); + + EXPECT_EQ(SendRequest(fake_dmserver.GetServiceURL(), + "/?apptype=Chrome&deviceid=fake_device_id&devicetype=2&" + "oauth_token=fake_policy_token&request=register"), + net::HTTP_OK); + + // Check if the data of the registered client is correct and written to the + // client state file. + std::vector<policy::ClientStorage::ClientInfo> clients = + fake_dmserver.client_storage()->GetAllClients(); + EXPECT_EQ(clients.size(), 1u); + EXPECT_EQ(clients[0].device_id, "fake_device_id"); + EXPECT_FALSE(clients[0].device_token.empty()); + EXPECT_FALSE(clients[0].machine_name.empty()); + EXPECT_EQ(clients[0].username.value(), "tast-user@managedchrome.com"); + EXPECT_EQ(clients[0].allowed_policy_types.size(), 1u); + EXPECT_EQ(*clients[0].allowed_policy_types.begin(), + policy::dm_protocol::kChromeUserPolicyType); + EXPECT_TRUE(clients[0].state_keys.empty()); + + JSONFileValueDeserializer deserializer(client_state_path_); + int error_code = 0; + std::string error_msg; + std::unique_ptr<base::Value> value = + deserializer.Deserialize(&error_code, &error_msg); + EXPECT_TRUE(value); + EXPECT_TRUE(value->is_dict()); + base::Value::Dict& state_dict = value->GetDict(); + EXPECT_EQ(state_dict.size(), 1u); + EXPECT_TRUE(state_dict.contains("fake_device_id")); + base::Value::Dict* client_dict = state_dict.FindDict("fake_device_id"); + EXPECT_NE(client_dict, nullptr); + EXPECT_TRUE(client_dict->contains("device_id")); + EXPECT_EQ(*client_dict->FindString("device_id"), "fake_device_id"); + EXPECT_TRUE(client_dict->contains("device_token")); + EXPECT_FALSE(client_dict->FindString("device_token")->empty()); + EXPECT_TRUE(client_dict->contains("machine_name")); + EXPECT_FALSE(client_dict->FindString("machine_name")->empty()); + EXPECT_TRUE(client_dict->contains("username")); + EXPECT_EQ(*client_dict->FindString("username"), + "tast-user@managedchrome.com"); + + base::Value::List* allowed_policy_types = + client_dict->FindList("allowed_policy_types"); + EXPECT_NE(allowed_policy_types, nullptr); + EXPECT_EQ(allowed_policy_types->size(), 1u); + EXPECT_EQ((*allowed_policy_types)[0].GetString(), + policy::dm_protocol::kChromeUserPolicyType); + + base::Value::List* state_keys = client_dict->FindList("state_keys"); + EXPECT_NE(state_keys, nullptr); + EXPECT_TRUE(state_keys->empty()); +} + +TEST_F(FakeDMServerTest, ReadClientStateFile_WithWrongJSONData_Fails) { + FakeDMServer fake_dmserver(policy_blob_path_.MaybeAsASCII(), + client_state_path_.MaybeAsASCII()); + EXPECT_TRUE(fake_dmserver.Start()); + + ASSERT_TRUE(base::WriteFile(client_state_path_, "wrong data")); + EXPECT_EQ(SendRequest(fake_dmserver.GetServiceURL(), + "/?apptype=Chrome&deviceid=fake_device_id&devicetype=2&" + "oauth_token=fake_policy_token&request=register"), + net::HTTP_INTERNAL_SERVER_ERROR); +} + +TEST_F(FakeDMServerTest, ReadClientStateFile_WithNonDictFile_Fails) { + FakeDMServer fake_dmserver(policy_blob_path_.MaybeAsASCII(), + client_state_path_.MaybeAsASCII()); + EXPECT_TRUE(fake_dmserver.Start()); + + ASSERT_TRUE(base::WriteFile(client_state_path_, R"([ "1", "2" ])")); + EXPECT_EQ(SendRequest(fake_dmserver.GetServiceURL(), + "/?apptype=Chrome&deviceid=fake_device_id&devicetype=2&" + "oauth_token=fake_policy_token&request=register"), + net::HTTP_INTERNAL_SERVER_ERROR); +} + +TEST_F(FakeDMServerTest, GetClientFromValue_WithNonDictValue_Fails) { + FakeDMServer fake_dmserver(policy_blob_path_.MaybeAsASCII(), + client_state_path_.MaybeAsASCII()); + EXPECT_TRUE(fake_dmserver.Start()); + + ASSERT_TRUE(base::WriteFile(client_state_path_, + R"({ "fake_device_id" : "not dict" })")); + EXPECT_EQ(SendRequest(fake_dmserver.GetServiceURL(), + "/?apptype=Chrome&deviceid=fake_device_id&devicetype=2&" + "oauth_token=fake_policy_token&request=register"), + net::HTTP_INTERNAL_SERVER_ERROR); +} + +TEST_F(FakeDMServerTest, GetClientFromValue_WithOnlyDeviceID_Fails) { + FakeDMServer fake_dmserver(policy_blob_path_.MaybeAsASCII(), + client_state_path_.MaybeAsASCII()); + EXPECT_TRUE(fake_dmserver.Start()); + + ASSERT_TRUE(base::WriteFile( + client_state_path_, + R"({ "fake_device_id" : { "device_id" : "fake_device_id" } })")); + EXPECT_EQ(SendRequest(fake_dmserver.GetServiceURL(), + "/?apptype=Chrome&deviceid=fake_device_id&devicetype=2&" + "oauth_token=fake_policy_token&request=register"), + net::HTTP_INTERNAL_SERVER_ERROR); +} + +TEST_F(FakeDMServerTest, GetClientFromValue_WithNonStringDeviceID_Fails) { + FakeDMServer fake_dmserver(policy_blob_path_.MaybeAsASCII(), + client_state_path_.MaybeAsASCII()); + EXPECT_TRUE(fake_dmserver.Start()); + + ASSERT_TRUE(base::WriteFile(client_state_path_, + R"({ "fake_device_id" : { "device_id" : 7 } })")); + EXPECT_EQ(SendRequest(fake_dmserver.GetServiceURL(), + "/?apptype=Chrome&deviceid=fake_device_id&devicetype=2&" + "oauth_token=fake_policy_token&request=register"), + net::HTTP_INTERNAL_SERVER_ERROR); +} + +TEST_F(FakeDMServerTest, GetClientFromValue_WithoutStateKeyList_Fails) { + FakeDMServer fake_dmserver(policy_blob_path_.MaybeAsASCII(), + client_state_path_.MaybeAsASCII()); + EXPECT_TRUE(fake_dmserver.Start()); + + ASSERT_TRUE(base::WriteFile(client_state_path_, R"( + { + "fake_device_id" : { + "device_id" : "fake_device_id", + "device_token" : "fake_device_token", + "machine_name" : "fake_machine_name", + "username" : "tast-user@managedchrome.com", + "allowed_policy_types" : [ "google/chromeos/user" ] + } + } + )")); + EXPECT_EQ(SendRequest(fake_dmserver.GetServiceURL(), + "/?apptype=Chrome&deviceid=fake_device_id&devicetype=2&" + "oauth_token=fake_policy_token&request=register"), + net::HTTP_INTERNAL_SERVER_ERROR); +} + +TEST_F(FakeDMServerTest, GetClientFromValue_WithNonStringStateKeys_Fails) { + FakeDMServer fake_dmserver(policy_blob_path_.MaybeAsASCII(), + client_state_path_.MaybeAsASCII()); + EXPECT_TRUE(fake_dmserver.Start()); + + ASSERT_TRUE(base::WriteFile(client_state_path_, R"( + { + "fake_device_id" : { + "device_id" : "fake_device_id", + "device_token" : "fake_device_token", + "machine_name" : "fake_machine_name", + "username" : "tast-user@managedchrome.com", + "state_keys" : [ 7 ], + "allowed_policy_types" : [ "google/chromeos/user" ] + } + } + )")); + EXPECT_EQ(SendRequest(fake_dmserver.GetServiceURL(), + "/?apptype=Chrome&deviceid=fake_device_id&devicetype=2&" + "oauth_token=fake_policy_token&request=register"), + net::HTTP_INTERNAL_SERVER_ERROR); +} + +TEST_F(FakeDMServerTest, GetClientFromValue_WithNonStringPolicyTypes_Fails) { + FakeDMServer fake_dmserver(policy_blob_path_.MaybeAsASCII(), + client_state_path_.MaybeAsASCII()); + EXPECT_TRUE(fake_dmserver.Start()); + + ASSERT_TRUE(base::WriteFile(client_state_path_, R"( + { + "fake_device_id" : { + "device_id" : "fake_device_id", + "device_token" : "fake_device_token", + "machine_name" : "fake_machine_name", + "username" : "tast-user@managedchrome.com", + "state_keys" : [ "fake_state_key" ], + "allowed_policy_types" : [ 7 ] + } + } + )")); + EXPECT_EQ(SendRequest(fake_dmserver.GetServiceURL(), + "/?apptype=Chrome&deviceid=fake_device_id&devicetype=2&" + "oauth_token=fake_policy_token&request=register"), + net::HTTP_INTERNAL_SERVER_ERROR); +} + +TEST_F(FakeDMServerTest, HandlePolicyRequest_Succeeds) { + FakeDMServer fake_dmserver(policy_blob_path_.MaybeAsASCII(), + client_state_path_.MaybeAsASCII()); + EXPECT_TRUE(fake_dmserver.Start()); + + ASSERT_TRUE(base::WriteFile( + policy_blob_path_, + R"( + { + "managed_users" : [ "*" ], + "policy_user" : "tast-user@managedchrome.com", + "policies" : [ + { + "policy_type" : "google/chromeos/user", "value" : "uhMCEAE=" + }, { + "policy_type" : "google/chromeos/device", + "value" : "qgFSCikSJWRlZmF1bHRNZ3NTZXRCeVRhc3RAbWFuYWdlZGNocm9tZS5jb)" + R"(20YABIlZGVmYXVsdE1nc1NldEJ5VGFzdEBtYW5hZ2VkY2hyb21lLmNvbQ==" + }, { + "entity_id" : "accountid@managedchrome.com", + "policy_type" : "google/chromeos/publicaccount", + "value" : "ojCsARKpAXsiaGFzaCI6IjdhMDUyYzVlNGYyM2MxNTk2NjgxNDhkZjJhM)" + R"(2MyMDJiZWQ0ZDY1NzQ5Y2FiNWVjZDBmYTdkYjIxMWMxMmEzYjgiLCJ1cmwiOiJodHRwcz)" + R"(ovL3N0b3JhZ2UuZ29vZ2xlYXBpcy5jb20vY2hyb21pdW1vcy10ZXN0LWFzc2V0cy1wdWJ)" + R"(saWMvZW50ZXJwcmlzZS9wcmludGVycy5qc29uIn0=" + } + ] + } + )")); + ASSERT_TRUE(base::WriteFile(client_state_path_, R"( + { + "fake_device_id" : { + "device_id" : "fake_device_id", + "device_token" : "fake_device_token", + "machine_name" : "fake_machine_name", + "username" : "tast-user@managedchrome.com", + "state_keys" : [ "fake_state_key" ], + "allowed_policy_types" : [ "google/chrome/extension", + "google/chromeos/user" ] + } + } + )")); + EXPECT_EQ(SendRequest(fake_dmserver.GetServiceURL(), + "/?apptype=Chrome&deviceid=fake_device_id&devicetype=2&" + "oauth_token=fake_policy_token&request=policy"), + net::HTTP_OK); + + std::string user_policy_payload = + fake_dmserver.policy_storage()->GetPolicyPayload("google/chromeos/user", + ""); + std::string user_policy_output; + base::Base64Encode(user_policy_payload, &user_policy_output); + EXPECT_EQ(user_policy_output, "uhMCEAE="); + + std::string device_policy_payload = + fake_dmserver.policy_storage()->GetPolicyPayload("google/chromeos/device", + ""); + std::string device_policy_output; + base::Base64Encode(device_policy_payload, &device_policy_output); + EXPECT_EQ(device_policy_output, + "qgFSCikSJWRlZmF1bHRNZ3NTZXRCeVRhc3RAbWFuYWdlZGNocm9tZS5jb20YABIlZG" + "VmYXVsdE1nc1NldEJ5VGFzdEBtYW5hZ2VkY2hyb21lLmNvbQ=="); + + std::string publicaccount_policy_payload = + fake_dmserver.policy_storage()->GetPolicyPayload( + "google/chromeos/publicaccount", "accountid@managedchrome.com"); + std::string public_policy_output; + base::Base64Encode(publicaccount_policy_payload, &public_policy_output); + EXPECT_EQ(public_policy_output, + "ojCsARKpAXsiaGFzaCI6IjdhMDUyYzVlNGYyM2MxNTk2NjgxNDhkZjJhM2MyMDJiZW" + "Q0ZDY1NzQ5Y2FiNWVjZDBmYTdkYjIxMWMxMmEzYjgiLCJ1cmwiOiJodHRwczovL3N0" + "b3JhZ2UuZ29vZ2xlYXBpcy5jb20vY2hyb21pdW1vcy10ZXN0LWFzc2V0cy1wdWJsaW" + "MvZW50ZXJwcmlzZS9wcmludGVycy5qc29uIn0="); +} + +TEST_F(FakeDMServerTest, ReadPolicyBlobFile_WithWrongJSONData_Fails) { + FakeDMServer fake_dmserver(policy_blob_path_.MaybeAsASCII(), + client_state_path_.MaybeAsASCII()); + EXPECT_TRUE(fake_dmserver.Start()); + + ASSERT_TRUE(base::WriteFile(policy_blob_path_, "wrong data")); + EXPECT_EQ(SendRequest(fake_dmserver.GetServiceURL(), + "/?apptype=Chrome&deviceid=fake_device_id&devicetype=2&" + "oauth_token=fake_policy_token&request=policy"), + net::HTTP_INTERNAL_SERVER_ERROR); +} + +TEST_F(FakeDMServerTest, ReadPolicyBlobFile_WithNonDictFile_Fails) { + FakeDMServer fake_dmserver(policy_blob_path_.MaybeAsASCII(), + client_state_path_.MaybeAsASCII()); + EXPECT_TRUE(fake_dmserver.Start()); + + ASSERT_TRUE(base::WriteFile(policy_blob_path_, R"([ "1", "2" ])")); + EXPECT_EQ(SendRequest(fake_dmserver.GetServiceURL(), + "/?apptype=Chrome&deviceid=fake_device_id&devicetype=2&" + "oauth_token=fake_policy_token&request=policy"), + net::HTTP_INTERNAL_SERVER_ERROR); +} + +TEST_F(FakeDMServerTest, ReadPolicyBlobFile_WithNonDictPolicies_Fails) { + FakeDMServer fake_dmserver(policy_blob_path_.MaybeAsASCII(), + client_state_path_.MaybeAsASCII()); + EXPECT_TRUE(fake_dmserver.Start()); + + ASSERT_TRUE(base::WriteFile(policy_blob_path_, R"( + { + "managed_users" : [ "*" ], + "policies" : [ "1", "2" ] + } + )")); + EXPECT_EQ(SendRequest(fake_dmserver.GetServiceURL(), + "/?apptype=Chrome&deviceid=fake_device_id&devicetype=2&" + "oauth_token=fake_policy_token&request=policy"), + net::HTTP_INTERNAL_SERVER_ERROR); +} + +TEST_F(FakeDMServerTest, SetPolicyPayload_WithoutValueOrTypeField_Fails) { + FakeDMServer fake_dmserver(policy_blob_path_.MaybeAsASCII(), + client_state_path_.MaybeAsASCII()); + EXPECT_TRUE(fake_dmserver.Start()); + + ASSERT_TRUE(base::WriteFile(policy_blob_path_, R"( + { + "managed_users" : [ "*" ], + "policies" : [ + { "wrong type" : "google/chromeos/user", "wrong value" : "uhMCEAE=" } + ] + } + )")); + EXPECT_EQ(SendRequest(fake_dmserver.GetServiceURL(), + "/?apptype=Chrome&deviceid=fake_device_id&devicetype=2&" + "oauth_token=fake_policy_token&request=policy"), + net::HTTP_INTERNAL_SERVER_ERROR); +} + +TEST_F(FakeDMServerTest, SetPolicyPayload_WithNonBase64Value_Fails) { + FakeDMServer fake_dmserver(policy_blob_path_.MaybeAsASCII(), + client_state_path_.MaybeAsASCII()); + EXPECT_TRUE(fake_dmserver.Start()); + + ASSERT_TRUE(base::WriteFile(policy_blob_path_, R"( + { + "managed_users" : [ "*" ], + "policies" : [ + { "policy_type" : "google/chromeos/user", "value" : "!@#$%^&*" } + ] + } + )")); + EXPECT_EQ(SendRequest(fake_dmserver.GetServiceURL(), + "/?apptype=Chrome&deviceid=fake_device_id&devicetype=2&" + "oauth_token=fake_policy_token&request=policy"), + net::HTTP_INTERNAL_SERVER_ERROR); +} + +} // namespace fakedms
diff --git a/components/safe_browsing/content/browser/client_side_detection_service.cc b/components/safe_browsing/content/browser/client_side_detection_service.cc index 235b006..577c103 100644 --- a/components/safe_browsing/content/browser/client_side_detection_service.cc +++ b/components/safe_browsing/content/browser/client_side_detection_service.cc
@@ -405,10 +405,8 @@ return; phishing_report_times_.clear(); - for (const base::Value& timestamp : - delegate_->GetPrefs() - ->GetList(prefs::kSafeBrowsingCsdPingTimestamps) - ->GetListDeprecated()) { + for (const base::Value& timestamp : delegate_->GetPrefs()->GetValueList( + prefs::kSafeBrowsingCsdPingTimestamps)) { phishing_report_times_.push_back( base::Time::FromDoubleT(timestamp.GetDouble())); }
diff --git a/components/safe_browsing/content/browser/triggers/trigger_throttler.cc b/components/safe_browsing/content/browser/triggers/trigger_throttler.cc index 8f3553e..58a5c3d 100644 --- a/components/safe_browsing/content/browser/triggers/trigger_throttler.cc +++ b/components/safe_browsing/content/browser/triggers/trigger_throttler.cc
@@ -159,9 +159,9 @@ if (!local_state_prefs_) return; - const base::Value* event_dict = local_state_prefs_->GetDictionary( + const base::Value::Dict& event_dict = local_state_prefs_->GetValueDict( prefs::kSafeBrowsingTriggerEventTimestamps); - for (auto trigger_pair : event_dict->DictItems()) { + for (auto trigger_pair : event_dict) { // Check that the first item in the pair is convertible to a trigger type // and that the second item is a list. int trigger_type_int; @@ -174,7 +174,7 @@ continue; const TriggerType trigger_type = static_cast<TriggerType>(trigger_type_int); - for (const auto& timestamp : trigger_pair.second.GetListDeprecated()) { + for (const auto& timestamp : trigger_pair.second.GetList()) { if (timestamp.is_double()) trigger_events_[trigger_type].push_back( base::Time::FromDoubleT(timestamp.GetDouble()));
diff --git a/components/safe_browsing/content/common/file_type_policies_policy_util.cc b/components/safe_browsing/content/common/file_type_policies_policy_util.cc index e13effdc..5f323c1 100644 --- a/components/safe_browsing/content/common/file_type_policies_policy_util.cc +++ b/components/safe_browsing/content/common/file_type_policies_policy_util.cc
@@ -37,39 +37,36 @@ kExemptDomainFileTypePairsFromFileTypeDownloadWarnings)) { return false; } - const base::Value* heuristic_overrides = prefs->GetList( + const base::Value::List& heuristic_overrides = prefs->GetValueList( file_type::prefs::kExemptDomainFileTypePairsFromFileTypeDownloadWarnings); const std::string lower_extension = base::ToLowerASCII(extension); - if (heuristic_overrides) { - base::Value::List domains_for_extension; - for (const base::Value& entry : heuristic_overrides->GetListDeprecated()) { - const base::DictionaryValue& extension_domain_patterns_dict = - base::Value::AsDictionaryValue(entry); - const std::string* extension_for_this_entry = - extension_domain_patterns_dict.FindStringKey(kFileExtensionNameKey); - if (extension_for_this_entry && - base::ToLowerASCII(*extension_for_this_entry) == lower_extension) { - const base::Value* domains_for_this_entry = - extension_domain_patterns_dict.FindListKey(kDomainListKey); - if (domains_for_this_entry) { - for (const base::Value& domain : - domains_for_this_entry->GetListDeprecated()) { - domains_for_extension.Append(domain.Clone()); - } + base::Value::List domains_for_extension; + for (const base::Value& entry : heuristic_overrides) { + const base::Value::Dict& extension_domain_patterns_dict = entry.GetDict(); + const std::string* extension_for_this_entry = + extension_domain_patterns_dict.FindString(kFileExtensionNameKey); + if (extension_for_this_entry && + base::ToLowerASCII(*extension_for_this_entry) == lower_extension) { + const base::Value::List* domains_for_this_entry = + extension_domain_patterns_dict.FindList(kDomainListKey); + if (domains_for_this_entry) { + for (const base::Value& domain : *domains_for_this_entry) { + domains_for_extension.Append(domain.Clone()); } } } - - if (!domains_for_extension.empty()) { - url_matcher::URLMatcher matcher; - base::MatcherStringPattern::ID id(0); - url_matcher::util::AddFilters(&matcher, true, &id, domains_for_extension); - auto matching_set_size = matcher.MatchURL(normalized_url).size(); - return matching_set_size > 0; - } } + + if (!domains_for_extension.empty()) { + url_matcher::URLMatcher matcher; + base::MatcherStringPattern::ID id(0); + url_matcher::util::AddFilters(&matcher, true, &id, domains_for_extension); + auto matching_set_size = matcher.MatchURL(normalized_url).size(); + return matching_set_size > 0; + } + return false; }
diff --git a/components/safe_browsing/core/browser/safe_browsing_metrics_collector.cc b/components/safe_browsing/core/browser/safe_browsing_metrics_collector.cc index c0612368..dcb19e9b 100644 --- a/components/safe_browsing/core/browser/safe_browsing_metrics_collector.cc +++ b/components/safe_browsing/core/browser/safe_browsing_metrics_collector.cc
@@ -283,29 +283,31 @@ } } -const base::Value* SafeBrowsingMetricsCollector::GetSafeBrowsingEventDictionary( +const base::Value::Dict* +SafeBrowsingMetricsCollector::GetSafeBrowsingEventDictionary( UserState user_state) { - const base::Value* state_dict = - pref_service_->GetDictionary(prefs::kSafeBrowsingEventTimestamps); + const base::Value::Dict& state_dict = + pref_service_->GetValueDict(prefs::kSafeBrowsingEventTimestamps); - return state_dict->FindDictKey(UserStateToPrefKey(user_state)); + return state_dict.FindDict(UserStateToPrefKey(user_state)); } absl::optional<SafeBrowsingMetricsCollector::Event> SafeBrowsingMetricsCollector::GetLatestEventFromEventType( UserState user_state, EventType event_type) { - const base::Value* event_dict = GetSafeBrowsingEventDictionary(user_state); + const base::Value::Dict* event_dict = + GetSafeBrowsingEventDictionary(user_state); if (!event_dict) { return absl::nullopt; } - const base::Value* timestamps = - event_dict->FindListKey(EventTypeToPrefKey(event_type)); + const base::Value::List* timestamps = + event_dict->FindList(EventTypeToPrefKey(event_type)); - if (timestamps && timestamps->GetListDeprecated().size() > 0) { - base::Time time = PrefValueToTime(timestamps->GetListDeprecated().back()); + if (timestamps && timestamps->size() > 0) { + base::Time time = PrefValueToTime(timestamps->back()); return Event(event_type, time); } @@ -357,7 +359,7 @@ void SafeBrowsingMetricsCollector:: LogThrottledEnhancedProtectionDisabledMetrics() { - const base::Value* event_dict = + const base::Value::Dict* event_dict = GetSafeBrowsingEventDictionary(UserState::kEnhancedProtection); if (!event_dict) { return; @@ -431,18 +433,18 @@ int SafeBrowsingMetricsCollector::GetEventCountSince(UserState user_state, EventType event_type, base::Time since_time) { - const base::Value* event_dict = GetSafeBrowsingEventDictionary(user_state); + const base::Value::Dict* event_dict = + GetSafeBrowsingEventDictionary(user_state); if (!event_dict) { return 0; } - const base::Value* timestamps = - event_dict->FindListKey(EventTypeToPrefKey(event_type)); + const base::Value::List* timestamps = + event_dict->FindList(EventTypeToPrefKey(event_type)); if (!timestamps) { return 0; } - return std::count_if(timestamps->GetListDeprecated().begin(), - timestamps->GetListDeprecated().end(), + return std::count_if(timestamps->begin(), timestamps->end(), [&](const base::Value& timestamp) { return PrefValueToTime(timestamp) > since_time; });
diff --git a/components/safe_browsing/core/browser/safe_browsing_metrics_collector.h b/components/safe_browsing/core/browser/safe_browsing_metrics_collector.h index 02bf49d..06122a6 100644 --- a/components/safe_browsing/core/browser/safe_browsing_metrics_collector.h +++ b/components/safe_browsing/core/browser/safe_browsing_metrics_collector.h
@@ -9,6 +9,7 @@ #include "base/memory/raw_ptr.h" #include "base/time/time.h" #include "base/timer/timer.h" +#include "base/values.h" #include "components/keyed_service/core/keyed_service.h" #include "components/prefs/pref_change_registrar.h" #include "components/safe_browsing/core/browser/db/hit_report.h" @@ -16,10 +17,6 @@ class PrefService; -namespace base { -class Value; -} // namespace base - namespace safe_browsing { // This class is for logging Safe Browsing metrics regularly. Metrics are logged @@ -168,7 +165,7 @@ absl::optional<SafeBrowsingMetricsCollector::Event> GetLatestEventFromEventTypeFilter(UserState user_state, EventTypeFilter event_type_filter); - const base::Value* GetSafeBrowsingEventDictionary(UserState user_state); + const base::Value::Dict* GetSafeBrowsingEventDictionary(UserState user_state); int GetEventCountSince(UserState user_state, EventType event_type, base::Time since_time);
diff --git a/components/safe_browsing/core/common/safe_browsing_prefs.cc b/components/safe_browsing/core/common/safe_browsing_prefs.cc index cf55188e..cbe84f00 100644 --- a/components/safe_browsing/core/common/safe_browsing_prefs.cc +++ b/components/safe_browsing/core/common/safe_browsing_prefs.cc
@@ -302,10 +302,10 @@ base::ListValue GetSafeBrowsingPoliciesList(PrefService* prefs) { base::ListValue preferences_list; - const base::Value* allowlist_domains = - prefs->GetList(prefs::kSafeBrowsingAllowlistDomains); + const base::Value::List& allowlist_domains = + prefs->GetValueList(prefs::kSafeBrowsingAllowlistDomains); std::vector<std::string> domain_list; - CanonicalizeDomainList(*allowlist_domains, &domain_list); + CanonicalizeDomainList(allowlist_domains, &domain_list); std::string domains; for (const auto& domain : domain_list) { domains = domains + " " + domain; @@ -335,21 +335,20 @@ void GetSafeBrowsingAllowlistDomainsPref( const PrefService& prefs, std::vector<std::string>* out_canonicalized_domain_list) { - const base::Value* pref_value = - prefs.GetList(prefs::kSafeBrowsingAllowlistDomains); - CanonicalizeDomainList(*pref_value, out_canonicalized_domain_list); + const base::Value::List& pref_value = + prefs.GetValueList(prefs::kSafeBrowsingAllowlistDomains); + CanonicalizeDomainList(pref_value, out_canonicalized_domain_list); } void CanonicalizeDomainList( - const base::Value& raw_domain_list, + const base::Value::List& raw_domain_list, std::vector<std::string>* out_canonicalized_domain_list) { out_canonicalized_domain_list->clear(); - for (auto it = raw_domain_list.GetListDeprecated().begin(); - it != raw_domain_list.GetListDeprecated().end(); it++) { + for (const base::Value& value : raw_domain_list) { // Verify if it is valid domain string. url::CanonHostInfo host_info; std::string canonical_host = - net::CanonicalizeHost(it->GetString(), &host_info); + net::CanonicalizeHost(value.GetString(), &host_info); if (!canonical_host.empty()) out_canonicalized_domain_list->push_back(canonical_host); } @@ -358,9 +357,9 @@ bool IsURLAllowlistedByPolicy(const GURL& url, const PrefService& pref) { if (!pref.HasPrefPath(prefs::kSafeBrowsingAllowlistDomains)) return false; - const base::Value* allowlist = - pref.GetList(prefs::kSafeBrowsingAllowlistDomains); - for (const base::Value& value : allowlist->GetListDeprecated()) { + const base::Value::List& allowlist = + pref.GetValueList(prefs::kSafeBrowsingAllowlistDomains); + for (const base::Value& value : allowlist) { if (url.DomainIs(value.GetString())) return true; } @@ -369,9 +368,9 @@ std::vector<std::string> GetURLAllowlistByPolicy(PrefService* pref_service) { std::vector<std::string> allowlist_domains; - const base::Value* allowlist = - pref_service->GetList(prefs::kSafeBrowsingAllowlistDomains); - for (const base::Value& value : allowlist->GetListDeprecated()) { + const base::Value::List& allowlist = + pref_service->GetValueList(prefs::kSafeBrowsingAllowlistDomains); + for (const base::Value& value : allowlist) { allowlist_domains.push_back(value.GetString()); } return allowlist_domains; @@ -388,10 +387,10 @@ void GetPasswordProtectionLoginURLsPref(const PrefService& prefs, std::vector<GURL>* out_login_url_list) { - const base::Value* pref_value = - prefs.GetList(prefs::kPasswordProtectionLoginURLs); + const base::Value::List& pref_value = + prefs.GetValueList(prefs::kPasswordProtectionLoginURLs); out_login_url_list->clear(); - for (const base::Value& value : pref_value->GetListDeprecated()) { + for (const base::Value& value : pref_value) { GURL login_url(value.GetString()); // Skip invalid or none-http/https login URLs. if (login_url.is_valid() && login_url.SchemeIsHTTPOrHTTPS())
diff --git a/components/safe_browsing/core/common/safe_browsing_prefs.h b/components/safe_browsing/core/common/safe_browsing_prefs.h index c32c617d..52ad7e2 100644 --- a/components/safe_browsing/core/common/safe_browsing_prefs.h +++ b/components/safe_browsing/core/common/safe_browsing_prefs.h
@@ -307,7 +307,7 @@ // Helper function to validate and canonicalize a list of domain strings. void CanonicalizeDomainList( - const base::Value& raw_domain_list, + const base::Value::List& raw_domain_list, std::vector<std::string>* out_canonicalized_domain_list); // Helper function to determine if |url| matches Safe Browsing allowlist domains
diff --git a/components/segmentation_platform/components_unittests.filter b/components/segmentation_platform/components_unittests.filter index 8b9310b..db2a3a76 100644 --- a/components/segmentation_platform/components_unittests.filter +++ b/components/segmentation_platform/components_unittests.filter
@@ -1,4 +1,3 @@ -ConfigParserTest.* CustomInputProcessorTest.* DatabaseMaintenanceImplTest.* DefaultModelManagerTest.* @@ -18,6 +17,10 @@ PriceTrackingActionModelTest.* PriceTrackingInputDelegateTest.* QueryTilesModelTest.* +SegmentInfoDatabaseTest.* +SegmentResultProviderTest.* +SegmentScoreProviderTest.* +SegmentSelectorTest.* SegmentationModelExecutorTest.* SegmentationPlatformDummyUkmManagerTest.* SegmentationPlatformServiceImplEmptyConfigTest.* @@ -25,10 +28,6 @@ SegmentationPlatformServiceImplTest.* SegmentationResultPrefsTest.* SegmentationUkmHelperTest.* -SegmentInfoDatabaseTest.* -SegmentResultProviderTest.* -SegmentScoreProviderTest.* -SegmentSelectorTest.* ServiceProxyImplTest.* SignalDatabaseImplTest.* SignalFilterProcessorTest.* @@ -39,8 +38,8 @@ StatsTest.* TrainingDataCollectorImplTest.* UkmConfigTest.* -UkmDatabaseBackendTest.* UkmDataManagerImplTest.* +UkmDatabaseBackendTest.* UkmMetricsTableTest.* UkmObserverTest.* UkmUrlTableTest.*
diff --git a/components/segmentation_platform/internal/BUILD.gn b/components/segmentation_platform/internal/BUILD.gn index 470d1d48..23eafde4 100644 --- a/components/segmentation_platform/internal/BUILD.gn +++ b/components/segmentation_platform/internal/BUILD.gn
@@ -19,8 +19,6 @@ ] sources = [ - "config_parser.cc", - "config_parser.h", "constants.cc", "constants.h", "data_collection/dummy_training_data_collector.cc", @@ -92,6 +90,8 @@ "metadata/metadata_utils.h", "metadata/metadata_writer.cc", "metadata/metadata_writer.h", + "metric_filter_utils.cc", + "metric_filter_utils.h", "platform_options.cc", "platform_options.h", "scheduler/execution_service.cc", @@ -201,7 +201,6 @@ # IMPORTANT NOTE: When adding new tests, also remember to update the list of # tests in //components/segmentation_platform/components_unittests.filter sources = [ - "config_parser_unittest.cc", "data_collection/training_data_collector_impl_unittest.cc", "database/database_maintenance_impl_unittest.cc", "database/mock_signal_database.cc",
diff --git a/components/segmentation_platform/internal/config_parser.cc b/components/segmentation_platform/internal/config_parser.cc deleted file mode 100644 index 5f8b934c..0000000 --- a/components/segmentation_platform/internal/config_parser.cc +++ /dev/null
@@ -1,72 +0,0 @@ -// Copyright 2022 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/segmentation_platform/internal/config_parser.h" - -#include "base/json/json_reader.h" -#include "base/logging.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/string_util.h" -#include "components/segmentation_platform/public/config.h" - -namespace segmentation_platform { -namespace { - -constexpr char kSegmentationKey[] = "segmentation_key"; -constexpr char kSegmentationUmaName[] = "segmentation_uma_name"; -constexpr char kSegmentIds[] = "segments"; -constexpr char kSegmentUmaName[] = "segment_uma_name"; -constexpr char kSegmentSelectionTTL[] = "segment_selection_ttl_days"; -constexpr char kUnknownSegmentSelectionTTL[] = - "unknown_segment_selection_ttl_days"; - -} // namespace - -std::unique_ptr<Config> ParseConfigFromString(const std::string& config_str) { - auto value_with_error = - base::JSONReader::ReadAndReturnValueWithError(config_str); - if (!value_with_error.has_value()) { - VLOG(1) << "Config failed to parse: " << config_str - << ". with error: " << value_with_error.error().message; - return nullptr; - } - const base::Value::Dict& config_dict = value_with_error.value().GetDict(); - const std::string* key = config_dict.FindString(kSegmentationKey); - const std::string* uma_name = config_dict.FindString(kSegmentationUmaName); - const base::Value::Dict* segments = config_dict.FindDict(kSegmentIds); - const absl::optional<int> selection_ttl_days = - config_dict.FindInt(kSegmentSelectionTTL); - const absl::optional<int> unknown_selection_ttl_days = - config_dict.FindInt(kUnknownSegmentSelectionTTL); - - if (!key || !uma_name || !segments || !selection_ttl_days) { - return nullptr; - } - auto config = std::make_unique<Config>(); - config->segmentation_key = *key; - config->segmentation_uma_name = *uma_name; - config->segment_selection_ttl = base::Days(*selection_ttl_days); - if (unknown_selection_ttl_days) { - config->unknown_selection_ttl = base::Days(*unknown_selection_ttl_days); - } - - for (const auto segment_id : *segments) { - int segment = 0; - if (!base::StringToInt(segment_id.first, &segment)) { - return nullptr; - } - const base::Value::Dict& segment_dict = segment_id.second.GetDict(); - const std::string* segment_uma_name = - segment_dict.FindString(kSegmentUmaName); - if (!segment_uma_name) { - return nullptr; - } - - config->segments.insert( - {static_cast<proto::SegmentId>(segment), {*segment_uma_name}}); - } - - return config; -} -} // namespace segmentation_platform
diff --git a/components/segmentation_platform/internal/config_parser.h b/components/segmentation_platform/internal/config_parser.h deleted file mode 100644 index 61dcd09..0000000 --- a/components/segmentation_platform/internal/config_parser.h +++ /dev/null
@@ -1,20 +0,0 @@ -// Copyright 2022 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_SEGMENTATION_PLATFORM_INTERNAL_CONFIG_PARSER_H_ -#define COMPONENTS_SEGMENTATION_PLATFORM_INTERNAL_CONFIG_PARSER_H_ - -#include <memory> -#include <string> - -namespace segmentation_platform { - -struct Config; - -// Parses and returns the segmentation config from JSON string. -std::unique_ptr<Config> ParseConfigFromString(const std::string& config_str); - -} // namespace segmentation_platform - -#endif // COMPONENTS_SEGMENTATION_PLATFORM_INTERNAL_CONFIG_PARSER_H_
diff --git a/components/segmentation_platform/internal/config_parser_unittest.cc b/components/segmentation_platform/internal/config_parser_unittest.cc deleted file mode 100644 index 2fbec70..0000000 --- a/components/segmentation_platform/internal/config_parser_unittest.cc +++ /dev/null
@@ -1,70 +0,0 @@ -// Copyright 2022 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/segmentation_platform/internal/config_parser.h" - -#include "components/segmentation_platform/public/config.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace segmentation_platform { - -TEST(ConfigParserTest, ParseInvalidConfig) { - constexpr char kInvalidJson[] = - R"({"segmentation_key":"test_key, "uma_name":})"; - EXPECT_FALSE(ParseConfigFromString(kInvalidJson)); - - constexpr char kMissingFields[] = R"({"segmentation_key":"test_key"})"; - EXPECT_FALSE(ParseConfigFromString(kMissingFields)); -} - -TEST(ConfigParserTest, ParseValidConfig) { - constexpr char kValidConfig1[] = R"({ - "segmentation_key": "test_key", - "segmentation_uma_name": "TestKey", - "segments": { - "2" : {"segment_uma_name" : "LowEngagement"}, - "7" : {"segment_uma_name" : "HighEngagement"}, - "9" : {"segment_uma_name" : "MediumEngagement"} - }, - "segment_selection_ttl_days": 10 - })"; - auto config1 = ParseConfigFromString(kValidConfig1); - ASSERT_TRUE(config1); - EXPECT_EQ(config1->segmentation_key, "test_key"); - EXPECT_EQ(config1->segmentation_uma_name, "TestKey"); - std::unordered_map<proto::SegmentId, Config::SegmentMetadata> expected1{ - {proto::SegmentId::OPTIMIZATION_TARGET_MODEL_VALIDATION, - Config::SegmentMetadata{"HighEngagement"}}, - {proto::SegmentId:: - OPTIMIZATION_TARGET_NOTIFICATION_PERMISSION_PREDICTIONS, - Config::SegmentMetadata{"MediumEngagement"}}, - {proto::SegmentId::OPTIMIZATION_TARGET_LANGUAGE_DETECTION, - Config::SegmentMetadata{"LowEngagement"}}}; - EXPECT_EQ(config1->segments, expected1); - EXPECT_EQ(config1->segment_selection_ttl, base::Days(10)); - EXPECT_EQ(config1->unknown_selection_ttl, base::Days(0)); - - constexpr char kValidConfig2[] = R"({ - "segmentation_key": "test_key", - "segmentation_uma_name": "TestKey", - "segments": { - "9" : {"segment_uma_name" : "FeedUser"} - }, - "segment_selection_ttl_days": 10, - "unknown_segment_selection_ttl_days": 14 - })"; - auto config2 = ParseConfigFromString(kValidConfig2); - ASSERT_TRUE(config2); - EXPECT_EQ(config2->segmentation_key, "test_key"); - EXPECT_EQ(config2->segmentation_uma_name, "TestKey"); - std::unordered_map<proto::SegmentId, Config::SegmentMetadata> expected2{ - {proto::SegmentId:: - OPTIMIZATION_TARGET_NOTIFICATION_PERMISSION_PREDICTIONS, - Config::SegmentMetadata{"FeedUser"}}}; - EXPECT_EQ(config2->segments, expected2); - EXPECT_EQ(config2->segment_selection_ttl, base::Days(10)); - EXPECT_EQ(config2->unknown_selection_ttl, base::Days(14)); -} - -} // namespace segmentation_platform
diff --git a/components/segmentation_platform/internal/data_collection/training_data_collector_impl.cc b/components/segmentation_platform/internal/data_collection/training_data_collector_impl.cc index 3a44fd8..7acceb3d 100644 --- a/components/segmentation_platform/internal/data_collection/training_data_collector_impl.cc +++ b/components/segmentation_platform/internal/data_collection/training_data_collector_impl.cc
@@ -60,9 +60,10 @@ return std::string(); for (const auto& config : *configs) { - auto it = config->segments.find(segment_id); - if (it != config->segments.end()) + if (std::find(config->segment_ids.begin(), config->segment_ids.end(), + segment_id) != config->segment_ids.end()) { return config->segmentation_key; + } } return std::string(); }
diff --git a/components/segmentation_platform/internal/data_collection/training_data_collector_impl_unittest.cc b/components/segmentation_platform/internal/data_collection/training_data_collector_impl_unittest.cc index 6b9a165..9dd7199 100644 --- a/components/segmentation_platform/internal/data_collection/training_data_collector_impl_unittest.cc +++ b/components/segmentation_platform/internal/data_collection/training_data_collector_impl_unittest.cc
@@ -85,11 +85,10 @@ configs_.emplace_back(std::make_unique<Config>()); configs_[0]->segmentation_key = kSegmentationKey; - configs_[0]->segments.insert( - {SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_NEW_TAB, - {"UmaNameNewTab"}}); - configs_[0]->segments.insert( - {SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_SHARE, {"UmaNameShare"}}); + configs_[0]->segment_ids.push_back( + SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_NEW_TAB); + configs_[0]->segment_ids.push_back( + SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_SHARE); SegmentationResultPrefs result_prefs(&prefs_); SelectedSegment selected_segment(
diff --git a/components/segmentation_platform/internal/metric_filter_utils.cc b/components/segmentation_platform/internal/metric_filter_utils.cc new file mode 100644 index 0000000..b6c18495 --- /dev/null +++ b/components/segmentation_platform/internal/metric_filter_utils.cc
@@ -0,0 +1,33 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/segmentation_platform/internal/metric_filter_utils.h" + +#include "base/strings/strcat.h" +#include "components/segmentation_platform/internal/stats.h" + +namespace segmentation_platform::stats { +namespace { +using proto::SegmentId; + +} // namespace + +std::string OptimizationTargetToSegmentGroupName(SegmentId segment_id) { + return OptimizationTargetToHistogramVariant(segment_id); +} + +std::string SegmentationKeyToTrialName(const std::string& segmentation_key) { + return base::StrCat( + {"Segmentation_", SegmentationKeyToUmaName(segmentation_key)}); +} + +std::string SegmentationKeyToSubsegmentTrialName( + const std::string& segmentation_key, + proto::SegmentId segment_id) { + return base::StrCat({"Segmentation_", + SegmentationKeyToUmaName(segmentation_key), "_", + OptimizationTargetToHistogramVariant(segment_id)}); +} + +} // namespace segmentation_platform::stats
diff --git a/components/segmentation_platform/internal/metric_filter_utils.h b/components/segmentation_platform/internal/metric_filter_utils.h new file mode 100644 index 0000000..f027cf6 --- /dev/null +++ b/components/segmentation_platform/internal/metric_filter_utils.h
@@ -0,0 +1,33 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_SEGMENTATION_PLATFORM_INTERNAL_METRIC_FILTER_UTILS_H_ +#define COMPONENTS_SEGMENTATION_PLATFORM_INTERNAL_METRIC_FILTER_UTILS_H_ + +#include <array> +#include <string> +#include <vector> + +#include "components/segmentation_platform/public/proto/segmentation_platform.pb.h" +#include "third_party/abseil-cpp/absl/types/optional.h" + +namespace segmentation_platform::stats { + +// Returns a name to be used in UMA dashboard as segment group for the given +// `segment_id`. +std::string OptimizationTargetToSegmentGroupName(proto::SegmentId segment_id); + +// Returns a name to be used in UMA dashboard as segmentation type for the given +// `segmentation_key`. +std::string SegmentationKeyToTrialName(const std::string& segmentation_key); + +// Returns a name to be used in UMA dashboard as segmentation subtype type for +// the given `segmentation_key` and `segment_id`. +std::string SegmentationKeyToSubsegmentTrialName( + const std::string& segmentation_key, + proto::SegmentId segment_id); + +} // namespace segmentation_platform::stats + +#endif // COMPONENTS_SEGMENTATION_PLATFORM_INTERNAL_METRIC_FILTER_UTILS_H_
diff --git a/components/segmentation_platform/internal/segmentation_platform_service_impl.cc b/components/segmentation_platform/internal/segmentation_platform_service_impl.cc index 9a55abb..f457fb5 100644 --- a/components/segmentation_platform/internal/segmentation_platform_service_impl.cc +++ b/components/segmentation_platform/internal/segmentation_platform_service_impl.cc
@@ -43,8 +43,8 @@ const std::vector<std::unique_ptr<Config>>& configs) { base::flat_set<SegmentId> all_segment_ids; for (const auto& config : configs) { - for (const auto& segment_id : config->segments) - all_segment_ids.insert(segment_id.first); + for (const auto& segment_id : config->segment_ids) + all_segment_ids.insert(segment_id); } return all_segment_ids; }
diff --git a/components/segmentation_platform/internal/segmentation_platform_service_test_base.cc b/components/segmentation_platform/internal/segmentation_platform_service_test_base.cc index e425c96..8fa92fb 100644 --- a/components/segmentation_platform/internal/segmentation_platform_service_test_base.cc +++ b/components/segmentation_platform/internal/segmentation_platform_service_test_base.cc
@@ -12,7 +12,6 @@ #include "components/segmentation_platform/internal/database/segment_info_database.h" #include "components/segmentation_platform/internal/execution/mock_model_provider.h" #include "components/segmentation_platform/internal/segmentation_platform_service_impl.h" -#include "components/segmentation_platform/internal/stats.h" #include "components/segmentation_platform/internal/ukm_data_manager.h" #include "components/segmentation_platform/public/config.h" #include "components/segmentation_platform/public/field_trial_register.h" @@ -21,13 +20,6 @@ namespace { -#define SEGMENT_ID_ENTRY(segment) \ - { \ - segment, Config::SegmentMetadata { \ - stats::OptimizationTargetToHistogramVariant(segment) \ - } \ - } - class MockFieldTrialRegister : public FieldTrialRegister { public: MOCK_METHOD2(RegisterFieldTrial, @@ -45,26 +37,23 @@ std::unique_ptr<Config> config = std::make_unique<Config>(); config->segmentation_key = kTestSegmentationKey1; config->segment_selection_ttl = base::Days(28); - config->segments = { - SEGMENT_ID_ENTRY(SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_NEW_TAB), - SEGMENT_ID_ENTRY(SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_SHARE)}; + config->segment_ids = {SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_NEW_TAB, + SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_SHARE}; configs.push_back(std::move(config)); } { std::unique_ptr<Config> config = std::make_unique<Config>(); config->segmentation_key = kTestSegmentationKey2; config->segment_selection_ttl = base::Days(10); - config->segments = { - SEGMENT_ID_ENTRY(SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_SHARE), - SEGMENT_ID_ENTRY(SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_VOICE)}; + config->segment_ids = {SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_SHARE, + SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_VOICE}; configs.push_back(std::move(config)); } { std::unique_ptr<Config> config = std::make_unique<Config>(); config->segmentation_key = kTestSegmentationKey3; config->segment_selection_ttl = base::Days(14); - config->segments = { - SEGMENT_ID_ENTRY(SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_NEW_TAB)}; + config->segment_ids = {SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_NEW_TAB}; configs.push_back(std::move(config)); } { @@ -114,8 +103,8 @@ std::vector<std::unique_ptr<Config>> configs = CreateTestConfigs(); base::flat_set<SegmentId> all_segment_ids; for (const auto& config : configs) { - for (const auto& segment_id : config->segments) - all_segment_ids.insert(segment_id.first); + for (const auto& segment_id : config->segment_ids) + all_segment_ids.insert(segment_id); } auto storage_service = std::make_unique<StorageService>( std::move(segment_db), std::move(signal_db),
diff --git a/components/segmentation_platform/internal/selection/experimental_group_recorder.cc b/components/segmentation_platform/internal/selection/experimental_group_recorder.cc index 61e294f..f7078cf 100644 --- a/components/segmentation_platform/internal/selection/experimental_group_recorder.cc +++ b/components/segmentation_platform/internal/selection/experimental_group_recorder.cc
@@ -7,26 +7,27 @@ #include "base/bind.h" #include "base/strings/strcat.h" #include "components/segmentation_platform/internal/metadata/metadata_utils.h" +#include "components/segmentation_platform/internal/metric_filter_utils.h" #include "components/segmentation_platform/internal/selection/segment_result_provider.h" #include "components/segmentation_platform/public/config.h" #include "components/segmentation_platform/public/field_trial_register.h" +#include "base/logging.h" + namespace segmentation_platform { ExperimentalGroupRecorder::ExperimentalGroupRecorder( SegmentResultProvider* result_provider, FieldTrialRegister* field_trial_register, - const Config& config, - proto::SegmentId segment_id) + const std::string& segmentation_key, + proto::SegmentId selected_segment) : field_trial_register_(field_trial_register), - subsegment_trial_name_( - base::StrCat({config.GetSegmentationFilterName(), "_", - config.GetSegmentUmaName(segment_id)})), - segment_id_(segment_id) { + segmentation_key_(segmentation_key), + segment_id_(selected_segment) { auto options = std::make_unique<SegmentResultProvider::GetResultOptions>(); options->segmentation_key = - base::StrCat({config.segmentation_key, kSubsegmentDiscreteMappingSuffix}); - options->segment_id = segment_id; + base::StrCat({segmentation_key, kSubsegmentDiscreteMappingSuffix}); + options->segment_id = selected_segment; options->callback = base::BindOnce(&ExperimentalGroupRecorder::OnGetSegment, weak_ptr_factory_.GetWeakPtr()); options->ignore_db_scores = false; @@ -37,6 +38,8 @@ void ExperimentalGroupRecorder::OnGetSegment( std::unique_ptr<SegmentResultProvider::SegmentResult> result) { + const std::string trial_name = stats::SegmentationKeyToSubsegmentTrialName( + segmentation_key_, segment_id_); int rank = 0; if (result && result->rank) { rank = *result->rank; @@ -45,7 +48,7 @@ // Can be nullptr in tests. if (field_trial_register_) { field_trial_register_->RegisterSubsegmentFieldTrialIfNeeded( - subsegment_trial_name_, segment_id_, rank); + trial_name, segment_id_, rank); } }
diff --git a/components/segmentation_platform/internal/selection/experimental_group_recorder.h b/components/segmentation_platform/internal/selection/experimental_group_recorder.h index e77ed09..f6c0f4d1 100644 --- a/components/segmentation_platform/internal/selection/experimental_group_recorder.h +++ b/components/segmentation_platform/internal/selection/experimental_group_recorder.h
@@ -14,7 +14,6 @@ namespace segmentation_platform { -struct Config; class FieldTrialRegister; // Records experimental sub groups for the given optimization target. @@ -25,8 +24,8 @@ // recording is complete, can be used only once. ExperimentalGroupRecorder(SegmentResultProvider* result_provider, FieldTrialRegister* field_trial_register, - const Config& config, - proto::SegmentId segment_id); + const std::string& segmentation_key, + proto::SegmentId selected_segment); ~ExperimentalGroupRecorder(); ExperimentalGroupRecorder(ExperimentalGroupRecorder&) = delete; @@ -37,7 +36,7 @@ std::unique_ptr<SegmentResultProvider::SegmentResult> result); const raw_ptr<FieldTrialRegister> field_trial_register_; - const std::string subsegment_trial_name_; + const std::string segmentation_key_; const proto::SegmentId segment_id_; base::WeakPtrFactory<ExperimentalGroupRecorder> weak_ptr_factory_{this};
diff --git a/components/segmentation_platform/internal/selection/segment_selector_impl.cc b/components/segmentation_platform/internal/selection/segment_selector_impl.cc index 019d414..ccbd8097 100644 --- a/components/segmentation_platform/internal/selection/segment_selector_impl.cc +++ b/components/segmentation_platform/internal/selection/segment_selector_impl.cc
@@ -6,14 +6,17 @@ #include "base/containers/contains.h" #include "base/containers/flat_map.h" +#include "base/containers/flat_set.h" #include "base/logging.h" #include "base/strings/strcat.h" #include "base/threading/thread_task_runner_handle.h" #include "base/time/clock.h" #include "base/time/time.h" +#include "components/segmentation_platform/internal/constants.h" #include "components/segmentation_platform/internal/database/segment_info_database.h" #include "components/segmentation_platform/internal/database/signal_storage_config.h" #include "components/segmentation_platform/internal/metadata/metadata_utils.h" +#include "components/segmentation_platform/internal/metric_filter_utils.h" #include "components/segmentation_platform/internal/platform_options.h" #include "components/segmentation_platform/internal/proto/model_prediction.pb.h" #include "components/segmentation_platform/internal/selection/experimental_group_recorder.h" @@ -22,6 +25,7 @@ #include "components/segmentation_platform/internal/stats.h" #include "components/segmentation_platform/public/config.h" #include "components/segmentation_platform/public/field_trial_register.h" +#include "components/segmentation_platform/public/model_provider.h" #include "components/segmentation_platform/public/proto/model_metadata.pb.h" #include "components/segmentation_platform/public/segment_selection_result.h" @@ -104,7 +108,8 @@ // Read selected segment from prefs. const auto& selected_segment = result_prefs_->ReadSegmentationResultFromPref(config_->segmentation_key); - const std::string& trial_name = config_->GetSegmentationFilterName(); + std::string trial_name = + stats::SegmentationKeyToTrialName(config_->segmentation_key); std::string group_name; if (selected_segment.has_value()) { selected_segment_last_session_.segment = selected_segment->segment_id; @@ -113,7 +118,8 @@ config_->segmentation_key, stats::SegmentationSelectionFailureReason::kSelectionAvailableInPrefs); - group_name = config_->GetSegmentUmaName(selected_segment->segment_id); + group_name = stats::OptimizationTargetToSegmentGroupName( + selected_segment->segment_id); } else { stats::RecordSegmentSelectionFailure( config_->segmentation_key, stats::SegmentationSelectionFailureReason:: @@ -143,11 +149,11 @@ // TODO(ssid): Store the scores in prefs so that this can be recorded earlier // in startup. if (selected_segment_last_session_.is_ready) { - for (const auto& segment_id : config_->segments) { + for (const SegmentId segment_id : config_->segment_ids) { experimental_group_recorder_.emplace_back( std::make_unique<ExperimentalGroupRecorder>( - segment_result_provider_.get(), field_trial_register_, *config_, - segment_id.first)); + segment_result_provider_.get(), field_trial_register_, + config_->segmentation_key, segment_id)); } } } @@ -175,7 +181,7 @@ DCHECK(segment_result_provider_); // If the |segment_id| is not in config, then skip any updates early. - if (!base::Contains(config_->segments, segment_id)) + if (!base::Contains(config_->segment_ids, segment_id)) return; if (!IsPreviousSelectionInvalid()) @@ -221,18 +227,18 @@ std::unique_ptr<SegmentRanks> ranks, scoped_refptr<InputContext> input_context, SegmentSelectionCallback callback) { - for (const auto& needed_segment : config_->segments) { - if (ranks->count(needed_segment.first) == 0) { + for (SegmentId needed_segment : config_->segment_ids) { + if (ranks->count(needed_segment) == 0) { auto options = std::make_unique<SegmentResultProvider::GetResultOptions>(); - options->segment_id = needed_segment.first; + options->segment_id = needed_segment; options->segmentation_key = config_->segmentation_key; options->ignore_db_scores = config_->on_demand_execution; options->input_context = input_context; - options->callback = base::BindOnce( - &SegmentSelectorImpl::OnGetResultForSegmentSelection, - weak_ptr_factory_.GetWeakPtr(), std::move(ranks), input_context, - std::move(callback), needed_segment.first); + options->callback = + base::BindOnce(&SegmentSelectorImpl::OnGetResultForSegmentSelection, + weak_ptr_factory_.GetWeakPtr(), std::move(ranks), + input_context, std::move(callback), needed_segment); segment_result_provider_->GetSegmentResult(std::move(options)); return;
diff --git a/components/segmentation_platform/internal/selection/segment_selector_unittest.cc b/components/segmentation_platform/internal/selection/segment_selector_unittest.cc index a44bad0..3ad9bea1 100644 --- a/components/segmentation_platform/internal/selection/segment_selector_unittest.cc +++ b/components/segmentation_platform/internal/selection/segment_selector_unittest.cc
@@ -14,8 +14,8 @@ #include "components/segmentation_platform/internal/execution/default_model_manager.h" #include "components/segmentation_platform/internal/execution/mock_model_provider.h" #include "components/segmentation_platform/internal/metadata/metadata_utils.h" +#include "components/segmentation_platform/internal/metric_filter_utils.h" #include "components/segmentation_platform/internal/selection/segmentation_result_prefs.h" -#include "components/segmentation_platform/internal/stats.h" #include "components/segmentation_platform/public/config.h" #include "components/segmentation_platform/public/field_trial_register.h" #include "testing/gmock/include/gmock/gmock.h" @@ -33,13 +33,6 @@ namespace { -#define SEGMENT_ID_ENTRY(segment) \ - { \ - segment, Config::SegmentMetadata { \ - stats::OptimizationTargetToHistogramVariant(segment) \ - } \ - } - class MockFieldTrialRegister : public FieldTrialRegister { public: MOCK_METHOD2(RegisterFieldTrial, @@ -55,12 +48,10 @@ Config CreateTestConfig() { Config config; config.segmentation_key = "test_key"; - config.segmentation_uma_name = "TestKey"; config.segment_selection_ttl = base::Days(28); config.unknown_selection_ttl = base::Days(14); - config.segments = { - SEGMENT_ID_ENTRY(SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_NEW_TAB), - SEGMENT_ID_ENTRY(SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_SHARE)}; + config.segment_ids = {SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_NEW_TAB, + SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_SHARE}; return config; } @@ -98,11 +89,8 @@ void SetUpWithConfig(const Config& config) { clock_.SetNow(base::Time::Now()); config_ = config; - std::vector<proto::SegmentId> all_segments; - for (auto it : config.segments) - all_segments.push_back(it.first); - default_manager_ = - std::make_unique<DefaultModelManager>(&provider_factory_, all_segments); + default_manager_ = std::make_unique<DefaultModelManager>( + &provider_factory_, config_.segment_ids); segment_database_ = std::make_unique<test::TestSegmentInfoDatabase>(); auto prefs_moved = std::make_unique<TestSegmentationResultPrefs>(); prefs_ = prefs_moved.get(); @@ -332,8 +320,8 @@ TEST_F(SegmentSelectorTest, UnknownSegmentTtlExpiryForBooleanModel) { Config config = CreateTestConfig(); - config.segments = {SEGMENT_ID_ENTRY( - SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_CHROME_START_ANDROID)}; + config.segment_ids = { + SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_CHROME_START_ANDROID}; SetUpWithConfig(config); SegmentId segment_id = @@ -477,7 +465,7 @@ // Create config with Feed segment. Config config = CreateTestConfig(); - config.segments.insert(SEGMENT_ID_ENTRY(kSubsegmentEnabledTarget)); + config.segment_ids.push_back(kSubsegmentEnabledTarget); // Previous selection result is not available at this time, so it should // record unselected. EXPECT_CALL(field_trial_register_, @@ -524,37 +512,30 @@ &config_, &field_trial_register_, &clock_, PlatformOptions::CreateDefault(), default_manager_.get()); - // When segment result is missing, unknown subsegment is recorded, otherwise - // record metrics based on the subsegment mapping. - base::RunLoop wait_for_subsegment; - std::vector<std::tuple<base::StringPiece, SegmentId, int>> actual_calls; - int call_count = 0; + // When segment result is missing, unknown subsegment is recorded. + EXPECT_CALL( + field_trial_register_, + RegisterSubsegmentFieldTrialIfNeeded( + base::StringPiece("Segmentation_TestKey_Share"), segment_id0, 0)); + EXPECT_CALL( + field_trial_register_, + RegisterSubsegmentFieldTrialIfNeeded( + base::StringPiece("Segmentation_TestKey_NewTab"), + proto::SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_NEW_TAB, 0)); + // The new selector will record subsegment metric groups based on the mapping. + base::RunLoop wait_for_subsegment; EXPECT_CALL(field_trial_register_, - RegisterSubsegmentFieldTrialIfNeeded(_, _, _)) - .Times(3) - .WillRepeatedly( - Invoke([&wait_for_subsegment, &actual_calls, &call_count]( - base::StringPiece trial, SegmentId id, int rank) { - actual_calls.emplace_back(trial, id, rank); - call_count++; - if (call_count == 3) - wait_for_subsegment.QuitClosure().Run(); + RegisterSubsegmentFieldTrialIfNeeded( + base::StringPiece("Segmentation_TestKey_FeedUserSegment"), + kSubsegmentEnabledTarget, 3)) + .WillOnce( + Invoke([&wait_for_subsegment](base::StringPiece, SegmentId, int) { + wait_for_subsegment.QuitClosure().Run(); })); segment_selector_->OnPlatformInitialized(nullptr); wait_for_subsegment.Run(); - EXPECT_THAT( - actual_calls, - testing::UnorderedElementsAre( - std::make_tuple(base::StringPiece("Segmentation_TestKey_Share"), - segment_id0, 0), - std::make_tuple( - base::StringPiece("Segmentation_TestKey_NewTab"), - proto::SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_NEW_TAB, 0), - std::make_tuple( - base::StringPiece("Segmentation_TestKey_FeedUserSegment"), - kSubsegmentEnabledTarget, 3))); } } // namespace segmentation_platform
diff --git a/components/segmentation_platform/internal/service_proxy_impl.cc b/components/segmentation_platform/internal/service_proxy_impl.cc index 551d922..10f6e23 100644 --- a/components/segmentation_platform/internal/service_proxy_impl.cc +++ b/components/segmentation_platform/internal/service_proxy_impl.cc
@@ -180,12 +180,12 @@ } } result.emplace_back(config->segmentation_key, selected); - for (const auto& segment_id : config->segments) { - if (!segment_ids.contains(segment_id.first)) + for (const auto& segment_id : config->segment_ids) { + if (!segment_ids.contains(segment_id)) continue; - const auto& info = segment_ids[segment_id.first]; + const auto& info = segment_ids[segment_id]; result.back().segment_status.emplace_back( - segment_id.first, SegmentMetadataToString(info), + segment_id, SegmentMetadataToString(info), PredictionResultToString(info), signal_storage_config_ ? signal_storage_config_->MeetsSignalCollectionRequirement(
diff --git a/components/segmentation_platform/internal/service_proxy_impl_unittest.cc b/components/segmentation_platform/internal/service_proxy_impl_unittest.cc index d4cd3c9..a2acb02 100644 --- a/components/segmentation_platform/internal/service_proxy_impl_unittest.cc +++ b/components/segmentation_platform/internal/service_proxy_impl_unittest.cc
@@ -43,7 +43,7 @@ info.set_segment_id(segment_id); db_entries->insert( std::make_pair(base::NumberToString(static_cast<int>(segment_id)), info)); - config->segments.insert({segment_id, {"UmaName"}}); + config->segment_ids.emplace_back(segment_id); return info; }
diff --git a/components/segmentation_platform/public/config.cc b/components/segmentation_platform/public/config.cc index 54bb957..4bf4403 100644 --- a/components/segmentation_platform/public/config.cc +++ b/components/segmentation_platform/public/config.cc
@@ -4,14 +4,8 @@ #include "components/segmentation_platform/public/config.h" -#include "base/strings/strcat.h" - namespace segmentation_platform { -bool Config::SegmentMetadata::operator==(const SegmentMetadata& other) const { - return other.uma_name == uma_name; -} - Config::Config() = default; Config::~Config() = default; @@ -20,17 +14,4 @@ Config& Config::operator=(const Config& other) = default; -std::string Config::GetSegmentationFilterName() const { - return base::StrCat({"Segmentation_", segmentation_uma_name}); -} - -std::string Config::GetSegmentUmaName(proto::SegmentId segment) const { - std::string name = "Other"; - auto it = segments.find(segment); - if (it == segments.end()) { - return "Other"; - } - return it->second.uma_name; -} - } // namespace segmentation_platform
diff --git a/components/segmentation_platform/public/config.h b/components/segmentation_platform/public/config.h index d3030bd2..ee2564b 100644 --- a/components/segmentation_platform/public/config.h +++ b/components/segmentation_platform/public/config.h
@@ -6,7 +6,6 @@ #define COMPONENTS_SEGMENTATION_PLATFORM_PUBLIC_CONFIG_H_ #include <string> -#include <unordered_map> #include "base/time/time.h" #include "components/segmentation_platform/public/proto/segmentation_platform.pb.h" @@ -62,9 +61,6 @@ // discrete mapping and writing results to prefs. std::string segmentation_key; - // The name used for the segmentation key in UMA filters. - std::string segmentation_uma_name; - // The trigger event type that triggers segment selection. If trigger is // non-none, |on_demand_execution| must be true. TriggerType trigger = TriggerType::kNone; @@ -80,26 +76,13 @@ // as output option after having served other valid segments. base::TimeDelta unknown_selection_ttl; - // List of segments needed to make a selection. - struct SegmentMetadata { - // The name used for this segment in UMA filters. - std::string uma_name; - - bool operator==(const SegmentMetadata& other) const; - }; - std::unordered_map<proto::SegmentId, SegmentMetadata> segments; + // List of segment ids that the current config requires to be available. + std::vector<proto::SegmentId> segment_ids; // The selection only supports returning results from on-demand model // executions instead of returning result from previous sessions. The // selection TTLs are ignored in this config. bool on_demand_execution = false; - - // Returns the filter name that will be shown in the metrics for this - // segmentation config. - std::string GetSegmentationFilterName() const; - - // Returns the segment name for the `segment` used by the metrics. - std::string GetSegmentUmaName(proto::SegmentId segment) const; }; } // namespace segmentation_platform
diff --git a/components/sync/engine/events/commit_request_event.cc b/components/sync/engine/events/commit_request_event.cc index ac81c0fd..2b14db2d 100644 --- a/components/sync/engine/events/commit_request_event.cc +++ b/components/sync/engine/events/commit_request_event.cc
@@ -47,7 +47,9 @@ std::unique_ptr<base::DictionaryValue> CommitRequestEvent::GetProtoMessage( bool include_specifics) const { - return ClientToServerMessageToValue(request_, include_specifics); + return ClientToServerMessageToValue( + request_, {.include_specifics = include_specifics, + .include_full_get_update_triggers = false}); } } // namespace syncer
diff --git a/components/sync/engine/events/commit_response_event.cc b/components/sync/engine/events/commit_response_event.cc index 4084214c..6543ea98 100644 --- a/components/sync/engine/events/commit_response_event.cc +++ b/components/sync/engine/events/commit_response_event.cc
@@ -34,7 +34,9 @@ std::unique_ptr<base::DictionaryValue> CommitResponseEvent::GetProtoMessage( bool include_specifics) const { - return ClientToServerResponseToValue(response_, include_specifics); + return ClientToServerResponseToValue( + response_, {.include_specifics = include_specifics, + .include_full_get_update_triggers = false}); } } // namespace syncer
diff --git a/components/sync/engine/events/configure_get_updates_request_event.cc b/components/sync/engine/events/configure_get_updates_request_event.cc index 501f6ca..8ab52f7 100644 --- a/components/sync/engine/events/configure_get_updates_request_event.cc +++ b/components/sync/engine/events/configure_get_updates_request_event.cc
@@ -37,7 +37,9 @@ std::unique_ptr<base::DictionaryValue> ConfigureGetUpdatesRequestEvent::GetProtoMessage(bool include_specifics) const { - return ClientToServerMessageToValue(request_, include_specifics); + return ClientToServerMessageToValue( + request_, {.include_specifics = include_specifics, + .include_full_get_update_triggers = false}); } } // namespace syncer
diff --git a/components/sync/engine/events/get_updates_response_event.cc b/components/sync/engine/events/get_updates_response_event.cc index 8729403..3498700 100644 --- a/components/sync/engine/events/get_updates_response_event.cc +++ b/components/sync/engine/events/get_updates_response_event.cc
@@ -63,7 +63,9 @@ std::unique_ptr<base::DictionaryValue> GetUpdatesResponseEvent::GetProtoMessage( bool include_specifics) const { - return ClientToServerResponseToValue(response_, include_specifics); + return ClientToServerResponseToValue( + response_, {.include_specifics = include_specifics, + .include_full_get_update_triggers = false}); } } // namespace syncer
diff --git a/components/sync/engine/events/normal_get_updates_request_event.cc b/components/sync/engine/events/normal_get_updates_request_event.cc index f456fd81d..0f75814b 100644 --- a/components/sync/engine/events/normal_get_updates_request_event.cc +++ b/components/sync/engine/events/normal_get_updates_request_event.cc
@@ -88,7 +88,9 @@ std::unique_ptr<base::DictionaryValue> NormalGetUpdatesRequestEvent::GetProtoMessage(bool include_specifics) const { - return ClientToServerMessageToValue(request_, include_specifics); + return ClientToServerMessageToValue( + request_, {.include_specifics = include_specifics, + .include_full_get_update_triggers = false}); } } // namespace syncer
diff --git a/components/sync/engine/events/poll_get_updates_request_event.cc b/components/sync/engine/events/poll_get_updates_request_event.cc index fe07a6bf..68df8ee 100644 --- a/components/sync/engine/events/poll_get_updates_request_event.cc +++ b/components/sync/engine/events/poll_get_updates_request_event.cc
@@ -33,7 +33,9 @@ std::unique_ptr<base::DictionaryValue> PollGetUpdatesRequestEvent::GetProtoMessage(bool include_specifics) const { - return ClientToServerMessageToValue(request_, include_specifics); + return ClientToServerMessageToValue( + request_, {.include_specifics = include_specifics, + .include_full_get_update_triggers = false}); } } // namespace syncer
diff --git a/components/sync/engine/traffic_logger.cc b/components/sync/engine/traffic_logger.cc index fbd3c92..a11ae1b3 100644 --- a/components/sync/engine/traffic_logger.cc +++ b/components/sync/engine/traffic_logger.cc
@@ -17,12 +17,13 @@ namespace { template <class T> void LogData(const T& data, - std::unique_ptr<base::DictionaryValue> ( - *to_dictionary_value)(const T&, bool), + std::unique_ptr<base::DictionaryValue> (*to_dictionary_value)( + const T&, + const ProtoValueConversionOptions& options), const std::string& description) { if (DCHECK_IS_ON() && VLOG_IS_ON(1)) { std::unique_ptr<base::DictionaryValue> value = - (*to_dictionary_value)(data, true /* include_specifics */); + (*to_dictionary_value)(data, /*options=*/{}); std::string message; base::JSONWriter::WriteWithOptions( *value, base::JSONWriter::OPTIONS_PRETTY_PRINT, &message);
diff --git a/components/sync/protocol/proto_value_conversions.cc b/components/sync/protocol/proto_value_conversions.cc index 4333003..25624d3bc 100644 --- a/components/sync/protocol/proto_value_conversions.cc +++ b/components/sync/protocol/proto_value_conversions.cc
@@ -21,6 +21,7 @@ #include "components/sync/protocol/autofill_offer_specifics.pb.h" #include "components/sync/protocol/autofill_specifics.pb.h" #include "components/sync/protocol/bookmark_specifics.pb.h" +#include "components/sync/protocol/data_type_progress_marker.pb.h" #include "components/sync/protocol/dictionary_specifics.pb.h" #include "components/sync/protocol/entity_specifics.pb.h" #include "components/sync/protocol/extension_setting_specifics.pb.h" @@ -126,9 +127,10 @@ // class ToValueVisitor { public: - explicit ToValueVisitor(bool include_specifics = true, + explicit ToValueVisitor(const ProtoValueConversionOptions& options = + ProtoValueConversionOptions(), base::DictionaryValue* value = nullptr) - : value_(value), include_specifics_(include_specifics) {} + : options_(options), value_(value) {} template <class P> void VisitBytes(const P& parent_proto, @@ -185,11 +187,41 @@ void Visit(const P& parent_proto, const char* field_name, const sync_pb::EntitySpecifics& field) { - if (include_specifics_) { + if (options_.include_specifics) { VisitImpl(parent_proto, field_name, field); } } + // GetUpdateTriggers. + std::unique_ptr<base::DictionaryValue> ToValue( + const sync_pb::GetUpdateTriggers& proto) const { + std::unique_ptr<base::DictionaryValue> value = ToValueImpl(proto); + if (!options_.include_full_get_update_triggers) { + if (!proto.client_dropped_hints()) { + value->RemoveKey("client_dropped_hints"); + } + if (!proto.invalidations_out_of_sync()) { + value->RemoveKey("invalidations_out_of_sync"); + } + if (proto.local_modification_nudges() == 0) { + value->RemoveKey("local_modification_nudges"); + } + if (proto.datatype_refresh_nudges() == 0) { + value->RemoveKey("datatype_refresh_nudges"); + } + if (!proto.server_dropped_hints()) { + value->RemoveKey("server_dropped_hints"); + } + if (!proto.initial_sync_in_progress()) { + value->RemoveKey("initial_sync_in_progress"); + } + if (!proto.sync_for_resolve_conflict_in_progress()) { + value->RemoveKey("sync_for_resolve_conflict_in_progress"); + } + } + return value; + } + // AutofillWalletSpecifics std::unique_ptr<base::DictionaryValue> ToValue( const sync_pb::AutofillWalletSpecifics& proto) const { @@ -221,7 +253,7 @@ template <class P> std::unique_ptr<base::DictionaryValue> ToValueImpl(const P& proto) const { auto value = std::make_unique<base::DictionaryValue>(); - ToValueVisitor visitor(include_specifics_, value.get()); + ToValueVisitor visitor(options_, value.get()); VisitProtoFields(visitor, proto); return value; } @@ -270,8 +302,8 @@ value_->Set(field_name, ToValue(field)); } + const ProtoValueConversionOptions options_; raw_ptr<base::DictionaryValue> value_; - bool include_specifics_; }; } // namespace @@ -282,10 +314,11 @@ return ToValueVisitor().ToValue(proto); \ } -#define IMPLEMENT_PROTO_TO_VALUE_INCLUDE_SPECIFICS(Proto) \ - std::unique_ptr<base::DictionaryValue> Proto##ToValue( \ - const sync_pb::Proto& proto, bool include_specifics) { \ - return ToValueVisitor(include_specifics).ToValue(proto); \ +#define IMPLEMENT_PROTO_TO_VALUE_WITH_OPTIONS(Proto) \ + std::unique_ptr<base::DictionaryValue> Proto##ToValue( \ + const sync_pb::Proto& proto, \ + const ProtoValueConversionOptions& options) { \ + return ToValueVisitor(options).ToValue(proto); \ } IMPLEMENT_PROTO_TO_VALUE(AppListSpecifics) @@ -351,11 +384,11 @@ IMPLEMENT_PROTO_TO_VALUE(WifiConfigurationSpecifics) IMPLEMENT_PROTO_TO_VALUE(WorkspaceDeskSpecifics) -IMPLEMENT_PROTO_TO_VALUE_INCLUDE_SPECIFICS(ClientToServerMessage) -IMPLEMENT_PROTO_TO_VALUE_INCLUDE_SPECIFICS(ClientToServerResponse) -IMPLEMENT_PROTO_TO_VALUE_INCLUDE_SPECIFICS(SyncEntity) +IMPLEMENT_PROTO_TO_VALUE_WITH_OPTIONS(ClientToServerMessage) +IMPLEMENT_PROTO_TO_VALUE_WITH_OPTIONS(ClientToServerResponse) +IMPLEMENT_PROTO_TO_VALUE_WITH_OPTIONS(SyncEntity) #undef IMPLEMENT_PROTO_TO_VALUE -#undef IMPLEMENT_PROTO_TO_VALUE_INCLUDE_SPECIFICS +#undef IMPLEMENT_PROTO_TO_VALUE_WITH_OPTIONS } // namespace syncer
diff --git a/components/sync/protocol/proto_value_conversions.h b/components/sync/protocol/proto_value_conversions.h index e83278a..992b567 100644 --- a/components/sync/protocol/proto_value_conversions.h +++ b/components/sync/protocol/proto_value_conversions.h
@@ -265,19 +265,27 @@ std::unique_ptr<base::DictionaryValue> WorkspaceDeskSpecificsToValue( const sync_pb::WorkspaceDeskSpecifics& workspace_desk_specifics); -// ToValue functions that allow omitting specifics. +// ToValue functions that allow omitting specifics and other fields. + +struct ProtoValueConversionOptions { + // Whether to include specifics. + bool include_specifics = true; + + // Whether to include default values which are set in GetUpdateTriggers. + bool include_full_get_update_triggers = true; +}; std::unique_ptr<base::DictionaryValue> ClientToServerMessageToValue( const sync_pb::ClientToServerMessage& proto, - bool include_specifics); + const ProtoValueConversionOptions& options); std::unique_ptr<base::DictionaryValue> ClientToServerResponseToValue( const sync_pb::ClientToServerResponse& proto, - bool include_specifics); + const ProtoValueConversionOptions& options); std::unique_ptr<base::DictionaryValue> SyncEntityToValue( const sync_pb::SyncEntity& entity, - bool include_specifics); + const ProtoValueConversionOptions& options); } // namespace syncer
diff --git a/components/sync/protocol/proto_value_conversions_unittest.cc b/components/sync/protocol/proto_value_conversions_unittest.cc index 6ab6c335..a43e653 100644 --- a/components/sync/protocol/proto_value_conversions_unittest.cc +++ b/components/sync/protocol/proto_value_conversions_unittest.cc
@@ -15,6 +15,7 @@ #include "components/sync/protocol/app_specifics.pb.h" #include "components/sync/protocol/autofill_specifics.pb.h" #include "components/sync/protocol/bookmark_specifics.pb.h" +#include "components/sync/protocol/data_type_progress_marker.pb.h" #include "components/sync/protocol/device_info_specifics.pb.h" #include "components/sync/protocol/encryption.pb.h" #include "components/sync/protocol/entity_specifics.pb.h" @@ -34,11 +35,14 @@ #include "components/sync/protocol/sync_entity.pb.h" #include "components/sync/protocol/theme_specifics.pb.h" #include "components/sync/protocol/typed_url_specifics.pb.h" +#include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" namespace syncer { namespace { +using testing::Not; + // Keep this file in sync with the .proto files in this directory. #define DEFINE_SPECIFICS_TO_VALUE_TEST(Key) \ @@ -197,7 +201,7 @@ entity.mutable_unique_position()->set_custom_compressed_v1("test"); std::unique_ptr<base::DictionaryValue> value = - SyncEntityToValue(entity, false); + SyncEntityToValue(entity, {.include_specifics = false}); std::string unique_position; EXPECT_TRUE(value->GetString("unique_position", &unique_position)); @@ -211,10 +215,10 @@ entity.mutable_specifics(); std::unique_ptr<base::DictionaryValue> value = - SyncEntityToValue(entity, true /* include_specifics */); + SyncEntityToValue(entity, {.include_specifics = true}); EXPECT_TRUE(value->GetDictionary("specifics", nullptr)); - value = SyncEntityToValue(entity, false /* include_specifics */); + value = SyncEntityToValue(entity, {.include_specifics = false}); EXPECT_FALSE(value->GetDictionary("specifics", nullptr)); } @@ -237,6 +241,33 @@ const base::DictionaryValue* specifics_dictionary = nullptr; return entry_dictionary.GetDictionary("specifics", &specifics_dictionary); } + +MATCHER(ValueHasNonEmptyGetUpdateTriggers, "") { + const base::DictionaryValue& value = arg; + + const base::ListValue* entities_list = nullptr; + if (!value.GetList("get_updates.from_progress_marker", &entities_list)) { + *result_listener << "no from_progress_marker list"; + return false; + } + + const base::Value& entry_dictionary_value = entities_list->GetList().front(); + if (!entry_dictionary_value.is_dict()) { + *result_listener << "from_progress_marker does not contain a dictionary"; + return false; + } + + const base::DictionaryValue& entry_dictionary = + base::Value::AsDictionaryValue(entry_dictionary_value); + const base::DictionaryValue* get_update_triggers_dictionary = nullptr; + if (!entry_dictionary.GetDictionary("get_update_triggers", + &get_update_triggers_dictionary)) { + *result_listener << "no get_update_triggers dictionary"; + return false; + } + + return !get_update_triggers_dictionary->GetDict().empty(); +} } // namespace // Create a ClientToServerMessage with an EntitySpecifics. Converting it to @@ -248,18 +279,46 @@ entity->mutable_specifics(); std::unique_ptr<base::DictionaryValue> value_with_specifics( - ClientToServerMessageToValue(message, true /* include_specifics */)); + ClientToServerMessageToValue(message, {.include_specifics = true})); EXPECT_FALSE(value_with_specifics->DictEmpty()); EXPECT_TRUE( ValueHasSpecifics(*(value_with_specifics.get()), "commit.entries")); std::unique_ptr<base::DictionaryValue> value_without_specifics( - ClientToServerMessageToValue(message, false /* include_specifics */)); + ClientToServerMessageToValue(message, {.include_specifics = false})); EXPECT_FALSE(value_without_specifics->DictEmpty()); EXPECT_FALSE( ValueHasSpecifics(*(value_without_specifics.get()), "commit.entries")); } +TEST(ProtoValueConversionsTest, ClientToServerMessageToValueGUTriggers) { + sync_pb::ClientToServerMessage message; + sync_pb::GetUpdateTriggers* get_update_triggers = + message.mutable_get_updates() + ->add_from_progress_marker() + ->mutable_get_update_triggers(); + get_update_triggers->set_client_dropped_hints(false); + get_update_triggers->set_server_dropped_hints(false); + get_update_triggers->set_datatype_refresh_nudges(0); + get_update_triggers->set_local_modification_nudges(0); + get_update_triggers->set_initial_sync_in_progress(false); + get_update_triggers->set_sync_for_resolve_conflict_in_progress(false); + + std::unique_ptr<base::DictionaryValue> value_with_full_gu_triggers( + ClientToServerMessageToValue(message, + {.include_full_get_update_triggers = true})); + EXPECT_FALSE(value_with_full_gu_triggers->DictEmpty()); + EXPECT_THAT(*value_with_full_gu_triggers, + ValueHasNonEmptyGetUpdateTriggers()); + + std::unique_ptr<base::DictionaryValue> value_without_full_gu_triggers( + ClientToServerMessageToValue( + message, {.include_full_get_update_triggers = false})); + EXPECT_FALSE(value_without_full_gu_triggers->DictEmpty()); + EXPECT_THAT(*value_without_full_gu_triggers, + Not(ValueHasNonEmptyGetUpdateTriggers())); +} + // Create a ClientToServerResponse with an EntitySpecifics. Converting it to // a value should respect the |include_specifics| flag. TEST(ProtoValueConversionsTest, ClientToServerResponseToValue) { @@ -269,13 +328,13 @@ entity->mutable_specifics(); std::unique_ptr<base::DictionaryValue> value_with_specifics( - ClientToServerResponseToValue(message, true /* include_specifics */)); + ClientToServerResponseToValue(message, {.include_specifics = true})); EXPECT_FALSE(value_with_specifics->DictEmpty()); EXPECT_TRUE( ValueHasSpecifics(*(value_with_specifics.get()), "get_updates.entries")); std::unique_ptr<base::DictionaryValue> value_without_specifics( - ClientToServerResponseToValue(message, false /* include_specifics */)); + ClientToServerResponseToValue(message, {.include_specifics = false})); EXPECT_FALSE(value_without_specifics->DictEmpty()); EXPECT_FALSE(ValueHasSpecifics(*(value_without_specifics.get()), "get_updates.entries"));
diff --git a/components/sync/test/fake_server/fake_server.cc b/components/sync/test/fake_server/fake_server.cc index a37db03..5591047 100644 --- a/components/sync/test/fake_server/fake_server.cc +++ b/components/sync/test/fake_server/fake_server.cc
@@ -219,16 +219,18 @@ LogForTestFailure(FROM_HERE, "REQUEST", PrettyPrintValue(syncer::ClientToServerMessageToValue( - message, /*include_specifics=*/true))); + message, {.include_specifics = true, + .include_full_get_update_triggers = false}))); sync_pb::ClientToServerResponse response_proto; net::HttpStatusCode http_status_code = HandleParsedCommand(message, &response_proto); - LogForTestFailure(FROM_HERE, "RESPONSE", - PrettyPrintValue(syncer::ClientToServerResponseToValue( - response_proto, - /*include_specifics=*/true))); + LogForTestFailure( + FROM_HERE, "RESPONSE", + PrettyPrintValue(syncer::ClientToServerResponseToValue( + response_proto, {.include_specifics = true, + .include_full_get_update_triggers = false}))); *response = response_proto.SerializeAsString(); return http_status_code;
diff --git a/components/translate/translate_internals/translate_internals_handler.h b/components/translate/translate_internals/translate_internals_handler.h index e1cdc5da..114ecc5 100644 --- a/components/translate/translate_internals/translate_internals_handler.h +++ b/components/translate/translate_internals/translate_internals_handler.h
@@ -11,6 +11,7 @@ #include "base/callback.h" #include "base/callback_list.h" +#include "base/strings/string_piece.h" #include "components/translate/core/browser/translate_client.h" #include "components/translate/core/browser/translate_language_list.h" #include "components/translate/core/browser/translate_manager.h" @@ -47,12 +48,12 @@ // Registers to handle |message| from JavaScript with |callback|. using MessageCallback = base::RepeatingCallback<void(const base::Value::List&)>; - virtual void RegisterMessageCallback(const std::string& message, + virtual void RegisterMessageCallback(base::StringPiece message, MessageCallback callback) = 0; // Calls a Javascript function with the given name and arguments. virtual void CallJavascriptFunction( - const std::string& function_name, + base::StringPiece function_name, base::span<const base::ValueView> args) = 0; protected:
diff --git a/components/viz/common/quads/render_pass_io.cc b/components/viz/common/quads/render_pass_io.cc index 0438074..8cd18e09 100644 --- a/components/viz/common/quads/render_pass_io.cc +++ b/components/viz/common/quads/render_pass_io.cc
@@ -1829,22 +1829,27 @@ dict.FindDoubleKey("de_jelly_delta_y"); if (!quad_to_target_transform || !quad_layer_rect || - !visible_quad_layer_rect || !mask_filter_info || !are_contents_opaque || - !opacity || !blend_mode || !sorting_context_id || - !is_fast_rounded_corner || !de_jelly_delta_y) { + !visible_quad_layer_rect || !are_contents_opaque || !opacity || + !blend_mode || !sorting_context_id || !is_fast_rounded_corner || + !de_jelly_delta_y) { return false; } gfx::Transform t_quad_to_target_transform; gfx::Rect t_quad_layer_rect, t_visible_quad_layer_rect, t_clip_rect; - gfx::MaskFilterInfo t_mask_filter_info; if (!TransformFromList(*quad_to_target_transform, &t_quad_to_target_transform) || !RectFromDict(*quad_layer_rect, &t_quad_layer_rect) || !RectFromDict(*visible_quad_layer_rect, &t_visible_quad_layer_rect) || - !MaskFilterInfoFromDict(*mask_filter_info, &t_mask_filter_info) || (clip_rect && !RectFromDict(*clip_rect, &t_clip_rect))) { return false; } + + gfx::MaskFilterInfo t_mask_filter_info; + if (mask_filter_info && + !MaskFilterInfoFromDict(*mask_filter_info, &t_mask_filter_info)) { + return false; + } + absl::optional<gfx::Rect> clip_rect_opt; // Some older files still use the is_clipped field. If it's present, we'll // respect it, and ignore clip_rect if it's false.
diff --git a/content/app/content_main.cc b/content/app/content_main.cc index b54d534b..34cbedd 100644 --- a/content/app/content_main.cc +++ b/content/app/content_main.cc
@@ -21,6 +21,7 @@ #include "base/process/memory.h" #include "base/process/process.h" #include "base/run_loop.h" +#include "base/strings/string_number_conversions.h" #include "base/task/single_thread_task_executor.h" #include "base/task/thread_pool/thread_pool_instance.h" #include "base/threading/platform_thread.h" @@ -217,6 +218,30 @@ CHECK_EQ(MOJO_RESULT_OK, result); } +void InitTimeTicksAtUnixEpoch() { + const auto* command_line = base::CommandLine::ForCurrentProcess(); + if (!command_line->HasSwitch(switches::kTimeTicksAtUnixEpoch)) { + return; + } + + std::string time_ticks_at_unix_epoch_as_string = + command_line->GetSwitchValueASCII(switches::kTimeTicksAtUnixEpoch); + + int64_t time_ticks_at_unix_epoch_delta_micro; + if (!base::StringToInt64(time_ticks_at_unix_epoch_as_string, + &time_ticks_at_unix_epoch_delta_micro)) { + return; + } + + base::TimeDelta time_ticks_at_unix_epoch_delta = + base::Microseconds(time_ticks_at_unix_epoch_delta_micro); + + base::TimeTicks time_ticks_at_unix_epoch = + base::TimeTicks() + time_ticks_at_unix_epoch_delta; + + base::TimeTicks::SetSharedUnixEpoch(time_ticks_at_unix_epoch); +} + } // namespace ContentMainParams::ContentMainParams(ContentMainDelegate* delegate) @@ -300,6 +325,8 @@ SetProcessTitleFromCommandLine(argv); #endif // !BUILDFLAG(IS_ANDROID) + InitTimeTicksAtUnixEpoch(); + // On Android setlocale() is not supported, and we don't override the signal // handlers so we can get a stack trace when crashing. #if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_ANDROID)
diff --git a/content/browser/accessibility/accessibility_win_browsertest.cc b/content/browser/accessibility/accessibility_win_browsertest.cc index 3c71626..83ffeb4 100644 --- a/content/browser/accessibility/accessibility_win_browsertest.cc +++ b/content/browser/accessibility/accessibility_win_browsertest.cc
@@ -44,6 +44,7 @@ #include "content/public/common/url_constants.h" #include "content/public/test/accessibility_notification_waiter.h" #include "content/public/test/browser_test.h" +#include "content/public/test/browser_test_utils.h" #include "content/public/test/content_browser_test_utils.h" #include "content/shell/browser/shell.h" #include "content/test/content_browser_test_utils_internal.h" @@ -4270,7 +4271,7 @@ <html> <body> <img src="" alt="image" - onclick="document.querySelector('img').alt = 'image2';"> + onclick="document.querySelector('img').alt = 'clicked';"> </body> </html>)HTML"); @@ -4302,31 +4303,62 @@ LONG n_actions = 0; EXPECT_HRESULT_SUCCEEDED(image_action->nActions(&n_actions)); - EXPECT_EQ(1, n_actions); + EXPECT_EQ(2, n_actions); base::win::ScopedBstr action_name; EXPECT_HRESULT_SUCCEEDED(image_action->get_name(0, action_name.Receive())); EXPECT_EQ(L"click", std::wstring(action_name.Get(), action_name.Length())); action_name.Release(); - EXPECT_HRESULT_FAILED(image_action->get_name(1, action_name.Receive())); + EXPECT_HRESULT_SUCCEEDED(image_action->get_name(1, action_name.Receive())); + EXPECT_EQ(L"showContextMenu", + std::wstring(action_name.Get(), action_name.Length())); + action_name.Release(); + EXPECT_HRESULT_FAILED(image_action->get_name(2, action_name.Receive())); EXPECT_EQ(nullptr, action_name.Get()); + base::win::ScopedBstr localized_name; + EXPECT_HRESULT_SUCCEEDED( + image_action->get_localizedName(0, localized_name.Receive())); + EXPECT_EQ(L"click", + std::wstring(localized_name.Get(), localized_name.Length())); + localized_name.Release(); + EXPECT_HRESULT_SUCCEEDED( + image_action->get_localizedName(1, localized_name.Receive())); + EXPECT_EQ(L"showContextMenu", + std::wstring(localized_name.Get(), localized_name.Length())); + localized_name.Release(); + EXPECT_HRESULT_FAILED( + image_action->get_localizedName(2, localized_name.Receive())); + EXPECT_EQ(nullptr, localized_name.Get()); + base::win::ScopedVariant childid_self(CHILDID_SELF); base::win::ScopedBstr image_name; EXPECT_HRESULT_SUCCEEDED( image->get_accName(childid_self, image_name.Receive())); EXPECT_EQ(L"image", std::wstring(image_name.Get(), image_name.Length())); image_name.Release(); - // Cllicking the image will change its name. - EXPECT_HRESULT_SUCCEEDED(image_action->doAction(0)); + // The action for index 0 is the default one, "click" in this case. + // Clicking the image will change its name. AccessibilityNotificationWaiter waiter( shell()->web_contents(), ui::kAXModeComplete, ui::AXEventGenerator::Event::NAME_CHANGED); + EXPECT_HRESULT_SUCCEEDED(image_action->doAction(0)); ASSERT_TRUE(waiter.WaitForNotification()); EXPECT_HRESULT_SUCCEEDED( image->get_accName(childid_self, image_name.Receive())); - EXPECT_EQ(L"image2", std::wstring(image_name.Get(), image_name.Length())); - EXPECT_HRESULT_FAILED(image_action->doAction(1)); + EXPECT_EQ(L"clicked", std::wstring(image_name.Get(), image_name.Length())); + image_name.Release(); + // The action for index 1 is "showContextMenu". + // We use a ContextMenuInterceptor to intercept the event before + // RenderFrameHost receives. + auto context_menu_interceptor = std::make_unique<ContextMenuInterceptor>( + shell()->web_contents()->GetPrimaryMainFrame(), + ContextMenuInterceptor::ShowBehavior::kPreventShow); + EXPECT_HRESULT_SUCCEEDED(image_action->doAction(1)); + // If the context menu event did not happen, the test would time out here: + context_menu_interceptor->Wait(); + // There are no more actions, calls for indexes >=2 will fail. + EXPECT_HRESULT_FAILED(image_action->doAction(2)); } IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest, HasHWNDAfterNavigation) {
diff --git a/content/browser/accessibility/browser_accessibility_com_win.cc b/content/browser/accessibility/browser_accessibility_com_win.cc index c7d8943..9cadc49 100644 --- a/content/browser/accessibility/browser_accessibility_com_win.cc +++ b/content/browser/accessibility/browser_accessibility_com_win.cc
@@ -684,16 +684,7 @@ if (!n_actions) return E_INVALIDARG; - // |IsHyperlink| is required for |IAccessibleHyperlink::anchor/anchorTarget| - // to work properly because the |IAccessibleHyperlink| interface inherits from - // |IAccessibleAction|. - if (IsHyperlink() || - owner()->HasIntAttribute(ax::mojom::IntAttribute::kDefaultActionVerb)) { - *n_actions = 1; - } else { - *n_actions = 0; - } - + *n_actions = static_cast<LONG>(owner()->GetSupportedActions().size()); return S_OK; } @@ -703,12 +694,19 @@ if (!owner()) return E_FAIL; - if (!owner()->HasIntAttribute(ax::mojom::IntAttribute::kDefaultActionVerb) || - action_index != 0) { + const std::vector<ax::mojom::Action> actions = owner()->GetSupportedActions(); + if (action_index < 0 || action_index >= static_cast<LONG>(actions.size())) return E_INVALIDARG; - } - Manager()->DoDefaultAction(*owner()); + if (action_index == 0 && owner()->HasDefaultActionVerb()) { + // If there is a default action, it will always be at index 0. + Manager()->DoDefaultAction(*owner()); + return S_OK; + } + ui::AXActionData data; + data.action = actions[action_index]; + owner()->AccessibilityPerformAction(data); + return S_OK; } @@ -726,7 +724,38 @@ LONG* n_bindings) { WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_KEY_BINDING); AddAccessibilityModeFlags(kScreenReaderAndHTMLAccessibilityModes); - return E_NOTIMPL; + if (!owner()) + return E_FAIL; + + if (!key_bindings || !n_bindings) + return E_INVALIDARG; + + const std::vector<ax::mojom::Action> actions = owner()->GetSupportedActions(); + if (action_index < 0 || action_index >= static_cast<LONG>(actions.size())) { + *key_bindings = nullptr; + return E_INVALIDARG; + } + n_bindings = 0; + int action; + std::u16string key_binding_string; + if (action_index == 0 && + owner()->GetIntAttribute(ax::mojom::IntAttribute::kDefaultActionVerb, + &action)) { + if (owner()->GetString16Attribute(ax::mojom::StringAttribute::kAccessKey, + &key_binding_string)) + *n_bindings = 1; + } + + if (n_bindings == 0) { + *key_bindings = nullptr; + return S_FALSE; + } + + *key_bindings = static_cast<BSTR*>(CoTaskMemAlloc(sizeof(BSTR))); + (*key_bindings)[0] = SysAllocString(base::as_wcstr(key_binding_string)); + + DCHECK(key_bindings); + return S_OK; } IFACEMETHODIMP BrowserAccessibilityComWin::get_name(LONG action_index, @@ -739,22 +768,29 @@ if (!name) return E_INVALIDARG; - int action; - if (!owner()->GetIntAttribute(ax::mojom::IntAttribute::kDefaultActionVerb, - &action) || - action_index != 0) { + const std::vector<ax::mojom::Action> actions = owner()->GetSupportedActions(); + if (action_index < 0 || action_index >= static_cast<LONG>(actions.size())) { *name = nullptr; return E_INVALIDARG; } - std::wstring action_verb = base::UTF8ToWide( - ui::ToString(static_cast<ax::mojom::DefaultActionVerb>(action))); - if (action_verb.empty() || action_verb == L"none") { + int action; + std::string action_verb; + if (action_index == 0 && + owner()->GetIntAttribute(ax::mojom::IntAttribute::kDefaultActionVerb, + &action)) { + action_verb = + ui::ToString(static_cast<ax::mojom::DefaultActionVerb>(action)); + } else { + action_verb = ui::ToString(actions[action_index]); + } + + if (action_verb.empty() || action_verb.compare("none") == 0) { *name = nullptr; return S_FALSE; } - *name = SysAllocString(action_verb.c_str()); + *name = SysAllocString(base::as_wcstr(base::UTF8ToUTF16(action_verb))); DCHECK(name); return S_OK; } @@ -770,22 +806,30 @@ if (!localized_name) return E_INVALIDARG; - int action; - if (!owner()->GetIntAttribute(ax::mojom::IntAttribute::kDefaultActionVerb, - &action) || - action_index != 0) { + const std::vector<ax::mojom::Action> actions = owner()->GetSupportedActions(); + if (action_index < 0 || action_index >= static_cast<LONG>(actions.size())) { *localized_name = nullptr; return E_INVALIDARG; } - std::wstring action_verb = base::UTF8ToWide( - ui::ToLocalizedString(static_cast<ax::mojom::DefaultActionVerb>(action))); + int action; + if (!owner()->GetIntAttribute(ax::mojom::IntAttribute::kDefaultActionVerb, + &action) || + action_index != 0) { + // There aren't localized names for actions except default ones, we fall + // back to returning the hard-coded, not localized name. + return get_name(action_index, localized_name); + } + + std::string action_verb = + ui::ToLocalizedString(static_cast<ax::mojom::DefaultActionVerb>(action)); if (action_verb.empty()) { *localized_name = nullptr; return S_FALSE; } - *localized_name = SysAllocString(action_verb.c_str()); + *localized_name = + SysAllocString(base::as_wcstr(base::UTF8ToUTF16(action_verb))); DCHECK(localized_name); return S_OK; }
diff --git a/content/browser/accessibility/browser_accessibility_manager.cc b/content/browser/accessibility/browser_accessibility_manager.cc index 0346e65..9556580 100644 --- a/content/browser/accessibility/browser_accessibility_manager.cc +++ b/content/browser/accessibility/browser_accessibility_manager.cc
@@ -624,8 +624,8 @@ event_target = RetargetForEvents( event_target, RetargetEventType::RetargetEventTypeGenerated); - DCHECK(event_target) << "No retargeted event target for " - << targeted_event.node_id; + if (!event_target) + continue; // Drop the event if RetargetForEvents() returns nullptr. if (!event_target->CanFireEvents()) continue; @@ -655,8 +655,8 @@ event_target = RetargetForEvents( event_target, RetargetEventType::RetargetEventTypeGenerated); - DCHECK(event_target) << "No retargeted event target for " - << targeted_event.node_id; + if (!event_target) + continue; // Drop the event if RetargetForEvents() returns nullptr. if (!event_target->CanFireEvents()) continue; @@ -675,8 +675,8 @@ ? RetargetEventType::RetargetEventTypeBlinkHover : RetargetEventType::RetargetEventTypeBlinkGeneral; BrowserAccessibility* retargeted = RetargetForEvents(event_target, type); - DCHECK(retargeted) << "No retargeted event target for " << event.id - << " with event type " << event.event_type; + if (!retargeted) + continue; // Drop the event if RetargetForEvents() returns nullptr. if (!retargeted->CanFireEvents()) continue;
diff --git a/content/browser/accessibility/browser_accessibility_win_unittest.cc b/content/browser/accessibility/browser_accessibility_win_unittest.cc index adc60e0..08ec07c 100644 --- a/content/browser/accessibility/browser_accessibility_win_unittest.cc +++ b/content/browser/accessibility/browser_accessibility_win_unittest.cc
@@ -2345,11 +2345,11 @@ hyperlink.Reset(); EXPECT_HRESULT_SUCCEEDED(root_accessible->GetCOM()->nActions(&n_actions)); - EXPECT_EQ(0, n_actions); + EXPECT_EQ(1, n_actions); EXPECT_HRESULT_SUCCEEDED(div_accessible->GetCOM()->nActions(&n_actions)); EXPECT_EQ(1, n_actions); EXPECT_HRESULT_SUCCEEDED(text_accessible->GetCOM()->nActions(&n_actions)); - EXPECT_EQ(0, n_actions); + EXPECT_EQ(1, n_actions); EXPECT_HRESULT_SUCCEEDED(link_accessible->GetCOM()->nActions(&n_actions)); EXPECT_EQ(1, n_actions);
diff --git a/content/browser/compute_pressure/pressure_service_impl.h b/content/browser/compute_pressure/pressure_service_impl.h index ca40e84..72c1494 100644 --- a/content/browser/compute_pressure/pressure_service_impl.h +++ b/content/browser/compute_pressure/pressure_service_impl.h
@@ -56,8 +56,6 @@ base::Time timestamp) override; private: - friend class content::DocumentUserData<PressureServiceImpl>; - PressureServiceImpl(RenderFrameHost* render_frame_host, base::TimeDelta visible_observer_rate_limit);
diff --git a/content/browser/preloading/prerender/prerender_browsertest.cc b/content/browser/preloading/prerender/prerender_browsertest.cc index aed209d..cfa3d2c 100644 --- a/content/browser/preloading/prerender/prerender_browsertest.cc +++ b/content/browser/preloading/prerender/prerender_browsertest.cc
@@ -2793,11 +2793,6 @@ ExpectFinalStatusForSpeculationRule(GetExpectedFinalStatus()); } -// TODO(https://crbug.com/1132746): Test canceling prerendering when its -// initiator is no longer interested in prerending this page. - -// TODO(https://crbug.com/1132746): Test prerendering for auth error, etc. - // Tests for feature restrictions in prerendered pages ========================= // Tests that window.open() in a prerendering page fails.
diff --git a/content/browser/renderer_host/direct_manipulation_win_browsertest.cc b/content/browser/renderer_host/direct_manipulation_win_browsertest.cc index 7294d66..2872143 100644 --- a/content/browser/renderer_host/direct_manipulation_win_browsertest.cc +++ b/content/browser/renderer_host/direct_manipulation_win_browsertest.cc
@@ -132,7 +132,7 @@ const ui::Event& event, const Continuation continuation) override { DCHECK(!last_event_); - last_event_ = ui::Event::Clone(event); + last_event_ = event.Clone(); return SendEvent(continuation, &event); }
diff --git a/content/browser/renderer_host/input/fling_browsertest.cc b/content/browser/renderer_host/input/fling_browsertest.cc index 5fcb019..e139ec5 100644 --- a/content/browser/renderer_host/input/fling_browsertest.cc +++ b/content/browser/renderer_host/input/fling_browsertest.cc
@@ -351,17 +351,12 @@ EXPECT_TRUE(GetWidgetHost()->GetView()->view_stopped_flinging_for_test()); } -// TODO(1269960): Fix flakiness on Linux. -#if BUILDFLAG(IS_LINUX) -#define MAYBE_FlingingStopsAfterNavigation DISABLED_FlingingStopsAfterNavigation -#else -#define MAYBE_FlingingStopsAfterNavigation FlingingStopsAfterNavigation -#endif +// TODO(crbug.com/1347271,crbug.com/269960): TODO: Re-enable this test. // Tests that flinging does not continue after navigating to a page that uses // the same renderer. IN_PROC_BROWSER_TEST_F(BrowserSideFlingBrowserTest, - MAYBE_FlingingStopsAfterNavigation) { + DISABLED_FlingingStopsAfterNavigation) { GURL first_url(embedded_test_server()->GetURL( "b.a.com", "/scrollable_page_with_iframe.html")); EXPECT_TRUE(NavigateToURL(shell(), first_url));
diff --git a/content/browser/renderer_host/media/media_stream_dispatcher_host.cc b/content/browser/renderer_host/media/media_stream_dispatcher_host.cc index 1b03628..ee13233 100644 --- a/content/browser/renderer_host/media/media_stream_dispatcher_host.cc +++ b/content/browser/renderer_host/media/media_stream_dispatcher_host.cc
@@ -596,6 +596,17 @@ media_stream_manager_->OnStreamStarted(label); } +void MediaStreamDispatcherHost::KeepDeviceAliveForTransfer( + const base::UnguessableToken& session_id, + const base::UnguessableToken& transfer_id, + KeepDeviceAliveForTransferCallback callback) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + + media_stream_manager_->KeepDeviceAliveForTransfer( + render_process_id_, render_frame_id_, requester_id_, session_id, + transfer_id, std::move(callback)); +} + #if !BUILDFLAG(IS_ANDROID) void MediaStreamDispatcherHost::FocusCapturedSurface(const std::string& label, bool focus) { @@ -657,6 +668,7 @@ void MediaStreamDispatcherHost::GetOpenDevice( int32_t page_request_id, const base::UnguessableToken& session_id, + const base::UnguessableToken& transfer_id, GetOpenDeviceCallback callback) { DCHECK_CURRENTLY_ON(BrowserThread::IO); @@ -680,12 +692,13 @@ render_frame_id_), base::BindOnce(&MediaStreamDispatcherHost::DoGetOpenDevice, weak_factory_.GetWeakPtr(), page_request_id, session_id, - std::move(callback))); + transfer_id, std::move(callback))); } void MediaStreamDispatcherHost::DoGetOpenDevice( int32_t page_request_id, const base::UnguessableToken& session_id, + const base::UnguessableToken& transfer_id, GetOpenDeviceCallback callback, MediaDeviceSaltAndOrigin salt_and_origin) { DCHECK_CURRENTLY_ON(BrowserThread::IO); @@ -697,12 +710,10 @@ return; } - // TODO(https://crbug.com/1288839): Replace created UnguessableToken with - // transfer_id passed to this function. media_stream_manager_->GetOpenDevice( - session_id, /*transfer_id=*/base::UnguessableToken::Create(), - render_process_id_, render_frame_id_, requester_id_, page_request_id, - std::move(salt_and_origin), std::move(callback), + session_id, transfer_id, render_process_id_, render_frame_id_, + requester_id_, page_request_id, std::move(salt_and_origin), + std::move(callback), base::BindRepeating(&MediaStreamDispatcherHost::OnDeviceStopped, weak_factory_.GetWeakPtr()), base::BindRepeating(&MediaStreamDispatcherHost::OnDeviceChanged,
diff --git a/content/browser/renderer_host/media/media_stream_dispatcher_host.h b/content/browser/renderer_host/media/media_stream_dispatcher_host.h index 7a767b5..8b9411c 100644 --- a/content/browser/renderer_host/media/media_stream_dispatcher_host.h +++ b/content/browser/renderer_host/media/media_stream_dispatcher_host.h
@@ -111,6 +111,10 @@ blink::mojom::MediaStreamType type, bool is_secure) override; void OnStreamStarted(const std::string& label) override; + void KeepDeviceAliveForTransfer( + const base::UnguessableToken& session_id, + const base::UnguessableToken& transfer_id, + KeepDeviceAliveForTransferCallback callback) override; #if !BUILDFLAG(IS_ANDROID) void FocusCapturedSurface(const std::string& label, bool focus) override; void Crop(const base::UnguessableToken& device_id, @@ -126,9 +130,11 @@ #endif void GetOpenDevice(int32_t page_request_id, const base::UnguessableToken& session_id, + const base::UnguessableToken& transfer_id, GetOpenDeviceCallback callback) override; void DoGetOpenDevice(int32_t page_request_id, const base::UnguessableToken& session_id, + const base::UnguessableToken& transfer_id, GetOpenDeviceCallback callback, MediaDeviceSaltAndOrigin salt_and_origin); void DoGenerateStreams(
diff --git a/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc b/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc index b822a33..dd451199 100644 --- a/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc +++ b/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc
@@ -23,6 +23,7 @@ #include "base/run_loop.h" #include "base/system/system_monitor.h" #include "base/task/single_thread_task_runner.h" +#include "base/test/bind.h" #include "base/test/gmock_move_support.h" #include "base/test/scoped_feature_list.h" #include "base/threading/thread_task_runner_handle.h" @@ -490,6 +491,10 @@ if (!optional_device.has_value()) return true; const blink::MediaStreamDevice& device = optional_device.value(); + if (device.type != blink::mojom::MediaStreamType::DEVICE_AUDIO_CAPTURE && + device.type != blink::mojom::MediaStreamType::DEVICE_VIDEO_CAPTURE) { + return true; + } bool found_match = false; media::AudioDeviceDescriptions::const_iterator audio_it = audio_device_descriptions_.begin(); @@ -513,8 +518,18 @@ void GetOpenDevice( int32_t request_id, const base::UnguessableToken& session_id, + const base::UnguessableToken& transfer_id, MediaStreamDispatcherHost::GetOpenDeviceCallback callback) { - host_->GetOpenDevice(request_id, session_id, std::move(callback)); + host_->GetOpenDevice(request_id, session_id, transfer_id, + std::move(callback)); + } + + void KeepDeviceAliveForTransfer( + const base::UnguessableToken& session_id, + const base::UnguessableToken& transfer_id, + MediaStreamDispatcherHost::KeepDeviceAliveForTransferCallback callback) { + host_->KeepDeviceAliveForTransfer(session_id, transfer_id, + std::move(callback)); } const absl::optional<blink::MediaStreamDevice>& audio_device( @@ -1242,6 +1257,7 @@ base::RunLoop loop; GetOpenDevice(/*request_id=*/0, /*session_id=*/base::UnguessableToken(), + /*transfer_id=*/base::UnguessableToken(), base::BindOnce([](blink::mojom::MediaStreamRequestResult result, blink::mojom::GetOpenDeviceResponsePtr ptr) { EXPECT_EQ( @@ -1252,6 +1268,57 @@ loop.Run(); } +TEST_F(MediaStreamDispatcherHostTest, GetOpenDeviceSucceeds) { + scoped_feature_list_.Reset(); + scoped_feature_list_ + .InitFromCommandLine(/*enable_features=*/ + "UserMediaCaptureOnFocus,GetDisplayMediaSet," + "GetDisplayMediaSetAutoSelectAllScreens," + "MediaStreamTrackTransfer", + /*disable_features=*/""); + base::RunLoop loop; + + // Generate stream. + SetupFakeUI(true); + blink::StreamControls controls(false, true); + controls.video.stream_type = + blink::mojom::MediaStreamType::DISPLAY_VIDEO_CAPTURE; + + blink::mojom::StreamDevicesSet expectation; + expectation.stream_devices.emplace_back(blink::mojom::StreamDevices::New( + absl::nullopt, blink::MediaStreamDevice())); + GenerateStreamAndWaitForResult(kPageRequestId, controls, expectation); + EXPECT_TRUE(video_device(/*stream_index=*/0u).has_value()); + blink::MediaStreamDevice current_video_device = + video_device(/*stream_index=*/0u).value(); + const base::UnguessableToken session_id = current_video_device.session_id(); + + // Get stream generated above. + base::UnguessableToken transfer_id = base::UnguessableToken::Create(); + GetOpenDevice(/*request_id=*/1, session_id, transfer_id, + base::BindOnce( + [](const std::string device_id, + const base::UnguessableToken& session_id, + blink::mojom::MediaStreamRequestResult result, + blink::mojom::GetOpenDeviceResponsePtr ptr) { + EXPECT_EQ(blink::mojom::MediaStreamRequestResult::OK, + result); + EXPECT_TRUE(ptr); + EXPECT_EQ(ptr->device.id, device_id); + EXPECT_NE(ptr->device.session_id(), session_id); + }, + current_video_device.id, session_id) + .Then(loop.QuitClosure())); + + // Keep MediaStreamDevice alive for GetOpenDevice to complete. + KeepDeviceAliveForTransfer( + session_id, transfer_id, base::BindOnce([](bool device_found) { + EXPECT_TRUE(device_found); + }).Then(base::BindLambdaForTesting([&]() { + host_->OnStopStreamDevice(current_video_device.id, session_id); + }))); + loop.Run(); +} // TODO(crbug.com/1300883): Add test cases for multi stream generation. } // namespace content
diff --git a/content/browser/renderer_host/native_web_keyboard_event_aura.cc b/content/browser/renderer_host/native_web_keyboard_event_aura.cc index 58b83ef..d20d797 100644 --- a/content/browser/renderer_host/native_web_keyboard_event_aura.cc +++ b/content/browser/renderer_host/native_web_keyboard_event_aura.cc
@@ -16,7 +16,7 @@ // RenderViewHostDelegate::HandledKeybardEvent after the original aura // event is destroyed. ui::Event* CopyEvent(const ui::Event* event) { - return event ? ui::Event::Clone(*event).release() : nullptr; + return event ? event->Clone().release() : nullptr; } int WebEventModifiersToEventFlags(int modifiers) {
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc index f4d1b23..997ce2ca 100644 --- a/content/browser/renderer_host/render_process_host_impl.cc +++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -3180,6 +3180,14 @@ command_line->AppendSwitchASCII(switches::kRendererClientId, std::to_string(GetID())); + + // Synchronize unix/monotonic clocks across consistent processes. + if (base::TimeTicks::IsConsistentAcrossProcesses()) { + command_line->AppendSwitchASCII( + switches::kTimeTicksAtUnixEpoch, + base::NumberToString( + base::TimeTicks::UnixEpoch().since_origin().InMicroseconds())); + } } void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer(
diff --git a/content/browser/renderer_host/render_widget_host_view_event_handler.cc b/content/browser/renderer_host/render_widget_host_view_event_handler.cc index 855e5ff6..da0e3c0 100644 --- a/content/browser/renderer_host/render_widget_host_view_event_handler.cc +++ b/content/browser/renderer_host/render_widget_host_view_event_handler.cc
@@ -659,7 +659,7 @@ // Take a copy of |event|, to avoid ConvertLocationToTarget mutating the // event. - std::unique_ptr<ui::Event> event_copy = ui::Event::Clone(*event); + std::unique_ptr<ui::Event> event_copy = event->Clone(); ui::MouseEvent* mouse_event = static_cast<ui::MouseEvent*>(event_copy.get()); mouse_event->ConvertLocationToTarget(window_.get(), window_->parent()); window_->parent()->delegate()->OnMouseEvent(mouse_event);
diff --git a/content/browser/webui/web_ui_impl.cc b/content/browser/webui/web_ui_impl.cc index 642a245..fbf415f 100644 --- a/content/browser/webui/web_ui_impl.cc +++ b/content/browser/webui/web_ui_impl.cc
@@ -12,6 +12,7 @@ #include "base/callback_helpers.h" #include "base/debug/dump_without_crashing.h" #include "base/json/json_writer.h" +#include "base/strings/strcat.h" #include "base/strings/string_piece.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" @@ -43,7 +44,7 @@ // static std::u16string WebUI::GetJavascriptCall( - const std::string& function_name, + base::StringPiece function_name, base::span<const base::ValueView> arg_list) { std::u16string result(base::ASCIIToUTF16(function_name)); result.push_back('('); @@ -206,48 +207,15 @@ frame_host_->GetLastCommittedURL().spec() == url::kAboutBlankURL); } -void WebUIImpl::CallJavascriptFunctionUnsafe(const std::string& function_name) { +void WebUIImpl::CallJavascriptFunctionUnsafe(base::StringPiece function_name) { DCHECK(base::IsStringASCII(function_name)); - std::u16string javascript = base::ASCIIToUTF16(function_name + "();"); + std::u16string javascript = + base::ASCIIToUTF16(base::StrCat({function_name, "();"})); ExecuteJavascript(javascript); } -void WebUIImpl::CallJavascriptFunctionUnsafe(const std::string& function_name, - base::ValueView arg) { - DCHECK(base::IsStringASCII(function_name)); - base::ValueView args[] = {arg}; - ExecuteJavascript(GetJavascriptCall(function_name, args)); -} - -void WebUIImpl::CallJavascriptFunctionUnsafe(const std::string& function_name, - base::ValueView arg1, - base::ValueView arg2) { - DCHECK(base::IsStringASCII(function_name)); - base::ValueView args[] = {arg1, arg2}; - ExecuteJavascript(GetJavascriptCall(function_name, args)); -} - -void WebUIImpl::CallJavascriptFunctionUnsafe(const std::string& function_name, - base::ValueView arg1, - base::ValueView arg2, - base::ValueView arg3) { - DCHECK(base::IsStringASCII(function_name)); - base::ValueView args[] = {arg1, arg2, arg3}; - ExecuteJavascript(GetJavascriptCall(function_name, args)); -} - -void WebUIImpl::CallJavascriptFunctionUnsafe(const std::string& function_name, - base::ValueView arg1, - base::ValueView arg2, - base::ValueView arg3, - base::ValueView arg4) { - DCHECK(base::IsStringASCII(function_name)); - base::ValueView args[] = {arg1, arg2, arg3, arg4}; - ExecuteJavascript(GetJavascriptCall(function_name, args)); -} - void WebUIImpl::CallJavascriptFunctionUnsafe( - const std::string& function_name, + base::StringPiece function_name, base::span<const base::ValueView> args) { DCHECK(base::IsStringASCII(function_name)); ExecuteJavascript(GetJavascriptCall(function_name, args));
diff --git a/content/browser/webui/web_ui_impl.h b/content/browser/webui/web_ui_impl.h index f86d0f8..fd28553 100644 --- a/content/browser/webui/web_ui_impl.h +++ b/content/browser/webui/web_ui_impl.h
@@ -79,23 +79,9 @@ const std::string& message, base::Value::List args) override; bool CanCallJavascript() override; - void CallJavascriptFunctionUnsafe(const std::string& function_name) override; - void CallJavascriptFunctionUnsafe(const std::string& function_name, - base::ValueView arg) override; - void CallJavascriptFunctionUnsafe(const std::string& function_name, - base::ValueView arg1, - base::ValueView arg2) override; - void CallJavascriptFunctionUnsafe(const std::string& function_name, - base::ValueView arg1, - base::ValueView arg2, - base::ValueView arg3) override; - void CallJavascriptFunctionUnsafe(const std::string& function_name, - base::ValueView arg1, - base::ValueView arg2, - base::ValueView arg3, - base::ValueView arg4) override; + void CallJavascriptFunctionUnsafe(base::StringPiece function_name) override; void CallJavascriptFunctionUnsafe( - const std::string& function_name, + base::StringPiece function_name, base::span<const base::ValueView> args) override; std::vector<std::unique_ptr<WebUIMessageHandler>>* GetHandlersForTesting() override;
diff --git a/content/browser/webui/web_ui_message_handler.cc b/content/browser/webui/web_ui_message_handler.cc index 77dc7397..51c0251 100644 --- a/content/browser/webui/web_ui_message_handler.cc +++ b/content/browser/webui/web_ui_message_handler.cc
@@ -42,16 +42,16 @@ } void WebUIMessageHandler::ResolveJavascriptCallback( - const base::Value& callback_id, - const base::Value& response) { + const base::ValueView callback_id, + const base::ValueView response) { // cr.webUIResponse is a global JS function exposed from cr.js. CallJavascriptFunction("cr.webUIResponse", callback_id, base::Value(true), response); } void WebUIMessageHandler::RejectJavascriptCallback( - const base::Value& callback_id, - const base::Value& response) { + const base::ValueView callback_id, + const base::ValueView response) { // cr.webUIResponse is a global JS function exposed from cr.js. CallJavascriptFunction("cr.webUIResponse", callback_id, base::Value(false), response);
diff --git a/content/gpu/in_process_gpu_thread.cc b/content/gpu/in_process_gpu_thread.cc index ee062fe..d5f2c044 100644 --- a/content/gpu/in_process_gpu_thread.cc +++ b/content/gpu/in_process_gpu_thread.cc
@@ -50,7 +50,7 @@ io_thread_type = base::ThreadType::kDisplayCritical; #endif - gpu_process_ = new ChildProcess(io_thread_type); + gpu_process_ = std::make_unique<ChildProcess>(io_thread_type); auto gpu_init = std::make_unique<gpu::GpuInit>(); gpu_init->InitializeInProcess(base::CommandLine::ForCurrentProcess(), @@ -76,7 +76,7 @@ void InProcessGpuThread::CleanUp() { SetThreadWasQuitProperly(true); - delete gpu_process_; + gpu_process_.reset(); } base::Thread* CreateInProcessGpuThread(
diff --git a/content/gpu/in_process_gpu_thread.h b/content/gpu/in_process_gpu_thread.h index 8ad89c6..b04c4d9 100644 --- a/content/gpu/in_process_gpu_thread.h +++ b/content/gpu/in_process_gpu_thread.h
@@ -35,7 +35,7 @@ InProcessChildThreadParams params_; // Deleted in CleanUp() on the gpu thread, so don't use smart pointers. - raw_ptr<ChildProcess, DanglingUntriaged> gpu_process_; + std::unique_ptr<ChildProcess> gpu_process_; gpu::GpuPreferences gpu_preferences_; };
diff --git a/content/public/browser/web_ui.h b/content/public/browser/web_ui.h index 9126521a..23e3694 100644 --- a/content/public/browser/web_ui.h +++ b/content/public/browser/web_ui.h
@@ -40,7 +40,7 @@ // Returns JavaScript code that, when executed, calls the function specified // by |function_name| with the arguments specified in |arg_list|. static std::u16string GetJavascriptCall( - const std::string& function_name, + base::StringPiece function_name, base::span<const base::ValueView> arg_list); virtual ~WebUI() {} @@ -111,25 +111,20 @@ // All function names in WebUI must consist of only ASCII characters. // There are variants for calls with more arguments. virtual void CallJavascriptFunctionUnsafe( - const std::string& function_name) = 0; - virtual void CallJavascriptFunctionUnsafe(const std::string& function_name, - base::ValueView arg) = 0; - virtual void CallJavascriptFunctionUnsafe(const std::string& function_name, - base::ValueView arg1, - base::ValueView arg2) = 0; - virtual void CallJavascriptFunctionUnsafe(const std::string& function_name, - base::ValueView arg1, - base::ValueView arg2, - base::ValueView arg3) = 0; - virtual void CallJavascriptFunctionUnsafe(const std::string& function_name, - base::ValueView arg1, - base::ValueView arg2, - base::ValueView arg3, - base::ValueView arg4) = 0; + base::StringPiece function_name) = 0; + virtual void CallJavascriptFunctionUnsafe( - const std::string& function_name, + base::StringPiece function_name, base::span<const base::ValueView> args) = 0; + template <typename... Args> + void CallJavascriptFunctionUnsafe(base::StringPiece function_name, + const base::ValueView arg1, + const Args&... arg) { + base::ValueView args[] = {arg1, arg...}; + CallJavascriptFunctionUnsafe(function_name, args); + } + // Allows mutable access to this WebUI's message handlers for testing. virtual std::vector<std::unique_ptr<WebUIMessageHandler>>* GetHandlersForTesting() = 0;
diff --git a/content/public/browser/web_ui_message_handler.h b/content/public/browser/web_ui_message_handler.h index 6b7d2b4..1fc52bd 100644 --- a/content/public/browser/web_ui_message_handler.h +++ b/content/public/browser/web_ui_message_handler.h
@@ -6,8 +6,6 @@ #define CONTENT_PUBLIC_BROWSER_WEB_UI_MESSAGE_HANDLER_H_ #include <ostream> -#include <string> -#include <vector> #include "base/check.h" #include "base/gtest_prod_util.h" @@ -77,19 +75,19 @@ // Helper method for responding to Javascript requests initiated with // cr.sendWithPromise() (defined in cr.js) for the case where the returned // promise should be resolved (request succeeded). - void ResolveJavascriptCallback(const base::Value& callback_id, - const base::Value& response); + void ResolveJavascriptCallback(const base::ValueView callback_id, + const base::ValueView response); // Helper method for responding to Javascript requests initiated with // cr.sendWithPromise() (defined in cr.js), for the case where the returned // promise should be rejected (request failed). - void RejectJavascriptCallback(const base::Value& callback_id, - const base::Value& response); + void RejectJavascriptCallback(const base::ValueView callback_id, + const base::ValueView response); // Helper method for notifying Javascript listeners added with // cr.addWebUIListener() (defined in cr.js). template <typename... Values> - void FireWebUIListener(const std::string& event_name, + void FireWebUIListener(base::StringPiece event_name, const Values&... values) { // cr.webUIListenerCallback is a global JS function exposed from cr.js. CallJavascriptFunction("cr.webUIListenerCallback", base::Value(event_name), @@ -103,7 +101,7 @@ // All function names in WebUI must consist of only ASCII characters. // These functions will crash if JavaScript is not currently allowed. template <typename... Values> - void CallJavascriptFunction(const std::string& function_name, + void CallJavascriptFunction(base::StringPiece function_name, const Values&... values) { CHECK(IsJavascriptAllowed()) << "Cannot CallJavascriptFunction before " "explicitly allowing JavaScript.";
diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc index 402bd19..c371b1e 100644 --- a/content/public/common/content_switches.cc +++ b/content/public/common/content_switches.cc
@@ -783,6 +783,11 @@ // should be used only for testing purpose. const char kTrustableWebBundleFileUrl[] = "trustable-web-bundles-file-url"; +// Accepts a number representing the time-ticks value at the Unix epoch. +// Since different processes can produce a different value for this due to +// system clock changes, this allows synchronizing them to a single value. +const char kTimeTicksAtUnixEpoch[] = "time-ticks-at-unix-epoch"; + // Replaces the existing codecs supported in peer connection with a single fake // codec entry that create a fake video encoder and decoder. const char kUseFakeCodecForPeerConnection[] =
diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h index f33a35c..17ccd7a 100644 --- a/content/public/common/content_switches.h +++ b/content/public/common/content_switches.h
@@ -210,6 +210,7 @@ extern const char kSkiaFontCacheLimitMb[]; extern const char kSkiaResourceCacheLimitMb[]; CONTENT_EXPORT extern const char kTestType[]; +CONTENT_EXPORT extern const char kTimeTicksAtUnixEpoch[]; CONTENT_EXPORT extern const char kTimeZoneForTesting[]; CONTENT_EXPORT extern const char kTouchEventFeatureDetection[]; CONTENT_EXPORT extern const char kTouchEventFeatureDetectionAuto[];
diff --git a/content/public/test/test_web_ui.cc b/content/public/test/test_web_ui.cc index d03a2e2..5c3d5be4 100644 --- a/content/public/test/test_web_ui.cc +++ b/content/public/test/test_web_ui.cc
@@ -99,55 +99,19 @@ return true; } -void TestWebUI::CallJavascriptFunctionUnsafe(const std::string& function_name) { +void TestWebUI::CallJavascriptFunctionUnsafe(base::StringPiece function_name) { call_data_.push_back(base::WrapUnique(new CallData(function_name))); OnJavascriptCall(*call_data_.back()); } -void TestWebUI::CallJavascriptFunctionUnsafe(const std::string& function_name, - base::ValueView arg1) { - call_data_.push_back(base::WrapUnique(new CallData(function_name))); - call_data_.back()->TakeAsArg1(base::Value::ToUniquePtrValue(arg1.ToValue())); - OnJavascriptCall(*call_data_.back()); -} - -void TestWebUI::CallJavascriptFunctionUnsafe(const std::string& function_name, - base::ValueView arg1, - base::ValueView arg2) { - call_data_.push_back(base::WrapUnique(new CallData(function_name))); - call_data_.back()->TakeAsArg1(base::Value::ToUniquePtrValue(arg1.ToValue())); - call_data_.back()->TakeAsArg2(base::Value::ToUniquePtrValue(arg2.ToValue())); - OnJavascriptCall(*call_data_.back()); -} - -void TestWebUI::CallJavascriptFunctionUnsafe(const std::string& function_name, - base::ValueView arg1, - base::ValueView arg2, - base::ValueView arg3) { - call_data_.push_back(base::WrapUnique(new CallData(function_name))); - call_data_.back()->TakeAsArg1(base::Value::ToUniquePtrValue(arg1.ToValue())); - call_data_.back()->TakeAsArg2(base::Value::ToUniquePtrValue(arg2.ToValue())); - call_data_.back()->TakeAsArg3(base::Value::ToUniquePtrValue(arg3.ToValue())); - OnJavascriptCall(*call_data_.back()); -} - -void TestWebUI::CallJavascriptFunctionUnsafe(const std::string& function_name, - base::ValueView arg1, - base::ValueView arg2, - base::ValueView arg3, - base::ValueView arg4) { - call_data_.push_back(base::WrapUnique(new CallData(function_name))); - call_data_.back()->TakeAsArg1(base::Value::ToUniquePtrValue(arg1.ToValue())); - call_data_.back()->TakeAsArg2(base::Value::ToUniquePtrValue(arg2.ToValue())); - call_data_.back()->TakeAsArg3(base::Value::ToUniquePtrValue(arg3.ToValue())); - call_data_.back()->TakeAsArg4(base::Value::ToUniquePtrValue(arg4.ToValue())); - OnJavascriptCall(*call_data_.back()); -} - void TestWebUI::CallJavascriptFunctionUnsafe( - const std::string& function_name, + base::StringPiece function_name, base::span<const base::ValueView> args) { - NOTREACHED(); + call_data_.push_back(base::WrapUnique(new CallData(function_name))); + for (const auto& arg : args) { + call_data_.back()->AppendArgument(arg.ToValue()); + } + OnJavascriptCall(*call_data_.back()); } void TestWebUI::OnJavascriptCall(const CallData& call_data) { @@ -160,27 +124,14 @@ return &handlers_; } -TestWebUI::CallData::CallData(const std::string& function_name) - : function_name_(function_name) { -} +TestWebUI::CallData::CallData(base::StringPiece function_name) + : function_name_(function_name.data(), function_name.size()) {} TestWebUI::CallData::~CallData() { } -void TestWebUI::CallData::TakeAsArg1(std::unique_ptr<base::Value> arg) { - args_[0] = std::move(arg); -} - -void TestWebUI::CallData::TakeAsArg2(std::unique_ptr<base::Value> arg) { - args_[1] = std::move(arg); -} - -void TestWebUI::CallData::TakeAsArg3(std::unique_ptr<base::Value> arg) { - args_[2] = std::move(arg); -} - -void TestWebUI::CallData::TakeAsArg4(std::unique_ptr<base::Value> arg) { - args_[3] = std::move(arg); +void TestWebUI::CallData::AppendArgument(base::Value arg) { + args_.push_back(std::move(arg)); } } // namespace content
diff --git a/content/public/test/test_web_ui.h b/content/public/test/test_web_ui.h index 63c75da..f8a6e01 100644 --- a/content/public/test/test_web_ui.h +++ b/content/public/test/test_web_ui.h
@@ -57,50 +57,34 @@ const std::string& message, base::Value::List args) override {} bool CanCallJavascript() override; - void CallJavascriptFunctionUnsafe(const std::string& function_name) override; - void CallJavascriptFunctionUnsafe(const std::string& function_name, - base::ValueView arg1) override; - void CallJavascriptFunctionUnsafe(const std::string& function_name, - base::ValueView arg1, - base::ValueView arg2) override; - void CallJavascriptFunctionUnsafe(const std::string& function_name, - base::ValueView arg1, - base::ValueView arg2, - base::ValueView arg3) override; - void CallJavascriptFunctionUnsafe(const std::string& function_name, - base::ValueView arg1, - base::ValueView arg2, - base::ValueView arg3, - base::ValueView arg4) override; + void CallJavascriptFunctionUnsafe(base::StringPiece function_name) override; void CallJavascriptFunctionUnsafe( - const std::string& function_name, + base::StringPiece function_name, base::span<const base::ValueView> args) override; std::vector<std::unique_ptr<WebUIMessageHandler>>* GetHandlersForTesting() override; class CallData { public: - explicit CallData(const std::string& function_name); + explicit CallData(base::StringPiece function_name); ~CallData(); - void TakeAsArg1(std::unique_ptr<base::Value> arg); - void TakeAsArg2(std::unique_ptr<base::Value> arg); - void TakeAsArg3(std::unique_ptr<base::Value> arg); - void TakeAsArg4(std::unique_ptr<base::Value> arg); + void AppendArgument(base::Value arg); const std::string& function_name() const { return function_name_; } - const base::Value* arg1() const { return args_[0].get(); } - const base::Value* arg2() const { return args_[1].get(); } - const base::Value* arg3() const { return args_[2].get(); } - const base::Value* arg4() const { return args_[3].get(); } - - const std::array<std::unique_ptr<base::Value>, 4>& args() const { - return args_; + const base::Value* arg_nth(size_t index) const { + return args_.size() > index ? &args_[index] : nullptr; } + const base::Value* arg1() const { return arg_nth(0); } + const base::Value* arg2() const { return arg_nth(1); } + const base::Value* arg3() const { return arg_nth(2); } + const base::Value* arg4() const { return arg_nth(3); } + + const std::vector<base::Value>& args() const { return args_; } private: std::string function_name_; - std::array<std::unique_ptr<base::Value>, 4> args_; + std::vector<base::Value> args_; }; const std::vector<std::unique_ptr<CallData>>& call_data() const {
diff --git a/content/test/data/accessibility/html/a-onclick-expected-win.txt b/content/test/data/accessibility/html/a-onclick-expected-win.txt index 0e3efd63..950fde8 100644 --- a/content/test/data/accessibility/html/a-onclick-expected-win.txt +++ b/content/test/data/accessibility/html/a-onclick-expected-win.txt
@@ -1,5 +1,5 @@ -ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE +ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE action_name='showContextMenu' ++ROLE_SYSTEM_LINK name='link with no href but onclick' LINKED default_action='jump' action_name='jump' -++++ROLE_SYSTEM_STATICTEXT name='link with no href but onclick' +++++ROLE_SYSTEM_STATICTEXT name='link with no href but onclick' action_name='showContextMenu' ++ROLE_SYSTEM_LINK name='link with no href and click handler added via script' LINKED default_action='jump' action_name='jump' -++++ROLE_SYSTEM_STATICTEXT name='link with no href and click handler added via script' \ No newline at end of file +++++ROLE_SYSTEM_STATICTEXT name='link with no href and click handler added via script' action_name='showContextMenu'
diff --git a/content/test/data/accessibility/html/action-verbs-expected-win.txt b/content/test/data/accessibility/html/action-verbs-expected-win.txt index 4edbfa1..b23fb4c 100644 --- a/content/test/data/accessibility/html/action-verbs-expected-win.txt +++ b/content/test/data/accessibility/html/action-verbs-expected-win.txt
@@ -1,11 +1,11 @@ -ROLE_SYSTEM_DOCUMENT name='Action verbs' READONLY FOCUSABLE -++IA2_ROLE_SECTION -++++ROLE_SYSTEM_STATICTEXT name='Generic div' -++IA2_ROLE_HEADING name='Heading' -++++ROLE_SYSTEM_STATICTEXT name='Heading' +ROLE_SYSTEM_DOCUMENT name='Action verbs' READONLY FOCUSABLE action_name='showContextMenu' +++IA2_ROLE_SECTION action_name='showContextMenu' +++++ROLE_SYSTEM_STATICTEXT name='Generic div' action_name='showContextMenu' +++IA2_ROLE_HEADING name='Heading' action_name='showContextMenu' +++++ROLE_SYSTEM_STATICTEXT name='Heading' action_name='showContextMenu' ++ROLE_SYSTEM_PUSHBUTTON name='Button' FOCUSABLE default_action='press' action_name='press' ++ROLE_SYSTEM_LINK name='Link' FOCUSABLE default_action='jump' action_name='jump' -++++ROLE_SYSTEM_STATICTEXT name='Link' +++++ROLE_SYSTEM_STATICTEXT name='Link' action_name='showContextMenu' ++ROLE_SYSTEM_TEXT FOCUSABLE default_action='activate' action_name='activate' ++ROLE_SYSTEM_TEXT FOCUSABLE default_action='activate' action_name='activate' ++ROLE_SYSTEM_TEXT FOCUSABLE IA2_STATE_MULTI_LINE default_action='activate' action_name='activate' @@ -14,16 +14,16 @@ ++ROLE_SYSTEM_CHECKBUTTON CHECKED FOCUSABLE IA2_STATE_CHECKABLE checkable:true default_action='uncheck' action_name='uncheck' ++ROLE_SYSTEM_RADIOBUTTON FOCUSABLE IA2_STATE_CHECKABLE checkable:true default_action='check' action_name='check' ++IA2_ROLE_TOGGLE_BUTTON name='ARIA Switch' FOCUSABLE IA2_STATE_CHECKABLE checkable:true default_action='check' action_name='check' -++ROLE_SYSTEM_GROUPING +++ROLE_SYSTEM_GROUPING action_name='showContextMenu' ++++ROLE_SYSTEM_PUSHBUTTON name='Summary' COLLAPSED FOCUSABLE default_action='press' action_name='press' -++++++ROLE_SYSTEM_STATICTEXT name='Summary' +++++++ROLE_SYSTEM_STATICTEXT name='Summary' action_name='showContextMenu' ++ROLE_SYSTEM_COMBOBOX value='Pop-up button' COLLAPSED FOCUSABLE HASPOPUP haspopup:menu default_action='open' action_name='open' ++IA2_ROLE_SECTION default_action='click' action_name='click' -++++ROLE_SYSTEM_STATICTEXT name='Div with click handler' +++++ROLE_SYSTEM_STATICTEXT name='Div with click handler' action_name='showContextMenu' ++ROLE_SYSTEM_GROUPING default_action='click' action_name='click' ++++IA2_ROLE_PARAGRAPH default_action='click ancestor' action_name='clickAncestor' -++++++ROLE_SYSTEM_STATICTEXT name='Paragraph with click handler on parent' -++ROLE_SYSTEM_MENUPOPUP +++++++ROLE_SYSTEM_STATICTEXT name='Paragraph with click handler on parent' action_name='showContextMenu' +++ROLE_SYSTEM_MENUPOPUP action_name='showContextMenu' ++++ROLE_SYSTEM_MENUITEM name='Menu item 1' default_action='select' action_name='select' ++++IA2_ROLE_CHECK_MENU_ITEM name='Menu item 2' CHECKED IA2_STATE_CHECKABLE checkable:true default_action='uncheck' action_name='uncheck' ++++IA2_ROLE_RADIO_MENU_ITEM name='Menu item 3' IA2_STATE_CHECKABLE checkable:true default_action='check' action_name='check' @@ -35,4 +35,4 @@ ++IA2_ROLE_SECTION default_action='click' action_name='click' ++++IA2_ROLE_TOGGLE_BUTTON name='ARIA switch in clickable container' IA2_STATE_CHECKABLE checkable:true default_action='check' action_name='check' ++++IA2_ROLE_SECTION default_action='click ancestor' action_name='clickAncestor' -++++++ROLE_SYSTEM_STATICTEXT name='Generic in clickable container' \ No newline at end of file +++++++ROLE_SYSTEM_STATICTEXT name='Generic in clickable container' action_name='showContextMenu'
diff --git a/docs/vscode.md b/docs/vscode.md index 31202583..fc112380 100644 --- a/docs/vscode.md +++ b/docs/vscode.md
@@ -102,7 +102,7 @@ You will most likely use the following extensions every day: ```bash -$ echo "ms-vscode.cpptools llvm-vs-code-extensions.vscode-clangd ms-python.python bbenoist.togglehs peterj.proto Google.vscode-mojom msedge-dev.gnls stkb.rewrap ms-vscode-remote.remote-ssh eamodio.gitlens" | xargs -n 1 code --install-extension --force +$ echo "ms-vscode.cpptools llvm-vs-code-extensions.vscode-clangd ms-python.python bbenoist.togglehs peterj.proto Google.vscode-mojom msedge-dev.gnls stkb.rewrap ms-vscode-remote.remote-ssh eamodio.gitlens" | xargs -n 1 code --force --install-extension ``` * [**C/C++**](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools) - @@ -144,7 +144,7 @@ The following extensions might be useful for you as well: ```bash -$ echo "wmaurer.change-case shd101wyy.markdown-preview-enhanced Gruntfuggly.todo-tree alefragnani.Bookmarks spmeesseman.vscode-taskexplorer streetsidesoftware.code-spell-checker tht13.html-preview-vscode anseki.vscode-color" | xargs -n 1 code --install-extension --force +$ echo "wmaurer.change-case shd101wyy.markdown-preview-enhanced Gruntfuggly.todo-tree alefragnani.Bookmarks spmeesseman.vscode-taskexplorer streetsidesoftware.code-spell-checker tht13.html-preview-vscode anseki.vscode-color" | xargs -n 1 code --force --install-extension ``` * **chromium-codesearch** -
diff --git a/extensions/browser/api/app_window/app_window_api.cc b/extensions/browser/api/app_window/app_window_api.cc index 6a622cd..5b64948 100644 --- a/extensions/browser/api/app_window/app_window_api.cc +++ b/extensions/browser/api/app_window/app_window_api.cc
@@ -401,7 +401,7 @@ if (!app_window) return RespondNow(Error(app_window_constants::kAppWindowCreationFailed)); - app_window->Init(url, new AppWindowContentsImpl(app_window), + app_window->Init(url, std::make_unique<AppWindowContentsImpl>(app_window), render_frame_host(), create_params); if (ExtensionsBrowserClient::Get()->IsRunningInForcedAppMode() && @@ -470,44 +470,36 @@ const app_window::BoundsSpecification* outer_bounds = options.outer_bounds.get(); if (inner_bounds && outer_bounds) { - if (!CheckBoundsConflict( - inner_bounds->left, outer_bounds->left, "left", error)) { - return false; - } - if (!CheckBoundsConflict( - inner_bounds->top, outer_bounds->top, "top", error)) { - return false; - } - if (!CheckBoundsConflict( - inner_bounds->width, outer_bounds->width, "width", error)) { - return false; - } - if (!CheckBoundsConflict( - inner_bounds->height, outer_bounds->height, "height", error)) { - return false; - } - if (!CheckBoundsConflict(inner_bounds->min_width, - outer_bounds->min_width, - "minWidth", + if (!CheckBoundsConflict(inner_bounds->left, outer_bounds->left, "left", error)) { return false; } + if (!CheckBoundsConflict(inner_bounds->top, outer_bounds->top, "top", + error)) { + return false; + } + if (!CheckBoundsConflict(inner_bounds->width, outer_bounds->width, + "width", error)) { + return false; + } + if (!CheckBoundsConflict(inner_bounds->height, outer_bounds->height, + "height", error)) { + return false; + } + if (!CheckBoundsConflict(inner_bounds->min_width, outer_bounds->min_width, + "minWidth", error)) { + return false; + } if (!CheckBoundsConflict(inner_bounds->min_height, - outer_bounds->min_height, - "minHeight", - error)) { + outer_bounds->min_height, "minHeight", error)) { return false; } - if (!CheckBoundsConflict(inner_bounds->max_width, - outer_bounds->max_width, - "maxWidth", - error)) { + if (!CheckBoundsConflict(inner_bounds->max_width, outer_bounds->max_width, + "maxWidth", error)) { return false; } if (!CheckBoundsConflict(inner_bounds->max_height, - outer_bounds->max_height, - "maxHeight", - error)) { + outer_bounds->max_height, "maxHeight", error)) { return false; } }
diff --git a/extensions/browser/app_window/app_window.cc b/extensions/browser/app_window/app_window.cc index 470f950f..3c3576848 100644 --- a/extensions/browser/app_window/app_window.cc +++ b/extensions/browser/app_window/app_window.cc
@@ -249,11 +249,11 @@ } void AppWindow::Init(const GURL& url, - AppWindowContents* app_window_contents, + std::unique_ptr<AppWindowContents> app_window_contents, content::RenderFrameHost* creator_frame, const CreateParams& params) { // Initialize the render interface and web contents - app_window_contents_.reset(app_window_contents); + app_window_contents_ = std::move(app_window_contents); app_window_contents_->Initialize(browser_context(), creator_frame, url); initial_url_ = url;
diff --git a/extensions/browser/app_window/app_window.h b/extensions/browser/app_window/app_window.h index c998a52..b0d66d3 100644 --- a/extensions/browser/app_window/app_window.h +++ b/extensions/browser/app_window/app_window.h
@@ -230,9 +230,8 @@ AppWindow& operator=(const AppWindow&) = delete; // Initializes the render interface, web contents, and native window. - // |app_window_contents| will become owned by AppWindow. void Init(const GURL& url, - AppWindowContents* app_window_contents, + std::unique_ptr<AppWindowContents> app_window_contents, content::RenderFrameHost* creator_frame, const CreateParams& params);
diff --git a/extensions/shell/test/shell_test_helper_aura.cc b/extensions/shell/test/shell_test_helper_aura.cc index 4c036c8e..38ce9a6d 100644 --- a/extensions/shell/test/shell_test_helper_aura.cc +++ b/extensions/shell/test/shell_test_helper_aura.cc
@@ -51,7 +51,7 @@ AppWindow::CreateParams params; params.content_spec.bounds = bounds; - app_window->Init(GURL(), app_window_contents.release(), main_frame, params); + app_window->Init(GURL(), std::move(app_window_contents), main_frame, params); } } // namespace extensions
diff --git a/ios/chrome/browser/flags/about_flags.mm b/ios/chrome/browser/flags/about_flags.mm index 5b978ac..23b50317 100644 --- a/ios/chrome/browser/flags/about_flags.mm +++ b/ios/chrome/browser/flags/about_flags.mm
@@ -891,6 +891,14 @@ flag_descriptions::kEnableUnicornAccountSupportDescription, flags_ui::kOsIos, FEATURE_VALUE_TYPE(signin::kEnableUnicornAccountSupport)}, + {"single-cell-content-suggestions", + flag_descriptions::kSingleCellContentSuggestionsName, + flag_descriptions::kSingleCellContentSuggestionsDescription, + flags_ui::kOsIos, FEATURE_VALUE_TYPE(kSingleCellContentSuggestions)}, + {"content-suggestions-header-migration", + flag_descriptions::kContentSuggestionsHeaderMigrationName, + flag_descriptions::kContentSuggestionsHeaderMigrationDescription, + flags_ui::kOsIos, FEATURE_VALUE_TYPE(kContentSuggestionsHeaderMigration)}, {"leak-detection-unauthenticated", flag_descriptions::kLeakDetectionUnauthenticatedName, flag_descriptions::kLeakDetectionUnauthenticatedDescription, @@ -935,6 +943,11 @@ flag_descriptions::kSendTabToSelfSigninPromoName, flag_descriptions::kSendTabToSelfSigninPromoDescription, flags_ui::kOsIos, FEATURE_VALUE_TYPE(send_tab_to_self::kSendTabToSelfSigninPromo)}, + {"content-suggestions-uiviewcontroller-migration", + flag_descriptions::kContentSuggestionsUIViewControllerMigrationName, + flag_descriptions::kContentSuggestionsUIViewControllerMigrationDescription, + flags_ui::kOsIos, + FEATURE_VALUE_TYPE(kContentSuggestionsUIViewControllerMigration)}, {"bubble-rich-iph", flag_descriptions::kBubbleRichIPHName, flag_descriptions::kBubbleRichIPHDescription, flags_ui::kOsIos, FEATURE_WITH_PARAMS_VALUE_TYPE(kBubbleRichIPH,
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc index 5edc494..8c2d6b1 100644 --- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc +++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
@@ -164,12 +164,24 @@ "When enabled, Experience Kit Calendar will use Text Classifier library in " "entity detection where possible."; +const char kContentSuggestionsHeaderMigrationName[] = + "Content Suggestions header migration"; +const char kContentSuggestionsHeaderMigrationDescription[] = + "When enabled, the Content Suggestions header will be logically moved to " + "the Discover feed ScrollView"; + const char kContentSuggestionsUIModuleRefreshName[] = "Content Suggestions UI Module Refresh"; const char kContentSuggestionsUIModuleRefreshDescription[] = "When enabled, the Content Suggestions will be redesigned to be contained " "into distinct modules."; +const char kContentSuggestionsUIViewControllerMigrationName[] = + "Content Suggestions UIViewController migration"; +const char kContentSuggestionsUIViewControllerMigrationDescription[] = + "When enabled, the Content Suggestions will be logically moved to a " + "UIViewController subclass implementation"; + const char kCrashpadIOSName[] = "Use Crashpad for crash collection."; const char kCrashpadIOSDescription[] = "When enabled use Crashpad to generate crash reports crash collection. " @@ -618,6 +630,11 @@ "Adds a Link to Text option in the Edit Menu which generates URLs with a " "text fragment."; +const char kSingleCellContentSuggestionsName[] = + "Use Single Cell for Content Suggestions"; +const char kSingleCellContentSuggestionsDescription[] = + "Uses a single cell for all items in the NTP's content suggestions."; + const char kShowAutofillTypePredictionsName[] = "Show Autofill predictions"; const char kShowAutofillTypePredictionsDescription[] = "Annotates web forms with Autofill field type predictions as placeholder "
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h index 3cb9769..b788026 100644 --- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h +++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
@@ -139,11 +139,21 @@ extern const char kEnableExpKitCalendarTextClassifierName[]; extern const char kEnableExpKitCalendarTextClassifierDescription[]; +// Title and description for the flag that moves the Content Suggestions header +// to the Discover feed ScrollView. +extern const char kContentSuggestionsHeaderMigrationName[]; +extern const char kContentSuggestionsHeaderMigrationDescription[]; + // Title and description for the flag that updates the Content Suggestions to a // new module design. extern const char kContentSuggestionsUIModuleRefreshName[]; extern const char kContentSuggestionsUIModuleRefreshDescription[]; +// Title and description for the flag that moves the Content Suggestions to a +// UIViewController. +extern const char kContentSuggestionsUIViewControllerMigrationName[]; +extern const char kContentSuggestionsUIViewControllerMigrationDescription[]; + // Title and description for the flag to control which crash generation tool // is used. extern const char kCrashpadIOSName[]; @@ -567,6 +577,11 @@ extern const char kShowAutofillTypePredictionsName[]; extern const char kShowAutofillTypePredictionsDescription[]; +// Title and description for the flag to use one cell for the Content +// Suggestions +extern const char kSingleCellContentSuggestionsName[]; +extern const char kSingleCellContentSuggestionsDescription[]; + // Title and description for the flag to enable smart sorting the new overflow // menu. extern const char kSmartSortingNewOverflowMenuName[];
diff --git a/ios/chrome/browser/ntp_tiles/ntp_tiles_egtest.mm b/ios/chrome/browser/ntp_tiles/ntp_tiles_egtest.mm index 66d63d1..0362388b 100644 --- a/ios/chrome/browser/ntp_tiles/ntp_tiles_egtest.mm +++ b/ios/chrome/browser/ntp_tiles/ntp_tiles_egtest.mm
@@ -41,6 +41,10 @@ - (AppLaunchConfiguration)appConfigurationForTestCase { AppLaunchConfiguration config; config.relaunch_policy = ForceRelaunchByCleanShutdown; + config.features_enabled.push_back(kSingleCellContentSuggestions); + config.features_enabled.push_back(kContentSuggestionsHeaderMigration); + config.features_enabled.push_back( + kContentSuggestionsUIViewControllerMigration); return config; }
diff --git a/ios/chrome/browser/passwords/ios_chrome_password_check_manager.mm b/ios/chrome/browser/passwords/ios_chrome_password_check_manager.mm index 52c5c2d..3e8f488 100644 --- a/ios/chrome/browser/passwords/ios_chrome_password_check_manager.mm +++ b/ios/chrome/browser/passwords/ios_chrome_password_check_manager.mm
@@ -95,7 +95,6 @@ // Instructs the presenter and manager to initialize and build their caches. saved_passwords_presenter_.Init(); - insecure_credentials_manager_.Init(); } IOSChromePasswordCheckManager::~IOSChromePasswordCheckManager() {
diff --git a/ios/chrome/browser/segmentation_platform/segmentation_platform_config.mm b/ios/chrome/browser/segmentation_platform/segmentation_platform_config.mm index 19dd012..240e1b49 100644 --- a/ios/chrome/browser/segmentation_platform/segmentation_platform_config.mm +++ b/ios/chrome/browser/segmentation_platform/segmentation_platform_config.mm
@@ -10,7 +10,6 @@ #import "base/metrics/field_trial_params.h" #import "base/time/time.h" #import "components/segmentation_platform/embedder/default_model/feed_user_segment.h" -#import "components/segmentation_platform/internal/stats.h" #import "components/segmentation_platform/public/config.h" #import "components/segmentation_platform/public/features.h" #import "components/segmentation_platform/public/model_provider.h" @@ -25,13 +24,6 @@ namespace { -#define SEGMENT_ID_ENTRY(segment) \ - { \ - segment, Config::SegmentMetadata { \ - stats::OptimizationTargetToHistogramVariant(segment) \ - } \ - } - using ::segmentation_platform::proto::SegmentId; constexpr int kFeedUserSegmentSelectionTTLDays = 14; @@ -40,10 +32,8 @@ std::unique_ptr<Config> GetConfigForFeedSegments() { auto config = std::make_unique<Config>(); config->segmentation_key = kFeedUserSegmentationKey; - config->segmentation_uma_name = - stats::SegmentationKeyToUmaName(config->segmentation_key); - config->segments = { - SEGMENT_ID_ENTRY(SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_FEED_USER), + config->segment_ids = { + SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_FEED_USER, }; config->segment_selection_ttl = base::Days(base::GetFieldTrialParamByFeatureAsInt(
diff --git a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm index bccf914..fabb8d6 100644 --- a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm +++ b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
@@ -2589,9 +2589,11 @@ - (BOOL)isTabScrolledToTopForBubblePresenter:(BubblePresenter*)bubblePresenter { DCHECK(bubblePresenter == _bubblePresenter); - // If NTP exists, check if it is scrolled to top. + // If NTP exists, use NTP coordinator's scroll offset. if (self.isNTPActiveForCurrentWebState) { - return [self.ntpCoordinator isScrolledToTop]; + NewTabPageCoordinator* coordinator = self.ntpCoordinator; + CGFloat scrolledToTopOffset = [coordinator contentInset].top; + return [coordinator contentOffset].y == scrolledToTopOffset; } CRWWebViewScrollViewProxy* scrollProxy =
diff --git a/ios/chrome/browser/ui/content_suggestions/BUILD.gn b/ios/chrome/browser/ui/content_suggestions/BUILD.gn index d93550f..18367615 100644 --- a/ios/chrome/browser/ui/content_suggestions/BUILD.gn +++ b/ios/chrome/browser/ui/content_suggestions/BUILD.gn
@@ -119,7 +119,6 @@ "//ui/strings", ] configs += [ "//build/config/compiler:enable_arc" ] - public_deps = [ "//ios/third_party/material_components_ios" ] } source_set("metrics") { @@ -145,17 +144,22 @@ source_set("public") { sources = [ "content_suggestions_menu_provider.h" ] + public_deps = [ "//ios/third_party/material_components_ios" ] configs += [ "//build/config/compiler:enable_arc" ] } source_set("content_suggestions_ui") { sources = [ + "content_suggestions_collection_consumer.h", "content_suggestions_collection_controlling.h", "content_suggestions_collection_synchronizing.h", + "content_suggestions_collection_view_controller.h", + "content_suggestions_collection_view_controller.mm", "content_suggestions_commands.h", "content_suggestions_consumer.h", "content_suggestions_header_commands.h", "content_suggestions_header_controlling.h", + "content_suggestions_header_provider.h", "content_suggestions_header_synchronizer.h", "content_suggestions_header_synchronizer.mm", "content_suggestions_header_synchronizing.h", @@ -164,6 +168,8 @@ "content_suggestions_header_view_controller.h", "content_suggestions_header_view_controller.mm", "content_suggestions_header_view_controller_delegate.h", + "content_suggestions_layout.h", + "content_suggestions_layout.mm", "content_suggestions_view_controller.h", "content_suggestions_view_controller.mm", "content_suggestions_view_controller_audience.h", @@ -208,7 +214,10 @@ "//ios/web/common", "//ui/base", ] - public_deps = [ ":content_suggestions_ui_util" ] + public_deps = [ + ":content_suggestions_ui_util", + "//ios/third_party/material_components_ios", + ] configs += [ "//build/config/compiler:enable_arc" ] } @@ -244,6 +253,7 @@ "//ios/chrome/common/ui/colors", "//ios/chrome/common/ui/util", "//ios/components/ui_util", + "//ios/third_party/material_components_ios", "//ios/web/common", "//ui/base", ]
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/BUILD.gn b/ios/chrome/browser/ui/content_suggestions/cells/BUILD.gn index a745014..0578d07 100644 --- a/ios/chrome/browser/ui/content_suggestions/cells/BUILD.gn +++ b/ios/chrome/browser/ui/content_suggestions/cells/BUILD.gn
@@ -5,16 +5,24 @@ source_set("cells") { sources = [ "content_suggestions_gesture_commands.h", + "content_suggestions_header_item.h", + "content_suggestions_header_item.mm", "content_suggestions_module_container.h", "content_suggestions_module_container.mm", + "content_suggestions_most_visited_action_cell.h", + "content_suggestions_most_visited_action_cell.mm", "content_suggestions_most_visited_action_item.h", "content_suggestions_most_visited_action_item.mm", + "content_suggestions_most_visited_cell.h", + "content_suggestions_most_visited_cell.mm", "content_suggestions_most_visited_constants.h", "content_suggestions_most_visited_constants.mm", "content_suggestions_most_visited_item.h", "content_suggestions_most_visited_item.mm", "content_suggestions_most_visited_tile_view.h", "content_suggestions_most_visited_tile_view.mm", + "content_suggestions_parent_item.h", + "content_suggestions_parent_item.mm", "content_suggestions_return_to_recent_tab_item.h", "content_suggestions_return_to_recent_tab_item.mm", "content_suggestions_return_to_recent_tab_view.h", @@ -64,9 +72,11 @@ "//ios/chrome/common/ui/table_view:cells_constants", "//ios/chrome/common/ui/util", "//ios/chrome/common/ui/util:dynamic_type_util", + "//ios/third_party/material_components_ios", "//ui/base", "//url", ] + public_deps = [ "//ios/third_party/material_components_ios" ] configs += [ "//build/config/compiler:enable_arc" ] } @@ -82,13 +92,18 @@ deps = [ "//ios/chrome/app/strings:ios_strings_grit", "//ios/chrome/browser/ui/icons:symbols", + "//ios/third_party/material_components_ios", "//ui/base:base", ] } source_set("unit_tests") { testonly = true - sources = [ "content_suggestions_tile_layout_util_unittest.mm" ] + sources = [ + "content_suggestions_header_item_unittest.mm", + "content_suggestions_tile_layout_util_unittest.mm", + "content_suggestions_whats_new_item_unittest.mm", + ] deps = [ ":cells", "//base",
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_header_item.h b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_header_item.h new file mode 100644 index 0000000..f6ff7ccb --- /dev/null +++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_header_item.h
@@ -0,0 +1,31 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CELLS_CONTENT_SUGGESTIONS_HEADER_ITEM_H_ +#define IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CELLS_CONTENT_SUGGESTIONS_HEADER_ITEM_H_ + +#import <MaterialComponents/MaterialCollectionCells.h> + +#import "ios/chrome/browser/ui/collection_view/cells/collection_view_item.h" + +// Item to display a view cell. +@interface ContentSuggestionsHeaderItem : CollectionViewItem + +// The view to be displayed. +@property(nonatomic, strong) UIView* view; + +// Accessibility identifier of the ContentSuggestionsHeaderCell. ++ (NSString*)accessibilityIdentifier; + +@end + +// Corresponding cell. +@interface ContentSuggestionsHeaderCell : MDCCollectionViewCell + +// The header view to be displayed. +@property(nonatomic, strong) UIView* headerView; + +@end + +#endif // IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CELLS_CONTENT_SUGGESTIONS_HEADER_ITEM_H_
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_header_item.mm b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_header_item.mm new file mode 100644 index 0000000..58bff46 --- /dev/null +++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_header_item.mm
@@ -0,0 +1,58 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_header_item.h" + +#import "ios/chrome/common/ui/util/constraints_ui_util.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +@implementation ContentSuggestionsHeaderItem + +@synthesize view; + +- (instancetype)initWithType:(NSInteger)type { + self = [super initWithType:type]; + if (self) { + self.cellClass = [ContentSuggestionsHeaderCell class]; + } + return self; +} + +- (void)configureCell:(ContentSuggestionsHeaderCell*)cell { + [super configureCell:cell]; + [cell setHeaderView:self.view]; + cell.accessibilityIdentifier = [[self class] accessibilityIdentifier]; +} + ++ (NSString*)accessibilityIdentifier { + return @"CSHeaderIdentifier"; +} + +@end + +@implementation ContentSuggestionsHeaderCell + +@synthesize headerView = _headerView; + +- (void)setHeaderView:(UIView*)header { + [_headerView removeFromSuperview]; + _headerView = header; + + if (!header) + return; + + header.translatesAutoresizingMaskIntoConstraints = NO; + [self.contentView addSubview:header]; + AddSameConstraints(self.contentView, header); +} + +- (void)prepareForReuse { + [super prepareForReuse]; + self.headerView = nil; +} + +@end
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_header_item_unittest.mm b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_header_item_unittest.mm new file mode 100644 index 0000000..69e8de8 --- /dev/null +++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_header_item_unittest.mm
@@ -0,0 +1,45 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_header_item.h" + +#include "testing/gtest/include/gtest/gtest.h" +#include "testing/platform_test.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +namespace { + +using ContentSuggestionsHeaderItemTest = PlatformTest; + +TEST_F(ContentSuggestionsHeaderItemTest, CellClass) { + // Setup. + ContentSuggestionsHeaderItem* item = + [[ContentSuggestionsHeaderItem alloc] initWithType:0]; + + // Action. + ContentSuggestionsHeaderCell* cell = [[[item cellClass] alloc] init]; + + // Test. + EXPECT_EQ([ContentSuggestionsHeaderCell class], [cell class]); +} + +TEST_F(ContentSuggestionsHeaderItemTest, Configure) { + // Setup. + UIView* view = [[UIView alloc] init]; + ContentSuggestionsHeaderItem* item = + [[ContentSuggestionsHeaderItem alloc] initWithType:0]; + item.view = view; + ContentSuggestionsHeaderCell* cell = [[[item cellClass] alloc] init]; + + // Action. + [item configureCell:cell]; + + // Test. + ASSERT_EQ(1U, [cell.contentView.subviews count]); + EXPECT_EQ(view, cell.contentView.subviews[0]); +} +}
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_action_cell.h b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_action_cell.h new file mode 100644 index 0000000..2e365b8 --- /dev/null +++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_action_cell.h
@@ -0,0 +1,30 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CELLS_CONTENT_SUGGESTIONS_MOST_VISITED_ACTION_CELL_H_ +#define IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CELLS_CONTENT_SUGGESTIONS_MOST_VISITED_ACTION_CELL_H_ + +#import <MaterialComponents/MaterialCollectionCells.h> + +// Associated cell to display a Most Visited Action tile based. +@interface ContentSuggestionsMostVisitedActionCell : MDCCollectionViewCell + +// View for action icon. +@property(nonatomic, strong, readonly, nonnull) UIImageView* iconView; + +// Title of the action. +@property(nonatomic, strong, readonly, nonnull) UILabel* titleLabel; + +// Container view for `countLabel`. +@property(nonatomic, strong, readonly, nonnull) UIView* countContainer; + +// Number shown in circle by top trailing side of cell. +@property(nonatomic, strong, readonly, nonnull) UILabel* countLabel; + +// Size for a an action tile. ++ (CGSize)defaultSize; + +@end + +#endif // IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CELLS_CONTENT_SUGGESTIONS_MOST_VISITED_ACTION_CELL_H_
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_action_cell.mm b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_action_cell.mm new file mode 100644 index 0000000..febb062 --- /dev/null +++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_action_cell.mm
@@ -0,0 +1,88 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_action_cell.h" + +#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_constants.h" +#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_shortcut_tile_view.h" +#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_tile_layout_util.h" +#include "ios/chrome/browser/ui/util/ui_util.h" +#import "ios/chrome/browser/ui/util/uikit_ui_util.h" +#import "ios/chrome/common/material_timing.h" +#import "ios/chrome/common/ui/favicon/favicon_view.h" +#import "ios/chrome/common/ui/util/constraints_ui_util.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +@interface ContentSuggestionsMostVisitedActionCell () + +@property(nonatomic, strong) ContentSuggestionsShortcutTileView* tileView; + +@end + +@implementation ContentSuggestionsMostVisitedActionCell : MDCCollectionViewCell + +#pragma mark - Public + +- (instancetype)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if (self) { + _tileView = + [[ContentSuggestionsShortcutTileView alloc] initWithFrame:frame]; + _tileView.translatesAutoresizingMaskIntoConstraints = NO; + [self.contentView addSubview:_tileView]; + AddSameConstraints(self.contentView, _tileView); + + self.isAccessibilityElement = YES; + } + return self; +} + +- (void)setHighlighted:(BOOL)highlighted { + [super setHighlighted:highlighted]; + + [UIView transitionWithView:self + duration:ios::material::kDuration8 + options:UIViewAnimationOptionCurveEaseInOut + animations:^{ + self.alpha = highlighted ? 0.5 : 1.0; + } + completion:nil]; +} + ++ (CGSize)defaultSize { + return MostVisitedCellSize( + UIApplication.sharedApplication.preferredContentSizeCategory); +} + +- (CGSize)intrinsicContentSize { + return [[self class] defaultSize]; +} + +- (void)prepareForReuse { + [super prepareForReuse]; + self.tileView.countContainer.hidden = YES; +} + +#pragma mark - properties + +- (UIImageView*)iconView { + return self.tileView.iconView; +} + +- (UILabel*)titleLabel { + return self.tileView.titleLabel; +} + +- (UIView*)countContainer { + return self.tileView.countContainer; +} + +- (UILabel*)countLabel { + return self.tileView.countLabel; +} + +@end
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_action_item.h b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_action_item.h index 3f045bdd..bd879383 100644 --- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_action_item.h +++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_action_item.h
@@ -7,12 +7,15 @@ #import <UIKit/UIKit.h> +#import "ios/chrome/browser/ui/collection_view/cells/collection_view_item.h" #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_tile_constants.h" +#import "ios/chrome/browser/ui/content_suggestions/cells/suggested_content.h" // Item containing a most visited action button. These buttons belong to the // collection section as most visited items, but have static placement (the last // four) and cannot be removed. -@interface ContentSuggestionsMostVisitedActionItem : NSObject +@interface ContentSuggestionsMostVisitedActionItem + : CollectionViewItem<SuggestedContent> - (nonnull instancetype)initWithCollectionShortcutType: (NTPCollectionShortcutType)type;
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_action_item.mm b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_action_item.mm index 73cffb49..4d23365 100644 --- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_action_item.mm +++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_action_item.mm
@@ -5,6 +5,7 @@ #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_action_item.h" #include "base/check.h" +#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_action_cell.h" #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_tile_constants.h" #import "ios/chrome/browser/ui/icons/chrome_symbol.h" @@ -13,9 +14,11 @@ #endif @implementation ContentSuggestionsMostVisitedActionItem +@synthesize metricsRecorded; +@synthesize suggestionIdentifier; - (instancetype)initWithCollectionShortcutType:(NTPCollectionShortcutType)type { - self = [super init]; + self = [super initWithType:0]; if (self) { _collectionShortcutType = type; switch (_collectionShortcutType) { @@ -34,6 +37,7 @@ default: break; } + self.cellClass = [ContentSuggestionsMostVisitedActionCell class]; self.title = TitleForCollectionShortcutType(_collectionShortcutType); } return self; @@ -55,6 +59,35 @@ [self updateAccessibilityLabel]; } +#pragma mark - AccessibilityCustomAction + +- (void)configureCell:(ContentSuggestionsMostVisitedActionCell*)cell { + [super configureCell:cell]; + cell.accessibilityCustomActions = nil; + cell.titleLabel.text = self.title; + cell.accessibilityLabel = + self.accessibilityLabel.length ? self.accessibilityLabel : self.title; + // The accessibilityUserInputLabel should just be the title, with nothing + // extra from the accessibilityLabel. + cell.accessibilityUserInputLabels = @[ self.title ]; + cell.iconView.image = + UseSymbols() ? SymbolForCollectionShortcutType(_collectionShortcutType) + : ImageForCollectionShortcutType(_collectionShortcutType); + cell.iconView.contentMode = UIViewContentModeCenter; + if (self.count != 0) { + cell.countLabel.text = [@(self.count) stringValue]; + cell.countContainer.hidden = NO; + } else { + cell.countContainer.hidden = YES; + } +} + +#pragma mark - ContentSuggestionsItem + +- (CGFloat)cellHeightForWidth:(CGFloat)width { + return [ContentSuggestionsMostVisitedActionCell defaultSize].height; +} + #pragma mark - Private // Updates self.accessibilityLabel based on the current property values.
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_cell.h b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_cell.h new file mode 100644 index 0000000..831cc647 --- /dev/null +++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_cell.h
@@ -0,0 +1,27 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CELLS_CONTENT_SUGGESTIONS_MOST_VISITED_CELL_H_ +#define IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CELLS_CONTENT_SUGGESTIONS_MOST_VISITED_CELL_H_ + +#import <MaterialComponents/MaterialCollectionCells.h> + +@class FaviconView; + +// Associated cell to display a Most Visited tile based on the suggestion. +// It displays the favicon for this Most Visited suggestion and its title. +@interface ContentSuggestionsMostVisitedCell : MDCCollectionViewCell + +// FaviconView displaying the favicon. +@property(nonatomic, strong, readonly, nonnull) FaviconView* faviconView; + +// Title of the Most Visited. +@property(nonatomic, strong, readonly, nonnull) UILabel* titleLabel; + +// Size for a Most Visited tile. ++ (CGSize)defaultSize; + +@end + +#endif // IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CELLS_CONTENT_SUGGESTIONS_MOST_VISITED_CELL_H_
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_cell.mm b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_cell.mm new file mode 100644 index 0000000..e5aa393a --- /dev/null +++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_cell.mm
@@ -0,0 +1,73 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_cell.h" + +#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_tile_view.h" + +#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_constants.h" +#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_tile_layout_util.h" +#include "ios/chrome/browser/ui/util/ui_util.h" +#import "ios/chrome/common/material_timing.h" +#import "ios/chrome/common/ui/favicon/favicon_view.h" +#import "ios/chrome/common/ui/util/constraints_ui_util.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +@interface ContentSuggestionsMostVisitedCell () + +@property(nonatomic, strong) + ContentSuggestionsMostVisitedTileView* mostVisitedTile; + +@end + +@implementation ContentSuggestionsMostVisitedCell : MDCCollectionViewCell + +#pragma mark - Public + +- (instancetype)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if (self) { + _mostVisitedTile = + [[ContentSuggestionsMostVisitedTileView alloc] initWithFrame:frame]; + [self.contentView addSubview:_mostVisitedTile]; + _mostVisitedTile.translatesAutoresizingMaskIntoConstraints = NO; + AddSameConstraints(self.contentView, _mostVisitedTile); + self.isAccessibilityElement = YES; + } + return self; +} + +- (FaviconView*)faviconView { + return self.mostVisitedTile.faviconView; +} + +- (UILabel*)titleLabel { + return self.mostVisitedTile.titleLabel; +} + +- (void)setHighlighted:(BOOL)highlighted { + [super setHighlighted:highlighted]; + + [UIView transitionWithView:self + duration:ios::material::kDuration8 + options:UIViewAnimationOptionCurveEaseInOut + animations:^{ + self.alpha = highlighted ? 0.5 : 1.0; + } + completion:nil]; +} + ++ (CGSize)defaultSize { + return MostVisitedCellSize( + UIApplication.sharedApplication.preferredContentSizeCategory); +} + +- (CGSize)intrinsicContentSize { + return [[self class] defaultSize]; +} + +@end
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item.h b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item.h index 6b1c38c..e5c7ccb9 100644 --- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item.h +++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item.h
@@ -7,15 +7,16 @@ #include "components/ntp_tiles/tile_source.h" #include "components/ntp_tiles/tile_title_source.h" - -#import <UIKit/UIKit.h> +#import "ios/chrome/browser/ui/collection_view/cells/collection_view_item.h" +#import "ios/chrome/browser/ui/content_suggestions/cells/suggested_content.h" @protocol ContentSuggestionsGestureCommands; @class FaviconAttributes; class GURL; // Item containing a Most Visited suggestion. -@interface ContentSuggestionsMostVisitedItem : NSObject +@interface ContentSuggestionsMostVisitedItem + : CollectionViewItem<SuggestedContent> // Text for the title and the accessibility label of the cell. @property(nonatomic, copy, nonnull) NSString* title;
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item.mm b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item.mm index 69e30e3..cfc7afcb 100644 --- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item.mm +++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item.mm
@@ -6,6 +6,7 @@ #include "base/check.h" #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_gesture_commands.h" +#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_cell.h" #import "ios/chrome/common/ui/favicon/favicon_attributes.h" #import "ios/chrome/common/ui/favicon/favicon_view.h" #include "ios/chrome/grit/ios_strings.h" @@ -18,12 +19,41 @@ @implementation ContentSuggestionsMostVisitedItem +@synthesize suggestionIdentifier = _suggestionIdentifier; @synthesize attributes = _attributes; @synthesize title = _title; @synthesize URL = _URL; @synthesize titleSource = _titleSource; @synthesize source = _source; @synthesize commandHandler = _commandHandler; +@synthesize metricsRecorded = _metricsRecorded; + +- (instancetype)initWithType:(NSInteger)type { + self = [super initWithType:type]; + if (self) { + self.cellClass = [ContentSuggestionsMostVisitedCell class]; + } + return self; +} + +- (void)configureCell:(MDCCollectionViewCell*)cell { + [super configureCell:cell]; + if (![cell isKindOfClass:[ContentSuggestionsMostVisitedCell class]]) { + // Do not attempt to configure cell if it is not the correct class + // (crbug.com/1276562). + return; + } + ContentSuggestionsMostVisitedCell* mostVisitedCell = + static_cast<ContentSuggestionsMostVisitedCell*>(cell); + mostVisitedCell.titleLabel.text = self.title; + mostVisitedCell.accessibilityLabel = self.title; + [mostVisitedCell.faviconView configureWithAttributes:self.attributes]; + mostVisitedCell.accessibilityCustomActions = [self customActions]; +} + +- (CGFloat)cellHeightForWidth:(CGFloat)width { + return [ContentSuggestionsMostVisitedCell defaultSize].height; +} #pragma mark - AccessibilityCustomAction
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_parent_item.h b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_parent_item.h new file mode 100644 index 0000000..b92f06cc --- /dev/null +++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_parent_item.h
@@ -0,0 +1,55 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CELLS_CONTENT_SUGGESTIONS_PARENT_ITEM_H_ +#define IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CELLS_CONTENT_SUGGESTIONS_PARENT_ITEM_H_ + +#import <MaterialComponents/MaterialCollectionCells.h> + +#import "ios/chrome/browser/ui/collection_view/cells/collection_view_item.h" +#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_selection_actions.h" +#import "ios/chrome/browser/ui/content_suggestions/cells/suggested_content.h" +#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_menu_provider.h" + +@class ContentSuggestionsMostVisitedActionItem; +@class ContentSuggestionsMostVisitedItem; +@class ContentSuggestionsReturnToRecentTabItem; +@class ContentSuggestionsWhatsNewItem; + +// Item containing all the Content Suggestions content. +@interface ContentSuggestionsParentItem : CollectionViewItem <SuggestedContent> + +// The configuration for the Return To Recent Tab tile. +@property(nonatomic, strong) + ContentSuggestionsReturnToRecentTabItem* returnToRecentItem; +// The configuration for the NTP promo view. +@property(nonatomic, strong) ContentSuggestionsWhatsNewItem* whatsNewItem; +// The list of configurations for the Most Visited Tiles to be shown. +@property(nonatomic, strong) + NSArray<ContentSuggestionsMostVisitedItem*>* mostVisitedItems; +// The list of configurations for the Shortcuts to be shown. +@property(nonatomic, strong) + NSArray<ContentSuggestionsMostVisitedActionItem*>* shortcutsItems; + +// The target for the Most Visited tiles. +@property(nonatomic, weak) id<ContentSuggestionsSelectionActions> tapTarget; + +// Provider of menu configurations for the Most Visited tiles. +@property(nonatomic, weak) id<ContentSuggestionsMenuProvider> menuProvider; + +@end + +// The cell associated with ContentSuggestionsParentItem. +@interface ContentSuggestionsParentCell : MDCCollectionViewCell + +// Adds `view` as a subview. If `spacing` is non-zero, a bottom spacing of +// `spacing` will be added below `view`. +- (void)addUIElement:(UIView*)view withCustomBottomSpacing:(CGFloat)spacing; + +// Removes all UI elements added by addUIElement:withCustomBottomSpacing:. +- (void)removeContentViews; + +@end + +#endif // IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CELLS_CONTENT_SUGGESTIONS_PARENT_ITEM_H_
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_parent_item.mm b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_parent_item.mm new file mode 100644 index 0000000..8ef25e4c --- /dev/null +++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_parent_item.mm
@@ -0,0 +1,266 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_parent_item.h" + +#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_cells_constants.h" +#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_action_item.h" +#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item.h" +#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_tile_view.h" +#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_parent_item.h" +#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_return_to_recent_tab_item.h" +#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_return_to_recent_tab_view.h" +#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_shortcut_tile_view.h" +#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_tile_layout_util.h" +#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_whats_new_view.h" +#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_utils.h" +#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_constants.h" +#import "ios/chrome/common/material_timing.h" +#import "ios/chrome/common/ui/util/constraints_ui_util.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +@interface ContentSuggestionsParentItem () + +// List of all UITapGestureRecognizers created for the Most Visisted tiles. +@property(nonatomic, strong) + NSMutableArray<UITapGestureRecognizer*>* mostVisitedTapRecognizers; +// The UILongPressGestureRecognizer for the Return To Recent Tab tile. +@property(nonatomic, strong) + UITapGestureRecognizer* returnToRecentTabTapRecognizer; +@property(nonatomic, strong) + UILongPressGestureRecognizer* returnToRecentTabLongPressRecognizer; +// The UITapGestureRecognizer for the NTP promo view. +@property(nonatomic, strong) UITapGestureRecognizer* promoTapRecognizer; + +@end + +@implementation ContentSuggestionsParentItem +@synthesize metricsRecorded; +@synthesize suggestionIdentifier; + +- (instancetype)initWithType:(NSInteger)type { + self = [super initWithType:type]; + if (self) { + self.cellClass = [ContentSuggestionsParentCell class]; + } + return self; +} + +- (void)configureCell:(ContentSuggestionsParentCell*)cell { + [super configureCell:cell]; + + // Remove subviews from StackView in case prepareForReuse was not called (e.g. + // itemHasChanged: was called). + [cell removeContentViews]; + + CGFloat horizontalSpacing = + ContentSuggestionsTilesHorizontalSpacing(cell.traitCollection); + if (self.returnToRecentItem) { + ContentSuggestionsReturnToRecentTabView* returnToRecentTabTile = + [[ContentSuggestionsReturnToRecentTabView alloc] + initWithConfiguration:self.returnToRecentItem]; + self.returnToRecentTabTapRecognizer = [[UITapGestureRecognizer alloc] + initWithTarget:self.tapTarget + action:@selector(contentSuggestionsElementTapped:)]; + [returnToRecentTabTile + addGestureRecognizer:self.returnToRecentTabTapRecognizer]; + self.returnToRecentTabTapRecognizer.enabled = YES; + // Add long press functionality for the Return to Recent Tab tile. + self.returnToRecentTabLongPressRecognizer = + [[UILongPressGestureRecognizer alloc] + initWithTarget:self.tapTarget + action:@selector(contentSuggestionsElementTapped:)]; + self.returnToRecentTabLongPressRecognizer.minimumPressDuration = + ios::material::kDuration8; + self.returnToRecentTabLongPressRecognizer.enabled = YES; + [returnToRecentTabTile + addGestureRecognizer:self.returnToRecentTabLongPressRecognizer]; + [cell addUIElement:returnToRecentTabTile + withCustomBottomSpacing:content_suggestions:: + kReturnToRecentTabSectionBottomMargin]; + CGFloat cardWidth = content_suggestions::searchFieldWidth( + cell.bounds.size.width, cell.traitCollection); + [NSLayoutConstraint activateConstraints:@[ + [returnToRecentTabTile.widthAnchor constraintEqualToConstant:cardWidth], + [returnToRecentTabTile.heightAnchor + constraintEqualToConstant:kReturnToRecentTabSize.height] + ]]; + } + if (self.whatsNewItem) { + ContentSuggestionsWhatsNewView* whatsNewView = + [[ContentSuggestionsWhatsNewView alloc] + initWithConfiguration:self.whatsNewItem]; + self.promoTapRecognizer = [[UITapGestureRecognizer alloc] + initWithTarget:self.tapTarget + action:@selector(contentSuggestionsElementTapped:)]; + [whatsNewView addGestureRecognizer:self.promoTapRecognizer]; + self.promoTapRecognizer.enabled = YES; + [cell addUIElement:whatsNewView withCustomBottomSpacing:0]; + CGFloat width = + MostVisitedTilesContentHorizontalSpace(cell.traitCollection); + CGSize size = + MostVisitedCellSize(cell.traitCollection.preferredContentSizeCategory); + [NSLayoutConstraint activateConstraints:@[ + [whatsNewView.widthAnchor constraintEqualToConstant:width], + [whatsNewView.heightAnchor constraintEqualToConstant:size.height] + ]]; + } + if (self.mostVisitedItems) { + UIStackView* stackView = [[UIStackView alloc] init]; + stackView.axis = UILayoutConstraintAxisHorizontal; + stackView.alignment = UIStackViewAlignmentTop; + stackView.distribution = UIStackViewDistributionFillEqually; + stackView.spacing = horizontalSpacing; + NSUInteger index = 0; + for (ContentSuggestionsMostVisitedItem* item in self.mostVisitedItems) { + ContentSuggestionsMostVisitedTileView* view = + [[ContentSuggestionsMostVisitedTileView alloc] + initWithConfiguration:item]; + view.accessibilityIdentifier = [NSString + stringWithFormat: + @"%@%li", + kContentSuggestionsMostVisitedAccessibilityIdentifierPrefix, + index]; + view.menuProvider = self.menuProvider; + UITapGestureRecognizer* tapRecognizer = [[UITapGestureRecognizer alloc] + initWithTarget:self.tapTarget + action:@selector(contentSuggestionsElementTapped:)]; + [view addGestureRecognizer:tapRecognizer]; + [self.mostVisitedTapRecognizers addObject:tapRecognizer]; + [stackView addArrangedSubview:view]; + index++; + } + [cell addUIElement:stackView + withCustomBottomSpacing:kMostVisitedBottomMargin]; + CGFloat width = + MostVisitedTilesContentHorizontalSpace(cell.traitCollection); + CGSize size = + MostVisitedCellSize(cell.traitCollection.preferredContentSizeCategory); + [NSLayoutConstraint activateConstraints:@[ + [stackView.widthAnchor constraintEqualToConstant:width], + [stackView.heightAnchor constraintEqualToConstant:size.height] + ]]; + } + if (self.shortcutsItems) { + UIStackView* stackView = [[UIStackView alloc] init]; + stackView.axis = UILayoutConstraintAxisHorizontal; + stackView.alignment = UIStackViewAlignmentTop; + stackView.distribution = UIStackViewDistributionFillEqually; + stackView.spacing = horizontalSpacing; + NSUInteger index = 0; + for (ContentSuggestionsMostVisitedActionItem* item in self.shortcutsItems) { + ContentSuggestionsShortcutTileView* view = + [[ContentSuggestionsShortcutTileView alloc] + initWithConfiguration:item]; + view.accessibilityIdentifier = [NSString + stringWithFormat: + @"%@%li", + kContentSuggestionsShortcutsAccessibilityIdentifierPrefix, index]; + UITapGestureRecognizer* tapRecognizer = [[UITapGestureRecognizer alloc] + initWithTarget:self.tapTarget + action:@selector(contentSuggestionsElementTapped:)]; + [view addGestureRecognizer:tapRecognizer]; + [self.mostVisitedTapRecognizers addObject:tapRecognizer]; + [stackView addArrangedSubview:view]; + index++; + } + + [cell addUIElement:stackView withCustomBottomSpacing:0]; + CGFloat width = + MostVisitedTilesContentHorizontalSpace(cell.traitCollection); + CGSize size = + MostVisitedCellSize(cell.traitCollection.preferredContentSizeCategory); + [NSLayoutConstraint activateConstraints:@[ + [stackView.widthAnchor constraintEqualToConstant:width], + // The parent StackView is UIStackViewDistributionFill so there will be no + // spacing below the last element. Add what would be bottom spacing below + // the last row to the height of this StackView. + // TODO(crbug.com/1285378): Move this spacing to between the Feed header + // and the ContentSuggestions parent view when migrating to + // UIViewController. + [stackView.heightAnchor + constraintEqualToConstant:size.height + kMostVisitedBottomMargin], + ]]; + } +} + +// Returns the default height of the content subviews and the spacing in between +// them. +- (CGFloat)cellHeightForWidth:(CGFloat)width { + CGFloat height = 0; + if (self.mostVisitedItems) { + height += MostVisitedCellSize( + UIApplication.sharedApplication.preferredContentSizeCategory) + .height + + kMostVisitedBottomMargin; + } + if (self.shortcutsItems) { + height += MostVisitedCellSize( + UIApplication.sharedApplication.preferredContentSizeCategory) + .height + + kMostVisitedBottomMargin; + } + if (self.returnToRecentItem) { + height += (kReturnToRecentTabSize.height + + content_suggestions::kReturnToRecentTabSectionBottomMargin); + } + if (self.whatsNewItem) { + height += MostVisitedCellSize( + UIApplication.sharedApplication.preferredContentSizeCategory) + .height; + } + return height; +} + +@end + +#pragma mark - ContentSuggestionsParentCell + +@interface ContentSuggestionsParentCell () + +// StackView holding all subviews. +@property(nonatomic, strong) UIStackView* verticalStackView; + +@end + +@implementation ContentSuggestionsParentCell + +- (instancetype)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if (self) { + _verticalStackView = [[UIStackView alloc] init]; + _verticalStackView.translatesAutoresizingMaskIntoConstraints = NO; + _verticalStackView.axis = UILayoutConstraintAxisVertical; + // A centered alignment will ensure the views are centered. + _verticalStackView.alignment = UIStackViewAlignmentCenter; + // A fill distribution allows for the custom spacing between elements and + // height/width configurations for each row. + _verticalStackView.distribution = UIStackViewDistributionFill; + [self.contentView addSubview:_verticalStackView]; + AddSameConstraints(self.contentView, _verticalStackView); + } + return self; +} + +- (void)addUIElement:(UIView*)view withCustomBottomSpacing:(CGFloat)spacing { + [_verticalStackView addArrangedSubview:view]; + if (spacing > 0) { + [_verticalStackView setCustomSpacing:spacing afterView:view]; + } +} +- (void)removeContentViews { + for (UIView* view in [self.verticalStackView arrangedSubviews]) { + [view removeFromSuperview]; + } +} + +- (void)prepareForReuse { + [super prepareForReuse]; + [self removeContentViews]; +} + +@end
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_return_to_recent_tab_item.h b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_return_to_recent_tab_item.h index c9ae07f..b2eb8f8 100644 --- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_return_to_recent_tab_item.h +++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_return_to_recent_tab_item.h
@@ -5,6 +5,9 @@ #ifndef IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CELLS_CONTENT_SUGGESTIONS_RETURN_TO_RECENT_TAB_ITEM_H_ #define IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CELLS_CONTENT_SUGGESTIONS_RETURN_TO_RECENT_TAB_ITEM_H_ +#import "ios/chrome/browser/ui/collection_view/cells/collection_view_item.h" + +#import <MaterialComponents/MaterialCollectionCells.h> #import <UIKit/UIKit.h> #import "ios/chrome/browser/ui/content_suggestions/cells/suggested_content.h" @@ -13,7 +16,8 @@ @class FaviconAttributes; // Item containing a Return to Recent Tab Start Surface tile. -@interface ContentSuggestionsReturnToRecentTabItem : NSObject +@interface ContentSuggestionsReturnToRecentTabItem + : CollectionViewItem <SuggestedContent> // Favicon image of the page of the most recent tab. @property(nonatomic, strong) UIImage* icon; @@ -29,4 +33,19 @@ @end +@interface ContentSuggestionsReturnToRecentTabCell : MDCCollectionViewCell + +// Sets the title of the most recent tab tile. +- (void)setTitle:(NSString*)title; + +// sets the subtitle of the most recent tab tile. +- (void)setSubtitle:(NSString*)subtitle; + ++ (CGSize)defaultSize; + +// Sets the image that should be displayed at the leading edge of the cell. +- (void)setIconImage:(UIImage*)image; + +@end + #endif // IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CELLS_CONTENT_SUGGESTIONS_RETURN_TO_RECENT_TAB_ITEM_H_
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_return_to_recent_tab_item.mm b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_return_to_recent_tab_item.mm index f58ac02..6e55e3f 100644 --- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_return_to_recent_tab_item.mm +++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_return_to_recent_tab_item.mm
@@ -16,9 +16,87 @@ #endif @implementation ContentSuggestionsReturnToRecentTabItem +@synthesize metricsRecorded; +@synthesize suggestionIdentifier; + +- (instancetype)initWithType:(NSInteger)type { + self = [super initWithType:type]; + if (self) { + self.cellClass = [ContentSuggestionsReturnToRecentTabCell class]; + } + return self; +} + +- (void)configureCell:(ContentSuggestionsReturnToRecentTabCell*)cell { + [super configureCell:cell]; + [cell setTitle:self.title]; + [cell setSubtitle:self.subtitle]; + cell.accessibilityLabel = self.title; + if (self.icon) { + [cell setIconImage:self.icon]; + } +} - (CGFloat)cellHeightForWidth:(CGFloat)width { return kReturnToRecentTabSize.height; } @end + +#pragma mark - ContentSuggestionsReturnToRecentTabCell + +@interface ContentSuggestionsReturnToRecentTabCell () + +// Container view holding Return to Recent Tab tile. +@property(nonatomic, strong) + ContentSuggestionsReturnToRecentTabView* recentTabView; + +@end + +@implementation ContentSuggestionsReturnToRecentTabCell + +- (instancetype)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if (self) { + _recentTabView = + [[ContentSuggestionsReturnToRecentTabView alloc] initWithFrame:frame]; + [self.contentView addSubview:_recentTabView]; + _recentTabView.translatesAutoresizingMaskIntoConstraints = NO; + AddSameConstraints(self.contentView, _recentTabView); + self.isAccessibilityElement = YES; + } + return self; +} + +- (void)setHighlighted:(BOOL)highlighted { + [super setHighlighted:highlighted]; + __weak ContentSuggestionsReturnToRecentTabCell* weakSelf = self; + [UIView transitionWithView:self + duration:ios::material::kDuration8 + options:UIViewAnimationOptionCurveEaseInOut + animations:^{ + weakSelf.recentTabView.backgroundColor = + highlighted ? [UIColor colorNamed:kGrey100Color] + : [UIColor clearColor]; + } + completion:nil]; +} + +- (void)setTitle:(NSString*)title { + self.recentTabView.titleLabel.text = title; +} + +- (void)setSubtitle:(NSString*)subtitle { + self.recentTabView.subtitleLabel.text = subtitle; +} + ++ (CGSize)defaultSize { + return kReturnToRecentTabSize; +} + +- (void)setIconImage:(UIImage*)image { + self.recentTabView.iconImageView.image = image; + self.recentTabView.iconImageView.hidden = image == nil; +} + +@end
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_whats_new_item.h b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_whats_new_item.h index 652ebbe..edaf50b 100644 --- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_whats_new_item.h +++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_whats_new_item.h
@@ -5,10 +5,13 @@ #ifndef IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CELLS_CONTENT_SUGGESTIONS_WHATS_NEW_ITEM_H_ #define IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CELLS_CONTENT_SUGGESTIONS_WHATS_NEW_ITEM_H_ -#import <UIKit/UIKit.h> +#import <MaterialComponents/MaterialCollectionCells.h> + +#import "ios/chrome/browser/ui/collection_view/cells/collection_view_item.h" +#import "ios/chrome/browser/ui/content_suggestions/cells/suggested_content.h" // Item to display what is new in the ContentSuggestions. -@interface ContentSuggestionsWhatsNewItem : NSObject +@interface ContentSuggestionsWhatsNewItem : CollectionViewItem<SuggestedContent> // Icon for the promo. @property(nonatomic, strong, nullable) UIImage* icon; @@ -18,4 +21,17 @@ + (nonnull NSString*)accessibilityIdentifier; @end + +// Associated cell, displaying what is new. +@interface ContentSuggestionsWhatsNewCell : MDCCollectionViewCell + +// Sets the icon of the promo. +- (void)setIcon:(nullable UIImage*)icon; +// Sets the text displayed. +- (void)setText:(nullable NSString*)text; +// Returns the height needed by a cell contained in `width` containing `text`. ++ (CGFloat)heightForWidth:(CGFloat)width withText:(nullable NSString*)text; + +@end + #endif // IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CELLS_CONTENT_SUGGESTIONS_WHATS_NEW_ITEM_H_
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_whats_new_item.mm b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_whats_new_item.mm index 5438add..66157d83 100644 --- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_whats_new_item.mm +++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_whats_new_item.mm
@@ -16,15 +16,134 @@ #error "This file requires ARC support." #endif +namespace { +const CGFloat kLabelMargin = 14; +const CGFloat kLabelLineSpacing = 4; +const CGFloat kLabelIconMargin = 8; +const CGFloat kLabelFontSize = 14; +const CGFloat kIconSize = 24; +} // namespace + #pragma mark - ContentSuggestionsWhatsNewItem @implementation ContentSuggestionsWhatsNewItem @synthesize text = _text; @synthesize icon = _icon; +@synthesize suggestionIdentifier = _suggestionIdentifier; +@synthesize metricsRecorded = _metricsRecorded; + +- (instancetype)initWithType:(NSInteger)type { + self = [super initWithType:type]; + if (self) { + self.cellClass = [ContentSuggestionsWhatsNewCell class]; + } + return self; +} + +- (void)configureCell:(ContentSuggestionsWhatsNewCell*)cell { + [super configureCell:cell]; + [cell setIcon:self.icon]; + [cell setText:self.text]; + cell.accessibilityIdentifier = [[self class] accessibilityIdentifier]; +} + +- (CGFloat)cellHeightForWidth:(CGFloat)width { + return [ContentSuggestionsWhatsNewCell heightForWidth:width + withText:self.text]; +} + (NSString*)accessibilityIdentifier { return kContentSuggestionsWhatsNewIdentifier; } @end + +#pragma mark - ContentSuggestionsWhatsNewCell + +@interface ContentSuggestionsWhatsNewCell () + +// View containing all UI elements +@property(nonatomic, strong) ContentSuggestionsWhatsNewView* whatsNewView; + +@end + +@implementation ContentSuggestionsWhatsNewCell + +- (instancetype)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if (self) { + _whatsNewView = + [[ContentSuggestionsWhatsNewView alloc] initWithFrame:frame]; + [self.contentView addSubview:_whatsNewView]; + _whatsNewView.translatesAutoresizingMaskIntoConstraints = NO; + AddSameConstraints(self.contentView, _whatsNewView); + } + return self; +} + +- (void)setIcon:(UIImage*)icon { + self.whatsNewView.iconView.image = icon; +} + +- (void)setText:(NSString*)text { + [[self class] configureLabel:self.whatsNewView.promoLabel withText:text]; +} + ++ (CGFloat)heightForWidth:(CGFloat)width withText:(NSString*)text { + UILabel* label = [[UILabel alloc] init]; + [self configureLabel:label withText:text]; + CGSize sizeForLabel = CGSizeMake(width - kLabelIconMargin - kIconSize, 500); + + return 2 * kLabelMargin + [label sizeThatFits:sizeForLabel].height; +} + +#pragma mark UIView + +// Implements -layoutSubviews as per instructions in documentation for +// +[MDCCollectionViewCell cr_preferredHeightForWidth:forItem:]. +- (void)layoutSubviews { + [super layoutSubviews]; + + // Adjust the text label preferredMaxLayoutWidth when the parent's width + // changes, for instance on screen rotation. + CGFloat parentWidth = CGRectGetWidth(self.contentView.bounds); + + self.whatsNewView.promoLabel.preferredMaxLayoutWidth = + parentWidth - kIconSize - kLabelIconMargin; + + // Re-layout with the new preferred width to allow the label to adjust its + // height. + [super layoutSubviews]; +} + +#pragma mark Private + +// Configures the `promoLabel` with the `text`. ++ (void)configureLabel:(UILabel*)promoLabel withText:(NSString*)text { + promoLabel.font = [UIFont systemFontOfSize:kLabelFontSize + weight:UIFontWeightRegular]; + promoLabel.textColor = [UIColor colorNamed:kTextPrimaryColor]; + promoLabel.numberOfLines = 0; + + // Sets the line spacing on the attributed string. + NSMutableParagraphStyle* style = [[NSMutableParagraphStyle alloc] init]; + [style setLineSpacing:kLabelLineSpacing]; + NSDictionary* textAttributes = @{ + NSParagraphStyleAttributeName : style, + }; + + // Sets the styling to mimic a link. + NSDictionary* linkAttributes = @{ + NSForegroundColorAttributeName : [UIColor colorNamed:kBlueColor], + NSUnderlineStyleAttributeName : @(NSUnderlineStyleSingle), + NSUnderlineColorAttributeName : [UIColor colorNamed:kBlueColor], + }; + + NSAttributedString* attributedText = + AttributedStringFromStringWithLink(text, textAttributes, linkAttributes); + + [promoLabel setAttributedText:attributedText]; +} + +@end
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_whats_new_item_unittest.mm b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_whats_new_item_unittest.mm new file mode 100644 index 0000000..9c897bf --- /dev/null +++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_whats_new_item_unittest.mm
@@ -0,0 +1,50 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_whats_new_item.h" + +#include "testing/gtest/include/gtest/gtest.h" +#include "testing/platform_test.h" +#import "third_party/ocmock/OCMock/OCMock.h" +#import "third_party/ocmock/gtest_support.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +namespace { + +using ContentSuggestionsWhatsNewItemTest = PlatformTest; + +TEST_F(ContentSuggestionsWhatsNewItemTest, CellClass) { + // Setup. + ContentSuggestionsWhatsNewItem* item = + [[ContentSuggestionsWhatsNewItem alloc] initWithType:0]; + + // Action. + ContentSuggestionsWhatsNewCell* cell = [[[item cellClass] alloc] init]; + + // Test. + EXPECT_EQ([ContentSuggestionsWhatsNewCell class], [cell class]); +} + +TEST_F(ContentSuggestionsWhatsNewItemTest, Configure) { + // Setup. + UIImage* image = [[UIImage alloc] init]; + NSString* text = @"What's new test!"; + ContentSuggestionsWhatsNewItem* item = + [[ContentSuggestionsWhatsNewItem alloc] initWithType:0]; + item.icon = image; + item.text = text; + id cell = OCMClassMock([ContentSuggestionsWhatsNewCell class]); + OCMExpect([cell setIcon:image]); + OCMExpect([cell setText:text]); + + // Action. + [item configureCell:cell]; + + // Test. + ASSERT_OCMOCK_VERIFY(cell); +} +}
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_consumer.h b/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_consumer.h new file mode 100644 index 0000000..2e74837 --- /dev/null +++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_consumer.h
@@ -0,0 +1,39 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CONTENT_SUGGESTIONS_COLLECTION_CONSUMER_H_ +#define IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CONTENT_SUGGESTIONS_COLLECTION_CONSUMER_H_ + +#import "ios/chrome/browser/ui/content_suggestions/cells/suggested_content.h" + +@class CollectionViewItem; +@class ContentSuggestionsSectionInformation; +@protocol SuggestedContent; + +using CSCollectionViewItem = CollectionViewItem<SuggestedContent>; + +@protocol ContentSuggestionsCollectionConsumer + +// Informs the consumer to reload with `sections` and `items`. +- (void)reloadDataWithSections: + (NSArray<ContentSuggestionsSectionInformation*>*)sections + andItems:(NSMutableDictionary<NSNumber*, NSArray*>*)items; + +// Informs the consumer to add `sectionInfo` to the model and call `completion` +// if a section is added. If the section already exists, `completion` will not +// be called. +- (void)addSection:(ContentSuggestionsSectionInformation*)sectionInfo + withItems:(NSArray<CSCollectionViewItem*>*)items + completion:(void (^)(void))completion; + +// The section corresponding to `sectionInfo` has been invalidated and must be +// cleared now. +- (void)clearSection:(ContentSuggestionsSectionInformation*)sectionInfo; + +// Notifies the consumer that the `item` has changed. +- (void)itemHasChanged:(CollectionViewItem<SuggestedContent>*)item; + +@end + +#endif // IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CONTENT_SUGGESTIONS_COLLECTION_CONSUMER_H_
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_view_controller.h b/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_view_controller.h new file mode 100644 index 0000000..487a101 --- /dev/null +++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_view_controller.h
@@ -0,0 +1,99 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CONTENT_SUGGESTIONS_COLLECTION_VIEW_CONTROLLER_H_ +#define IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CONTENT_SUGGESTIONS_COLLECTION_VIEW_CONTROLLER_H_ + +#import <UIKit/UIKit.h> + +#import "ios/chrome/browser/ui/collection_view/collection_view_controller.h" +#import "ios/chrome/browser/ui/content_suggestions/cells/suggested_content.h" +#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_consumer.h" + +namespace { + +using CSCollectionViewModel = CollectionViewModel<CSCollectionViewItem*>; + +// Enum defining the type of a ContentSuggestions. +typedef NS_ENUM(NSInteger, ContentSuggestionType) { + // Use this type to pass information about an empty section. Suggestion of + // this type are empty and should not be displayed. The information to be + // displayed are contained in the SectionInfo. + ContentSuggestionTypeEmpty, + ContentSuggestionTypeMostVisited, + ContentSuggestionTypeReturnToRecentTab, + ContentSuggestionTypePromo, +}; + +// Enum defining the ItemTypes of this ContentSuggestionsViewController. +typedef NS_ENUM(NSInteger, ItemType) { + ItemTypeFooter = kItemTypeEnumZero, + ItemTypeHeader, + ItemTypeEmpty, + ItemTypeMostVisited, + ItemTypePromo, + ItemTypeReturnToRecentTab, + ItemTypeSingleCell, + ItemTypeUnknown, +}; + +// Enum defining the SectionIdentifiers of this +// ContentSuggestionsViewController. +typedef NS_ENUM(NSInteger, SectionIdentifier) { + SectionIdentifierMostVisited = kSectionIdentifierEnumZero, + SectionIdentifierLogo, + SectionIdentifierReturnToRecentTab, + SectionIdentifierPromo, + SectionIdentifierSingleCell, + SectionIdentifierDefault, +}; + +} // namespace + +@class ContentSuggestionsSectionInformation; +@protocol ContentSuggestionsActionHandler; +@protocol ContentSuggestionsCommands; +@protocol ContentSuggestionsHeaderControlling; +@protocol ContentSuggestionsMenuProvider; +@protocol ContentSuggestionsViewControllerAudience; +@protocol SuggestedContent; + +// CollectionViewController to display the suggestions items. +@interface ContentSuggestionsCollectionViewController + : CollectionViewController <ContentSuggestionsCollectionConsumer> + +// Inits view controller with `style`. +- (instancetype)initWithStyle:(CollectionViewControllerStyle)style + NS_DESIGNATED_INITIALIZER; + +- (instancetype)initWithLayout:(UICollectionViewLayout*)layout + style:(CollectionViewControllerStyle)style + NS_UNAVAILABLE; + +// Handler for the commands sent by the ContentSuggestionsViewController. +@property(nonatomic, weak) id<ContentSuggestionsCommands> + suggestionCommandHandler; +@property(nonatomic, weak) id<ContentSuggestionsViewControllerAudience> + audience; +// Override from superclass to have a more specific type. +@property(nonatomic, readonly) + CollectionViewModel<CollectionViewItem<SuggestedContent>*>* + collectionViewModel; +// Whether or not the contents section should be hidden completely. +@property(nonatomic, assign) BOOL contentSuggestionsEnabled; +// Provides information about the content suggestions header. Used to get the +// header height. +// TODO(crbug.com/1114792): Remove this and replace its call with refactored +// header synchronizer. +@property(nonatomic, weak) id<ContentSuggestionsHeaderControlling> + headerProvider; +// Delegate for handling actions relating to content suggestions. +@property(nonatomic, weak) id<ContentSuggestionsActionHandler> handler; +// Provider of menu configurations for the contentSuggestions component. +@property(nonatomic, weak) id<ContentSuggestionsMenuProvider> menuProvider; +// Returns the header view containing the logo and omnibox to be displayed. +- (UIView*)headerViewForWidth:(CGFloat)width; +@end + +#endif // IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CONTENT_SUGGESTIONS_COLLECTION_VIEW_CONTROLLER_H_
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_view_controller.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_view_controller.mm new file mode 100644 index 0000000..262071a --- /dev/null +++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_view_controller.mm
@@ -0,0 +1,770 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_view_controller.h" + +#include "base/mac/foundation_util.h" +#include "base/metrics/user_metrics.h" +#include "base/metrics/user_metrics_action.h" +#include "components/strings/grit/components_strings.h" +#import "ios/chrome/browser/ui/collection_view/cells/MDCCollectionViewCell+Chrome.h" +#import "ios/chrome/browser/ui/collection_view/cells/collection_view_item.h" +#import "ios/chrome/browser/ui/collection_view/collection_view_model.h" +#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_cells_constants.h" +#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_header_item.h" +#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_action_item.h" +#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_cell.h" +#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item.h" +#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_tile_view.h" +#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_parent_item.h" +#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_return_to_recent_tab_view.h" +#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_selection_actions.h" +#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_shortcut_tile_view.h" +#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_text_item.h" +#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_tile_layout_util.h" +#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_whats_new_view.h" +#import "ios/chrome/browser/ui/content_suggestions/cells/suggested_content.h" +#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_utils.h" +#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_commands.h" +#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_constants.h" +#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_feature.h" +#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_header_controlling.h" +#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_header_synchronizing.h" +#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_layout.h" +#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_menu_provider.h" +#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller_audience.h" +#import "ios/chrome/browser/ui/content_suggestions/identifier/content_suggestions_section_information.h" +#import "ios/chrome/browser/ui/content_suggestions/ntp_home_constant.h" +#import "ios/chrome/browser/ui/list_model/list_item+Controller.h" +#import "ios/chrome/browser/ui/ntp/new_tab_page_header_constants.h" +#import "ios/chrome/browser/ui/start_surface/start_surface_features.h" +#import "ios/chrome/browser/ui/toolbar/public/toolbar_utils.h" +#import "ios/chrome/browser/ui/ui_feature_flags.h" +#import "ios/chrome/browser/ui/util/uikit_ui_util.h" +#import "ios/chrome/common/material_timing.h" +#import "ios/chrome/common/ui/colors/semantic_color_names.h" +#import "ios/chrome/common/ui/util/constraints_ui_util.h" +#include "ui/base/l10n/l10n_util.h" +#include "url/gurl.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +namespace { +const CGFloat kCardBorderRadius = 11; +} // namespace + +@interface ContentSuggestionsCollectionViewController () < + UIGestureRecognizerDelegate, + ContentSuggestionsSelectionActions> + +// The layout of the content suggestions collection view. +@property(nonatomic, strong) ContentSuggestionsLayout* layout; + +// Dictionary keyed by SectionIdentifier containing section configuration +// information. +@property(nonatomic, strong) + NSMutableDictionary<NSNumber*, ContentSuggestionsSectionInformation*>* + sectionInfoBySectionIdentifier; + +// Ordered list of sections being shown. +@property(nonatomic, strong) + NSMutableArray<ContentSuggestionsSectionInformation*>* orderedSectionsInfo; +// Whether an item of type ItemTypePromo has already been added to the model. +@property(nonatomic, assign) BOOL promoAdded; + +@end + +@implementation ContentSuggestionsCollectionViewController + +@dynamic collectionViewModel; + +#pragma mark - Lifecycle + +- (instancetype)initWithStyle:(CollectionViewControllerStyle)style { + _layout = [[ContentSuggestionsLayout alloc] init]; + self = [super initWithLayout:_layout style:style]; + return self; +} + +#pragma mark - Public + +// Removes the `section`. +- (void)dismissSection:(NSInteger)section { + if (section >= [self numberOfSectionsInCollectionView:self.collectionView]) { + return; + } + + NSInteger sectionIdentifier = + [self.collectionViewModel sectionIdentifierForSectionIndex:section]; + + [self.collectionView + performBatchUpdates:^{ + [self.collectionViewModel + removeSectionWithIdentifier:sectionIdentifier]; + [self.collectionView + deleteSections:[NSIndexSet indexSetWithIndex:section]]; + } + completion:nil]; +} + +#pragma mark - UIViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.collectionView.prefetchingEnabled = NO; + // Overscroll action does not work well with content offset, so set this + // to never and internally offset the UI to account for safe area insets. + self.collectionView.contentInsetAdjustmentBehavior = + UIScrollViewContentInsetAdjustmentNever; + + self.collectionView.delegate = self; + self.collectionView.backgroundColor = ntp_home::kNTPBackgroundColor(); + self.styler.cellStyle = MDCCollectionViewCellStyleCard; + self.styler.cardBorderRadius = kCardBorderRadius; + self.styler.separatorColor = [UIColor clearColor]; + self.collectionView.translatesAutoresizingMaskIntoConstraints = NO; + + ApplyVisualConstraints(@[ @"V:|[collection]|", @"H:|[collection]|" ], + @{@"collection" : self.collectionView}); +} + +- (void)viewDidDisappear:(BOOL)animated { + [super viewDidDisappear:animated]; + if (ShouldShowReturnToMostRecentTabForStartSurface()) { + [self.audience viewDidDisappear]; + } +} + +#pragma mark - UICollectionViewDelegate + +- (void)collectionView:(UICollectionView*)collectionView + didSelectItemAtIndexPath:(NSIndexPath*)indexPath { + [super collectionView:collectionView didSelectItemAtIndexPath:indexPath]; + + CollectionViewItem* item = + [self.collectionViewModel itemAtIndexPath:indexPath]; + switch ([self contentSuggestionTypeForItem:item]) { + case ContentSuggestionTypeMostVisited: + [self.suggestionCommandHandler openMostVisitedItem:item + atIndex:indexPath.item]; + break; + case ContentSuggestionTypeReturnToRecentTab: + [self.suggestionCommandHandler openMostRecentTab]; + break; + case ContentSuggestionTypePromo: + [self dismissSection:indexPath.section]; + [self.suggestionCommandHandler handlePromoTapped]; + [self.collectionViewLayout invalidateLayout]; + break; + case ContentSuggestionTypeEmpty: + break; + } +} + +- (UICollectionViewCell*)collectionView:(UICollectionView*)collectionView + cellForItemAtIndexPath:(NSIndexPath*)indexPath { + UICollectionViewCell* cell = [super collectionView:collectionView + cellForItemAtIndexPath:indexPath]; + if ([self isMostVisitedSection:indexPath.section]) { + cell.accessibilityIdentifier = [NSString + stringWithFormat: + @"%@%li", + kContentSuggestionsMostVisitedAccessibilityIdentifierPrefix, + indexPath.row]; + // Apple doesn't handle the transparency of the background during animations + // linked to context menus. To prevent the cell from turning black during + // animations, its background is set to be the same as the NTP background. + // See: crbug.com/1120321. + cell.backgroundColor = ntp_home::kNTPBackgroundColor(); + [self.collectionViewModel itemAtIndexPath:indexPath] + .accessibilityIdentifier = cell.accessibilityIdentifier; + } + + return cell; +} + +- (UIContextMenuConfiguration*)collectionView:(UICollectionView*)collectionView + contextMenuConfigurationForItemAtIndexPath:(NSIndexPath*)indexPath + point:(CGPoint)point { + CollectionViewItem* item = + [self.collectionViewModel itemAtIndexPath:indexPath]; + + if (![item isKindOfClass:[ContentSuggestionsMostVisitedItem class]]) + return nil; + + ContentSuggestionsMostVisitedItem* contentSuggestionsItem = + base::mac::ObjCCastStrict<ContentSuggestionsMostVisitedItem>(item); + + return [self.menuProvider + contextMenuConfigurationForItem:contentSuggestionsItem + fromView:[self.collectionView + cellForItemAtIndexPath:indexPath]]; +} + +#pragma mark - UICollectionViewDelegateFlowLayout + +- (CGSize)collectionView:(UICollectionView*)collectionView + layout:(UICollectionViewLayout*)collectionViewLayout + sizeForItemAtIndexPath:(NSIndexPath*)indexPath { + if ([self isMostVisitedSection:indexPath.section]) { + return [ContentSuggestionsMostVisitedCell defaultSize]; + } + CGSize size = [super collectionView:collectionView + layout:collectionViewLayout + sizeForItemAtIndexPath:indexPath]; + return size; +} + +- (UIEdgeInsets)collectionView:(UICollectionView*)collectionView + layout:(UICollectionViewLayout*)collectionViewLayout + insetForSectionAtIndex:(NSInteger)section { + UIEdgeInsets parentInset = [super collectionView:collectionView + layout:collectionViewLayout + insetForSectionAtIndex:section]; + if ([self isHeaderSection:section] || [self isSingleCellSection:section]) { + parentInset.top = 0; + parentInset.left = 0; + parentInset.right = 0; + } else if ([self isReturnToRecentTabSection:section]) { + CGFloat collectionWidth = collectionView.bounds.size.width; + CGFloat maxCardWidth = content_suggestions::searchFieldWidth( + collectionWidth, self.traitCollection); + CGFloat margin = + MAX(0, (collectionView.frame.size.width - maxCardWidth) / 2); + parentInset.left = margin; + parentInset.right = margin; + parentInset.bottom = + content_suggestions::kReturnToRecentTabSectionBottomMargin; + } else if ([self isMostVisitedSection:section] || + [self isPromoSection:section]) { + CGFloat margin = CenteredTilesMarginForWidth( + self.traitCollection, collectionView.frame.size.width); + parentInset.left = margin; + parentInset.right = margin; + if ([self isMostVisitedSection:section]) { + parentInset.bottom = kMostVisitedBottomMargin; + } + } + return parentInset; +} + +- (CGFloat)collectionView:(UICollectionView*)collectionView + layout:(UICollectionViewLayout*) + collectionViewLayout + minimumLineSpacingForSectionAtIndex:(NSInteger)section { + if ([self isMostVisitedSection:section]) { + return kContentSuggestionsTilesVerticalSpacing; + } + return [super collectionView:collectionView + layout:collectionViewLayout + minimumLineSpacingForSectionAtIndex:section]; +} + +#pragma mark - MDCCollectionViewStylingDelegate + +- (BOOL)collectionView:(UICollectionView*)collectionView + hidesInkViewAtIndexPath:(NSIndexPath*)indexPath { + return YES; +} + +- (UIColor*)collectionView:(nonnull UICollectionView*)collectionView + cellBackgroundColorAtIndexPath:(nonnull NSIndexPath*)indexPath { + if ([self shouldUseCustomStyleForSection:indexPath.section]) { + return UIColor.clearColor; + } + return ntp_home::kNTPBackgroundColor(); +} + +- (CGSize)collectionView:(UICollectionView*)collectionView + layout: + (UICollectionViewLayout*)collectionViewLayout + referenceSizeForHeaderInSection:(NSInteger)section { + if ([self isHeaderSection:section]) { + DCHECK(!IsContentSuggestionsHeaderMigrationEnabled()); + return CGSizeMake(0, [self.headerProvider headerHeight]); + } + CGSize defaultSize = [super collectionView:collectionView + layout:collectionViewLayout + referenceSizeForHeaderInSection:section]; + if (UIContentSizeCategoryIsAccessibilityCategory( + self.traitCollection.preferredContentSizeCategory)) { + // Double the size of the header as it is now on two lines. + defaultSize.height *= 2; + } + return defaultSize; +} + +- (BOOL)collectionView:(nonnull UICollectionView*)collectionView + shouldHideItemBackgroundAtIndexPath:(nonnull NSIndexPath*)indexPath { + return [self shouldUseCustomStyleForSection:indexPath.section]; +} + +- (BOOL)collectionView:(UICollectionView*)collectionView + shouldHideHeaderBackgroundForSection:(NSInteger)section { + return [self shouldUseCustomStyleForSection:section]; +} + +- (CGFloat)collectionView:(UICollectionView*)collectionView + cellHeightAtIndexPath:(NSIndexPath*)indexPath { + CSCollectionViewItem* item = + [self.collectionViewModel itemAtIndexPath:indexPath]; + UIEdgeInsets inset = [self collectionView:collectionView + layout:collectionView.collectionViewLayout + insetForSectionAtIndex:indexPath.section]; + CGFloat width = + CGRectGetWidth(collectionView.bounds) - inset.left - inset.right; + + return [item cellHeightForWidth:width]; +} + +- (BOOL)collectionView:(UICollectionView*)collectionView + shouldHideHeaderSeparatorForSection:(NSInteger)section { + return [self shouldUseCustomStyleForSection:section]; +} + +#pragma mark - UIGestureRecognizerDelegate + +- (BOOL)gestureRecognizer:(UIGestureRecognizer*)gestureRecognizer + shouldReceiveTouch:(UITouch*)touch { + return touch.view.accessibilityIdentifier != + ntp_home::FakeOmniboxAccessibilityID() && + touch.view.superview.accessibilityIdentifier != + ntp_home::FakeOmniboxAccessibilityID(); +} + +#pragma mark - ContentSuggestionsCollectionConsumer + +- (void)reloadDataWithSections: + (NSArray<ContentSuggestionsSectionInformation*>*)sections + andItems: + (NSMutableDictionary<NSNumber*, NSArray*>*)items { + [self resetModels]; + self.orderedSectionsInfo = [sections mutableCopy]; + + // The data is reset, add the new data directly in the model then reload the + // collection. + [self addSectionsForSectionInfoToModel:sections withItems:items]; + for (ContentSuggestionsSectionInformation* sectionInfo in sections) { + if (sectionInfo.sectionID == ContentSuggestionsSectionSingleCell) { + DCHECK(IsSingleCellContentSuggestionsEnabled()); + DCHECK_EQ(1.0, [items[@(sectionInfo.sectionID)] count]); + ContentSuggestionsParentItem* item = + static_cast<ContentSuggestionsParentItem*>( + items[@(sectionInfo.sectionID)][0]); + item.tapTarget = self; + item.menuProvider = self.menuProvider; + } + [self addSuggestionsToModel:items[@(sectionInfo.sectionID)] + withSectionInfo:sectionInfo]; + } + [self.collectionView reloadData]; +} + +- (void)addSection:(ContentSuggestionsSectionInformation*)sectionInfo + withItems:(NSArray<CSCollectionViewItem*>*)items + completion:(void (^)(void))completion { + SectionIdentifier sectionIdentifier = + [self sectionIdentifierForInfo:sectionInfo]; + CSCollectionViewModel* model = self.collectionViewModel; + + if ([model hasSectionForSectionIdentifier:sectionIdentifier]) + return; + + auto addSectionBlock = ^{ + NSIndexSet* addedSection = [self + addSectionsForSectionInfoToModel:@[ sectionInfo ] + withItems:@{@(sectionInfo.sectionID) : items}]; + [self.collectionView insertSections:addedSection]; + NSArray<NSIndexPath*>* addedItems = + [self addSuggestionsToModel:items withSectionInfo:sectionInfo]; + [self.collectionView insertItemsAtIndexPaths:addedItems]; + }; + + [UIView performWithoutAnimation:^{ + [self.collectionView performBatchUpdates:addSectionBlock + completion:^(BOOL finished) { + completion(); + }]; + }]; +} + +- (void)clearSection:(ContentSuggestionsSectionInformation*)sectionInfo { + SectionIdentifier sectionIdentifier = + [self sectionIdentifierForInfo:sectionInfo]; + CSCollectionViewModel* model = self.collectionViewModel; + + if (![model hasSectionForSectionIdentifier:sectionIdentifier]) + return; + + NSInteger section = [model sectionForSectionIdentifier:sectionIdentifier]; + + [self dismissSection:section]; +} + +- (void)itemHasChanged:(CollectionViewItem<SuggestedContent>*)item { + if (![self.collectionViewModel hasItem:item]) { + return; + } + if (IsSingleCellContentSuggestionsEnabled()) { + ContentSuggestionsParentItem* parentItem = + static_cast<ContentSuggestionsParentItem*>(item); + parentItem.tapTarget = self; + } + [self reconfigureCellsForItems:@[ item ]]; +} + +#pragma mark - UIAccessibilityAction + +- (BOOL)accessibilityScroll:(UIAccessibilityScrollDirection)direction { + CGFloat toolbarHeight = + ToolbarExpandedHeight(self.traitCollection.preferredContentSizeCategory); + // The collection displays the fake omnibox on the top of the other elements. + // The default scrolling action scrolls for the full height of the collection, + // hiding elements behing the fake omnibox. This reduces the scrolling by the + // height of the fake omnibox. + if (direction == UIAccessibilityScrollDirectionDown) { + CGFloat newYOffset = self.collectionView.contentOffset.y + + self.collectionView.bounds.size.height - toolbarHeight; + newYOffset = MIN(self.collectionView.contentSize.height - + self.collectionView.bounds.size.height, + newYOffset); + self.collectionView.contentOffset = + CGPointMake(self.collectionView.contentOffset.x, newYOffset); + } else if (direction == UIAccessibilityScrollDirectionUp) { + CGFloat newYOffset = self.collectionView.contentOffset.y - + self.collectionView.bounds.size.height + toolbarHeight; + newYOffset = MAX(0, newYOffset); + self.collectionView.contentOffset = + CGPointMake(self.collectionView.contentOffset.x, newYOffset); + } else { + return NO; + } + return YES; +} + +#pragma mark - ContentSuggestionsSelectionActions + +- (void)contentSuggestionsElementTapped:(UIGestureRecognizer*)sender { + if ([sender.view + isKindOfClass:[ContentSuggestionsMostVisitedTileView class]]) { + ContentSuggestionsMostVisitedTileView* mostVisitedView = + static_cast<ContentSuggestionsMostVisitedTileView*>(sender.view); + [self.suggestionCommandHandler + openMostVisitedItem:mostVisitedView.config + atIndex:mostVisitedView.config.index]; + } else if ([sender.view + isKindOfClass:[ContentSuggestionsShortcutTileView class]]) { + ContentSuggestionsShortcutTileView* shortcutView = + static_cast<ContentSuggestionsShortcutTileView*>(sender.view); + int index = static_cast<int>(shortcutView.config.index); + [self.suggestionCommandHandler openMostVisitedItem:shortcutView.config + atIndex:index]; + } else if ([sender.view isKindOfClass:[ContentSuggestionsReturnToRecentTabView + class]]) { + ContentSuggestionsReturnToRecentTabView* returnToRecentTabView = + static_cast<ContentSuggestionsReturnToRecentTabView*>(sender.view); + __weak ContentSuggestionsReturnToRecentTabView* weakRecentTabView = + returnToRecentTabView; + UIGestureRecognizerState state = sender.state; + if (state == UIGestureRecognizerStateChanged || + state == UIGestureRecognizerStateCancelled) { + // Do nothing if isn't a gesture start or end. + // If the gesture was cancelled by the system, then reset the background + // color since UIGestureRecognizerStateEnded will not be received. + if (state == UIGestureRecognizerStateCancelled) { + returnToRecentTabView.backgroundColor = [UIColor clearColor]; + } + return; + } + BOOL touchBegan = state == UIGestureRecognizerStateBegan; + [UIView transitionWithView:returnToRecentTabView + duration:ios::material::kDuration8 + options:UIViewAnimationOptionCurveEaseInOut + animations:^{ + weakRecentTabView.backgroundColor = + touchBegan ? [UIColor colorNamed:kGrey100Color] + : [UIColor clearColor]; + } + completion:nil]; + if (state == UIGestureRecognizerStateEnded) { + CGPoint point = [sender locationInView:returnToRecentTabView]; + if (point.x < 0 || point.y < 0 || + point.x > kReturnToRecentTabSize.width || + point.y > kReturnToRecentTabSize.height) { + // Reset the highlighted state and do nothing if the gesture ended + // outside of the tile. + returnToRecentTabView.backgroundColor = [UIColor clearColor]; + return; + } + [self.suggestionCommandHandler openMostRecentTab]; + } + } else if ([sender.view + isKindOfClass:[ContentSuggestionsWhatsNewView class]]) { + [self.suggestionCommandHandler handlePromoTapped]; + } +} + +#pragma mark - Private + +// Checks if the `section` is empty and add an empty element if it is the case. +// Must be called from inside a performBatchUpdates: block. +- (void)addEmptySectionPlaceholderIfNeeded:(NSInteger)section { + if ([self.collectionViewModel numberOfItemsInSection:section] > 0) + return; + + NSIndexPath* emptyItem = [self addEmptyItemForSection:section]; + if (emptyItem) + [self.collectionView insertItemsAtIndexPaths:@[ emptyItem ]]; +} + +// Returns the ContentSuggestionType associated with an ItemType `type`. +- (ContentSuggestionType)contentSuggestionTypeForItemType:(NSInteger)type { + switch (type) { + case ItemTypeEmpty: + return ContentSuggestionTypeEmpty; + case ItemTypeReturnToRecentTab: + return ContentSuggestionTypeReturnToRecentTab; + case ItemTypeMostVisited: + return ContentSuggestionTypeMostVisited; + case ItemTypePromo: + return ContentSuggestionTypePromo; + default: + return ContentSuggestionTypeEmpty; + } +} + +// Returns the item type corresponding to the section `info`. +- (ItemType)itemTypeForInfo:(ContentSuggestionsSectionInformation*)info { + switch (info.sectionID) { + case ContentSuggestionsSectionReturnToRecentTab: + return ItemTypeReturnToRecentTab; + case ContentSuggestionsSectionMostVisited: + return ItemTypeMostVisited; + case ContentSuggestionsSectionPromo: + return ItemTypePromo; + case ContentSuggestionsSectionSingleCell: + return ItemTypeSingleCell; + case ContentSuggestionsSectionLogo: + case ContentSuggestionsSectionUnknown: + return ItemTypeUnknown; + } +} + +// Returns the section identifier corresponding to the section `info`. +- (SectionIdentifier)sectionIdentifierForInfo: + (ContentSuggestionsSectionInformation*)info { + switch (info.sectionID) { + case ContentSuggestionsSectionMostVisited: + return SectionIdentifierMostVisited; + case ContentSuggestionsSectionLogo: + return SectionIdentifierLogo; + case ContentSuggestionsSectionReturnToRecentTab: + return SectionIdentifierReturnToRecentTab; + case ContentSuggestionsSectionPromo: + return SectionIdentifierPromo; + case ContentSuggestionsSectionSingleCell: + return SectionIdentifierSingleCell; + case ContentSuggestionsSectionUnknown: + return SectionIdentifierDefault; + } +} + +- (BOOL)shouldUseCustomStyleForSection:(NSInteger)section { + NSNumber* identifier = + @([self.collectionViewModel sectionIdentifierForSectionIndex:section]); + ContentSuggestionsSectionInformation* sectionInformation = + self.sectionInfoBySectionIdentifier[identifier]; + return sectionInformation.layout == ContentSuggestionsSectionLayoutCustom; +} + +- (ContentSuggestionType)contentSuggestionTypeForItem: + (CollectionViewItem*)item { + return [self contentSuggestionTypeForItemType:item.type]; +} + +- (NSArray<NSIndexPath*>*) + addSuggestionsToModel:(NSArray<CSCollectionViewItem*>*)suggestions + withSectionInfo:(ContentSuggestionsSectionInformation*)sectionInfo { + NSMutableArray<NSIndexPath*>* indexPaths = [NSMutableArray array]; + + CSCollectionViewModel* model = self.collectionViewModel; + NSInteger sectionIdentifier = [self sectionIdentifierForInfo:sectionInfo]; + + if (suggestions.count == 0) { + // No suggestions for this section. Add the item signaling this section is + // empty if there is currently no item in it. + if ([model hasSectionForSectionIdentifier:sectionIdentifier] && + [model numberOfItemsInSection:[model sectionForSectionIdentifier: + sectionIdentifier]] == 0) { + NSIndexPath* emptyItemIndexPath = + [self addEmptyItemForSection: + [model sectionForSectionIdentifier:sectionIdentifier]]; + if (emptyItemIndexPath) { + [indexPaths addObject:emptyItemIndexPath]; + } + } + return indexPaths; + } + + // Add the items from this section. + [suggestions enumerateObjectsUsingBlock:^(CSCollectionViewItem* item, + NSUInteger index, BOOL* stop) { + ItemType type = [self itemTypeForInfo:sectionInfo]; + if (type == ItemTypePromo && !self.promoAdded) { + self.promoAdded = YES; + [self.audience promoShown]; + } + item.type = type; + NSIndexPath* addedIndexPath = [self addItem:item + toSectionWithIdentifier:sectionIdentifier]; + + [indexPaths addObject:addedIndexPath]; + }]; + + return indexPaths; +} + +- (NSIndexSet*) + addSectionsForSectionInfoToModel: + (NSArray<ContentSuggestionsSectionInformation*>*)sectionsInfo + withItems:(NSDictionary<NSNumber*, NSArray*>*)items { + NSMutableIndexSet* addedSectionIdentifiers = [NSMutableIndexSet indexSet]; + + CSCollectionViewModel* model = self.collectionViewModel; + for (ContentSuggestionsSectionInformation* sectionInfo in sectionsInfo) { + NSInteger sectionIdentifier = [self sectionIdentifierForInfo:sectionInfo]; + NSArray* itemsArray = items[@(sectionInfo.sectionID)]; + if ([model hasSectionForSectionIdentifier:sectionIdentifier] || + (!sectionInfo.showIfEmpty && [itemsArray count] == 0)) { + continue; + } + + NSUInteger sectionIndex = 0; + for (ContentSuggestionsSectionInformation* orderedSectionInfo in self + .orderedSectionsInfo) { + NSInteger orderedSectionIdentifier = + [self sectionIdentifierForInfo:orderedSectionInfo]; + if (orderedSectionIdentifier == sectionIdentifier) { + break; + } + if ([model hasSectionForSectionIdentifier:orderedSectionIdentifier]) { + sectionIndex++; + } + } + [model insertSectionWithIdentifier:sectionIdentifier atIndex:sectionIndex]; + + self.sectionInfoBySectionIdentifier[@(sectionIdentifier)] = sectionInfo; + [addedSectionIdentifiers addIndex:sectionIdentifier]; + + if (sectionIdentifier == SectionIdentifierLogo) { + [self addLogoHeaderIfNeeded]; + } + } + + NSMutableIndexSet* indexSet = [NSMutableIndexSet indexSet]; + [addedSectionIdentifiers enumerateIndexesUsingBlock:^( + NSUInteger sectionIdentifier, BOOL* stop) { + [indexSet addIndex:[model sectionForSectionIdentifier:sectionIdentifier]]; + }]; + return indexSet; +} + +- (NSIndexPath*)addEmptyItemForSection:(NSInteger)section { + CSCollectionViewModel* model = self.collectionViewModel; + NSInteger sectionIdentifier = + [model sectionIdentifierForSectionIndex:section]; + ContentSuggestionsSectionInformation* sectionInfo = + self.sectionInfoBySectionIdentifier[@(sectionIdentifier)]; + + CSCollectionViewItem* item = [self emptyItemForSectionInfo:sectionInfo]; + if (!item) { + return nil; + } + return [self addItem:item toSectionWithIdentifier:sectionIdentifier]; +} + +- (BOOL)isReturnToRecentTabSection:(NSInteger)section { + return [self.collectionViewModel sectionIdentifierForSectionIndex:section] == + SectionIdentifierReturnToRecentTab; +} + +- (BOOL)isMostVisitedSection:(NSInteger)section { + return [self.collectionViewModel sectionIdentifierForSectionIndex:section] == + SectionIdentifierMostVisited; +} + +- (BOOL)isHeaderSection:(NSInteger)section { + return [self.collectionViewModel sectionIdentifierForSectionIndex:section] == + SectionIdentifierLogo; +} + +- (BOOL)isPromoSection:(NSInteger)section { + return [self.collectionViewModel sectionIdentifierForSectionIndex:section] == + SectionIdentifierPromo; +} + +- (BOOL)isSingleCellSection:(NSInteger)section { + return [self.collectionViewModel sectionIdentifierForSectionIndex:section] == + SectionIdentifierSingleCell; +} + +// Adds the header for the first section, containing the logo and the omnibox, +// if there is no header for the section. +- (void)addLogoHeaderIfNeeded { + DCHECK(!IsContentSuggestionsHeaderMigrationEnabled()); + if (![self.collectionViewModel + headerForSectionWithIdentifier:SectionIdentifierLogo]) { + ContentSuggestionsHeaderItem* header = + [[ContentSuggestionsHeaderItem alloc] initWithType:ItemTypeHeader]; + header.view = + [self headerViewForWidth:self.collectionView.bounds.size.width]; + [self.collectionViewModel setHeader:header + forSectionWithIdentifier:SectionIdentifierLogo]; + } +} + +- (UIView*)headerViewForWidth:(CGFloat)width { + return [self.headerProvider + headerForWidth:width + safeAreaInsets:[self.audience safeAreaInsetsForDiscoverFeed]]; +} + +// Resets the models, removing the current CollectionViewItem and the +// SectionInfo. +- (void)resetModels { + [self loadModel]; + self.sectionInfoBySectionIdentifier = [[NSMutableDictionary alloc] init]; +} + +// Returns a item to be displayed when the section identified by `sectionInfo` +// is empty. +// Returns nil if there is no empty item for this section info. +- (CSCollectionViewItem*)emptyItemForSectionInfo: + (ContentSuggestionsSectionInformation*)sectionInfo { + if (!sectionInfo.emptyText || !sectionInfo.expanded) + return nil; + ContentSuggestionsTextItem* item = + [[ContentSuggestionsTextItem alloc] initWithType:ItemTypeEmpty]; + item.text = l10n_util::GetNSString(IDS_NTP_TITLE_NO_SUGGESTIONS); + item.detailText = sectionInfo.emptyText; + + return item; +} + +// Adds `item` to `sectionIdentifier` section of the model of the +// CollectionView. Returns the IndexPath of the newly added item. +- (NSIndexPath*)addItem:(CSCollectionViewItem*)item + toSectionWithIdentifier:(NSInteger)sectionIdentifier { + CSCollectionViewModel* model = self.collectionViewModel; + NSInteger section = [model sectionForSectionIdentifier:sectionIdentifier]; + NSInteger itemNumber = [model numberOfItemsInSection:section]; + [model addItem:item toSectionWithIdentifier:sectionIdentifier]; + + return [NSIndexPath indexPathForItem:itemNumber inSection:section]; +} + +@end
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_commands.h b/ios/chrome/browser/ui/content_suggestions/content_suggestions_commands.h index 5385567..6fa389e 100644 --- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_commands.h +++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_commands.h
@@ -13,7 +13,8 @@ @protocol ContentSuggestionsCommands // Opens the Most Visited associated with this `item` at the `mostVisitedItem`. -- (void)openMostVisitedItem:(NSObject*)item atIndex:(NSInteger)mostVisitedIndex; +- (void)openMostVisitedItem:(CollectionViewItem*)item + atIndex:(NSInteger)mostVisitedIndex; // Handles the actions tapping the "Return to Recent Tab" item that returns the // user to the last opened tab. - (void)openMostRecentTab;
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_coordinator.h b/ios/chrome/browser/ui/content_suggestions/content_suggestions_coordinator.h index 4bcd486..ad413b4 100644 --- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_coordinator.h +++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_coordinator.h
@@ -33,7 +33,17 @@ // YES if the coordinator has started. If YES, start is a no-op. @property(nonatomic, readonly) BOOL started; -// The ViewController that this coordinator managers. +@property(nonatomic, strong, readonly) + ContentSuggestionsHeaderViewController* headerController; + +// The CollectionView that this coordinator manages. +@property(nonatomic, strong, readonly) + UICollectionViewController* contentSuggestionsCollectionViewController; + +// The ViewController that this coordinator managers if +// kContentSuggestionsUIViewControllerMigration is enabled. +// TODO(crbug.com/1285378): remove `contentSuggestionsCollectionViewController` +// once migration is finished. @property(nonatomic, strong, readonly) ContentSuggestionsViewController* viewController; @@ -53,6 +63,13 @@ // Delegate used to communicate to communicate events to the feed. @property(nonatomic, weak) id<FeedDelegate> feedDelegate; +// Stop any scrolling in the scroll view. +- (void)stopScrolling; + +// The content inset and offset of the scroll view. +- (UIEdgeInsets)contentInset; +- (CGPoint)contentOffset; + // Reloads the suggestions. - (void)reload;
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_coordinator.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_coordinator.mm index 622ec0e..cdd114e 100644 --- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_coordinator.mm +++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_coordinator.mm
@@ -37,6 +37,7 @@ #import "ios/chrome/browser/ui/commands/omnibox_commands.h" #import "ios/chrome/browser/ui/commands/open_new_tab_command.h" #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item.h" +#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_view_controller.h" #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_constants.h" #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_feature.h" #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_header_commands.h" @@ -77,6 +78,7 @@ #endif @interface ContentSuggestionsCoordinator () < + AppStateObserver, ContentSuggestionsHeaderCommands, ContentSuggestionsMenuProvider, ContentSuggestionsViewControllerAudience, @@ -85,6 +87,9 @@ // StartSurfaceRecentTabObserverBridge. std::unique_ptr<StartSurfaceRecentTabObserverBridge> _startSurfaceObserver; } + +@property(nonatomic, strong) + ContentSuggestionsCollectionViewController* collectionViewController; @property(nonatomic, strong) ContentSuggestionsViewController* contentSuggestionsViewController; @property(nonatomic, strong) @@ -93,6 +98,9 @@ ContentSuggestionsHeaderSynchronizer* headerCollectionInteractionHandler; @property(nonatomic, strong) URLDragDropHandler* dragDropHandler; @property(nonatomic, strong) ActionSheetCoordinator* alertCoordinator; +// Redefined as readwrite. +@property(nonatomic, strong, readwrite) + ContentSuggestionsHeaderViewController* headerController; @property(nonatomic, assign) BOOL contentSuggestionsEnabled; // Authentication Service for the user's signed-in state. @property(nonatomic, assign) AuthenticationService* authService; @@ -130,6 +138,37 @@ prefs->GetBoolean(prefs::kArticlesForYouEnabled) && prefs->GetBoolean(prefs::kNTPContentSuggestionsEnabled); + if (!IsContentSuggestionsHeaderMigrationEnabled()) { + self.headerController = + [[ContentSuggestionsHeaderViewController alloc] init]; + // TODO(crbug.com/1045047): Use HandlerForProtocol after commands protocol + // clean up. + self.headerController.dispatcher = + static_cast<id<ApplicationCommands, BrowserCommands, OmniboxCommands, + FakeboxFocuser>>(self.browser->GetCommandDispatcher()); + self.headerController.commandHandler = self; + self.headerController.delegate = self.ntpMediator; + + self.headerController.readingListModel = + ReadingListModelFactory::GetForBrowserState( + self.browser->GetBrowserState()); + self.headerController.toolbarDelegate = self.toolbarDelegate; + + // Only handle app state for the new First Run UI. + if (base::FeatureList::IsEnabled(kEnableFREUIModuleIOS)) { + SceneState* sceneState = + SceneStateBrowserAgent::FromBrowser(self.browser)->GetSceneState(); + AppState* appState = sceneState.appState; + [appState addObserver:self]; + + // Do not focus on omnibox for voice over if there are other screens to + // show. + if (appState.initStage < InitStageFinal) { + self.headerController.focusOmniboxWhenViewAppears = NO; + } + } + } + favicon::LargeIconService* largeIconService = IOSChromeLargeIconServiceFactory::GetForBrowserState( self.browser->GetBrowserState()); @@ -165,24 +204,83 @@ self.contentSuggestionsMediator.webState = self.webState; [self configureStartSurfaceIfNeeded]; + if (!IsContentSuggestionsHeaderMigrationEnabled()) { + self.headerController.promoCanShow = + [self.contentSuggestionsMediator notificationPromo]->CanShow(); + } + + if (IsContentSuggestionsUIViewControllerMigrationEnabled()) { self.contentSuggestionsViewController = [[ContentSuggestionsViewController alloc] init]; self.contentSuggestionsViewController.suggestionCommandHandler = self.contentSuggestionsMediator; self.contentSuggestionsViewController.audience = self; self.contentSuggestionsViewController.menuProvider = self; + } else { + self.collectionViewController = + [[ContentSuggestionsCollectionViewController alloc] + initWithStyle:CollectionViewControllerStyleDefault]; + self.collectionViewController.suggestionCommandHandler = + self.contentSuggestionsMediator; + self.collectionViewController.audience = self; + self.collectionViewController.contentSuggestionsEnabled = + self.contentSuggestionsEnabled; + self.collectionViewController.menuProvider = self; + } - self.contentSuggestionsMediator.consumer = - self.contentSuggestionsViewController; + if (IsContentSuggestionsHeaderMigrationEnabled()) { + if (IsContentSuggestionsUIViewControllerMigrationEnabled()) { + self.contentSuggestionsMediator.consumer = + self.contentSuggestionsViewController; + } else { + self.contentSuggestionsMediator.collectionConsumer = + self.collectionViewController; + } + } - self.ntpMediator.suggestionsMediator = self.contentSuggestionsMediator; - [self.ntpMediator setUp]; + if (!IsContentSuggestionsHeaderMigrationEnabled()) { + self.ntpMediator.consumer = self.headerController; + } + // IsContentSuggestionsUIViewControllerMigrationEnabled() doesn't need to set + // the suggestionsViewController since it won't be retrieving an item's index + // from the CollectionView model. + if (!IsContentSuggestionsUIViewControllerMigrationEnabled()) { + self.ntpMediator.suggestionsViewController = self.collectionViewController; + } + self.ntpMediator.suggestionsMediator = self.contentSuggestionsMediator; + [self.ntpMediator setUp]; - self.dragDropHandler = [[URLDragDropHandler alloc] init]; - self.dragDropHandler.dropDelegate = self; + if (!IsContentSuggestionsHeaderMigrationEnabled()) { + [self.collectionViewController + addChildViewController:self.headerController]; + [self.headerController + didMoveToParentViewController:self.collectionViewController]; + + // TODO(crbug.com/1114792): Remove header provider and use refactored + // header synchronizer instead. + self.collectionViewController.headerProvider = self.headerController; + + // Set consumer after configuring the header to ensure that view + // controller has access to it when configuring its elements. + DCHECK(self.collectionViewController.headerProvider); + self.contentSuggestionsMediator.collectionConsumer = + self.collectionViewController; + + self.collectionViewController.collectionView.accessibilityIdentifier = + kContentSuggestionsCollectionIdentifier; + } + + self.dragDropHandler = [[URLDragDropHandler alloc] init]; + self.dragDropHandler.dropDelegate = self; + if (IsContentSuggestionsUIViewControllerMigrationEnabled()) { [self.contentSuggestionsViewController.view addInteraction:[[UIDropInteraction alloc] initWithDelegate:self.dragDropHandler]]; + } else { + [self.collectionViewController.collectionView + addInteraction:[[UIDropInteraction alloc] + initWithDelegate:self.dragDropHandler]]; + } } - (void)stop { @@ -197,16 +295,27 @@ } [self.contentSuggestionsMediator disconnect]; self.contentSuggestionsMediator = nil; - self.contentSuggestionsViewController = nil; + if (IsContentSuggestionsUIViewControllerMigrationEnabled()) { + self.contentSuggestionsViewController = nil; + } else { + self.collectionViewController = nil; + } [self.sharingCoordinator stop]; self.sharingCoordinator = nil; + self.headerController = nil; _started = NO; } - (UIViewController*)viewController { + DCHECK(IsContentSuggestionsUIViewControllerMigrationEnabled()); return self.contentSuggestionsViewController; } +- (UICollectionViewController*)contentSuggestionsCollectionViewController { + DCHECK(!IsContentSuggestionsUIViewControllerMigrationEnabled()); + return self.collectionViewController; +} + #pragma mark - Setters - (void)setWebState:(web::WebState*)webState { @@ -220,6 +329,7 @@ NotificationPromoWhatsNew* notificationPromo = [self.contentSuggestionsMediator notificationPromo]; notificationPromo->HandleViewed(); + [self.headerController setPromoCanShow:notificationPromo->CanShow()]; } - (void)viewDidDisappear { @@ -268,7 +378,26 @@ #pragma mark - Public methods - (UIView*)view { - return self.contentSuggestionsViewController.view; + return IsContentSuggestionsUIViewControllerMigrationEnabled() + ? self.contentSuggestionsViewController.view + : self.collectionViewController.view; +} + +- (void)stopScrolling { + UIScrollView* scrollView = self.collectionViewController.collectionView; + [scrollView setContentOffset:scrollView.contentOffset animated:NO]; +} + +- (UIEdgeInsets)contentInset { + return self.collectionViewController.collectionView.contentInset; +} + +- (CGPoint)contentOffset { + CGPoint collectionOffset = + self.collectionViewController.collectionView.contentOffset; + collectionOffset.y -= + self.headerCollectionInteractionHandler.collectionShiftingOffset; + return collectionOffset; } - (void)reload { @@ -313,6 +442,12 @@ NSMutableArray<UIMenuElement*>* menuElements = [[NSMutableArray alloc] init]; + NSInteger index = + IsSingleCellContentSuggestionsEnabled() + ? item.index + : [self.collectionViewController.collectionViewModel + indexPathForItem:item] + .item; CGPoint centerPoint = [view.superview convertPoint:view.center toView:nil]; @@ -320,7 +455,7 @@ [weakSelf.contentSuggestionsMediator openNewTabWithMostVisitedItem:item incognito:NO - atIndex:item.index + atIndex:index fromPoint:centerPoint]; }]]; @@ -329,7 +464,7 @@ [weakSelf.contentSuggestionsMediator openNewTabWithMostVisitedItem:item incognito:YES - atIndex:item.index + atIndex:index fromPoint:centerPoint]; }]; @@ -433,12 +568,30 @@ [[ActivityParams alloc] initWithURL:URL title:title scenario:ActivityScenario::MostVisitedEntry]; + UIViewController* contentSuggestionsVC = + IsContentSuggestionsUIViewControllerMigrationEnabled() + ? self.contentSuggestionsViewController + : self.collectionViewController; self.sharingCoordinator = [[SharingCoordinator alloc] - initWithBaseViewController:self.contentSuggestionsViewController + initWithBaseViewController:contentSuggestionsVC browser:self.browser params:params originView:view]; [self.sharingCoordinator start]; } +#pragma mark - AppStateObserver + +- (void)appState:(AppState*)appState + didTransitionFromInitStage:(InitStage)previousInitStage { + if (base::FeatureList::IsEnabled(kEnableFREUIModuleIOS)) { + if (previousInitStage == InitStageFirstRun) { + self.headerController.focusOmniboxWhenViewAppears = YES; + [self.headerController focusAccessibilityOnOmnibox]; + + [appState removeObserver:self]; + } + } +} + @end
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_favicon_mediator.h b/ios/chrome/browser/ui/content_suggestions/content_suggestions_favicon_mediator.h index efb51ba..1fd7752 100644 --- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_favicon_mediator.h +++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_favicon_mediator.h
@@ -16,6 +16,7 @@ @protocol ContentSuggestionsCollectionConsumer; @protocol ContentSuggestionsConsumer; @class ContentSuggestionsMostVisitedItem; +@class ContentSuggestionsParentItem; @class FaviconAttributesProvider; class LargeIconCache; @@ -32,6 +33,12 @@ - (instancetype)init NS_UNAVAILABLE; +// The consumer that will be notified when the data change. `consumer` is used +// if kContentSuggestionsUIViewControllerMigration is enabled. +// TODO(crbug.com/1285378): remove after completion of UIViewController +// migration. +@property(nonatomic, weak) id<ContentSuggestionsCollectionConsumer> + collectionConsumer; @property(nonatomic, weak) id<ContentSuggestionsConsumer> consumer; // FaviconAttributesProvider to fetch the favicon for the most visited tiles. @@ -44,6 +51,11 @@ // Fetches the favicon for this `item`. - (void)fetchFaviconForMostVisited:(ContentSuggestionsMostVisitedItem*)item; +// Fetches the favicon for `item` within `parentItem`. +// TODO(crbug.com/1285378): Remove this after fully migrating ContentSuggestions +// to UIViewController. +- (void)fetchFaviconForMostVisited:(ContentSuggestionsMostVisitedItem*)item + parentItem:(ContentSuggestionsParentItem*)parentItem; @end
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_favicon_mediator.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_favicon_mediator.mm index eefa6751..28cba5627 100644 --- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_favicon_mediator.mm +++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_favicon_mediator.mm
@@ -8,6 +8,8 @@ #include "components/favicon/core/large_icon_service.h" #include "ios/chrome/browser/application_context.h" #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item.h" +#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_parent_item.h" +#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_consumer.h" #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_consumer.h" #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_feature.h" #import "ios/chrome/browser/ui/content_suggestions/identifier/content_suggestions_section_information.h" @@ -69,6 +71,39 @@ _mostVisitedDataForLogging = mostVisitedData; } +- (void)fetchFaviconForMostVisited:(ContentSuggestionsMostVisitedItem*)item + parentItem:(ContentSuggestionsParentItem*)parentItem { + DCHECK(IsSingleCellContentSuggestionsEnabled()); + __weak ContentSuggestionsFaviconMediator* weakSelf = self; + __weak ContentSuggestionsMostVisitedItem* weakItem = item; + __weak ContentSuggestionsParentItem* weakParentItem = parentItem; + + void (^completion)(FaviconAttributes*) = ^(FaviconAttributes* attributes) { + ContentSuggestionsFaviconMediator* strongSelf = weakSelf; + ContentSuggestionsMostVisitedItem* strongItem = weakItem; + ContentSuggestionsParentItem* strongParentItem = weakParentItem; + if (!strongSelf || !strongItem) { + return; + } + + strongItem.attributes = attributes; + if (!parentItem) { + return; + } + for (__strong ContentSuggestionsMostVisitedItem* mvtItem in strongParentItem + .mostVisitedItems) { + if (mvtItem.index == strongItem.index) { + mvtItem = strongItem; + } + } + [strongSelf logFaviconFetchedForItem:strongItem]; + [strongSelf.collectionConsumer itemHasChanged:strongParentItem]; + }; + + [self.mostVisitedAttributesProvider fetchFaviconAttributesForURL:item.URL + completion:completion]; +} + - (void)fetchFaviconForMostVisited:(ContentSuggestionsMostVisitedItem*)item { __weak ContentSuggestionsFaviconMediator* weakSelf = self; __weak ContentSuggestionsMostVisitedItem* weakItem = item; @@ -81,7 +116,11 @@ strongItem.attributes = attributes; [strongSelf logFaviconFetchedForItem:strongItem]; - [strongSelf.consumer updateMostVisitedTileConfig:strongItem]; + if (IsContentSuggestionsUIViewControllerMigrationEnabled()) { + [strongSelf.consumer updateMostVisitedTileConfig:strongItem]; + } else { + [strongSelf.collectionConsumer itemHasChanged:strongItem]; + } }; [self.mostVisitedAttributesProvider fetchFaviconAttributesForURL:item.URL
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_feature.h b/ios/chrome/browser/ui/content_suggestions/content_suggestions_feature.h index 60e3595..fe998d3 100644 --- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_feature.h +++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_feature.h
@@ -15,6 +15,16 @@ // Feature to use one NTP for all tabs in a Browser. extern const base::Feature kSingleNtp; +// Feature to use one cell for Content Suggestions +extern const base::Feature kSingleCellContentSuggestions; + +// Feature to move the Content Suggestions header view into the Discover +// ScrollView. +extern const base::Feature kContentSuggestionsHeaderMigration; + +// Feature to move the Content Suggestions ViewController to a UIViewController. +extern const base::Feature kContentSuggestionsUIViewControllerMigration; + // Feature to section the Content Suggestions into modules. extern const base::Feature kContentSuggestionsUIModuleRefresh; @@ -33,6 +43,16 @@ // Whether the Discover feed is enabled instead of the Zine feed. bool IsDiscoverFeedEnabled(); +// Whether the single cell content suggestions feature is enabled. +bool IsSingleCellContentSuggestionsEnabled(); + +// Whether the Content Suggestions header migration feature is enabled. +bool IsContentSuggestionsHeaderMigrationEnabled(); + +// Whether the Content Suggestions UIViewController migration feature is +// enabled. +bool IsContentSuggestionsUIViewControllerMigrationEnabled(); + // Whether the Content Suggestions UI Module Refresh feature is enabled. bool IsContentSuggestionsUIModuleRefreshEnabled();
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_feature.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_feature.mm index 8f8f503..f3fb458 100644 --- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_feature.mm +++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_feature.mm
@@ -18,6 +18,19 @@ const base::Feature kSingleNtp{"SingleNTP", base::FEATURE_ENABLED_BY_DEFAULT}; // Feature disabled by default. +const base::Feature kSingleCellContentSuggestions{ + "SingleCellContentSuggestions", base::FEATURE_ENABLED_BY_DEFAULT}; + +// Feature disabled by default. +const base::Feature kContentSuggestionsHeaderMigration{ + "ContentSuggestionsHeaderMigration", base::FEATURE_ENABLED_BY_DEFAULT}; + +// Feature disabled by default. +const base::Feature kContentSuggestionsUIViewControllerMigration{ + "ContentSuggestionsUIViewControllerMigration", + base::FEATURE_ENABLED_BY_DEFAULT}; + +// Feature disabled by default. const base::Feature kContentSuggestionsUIModuleRefresh{ "ContentSuggestionsUIModuleRefresh", base::FEATURE_DISABLED_BY_DEFAULT}; @@ -37,6 +50,19 @@ return base::FeatureList::IsEnabled(kDiscoverFeedInNtp); } +bool IsSingleCellContentSuggestionsEnabled() { + return base::FeatureList::IsEnabled(kSingleCellContentSuggestions); +} + +bool IsContentSuggestionsHeaderMigrationEnabled() { + return base::FeatureList::IsEnabled(kContentSuggestionsHeaderMigration); +} + +bool IsContentSuggestionsUIViewControllerMigrationEnabled() { + return base::FeatureList::IsEnabled( + kContentSuggestionsUIViewControllerMigration); +} + bool IsContentSuggestionsUIModuleRefreshEnabled() { return base::FeatureList::IsEnabled(kContentSuggestionsUIModuleRefresh); }
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_controlling.h b/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_controlling.h index 0db1294..1dfa011 100644 --- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_controlling.h +++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_controlling.h
@@ -21,6 +21,10 @@ // ignored. @property(nonatomic, assign, getter=isShowing) BOOL showing; +// Returns the header view containing the logo and omnibox to be displayed. +- (UIView*)headerForWidth:(CGFloat)width + safeAreaInsets:(UIEdgeInsets)safeAreaInsets; + // Updates the iPhone fakebox's frame based on the current scroll view `offset` // and `width`. `width` is the width of the screen, including the space outside // the safe area. The `safeAreaInsets` is relative to the view used to calculate
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_provider.h b/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_provider.h new file mode 100644 index 0000000..1952fc6e --- /dev/null +++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_provider.h
@@ -0,0 +1,16 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CONTENT_SUGGESTIONS_HEADER_PROVIDER_H_ +#define IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CONTENT_SUGGESTIONS_HEADER_PROVIDER_H_ + +// Object providing a header view for the content suggestions. +@protocol ContentSuggestionsHeaderProvider + +- (nullable UIView*)headerForWidth:(CGFloat)width + safeAreaInsets:(UIEdgeInsets)safeAreaInsets; + +@end + +#endif // IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CONTENT_SUGGESTIONS_HEADER_PROVIDER_H_
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_synchronizer.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_synchronizer.mm index 34cb0c8b..c695ecba 100644 --- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_synchronizer.mm +++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_synchronizer.mm
@@ -6,8 +6,11 @@ #include "base/ios/ios_util.h" #import "base/mac/foundation_util.h" +#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_action_cell.h" +#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_cell.h" #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_controlling.h" #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_utils.h" +#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_view_controller.h" #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_header_controlling.h" #import "ios/chrome/browser/ui/util/uikit_ui_util.h" @@ -268,6 +271,17 @@ #pragma mark - UIGestureRecognizerDelegate +- (BOOL)gestureRecognizer:(UIGestureRecognizer*)gestureRecognizer + shouldReceiveTouch:(UITouch*)touch { + BOOL isMostVisitedCell = + content_suggestions::nearestAncestor( + touch.view, [ContentSuggestionsMostVisitedCell class]) != nil; + BOOL isMostVisitedActionCell = + content_suggestions::nearestAncestor( + touch.view, [ContentSuggestionsMostVisitedActionCell class]) != nil; + return !isMostVisitedCell && !isMostVisitedActionCell; +} + - (UIView*)nearestAncestorOfView:(UIView*)view withClass:(Class)aClass { if (!view) { return nil;
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.h b/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.h index c10500a..4c11bcf 100644 --- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.h +++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.h
@@ -8,6 +8,7 @@ #import <UIKit/UIKit.h> #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_header_controlling.h" +#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_header_provider.h" #import "ios/chrome/browser/ui/content_suggestions/ntp_home_consumer.h" #import "ios/chrome/browser/ui/ntp/logo_animation_controller.h" @@ -27,9 +28,10 @@ // the interactions between the header and the collection, and the rest of the // application. @interface ContentSuggestionsHeaderViewController - : UIViewController <ContentSuggestionsHeaderControlling, - NTPHomeConsumer, - LogoAnimationControllerOwnerOwner> + : UIViewController<ContentSuggestionsHeaderControlling, + ContentSuggestionsHeaderProvider, + NTPHomeConsumer, + LogoAnimationControllerOwnerOwner> - (instancetype)init NS_DESIGNATED_INITIALIZER; - (instancetype)initWithNibName:(NSString*)nibNameOrNil
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.mm index 4548124..9ee491a 100644 --- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.mm +++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.mm
@@ -215,6 +215,14 @@ return AlignValueToPixel(offsetY); } +- (void)loadView { + if (IsContentSuggestionsHeaderMigrationEnabled()) { + [super loadView]; + } else { + self.view = [[ContentSuggestionsHeaderView alloc] init]; + } +} + - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; @@ -232,7 +240,7 @@ - (void)viewDidLoad { [super viewDidLoad]; - if (!self.headerView) { + if (IsContentSuggestionsHeaderMigrationEnabled() && !self.headerView) { CGFloat width = self.view.frame.size.width; self.headerView = [[ContentSuggestionsHeaderView alloc] init]; @@ -272,6 +280,56 @@ } } +#pragma mark - ContentSuggestionsHeaderProvider + +- (UIView*)headerForWidth:(CGFloat)width + safeAreaInsets:(UIEdgeInsets)safeAreaInsets { + DCHECK(!IsContentSuggestionsHeaderMigrationEnabled()); + if (!self.headerView) { + self.headerView = + base::mac::ObjCCastStrict<ContentSuggestionsHeaderView>(self.view); + [self addFakeOmnibox]; + + [self.headerView addSubview:self.logoVendor.view]; + // Fake Tap View has identity disc, which should render above the doodle. + [self addFakeTapView]; + [self.headerView addSubview:self.fakeOmnibox]; + self.logoVendor.view.translatesAutoresizingMaskIntoConstraints = NO; + self.logoVendor.view.accessibilityIdentifier = + ntp_home::NTPLogoAccessibilityID(); + self.fakeOmnibox.translatesAutoresizingMaskIntoConstraints = NO; + + [self.headerView addSeparatorToSearchField:self.fakeOmnibox]; + + // Identity disc needs to be added after the Google logo/doodle since it + // needs to respond to user taps first. + [self addIdentityDisc]; + + // -headerForView is regularly called before self.headerView has been added + // to the view hierarchy, so there's no simple way to get the correct + // safeAreaInsets. Since this situation is universally called for the full + // screen new tab animation, it's safe to check the rootViewController's + // view instead. + // TODO(crbug.com/791784) : Remove use of rootViewController. + if (self.headerView.window) { + safeAreaInsets = + self.headerView.window.rootViewController.view.safeAreaInsets; + } + width = std::max<CGFloat>( + 0, width - safeAreaInsets.left - safeAreaInsets.right); + + self.fakeOmniboxWidthConstraint = [self.fakeOmnibox.widthAnchor + constraintEqualToConstant:content_suggestions::searchFieldWidth( + width, self.traitCollection)]; + [self addConstraintsForLogoView:self.logoVendor.view + fakeOmnibox:self.fakeOmnibox + andHeaderView:self.headerView]; + + [self.logoVendor fetchDoodle]; + } + return self.headerView; +} + #pragma mark - Private // Initialize and add a search field tap target and a voice search button. @@ -453,11 +511,15 @@ self.logoVendor.isShowingDoodle, self.traitCollection)]; self.fakeOmnibox.hidden = IsRegularXRegularSizeClass(self) && !self.logoIsShowing; - [self.headerView layoutIfNeeded]; - self.headerViewHeightConstraint.constant = - content_suggestions::heightForLogoHeader( - self.logoIsShowing, self.logoVendor.isShowingDoodle, - self.promoCanShow, YES, [self topInset], self.traitCollection); + if (IsContentSuggestionsHeaderMigrationEnabled()) { + [self.headerView layoutIfNeeded]; + self.headerViewHeightConstraint.constant = + content_suggestions::heightForLogoHeader( + self.logoIsShowing, self.logoVendor.isShowingDoodle, + self.promoCanShow, YES, [self topInset], self.traitCollection); + } else { + [self.collectionSynchronizer invalidateLayout]; + } } // If Google is not the default search engine, hides the logo, doodle and @@ -499,9 +561,11 @@ self.fakeOmniboxTopMarginConstraint = [logoView.bottomAnchor constraintEqualToAnchor:fakeOmnibox.topAnchor constant:-content_suggestions::searchFieldTopMargin()]; - self.headerViewHeightConstraint = - [headerView.heightAnchor constraintEqualToConstant:[self headerHeight]]; - self.headerViewHeightConstraint.active = YES; + if (IsContentSuggestionsHeaderMigrationEnabled()) { + self.headerViewHeightConstraint = + [headerView.heightAnchor constraintEqualToConstant:[self headerHeight]]; + self.headerViewHeightConstraint.active = YES; + } self.doodleTopMarginConstraint.active = YES; self.doodleHeightConstraint.active = YES; self.fakeOmniboxWidthConstraint.active = YES; @@ -596,7 +660,9 @@ } - (CGFloat)topInset { - return 0; + return IsContentSuggestionsHeaderMigrationEnabled() + ? 0 + : self.parentViewController.view.safeAreaInsets.top; } #pragma mark - UIIndirectScribbleInteractionDelegate @@ -672,10 +738,12 @@ setConstant:content_suggestions::doodleHeight(self.logoVendor.showingLogo, doodleShowing, self.traitCollection)]; - self.headerViewHeightConstraint.constant = - content_suggestions::heightForLogoHeader( - self.logoIsShowing, self.logoVendor.isShowingDoodle, - self.promoCanShow, YES, [self topInset], self.traitCollection); + if (IsContentSuggestionsHeaderMigrationEnabled()) { + self.headerViewHeightConstraint.constant = + content_suggestions::heightForLogoHeader( + self.logoIsShowing, self.logoVendor.isShowingDoodle, + self.promoCanShow, YES, [self topInset], self.traitCollection); + } [self.commandHandler updateForHeaderSizeChange]; }
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_layout.h b/ios/chrome/browser/ui/content_suggestions/content_suggestions_layout.h new file mode 100644 index 0000000..7ccb1fe --- /dev/null +++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_layout.h
@@ -0,0 +1,34 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CONTENT_SUGGESTIONS_LAYOUT_H_ +#define IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CONTENT_SUGGESTIONS_LAYOUT_H_ + +#import <MaterialComponents/MDCCollectionViewFlowLayout.h> + +@protocol NewTabPageOmniboxPositioning; + +// Layout used for ContentSuggestions. It makes sure the collection is high +// enough to be scrolled up to the point the fake omnibox is hidden. For size +// classes other than RegularXRegular, this layout makes sure the fake omnibox +// is pinned to the top of the collection. +@interface ContentSuggestionsLayout : MDCCollectionViewFlowLayout + +// The parent collection view that contains the content suggestions collection +// view. +@property(nonatomic, weak) UICollectionView* parentCollectionView; + +// Provides information relating to the fake omnibox size. +@property(nonatomic, weak) id<NewTabPageOmniboxPositioning> omniboxPositioner; + +// Whether or not the user has scrolled into the feed, transferring ownership of +// the omnibox to allow it to stick to the top of the NTP. +@property(nonatomic, assign) BOOL isScrolledIntoFeed; + +// Minimum height of the NTP scroll view to allow for scrolling to omnibox. +- (CGFloat)minimumNTPHeight; + +@end + +#endif // IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CONTENT_SUGGESTIONS_LAYOUT_H_
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_layout.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_layout.mm new file mode 100644 index 0000000..f726232 --- /dev/null +++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_layout.mm
@@ -0,0 +1,195 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_layout.h" + +#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_utils.h" +#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_feature.h" +#import "ios/chrome/browser/ui/ntp/new_tab_page_header_constants.h" +#import "ios/chrome/browser/ui/ntp/new_tab_page_omnibox_positioning.h" +#import "ios/chrome/browser/ui/toolbar/public/toolbar_utils.h" +#import "ios/chrome/browser/ui/util/ui_util.h" +#import "ios/chrome/browser/ui/util/uikit_ui_util.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +@implementation ContentSuggestionsLayout + +- (CGFloat)minimumNTPHeight { + CGFloat collectionViewHeight = self.parentCollectionView.bounds.size.height; + CGFloat headerHeight = [self firstHeaderHeight]; + + // The minimum height for the collection view content should be the height of + // the header plus the height of the collection view minus the height of the + // NTP bottom bar. This allows the Most Visited cells to be scrolled up to the + // top of the screen. Also computes the total NTP scrolling height for + // Discover infinite feed. + CGFloat ntpHeight = collectionViewHeight + headerHeight; + CGFloat minimumHeight = + ntpHeight - ntp_header::kScrolledToTopOmniboxBottomMargin; + if (!IsRegularXRegularSizeClass(self.collectionView)) { + CGFloat toolbarHeight = + IsSplitToolbarMode(self.collectionView) + ? ToolbarExpandedHeight([UIApplication sharedApplication] + .preferredContentSizeCategory) + : 0; + CGFloat additionalHeight = + toolbarHeight + self.collectionView.contentInset.bottom; + minimumHeight -= additionalHeight; + } + + return minimumHeight; +} + +- (NSArray*)layoutAttributesForElementsInRect:(CGRect)rect { + if (IsRegularXRegularSizeClass(self.collectionView) || + IsContentSuggestionsHeaderMigrationEnabled()) + return [super layoutAttributesForElementsInRect:rect]; + + NSMutableArray* layoutAttributes = + [[super layoutAttributesForElementsInRect:rect] mutableCopy]; + UICollectionViewLayoutAttributes* fixedHeaderAttributes = nil; + NSIndexPath* fixedHeaderIndexPath = + [NSIndexPath indexPathForItem:0 inSection:0]; + + for (UICollectionViewLayoutAttributes* attributes in layoutAttributes) { + if ([attributes.representedElementKind + isEqualToString:UICollectionElementKindSectionHeader] && + attributes.indexPath.section == fixedHeaderIndexPath.section) { + fixedHeaderAttributes = [self + layoutAttributesForSupplementaryViewOfKind: + UICollectionElementKindSectionHeader + atIndexPath:fixedHeaderIndexPath]; + attributes.zIndex = fixedHeaderAttributes.zIndex; + attributes.frame = fixedHeaderAttributes.frame; + } + } + + // The fixed header's attributes are not updated if the header's default frame + // is far enough away from `rect`, which can occur when the NTP is scrolled + // up. + if (!fixedHeaderAttributes) { + UICollectionViewLayoutAttributes* fixedHeaderAttributes = + [self layoutAttributesForSupplementaryViewOfKind: + UICollectionElementKindSectionHeader + atIndexPath:fixedHeaderIndexPath]; + [layoutAttributes addObject:fixedHeaderAttributes]; + } + + return layoutAttributes; +} + +- (UICollectionViewLayoutAttributes*) +layoutAttributesForSupplementaryViewOfKind:(NSString*)kind + atIndexPath:(NSIndexPath*)indexPath { + UICollectionViewLayoutAttributes* attributes = + [super layoutAttributesForSupplementaryViewOfKind:kind + atIndexPath:indexPath]; + if (!IsSplitToolbarMode(self.collectionView) || + IsContentSuggestionsHeaderMigrationEnabled()) + return attributes; + + if ([kind isEqualToString:UICollectionElementKindSectionHeader] && + indexPath.section == 0) { + CGFloat contentOffset = self.parentCollectionView.contentOffset.y + + self.collectionView.contentSize.height; + + CGFloat headerHeight = CGRectGetHeight(attributes.frame); + CGPoint origin = attributes.frame.origin; + + // Keep the header in front of all other views. + attributes.zIndex = NSIntegerMax; + + // TODO(crbug.com/1114792): Remove this and only use omniboxPositioner after + // refactoring is complete. + CGFloat minY = + headerHeight - ntp_header::kFakeOmniboxScrolledToTopMargin - + ToolbarExpandedHeight( + [UIApplication sharedApplication].preferredContentSizeCategory) - + self.collectionView.safeAreaInsets.top; + + minY = [self.omniboxPositioner stickyOmniboxHeight]; + // TODO(crbug.com/1114792): Remove mentioned of "refactored" from the + // variable name once this launches. + BOOL hasScrolledIntoRefactoredDiscoverFeed = self.isScrolledIntoFeed; + if (contentOffset > minY && !hasScrolledIntoRefactoredDiscoverFeed) { + origin.y = contentOffset - minY; + } + attributes.frame = {origin, attributes.frame.size}; + } + return attributes; +} + +- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBound { + if (IsRegularXRegularSizeClass(self.collectionView)) + return [super shouldInvalidateLayoutForBoundsChange:newBound]; + return YES; +} + +#pragma mark - MDCCollectionViewFlowLayout overrides +// This section contains overrides of methods to avoid ugly effects during +// rotation due to the default behavior of the MDCCollectionViewFlowLayout. See +// http://crbug.com/949659 . + +- (UICollectionViewLayoutAttributes*) + initialLayoutAttributesForAppearingItemAtIndexPath: + (NSIndexPath*)itemIndexPath { + UICollectionViewLayoutAttributes* attribute = + [super initialLayoutAttributesForAppearingItemAtIndexPath:itemIndexPath]; + attribute.alpha = 0; + return attribute; +} + +- (UICollectionViewLayoutAttributes*) + initialLayoutAttributesForAppearingSupplementaryElementOfKind: + (NSString*)elementKind + atIndexPath: + (NSIndexPath*) + elementIndexPath { + UICollectionViewLayoutAttributes* attribute = [super + initialLayoutAttributesForAppearingSupplementaryElementOfKind:elementKind + atIndexPath: + elementIndexPath]; + attribute.alpha = 0; + return attribute; +} + +- (UICollectionViewLayoutAttributes*) + finalLayoutAttributesForDisappearingItemAtIndexPath: + (NSIndexPath*)itemIndexPath { + UICollectionViewLayoutAttributes* attribute = + [super finalLayoutAttributesForDisappearingItemAtIndexPath:itemIndexPath]; + attribute.alpha = 0; + return attribute; +} + +- (UICollectionViewLayoutAttributes*) + finalLayoutAttributesForDisappearingSupplementaryElementOfKind: + (NSString*)elementKind + atIndexPath: + (NSIndexPath*) + indexPath { + UICollectionViewLayoutAttributes* attribute = [super + finalLayoutAttributesForDisappearingSupplementaryElementOfKind:elementKind + atIndexPath:indexPath]; + attribute.alpha = 0; + return attribute; +} + +#pragma mark - Private. + +// Returns the height of the header of the first section. +- (CGFloat)firstHeaderHeight { + id<UICollectionViewDelegateFlowLayout> delegate = + static_cast<id<UICollectionViewDelegateFlowLayout>>( + self.collectionView.delegate); + return [delegate collectionView:self.collectionView + layout:self + referenceSizeForHeaderInSection:0] + .height; +} + +@end
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.h b/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.h index 9359d77..dc571ce9 100644 --- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.h +++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.h
@@ -11,6 +11,7 @@ #include "components/prefs/pref_service.h" #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_gesture_commands.h" +#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_consumer.h" #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_commands.h" #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_consumer.h" #import "ios/chrome/browser/ui/content_suggestions/start_suggest_service_response_bridge.h" @@ -31,6 +32,7 @@ @protocol ApplicationCommands; class Browser; @protocol BrowserCoordinatorCommands; +@protocol ContentSuggestionsCollectionConsumer; @protocol FeedDelegate; class GURL; class LargeIconCache; @@ -76,6 +78,8 @@ @property(nonatomic, weak) id<FeedDelegate> feedDelegate; // The consumer that will be notified when the data change. +@property(nonatomic, weak) id<ContentSuggestionsCollectionConsumer> + collectionConsumer; @property(nonatomic, weak) id<ContentSuggestionsConsumer> consumer; // YES if the Start Surface is being shown.
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 4da3721..b077fadd 100644 --- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.mm +++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.mm
@@ -40,6 +40,7 @@ #import "ios/chrome/browser/ui/commands/snackbar_commands.h" #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_action_item.h" #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item.h" +#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_parent_item.h" #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_return_to_recent_tab_item.h" #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_tile_constants.h" #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_whats_new_item.h" @@ -130,12 +131,17 @@ // Item for the "Return to Recent Tab" tile. @property(nonatomic, strong) ContentSuggestionsReturnToRecentTabItem* returnToRecentTabItem; +// Parent Item for single cell layout. +@property(nonatomic, strong) ContentSuggestionsParentItem* parentItem; // Section Info for the What's New promo section. @property(nonatomic, strong) ContentSuggestionsSectionInformation* promoSectionInfo; // Section Info for the Most Visited section. @property(nonatomic, strong) ContentSuggestionsSectionInformation* mostVisitedSectionInfo; +// Section Info for the single cell parent item section. +@property(nonatomic, strong) + ContentSuggestionsSectionInformation* singleCellSectionInfo; // Whether the page impression has been recorded. @property(nonatomic, assign) BOOL recordedPageImpression; // Map the section information created to the relevant category. @@ -197,8 +203,12 @@ largeIconCache:largeIconCache]; _logoSectionInfo = LogoSectionInformation(); - _promoSectionInfo = PromoSectionInformation(); - _mostVisitedSectionInfo = MostVisitedSectionInformation(); + if (IsSingleCellContentSuggestionsEnabled()) { + _singleCellSectionInfo = SingleCellSectionInformation(); + } else { + _promoSectionInfo = PromoSectionInformation(); + _mostVisitedSectionInfo = MostVisitedSectionInformation(); + } _notificationPromo = std::make_unique<NotificationPromoWhatsNew>( GetApplicationContext()->GetLocalState()); @@ -243,29 +253,40 @@ } - (void)reloadAllData { - if (!self.consumer) { + if (IsContentSuggestionsUIViewControllerMigrationEnabled()) { + if (!self.consumer) { + return; + } + if (_notificationPromo->CanShow()) { + ContentSuggestionsWhatsNewItem* item = + [[ContentSuggestionsWhatsNewItem alloc] initWithType:0]; + item.icon = _notificationPromo->GetIcon(); + item.text = base::SysUTF8ToNSString(_notificationPromo->promo_text()); + [self.consumer showWhatsNewViewWithConfig:item]; + } + if (self.returnToRecentTabItem) { + [self.consumer + showReturnToRecentTabTileWithConfig:self.returnToRecentTabItem]; + } + if ([self.mostVisitedItems count]) { + [self.consumer setMostVisitedTilesWithConfigs:self.mostVisitedItems]; + } + if (!ShouldHideShortcutsForTrendingQueries()) { + [self.consumer setShortcutTilesWithConfigs:self.actionButtonItems]; + } + if (IsTrendingQueriesModuleEnabled()) { + [self fetchTrendingQueriesIfApplicable]; + } return; } - if (_notificationPromo->CanShow()) { - ContentSuggestionsWhatsNewItem* item = - [[ContentSuggestionsWhatsNewItem alloc] init]; - item.icon = _notificationPromo->GetIcon(); - item.text = base::SysUTF8ToNSString(_notificationPromo->promo_text()); - [self.consumer showWhatsNewViewWithConfig:item]; + NSArray<ContentSuggestionsSectionInformation*>* sections = + [self sectionsInfo]; + NSMutableDictionary<NSNumber*, NSArray*>* items = + [[NSMutableDictionary alloc] init]; + for (ContentSuggestionsSectionInformation* section in sections) { + items[@(section.sectionID)] = [self itemsForSectionInfo:section]; } - if (self.returnToRecentTabItem) { - [self.consumer - showReturnToRecentTabTileWithConfig:self.returnToRecentTabItem]; - } - if ([self.mostVisitedItems count]) { - [self.consumer setMostVisitedTilesWithConfigs:self.mostVisitedItems]; - } - if (!ShouldHideShortcutsForTrendingQueries()) { - [self.consumer setShortcutTilesWithConfigs:self.actionButtonItems]; - } - if (IsTrendingQueriesModuleEnabled()) { - [self fetchTrendingQueriesIfApplicable]; - } + [self.collectionConsumer reloadDataWithSections:sections andItems:items]; } - (void)blockMostVisitedURL:(GURL)URL { @@ -282,6 +303,13 @@ return _notificationPromo.get(); } +- (void)setCollectionConsumer: + (id<ContentSuggestionsCollectionConsumer>)collectionConsumer { + _collectionConsumer = collectionConsumer; + self.faviconMediator.collectionConsumer = collectionConsumer; + [self reloadAllData]; +} + - (void)setConsumer:(id<ContentSuggestionsConsumer>)consumer { _consumer = consumer; self.faviconMediator.consumer = consumer; @@ -308,7 +336,7 @@ self.returnToRecentTabSectionInfo = ReturnToRecentTabSectionInformation(); if (!self.returnToRecentTabItem) { self.returnToRecentTabItem = - [[ContentSuggestionsReturnToRecentTabItem alloc] init]; + [[ContentSuggestionsReturnToRecentTabItem alloc] initWithType:0]; } // Retrieve favicon associated with the page. @@ -331,8 +359,18 @@ webState->GetTitle()) timeString:timeLabel]; self.showMostRecentTabStartSurfaceTile = YES; - [self.consumer - showReturnToRecentTabTileWithConfig:self.returnToRecentTabItem]; + NSArray<CSCollectionViewItem*>* items = + [self itemsForSectionInfo:self.returnToRecentTabSectionInfo]; + if (IsContentSuggestionsUIViewControllerMigrationEnabled()) { + [self.consumer + showReturnToRecentTabTileWithConfig:self.returnToRecentTabItem]; + } else { + [self.collectionConsumer addSection:self.returnToRecentTabSectionInfo + withItems:items + completion:^{ + [self.feedDelegate returnToRecentTabWasAdded]; + }]; + } } - (void)hideRecentTabTile { @@ -340,18 +378,33 @@ if (self.showMostRecentTabStartSurfaceTile) { self.showMostRecentTabStartSurfaceTile = NO; self.returnToRecentTabItem = nil; - [self.consumer hideReturnToRecentTabTile]; + if (IsContentSuggestionsUIViewControllerMigrationEnabled()) { + [self.consumer hideReturnToRecentTabTile]; + } else { + if (IsSingleCellContentSuggestionsEnabled()) { + [self reloadAllData]; + } else { + [self.collectionConsumer + clearSection:self.returnToRecentTabSectionInfo]; + } + } } } - (void)hidePromo { self.shouldHidePromoAfterTap = YES; - [self.consumer hideWhatsNewView]; + if (IsContentSuggestionsUIViewControllerMigrationEnabled()) { + [self.consumer hideWhatsNewView]; + } else { + // By reloading data, checking `notificationPromo` will remove the promo + // view. + [self reloadAllData]; + } } #pragma mark - ContentSuggestionsCommands -- (void)openMostVisitedItem:(NSObject*)item +- (void)openMostVisitedItem:(CollectionViewItem*)item atIndex:(NSInteger)mostVisitedIndex { NewTabPageTabHelper* NTPHelper = NewTabPageTabHelper::FromWebState(self.webState); @@ -405,6 +458,9 @@ DCHECK(notificationPromo); notificationPromo->HandleClosed(); [self.NTPMetrics recordAction:new_tab_page_uma::ACTION_OPENED_PROMO]; + if (IsSingleCellContentSuggestionsEnabled()) { + [self hidePromo]; + } if (notificationPromo->IsURLPromo()) { UrlLoadParams params = UrlLoadParams::InNewTab(notificationPromo->url()); @@ -532,8 +588,17 @@ - (void)mostRecentTabFaviconUpdatedWithImage:(UIImage*)image { if (self.returnToRecentTabItem) { self.returnToRecentTabItem.icon = image; - [self.consumer - updateReturnToRecentTabTileWithConfig:self.returnToRecentTabItem]; + if (IsContentSuggestionsUIViewControllerMigrationEnabled()) { + [self.consumer + updateReturnToRecentTabTileWithConfig:self.returnToRecentTabItem]; + } else { + if (IsSingleCellContentSuggestionsEnabled()) { + self.parentItem.returnToRecentItem = self.returnToRecentTabItem; + [self.collectionConsumer itemHasChanged:self.parentItem]; + } else { + [self.collectionConsumer itemHasChanged:self.returnToRecentTabItem]; + } + } } } @@ -569,7 +634,13 @@ item.index = index; DCHECK(index < kShortcutMinimumIndex); index++; - [self.faviconMediator fetchFaviconForMostVisited:item]; + if (!IsSingleCellContentSuggestionsEnabled() || + IsContentSuggestionsUIViewControllerMigrationEnabled()) { + [self.faviconMediator fetchFaviconForMostVisited:item]; + } else { + [self.faviconMediator fetchFaviconForMostVisited:item + parentItem:self.parentItem]; + } [self.freshMostVisitedItems addObject:item]; } @@ -590,7 +661,13 @@ for (ContentSuggestionsMostVisitedItem* item in self.mostVisitedItems) { if (item.URL == siteURL) { - [self.faviconMediator fetchFaviconForMostVisited:item]; + if (!IsSingleCellContentSuggestionsEnabled() || + IsContentSuggestionsUIViewControllerMigrationEnabled()) { + [self.faviconMediator fetchFaviconForMostVisited:item]; + } else { + [self.faviconMediator fetchFaviconForMostVisited:item + parentItem:self.parentItem]; + } return; } } @@ -609,11 +686,95 @@ // Replaces the Most Visited items currently displayed by the most recent ones. - (void)useFreshMostVisited { self.mostVisitedItems = self.freshMostVisitedItems; - [self.consumer setMostVisitedTilesWithConfigs:self.mostVisitedItems]; + if (IsContentSuggestionsUIViewControllerMigrationEnabled()) { + [self.consumer setMostVisitedTilesWithConfigs:self.mostVisitedItems]; + } else { + // All data needs to be reloaded in order to force a re-layout, this is + // cheaper since the Feed is not part of this ViewController when Discover + // is enabled. + [self reloadAllData]; + } [self.feedDelegate contentSuggestionsWasUpdated]; } +- (NSArray<ContentSuggestionsSectionInformation*>*)sectionsInfo { + NSMutableArray<ContentSuggestionsSectionInformation*>* sectionsInfo = + [NSMutableArray array]; + + if (!IsContentSuggestionsHeaderMigrationEnabled()) { + [sectionsInfo addObject:self.logoSectionInfo]; + } + + if (IsSingleCellContentSuggestionsEnabled()) { + [sectionsInfo addObject:self.singleCellSectionInfo]; + } else { + if (self.showMostRecentTabStartSurfaceTile) { + DCHECK(IsStartSurfaceEnabled()); + [sectionsInfo addObject:self.returnToRecentTabSectionInfo]; + } + + if (_notificationPromo->CanShow()) { + [sectionsInfo addObject:self.promoSectionInfo]; + } + + [sectionsInfo addObject:self.mostVisitedSectionInfo]; + } + + return sectionsInfo; +} + +- (NSArray<CSCollectionViewItem*>*)itemsForSectionInfo: + (ContentSuggestionsSectionInformation*)sectionInfo { + NSMutableArray<CSCollectionViewItem*>* convertedSuggestions = + [NSMutableArray array]; + + if (sectionInfo == self.logoSectionInfo) { + // Section empty on purpose. + } else if (sectionInfo == self.promoSectionInfo) { + if (_notificationPromo->CanShow()) { + ContentSuggestionsWhatsNewItem* item = + [[ContentSuggestionsWhatsNewItem alloc] initWithType:0]; + item.icon = _notificationPromo->GetIcon(); + item.text = base::SysUTF8ToNSString(_notificationPromo->promo_text()); + [convertedSuggestions addObject:item]; + } + } else if (sectionInfo == self.returnToRecentTabSectionInfo) { + DCHECK(IsStartSurfaceEnabled()); + [convertedSuggestions addObject:self.returnToRecentTabItem]; + } else if (sectionInfo == self.mostVisitedSectionInfo) { + [convertedSuggestions addObjectsFromArray:self.mostVisitedItems]; + if (!ShouldHideShortcutsForStartSurface()) { + [convertedSuggestions addObjectsFromArray:self.actionButtonItems]; + } + } else if (sectionInfo == self.singleCellSectionInfo) { + if (!self.parentItem) { + self.parentItem = [[ContentSuggestionsParentItem alloc] initWithType:0]; + } + if (_notificationPromo->CanShow() && !self.shouldHidePromoAfterTap) { + ContentSuggestionsWhatsNewItem* item = + [[ContentSuggestionsWhatsNewItem alloc] initWithType:0]; + item.icon = _notificationPromo->GetIcon(); + item.text = base::SysUTF8ToNSString(_notificationPromo->promo_text()); + self.parentItem.whatsNewItem = item; + } else { + self.parentItem.whatsNewItem = nil; + } + if (self.showMostRecentTabStartSurfaceTile) { + self.parentItem.returnToRecentItem = self.returnToRecentTabItem; + } else { + self.parentItem.returnToRecentItem = nil; + } + self.parentItem.mostVisitedItems = self.mostVisitedItems; + if (!ShouldHideShortcutsForStartSurface()) { + self.parentItem.shortcutsItems = self.actionButtonItems; + } + [convertedSuggestions addObject:self.parentItem]; + } + + return convertedSuggestions; +} + // Opens the `URL` in a new tab `incognito` or not. `originPoint` is the origin // of the new tab animation if the tab is opened in background, in window // coordinates. @@ -752,7 +913,11 @@ self.readingListUnreadCount = model->unread_size(); if (self.readingListItem) { self.readingListItem.count = self.readingListUnreadCount; - [self.consumer updateReadingListCount:self.readingListUnreadCount]; + if (IsContentSuggestionsUIViewControllerMigrationEnabled()) { + [self.consumer updateReadingListCount:self.readingListUnreadCount]; + } else { + [self.collectionConsumer itemHasChanged:self.readingListItem]; + } } }
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator_unittest.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator_unittest.mm index 16493728..4f279ea 100644 --- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator_unittest.mm +++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator_unittest.mm
@@ -68,6 +68,12 @@ class ContentSuggestionsMediatorTest : public PlatformTest { public: ContentSuggestionsMediatorTest() { + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitWithFeatures( + {kSingleCellContentSuggestions, kContentSuggestionsHeaderMigration, + kContentSuggestionsUIViewControllerMigration}, + {}); + TestChromeBrowserState::Builder test_cbs_builder; test_cbs_builder.AddTestingFactory( IOSChromeLargeIconServiceFactory::GetInstance(), @@ -180,7 +186,7 @@ TEST_F(ContentSuggestionsMediatorTest, TestOpenMostVisited) { GURL url = GURL("http://chromium.org"); ContentSuggestionsMostVisitedItem* item = - [[ContentSuggestionsMostVisitedItem alloc] init]; + [[ContentSuggestionsMostVisitedItem alloc] initWithType:0]; item.URL = url; histogram_tester_->ExpectUniqueSample( "IOS.ContentSuggestions.ActionOnNTP",
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm index 0f3f7877..bc33707 100644 --- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm +++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm
@@ -13,6 +13,7 @@ #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_action_item.h" #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item.h" #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_tile_view.h" +#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_parent_item.h" #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_return_to_recent_tab_item.h" #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_return_to_recent_tab_view.h" #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_selection_actions.h"
diff --git a/ios/chrome/browser/ui/content_suggestions/mediator_util.mm b/ios/chrome/browser/ui/content_suggestions/mediator_util.mm index 5404039..211c23bb 100644 --- a/ios/chrome/browser/ui/content_suggestions/mediator_util.mm +++ b/ios/chrome/browser/ui/content_suggestions/mediator_util.mm
@@ -66,7 +66,7 @@ const ntp_tiles::NTPTile& tile, ContentSuggestionsSectionInformation* sectionInfo) { ContentSuggestionsMostVisitedItem* suggestion = - [[ContentSuggestionsMostVisitedItem alloc] init]; + [[ContentSuggestionsMostVisitedItem alloc] initWithType:0]; suggestion.title = base::SysUTF16ToNSString(tile.title); suggestion.URL = tile.url; @@ -74,6 +74,10 @@ suggestion.titleSource = tile.title_source; suggestion.accessibilityTraits = UIAccessibilityTraitButton; + suggestion.suggestionIdentifier = [[ContentSuggestionIdentifier alloc] init]; + suggestion.suggestionIdentifier.IDInSection = tile.url.spec(); + suggestion.suggestionIdentifier.sectionInfo = sectionInfo; + return suggestion; }
diff --git a/ios/chrome/browser/ui/content_suggestions/ntp_home_egtest.mm b/ios/chrome/browser/ui/content_suggestions/ntp_home_egtest.mm index 41ed132..3ddcf9d 100644 --- a/ios/chrome/browser/ui/content_suggestions/ntp_home_egtest.mm +++ b/ios/chrome/browser/ui/content_suggestions/ntp_home_egtest.mm
@@ -137,6 +137,10 @@ config.additional_args.push_back(std::string("--") + switches::kEnableDiscoverFeed); config.features_enabled.push_back(kDiscoverFeedInNtp); + config.features_enabled.push_back(kSingleCellContentSuggestions); + config.features_enabled.push_back(kContentSuggestionsHeaderMigration); + config.features_enabled.push_back( + kContentSuggestionsUIViewControllerMigration); return config; }
diff --git a/ios/chrome/browser/ui/content_suggestions/ntp_home_mediator.h b/ios/chrome/browser/ui/content_suggestions/ntp_home_mediator.h index 3b938b5..e836077 100644 --- a/ios/chrome/browser/ui/content_suggestions/ntp_home_mediator.h +++ b/ios/chrome/browser/ui/content_suggestions/ntp_home_mediator.h
@@ -23,6 +23,7 @@ @protocol ContentSuggestionsCollectionControlling; @class ContentSuggestionsHeaderSynchronizer; @class ContentSuggestionsMediator; +@class ContentSuggestionsCollectionViewController; @protocol FeedControlDelegate; @class FeedMetricsRecorder; class GURL; @@ -56,6 +57,12 @@ @property(nonatomic, strong) NTPHomeMetrics* NTPMetrics; // Recorder for the metrics related to the feed. @property(nonatomic, strong) FeedMetricsRecorder* feedMetricsRecorder; +// View Controller for the NTP if using the non refactored NTP or the Feed is +// not visible. +// TODO(crbug.com/1114792): Create a protocol to avoid duplication and update +// comment. +@property(nonatomic, weak) + ContentSuggestionsCollectionViewController* suggestionsViewController; // View Controller forthe NTP if using the refactored NTP and the Feed is // visible. // TODO(crbug.com/1114792): Create a protocol to avoid duplication and update
diff --git a/ios/chrome/browser/ui/content_suggestions/ntp_home_mediator.mm b/ios/chrome/browser/ui/content_suggestions/ntp_home_mediator.mm index 4c32aeb..ba32fd2e 100644 --- a/ios/chrome/browser/ui/content_suggestions/ntp_home_mediator.mm +++ b/ios/chrome/browser/ui/content_suggestions/ntp_home_mediator.mm
@@ -25,9 +25,9 @@ #import "ios/chrome/browser/signin/authentication_service.h" #import "ios/chrome/browser/signin/chrome_account_manager_service.h" #import "ios/chrome/browser/signin/chrome_account_manager_service_observer_bridge.h" -#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_cells_constants.h" #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_return_to_recent_tab_item.h" #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_utils.h" +#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_view_controller.h" #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_feature.h" #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_header_synchronizer.h" #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.h" @@ -203,7 +203,7 @@ // Return to Recent tab tile is only shown one time, so subtract it's // vertical space to preserve relative scroll position from top. CGFloat tileSectionHeight = - kReturnToRecentTabSize.height + + [ContentSuggestionsReturnToRecentTabCell defaultSize].height + content_suggestions::kReturnToRecentTabSectionBottomMargin; if (scrollPosition > tileSectionHeight +
diff --git a/ios/chrome/browser/ui/content_suggestions/ntp_home_mediator_unittest.mm b/ios/chrome/browser/ui/content_suggestions/ntp_home_mediator_unittest.mm index 79376e5d..f026b33 100644 --- a/ios/chrome/browser/ui/content_suggestions/ntp_home_mediator_unittest.mm +++ b/ios/chrome/browser/ui/content_suggestions/ntp_home_mediator_unittest.mm
@@ -20,6 +20,7 @@ #import "ios/chrome/browser/ui/collection_view/collection_view_controller.h" #import "ios/chrome/browser/ui/collection_view/collection_view_model.h" #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item.h" +#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_view_controller.h" #import "ios/chrome/browser/ui/content_suggestions/ntp_home_consumer.h" #import "ios/chrome/browser/ui/ntp/logo_vendor.h" #import "ios/chrome/browser/ui/toolbar/test/toolbar_test_navigation_manager.h" @@ -60,6 +61,8 @@ navigation_manager_ = navigation_manager.get(); fake_web_state_ = std::make_unique<web::FakeWebState>(); logo_vendor_ = OCMProtocolMock(@protocol(LogoVendor)); + suggestions_view_controller_ = + OCMClassMock([ContentSuggestionsCollectionViewController class]); voice_availability_.SetVoiceProviderEnabled(true); UrlLoadingNotifierBrowserAgent::CreateForBrowser(browser_.get()); @@ -86,6 +89,7 @@ accountManagerService:accountManagerService logoVendor:logo_vendor_ voiceSearchAvailability:&voice_availability_]; + mediator_.suggestionsViewController = suggestions_view_controller_; consumer_ = OCMProtocolMock(@protocol(NTPHomeConsumer)); mediator_.consumer = consumer_; } @@ -100,6 +104,7 @@ std::unique_ptr<Browser> browser_; id consumer_; id logo_vendor_; + id suggestions_view_controller_; FakeVoiceSearchAvailability voice_availability_; NTPHomeMediator* mediator_; ToolbarTestNavigationManager* navigation_manager_;
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_coordinator.h b/ios/chrome/browser/ui/ntp/new_tab_page_coordinator.h index 0015c71..b51dfe0 100644 --- a/ios/chrome/browser/ui/ntp/new_tab_page_coordinator.h +++ b/ios/chrome/browser/ui/ntp/new_tab_page_coordinator.h
@@ -54,6 +54,10 @@ @property(nonatomic, weak, readonly) id<ThumbStripSupporting> thumbStripSupporting; +// Exposes content inset of contentSuggestions collectionView to ensure all of +// content is visible under the bottom toolbar. +@property(nonatomic, readonly) UIEdgeInsets contentInset; + // Bubble presenter for displaying IPH bubbles relating to the NTP. @property(nonatomic, strong) BubblePresenter* bubblePresenter; @@ -67,8 +71,8 @@ // Stop any scrolling in the scroll view. - (void)stopScrolling; -// Whether the NTP is scrolled to the top. -- (BOOL)isScrolledToTop; +// The content offset of the scroll view. +- (CGPoint)contentOffset; // Reloads the content of the NewTabPage. Does not do anything on Incognito. - (void)reload;
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_coordinator.mm b/ios/chrome/browser/ui/ntp/new_tab_page_coordinator.mm index bd090eb8..0894011a 100644 --- a/ios/chrome/browser/ui/ntp/new_tab_page_coordinator.mm +++ b/ios/chrome/browser/ui/ntp/new_tab_page_coordinator.mm
@@ -290,6 +290,7 @@ self.feedMetricsRecorder.feedControlDelegate = self; self.feedMetricsRecorder.followDelegate = self; + if (IsContentSuggestionsHeaderMigrationEnabled()) { self.headerController = [[ContentSuggestionsHeaderViewController alloc] init]; // TODO(crbug.com/1045047): Use HandlerForProtocol after commands protocol @@ -320,6 +321,7 @@ self.headerController.focusOmniboxWhenViewAppears = NO; } } + } if (IsDiscoverFeedTopSyncPromoEnabled()) { self.feedTopSectionCoordinator = [self createFeedTopSectionCoordinator]; @@ -328,8 +330,10 @@ self.contentSuggestionsCoordinator = [self createContentSuggestionsCoordinator]; - self.headerController.promoCanShow = - [self.contentSuggestionsCoordinator notificationPromo]->CanShow(); + if (IsContentSuggestionsHeaderMigrationEnabled()) { + self.headerController.promoCanShow = + [self.contentSuggestionsCoordinator notificationPromo]->CanShow(); + } // Fetches feed header and conditionally fetches feed. Feed can only be // visible if feed header is visible. @@ -355,6 +359,14 @@ self.viewPresented = NO; [self updateVisible]; + if (!IsContentSuggestionsHeaderMigrationEnabled()) { + // Unfocus omnibox, to prevent it from lingering when it should be dismissed + // (for example, when navigating away or when changing feed visibility). + id<OmniboxCommands> omniboxCommandHandler = HandlerForProtocol( + self.browser->GetCommandDispatcher(), OmniboxCommands); + [omniboxCommandHandler cancelOmniboxEdit]; + } + SceneState* sceneState = SceneStateBrowserAgent::FromBrowser(self.browser)->GetSceneState(); [sceneState removeObserver:self]; @@ -439,8 +451,14 @@ - (void)configureNTPViewController { DCHECK(self.ntpViewController); - self.ntpViewController.contentSuggestionsViewController = - self.contentSuggestionsCoordinator.viewController; + if (IsContentSuggestionsUIViewControllerMigrationEnabled()) { + self.ntpViewController.contentSuggestionsViewController = + self.contentSuggestionsCoordinator.viewController; + } else { + self.ntpViewController.contentSuggestionsCollectionViewController = + self.contentSuggestionsCoordinator + .contentSuggestionsCollectionViewController; + } self.ntpViewController.panGestureHandler = self.panGestureHandler; self.ntpViewController.feedVisible = [self isFeedVisible]; @@ -454,16 +472,16 @@ self.headerSynchronizer = [[ContentSuggestionsHeaderSynchronizer alloc] initWithCollectionController:self.ntpViewController - headerController:self.headerController]; + headerController:[self headerController]]; self.ntpViewController.feedWrapperViewController = self.feedWrapperViewController; self.ntpViewController.overscrollDelegate = self; self.ntpViewController.ntpContentDelegate = self; self.ntpViewController.identityDiscButton = - [self.headerController identityDiscButton]; + [[self headerController] identityDiscButton]; - self.ntpViewController.headerController = self.headerController; + self.ntpViewController.headerController = [self headerController]; [self configureMainViewControllerUsing:self.ntpViewController]; self.ntpViewController.feedMetricsRecorder = self.feedMetricsRecorder; @@ -521,8 +539,12 @@ [self.ntpViewController stopScrolling]; } -- (BOOL)isScrolledToTop { - return [self.ntpViewController isNTPScrolledToTop]; +- (UIEdgeInsets)contentInset { + return [self.contentSuggestionsCoordinator contentInset]; +} + +- (CGPoint)contentOffset { + return [self.contentSuggestionsCoordinator contentOffset]; } - (void)willUpdateSnapshot { @@ -535,7 +557,7 @@ if (self.feedViewController) { [self.ntpViewController focusFakebox]; } else { - [self.headerController focusFakebox]; + [[self headerController] focusFakebox]; } } @@ -794,10 +816,11 @@ - (void)appState:(AppState*)appState didTransitionFromInitStage:(InitStage)previousInitStage { + DCHECK(IsContentSuggestionsHeaderMigrationEnabled()); if (base::FeatureList::IsEnabled(kEnableFREUIModuleIOS)) { if (previousInitStage == InitStageFirstRun) { - self.headerController.focusOmniboxWhenViewAppears = YES; - [self.headerController focusAccessibilityOnOmnibox]; + [self headerController].focusOmniboxWhenViewAppears = YES; + [[self headerController] focusAccessibilityOnOmnibox]; [appState removeObserver:self]; } @@ -807,7 +830,7 @@ #pragma mark - LogoAnimationControllerOwnerOwner - (id<LogoAnimationControllerOwner>)logoAnimationControllerOwner { - return [self.headerController logoAnimationControllerOwner]; + return [[self headerController] logoAnimationControllerOwner]; } #pragma mark - SceneStateObserver @@ -914,7 +937,7 @@ - (UIView*)toolbarSnapshotViewForOverscrollActionsController: (OverscrollActionsController*)controller { return - [[self.headerController toolBarView] snapshotViewAfterScreenUpdates:NO]; + [[[self headerController] toolBarView] snapshotViewAfterScreenUpdates:NO]; } - (UIView*)headerViewForOverscrollActionsController: @@ -929,7 +952,7 @@ - (CGFloat)headerHeightForOverscrollActionsController: (OverscrollActionsController*)controller { - CGFloat height = [self.headerController toolBarView].bounds.size.height; + CGFloat height = [[self headerController] toolBarView].bounds.size.height; CGFloat topInset = self.feedWrapperViewController.view.safeAreaInsets.top; return height + topInset; } @@ -948,10 +971,14 @@ #pragma mark - NewTabPageContentDelegate - (void)reloadContentSuggestions { - // No need to reload ContentSuggestions since the mediator receives all - // model state changes and immediately updates the consumer with the new - // state. - return; + if (IsContentSuggestionsHeaderMigrationEnabled() && + IsContentSuggestionsUIViewControllerMigrationEnabled()) { + // No need to reload ContentSuggestions since the mediator receives all + // model state changes and immediately updates the consumer with the new + // state. + return; + } + [self.contentSuggestionsCoordinator reload]; } - (BOOL)isContentHeaderSticky { @@ -1069,6 +1096,16 @@ } } +// TODO(crbug.com/1285378): Remove this after +// kContentSuggestionsHeaderMigrationEnabled is launched. +- (ContentSuggestionsHeaderViewController*)headerController { + if (IsContentSuggestionsHeaderMigrationEnabled()) { + return _headerController; + } else { + return self.contentSuggestionsCoordinator.headerController; + } +} + // Feed header is always visible unless it is disabled from the Chrome settings // menu, or by an enterprise policy. - (BOOL)isFeedHeaderVisible { @@ -1163,10 +1200,17 @@ initWithBaseViewController:nil browser:self.browser]; contentSuggestionsCoordinator.webState = self.webState; + if (!IsContentSuggestionsHeaderMigrationEnabled()) { + contentSuggestionsCoordinator.toolbarDelegate = self.toolbarDelegate; + } contentSuggestionsCoordinator.ntpMediator = self.ntpMediator; contentSuggestionsCoordinator.ntpDelegate = self; contentSuggestionsCoordinator.feedDelegate = self; [contentSuggestionsCoordinator start]; + if (!IsContentSuggestionsHeaderMigrationEnabled()) { + contentSuggestionsCoordinator.headerController.baseViewController = + self.baseViewController; + } return contentSuggestionsCoordinator; }
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_view_controller.h b/ios/chrome/browser/ui/ntp/new_tab_page_view_controller.h index 54c33a25..610099e 100644 --- a/ios/chrome/browser/ui/ntp/new_tab_page_view_controller.h +++ b/ios/chrome/browser/ui/ntp/new_tab_page_view_controller.h
@@ -51,6 +51,12 @@ // ContentSuggestions. @property(nonatomic, weak) UIButton* identityDiscButton; +// View controller representing the NTP content suggestions. These suggestions +// include the most visited site tiles, the shortcut tiles, the fake omnibox and +// the Google doodle. `contentSuggestionsUIViewController` is used if +// kContentSuggestionsUIViewControllerMigration is enabled. +@property(nonatomic, strong) + UICollectionViewController* contentSuggestionsCollectionViewController; @property(nonatomic, strong) ContentSuggestionsViewController* contentSuggestionsViewController;
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 5df61e59..3ff01089 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
@@ -13,6 +13,7 @@ #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_feature.h" #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_header_synchronizing.h" #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.h" +#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_layout.h" #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.h" #import "ios/chrome/browser/ui/content_suggestions/ntp_home_constant.h" #import "ios/chrome/browser/ui/gestures/view_revealing_vertical_pan_handler.h" @@ -56,6 +57,10 @@ // Whether or not the fake omnibox is pineed to the top of the NTP. @property(nonatomic, assign) BOOL fakeOmniboxPinnedToTop; +// The collection view layout for the uppermost content suggestions collection +// view. +@property(nonatomic, weak) ContentSuggestionsLayout* contentSuggestionsLayout; + // Constraint to determine the height of the contained ContentSuggestions view. @property(nonatomic, strong) NSLayoutConstraint* contentSuggestionsHeightConstraint; @@ -106,11 +111,11 @@ [super viewDidLoad]; DCHECK(self.feedWrapperViewController); - DCHECK(self.contentSuggestionsViewController); + DCHECK([self contentSuggestionsViewController]); // TODO(crbug.com/1262536): Remove this when bug is fixed. [self.feedWrapperViewController loadViewIfNeeded]; - [self.contentSuggestionsViewController loadViewIfNeeded]; + [[self contentSuggestionsViewController] loadViewIfNeeded]; // Prevent the NTP from spilling behind the toolbar and tab strip. self.view.clipsToBounds = YES; @@ -124,6 +129,22 @@ singleTapRecognizer.delegate = self; [self.view addGestureRecognizer:singleTapRecognizer]; + if (!IsContentSuggestionsUIViewControllerMigrationEnabled()) { + // Ensures that there is never any nested scrolling, since we are nesting + // the content suggestions collection view in the feed collection view. + self.contentSuggestionsCollectionViewController.collectionView.bounces = NO; + self.contentSuggestionsCollectionViewController.collectionView + .alwaysBounceVertical = NO; + self.contentSuggestionsCollectionViewController.collectionView + .scrollEnabled = NO; + + self.contentSuggestionsLayout = static_cast<ContentSuggestionsLayout*>( + self.contentSuggestionsCollectionViewController.collectionView + .collectionViewLayout); + self.contentSuggestionsLayout.isScrolledIntoFeed = self.isScrolledIntoFeed; + self.contentSuggestionsLayout.omniboxPositioner = self; + } + if (IsContentSuggestionsUIModuleRefreshEnabled()) { GradientView* gradientView = [[GradientView alloc] initWithTopColor:[UIColor colorNamed:kBackgroundColor] @@ -242,6 +263,9 @@ weakSelf.collectionView.contentOffset = CGPointMake(0, yOffsetBeforeRotation - heightAboveFeedDifference); [weakSelf updateNTPLayout]; + } else if (!IsContentSuggestionsUIViewControllerMigrationEnabled()) { + [weakSelf.contentSuggestionsCollectionViewController.collectionView + .collectionViewLayout invalidateLayout]; } [weakSelf.view setNeedsLayout]; [weakSelf.view layoutIfNeeded]; @@ -280,13 +304,17 @@ // height. self.headerTopAnchor.constant = -([self stickyOmniboxHeight] + [self feedHeaderHeight]); - [self.contentSuggestionsViewController.view setNeedsLayout]; - [self.contentSuggestionsViewController.view layoutIfNeeded]; + [[self contentSuggestionsViewController].view setNeedsLayout]; + [[self contentSuggestionsViewController].view layoutIfNeeded]; [self.ntpContentDelegate reloadContentSuggestions]; } if (previousTraitCollection.preferredContentSizeCategory != self.traitCollection.preferredContentSizeCategory) { + if (!IsContentSuggestionsUIViewControllerMigrationEnabled()) { + [self.contentSuggestionsCollectionViewController.collectionView + .collectionViewLayout invalidateLayout]; + } [self.headerSynchronizer updateFakeOmniboxForScrollPosition]; } @@ -298,7 +326,7 @@ - (void)layoutContentInParentCollectionView { DCHECK(self.feedWrapperViewController); - DCHECK(self.contentSuggestionsViewController); + DCHECK([self contentSuggestionsViewController]); // Ensure the view is loaded so we can set the accessibility identifier. [self.feedWrapperViewController loadViewIfNeeded]; @@ -315,10 +343,11 @@ // Configures the content suggestions in the view hierarchy. // TODO(crbug.com/1262536): Remove this when issue is fixed. - if (self.contentSuggestionsViewController.parentViewController) { - [self.contentSuggestionsViewController willMoveToParentViewController:nil]; - [self.contentSuggestionsViewController.view removeFromSuperview]; - [self.contentSuggestionsViewController removeFromParentViewController]; + if ([self contentSuggestionsViewController].parentViewController) { + [[self contentSuggestionsViewController] + willMoveToParentViewController:nil]; + [[self contentSuggestionsViewController].view removeFromSuperview]; + [[self contentSuggestionsViewController] removeFromParentViewController]; [self.feedMetricsRecorder recordBrokenNTPHierarchy:BrokenNTPHierarchyRelationship:: kContentSuggestionsReset]; @@ -335,8 +364,11 @@ [self addViewController:self.feedHeaderViewController toParentViewController:parentViewController]; } - [self addViewController:self.contentSuggestionsViewController + [self addViewController:[self contentSuggestionsViewController] toParentViewController:parentViewController]; + if (!IsContentSuggestionsUIViewControllerMigrationEnabled()) { + self.contentSuggestionsLayout.parentCollectionView = self.collectionView; + } // Adds the feed top section to the view hierarchy if it exists. if (IsDiscoverFeedTopSyncPromoEnabled() && @@ -345,26 +377,28 @@ toParentViewController:parentViewController]; } + if (IsContentSuggestionsHeaderMigrationEnabled()) { [self addViewController:self.headerController toParentViewController:parentViewController]; DCHECK([self.headerController.view isDescendantOfView:self.containerView]); self.headerController.view.translatesAutoresizingMaskIntoConstraints = NO; + } - // TODO(crbug.com/1170995): The contentCollectionView width might be - // narrower than the ContentSuggestions view. This causes elements to be - // hidden, so we set clipsToBounds to ensure that they remain visible. The - // collection view changes, so we must set this property each time it does. - self.collectionView.clipsToBounds = NO; + // TODO(crbug.com/1170995): The contentCollectionView width might be narrower + // than the ContentSuggestions view. This causes elements to be hidden, so we + // set clipsToBounds to ensure that they remain visible. The collection view + // changes, so we must set this property each time it does. + self.collectionView.clipsToBounds = NO; - [self.overscrollActionsController invalidate]; - [self configureOverscrollActionsController]; + [self.overscrollActionsController invalidate]; + [self configureOverscrollActionsController]; - // If viewDidAppear, then we are just changing the NTP collection view. In - // that case, we apply the constraints here. - if (self.viewDidAppear) { - [self applyCollectionViewConstraints]; - } + // If viewDidAppear, then we are just changing the NTP collection view. In + // that case, we apply the constraints here. + if (self.viewDidAppear) { + [self applyCollectionViewConstraints]; + } // 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 @@ -409,6 +443,10 @@ // presented in front of the NTP. [self.headerSynchronizer updateFakeOmniboxOnNewWidth:self.collectionView.bounds.size.width]; + if (!IsContentSuggestionsUIViewControllerMigrationEnabled()) { + [self.contentSuggestionsCollectionViewController.collectionView + .collectionViewLayout invalidateLayout]; + } // Ensure initial fake omnibox layout. [self.headerSynchronizer updateFakeOmniboxForScrollPosition]; @@ -431,15 +469,17 @@ - (CGFloat)heightAboveFeed { CGFloat height = [self adjustedContentSuggestionsHeight] + [self feedHeaderHeight] + [self feedTopSectionHeight]; - // Add the header height since it is no longer a part of the Content - // Suggestions. - height += [self.headerController headerHeight]; + if (IsContentSuggestionsHeaderMigrationEnabled()) { + // Add the header height since it is no longer a part of the Content + // Suggestions. + height += [self.headerController headerHeight]; + } return height; } - (void)resetViewHierarchy { [self removeFromViewHierarchy:self.feedWrapperViewController]; - [self removeFromViewHierarchy:self.contentSuggestionsViewController]; + [self removeFromViewHierarchy:[self contentSuggestionsViewController]]; if (self.feedHeaderViewController) { [self removeFromViewHierarchy:self.feedHeaderViewController]; } @@ -489,6 +529,14 @@ #pragma mark - UIScrollViewDelegate - (void)scrollViewDidScroll:(UIScrollView*)scrollView { + // Scroll events should not be handled until the content suggestions have been + // layed out. + if (!IsContentSuggestionsUIViewControllerMigrationEnabled() && + !self.contentSuggestionsCollectionViewController.collectionView + .contentSize.height) { + return; + } + [self.overscrollActionsController scrollViewDidScroll:scrollView]; [self.panGestureHandler scrollViewDidScroll:scrollView]; [self.headerSynchronizer updateFakeOmniboxForScrollPosition]; @@ -496,6 +544,13 @@ [self updateScrolledToMinimumHeight]; CGFloat scrollPosition = scrollView.contentOffset.y; + // Fixes the content suggestions collection view layout so that the header + // scrolls at the same rate as the rest. + if (scrollPosition > -[self heightAboveFeed] && + !IsContentSuggestionsUIViewControllerMigrationEnabled()) { + [self.contentSuggestionsCollectionViewController.collectionView + .collectionViewLayout invalidateLayout]; + } [self handleStickyElementsForScrollPosition:scrollPosition force:NO]; } @@ -656,36 +711,79 @@ return; } - [NSLayoutConstraint deactivateConstraints:self.fakeOmniboxConstraints]; + if (IsContentSuggestionsHeaderMigrationEnabled()) { + [NSLayoutConstraint deactivateConstraints:self.fakeOmniboxConstraints]; + } else { + [self.headerController removeFromParentViewController]; + [self.headerController.view removeFromSuperview]; + [self.view addSubview:self.headerController.view]; + } - self.headerTopAnchor = [self.headerController.view.topAnchor - constraintEqualToAnchor:self.feedWrapperViewController.view.topAnchor - constant:-([self stickyOmniboxHeight] + - [self feedHeaderHeight])]; - // This issue fundamentally comes down to the topAnchor being set just once - // and if it is set in landscape mode, it never is updated upon rotation. - // And landscape is when it doesn't matter. - self.fakeOmniboxConstraints = @[ - self.headerTopAnchor, - [self.headerController.view.leadingAnchor - constraintEqualToAnchor:self.feedWrapperViewController.view - .leadingAnchor], - [self.headerController.view.trailingAnchor - constraintEqualToAnchor:self.feedWrapperViewController.view - .trailingAnchor], - ]; + if (IsContentSuggestionsHeaderMigrationEnabled()) { + self.headerTopAnchor = [self.headerController.view.topAnchor + constraintEqualToAnchor:self.feedWrapperViewController.view.topAnchor + constant:-([self stickyOmniboxHeight] + + [self feedHeaderHeight])]; + // This issue fundamentally comes down to the topAnchor being set just once + // and if it is set in landscape mode, it never is updated upon rotation. + // And landscape is when it doesn't matter. + self.fakeOmniboxConstraints = @[ + self.headerTopAnchor, + [self.headerController.view.leadingAnchor + constraintEqualToAnchor:self.feedWrapperViewController.view + .leadingAnchor], + [self.headerController.view.trailingAnchor + constraintEqualToAnchor:self.feedWrapperViewController.view + .trailingAnchor], + ]; + } else { + self.fakeOmniboxConstraints = @[ + [self.headerController.view.topAnchor + constraintEqualToAnchor:self.feedWrapperViewController.view.topAnchor + constant:-([self stickyOmniboxHeight] + + [self feedHeaderHeight])], + [self.headerController.view.leadingAnchor + constraintEqualToAnchor:self.feedWrapperViewController.view + .leadingAnchor], + [self.headerController.view.trailingAnchor + constraintEqualToAnchor:self.feedWrapperViewController.view + .trailingAnchor], + [self.headerController.view.heightAnchor + constraintEqualToConstant:self.headerController.view.frame.size + .height], + ]; + } + + if (!IsContentSuggestionsHeaderMigrationEnabled()) { + self.contentSuggestionsHeightConstraint.active = NO; + } [NSLayoutConstraint activateConstraints:self.fakeOmniboxConstraints]; } // Gives content suggestions collection view ownership of the fake omnibox for // the width animation. - (void)setInitialFakeOmniboxConstraints { + if (!IsContentSuggestionsHeaderMigrationEnabled()) { + [self.headerController removeFromParentViewController]; + [self.headerController.view removeFromSuperview]; + self.contentSuggestionsHeightConstraint.active = YES; + } + [NSLayoutConstraint deactivateConstraints:self.fakeOmniboxConstraints]; - self.fakeOmniboxConstraints = @[ - [self.contentSuggestionsViewController.view.topAnchor - constraintEqualToAnchor:self.headerController.view.bottomAnchor], - ]; - [NSLayoutConstraint activateConstraints:self.fakeOmniboxConstraints]; + if (IsContentSuggestionsHeaderMigrationEnabled()) { + self.fakeOmniboxConstraints = @[ + [[self contentSuggestionsViewController].view.topAnchor + constraintEqualToAnchor:self.headerController.view.bottomAnchor], + ]; + [NSLayoutConstraint activateConstraints:self.fakeOmniboxConstraints]; + } + + // Reload the content suggestions so that the fake omnibox goes back where it + // belongs. This can probably be optimized by just reloading the header, if + // that doesn't mess up any collection/header interactions. + if (!IsContentSuggestionsHeaderMigrationEnabled()) { + [self.ntpContentDelegate reloadContentSuggestions]; + } } // Pins feed header to top of the NTP when scrolled into the feed, below the @@ -706,8 +804,8 @@ [self.feedHeaderViewController customSearchEngineViewHeight])], [self.collectionView.topAnchor - constraintEqualToAnchor:self.contentSuggestionsViewController.view - .bottomAnchor], + constraintEqualToAnchor:[self contentSuggestionsViewController] + .view.bottomAnchor], ]; } else { self.feedHeaderConstraints = @[ @@ -716,8 +814,8 @@ constant:-[self.feedHeaderViewController customSearchEngineViewHeight]], [self.collectionView.topAnchor - constraintEqualToAnchor:self.contentSuggestionsViewController.view - .bottomAnchor], + constraintEqualToAnchor:[self contentSuggestionsViewController] + .view.bottomAnchor], ]; } @@ -739,8 +837,8 @@ } self.feedHeaderConstraints = @[ [self.feedHeaderViewController.view.topAnchor - constraintEqualToAnchor:self.contentSuggestionsViewController.view - .bottomAnchor], + constraintEqualToAnchor:[self contentSuggestionsViewController] + .view.bottomAnchor], [bottomView.topAnchor constraintEqualToAnchor:self.feedHeaderViewController .view.bottomAnchor], ]; @@ -771,8 +869,8 @@ -[self feedHeaderHeight] - [self feedTopSectionHeight], self.view.frame.size.width, [self feedHeaderHeight]); } - self.contentSuggestionsViewController.view.frame = CGRectMake( - self.contentSuggestionsViewController.view.frame.origin.x, + [self contentSuggestionsViewController].view.frame = CGRectMake( + [self contentSuggestionsViewController].view.frame.origin.x, -[self contentSuggestionsContentHeight] - [self feedHeaderHeight] - [self feedTopSectionHeight], self.view.frame.size.width, [self contentSuggestionsContentHeight]); @@ -866,7 +964,7 @@ // Applies constraints to the NTP collection view, along with the constraints // for the content suggestions within it. - (void)applyCollectionViewConstraints { - UIView* contentSuggestionsView = self.contentSuggestionsViewController.view; + UIView* contentSuggestionsView = [self contentSuggestionsViewController].view; contentSuggestionsView.translatesAutoresizingMaskIntoConstraints = NO; self.contentSuggestionsHeightConstraint = [contentSuggestionsView.heightAnchor @@ -902,6 +1000,7 @@ ]]; } + if (IsContentSuggestionsHeaderMigrationEnabled()) { [NSLayoutConstraint activateConstraints:@[ [[self containerView].safeAreaLayoutGuide.leadingAnchor constraintEqualToAnchor:self.headerController.view.leadingAnchor], @@ -909,14 +1008,15 @@ constraintEqualToAnchor:self.headerController.view.trailingAnchor], ]]; [self setInitialFakeOmniboxConstraints]; + } - [NSLayoutConstraint activateConstraints:@[ - [[self containerView].safeAreaLayoutGuide.leadingAnchor - constraintEqualToAnchor:contentSuggestionsView.leadingAnchor], - [[self containerView].safeAreaLayoutGuide.trailingAnchor - constraintEqualToAnchor:contentSuggestionsView.trailingAnchor], - self.contentSuggestionsHeightConstraint, - ]]; + [NSLayoutConstraint activateConstraints:@[ + [[self containerView].safeAreaLayoutGuide.leadingAnchor + constraintEqualToAnchor:contentSuggestionsView.leadingAnchor], + [[self containerView].safeAreaLayoutGuide.trailingAnchor + constraintEqualToAnchor:contentSuggestionsView.trailingAnchor], + self.contentSuggestionsHeightConstraint, + ]]; } // Sets minimum height for the NTP collection view, allowing it to scroll enough @@ -935,38 +1035,49 @@ #pragma mark - Helpers - (UIViewController*)contentSuggestionsViewController { - return _contentSuggestionsViewController; + return IsContentSuggestionsUIViewControllerMigrationEnabled() + ? _contentSuggestionsViewController + : self.contentSuggestionsCollectionViewController; } - (CGFloat)minimumNTPHeight { - CGFloat collectionViewHeight = self.collectionView.bounds.size.height; - CGFloat headerHeight = [self.headerController headerHeight]; + if (IsContentSuggestionsHeaderMigrationEnabled()) { + CGFloat collectionViewHeight = self.collectionView.bounds.size.height; + CGFloat headerHeight = [self.headerController headerHeight]; - // The minimum height for the collection view content should be the height - // of the header plus the height of the collection view minus the height of - // the NTP bottom bar. This allows the Most Visited cells to be scrolled up - // to the top of the screen. Also computes the total NTP scrolling height - // for Discover infinite feed. - CGFloat ntpHeight = collectionViewHeight + headerHeight; - CGFloat minimumHeight = - ntpHeight - ntp_header::kScrolledToTopOmniboxBottomMargin; - if (!IsRegularXRegularSizeClass(self.collectionView)) { - CGFloat toolbarHeight = - IsSplitToolbarMode(self.collectionView) - ? ToolbarExpandedHeight([UIApplication sharedApplication] - .preferredContentSizeCategory) - : 0; - CGFloat additionalHeight = - toolbarHeight + self.collectionView.contentInset.bottom; - minimumHeight -= additionalHeight; + // The minimum height for the collection view content should be the height + // of the header plus the height of the collection view minus the height of + // the NTP bottom bar. This allows the Most Visited cells to be scrolled up + // to the top of the screen. Also computes the total NTP scrolling height + // for Discover infinite feed. + CGFloat ntpHeight = collectionViewHeight + headerHeight; + CGFloat minimumHeight = + ntpHeight - ntp_header::kScrolledToTopOmniboxBottomMargin; + if (!IsRegularXRegularSizeClass(self.collectionView)) { + CGFloat toolbarHeight = + IsSplitToolbarMode(self.collectionView) + ? ToolbarExpandedHeight([UIApplication sharedApplication] + .preferredContentSizeCategory) + : 0; + CGFloat additionalHeight = + toolbarHeight + self.collectionView.contentInset.bottom; + minimumHeight -= additionalHeight; + } + + return minimumHeight; + } else { + return [self.contentSuggestionsLayout minimumNTPHeight]; } - - return minimumHeight; } // Returns the current height of the content suggestions content. - (CGFloat)contentSuggestionsContentHeight { - return [self.contentSuggestionsViewController contentSuggestionsHeight]; + if (IsContentSuggestionsUIViewControllerMigrationEnabled()) { + return [self.contentSuggestionsViewController contentSuggestionsHeight]; + } else { + return self.contentSuggestionsCollectionViewController.collectionView + .contentSize.height; + } } // Content suggestions height adjusted with the safe area top insets. @@ -1015,8 +1126,12 @@ - (CGFloat)offsetToStickOmnibox { CGFloat offset = -(self.headerController.view.frame.size.height - - [self stickyOmniboxHeight] - [self contentSuggestionsContentHeight] - + [self stickyOmniboxHeight] - [self.feedHeaderViewController customSearchEngineViewHeight]); + if (IsSplitToolbarMode(self) && + IsContentSuggestionsHeaderMigrationEnabled()) { + offset -= [self contentSuggestionsContentHeight]; + } if (self.feedTopSectionViewController) { offset -= self.feedTopSectionViewController.view.frame.size.height; } @@ -1041,21 +1156,23 @@ // self.feedWrapperViewController.feedViewController.view -> // self.collectionView -> self.contentSuggestionsViewController.view. if (![self.collectionView.subviews - containsObject:self.contentSuggestionsViewController.view]) { + containsObject:[self contentSuggestionsViewController].view]) { // Remove child VC from old parent. - [self.contentSuggestionsViewController willMoveToParentViewController:nil]; - [self.contentSuggestionsViewController removeFromParentViewController]; - [self.contentSuggestionsViewController.view removeFromSuperview]; - [self.contentSuggestionsViewController didMoveToParentViewController:nil]; + [[self contentSuggestionsViewController] + willMoveToParentViewController:nil]; + [[self contentSuggestionsViewController] removeFromParentViewController]; + [[self contentSuggestionsViewController].view removeFromSuperview]; + [[self contentSuggestionsViewController] didMoveToParentViewController:nil]; // Add child VC to new parent. - [self.contentSuggestionsViewController + [[self contentSuggestionsViewController] willMoveToParentViewController:self.feedWrapperViewController .feedViewController]; [self.feedWrapperViewController.feedViewController - addChildViewController:self.contentSuggestionsViewController]; - [self.collectionView addSubview:self.contentSuggestionsViewController.view]; - [self.contentSuggestionsViewController + addChildViewController:[self contentSuggestionsViewController]]; + [self.collectionView + addSubview:[self contentSuggestionsViewController].view]; + [[self contentSuggestionsViewController] didMoveToParentViewController:self.feedWrapperViewController .feedViewController]; @@ -1064,10 +1181,12 @@ kContentSuggestionsParent]; } - [self ensureView:self.headerController.view - isSubviewOf:self.collectionView - withRelationshipID:BrokenNTPHierarchyRelationship:: - kContentSuggestionsHeaderParent]; + if (IsContentSuggestionsHeaderMigrationEnabled()) { + [self ensureView:self.headerController.view + isSubviewOf:self.collectionView + withRelationshipID:BrokenNTPHierarchyRelationship:: + kContentSuggestionsHeaderParent]; + } [self ensureView:self.feedHeaderViewController.view isSubviewOf:self.collectionView @@ -1155,6 +1274,7 @@ // view controls its position. - (void)setIsScrolledIntoFeed:(BOOL)scrolledIntoFeed { _scrolledIntoFeed = scrolledIntoFeed; + self.contentSuggestionsLayout.isScrolledIntoFeed = scrolledIntoFeed; } // Sets the y content offset of the NTP collection view.
diff --git a/ios/chrome/browser/ui/settings/BUILD.gn b/ios/chrome/browser/ui/settings/BUILD.gn index 5a00ec3..1959d96f 100644 --- a/ios/chrome/browser/ui/settings/BUILD.gn +++ b/ios/chrome/browser/ui/settings/BUILD.gn
@@ -209,7 +209,6 @@ "//url", ] allow_circular_includes_from = [ "//ios/chrome/browser/ui/authentication" ] - public_deps = [ "//ios/third_party/material_components_ios" ] frameworks = [ "CoreLocation.framework", "UIKit.framework",
diff --git a/ios/chrome/browser/ui/start_surface/start_surface_egtest.mm b/ios/chrome/browser/ui/start_surface/start_surface_egtest.mm index d02ee45..64d16e4 100644 --- a/ios/chrome/browser/ui/start_surface/start_surface_egtest.mm +++ b/ios/chrome/browser/ui/start_surface/start_surface_egtest.mm
@@ -35,6 +35,9 @@ - (AppLaunchConfiguration)appConfigurationForTestCase { AppLaunchConfiguration config; config.relaunch_policy = ForceRelaunchByCleanShutdown; + config.features_enabled.push_back(kContentSuggestionsHeaderMigration); + config.features_enabled.push_back( + kContentSuggestionsUIViewControllerMigration); config.additional_args.push_back( std::string("--force-fieldtrial-params=StartSurface.ShrinkLogo:" "ReturnToStartSurfaceInactiveDurationInSeconds/0"));
diff --git a/ios/chrome/browser/ui/webui/ntp_tiles_internals_ui.cc b/ios/chrome/browser/ui/webui/ntp_tiles_internals_ui.cc index 91215b6..fabacfe 100644 --- a/ios/chrome/browser/ui/webui/ntp_tiles_internals_ui.cc +++ b/ios/chrome/browser/ui/webui/ntp_tiles_internals_ui.cc
@@ -50,10 +50,10 @@ PrefService* GetPrefs() override; using MessageCallback = base::RepeatingCallback<void(const base::Value::List&)>; - void RegisterMessageCallback(const std::string& message, + void RegisterMessageCallback(base::StringPiece message, MessageCallback callback) override; void CallJavascriptFunctionSpan( - const std::string& name, + base::StringPiece name, base::span<const base::ValueView> values) override; ntp_tiles::NTPTilesInternalsMessageHandler handler_; @@ -95,13 +95,13 @@ } void IOSNTPTilesInternalsMessageHandlerBridge::RegisterMessageCallback( - const std::string& message, + base::StringPiece message, MessageCallback callback) { web_ui()->RegisterMessageCallback(message, std::move(callback)); } void IOSNTPTilesInternalsMessageHandlerBridge::CallJavascriptFunctionSpan( - const std::string& name, + base::StringPiece name, base::span<const base::ValueView> values) { web_ui()->CallJavascriptFunction(name, values); }
diff --git a/ios/chrome/browser/ui/webui/translate_internals/ios_translate_internals_handler.h b/ios/chrome/browser/ui/webui/translate_internals/ios_translate_internals_handler.h index 5bc0480..7820298 100644 --- a/ios/chrome/browser/ui/webui/translate_internals/ios_translate_internals_handler.h +++ b/ios/chrome/browser/ui/webui/translate_internals/ios_translate_internals_handler.h
@@ -36,9 +36,9 @@ // translate::TranslateInternalsHandler. translate::TranslateClient* GetTranslateClient() override; variations::VariationsService* GetVariationsService() override; - void RegisterMessageCallback(const std::string& message, + void RegisterMessageCallback(base::StringPiece message, MessageCallback callback) override; - void CallJavascriptFunction(const std::string& function_name, + void CallJavascriptFunction(base::StringPiece function_name, base::span<const base::ValueView> args) override; // web::WebUIIOSMessageHandler.
diff --git a/ios/chrome/browser/ui/webui/translate_internals/ios_translate_internals_handler.mm b/ios/chrome/browser/ui/webui/translate_internals/ios_translate_internals_handler.mm index cbb5695..2d52368b 100644 --- a/ios/chrome/browser/ui/webui/translate_internals/ios_translate_internals_handler.mm +++ b/ios/chrome/browser/ui/webui/translate_internals/ios_translate_internals_handler.mm
@@ -33,13 +33,13 @@ } void IOSTranslateInternalsHandler::RegisterMessageCallback( - const std::string& message, + base::StringPiece message, MessageCallback callback) { web_ui()->RegisterMessageCallback(message, std::move(callback)); } void IOSTranslateInternalsHandler::CallJavascriptFunction( - const std::string& function_name, + base::StringPiece function_name, base::span<const base::ValueView> args) { web_ui()->CallJavascriptFunction(function_name, args); }
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 index e0f9da1e..7aefc53 100644 --- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -a29d3e104ead2e219cc5b32aee9cf11c4760bb96 \ No newline at end of file +afe3f9fbc0f935ef0975cfca9b0a43783793d0fe \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 index 99401d5..6ad5024 100644 --- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -24971d9d4b0d5ed753e617459af348412c33f561 \ No newline at end of file +8cadbd516410dc83b83198c20235c08f06702d95 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 index 9878bb9..a8d2be4e 100644 --- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -21391146dc26a538b0f3320f304f4dde5d4abc9f \ No newline at end of file +308fe47d96f0d1243ff68039f77249c9d507864c \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 index e430bd38..99a2e0c 100644 --- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -0c596d892aec1155c28c04df0d532994a261b1f0 \ No newline at end of file +c764e1a683991c9ed3a9a359c0cda5ce6f865594 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1 index ca9b6a3..dcf81ef6 100644 --- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -a82fc27d0be47a38fd27b11690d70dc91c3b0fe3 \ No newline at end of file +a180733206934b878d878558ca419d793174277b \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1 index bb225ed..f5357938 100644 --- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -4e293bc7a70e347309532a8a9242a23728718842 \ No newline at end of file +e9ff32e203c63c9b78f69129d8acfdd82a925fc7 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 index 5cd48cb3..e586322 100644 --- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -9bf5534eac86ea684170eb81e835e86d62724aff \ No newline at end of file +fd9d4f38e27f04ce3a867f436fd348fd7bf561a3 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 index 0a04b70..2666313 100644 --- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -0b21d62cc765ce092a10543c1b30733ac62cff96 \ No newline at end of file +935504d64af8a74e00159b599ecf788120b52ea1 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 index 3ee4cac2..1debb09 100644 --- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -d1a242a723f93531330bceff731324955eea8217 \ No newline at end of file +90824bfd2ae442a0b5be5bf60fac14843ec46668 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 index b803241b..3379a3f54 100644 --- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -7ab9999ff352cd096143f35a8a66926fe709739e \ No newline at end of file +f7f548e827bfaf902f6f9e74b30cf467da7f619e \ No newline at end of file
diff --git a/media/capture/BUILD.gn b/media/capture/BUILD.gn index 927a163..90e7a439 100644 --- a/media/capture/BUILD.gn +++ b/media/capture/BUILD.gn
@@ -477,10 +477,9 @@ "video/fuchsia/video_capture_device_factory_fuchsia_test.cc", "video/fuchsia/video_capture_device_fuchsia_test.cc", ] - use_cfv2 = false - additional_manifest_fragments = [ - "//build/config/fuchsia/test/web_engine_required_capabilities.test-cmx", - ] + use_cfv1 = false + additional_manifest_fragments = + [ "//media/fuchsia/camera/test_support.shard.test-cml" ] } if (is_mac) {
diff --git a/media/fuchsia/camera/BUILD.gn b/media/fuchsia/camera/BUILD.gn index c8ec86f..1140551e 100644 --- a/media/fuchsia/camera/BUILD.gn +++ b/media/fuchsia/camera/BUILD.gn
@@ -2,6 +2,9 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +# Tests may include the accompanying test_support.shard.test-cml in this +# directory in their additional_manifest_fragments to satisfy capability +# requirements for this target. source_set("test_support") { testonly = true public_deps = [
diff --git a/media/fuchsia/camera/test_support.shard.test-cml b/media/fuchsia/camera/test_support.shard.test-cml new file mode 100644 index 0000000..3ffd910 --- /dev/null +++ b/media/fuchsia/camera/test_support.shard.test-cml
@@ -0,0 +1,10 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +{ + use: [ + { + protocol: "fuchsia.sysmem.Allocator", + }, + ], +}
diff --git a/services/network/OWNERS b/services/network/OWNERS index 20bbe264..4205752 100644 --- a/services/network/OWNERS +++ b/services/network/OWNERS
@@ -40,3 +40,7 @@ # Cookies per-file *cookie*=file://net/cookies/OWNERS + +# Private Network Access +per-file private_network_access*=titouan@chromium.org +per-file private_network_access*=lyf@chromium.org
diff --git a/services/network/private_network_access_checker.cc b/services/network/private_network_access_checker.cc index 5a8added..b7d1cfd 100644 --- a/services/network/private_network_access_checker.cc +++ b/services/network/private_network_access_checker.cc
@@ -198,8 +198,14 @@ // for this request. Further checks should not be run, otherwise we might // return `kBlockedByPolicyPreflightWarn` and trigger a new preflight to be // sent, thus causing https://crbug.com/1279376 all over again. + // + // Redirection blocked by PNA check in https://crbug.com/1334689. + // A request with HTTPS is under PNA warning mode other than allow mode. + // Private network access checker should not be applied to these requests. if (policy == mojom::PrivateNetworkRequestPolicy::kPreflightWarn) { return Result::kAllowedByPolicyPreflightWarn; + } else if (policy == mojom::PrivateNetworkRequestPolicy::kWarn) { + return Result::kAllowedByPolicyWarn; } return Result::kBlockedByInconsistentIpAddressSpace;
diff --git a/services/network/private_network_access_checker_unittest.cc b/services/network/private_network_access_checker_unittest.cc index d125d76e..7876bebb 100644 --- a/services/network/private_network_access_checker_unittest.cc +++ b/services/network/private_network_access_checker_unittest.cc
@@ -237,6 +237,29 @@ } TEST(PrivateNetworkAccessCheckerTest, + CheckAllowedByPolicyWarnInconsistentIpAddressSpace) { + base::HistogramTester histogram_tester; + + auto factory_params = mojom::URLLoaderFactoryParams::New(); + factory_params->client_security_state = mojom::ClientSecurityState::New(); + factory_params->client_security_state->ip_address_space = + mojom::IPAddressSpace::kPublic; + factory_params->client_security_state->private_network_request_policy = + mojom::PrivateNetworkRequestPolicy::kWarn; + + PrivateNetworkAccessChecker checker(ResourceRequest(), factory_params.get(), + mojom::kURLLoadOptionNone); + + EXPECT_EQ(checker.Check(DirectTransport(PrivateEndpoint())), + Result::kAllowedByPolicyWarn); + + // Even though this is inconsistent with the previous IP address space, the + // inconsistency is ignored because of the `kWarn` policy. + EXPECT_EQ(checker.Check(DirectTransport(PublicEndpoint())), + Result::kAllowedByPolicyWarn); +} + +TEST(PrivateNetworkAccessCheckerTest, CheckAllowedByPolicyAllowInconsistentIpAddressSpace) { base::HistogramTester histogram_tester;
diff --git a/services/tracing/public/cpp/perfetto/java_heap_profiler/hprof_parser_android.cc b/services/tracing/public/cpp/perfetto/java_heap_profiler/hprof_parser_android.cc index d251211..61a6ff4 100644 --- a/services/tracing/public/cpp/perfetto/java_heap_profiler/hprof_parser_android.cc +++ b/services/tracing/public/cpp/perfetto/java_heap_profiler/hprof_parser_android.cc
@@ -382,35 +382,32 @@ case 0x01: { // ROOT_JNI_GLOBAL = 1; ObjectId root_object_id = hprof_buffer_->GetId(); hprof_buffer_->SkipId(); - roots_[RootType::HeapGraphRoot_Type_ROOT_JNI_GLOBAL].push_back( - root_object_id); + roots_[HeapGraphRoot::Type::ROOT_JNI_GLOBAL].push_back(root_object_id); break; } case 0x02: { // ROOT_JNI_LOCAL = 2; ObjectId root_object_id = hprof_buffer_->GetId(); hprof_buffer_->Skip(8); - roots_[RootType::HeapGraphRoot_Type_ROOT_JNI_LOCAL].push_back( - root_object_id); + roots_[HeapGraphRoot::Type::ROOT_JNI_LOCAL].push_back(root_object_id); break; } case 0x03: { // ROOT_JAVA_FRAME = 3; ObjectId root_object_id = hprof_buffer_->GetId(); hprof_buffer_->Skip(8); - roots_[RootType::HeapGraphRoot_Type_ROOT_JAVA_FRAME].push_back( - root_object_id); + roots_[HeapGraphRoot::Type::ROOT_JAVA_FRAME].push_back(root_object_id); break; } case 0x04: { // ROOT_NATIVE_STACK = 4; ObjectId root_object_id = hprof_buffer_->GetId(); hprof_buffer_->Skip(4); - roots_[RootType::HeapGraphRoot_Type_ROOT_NATIVE_STACK].push_back( + roots_[HeapGraphRoot::Type::ROOT_NATIVE_STACK].push_back( root_object_id); break; } case 0x05: { // ROOT_STICKY_CLASS = 5; ObjectId root_object_id = hprof_buffer_->GetId(); - roots_[RootType::HeapGraphRoot_Type_ROOT_STICKY_CLASS].push_back( + roots_[HeapGraphRoot::Type::ROOT_STICKY_CLASS].push_back( root_object_id); break; } @@ -418,52 +415,48 @@ ObjectId root_object_id = hprof_buffer_->GetId(); hprof_buffer_->Skip(4); - roots_[RootType::HeapGraphRoot_Type_ROOT_THREAD_BLOCK].push_back( + roots_[HeapGraphRoot::Type::ROOT_THREAD_BLOCK].push_back( root_object_id); break; } case 0x07: { // ROOT_MONITOR_USED = 7; ObjectId root_object_id = hprof_buffer_->GetId(); - roots_[RootType::HeapGraphRoot_Type_ROOT_MONITOR_USED].push_back( + roots_[HeapGraphRoot::Type::ROOT_MONITOR_USED].push_back( root_object_id); break; } case 0x08: { // ROOT_THREAD_OBJECT = 8; ObjectId root_object_id = hprof_buffer_->GetId(); hprof_buffer_->Skip(8); - roots_[RootType::HeapGraphRoot_Type_ROOT_THREAD_OBJECT].push_back( + roots_[HeapGraphRoot::Type::ROOT_THREAD_OBJECT].push_back( root_object_id); break; } case 0x89: { // ROOT_INTERNED_STRING = 9 ObjectId root_object_id = hprof_buffer_->GetId(); - roots_[RootType::HeapGraphRoot_Type_ROOT_INTERNED_STRING].push_back( + roots_[HeapGraphRoot::Type::ROOT_INTERNED_STRING].push_back( root_object_id); break; } case 0x8a: { // ROOT_FINALIZING = 10; ObjectId root_object_id = hprof_buffer_->GetId(); - roots_[RootType::HeapGraphRoot_Type_ROOT_FINALIZING].push_back( - root_object_id); + roots_[HeapGraphRoot::Type::ROOT_FINALIZING].push_back(root_object_id); break; } case 0x8b: { // ROOT_DEBUGGER = 11; ObjectId root_object_id = hprof_buffer_->GetId(); - roots_[RootType::HeapGraphRoot_Type_ROOT_DEBUGGER].push_back( - root_object_id); + roots_[HeapGraphRoot::Type::ROOT_DEBUGGER].push_back(root_object_id); break; } case 0x8d: { // ROOT_VM_INTERNAL = 13; ObjectId root_object_id = hprof_buffer_->GetId(); - roots_[RootType::HeapGraphRoot_Type_ROOT_VM_INTERNAL].push_back( - root_object_id); + roots_[HeapGraphRoot::Type::ROOT_VM_INTERNAL].push_back(root_object_id); break; } case 0x8e: { // ROOT_JNI_MONITOR = 14; ObjectId root_object_id = hprof_buffer_->GetId(); hprof_buffer_->Skip(8); - roots_[RootType::HeapGraphRoot_Type_ROOT_JNI_MONITOR].push_back( - root_object_id); + roots_[HeapGraphRoot::Type::ROOT_JNI_MONITOR].push_back(root_object_id); break; } case 0xfe: // HEAP DUMP INFO (ANDROID) @@ -471,8 +464,7 @@ break; case 0xff: { // ROOT_UNKNOWN = 0; ObjectId root_object_id = hprof_buffer_->GetId(); - roots_[RootType::HeapGraphRoot_Type_ROOT_UNKNOWN].push_back( - root_object_id); + roots_[HeapGraphRoot::Type::ROOT_UNKNOWN].push_back(root_object_id); break; }
diff --git a/services/tracing/public/cpp/perfetto/java_heap_profiler/hprof_parser_android.h b/services/tracing/public/cpp/perfetto/java_heap_profiler/hprof_parser_android.h index 488f0412..b6085ae 100644 --- a/services/tracing/public/cpp/perfetto/java_heap_profiler/hprof_parser_android.h +++ b/services/tracing/public/cpp/perfetto/java_heap_profiler/hprof_parser_android.h
@@ -18,7 +18,8 @@ namespace tracing { using ObjectId = uint64_t; -using RootType = ::perfetto::protos::pbzero::HeapGraphRoot_Type; +using RootType = ::perfetto::protos::pbzero::HeapGraphRoot::Type; +using HeapGraphRoot = ::perfetto::protos::pbzero::HeapGraphRoot; const uint64_t kInvalidObjectId = std::numeric_limits<uint64_t>::max(); // This class takes in a temporary file_path where Java API endpoint
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json index f2cf067cd..f7bbdfa 100644 --- a/testing/buildbot/chromium.chromiumos.json +++ b/testing/buildbot/chromium.chromiumos.json
@@ -5686,21 +5686,21 @@ { "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_v104.0.5112.64/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v104.0.5112.83/test_ash_chrome" ], "isolate_profile_data": true, "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" }, - "name": "interactive_ui_tests Lacros version skew testing ash 104.0.5112.64", + "name": "interactive_ui_tests Lacros version skew testing ash 104.0.5112.83", "swarming": { "can_use_on_swarming_builders": true, "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v104.0.5112.64", - "revision": "version:104.0.5112.64" + "location": "lacros_version_skew_tests_v104.0.5112.83", + "revision": "version:104.0.5112.83" } ], "dimension_sets": [ @@ -5713,7 +5713,7 @@ }, "test": "interactive_ui_tests", "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/", - "variant_id": "Lacros version skew testing ash 104.0.5112.64" + "variant_id": "Lacros version skew testing ash 104.0.5112.83" }, { "args": [ @@ -5750,21 +5750,21 @@ { "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_v106.0.5215.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v106.0.5216.0/test_ash_chrome" ], "isolate_profile_data": true, "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" }, - "name": "interactive_ui_tests Lacros version skew testing ash 106.0.5215.0", + "name": "interactive_ui_tests Lacros version skew testing ash 106.0.5216.0", "swarming": { "can_use_on_swarming_builders": true, "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v106.0.5215.0", - "revision": "version:106.0.5215.0" + "location": "lacros_version_skew_tests_v106.0.5216.0", + "revision": "version:106.0.5216.0" } ], "dimension_sets": [ @@ -5777,7 +5777,7 @@ }, "test": "interactive_ui_tests", "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/", - "variant_id": "Lacros version skew testing ash 106.0.5215.0" + "variant_id": "Lacros version skew testing ash 106.0.5216.0" }, { "isolate_profile_data": true, @@ -5853,21 +5853,21 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v104.0.5112.64/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v104.0.5112.83/test_ash_chrome" ], "isolate_profile_data": true, "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" }, - "name": "lacros_chrome_browsertests Lacros version skew testing ash 104.0.5112.64", + "name": "lacros_chrome_browsertests Lacros version skew testing ash 104.0.5112.83", "swarming": { "can_use_on_swarming_builders": true, "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v104.0.5112.64", - "revision": "version:104.0.5112.64" + "location": "lacros_version_skew_tests_v104.0.5112.83", + "revision": "version:104.0.5112.83" } ], "dimension_sets": [ @@ -5879,7 +5879,7 @@ }, "test": "lacros_chrome_browsertests", "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests/", - "variant_id": "Lacros version skew testing ash 104.0.5112.64" + "variant_id": "Lacros version skew testing ash 104.0.5112.83" }, { "args": [ @@ -5915,21 +5915,21 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v106.0.5215.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v106.0.5216.0/test_ash_chrome" ], "isolate_profile_data": true, "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" }, - "name": "lacros_chrome_browsertests Lacros version skew testing ash 106.0.5215.0", + "name": "lacros_chrome_browsertests Lacros version skew testing ash 106.0.5216.0", "swarming": { "can_use_on_swarming_builders": true, "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v106.0.5215.0", - "revision": "version:106.0.5215.0" + "location": "lacros_version_skew_tests_v106.0.5216.0", + "revision": "version:106.0.5216.0" } ], "dimension_sets": [ @@ -5941,7 +5941,7 @@ }, "test": "lacros_chrome_browsertests", "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests/", - "variant_id": "Lacros version skew testing ash 106.0.5215.0" + "variant_id": "Lacros version skew testing ash 106.0.5216.0" }, { "args": [ @@ -5999,21 +5999,21 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v104.0.5112.64/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v104.0.5112.83/test_ash_chrome" ], "isolate_profile_data": true, "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" }, - "name": "lacros_chrome_browsertests_run_in_series Lacros version skew testing ash 104.0.5112.64", + "name": "lacros_chrome_browsertests_run_in_series Lacros version skew testing ash 104.0.5112.83", "swarming": { "can_use_on_swarming_builders": true, "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v104.0.5112.64", - "revision": "version:104.0.5112.64" + "location": "lacros_version_skew_tests_v104.0.5112.83", + "revision": "version:104.0.5112.83" } ], "dimension_sets": [ @@ -6025,7 +6025,7 @@ }, "test": "lacros_chrome_browsertests_run_in_series", "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests_run_in_series/", - "variant_id": "Lacros version skew testing ash 104.0.5112.64" + "variant_id": "Lacros version skew testing ash 104.0.5112.83" }, { "args": [ @@ -6061,21 +6061,21 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v106.0.5215.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v106.0.5216.0/test_ash_chrome" ], "isolate_profile_data": true, "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" }, - "name": "lacros_chrome_browsertests_run_in_series Lacros version skew testing ash 106.0.5215.0", + "name": "lacros_chrome_browsertests_run_in_series Lacros version skew testing ash 106.0.5216.0", "swarming": { "can_use_on_swarming_builders": true, "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v106.0.5215.0", - "revision": "version:106.0.5215.0" + "location": "lacros_version_skew_tests_v106.0.5216.0", + "revision": "version:106.0.5216.0" } ], "dimension_sets": [ @@ -6087,7 +6087,7 @@ }, "test": "lacros_chrome_browsertests_run_in_series", "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests_run_in_series/", - "variant_id": "Lacros version skew testing ash 106.0.5215.0" + "variant_id": "Lacros version skew testing ash 106.0.5216.0" }, { "isolate_profile_data": true,
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json index 6eb10323..0f8b1f7c 100644 --- a/testing/buildbot/chromium.fyi.json +++ b/testing/buildbot/chromium.fyi.json
@@ -88558,21 +88558,21 @@ { "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_v104.0.5112.64/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v104.0.5112.83/test_ash_chrome" ], "isolate_profile_data": true, "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" }, - "name": "interactive_ui_tests Lacros version skew testing ash 104.0.5112.64", + "name": "interactive_ui_tests Lacros version skew testing ash 104.0.5112.83", "swarming": { "can_use_on_swarming_builders": true, "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v104.0.5112.64", - "revision": "version:104.0.5112.64" + "location": "lacros_version_skew_tests_v104.0.5112.83", + "revision": "version:104.0.5112.83" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", @@ -88580,7 +88580,7 @@ }, "test": "interactive_ui_tests", "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/", - "variant_id": "Lacros version skew testing ash 104.0.5112.64" + "variant_id": "Lacros version skew testing ash 104.0.5112.83" }, { "args": [ @@ -88612,21 +88612,21 @@ { "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_v106.0.5215.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v106.0.5216.0/test_ash_chrome" ], "isolate_profile_data": true, "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" }, - "name": "interactive_ui_tests Lacros version skew testing ash 106.0.5215.0", + "name": "interactive_ui_tests Lacros version skew testing ash 106.0.5216.0", "swarming": { "can_use_on_swarming_builders": true, "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v106.0.5215.0", - "revision": "version:106.0.5215.0" + "location": "lacros_version_skew_tests_v106.0.5216.0", + "revision": "version:106.0.5216.0" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", @@ -88634,7 +88634,7 @@ }, "test": "interactive_ui_tests", "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/", - "variant_id": "Lacros version skew testing ash 106.0.5215.0" + "variant_id": "Lacros version skew testing ash 106.0.5216.0" }, { "isolate_profile_data": true, @@ -88695,28 +88695,28 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v104.0.5112.64/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v104.0.5112.83/test_ash_chrome" ], "isolate_profile_data": true, "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" }, - "name": "lacros_chrome_browsertests Lacros version skew testing ash 104.0.5112.64", + "name": "lacros_chrome_browsertests Lacros version skew testing ash 104.0.5112.83", "swarming": { "can_use_on_swarming_builders": true, "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v104.0.5112.64", - "revision": "version:104.0.5112.64" + "location": "lacros_version_skew_tests_v104.0.5112.83", + "revision": "version:104.0.5112.83" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "lacros_chrome_browsertests", "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests/", - "variant_id": "Lacros version skew testing ash 104.0.5112.64" + "variant_id": "Lacros version skew testing ash 104.0.5112.83" }, { "args": [ @@ -88747,28 +88747,28 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v106.0.5215.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v106.0.5216.0/test_ash_chrome" ], "isolate_profile_data": true, "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" }, - "name": "lacros_chrome_browsertests Lacros version skew testing ash 106.0.5215.0", + "name": "lacros_chrome_browsertests Lacros version skew testing ash 106.0.5216.0", "swarming": { "can_use_on_swarming_builders": true, "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v106.0.5215.0", - "revision": "version:106.0.5215.0" + "location": "lacros_version_skew_tests_v106.0.5216.0", + "revision": "version:106.0.5216.0" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "lacros_chrome_browsertests", "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests/", - "variant_id": "Lacros version skew testing ash 106.0.5215.0" + "variant_id": "Lacros version skew testing ash 106.0.5216.0" }, { "args": [ @@ -88816,28 +88816,28 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v104.0.5112.64/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v104.0.5112.83/test_ash_chrome" ], "isolate_profile_data": true, "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" }, - "name": "lacros_chrome_browsertests_run_in_series Lacros version skew testing ash 104.0.5112.64", + "name": "lacros_chrome_browsertests_run_in_series Lacros version skew testing ash 104.0.5112.83", "swarming": { "can_use_on_swarming_builders": true, "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v104.0.5112.64", - "revision": "version:104.0.5112.64" + "location": "lacros_version_skew_tests_v104.0.5112.83", + "revision": "version:104.0.5112.83" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "lacros_chrome_browsertests_run_in_series", "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests_run_in_series/", - "variant_id": "Lacros version skew testing ash 104.0.5112.64" + "variant_id": "Lacros version skew testing ash 104.0.5112.83" }, { "args": [ @@ -88868,28 +88868,28 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v106.0.5215.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v106.0.5216.0/test_ash_chrome" ], "isolate_profile_data": true, "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" }, - "name": "lacros_chrome_browsertests_run_in_series Lacros version skew testing ash 106.0.5215.0", + "name": "lacros_chrome_browsertests_run_in_series Lacros version skew testing ash 106.0.5216.0", "swarming": { "can_use_on_swarming_builders": true, "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v106.0.5215.0", - "revision": "version:106.0.5215.0" + "location": "lacros_version_skew_tests_v106.0.5216.0", + "revision": "version:106.0.5216.0" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "lacros_chrome_browsertests_run_in_series", "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests_run_in_series/", - "variant_id": "Lacros version skew testing ash 106.0.5215.0" + "variant_id": "Lacros version skew testing ash 106.0.5216.0" }, { "isolate_profile_data": true, @@ -90163,20 +90163,20 @@ { "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_v104.0.5112.64/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v104.0.5112.83/test_ash_chrome" ], "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" }, - "name": "interactive_ui_tests Lacros version skew testing ash 104.0.5112.64", + "name": "interactive_ui_tests Lacros version skew testing ash 104.0.5112.83", "swarming": { "can_use_on_swarming_builders": true, "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v104.0.5112.64", - "revision": "version:104.0.5112.64" + "location": "lacros_version_skew_tests_v104.0.5112.83", + "revision": "version:104.0.5112.83" } ], "dimension_sets": [ @@ -90190,7 +90190,7 @@ }, "test": "interactive_ui_tests", "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/", - "variant_id": "Lacros version skew testing ash 104.0.5112.64" + "variant_id": "Lacros version skew testing ash 104.0.5112.83" }, { "args": [ @@ -90227,20 +90227,20 @@ { "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_v106.0.5215.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v106.0.5216.0/test_ash_chrome" ], "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" }, - "name": "interactive_ui_tests Lacros version skew testing ash 106.0.5215.0", + "name": "interactive_ui_tests Lacros version skew testing ash 106.0.5216.0", "swarming": { "can_use_on_swarming_builders": true, "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v106.0.5215.0", - "revision": "version:106.0.5215.0" + "location": "lacros_version_skew_tests_v106.0.5216.0", + "revision": "version:106.0.5216.0" } ], "dimension_sets": [ @@ -90254,7 +90254,7 @@ }, "test": "interactive_ui_tests", "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/", - "variant_id": "Lacros version skew testing ash 106.0.5215.0" + "variant_id": "Lacros version skew testing ash 106.0.5216.0" }, { "merge": { @@ -90330,20 +90330,20 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v104.0.5112.64/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v104.0.5112.83/test_ash_chrome" ], "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" }, - "name": "lacros_chrome_browsertests Lacros version skew testing ash 104.0.5112.64", + "name": "lacros_chrome_browsertests Lacros version skew testing ash 104.0.5112.83", "swarming": { "can_use_on_swarming_builders": true, "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v104.0.5112.64", - "revision": "version:104.0.5112.64" + "location": "lacros_version_skew_tests_v104.0.5112.83", + "revision": "version:104.0.5112.83" } ], "dimension_sets": [ @@ -90356,7 +90356,7 @@ }, "test": "lacros_chrome_browsertests", "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests/", - "variant_id": "Lacros version skew testing ash 104.0.5112.64" + "variant_id": "Lacros version skew testing ash 104.0.5112.83" }, { "args": [ @@ -90392,20 +90392,20 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v106.0.5215.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v106.0.5216.0/test_ash_chrome" ], "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" }, - "name": "lacros_chrome_browsertests Lacros version skew testing ash 106.0.5215.0", + "name": "lacros_chrome_browsertests Lacros version skew testing ash 106.0.5216.0", "swarming": { "can_use_on_swarming_builders": true, "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v106.0.5215.0", - "revision": "version:106.0.5215.0" + "location": "lacros_version_skew_tests_v106.0.5216.0", + "revision": "version:106.0.5216.0" } ], "dimension_sets": [ @@ -90418,7 +90418,7 @@ }, "test": "lacros_chrome_browsertests", "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests/", - "variant_id": "Lacros version skew testing ash 106.0.5215.0" + "variant_id": "Lacros version skew testing ash 106.0.5216.0" }, { "args": [ @@ -90476,20 +90476,20 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v104.0.5112.64/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v104.0.5112.83/test_ash_chrome" ], "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" }, - "name": "lacros_chrome_browsertests_run_in_series Lacros version skew testing ash 104.0.5112.64", + "name": "lacros_chrome_browsertests_run_in_series Lacros version skew testing ash 104.0.5112.83", "swarming": { "can_use_on_swarming_builders": true, "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v104.0.5112.64", - "revision": "version:104.0.5112.64" + "location": "lacros_version_skew_tests_v104.0.5112.83", + "revision": "version:104.0.5112.83" } ], "dimension_sets": [ @@ -90502,7 +90502,7 @@ }, "test": "lacros_chrome_browsertests_run_in_series", "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests_run_in_series/", - "variant_id": "Lacros version skew testing ash 104.0.5112.64" + "variant_id": "Lacros version skew testing ash 104.0.5112.83" }, { "args": [ @@ -90538,20 +90538,20 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v106.0.5215.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v106.0.5216.0/test_ash_chrome" ], "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" }, - "name": "lacros_chrome_browsertests_run_in_series Lacros version skew testing ash 106.0.5215.0", + "name": "lacros_chrome_browsertests_run_in_series Lacros version skew testing ash 106.0.5216.0", "swarming": { "can_use_on_swarming_builders": true, "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v106.0.5215.0", - "revision": "version:106.0.5215.0" + "location": "lacros_version_skew_tests_v106.0.5216.0", + "revision": "version:106.0.5216.0" } ], "dimension_sets": [ @@ -90564,7 +90564,7 @@ }, "test": "lacros_chrome_browsertests_run_in_series", "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests_run_in_series/", - "variant_id": "Lacros version skew testing ash 106.0.5215.0" + "variant_id": "Lacros version skew testing ash 106.0.5216.0" }, { "merge": { @@ -91996,20 +91996,20 @@ { "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_v104.0.5112.64/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v104.0.5112.83/test_ash_chrome" ], "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" }, - "name": "interactive_ui_tests Lacros version skew testing ash 104.0.5112.64", + "name": "interactive_ui_tests Lacros version skew testing ash 104.0.5112.83", "swarming": { "can_use_on_swarming_builders": true, "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v104.0.5112.64", - "revision": "version:104.0.5112.64" + "location": "lacros_version_skew_tests_v104.0.5112.83", + "revision": "version:104.0.5112.83" } ], "dimension_sets": [ @@ -92023,7 +92023,7 @@ }, "test": "interactive_ui_tests", "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/", - "variant_id": "Lacros version skew testing ash 104.0.5112.64" + "variant_id": "Lacros version skew testing ash 104.0.5112.83" }, { "args": [ @@ -92060,20 +92060,20 @@ { "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_v106.0.5215.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v106.0.5216.0/test_ash_chrome" ], "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" }, - "name": "interactive_ui_tests Lacros version skew testing ash 106.0.5215.0", + "name": "interactive_ui_tests Lacros version skew testing ash 106.0.5216.0", "swarming": { "can_use_on_swarming_builders": true, "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v106.0.5215.0", - "revision": "version:106.0.5215.0" + "location": "lacros_version_skew_tests_v106.0.5216.0", + "revision": "version:106.0.5216.0" } ], "dimension_sets": [ @@ -92087,7 +92087,7 @@ }, "test": "interactive_ui_tests", "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/", - "variant_id": "Lacros version skew testing ash 106.0.5215.0" + "variant_id": "Lacros version skew testing ash 106.0.5216.0" }, { "merge": { @@ -92163,20 +92163,20 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v104.0.5112.64/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v104.0.5112.83/test_ash_chrome" ], "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" }, - "name": "lacros_chrome_browsertests Lacros version skew testing ash 104.0.5112.64", + "name": "lacros_chrome_browsertests Lacros version skew testing ash 104.0.5112.83", "swarming": { "can_use_on_swarming_builders": true, "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v104.0.5112.64", - "revision": "version:104.0.5112.64" + "location": "lacros_version_skew_tests_v104.0.5112.83", + "revision": "version:104.0.5112.83" } ], "dimension_sets": [ @@ -92189,7 +92189,7 @@ }, "test": "lacros_chrome_browsertests", "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests/", - "variant_id": "Lacros version skew testing ash 104.0.5112.64" + "variant_id": "Lacros version skew testing ash 104.0.5112.83" }, { "args": [ @@ -92225,20 +92225,20 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v106.0.5215.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v106.0.5216.0/test_ash_chrome" ], "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" }, - "name": "lacros_chrome_browsertests Lacros version skew testing ash 106.0.5215.0", + "name": "lacros_chrome_browsertests Lacros version skew testing ash 106.0.5216.0", "swarming": { "can_use_on_swarming_builders": true, "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v106.0.5215.0", - "revision": "version:106.0.5215.0" + "location": "lacros_version_skew_tests_v106.0.5216.0", + "revision": "version:106.0.5216.0" } ], "dimension_sets": [ @@ -92251,7 +92251,7 @@ }, "test": "lacros_chrome_browsertests", "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests/", - "variant_id": "Lacros version skew testing ash 106.0.5215.0" + "variant_id": "Lacros version skew testing ash 106.0.5216.0" }, { "args": [ @@ -92309,20 +92309,20 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v104.0.5112.64/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v104.0.5112.83/test_ash_chrome" ], "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" }, - "name": "lacros_chrome_browsertests_run_in_series Lacros version skew testing ash 104.0.5112.64", + "name": "lacros_chrome_browsertests_run_in_series Lacros version skew testing ash 104.0.5112.83", "swarming": { "can_use_on_swarming_builders": true, "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v104.0.5112.64", - "revision": "version:104.0.5112.64" + "location": "lacros_version_skew_tests_v104.0.5112.83", + "revision": "version:104.0.5112.83" } ], "dimension_sets": [ @@ -92335,7 +92335,7 @@ }, "test": "lacros_chrome_browsertests_run_in_series", "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests_run_in_series/", - "variant_id": "Lacros version skew testing ash 104.0.5112.64" + "variant_id": "Lacros version skew testing ash 104.0.5112.83" }, { "args": [ @@ -92371,20 +92371,20 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v106.0.5215.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v106.0.5216.0/test_ash_chrome" ], "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" }, - "name": "lacros_chrome_browsertests_run_in_series Lacros version skew testing ash 106.0.5215.0", + "name": "lacros_chrome_browsertests_run_in_series Lacros version skew testing ash 106.0.5216.0", "swarming": { "can_use_on_swarming_builders": true, "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v106.0.5215.0", - "revision": "version:106.0.5215.0" + "location": "lacros_version_skew_tests_v106.0.5216.0", + "revision": "version:106.0.5216.0" } ], "dimension_sets": [ @@ -92397,7 +92397,7 @@ }, "test": "lacros_chrome_browsertests_run_in_series", "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests_run_in_series/", - "variant_id": "Lacros version skew testing ash 106.0.5215.0" + "variant_id": "Lacros version skew testing ash 106.0.5216.0" }, { "merge": { @@ -93070,20 +93070,20 @@ { "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_v104.0.5112.64/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v104.0.5112.83/test_ash_chrome" ], "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" }, - "name": "interactive_ui_tests Lacros version skew testing ash 104.0.5112.64", + "name": "interactive_ui_tests Lacros version skew testing ash 104.0.5112.83", "swarming": { "can_use_on_swarming_builders": true, "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v104.0.5112.64", - "revision": "version:104.0.5112.64" + "location": "lacros_version_skew_tests_v104.0.5112.83", + "revision": "version:104.0.5112.83" } ], "dimension_sets": [ @@ -93096,7 +93096,7 @@ }, "test": "interactive_ui_tests", "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/", - "variant_id": "Lacros version skew testing ash 104.0.5112.64" + "variant_id": "Lacros version skew testing ash 104.0.5112.83" }, { "args": [ @@ -93132,20 +93132,20 @@ { "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_v106.0.5215.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v106.0.5216.0/test_ash_chrome" ], "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" }, - "name": "interactive_ui_tests Lacros version skew testing ash 106.0.5215.0", + "name": "interactive_ui_tests Lacros version skew testing ash 106.0.5216.0", "swarming": { "can_use_on_swarming_builders": true, "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v106.0.5215.0", - "revision": "version:106.0.5215.0" + "location": "lacros_version_skew_tests_v106.0.5216.0", + "revision": "version:106.0.5216.0" } ], "dimension_sets": [ @@ -93158,7 +93158,7 @@ }, "test": "interactive_ui_tests", "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/", - "variant_id": "Lacros version skew testing ash 106.0.5215.0" + "variant_id": "Lacros version skew testing ash 106.0.5216.0" } ] },
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json index d0f4382..d469f4b 100644 --- a/testing/buildbot/chromium.memory.json +++ b/testing/buildbot/chromium.memory.json
@@ -20807,21 +20807,21 @@ { "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_v104.0.5112.64/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v104.0.5112.83/test_ash_chrome" ], "isolate_profile_data": true, "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" }, - "name": "interactive_ui_tests Lacros version skew testing ash 104.0.5112.64", + "name": "interactive_ui_tests Lacros version skew testing ash 104.0.5112.83", "swarming": { "can_use_on_swarming_builders": true, "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v104.0.5112.64", - "revision": "version:104.0.5112.64" + "location": "lacros_version_skew_tests_v104.0.5112.83", + "revision": "version:104.0.5112.83" } ], "dimension_sets": [ @@ -20834,7 +20834,7 @@ }, "test": "interactive_ui_tests", "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/", - "variant_id": "Lacros version skew testing ash 104.0.5112.64" + "variant_id": "Lacros version skew testing ash 104.0.5112.83" }, { "args": [ @@ -20871,21 +20871,21 @@ { "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_v106.0.5215.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v106.0.5216.0/test_ash_chrome" ], "isolate_profile_data": true, "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" }, - "name": "interactive_ui_tests Lacros version skew testing ash 106.0.5215.0", + "name": "interactive_ui_tests Lacros version skew testing ash 106.0.5216.0", "swarming": { "can_use_on_swarming_builders": true, "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v106.0.5215.0", - "revision": "version:106.0.5215.0" + "location": "lacros_version_skew_tests_v106.0.5216.0", + "revision": "version:106.0.5216.0" } ], "dimension_sets": [ @@ -20898,7 +20898,7 @@ }, "test": "interactive_ui_tests", "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/", - "variant_id": "Lacros version skew testing ash 106.0.5215.0" + "variant_id": "Lacros version skew testing ash 106.0.5216.0" }, { "isolate_profile_data": true, @@ -20974,21 +20974,21 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v104.0.5112.64/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v104.0.5112.83/test_ash_chrome" ], "isolate_profile_data": true, "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" }, - "name": "lacros_chrome_browsertests Lacros version skew testing ash 104.0.5112.64", + "name": "lacros_chrome_browsertests Lacros version skew testing ash 104.0.5112.83", "swarming": { "can_use_on_swarming_builders": true, "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v104.0.5112.64", - "revision": "version:104.0.5112.64" + "location": "lacros_version_skew_tests_v104.0.5112.83", + "revision": "version:104.0.5112.83" } ], "dimension_sets": [ @@ -21000,7 +21000,7 @@ }, "test": "lacros_chrome_browsertests", "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests/", - "variant_id": "Lacros version skew testing ash 104.0.5112.64" + "variant_id": "Lacros version skew testing ash 104.0.5112.83" }, { "args": [ @@ -21036,21 +21036,21 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v106.0.5215.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v106.0.5216.0/test_ash_chrome" ], "isolate_profile_data": true, "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" }, - "name": "lacros_chrome_browsertests Lacros version skew testing ash 106.0.5215.0", + "name": "lacros_chrome_browsertests Lacros version skew testing ash 106.0.5216.0", "swarming": { "can_use_on_swarming_builders": true, "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v106.0.5215.0", - "revision": "version:106.0.5215.0" + "location": "lacros_version_skew_tests_v106.0.5216.0", + "revision": "version:106.0.5216.0" } ], "dimension_sets": [ @@ -21062,7 +21062,7 @@ }, "test": "lacros_chrome_browsertests", "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests/", - "variant_id": "Lacros version skew testing ash 106.0.5215.0" + "variant_id": "Lacros version skew testing ash 106.0.5216.0" }, { "args": [ @@ -21120,21 +21120,21 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v104.0.5112.64/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v104.0.5112.83/test_ash_chrome" ], "isolate_profile_data": true, "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" }, - "name": "lacros_chrome_browsertests_run_in_series Lacros version skew testing ash 104.0.5112.64", + "name": "lacros_chrome_browsertests_run_in_series Lacros version skew testing ash 104.0.5112.83", "swarming": { "can_use_on_swarming_builders": true, "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v104.0.5112.64", - "revision": "version:104.0.5112.64" + "location": "lacros_version_skew_tests_v104.0.5112.83", + "revision": "version:104.0.5112.83" } ], "dimension_sets": [ @@ -21146,7 +21146,7 @@ }, "test": "lacros_chrome_browsertests_run_in_series", "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests_run_in_series/", - "variant_id": "Lacros version skew testing ash 104.0.5112.64" + "variant_id": "Lacros version skew testing ash 104.0.5112.83" }, { "args": [ @@ -21182,21 +21182,21 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v106.0.5215.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v106.0.5216.0/test_ash_chrome" ], "isolate_profile_data": true, "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" }, - "name": "lacros_chrome_browsertests_run_in_series Lacros version skew testing ash 106.0.5215.0", + "name": "lacros_chrome_browsertests_run_in_series Lacros version skew testing ash 106.0.5216.0", "swarming": { "can_use_on_swarming_builders": true, "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v106.0.5215.0", - "revision": "version:106.0.5215.0" + "location": "lacros_version_skew_tests_v106.0.5216.0", + "revision": "version:106.0.5216.0" } ], "dimension_sets": [ @@ -21208,7 +21208,7 @@ }, "test": "lacros_chrome_browsertests_run_in_series", "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests_run_in_series/", - "variant_id": "Lacros version skew testing ash 106.0.5215.0" + "variant_id": "Lacros version skew testing ash 106.0.5216.0" }, { "isolate_profile_data": true,
diff --git a/testing/buildbot/variants.pyl b/testing/buildbot/variants.pyl index 1affd53..a0f3c57 100644 --- a/testing/buildbot/variants.pyl +++ b/testing/buildbot/variants.pyl
@@ -22,15 +22,15 @@ }, 'LACROS_VERSION_SKEW_CANARY': { 'args': [ - '--ash-chrome-path-override=../../lacros_version_skew_tests_v106.0.5215.0/test_ash_chrome', + '--ash-chrome-path-override=../../lacros_version_skew_tests_v106.0.5216.0/test_ash_chrome', ], - 'identifier': 'Lacros version skew testing ash 106.0.5215.0', + 'identifier': 'Lacros version skew testing ash 106.0.5216.0', 'swarming': { 'cipd_packages': [ { 'cipd_package': 'chromium/testing/linux-ash-chromium/x86_64/ash.zip', - 'location': 'lacros_version_skew_tests_v106.0.5215.0', - 'revision': 'version:106.0.5215.0', + 'location': 'lacros_version_skew_tests_v106.0.5216.0', + 'revision': 'version:106.0.5216.0', }, ], }, @@ -52,15 +52,15 @@ }, 'LACROS_VERSION_SKEW_BETA': { 'args': [ - '--ash-chrome-path-override=../../lacros_version_skew_tests_v104.0.5112.64/test_ash_chrome', + '--ash-chrome-path-override=../../lacros_version_skew_tests_v104.0.5112.83/test_ash_chrome', ], - 'identifier': 'Lacros version skew testing ash 104.0.5112.64', + 'identifier': 'Lacros version skew testing ash 104.0.5112.83', 'swarming': { 'cipd_packages': [ { 'cipd_package': 'chromium/testing/linux-ash-chromium/x86_64/ash.zip', - 'location': 'lacros_version_skew_tests_v104.0.5112.64', - 'revision': 'version:104.0.5112.64', + 'location': 'lacros_version_skew_tests_v104.0.5112.83', + 'revision': 'version:104.0.5112.83', }, ], },
diff --git a/third_party/apache-portable-runtime/BUILD.gn b/third_party/apache-portable-runtime/BUILD.gn index 0918a5d..cc253d8 100644 --- a/third_party/apache-portable-runtime/BUILD.gn +++ b/third_party/apache-portable-runtime/BUILD.gn
@@ -8,9 +8,6 @@ config("apr_warnings") { if (is_clang) { cflags = [ - # TODO(https://crbug.com/1347085): Investigate, fix. - "-Wno-int-conversion", - # TODO(https://crbug.com/1347226): Investigate, fix. "-Wno-deprecated-declarations", ] @@ -127,4 +124,9 @@ # Must be after no_chromium_code so -Wno flags show up after -Wall. ":apr_warnings", ] + + # See https://crbug.com/1347085 --- older Android's NDK has different strerror_p. + if (is_android && default_min_sdk_version < 23) { + defines = [ "STRERROR_R_RC_INT" ] + } }
diff --git a/third_party/blink/perf_tests/paint/custom-highlights-heavy.html b/third_party/blink/perf_tests/paint/custom-highlights-heavy.html new file mode 100644 index 0000000..a27c4ad --- /dev/null +++ b/third_party/blink/perf_tests/paint/custom-highlights-heavy.html
@@ -0,0 +1,37 @@ +<!DOCTYPE html> +<title>Custom Highlights Painting</title> +<style> +::highlight(example) { + color: blue; + background: yellow; +} +.lime ::highlight(example) { + background: lime; +} +</style> +<script src="../resources/runner.js"></script> +<script src="resources/paint.js"></script> +<main></main> +<pre id="log"></pre> +<script> + const LOREM_IPSUM = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. ".repeat(42); + + const highlight = new Highlight; + const main = document.querySelector("main"); + main.textContent = LOREM_IPSUM; + + for (let i = 0; i < LOREM_IPSUM.length; i += 2) { + const range = new Range; + range.setStart(main.firstChild, i); + range.setEnd(main.firstChild, i + 1); + highlight.add(range); + } + + CSS.highlights.set("example", highlight); + + measurePaint({ + description: "Measure time for painting Custom Highlights (emulates searching 'a' in a large text)", + run: () => document.body.classList.toggle("lime"), + }); + +</script>
diff --git a/third_party/blink/public/mojom/mediastream/media_stream.mojom b/third_party/blink/public/mojom/mediastream/media_stream.mojom index f22f72f8..5cf1603 100644 --- a/third_party/blink/public/mojom/mediastream/media_stream.mojom +++ b/third_party/blink/public/mojom/mediastream/media_stream.mojom
@@ -201,6 +201,10 @@ CancelRequest(int32 request_id); // Closes a stream device that has been opened by GenerateStream. + // If the corresponding MediaStreamDevice (identified by |device_id| and + // |session_id|) has ongoing transfers, in case of transferred + // MediaStreamTracks, the MediaStreamDevice will not stop immediately and + // will be kept alive until all the transfers are complete. StopStreamDevice(string device_id, mojo_base.mojom.UnguessableToken? session_id); // Opens a device identified by |device_id|. @@ -252,9 +256,34 @@ // of the MediaStreamDevice created by the original context. // |request_id| is used by the renderer to identify the stream generation // request. - // Response is null if and only if result != OK. - GetOpenDevice(int32 request_id, mojo_base.mojom.UnguessableToken session_id) - => (MediaStreamRequestResult result, GetOpenDeviceResponse? response); + // |session_id| is used to uniquely identify a session/MediaStreamDevice. + // |transfer_id| is used to identify a MediaStreamTrack transfer request. + // This is generated in the original context and passed to the receiving + // context to identify this transfer in the browser process. + // |response| is null if and only if result != OK. + GetOpenDevice(int32 request_id, mojo_base.mojom.UnguessableToken session_id, + mojo_base.mojom.UnguessableToken transfer_id) + => (MediaStreamRequestResult result, GetOpenDeviceResponse? response); + + // Keeps a MediaStreamDevice alive even if it has been requested to stop. + // + // This method is called by the original renderer while transferring + // MediaStreamTrack between contexts to ensure the MediaStreamDevice does not + // stop before the transfer finishes. Once the transfer is complete, we check + // for any other ongoing transfers of this MediaStreamDevice. If there are + // none and the MediaStreamDevice is marked to be stopped, stop the + // MediaStreamDevice. + // |session_id| is used to uniquely identify a session/MediaStreamDevice. + // This is the same MediaStreamDevice that is to be cloned in GetOpenDevice + // to be connected to the transferred track. + // |transfer_id| is used to identify a MediaStreamTrack transfer request. + // This is generated in the original context, which calls this function, and + // is passed to the receiving context to identify this transfer in the + // browser process. + // |device_found| is true if the MediaStreamDevice was found. + KeepDeviceAliveForTransfer(mojo_base.mojom.UnguessableToken session_id, + mojo_base.mojom.UnguessableToken transfer_id) + => (bool device_found); }; // Browser-side interface that is used by the renderer process to notify the
diff --git a/third_party/blink/renderer/core/css/css_container_values.cc b/third_party/blink/renderer/core/css/css_container_values.cc index 1146a16..b87b6b4 100644 --- a/third_party/blink/renderer/core/css/css_container_values.cc +++ b/third_party/blink/renderer/core/css/css_container_values.cc
@@ -46,6 +46,10 @@ return font_sizes_.Ch(); } +float CSSContainerValues::IcFontSize() const { + return font_sizes_.Ic(); +} + double CSSContainerValues::ContainerWidth() const { return container_sizes_.Width().value_or(SmallViewportWidth()); }
diff --git a/third_party/blink/renderer/core/css/css_container_values.h b/third_party/blink/renderer/core/css/css_container_values.h index db265ea..35026b8 100644 --- a/third_party/blink/renderer/core/css/css_container_values.h +++ b/third_party/blink/renderer/core/css/css_container_values.h
@@ -34,6 +34,7 @@ float RemFontSize() const override; float ExFontSize() const override; float ChFontSize() const override; + float IcFontSize() const override; // Note that ContainerWidth/ContainerHeight are used to resolve // container *units*. See `container_sizes_`. double ContainerWidth() const override;
diff --git a/third_party/blink/renderer/core/css/css_length_resolver.cc b/third_party/blink/renderer/core/css/css_length_resolver.cc index adab5b3..9c2da5c 100644 --- a/third_party/blink/renderer/core/css/css_length_resolver.cc +++ b/third_party/blink/renderer/core/css/css_length_resolver.cc
@@ -273,6 +273,9 @@ case CSSPrimitiveValue::UnitType::kChs: return value * ChFontSize(); + case CSSPrimitiveValue::UnitType::kIcs: + return value * IcFontSize(); + default: NOTREACHED(); return 0;
diff --git a/third_party/blink/renderer/core/css/css_length_resolver.h b/third_party/blink/renderer/core/css/css_length_resolver.h index 7c18525..a24dd87a 100644 --- a/third_party/blink/renderer/core/css/css_length_resolver.h +++ b/third_party/blink/renderer/core/css/css_length_resolver.h
@@ -24,6 +24,7 @@ virtual float RemFontSize() const = 0; virtual float ExFontSize() const = 0; virtual float ChFontSize() const = 0; + virtual float IcFontSize() const = 0; // Other sizes must not be pre-zoomed. virtual double ViewportWidth() const = 0;
diff --git a/third_party/blink/renderer/core/css/css_math_expression_node.cc b/third_party/blink/renderer/core/css/css_math_expression_node.cc index 7f504dcc..ed7ade4 100644 --- a/third_party/blink/renderer/core/css/css_math_expression_node.cc +++ b/third_party/blink/renderer/core/css/css_math_expression_node.cc
@@ -101,6 +101,9 @@ return RuntimeEnabledFeatures::CSSContainerRelativeUnitsEnabled() ? kCalcLength : kCalcOther; + case CSSPrimitiveValue::UnitType::kIcs: + return RuntimeEnabledFeatures::CSSIcUnitEnabled() ? kCalcLength + : kCalcOther; case CSSPrimitiveValue::UnitType::kDegrees: case CSSPrimitiveValue::UnitType::kGradians: case CSSPrimitiveValue::UnitType::kRadians: @@ -124,6 +127,7 @@ case CSSPrimitiveValue::UnitType::kEms: case CSSPrimitiveValue::UnitType::kExs: case CSSPrimitiveValue::UnitType::kChs: + case CSSPrimitiveValue::UnitType::kIcs: case CSSPrimitiveValue::UnitType::kRems: case CSSPrimitiveValue::UnitType::kPixels: case CSSPrimitiveValue::UnitType::kCentimeters:
diff --git a/third_party/blink/renderer/core/css/css_numeric_literal_value.cc b/third_party/blink/renderer/core/css/css_numeric_literal_value.cc index 869b36c..f0954ba8 100644 --- a/third_party/blink/renderer/core/css/css_numeric_literal_value.cc +++ b/third_party/blink/renderer/core/css/css_numeric_literal_value.cc
@@ -191,6 +191,7 @@ case UnitType::kExs: case UnitType::kRems: case UnitType::kChs: + case UnitType::kIcs: case UnitType::kPixels: case UnitType::kCentimeters: case UnitType::kDotsPerPixel:
diff --git a/third_party/blink/renderer/core/css/css_numeric_literal_value.h b/third_party/blink/renderer/core/css/css_numeric_literal_value.h index c9c52a1f..38bf362 100644 --- a/third_party/blink/renderer/core/css/css_numeric_literal_value.h +++ b/third_party/blink/renderer/core/css/css_numeric_literal_value.h
@@ -29,7 +29,7 @@ bool IsFontRelativeLength() const { return GetType() == UnitType::kQuirkyEms || GetType() == UnitType::kEms || GetType() == UnitType::kExs || GetType() == UnitType::kRems || - GetType() == UnitType::kChs; + GetType() == UnitType::kChs || GetType() == UnitType::kIcs; } bool IsQuirkyEms() const { return GetType() == UnitType::kQuirkyEms; } bool IsViewportPercentageLength() const {
diff --git a/third_party/blink/renderer/core/css/css_primitive_value.cc b/third_party/blink/renderer/core/css/css_primitive_value.cc index b085b11..5ee5336 100644 --- a/third_party/blink/renderer/core/css/css_primitive_value.cc +++ b/third_party/blink/renderer/core/css/css_primitive_value.cc
@@ -488,6 +488,9 @@ case CSSPrimitiveValue::UnitType::kChs: length_type = kUnitTypeZeroCharacterWidth; return true; + case CSSPrimitiveValue::UnitType::kIcs: + length_type = kUnitTypeIdeographicFullWidth; + return true; case CSSPrimitiveValue::UnitType::kPercentage: length_type = kUnitTypePercentage; return true; @@ -599,6 +602,8 @@ return CSSPrimitiveValue::UnitType::kRems; case kUnitTypeZeroCharacterWidth: return CSSPrimitiveValue::UnitType::kChs; + case kUnitTypeIdeographicFullWidth: + return CSSPrimitiveValue::UnitType::kIcs; case kUnitTypePercentage: return CSSPrimitiveValue::UnitType::kPercentage; case kUnitTypeViewportWidth: @@ -685,6 +690,8 @@ return "rem"; case UnitType::kChs: return "ch"; + case UnitType::kIcs: + return "ic"; case UnitType::kPixels: return "px"; case UnitType::kCentimeters:
diff --git a/third_party/blink/renderer/core/css/css_primitive_value.h b/third_party/blink/renderer/core/css/css_primitive_value.h index 67210a2..189f20b 100644 --- a/third_party/blink/renderer/core/css/css_primitive_value.h +++ b/third_party/blink/renderer/core/css/css_primitive_value.h
@@ -121,6 +121,7 @@ kRems, kChs, + kIcs, kUserUnits, // The SVG term for unitless lengths // Angle units kDegrees, @@ -188,6 +189,7 @@ kUnitTypeContainerBlockSize, kUnitTypeContainerMin, kUnitTypeContainerMax, + kUnitTypeIdeographicFullWidth, // This value must come after the last length unit type to enable iteration // over the length unit types. @@ -277,7 +279,8 @@ static inline bool IsRelativeUnit(UnitType type) { return type == UnitType::kPercentage || type == UnitType::kEms || type == UnitType::kExs || type == UnitType::kRems || - type == UnitType::kChs || IsViewportPercentageLength(type) || + type == UnitType::kChs || type == UnitType::kIcs || + IsViewportPercentageLength(type) || IsContainerPercentageLength(type); } bool IsLength() const;
diff --git a/third_party/blink/renderer/core/css/css_primitive_value_units.json5 b/third_party/blink/renderer/core/css/css_primitive_value_units.json5 index fa3c8641f..994a64b 100644 --- a/third_party/blink/renderer/core/css/css_primitive_value_units.json5 +++ b/third_party/blink/renderer/core/css/css_primitive_value_units.json5
@@ -223,6 +223,10 @@ unit_type: "kChs", }, { + name: "ic", + unit_type: "kIcs", + }, + { name: "__qem", unit_type: "kQuirkyEms", },
diff --git a/third_party/blink/renderer/core/css/css_to_length_conversion_data.cc b/third_party/blink/renderer/core/css/css_to_length_conversion_data.cc index 2fc134e..77e23c8 100644 --- a/third_party/blink/renderer/core/css/css_to_length_conversion_data.cc +++ b/third_party/blink/renderer/core/css/css_to_length_conversion_data.cc
@@ -107,6 +107,20 @@ : 0; } +float CSSToLengthConversionData::FontSizes::Ic() const { + DCHECK(font_); + const SimpleFontData* font_data = font_->PrimaryFont(); + DCHECK(font_data); + absl::optional<float> full_width = + font_data->GetFontMetrics().IdeographicFullWidth(); + if (!full_width.has_value()) + return Em(); + // Font-metrics has zoom applied, which means we need to unzoom to get the + // value in CSS pixels. + float unzoom = (zoom_adjust_.has_value() ? zoom_ : 1.0f); + return full_width.value() / unzoom * zoom_adjust_.value_or(1.0f); +} + CSSToLengthConversionData::FontSizes CSSToLengthConversionData::FontSizes::CopyWithAdjustedZoom( float new_zoom) const { @@ -233,6 +247,12 @@ return font_sizes_.Ch(); } +float CSSToLengthConversionData::IcFontSize() const { + if (style_) + const_cast<ComputedStyle*>(style_)->SetHasGlyphRelativeUnits(); + return font_sizes_.Ic(); +} + double CSSToLengthConversionData::ViewportWidth() const { if (style_) const_cast<ComputedStyle*>(style_)->SetHasStaticViewportUnits();
diff --git a/third_party/blink/renderer/core/css/css_to_length_conversion_data.h b/third_party/blink/renderer/core/css/css_to_length_conversion_data.h index 6e8e5fb..34398021 100644 --- a/third_party/blink/renderer/core/css/css_to_length_conversion_data.h +++ b/third_party/blink/renderer/core/css/css_to_length_conversion_data.h
@@ -65,6 +65,7 @@ float Rem() const { return rem_ * zoom_adjust_.value_or(zoom_); } float Ex() const; float Ch() const; + float Ic() const; private: friend class CSSToLengthConversionData; @@ -177,6 +178,7 @@ float RemFontSize() const override; float ExFontSize() const override; float ChFontSize() const override; + float IcFontSize() const override; double ViewportWidth() const override; double ViewportHeight() const override; double SmallViewportWidth() const override;
diff --git a/third_party/blink/renderer/core/css/css_variable_data.cc b/third_party/blink/renderer/core/css/css_variable_data.cc index a2294cc7..a28a3980 100644 --- a/third_party/blink/renderer/core/css/css_variable_data.cc +++ b/third_party/blink/renderer/core/css/css_variable_data.cc
@@ -39,6 +39,7 @@ case CSSPrimitiveValue::UnitType::kEms: case CSSPrimitiveValue::UnitType::kChs: case CSSPrimitiveValue::UnitType::kExs: + case CSSPrimitiveValue::UnitType::kIcs: return true; default: return false;
diff --git a/third_party/blink/renderer/core/css/cssom/css_numeric_value_type.cc b/third_party/blink/renderer/core/css/cssom/css_numeric_value_type.cc index 8576b649..28b2a39 100644 --- a/third_party/blink/renderer/core/css/cssom/css_numeric_value_type.cc +++ b/third_party/blink/renderer/core/css/cssom/css_numeric_value_type.cc
@@ -59,6 +59,7 @@ case UnitType::kContainerMax: case UnitType::kRems: case UnitType::kChs: + case UnitType::kIcs: return BaseType::kLength; case UnitType::kMilliseconds: case UnitType::kSeconds:
diff --git a/third_party/blink/renderer/core/css/cssom/css_unit_values.h b/third_party/blink/renderer/core/css/cssom/css_unit_values.h index 8bb4297..55245ac 100644 --- a/third_party/blink/renderer/core/css/cssom/css_unit_values.h +++ b/third_party/blink/renderer/core/css/cssom/css_unit_values.h
@@ -35,6 +35,10 @@ return CSSUnitValue::Create(value, CSSPrimitiveValue::UnitType::kChs); } + static CSSUnitValue* ic(double value) { + return CSSUnitValue::Create(value, CSSPrimitiveValue::UnitType::kIcs); + } + static CSSUnitValue* rem(double value) { return CSSUnitValue::Create(value, CSSPrimitiveValue::UnitType::kRems); }
diff --git a/third_party/blink/renderer/core/css/media_query_exp.cc b/third_party/blink/renderer/core/css/media_query_exp.cc index 92196902..3d4ca58ce 100644 --- a/third_party/blink/renderer/core/css/media_query_exp.cc +++ b/third_party/blink/renderer/core/css/media_query_exp.cc
@@ -538,7 +538,9 @@ if (length_type_flags.test(CSSPrimitiveValue::kUnitTypeFontSize) || length_type_flags.test(CSSPrimitiveValue::kUnitTypeFontXSize) || - length_type_flags.test(CSSPrimitiveValue::kUnitTypeZeroCharacterWidth)) { + length_type_flags.test(CSSPrimitiveValue::kUnitTypeZeroCharacterWidth) || + length_type_flags.test( + CSSPrimitiveValue::kUnitTypeIdeographicFullWidth)) { unit_flags |= UnitFlags::kFontRelative; }
diff --git a/third_party/blink/renderer/core/css/media_values.cc b/third_party/blink/renderer/core/css/media_values.cc index 362dbb8..b838a936 100644 --- a/third_party/blink/renderer/core/css/media_values.cc +++ b/third_party/blink/renderer/core/css/media_values.cc
@@ -237,6 +237,16 @@ return CSSToLengthConversionData::FontSizes(style, style).Unzoomed().Ch(); } +float MediaValues::CalculateIcSize(LocalFrame* frame) { + DCHECK(frame); + DCHECK(frame->GetDocument()); + const ComputedStyle* style = frame->GetDocument()->GetComputedStyle(); + DCHECK(style); + // CSSToLengthConversionData::FontSizes returns pre-zoomed font sizes. Need to + // scale back to CSS pixels. + return CSSToLengthConversionData::FontSizes(style, style).Unzoomed().Ic(); +} + const String MediaValues::CalculateMediaType(LocalFrame* frame) { DCHECK(frame); if (!frame->View())
diff --git a/third_party/blink/renderer/core/css/media_values.h b/third_party/blink/renderer/core/css/media_values.h index 1eeacfab..a1e781e 100644 --- a/third_party/blink/renderer/core/css/media_values.h +++ b/third_party/blink/renderer/core/css/media_values.h
@@ -103,6 +103,7 @@ static float CalculateEmSize(LocalFrame*); static float CalculateExSize(LocalFrame*); static float CalculateChSize(LocalFrame*); + static float CalculateIcSize(LocalFrame*); static int CalculateDeviceWidth(LocalFrame*); static int CalculateDeviceHeight(LocalFrame*); static bool CalculateStrictMode(LocalFrame*);
diff --git a/third_party/blink/renderer/core/css/media_values_cached.cc b/third_party/blink/renderer/core/css/media_values_cached.cc index 089d627..630c325f 100644 --- a/third_party/blink/renderer/core/css/media_values_cached.cc +++ b/third_party/blink/renderer/core/css/media_values_cached.cc
@@ -59,6 +59,7 @@ // virtual/highdpi-threaded/external/wpt/css/css-paint-api/hidpi/device-pixel-ratio.https.html ex_size = em_size / 2.0; ch_size = em_size / 2.0; + ic_size = em_size; three_d_enabled = MediaValues::CalculateThreeDEnabled(frame); immersive_mode = MediaValues::CalculateInImmersiveMode(frame); strict_mode = MediaValues::CalculateStrictMode(frame); @@ -107,6 +108,10 @@ return data_.ch_size; } +float MediaValuesCached::IcFontSize() const { + return data_.ic_size; +} + double MediaValuesCached::ViewportWidth() const { return data_.viewport_width; }
diff --git a/third_party/blink/renderer/core/css/media_values_cached.h b/third_party/blink/renderer/core/css/media_values_cached.h index 8f38620d..8725509 100644 --- a/third_party/blink/renderer/core/css/media_values_cached.h +++ b/third_party/blink/renderer/core/css/media_values_cached.h
@@ -52,6 +52,7 @@ float em_size = 16.f; float ex_size = 8.f; float ch_size = 8.f; + float ic_size = 16.f; bool three_d_enabled = false; bool immersive_mode = false; bool strict_mode = true; @@ -92,6 +93,7 @@ data.em_size = em_size; data.ex_size = ex_size; data.ch_size = ch_size; + data.ch_size = ic_size; data.three_d_enabled = three_d_enabled; data.immersive_mode = immersive_mode; data.strict_mode = strict_mode; @@ -153,6 +155,7 @@ float RemFontSize() const override; float ExFontSize() const override; float ChFontSize() const override; + float IcFontSize() const override; double ViewportWidth() const override; double ViewportHeight() const override; double SmallViewportWidth() const override;
diff --git a/third_party/blink/renderer/core/css/media_values_dynamic.cc b/third_party/blink/renderer/core/css/media_values_dynamic.cc index 838bbfbe..3158a01 100644 --- a/third_party/blink/renderer/core/css/media_values_dynamic.cc +++ b/third_party/blink/renderer/core/css/media_values_dynamic.cc
@@ -62,6 +62,10 @@ return CalculateChSize(frame_); } +float MediaValuesDynamic::IcFontSize() const { + return CalculateIcSize(frame_); +} + double MediaValuesDynamic::ViewportWidth() const { if (viewport_dimensions_overridden_) return viewport_width_override_;
diff --git a/third_party/blink/renderer/core/css/media_values_dynamic.h b/third_party/blink/renderer/core/css/media_values_dynamic.h index 075eea9..ca70144e 100644 --- a/third_party/blink/renderer/core/css/media_values_dynamic.h +++ b/third_party/blink/renderer/core/css/media_values_dynamic.h
@@ -59,6 +59,7 @@ float RemFontSize() const override; float ExFontSize() const override; float ChFontSize() const override; + float IcFontSize() const override; double ViewportWidth() const override; double ViewportHeight() const override; double SmallViewportWidth() const override;
diff --git a/third_party/blink/renderer/core/css/media_values_test.cc b/third_party/blink/renderer/core/css/media_values_test.cc index 5ea7077..b00d13d 100644 --- a/third_party/blink/renderer/core/css/media_values_test.cc +++ b/third_party/blink/renderer/core/css/media_values_test.cc
@@ -35,6 +35,7 @@ {40.0, CSSPrimitiveValue::UnitType::kRems, 16, 300, 300, true, 640}, {40.0, CSSPrimitiveValue::UnitType::kExs, 16, 300, 300, true, 320}, {40.0, CSSPrimitiveValue::UnitType::kChs, 16, 300, 300, true, 320}, + {40.0, CSSPrimitiveValue::UnitType::kIcs, 16, 300, 300, true, 640}, {43.0, CSSPrimitiveValue::UnitType::kViewportWidth, 16, 848, 976, true, 364.64}, {100.0, CSSPrimitiveValue::UnitType::kViewportWidth, 16, 821, 976, true, @@ -94,6 +95,7 @@ double rem = 0; double ex = 0; double ch = 0; + double ic = 0; using UnitType = CSSPrimitiveValue::UnitType; @@ -101,11 +103,13 @@ EXPECT_TRUE(media_values->ComputeLength(1.0, UnitType::kRems, rem)); EXPECT_TRUE(media_values->ComputeLength(1.0, UnitType::kExs, ex)); EXPECT_TRUE(media_values->ComputeLength(1.0, UnitType::kChs, ch)); + EXPECT_TRUE(media_values->ComputeLength(1.0, UnitType::kIcs, ic)); EXPECT_DOUBLE_EQ(10.0, em); EXPECT_DOUBLE_EQ(10.0, rem); EXPECT_DOUBLE_EQ(8.0, ex); EXPECT_DOUBLE_EQ(10.0, ch); + EXPECT_DOUBLE_EQ(10.0, ic); } } // namespace blink
diff --git a/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc b/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc index 7c2066b..c8121b9 100644 --- a/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc +++ b/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc
@@ -944,6 +944,10 @@ if (!RuntimeEnabledFeatures::CSSContainerRelativeUnitsEnabled()) return nullptr; break; + case CSSPrimitiveValue::UnitType::kIcs: + if (!RuntimeEnabledFeatures::CSSIcUnitEnabled()) + return nullptr; + break; default: return nullptr; }
diff --git a/third_party/blink/renderer/core/editing/build.gni b/third_party/blink/renderer/core/editing/build.gni index fa4b244..b0c74aa 100644 --- a/third_party/blink/renderer/core/editing/build.gni +++ b/third_party/blink/renderer/core/editing/build.gni
@@ -377,6 +377,7 @@ "commands/replace_selection_command_test.cc", "commands/set_character_data_command_test.cc", "commands/split_text_node_command_test.cc", + "commands/style_commands_test.cc", "commands/typing_command_test.cc", "editing_strategy_test.cc", "editing_style_test.cc",
diff --git a/third_party/blink/renderer/core/editing/commands/style_commands.h b/third_party/blink/renderer/core/editing/commands/style_commands.h index 4573857c..b59d36a0 100644 --- a/third_party/blink/renderer/core/editing/commands/style_commands.h +++ b/third_party/blink/renderer/core/editing/commands/style_commands.h
@@ -33,6 +33,7 @@ #define THIRD_PARTY_BLINK_RENDERER_CORE_EDITING_COMMANDS_STYLE_COMMANDS_H_ #include "mojo/public/mojom/base/text_direction.mojom-blink-forward.h" +#include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/core/events/input_event.h" #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" #include "third_party/blink/renderer/platform/wtf/forward.h" @@ -49,7 +50,7 @@ enum class EditorCommandSource; // This class provides static functions about commands related to style. -class StyleCommands { +class CORE_EXPORT StyleCommands { STATIC_ONLY(StyleCommands); public:
diff --git a/third_party/blink/renderer/core/editing/commands/style_commands_test.cc b/third_party/blink/renderer/core/editing/commands/style_commands_test.cc new file mode 100644 index 0000000..b108d84 --- /dev/null +++ b/third_party/blink/renderer/core/editing/commands/style_commands_test.cc
@@ -0,0 +1,37 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/renderer/core/editing/commands/style_commands.h" + +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/renderer/core/dom/document.h" +#include "third_party/blink/renderer/core/editing/editor.h" +#include "third_party/blink/renderer/core/editing/frame_selection.h" +#include "third_party/blink/renderer/core/editing/position.h" +#include "third_party/blink/renderer/core/editing/selection_template.h" +#include "third_party/blink/renderer/core/editing/testing/editing_test_base.h" +#include "third_party/blink/renderer/core/frame/local_frame.h" + +namespace blink { + +class StyleCommandsTest : public EditingTestBase {}; + +// http://crbug.com/1348478 +TEST_F(StyleCommandsTest, ComputeAndSetTypingStyleWithNullPosition) { + GetDocument().setDesignMode("on"); + InsertStyleElement( + "b {" + "display: inline-block;" + "overflow-x: scroll;" + "}"); + Selection().SetSelection(SetSelectionTextToBody("|<b></b> "), + SetSelectionOptions()); + + EXPECT_TRUE(StyleCommands::ExecuteToggleBold(GetFrame(), nullptr, + EditorCommandSource::kDOM, "")); + + EXPECT_EQ("|<b></b> ", GetSelectionTextFromBody()); +} + +} // namespace blink
diff --git a/third_party/blink/renderer/core/editing/editor.cc b/third_party/blink/renderer/core/editing/editor.cc index 8205bff..9c31f4ef 100644 --- a/third_party/blink/renderer/core/editing/editor.cc +++ b/third_party/blink/renderer/core/editing/editor.cc
@@ -751,13 +751,15 @@ else typing_style_ = MakeGarbageCollected<EditingStyle>(style); - typing_style_->PrepareToApplyAt( - GetFrame() - .Selection() - .ComputeVisibleSelectionInDOMTreeDeprecated() - .VisibleStart() - .DeepEquivalent(), - EditingStyle::kPreserveWritingDirection); + const Position& position = GetFrame() + .Selection() + .ComputeVisibleSelectionInDOMTreeDeprecated() + .VisibleStart() + .DeepEquivalent(); + if (position.IsNull()) + return; + typing_style_->PrepareToApplyAt(position, + EditingStyle::kPreserveWritingDirection); // Handle block styles, substracting these from the typing style. EditingStyle* block_style =
diff --git a/third_party/blink/renderer/core/html/html_frame_set_element.cc b/third_party/blink/renderer/core/html/html_frame_set_element.cc index f681be48e9..e91d93c 100644 --- a/third_party/blink/renderer/core/html/html_frame_set_element.cc +++ b/third_party/blink/renderer/core/html/html_frame_set_element.cc
@@ -376,8 +376,8 @@ if (event.type() == event_type_names::kMousedown && event.IsLeftButton()) { gfx::PointF local_pos = layout_frame_set.AbsoluteToLocalPoint(event.AbsoluteLocation()); - StartResizing(layout_frame_set.cols_, local_pos.x(), resize_cols_); - StartResizing(layout_frame_set.rows_, local_pos.y(), resize_rows_); + StartResizing(layout_frame_set.Columns(), local_pos.x(), resize_cols_); + StartResizing(layout_frame_set.Rows(), local_pos.y(), resize_rows_); if (resize_cols_.IsResizingSplit() || resize_rows_.IsResizingSplit()) { SetIsResizing(true); return true; @@ -388,8 +388,8 @@ (event.type() == event_type_names::kMouseup && event.IsLeftButton())) { gfx::PointF local_pos = layout_frame_set.AbsoluteToLocalPoint(event.AbsoluteLocation()); - ContinueResizing(layout_frame_set.cols_, local_pos.x(), resize_cols_); - ContinueResizing(layout_frame_set.rows_, local_pos.y(), resize_rows_); + ContinueResizing(layout_frame_set.Columns(), local_pos.x(), resize_cols_); + ContinueResizing(layout_frame_set.Rows(), local_pos.y(), resize_rows_); if (event.type() == event_type_names::kMouseup && event.IsLeftButton()) { SetIsResizing(false); return true; @@ -406,7 +406,7 @@ frame->GetEventHandler().SetResizingFrameSet(is_resizing ? this : nullptr); } -void HTMLFrameSetElement::StartResizing(LayoutFrameSet::GridAxis& axis, +void HTMLFrameSetElement::StartResizing(const LayoutFrameSet::GridAxis& axis, int position, ResizeAxis& resize_axis) { int split = HitTestSplit(axis, position); @@ -418,7 +418,7 @@ resize_axis.split_resize_offset_ = position - SplitPosition(axis, split); } -void HTMLFrameSetElement::ContinueResizing(LayoutFrameSet::GridAxis& axis, +void HTMLFrameSetElement::ContinueResizing(const LayoutFrameSet::GridAxis& axis, int position, ResizeAxis& resize_axis) { if (GetLayoutObject()->NeedsLayout())
diff --git a/third_party/blink/renderer/core/html/html_frame_set_element.h b/third_party/blink/renderer/core/html/html_frame_set_element.h index ccdee37..39a78a0 100644 --- a/third_party/blink/renderer/core/html/html_frame_set_element.h +++ b/third_party/blink/renderer/core/html/html_frame_set_element.h
@@ -122,10 +122,10 @@ bool UserResize(const MouseEvent& event); void SetIsResizing(bool is_resizing); - void StartResizing(LayoutFrameSet::GridAxis& axis, + void StartResizing(const LayoutFrameSet::GridAxis& axis, int position, ResizeAxis& resize_axis); - void ContinueResizing(LayoutFrameSet::GridAxis& axis, + void ContinueResizing(const LayoutFrameSet::GridAxis& axis, int position, ResizeAxis& resize_axis); int SplitPosition(const LayoutFrameSet::GridAxis& axis, int split) const;
diff --git a/third_party/blink/renderer/core/layout/layout_frame_set.h b/third_party/blink/renderer/core/layout/layout_frame_set.h index e6f18f3..cd6eeacc 100644 --- a/third_party/blink/renderer/core/layout/layout_frame_set.h +++ b/third_party/blink/renderer/core/layout/layout_frame_set.h
@@ -137,9 +137,6 @@ GridAxis rows_; GridAxis cols_; - - // Temporal friend until we complete to move the resizing code. - friend HTMLFrameSetElement; }; template <>
diff --git a/third_party/blink/renderer/core/paint/ng/ng_highlight_overlay.cc b/third_party/blink/renderer/core/paint/ng/ng_highlight_overlay.cc index 0418cb0..820f296 100644 --- a/third_party/blink/renderer/core/paint/ng/ng_highlight_overlay.cc +++ b/third_party/blink/renderer/core/paint/ng/ng_highlight_overlay.cc
@@ -8,6 +8,7 @@ #include "third_party/blink/renderer/core/editing/frame_selection.h" #include "third_party/blink/renderer/core/editing/markers/custom_highlight_marker.h" #include "third_party/blink/renderer/core/highlight/highlight_registry.h" +#include "third_party/blink/renderer/core/layout/layout_text.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.h" #include "third_party/blink/renderer/platform/fonts/ng_text_fragment_paint_info.h" #include "third_party/blink/renderer/platform/wtf/text/string_builder.h" @@ -227,6 +228,7 @@ Vector<HighlightEdge> NGHighlightOverlay::ComputeEdges( const Node* node, const HighlightRegistry* registry, + const NGTextFragmentPaintInfo& originating, const LayoutSelectionStatus* selection, const DocumentMarkerVector& custom, const DocumentMarkerVector& grammar, @@ -236,6 +238,16 @@ Vector<HighlightEdge> result{}; + if (selection) { + DCHECK_LT(selection->start, selection->end); + result.emplace_back(selection->start, + HighlightLayer{HighlightLayerType::kSelection}, + HighlightEdgeType::kStart); + result.emplace_back(selection->end, + HighlightLayer{HighlightLayerType::kSelection}, + HighlightEdgeType::kEnd); + } + // |node| might not be a Text node (e.g. <br>), or it might be nullptr (e.g. // ::first-letter). In both cases, we should still try to paint kOriginating // and kSelection if necessary, but we can’t paint marker-based highlights, @@ -246,75 +258,90 @@ DCHECK(custom.IsEmpty() && grammar.IsEmpty() && spelling.IsEmpty() && target.IsEmpty()) << "markers can not be painted without a valid Text node"; - } + } else { + // We can save time by skipping marker-based highlights that are outside the + // originating fragment (e.g. on a different line), but we can only compare + // offsets that are in the same offset space (DOM or canonical text), and + // converting each marker to canonical text offsets is the most expensive + // step of this function. We can avoid that by converting the originating + // fragment back to DOM offsets for comparison. + const NGOffsetMapping* mapping = + NGOffsetMapping::GetFor(text_node->GetLayoutObject()); + unsigned last_from = + mapping->GetLastPosition(originating.from).OffsetInContainerNode(); + unsigned first_to = + mapping->GetFirstPosition(originating.to).OffsetInContainerNode(); - for (const auto& marker : custom) { - auto* custom = To<CustomHighlightMarker>(marker.Get()); - unsigned content_start = - GetTextContentOffset(*text_node, marker->StartOffset()); - unsigned content_end = - GetTextContentOffset(*text_node, marker->EndOffset()); - if (content_start >= content_end) - continue; - result.emplace_back( - content_start, - HighlightLayer{HighlightLayerType::kCustom, custom->GetHighlightName()}, - HighlightEdgeType::kStart); - result.emplace_back( - content_end, - HighlightLayer{HighlightLayerType::kCustom, custom->GetHighlightName()}, - HighlightEdgeType::kEnd); - } - for (const auto& marker : grammar) { - unsigned content_start = - GetTextContentOffset(*text_node, marker->StartOffset()); - unsigned content_end = - GetTextContentOffset(*text_node, marker->EndOffset()); - if (content_start >= content_end) - continue; - result.emplace_back(content_start, - HighlightLayer{HighlightLayerType::kGrammar}, - HighlightEdgeType::kStart); - result.emplace_back(content_end, - HighlightLayer{HighlightLayerType::kGrammar}, - HighlightEdgeType::kEnd); - } - for (const auto& marker : spelling) { - unsigned content_start = - GetTextContentOffset(*text_node, marker->StartOffset()); - unsigned content_end = - GetTextContentOffset(*text_node, marker->EndOffset()); - if (content_start >= content_end) - continue; - result.emplace_back(content_start, - HighlightLayer{HighlightLayerType::kSpelling}, - HighlightEdgeType::kStart); - result.emplace_back(content_end, - HighlightLayer{HighlightLayerType::kSpelling}, - HighlightEdgeType::kEnd); - } - for (const auto& marker : target) { - unsigned content_start = - GetTextContentOffset(*text_node, marker->StartOffset()); - unsigned content_end = - GetTextContentOffset(*text_node, marker->EndOffset()); - if (content_start >= content_end) - continue; - result.emplace_back(content_start, - HighlightLayer{HighlightLayerType::kTargetText}, - HighlightEdgeType::kStart); - result.emplace_back(content_end, - HighlightLayer{HighlightLayerType::kTargetText}, - HighlightEdgeType::kEnd); - } - if (selection) { - DCHECK_LT(selection->start, selection->end); - result.emplace_back(selection->start, - HighlightLayer{HighlightLayerType::kSelection}, - HighlightEdgeType::kStart); - result.emplace_back(selection->end, - HighlightLayer{HighlightLayerType::kSelection}, - HighlightEdgeType::kEnd); + for (const auto& marker : custom) { + if (marker->EndOffset() <= last_from || marker->StartOffset() >= first_to) + continue; + auto* custom = To<CustomHighlightMarker>(marker.Get()); + unsigned content_start = + GetTextContentOffset(*text_node, marker->StartOffset()); + unsigned content_end = + GetTextContentOffset(*text_node, marker->EndOffset()); + if (content_start >= content_end) + continue; + result.emplace_back(content_start, + HighlightLayer{HighlightLayerType::kCustom, + custom->GetHighlightName()}, + HighlightEdgeType::kStart); + result.emplace_back(content_end, + HighlightLayer{HighlightLayerType::kCustom, + custom->GetHighlightName()}, + HighlightEdgeType::kEnd); + } + + for (const auto& marker : grammar) { + if (marker->EndOffset() <= last_from || marker->StartOffset() >= first_to) + continue; + unsigned content_start = + GetTextContentOffset(*text_node, marker->StartOffset()); + unsigned content_end = + GetTextContentOffset(*text_node, marker->EndOffset()); + if (content_start >= content_end) + continue; + result.emplace_back(content_start, + HighlightLayer{HighlightLayerType::kGrammar}, + HighlightEdgeType::kStart); + result.emplace_back(content_end, + HighlightLayer{HighlightLayerType::kGrammar}, + HighlightEdgeType::kEnd); + } + + for (const auto& marker : spelling) { + if (marker->EndOffset() <= last_from || marker->StartOffset() >= first_to) + continue; + unsigned content_start = + GetTextContentOffset(*text_node, marker->StartOffset()); + unsigned content_end = + GetTextContentOffset(*text_node, marker->EndOffset()); + if (content_start >= content_end) + continue; + result.emplace_back(content_start, + HighlightLayer{HighlightLayerType::kSpelling}, + HighlightEdgeType::kStart); + result.emplace_back(content_end, + HighlightLayer{HighlightLayerType::kSpelling}, + HighlightEdgeType::kEnd); + } + + for (const auto& marker : target) { + if (marker->EndOffset() <= last_from || marker->StartOffset() >= first_to) + continue; + unsigned content_start = + GetTextContentOffset(*text_node, marker->StartOffset()); + unsigned content_end = + GetTextContentOffset(*text_node, marker->EndOffset()); + if (content_start >= content_end) + continue; + result.emplace_back(content_start, + HighlightLayer{HighlightLayerType::kTargetText}, + HighlightEdgeType::kStart); + result.emplace_back(content_end, + HighlightLayer{HighlightLayerType::kTargetText}, + HighlightEdgeType::kEnd); + } } std::sort(result.begin(), result.end(),
diff --git a/third_party/blink/renderer/core/paint/ng/ng_highlight_overlay.h b/third_party/blink/renderer/core/paint/ng/ng_highlight_overlay.h index 6b788e2..72e13deb 100644 --- a/third_party/blink/renderer/core/paint/ng/ng_highlight_overlay.h +++ b/third_party/blink/renderer/core/paint/ng/ng_highlight_overlay.h
@@ -107,6 +107,7 @@ static Vector<HighlightEdge> ComputeEdges( const Node*, const HighlightRegistry*, + const NGTextFragmentPaintInfo& originating, const LayoutSelectionStatus* selection, const DocumentMarkerVector& custom, const DocumentMarkerVector& grammar,
diff --git a/third_party/blink/renderer/core/paint/ng/ng_highlight_overlay_test.cc b/third_party/blink/renderer/core/paint/ng/ng_highlight_overlay_test.cc index ac14cfc9..7db23be9 100644 --- a/third_party/blink/renderer/core/paint/ng/ng_highlight_overlay_test.cc +++ b/third_party/blink/renderer/core/paint/ng/ng_highlight_overlay_test.cc
@@ -108,14 +108,18 @@ } TEST_F(NGHighlightOverlayTest, ComputeEdges) { - SetBodyInnerHTML(R"HTML( foo<br>)HTML"); - const Node* node = GetDocument().body()->childNodes()->item(0); - const Node* br = GetDocument().body()->childNodes()->item(1); + // #text " foo" has two offset mapping units: + // • DOM [0,3), text content [1,1) + // • DOM [3,6), text content [1,4) + SetBodyInnerHTML(R"HTML(<br> foo<br>)HTML"); + const Node* br = GetDocument().body()->childNodes()->item(0); + const Node* text = GetDocument().body()->childNodes()->item(1); UpdateAllLifecyclePhasesForTest(); auto* registry = MakeGarbageCollected<HighlightRegistry>(*GetFrame().DomWindow()); - LayoutSelectionStatus selection{0, 2, SelectSoftLineBreak::kNotSelected}; + NGTextFragmentPaintInfo originating{"", 1, 4}; + LayoutSelectionStatus selection{1, 3, SelectSoftLineBreak::kNotSelected}; auto* none = MakeGarbageCollected<DocumentMarkerVector>(); HighlightLayer originating_layer{HighlightLayerType::kOriginating}; HighlightLayer selection_layer{HighlightLayerType::kSelection}; @@ -123,25 +127,28 @@ HighlightLayer spelling_layer{HighlightLayerType::kSpelling}; HighlightLayer target_layer{HighlightLayerType::kTargetText}; - EXPECT_EQ(NGHighlightOverlay::ComputeEdges(node, registry, nullptr, *none, - *none, *none, *none), - (Vector<HighlightEdge>{})) + EXPECT_EQ( + NGHighlightOverlay::ComputeEdges(text, registry, originating, nullptr, + *none, *none, *none, *none), + (Vector<HighlightEdge>{})) << "should return no edges when nothing is highlighted"; - EXPECT_EQ(NGHighlightOverlay::ComputeEdges(nullptr, registry, &selection, - *none, *none, *none, *none), - (Vector<HighlightEdge>{ - HighlightEdge{0, selection_layer, HighlightEdgeType::kStart}, - HighlightEdge{2, selection_layer, HighlightEdgeType::kEnd}, - })) + EXPECT_EQ( + NGHighlightOverlay::ComputeEdges(nullptr, registry, originating, + &selection, *none, *none, *none, *none), + (Vector<HighlightEdge>{ + HighlightEdge{1, selection_layer, HighlightEdgeType::kStart}, + HighlightEdge{3, selection_layer, HighlightEdgeType::kEnd}, + })) << "should still return non-marker edges when node is nullptr"; - EXPECT_EQ(NGHighlightOverlay::ComputeEdges(br, registry, &selection, *none, - *none, *none, *none), - (Vector<HighlightEdge>{ - HighlightEdge{0, selection_layer, HighlightEdgeType::kStart}, - HighlightEdge{2, selection_layer, HighlightEdgeType::kEnd}, - })) + EXPECT_EQ( + NGHighlightOverlay::ComputeEdges(br, registry, originating, &selection, + *none, *none, *none, *none), + (Vector<HighlightEdge>{ + HighlightEdge{1, selection_layer, HighlightEdgeType::kStart}, + HighlightEdge{3, selection_layer, HighlightEdgeType::kEnd}, + })) << "should still return non-marker edges when node is <br>"; auto* grammar = MakeGarbageCollected<DocumentMarkerVector>(); @@ -153,27 +160,45 @@ spelling->push_back(MakeGarbageCollected<SpellingMarker>(4, 5, "")); spelling->push_back(MakeGarbageCollected<SpellingMarker>(5, 6, "")); - EXPECT_EQ(NGHighlightOverlay::ComputeEdges(node, registry, &selection, *none, - *grammar, *spelling, *target), - (Vector<HighlightEdge>{ - HighlightEdge{0, grammar_layer, HighlightEdgeType::kStart}, - HighlightEdge{0, selection_layer, HighlightEdgeType::kStart}, - HighlightEdge{1, grammar_layer, HighlightEdgeType::kEnd}, - HighlightEdge{1, grammar_layer, HighlightEdgeType::kStart}, - HighlightEdge{1, spelling_layer, HighlightEdgeType::kStart}, - HighlightEdge{1, target_layer, HighlightEdgeType::kStart}, - HighlightEdge{2, grammar_layer, HighlightEdgeType::kEnd}, - HighlightEdge{2, spelling_layer, HighlightEdgeType::kEnd}, - HighlightEdge{2, target_layer, HighlightEdgeType::kEnd}, - HighlightEdge{2, selection_layer, HighlightEdgeType::kEnd}, - HighlightEdge{2, spelling_layer, HighlightEdgeType::kStart}, - HighlightEdge{3, spelling_layer, HighlightEdgeType::kEnd}, - })) + EXPECT_EQ( + NGHighlightOverlay::ComputeEdges(text, registry, originating, &selection, + *none, *grammar, *spelling, *target), + (Vector<HighlightEdge>{ + HighlightEdge{1, grammar_layer, HighlightEdgeType::kStart}, + HighlightEdge{1, selection_layer, HighlightEdgeType::kStart}, + HighlightEdge{2, grammar_layer, HighlightEdgeType::kEnd}, + HighlightEdge{2, grammar_layer, HighlightEdgeType::kStart}, + HighlightEdge{2, spelling_layer, HighlightEdgeType::kStart}, + HighlightEdge{2, target_layer, HighlightEdgeType::kStart}, + HighlightEdge{3, grammar_layer, HighlightEdgeType::kEnd}, + HighlightEdge{3, spelling_layer, HighlightEdgeType::kEnd}, + HighlightEdge{3, target_layer, HighlightEdgeType::kEnd}, + HighlightEdge{3, selection_layer, HighlightEdgeType::kEnd}, + HighlightEdge{3, spelling_layer, HighlightEdgeType::kStart}, + HighlightEdge{4, spelling_layer, HighlightEdgeType::kEnd}, + })) << "should return edges in correct order"; + + NGTextFragmentPaintInfo originating2{"", 2, 3}; + + EXPECT_EQ( + NGHighlightOverlay::ComputeEdges(text, registry, originating2, &selection, + *none, *grammar, *spelling, *target), + (Vector<HighlightEdge>{ + HighlightEdge{1, selection_layer, HighlightEdgeType::kStart}, + HighlightEdge{2, grammar_layer, HighlightEdgeType::kStart}, + HighlightEdge{2, spelling_layer, HighlightEdgeType::kStart}, + HighlightEdge{2, target_layer, HighlightEdgeType::kStart}, + HighlightEdge{3, grammar_layer, HighlightEdgeType::kEnd}, + HighlightEdge{3, spelling_layer, HighlightEdgeType::kEnd}, + HighlightEdge{3, target_layer, HighlightEdgeType::kEnd}, + HighlightEdge{3, selection_layer, HighlightEdgeType::kEnd}, + })) + << "should skip edge pairs that are completely outside fragment"; } TEST_F(NGHighlightOverlayTest, ComputeParts) { - SetBodyInnerHTML(R"HTML(brown fxo oevr lazy dgo)HTML"); + SetBodyInnerHTML(R"HTML(brown fxo oevr lazy dgo today)HTML"); const Node* node = GetDocument().body()->childNodes()->item(0); UpdateAllLifecyclePhasesForTest(); @@ -211,17 +236,17 @@ Vector<HighlightLayer> layers = NGHighlightOverlay::ComputeLayers( registry, &selection, *custom, *grammar, *spelling, *target); - // 0 6 10 15 20 - // brown fxo oevr lazy dgo - // [ ] originating - // ::highlight(foo), not active - // ::highlight(bar), not active - // ::spelling-error, not active - // ::target-text, not active - // ::selection, not active + // 0 6 10 15 20 24 + // brown fxo oevr lazy dgo today + // [ ] originating + // ::highlight(foo), not active + // ::highlight(bar), not active + // ::spelling-error, not active + // ::target-text, not active + // ::selection, not active Vector<HighlightEdge> edges = NGHighlightOverlay::ComputeEdges( - node, registry, nullptr, *none, *none, *none, *none); + node, registry, originating, nullptr, *none, *none, *none, *none); EXPECT_EQ(NGHighlightOverlay::ComputeParts(originating, layers, edges), (Vector<HighlightPart>{ @@ -229,17 +254,18 @@ })) << "should return correct kOriginating part when nothing is highlighted"; - // 0 6 10 15 20 - // brown fxo oevr lazy dgo - // [ ] originating, as above - // [ ] ::highlight(foo), changed! - // [ ] ::highlight(bar), changed! - // [ ] [ ] [ ] ::spelling-error, changed! - // [ ] ::target-text, changed! - // [ ] ::selection, changed! + // 0 6 10 15 20 24 + // brown fxo oevr lazy dgo today + // [ ] originating, as above + // [ ] ::highlight(foo), changed! + // [ ] ::highlight(bar), changed! + // [ ] [ ] [ ] ::spelling-error, changed! + // [ ] ::target-text, changed! + // [ ] ::selection, changed! - Vector<HighlightEdge> edges2 = NGHighlightOverlay::ComputeEdges( - node, registry, &selection, *custom, *grammar, *spelling, *target); + Vector<HighlightEdge> edges2 = + NGHighlightOverlay::ComputeEdges(node, registry, originating, &selection, + *custom, *grammar, *spelling, *target); EXPECT_EQ(NGHighlightOverlay::ComputeParts(originating, layers, edges2), (Vector<HighlightPart>{ @@ -256,18 +282,19 @@ })) << "should return correct parts given several active highlights"; - // 0 6 10 15 20 - // brown fxo oevr lazy dgo - // [ ] originating, as above - // [ ] ::highlight(foo), changed! - // [ ] ::highlight(bar), as above - // [ ] [ ] [ ] ::spelling-error, as above - // [ ] ::target-text, as above - // [ ] ::selection, as above + // 0 6 10 15 20 24 + // brown fxo oevr lazy dgo today + // [ ] originating, as above + // [ ] ::highlight(foo), changed! + // [ ] ::highlight(bar), as above + // [ ] [ ] [ ] ::spelling-error, as above + // [ ] ::target-text, as above + // [ ] ::selection, as above custom->at(0)->SetStartOffset(6); - Vector<HighlightEdge> edges3 = NGHighlightOverlay::ComputeEdges( - node, registry, &selection, *custom, *grammar, *spelling, *target); + Vector<HighlightEdge> edges3 = + NGHighlightOverlay::ComputeEdges(node, registry, originating, &selection, + *custom, *grammar, *spelling, *target); EXPECT_EQ(NGHighlightOverlay::ComputeParts(originating, layers, edges3), (Vector<HighlightPart>{ @@ -284,18 +311,21 @@ })) << "correct when first edge starts after start of originating fragment"; - // 0 6 10 15 20 - // brown fxo oevr lazy dgo - // [ ] originating, changed! - // [ ] ::highlight(foo), as above - // [ ] ::highlight(bar), as above - // [ ] [ ] [ ] ::spelling-error, as above - // [ ] ::target-text, as above - // [ ] ::selection, as above + // 0 6 10 15 20 24 + // brown fxo oevr lazy dgo today + // [ ] originating, changed! + // [ ] ::highlight(foo), as above + // [ ] ::highlight(bar), as above + // [ ] [ ] [ ] ::spelling-error, as above + // [ ] ::target-text, as above + // [ ] ::selection, as above NGTextFragmentPaintInfo originating2{"", 8, 18}; + Vector<HighlightEdge> edges4 = + NGHighlightOverlay::ComputeEdges(node, registry, originating, &selection, + *custom, *grammar, *spelling, *target); - EXPECT_EQ(NGHighlightOverlay::ComputeParts(originating2, layers, edges3), + EXPECT_EQ(NGHighlightOverlay::ComputeParts(originating2, layers, edges4), (Vector<HighlightPart>{ HighlightPart{spel, 8, 9, {orig, foo, spel}}, HighlightPart{foo, 9, 10, {orig, foo}}, @@ -306,19 +336,19 @@ })) << "should clamp result to originating fragment offsets"; - // 0 6 10 15 20 - // brown fxo oevr lazy dgo - // [ ] originating, as above - // ::highlight(foo), changed! - // ::highlight(bar), changed! - // [ ] [ ] [ ] ::spelling-error, as above - // ::target-text, changed! - // ::selection, changed! + // 0 6 10 15 20 24 + // brown fxo oevr lazy dgo today + // [ ] originating, as above + // ::highlight(foo), changed! + // ::highlight(bar), changed! + // [ ] [ ] [ ] ::spelling-error, as above + // ::target-text, changed! + // ::selection, changed! - Vector<HighlightEdge> edges4 = NGHighlightOverlay::ComputeEdges( - node, registry, nullptr, *none, *none, *spelling, *none); + Vector<HighlightEdge> edges5 = NGHighlightOverlay::ComputeEdges( + node, registry, originating, nullptr, *none, *none, *spelling, *none); - EXPECT_EQ(NGHighlightOverlay::ComputeParts(originating2, layers, edges4), + EXPECT_EQ(NGHighlightOverlay::ComputeParts(originating2, layers, edges5), (Vector<HighlightPart>{ HighlightPart{spel, 8, 9, {orig, spel}}, HighlightPart{orig, 9, 10, {orig}}, @@ -327,24 +357,27 @@ })) << "should not crash if there is a gap in active layers"; - // 0 6 10 15 20 - // brown fxo oevr lazy dgo - // [ ] originating, changed! - // ::highlight(foo), as above - // ::highlight(bar), as above - // [ ] [ ] [ ] ::spelling-error, as above - // ::target-text, as above - // ::selection, as above + // 0 6 10 15 20 24 + // brown fxo oevr lazy dgo today + // [ ] originating, changed! + // ::highlight(foo), as above + // ::highlight(bar), as above + // [ ] [ ] [ ] ::spelling-error, as above + // ::target-text, as above + // ::selection, as above NGTextFragmentPaintInfo originating3{"", 1, 4}; + Vector<HighlightEdge> edges6 = + NGHighlightOverlay::ComputeEdges(node, registry, originating, &selection, + *custom, *grammar, *spelling, *target); - EXPECT_EQ(NGHighlightOverlay::ComputeParts(originating3, layers, edges4), + EXPECT_EQ(NGHighlightOverlay::ComputeParts(originating3, layers, edges6), (Vector<HighlightPart>{ HighlightPart{orig, 1, 4, {orig}}, })) << "correct when first edge starts after end of originating fragment"; - // 0 6 10 15 20 + // 0 6 10 15 20 24 // brown fxo oevr lazy dgo today // [ ] originating, changed! // ::highlight(foo), as above @@ -354,8 +387,11 @@ // ::selection, as above NGTextFragmentPaintInfo originating4{"", 25, 28}; + Vector<HighlightEdge> edges7 = + NGHighlightOverlay::ComputeEdges(node, registry, originating, &selection, + *custom, *grammar, *spelling, *target); - EXPECT_EQ(NGHighlightOverlay::ComputeParts(originating4, layers, edges4), + EXPECT_EQ(NGHighlightOverlay::ComputeParts(originating4, layers, edges7), (Vector<HighlightPart>{ HighlightPart{orig, 25, 28, {orig}}, }))
diff --git a/third_party/blink/renderer/core/paint/ng/ng_highlight_painter.cc b/third_party/blink/renderer/core/paint/ng/ng_highlight_painter.cc index 293db4d..cd3d447 100644 --- a/third_party/blink/renderer/core/paint/ng/ng_highlight_painter.cc +++ b/third_party/blink/renderer/core/paint/ng/ng_highlight_painter.cc
@@ -384,8 +384,8 @@ GetHighlightRegistry(node_), GetSelectionStatus(selection_), custom_, grammar_, spelling_, target_); Vector<HighlightEdge> edges = NGHighlightOverlay::ComputeEdges( - node_, GetHighlightRegistry(node_), GetSelectionStatus(selection_), - custom_, grammar_, spelling_, target_); + node_, GetHighlightRegistry(node_), fragment_paint_info_, + GetSelectionStatus(selection_), custom_, grammar_, spelling_, target_); parts_ = NGHighlightOverlay::ComputeParts(fragment_paint_info_, layers, edges); @@ -773,9 +773,11 @@ fragment_item_.LocalRect(text, clamped_start, clamped_end), background_color, background_auto_dark_mode_); - text_painter_.Paint(clamped_start, clamped_end, length, layer.text_style, - node_id, foreground_auto_dark_mode_, - TextPainterBase::kShadowsOnly); + if (layer.text_style.shadow) { + text_painter_.Paint( + clamped_start, clamped_end, length, layer.text_style, node_id, + foreground_auto_dark_mode_, TextPainterBase::kShadowsOnly); + } } }
diff --git a/third_party/blink/renderer/core/svg/svg_length_context.cc b/third_party/blink/renderer/core/svg/svg_length_context.cc index 7671162..36f875c 100644 --- a/third_party/blink/renderer/core/svg/svg_length_context.cc +++ b/third_party/blink/renderer/core/svg/svg_length_context.cc
@@ -332,6 +332,9 @@ case CSSPrimitiveValue::UnitType::kChs: user_units = ConvertValueFromCHSToUserUnits(value); break; + case CSSPrimitiveValue::UnitType::kIcs: + user_units = ConvertValueFromICSToUserUnits(value); + break; case CSSPrimitiveValue::UnitType::kViewportWidth: case CSSPrimitiveValue::UnitType::kViewportHeight: case CSSPrimitiveValue::UnitType::kViewportMin: @@ -387,6 +390,8 @@ return ConvertValueFromUserUnitsToEMS(RootElementStyle(context_), value); case CSSPrimitiveValue::UnitType::kChs: return ConvertValueFromUserUnitsToCHS(value); + case CSSPrimitiveValue::UnitType::kIcs: + return ConvertValueFromUserUnitsToICS(value); case CSSPrimitiveValue::UnitType::kCentimeters: return value / kCssPixelsPerCentimeter; case CSSPrimitiveValue::UnitType::kMillimeters: @@ -445,6 +450,35 @@ style->EffectiveZoom(); } +float SVGLengthContext::ConvertValueFromUserUnitsToICS(float value) const { + const ComputedStyle* style = ComputedStyleForLengthResolving(context_); + if (!style) + return 0; + const SimpleFontData* font_data = style->GetFont().PrimaryFont(); + if (!font_data) + return 0; + float ideographic_full_width = + font_data->GetFontMetrics().IdeographicFullWidth().value_or( + style->ComputedFontSize()) / + style->EffectiveZoom(); + if (!ideographic_full_width) + return 0; + return value / ideographic_full_width; +} + +float SVGLengthContext::ConvertValueFromICSToUserUnits(float value) const { + const ComputedStyle* style = ComputedStyleForLengthResolving(context_); + if (!style) + return 0; + const SimpleFontData* font_data = style->GetFont().PrimaryFont(); + if (!font_data) + return 0; + return value * + font_data->GetFontMetrics().IdeographicFullWidth().value_or( + style->ComputedFontSize()) / + style->EffectiveZoom(); +} + float SVGLengthContext::ConvertValueFromUserUnitsToEXS(float value) const { const ComputedStyle* style = ComputedStyleForLengthResolving(context_); if (!style)
diff --git a/third_party/blink/renderer/core/svg/svg_length_context.h b/third_party/blink/renderer/core/svg/svg_length_context.h index 44688ea..b083f731 100644 --- a/third_party/blink/renderer/core/svg/svg_length_context.h +++ b/third_party/blink/renderer/core/svg/svg_length_context.h
@@ -103,6 +103,9 @@ float ConvertValueFromUserUnitsToCHS(float value) const; float ConvertValueFromCHSToUserUnits(float value) const; + float ConvertValueFromUserUnitsToICS(float value) const; + float ConvertValueFromICSToUserUnits(float value) const; + const SVGElement* context_; };
diff --git a/third_party/blink/renderer/modules/mediastream/mock_mojo_media_stream_dispatcher_host.h b/third_party/blink/renderer/modules/mediastream/mock_mojo_media_stream_dispatcher_host.h index 28139f6..a41ae1e6d 100644 --- a/third_party/blink/renderer/modules/mediastream/mock_mojo_media_stream_dispatcher_host.h +++ b/third_party/blink/renderer/modules/mediastream/mock_mojo_media_stream_dispatcher_host.h
@@ -51,6 +51,10 @@ mojom::blink::MediaStreamType, bool)); MOCK_METHOD1(OnStreamStarted, void(const WTF::String&)); + MOCK_METHOD3(KeepDeviceAliveForTransfer, + void(const base::UnguessableToken&, + const base::UnguessableToken&, + KeepDeviceAliveForTransferCallback)); #if !BUILDFLAG(IS_ANDROID) MOCK_METHOD2(FocusCapturedSurface, void(const WTF::String&, bool)); MOCK_METHOD4(Crop, @@ -59,9 +63,10 @@ uint32_t, CropCallback)); #endif - MOCK_METHOD3(GetOpenDevice, + MOCK_METHOD4(GetOpenDevice, void(int32_t request_id, const base::UnguessableToken&, + const base::UnguessableToken&, GetOpenDeviceCallback)); void ResetSessionId() { session_id_ = base::UnguessableToken::Create(); }
diff --git a/third_party/blink/renderer/modules/mediastream/user_media_controller.h b/third_party/blink/renderer/modules/mediastream/user_media_controller.h index 8a9956f..8629b6c0 100644 --- a/third_party/blink/renderer/modules/mediastream/user_media_controller.h +++ b/third_party/blink/renderer/modules/mediastream/user_media_controller.h
@@ -59,12 +59,10 @@ private: Member<UserMediaClient> client_; - bool has_requested_user_media_ = false; }; inline void UserMediaController::RequestUserMedia(UserMediaRequest* request) { Client()->RequestUserMedia(request); - has_requested_user_media_ = true; } inline void UserMediaController::CancelUserMediaRequest( @@ -81,10 +79,6 @@ Client()->StopTrack(track); } -inline bool UserMediaController::HasRequestedUserMedia() { - return has_requested_user_media_; -} - } // namespace blink #endif // THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASTREAM_USER_MEDIA_CONTROLLER_H_
diff --git a/third_party/blink/renderer/modules/mediastream/user_media_processor.cc b/third_party/blink/renderer/modules/mediastream/user_media_processor.cc index d580716..57dc2d3 100644 --- a/third_party/blink/renderer/modules/mediastream/user_media_processor.cc +++ b/third_party/blink/renderer/modules/mediastream/user_media_processor.cc
@@ -995,6 +995,7 @@ GetMediaStreamDispatcherHost()->GetOpenDevice( current_request_info_->request_id(), *current_request_info_->request()->GetSessionId(), + /*transfer_id=*/base::UnguessableToken::Create(), WTF::Bind(&UserMediaProcessor::GotOpenDevice, WrapWeakPersistent(this), current_request_info_->request_id())); } else {
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc index 0e08fa14..176e0b2 100644 --- a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc +++ b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc
@@ -1034,15 +1034,6 @@ MakeGarbageCollected<RTCCertificate>(std::move(certificate))); } -bool RTCPeerConnection::HasDocumentMedia() const { - if (!GetExecutionContext()) - return false; - UserMediaController* user_media_controller = - UserMediaController::From(To<LocalDOMWindow>(GetExecutionContext())); - return user_media_controller && - user_media_controller->HasRequestedUserMedia(); -} - void RTCPeerConnection::UpdateIceConnectionState() { DCHECK_EQ(webrtc::SdpSemantics::kUnifiedPlan, sdp_semantics_); auto new_state = ComputeIceConnectionState();
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.h b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.h index 7501a50..48160df 100644 --- a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.h +++ b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.h
@@ -350,9 +350,6 @@ static void GenerateCertificateCompleted( ScriptPromiseResolver* resolver, rtc::scoped_refptr<rtc::RTCCertificate> certificate); - // Checks if the document that the peer connection lives in has ever executed - // getUserMedia(). - bool HasDocumentMedia() const; // Called by RTCIceTransport::OnStateChange to update the ice connection // state.
diff --git a/third_party/blink/renderer/platform/loader/fetch/raw_resource.cc b/third_party/blink/renderer/platform/loader/fetch/raw_resource.cc index 01e037e..02a141e9 100644 --- a/third_party/blink/renderer/platform/loader/fetch/raw_resource.cc +++ b/third_party/blink/renderer/platform/loader/fetch/raw_resource.cc
@@ -313,47 +313,6 @@ !params.GetResourceRequest().UseStreamOnResponse(); } -static bool ShouldIgnoreHeaderForCacheReuse(AtomicString header_name) { - // FIXME: This list of headers that don't affect cache policy almost certainly - // isn't complete. - DEFINE_STATIC_LOCAL( - HashSet<AtomicString>, headers, - ({"Cache-Control", "If-Modified-Since", "If-None-Match", "Origin", - "Pragma", "Purpose", "Referer", "User-Agent"})); - return headers.Contains(header_name); -} - -Resource::MatchStatus RawResource::CanReuse( - const FetchParameters& new_fetch_parameters) const { - const ResourceRequest& new_request = - new_fetch_parameters.GetResourceRequest(); - // Ensure most headers match the existing headers before continuing. Note that - // the list of ignored headers includes some headers explicitly related to - // caching. A more detailed check of caching policy will be performed later, - // this is simply a list of headers that we might permit to be different and - // still reuse the existing Resource. - const HTTPHeaderMap& new_headers = new_request.HttpHeaderFields(); - const HTTPHeaderMap& old_headers = GetResourceRequest().HttpHeaderFields(); - - for (const auto& header : new_headers) { - AtomicString header_name = header.key; - if (!ShouldIgnoreHeaderForCacheReuse(header_name) && - header.value != old_headers.Get(header_name)) { - return MatchStatus::kRequestHeadersDoNotMatch; - } - } - - for (const auto& header : old_headers) { - AtomicString header_name = header.key; - if (!ShouldIgnoreHeaderForCacheReuse(header_name) && - header.value != new_headers.Get(header_name)) { - return MatchStatus::kRequestHeadersDoNotMatch; - } - } - - return Resource::CanReuse(new_fetch_parameters); -} - void RawResourceClient::DidDownloadToBlob(Resource*, scoped_refptr<BlobDataHandle>) {}
diff --git a/third_party/blink/renderer/platform/loader/fetch/raw_resource.h b/third_party/blink/renderer/platform/loader/fetch/raw_resource.h index 167a6f9..05e23c9 100644 --- a/third_party/blink/renderer/platform/loader/fetch/raw_resource.h +++ b/third_party/blink/renderer/platform/loader/fetch/raw_resource.h
@@ -77,7 +77,6 @@ const ResourceLoaderOptions&); // Resource implementation - MatchStatus CanReuse(const FetchParameters&) const override; bool WillFollowRedirect(const ResourceRequest&, const ResourceResponse&) override;
diff --git a/third_party/blink/renderer/platform/loader/fetch/raw_resource_test.cc b/third_party/blink/renderer/platform/loader/fetch/raw_resource_test.cc index 61fb50e..83d16d2 100644 --- a/third_party/blink/renderer/platform/loader/fetch/raw_resource_test.cc +++ b/third_party/blink/renderer/platform/loader/fetch/raw_resource_test.cc
@@ -79,25 +79,6 @@ platform_; }; -TEST_F(RawResourceTest, DontIgnoreAcceptForCacheReuse) { - scoped_refptr<const SecurityOrigin> source_origin = - SecurityOrigin::CreateUniqueOpaque(); - - ResourceRequest jpeg_request; - jpeg_request.SetHTTPAccept("image/jpeg"); - jpeg_request.SetRequestorOrigin(source_origin); - - RawResource* jpeg_resource( - RawResource::CreateForTest(jpeg_request, ResourceType::kRaw)); - - ResourceRequest png_request; - png_request.SetHTTPAccept("image/png"); - png_request.SetRequestorOrigin(source_origin); - EXPECT_NE(jpeg_resource->CanReuse( - FetchParameters::CreateForTest(std::move(png_request))), - Resource::MatchStatus::kOk); -} - class DummyClient final : public GarbageCollected<DummyClient>, public RawResourceClient { public:
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource.h b/third_party/blink/renderer/platform/loader/fetch/resource.h index e9ee256e..993e1e3 100644 --- a/third_party/blink/renderer/platform/loader/fetch/resource.h +++ b/third_party/blink/renderer/platform/loader/fetch/resource.h
@@ -140,9 +140,6 @@ // Match fails due to different request methods. kRequestMethodDoesNotMatch, - // Match fails due to different request headers. - kRequestHeadersDoNotMatch, - // Match fails due to different script types. kScriptTypeDoesNotMatch, }; @@ -363,7 +360,7 @@ } // Returns |kOk| when |this| can be resused for the given arguments. - virtual MatchStatus CanReuse(const FetchParameters& params) const; + MatchStatus CanReuse(const FetchParameters& params) const; // TODO(yhirano): Remove this once out-of-blink CORS is fully enabled. void SetResponseType(network::mojom::FetchResponseType response_type) {
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc index 1bdcf95..e93e57b 100644 --- a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc +++ b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
@@ -1468,9 +1468,6 @@ case Resource::MatchStatus::kRequestMethodDoesNotMatch: builder.Append("because the request HTTP method does not match."); break; - case Resource::MatchStatus::kRequestHeadersDoNotMatch: - builder.Append("because the request headers do not match."); - break; case Resource::MatchStatus::kScriptTypeDoesNotMatch: builder.Append("because the script type does not match."); break;
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5 index 67f169c1..787a85a 100644 --- a/third_party/blink/renderer/platform/runtime_enabled_features.json5 +++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -575,7 +575,7 @@ { name: "CSSGridTemplatePropertyInterpolation", depends_on: ["LayoutNGGridFragmentation"], - status: "experimental", + status: "stable", }, { // This needs to be kept as a runtime flag as long as we need to forcibly @@ -585,6 +585,10 @@ status: "stable", }, { + name: "CSSIcUnit", + status: "experimental", + }, + { name: "CSSIndependentTransformProperties", status: "stable", }, @@ -1280,6 +1284,11 @@ status: "stable", }, { + // crbug.com/1346221 + name: "LayoutNGFrameSet", + depends_on: ["LayoutNG"], + }, + { // Block fragmentation support in the grid layout algorithm. // https://drafts.csswg.org/css-grid-1/#pagination name: "LayoutNGGridFragmentation",
diff --git a/third_party/blink/web_tests/.clang-format b/third_party/blink/web_tests/.clang-format new file mode 100644 index 0000000..30204ef --- /dev/null +++ b/third_party/blink/web_tests/.clang-format
@@ -0,0 +1,4 @@ +BasedOnStyle: InheritParentConfig +Language: JavaScript +// Don't reformat the '// META: ...' lines +CommentPragmas: '^ META:'
diff --git a/third_party/blink/web_tests/FlagExpectations/disable-layout-ng b/third_party/blink/web_tests/FlagExpectations/disable-layout-ng index a120dbd..8f6055d 100644 --- a/third_party/blink/web_tests/FlagExpectations/disable-layout-ng +++ b/third_party/blink/web_tests/FlagExpectations/disable-layout-ng
@@ -11,6 +11,7 @@ # Tests that fail in legacy but pass in NG # ====== New tests from wpt-importer added here ====== +crbug.com/626703 external/wpt/css/css-sizing/aspect-ratio/block-aspect-ratio-050.html [ Failure ] crbug.com/626703 external/wpt/css/css-sizing/aspect-ratio/grid-aspect-ratio-040.html [ Crash ] crbug.com/626703 external/wpt/css/css-sizing/contain-intrinsic-size/contain-intrinsic-size-028.html [ Crash ] crbug.com/626703 external/wpt/css/cssom/caretPositionFromPoint-with-transformation.html [ Timeout ]
diff --git a/third_party/blink/web_tests/NeverFixTests b/third_party/blink/web_tests/NeverFixTests index f155c5c3..de95701 100644 --- a/third_party/blink/web_tests/NeverFixTests +++ b/third_party/blink/web_tests/NeverFixTests
@@ -959,12 +959,6 @@ external/wpt/css/css-backgrounds/css3-border-image-repeat-stretch.html [ Skip ] external/wpt/css/css-backgrounds/first-letter-space-not-selected.html [ Skip ] -# The ic unit isn't supported. https://crbug.com/778495 -external/wpt/css/css-values/ic-unit-001.html [ Skip ] -external/wpt/css/css-values/ic-unit-002.html [ Skip ] -external/wpt/css/css-values/ic-unit-003.html [ Skip ] -external/wpt/css/css-values/ic-unit-004.html [ Skip ] - # lab() and lch() aren't supported. external/wpt/css/css-color/lab-001.html [ Skip ] external/wpt/css/css-color/lab-002.html [ Skip ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index 776d1919..33e44ff 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -3147,13 +3147,12 @@ crbug.com/1053965 external/wpt/css/css-values/ex-unit-004.html [ Failure ] crbug.com/759914 external/wpt/css/css-values/ch-unit-011.html [ Failure ] crbug.com/965366 external/wpt/css/css-values/ch-unit-017.html [ Failure ] -crbug.com/937101 external/wpt/css/css-values/ic-unit-008.html [ Failure ] -crbug.com/937101 external/wpt/css/css-values/ic-unit-009.html [ Failure ] -crbug.com/937101 external/wpt/css/css-values/ic-unit-010.html [ Failure ] -crbug.com/937101 external/wpt/css/css-values/ic-unit-011.html [ Failure ] +crbug.com/937101 [ Mac ] external/wpt/css/css-values/ic-unit-002.html [ Failure ] +crbug.com/937101 [ Mac ] external/wpt/css/css-values/ic-unit-003.html [ Failure ] +crbug.com/937101 [ Mac ] external/wpt/css/css-values/ic-unit-009.html [ Failure ] +crbug.com/937101 [ Mac ] external/wpt/css/css-values/ic-unit-010.html [ Failure ] +crbug.com/937101 [ Mac ] external/wpt/css/css-values/ic-unit-011.html [ Failure ] crbug.com/937101 external/wpt/css/css-values/ic-unit-012.html [ Failure ] -crbug.com/937101 external/wpt/css/css-values/ic-unit-013.html [ Failure ] -crbug.com/937101 external/wpt/css/css-values/ic-unit-014.html [ Failure ] crbug.com/937104 external/wpt/css/css-values/lh-unit-002.html [ Failure ] crbug.com/937104 external/wpt/css/css-values/lh-unit-001.html [ Failure ] @@ -6966,9 +6965,6 @@ crbug.com/1341090 external/wpt/webmessaging/with-ports/021.html [ Failure Pass ] crbug.com/1341090 external/wpt/webmessaging/without-ports/021.html [ Failure Pass ] -# Disable test to land a DevTools change -crbug.com/1299832 http/tests/devtools/extensions/extensions-api.js [ Skip ] - # Sheriff 2022-07-07 crbug.com/1339538 [ Mac ] fast/frames/002.html [ Failure Pass ] crbug.com/1339538 [ Linux ] fast/frames/002.html [ Failure Pass ]
diff --git a/third_party/blink/web_tests/external/Version b/third_party/blink/web_tests/external/Version index d1f3986..c861d62 100644 --- a/third_party/blink/web_tests/external/Version +++ b/third_party/blink/web_tests/external/Version
@@ -1 +1 @@ -Version: 9f072679c6f3367ea1685254ff5f5cc84f6e8d9d +Version: 8e5c6c20c3b9ef12d7b0486470fcf87cb160a8ea
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 43321cd..5b7804e 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
@@ -159855,6 +159855,19 @@ {} ] ], + "block-aspect-ratio-050.html": [ + "360c83dfbd3afa1df72d0cc9230a5ae32b4b56d7", + [ + null, + [ + [ + "/css/reference/ref-filled-green-100px-square.xht", + "==" + ] + ], + {} + ] + ], "block-aspect-ratio-with-margin-collapsing-001.html": [ "78a0418fe285da58030cdd863460add0533e6af5", [ @@ -316537,7 +316550,7 @@ [] ], "popup-utils.js": [ - "886a2302cad0ecc182f587e9486196dfdc8725c4", + "f91b8cd56c8c234e84ac667fa2e20b1f9e9f9103", [] ] } @@ -346078,6 +346091,85 @@ {} ] ], + "storage-buckets.https.any.js": [ + "0000adf859aab046bc64a2c45771605675ad09dc", + [ + "IndexedDB/storage-buckets.https.any.html", + { + "script_metadata": [ + [ + "title", + "Buckets API: Tests for indexedDB API." + ], + [ + "global", + "window,worker" + ], + [ + "script", + "resources/support-promises.js" + ] + ] + } + ], + [ + "IndexedDB/storage-buckets.https.any.serviceworker.html", + { + "script_metadata": [ + [ + "title", + "Buckets API: Tests for indexedDB API." + ], + [ + "global", + "window,worker" + ], + [ + "script", + "resources/support-promises.js" + ] + ] + } + ], + [ + "IndexedDB/storage-buckets.https.any.sharedworker.html", + { + "script_metadata": [ + [ + "title", + "Buckets API: Tests for indexedDB API." + ], + [ + "global", + "window,worker" + ], + [ + "script", + "resources/support-promises.js" + ] + ] + } + ], + [ + "IndexedDB/storage-buckets.https.any.worker.html", + { + "script_metadata": [ + [ + "title", + "Buckets API: Tests for indexedDB API." + ], + [ + "global", + "window,worker" + ], + [ + "script", + "resources/support-promises.js" + ] + ] + } + ] + ], "string-list-ordering.htm": [ "ddbbc3036fb0ade4ec2b9da1a219f1c5c689446e", [ @@ -376869,7 +376961,7 @@ ] ], "container-computed.html": [ - "d83f3616400518bcceeb567678211b454eb95324", + "2be304481bac32928a602fadb083222d993a02fe", [ null, {} @@ -376932,7 +377024,7 @@ ] ], "container-parsing.html": [ - "9f1293f51cc7dfc1e22b12f7a8b16feb90e40693", + "44989c225aa3c28d46570eea9351002e6160a742", [ null, {} @@ -376995,7 +377087,7 @@ ] ], "container-type-parsing.html": [ - "34023cbc4f2ad022b10f1b6d311f4a2163a33810", + "5805a927b327eefc1a687db3cdbb8c27c306fb04", [ null, {} @@ -396763,7 +396855,7 @@ ] ], "container-type.html": [ - "c823ffb759894f1a1cbc2a2f095eca9210ba9c84", + "23474abff4b25b994db4b625252ad14e142ccdf0", [ null, {} @@ -480027,8 +480119,18 @@ } ] ], + "popup-hover-hide.tentative.html": [ + "e04c538f24da9aae33a8027cf63a3ea5a11e5197", + [ + null, + { + "testdriver": true, + "timeout": "long" + } + ] + ], "popup-hoverpopup-attribute.tentative.html": [ - "3f1ce38c881574d45a2de8fa3b6cc1b32ebb8ff3", + "b34e6df3f0d11883dac13949e78df609f2aca85e", [ null, {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-contain/container-queries/font-relative-units.html b/third_party/blink/web_tests/external/wpt/css/css-contain/container-queries/font-relative-units.html index b069510..2bd9eff 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-contain/container-queries/font-relative-units.html +++ b/third_party/blink/web_tests/external/wpt/css/css-contain/container-queries/font-relative-units.html
@@ -21,6 +21,11 @@ font-size: 50px; width: 10ch; } + #ic_container { + container-type: inline-size; + font-size: 50px; + width: 10ic; + } @container (width: 1em) { #em_test { color: green } } @@ -33,6 +38,9 @@ @container (width: 10ch) { #ch_test { color: green } } + @container (width: 10ic) { + #ic_test { color: green } + } </style> <div id="em_container"> <div id="em_test"></div> @@ -44,6 +52,9 @@ <div id="ch_container"> <div id="ch_test"></div> </div> +<div id="ic_container"> + <div id="ic_test"></div> +</div> <script> setup(() => assert_implements_container_queries()); @@ -52,4 +63,5 @@ test(() => assert_equals(getComputedStyle(rem_test).color, green), "rem relative inline-size"); test(() => assert_equals(getComputedStyle(ex_test).color, green), "ex relative inline-size"); test(() => assert_equals(getComputedStyle(ch_test).color, green), "ch relative inline-size"); + test(() => assert_equals(getComputedStyle(ic_test).color, green), "ic relative inline-size"); </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-sizing/aspect-ratio/block-aspect-ratio-050.html b/third_party/blink/web_tests/external/wpt/css/css-sizing/aspect-ratio/block-aspect-ratio-050.html new file mode 100644 index 0000000..360c83d --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-sizing/aspect-ratio/block-aspect-ratio-050.html
@@ -0,0 +1,12 @@ +<!DOCTYPE html> +<title>CSS aspect-ratio: Use correct box-sizing when calculating block size</title> +<link rel="help" href="https://drafts.csswg.org/css-sizing-4/#valdef-aspect-ratio-auto--ratio"> +<link rel="help" href="https://drafts.csswg.org/css-sizing-4/#aspect-ratio-minimum"> +<link rel="match" href="../../reference/ref-filled-green-100px-square.xht" /> +<meta name="assert" content="CSS aspect-ratio: Use correct box-sizing when calculating block size."> + +<p>Test passes if there is a filled green square and <strong>no red</strong>.</p> + +<div style="background: green; width: 100px; aspect-ratio: auto 1/1; box-sizing: border-box; padding-top:10px; padding-left: 50px"> + <div style="height: 90px"></div> +</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/mediaqueries/relative-units-005.html b/third_party/blink/web_tests/external/wpt/css/mediaqueries/relative-units-005.html index 91f85ec..8b34474 100644 --- a/third_party/blink/web_tests/external/wpt/css/mediaqueries/relative-units-005.html +++ b/third_party/blink/web_tests/external/wpt/css/mediaqueries/relative-units-005.html
@@ -1,10 +1,11 @@ <!doctype html> -<title>CSS Media Queries Test: ex and ch from initial font</title> +<title>CSS Media Queries Test: ex, ch, and ic from initial font</title> <link rel="help" href="https://drafts.csswg.org/mediaqueries/#units"> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <div id="ex_ref" style="width: 100ex"></div> <div id="ch_ref" style="width: 100ch"></div> +<div id="ic_ref" style="width: 100ic"></div> <script> const viewport_width = document.documentElement.offsetWidth; @@ -19,4 +20,10 @@ const ch_query = `(min-width: ${viewport_ch-0.5}ch) and (max-width: ${viewport_ch+0.5}ch)`; assert_true(matchMedia(ch_query).matches); }, "ch unit in media queries should match initial font"); + + test(() => { + const viewport_ic = (viewport_width * 100) / ic_ref.offsetWidth; + const ic_query = `(min-width: ${viewport_ic-0.5}ic) and (max-width: ${viewport_ic+0.5}ic)`; + assert_true(matchMedia(ic_query).matches); + }, "ic unit in media queries should match initial font"); </script>
diff --git a/third_party/blink/web_tests/external/wpt/svg/types/scripted/SVGLength-ic.html b/third_party/blink/web_tests/external/wpt/svg/types/scripted/SVGLength-ic.html new file mode 100644 index 0000000..ed8a6364 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/svg/types/scripted/SVGLength-ic.html
@@ -0,0 +1,23 @@ +<!DOCTYPE HTML> +<title>SVGLength with 'ic' unit</title> +<link rel="help" href="https://www.w3.org/TR/SVG/types.html#InterfaceSVGLength"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="ic_ref" style="font-family:initial; font-size:20px; width:10ic"></div> +<svg> + <text id="ic_test" x="10ic" style="font-family:initial; font-size:20px"></text> +</svg> +<script> + let ref_width = ic_ref.offsetWidth; + let ic_length = ic_test.x.baseVal[0]; + + test(() => { + assert_equals(ic_length.unitType, SVGLength.SVG_LENGTHTYPE_UNKNOWN); + assert_equals(ic_length.value, ref_width); + }, "ic unit in SVGLength"); + + test(() => { + ic_length.value = ref_width * 2; + assert_equals(ic_length.valueInSpecifiedUnits, 20); + }, "Convert back to ic from new user unit value"); +</script>
diff --git a/third_party/blink/web_tests/http/tests/preload/warning/request-headers.html b/third_party/blink/web_tests/http/tests/preload/warning/request-headers.html deleted file mode 100644 index 2059224..0000000 --- a/third_party/blink/web_tests/http/tests/preload/warning/request-headers.html +++ /dev/null
@@ -1,14 +0,0 @@ -<!doctype html> -<html> -<link rel="preload" as="fetch" crossorigin="anonymous" href="resources/hello.txt"></link> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<body> -<script> -promise_test(async (t) => { - await fetch('resources/hello.txt', {headers: {'foo': 'bar'}}); -}, 'Preload match fails because the request headers do not match (see the console log).'); -</script> -</body> -</html> -
diff --git a/third_party/blink/web_tests/platform/generic/external/wpt/css/css-typed-om/stylevalue-subclasses/numeric-objects/cssUnitValue-expected.txt b/third_party/blink/web_tests/platform/generic/external/wpt/css/css-typed-om/stylevalue-subclasses/numeric-objects/cssUnitValue-expected.txt index 79f57d4..6aef91a 100644 --- a/third_party/blink/web_tests/platform/generic/external/wpt/css/css-typed-om/stylevalue-subclasses/numeric-objects/cssUnitValue-expected.txt +++ b/third_party/blink/web_tests/platform/generic/external/wpt/css/css-typed-om/stylevalue-subclasses/numeric-objects/cssUnitValue-expected.txt
@@ -6,7 +6,7 @@ PASS CSSUnitValue can be constructed with em PASS CSSUnitValue can be constructed with ex PASS CSSUnitValue can be constructed with ch -FAIL CSSUnitValue can be constructed with ic Failed to construct 'CSSUnitValue': Invalid unit: ic +PASS CSSUnitValue can be constructed with ic PASS CSSUnitValue can be constructed with rem FAIL CSSUnitValue can be constructed with lh Failed to construct 'CSSUnitValue': Invalid unit: lh FAIL CSSUnitValue can be constructed with rlh Failed to construct 'CSSUnitValue': Invalid unit: rlh
diff --git a/third_party/blink/web_tests/platform/generic/http/tests/devtools/extensions/extensions-api-expected.txt b/third_party/blink/web_tests/platform/generic/http/tests/devtools/extensions/extensions-api-expected.txt index dd7e0712..974a354 100644 --- a/third_party/blink/web_tests/platform/generic/http/tests/devtools/extensions/extensions-api-expected.txt +++ b/third_party/blink/web_tests/platform/generic/http/tests/devtools/extensions/extensions-api-expected.txt
@@ -18,6 +18,10 @@ reload : <function> } languageServices : { + getWasmGlobal : <function> + getWasmLinearMemory : <function> + getWasmLocal : <function> + getWasmOp : <function> registerLanguageExtensionPlugin : <function> unregisterLanguageExtensionPlugin : <function> }
diff --git a/third_party/blink/web_tests/platform/generic/http/tests/preload/warning/request-headers-expected.txt b/third_party/blink/web_tests/platform/generic/http/tests/preload/warning/request-headers-expected.txt deleted file mode 100644 index 3eebfa3..0000000 --- a/third_party/blink/web_tests/platform/generic/http/tests/preload/warning/request-headers-expected.txt +++ /dev/null
@@ -1,5 +0,0 @@ -CONSOLE WARNING: A preload for 'http://127.0.0.1:8000/preload/warning/resources/hello.txt' is found, but is not used because the request headers do not match. -This is a testharness.js-based test. -PASS Preload match fails because the request headers do not match (see the console log). -Harness: the test ran to completion. -
diff --git a/tools/clang/scripts/package.py b/tools/clang/scripts/package.py index d649835..bd87821 100755 --- a/tools/clang/scripts/package.py +++ b/tools/clang/scripts/package.py
@@ -4,13 +4,12 @@ # found in the LICENSE file. """This script will check out llvm and clang, and then package the results up -to a tgz file.""" - -from __future__ import print_function +to a number of tarballs.""" import argparse import fnmatch import itertools +import lzma import multiprocessing.dummy import os import platform @@ -101,16 +100,24 @@ if not os.path.islink(file_path): subprocess.call(['strip', file_path]) - with tarfile.open(archive_path, 'w:gz') as tar: - for f in os.listdir(directory_path): - tar.add(os.path.join(directory_path, f), - arcname=f, filter=PrintTarProgress) + with tarfile.open(archive_path + '.tar.xz', + 'w:xz', + preset=9 | lzma.PRESET_EXTREME) as tar_xz: + with tarfile.open(archive_path + '.tgz', 'w:gz') as tar_gz: + for f in sorted(os.listdir(directory_path)): + tar_xz.add(os.path.join(directory_path, f), + arcname=f, + filter=PrintTarProgress) + # TODO(crbug.com/1261812) Stop making gzip'ed archives once the + # goma/reclient push processes are updated to consume the .xz files + # instead. + tar_gz.add(os.path.join(directory_path, f), arcname=f) def MaybeUpload(do_upload, filename, gcs_platform, extra_gsutil_args=[]): gsutil_args = ['cp'] + extra_gsutil_args + [ '-n', '-a', 'public-read', filename, - 'gs://chromium-browser-clang-staging/%s/%s' % (gcs_platform, filename) + 'gs://chromium-browser-clang-staging/%s/' % (gcs_platform) ] if do_upload: print('Uploading %s to Google Cloud Storage...' % filename) @@ -535,8 +542,8 @@ old, os.path.join(pdir, 'lib', 'clang', RELEASE_VERSION, 'lib', new)) # Create main archive. - PackageInArchive(pdir, pdir + '.tgz') - MaybeUpload(args.upload, pdir + '.tgz', gcs_platform) + PackageInArchive(pdir, pdir) + MaybeUpload(args.upload, pdir + '.t*z', gcs_platform) # Upload build log next to it. os.rename('buildlog.txt', pdir + '-buildlog.txt') @@ -553,8 +560,8 @@ for filename in ['llvm-cov', 'llvm-profdata']: shutil.copy(os.path.join(LLVM_RELEASE_DIR, 'bin', filename + exe_ext), os.path.join(code_coverage_dir, 'bin')) - PackageInArchive(code_coverage_dir, code_coverage_dir + '.tgz') - MaybeUpload(args.upload, code_coverage_dir + '.tgz', gcs_platform) + PackageInArchive(code_coverage_dir, code_coverage_dir) + MaybeUpload(args.upload, code_coverage_dir + '.t*z', gcs_platform) # Zip up llvm-objdump and related tools for sanitizer coverage and Supersize. objdumpdir = 'llvmobjdump-' + stamp @@ -573,8 +580,8 @@ f.write('\n') if sys.platform != 'win32': os.symlink('llvm-objdump', os.path.join(objdumpdir, 'bin', 'llvm-otool')) - PackageInArchive(objdumpdir, objdumpdir + '.tgz') - MaybeUpload(args.upload, objdumpdir + '.tgz', gcs_platform) + PackageInArchive(objdumpdir, objdumpdir) + MaybeUpload(args.upload, objdumpdir + '.t*z', gcs_platform) # Zip up clang-tidy for users who opt into it, and Tricium. clang_tidy_dir = 'clang-tidy-' + stamp @@ -582,8 +589,8 @@ os.makedirs(os.path.join(clang_tidy_dir, 'bin')) shutil.copy(os.path.join(LLVM_RELEASE_DIR, 'bin', 'clang-tidy' + exe_ext), os.path.join(clang_tidy_dir, 'bin')) - PackageInArchive(clang_tidy_dir, clang_tidy_dir + '.tgz') - MaybeUpload(args.upload, clang_tidy_dir + '.tgz', gcs_platform) + PackageInArchive(clang_tidy_dir, clang_tidy_dir) + MaybeUpload(args.upload, clang_tidy_dir + '.t*z', gcs_platform) # Zip up clang-format so we can update it (separately from the clang roll). clang_format_dir = 'clang-format-' + stamp @@ -591,8 +598,8 @@ os.makedirs(os.path.join(clang_format_dir, 'bin')) shutil.copy(os.path.join(LLVM_RELEASE_DIR, 'bin', 'clang-format' + exe_ext), os.path.join(clang_format_dir, 'bin')) - PackageInArchive(clang_format_dir, clang_format_dir + '.tgz') - MaybeUpload(args.upload, clang_format_dir + '.tgz', gcs_platform) + PackageInArchive(clang_format_dir, clang_format_dir) + MaybeUpload(args.upload, clang_format_dir + '.t*z', gcs_platform) # Zip up clang-libs for users who opt into it. We want Clang and LLVM headers # and libs, as well as a couple binaries. The LLVM parts are needed by the @@ -643,8 +650,8 @@ if fnmatch.fnmatch(lib_path, lib_want): shutil.copy(os.path.join(LLVM_BOOTSTRAP_DIR, 'lib', lib_path), os.path.join(clang_libs_dir, 'lib')) - PackageInArchive(clang_libs_dir, clang_libs_dir + '.tgz') - MaybeUpload(args.upload, clang_libs_dir + '.tgz', gcs_platform) + PackageInArchive(clang_libs_dir, clang_libs_dir) + MaybeUpload(args.upload, clang_libs_dir + '.t*z', gcs_platform) if sys.platform == 'darwin': # dsymutil isn't part of the main zip, and it gets periodically @@ -655,8 +662,8 @@ os.makedirs(os.path.join(dsymdir, 'bin')) shutil.copy(os.path.join(LLVM_RELEASE_DIR, 'bin', 'dsymutil'), os.path.join(dsymdir, 'bin')) - PackageInArchive(dsymdir, dsymdir + '.tgz') - MaybeUpload(args.upload, dsymdir + '.tgz', gcs_platform) + PackageInArchive(dsymdir, dsymdir) + MaybeUpload(args.upload, dsymdir + '.t*z', gcs_platform) # Zip up the translation_unit tool. translation_unit_dir = 'translation_unit-' + stamp @@ -665,8 +672,8 @@ shutil.copy(os.path.join(LLVM_RELEASE_DIR, 'bin', 'translation_unit' + exe_ext), os.path.join(translation_unit_dir, 'bin')) - PackageInArchive(translation_unit_dir, translation_unit_dir + '.tgz') - MaybeUpload(args.upload, translation_unit_dir + '.tgz', gcs_platform) + PackageInArchive(translation_unit_dir, translation_unit_dir) + MaybeUpload(args.upload, translation_unit_dir + '.t*z', gcs_platform) # Zip up the libclang binaries. libclang_dir = 'libclang-' + stamp @@ -680,8 +687,8 @@ shutil.copy(os.path.join(LLVM_DIR, 'clang', 'bindings', 'python', 'clang', filename), os.path.join(libclang_dir, 'bindings', 'python', 'clang')) - PackageInArchive(libclang_dir, libclang_dir + '.tgz') - MaybeUpload(args.upload, libclang_dir + '.tgz', gcs_platform) + PackageInArchive(libclang_dir, libclang_dir) + MaybeUpload(args.upload, libclang_dir + '.t*z', gcs_platform) if sys.platform == 'win32' and args.upload: binaries = [f for f in want if f.endswith('.exe') or f.endswith('.dll')]
diff --git a/tools/clang/scripts/update.py b/tools/clang/scripts/update.py index f25be7d1..faf7ec7 100755 --- a/tools/clang/scripts/update.py +++ b/tools/clang/scripts/update.py
@@ -36,7 +36,7 @@ # Reverting problematic clang rolls is safe, though. # This is the output of `git describe` and is usable as a commit-ish. CLANG_REVISION = 'llvmorg-16-init-572-gdde41c6c' -CLANG_SUB_REVISION = 1 +CLANG_SUB_REVISION = 2 PACKAGE_VERSION = '%s-%s' % (CLANG_REVISION, CLANG_SUB_REVISION) RELEASE_VERSION = '16.0.0' @@ -182,7 +182,7 @@ def DownloadAndUnpackPackage(package_file, output_dir, host_os): - cds_file = "%s-%s.tgz" % (package_file, PACKAGE_VERSION) + cds_file = "%s-%s.tar.xz" % (package_file, PACKAGE_VERSION) cds_full_url = GetPlatformUrlPrefix(host_os) + cds_file try: DownloadAndUnpack(cds_full_url, output_dir) @@ -194,7 +194,7 @@ def DownloadAndUnpackClangMacRuntime(output_dir): - cds_file = "clang-%s.tgz" % PACKAGE_VERSION + cds_file = "clang-%s.tar.xz" % PACKAGE_VERSION # We run this only for the runtime libraries, and 'mac' and 'mac-arm64' both # have the same (universal) runtime libraries. It doesn't matter which one # we download here. @@ -213,7 +213,7 @@ # TODO(hans): Create a clang-win-runtime package instead. def DownloadAndUnpackClangWinRuntime(output_dir): - cds_file = "clang-%s.tgz" % PACKAGE_VERSION + cds_file = "clang-%s.tar.xz" % PACKAGE_VERSION cds_full_url = GetPlatformUrlPrefix('win') + cds_file path_prefixes = [ 'lib/clang/' + RELEASE_VERSION + '/lib/windows', 'bin/llvm-symbolizer.exe'
diff --git a/tools/gritsettings/resource_ids.spec b/tools/gritsettings/resource_ids.spec index 1bc95f7..0bde43a 100644 --- a/tools/gritsettings/resource_ids.spec +++ b/tools/gritsettings/resource_ids.spec
@@ -100,7 +100,7 @@ "includes": [1220], "structures": [1240], }, - "<(SHARED_INTERMEDIATE_DIR)/chrome/browser/resources/feedback_webui/resources.grd": { + "<(SHARED_INTERMEDIATE_DIR)/chrome/browser/resources/feedback/resources.grd": { "META": {"sizes": {"includes": [20],}}, "includes": [1260], }, @@ -283,7 +283,7 @@ "META": {"sizes": {"includes": [1000],}}, "includes": [1940], }, - "<(SHARED_INTERMEDIATE_DIR)/chrome/browser/resources/settings/settings_resources.grd": { + "<(SHARED_INTERMEDIATE_DIR)/chrome/browser/resources/settings/resources.grd": { "META": {"sizes": {"includes": [500],}}, "includes": [1960], },
diff --git a/tools/json_schema_compiler/test/additional_properties_unittest.cc b/tools/json_schema_compiler/test/additional_properties_unittest.cc index fdda776..4bded88 100644 --- a/tools/json_schema_compiler/test/additional_properties_unittest.cc +++ b/tools/json_schema_compiler/test/additional_properties_unittest.cc
@@ -27,25 +27,27 @@ EXPECT_EQ(type->additional_properties, type_value); } { - auto type_value = std::make_unique<base::DictionaryValue>(); - type_value->SetInteger("string", 3); + base::Value::Dict type_dict; + type_dict.Set("string", 3); + base::Value type_value(std::move(type_dict)); auto type = std::make_unique<ap::AdditionalPropertiesType>(); EXPECT_FALSE( - ap::AdditionalPropertiesType::Populate(*type_value, type.get())); + ap::AdditionalPropertiesType::Populate(type_value, type.get())); } } TEST(JsonSchemaCompilerAdditionalPropertiesTest, AdditionalPropertiesParamsCreate) { - auto param_object_value = std::make_unique<base::DictionaryValue>(); - param_object_value->SetString("str", "a"); - param_object_value->SetInteger("num", 1); + base::Value::Dict param_object_dict; + param_object_dict.Set("str", "a"); + param_object_dict.Set("num", 1); + base::Value param_object_value(std::move(param_object_dict)); base::Value::List params_value; - params_value.Append(param_object_value->Clone()); + params_value.Append(param_object_value.Clone()); std::unique_ptr<ap::AdditionalProperties::Params> params( ap::AdditionalProperties::Params::Create(params_value)); EXPECT_TRUE(params.get()); - EXPECT_EQ(params->param_object.additional_properties, *param_object_value); + EXPECT_EQ(params->param_object.additional_properties, param_object_value); } TEST(JsonSchemaCompilerAdditionalPropertiesTest,
diff --git a/tools/json_schema_compiler/test/any_unittest.cc b/tools/json_schema_compiler/test/any_unittest.cc index d6ed9f6..45bd203 100644 --- a/tools/json_schema_compiler/test/any_unittest.cc +++ b/tools/json_schema_compiler/test/any_unittest.cc
@@ -12,19 +12,21 @@ TEST(JsonSchemaCompilerAnyTest, AnyTypePopulate) { { test::api::any::AnyType any_type; - auto any_type_value = std::make_unique<base::DictionaryValue>(); - any_type_value->SetString("any", "value"); - EXPECT_TRUE(test::api::any::AnyType::Populate(*any_type_value, &any_type)); + base::Value::Dict any_type_dict; + any_type_dict.Set("any", "value"); + base::Value any_type_value(std::move(any_type_dict)); + EXPECT_TRUE(test::api::any::AnyType::Populate(any_type_value, &any_type)); std::unique_ptr<base::Value> any_type_to_value(any_type.ToValue()); - EXPECT_EQ(*any_type_value, *any_type_to_value.get()); + EXPECT_EQ(any_type_value, *any_type_to_value.get()); } { test::api::any::AnyType any_type; - auto any_type_value = std::make_unique<base::DictionaryValue>(); - any_type_value->SetInteger("any", 5); - EXPECT_TRUE(test::api::any::AnyType::Populate(*any_type_value, &any_type)); + base::Value::Dict any_type_dict; + any_type_dict.Set("any", 5); + base::Value any_type_value(std::move(any_type_dict)); + EXPECT_TRUE(test::api::any::AnyType::Populate(any_type_value, &any_type)); std::unique_ptr<base::Value> any_type_to_value(any_type.ToValue()); - EXPECT_EQ(*any_type_value, *any_type_to_value.get()); + EXPECT_EQ(any_type_value, *any_type_to_value.get()); } }
diff --git a/tools/json_schema_compiler/test/choices_unittest.cc b/tools/json_schema_compiler/test/choices_unittest.cc index a1898b8..1a64a276 100644 --- a/tools/json_schema_compiler/test/choices_unittest.cc +++ b/tools/json_schema_compiler/test/choices_unittest.cc
@@ -120,9 +120,10 @@ for (const auto& string : strings) strings_value.Append(string); - base::DictionaryValue value; - value.SetInteger("integers", 4); - value.SetKey("strings", std::move(strings_value)); + base::Value::Dict dict; + dict.Set("integers", 4); + dict.Set("strings", std::move(strings_value)); + base::Value value(std::move(dict)); choices::ChoiceType out; ASSERT_TRUE(choices::ChoiceType::Populate(value, &out)); @@ -141,9 +142,10 @@ strings_value.Append("of"); strings_value.Append("strings"); - base::DictionaryValue value; - value.SetInteger("integers", 5); - value.SetKey("strings", std::move(strings_value)); + base::Value::Dict dict; + dict.Set("integers", 5); + dict.Set("strings", std::move(strings_value)); + base::Value value(std::move(dict)); choices::ChoiceType out; ASSERT_TRUE(choices::ChoiceType::Populate(value, &out));
diff --git a/tools/json_schema_compiler/test/crossref_unittest.cc b/tools/json_schema_compiler/test/crossref_unittest.cc index f8882ce..39b76a6 100644 --- a/tools/json_schema_compiler/test/crossref_unittest.cc +++ b/tools/json_schema_compiler/test/crossref_unittest.cc
@@ -19,7 +19,7 @@ base::DictionaryValue CreateTestTypeValue() { base::DictionaryValue value; - value.SetDouble("number", 1.1); + value.GetDict().Set("number", 1.1); value.SetInteger("integer", 4); value.SetString("string", "bling"); value.SetBoolean("boolean", true);
diff --git a/tools/json_schema_compiler/test/functions_on_types_unittest.cc b/tools/json_schema_compiler/test/functions_on_types_unittest.cc index 0e047a3..a779c53 100644 --- a/tools/json_schema_compiler/test/functions_on_types_unittest.cc +++ b/tools/json_schema_compiler/test/functions_on_types_unittest.cc
@@ -53,7 +53,7 @@ TEST(JsonSchemaCompilerFunctionsOnTypesTest, StorageAreaGetResultCreate) { functions_on_types::StorageArea::Get::Results::Items items; - items.additional_properties.SetDouble("asdf", 0.1); + items.additional_properties.GetDict().Set("asdf", 0.1); items.additional_properties.SetString("sdfg", "zxcv"); base::Value results( functions_on_types::StorageArea::Get::Results::Create(items));
diff --git a/tools/json_schema_compiler/test/idl_schemas_unittest.cc b/tools/json_schema_compiler/test/idl_schemas_unittest.cc index 8671b5fa..b1c3d61d 100644 --- a/tools/json_schema_compiler/test/idl_schemas_unittest.cc +++ b/tools/json_schema_compiler/test/idl_schemas_unittest.cc
@@ -48,14 +48,14 @@ // Test Function3, which takes a MyType1 parameter. list.clear(); - base::DictionaryValue tmp; - tmp.SetInteger("x", 17); - tmp.SetString("y", "hello"); - tmp.SetString("z", "zstring"); - tmp.SetString("a", "astring"); - tmp.SetString("b", "bstring"); - tmp.SetString("c", "cstring"); - list.Append(std::move(tmp)); + base::Value::Dict tmp; + tmp.Set("x", 17); + tmp.Set("y", "hello"); + tmp.Set("z", "zstring"); + tmp.Set("a", "astring"); + tmp.Set("b", "bstring"); + tmp.Set("c", "cstring"); + list.Append(base::Value(std::move(tmp))); std::unique_ptr<Function3::Params> f3_params = Function3::Params::Create(list); EXPECT_EQ(17, f3_params->arg.x); @@ -109,14 +109,14 @@ Function9::Params::Create(list); EXPECT_EQ(nullptr, f9_params->arg.get()); list.clear(); - base::DictionaryValue tmp; - tmp.SetInteger("x", 17); - tmp.SetString("y", "hello"); - tmp.SetString("z", "zstring"); - tmp.SetString("a", "astring"); - tmp.SetString("b", "bstring"); - tmp.SetString("c", "cstring"); - list.Append(std::move(tmp)); + base::Value::Dict tmp; + tmp.Set("x", 17); + tmp.Set("y", "hello"); + tmp.Set("z", "zstring"); + tmp.Set("a", "astring"); + tmp.Set("b", "bstring"); + tmp.Set("c", "cstring"); + list.Append(base::Value(std::move(tmp))); f9_params = Function9::Params::Create(list); ASSERT_TRUE(f9_params->arg.get() != nullptr); MyType1* t1 = f9_params->arg.get(); @@ -191,8 +191,9 @@ EXPECT_EQ(7, b2.x->GetInt()); // Test the params to the ObjectFunction1 function. - base::DictionaryValue icon_props; - icon_props.SetString("hello", "world"); + base::Value::Dict icon_props_dict; + icon_props_dict.Set("hello", "world"); + base::Value icon_props(std::move(icon_props_dict)); ObjectFunction1::Params::Icon icon; EXPECT_TRUE(ObjectFunction1::Params::Icon::Populate(icon_props, &icon)); base::Value::List list;
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 12c1fb3..6010575f 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -53629,6 +53629,12 @@ <int value="14" label="Add language to 'Always Translate' list"/> <int value="15" label="Remove site from 'Never translate sites' list"/> <int value="16" label="Restart Chrome for split install"/> + <int value="17" label="Spell check enabled globally"/> + <int value="18" label="Spell check disabled globally"/> + <int value="19" label="Spell check enabled for a language"/> + <int value="20" label="Spell check disabled for a language"/> + <int value="21" label="Basic spell check selected"/> + <int value="22" label="Enhanced spell check selected"/> </enum> <enum name="LanguageSettingsAppLanguagePromptAction"> @@ -56293,6 +56299,7 @@ label="SafeBrowsingkRealTimeUrlLookupEnterpriseGaEndpoint:disabled"/> <int value="-1621963267" label="EnableAssistantLauncherUI:enabled"/> <int value="-1620942609" label="MuteCompromisedPasswords:enabled"/> + <int value="-1620860283" label="KioskEnableAppService:disabled"/> <int value="-1620804800" label="NoScriptPreviews:disabled"/> <int value="-1620568042" label="FeaturePolicy:disabled"/> <int value="-1620425260" label="ShelfPalmRejectionSwipeOffset:disabled"/> @@ -57454,6 +57461,7 @@ <int value="-932164609" label="ProcessSharingWithDefaultSiteInstances:enabled"/> <int value="-931494909" label="DefaultLinkCapturingInBrowser:disabled"/> + <int value="-930478115" label="CameraAppDocScanDlc:enabled"/> <int value="-929944930" label="AutofillRationalizeRepeatedServerPredictions:disabled"/> <int value="-928138978" label="IPH_DemoMode:disabled"/> @@ -61290,6 +61298,7 @@ <int value="1534561775" label="HeavyAdPrivacyMitigations:disabled"/> <int value="1536568742" label="SyncAndroidPromosWithIllustration:enabled"/> <int value="1536921097" label="NavigationMojoResponse:disabled"/> + <int value="1537693783" label="KioskEnableAppService:enabled"/> <int value="1538685213" label="DownloadHomeV2:enabled"/> <int value="1538690515" label="OneGoogleBarOnLocalNtp:enabled"/> <int value="1540395380" label="WebContentsOcclusion:enabled"/> @@ -61590,6 +61599,7 @@ label="AutofillSuggestVirtualCardsOnIncompleteForm:disabled"/> <int value="1742398600" label="OmniboxUIExperimentBoldUserTextOnSearchSuggestions:enabled"/> + <int value="1743603853" label="CameraAppDocScanDlc:disabled"/> <int value="1745053254" label="ClickToCallOpenDialerDirectly:enabled"/> <int value="1747279677" label="disable-delegated-renderer"/> <int value="1748481830" label="AppManagement:enabled"/> @@ -64578,6 +64588,7 @@ <int value="9" label="RouteAlreadyExists"/> <int value="10" label="DesktopPickerFailed"/> <int value="11" label="RouteAlreadyTerminated"/> + <int value="12" label="RedundantRequest"/> </enum> <enum name="MediaRouteProviderVersion"> @@ -64736,14 +64747,6 @@ <int value="10" label="Utility process error"/> </enum> -<enum name="MediaRouterDialTerminateRouteResult"> - <int value="0" label="Success"/> - <int value="1" label="Route not found"/> - <int value="2" label="Sink not found"/> - <int value="3" label="Stop app failed"/> - <int value="4" label="App already terminated"/> -</enum> - <enum name="MediaRouterIconState"> <int value="0" label="Ephemeral"/> <int value="1" label="Pinned"/> @@ -76014,10 +76017,14 @@ </enum> <enum name="PasswordStoreAndroidBackendAPIError"> + <int value="4" label="SIGN_IN_REQUIRED"/> + <int value="5" label="INVALID_ACCOUNT"/> + <int value="6" label="RESOLUTION_REQUIRED"/> <int value="7" label="NETWORK_ERROR"/> <int value="8" label="INTERNAL_ERROR"/> <int value="10" label="DEVELOPER_ERROR"/> <int value="17" label="API_NOT_CONNECTED"/> + <int value="19" label="REMOTE_EXCEPTION"/> <int value="20" label="CONNECTION_SUSPENDED_DURING_CALL"/> <int value="22" label="RECONNECTION_TIMED_OUT"/> <int value="11000" label="PASSPHRASE_REQUIRED"/> @@ -76037,6 +76044,33 @@ <int value="43509" label="LEAK_CHECK_SERVICE_RESOURCE_EXHAUSTED"/> </enum> +<enum name="PasswordStoreAndroidBackendConnectionResultCode"> + <int value="0" label="SUCCESS"/> + <int value="1" label="SERVICE_MISSING"/> + <int value="2" label="SERVICE_VERSION_UPDATE_REQUIRED"/> + <int value="3" label="SERVICE_DISABLED"/> + <int value="4" label="SIGN_IN_REQUIRED"/> + <int value="5" label="INVALID_ACCOUNT"/> + <int value="6" label="RESOLUTION_REQUIRED"/> + <int value="7" label="NETWORK_ERROR"/> + <int value="8" label="INTERNAL_ERROR"/> + <int value="9" label="SERVICE_INVALID"/> + <int value="10" label="DEVELOPER_ERROR"/> + <int value="11" label="LICENSE_CHECK_FAILED"/> + <int value="13" label="CANCELED"/> + <int value="14" label="TIMEOUT"/> + <int value="15" label="INTERRUPTED"/> + <int value="16" label="API_UNAVAILABLE"/> + <int value="17" label="SIGN_IN_FAILED"/> + <int value="18" label="SERVICE_UPDATING"/> + <int value="19" label="SERVICE_MISSING_PERMISSION"/> + <int value="20" label="RESTRICTED_PROFILE"/> + <int value="21" label="API_VERSION_UPDATE_REQUIRED"/> + <int value="22" label="RESOLUTION_ACTIVITY_NOT_FOUND"/> + <int value="23" label="API_DISABLED"/> + <int value="24" label="API_DISABLED_FOR_CONNECTION"/> +</enum> + <enum name="PasswordStoreAndroidBackendError"> <int value="0" label="Error can't be categorized."/> <int value="1" label="API was called without a context."/> @@ -101494,6 +101528,7 @@ <int value="31" label="Ad personalization settings opened"/> <int value="32" label="AboutThisSite 'more about' link opened"/> <int value="33" label="Cookies subpage opened"/> + <int value="34" label="Cookies settings opened"/> </enum> <enum name="WebSiteSettingsAllSitesAction">
diff --git a/tools/metrics/histograms/metadata/media/histograms.xml b/tools/metrics/histograms/metadata/media/histograms.xml index 4bbb9a3c..c0bb0e6 100644 --- a/tools/metrics/histograms/metadata/media/histograms.xml +++ b/tools/metrics/histograms/metadata/media/histograms.xml
@@ -6051,17 +6051,6 @@ </summary> </histogram> -<histogram name="MediaRouter.Dial.TerminateRoute" - enum="MediaRouterDialTerminateRouteResult" expires_after="2022-08-14"> - <owner>takumif@chromium.org</owner> - <owner>mfoltz@chromium.org</owner> - <owner>openscreen-eng@google.com</owner> - <summary> - The result of a DIAL TerminateRoute request. Recorded the user requests to - terminate a DIAL media route. - </summary> -</histogram> - <histogram name="MediaRouter.Icon.Click.Location" enum="MediaRouterDialogActivationLocation" expires_after="2022-12-25"> <owner>takumif@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/oobe/histograms.xml b/tools/metrics/histograms/metadata/oobe/histograms.xml index ec6281a..9af1f07 100644 --- a/tools/metrics/histograms/metadata/oobe/histograms.xml +++ b/tools/metrics/histograms/metadata/oobe/histograms.xml
@@ -404,7 +404,7 @@ <histogram name="OOBE.MarketingOptInScreen.BackendConnector.{OOBEMarketingCountry}" - enum="MarketingOptInBackendConnectorEvent" expires_after="2022-11-30"> + enum="MarketingOptInBackendConnectorEvent" expires_after="2023-08-01"> <owner>rrsilva@google.com</owner> <owner>cros-oac@google.com</owner> <summary> @@ -417,7 +417,7 @@ </histogram> <histogram name="OOBE.MarketingOptInScreen.Event.{OOBEMarketingCountry}" - enum="MarketingOptInScreenEvent" expires_after="2022-04-24"> + enum="MarketingOptInScreenEvent" expires_after="2023-08-01"> <owner>rrsilva@google.com</owner> <owner>cros-oac@google.com</owner> <summary> @@ -428,7 +428,7 @@ </histogram> <histogram name="OOBE.MarketingOptInScreen.GeolocationResolve" - enum="MarketingOptInGeolocationEvent" expires_after="2022-11-30"> + enum="MarketingOptInGeolocationEvent" expires_after="2023-08-01"> <owner>rrsilva@google.com</owner> <owner>cros-oac@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/password/histograms.xml b/tools/metrics/histograms/metadata/password/histograms.xml index dd4b5203..95e2dfb 100644 --- a/tools/metrics/histograms/metadata/password/histograms.xml +++ b/tools/metrics/histograms/metadata/password/histograms.xml
@@ -2407,6 +2407,35 @@ </histogram> <histogram + name="PasswordManager.PasswordStoreAndroidBackend{Function}{UnenrollmentFromUPM}.ConnectionResultCode" + enum="PasswordStoreAndroidBackendConnectionResultCode" expires_after="M110"> + <owner>maxan@google.com</owner> + <owner>vasilii@chromium.org</owner> + <summary> + The connection result status code returned by the GMS Core ChromeSync 1P + API{Function}. Recorded when the asynchronous job has returned with error + and only if ConnectionResult was set on the returned error. + {UnenrollmentFromUPM} + </summary> + <token key="Function"> + <variant name=""/> + <variant name=".AddLoginAsync" summary="for AddLoginAsync"/> + <variant name=".GetAllLoginsAsync" summary="for GetAllLoginsAsync"/> + <variant name=".GetAutofillableLoginsAsync" + summary="for GetAutofillableLoginsAsync"/> + <variant name=".GetLoginsAsync" summary="for GetLoginsAsync"/> + <variant name=".RemoveLoginAsync" summary="for RemoveLoginAsync"/> + <variant name=".UpdateLoginAsync" summary="for UpdateLoginAsync"/> + </token> + <token key="UnenrollmentFromUPM"> + <variant name=""/> + <variant name=".UnenrolledFromUPM" + summary="Recorded for clients unenrolled from UnifiedPasswordManager + after experiencing an error."/> + </token> +</histogram> + +<histogram name="PasswordManager.PasswordStoreAndroidBackend{Function}{UnenrollmentFromUPM}.ErrorCode" enum="PasswordStoreAndroidBackendError" expires_after="M110"> <owner>fhorschig@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/sync/histograms.xml b/tools/metrics/histograms/metadata/sync/histograms.xml index f5d44a9d..a5d3b38 100644 --- a/tools/metrics/histograms/metadata/sync/histograms.xml +++ b/tools/metrics/histograms/metadata/sync/histograms.xml
@@ -1025,7 +1025,7 @@ </histogram> <histogram name="Sync.Startup.DeferredInitTrigger" - enum="SyncDeferredInitTrigger" expires_after="2022-08-28"> + enum="SyncDeferredInitTrigger" expires_after="2023-08-28"> <owner>mastiz@chromium.org</owner> <owner>treib@chromium.org</owner> <component>Services>Sync</component>
diff --git a/ui/accessibility/ax_computed_node_data.cc b/ui/accessibility/ax_computed_node_data.cc index f08b4472..1a6fe8b8 100644 --- a/ui/accessibility/ax_computed_node_data.cc +++ b/ui/accessibility/ax_computed_node_data.cc
@@ -25,22 +25,59 @@ AXComputedNodeData::~AXComputedNodeData() = default; int AXComputedNodeData::GetOrComputeUnignoredIndexInParent() const { - DCHECK(!owner_->IsIgnored()); + DCHECK(!owner_->IsIgnored()) + << "Ignored nodes cannot have an `unignored index in parent`.\n" + << *owner_; if (unignored_index_in_parent_) return *unignored_index_in_parent_; - if (const AXNode* unignored_parent = owner_->GetUnignoredParent()) { + if (const AXNode* unignored_parent = SlowGetUnignoredParent()) { + DCHECK_NE(unignored_parent->id(), kInvalidAXNodeID) + << "All nodes should have a valid ID.\n" + << *owner_; unignored_parent->GetComputedNodeData().ComputeUnignoredValues(); } else { // This should be the root node and, by convention, we assign it an // index-in-parent of 0. unignored_index_in_parent_ = 0; + unignored_parent_id_ = kInvalidAXNodeID; } return *unignored_index_in_parent_; } +AXNodeID AXComputedNodeData::GetOrComputeUnignoredParentID() const { + if (unignored_parent_id_) + return *unignored_parent_id_; + + if (const AXNode* unignored_parent = SlowGetUnignoredParent()) { + DCHECK_NE(unignored_parent->id(), kInvalidAXNodeID) + << "All nodes should have a valid ID.\n" + << *owner_; + unignored_parent_id_ = unignored_parent->id(); + } else { + // This should be the root node and, by convention, we assign it an + // index-in-parent of 0. + DCHECK(!owner_->GetParent()) + << "If `unignored_parent` is nullptr, then this should be the " + "rootnode, since in all trees the rootnode should be unignored.\n" + << *owner_; + unignored_index_in_parent_ = 0; + unignored_parent_id_ = kInvalidAXNodeID; + } + return *unignored_parent_id_; +} + +AXNode* AXComputedNodeData::GetOrComputeUnignoredParent() const { + DCHECK(owner_->tree()) + << "All nodes should be owned by an accessibility tree.\n" + << *owner_; + return owner_->tree()->GetFromId(GetOrComputeUnignoredParentID()); +} + int AXComputedNodeData::GetOrComputeUnignoredChildCount() const { - DCHECK(!owner_->IsIgnored()); + DCHECK(!owner_->IsIgnored()) + << "Ignored nodes cannot have an `unignored child count`.\n" + << *owner_; if (!unignored_child_count_) ComputeUnignoredValues(); return *unignored_child_count_; @@ -48,12 +85,20 @@ const std::vector<AXNodeID>& AXComputedNodeData::GetOrComputeUnignoredChildIDs() const { - DCHECK(!owner_->IsIgnored()); + DCHECK(!owner_->IsIgnored()) + << "Ignored nodes cannot have `unignored child IDs`.\n" + << *owner_; if (!unignored_child_ids_) ComputeUnignoredValues(); return *unignored_child_ids_; } +bool AXComputedNodeData::GetOrComputeIsDescendantOfPlatformLeaf() const { + if (!is_descendant_of_leaf_) + ComputeIsDescendantOfPlatformLeaf(); + return *is_descendant_of_leaf_; +} + bool AXComputedNodeData::HasOrCanComputeAttribute( const ax::mojom::StringAttribute attribute) const { if (owner_->data().HasStringAttribute(attribute)) @@ -235,12 +280,18 @@ } void AXComputedNodeData::ComputeUnignoredValues( + AXNodeID unignored_parent_id, int starting_index_in_parent) const { + DCHECK_GE(starting_index_in_parent, 0); // Reset any previously computed values. unignored_index_in_parent_ = absl::nullopt; + unignored_parent_id_ = absl::nullopt; unignored_child_count_ = absl::nullopt; unignored_child_ids_ = absl::nullopt; + AXNodeID unignored_parent_id_for_child = unignored_parent_id; + if (!owner_->IsIgnored()) + unignored_parent_id_for_child = owner_->id(); int unignored_child_count = 0; std::vector<AXNodeID> unignored_child_ids; for (auto iter = owner_->AllChildrenBegin(); iter != owner_->AllChildrenEnd(); @@ -250,7 +301,8 @@ if (iter->IsIgnored()) { // Skip the ignored node and recursively look at its children. - computed_data.ComputeUnignoredValues(new_index_in_parent); + computed_data.ComputeUnignoredValues(unignored_parent_id_for_child, + new_index_in_parent); DCHECK(computed_data.unignored_child_count_); unignored_child_count += *computed_data.unignored_child_count_; DCHECK(computed_data.unignored_child_ids_); @@ -258,18 +310,50 @@ computed_data.unignored_child_ids_->begin(), computed_data.unignored_child_ids_->end()); } else { + // Setting `unignored_index_in_parent_` and `unignored_parent_id_` is the + // responsibility of the parent node, since only the parent node can + // calculate these values. This is in contrast to `unignored_child_count_` + // and `unignored_child_ids_` that are only set if this method is called + // on the node itself. + computed_data.unignored_index_in_parent_ = new_index_in_parent; + if (unignored_parent_id_for_child != kInvalidAXNodeID) + computed_data.unignored_parent_id_ = unignored_parent_id_for_child; + ++unignored_child_count; unignored_child_ids.push_back(iter->id()); - computed_data.unignored_index_in_parent_ = new_index_in_parent; } } + if (unignored_parent_id != kInvalidAXNodeID) + unignored_parent_id_ = unignored_parent_id; // Ignored nodes store unignored child information in order to propagate it to - // their parents, but do not expose it directly. + // their parents, but do not expose it directly. The latter is guarded via a + // DCHECK. unignored_child_count_ = unignored_child_count; unignored_child_ids_ = unignored_child_ids; } +AXNode* AXComputedNodeData::SlowGetUnignoredParent() const { + AXNode* unignored_parent = owner_->GetParent(); + while (unignored_parent && unignored_parent->IsIgnored()) + unignored_parent = unignored_parent->GetParent(); + return unignored_parent; +} + +void AXComputedNodeData::ComputeIsDescendantOfPlatformLeaf() const { + is_descendant_of_leaf_ = false; + for (const AXNode* ancestor = GetOrComputeUnignoredParent(); ancestor; + ancestor = + ancestor->GetComputedNodeData().GetOrComputeUnignoredParent()) { + if (ancestor->GetComputedNodeData().is_descendant_of_leaf_.value_or( + false) || + ancestor->IsLeaf()) { + is_descendant_of_leaf_ = true; + return; + } + } +} + void AXComputedNodeData::ComputeLineOffsetsIfNeeded() const { if (line_starts_ || line_ends_) { DCHECK_EQ(line_starts_->size(), line_ends_->size());
diff --git a/ui/accessibility/ax_computed_node_data.h b/ui/accessibility/ax_computed_node_data.h index fe7d526..c7e82426 100644 --- a/ui/accessibility/ax_computed_node_data.h +++ b/ui/accessibility/ax_computed_node_data.h
@@ -15,6 +15,7 @@ #include "ui/accessibility/ax_enums.mojom-forward.h" #include "ui/accessibility/ax_export.h" #include "ui/accessibility/ax_node_data.h" +#include "ui/accessibility/ax_node_id_forward.h" namespace ui { @@ -37,6 +38,12 @@ // associated node is ignored. int GetOrComputeUnignoredIndexInParent() const; + // The lowest unignored parent. This value should be computed for all + // associated nodes, ignored and unignored. Only the rootnode should not have + // an unignored parent. + AXNodeID GetOrComputeUnignoredParentID() const; + AXNode* GetOrComputeUnignoredParent() const; + // If the associated node is unignored, i.e. exposed to the platform's // assistive software, the number of its children that are also unignored. // Naturally, this value is not defined when the associated node is ignored. @@ -46,6 +53,11 @@ // assistive software, the IDs of its children that are also unignored. const std::vector<AXNodeID>& GetOrComputeUnignoredChildIDs() const; + // Whether the associated node is a descendant of a platform leaf. The set of + // platform leaves are the lowest nodes that are exposed to the platform's + // assistive software. + bool GetOrComputeIsDescendantOfPlatformLeaf() const; + // Given an accessibility attribute, returns whether the attribute is // currently present in the node's data, or if it can always be computed on // demand. @@ -97,10 +109,20 @@ int GetOrComputeTextContentLengthUTF16() const; private: - // Computes and caches the `unignored_index_in_parent_`, + // Computes and caches the `unignored_index_in_parent_`, `unignored_parent_`, // `unignored_child_count_` and `unignored_child_ids_` for the associated // node. - void ComputeUnignoredValues(int starting_index_in_parent = 0) const; + void ComputeUnignoredValues(AXNodeID unignored_parent_id = kInvalidAXNodeID, + int starting_index_in_parent = 0) const; + + // Walks up the accessibility tree from the associated node until it finds the + // lowest unignored ancestor. + AXNode* SlowGetUnignoredParent() const; + + // Computes and caches (if not already in the cache) whether the associated + // node is a descendant of a platform leaf. The set of platform leaves are the + // lowest nodes that are exposed to the platform's assistive software. + void ComputeIsDescendantOfPlatformLeaf() const; // Computes and caches (if not already in the cache) the character offsets // where each line in the associated node's on-screen text starts and ends. @@ -126,8 +148,10 @@ const raw_ptr<const AXNode> owner_; mutable absl::optional<int> unignored_index_in_parent_; + mutable absl::optional<AXNodeID> unignored_parent_id_; mutable absl::optional<int> unignored_child_count_; mutable absl::optional<std::vector<AXNodeID>> unignored_child_ids_; + mutable absl::optional<bool> is_descendant_of_leaf_; mutable absl::optional<std::vector<int32_t>> line_starts_; mutable absl::optional<std::vector<int32_t>> line_ends_; mutable absl::optional<std::vector<int32_t>> sentence_starts_;
diff --git a/ui/accessibility/ax_computed_node_data_unittest.cc b/ui/accessibility/ax_computed_node_data_unittest.cc index f9e900a..c6e6e16 100644 --- a/ui/accessibility/ax_computed_node_data_unittest.cc +++ b/ui/accessibility/ax_computed_node_data_unittest.cc
@@ -13,6 +13,7 @@ #include "testing/gtest/include/gtest/gtest.h" #include "ui/accessibility/ax_enums.mojom.h" #include "ui/accessibility/ax_node_data.h" +#include "ui/accessibility/ax_node_id_forward.h" #include "ui/accessibility/ax_position.h" #include "ui/accessibility/ax_tree.h" #include "ui/accessibility/ax_tree_data.h" @@ -159,6 +160,8 @@ TEST_F(AXComputedNodeDataTest, UnignoredValues) { const AXNode* paragraph_0_node = root_node_->GetChildAtIndex(0); + const AXNode* static_text_0_0_ignored_node = + paragraph_0_node->GetChildAtIndex(0); const AXNode* paragraph_1_ignored_node = root_node_->GetChildAtIndex(1); const AXNode* static_text_1_0_node = paragraph_1_ignored_node->GetChildAtIndex(0); @@ -185,6 +188,65 @@ .GetOrComputeUnignoredIndexInParent()); EXPECT_EQ( + kInvalidAXNodeID, + root_node_->GetComputedNodeData().GetOrComputeUnignoredParentID()); + EXPECT_EQ(nullptr, + root_node_->GetComputedNodeData().GetOrComputeUnignoredParent()); + EXPECT_FALSE(root_node_->GetComputedNodeData() + .GetOrComputeIsDescendantOfPlatformLeaf()); + EXPECT_EQ(root_node_->id(), paragraph_0_node->GetComputedNodeData() + .GetOrComputeUnignoredParentID()); + EXPECT_EQ( + root_node_, + paragraph_0_node->GetComputedNodeData().GetOrComputeUnignoredParent()); + EXPECT_FALSE(paragraph_0_node->GetComputedNodeData() + .GetOrComputeIsDescendantOfPlatformLeaf()); + EXPECT_EQ(paragraph_0_node->id(), + static_text_0_0_ignored_node->GetComputedNodeData() + .GetOrComputeUnignoredParentID()); + EXPECT_EQ(paragraph_0_node, + static_text_0_0_ignored_node->GetComputedNodeData() + .GetOrComputeUnignoredParent()); + EXPECT_TRUE(static_text_0_0_ignored_node->GetComputedNodeData() + .GetOrComputeIsDescendantOfPlatformLeaf()); + EXPECT_EQ(root_node_->id(), paragraph_1_ignored_node->GetComputedNodeData() + .GetOrComputeUnignoredParentID()); + EXPECT_EQ(root_node_, paragraph_1_ignored_node->GetComputedNodeData() + .GetOrComputeUnignoredParent()); + EXPECT_FALSE(paragraph_1_ignored_node->GetComputedNodeData() + .GetOrComputeIsDescendantOfPlatformLeaf()); + EXPECT_EQ(root_node_->id(), static_text_1_0_node->GetComputedNodeData() + .GetOrComputeUnignoredParentID()); + EXPECT_EQ(root_node_, static_text_1_0_node->GetComputedNodeData() + .GetOrComputeUnignoredParent()); + EXPECT_FALSE(static_text_1_0_node->GetComputedNodeData() + .GetOrComputeIsDescendantOfPlatformLeaf()); + EXPECT_EQ(root_node_->id(), paragraph_2_ignored_node->GetComputedNodeData() + .GetOrComputeUnignoredParentID()); + EXPECT_EQ(root_node_, paragraph_2_ignored_node->GetComputedNodeData() + .GetOrComputeUnignoredParent()); + EXPECT_FALSE(paragraph_2_ignored_node->GetComputedNodeData() + .GetOrComputeIsDescendantOfPlatformLeaf()); + EXPECT_EQ(root_node_->id(), link_2_0_ignored_node->GetComputedNodeData() + .GetOrComputeUnignoredParentID()); + EXPECT_EQ(root_node_, link_2_0_ignored_node->GetComputedNodeData() + .GetOrComputeUnignoredParent()); + EXPECT_FALSE(link_2_0_ignored_node->GetComputedNodeData() + .GetOrComputeIsDescendantOfPlatformLeaf()); + EXPECT_EQ(root_node_->id(), static_text_2_0_0_node->GetComputedNodeData() + .GetOrComputeUnignoredParentID()); + EXPECT_EQ(root_node_, static_text_2_0_0_node->GetComputedNodeData() + .GetOrComputeUnignoredParent()); + EXPECT_FALSE(static_text_2_0_0_node->GetComputedNodeData() + .GetOrComputeIsDescendantOfPlatformLeaf()); + EXPECT_EQ(root_node_->id(), static_text_2_0_1_node->GetComputedNodeData() + .GetOrComputeUnignoredParentID()); + EXPECT_EQ(root_node_, static_text_2_0_1_node->GetComputedNodeData() + .GetOrComputeUnignoredParent()); + EXPECT_FALSE(static_text_2_0_1_node->GetComputedNodeData() + .GetOrComputeIsDescendantOfPlatformLeaf()); + + EXPECT_EQ( 4, root_node_->GetComputedNodeData().GetOrComputeUnignoredChildCount()); EXPECT_EQ(0, paragraph_0_node->GetComputedNodeData() .GetOrComputeUnignoredChildCount());
diff --git a/ui/aura/env.cc b/ui/aura/env.cc index 0f7b3b3..0268a5f 100644 --- a/ui/aura/env.cc +++ b/ui/aura/env.cc
@@ -69,7 +69,7 @@ // ui::EventHandler: void OnEvent(ui::Event* event) override { if (types_.count(event->type()) > 0) { - std::unique_ptr<ui::Event> cloned_event = ui::Event::Clone(*event); + std::unique_ptr<ui::Event> cloned_event = event->Clone(); ui::Event::DispatcherApi(cloned_event.get()).set_target(event->target()); // The root location of located events should be in screen coordinates. if (cloned_event->IsLocatedEvent() && cloned_event->target()) {
diff --git a/ui/chromeos/events/event_rewriter_chromeos.cc b/ui/chromeos/events/event_rewriter_chromeos.cc index 73127b0..5238b0c 100644 --- a/ui/chromeos/events/event_rewriter_chromeos.cc +++ b/ui/chromeos/events/event_rewriter_chromeos.cc
@@ -1276,7 +1276,7 @@ return SendEvent(continuation, &mouse_event); } - std::unique_ptr<Event> rewritten_event = Event::Clone(mouse_event); + std::unique_ptr<Event> rewritten_event = mouse_event.Clone(); rewritten_event->set_flags(flags); if (changed_button != EF_NONE) { static_cast<MouseEvent*>(rewritten_event.get())
diff --git a/ui/events/event.cc b/ui/events/event.cc index 48256fa..4b3edab 100644 --- a/ui/events/event.cc +++ b/ui/events/event.cc
@@ -163,11 +163,6 @@ //////////////////////////////////////////////////////////////////////////////// // Event -// static -std::unique_ptr<Event> Event::Clone(const Event& event) { - return event.Clone(); -} - Event::~Event() { if (delete_native_event_) ReleaseCopiedNativeEvent(native_event_);
diff --git a/ui/events/event.h b/ui/events/event.h index f30ccb4..0d8d8bc 100644 --- a/ui/events/event.h +++ b/ui/events/event.h
@@ -51,11 +51,6 @@ public: using Properties = base::flat_map<std::string, std::vector<uint8_t>>; - // Copies an arbitrary event. If you have a typed event (e.g. a MouseEvent) - // just use its copy constructor. - // TODO(yzshen): Remove this static method and switch callers to Clone(). - static std::unique_ptr<Event> Clone(const Event& event); - virtual ~Event(); class DispatcherApi { @@ -296,6 +291,9 @@ // For debugging. Not a stable serialization format. virtual std::string ToString() const; + // Copies an arbitrary event. If you have a typed event (e.g. a MouseEvent) + // just use its copy constructor. + // // Every concrete class transitively inheriting Event must implement this // method, even if any ancestors have provided an implementation. virtual std::unique_ptr<Event> Clone() const = 0;
diff --git a/ui/events/event_processor.cc b/ui/events/event_processor.cc index 219ce8d..796eda3 100644 --- a/ui/events/event_processor.cc +++ b/ui/events/event_processor.cc
@@ -23,7 +23,7 @@ Event* event_to_dispatch = event; std::unique_ptr<Event> event_copy; if (!dispatch_original_event) { - event_copy = Event::Clone(*event); + event_copy = event->Clone(); event_to_dispatch = event_copy.get(); }
diff --git a/ui/events/event_source.cc b/ui/events/event_source.cc index 0e4e835..2f88466b 100644 --- a/ui/events/event_source.cc +++ b/ui/events/event_source.cc
@@ -127,7 +127,7 @@ // EventRewriters don't expect an event with differing location and // root-location (because they don't honor the target). Provide such an // event. - event_for_rewriting_ptr = ui::Event::Clone(*event); + event_for_rewriting_ptr = event->Clone(); event_for_rewriting_ptr->AsLocatedEvent()->set_location_f( event_for_rewriting_ptr->AsLocatedEvent()->root_location_f()); event_for_rewriting = event_for_rewriting_ptr.get();
diff --git a/ui/events/fuchsia/input_event_dispatcher_unittest.cc b/ui/events/fuchsia/input_event_dispatcher_unittest.cc index f97db947..6fa9475 100644 --- a/ui/events/fuchsia/input_event_dispatcher_unittest.cc +++ b/ui/events/fuchsia/input_event_dispatcher_unittest.cc
@@ -30,7 +30,7 @@ void DispatchEvent(Event* event) override { DCHECK(!captured_event_); - captured_event_ = Event::Clone(*event); + captured_event_ = event->Clone(); } protected:
diff --git a/ui/events/fuchsia/pointer_events_handler_unittest.cc b/ui/events/fuchsia/pointer_events_handler_unittest.cc index ac85321..5c890ca 100644 --- a/ui/events/fuchsia/pointer_events_handler_unittest.cc +++ b/ui/events/fuchsia/pointer_events_handler_unittest.cc
@@ -72,7 +72,7 @@ TEST_F(PointerEventsHandlerTest, Watch_EventCallbacksAreIndependent) { std::vector<std::unique_ptr<Event>> events; pointer_handler_->StartWatching(base::BindLambdaForTesting( - [&events](Event* event) { events.push_back(Event::Clone(*event)); })); + [&events](Event* event) { events.push_back(event->Clone()); })); RunLoopUntilIdle(); // Server gets watch call. std::vector<fup::TouchEvent> touch_events = @@ -505,10 +505,10 @@ base::BindLambdaForTesting([&mouse_events](Event* event) { ASSERT_TRUE(event->IsMouseEvent()); if (event->IsMouseWheelEvent()) { - auto e = Event::Clone(*event->AsMouseWheelEvent()); + auto e = event->AsMouseWheelEvent()->Clone(); mouse_events.push_back(std::move(e)); } else if (event->IsMouseEvent()) { - auto e = Event::Clone(*event->AsMouseEvent()); + auto e = event->AsMouseEvent()->Clone(); mouse_events.push_back(std::move(e)); } else { NOTREACHED(); @@ -555,10 +555,10 @@ base::BindLambdaForTesting([&mouse_events](Event* event) { ASSERT_TRUE(event->IsMouseEvent()); if (event->IsMouseWheelEvent()) { - auto e = Event::Clone(*event->AsMouseWheelEvent()); + auto e = event->AsMouseWheelEvent()->Clone(); mouse_events.push_back(std::move(e)); } else if (event->IsMouseEvent()) { - auto e = Event::Clone(*event->AsMouseEvent()); + auto e = event->AsMouseEvent()->Clone(); mouse_events.push_back(std::move(e)); } else { NOTREACHED();
diff --git a/ui/events/mojom/mojom_traits_unittest.cc b/ui/events/mojom/mojom_traits_unittest.cc index 5f7a444..11a0f01 100644 --- a/ui/events/mojom/mojom_traits_unittest.cc +++ b/ui/events/mojom/mojom_traits_unittest.cc
@@ -111,7 +111,7 @@ }; for (size_t i = 0; i < std::size(kTestData); i++) { - std::unique_ptr<Event> expected_copy = Event::Clone(kTestData[i]); + std::unique_ptr<Event> expected_copy = kTestData[i].Clone(); std::unique_ptr<Event> output; ASSERT_TRUE(mojo::test::SerializeAndDeserialize<mojom::Event>(expected_copy, output)); @@ -150,7 +150,7 @@ }; for (size_t i = 0; i < std::size(kTestData); i++) { - std::unique_ptr<Event> expected_copy = Event::Clone(kTestData[i]); + std::unique_ptr<Event> expected_copy = kTestData[i].Clone(); std::unique_ptr<Event> output; ASSERT_TRUE(mojo::test::SerializeAndDeserialize<mojom::Event>(expected_copy, output)); @@ -176,7 +176,7 @@ }; for (size_t i = 0; i < std::size(kTestData); i++) { - std::unique_ptr<Event> expected_copy = Event::Clone(kTestData[i]); + std::unique_ptr<Event> expected_copy = kTestData[i].Clone(); std::unique_ptr<Event> output; ASSERT_TRUE(mojo::test::SerializeAndDeserialize<mojom::Event>(expected_copy, output)); @@ -206,7 +206,7 @@ // Serialize and deserialize does not round or truncate the locations. for (Event* event : test_data) { - std::unique_ptr<Event> event_copy = Event::Clone(*event); + std::unique_ptr<Event> event_copy = event->Clone(); std::unique_ptr<Event> output; ASSERT_TRUE( mojo::test::SerializeAndDeserialize<mojom::Event>(event_copy, output)); @@ -225,7 +225,7 @@ properties[key] = value; key_event.SetProperties(properties); - std::unique_ptr<Event> event_ptr = Event::Clone(key_event); + std::unique_ptr<Event> event_ptr = key_event.Clone(); std::unique_ptr<Event> deserialized; ASSERT_TRUE(mojom::Event::Deserialize(mojom::Event::Serialize(&event_ptr), &deserialized)); @@ -257,7 +257,7 @@ }; for (size_t i = 0; i < std::size(kTestData); i++) { - std::unique_ptr<Event> expected_copy = Event::Clone(kTestData[i]); + std::unique_ptr<Event> expected_copy = kTestData[i].Clone(); std::unique_ptr<Event> output; ASSERT_TRUE(mojo::test::SerializeAndDeserialize<mojom::Event>(expected_copy, output)); @@ -303,7 +303,7 @@ }; for (size_t i = 0; i < std::size(kTestData); i++) { - std::unique_ptr<Event> expected_copy = Event::Clone(kTestData[i]); + std::unique_ptr<Event> expected_copy = kTestData[i].Clone(); std::unique_ptr<Event> output; ASSERT_TRUE(mojo::test::SerializeAndDeserialize<mojom::Event>(expected_copy, output)); @@ -356,7 +356,7 @@ {ET_TOUCH_CANCELLED, {1, 2}, base::TimeTicks::Now(), {}, EF_NONE}, }; for (size_t i = 0; i < std::size(kTestData); i++) { - std::unique_ptr<Event> expected_copy = Event::Clone(kTestData[i]); + std::unique_ptr<Event> expected_copy = kTestData[i].Clone(); std::unique_ptr<Event> output; ASSERT_TRUE(mojo::test::SerializeAndDeserialize<mojom::Event>(expected_copy, output));
diff --git a/ui/events/ozone/evdev/event_converter_evdev_impl_unittest.cc b/ui/events/ozone/evdev/event_converter_evdev_impl_unittest.cc index 0ceac82f..f90a86e 100644 --- a/ui/events/ozone/evdev/event_converter_evdev_impl_unittest.cc +++ b/ui/events/ozone/evdev/event_converter_evdev_impl_unittest.cc
@@ -132,7 +132,7 @@ private: void DispatchEventForTest(ui::Event* event) { - std::unique_ptr<ui::Event> cloned_event = ui::Event::Clone(*event); + std::unique_ptr<ui::Event> cloned_event = event->Clone(); dispatched_events_.push_back(std::move(cloned_event)); }
diff --git a/ui/events/ozone/evdev/stylus_button_event_converter_evdev_unittest.cc b/ui/events/ozone/evdev/stylus_button_event_converter_evdev_unittest.cc index eea6521..e3c981be 100644 --- a/ui/events/ozone/evdev/stylus_button_event_converter_evdev_unittest.cc +++ b/ui/events/ozone/evdev/stylus_button_event_converter_evdev_unittest.cc
@@ -153,7 +153,7 @@ } void DispatchEventForTest(ui::Event* event) { - std::unique_ptr<ui::Event> cloned_event = ui::Event::Clone(*event); + std::unique_ptr<ui::Event> cloned_event = event->Clone(); dispatched_events_.push_back(std::move(cloned_event)); }
diff --git a/ui/events/ozone/evdev/tablet_event_converter_evdev_unittest.cc b/ui/events/ozone/evdev/tablet_event_converter_evdev_unittest.cc index a37706d..00e4c729 100644 --- a/ui/events/ozone/evdev/tablet_event_converter_evdev_unittest.cc +++ b/ui/events/ozone/evdev/tablet_event_converter_evdev_unittest.cc
@@ -264,7 +264,7 @@ } void DispatchEventForTest(ui::Event* event) { - std::unique_ptr<ui::Event> cloned_event = ui::Event::Clone(*event); + std::unique_ptr<ui::Event> cloned_event = event->Clone(); dispatched_events_.push_back(std::move(cloned_event)); }
diff --git a/ui/events/test/test_event_rewriter.cc b/ui/events/test/test_event_rewriter.cc index 185f304..01451c8 100644 --- a/ui/events/test/test_event_rewriter.cc +++ b/ui/events/test/test_event_rewriter.cc
@@ -17,7 +17,7 @@ const ui::Event& event, const Continuation continuation) { ++events_seen_; - last_event_ = ui::Event::Clone(event); + last_event_ = event.Clone(); return SendEvent(continuation, &event); }
diff --git a/ui/gfx/x/xlib_support.cc b/ui/gfx/x/xlib_support.cc index 00d979df..aa362ed 100644 --- a/ui/gfx/x/xlib_support.cc +++ b/ui/gfx/x/xlib_support.cc
@@ -81,7 +81,9 @@ // events, they will just queue up and leak memory. This check makes sure // |display_| never had any pending events before it is closed. CHECK(!loader->XPending(display_)); - loader->XCloseDisplay(display_); + // ExtractAsDangling clears the underlying pointer and returns another raw_ptr + // instance that is allowed to dangle. + loader->XCloseDisplay(display_.ExtractAsDangling()); } DISABLE_CFI_DLSYM
diff --git a/ui/gfx/x/xlib_support.h b/ui/gfx/x/xlib_support.h index a2dd18c..91edc32 100644 --- a/ui/gfx/x/xlib_support.h +++ b/ui/gfx/x/xlib_support.h
@@ -48,7 +48,7 @@ explicit XlibDisplay(const std::string& address); - raw_ptr<struct _XDisplay, DanglingUntriaged> display_ = nullptr; + raw_ptr<struct _XDisplay> display_ = nullptr; }; // A temporary wrapper around an unowned Xlib display that adds behavior
diff --git a/ui/message_center/views/notification_view_util.cc b/ui/message_center/views/notification_view_util.cc index e5cc69c..74f5e3e7 100644 --- a/ui/message_center/views/notification_view_util.cc +++ b/ui/message_center/views/notification_view_util.cc
@@ -16,7 +16,7 @@ // Convert the point of |event| from the coordinate system of its target to // that of the passed in |target| and create a new LocatedEvent. - std::unique_ptr<ui::Event> cloned_event = ui::Event::Clone(event); + std::unique_ptr<ui::Event> cloned_event = event.Clone(); ui::LocatedEvent* located_event = cloned_event->AsLocatedEvent(); event.target()->ConvertEventToTarget(target, located_event);
diff --git a/ui/ozone/platform/wayland/host/wayland_keyboard_unittest.cc b/ui/ozone/platform/wayland/host/wayland_keyboard_unittest.cc index 3b62155..31530b82 100644 --- a/ui/ozone/platform/wayland/host/wayland_keyboard_unittest.cc +++ b/ui/ozone/platform/wayland/host/wayland_keyboard_unittest.cc
@@ -115,7 +115,7 @@ }; ACTION_P(CloneEvent, ptr) { - *ptr = Event::Clone(*arg0); + *ptr = arg0->Clone(); } TEST_P(WaylandKeyboardTest, Keypress) {
diff --git a/ui/ozone/platform/wayland/host/wayland_pointer_unittest.cc b/ui/ozone/platform/wayland/host/wayland_pointer_unittest.cc index 6fc42a0..cfda16e 100644 --- a/ui/ozone/platform/wayland/host/wayland_pointer_unittest.cc +++ b/ui/ozone/platform/wayland/host/wayland_pointer_unittest.cc
@@ -94,7 +94,7 @@ } ACTION_P(CloneEvent, ptr) { - *ptr = Event::Clone(*arg0); + *ptr = arg0->Clone(); } TEST_P(WaylandPointerTest, Enter) { @@ -149,7 +149,7 @@ ACTION_P3(CloneEventAndCheckCapture, window, result, ptr) { ASSERT_TRUE(window->HasCapture() == result); - *ptr = Event::Clone(*arg0); + *ptr = arg0->Clone(); } TEST_P(WaylandPointerTest, Motion) {
diff --git a/ui/ozone/platform/wayland/host/wayland_touch_unittest.cc b/ui/ozone/platform/wayland/host/wayland_touch_unittest.cc index 4cfceac6..068a40e 100644 --- a/ui/ozone/platform/wayland/host/wayland_touch_unittest.cc +++ b/ui/ozone/platform/wayland/host/wayland_touch_unittest.cc
@@ -32,7 +32,7 @@ namespace { ACTION_P(CloneEvent, ptr) { - *ptr = Event::Clone(*arg0); + *ptr = arg0->Clone(); } bool CompareFloat(float a, float b) {
diff --git a/ui/ozone/platform/wayland/host/wayland_window_unittest.cc b/ui/ozone/platform/wayland/host/wayland_window_unittest.cc index 4c8f2377..964ff2d 100644 --- a/ui/ozone/platform/wayland/host/wayland_window_unittest.cc +++ b/ui/ozone/platform/wayland/host/wayland_window_unittest.cc
@@ -1278,7 +1278,7 @@ } ACTION_P(CloneEvent, ptr) { - *ptr = Event::Clone(*arg0); + *ptr = arg0->Clone(); } TEST_P(WaylandWindowTest, DispatchEvent) {
diff --git a/ui/ozone/platform/x11/x11_window_ozone_unittest.cc b/ui/ozone/platform/x11/x11_window_ozone_unittest.cc index 5e008e1..7b9c573 100644 --- a/ui/ozone/platform/x11/x11_window_ozone_unittest.cc +++ b/ui/ozone/platform/x11/x11_window_ozone_unittest.cc
@@ -36,7 +36,7 @@ } ACTION_P(CloneEvent, event_ptr) { - *event_ptr = Event::Clone(*arg0); + *event_ptr = arg0->Clone(); } // TestScreen implementation. We need to set a screen instance, because
diff --git a/ui/views/animation/ink_drop_event_handler.cc b/ui/views/animation/ink_drop_event_handler.cc index af6b440..086b374 100644 --- a/ui/views/animation/ink_drop_event_handler.cc +++ b/ui/views/animation/ink_drop_event_handler.cc
@@ -48,7 +48,7 @@ } #endif last_ripple_triggering_event_.reset( - event ? ui::Event::Clone(*event).release()->AsLocatedEvent() : nullptr); + event ? event->Clone().release()->AsLocatedEvent() : nullptr); // If no ink drop exists and we are not transitioning to a visible ink drop // state the transition have no visual effect. The call to GetInkDrop() will
diff --git a/ui/views/controls/menu/menu_controller.cc b/ui/views/controls/menu/menu_controller.cc index 146a825f..906bffb 100644 --- a/ui/views/controls/menu/menu_controller.cc +++ b/ui/views/controls/menu/menu_controller.cc
@@ -336,7 +336,7 @@ gfx::Point root_loc(screen_loc); spc->ConvertPointFromScreen(root, &root_loc); - std::unique_ptr<ui::Event> clone = ui::Event::Clone(*event); + std::unique_ptr<ui::Event> clone = event->Clone(); std::unique_ptr<ui::LocatedEvent> located_event( static_cast<ui::LocatedEvent*>(clone.release())); located_event->set_location(root_loc);
diff --git a/ui/webui/resources/BUILD.gn b/ui/webui/resources/BUILD.gn index 3bb92c2..d7f4815 100644 --- a/ui/webui/resources/BUILD.gn +++ b/ui/webui/resources/BUILD.gn
@@ -169,7 +169,7 @@ "cr_elements/cr_container_shadow_behavior.m.d.ts", "cr_elements/cr_dialog/cr_dialog.m.d.ts", "cr_elements/cr_expand_button/cr_expand_button.m.d.ts", - "cr_elements/cr_fingerprint/cr_fingerprint_progress_arc.m.d.ts", + "cr_elements/cr_fingerprint/cr_fingerprint_progress_arc.d.ts", "cr_elements/cr_icon_button/cr_icon_button.m.d.ts", "cr_elements/cr_input/cr_input.m.d.ts", "cr_elements/cr_lottie/cr_lottie.m.d.ts", @@ -267,7 +267,7 @@ if (include_polymer) { generate_definitions_js_files += [ "cr_elements/action_link_css.m.js", - "cr_elements/cr_fingerprint/cr_fingerprint_icon.m.js", + "cr_elements/cr_fingerprint/cr_fingerprint_icon.js", "cr_elements/cr_actionable_row_style.m.js", "cr_elements/cr_icons_css.m.js", "cr_elements/cr_input/cr_input_style_css.m.js",
diff --git a/ui/webui/resources/cr_elements/BUILD.gn b/ui/webui/resources/cr_elements/BUILD.gn index 4d72bed..7e73565 100644 --- a/ui/webui/resources/cr_elements/BUILD.gn +++ b/ui/webui/resources/cr_elements/BUILD.gn
@@ -94,9 +94,6 @@ "cr_dialog/cr_dialog.js", "cr_expand_button/cr_expand_button.html", "cr_expand_button/cr_expand_button.js", - "cr_fingerprint/cr_fingerprint_icon.html", - "cr_fingerprint/cr_fingerprint_progress_arc.html", - "cr_fingerprint/cr_fingerprint_progress_arc.js", "cr_icon_button/cr_icon_button.html", "cr_icon_button/cr_icon_button.js", "cr_icons_css.html", @@ -150,8 +147,8 @@ "cr_container_shadow_behavior.m.js", "cr_dialog/cr_dialog.m.js", "cr_expand_button/cr_expand_button.m.js", - "cr_fingerprint/cr_fingerprint_icon.m.js", - "cr_fingerprint/cr_fingerprint_progress_arc.m.js", + "cr_fingerprint/cr_fingerprint_icon.js", + "cr_fingerprint/cr_fingerprint_progress_arc.js", "cr_icon_button/cr_icon_button.m.js", "cr_icons_css.m.js", "cr_input/cr_input.m.js", @@ -187,7 +184,6 @@ ":cr_elements_resources", "cr_checkbox:closure_compile", "cr_dialog:closure_compile", - "cr_fingerprint:closure_compile", "cr_icon_button:closure_compile", "cr_input:closure_compile", "cr_lottie:closure_compile", @@ -311,7 +307,7 @@ "cr_checkbox:cr_checkbox_module", "cr_dialog:cr_dialog_module", "cr_expand_button:cr_expand_button_module", - "cr_fingerprint:polymer3_elements", + "cr_fingerprint:web_components", "cr_icon_button:cr_icon_button_module", "cr_input:polymer3_elements", "cr_lottie:cr_lottie_module",
diff --git a/ui/webui/resources/cr_elements/cr_fingerprint/BUILD.gn b/ui/webui/resources/cr_elements/cr_fingerprint/BUILD.gn index b274ec3..d39f1d9 100644 --- a/ui/webui/resources/cr_elements/cr_fingerprint/BUILD.gn +++ b/ui/webui/resources/cr_elements/cr_fingerprint/BUILD.gn
@@ -3,50 +3,24 @@ # found in the LICENSE file. import("//third_party/closure_compiler/compile_js.gni") -import("//tools/polymer/polymer.gni") +import("//tools/polymer/html_to_js.gni") -js_type_check("closure_compile") { - uses_legacy_modules = true +html_to_js("web_components") { + js_files = [ + "cr_fingerprint_progress_arc.js", + "cr_fingerprint_icon.js", + ] +} + +js_type_check("closure_compile_module") { + is_polymer3 = true deps = [ ":cr_fingerprint_progress_arc" ] } js_library("cr_fingerprint_progress_arc") { deps = [ - "../cr_lottie:cr_lottie", - "//third_party/polymer/v1_0/components-chromium/iron-icon:iron-icon-extracted", - ] -} - -group("polymer3_elements") { - public_deps = [ - ":cr_fingerprint_icon_module", - ":cr_fingerprint_progress_arc_module", - ] -} - -polymer_modulizer("cr_fingerprint_progress_arc") { - js_file = "cr_fingerprint_progress_arc.js" - html_file = "cr_fingerprint_progress_arc.html" - html_type = "dom-module" -} - -polymer_modulizer("cr_fingerprint_icon") { - js_file = "cr_fingerprint_icon.m.js" - html_file = "cr_fingerprint_icon.html" - html_type = "iron-iconset" -} - -js_type_check("closure_compile_module") { - is_polymer3 = true - deps = [ ":cr_fingerprint_progress_arc.m" ] -} - -js_library("cr_fingerprint_progress_arc.m") { - sources = [ "$root_gen_dir/ui/webui/resources/cr_elements/cr_fingerprint/cr_fingerprint_progress_arc.m.js" ] - deps = [ "../cr_lottie:cr_lottie.m", "//third_party/polymer/v3_0/components-chromium/iron-icon:iron-icon", "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", ] - extra_deps = [ ":cr_fingerprint_progress_arc_module" ] }
diff --git a/ui/webui/resources/cr_elements/cr_fingerprint/cr_fingerprint_icon.html b/ui/webui/resources/cr_elements/cr_fingerprint/cr_fingerprint_icon.html index 7b7be357..db8f98b 100644 --- a/ui/webui/resources/cr_elements/cr_fingerprint/cr_fingerprint_icon.html +++ b/ui/webui/resources/cr_elements/cr_fingerprint/cr_fingerprint_icon.html
@@ -1,6 +1,3 @@ -<link rel="import" href="../../html/polymer.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/iron-iconset-svg/iron-iconset-svg.html"> - <iron-iconset-svg name="cr-fingerprint-icon" size="32"> <svg> <defs>
diff --git a/ui/webui/resources/cr_elements/cr_fingerprint/cr_fingerprint_icon.js b/ui/webui/resources/cr_elements/cr_fingerprint/cr_fingerprint_icon.js new file mode 100644 index 0000000..5df0d68 --- /dev/null +++ b/ui/webui/resources/cr_elements/cr_fingerprint/cr_fingerprint_icon.js
@@ -0,0 +1,10 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import '//resources/polymer/v3_0/iron-iconset-svg/iron-iconset-svg.js'; + +import {html} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; + +const template = html`{__html_template__}`; +document.head.appendChild(template.content);
diff --git a/ui/webui/resources/cr_elements/cr_fingerprint/cr_fingerprint_progress_arc.m.d.ts b/ui/webui/resources/cr_elements/cr_fingerprint/cr_fingerprint_progress_arc.d.ts similarity index 100% rename from ui/webui/resources/cr_elements/cr_fingerprint/cr_fingerprint_progress_arc.m.d.ts rename to ui/webui/resources/cr_elements/cr_fingerprint/cr_fingerprint_progress_arc.d.ts
diff --git a/ui/webui/resources/cr_elements/cr_fingerprint/cr_fingerprint_progress_arc.html b/ui/webui/resources/cr_elements/cr_fingerprint/cr_fingerprint_progress_arc.html index a83d498..a42149b5 100644 --- a/ui/webui/resources/cr_elements/cr_fingerprint/cr_fingerprint_progress_arc.html +++ b/ui/webui/resources/cr_elements/cr_fingerprint/cr_fingerprint_progress_arc.html
@@ -1,11 +1,3 @@ -<link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/iron-media-query/iron-media-query.html"> -<link rel="import" href="../../html/polymer.html"> -<link rel="import" href="cr_fingerprint_icon.html"> -<link rel="import" href="../cr_lottie/cr_lottie.html"> - -<dom-module id="cr-fingerprint-progress-arc"> - <template> <style> :host { user-select: none; @@ -42,6 +34,3 @@ </cr-lottie> <iron-icon id="fingerprintScanned" hidden></iron-icon> </div> - </template> - <script src="cr_fingerprint_progress_arc.js"></script> -</dom-module>
diff --git a/ui/webui/resources/cr_elements/cr_fingerprint/cr_fingerprint_progress_arc.js b/ui/webui/resources/cr_elements/cr_fingerprint/cr_fingerprint_progress_arc.js index 818460e..37feb7c2 100644 --- a/ui/webui/resources/cr_elements/cr_fingerprint/cr_fingerprint_progress_arc.js +++ b/ui/webui/resources/cr_elements/cr_fingerprint/cr_fingerprint_progress_arc.js
@@ -2,12 +2,19 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import '//resources/polymer/v3_0/iron-icon/iron-icon.js'; +import '//resources/polymer/v3_0/iron-media-query/iron-media-query.js'; +import './cr_fingerprint_icon.js'; +import '../cr_lottie/cr_lottie.m.js'; + +import {html, Polymer} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; + /** * The dark-mode fingerprint icon displayed temporarily each time a user scans * their fingerprint and persistently once the enrollment process is complete. * @type {string} */ -/* #export */ const FINGERPRINT_SCANNED_ICON_DARK = +export const FINGERPRINT_SCANNED_ICON_DARK = 'cr-fingerprint-icon:fingerprint-scanned-dark'; /** @@ -15,46 +22,41 @@ * their fingerprint and persistently once the enrollment process is complete. * @type {string} */ -/* #export */ const FINGERPRINT_SCANNED_ICON_LIGHT = +export const FINGERPRINT_SCANNED_ICON_LIGHT = 'cr-fingerprint-icon:fingerprint-scanned-light'; /** @type {string} */ -/* #export */ const FINGERPRINT_CHECK_DARK_URL = +export const FINGERPRINT_CHECK_DARK_URL = 'chrome://theme/IDR_FINGERPRINT_COMPLETE_CHECK_DARK'; /** @type {string} */ -/* #export */ const FINGERPRINT_CHECK_LIGHT_URL = +export const FINGERPRINT_CHECK_LIGHT_URL = 'chrome://theme/IDR_FINGERPRINT_COMPLETE_CHECK_LIGHT'; /** * The dark-mode color of the progress circle background: Google Grey 700. * @type {string} */ -/* #export */ const PROGRESS_CIRCLE_BACKGROUND_COLOR_DARK = - 'rgba(95, 99, 104, 1.0)'; +export const PROGRESS_CIRCLE_BACKGROUND_COLOR_DARK = 'rgba(95, 99, 104, 1.0)'; /** * The light-mode color of the progress circle background: Google Grey 200. * @type {string} */ -/* #export */ const PROGRESS_CIRCLE_BACKGROUND_COLOR_LIGHT = +export const PROGRESS_CIRCLE_BACKGROUND_COLOR_LIGHT = 'rgba(232, 234, 237, 1.0)'; /** * The dark-mode color of the setup progress arc: Google Blue 400. * @type {string} */ -/* #export */ const PROGRESS_CIRCLE_FILL_COLOR_DARK = - 'rgba(102, 157, 246, 1.0)'; +export const PROGRESS_CIRCLE_FILL_COLOR_DARK = 'rgba(102, 157, 246, 1.0)'; /** * The light-mode color of the setup progress arc: Google Blue 500. * @type {string} */ -/* #export */ const PROGRESS_CIRCLE_FILL_COLOR_LIGHT = - 'rgba(66, 133, 244, 1.0)'; - -(function() { +export const PROGRESS_CIRCLE_FILL_COLOR_LIGHT = 'rgba(66, 133, 244, 1.0)'; /** * The time in milliseconds of the animation updates. @@ -111,6 +113,8 @@ Polymer({ is: 'cr-fingerprint-progress-arc', + _template: html`{__html_template__}`, + properties: { /** * Radius of the fingerprint progress circle being displayed. @@ -478,5 +482,3 @@ target.style.top = top + 'px'; }, }); -/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.'); -})();
diff --git a/weblayer/browser/url_bar/page_info_delegate_impl.cc b/weblayer/browser/url_bar/page_info_delegate_impl.cc index 49d1050..a3ae2bbd 100644 --- a/weblayer/browser/url_bar/page_info_delegate_impl.cc +++ b/weblayer/browser/url_bar/page_info_delegate_impl.cc
@@ -74,6 +74,11 @@ NOTREACHED(); } +void PageInfoDelegateImpl::ShowCookiesSettings() { + // Used for desktop only. Doesn't need implementation for WebLayer. + NOTREACHED(); +} + void PageInfoDelegateImpl::OpenCookiesDialog() { // Used for desktop only. Doesn't need implementation for WebLayer. NOTREACHED();
diff --git a/weblayer/browser/url_bar/page_info_delegate_impl.h b/weblayer/browser/url_bar/page_info_delegate_impl.h index 384cf99..7c3062f 100644 --- a/weblayer/browser/url_bar/page_info_delegate_impl.h +++ b/weblayer/browser/url_bar/page_info_delegate_impl.h
@@ -39,6 +39,7 @@ #if !BUILDFLAG(IS_ANDROID) bool CreateInfoBarDelegate() override; void ShowSiteSettings(const GURL& site_url) override; + void ShowCookiesSettings() override; void OpenCookiesDialog() override; void OpenCertificateDialog(net::X509Certificate* certificate) override; void OpenConnectionHelpCenterPage(const ui::Event& event) override;
diff --git a/weblayer/public/java/BUILD.gn b/weblayer/public/java/BUILD.gn index 8287c29..91c7716 100644 --- a/weblayer/public/java/BUILD.gn +++ b/weblayer/public/java/BUILD.gn
@@ -181,6 +181,8 @@ "org/chromium/browserfragment/interfaces/IBrowserFragmentDelegateClient.aidl", "org/chromium/browserfragment/interfaces/IBrowserSandboxCallback.aidl", "org/chromium/browserfragment/interfaces/IBrowserSandboxService.aidl", + "org/chromium/browserfragment/interfaces/IRequestNavigationCallback.aidl", + "org/chromium/browserfragment/interfaces/ITabNavigationControllerProxy.aidl", "org/chromium/browserfragment/interfaces/ITabObserverDelegate.aidl", "org/chromium/browserfragment/interfaces/ITabProxy.aidl", ] @@ -197,6 +199,7 @@ "org/chromium/browserfragment/BrowserFragment.java", "org/chromium/browserfragment/Tab.java", "org/chromium/browserfragment/TabManager.java", + "org/chromium/browserfragment/TabNavigationController.java", "org/chromium/browserfragment/TabObserver.java", "org/chromium/browserfragment/TabObserverDelegate.java", ] @@ -223,6 +226,7 @@ "org/chromium/weblayer/BrowserFragmentDelegate.java", "org/chromium/weblayer/BrowserFragmentTabDelegate.java", "org/chromium/weblayer/BrowserSandboxService.java", + "org/chromium/weblayer/TabNavigationControllerProxy.java", "org/chromium/weblayer/TabProxy.java", ] resources_package = "org.chromium.weblayer"
diff --git a/weblayer/public/java/org/chromium/browserfragment/Tab.java b/weblayer/public/java/org/chromium/browserfragment/Tab.java index 477cd20..598820d 100644 --- a/weblayer/public/java/org/chromium/browserfragment/Tab.java +++ b/weblayer/public/java/org/chromium/browserfragment/Tab.java
@@ -15,20 +15,16 @@ */ public class Tab { private ITabProxy mTabProxy; + private TabNavigationController mTabNavigationController; Tab(ITabProxy tabProxy) { mTabProxy = tabProxy; - } - /** - * Navigates this Tab to the given URI. - * - * @param uri The destination URI. - */ - public void navigate(@NonNull String uri) { try { - mTabProxy.navigate(uri); + mTabNavigationController = + new TabNavigationController(mTabProxy.getNavigationController()); } catch (RemoteException e) { + // TODO(swestphal): Raise exception. } } @@ -41,4 +37,14 @@ } catch (RemoteException e) { } } + + /** + * Returns the navigation controller for this Tab. + * + * @return The TabNavigationController. + */ + @NonNull + public TabNavigationController getNavigationController() { + return mTabNavigationController; + } }
diff --git a/weblayer/public/java/org/chromium/browserfragment/TabNavigationController.java b/weblayer/public/java/org/chromium/browserfragment/TabNavigationController.java new file mode 100644 index 0000000..0ec3216 --- /dev/null +++ b/weblayer/public/java/org/chromium/browserfragment/TabNavigationController.java
@@ -0,0 +1,103 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.browserfragment; + +import android.os.RemoteException; + +import androidx.annotation.NonNull; +import androidx.concurrent.futures.CallbackToFutureAdapter; + +import com.google.common.util.concurrent.ListenableFuture; + +import org.chromium.browserfragment.interfaces.IRequestNavigationCallback; +import org.chromium.browserfragment.interfaces.ITabNavigationControllerProxy; + +/** + * TabNavigationController controls the navigation in a Tab. + */ +public class TabNavigationController { + private final ITabNavigationControllerProxy mTabNavigationControllerProxy; + + private final class RequestNavigationCallback extends IRequestNavigationCallback.Stub { + private CallbackToFutureAdapter.Completer<Boolean> mCompleter; + + RequestNavigationCallback(CallbackToFutureAdapter.Completer<Boolean> completer) { + mCompleter = completer; + } + + @Override + public void canNavigate(boolean possible) { + mCompleter.set(possible); + } + }; + + TabNavigationController(ITabNavigationControllerProxy tabNavigationControllerProxy) { + mTabNavigationControllerProxy = tabNavigationControllerProxy; + } + + /** + * Navigates this Tab to the given URI. + * + * @param uri The destination URI. + */ + public void navigate(@NonNull String uri) { + try { + mTabNavigationControllerProxy.navigate(uri); + } catch (RemoteException e) { + } + } + + /** + * Navigates to the previous navigation. + */ + public void goBack() { + try { + mTabNavigationControllerProxy.goBack(); + } catch (RemoteException e) { + } + } + + /** + * Navigates to the next navigation. + */ + public void goForward() { + try { + mTabNavigationControllerProxy.goForward(); + } 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 + * one. + */ + @NonNull + public ListenableFuture<Boolean> canGoBack() { + return CallbackToFutureAdapter.getFuture(completer -> { + mTabNavigationControllerProxy.canGoBack(new RequestNavigationCallback(completer)); + + // Debug string. + return "Can navigate back Future"; + }); + } + + /** + * Returns true if there is a navigation after the current one. + * + * @return ListenableFuture with a Boolean stating if there is a navigation after the current + * one. + */ + @NonNull + public ListenableFuture<Boolean> canGoForward() { + return CallbackToFutureAdapter.getFuture(completer -> { + mTabNavigationControllerProxy.canGoForward(new RequestNavigationCallback(completer)); + + // Debug string. + return "Can navigate forward Future"; + }); + } +} \ No newline at end of file
diff --git a/weblayer/public/java/org/chromium/browserfragment/interfaces/IBrowserFragmentDelegateClient.aidl b/weblayer/public/java/org/chromium/browserfragment/interfaces/IBrowserFragmentDelegateClient.aidl index 5ab5e3e..5f423de 100644 --- a/weblayer/public/java/org/chromium/browserfragment/interfaces/IBrowserFragmentDelegateClient.aidl +++ b/weblayer/public/java/org/chromium/browserfragment/interfaces/IBrowserFragmentDelegateClient.aidl
@@ -6,7 +6,7 @@ import android.view.SurfaceControlViewHost.SurfacePackage; -interface IBrowserFragmentDelegateClient { +oneway interface IBrowserFragmentDelegateClient { void onSurfacePackageReady(in SurfacePackage surfacePackage) = 1; void onStarted() = 2; } \ No newline at end of file
diff --git a/weblayer/public/java/org/chromium/browserfragment/interfaces/IBrowserSandboxCallback.aidl b/weblayer/public/java/org/chromium/browserfragment/interfaces/IBrowserSandboxCallback.aidl index d514f081..74a696c 100644 --- a/weblayer/public/java/org/chromium/browserfragment/interfaces/IBrowserSandboxCallback.aidl +++ b/weblayer/public/java/org/chromium/browserfragment/interfaces/IBrowserSandboxCallback.aidl
@@ -6,6 +6,6 @@ import android.view.SurfaceControlViewHost.SurfacePackage; -interface IBrowserSandboxCallback { +oneway interface IBrowserSandboxCallback { void onBrowserProcessInitialized() = 1; } \ No newline at end of file
diff --git a/weblayer/public/java/org/chromium/browserfragment/interfaces/IRequestNavigationCallback.aidl b/weblayer/public/java/org/chromium/browserfragment/interfaces/IRequestNavigationCallback.aidl new file mode 100644 index 0000000..e57495a --- /dev/null +++ b/weblayer/public/java/org/chromium/browserfragment/interfaces/IRequestNavigationCallback.aidl
@@ -0,0 +1,9 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.browserfragment.interfaces; + +oneway interface IRequestNavigationCallback { + void canNavigate(in boolean result) = 1; +} \ No newline at end of file
diff --git a/weblayer/public/java/org/chromium/browserfragment/interfaces/ITabNavigationControllerProxy.aidl b/weblayer/public/java/org/chromium/browserfragment/interfaces/ITabNavigationControllerProxy.aidl new file mode 100644 index 0000000..1539274 --- /dev/null +++ b/weblayer/public/java/org/chromium/browserfragment/interfaces/ITabNavigationControllerProxy.aidl
@@ -0,0 +1,15 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.browserfragment.interfaces; + +import org.chromium.browserfragment.interfaces.IRequestNavigationCallback; + +oneway interface ITabNavigationControllerProxy { + void navigate(in String uri) = 1; + void goBack() = 2; + void goForward() = 3; + void canGoBack(IRequestNavigationCallback callback) = 4; + void canGoForward(IRequestNavigationCallback callback) = 5; +} \ No newline at end of file
diff --git a/weblayer/public/java/org/chromium/browserfragment/interfaces/ITabObserverDelegate.aidl b/weblayer/public/java/org/chromium/browserfragment/interfaces/ITabObserverDelegate.aidl index fdd7619..f05e875 100644 --- a/weblayer/public/java/org/chromium/browserfragment/interfaces/ITabObserverDelegate.aidl +++ b/weblayer/public/java/org/chromium/browserfragment/interfaces/ITabObserverDelegate.aidl
@@ -6,7 +6,7 @@ import org.chromium.browserfragment.interfaces.ITabProxy; -interface ITabObserverDelegate { +oneway interface ITabObserverDelegate { void notifyActiveTabChanged(in ITabProxy activeTab) = 1; void notifyTabAdded(in ITabProxy tab) = 2; void notifyTabRemoved(in ITabProxy tab) = 3;
diff --git a/weblayer/public/java/org/chromium/browserfragment/interfaces/ITabProxy.aidl b/weblayer/public/java/org/chromium/browserfragment/interfaces/ITabProxy.aidl index a292b36..4ff9e50 100644 --- a/weblayer/public/java/org/chromium/browserfragment/interfaces/ITabProxy.aidl +++ b/weblayer/public/java/org/chromium/browserfragment/interfaces/ITabProxy.aidl
@@ -4,8 +4,9 @@ package org.chromium.browserfragment.interfaces; +import org.chromium.browserfragment.interfaces.ITabNavigationControllerProxy; + interface ITabProxy { - // TODO(swestphal): Move this to the navigationController when we expose one. - void navigate(in String url) = 1; - void setActive() = 2; + void setActive() = 1; + ITabNavigationControllerProxy getNavigationController() = 2; }
diff --git a/weblayer/public/java/org/chromium/weblayer/Tab.java b/weblayer/public/java/org/chromium/weblayer/Tab.java index 9178b7a..ac81926 100644 --- a/weblayer/public/java/org/chromium/weblayer/Tab.java +++ b/weblayer/public/java/org/chromium/weblayer/Tab.java
@@ -312,7 +312,6 @@ @NonNull public NavigationController getNavigationController() { - ThreadCheck.ensureOnUiThread(); throwIfDestroyed(); return mNavigationController; }
diff --git a/weblayer/public/java/org/chromium/weblayer/TabNavigationControllerProxy.java b/weblayer/public/java/org/chromium/weblayer/TabNavigationControllerProxy.java new file mode 100644 index 0000000..916c470 --- /dev/null +++ b/weblayer/public/java/org/chromium/weblayer/TabNavigationControllerProxy.java
@@ -0,0 +1,62 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.weblayer; + +import android.net.Uri; +import android.os.Handler; +import android.os.Looper; +import android.os.RemoteException; + +import org.chromium.browserfragment.interfaces.IRequestNavigationCallback; +import org.chromium.browserfragment.interfaces.ITabNavigationControllerProxy; + +class TabNavigationControllerProxy extends ITabNavigationControllerProxy.Stub { + private final Handler mHandler = new Handler(Looper.getMainLooper()); + + private final NavigationController mNavigationController; + + TabNavigationControllerProxy(NavigationController navigationController) { + mNavigationController = navigationController; + } + + @Override + public void navigate(String uri) { + mHandler.post(() -> { + NavigateParams.Builder navigateParamsBuilder = + new NavigateParams.Builder().disableIntentProcessing(); + mNavigationController.navigate(Uri.parse(uri), navigateParamsBuilder.build()); + }); + } + + @Override + public void goBack() { + mHandler.post(() -> { mNavigationController.goBack(); }); + } + + @Override + public void goForward() { + mHandler.post(() -> { mNavigationController.goForward(); }); + } + + @Override + public void canGoBack(IRequestNavigationCallback callback) { + mHandler.post(() -> { + try { + callback.canNavigate(mNavigationController.canGoBack()); + } catch (RemoteException e) { + } + }); + } + + @Override + public void canGoForward(IRequestNavigationCallback callback) { + mHandler.post(() -> { + try { + callback.canNavigate(mNavigationController.canGoForward()); + } catch (RemoteException e) { + } + }); + } +} \ No newline at end of file
diff --git a/weblayer/public/java/org/chromium/weblayer/TabProxy.java b/weblayer/public/java/org/chromium/weblayer/TabProxy.java index 28bc6e0e..f98e0a2 100644 --- a/weblayer/public/java/org/chromium/weblayer/TabProxy.java +++ b/weblayer/public/java/org/chromium/weblayer/TabProxy.java
@@ -4,10 +4,10 @@ package org.chromium.weblayer; -import android.net.Uri; import android.os.Handler; import android.os.Looper; +import org.chromium.browserfragment.interfaces.ITabNavigationControllerProxy; import org.chromium.browserfragment.interfaces.ITabProxy; /** @@ -17,12 +17,17 @@ class TabProxy extends ITabProxy.Stub { private Handler mHandler = new Handler(Looper.getMainLooper()); + private final ITabNavigationControllerProxy mTabNavigationControllerProxy; + private int mTabId; private String mGuid; TabProxy(Tab tab) { mTabId = tab.getId(); mGuid = tab.getGuid(); + + mTabNavigationControllerProxy = + new TabNavigationControllerProxy(tab.getNavigationController()); } private Tab getTab() { @@ -30,20 +35,15 @@ } @Override - public void navigate(String uri) { - mHandler.post(() -> { - NavigateParams.Builder navigateParamsBuilder = - new NavigateParams.Builder().disableIntentProcessing(); - getTab().getNavigationController().navigate( - Uri.parse(uri), navigateParamsBuilder.build()); - }); - } - - @Override public void setActive() { mHandler.post(() -> { Tab tab = getTab(); tab.getBrowser().setActiveTab(tab); }); } + + @Override + public ITabNavigationControllerProxy getNavigationController() { + return mTabNavigationControllerProxy; + } } \ No newline at end of file
diff --git a/weblayer/shell/android/browserfragment_shell_apk/src/org/chromium/browserfragment/shell/BrowserFragmentShellActivity.java b/weblayer/shell/android/browserfragment_shell_apk/src/org/chromium/browserfragment/shell/BrowserFragmentShellActivity.java index 8390eb6a..72a0db4 100644 --- a/weblayer/shell/android/browserfragment_shell_apk/src/org/chromium/browserfragment/shell/BrowserFragmentShellActivity.java +++ b/weblayer/shell/android/browserfragment_shell_apk/src/org/chromium/browserfragment/shell/BrowserFragmentShellActivity.java
@@ -20,6 +20,7 @@ import org.chromium.browserfragment.BrowserFragment; import org.chromium.browserfragment.Tab; import org.chromium.browserfragment.TabManager; +import org.chromium.browserfragment.TabNavigationController; import org.chromium.browserfragment.TabObserver; /** @@ -30,6 +31,8 @@ private Context mContext; + private TabManager mTabManager; + @Override protected void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -83,8 +86,9 @@ Futures.addCallback(tabManagerFuture, new FutureCallback<TabManager>() { @Override public void onSuccess(TabManager tabManager) { + mTabManager = tabManager; Tab tab = tabManager.getActiveTab(); - tab.navigate("https://google.com"); + tab.getNavigationController().navigate("https://google.com"); } @Override public void onFailure(Throwable thrown) {} @@ -96,4 +100,35 @@ .add(R.id.fragment_container_view, fragment) .commit(); } + + @Override + public void onBackPressed() { + if (mTabManager == null) { + // BrowserFragment not yet initialized. + super.onBackPressed(); + } + Tab activeTab = mTabManager.getActiveTab(); + if (activeTab == null) { + // TODO(swestphal): Check if there are any tabs? + super.onBackPressed(); + } + TabNavigationController navigationController = activeTab.getNavigationController(); + + ListenableFuture<Boolean> canGoBackFuture = navigationController.canGoBack(); + + Futures.addCallback(canGoBackFuture, new FutureCallback<Boolean>() { + @Override + public void onSuccess(Boolean canGoBack) { + if (canGoBack) { + navigationController.goBack(); + } else { + BrowserFragmentShellActivity.super.onBackPressed(); + } + } + @Override + public void onFailure(Throwable thrown) { + BrowserFragmentShellActivity.super.onBackPressed(); + } + }, mContext.getMainExecutor()); + } }