diff --git a/DEPS b/DEPS index dc7b56a..5a180bc 100644 --- a/DEPS +++ b/DEPS
@@ -304,7 +304,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and whatever else without interference from each other. - 'skia_revision': 'c7c9cf8860da5fb237654ea5138374d693ae57c4', + 'skia_revision': 'c9694bab7fed39d279a99407be2851d3775f7959', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. @@ -312,11 +312,11 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ANGLE # and whatever else without interference from each other. - 'angle_revision': 'ed4851c12e2ceb7b0824c83acce888c77f5d1698', + 'angle_revision': '23ec06204174174a3bb5bec3edad6df87bbd50b2', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. - 'swiftshader_revision': '08f12cdc2290dfe803f1b1d936c04e08d1b8bdf9', + 'swiftshader_revision': 'ae4fde42a296af61dfc169aa8769e7b45058f6cb', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. @@ -375,7 +375,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': 'd52492be205d415f6c16e3201880b27ce139f8ad', + 'catapult_revision': '90ccad42f044abf42063a7468b9a64b44c3552bd', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling CrossBench # and whatever else without interference from each other. @@ -431,7 +431,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': '4299bd0ac9e80af6b43827d391ec63f3585ff143', + 'dawn_revision': '087deedbc81554cfdca85969a74629fd6ca3a378', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -479,7 +479,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. - 'libunwind_revision': '041196414ab036285f40c4fe6c3e761d2f012705', + 'libunwind_revision': '2868dcda2b0c2912e5c5d911992446a46a7fe4ae', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -790,7 +790,7 @@ 'src/clank': { 'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' + - '37cae201ad080f3a5ded5cfa13df60fd26eac781', + '811c7d5f7545a01d33ff119d58b0feadfd618344', 'condition': 'checkout_android and checkout_src_internal', }, @@ -799,7 +799,7 @@ }, 'src/ios/third_party/earl_grey2/src': { - 'url': Var('chromium_git') + '/external/github.com/google/EarlGrey.git' + '@' + '1049533da8dbe2a31eafa800c9ebe115c5642252', + 'url': Var('chromium_git') + '/external/github.com/google/EarlGrey.git' + '@' + '24f6f1977323fe5950da55b4c156518b3c9b3184', 'condition': 'checkout_ios', }, @@ -979,7 +979,7 @@ 'packages': [ { 'package': 'chromium/third_party/androidx', - 'version': '3B8F5G_FvmGQNHfDjnaEsK4d1ZIuuNlAGjw4zubOCuMC', + 'version': 'e_xThl5K5yWLuSiHwr9yxmTzliWlybPi5jubU1h0EWAC', }, ], 'condition': 'checkout_android', @@ -1219,7 +1219,7 @@ }, 'src/third_party/depot_tools': - Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '0a590f3e185c9541feeb75c5fd3b1bb68ffc0362', + Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '019e73a13bf58542f2572daba6fbc5e389c40607', 'src/third_party/devtools-frontend/src': Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'), @@ -1966,7 +1966,7 @@ Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'), 'src-internal': { - 'url': Var('chrome_git') + '/chrome/src-internal.git@91755631c876c6b2e9aa3306dbf456782991769d', + 'url': Var('chrome_git') + '/chrome/src-internal.git@ec0ed902ed73f885fb37cc943e6386de81ee6662', 'condition': 'checkout_src_internal', }, @@ -2007,7 +2007,7 @@ 'packages': [ { 'package': 'chromeos_internal/apps/media_app/app', - 'version': 'MpX0PGyQcMKkbC0mhA9Wemg97CWpQFATERGLF1iooL8C', + 'version': 'aXbijvAGHDsu_d9_wu1aANoFhYM2G0A1RdKE9gP5IjsC', }, ], 'condition': 'checkout_chromeos and checkout_src_internal', @@ -4548,7 +4548,7 @@ # Download Telemetry's binary dependencies via conditionals { 'name': 'checkout_telemetry_binary_dependencies', - 'condition': 'checkout_telemetry_dependencies', + 'condition': 'checkout_telemetry_dependencies or checkout_chromium_autofill_test_dependencies or checkout_chromium_password_manager_test_dependencies', 'pattern': '.', 'action': [ 'vpython3', 'src/third_party/catapult/telemetry/bin/fetch_telemetry_binary_dependencies',
diff --git a/ash/BUILD.gn b/ash/BUILD.gn index ebec2fb..7047f46e 100644 --- a/ash/BUILD.gn +++ b/ash/BUILD.gn
@@ -2224,14 +2224,6 @@ "wm/desks/desks_util.h", "wm/desks/expanded_desks_bar_button.cc", "wm/desks/expanded_desks_bar_button.h", - "wm/desks/persistent_desks_bar/persistent_desks_bar_button.cc", - "wm/desks/persistent_desks_bar/persistent_desks_bar_button.h", - "wm/desks/persistent_desks_bar/persistent_desks_bar_context_menu.cc", - "wm/desks/persistent_desks_bar/persistent_desks_bar_context_menu.h", - "wm/desks/persistent_desks_bar/persistent_desks_bar_controller.cc", - "wm/desks/persistent_desks_bar/persistent_desks_bar_controller.h", - "wm/desks/persistent_desks_bar/persistent_desks_bar_view.cc", - "wm/desks/persistent_desks_bar/persistent_desks_bar_view.h", "wm/desks/root_window_desk_switch_animator.cc", "wm/desks/root_window_desk_switch_animator.h", "wm/desks/scroll_arrow_button.cc", @@ -3574,6 +3566,8 @@ "//chromeos/ash/services/federated/public/cpp", "//chromeos/ash/services/federated/public/cpp:test_support", "//chromeos/ash/services/hotspot_config:hotspot_config", + "//chromeos/ash/services/hotspot_config:in_process_hotspot_config", + "//chromeos/ash/services/hotspot_config/public/cpp:test_support", "//chromeos/ash/services/multidevice_setup/public/cpp:test_support", "//chromeos/ash/services/multidevice_setup/public/mojom", "//chromeos/ash/services/nearby/public/cpp",
diff --git a/ash/app_list/views/app_list_view.cc b/ash/app_list/views/app_list_view.cc index aa2e1e1..92404680 100644 --- a/ash/app_list/views/app_list_view.cc +++ b/ash/app_list/views/app_list_view.cc
@@ -22,9 +22,7 @@ #include "ash/keyboard/ui/keyboard_ui_controller.h" #include "ash/public/cpp/app_list/app_list_types.h" #include "ash/public/cpp/metrics_util.h" -#include "ash/shell.h" #include "ash/strings/grit/ash_strings.h" -#include "ash/wm/work_area_insets.h" #include "base/functional/bind.h" #include "base/metrics/histogram_macros.h" #include "ui/base/l10n/l10n_util.h" @@ -638,16 +636,6 @@ if (!set_state_request) return; - // Bail out if `WorkAreaInsets::SetPersistentDeskBarHeight(int height)` causes - // another call to `SetState()`. Note, the persistent desks bar is created in - // the primary display for now. - if (Shell::HasInstance() && - WorkAreaInsets::ForWindow(Shell::GetPrimaryRootWindow()) - ->PersistentDeskBarHeightInChange() && - app_list_state_ == new_state) { - return; - } - MaybeCreateAccessibilityEvent(new_state); app_list_main_view_->contents_view()->OnAppListViewTargetStateChanged(
diff --git a/ash/ash_prefs.cc b/ash/ash_prefs.cc index b682556..a805dbf 100644 --- a/ash/ash_prefs.cc +++ b/ash/ash_prefs.cc
@@ -60,7 +60,6 @@ #include "ash/touch/touch_devices_controller.h" #include "ash/wallpaper/wallpaper_pref_manager.h" #include "ash/wm/desks/desks_restore_util.h" -#include "ash/wm/desks/persistent_desks_bar/persistent_desks_bar_controller.h" #include "ash/wm/desks/templates/saved_desk_util.h" #include "ash/wm/float/tablet_mode_tuck_education.h" #include "ash/wm/lock_state_controller.h" @@ -116,7 +115,6 @@ PaletteTray::RegisterProfilePrefs(registry); PaletteWelcomeBubble::RegisterProfilePrefs(registry); PciePeripheralNotificationController::RegisterProfilePrefs(registry); - PersistentDesksBarController::RegisterProfilePrefs(registry); PrivacyHubController::RegisterProfilePrefs(registry); PrivacyScreenController::RegisterProfilePrefs(registry); ProjectorControllerImpl::RegisterProfilePrefs(registry);
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd index 54baaee..0ce46787 100644 --- a/ash/ash_strings.grd +++ b/ash/ash_strings.grd
@@ -2581,6 +2581,9 @@ <message name="IDS_ASH_HOTSPOT_WIFI_TURNED_OFF_MESSAGE" desc="Message displayed in the system notification shown when WiFi is turned off upon enabling hotspot."> We've turned off the WiFi to start using Hotspot through Mobile data. This may incur data costs. </message> + <message name="IDS_ASH_HOTSPOT_WIFI_TURNED_ON_MESSAGE" desc="Message displayed in the system notification shown when hotspot is disabled due to WiFi being turned on."> + Hotspot has been turned off to use WiFi. To use Hotspot, turn WiFi off. + </message> <message name="IDS_ASH_HOTSPOT_ADMIN_RESTRICTED_MESSAGE" desc="Message displayed in the system notification shown when the hotspot is turned off by the administrator."> Your administrator has turned Hotspot off. </message> @@ -5848,16 +5851,6 @@ <message name="IDS_ASH_A11Y_DICTATION_NOTIFICATION_ONLY_SODA_DOWNLOADED_DESC" desc="The description for a notification that is shown when speech recognition files download successfully. This notification is only shown if speech recognition assets are downloaded and command parsing assets are not."> Speech is processed locally and dictation works offline, but some voice commands won’t work. </message> - <!-- Strings for persistent desks bar--> - <message name="IDS_ASH_PERSISTENT_DESKS_BAR_CONTEXT_MENU_FEEDBACK" desc="Title of the menu item in the context menu to send feedback."> - Feedback - </message> - <message name="IDS_ASH_PERSISTENT_DESKS_BAR_CONTEXT_MENU_SHOW_DESKS_BAR" desc="Title of the menu item in the context menu to show the desks bar."> - Show deskbar - </message> - <message name="IDS_ASH_PERSISTENT_DESKS_BAR_CONTEXT_MENU_HIDE_DESKS_BAR" desc="Title of the menu item in the context menu to hide the desks bar."> - Hide deskbar - </message> <!-- Debugd notification strings --> <message name="IDS_ASH_DEBUG_PACKET_CAPTURE_STARTED" desc="The label used for the notification to indicate network packet capture operation has started and network information is being collected on the device.">
diff --git a/ash/ash_strings_grd/IDS_ASH_HOTSPOT_WIFI_TURNED_ON_MESSAGE.png.sha1 b/ash/ash_strings_grd/IDS_ASH_HOTSPOT_WIFI_TURNED_ON_MESSAGE.png.sha1 new file mode 100644 index 0000000..2db8e0e7 --- /dev/null +++ b/ash/ash_strings_grd/IDS_ASH_HOTSPOT_WIFI_TURNED_ON_MESSAGE.png.sha1
@@ -0,0 +1 @@ +6e5e4264f14a3000f4ca776dcf237888efdfaf6f \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_PERSISTENT_DESKS_BAR_CONTEXT_MENU_FEEDBACK.png.sha1 b/ash/ash_strings_grd/IDS_ASH_PERSISTENT_DESKS_BAR_CONTEXT_MENU_FEEDBACK.png.sha1 deleted file mode 100644 index 7fda3e7..0000000 --- a/ash/ash_strings_grd/IDS_ASH_PERSISTENT_DESKS_BAR_CONTEXT_MENU_FEEDBACK.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -f1c088eeda6fc7e607c2bdacaba9d80e2bc792b2 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_PERSISTENT_DESKS_BAR_CONTEXT_MENU_HIDE_DESKS_BAR.png.sha1 b/ash/ash_strings_grd/IDS_ASH_PERSISTENT_DESKS_BAR_CONTEXT_MENU_HIDE_DESKS_BAR.png.sha1 deleted file mode 100644 index 13e5576..0000000 --- a/ash/ash_strings_grd/IDS_ASH_PERSISTENT_DESKS_BAR_CONTEXT_MENU_HIDE_DESKS_BAR.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -0d9869089801ef85b897f6895f129e17d1df62a8 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_PERSISTENT_DESKS_BAR_CONTEXT_MENU_SHOW_DESKS_BAR.png.sha1 b/ash/ash_strings_grd/IDS_ASH_PERSISTENT_DESKS_BAR_CONTEXT_MENU_SHOW_DESKS_BAR.png.sha1 deleted file mode 100644 index 9e8a739ae..0000000 --- a/ash/ash_strings_grd/IDS_ASH_PERSISTENT_DESKS_BAR_CONTEXT_MENU_SHOW_DESKS_BAR.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -403e462388a9823e41e1083ad9becb078656582e \ No newline at end of file
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc index d70d80d..510fd33 100644 --- a/ash/constants/ash_features.cc +++ b/ash/constants/ash_features.cc
@@ -234,10 +234,6 @@ "AvatarsCloudMigration", base::FEATURE_ENABLED_BY_DEFAULT); -// Enables the persistent desks bar at the top of the screen in clamshell mode -// when there are more than one desk. -BASE_FEATURE(kBentoBar, "BentoBar", base::FEATURE_DISABLED_BY_DEFAULT); - // Enables or disables the usage of fixed Bluetooth A2DP packet size to improve // audio performance in noisy environment. BASE_FEATURE(kBluetoothFixA2dpPacketSize, @@ -779,6 +775,10 @@ &kEolIncentive, "incentive_type", EolIncentiveParam::kNoOffer, &eol_incentive_options}; +BASE_FEATURE(kEolIncentiveSettings, + "EolIncentiveSettings", + base::FEATURE_DISABLED_BY_DEFAULT); + // Enable or disable support for touchpad with haptic feedback. BASE_FEATURE(kExoHapticFeedbackSupport, "ExoHapticFeedbackSupport", @@ -843,6 +843,12 @@ "FastPairBleRotation", base::FEATURE_ENABLED_BY_DEFAULT); +// Sets mode to DEBUG when fetching metadata from the Nearby server, allowing +// debug devices to trigger Fast Pair notifications. +BASE_FEATURE(kFastPairDebugMetadata, + "FastPairDebugMetadata", + base::FEATURE_DISABLED_BY_DEFAULT); + // Enables using new Handshake retry logic for Fast Pair. BASE_FEATURE(kFastPairHandshakeRefactor, "FastPairHandshakeRefactor", @@ -1848,12 +1854,6 @@ "ReleaseNotesSuggestionChip", base::FEATURE_ENABLED_BY_DEFAULT); -// Enables or disables display of the release track in the system tray and quick -// settings, for devices running on channels other than "stable." -BASE_FEATURE(kReleaseTrackUi, - "ReleaseTrackUi", - base::FEATURE_ENABLED_BY_DEFAULT); - // Enables rendering ARC notifications using ChromeOS notification framework BASE_FEATURE(kRenderArcNotificationsByChrome, "RenderArcNotificationsByChrome", @@ -2503,10 +2503,6 @@ #endif } -bool IsBentoBarEnabled() { - return base::FeatureList::IsEnabled(kBentoBar); -} - bool IsBluetoothQualityReportEnabled() { return base::FeatureList::IsEnabled(kBluetoothQualityReport); } @@ -2669,6 +2665,10 @@ return base::FeatureList::IsEnabled(kFastPairBleRotation); } +bool IsFastPairDebugMetadataEnabled() { + return base::FeatureList::IsEnabled(kFastPairDebugMetadata); +} + bool IsFastPairHandshakeRefactorEnabled() { return base::FeatureList::IsEnabled(kFastPairHandshakeRefactor); } @@ -3245,10 +3245,6 @@ return base::FeatureList::IsEnabled(kEnablePerDeskZOrder); } -bool IsReleaseTrackUiEnabled() { - return base::FeatureList::IsEnabled(kReleaseTrackUi); -} - bool IsRenderArcNotificationsByChromeEnabled() { return base::FeatureList::IsEnabled(kRenderArcNotificationsByChrome); }
diff --git a/ash/constants/ash_features.h b/ash/constants/ash_features.h index f41122f..4797f82 100644 --- a/ash/constants/ash_features.h +++ b/ash/constants/ash_features.h
@@ -70,7 +70,6 @@ COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kAutozoomNudgeSessionReset); COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kAvatarsCloudMigration); -COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kBentoBar); COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kBluetoothFixA2dpPacketSize); COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kBluetoothQualityReport); @@ -234,6 +233,7 @@ enum class EolIncentiveParam { kNoOffer, kOffer, kOfferWithWarning }; COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::FeatureParam<EolIncentiveParam> kEolIncentiveParam; +COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kEolIncentiveSettings); COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kExoHapticFeedbackSupport); COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kExoLinuxDmabufV3); COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kExoLinuxDmabufV4); @@ -247,6 +247,7 @@ COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kFastPair); COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kFastPairBleRotation); +COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kFastPairDebugMetadata); COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kFastPairHandshakeRefactor); COMPONENT_EXPORT(ASH_CONSTANTS) @@ -533,7 +534,6 @@ BASE_DECLARE_FEATURE(kReleaseNotesNotificationAllChannels); COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kReleaseNotesSuggestionChip); -COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kReleaseTrackUi); COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kRenderArcNotificationsByChrome); COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kReverseScrollGestures); @@ -686,7 +686,6 @@ bool IsAudioPeripheralVolumeGranularityEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsAutoNightLightEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsBackgroundBlurEnabled(); -COMPONENT_EXPORT(ASH_CONSTANTS) bool IsBentoBarEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsBluetoothQualityReportEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsCalendarJellyEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsCaptivePortalErrorPageEnabled(); @@ -730,6 +729,7 @@ COMPONENT_EXPORT(ASH_CONSTANTS) bool IsFamilyLinkOnSchoolDeviceEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsFastPairEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsFastPairBleRotationEnabled(); +COMPONENT_EXPORT(ASH_CONSTANTS) bool IsFastPairDebugMetadataEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsFastPairHandshakeRefactorEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsFastPairHIDEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsFastPairSavedDevicesNicknamesEnabled(); @@ -884,7 +884,6 @@ COMPONENT_EXPORT(ASH_CONSTANTS) bool IsQuickDimEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsPerDeskZOrderEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsPersonalizationJellyEnabled(); -COMPONENT_EXPORT(ASH_CONSTANTS) bool IsReleaseTrackUiEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsRenderArcNotificationsByChromeEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsReverseScrollGesturesEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsRgbKeyboardEnabled();
diff --git a/ash/public/cpp/style/color_provider.h b/ash/public/cpp/style/color_provider.h index f2ce21b..3092732 100644 --- a/ash/public/cpp/style/color_provider.h +++ b/ash/public/cpp/style/color_provider.h
@@ -57,12 +57,6 @@ kControlBackgroundColorPositive, kFocusAuraColor, kFocusRingColor, - kHighlightColor1, - kHighlightColor2, - kHighlightColor3, - kBorderColor1, - kBorderColor2, - kBorderColor3, }; enum class ContentLayerType {
diff --git a/ash/quick_pair/repository/fast_pair/device_metadata_fetcher.cc b/ash/quick_pair/repository/fast_pair/device_metadata_fetcher.cc index 86ddfaf..1cc782a 100644 --- a/ash/quick_pair/repository/fast_pair/device_metadata_fetcher.cc +++ b/ash/quick_pair/repository/fast_pair/device_metadata_fetcher.cc
@@ -4,6 +4,7 @@ #include "ash/quick_pair/repository/fast_pair/device_metadata_fetcher.h" +#include "ash/constants/ash_features.h" #include "ash/quick_pair/common/fast_pair/fast_pair_http_result.h" #include "ash/quick_pair/common/fast_pair/fast_pair_metrics.h" #include "ash/quick_pair/common/logging.h" @@ -19,7 +20,9 @@ const char kGetObservedDeviceUrl[] = "https://nearbydevices-pa.googleapis.com/v1/device/" - "%d?key=%s&mode=MODE_RELEASE&alt=proto"; + "%d?key=%s&mode=%s&alt=proto"; +const char kReleaseMode[] = "MODE_RELEASE"; +const char kDebugMode[] = "MODE_DEBUG"; const net::NetworkTrafficAnnotationTag kTrafficAnnotation = net::DefineNetworkTrafficAnnotation("fast_pair_device_metadata_fetcher", R"( @@ -63,8 +66,17 @@ void DeviceMetadataFetcher::LookupDeviceId(int id, GetObservedDeviceCallback callback) { + const char* mode; + if (features::IsFastPairDebugMetadataEnabled()) { + QP_LOG(INFO) << __func__ << ": Fetching DEBUG_MODE metadata."; + mode = kDebugMode; + } else { + mode = kReleaseMode; + } + GURL url = GURL(base::StringPrintf(kGetObservedDeviceUrl, id, - google_apis::GetAPIKey().c_str())); + google_apis::GetAPIKey().c_str(), mode)); + http_fetcher_->ExecuteGetRequest( url, base::BindOnce(&DeviceMetadataFetcher::OnFetchComplete, weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
diff --git a/ash/resources/vector_icons/BUILD.gn b/ash/resources/vector_icons/BUILD.gn index d0de142..eab3730 100644 --- a/ash/resources/vector_icons/BUILD.gn +++ b/ash/resources/vector_icons/BUILD.gn
@@ -235,11 +235,6 @@ "palette_tray_icon_projector_red.icon", "palette_tray_icon_projector_yellow.icon", "pause.icon", - "persistent_desks_bar_chevron_down.icon", - "persistent_desks_bar_feedback.icon", - "persistent_desks_bar_not_visible.icon", - "persistent_desks_bar_vertical_dots.icon", - "persistent_desks_bar_visible.icon", "phone_hub_battery_saver.icon", "phone_hub_battery_saver_outline.icon", "phone_hub_battery_saver_outline_mask.icon", @@ -521,6 +516,7 @@ "unpinned.icon", "unrendered_html_placeholder.icon", "upgrade.icon", + "vertical_dots.icon", "video_conference_background_blur_light.icon", "video_conference_background_blur_maximum.icon", "video_conference_background_blur_off.icon",
diff --git a/ash/resources/vector_icons/persistent_desks_bar_chevron_down.icon b/ash/resources/vector_icons/persistent_desks_bar_chevron_down.icon deleted file mode 100644 index 98a68638..0000000 --- a/ash/resources/vector_icons/persistent_desks_bar_chevron_down.icon +++ /dev/null
@@ -1,13 +0,0 @@ -// Copyright 2021 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -CANVAS_DIMENSIONS, 20, -MOVE_TO, 5.41f, 6, -LINE_TO, 10, 10.94f, -LINE_TO, 14.59f, 6, -LINE_TO, 16, 7.52f, -LINE_TO, 10, 14, -LINE_TO, 4, 7.52f, -LINE_TO, 5.41f, 6, -CLOSE
diff --git a/ash/resources/vector_icons/persistent_desks_bar_feedback.icon b/ash/resources/vector_icons/persistent_desks_bar_feedback.icon deleted file mode 100644 index 0d6405f2..0000000 --- a/ash/resources/vector_icons/persistent_desks_bar_feedback.icon +++ /dev/null
@@ -1,35 +0,0 @@ -// Copyright 2021 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -CANVAS_DIMENSIONS, 20, -MOVE_TO, 9, 5, -H_LINE_TO, 11, -V_LINE_TO, 9, -H_LINE_TO, 9, -V_LINE_TO, 5, -CLOSE, -NEW_PATH, -MOVE_TO, 9, 10, -H_LINE_TO, 11, -V_LINE_TO, 12, -H_LINE_TO, 9, -V_LINE_TO, 10, -CLOSE, -NEW_PATH, -MOVE_TO, 3.67f, 2, -H_LINE_TO, 16, -CUBIC_TO, 16.92f, 2, 18, 2.58f, 18, 3.5f, -V_LINE_TO, 13.5f, -CUBIC_TO, 18, 14.42f, 16.92f, 15, 16, 15, -H_LINE_TO, 5, -LINE_TO, 2, 17.5f, -LINE_TO, 2.01f, 3.67f, -CUBIC_TO, 2.01f, 2.75f, 2.75f, 2, 3.67f, 2, -CLOSE, -MOVE_TO, 4, 13, -H_LINE_TO, 16, -V_LINE_TO, 4, -H_LINE_TO, 4, -V_LINE_TO, 13, -CLOSE
diff --git a/ash/resources/vector_icons/persistent_desks_bar_not_visible.icon b/ash/resources/vector_icons/persistent_desks_bar_not_visible.icon deleted file mode 100644 index bcb1d318..0000000 --- a/ash/resources/vector_icons/persistent_desks_bar_not_visible.icon +++ /dev/null
@@ -1,42 +0,0 @@ -// Copyright 2021 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -CANVAS_DIMENSIONS, 20, -MOVE_TO, 17.39f, 18.02f, -LINE_TO, 1.99f, 2.62f, -LINE_TO, 2.01f, 2.6f, -LINE_TO, 0.59f, 4, -LINE_TO, 3.29f, 6.71f, -CUBIC_TO, 2.42f, 7.59f, 1.66f, 8.69f, 1, 10, -CUBIC_TO, 2.67f, 14, 5.67f, 16, 10, 16, -CUBIC_TO, 10.84f, 16, 11.62f, 15.93f, 12.36f, 15.78f, -LINE_TO, 16, 19.41f, -LINE_TO, 17.39f, 18.02f, -CLOSE, -MOVE_TO, 3.24f, 10.07f, -CUBIC_TO, 3.68f, 9.31f, 4.17f, 8.66f, 4.71f, 8.12f, -LINE_TO, 7.03f, 10.45f, -CUBIC_TO, 7.23f, 11.75f, 8.25f, 12.77f, 9.55f, 12.97f, -LINE_TO, 10.57f, 13.99f, -CUBIC_TO, 10.39f, 14, 10.19f, 14, 10, 14, -CUBIC_TO, 6.79f, 14, 4.62f, 12.75f, 3.24f, 10.07f, -CLOSE, -NEW_PATH, -MOVE_TO, 16.18f, 13.99f, -CUBIC_TO, 17.36f, 13.02f, 18.3f, 11.69f, 19, 10, -CUBIC_TO, 17, 6, 14, 4, 10, 4, -CUBIC_TO, 8.82f, 4, 7.72f, 4.17f, 6.72f, 4.52f, -LINE_TO, 8.35f, 6.15f, -CUBIC_TO, 8.87f, 6.05f, 9.42f, 6, 10, 6, -CUBIC_TO, 12.94f, 6, 15.13f, 7.29f, 16.76f, 10.07f, -CUBIC_TO, 16.22f, 11.12f, 15.56f, 11.95f, 14.76f, 12.57f, -LINE_TO, 16.18f, 13.99f, -CLOSE, -NEW_PATH, -MOVE_TO, 12.91f, 10.72f, -LINE_TO, 9.28f, 7.09f, -CUBIC_TO, 9.51f, 7.03f, 9.75f, 7, 10, 7, -CUBIC_TO, 11.66f, 7, 13, 8.34f, 13, 10, -CUBIC_TO, 13, 10.25f, 12.97f, 10.49f, 12.91f, 10.72f, -CLOSE
diff --git a/ash/resources/vector_icons/persistent_desks_bar_visible.icon b/ash/resources/vector_icons/persistent_desks_bar_visible.icon deleted file mode 100644 index a3d4a5a2..0000000 --- a/ash/resources/vector_icons/persistent_desks_bar_visible.icon +++ /dev/null
@@ -1,29 +0,0 @@ -// Copyright 2021 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -CANVAS_DIMENSIONS, 20, -MOVE_TO, 13, 10, -CUBIC_TO, 13, 11.66f, 11.66f, 13, 10, 13, -CUBIC_TO, 8.34f, 13, 7, 11.66f, 7, 10, -CUBIC_TO, 7, 8.34f, 8.34f, 7, 10, 7, -CUBIC_TO, 11.66f, 7, 13, 8.34f, 13, 10, -CLOSE, -MOVE_TO, 11, 10, -CUBIC_TO, 11, 10.55f, 10.55f, 11, 10, 11, -CUBIC_TO, 9.45f, 11, 9, 10.55f, 9, 10, -CUBIC_TO, 9, 9.45f, 9.45f, 9, 10, 9, -CUBIC_TO, 10.55f, 9, 11, 9.45f, 11, 10, -CLOSE, -MOVE_TO, 10, 16, -CUBIC_TO, 14.33f, 16, 17.33f, 14, 19, 10, -CUBIC_TO, 17, 6, 14, 4, 10, 4, -CUBIC_TO, 6, 4, 3, 6, 1, 10, -CUBIC_TO, 2.67f, 14, 5.67f, 16, 10, 16, -CLOSE, -MOVE_TO, 10, 6, -CUBIC_TO, 12.94f, 6, 15.13f, 7.29f, 16.76f, 10.07f, -CUBIC_TO, 15.38f, 12.75f, 13.21f, 14, 10, 14, -CUBIC_TO, 6.79f, 14, 4.62f, 12.75f, 3.24f, 10.07f, -CUBIC_TO, 4.87f, 7.29f, 7.06f, 6, 10, 6, -CLOSE
diff --git a/ash/resources/vector_icons/persistent_desks_bar_vertical_dots.icon b/ash/resources/vector_icons/vertical_dots.icon similarity index 100% rename from ash/resources/vector_icons/persistent_desks_bar_vertical_dots.icon rename to ash/resources/vector_icons/vertical_dots.icon
diff --git a/ash/shell.cc b/ash/shell.cc index a5fdc3d..72ffbc1 100644 --- a/ash/shell.cc +++ b/ash/shell.cc
@@ -182,7 +182,6 @@ #include "ash/wm/container_finder.h" #include "ash/wm/cursor_manager_chromeos.h" #include "ash/wm/desks/desks_controller.h" -#include "ash/wm/desks/persistent_desks_bar/persistent_desks_bar_controller.h" #include "ash/wm/desks/templates/saved_desk_controller.h" #include "ash/wm/event_client_impl.h" #include "ash/wm/float/float_controller.h" @@ -762,11 +761,6 @@ shelf_controller_->Shutdown(); shelf_config_->Shutdown(); - // Destroy PersistentDesksBarController before `overview_controller_`, - // `tablet_mode_controller_`, `desks_controller_` and - // `app_list_controller_` that it observes. - persistent_desks_bar_controller_.reset(); - // Depends on `app_list_controller_` and `tablet_mode_controller_`. app_list_feature_usage_metrics_.reset(); @@ -1459,14 +1453,6 @@ // used in its constructor. app_list_controller_ = std::make_unique<AppListControllerImpl>(); - // Create PersistentDesksBarController after `overview_controller_`, - // `tablet_mode_controller_`, `desks_controller_` and - // `app_list_controller_` that it observes. - if (features::IsBentoBarEnabled()) { - persistent_desks_bar_controller_ = - std::make_unique<PersistentDesksBarController>(); - } - autoclick_controller_ = std::make_unique<AutoclickController>(); color_enhancement_controller_ =
diff --git a/ash/shell.h b/ash/shell.h index d588d4a..8a979c1 100644 --- a/ash/shell.h +++ b/ash/shell.h
@@ -190,7 +190,6 @@ class UsbPeripheralNotificationController; class PeripheralBatteryListener; class PeripheralBatteryNotifier; -class PersistentDesksBarController; class PersistentWindowController; class PolicyRecommendationRestorer; class PowerButtonController; @@ -449,9 +448,6 @@ return dark_light_mode_controller_.get(); } DesksController* desks_controller() { return desks_controller_.get(); } - PersistentDesksBarController* persistent_desks_bar_controller() { - return persistent_desks_bar_controller_.get(); - } SavedDeskController* saved_desk_controller() { return saved_desk_controller_.get(); } @@ -985,8 +981,6 @@ std::unique_ptr<PrivacyHubController> privacy_hub_controller_; std::unique_ptr<UsbPeripheralNotificationController> usb_peripheral_notification_controller_; - std::unique_ptr<PersistentDesksBarController> - persistent_desks_bar_controller_; std::unique_ptr<RgbKeyboardManager> rgb_keyboard_manager_; std::unique_ptr<RasterScaleController> raster_scale_controller_; std::unique_ptr<ResizeShadowController> resize_shadow_controller_;
diff --git a/ash/shell_delegate.h b/ash/shell_delegate.h index d64df7f..b8cc0281 100644 --- a/ash/shell_delegate.h +++ b/ash/shell_delegate.h
@@ -48,7 +48,6 @@ class ASH_EXPORT ShellDelegate { public: enum class FeedbackSource { - kBentoBar, kWindowLayoutMenu, };
diff --git a/ash/style/ash_color_provider.cc b/ash/style/ash_color_provider.cc index f8692ef6..f90cc67b 100644 --- a/ash/style/ash_color_provider.cc +++ b/ash/style/ash_color_provider.cc
@@ -99,18 +99,6 @@ return color_provider->GetColor(kColorAshFocusAuraColor); case ControlsLayerType::kFocusRingColor: return color_provider->GetColor(ui::kColorAshFocusRing); - case ControlsLayerType::kHighlightColor1: - return color_provider->GetColor(ui::kColorHighlightBorderHighlight1); - case ControlsLayerType::kHighlightColor2: - return color_provider->GetColor(ui::kColorHighlightBorderHighlight2); - case ControlsLayerType::kHighlightColor3: - return color_provider->GetColor(ui::kColorHighlightBorderHighlight3); - case ControlsLayerType::kBorderColor1: - return color_provider->GetColor(ui::kColorHighlightBorderBorder1); - case ControlsLayerType::kBorderColor2: - return color_provider->GetColor(ui::kColorHighlightBorderBorder2); - case ControlsLayerType::kBorderColor3: - return color_provider->GetColor(ui::kColorHighlightBorderBorder3); } }
diff --git a/ash/style/ash_color_provider_unittest.cc b/ash/style/ash_color_provider_unittest.cc index 78b51371..a7f71e7 100644 --- a/ash/style/ash_color_provider_unittest.cc +++ b/ash/style/ash_color_provider_unittest.cc
@@ -173,18 +173,6 @@ SkColorSetARGB(0x3D, 0x8A, 0xB4, 0xF8)}, {ColorMode::kDark, ColorProvider::ControlsLayerType::kFocusRingColor, SkColorSetRGB(0x8A, 0xB4, 0xF8)}, - {ColorMode::kDark, ColorProvider::ControlsLayerType::kHighlightColor1, - SkColorSetARGB(0x14, 0xFF, 0xFF, 0xFF)}, - {ColorMode::kDark, ColorProvider::ControlsLayerType::kHighlightColor2, - SkColorSetARGB(0x0F, 0xFF, 0xFF, 0xFF)}, - {ColorMode::kDark, ColorProvider::ControlsLayerType::kHighlightColor3, - SkColorSetARGB(0x14, 0xFF, 0xFF, 0xFF)}, - {ColorMode::kDark, ColorProvider::ControlsLayerType::kBorderColor1, - SkColorSetARGB(0xCC, 0x20, 0x21, 0x24)}, - {ColorMode::kDark, ColorProvider::ControlsLayerType::kBorderColor2, - SkColorSetARGB(0x99, 0x20, 0x21, 0x24)}, - {ColorMode::kDark, ColorProvider::ControlsLayerType::kBorderColor3, - SkColorSetARGB(0x0F, 0x0, 0x0, 0x0)}, // Light mode {ColorMode::kLight, @@ -208,19 +196,7 @@ {ColorMode::kLight, ColorProvider::ControlsLayerType::kFocusAuraColor, SkColorSetARGB(0x3D, 0x1A, 0x73, 0xE8)}, {ColorMode::kLight, ColorProvider::ControlsLayerType::kFocusRingColor, - SkColorSetRGB(0x1A, 0x73, 0xE8)}, - {ColorMode::kLight, ColorProvider::ControlsLayerType::kHighlightColor1, - SkColorSetARGB(0x4C, 0xFF, 0xFF, 0xFF)}, - {ColorMode::kLight, ColorProvider::ControlsLayerType::kHighlightColor2, - SkColorSetARGB(0x33, 0xFF, 0xFF, 0xFF)}, - {ColorMode::kLight, ColorProvider::ControlsLayerType::kHighlightColor3, - SkColorSetARGB(0x4C, 0xFF, 0xFF, 0xFF)}, - {ColorMode::kLight, ColorProvider::ControlsLayerType::kBorderColor1, - SkColorSetARGB(0x0F, 0x0, 0x0, 0x0)}, - {ColorMode::kLight, ColorProvider::ControlsLayerType::kBorderColor2, - SkColorSetARGB(0x0F, 0x0, 0x0, 0x0)}, - {ColorMode::kLight, ColorProvider::ControlsLayerType::kBorderColor3, - SkColorSetARGB(0x0F, 0x0, 0x0, 0x0)}})); + SkColorSetRGB(0x1A, 0x73, 0xE8)}})); class AshColorProviderContentTest : public AshColorProviderBase<ColorProvider::ContentLayerType> {};
diff --git a/ash/style/dark_light_mode_controller_impl.cc b/ash/style/dark_light_mode_controller_impl.cc index e949128b..e6c065d 100644 --- a/ash/style/dark_light_mode_controller_impl.cc +++ b/ash/style/dark_light_mode_controller_impl.cc
@@ -254,8 +254,11 @@ void DarkLightModeControllerImpl::NotifyIfDarkModeChanged( bool old_is_dark_mode_enabled) { - if (old_is_dark_mode_enabled == IsDarkModeEnabled()) + // If this is the first check, always notify. + if (last_value_.has_value() && + old_is_dark_mode_enabled == IsDarkModeEnabled()) { return; + } NotifyColorModeChanges(); }
diff --git a/ash/system/channel_indicator/channel_indicator_unittest.cc b/ash/system/channel_indicator/channel_indicator_unittest.cc index 2e8cea4d..da3e3b3 100644 --- a/ash/system/channel_indicator/channel_indicator_unittest.cc +++ b/ash/system/channel_indicator/channel_indicator_unittest.cc
@@ -4,7 +4,6 @@ #include "ash/system/channel_indicator/channel_indicator.h" -#include "ash/constants/ash_features.h" #include "ash/public/cpp/shelf_types.h" #include "ash/resources/vector_icons/vector_icons.h" #include "ash/session/session_controller_impl.h" @@ -17,7 +16,6 @@ #include "ash/system/unified/unified_system_tray.h" #include "ash/test/ash_test_base.h" #include "ash/test_shell_delegate.h" -#include "base/test/scoped_feature_list.h" #include "components/session_manager/session_manager_types.h" #include "components/version_info/channel.h" #include "ui/views/controls/image_view.h" @@ -44,10 +42,6 @@ // AshTestBase: void SetUp() override { - // Need this feature enabled in order for the `ChannelIndicatorView` to be - // instantiated. - feature_list_.InitAndEnableFeature(features::kReleaseTrackUi); - // Instantiate a `TestShellDelegate` with the channel set to our param. std::unique_ptr<TestShellDelegate> shell_delegate = std::make_unique<TestShellDelegate>(); @@ -78,9 +72,6 @@ } return is_squished; } - - private: - base::test::ScopedFeatureList feature_list_; }; // Run the `Visible` test below for each value of version_info::Channel.
diff --git a/ash/system/media/quick_settings_media_view.cc b/ash/system/media/quick_settings_media_view.cc index 748c799..5c0124a 100644 --- a/ash/system/media/quick_settings_media_view.cc +++ b/ash/system/media/quick_settings_media_view.cc
@@ -4,8 +4,11 @@ #include "ash/system/media/quick_settings_media_view.h" +#include "ash/public/cpp/pagination/pagination_controller.h" +#include "ash/public/cpp/pagination/pagination_model.h" #include "ash/public/cpp/pagination/pagination_model_observer.h" #include "ash/strings/grit/ash_strings.h" +#include "ash/style/pagination_view.h" #include "ash/system/media/quick_settings_media_view_controller.h" #include "components/global_media_controls/public/views/media_item_ui_view.h" #include "ui/base/l10n/l10n_util.h" @@ -96,6 +99,10 @@ pagination_view_->SetPaintToLayer(); pagination_view_->layer()->SetFillsBoundsOpaquely(false); + pagination_controller_ = std::make_unique<PaginationController>( + pagination_model_.get(), PaginationController::SCROLL_AXIS_HORIZONTAL, + base::BindRepeating([](ui::EventType) {})); + SetAccessibleName(l10n_util::GetStringUTF16( IDS_ASH_QUICK_SETTINGS_BUBBLE_MEDIA_CONTROLS_SUB_MENU_ACCESSIBLE_DESCRIPTION)); } @@ -123,6 +130,20 @@ pagination_view_->SetVisible(items_.size() > 1); } +void QuickSettingsMediaView::OnGestureEvent(ui::GestureEvent* event) { + // The pagination controller will handle the touch gesture event to swipe + // between media items. + if (pagination_controller_->OnGestureEvent(*event, GetContentsBounds())) { + event->SetHandled(); + } else if (event->type() == ui::ET_GESTURE_TAP) { + // A tap gesture is handled in the same way as a mouse click event. The + // controller does not need to know the item id for now so we do not need to + // record it. + controller_->OnMediaItemUIClicked(/*id=*/""); + event->SetHandled(); + } +} + /////////////////////////////////////////////////////////////////////////////// // QuickSettingsMediaView implementations:
diff --git a/ash/system/media/quick_settings_media_view.h b/ash/system/media/quick_settings_media_view.h index 99a8f1f..beae7ae5 100644 --- a/ash/system/media/quick_settings_media_view.h +++ b/ash/system/media/quick_settings_media_view.h
@@ -8,8 +8,6 @@ #include <map> #include "ash/ash_export.h" -#include "ash/public/cpp/pagination/pagination_model.h" -#include "ash/style/pagination_view.h" #include "ui/views/view.h" namespace global_media_controls { @@ -22,6 +20,9 @@ class MediaScrollView; } // namespace +class PaginationController; +class PaginationModel; +class PaginationView; class QuickSettingsMediaViewController; // Media view displayed in the quick settings view. @@ -35,6 +36,7 @@ // views::View: gfx::Size CalculatePreferredSize() const override; void Layout() override; + void OnGestureEvent(ui::GestureEvent* event) override; // Shows the given media item in the media view. void ShowItem(const std::string& id, @@ -48,6 +50,8 @@ std::unique_ptr<PaginationModel> pagination_model_; + std::unique_ptr<PaginationController> pagination_controller_; + raw_ptr<MediaScrollView> media_scroll_view_ = nullptr; raw_ptr<PaginationView> pagination_view_ = nullptr;
diff --git a/ash/system/message_center/ash_notification_view.cc b/ash/system/message_center/ash_notification_view.cc index 7090277..8728aa2 100644 --- a/ash/system/message_center/ash_notification_view.cc +++ b/ash/system/message_center/ash_notification_view.cc
@@ -20,6 +20,7 @@ #include "ash/style/dark_light_mode_controller_impl.h" #include "ash/style/icon_button.h" #include "ash/style/pill_button.h" +#include "ash/style/typography.h" #include "ash/system/message_center/ash_notification_control_button_factory.h" #include "ash/system/message_center/ash_notification_drag_controller.h" #include "ash/system/message_center/ash_notification_expand_button.h" @@ -42,6 +43,7 @@ #include "ui/base/dragdrop/os_exchange_data.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/metadata/metadata_impl_macros.h" +#include "ui/chromeos/styles/cros_tokens_color_mappings.h" #include "ui/color/color_id.h" #include "ui/color/color_provider.h" #include "ui/compositor/animation_throughput_reporter.h" @@ -356,6 +358,17 @@ timestamp_in_collapsed_view_->SetProperty(views::kMarginsKey, kTimeStampInCollapsedStatePadding); timestamp_in_collapsed_view_->SetElideBehavior(gfx::ElideBehavior::NO_ELIDE); + if (chromeos::features::IsJellyEnabled()) { + ash::TypographyProvider::Get()->StyleLabel( + ash::TypographyToken::kCrosButton2, *title_view_); + title_view_->SetEnabledColorId(cros_tokens::kCrosSysSurface); + + timestamp_in_collapsed_view_->SetEnabledColorId( + cros_tokens::kCrosSysSecondary); + ash::TypographyProvider::Get()->StyleLabel( + ash::TypographyToken::kCrosAnnotation1, *timestamp_in_collapsed_view_); + } + title_view_->SetProperty( views::kFlexBehaviorKey, views::FlexSpecification(views::MinimumFlexSizeRule::kScaleToMinimum,
diff --git a/ash/system/network/hotspot_notifier.cc b/ash/system/network/hotspot_notifier.cc index 5c6487c..47a7a91 100644 --- a/ash/system/network/hotspot_notifier.cc +++ b/ash/system/network/hotspot_notifier.cc
@@ -19,6 +19,9 @@ const char HotspotNotifier::kAdminRestrictedNotificationId[] = "cros_hotspot_notifier_ids.admin_restricted"; +const char HotspotNotifier::kWiFiTurnedOnNotificationId[] = + "cros_hotspot_notifier_ids.wifi_turned_on"; + const char kNotifierHotspot[] = "ash.hotspot"; HotspotNotifier::HotspotNotifier() { @@ -48,20 +51,32 @@ void HotspotNotifier::OnHotspotTurnedOff( hotspot_config::mojom::DisableReason disable_reason) { - if (disable_reason == - hotspot_config::mojom::DisableReason::kProhibitedByPolicy) { - std::unique_ptr<message_center::Notification> notification = - CreateNotification(IDS_ASH_HOTSPOT_OFF_TITLE, - IDS_ASH_HOTSPOT_ADMIN_RESTRICTED_MESSAGE, - kAdminRestrictedNotificationId, - /*delegate=*/nullptr); - - message_center::MessageCenter* message_center = - message_center::MessageCenter::Get(); - message_center->RemoveNotification(kAdminRestrictedNotificationId, - /*by_user=*/false); - message_center->AddNotification(std::move(notification)); + scoped_refptr<message_center::NotificationDelegate> delegate = nullptr; + int title_id; + int message_id; + const char* notification_id; + switch (disable_reason) { + case hotspot_config::mojom::DisableReason::kProhibitedByPolicy: + title_id = IDS_ASH_HOTSPOT_OFF_TITLE; + message_id = IDS_ASH_HOTSPOT_ADMIN_RESTRICTED_MESSAGE; + notification_id = kAdminRestrictedNotificationId; + break; + case hotspot_config::mojom::DisableReason::kWifiEnabled: + title_id = IDS_ASH_HOTSPOT_OFF_TITLE; + message_id = IDS_ASH_HOTSPOT_WIFI_TURNED_ON_MESSAGE; + notification_id = kWiFiTurnedOnNotificationId; + break; + default: + return; } + std::unique_ptr<message_center::Notification> notification = + CreateNotification(title_id, message_id, notification_id, delegate); + + message_center::MessageCenter* message_center = + message_center::MessageCenter::Get(); + message_center->RemoveNotification(notification_id, + /*by_user=*/false); + message_center->AddNotification(std::move(notification)); } std::unique_ptr<message_center::Notification>
diff --git a/ash/system/network/hotspot_notifier.h b/ash/system/network/hotspot_notifier.h index 63cd1a9..388e9a2 100644 --- a/ash/system/network/hotspot_notifier.h +++ b/ash/system/network/hotspot_notifier.h
@@ -33,6 +33,7 @@ static const char kWiFiTurnedOffNotificationId[]; static const char kAdminRestrictedNotificationId[]; + static const char kWiFiTurnedOnNotificationId[]; private: friend class HotspotNotifierTest;
diff --git a/ash/system/network/hotspot_notifier_unittest.cc b/ash/system/network/hotspot_notifier_unittest.cc index e3a079e..928d8a29 100644 --- a/ash/system/network/hotspot_notifier_unittest.cc +++ b/ash/system/network/hotspot_notifier_unittest.cc
@@ -4,17 +4,15 @@ #include "ash/system/network/hotspot_notifier.h" #include "ash/constants/ash_features.h" -#include "ash/public/cpp/hotspot_config_service.h" #include "ash/test/ash_test_base.h" #include "base/test/bind.h" #include "base/test/scoped_feature_list.h" +#include "chromeos/ash/components/network/hotspot_enabled_state_notifier.h" +#include "chromeos/ash/components/network/hotspot_state_handler.h" #include "chromeos/ash/components/network/network_handler.h" #include "chromeos/ash/components/network/network_handler_test_helper.h" -#include "chromeos/ash/components/network/network_state_test_helper.h" -#include "chromeos/ash/services/hotspot_config/cros_hotspot_config.h" -#include "chromeos/ash/services/hotspot_config/public/mojom/cros_hotspot_config.mojom.h" +#include "chromeos/ash/services/hotspot_config/public/cpp/cros_hotspot_config_test_helper.h" #include "chromeos/ash/services/network_config/public/cpp/cros_network_config_test_helper.h" -#include "chromeos/services/network_config/public/mojom/cros_network_config.mojom.h" namespace ash { @@ -39,8 +37,11 @@ network_handler_test_helper_ = std::make_unique<NetworkHandlerTestHelper>(); network_handler_test_helper_->AddDefaultProfiles(); network_handler_test_helper_->ResetDevicesAndServices(); - GetHotspotConfigService(cros_hotspot_config_.BindNewPipeAndPassReceiver()); - hotspot_notifier_ = std::make_unique<ash::HotspotNotifier>(); + + cros_network_config_test_helper_ = + std::make_unique<network_config::CrosNetworkConfigTestHelper>(); + cros_hotspot_config_test_helper_ = + std::make_unique<hotspot_config::CrosHotspotConfigTestHelper>(); NoSessionAshTestBase::SetUp(); LogIn(); @@ -50,7 +51,8 @@ void TearDown() override { NoSessionAshTestBase::TearDown(); - network_config_helper_.reset(); + cros_hotspot_config_test_helper_.reset(); + cros_network_config_test_helper_.reset(); network_handler_test_helper_.reset(); } @@ -89,16 +91,16 @@ return network_handler_test_helper_.get(); } - hotspot_config::mojom::HotspotControlResult EnableHotspot() { - base::RunLoop run_loop; - hotspot_config::mojom::HotspotControlResult out_result; - cros_hotspot_config_->EnableHotspot(base::BindLambdaForTesting( - [&](hotspot_config::mojom::HotspotControlResult result) { - out_result = result; - run_loop.Quit(); - })); - run_loop.Run(); - return out_result; + void EnableHotspot() { + cros_hotspot_config_test_helper_->EnableHotspot(); + base::RunLoop().RunUntilIdle(); + } + + void NotifyHotspotTurnedOff( + hotspot_config::mojom::DisableReason disable_reason) { + NetworkHandler* network_handler = NetworkHandler::Get(); + network_handler->hotspot_enabled_state_notifier()->OnHotspotTurnedOff( + disable_reason); } void AddActiveCellularService() { @@ -111,9 +113,9 @@ base::test::ScopedFeatureList scoped_feature_list_; std::unique_ptr<NetworkHandlerTestHelper> network_handler_test_helper_; std::unique_ptr<network_config::CrosNetworkConfigTestHelper> - network_config_helper_; - std::unique_ptr<HotspotNotifier> hotspot_notifier_; - mojo::Remote<hotspot_config::mojom::CrosHotspotConfig> cros_hotspot_config_; + cros_network_config_test_helper_; + std::unique_ptr<hotspot_config::CrosHotspotConfigTestHelper> + cros_hotspot_config_test_helper_; }; TEST_F(HotspotNotifierTest, WiFiTurnedOff) { @@ -124,10 +126,46 @@ FakeShillSimulatedResult::kSuccess, shill::kTetheringEnableResultSuccess); base::RunLoop().RunUntilIdle(); - EXPECT_EQ(hotspot_config::mojom::HotspotControlResult::kSuccess, - EnableHotspot()); + EnableHotspot(); EXPECT_TRUE(message_center::MessageCenter::Get()->FindVisibleNotificationById( HotspotNotifier::kWiFiTurnedOffNotificationId)); } +TEST_F(HotspotNotifierTest, AdminRestricted) { + SetValidHotspotCapabilities(); + SetReadinessCheckResultReady(); + AddActiveCellularService(); + helper()->manager_test()->SetSimulateTetheringEnableResult( + FakeShillSimulatedResult::kSuccess, shill::kTetheringEnableResultSuccess); + base::RunLoop().RunUntilIdle(); + + EnableHotspot(); + EXPECT_TRUE(message_center::MessageCenter::Get()->FindVisibleNotificationById( + HotspotNotifier::kWiFiTurnedOffNotificationId)); + + NotifyHotspotTurnedOff( + hotspot_config::mojom::DisableReason::kProhibitedByPolicy); + base::RunLoop().RunUntilIdle(); + EXPECT_TRUE(message_center::MessageCenter::Get()->FindVisibleNotificationById( + HotspotNotifier::kAdminRestrictedNotificationId)); +} + +TEST_F(HotspotNotifierTest, WiFiTurnedOn) { + SetValidHotspotCapabilities(); + SetReadinessCheckResultReady(); + AddActiveCellularService(); + helper()->manager_test()->SetSimulateTetheringEnableResult( + FakeShillSimulatedResult::kSuccess, shill::kTetheringEnableResultSuccess); + base::RunLoop().RunUntilIdle(); + + EnableHotspot(); + EXPECT_TRUE(message_center::MessageCenter::Get()->FindVisibleNotificationById( + HotspotNotifier::kWiFiTurnedOffNotificationId)); + + NotifyHotspotTurnedOff(hotspot_config::mojom::DisableReason::kWifiEnabled); + base::RunLoop().RunUntilIdle(); + EXPECT_TRUE(message_center::MessageCenter::Get()->FindVisibleNotificationById( + HotspotNotifier::kWiFiTurnedOnNotificationId)); +} + } // namespace ash
diff --git a/ash/system/overview/overview_button_tray.cc b/ash/system/overview/overview_button_tray.cc index 8f9cb2f0..341dcb3b 100644 --- a/ash/system/overview/overview_button_tray.cc +++ b/ash/system/overview/overview_button_tray.cc
@@ -52,19 +52,16 @@ } // Check whether the button should be visible for 'kOverviewButton' feature, - // which is running as an experiment now. It is only enabled for a specific - // group of existing desks users, see `kUserHasUsedDesksRecently` for more - // details. But we also want to enable it if the user has explicitly enabled - // `kOverviewButton` from chrome://flags or from the command line. Even though - // the user is not in the group of existing desks users. Note, can be removed - // once the experiment is done. Note, only check whether the feature is - // overridden from command line if the FeatureList is initialized. + // which is running as an experiment now. We want to enable it if the user has + // explicitly enabled `kOverviewButton` from chrome://flags or from the + // command line. + // Note: only check whether the feature is overridden from command line if the + // FeatureList is initialized. const base::FeatureList* feature_list = base::FeatureList::GetInstance(); if ((feature_list && feature_list->IsFeatureOverriddenFromCommandLine( features::kOverviewButton.name, base::FeatureList::OVERRIDE_ENABLE_FEATURE)) || - (base::FeatureList::IsEnabled(features::kOverviewButton) && - desks_restore_util::HasPrimaryUserUsedDesksRecently())) { + base::FeatureList::IsEnabled(features::kOverviewButton)) { return true; }
diff --git a/ash/system/power/power_sounds_controller.cc b/ash/system/power/power_sounds_controller.cc index 3aa1db51..eb8abb06 100644 --- a/ash/system/power/power_sounds_controller.cc +++ b/ash/system/power/power_sounds_controller.cc
@@ -6,8 +6,10 @@ #include "ash/shell.h" #include "ash/system/power/power_status.h" +#include "base/check.h" #include "base/metrics/histogram_functions.h" #include "chromeos/ash/components/audio/sounds.h" +#include "chromeos/dbus/power/power_manager_client.h" #include "ui/message_center/message_center.h" namespace ash { @@ -32,14 +34,6 @@ : Sound::kChargeLowBattery; } -// Returns true if the device can play sounds. -bool CanPlaySounds() { - // Do not play any sound if the device is in Focus mode, in DND mode. - // TODO(hongyulong): When Focus mode is available, we need to add this - // condition here. - return !message_center::MessageCenter::Get()->IsQuietMode(); -} - } // namespace // static @@ -51,6 +45,15 @@ "Ash.PowerSoundsController.UnpluggedBatteryLevel"; PowerSoundsController::PowerSoundsController() { + chromeos::PowerManagerClient* client = chromeos::PowerManagerClient::Get(); + DCHECK(client); + client->AddObserver(this); + + // Get the initial lid state. + client->GetSwitchStates( + base::BindOnce(&PowerSoundsController::OnReceiveSwitchStates, + weak_factory_.GetWeakPtr())); + PowerStatus* power_status = PowerStatus::Get(); power_status->AddObserver(this); @@ -60,6 +63,7 @@ PowerSoundsController::~PowerSoundsController() { PowerStatus::Get()->RemoveObserver(this); + chromeos::PowerManagerClient::Get()->RemoveObserver(this); } void PowerSoundsController::OnPowerStatusChanged() { @@ -69,6 +73,26 @@ status.IsLinePowerConnected(), status.IsBatteryCharging()); } +void PowerSoundsController::LidEventReceived( + chromeos::PowerManagerClient::LidState state, + base::TimeTicks timestamp) { + lid_state_ = state; +} + +void PowerSoundsController::OnReceiveSwitchStates( + absl::optional<chromeos::PowerManagerClient::SwitchStates> switch_states) { + if (switch_states.has_value()) { + lid_state_ = switch_states->lid_state; + } +} + +bool PowerSoundsController::CanPlaySounds() const { + // Do not play any sound if the device is in DND mode, or if the lid is not + // open. + return !message_center::MessageCenter::Get()->IsQuietMode() && + lid_state_ == chromeos::PowerManagerClient::LidState::OPEN; +} + void PowerSoundsController::SetPowerStatus(int battery_level, bool is_line_power_connected, bool is_battery_charging) {
diff --git a/ash/system/power/power_sounds_controller.h b/ash/system/power/power_sounds_controller.h index 74b95e7..ff49c9c4 100644 --- a/ash/system/power/power_sounds_controller.h +++ b/ash/system/power/power_sounds_controller.h
@@ -6,11 +6,14 @@ #define ASH_SYSTEM_POWER_POWER_SOUNDS_CONTROLLER_H_ #include "ash/system/power/power_status.h" +#include "chromeos/dbus/power/power_manager_client.h" namespace ash { // Controller class to manage power/battery sounds. -class ASH_EXPORT PowerSoundsController : public PowerStatus::Observer { +class ASH_EXPORT PowerSoundsController + : public PowerStatus::Observer, + public chromeos::PowerManagerClient::Observer { public: static const char kPluggedInBatteryLevelHistogramName[]; static const char kUnpluggedBatteryLevelHistogramName[]; @@ -23,9 +26,20 @@ // PowerStatus::Observer: void OnPowerStatusChanged() override; + // chromeos::PowerManagerClient::Observer: + void LidEventReceived(chromeos::PowerManagerClient::LidState state, + base::TimeTicks timestamp) override; + private: friend class PowerSoundsControllerTest; + // Updates the lid state from received switch states. + void OnReceiveSwitchStates( + absl::optional<chromeos::PowerManagerClient::SwitchStates> switch_states); + + // Returns true if the device can play sounds. + bool CanPlaySounds() const; + void SetPowerStatus(int battery_level, bool line_power_connected, bool is_battery_charging); @@ -48,6 +62,11 @@ // True if line power is connected when the `OnPowerStatusChanged()` was // called. bool is_line_power_connected_; + + chromeos::PowerManagerClient::LidState lid_state_ = + chromeos::PowerManagerClient::LidState::OPEN; + + base::WeakPtrFactory<PowerSoundsController> weak_factory_{this}; }; } // namespace ash
diff --git a/ash/system/power/power_sounds_controller_unittest.cc b/ash/system/power/power_sounds_controller_unittest.cc index 068ba17..9c885285 100644 --- a/ash/system/power/power_sounds_controller_unittest.cc +++ b/ash/system/power/power_sounds_controller_unittest.cc
@@ -8,9 +8,11 @@ #include "ash/constants/ash_features.h" #include "ash/shell.h" +#include "ash/system/system_notification_controller.h" #include "ash/system/test_system_sounds_delegate.h" #include "ash/test/ash_test_base.h" #include "base/containers/flat_map.h" +#include "base/run_loop.h" #include "base/test/metrics/histogram_tester.h" #include "base/test/scoped_feature_list.h" #include "chromeos/dbus/power/fake_power_manager_client.h" @@ -56,6 +58,18 @@ return true; } + // Returns true if the lid is closed. + bool SetLidState(bool closed) { + chromeos::FakePowerManagerClient::Get()->SetLidState( + closed ? chromeos::PowerManagerClient::LidState::CLOSED + : chromeos::PowerManagerClient::LidState::OPEN, + base::TimeTicks::Now()); + return Shell::Get() + ->system_notification_controller() + ->power_sounds_->lid_state_ == + chromeos::PowerManagerClient::LidState::CLOSED; + } + void SetPowerStatus(int battery_level, bool line_power_connected) { ASSERT_GE(battery_level, 0); ASSERT_LE(battery_level, 100); @@ -90,6 +104,7 @@ // disconnected with a charger and 5% battery level. is_line_power_connected_ = true; SetPowerStatus(5, /*line_power_connected=*/false); + EXPECT_FALSE(SetLidState(/*closed=*/false)); } protected: @@ -201,4 +216,24 @@ } } +// Tests that the sounds can only be played if the lid is opened; otherwise, we +// don't play any sounds. +TEST_F(PowerSoundsControllerTest, PlaySoundsOnlyIfLidIsOpened) { + // When the lid is closed, plugging in a line power, the device don't play any + // sound. + EXPECT_TRUE(SetLidState(/*closed=*/true)); + SetPowerStatus(5, /*line_power_connected=*/true); + EXPECT_TRUE(GetSystemSoundsDelegate()->empty()); + + // When we open the lid, it doesn't play the delayed sound. + EXPECT_FALSE(SetLidState(/*closed=*/false)); + EXPECT_TRUE(GetSystemSoundsDelegate()->empty()); + + // Under the condition of the lid opening, the device will play a sound when + // charging it. + SetPowerStatus(10, /*line_power_connected=*/false); + SetPowerStatus(5, /*line_power_connected=*/true); + EXPECT_TRUE(VerifySounds({Sound::kChargeLowBattery})); +} + } // namespace ash \ No newline at end of file
diff --git a/ash/system/time/calendar_month_view.cc b/ash/system/time/calendar_month_view.cc index 9606f14..dd87031 100644 --- a/ash/system/time/calendar_month_view.cc +++ b/ash/system/time/calendar_month_view.cc
@@ -103,8 +103,9 @@ DisableFocus(); if (!grayed_out_) { - if (calendar_utils::ShouldFetchEvents() && is_fetched_) + if (calendar_utils::ShouldFetchEvents() && is_fetched_) { UpdateFetchStatus(true); + } SetTooltipAndAccessibleName(); is_selected_ = calendar_view_controller->selected_date_cell_view() == this; @@ -135,8 +136,9 @@ // this is a grayed out date, which is shown in its previous/next month, this // background won't be drawn. void CalendarDateCellView::OnPaintBackground(gfx::Canvas* canvas) { - if (grayed_out_) + if (grayed_out_) { return; + } const AshColorProvider* color_provider = AshColorProvider::Get(); const SkColor bg_color = @@ -207,8 +209,9 @@ } void CalendarDateCellView::CloseEventList() { - if (!is_selected_) + if (!is_selected_) { return; + } // If this date is selected, repaint the background. is_selected_ = false; @@ -216,8 +219,9 @@ } void CalendarDateCellView::EnableFocus() { - if (grayed_out_) + if (grayed_out_) { return; + } SetFocusBehavior(FocusBehavior::ALWAYS); } @@ -249,8 +253,9 @@ void CalendarDateCellView::UpdateFetchStatus(bool is_fetched) { // No need to re-paint the grayed out cells, since here should be no change // for them. - if (grayed_out_) + if (grayed_out_) { return; + } if (!calendar_utils::ShouldFetchEvents()) { SetTooltipAndAccessibleName(); @@ -258,8 +263,9 @@ } // If the fetching status remains unfetched, no need to schedule repaint. - if (!is_fetched_ && !is_fetched) + if (!is_fetched_ && !is_fetched) { return; + } // If the events are fetched, gets the event number and checks if the event // number has been changed. If the event number hasn't been changed and the @@ -267,12 +273,14 @@ // change), no need to repaint. In all other cases, schedules a repaint. if (is_fetched) { const int event_number = calendar_view_controller_->GetEventNumber(date_); - if (event_number_ == event_number && is_fetched_) + if (event_number_ == event_number && is_fetched_) { return; + } event_number_ = event_number; - if (is_today_) + if (is_today_) { calendar_view_controller_->OnTodaysEventFetchComplete(); + } } is_fetched_ = is_fetched; @@ -287,8 +295,9 @@ void CalendarDateCellView::PaintButtonContents(gfx::Canvas* canvas) { views::LabelButton::PaintButtonContents(canvas); - if (grayed_out_) + if (grayed_out_) { return; + } if (!features::IsCalendarJellyEnabled()) { const AshColorProvider* color_provider = AshColorProvider::Get(); @@ -309,8 +318,9 @@ } void CalendarDateCellView::OnDateCellActivated(const ui::Event& event) { - if (grayed_out_ || !calendar_utils::ShouldFetchEvents()) + if (grayed_out_ || !calendar_utils::ShouldFetchEvents()) { return; + } // Explicitly request focus after being activated to ensure focus moves away // from any CalendarDateCellView which was focused prior. @@ -331,11 +341,13 @@ void CalendarDateCellView::MaybeDrawEventsIndicator(gfx::Canvas* canvas) { // Not drawing the event dot if it's a grayed out cell or the user is not in // an active session (without a vilid user account id). - if (grayed_out_ || !calendar_utils::ShouldFetchEvents()) + if (grayed_out_ || !calendar_utils::ShouldFetchEvents()) { return; + } - if (event_number_ == 0) + if (event_number_ == 0) { return; + } const SkColor jelly_color = GetColorProvider()->GetColor(cros_tokens::kCrosSysOnPrimaryContainer); @@ -377,9 +389,12 @@ base::Time first_day_of_month_local = first_day_of_month + time_difference; base::Time::Exploded first_day_of_month_exploded = calendar_utils::GetExplodedUTC(first_day_of_month_local); - // Find the first day of the week. + // Find the first day of the week. Use 8:00 in the morning to avoid any issues + // caused by DTS, since some timezones' DST start at midnight, some start at + // 1:00AM etc, but no one starts at 8:00 in the morning. base::Time current_date = - calendar_utils::GetFirstDayOfWeekLocalMidnight(first_day_of_month); + calendar_utils::GetFirstDayOfWeekLocalMidnight(first_day_of_month) + + base::Hours(8); base::Time current_date_local = current_date + time_difference; base::Time::Exploded current_date_exploded = calendar_utils::GetExplodedUTC(current_date_local); @@ -458,11 +473,13 @@ calendar_view_controller_->IsSuccessfullyFetched(fetch_month_); // If the fetching status changed, schedule repaint. - if (updated_has_fetched_data != has_fetched_data) + if (updated_has_fetched_data != has_fetched_data) { UpdateIsFetchedAndRepaint(updated_has_fetched_data); + } - if (calendar_utils::GetDayOfWeekInt(current_date) == 1) + if (calendar_utils::GetDayOfWeekInt(current_date) == 1) { return; + } // Adds the first several days from the next month if the last day is not the // end day of this week. The end date of the last row should be 6 day's away @@ -501,13 +518,15 @@ auto* todays_date_cell_view = calendar_view_controller_->todays_date_cell_view(); - if (todays_date_cell_view && todays_date_cell_view->parent() == this) + if (todays_date_cell_view && todays_date_cell_view->parent() == this) { calendar_view_controller_->set_todays_date_cell_view(nullptr); + } auto* selected_date_cell_view = calendar_view_controller_->selected_date_cell_view(); - if (selected_date_cell_view && selected_date_cell_view->parent() == this) + if (selected_date_cell_view && selected_date_cell_view->parent() == this) { calendar_view_controller_->set_selected_date_cell_view(nullptr); + } } void CalendarMonthView::OnEventsFetched( @@ -531,19 +550,22 @@ } void CalendarMonthView::EnableFocus() { - for (auto* cell : children()) + for (auto* cell : children()) { static_cast<CalendarDateCellView*>(cell)->EnableFocus(); + } } void CalendarMonthView::DisableFocus() { - for (auto* cell : children()) + for (auto* cell : children()) { static_cast<CalendarDateCellView*>(cell)->DisableFocus(); + } } void CalendarMonthView::UpdateIsFetchedAndRepaint(bool updated_is_fetched) { - for (auto* cell : children()) + for (auto* cell : children()) { static_cast<CalendarDateCellView*>(cell)->UpdateFetchStatus( updated_is_fetched); + } } CalendarDateCellView* CalendarMonthView::AddDateCellToLayout( @@ -553,8 +575,9 @@ int row_index, bool is_fetched) { auto* layout_manager = static_cast<views::TableLayout*>(GetLayoutManager()); - if (column == 0) + if (column == 0) { layout_manager->AddRows(1, views::TableLayout::kFixedSize); + } return AddChildView(std::make_unique<CalendarDateCellView>( calendar_view_controller_, current_date, calendar_utils::GetTimeDifference(current_date),
diff --git a/ash/system/time/calendar_month_view_unittest.cc b/ash/system/time/calendar_month_view_unittest.cc index 36046547..7172ee5 100644 --- a/ash/system/time/calendar_month_view_unittest.cc +++ b/ash/system/time/calendar_month_view_unittest.cc
@@ -286,6 +286,37 @@ EXPECT_EQ(3, bottom / (bottom - top)); } +// Regression test for b/276840405. +// Test the `CalendarMonthView` with time zone Central European Summer Time +// (Oslo) on a DST starting month. +TEST_F(CalendarMonthViewTest, OsloTimeDSTMonth) { + // Create a monthview based on Apr,1st 2023. DST starts from 02:00 on Mar + // 26th in 2023 with Central European Summer Time (Oslo). + // + // 26, 27, 28, 29, 30, 31, 1 + // 2, 3, 4, 5, 6, 7, 8 + // 9, 10, 11, 12, 13, 14, 15 + // 16, 17, 18, 19, 20, 21, 22 + // 23, 24, 25, 26, 27, 28, 29 + // 30, 1, 2, 3, 4, 5, 6 + base::Time date; + ASSERT_TRUE(base::Time::FromString("1 Apr 2023 10:00 GMT", &date)); + + // Sets the timezone to "Oslo"; + ash::system::ScopedTimezoneSettings timezone_settings(u"Europe/Oslo"); + CreateMonthView(date); + + // Check some dates in this month view. + EXPECT_EQ( + u"26", + static_cast<views::LabelButton*>(month_view()->children()[0])->GetText()); + EXPECT_EQ(u"25", + static_cast<views::LabelButton*>(month_view()->children()[30]) + ->GetText()); + EXPECT_EQ(u"1", static_cast<views::LabelButton*>(month_view()->children()[36]) + ->GetText()); +} + class CalendarMonthViewFetchTest : public AshTestBase { public: CalendarMonthViewFetchTest() @@ -344,15 +375,17 @@ int EventsNumberOfDay(const char* day, SingleDayEventList* events) { base::Time day_base = calendar_test_utils::GetTimeFromString(day); - if (events) + if (events) { events->clear(); + } return calendar_model_->EventsNumberOfDay(day_base, events); } int EventsNumberOfDay(base::Time day, SingleDayEventList* events) { - if (events) + if (events) { events->clear(); + } return calendar_model_->EventsNumberOfDay(day, events); }
diff --git a/ash/system/unified/unified_system_info_view.cc b/ash/system/unified/unified_system_info_view.cc index a04de34..76be51b 100644 --- a/ash/system/unified/unified_system_info_view.cc +++ b/ash/system/unified/unified_system_info_view.cc
@@ -278,7 +278,7 @@ // If the release track is not "stable" then channel indicator UI for quick // settings is put up. auto channel = Shell::Get()->shell_delegate()->GetChannel(); - if (features::IsReleaseTrackUiEnabled() && !eol_notice_ && + if (!eol_notice_ && channel_indicator_utils::IsDisplayableChannel(channel)) { channel_view_ = AddChildView(std::make_unique<ChannelIndicatorQuickSettingsView>(
diff --git a/ash/system/unified/unified_system_info_view_unittest.cc b/ash/system/unified/unified_system_info_view_unittest.cc index 502596e1..121100e 100644 --- a/ash/system/unified/unified_system_info_view_unittest.cc +++ b/ash/system/unified/unified_system_info_view_unittest.cc
@@ -4,7 +4,6 @@ #include "ash/system/unified/unified_system_info_view.h" -#include "ash/constants/ash_features.h" #include "ash/public/cpp/ash_view_ids.h" #include "ash/public/cpp/login_types.h" #include "ash/public/cpp/system_tray_client.h" @@ -19,7 +18,6 @@ #include "ash/test/ash_test_base.h" #include "ash/test_shell_delegate.h" #include "base/memory/scoped_refptr.h" -#include "base/test/scoped_feature_list.h" #include "base/test/task_environment.h" #include "base/time/time.h" #include "components/version_info/channel.h" @@ -28,7 +26,6 @@ namespace ash { // Tests are parameterized by the release track UI: -// - Whether the release track UI feature is enabled, and // - Whether the release track is a value other than "stable" // - Whether EOL notice is expected to be shown. // The release track UI only shows if both conditions are met. @@ -36,7 +33,7 @@ // NOTE: For QsRevamp, see similar tests in QuickSettingsHeaderTest. class UnifiedSystemInfoViewTest : public AshTestBase, - public testing::WithParamInterface<std::tuple<bool, bool, bool>> { + public testing::WithParamInterface<std::tuple<bool, bool>> { public: UnifiedSystemInfoViewTest() : AshTestBase(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {} @@ -58,11 +55,6 @@ Shell::Get()->system_tray_model()->SetShowEolNotice(true); } - // Enable/disable features based on the passed-in parameter. - scoped_feature_list_ = std::make_unique<base::test::ScopedFeatureList>(); - scoped_feature_list_->InitWithFeatureState(features::kReleaseTrackUi, - IsReleaseTrackUiEnabled()); - // Instantiate members. model_ = base::MakeRefCounted<UnifiedSystemTrayModel>(nullptr); controller_ = std::make_unique<UnifiedSystemTrayController>(model_.get()); @@ -75,11 +67,9 @@ widget_->SetContentsView(std::move(info_view)); } - bool IsReleaseTrackUiEnabled() const { return std::get<0>(GetParam()); } + bool IsReleaseTrackNotStable() const { return std::get<0>(GetParam()); } - bool IsReleaseTrackNotStable() const { return std::get<1>(GetParam()); } - - bool ShouldShowEolNotice() const { return std::get<2>(GetParam()); } + bool ShouldShowEolNotice() const { return std::get<1>(GetParam()); } views::View* GetDateButton() { return info_view_->GetViewByID(VIEW_ID_QS_DATE_VIEW_BUTTON); @@ -110,7 +100,6 @@ widget_.reset(); controller_.reset(); model_.reset(); - scoped_feature_list_.reset(); AshTestBase::TearDown(); } @@ -125,14 +114,11 @@ std::unique_ptr<UnifiedSystemTrayController> controller_; UnifiedSystemInfoView* info_view_ = nullptr; std::unique_ptr<views::Widget> widget_; - std::unique_ptr<base::test::ScopedFeatureList> scoped_feature_list_; }; INSTANTIATE_TEST_SUITE_P(All, UnifiedSystemInfoViewTest, - testing::Combine(testing::Bool(), - testing::Bool(), - testing::Bool())); + testing::Combine(testing::Bool(), testing::Bool())); TEST_P(UnifiedSystemInfoViewTest, ButtonNameAndVisibility) { // By default, EnterpriseManagedView is not shown. @@ -159,9 +145,8 @@ EXPECT_EQ(1, GetSystemTrayClient()->show_eol_info_count()); } - const bool show_release_track_info = IsReleaseTrackUiEnabled() && - IsReleaseTrackNotStable() && - !ShouldShowEolNotice(); + const bool show_release_track_info = + IsReleaseTrackNotStable() && !ShouldShowEolNotice(); // If the release track UI is enabled AND the release track is non-stable, the // version button is shown. @@ -194,9 +179,8 @@ EXPECT_EQ(1, GetSystemTrayClient()->show_eol_info_count()); } - const bool show_release_track_info = IsReleaseTrackUiEnabled() && - IsReleaseTrackNotStable() && - !ShouldShowEolNotice(); + const bool show_release_track_info = + IsReleaseTrackNotStable() && !ShouldShowEolNotice(); // If the release track UI is enabled AND the release track is non-stable, the // version button is shown. @@ -229,9 +213,8 @@ EXPECT_EQ(1, GetSystemTrayClient()->show_eol_info_count()); } - const bool show_release_track_info = IsReleaseTrackUiEnabled() && - IsReleaseTrackNotStable() && - !ShouldShowEolNotice(); + const bool show_release_track_info = + IsReleaseTrackNotStable() && !ShouldShowEolNotice(); // If the release track UI is enabled AND the release track is non-stable, the // version button is shown.
diff --git a/ash/system/unified/unified_system_tray.cc b/ash/system/unified/unified_system_tray.cc index 4edac3a..9fa5370 100644 --- a/ash/system/unified/unified_system_tray.cc +++ b/ash/system/unified/unified_system_tray.cc
@@ -571,9 +571,8 @@ } bool UnifiedSystemTray::ShouldChannelIndicatorBeShown() const { - return features::IsReleaseTrackUiEnabled() && - channel_indicator_utils::IsDisplayableChannel( - Shell::Get()->shell_delegate()->GetChannel()); + return channel_indicator_utils::IsDisplayableChannel( + Shell::Get()->shell_delegate()->GetChannel()); } void UnifiedSystemTray::SetTrayEnabled(bool enabled) {
diff --git a/ash/webui/common/resources/navigation_view_panel.html b/ash/webui/common/resources/navigation_view_panel.html index 60b1599..b902ce39 100644 --- a/ash/webui/common/resources/navigation_view_panel.html +++ b/ash/webui/common/resources/navigation_view_panel.html
@@ -59,6 +59,11 @@ z-index: 3; } + #container { + height: 100%; + overflow: hidden; + } + cr-drawer { --cr-separator-line: none; --cr-drawer-header-color: var(--cros-text-color-secondary); @@ -83,10 +88,13 @@ } #navigationBody { + box-sizing: border-box; grid-area: main; - justify-self: center; + height: 100%; min-width: 0; + overflow: overlay; padding-inline: var(--container-padding-nav); + width: 100%; } .left-aligned {
diff --git a/ash/webui/diagnostics_ui/resources/diagnostics_app.html b/ash/webui/diagnostics_ui/resources/diagnostics_app.html index af2d4f6..a04d8abf 100644 --- a/ash/webui/diagnostics_ui/resources/diagnostics_app.html +++ b/ash/webui/diagnostics_ui/resources/diagnostics_app.html
@@ -5,6 +5,10 @@ height: 100%; } + #diagnosticsAppContainer { + height: 100%; + } + page-toolbar { min-height: 56px; position: sticky;
diff --git a/ash/webui/eche_app_ui/system_info_provider.cc b/ash/webui/eche_app_ui/system_info_provider.cc index 359d742..518a6e6 100644 --- a/ash/webui/eche_app_ui/system_info_provider.cc +++ b/ash/webui/eche_app_ui/system_info_provider.cc
@@ -176,8 +176,8 @@ } // network_config::mojom::CrosNetworkConfigObserver implementation: -void SystemInfoProvider::OnNetworkStateChanged( - network_config::mojom::NetworkStatePropertiesPtr network) { +void SystemInfoProvider::OnActiveNetworksChanged( + std::vector<network_config::mojom::NetworkStatePropertiesPtr> networks) { FetchWifiNetworkList(); } @@ -185,47 +185,37 @@ PA_LOG(INFO) << "echeapi SystemInfoProvider FetchWifiNetworkSsidHash"; cros_network_config_->GetNetworkStateList( network_config::mojom::NetworkFilter::New( - network_config::mojom::FilterType::kVisible, + network_config::mojom::FilterType::kActive, network_config::mojom::NetworkType::kWiFi, network_config::mojom::kNoLimit), - base::BindOnce(&SystemInfoProvider::OnWifiNetworkListSsidFetch, + base::BindOnce(&SystemInfoProvider::OnActiveWifiNetworkListFetched, base::Unretained(this))); } -void SystemInfoProvider::OnWifiNetworkListSsidFetch( - std::vector<network_config::mojom::NetworkStatePropertiesPtr> networks) { - PA_LOG(INFO) << "echeapi SystemInfoProvider OnWifiNetworkListSsidFetch"; - for (const auto& network : networks) { - if (network->type == chromeos::network_config::mojom::NetworkType::kWiFi) { - std::string wifi_ssid = network->type_state->get_wifi()->ssid; - std::string hashed_wifi_ssid = crypto::SHA256HashString(wifi_ssid); - hashed_wifi_ssid_ = hashed_wifi_ssid; - return; - } - } - hashed_wifi_ssid_ = std::string(); -} - void SystemInfoProvider::FetchWifiNetworkList() { cros_network_config_->GetNetworkStateList( network_config::mojom::NetworkFilter::New( - network_config::mojom::FilterType::kVisible, + network_config::mojom::FilterType::kActive, network_config::mojom::NetworkType::kWiFi, network_config::mojom::kNoLimit), - base::BindOnce(&SystemInfoProvider::OnWifiNetworkList, + base::BindOnce(&SystemInfoProvider::OnActiveWifiNetworkListFetched, base::Unretained(this))); } -void SystemInfoProvider::OnWifiNetworkList( +void SystemInfoProvider::OnActiveWifiNetworkListFetched( std::vector<network_config::mojom::NetworkStatePropertiesPtr> networks) { - using network_config::mojom::NetworkType; - for (const auto& network : networks) { - if (network->type == NetworkType::kWiFi) { + if (network->type == chromeos::network_config::mojom::NetworkType::kWiFi) { + hashed_wifi_ssid_ = + crypto::SHA256HashString(network->type_state->get_wifi()->ssid); wifi_connection_state_ = network->connection_state; return; } } + + // Reset connection state and SSID hash if there is no active WiFi network. + wifi_connection_state_ = ConnectionStateType::kNotConnected; + hashed_wifi_ssid_ = std::string(); } } // namespace eche_app
diff --git a/ash/webui/eche_app_ui/system_info_provider.h b/ash/webui/eche_app_ui/system_info_provider.h index ef2a0e4..07b33e9 100644 --- a/ash/webui/eche_app_ui/system_info_provider.h +++ b/ash/webui/eche_app_ui/system_info_provider.h
@@ -81,17 +81,11 @@ void SetTabletModeChanged(bool enabled); // network_config::CrosNetworkConfigObserver overrides: - void OnNetworkStateChanged( - chromeos::network_config::mojom::NetworkStatePropertiesPtr network) - override; - - // Callback invoked from within FetchWifiNetworkSsidHash() that produces a - // list of networks. - void OnWifiNetworkListSsidFetch( + void OnActiveNetworksChanged( std::vector<chromeos::network_config::mojom::NetworkStatePropertiesPtr> - networks); + networks) override; void FetchWifiNetworkList(); - void OnWifiNetworkList( + void OnActiveWifiNetworkListFetched( std::vector<chromeos::network_config::mojom::NetworkStatePropertiesPtr> networks);
diff --git a/ash/webui/eche_app_ui/system_info_provider_unittest.cc b/ash/webui/eche_app_ui/system_info_provider_unittest.cc index dc86086f..ebfe267 100644 --- a/ash/webui/eche_app_ui/system_info_provider_unittest.cc +++ b/ash/webui/eche_app_ui/system_info_provider_unittest.cc
@@ -251,7 +251,8 @@ } void SetWifiConnectionStateList() { - system_info_provider_->OnWifiNetworkList(GetWifiNetworkStateList()); + system_info_provider_->OnActiveWifiNetworkListFetched( + GetWifiNetworkStateList()); } void SetOnScreenBacklightStateChanged() { @@ -270,9 +271,53 @@ std::vector<network_config::mojom::NetworkStatePropertiesPtr> GetWifiNetworkStateList() { std::vector<network_config::mojom::NetworkStatePropertiesPtr> result; - auto network = network_config::mojom::NetworkStateProperties::New(); + + // Create a WiFiStatePropertiesPtr object + network_config::mojom::WiFiStatePropertiesPtr wifi_state_properties = + network_config::mojom::WiFiStateProperties::New(); + + // Set the required properties + wifi_state_properties->bssid = "00:11:22:33:44:55"; + wifi_state_properties->frequency = 2412; + wifi_state_properties->hex_ssid = "48656c6c6f"; + wifi_state_properties->security = + network_config::mojom::SecurityType::kNone; + wifi_state_properties->signal_strength = -50; + wifi_state_properties->ssid = "Test"; + wifi_state_properties->hidden_ssid = false; + + // Create a new NetworkTypeStateProperties object with the + // WiFiStateProperties + network_config::mojom::NetworkTypeStatePropertiesPtr + network_type_state_properties = + network_config::mojom::NetworkTypeStateProperties::NewWifi( + std::move(wifi_state_properties)); + + // auto network = network_config::mojom::NetworkStateProperties::New(); + auto network = network_config::mojom::NetworkStateProperties::New( + /*connectable=*/true, + /*connect_requested=*/false, + /*connection_state=*/ + kFakeWifiConnectionState, + /*error_state=*/absl::nullopt, + /*guid=*/"some_guid", + /*name=*/"some_name", + /*portal_state=*/ + network_config::mojom::PortalState::kUnknown, + /*portal_probe_url=*/absl::nullopt, + /*priority=*/1, + /*proxy_mode=*/network_config::mojom::ProxyMode::kDirect, + /*dns_queries_monitored=*/false, + /*prohibited_by_policy=*/false, + /*source=*/ + network_config::mojom::OncSource::kUser, + /*network_type*/ network_config::mojom::NetworkType::kWiFi, + /*network_type_state*/ std::move(network_type_state_properties)); + network->type = network_config::mojom::NetworkType::kWiFi; network->connection_state = kFakeWifiConnectionState; + // network->type_state = network_type_state_properties; + result.emplace_back(std::move(network)); return result; }
diff --git a/ash/webui/shortcut_customization_ui/resources/index.html b/ash/webui/shortcut_customization_ui/resources/index.html index 2bcc39c..618d47af 100644 --- a/ash/webui/shortcut_customization_ui/resources/index.html +++ b/ash/webui/shortcut_customization_ui/resources/index.html
@@ -9,9 +9,11 @@ <style> html { background-color: var(--cros-bg-color); + height: 100%; } body { + height: 100%; margin: 0; } </style>
diff --git a/ash/webui/shortcut_customization_ui/resources/js/accelerator_subsection.html b/ash/webui/shortcut_customization_ui/resources/js/accelerator_subsection.html index 04f376e..6a0dd2a 100644 --- a/ash/webui/shortcut_customization_ui/resources/js/accelerator_subsection.html +++ b/ash/webui/shortcut_customization_ui/resources/js/accelerator_subsection.html
@@ -1,4 +1,8 @@ <style> + #container { + width: var(--cr-toolbar-field-width); + } + #title { align-items: center; color: var(--cros-text-color-primary); @@ -8,15 +12,6 @@ height: 48px; } - accelerator-row { - /** - * scroll-margin-top is used to position this element when it's scrolled - * to the top of the page by shortcuts-page when a search result is - * selected. Without this, the element would be hidden by the toolbar. - */ - scroll-margin-top: var(--navigation-view-panel-toolbar-height); - } - accelerator-row:not(:last-of-type) { border-bottom: var(--cr-separator-line); }
diff --git a/ash/webui/shortcut_customization_ui/resources/js/shortcut_customization_app.html b/ash/webui/shortcut_customization_ui/resources/js/shortcut_customization_app.html index 4517b04d..3d25675 100644 --- a/ash/webui/shortcut_customization_ui/resources/js/shortcut_customization_app.html +++ b/ash/webui/shortcut_customization_ui/resources/js/shortcut_customization_app.html
@@ -5,6 +5,7 @@ font-family: var(--shortcuts-font-family-default); font-size: var(--shortcuts-font-size-default); font-weight: var(--shortcuts-font-weight-regular); + height: 100%; } @media (max-width: 768px) { @@ -13,10 +14,6 @@ } } - #navigationPanel::part(nav-body) { - width: var(--cr-toolbar-field-width); - } - #navigationPanel::part(title) { color: var(--cros-text-color-secondary); padding-inline-start: 8px;
diff --git a/ash/webui/shortcut_customization_ui/resources/js/shortcuts_page.html b/ash/webui/shortcut_customization_ui/resources/js/shortcuts_page.html index 8ed3c32..bf9222c 100644 --- a/ash/webui/shortcut_customization_ui/resources/js/shortcuts_page.html +++ b/ash/webui/shortcut_customization_ui/resources/js/shortcuts_page.html
@@ -1,7 +1,10 @@ <style include="shortcut-customization-shared cr-shared-style"> #container { + align-items: center; + display: flex; + flex-direction: column; margin-top: 20px; - max-width: var(--cr-centered-card-max-width); + width: 100%; } #container accelerator-subsection:not(:first-child)::part(container) {
diff --git a/ash/webui/shortcut_customization_ui/resources/js/shortcuts_page.ts b/ash/webui/shortcut_customization_ui/resources/js/shortcuts_page.ts index dda9703..08ee73e 100644 --- a/ash/webui/shortcut_customization_ui/resources/js/shortcuts_page.ts +++ b/ash/webui/shortcut_customization_ui/resources/js/shortcuts_page.ts
@@ -102,6 +102,9 @@ onNavigationPageChanged({isActive}: {isActive: boolean}): void { if (isActive) { afterNextRender(this, () => { + // Scroll to the top of the page after the active page changes. + window.scrollTo({top: 0}); + // Scroll to the specific accelerator if this page change was caused by // clicking on a search result. If the page change was manual, the // method below will be a no-op.
diff --git a/ash/wm/desks/cros_next_desk_button_base.cc b/ash/wm/desks/cros_next_desk_button_base.cc index 87bc13a..ff209f9 100644 --- a/ash/wm/desks/cros_next_desk_button_base.cc +++ b/ash/wm/desks/cros_next_desk_button_base.cc
@@ -85,6 +85,7 @@ void CrOSNextDeskButtonBase::OnViewHighlighted() { UpdateFocusState(); + bar_view_->ScrollToShowViewIfNecessary(this); } void CrOSNextDeskButtonBase::OnViewUnhighlighted() {
diff --git a/ash/wm/desks/desk_button_base.cc b/ash/wm/desks/desk_button_base.cc index bcccec76..d2c43f5 100644 --- a/ash/wm/desks/desk_button_base.cc +++ b/ash/wm/desks/desk_button_base.cc
@@ -16,6 +16,7 @@ #include "ui/views/border.h" #include "ui/views/controls/focus_ring.h" #include "ui/views/controls/highlight_path_generator.h" +#include "ui/views/view.h" namespace ash { @@ -111,6 +112,19 @@ void DeskButtonBase::OnViewHighlighted() { UpdateFocusState(); + + // TODO(yongshun): When the persistent desk bar is deprecated, remove check + // for `bar_view_` as it will not be a nullptr. + if (bar_view_) { + views::View* view = this; + while (view->parent()) { + if (view->parent() == bar_view_->scroll_view_contents()) { + bar_view_->ScrollToShowViewIfNecessary(view); + break; + } + view = view->parent(); + } + } } void DeskButtonBase::OnViewUnhighlighted() {
diff --git a/ash/wm/desks/desk_name_view.cc b/ash/wm/desks/desk_name_view.cc index a13b9b5..7ffdae5 100644 --- a/ash/wm/desks/desk_name_view.cc +++ b/ash/wm/desks/desk_name_view.cc
@@ -35,6 +35,13 @@ DeskNameView::~DeskNameView() = default; +void DeskNameView::OnFocus() { + DeskTextfield::OnFocus(); + + // When this gets focus, scroll to make `mini_view_` visible. + mini_view_->owner_bar()->ScrollToShowViewIfNecessary(mini_view_); +} + void DeskNameView::OnViewHighlighted() { if (!HasFocus()) { // When the highlight is the result of tabbing, as opposed to clicking or @@ -47,7 +54,7 @@ } DeskTextfield::OnViewHighlighted(); - mini_view_->owner_bar()->ScrollToShowMiniViewIfNecessary(mini_view_); + mini_view_->owner_bar()->ScrollToShowViewIfNecessary(mini_view_); } BEGIN_METADATA(DeskNameView, DeskTextfield)
diff --git a/ash/wm/desks/desk_name_view.h b/ash/wm/desks/desk_name_view.h index 95e7c49..225924d 100644 --- a/ash/wm/desks/desk_name_view.h +++ b/ash/wm/desks/desk_name_view.h
@@ -27,6 +27,7 @@ ~DeskNameView() override; // DeskTextfield: + void OnFocus() override; void OnViewHighlighted() override; private:
diff --git a/ash/wm/desks/desk_preview_view.cc b/ash/wm/desks/desk_preview_view.cc index e3b74f69..39aa819 100644 --- a/ash/wm/desks/desk_preview_view.cc +++ b/ash/wm/desks/desk_preview_view.cc
@@ -10,7 +10,6 @@ #include "ash/public/cpp/window_properties.h" #include "ash/shell.h" -#include "ash/style/ash_color_provider.h" #include "ash/style/style_util.h" #include "ash/wallpaper/wallpaper_base_view.h" #include "ash/wm/desks/desk.h" @@ -38,6 +37,7 @@ #include "chromeos/ui/wm/features.h" #include "ui/accessibility/ax_node_data.h" #include "ui/aura/client/aura_constants.h" +#include "ui/color/color_provider.h" #include "ui/compositor/layer.h" #include "ui/compositor/layer_tree_owner.h" #include "ui/compositor/layer_type.h" @@ -553,10 +553,9 @@ void DeskPreviewView::OnThemeChanged() { views::Button::OnThemeChanged(); - highlight_overlay_->layer()->SetColor( - SkColorSetA(AshColorProvider::Get()->GetControlsLayerColor( - AshColorProvider::ControlsLayerType::kHighlightColor1), - kHighlightTransparency)); + highlight_overlay_->layer()->SetColor(SkColorSetA( + GetColorProvider()->GetColor(ui::kColorHighlightBorderHighlight1), + kHighlightTransparency)); } void DeskPreviewView::OnFocus() { @@ -615,7 +614,7 @@ void DeskPreviewView::OnViewHighlighted() { mini_view_->UpdateFocusColor(); - mini_view_->owner_bar()->ScrollToShowMiniViewIfNecessary(mini_view_); + mini_view_->owner_bar()->ScrollToShowViewIfNecessary(mini_view_); } void DeskPreviewView::OnViewUnhighlighted() {
diff --git a/ash/wm/desks/desks_bar_view.cc b/ash/wm/desks/desks_bar_view.cc index 287fe9db..df572b0 100644 --- a/ash/wm/desks/desks_bar_view.cc +++ b/ash/wm/desks/desks_bar_view.cc
@@ -25,8 +25,6 @@ #include "ash/wm/desks/desk_preview_view.h" #include "ash/wm/desks/desks_util.h" #include "ash/wm/desks/expanded_desks_bar_button.h" -#include "ash/wm/desks/persistent_desks_bar/persistent_desks_bar_button.h" -#include "ash/wm/desks/persistent_desks_bar/persistent_desks_bar_controller.h" #include "ash/wm/desks/scroll_arrow_button.h" #include "ash/wm/desks/templates/saved_desk_metrics_util.h" #include "ash/wm/desks/templates/saved_desk_presenter.h" @@ -41,6 +39,7 @@ #include "base/check.h" #include "base/containers/contains.h" #include "base/functional/bind.h" +#include "base/i18n/rtl.h" #include "base/ranges/algorithm.h" #include "chromeos/constants/chromeos_features.h" #include "third_party/skia/include/core/SkColor.h" @@ -90,9 +89,6 @@ constexpr int kGradientZoneLength = 40; -constexpr int kVerticalDotsButtonVerticalPadding = 8; -constexpr int kVerticalDotsButtonRightPadding = 8; - constexpr int kDeskPreviewViewFocusRingThicknessAndPadding = 4; constexpr int kDeskIconButtonAndLabelSpacing = 8; @@ -551,13 +547,6 @@ base::Unretained(this)), /*is_left_arrow=*/false, this)); - if (PersistentDesksBarController::ShouldPersistentDesksBarBeVisible()) { - vertical_dots_button_ = - AddChildView(std::make_unique<PersistentDesksBarVerticalDotsButton>()); - vertical_dots_button_->SetPaintToLayer(); - vertical_dots_button_->layer()->SetFillsBoundsOpaquely(false); - } - // Make the scroll content view animatable by painting to a layer. scroll_view_contents_ = scroll_view_->SetContents(std::make_unique<views::View>()); @@ -699,6 +688,15 @@ void DesksBarView::Init() { UpdateNewMiniViews(/*initializing_bar_view=*/true, /*expanding_bar_view=*/false); + + // When the bar is initialized, scroll to make active desk mini view visible. + auto it = base::ranges::find_if(mini_views_, [](DeskMiniView* mini_view) { + return mini_view->desk()->is_active(); + }); + if (it != mini_views_.end()) { + ScrollToShowViewIfNecessary(*it); + } + hover_observer_ = std::make_unique<DeskBarHoverObserver>( this, GetWidget()->GetNativeWindow()); } @@ -929,7 +927,7 @@ // drag is ended due to the start of a new drag or the end of the overview, // directly finalize current drag. if (end_by_user) { - ScrollToShowMiniViewIfNecessary(drag_view_); + ScrollToShowViewIfNecessary(drag_view_); drag_proxy_->SnapBackToDragView(); } else { FinalizeDragDesk(); @@ -981,16 +979,6 @@ (kScrollButtonWidth - kScrollViewMinimumHorizontalPadding), bounds().y(), kScrollButtonWidth, bounds().height()); - if (vertical_dots_button_) { - const gfx::Size vertical_dots_button_size = - vertical_dots_button_->GetPreferredSize(); - vertical_dots_button_->SetBoundsRect(gfx::Rect( - gfx::Point(bounds().right() - vertical_dots_button_size.width() - - kVerticalDotsButtonRightPadding, - bounds().y() + kVerticalDotsButtonVerticalPadding), - vertical_dots_button_size)); - } - gfx::Rect scroll_bounds = bounds(); // Align with the overview grid in horizontal, so only horizontal insets are // needed here. @@ -1211,19 +1199,18 @@ begin_x - GetFirstMiniViewXOffset()); } -void DesksBarView::ScrollToShowMiniViewIfNecessary( - const DeskMiniView* mini_view) { - DCHECK(base::Contains(mini_views_, mini_view)); +void DesksBarView::ScrollToShowViewIfNecessary(const views::View* view) { + CHECK(base::Contains(scroll_view_contents_->children(), view)); const gfx::Rect visible_bounds = scroll_view_->GetVisibleRect(); - const gfx::Rect mini_view_bounds = mini_view->bounds(); - const bool beyond_left = mini_view_bounds.x() < visible_bounds.x(); - const bool beyond_right = mini_view_bounds.right() > visible_bounds.right(); + const gfx::Rect view_bounds = view->bounds(); + const bool beyond_left = view_bounds.x() < visible_bounds.x(); + const bool beyond_right = view_bounds.right() > visible_bounds.right(); auto* scroll_bar = scroll_view_->horizontal_scroll_bar(); if (beyond_left) { scroll_view_->ScrollToPosition( - scroll_bar, mini_view_bounds.right() - scroll_view_->bounds().width()); + scroll_bar, view_bounds.right() - scroll_view_->bounds().width()); } else if (beyond_right) { - scroll_view_->ScrollToPosition(scroll_bar, mini_view_bounds.x()); + scroll_view_->ScrollToPosition(scroll_bar, view_bounds.x()); } } @@ -1234,6 +1221,16 @@ return; controller->NewDesk(desks_creation_removal_source); NudgeDeskName(mini_views_.size() - 1); + + // TODO(b/277081702): When desk order is adjusted for RTL, remove the check + // below to always make new desk button visible. + if (!base::i18n::IsRTL()) { + if (new_desk_button_) { + ScrollToShowViewIfNecessary(new_desk_button_); + } else if (expanded_state_new_desk_button_) { + ScrollToShowViewIfNecessary(expanded_state_new_desk_button_); + } + } } void DesksBarView::UpdateButtonsForSavedDeskGrid() { @@ -1263,8 +1260,6 @@ zero_state_default_desk_button_->SetVisible(is_zero_state); zero_state_new_desk_button_->SetVisible(is_zero_state); expanded_state_new_desk_button_->SetVisible(!is_zero_state); - if (vertical_dots_button_) - vertical_dots_button_->SetVisible(!is_zero_state); UpdateLibraryButtonVisibility(); } @@ -1272,9 +1267,6 @@ void DesksBarView::UpdateDeskButtonsVisibilityCrOSNext() { const bool is_zero_state = IsZeroState(); default_desk_button_->SetVisible(is_zero_state); - if (vertical_dots_button_) { - vertical_dots_button_->SetVisible(!is_zero_state); - } new_desk_button_label_->SetVisible(new_desk_button_->state() == CrOSNextDeskIconButton::State::kActive); @@ -1378,11 +1370,6 @@ void DesksBarView::SwitchToZeroState() { DCHECK(!chromeos::features::IsJellyrollEnabled()); - // Hiding the button immediately instead of the ends of the animation while - // switching from expanded state to zero state. - if (vertical_dots_button_) - vertical_dots_button_->SetVisible(false); - // In zero state, if the only desk is being dragged, we should end dragging. // Because the dragged desk's mini view is removed, the mouse released or // gesture ended events cannot be received. |drag_view_| will keep the stale
diff --git a/ash/wm/desks/desks_bar_view.h b/ash/wm/desks/desks_bar_view.h index 4d3cb83..7d5a239 100644 --- a/ash/wm/desks/desks_bar_view.h +++ b/ash/wm/desks/desks_bar_view.h
@@ -27,7 +27,6 @@ class DeskMiniView; class ExpandedDesksBarButton; class OverviewGrid; -class PersistentDesksBarVerticalDotsButton; class ScrollArrowButton; class ZeroStateDefaultDeskButton; class ZeroStateIconButton; @@ -121,6 +120,10 @@ overview_grid_ = overview_grid; } + const views::View* scroll_view_contents() const { + return scroll_view_contents_; + } + // Initializes and creates mini_views for any pre-existing desks, before the // bar was created. This should only be called after this view has been added // to a widget, as it needs to call `GetWidget()` when it's performing a @@ -210,9 +213,10 @@ // |initializing_bar_view| is false. void UpdateNewMiniViews(bool initializing_bar_view, bool expanding_bar_view); - // If the focused |mini_view| is outside of the scroll view's visible bounds, - // scrolls the bar to make sure it can always be seen. - void ScrollToShowMiniViewIfNecessary(const DeskMiniView* mini_view); + // If the focused `view` is outside of the scroll view's visible bounds, + // scrolls the bar to make sure it can always be seen. Please note, `view` + // must be a child of `scroll_view_contents_`. + void ScrollToShowViewIfNecessary(const views::View* view); void OnNewDeskButtonPressed( DesksCreationRemovalSource desks_creation_removal_source); @@ -228,8 +232,8 @@ // and the ExpandedDesksBarButton on the desk bar's state. void UpdateDeskButtonsVisibility(); - // Udates the visibility of the `default_desk_button_` and - // `vertical_dots_button_` on the desks bar's state. + // Udates the visibility of the `default_desk_button_` on the desks bar's + // state. // TODO(conniekxu): Remove `UpdateDeskButtonsVisibility`, replace it with this // function, and rename this function by removing the prefix CrOSNext. void UpdateDeskButtonsVisibilityCrOSNext(); @@ -378,11 +382,6 @@ // Drag proxy for the dragged desk. std::unique_ptr<DeskDragProxy> drag_proxy_; - // A circular button which when clicked will open the context menu of the - // persistent desks bar. Note that this button will only be created when - // persistent desks bar should be shown. - PersistentDesksBarVerticalDotsButton* vertical_dots_button_ = nullptr; - // ScrollView callback subscriptions. base::CallbackListSubscription on_contents_scrolled_subscription_; base::CallbackListSubscription on_contents_scroll_ended_subscription_;
diff --git a/ash/wm/desks/desks_histogram_enums.h b/ash/wm/desks/desks_histogram_enums.h index 8535a6b..8e1b9c8 100644 --- a/ash/wm/desks/desks_histogram_enums.h +++ b/ash/wm/desks/desks_histogram_enums.h
@@ -46,7 +46,7 @@ kWindowActivated = 4, kDeskSwitchTouchpad = 5, kUserSwitch = 6, - kPersistentDesksBar = 7, + // kPersistentDesksBar = 7, // Deprecated, feature has been deleted. kLaunchTemplate = 8, kIndexedDeskSwitchShortcut = 9, kRemovalUndone = 10,
diff --git a/ash/wm/desks/desks_restore_util.cc b/ash/wm/desks/desks_restore_util.cc index 3b0999c5..7d549f0 100644 --- a/ash/wm/desks/desks_restore_util.cc +++ b/ash/wm/desks/desks_restore_util.cc
@@ -55,15 +55,6 @@ constexpr char kWeeklyActiveDesksKey[] = "weekly_active_desks"; constexpr char kReportTimeKey[] = "report_time"; -// A boolean pref that indicates whether the user has used desks recently. -// A user has `used` desks means that there are desks added, removed or renamed -// by the user. `Recently` means the `used` action happens between 07/27/2021 -// and 09/07/2021. Only the users that used desks in this period of time will be -// included in the experiment of bento bar and overview button. Note, this pref -// will not be set to false once it has been set to true. But this perf could be -// removed after the experiment. -constexpr char kUserHasUsedDesksRecently[] = "ash.user_has_used_desks_recently"; - // While restore is in progress, changes are being made to the desks and their // names. Those changes should not trigger an update to the prefs. bool g_pause_desks_prefs_updates = false; @@ -83,30 +74,6 @@ desk_index < static_cast<int>(DesksController::Get()->desks().size()); } -base::Time GetTime(int year, int month, int day_of_month, int day_of_week) { - base::Time::Exploded time_exploded; - time_exploded.year = year; - time_exploded.month = month; - time_exploded.day_of_week = day_of_week; - time_exploded.day_of_month = day_of_month; - time_exploded.hour = 0; - time_exploded.minute = 0; - time_exploded.second = 0; - time_exploded.millisecond = 0; - base::Time time; - const bool result = base::Time::FromLocalExploded(time_exploded, &time); - DCHECK(result); - return time; -} - -// Check if GetTimeNow() is during the time period 07/27/2021 to 09/07/2021 (not -// included). -bool IsNowInValidTimePeriod() { - base::Time now = GetTimeNow(); - return now <= GetTime(2021, 9, 7, /*Tuesday=*/2) && - now >= GetTime(2021, 7, 27, /*Tuesday=*/2); -} - // Returns Jan 1, 2010 00:00:00 as a base::Time object in the local timezone. base::Time GetLocalEpoch() { static const base::Time local_epoch = [] { @@ -128,8 +95,6 @@ registry->RegisterDictionaryPref(prefs::kDesksWeeklyActiveDesksMetrics); registry->RegisterIntegerPref(prefs::kDesksActiveDesk, kDefaultActiveDeskIndex); - registry->RegisterBooleanPref(kUserHasUsedDesksRecently, - /*default_value=*/false); } void RestorePrimaryUserDesks() { @@ -141,9 +106,6 @@ return; } - if (primary_user_prefs->GetBoolean(kUserHasUsedDesksRecently)) - UMA_HISTOGRAM_BOOLEAN("Ash.Desks.UserHasUsedDesksRecently", true); - const base::Value::List& desks_names_list = primary_user_prefs->GetList(prefs::kDesksNamesList); const base::Value::List& desks_guids_list = @@ -281,11 +243,6 @@ } DCHECK_EQ(name_pref_data.size(), desks.size()); - - if (IsNowInValidTimePeriod() && - !primary_user_prefs->GetBoolean(kUserHasUsedDesksRecently)) { - primary_user_prefs->SetBoolean(kUserHasUsedDesksRecently, true); - } } void UpdatePrimaryUserDeskGuidsPrefs() { @@ -368,16 +325,6 @@ primary_user_prefs->SetInteger(prefs::kDesksActiveDesk, active_desk_index); } -bool HasPrimaryUserUsedDesksRecently() { - PrefService* primary_user_prefs = GetPrimaryUserPrefService(); - if (!primary_user_prefs) { - // Can be null in tests. - return false; - } - - return primary_user_prefs->GetBoolean(kUserHasUsedDesksRecently); -} - const base::Time GetTimeNow() { return g_override_clock_ ? g_override_clock_->Now() : base::Time::Now(); } @@ -390,12 +337,6 @@ g_override_clock_ = test_clock; } -void SetPrimaryUserHasUsedDesksRecentlyForTesting(bool value) { - PrefService* primary_user_prefs = GetPrimaryUserPrefService(); - DCHECK(primary_user_prefs); - primary_user_prefs->SetBoolean(kUserHasUsedDesksRecently, value); -} - } // namespace desks_restore_util } // namespace ash
diff --git a/ash/wm/desks/desks_restore_util.h b/ash/wm/desks/desks_restore_util.h index 4540993..94135b8 100644 --- a/ash/wm/desks/desks_restore_util.h +++ b/ash/wm/desks/desks_restore_util.h
@@ -42,9 +42,6 @@ // the primary user switches an active desk. void UpdatePrimaryUserActiveDeskPrefs(int active_desk_index); -// Returns true if pref `kUserHasUsedDesksRecently` of the primary user is true. -ASH_EXPORT bool HasPrimaryUserUsedDesksRecently(); - // Returns the time from `g_override_clock_` if it is not nullptr, or time from // base::Time::Now() otherwise. const base::Time GetTimeNow(); @@ -55,7 +52,6 @@ ASH_EXPORT int GetDaysFromLocalEpoch(); ASH_EXPORT void OverrideClockForTesting(base::Clock* test_clock); -ASH_EXPORT void SetPrimaryUserHasUsedDesksRecentlyForTesting(bool value); } // namespace desks_restore_util
diff --git a/ash/wm/desks/desks_test_api.cc b/ash/wm/desks/desks_test_api.cc index 83960a94..f66317c 100644 --- a/ash/wm/desks/desks_test_api.cc +++ b/ash/wm/desks/desks_test_api.cc
@@ -14,10 +14,6 @@ #include "ash/wm/desks/desks_bar_view.h" #include "ash/wm/desks/desks_restore_util.h" #include "ash/wm/desks/expanded_desks_bar_button.h" -#include "ash/wm/desks/persistent_desks_bar/persistent_desks_bar_button.h" -#include "ash/wm/desks/persistent_desks_bar/persistent_desks_bar_context_menu.h" -#include "ash/wm/desks/persistent_desks_bar/persistent_desks_bar_controller.h" -#include "ash/wm/desks/persistent_desks_bar/persistent_desks_bar_view.h" #include "ash/wm/overview/overview_controller.h" #include "ash/wm/overview/overview_grid.h" #include "ash/wm/overview/overview_test_util.h" @@ -37,13 +33,6 @@ ->desks_bar_view(); } -const PersistentDesksBarView* GetPersistentDesksBarView() { - auto* persistent_desks_bar_controller = - Shell::Get()->persistent_desks_bar_controller(); - DCHECK(persistent_desks_bar_controller); - return persistent_desks_bar_controller->persistent_desks_bar_view(); -} - } // namespace // static @@ -67,24 +56,6 @@ } // static -PersistentDesksBarContextMenu* DesksTestApi::GetDesksBarContextMenu() { - return GetDesksBarView()->vertical_dots_button_->context_menu_.get(); -} - -// static -PersistentDesksBarContextMenu* -DesksTestApi::GetPersistentDesksBarContextMenu() { - return GetPersistentDesksBarView() - ->vertical_dots_button_->context_menu_.get(); -} - -// static -const std::vector<PersistentDesksBarDeskButton*> -DesksTestApi::GetPersistentDesksBarDeskButtons() { - return GetPersistentDesksBarView()->desk_buttons_; -} - -// static DeskActionContextMenu* DesksTestApi::GetContextMenuForDesk(int index) { return GetDesksBarView()->mini_views()[index]->context_menu_.get(); } @@ -127,11 +98,6 @@ } // static -bool DesksTestApi::HasVerticalDotsButton() { - return GetDesksBarView()->vertical_dots_button_; -} - -// static bool DesksTestApi::DesksControllerHasDesk(Desk* desk) { return DesksController::Get()->HasDesk(desk); }
diff --git a/ash/wm/desks/desks_test_api.h b/ash/wm/desks/desks_test_api.h index 6a6d522..c1d183f 100644 --- a/ash/wm/desks/desks_test_api.h +++ b/ash/wm/desks/desks_test_api.h
@@ -30,13 +30,10 @@ class Desk; class DeskActionContextMenu; class DeskMiniView; -class PersistentDesksBarContextMenu; -class PersistentDesksBarDeskButton; class ScrollArrowButton; // Helper class used by tests to access desks' internal elements. Including -// elements of multiple different objects of desks. E.g, DesksBarView, Desk, -// PersistentDesksBarView. +// elements of multiple different objects of desks. E.g, DesksBarView, Desk. class DesksTestApi { public: // Don't instantiate, just use the static helpers below. @@ -47,10 +44,6 @@ static ScrollArrowButton* GetDesksBarRightScrollButton(); static views::ScrollView* GetDesksBarScrollView(); static const DeskMiniView* GetDesksBarDragView(); - static PersistentDesksBarContextMenu* GetDesksBarContextMenu(); - static PersistentDesksBarContextMenu* GetPersistentDesksBarContextMenu(); - static const std::vector<PersistentDesksBarDeskButton*> - GetPersistentDesksBarDeskButtons(); static DeskActionContextMenu* GetContextMenuForDesk(int index); static views::LabelButton* GetCloseAllUndoToastDismissButton(); static const ui::SimpleMenuModel& GetContextMenuModelForDesk(int index);
diff --git a/ash/wm/desks/desks_unittests.cc b/ash/wm/desks/desks_unittests.cc index 4d655bc..a581e7f8 100644 --- a/ash/wm/desks/desks_unittests.cc +++ b/ash/wm/desks/desks_unittests.cc
@@ -59,10 +59,6 @@ #include "ash/wm/desks/desks_test_util.h" #include "ash/wm/desks/desks_util.h" #include "ash/wm/desks/expanded_desks_bar_button.h" -#include "ash/wm/desks/persistent_desks_bar/persistent_desks_bar_button.h" -#include "ash/wm/desks/persistent_desks_bar/persistent_desks_bar_context_menu.h" -#include "ash/wm/desks/persistent_desks_bar/persistent_desks_bar_controller.h" -#include "ash/wm/desks/persistent_desks_bar/persistent_desks_bar_view.h" #include "ash/wm/desks/root_window_desk_switch_animator_test_api.h" #include "ash/wm/desks/scroll_arrow_button.h" #include "ash/wm/desks/templates/saved_desk_test_util.h" @@ -88,6 +84,7 @@ #include "base/containers/contains.h" #include "base/containers/cxx20_erase.h" #include "base/functional/callback_forward.h" +#include "base/i18n/rtl.h" #include "base/ranges/algorithm.h" #include "base/scoped_observation.h" #include "base/strings/stringprintf.h" @@ -127,6 +124,7 @@ #include "ui/events/devices/device_data_manager_test_api.h" #include "ui/events/devices/input_device.h" #include "ui/events/event_constants.h" +#include "ui/events/keycodes/keyboard_codes_posix.h" #include "ui/events/test/event_generator.h" #include "ui/gfx/geometry/point.h" #include "ui/gfx/geometry/point_conversions.h" @@ -457,15 +455,6 @@ return bar_view->expanded_state_new_desk_button()->GetInnerButton(); } - const views::LabelButton* GetExpandedStateLibraryButton( - const DesksBarView* bar_view) { - if (GetParam().enable_jellyroll) { - return bar_view->library_button(); - } - - return bar_view->expanded_state_library_button()->GetInnerButton(); - } - void VerifyZeroStateNewDeskButtonVisibility(const DesksBarView* bar_view, bool expected_visibility) { // If `Jellyroll` is enabled, new desk button is always visible no matter @@ -5991,6 +5980,49 @@ } } +// Tests that active desk mini view is visible when entering overview especially +// with 16 desks. +TEST_P(DesksTest, ActiveDeskMiniViewIsVisible) { + for (size_t i = 1; i < desks_util::GetMaxNumberOfDesks(); i++) { + // Create a new desk and go to that desk. + NewDesk(); + ActivateDesk(DesksController::Get()->desks().back().get()); + + // Enter overview and check the active mini view is fully visible. + EnterOverview(); + auto* desks_bar = + GetOverviewGridForRoot(Shell::GetPrimaryRootWindow())->desks_bar_view(); + for (auto* mini_view : desks_bar->mini_views()) { + if (mini_view->desk()->is_active()) { + EXPECT_EQ(mini_view->size(), mini_view->GetVisibleBounds().size()); + } + } + + ExitOverview(); + } +} + +// Tests that change the highlighted new desk button is fully visible. +TEST_P(DesksTest, HighlightedButtonIsVisible) { + // Create `GetMaxNumberOfDesks() - 1` desks so that the new desk button is + // still enabled. + for (size_t i = 1; i < desks_util::GetMaxNumberOfDesks() - 1; i++) { + NewDesk(); + } + + EnterOverview(); + + auto* desk_bar = + GetOverviewGridForRoot(Shell::GetPrimaryRootWindow())->desks_bar_view(); + auto* new_desk_button = GetExpandedStateInnerNewDeskButton(desk_bar); + SendKey(ui::VKEY_TAB, ui::EF_SHIFT_DOWN); + EXPECT_TRUE(new_desk_button->GetVisible()); + EXPECT_EQ(new_desk_button->size(), + new_desk_button->GetVisibleBounds().size()); + + ExitOverview(); +} + // Tests that the bounds of a window that is visible on all desks is shared // across desks. TEST_P(DesksTest, VisibleOnAllDesksGlobalBounds) { @@ -6413,6 +6445,18 @@ for (size_t i = 1; i < desks_util::GetMaxNumberOfDesks(); i++) { ClickOnView(new_desk_button, event_generator); + + // When a new desk is created, ensure its desk mini view fully visible. + auto* mini_view = desks_bar_view->mini_views().back(); + EXPECT_EQ(mini_view->size(), mini_view->GetVisibleBounds().size()); + + // TODO(b/277081702): When desk order is adjusted for RTL, remove the check + // below to always make new desk button visible. + if (!base::i18n::IsRTL()) { + EXPECT_EQ(new_desk_button->size(), + new_desk_button->GetVisibleBounds().size()); + } + ClickOnView(scroll_right_button, event_generator); } @@ -7238,41 +7282,6 @@ EXPECT_EQ(std::u16string(), desk_name_view->GetText()); } -// Tests the time period to set perf `kUserHasUsedDesksRecently`. -TEST_P(DesksTest, PrimaryUserHasUsedDesksRecently) { - base::SimpleTestClock test_clock; - base::Time time; - auto* desks_controller = DesksController::Get(); - // `kUserHasUsedDesksRecently` should not be set before 07/27/2021. - ASSERT_TRUE(base::Time::FromString("Mon, 26 Jul 2021 23:59:59", &time)); - test_clock.SetNow(time); - desks_restore_util::OverrideClockForTesting(&test_clock); - NewDesk(); - RemoveDesk(desks_controller->desks().back().get()); - EXPECT_FALSE(desks_restore_util::HasPrimaryUserUsedDesksRecently()); - - // `kUserHasUsedDesksRecently` should not be set in 09/07/2021 and after. - ASSERT_TRUE(base::Time::FromString("Tue, 7 Sep 2021 00:00:01", &time)); - test_clock.SetNow(time); - - NewDesk(); - RemoveDesk(desks_controller->desks().back().get()); - EXPECT_FALSE(desks_restore_util::HasPrimaryUserUsedDesksRecently()); - - // `kUserHasUsedDesksRecently` should be set during [07/27/2021, 09/07/2021). - ASSERT_TRUE(base::Time::FromString("Tue, 27 Jul 2021 00:00:01", &time)); - test_clock.SetNow(time); - - NewDesk(); - RemoveDesk(desks_controller->desks().back().get()); - EXPECT_TRUE(desks_restore_util::HasPrimaryUserUsedDesksRecently()); - - // `kUserHasUsedDesksRecently` should be kept as true after setting. - test_clock.Advance(base::Days(50)); - EXPECT_TRUE(desks_restore_util::HasPrimaryUserUsedDesksRecently()); - desks_restore_util::OverrideClockForTesting(nullptr); -} - // Tests that metrics are being recorded when a desk is renamed, when new desks // are added, and when a desk is being removed. TEST_P(DesksTest, TestCustomDeskNameMetricsRecording) { @@ -7349,40 +7358,6 @@ } } -class DesksBentoBarTest : public DesksTest { - public: - DesksBentoBarTest() { - // Enable the bento bar feature through FeatureList instead of command line. - auto feature_list = std::make_unique<base::FeatureList>(); - feature_list->RegisterFieldTrialOverride( - features::kBentoBar.name, base::FeatureList::OVERRIDE_ENABLE_FEATURE, - base::FieldTrialList::CreateFieldTrial("FooTrial", "Group1")); - scoped_feature_list_.InitWithFeatureList(std::move(feature_list)); - } - - private: - base::test::ScopedFeatureList scoped_feature_list_; -}; - -// Tests the visibility of the vertical dots button inside desks bar. -TEST_P(DesksBentoBarTest, VerticalDotsButtonVisibility) { - ASSERT_FALSE(desks_restore_util::HasPrimaryUserUsedDesksRecently()); - EXPECT_TRUE(features::IsBentoBarEnabled()); - - // Vertical dots button should not be shown even though bento bar is enabled - // but HasPrimaryUserUsedDesksRecently is false. - NewDesk(); - EnterOverview(); - EXPECT_FALSE(DesksTestApi::HasVerticalDotsButton()); - - // Vertical dots button should be shown if bento bar is enabled and - // HasPrimaryUserUsedDesksRecently is true. - ExitOverview(); - desks_restore_util::SetPrimaryUserHasUsedDesksRecentlyForTesting(true); - EnterOverview(); - EXPECT_TRUE(DesksTestApi::HasVerticalDotsButton()); -} - // A test class that uses a mock time test environment. class DesksMockTimeTest : public DesksTest { public: @@ -7494,588 +7469,6 @@ number_of_one_bucket_entries + 1); } -class PersistentDesksBarTest : public DesksTest { - public: - void SetUp() override { - scoped_feature_list_.InitAndEnableFeature(features::kBentoBar); - DesksTest::SetUp(); - - desks_restore_util::SetPrimaryUserHasUsedDesksRecentlyForTesting(true); - ASSERT_TRUE(desks_restore_util::HasPrimaryUserUsedDesksRecently()); - } - PersistentDesksBarTest() = default; - PersistentDesksBarTest(const PersistentDesksBarTest&) = delete; - PersistentDesksBarTest& operator=(const PersistentDesksBarTest&) = delete; - ~PersistentDesksBarTest() override = default; - - const views::Widget* GetBarWidget() const { - return Shell::Get() - ->persistent_desks_bar_controller() - ->persistent_desks_bar_widget(); - } - - bool IsWidgetVisible() const { - auto* bar_widget = GetBarWidget(); - DCHECK(bar_widget); - return bar_widget->GetLayer()->GetTargetVisibility(); - } - - private: - base::test::ScopedFeatureList scoped_feature_list_; -}; - -// Tests that the bar will only be created and shown when there are more than -// one desk. -TEST_P(PersistentDesksBarTest, MoreThanOneDesk) { - auto* shell = Shell::Get(); - ASSERT_FALSE(shell->tablet_mode_controller()->InTabletMode()); - auto* desks_controller = DesksController::Get(); - ASSERT_EQ(1u, desks_controller->desks().size()); - auto* bar_controller = shell->persistent_desks_bar_controller(); - ASSERT_TRUE(bar_controller); - - // The bar should not be created if there is only one desk. - EXPECT_FALSE(GetBarWidget()); - - // Create a new desk should cause the bar to be created and shown. - NewDesk(); - EXPECT_EQ(2u, desks_controller->desks().size()); - EXPECT_TRUE(GetBarWidget()); - EXPECT_TRUE(IsWidgetVisible()); - - // The bar should be destroyed after removed a desk and then there is only one - // desk left. - RemoveDesk(desks_controller->desks()[1].get()); - EXPECT_EQ(1u, desks_controller->desks().size()); - EXPECT_FALSE(GetBarWidget()); -} - -// Tests that the bar will only be created and shown in clamshell mode. -TEST_P(PersistentDesksBarTest, ClamshellOnly) { - auto* shell = Shell::Get(); - TabletModeControllerTestApi().EnterTabletMode(); - ASSERT_TRUE(shell->tablet_mode_controller()->InTabletMode()); - auto* desks_controller = DesksController::Get(); - ASSERT_EQ(1u, desks_controller->desks().size()); - auto* bar_controller = shell->persistent_desks_bar_controller(); - ASSERT_TRUE(bar_controller); - - // Create or remove a desk in tablet mode should not create the bar or cause - // any crash. - EXPECT_FALSE(GetBarWidget()); - NewDesk(); - EXPECT_EQ(2u, desks_controller->desks().size()); - EXPECT_FALSE(GetBarWidget()); - RemoveDesk(desks_controller->desks()[0].get()); - EXPECT_FALSE(GetBarWidget()); - NewDesk(); - - // Leaving tablet mode to clamshell mode with more than one desk should create - // and show the bar. - TabletModeControllerTestApi().LeaveTabletMode(); - EXPECT_TRUE(GetBarWidget()); - EXPECT_TRUE(IsWidgetVisible()); - - // The bar should be destroyed if tablet mode is entered. - TabletModeControllerTestApi().EnterTabletMode(); - EXPECT_TRUE(shell->tablet_mode_controller()->InTabletMode()); - EXPECT_FALSE(GetBarWidget()); -} - -// Tests the bar's visibility while entering or leaving overview mode. -TEST_P(PersistentDesksBarTest, OverviewMode) { - auto* desks_controller = DesksController::Get(); - ASSERT_EQ(1u, desks_controller->desks().size()); - - NewDesk(); - EXPECT_TRUE(GetBarWidget()); - // Create a window thus `UpdateBarOnWindowStateChanges()` will be called while - // entering overview mode. Bento bar should not be created and the desks bar - // should be at the top of the display in this case. - std::unique_ptr<aura::Window> window = - CreateTestWindow(gfx::Rect(0, 0, 300, 300)); - WindowState* window_state = WindowState::Get(window.get()); - window_state->Minimize(); - - // Entering overview mode should destroy the bar. Exiting overview mode with - // more than one desk should create the bar and show it. - EnterOverview(); - EXPECT_EQ(GetOverviewGridForRoot(Shell::GetPrimaryRootWindow()) - ->desks_bar_view() - ->GetBoundsInScreen() - .origin(), - gfx::Point(0, 0)); - EXPECT_FALSE(GetBarWidget()); - EXPECT_EQ(2u, desks_controller->desks().size()); - ExitOverview(); - EXPECT_TRUE(GetBarWidget()); - EXPECT_TRUE(IsWidgetVisible()); - - // Exiting overview mode with only one desk should not create the bar. - EnterOverview(); - EXPECT_FALSE(GetBarWidget()); - RemoveDesk(desks_controller->desks()[1].get()); - EXPECT_EQ(1u, desks_controller->desks().size()); - ExitOverview(); - EXPECT_FALSE(GetBarWidget()); - - // Each desk button in the bar should show the corresponding desk's name. - EnterOverview(); - NewDesk(); - EXPECT_EQ(2u, desks_controller->desks().size()); - desks_controller->desks()[1].get()->SetName(u"test", /*set_by_user=*/true); - ExitOverview(); - auto desk_buttons = DesksTestApi::GetPersistentDesksBarDeskButtons(); - for (size_t i = 0; i < desk_buttons.size(); i++) - EXPECT_EQ(desk_buttons[i]->GetText(), desks_controller->desks()[i]->name()); - - // The desk buttons should have the same order as the desks after reordering. - auto* event_generator = GetEventGenerator(); - EnterOverview(); - EXPECT_EQ(u"test", desks_controller->desks()[1]->name()); - const auto* desks_bar_view = - GetOverviewGridForRoot(Shell::GetPrimaryRootWindow())->desks_bar_view(); - StartDragDeskPreview(desks_bar_view->mini_views()[1], event_generator); - event_generator->MoveMouseTo(desks_bar_view->mini_views()[0] - ->GetPreviewBoundsInScreen() - .CenterPoint()); - event_generator->ReleaseLeftButton(); - EXPECT_EQ(u"test", desks_controller->desks()[0]->name()); - ExitOverview(); - desk_buttons = DesksTestApi::GetPersistentDesksBarDeskButtons(); - for (size_t i = 0; i < desk_buttons.size(); i++) - EXPECT_EQ(desk_buttons[i]->GetText(), desks_controller->desks()[i]->name()); -} - -// Tests the desk activation changes after clicking the desk button in the bar. -TEST_P(PersistentDesksBarTest, DeskActivation) { - auto* desks_controller = DesksController::Get(); - auto* event_generator = GetEventGenerator(); - - NewDesk(); - EXPECT_EQ(2u, desks_controller->desks().size()); - EXPECT_TRUE(GetBarWidget()); - EXPECT_EQ(0, desks_controller->GetActiveDeskIndex()); - - // Should activate `Desk 2` after clicking the corresponding desk button. - { - DeskSwitchAnimationWaiter waiter; - ClickOnView(DesksTestApi::GetPersistentDesksBarDeskButtons()[1], - event_generator); - waiter.Wait(); - EXPECT_TRUE(GetBarWidget()); - EXPECT_EQ(1, desks_controller->GetActiveDeskIndex()); - } - - // Should activate `Desk 1` after double-clicking the corresponding desk - // button without crash. - { - DeskSwitchAnimationWaiter waiter; - DoubleClickOnView(DesksTestApi::GetPersistentDesksBarDeskButtons()[0], - event_generator); - waiter.Wait(); - EXPECT_TRUE(GetBarWidget()); - EXPECT_EQ(0, desks_controller->GetActiveDeskIndex()); - } -} - -TEST_P(PersistentDesksBarTest, LeavingOrEnteringTabletModeWithOverviewModeOn) { - NewDesk(); - EXPECT_EQ(2u, DesksController::Get()->desks().size()); - EXPECT_TRUE(GetBarWidget()); - - // The bar should not be created after entering or leaving tablet mode with - // overview mode on. - auto* overview_controller = Shell::Get()->overview_controller(); - EnterOverview(); - TabletModeControllerTestApi().EnterTabletMode(); - EXPECT_TRUE(overview_controller->InOverviewSession()); - EXPECT_FALSE(GetBarWidget()); - TabletModeControllerTestApi().LeaveTabletMode(); - EXPECT_TRUE(overview_controller->InOverviewSession()); - EXPECT_FALSE(GetBarWidget()); -} - -// Tests that the bar can be shown or hidden correctly through the context menu -// of the bar. -TEST_P(PersistentDesksBarTest, ShowOrHideBarThroughContextMenu) { - NewDesk(); - EXPECT_EQ(2u, DesksController::Get()->desks().size()); - EXPECT_TRUE(GetBarWidget()); - - // The bar should be destroyed after it is set to hide. - PersistentDesksBarContextMenu* context_menu = - DesksTestApi::GetPersistentDesksBarContextMenu(); - context_menu->ExecuteCommand( - static_cast<int>( - PersistentDesksBarContextMenu::CommandId::kShowOrHideBar), - /*event_flags=*/0); - EXPECT_FALSE(GetBarWidget()); - - // With the bar being set to hide, it should not be created after exiting - // overview mode with more than one desk. - EnterOverview(); - ExitOverview(); - EXPECT_FALSE(GetBarWidget()); - - // With the bar being set to show, it should be created after exiting overview - // mode with more than one desk. - EnterOverview(); - context_menu = DesksTestApi::GetDesksBarContextMenu(); - context_menu->ExecuteCommand( - static_cast<int>( - PersistentDesksBarContextMenu::CommandId::kShowOrHideBar), - /*event_flags=*/0); - ExitOverview(); - EXPECT_TRUE(GetBarWidget()); - EXPECT_TRUE(IsWidgetVisible()); -} - -// Tests that the bar will only be created and shown when the shelf is -// bottom-aligned. -TEST_P(PersistentDesksBarTest, BentoBarWithShelfAlignment) { - Shelf* shelf = Shelf::ForWindow(Shell::GetPrimaryRootWindow()); - - // Create a new desk should cause the bar to be created and shown. - NewDesk(); - EXPECT_EQ(2u, DesksController::Get()->desks().size()); - EXPECT_TRUE(GetBarWidget()); - EXPECT_TRUE(IsWidgetVisible()); - - // The bar should be created when the shelf is bottom aligned. - EXPECT_TRUE(shelf->alignment() == ShelfAlignment::kBottom); - EXPECT_TRUE(GetBarWidget()); - EXPECT_TRUE(IsWidgetVisible()); - - // The bar should be destroyed when the shelf is left aligned. - shelf->SetAlignment(ShelfAlignment::kLeft); - EXPECT_TRUE(shelf->alignment() == ShelfAlignment::kLeft); - EXPECT_FALSE(GetBarWidget()); - - // The bar should be destroyed when the shelf is right aligned. - shelf->SetAlignment(ShelfAlignment::kRight); - EXPECT_TRUE(shelf->alignment() == ShelfAlignment::kRight); - EXPECT_FALSE(GetBarWidget()); - - // The bar should be re-created when the shelf is bottom aligned. - shelf->SetAlignment(ShelfAlignment::kBottom); - EXPECT_TRUE(shelf->alignment() == ShelfAlignment::kBottom); - EXPECT_TRUE(GetBarWidget()); - EXPECT_TRUE(IsWidgetVisible()); -} - -// Tests that the bar is not affected by the launcher opening. -TEST_P(PersistentDesksBarTest, BarStaysOpenWhenLauncherOpens) { - AppListControllerImpl* app_list_controller = - Shell::Get()->app_list_controller(); - - // The bar should be created when the app list is closed. - NewDesk(); - EXPECT_EQ(2u, DesksController::Get()->desks().size()); - EXPECT_TRUE(GetBarWidget()); - EXPECT_TRUE(IsWidgetVisible()); - - // The bar should still exist when the app list is opened. - app_list_controller->ShowAppList(AppListShowSource::kSearchKey); - EXPECT_TRUE(GetBarWidget()); - EXPECT_TRUE(IsWidgetVisible()); - - // The bar should still exist when the app list is closed again. - app_list_controller->DismissAppList(); - EXPECT_TRUE(GetBarWidget()); - EXPECT_TRUE(IsWidgetVisible()); -} - -// Tests that the bar will not be created if Docked Magnifier is on. -TEST_P(PersistentDesksBarTest, NoPersistentDesksBarWithDockedMagnifierOn) { - AccessibilityControllerImpl* accessibility_controller = - Shell::Get()->accessibility_controller(); - - // Create a new desk should cause the bar to be created and shown. - NewDesk(); - EXPECT_EQ(2u, DesksController::Get()->desks().size()); - EXPECT_TRUE(GetBarWidget()); - EXPECT_TRUE(IsWidgetVisible()); - - // Use the bounds at this point as reference for comparison later. - gfx::Rect bounds = GetBarWidget()->GetWindowBoundsInScreen(); - - // The bar should be destroyed when the Docked Magnifier is on. - accessibility_controller->docked_magnifier().SetEnabled(true); - EXPECT_TRUE(accessibility_controller->docked_magnifier().enabled()); - EXPECT_FALSE(GetBarWidget()); - - // The bar should be created when the Docked Magnifier is off. - accessibility_controller->docked_magnifier().SetEnabled(false); - EXPECT_FALSE(accessibility_controller->docked_magnifier().enabled()); - EXPECT_TRUE(GetBarWidget()); - EXPECT_TRUE(IsWidgetVisible()); - - // The bounds should be the same with its original value. - EXPECT_EQ(bounds, GetBarWidget()->GetWindowBoundsInScreen()); -} - -// Tests that the bar will not be created if ChromeVox is on. -TEST_P(PersistentDesksBarTest, NoPersistentDesksBarWithChromeVoxOn) { - AccessibilityControllerImpl* accessibility_controller = - Shell::Get()->accessibility_controller(); - - // Create a new desk should cause the bar to be created and shown. - NewDesk(); - EXPECT_EQ(2u, DesksController::Get()->desks().size()); - EXPECT_TRUE(GetBarWidget()); - EXPECT_TRUE(IsWidgetVisible()); - - // Use the bounds at this point as reference for comparison later. - gfx::Rect bounds = GetBarWidget()->GetWindowBoundsInScreen(); - - // The bar should be destroyed when Chromevox is on. - accessibility_controller->spoken_feedback().SetEnabled(true); - EXPECT_TRUE(accessibility_controller->spoken_feedback().enabled()); - EXPECT_FALSE(GetBarWidget()); - - // The bar should be created when Chromevox is off. - accessibility_controller->spoken_feedback().SetEnabled(false); - EXPECT_FALSE(accessibility_controller->spoken_feedback().enabled()); - EXPECT_TRUE(GetBarWidget()); - EXPECT_TRUE(IsWidgetVisible()); - - // The bounds should be the same with its original value. - EXPECT_EQ(bounds, GetBarWidget()->GetWindowBoundsInScreen()); -} - -// Tests that the bar will not be created if any window is fullscreened. -TEST_P(PersistentDesksBarTest, NoPersistentDesksBarWithFullscreenedWindow) { - // Create a secondary display. - UpdateDisplay("400x300,500x400"); - WMEvent event_toggle_fullscreen(WM_EVENT_TOGGLE_FULLSCREEN); - WMEvent event_fullscreen(WM_EVENT_FULLSCREEN); - std::unique_ptr<aura::Window> window1 = - CreateTestWindow(gfx::Rect(0, 0, 300, 300)); - std::unique_ptr<aura::Window> window2 = - CreateTestWindow(gfx::Rect(0, 0, 300, 300)); - WindowState* window_state1 = WindowState::Get(window1.get()); - WindowState* window_state2 = WindowState::Get(window2.get()); - NewDesk(); - gfx::Rect bounds = GetBarWidget()->GetWindowBoundsInScreen(); - - // window1 and window2 should fall into the primary display. - EXPECT_EQ(window1->GetRootWindow(), Shell::GetPrimaryRootWindow()); - EXPECT_EQ(window2->GetRootWindow(), Shell::GetPrimaryRootWindow()); - - // The bar should be destroyed after `window1` entering fullscreen mode and be - // recreated after 'window1' exiting fullscreen mode. - window_state1->OnWMEvent(&event_toggle_fullscreen); - EXPECT_TRUE(window_state1->IsFullscreen()); - EXPECT_FALSE(GetBarWidget()); - window_state1->OnWMEvent(&event_toggle_fullscreen); - EXPECT_FALSE(window_state1->IsFullscreen()); - EXPECT_TRUE(GetBarWidget()); - EXPECT_TRUE(IsWidgetVisible()); - EXPECT_EQ(bounds, GetBarWidget()->GetWindowBoundsInScreen()); - - // The bar should not be created until both `window1` and `window2` exiting - // fullscreen mode. - window_state1->OnWMEvent(&event_toggle_fullscreen); - window_state2->OnWMEvent(&event_toggle_fullscreen); - EXPECT_FALSE(GetBarWidget()); - window_state1->OnWMEvent(&event_toggle_fullscreen); - EXPECT_FALSE(GetBarWidget()); - window_state2->OnWMEvent(&event_toggle_fullscreen); - EXPECT_TRUE(GetBarWidget()); - EXPECT_TRUE(IsWidgetVisible()); - EXPECT_EQ(bounds, GetBarWidget()->GetWindowBoundsInScreen()); - - // Fullscreen window within the secondary display should not impact - // the persistent desks bar. - std::unique_ptr<aura::Window> window3 = CreateTestWindow(); - window3->SetBoundsInScreen(gfx::Rect(600, 0, 125, 100), - GetSecondaryDisplay()); - WindowState* window_state3 = WindowState::Get(window3.get()); - EXPECT_EQ(window3->GetRootWindow(), Shell::Get()->GetAllRootWindows()[1]); - window_state3->OnWMEvent(&event_toggle_fullscreen); - EXPECT_TRUE(GetBarWidget()); - EXPECT_TRUE(IsWidgetVisible()); - EXPECT_EQ(bounds, GetBarWidget()->GetWindowBoundsInScreen()); - - // The bar should be created after `window1` being minimized. - window_state1->Minimize(); - EXPECT_TRUE(GetBarWidget()); - EXPECT_TRUE(IsWidgetVisible()); - EXPECT_EQ(bounds, GetBarWidget()->GetWindowBoundsInScreen()); - window_state1->OnWMEvent(&event_fullscreen); - EXPECT_FALSE(GetBarWidget()); - window_state1->OnWMEvent(&event_toggle_fullscreen); - - // The bar should not be created until both `window1` and `window2` being - // closed. - window_state1->OnWMEvent(&event_toggle_fullscreen); - window_state2->OnWMEvent(&event_toggle_fullscreen); - window1.reset(); - EXPECT_FALSE(GetBarWidget()); - window2.reset(); - EXPECT_TRUE(GetBarWidget()); - EXPECT_TRUE(IsWidgetVisible()); - EXPECT_EQ(bounds, GetBarWidget()->GetWindowBoundsInScreen()); -} - -// Tests that the bar should not be created in non-active user session. -TEST_P(PersistentDesksBarTest, NoPersistentDesksBarInNonActiveUserSession) { - AccessibilityControllerImpl* accessibility_controller = - Shell::Get()->accessibility_controller(); - TestSessionControllerClient* client = GetSessionControllerClient(); - - // The bar should be created with two desks. - NewDesk(); - EXPECT_TRUE(GetBarWidget()); - EXPECT_TRUE(IsWidgetVisible()); - - // The bar should not be created in LOCKED user session when docked magnifier - // is enabled/disabled. - client->SetSessionState(session_manager::SessionState::LOCKED); - EXPECT_FALSE(GetBarWidget()); - accessibility_controller->docked_magnifier().SetEnabled(true); - EXPECT_FALSE(GetBarWidget()); - accessibility_controller->docked_magnifier().SetEnabled(false); - EXPECT_FALSE(GetBarWidget()); - - // The bar should be created when the user session is active. - client->SetSessionState(session_manager::SessionState::ACTIVE); - EXPECT_TRUE(GetBarWidget()); - EXPECT_TRUE(IsWidgetVisible()); -} - -TEST_P(PersistentDesksBarTest, DisplayMetricsChanged) { - UpdateDisplay("800x600,400x500"); - NewDesk(); - EXPECT_TRUE(GetBarWidget()); - EXPECT_EQ(GetBarWidget()->GetWindowBoundsInScreen().width(), - GetPrimaryDisplay().bounds().width()); - - // The bar should be recreated in the new primary display and with the same - // width as it. - const display::Display old_primary_display = GetPrimaryDisplay(); - SwapPrimaryDisplay(); - const display::Display new_primary_display = GetPrimaryDisplay(); - ASSERT_NE(old_primary_display.id(), new_primary_display.id()); - ASSERT_NE(old_primary_display.bounds().width(), - new_primary_display.bounds().width()); - EXPECT_TRUE(GetBarWidget()); - EXPECT_EQ(GetBarWidget()->GetWindowBoundsInScreen().width(), - new_primary_display.bounds().width()); - - // The bar should be recreated on display rotation to adapt the new display - // bounds. - SwapPrimaryDisplay(); - const int display_width_before_rotate = GetPrimaryDisplay().bounds().width(); - EXPECT_EQ(display_width_before_rotate, - GetBarWidget()->GetWindowBoundsInScreen().width()); - display::test::DisplayManagerTestApi(display_manager()) - .SetFirstDisplayAsInternalDisplay(); - ScreenOrientationControllerTestApi test_api( - Shell::Get()->screen_orientation_controller()); - test_api.SetDisplayRotation(display::Display::ROTATE_90, - display::Display::RotationSource::ACTIVE); - EXPECT_EQ(test_api.GetCurrentOrientation(), - chromeos::OrientationType::kPortraitSecondary); - const int display_width_after_rotate = GetPrimaryDisplay().bounds().width(); - ASSERT_NE(display_width_before_rotate, display_width_after_rotate); - EXPECT_EQ(display_width_after_rotate, - GetBarWidget()->GetWindowBoundsInScreen().width()); - - // Scale up the display, the bar should have the same width as the display - // after scale up. - const int display_width_before_scale_up = display_width_after_rotate; - SendKey(ui::VKEY_OEM_MINUS, ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN); - const int display_width_after_scale_up = GetPrimaryDisplay().bounds().width(); - EXPECT_LE(display_width_before_scale_up, display_width_after_scale_up); - EXPECT_EQ(display_width_after_scale_up, - GetBarWidget()->GetWindowBoundsInScreen().width()); -} - -// Tests bento bar's state on the pref `kBentoBarEnabled` changes. And its value -// should be independent among users. -TEST_P(PersistentDesksBarTest, UpdateBarStateOnPrefChanges) { - const char kUser1[] = "user1@test.com"; - const char kUser2[] = "user2@test.com"; - const AccountId kUserAccount1 = AccountId::FromUserEmail(kUser1); - const AccountId kUserAccount2 = AccountId::FromUserEmail(kUser2); - - TestSessionControllerClient* session_controller = - GetSessionControllerClient(); - // Setup 2 users. - session_controller->AddUserSession(kUser1, user_manager::USER_TYPE_REGULAR, - /*provide_pref_service=*/false); - session_controller->AddUserSession(kUser2, user_manager::USER_TYPE_REGULAR, - /*provide_pref_service=*/false); - - auto user_1_prefs = std::make_unique<TestingPrefServiceSimple>(); - RegisterUserProfilePrefs(user_1_prefs->registry(), /*for_test=*/true); - auto user_2_prefs = std::make_unique<TestingPrefServiceSimple>(); - RegisterUserProfilePrefs(user_2_prefs->registry(), /*for_test=*/true); - session_controller->SetUserPrefService(kUserAccount1, - std::move(user_1_prefs)); - session_controller->SetUserPrefService(kUserAccount2, - std::move(user_2_prefs)); - - session_controller->SwitchActiveUser(kUserAccount1); - session_controller->SetSessionState(session_manager::SessionState::ACTIVE); - auto* bar_controller = Shell::Get()->persistent_desks_bar_controller(); - // Toggling to hide the bar for user1. - NewDesk(); - EXPECT_TRUE(GetBarWidget()); - EXPECT_TRUE(bar_controller->IsEnabled()); - bar_controller->ToggleEnabledState(); - EXPECT_FALSE(GetBarWidget()); - EXPECT_FALSE(bar_controller->IsEnabled()); - - // Toggling to hide the bar for user1 should not affect user2. The bar should - // still visible for user2. - session_controller->SwitchActiveUser(kUserAccount2); - EXPECT_TRUE(GetBarWidget()); - EXPECT_TRUE(bar_controller->IsEnabled()); - - // Switching back to user1. The bar should still be hidden. - session_controller->SwitchActiveUser(kUserAccount1); - EXPECT_FALSE(GetBarWidget()); - EXPECT_FALSE(bar_controller->IsEnabled()); -} - -// Tests desks bar's position in overview and app window's position in -// split view. -TEST_P(PersistentDesksBarTest, SnappingWindowsInOverview) { - UpdateDisplay("800x600"); - NewDesk(); - std::unique_ptr<aura::Window> window1 = - CreateTestWindow(gfx::Rect(0, 0, 300, 300)); - std::unique_ptr<aura::Window> window2 = - CreateTestWindow(gfx::Rect(0, 0, 300, 300)); - EnterOverview(); - - OverviewController* overview_controller = Shell::Get()->overview_controller(); - OverviewSession* overview_session = overview_controller->overview_session(); - OverviewGrid* overview_grid = - overview_session->GetGridWithRootWindow(Shell::GetPrimaryRootWindow()); - OverviewItem* overview_item_1 = - overview_session->GetOverviewItemForWindow(window1.get()); - OverviewItem* overview_item_2 = - overview_session->GetOverviewItemForWindow(window2.get()); - - // Test the desks bar is at the top of the display while trying to snap a - // window in overview mode. - ui::test::EventGenerator* event_generator = GetEventGenerator(); - DragItemToPoint(overview_item_1, gfx::Point(0, 300), event_generator); - EXPECT_TRUE(overview_controller->InOverviewSession()); - EXPECT_EQ(overview_grid->desks_widget()->GetNativeWindow()->bounds().y(), 0); - - // Test windows are at the correct position after snapping. - DragItemToPoint(overview_item_2, gfx::Point(800, 300), event_generator); - EXPECT_FALSE(overview_controller->InOverviewSession()); - const int bar_height = PersistentDesksBarController::kBarHeight; - EXPECT_EQ(window1->GetBoundsInScreen().y(), bar_height); - EXPECT_EQ(window2->GetBoundsInScreen().y(), bar_height); -} - // A class that maintains a window created inside of a test. If the window is // destroyed from outside of the class, it releases the window's unique pointer // to prevent use-after-free issues. @@ -9277,9 +8670,7 @@ INSTANTIATE_TEST_SUITE_P(All, DesksEditableNamesTest, ValuesIn(kDeskCountOnly)); INSTANTIATE_TEST_SUITE_P(All, TabletModeDesksTest, ValuesIn(kDeskCountOnly)); INSTANTIATE_TEST_SUITE_P(All, DesksAcceleratorsTest, ValuesIn(kDeskCountOnly)); -INSTANTIATE_TEST_SUITE_P(All, DesksBentoBarTest, ValuesIn(kDeskCountOnly)); INSTANTIATE_TEST_SUITE_P(All, DesksMockTimeTest, ValuesIn(kDeskCountOnly)); -INSTANTIATE_TEST_SUITE_P(All, PersistentDesksBarTest, ValuesIn(kDeskCountOnly)); INSTANTIATE_TEST_SUITE_P(All, DesksCloseAllTest, ValuesIn(kDeskCountOnly)); INSTANTIATE_TEST_SUITE_P(All, PerDeskShelfTest, ::testing::Bool()); INSTANTIATE_TEST_SUITE_P(All, BentoButtonTest, ValuesIn(kAllCombinations));
diff --git a/ash/wm/desks/persistent_desks_bar/DIR_METADATA b/ash/wm/desks/persistent_desks_bar/DIR_METADATA deleted file mode 100644 index 6f3cab8..0000000 --- a/ash/wm/desks/persistent_desks_bar/DIR_METADATA +++ /dev/null
@@ -1,7 +0,0 @@ -team_email: "chromeos-wms@google.com" -buganizer { - component_id: 1238313 -} -buganizer_public { - component_id: 1238363 -} \ No newline at end of file
diff --git a/ash/wm/desks/persistent_desks_bar/persistent_desks_bar_button.cc b/ash/wm/desks/persistent_desks_bar/persistent_desks_bar_button.cc deleted file mode 100644 index 0685d5e..0000000 --- a/ash/wm/desks/persistent_desks_bar/persistent_desks_bar_button.cc +++ /dev/null
@@ -1,165 +0,0 @@ -// Copyright 2021 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/desks/persistent_desks_bar/persistent_desks_bar_button.h" - -#include "ash/resources/vector_icons/vector_icons.h" -#include "ash/shell.h" -#include "ash/style/ash_color_provider.h" -#include "ash/style/style_util.h" -#include "ash/wm/desks/desk.h" -#include "ash/wm/desks/desks_controller.h" -#include "ash/wm/desks/persistent_desks_bar/persistent_desks_bar_context_menu.h" -#include "ash/wm/overview/overview_controller.h" -#include "base/functional/bind.h" -#include "ui/base/metadata/metadata_impl_macros.h" -#include "ui/gfx/paint_vector_icon.h" -#include "ui/views/animation/ink_drop.h" -#include "ui/views/controls/highlight_path_generator.h" - -namespace ash { - -namespace { - -constexpr int kCircularButtonSize = 32; - -constexpr int kCornerRadius = 8; - -} // namespace - -// ----------------------------------------------------------------------------- -// PersistentDesksBarDeskButton: - -PersistentDesksBarDeskButton::PersistentDesksBarDeskButton(const Desk* desk) - : DeskButtonBase( - desk->name(), - /*set_text=*/true, - /*bar_view=*/nullptr, - base::BindRepeating(&PersistentDesksBarDeskButton::OnButtonPressed, - base::Unretained(this)), - kCornerRadius), - desk_(desk) { - // TODO(minch): A11y of bento bar. - SetAccessibleName(base::UTF8ToUTF16(GetClassName())); - // Only paint the background of the active desk's button. - SetShouldPaintBackground(desk_ == DesksController::Get()->active_desk()); -} - -void PersistentDesksBarDeskButton::UpdateText(std::u16string name) { - SetText(std::move(name)); -} - -void PersistentDesksBarDeskButton::OnButtonPressed() { - // If there is an ongoing desk activation, do nothing. - DesksController* desks_controller = DesksController::Get(); - if (!desks_controller->AreDesksBeingModified()) { - desks_controller->ActivateDesk(desk_, - DesksSwitchSource::kPersistentDesksBar); - } -} - -void PersistentDesksBarDeskButton::OnThemeChanged() { - DeskButtonBase::OnThemeChanged(); - SetEnabledTextColors(AshColorProvider::Get()->GetContentLayerColor( - AshColorProvider::ContentLayerType::kTextColorPrimary)); -} - -void PersistentDesksBarDeskButton::OnMouseEntered(const ui::MouseEvent& event) { - SetShouldPaintBackground(true); -} - -void PersistentDesksBarDeskButton::OnMouseExited(const ui::MouseEvent& event) { - SetShouldPaintBackground(desk_ == DesksController::Get()->active_desk()); -} - -BEGIN_METADATA(PersistentDesksBarDeskButton, DeskButtonBase) -END_METADATA - -// ----------------------------------------------------------------------------- -// PersistentDesksBarCircularButton: - -PersistentDesksBarCircularButton::PersistentDesksBarCircularButton( - const gfx::VectorIcon& icon) - : views::ImageButton(base::BindRepeating( - &PersistentDesksBarCircularButton::OnButtonPressed, - base::Unretained(this))), - icon_(icon) { - // TODO(minch): A11y of bento bar. - SetAccessibleName(base::UTF8ToUTF16(GetClassName())); - SetImageHorizontalAlignment(ALIGN_CENTER); - SetImageVerticalAlignment(ALIGN_MIDDLE); - // Keeping the same inkdrop and highlight as the buttons inside the system - // tray menu for now since specs are not ready. - // TODO(minch): Update once the specs are ready and need to be updated. - StyleUtil::SetUpInkDropForButton(this); - views::InstallCircleHighlightPathGenerator(this); -} - -gfx::Size PersistentDesksBarCircularButton::CalculatePreferredSize() const { - return gfx::Size(kCircularButtonSize, kCircularButtonSize); -} - -void PersistentDesksBarCircularButton::OnThemeChanged() { - views::ImageButton::OnThemeChanged(); - - const SkColor enabled_icon_color = - AshColorProvider::Get()->GetContentLayerColor( - AshColorProvider::ContentLayerType::kButtonIconColor); - SetImage(views::Button::STATE_NORMAL, - gfx::CreateVectorIcon(icon_, enabled_icon_color)); -} - -BEGIN_METADATA(PersistentDesksBarCircularButton, views::ImageButton) -END_METADATA - -// ----------------------------------------------------------------------------- -// PersistentDesksBarVerticalDotsButton: - -PersistentDesksBarVerticalDotsButton::PersistentDesksBarVerticalDotsButton() - : PersistentDesksBarCircularButton(kPersistentDesksBarVerticalDotsIcon), - context_menu_( - std::make_unique<PersistentDesksBarContextMenu>(base::BindRepeating( - &PersistentDesksBarVerticalDotsButton::OnMenuClosed, - base::Unretained(this)))) {} - -PersistentDesksBarVerticalDotsButton::~PersistentDesksBarVerticalDotsButton() = - default; - -void PersistentDesksBarVerticalDotsButton::OnButtonPressed() { - context_menu_->ShowContextMenuForView(this, GetBoundsInScreen().CenterPoint(), - ui::MENU_SOURCE_NONE); - // Keeping InkDrop as activated after releasing the mouse with the context - // menu opened. It will be set as deactivated after the context menu is - // closed. - views::InkDrop::Get(this)->GetInkDrop()->AnimateToState( - views::InkDropState::ACTIVATED); -} - -void PersistentDesksBarVerticalDotsButton::OnMenuClosed() { - views::InkDrop::Get(this)->GetInkDrop()->AnimateToState( - views::InkDropState::DEACTIVATED); -} - -BEGIN_METADATA(PersistentDesksBarVerticalDotsButton, - PersistentDesksBarCircularButton) -END_METADATA - -// ----------------------------------------------------------------------------- -// PersistentDesksBarOverviewButton: - -PersistentDesksBarOverviewButton::PersistentDesksBarOverviewButton() - : PersistentDesksBarCircularButton(kPersistentDesksBarChevronDownIcon) {} - -PersistentDesksBarOverviewButton::~PersistentDesksBarOverviewButton() = default; - -void PersistentDesksBarOverviewButton::OnButtonPressed() { - Shell::Get()->overview_controller()->StartOverview( - OverviewStartAction::kBentoBar); -} - -BEGIN_METADATA(PersistentDesksBarOverviewButton, - PersistentDesksBarCircularButton) -END_METADATA - -} // namespace ash
diff --git a/ash/wm/desks/persistent_desks_bar/persistent_desks_bar_button.h b/ash/wm/desks/persistent_desks_bar/persistent_desks_bar_button.h deleted file mode 100644 index 562b0d3..0000000 --- a/ash/wm/desks/persistent_desks_bar/persistent_desks_bar_button.h +++ /dev/null
@@ -1,117 +0,0 @@ -// Copyright 2021 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_DESKS_PERSISTENT_DESKS_BAR_BUTTON_H_ -#define ASH_WM_DESKS_PERSISTENT_DESKS_BAR_BUTTON_H_ - -#include <string> - -#include "ash/wm/desks/desk_button_base.h" -#include "ui/gfx/vector_icon_types.h" -#include "ui/views/controls/button/image_button.h" - -namespace ash { - -class Desk; -class PersistentDesksBarContextMenu; - -// The button with the desk's name inside the PersistentDesksBarView. -class PersistentDesksBarDeskButton : public DeskButtonBase { - public: - METADATA_HEADER(PersistentDesksBarDeskButton); - - explicit PersistentDesksBarDeskButton(const Desk* desk); - PersistentDesksBarDeskButton(const PersistentDesksBarDeskButton&) = delete; - PersistentDesksBarDeskButton& operator=(const PersistentDesksBarDeskButton) = - delete; - ~PersistentDesksBarDeskButton() override = default; - - const Desk* desk() const { return desk_; } - void UpdateText(std::u16string name); - - private: - // DeskButtonBase: - void OnThemeChanged() override; - void OnMouseEntered(const ui::MouseEvent& event) override; - void OnMouseExited(const ui::MouseEvent& event) override; - - void OnButtonPressed(); - - const Desk* desk_; -}; - -// The base class of the circular buttons inside the persistent desks bar. -// Including PersistentDesksBarVerticalDotsButton and -// PersistentDesksBarOverviewButton. -class PersistentDesksBarCircularButton : public views::ImageButton { - public: - METADATA_HEADER(PersistentDesksBarCircularButton); - - explicit PersistentDesksBarCircularButton(const gfx::VectorIcon& icon); - PersistentDesksBarCircularButton(const PersistentDesksBarCircularButton&) = - delete; - PersistentDesksBarCircularButton& operator=( - const PersistentDesksBarCircularButton&) = delete; - ~PersistentDesksBarCircularButton() override = default; - - // views::ImageButton: - gfx::Size CalculatePreferredSize() const override; - void OnThemeChanged() override; - - private: - virtual void OnButtonPressed() = 0; - - const gfx::VectorIcon& icon_; -}; - -// A circular button inside the persistent desks bar or the desks bar in -// overview mode with kPersistentDesksBarVerticalDotsIcon. Clicking the button -// will open a context menu that can be used to send feedback or show/hide the -// persistent desks bar. -class PersistentDesksBarVerticalDotsButton - : public PersistentDesksBarCircularButton { - public: - METADATA_HEADER(PersistentDesksBarVerticalDotsButton); - - PersistentDesksBarVerticalDotsButton(); - PersistentDesksBarVerticalDotsButton( - const PersistentDesksBarVerticalDotsButton&) = delete; - PersistentDesksBarVerticalDotsButton& operator=( - const PersistentDesksBarVerticalDotsButton&); - ~PersistentDesksBarVerticalDotsButton() override; - - private: - friend class DesksTestApi; - - // PersistentDesksBarCircularButton: - void OnButtonPressed() override; - - void OnMenuClosed(); - - std::unique_ptr<PersistentDesksBarContextMenu> context_menu_; -}; - -// A circular button inside the persistent desks bar with -// kPersistentDesksBarChevronDownIcon. Clicking the button will destroy the bar -// and enter overview mode. -class PersistentDesksBarOverviewButton - : public PersistentDesksBarCircularButton { - public: - METADATA_HEADER(PersistentDesksBarOverviewButton); - - PersistentDesksBarOverviewButton(); - PersistentDesksBarOverviewButton(const PersistentDesksBarOverviewButton&) = - delete; - const PersistentDesksBarOverviewButton& operator=( - const PersistentDesksBarOverviewButton&) = delete; - ~PersistentDesksBarOverviewButton() override; - - private: - // PersistentDesksBarCircularButton: - void OnButtonPressed() override; -}; - -} // namespace ash - -#endif // ASH_WM_DESKS_PERSISTENT_DESKS_BAR_BUTTON_H_
diff --git a/ash/wm/desks/persistent_desks_bar/persistent_desks_bar_context_menu.cc b/ash/wm/desks/persistent_desks_bar/persistent_desks_bar_context_menu.cc deleted file mode 100644 index 5c98f2b..0000000 --- a/ash/wm/desks/persistent_desks_bar/persistent_desks_bar_context_menu.cc +++ /dev/null
@@ -1,87 +0,0 @@ -// Copyright 2021 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/desks/persistent_desks_bar/persistent_desks_bar_context_menu.h" - -#include "ash/resources/vector_icons/vector_icons.h" -#include "ash/shell.h" -#include "ash/shell_delegate.h" -#include "ash/strings/grit/ash_strings.h" -#include "ash/wm/desks/persistent_desks_bar/persistent_desks_bar_controller.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/views/controls/menu/menu_runner.h" -#include "ui/views/view.h" - -namespace ash { - -PersistentDesksBarContextMenu::PersistentDesksBarContextMenu( - base::RepeatingClosure on_menu_closed_callback) - : on_menu_closed_callback_(std::move(on_menu_closed_callback)) {} - -PersistentDesksBarContextMenu::~PersistentDesksBarContextMenu() = default; - -void PersistentDesksBarContextMenu::ShowContextMenuForViewImpl( - views::View* source, - const gfx::Point& point, - ui::MenuSourceType source_type) { - const int run_types = views::MenuRunner::USE_ASH_SYS_UI_LAYOUT | - views::MenuRunner::CONTEXT_MENU | - views::MenuRunner::FIXED_ANCHOR; - - context_menu_runner_ = - std::make_unique<views::MenuRunner>(BuildMenuModel(), run_types); - context_menu_runner_->RunMenuAt( - source->GetWidget(), /*button_controller=*/nullptr, - gfx::Rect(source->GetBoundsInScreen().bottom_right(), gfx::Size()), - views::MenuAnchorPosition::kBubbleBottomRight, source_type); -} - -void PersistentDesksBarContextMenu::ExecuteCommand(int command_id, - int event_flags) { - auto* shell = Shell::Get(); - switch (static_cast<CommandId>(command_id)) { - case CommandId::kFeedBack: - shell->shell_delegate()->OpenFeedbackDialog( - ShellDelegate::FeedbackSource::kBentoBar, - /*description_template=*/"#BentoBar\n\n"); - break; - case CommandId::kShowOrHideBar: - shell->persistent_desks_bar_controller()->ToggleEnabledState(); - break; - default: - NOTREACHED(); - break; - } -} - -void PersistentDesksBarContextMenu::MenuClosed(ui::SimpleMenuModel* menu) { - on_menu_closed_callback_.Run(); -} - -ui::SimpleMenuModel* PersistentDesksBarContextMenu::BuildMenuModel() { - context_menu_model_ = std::make_unique<ui::SimpleMenuModel>(this); - context_menu_model_->AddItemWithIcon( - static_cast<int>(CommandId::kFeedBack), - l10n_util::GetStringUTF16( - IDS_ASH_PERSISTENT_DESKS_BAR_CONTEXT_MENU_FEEDBACK), - ui::ImageModel::FromVectorIcon(kPersistentDesksBarFeedbackIcon, - ui::kColorAshSystemUIMenuIcon)); - - auto* bar_controller = Shell::Get()->persistent_desks_bar_controller(); - const bool is_enabled = bar_controller->IsEnabled(); - context_menu_model_->AddItemWithIcon( - static_cast<int>(CommandId::kShowOrHideBar), - l10n_util::GetStringUTF16( - is_enabled - ? IDS_ASH_PERSISTENT_DESKS_BAR_CONTEXT_MENU_HIDE_DESKS_BAR - : IDS_ASH_PERSISTENT_DESKS_BAR_CONTEXT_MENU_SHOW_DESKS_BAR), - ui::ImageModel::FromVectorIcon(is_enabled - ? kPersistentDesksBarNotVisibleIcon - : kPersistentDesksBarVisibleIcon, - ui::kColorAshSystemUIMenuIcon)); - - return context_menu_model_.get(); -} - -} // namespace ash
diff --git a/ash/wm/desks/persistent_desks_bar/persistent_desks_bar_context_menu.h b/ash/wm/desks/persistent_desks_bar/persistent_desks_bar_context_menu.h deleted file mode 100644 index fe9496f..0000000 --- a/ash/wm/desks/persistent_desks_bar/persistent_desks_bar_context_menu.h +++ /dev/null
@@ -1,56 +0,0 @@ -// Copyright 2021 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_DESKS_PERSISTENT_DESKS_BAR_CONTEXT_MENU_H_ -#define ASH_WM_DESKS_PERSISTENT_DESKS_BAR_CONTEXT_MENU_H_ - -#include <memory> - -#include "ui/base/models/simple_menu_model.h" -#include "ui/views/context_menu_controller.h" - -namespace views { -class MenuRunner; -} // namespace views - -namespace ash { - -// A helper class to manage the context menu of the persistent desks bar. -class PersistentDesksBarContextMenu : public views::ContextMenuController, - public ui::SimpleMenuModel::Delegate { - public: - // Commands of the context menu. - enum class CommandId { - kFeedBack, - kShowOrHideBar, - }; - - explicit PersistentDesksBarContextMenu( - base::RepeatingClosure on_menu_closed_callback); - PersistentDesksBarContextMenu(const PersistentDesksBarContextMenu&) = delete; - PersistentDesksBarContextMenu& operator=( - const PersistentDesksBarContextMenu&) = delete; - ~PersistentDesksBarContextMenu() override; - - // views::ContextMenuController: - void ShowContextMenuForViewImpl(views::View* source, - const gfx::Point& point, - ui::MenuSourceType source_type) override; - - // ui::SimpleMenuModel::Delegate: - void ExecuteCommand(int command_id, int event_flags) override; - void MenuClosed(ui::SimpleMenuModel* menu) override; - - private: - ui::SimpleMenuModel* BuildMenuModel(); - - std::unique_ptr<ui::SimpleMenuModel> context_menu_model_; - std::unique_ptr<views::MenuRunner> context_menu_runner_; - - base::RepeatingClosure on_menu_closed_callback_; -}; - -} // namespace ash - -#endif // ASH_WM_DESKS_PERSISTENT_DESKS_BAR_CONTEXT_MENU_H_
diff --git a/ash/wm/desks/persistent_desks_bar/persistent_desks_bar_controller.cc b/ash/wm/desks/persistent_desks_bar/persistent_desks_bar_controller.cc deleted file mode 100644 index 6a5459b2..0000000 --- a/ash/wm/desks/persistent_desks_bar/persistent_desks_bar_controller.cc +++ /dev/null
@@ -1,368 +0,0 @@ -// Copyright 2021 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/desks/persistent_desks_bar/persistent_desks_bar_controller.h" - -#include "ash/accessibility/accessibility_controller_impl.h" -#include "ash/app_list/app_list_controller_impl.h" -#include "ash/constants/ash_features.h" -#include "ash/public/cpp/app_list/app_list_types.h" -#include "ash/public/cpp/shell_window_ids.h" -#include "ash/session/session_controller_impl.h" -#include "ash/shelf/shelf.h" -#include "ash/shell.h" -#include "ash/wm/desks/desks_restore_util.h" -#include "ash/wm/desks/persistent_desks_bar/persistent_desks_bar_view.h" -#include "ash/wm/mru_window_tracker.h" -#include "ash/wm/overview/overview_controller.h" -#include "ash/wm/tablet_mode/tablet_mode_controller.h" -#include "ash/wm/work_area_insets.h" -#include "base/containers/contains.h" -#include "base/metrics/histogram_macros.h" -#include "components/prefs/pref_change_registrar.h" -#include "components/prefs/pref_service.h" -#include "ui/aura/window.h" -#include "ui/display/screen.h" -#include "ui/views/widget/widget.h" - -namespace ash { - -namespace { - -// A boolean pref indicates whether the bar is set to show or hide through the -// context menu. Showing the bar if this pref is true, hiding otherwise. -constexpr char kBentoBarEnabled[] = "ash.bento_bar.enabled"; - -// Creates and returns the widget that contains the PersistentDesksBarView. The -// returned widget has no content view yet, and hasn't been shown yet. -std::unique_ptr<views::Widget> CreatePersistentDesksBarWidget() { - auto widget = std::make_unique<views::Widget>(); - views::Widget::InitParams params( - views::Widget::InitParams::TYPE_WINDOW_FRAMELESS); - params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; - params.activatable = views::Widget::InitParams::Activatable::kNo; - params.accept_events = true; - params.opacity = views::Widget::InitParams::WindowOpacity::kTranslucent; - // Create and show the bar only in the primary display for now. Since it is - // enough to collect the metrics for the experiment, it can also avoid the bar - // to consume space from all the displays. - auto* root_window = Shell::GetPrimaryRootWindow(); - params.parent = root_window->GetChildById(kShellWindowId_ShelfContainer); - gfx::Rect bounds = display::Screen::GetScreen() - ->GetDisplayNearestWindow(root_window) - .bounds(); - bounds.set_height(PersistentDesksBarController::kBarHeight); - params.bounds = bounds; - params.name = "PersistentDesksBarWidget"; - - widget->Init(std::move(params)); - return widget; -} - -} // namespace - -PersistentDesksBarController::PersistentDesksBarController() { - auto* shell = Shell::Get(); - shell->session_controller()->AddObserver(this); - shell->overview_controller()->AddObserver(this); - shell->desks_controller()->AddObserver(this); - shell->tablet_mode_controller()->AddObserver(this); - shell->AddShellObserver(this); - shell->app_list_controller()->AddObserver(this); - shell->accessibility_controller()->AddObserver(this); - display::Screen::GetScreen()->AddObserver(this); -} - -PersistentDesksBarController::~PersistentDesksBarController() { - display::Screen::GetScreen()->RemoveObserver(this); - auto* shell = Shell::Get(); - shell->accessibility_controller()->RemoveObserver(this); - shell->app_list_controller()->RemoveObserver(this); - shell->RemoveShellObserver(this); - shell->tablet_mode_controller()->RemoveObserver(this); - shell->desks_controller()->RemoveObserver(this); - shell->overview_controller()->RemoveObserver(this); - shell->session_controller()->RemoveObserver(this); -} - -// static -void PersistentDesksBarController::RegisterProfilePrefs( - PrefRegistrySimple* registry) { - registry->RegisterBooleanPref(kBentoBarEnabled, /*default_value=*/true); -} - -// static -bool PersistentDesksBarController::ShouldPersistentDesksBarBeVisible() { - // Only check whether the feature is overridden from command line if the - // FeatureList is initialized. - const base::FeatureList* feature_list = base::FeatureList::GetInstance(); - return (feature_list && feature_list->IsFeatureOverriddenFromCommandLine( - features::kBentoBar.name, - base::FeatureList::OVERRIDE_ENABLE_FEATURE)) || - (features::IsBentoBarEnabled() && - desks_restore_util::HasPrimaryUserUsedDesksRecently()); -} - -void PersistentDesksBarController::OnSessionStateChanged( - session_manager::SessionState state) { - if (state == session_manager::SessionState::ACTIVE) - MaybeInitBarWidget(); - else - DestroyBarWidget(); -} - -void PersistentDesksBarController::OnActiveUserPrefServiceChanged( - PrefService* prefs) { - active_user_pref_service_ = prefs; - pref_change_registrar_ = std::make_unique<PrefChangeRegistrar>(); - pref_change_registrar_->Init(prefs); - - pref_change_registrar_->Add( - kBentoBarEnabled, - base::BindRepeating( - &PersistentDesksBarController::UpdateBarStateOnPrefChanges, - base::Unretained(this))); - UpdateBarStateOnPrefChanges(); -} - -void PersistentDesksBarController::OnOverviewModeWillStart() { - overview_mode_in_progress_ = true; - DestroyBarWidget(); -} - -void PersistentDesksBarController::OnOverviewModeEndingAnimationComplete( - bool canceled) { - overview_mode_in_progress_ = false; - if (!canceled) - MaybeInitBarWidget(); -} - -void PersistentDesksBarController::OnDeskAdded(const Desk* desk) { - MaybeInitBarWidget(); -} - -void PersistentDesksBarController::OnDeskRemoved(const Desk* desk) { - if (!persistent_desks_bar_widget_) - return; - - if (DesksController::Get()->desks().size() == 1) - DestroyBarWidget(); - else - persistent_desks_bar_view_->RefreshDeskButtons(); -} - -void PersistentDesksBarController::OnDeskReordered(int old_index, - int new_index) { - // Desk reordering is supported in overview mode only. The bar should have - // been destroyed while entering overview mode. - DCHECK(!persistent_desks_bar_widget_); -} - -void PersistentDesksBarController::OnDeskActivationChanged( - const Desk* activated, - const Desk* deactivated) { - if (!persistent_desks_bar_widget_) - return; - - persistent_desks_bar_view_->RefreshDeskButtons(); -} - -void PersistentDesksBarController::OnDeskNameChanged( - const Desk* desk, - const std::u16string& new_name) { - if (persistent_desks_bar_view_) - persistent_desks_bar_view_->RefreshDeskButtons(); -} - -void PersistentDesksBarController::OnTabletModeStarted() { - DestroyBarWidget(); -} - -void PersistentDesksBarController::OnTabletModeEnded() { - MaybeInitBarWidget(); -} - -void PersistentDesksBarController::OnShelfAlignmentChanged( - aura::Window* root_window, - ShelfAlignment old_alignment) { - const Shelf* shelf = Shelf::ForWindow(root_window); - if (shelf->IsHorizontalAlignment()) - MaybeInitBarWidget(); - else - DestroyBarWidget(); -} - -void PersistentDesksBarController::OnViewStateChanged(AppListViewState state) { - if (state == AppListViewState::kFullscreenAllApps || - state == AppListViewState::kFullscreenSearch) { - DestroyBarWidget(); - } else { - MaybeInitBarWidget(); - } -} - -void PersistentDesksBarController::OnAccessibilityStatusChanged() { - AccessibilityControllerImpl* accessibility_controller = - Shell::Get()->accessibility_controller(); - if (accessibility_controller->spoken_feedback().enabled() || - accessibility_controller->docked_magnifier().enabled()) { - DestroyBarWidget(); - } else { - MaybeInitBarWidget(); - } -} - -void PersistentDesksBarController::OnDisplayMetricsChanged( - const display::Display& display, - uint32_t changed_metrics) { - // Ignore all metrics except for those listed in `filter`. - const uint32_t filter = - display::DisplayObserver::DISPLAY_METRIC_BOUNDS | - display::DisplayObserver::DISPLAY_METRIC_PRIMARY | - display::DisplayObserver::DISPLAY_METRIC_ROTATION | - display::DisplayObserver::DISPLAY_METRIC_DEVICE_SCALE_FACTOR; - if ((filter & changed_metrics) == 0) - return; - - DestroyBarWidget(); - MaybeInitBarWidget(); -} - -bool PersistentDesksBarController::IsEnabled() const { - return active_user_pref_service_ && - active_user_pref_service_->GetBoolean(kBentoBarEnabled); -} - -void PersistentDesksBarController::ToggleEnabledState() { - DCHECK(active_user_pref_service_); - const bool new_state = !IsEnabled(); - active_user_pref_service_->SetBoolean(kBentoBarEnabled, new_state); - if (!new_state) - DestroyBarWidget(); - - UMA_HISTOGRAM_BOOLEAN("Ash.Desks.BentoBarEnabled", new_state); -} - -void PersistentDesksBarController::MaybeInitBarWidget() { - if (!ShouldPersistentDesksBarBeCreated()) - return; - - if (!persistent_desks_bar_widget_) { - DCHECK(!persistent_desks_bar_view_); - persistent_desks_bar_widget_ = CreatePersistentDesksBarWidget(); - persistent_desks_bar_view_ = persistent_desks_bar_widget_->SetContentsView( - std::make_unique<PersistentDesksBarView>()); - } - persistent_desks_bar_view_->RefreshDeskButtons(); - persistent_desks_bar_widget_->Show(); - - // Update work area on the persistent desks bar's state. Note, the bar is only - // created in the primary display. - WorkAreaInsets::ForWindow(Shell::GetPrimaryRootWindow()) - ->SetPersistentDeskBarHeight(kBarHeight); - - UMA_HISTOGRAM_BOOLEAN("Ash.Desks.BentoBarIsVisible", true); -} - -void PersistentDesksBarController::DestroyBarWidget() { - persistent_desks_bar_widget_.reset(); - persistent_desks_bar_view_ = nullptr; - - // Update work area on the persistent desks bar's state. Note, the bar is only - // created in the primary display. - WorkAreaInsets::ForWindow(Shell::GetPrimaryRootWindow()) - ->SetPersistentDeskBarHeight(0); -} - -void PersistentDesksBarController::UpdateBarOnWindowStateChanges( - aura::Window* window) { - if (window->GetRootWindow() != Shell::GetPrimaryRootWindow()) - return; - - MruWindowTracker::WindowList windows = - Shell::Get()->mru_window_tracker()->BuildMruWindowList(kActiveDesk); - if (!base::Contains(windows, window)) - return; - - if (WindowState::Get(window)->IsFullscreen()) - DestroyBarWidget(); - else - MaybeInitBarWidget(); -} - -void PersistentDesksBarController::UpdateBarOnWindowDestroying( - aura::Window* window) { - if (!WindowState::Get(window)->IsFullscreen() || - window->GetRootWindow() != Shell::GetPrimaryRootWindow()) { - return; - } - MaybeInitBarWidget(); -} - -bool PersistentDesksBarController::ShouldPersistentDesksBarBeCreated() const { - if (!ShouldPersistentDesksBarBeVisible()) - return false; - - if (!IsEnabled()) - return false; - - Shell* shell = Shell::Get(); - - // Do not create the bar in tablet mode, overview mode or if there is - // only one desk. - if (TabletMode::Get()->InTabletMode() || overview_mode_in_progress_ || - DesksController::Get()->desks().size() == 1) { - return false; - } - - // Do not create the bar in non-active user session. - if (shell->session_controller()->GetSessionState() != - session_manager::SessionState::ACTIVE) { - return false; - } - - // Do not create the bar if the shelf is not horizontal-aligned. - if (!Shelf::ForWindow(Shell::GetPrimaryRootWindow())->IsHorizontalAlignment()) - return false; - - // Do not create the bar if the app list is fullscreened. - AppListControllerImpl* app_list_controller = shell->app_list_controller(); - if (app_list_controller) { - const AppListViewState state = app_list_controller->GetAppListViewState(); - if (state == AppListViewState::kFullscreenAllApps || - state == AppListViewState::kFullscreenSearch) { - return false; - } - } - - // Do not create the bar if ChromeVox or Docked Magnifier is on. - AccessibilityControllerImpl* accessibility_controller = - shell->accessibility_controller(); - if (accessibility_controller->spoken_feedback().enabled() || - accessibility_controller->docked_magnifier().enabled()) { - return false; - } - - // Do not create the bar if any window within the primary display is - // fullscreened. - MruWindowTracker::WindowList windows = - shell->mru_window_tracker()->BuildMruWindowList(kActiveDesk); - for (aura::Window* window : windows) { - if (window->GetRootWindow() != Shell::GetPrimaryRootWindow()) - continue; - if (WindowState::Get(window)->IsFullscreen()) - return false; - } - - return true; -} - -void PersistentDesksBarController::UpdateBarStateOnPrefChanges() { - if (IsEnabled()) - MaybeInitBarWidget(); - else - DestroyBarWidget(); -} - -} // namespace ash
diff --git a/ash/wm/desks/persistent_desks_bar/persistent_desks_bar_controller.h b/ash/wm/desks/persistent_desks_bar/persistent_desks_bar_controller.h deleted file mode 100644 index 3f192d14..0000000 --- a/ash/wm/desks/persistent_desks_bar/persistent_desks_bar_controller.h +++ /dev/null
@@ -1,154 +0,0 @@ -// Copyright 2021 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_DESKS_PERSISTENT_DESKS_BAR_CONTROLLER_H_ -#define ASH_WM_DESKS_PERSISTENT_DESKS_BAR_CONTROLLER_H_ - -#include "ash/accessibility/accessibility_observer.h" -#include "ash/ash_export.h" -#include "ash/public/cpp/app_list/app_list_controller_observer.h" -#include "ash/public/cpp/session/session_observer.h" -#include "ash/public/cpp/shelf_types.h" -#include "ash/public/cpp/tablet_mode_observer.h" -#include "ash/shell_observer.h" -#include "ash/wm/desks/desks_controller.h" -#include "ash/wm/overview/overview_observer.h" -#include "ui/display/display_observer.h" -#include "ui/views/widget/unique_widget_ptr.h" - -class PrefChangeRegistrar; -class PrefRegistrySimple; -class PrefService; - -namespace aura { -class Window; -} // namespace aura - -namespace ash { - -class PersistentDesksBarView; -enum class AppListViewState; - -// Controller for the persistent desks bar. One per display, because each -// display has its own persistent desks bar widget and view hierarchy, different -// settings to show or hide the bar as well. -class ASH_EXPORT PersistentDesksBarController - : public SessionObserver, - public OverviewObserver, - public DesksController::Observer, - public TabletModeObserver, - public ShellObserver, - public AppListControllerObserver, - public AccessibilityObserver, - public display::DisplayObserver { - public: - constexpr static int kBarHeight = 40; - - PersistentDesksBarController(); - PersistentDesksBarController(const PersistentDesksBarController&) = delete; - PersistentDesksBarController& operator=(const PersistentDesksBarController&) = - delete; - ~PersistentDesksBarController() override; - - static void RegisterProfilePrefs(PrefRegistrySimple* registry); - - // Returns true if it satisfies the prerequisites to show the persistent - // desks bar. `kBentoBar` feature is running as an experiment now. And we will - // only enable it for a specific group of existing desks users, see - // `kUserHasUsedDesksRecently` for more details. But we also want to enable it - // if the user has explicitly enabled `kBentoBar` from chrome://flags or from - // the command line. Even though the user is not in the group of existing - // desks users. - static bool ShouldPersistentDesksBarBeVisible(); - - const views::Widget* persistent_desks_bar_widget() const { - return persistent_desks_bar_widget_.get(); - } - - const PersistentDesksBarView* persistent_desks_bar_view() const { - return persistent_desks_bar_view_; - } - - // SessionObserver: - void OnSessionStateChanged(session_manager::SessionState state) override; - void OnActiveUserPrefServiceChanged(PrefService* prefs) override; - - // OverviewObserver: - void OnOverviewModeWillStart() override; - void OnOverviewModeEndingAnimationComplete(bool canceled) override; - - // DesksController::Observer: - void OnDeskAdded(const Desk* desk) override; - void OnDeskRemoved(const Desk* desk) override; - void OnDeskReordered(int old_index, int new_index) override; - void OnDeskActivationChanged(const Desk* activated, - const Desk* deactivated) override; - void OnDeskNameChanged(const Desk* desk, - const std::u16string& new_name) override; - - // TabletModeObserver: - void OnTabletModeStarted() override; - void OnTabletModeEnded() override; - - // ShellObserver: - void OnShelfAlignmentChanged(aura::Window* root_window, - ShelfAlignment old_alignment) override; - - // AppListControllerObserver: - void OnViewStateChanged(AppListViewState state) override; - - // AccessibilityObserver: - void OnAccessibilityStatusChanged() override; - - // display::DisplayObserver: - void OnDisplayMetricsChanged(const display::Display& display, - uint32_t changed_metrics) override; - - // Returns the value of the pref 'kBentoBarEnabled'. - bool IsEnabled() const; - - // Toggles the value of `is_enabled_` and destroys the bar if it is togggled - // to false. - void ToggleEnabledState(); - - // Initializes and shows the widget that contains the PersistentDesksBarView - // contents. Creates the widget only if ShouldPersistentDesksBarBeCreated() - // returns true and it hasn't been created already. Only refreshes the - // contents and shows the widget if it has been created. - void MaybeInitBarWidget(); - - // Destroys `persistent_desks_bar_widget_` and `persistent_desks_bar_view_`. - void DestroyBarWidget(); - - // Updates the bar's status on window state changes. - void UpdateBarOnWindowStateChanges(aura::Window* window); - - // Updates the bar's status when the given `window` is destroying. - void UpdateBarOnWindowDestroying(aura::Window* window); - - private: - // Returns true if the persistent desks bar should be created and shown. - bool ShouldPersistentDesksBarBeCreated() const; - - // Updates bar's state on the pref `kBentoBarEnabled` changes. - void UpdateBarStateOnPrefChanges(); - - views::UniqueWidgetPtr persistent_desks_bar_widget_; - // The contents view of the above |persistent_desks_bar_widget_| if created. - PersistentDesksBarView* persistent_desks_bar_view_ = nullptr; - - std::unique_ptr<PrefChangeRegistrar> pref_change_registrar_; - PrefService* active_user_pref_service_ = nullptr; - - // Indicates if overview mode will start. This is used to guarantee the work - // area will be updated on the bento bar’s visibility changes before entering - // overview mode. Since the work area will not be updated once we are already - // in overview mode. Note, this will be set to true when overview mode will - // start and set to false until overview mode ends. - bool overview_mode_in_progress_ = false; -}; - -} // namespace ash - -#endif // ASH_WM_DESKS_PERSISTENT_DESKS_BAR_CONTROLLER_H_
diff --git a/ash/wm/desks/persistent_desks_bar/persistent_desks_bar_view.cc b/ash/wm/desks/persistent_desks_bar/persistent_desks_bar_view.cc deleted file mode 100644 index bdf7c89..0000000 --- a/ash/wm/desks/persistent_desks_bar/persistent_desks_bar_view.cc +++ /dev/null
@@ -1,108 +0,0 @@ -// Copyright 2021 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/desks/persistent_desks_bar/persistent_desks_bar_view.h" - -#include "ash/style/ash_color_provider.h" -#include "ash/wm/desks/desk.h" -#include "ash/wm/desks/desks_controller.h" -#include "ash/wm/desks/desks_histogram_enums.h" -#include "ash/wm/desks/persistent_desks_bar/persistent_desks_bar_button.h" -#include "base/containers/cxx20_erase.h" -#include "base/containers/flat_set.h" -#include "base/ranges/algorithm.h" -#include "ui/views/background.h" - -namespace ash { - -namespace { - -constexpr int kDeskButtonWidth = 60; -constexpr int kDeskButtonHeight = 28; -constexpr int kDeskButtonSpacing = 8; -constexpr int kDeskButtonsY = 6; - -constexpr int kOverviewButtonRightPadding = 6; -constexpr int kVerticalDotsButtonAndOverviewButtonSpacing = 8; - -} // namespace - -PersistentDesksBarView::PersistentDesksBarView() - : vertical_dots_button_(AddChildView( - std::make_unique<PersistentDesksBarVerticalDotsButton>())), - overview_button_( - AddChildView(std::make_unique<PersistentDesksBarOverviewButton>())) {} - -PersistentDesksBarView::~PersistentDesksBarView() = default; - -void PersistentDesksBarView::RefreshDeskButtons() { - base::flat_set<PersistentDesksBarDeskButton*> to_be_removed( - desk_buttons_.begin(), desk_buttons_.end()); - auto* desk_controller = DesksController::Get(); - const auto& desks = desk_controller->desks(); - const size_t previous_desk_buttons_size = desk_buttons_.size(); - for (const auto& desk : desks) { - const Desk* desk_ptr = desk.get(); - auto iter = base::ranges::find(to_be_removed, desk_ptr, - &PersistentDesksBarDeskButton::desk); - if (iter != to_be_removed.end()) { - (*iter)->SetShouldPaintBackground(desk->is_active()); - (*iter)->UpdateText(desk->name()); - to_be_removed.erase(iter); - continue; - } - - desk_buttons_.push_back( - AddChildView(std::make_unique<PersistentDesksBarDeskButton>(desk_ptr))); - } - - if (!to_be_removed.empty()) { - DCHECK_EQ(1u, to_be_removed.size()); - auto* to_be_removed_desk_button = *(to_be_removed.begin()); - base::Erase(desk_buttons_, to_be_removed_desk_button); - RemoveChildViewT(to_be_removed_desk_button); - } - if (desks.size() != previous_desk_buttons_size) - Layout(); -} - -void PersistentDesksBarView::Layout() { - const int width = bounds().width(); - const int content_width = - (desk_buttons_.size() + 1) * (kDeskButtonWidth + kDeskButtonSpacing) - - kDeskButtonSpacing; - int x = (width - content_width) / 2; - for (auto* desk_button : desk_buttons_) { - desk_button->SetBoundsRect( - gfx::Rect(gfx::Point(x, kDeskButtonsY), - gfx::Size(kDeskButtonWidth, kDeskButtonHeight))); - x += (kDeskButtonWidth + kDeskButtonSpacing); - } - - const gfx::Size overview_button_size = overview_button_->GetPreferredSize(); - const int overview_button_x = bounds().right() - - overview_button_size.width() - - kOverviewButtonRightPadding; - const int overview_button_y = - (bounds().height() - overview_button_size.height()) / 2; - overview_button_->SetBoundsRect(gfx::Rect( - gfx::Point(overview_button_x, overview_button_y), overview_button_size)); - - // `vertical_dots_button_` has the same size and y-axis position as - // `overview_button_`. - vertical_dots_button_->SetBoundsRect( - gfx::Rect(gfx::Point(overview_button_x - overview_button_size.width() - - kVerticalDotsButtonAndOverviewButtonSpacing, - overview_button_y), - overview_button_size)); -} - -void PersistentDesksBarView::OnThemeChanged() { - views::View::OnThemeChanged(); - SetBackground( - views::CreateSolidBackground(AshColorProvider::Get()->GetBaseLayerColor( - AshColorProvider::BaseLayerType::kOpaque))); -} - -} // namespace ash
diff --git a/ash/wm/desks/persistent_desks_bar/persistent_desks_bar_view.h b/ash/wm/desks/persistent_desks_bar/persistent_desks_bar_view.h deleted file mode 100644 index 80f5c87..0000000 --- a/ash/wm/desks/persistent_desks_bar/persistent_desks_bar_view.h +++ /dev/null
@@ -1,56 +0,0 @@ -// Copyright 2021 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_DESKS_PERSISTENT_DESKS_BAR_VIEW_H_ -#define ASH_WM_DESKS_PERSISTENT_DESKS_BAR_VIEW_H_ - -#include <vector> - -#include "ash/ash_export.h" -#include "ui/views/view.h" - -namespace ash { - -class PersistentDesksBarDeskButton; -class PersistentDesksBarOverviewButton; -class PersistentDesksBarVerticalDotsButton; - -// A bar that resides at the top of the screen in clamshell mode when there are -// more than one desk. It includes the desk buttons that show the corresponding -// desk's name, as well as a toggle button to enter overview mode. -class ASH_EXPORT PersistentDesksBarView : public views::View { - public: - PersistentDesksBarView(); - PersistentDesksBarView(const PersistentDesksBarView&) = delete; - PersistentDesksBarView& operator=(const PersistentDesksBarView&) = delete; - ~PersistentDesksBarView() override; - - // Updates `desk_buttons_` on desk addition, removal, activation changes and - // desk name changes. It should just include desk buttons for all of the - // current desks with current names and keep the background of the desk button - // for current active desk be painted. - void RefreshDeskButtons(); - - private: - friend class DesksTestApi; - - // views::View: - void Layout() override; - void OnThemeChanged() override; - - // A list of buttons with the desks' name. The buttons here should have the - // same number as the current desks, same order as well. - std::vector<PersistentDesksBarDeskButton*> desk_buttons_; - - // A circular button which when clicked will open the context menu of the bar. - PersistentDesksBarVerticalDotsButton* vertical_dots_button_; - - // A button at the right side of the bar which when clicked will hide the bar - // and enter overview mode. - PersistentDesksBarOverviewButton* overview_button_; -}; - -} // namespace ash - -#endif // ASH_WM_DESKS_PERSISTENT_DESKS_BAR_VIEW_H_
diff --git a/ash/wm/desks/templates/saved_desk_constants.h b/ash/wm/desks/templates/saved_desk_constants.h index 36dcd4e..b19ad5a 100644 --- a/ash/wm/desks/templates/saved_desk_constants.h +++ b/ash/wm/desks/templates/saved_desk_constants.h
@@ -21,6 +21,12 @@ // Used in desk grid padding, SavedDeskItemView horizontal padding. constexpr int kSaveDeskPaddingDp = 24; +// Windows launched from admin templates will start with this activation index, +// and then proceed downwards. In other words, all windows launched from admin +// templates will have an activation index that is equal to or lower than this +// value. +constexpr int kAdminTemplateStartingActivationIndex = -1000000; + } // namespace ash #endif // ASH_WM_DESKS_TEMPLATES_SAVED_DESK_CONSTANTS_H_
diff --git a/ash/wm/desks/templates/saved_desk_controller.cc b/ash/wm/desks/templates/saved_desk_controller.cc index 1300cb1..2595676 100644 --- a/ash/wm/desks/templates/saved_desk_controller.cc +++ b/ash/wm/desks/templates/saved_desk_controller.cc
@@ -8,10 +8,13 @@ #include "ash/public/cpp/saved_desk_delegate.h" #include "ash/shell.h" #include "ash/wm/desks/desks_controller.h" +#include "ash/wm/desks/templates/saved_desk_constants.h" #include "base/check.h" +#include "base/containers/adapters.h" #include "base/json/json_string_value_serializer.h" #include "base/time/time.h" #include "base/values.h" +#include "components/app_restore/app_restore_data.h" #include "components/app_restore/restore_data.h" namespace ash { @@ -59,6 +62,27 @@ // Pointer to the global `SavedDeskController` instance. SavedDeskController* g_instance = nullptr; +// The next activation index to assign to an admin template window. +int32_t g_admin_template_next_activation_index = + kAdminTemplateStartingActivationIndex; + +// This function updates the activation indices of all the windows in an admin +// template so that windows launched from it will stack in the order they are +// defined, while also stacking on top of any existing windows. +void UpdateAdminTemplateActivationIndices(DeskTemplate& saved_desk) { + auto& app_id_to_launch_list = + saved_desk.mutable_desk_restore_data()->mutable_app_id_to_launch_list(); + // Go through the windows as defined in the saved desk in reverse order so + // that the window with the lowest id gets the lowest activation index. NB: + // for now, we expect admin templates to only contain a single app. + for (auto& [app_id, launch_list] : app_id_to_launch_list) { + for (auto& [window_id, app_restore_data] : base::Reversed(launch_list)) { + app_restore_data->activation_index = + g_admin_template_next_activation_index--; + } + } +} + } // namespace SavedDeskController::SavedDeskController() { @@ -82,8 +106,8 @@ } bool SavedDeskController::LaunchAdminTemplate(const base::GUID& template_uuid) { - auto placeholder_template = CreatePlaceholderTemplate(); - if (!placeholder_template || template_uuid != placeholder_template->uuid()) { + auto admin_template = GetAdminTemplate(template_uuid); + if (!admin_template) { return false; } @@ -91,12 +115,34 @@ auto* desks_controller = DesksController::Get(); const int desk_index = desks_controller->GetDeskIndex(desks_controller->active_desk()); - placeholder_template->SetDeskIndex(desk_index); + admin_template->SetDeskIndex(desk_index); + + UpdateAdminTemplateActivationIndices(*admin_template); Shell::Get()->saved_desk_delegate()->LaunchAppsFromSavedDesk( - std::move(placeholder_template)); + std::move(admin_template)); return true; } +std::unique_ptr<DeskTemplate> SavedDeskController::GetAdminTemplate( + const base::GUID& template_uuid) const { + if (admin_template_for_testing_ && + admin_template_for_testing_->uuid() == template_uuid) { + return admin_template_for_testing_->Clone(); + } + + auto placeholder_template = CreatePlaceholderTemplate(); + if (placeholder_template && template_uuid == placeholder_template->uuid()) { + return placeholder_template; + } + + return nullptr; +} + +void SavedDeskController::SetAdminTemplateForTesting( + std::unique_ptr<DeskTemplate> admin_template) { + admin_template_for_testing_ = std::move(admin_template); +} + } // namespace ash
diff --git a/ash/wm/desks/templates/saved_desk_controller.h b/ash/wm/desks/templates/saved_desk_controller.h index 70da972..43da70f2 100644 --- a/ash/wm/desks/templates/saved_desk_controller.h +++ b/ash/wm/desks/templates/saved_desk_controller.h
@@ -13,6 +13,8 @@ namespace ash { +class DeskTemplate; + struct AdminTemplateMetadata { // Uniquely identifies the template. base::GUID uuid; @@ -38,6 +40,18 @@ // Launch the template identified by `template_uuid`. Returns false if the // template doesn't exist. virtual bool LaunchAdminTemplate(const base::GUID& template_uuid); + + private: + friend class SavedDeskControllerTestApi; + + std::unique_ptr<DeskTemplate> GetAdminTemplate( + const base::GUID& template_uuid) const; + + // Install an admin template that can be used by `LaunchAdminTemplate`. + void SetAdminTemplateForTesting(std::unique_ptr<DeskTemplate> admin_template); + + // An optional admin template used for testing. + std::unique_ptr<DeskTemplate> admin_template_for_testing_; }; } // namespace ash
diff --git a/ash/wm/desks/templates/saved_desk_test_util.cc b/ash/wm/desks/templates/saved_desk_test_util.cc index b2feefc..203cd8c1 100644 --- a/ash/wm/desks/templates/saved_desk_test_util.cc +++ b/ash/wm/desks/templates/saved_desk_test_util.cc
@@ -8,6 +8,7 @@ #include "ash/style/icon_button.h" #include "ash/wm/desks/desks_bar_view.h" #include "ash/wm/desks/expanded_desks_bar_button.h" +#include "ash/wm/desks/templates/saved_desk_controller.h" #include "ash/wm/desks/templates/saved_desk_dialog_controller.h" #include "ash/wm/desks/templates/saved_desk_icon_container.h" #include "ash/wm/desks/templates/saved_desk_item_view.h" @@ -146,6 +147,17 @@ SavedDeskIconViewTestApi::~SavedDeskIconViewTestApi() = default; +SavedDeskControllerTestApi::SavedDeskControllerTestApi( + SavedDeskController* saved_desk_controller) + : saved_desk_controller_(saved_desk_controller) {} + +SavedDeskControllerTestApi::~SavedDeskControllerTestApi() = default; + +void SavedDeskControllerTestApi::SetAdminTemplate( + std::unique_ptr<DeskTemplate> admin_template) { + saved_desk_controller_->SetAdminTemplateForTesting(std::move(admin_template)); +} + std::vector<SavedDeskItemView*> GetItemViewsFromDeskLibrary( const OverviewGrid* overview_grid) { SavedDeskLibraryView* saved_desk_library_view =
diff --git a/ash/wm/desks/templates/saved_desk_test_util.h b/ash/wm/desks/templates/saved_desk_test_util.h index 0af8fd2..5baf56b 100644 --- a/ash/wm/desks/templates/saved_desk_test_util.h +++ b/ash/wm/desks/templates/saved_desk_test_util.h
@@ -25,6 +25,7 @@ class IconButton; class OverviewGrid; class PillButton; +class SavedDeskController; class SavedDeskPresenter; // Wrapper for `SavedDeskPresenter` that exposes internal state to test @@ -142,6 +143,22 @@ const SavedDeskIconView* saved_desk_icon_view_; }; +// Test API for `SavedDeskController`. +class SavedDeskControllerTestApi { + public: + explicit SavedDeskControllerTestApi( + SavedDeskController* saved_desk_controller); + SavedDeskControllerTestApi(const SavedDeskControllerTestApi&) = delete; + SavedDeskControllerTestApi& operator=(const SavedDeskControllerTestApi&) = + delete; + ~SavedDeskControllerTestApi(); + + void SetAdminTemplate(std::unique_ptr<DeskTemplate> admin_template); + + private: + SavedDeskController* saved_desk_controller_; +}; + // Returns all saved desk item views from the desk library on the given // `overview_grid`. std::vector<SavedDeskItemView*> GetItemViewsFromDeskLibrary(
diff --git a/ash/wm/desks/templates/saved_desk_util.cc b/ash/wm/desks/templates/saved_desk_util.cc index a4409d2..1b25b82e 100644 --- a/ash/wm/desks/templates/saved_desk_util.cc +++ b/ash/wm/desks/templates/saved_desk_util.cc
@@ -9,8 +9,10 @@ #include "ash/public/cpp/session/session_types.h" #include "ash/session/session_controller_impl.h" #include "ash/shell.h" +#include "ash/wm/desks/templates/saved_desk_constants.h" #include "ash/wm/overview/overview_controller.h" #include "ash/wm/overview/overview_session.h" +#include "components/app_restore/window_properties.h" #include "components/prefs/pref_registry_simple.h" #include "components/prefs/pref_service.h" @@ -81,5 +83,12 @@ return presenter; } +bool IsAdminTemplateWindow(aura::Window* window) { + const int32_t* activation_index = + window->GetProperty(app_restore::kActivationIndexKey); + return activation_index && + *activation_index <= kAdminTemplateStartingActivationIndex; +} + } // namespace saved_desk_util } // namespace ash
diff --git a/ash/wm/desks/templates/saved_desk_util.h b/ash/wm/desks/templates/saved_desk_util.h index 101fc3d..7e026d0 100644 --- a/ash/wm/desks/templates/saved_desk_util.h +++ b/ash/wm/desks/templates/saved_desk_util.h
@@ -9,6 +9,10 @@ class PrefRegistrySimple; +namespace aura { +class Window; +} + namespace ash { class SavedDeskDialogController; @@ -30,6 +34,9 @@ // Will return null if overview mode is not active. ASH_EXPORT SavedDeskPresenter* GetSavedDeskPresenter(); +// Returns true if `window` was launched from an admin template. +bool IsAdminTemplateWindow(aura::Window* window); + } // namespace saved_desk_util } // namespace ash
diff --git a/ash/wm/gestures/back_gesture/back_gesture_affordance.cc b/ash/wm/gestures/back_gesture/back_gesture_affordance.cc index b56c1a8..9b91f780 100644 --- a/ash/wm/gestures/back_gesture/back_gesture_affordance.cc +++ b/ash/wm/gestures/back_gesture/back_gesture_affordance.cc
@@ -160,7 +160,7 @@ if (chromeos::features::IsDarkLightModeEnabled()) // Draw highlight border circles. - DrawCircleHighlightBorder(canvas, center_point, kBackgroundRadius); + DrawCircleHighlightBorder(this, canvas, center_point, kBackgroundRadius); // Draw the arrow background circle. cc::PaintFlags bg_flags;
diff --git a/ash/wm/gestures/back_gesture/back_gesture_contextual_nudge.cc b/ash/wm/gestures/back_gesture/back_gesture_contextual_nudge.cc index 4f764cd..0d3d9918 100644 --- a/ash/wm/gestures/back_gesture/back_gesture_contextual_nudge.cc +++ b/ash/wm/gestures/back_gesture/back_gesture_contextual_nudge.cc
@@ -279,7 +279,7 @@ if (chromeos::features::IsDarkLightModeEnabled()) { // Draw highlight border circles for the affordance. - DrawCircleHighlightBorder(canvas, center_point, kCircleRadius); + DrawCircleHighlightBorder(this, canvas, center_point, kCircleRadius); } // Draw the black round rectangle around the text. @@ -295,7 +295,8 @@ if (chromeos::features::IsDarkLightModeEnabled()) { // Draw highlight border for the black round rectangle around the text. - DrawRoundRectHighlightBorder(canvas, label_bounds, kLabelCornerRadius); + DrawRoundRectHighlightBorder(this, canvas, label_bounds, + kLabelCornerRadius); } }
diff --git a/ash/wm/gestures/back_gesture/back_gesture_util.cc b/ash/wm/gestures/back_gesture/back_gesture_util.cc index 982e4b6..cd23e8b 100644 --- a/ash/wm/gestures/back_gesture/back_gesture_util.cc +++ b/ash/wm/gestures/back_gesture/back_gesture_util.cc
@@ -4,10 +4,11 @@ #include "ash/wm/gestures/back_gesture/back_gesture_util.h" -#include "ash/style/ash_color_provider.h" +#include "ui/color/color_provider.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/scoped_canvas.h" #include "ui/views/highlight_border.h" +#include "ui/views/view.h" namespace ash { @@ -18,14 +19,15 @@ constexpr float kInnerHightlightBorderThickness = views::kHighlightBorderThickness / 2.f; -SkColor GetHighlightBorderInnerColor() { - return AshColorProvider::Get()->GetControlsLayerColor( - AshColorProvider::ControlsLayerType::kHighlightColor1); +SkColor GetHighlightBorderInnerColor(views::View* view) { + DCHECK(view); + return view->GetColorProvider()->GetColor( + ui::kColorHighlightBorderHighlight1); } -SkColor GetHighlightBorderOuterColor() { - return AshColorProvider::Get()->GetControlsLayerColor( - AshColorProvider::ControlsLayerType::kBorderColor1); +SkColor GetHighlightBorderOuterColor(views::View* view) { + DCHECK(view); + return view->GetColorProvider()->GetColor(ui::kColorHighlightBorderBorder1); } cc::PaintFlags GetHighlightBorderPaintFlags() { @@ -38,7 +40,8 @@ } // namespace -void DrawCircleHighlightBorder(gfx::Canvas* canvas, +void DrawCircleHighlightBorder(views::View* view, + gfx::Canvas* canvas, const gfx::PointF& circle_center, int radius) { gfx::ScopedCanvas scoped_canvas(canvas); @@ -50,17 +53,18 @@ scaled_circle_center.Scale(dsf); cc::PaintFlags hb_flags = GetHighlightBorderPaintFlags(); - hb_flags.setColor(GetHighlightBorderOuterColor()); + hb_flags.setColor(GetHighlightBorderOuterColor(view)); canvas->DrawCircle(scaled_circle_center, scaled_corner_radius + kOuterHightlightBorderThickness, hb_flags); - hb_flags.setColor(GetHighlightBorderInnerColor()); + hb_flags.setColor(GetHighlightBorderInnerColor(view)); canvas->DrawCircle(scaled_circle_center, scaled_corner_radius + kInnerHightlightBorderThickness, hb_flags); } -void DrawRoundRectHighlightBorder(gfx::Canvas* canvas, +void DrawRoundRectHighlightBorder(views::View* view, + gfx::Canvas* canvas, const gfx::Rect& bounds, int corner_radius) { gfx::ScopedCanvas scoped_canvas(canvas); @@ -73,14 +77,14 @@ cc::PaintFlags hb_flags = GetHighlightBorderPaintFlags(); - hb_flags.setColor(GetHighlightBorderOuterColor()); + hb_flags.setColor(GetHighlightBorderOuterColor(view)); canvas->DrawRoundRect(scaled_outer_bounds, scaled_corner_radius + kOuterHightlightBorderThickness, hb_flags); - hb_flags.setColor(GetHighlightBorderInnerColor()); + hb_flags.setColor(GetHighlightBorderInnerColor(view)); canvas->DrawRoundRect(scaled_inner_bounds, scaled_corner_radius + kInnerHightlightBorderThickness, hb_flags); } -} // namespace ash \ No newline at end of file +} // namespace ash
diff --git a/ash/wm/gestures/back_gesture/back_gesture_util.h b/ash/wm/gestures/back_gesture/back_gesture_util.h index 7e9ac39..d7f0602bf 100644 --- a/ash/wm/gestures/back_gesture/back_gesture_util.h +++ b/ash/wm/gestures/back_gesture/back_gesture_util.h
@@ -13,18 +13,25 @@ class Rect; } // namespace gfx +namespace views { +class View; +} // namespace views + namespace ash { -// Paints the circular shaped highlight border onto `canvas`. -void DrawCircleHighlightBorder(gfx::Canvas* canvas, +// Paints the circular shaped highlight border onto `canvas` for `view`. +void DrawCircleHighlightBorder(views::View* view, + gfx::Canvas* canvas, const gfx::PointF& circle_center, int radius); -// Paints the round rectangular shaped highlight border onto `canvas`. -void DrawRoundRectHighlightBorder(gfx::Canvas* canvas, +// Paints the round rectangular shaped highlight border onto `canvas` for +// `view`. +void DrawRoundRectHighlightBorder(views::View* view, + gfx::Canvas* canvas, const gfx::Rect& bounds, int corner_radius); } // namespace ash -#endif // ASH_WM_GESTURES_BACK_GESTURE_BACK_GESTURE_UTIL_H_ \ No newline at end of file +#endif // ASH_WM_GESTURES_BACK_GESTURE_BACK_GESTURE_UTIL_H_
diff --git a/ash/wm/overview/overview_metrics.h b/ash/wm/overview/overview_metrics.h index 03202ad8..014c1f7e 100644 --- a/ash/wm/overview/overview_metrics.h +++ b/ash/wm/overview/overview_metrics.h
@@ -16,7 +16,7 @@ kExitHomeLauncher, kOverviewButton, kOverviewButtonLongPress, - kBentoBar, + kBentoBar_DEPRECATED, k3FingerVerticalScroll, kDevTools, kTests,
diff --git a/ash/wm/window_restore/window_restore_controller.cc b/ash/wm/window_restore/window_restore_controller.cc index 6bf0dff..91375c9 100644 --- a/ash/wm/window_restore/window_restore_controller.cc +++ b/ash/wm/window_restore/window_restore_controller.cc
@@ -15,6 +15,7 @@ #include "ash/shell.h" #include "ash/wm/container_finder.h" #include "ash/wm/desks/desks_util.h" +#include "ash/wm/desks/templates/saved_desk_util.h" #include "ash/wm/float/float_controller.h" #include "ash/wm/mru_window_tracker.h" #include "ash/wm/tablet_mode/tablet_mode_controller.h" @@ -230,13 +231,26 @@ WindowRestoreController::GetWindowToInsertBefore( aura::Window* window, const std::vector<aura::Window*>& windows) { - int32_t* activation_index = + const int32_t* activation_index = window->GetProperty(app_restore::kActivationIndexKey); DCHECK(activation_index); + // If this is an admin template window, it should be placed on top of existing + // windows (but relative to other desk template windows). + if (saved_desk_util::IsAdminTemplateWindow(window)) { + for (auto it = windows.begin(); it != windows.end(); ++it) { + const int32_t* next_activation_index = + (*it)->GetProperty(app_restore::kActivationIndexKey); + if (next_activation_index && *activation_index > *next_activation_index) { + return it; + } + } + return windows.end(); + } + auto it = windows.begin(); while (it != windows.end()) { - int32_t* next_activation_index = + const int32_t* next_activation_index = (*it)->GetProperty(app_restore::kActivationIndexKey); if (!next_activation_index || *activation_index > *next_activation_index) {
diff --git a/ash/wm/window_state.cc b/ash/wm/window_state.cc index c89760c0..46f7e90 100644 --- a/ash/wm/window_state.cc +++ b/ash/wm/window_state.cc
@@ -23,7 +23,6 @@ #include "ash/strings/grit/ash_strings.h" #include "ash/wm/collision_detection/collision_detection_utils.h" #include "ash/wm/default_state.h" -#include "ash/wm/desks/persistent_desks_bar/persistent_desks_bar_controller.h" #include "ash/wm/float/float_controller.h" #include "ash/wm/pip/pip_positioner.h" #include "ash/wm/splitview/split_view_constants.h" @@ -561,11 +560,6 @@ // the window has a minimum size requirement. if (event->IsBoundsEvent()) UpdateSnapRatio(); - - PersistentDesksBarController* bar_controller = - Shell::Get()->persistent_desks_bar_controller(); - if (bar_controller) - bar_controller->UpdateBarOnWindowStateChanges(window_); } gfx::Rect WindowState::GetCurrentBoundsInScreen() const { @@ -1413,11 +1407,6 @@ void WindowState::OnWindowDestroying(aura::Window* window) { DCHECK_EQ(window_, window); - PersistentDesksBarController* bar_controller = - Shell::Get()->persistent_desks_bar_controller(); - if (bar_controller) - bar_controller->UpdateBarOnWindowDestroying(window_); - // If the window is destroyed during PIP, count that as exiting. if (IsPip()) CollectPipEnterExitMetrics(/*enter=*/false);
diff --git a/ash/wm/work_area_insets.cc b/ash/wm/work_area_insets.cc index 3931e6e..9afbd914 100644 --- a/ash/wm/work_area_insets.cc +++ b/ash/wm/work_area_insets.cc
@@ -20,13 +20,11 @@ namespace { // Returns work area insets calculated for the provided parameters. -gfx::Insets CalculateWorkAreaInsets(const gfx::Insets accessibility_insets, - const gfx::Insets persistent_bar_insets, - const gfx::Insets shelf_insets, - const gfx::Rect keyboard_bounds) { +gfx::Insets CalculateWorkAreaInsets(const gfx::Insets& accessibility_insets, + const gfx::Insets& shelf_insets, + const gfx::Rect& keyboard_bounds) { gfx::Insets work_area_insets; work_area_insets += accessibility_insets; - work_area_insets += persistent_bar_insets; // The virtual keyboard always hides the shelf (in any orientation). // Therefore, if the keyboard is shown, there is no need to reduce the work // area by the size of the shelf. @@ -39,14 +37,12 @@ // Returns work area bounds calculated for the given |window| and given // parameters. -gfx::Rect CalculateWorkAreaBounds(const gfx::Insets accessibility_insets, - const gfx::Insets persistent_bar_insets, - const gfx::Rect shelf_bounds_in_screen, - const gfx::Rect keyboard_bounds_in_screen, +gfx::Rect CalculateWorkAreaBounds(const gfx::Insets& accessibility_insets, + const gfx::Rect& shelf_bounds_in_screen, + const gfx::Rect& keyboard_bounds_in_screen, aura::Window* window) { gfx::Rect work_area_bounds = screen_util::GetDisplayBoundsWithShelf(window); work_area_bounds.Inset(accessibility_insets); - work_area_bounds.Inset(persistent_bar_insets); work_area_bounds.Subtract(shelf_bounds_in_screen); work_area_bounds.Subtract(keyboard_bounds_in_screen); return work_area_bounds; @@ -87,12 +83,6 @@ accessibility_panel_height_ + docked_magnifier_height_, 0, 0, 0); } -gfx::Insets WorkAreaInsets::GetPersistentDeskBarInsets() const { - if (accessibility_panel_height_ + docked_magnifier_height_ == 0) - return gfx::Insets::TLBR(persistent_desk_bar_height_, 0, 0, 0); - return gfx::Insets(); -} - gfx::Rect WorkAreaInsets::ComputeStableWorkArea() const { aura::Window* root_window = root_window_controller_->GetRootWindow(); @@ -101,9 +91,9 @@ root_window_controller_->shelf()->GetIdealBoundsForWorkAreaCalculation()); ::wm::ConvertRectToScreen(root_window, &shelf_bounds_in_screen); - return CalculateWorkAreaBounds( - GetAccessibilityInsets(), GetPersistentDeskBarInsets(), - shelf_bounds_in_screen, keyboard_displaced_bounds_, root_window); + return CalculateWorkAreaBounds(GetAccessibilityInsets(), + shelf_bounds_in_screen, + keyboard_displaced_bounds_, root_window); } bool WorkAreaInsets::IsKeyboardShown() const { @@ -124,21 +114,6 @@ root_window_controller_->GetRootWindow()); } -void WorkAreaInsets::SetPersistentDeskBarHeight(int height) { - if (persistent_desk_bar_height_ == height) - return; - base::AutoReset<bool> in_progress(&persistent_desk_bar_height_in_change_, - true); - persistent_desk_bar_height_ = height; - UpdateWorkArea(); - Shell::Get()->NotifyUserWorkAreaInsetsChanged( - root_window_controller_->GetRootWindow()); -} - -bool WorkAreaInsets::PersistentDeskBarHeightInChange() { - return persistent_desk_bar_height_in_change_; -} - void WorkAreaInsets::SetShelfBoundsAndInsets( const gfx::Rect& shelf_bounds, const gfx::Insets& insets, @@ -178,15 +153,14 @@ // Note: Different keyboard bounds properties are used to calculate insets and // bounds. See ui/keyboard/keyboard_controller_observer.h for details. user_work_area_insets_ = CalculateWorkAreaInsets( - GetAccessibilityInsets(), GetPersistentDeskBarInsets(), shelf_insets_, - keyboard_displaced_bounds_); + GetAccessibilityInsets(), shelf_insets_, keyboard_displaced_bounds_); user_work_area_bounds_ = CalculateWorkAreaBounds( - GetAccessibilityInsets(), GetPersistentDeskBarInsets(), shelf_bounds_, - keyboard_occluded_bounds_, root_window_controller_->GetRootWindow()); + GetAccessibilityInsets(), shelf_bounds_, keyboard_occluded_bounds_, + root_window_controller_->GetRootWindow()); in_session_user_work_area_insets_ = CalculateWorkAreaInsets( - GetAccessibilityInsets(), GetPersistentDeskBarInsets(), - in_session_shelf_insets_, keyboard_displaced_bounds_); + GetAccessibilityInsets(), in_session_shelf_insets_, + keyboard_displaced_bounds_); } } // namespace ash
diff --git a/ash/wm/work_area_insets.h b/ash/wm/work_area_insets.h index 1a408a9f..c6bda74 100644 --- a/ash/wm/work_area_insets.h +++ b/ash/wm/work_area_insets.h
@@ -72,9 +72,6 @@ // Returns accessibility insets in DIPs. gfx::Insets GetAccessibilityInsets() const; - // Returns the persistent desk bar insets in DIPs. - gfx::Insets GetPersistentDeskBarInsets() const; - // Returns bounds of the stable work area (work area when the shelf is // visible) in screen coordinates DIPs. gfx::Rect ComputeStableWorkArea() const; @@ -92,16 +89,6 @@ // Shell observers will be notified that accessibility insets changed. void SetAccessibilityPanelHeight(int height); - // Sets height of the persistent desk bar in DIPs for this root - // window. Shell observers will be notified that persistent desk bar - // insets changed. - void SetPersistentDeskBarHeight(int height); - - // Indicates if the persistent desk bar height is in change. This is useful to - // prevent circular call from the App List as it also observes the work area - // value. - bool PersistentDeskBarHeightInChange(); - // Sets bounds (in window coordinates) and insets of the shelf for this root // window. |bounds| and |insets| are passed separately, because insets depend // on shelf visibility and can be different than calculated from bounds. @@ -157,13 +144,6 @@ // Cached height of the accessibility panel in DIPs at the top of the // screen. It needs to be removed from the available work area. int accessibility_panel_height_ = 0; - - // Cached height of the persistent desk bar in DIPs at the top of the - // screen. It needs to be removed from the available work area. - int persistent_desk_bar_height_ = 0; - - // Indicates if the persistent desk bar height is in change. - bool persistent_desk_bar_height_in_change_ = false; }; } // namespace ash
diff --git a/base/BUILD.gn b/base/BUILD.gn index c41f25e..520cb8b 100644 --- a/base/BUILD.gn +++ b/base/BUILD.gn
@@ -1209,8 +1209,6 @@ "android/important_file_writer_android.cc", "android/int_string_callback.cc", "android/int_string_callback.h", - "android/jank_metric_uma_recorder.cc", - "android/jank_metric_uma_recorder.h", "android/java_handler_thread.cc", "android/java_handler_thread.h", "android/java_heap_dump_generator.cc", @@ -3660,7 +3658,6 @@ "android/application_status_listener_unittest.cc", "android/child_process_unittest.cc", "android/content_uri_utils_unittest.cc", - "android/jank_metric_uma_recorder_unittest.cc", "android/java_handler_thread_unittest.cc", "android/jni_android_unittest.cc", "android/jni_array_unittest.cc", @@ -4115,7 +4112,6 @@ "android/java/src/org/chromium/base/TimezoneUtils.java", "android/java/src/org/chromium/base/TraceEvent.java", "android/java/src/org/chromium/base/UnguessableToken.java", - "android/java/src/org/chromium/base/jank_tracker/JankMetricUMARecorder.java", "android/java/src/org/chromium/base/library_loader/LibraryLoader.java", "android/java/src/org/chromium/base/library_loader/LibraryPrefetcher.java", "android/java/src/org/chromium/base/memory/JavaHeapDumpGenerator.java", @@ -4299,19 +4295,6 @@ "android/java/src/org/chromium/base/compat/ApiHelperForQ.java", "android/java/src/org/chromium/base/compat/ApiHelperForR.java", "android/java/src/org/chromium/base/compat/ApiHelperForS.java", - "android/java/src/org/chromium/base/jank_tracker/DummyJankTracker.java", - "android/java/src/org/chromium/base/jank_tracker/FrameMetrics.java", - "android/java/src/org/chromium/base/jank_tracker/FrameMetricsListener.java", - "android/java/src/org/chromium/base/jank_tracker/FrameMetricsStore.java", - "android/java/src/org/chromium/base/jank_tracker/JankActivityTracker.java", - "android/java/src/org/chromium/base/jank_tracker/JankMetricCalculator.java", - "android/java/src/org/chromium/base/jank_tracker/JankMetricUMARecorder.java", - "android/java/src/org/chromium/base/jank_tracker/JankMetrics.java", - "android/java/src/org/chromium/base/jank_tracker/JankReportingRunnable.java", - "android/java/src/org/chromium/base/jank_tracker/JankReportingScheduler.java", - "android/java/src/org/chromium/base/jank_tracker/JankScenario.java", - "android/java/src/org/chromium/base/jank_tracker/JankTracker.java", - "android/java/src/org/chromium/base/jank_tracker/JankTrackerImpl.java", "android/java/src/org/chromium/base/library_loader/LibraryLoader.java", "android/java/src/org/chromium/base/library_loader/LibraryPrefetcher.java", "android/java/src/org/chromium/base/library_loader/Linker.java", @@ -4629,13 +4612,6 @@ "android/junit/src/org/chromium/base/TraceEventTest.java", "android/junit/src/org/chromium/base/UnownedUserDataHostTest.java", "android/junit/src/org/chromium/base/UnownedUserDataKeyTest.java", - "android/junit/src/org/chromium/base/jank_tracker/FrameMetricsListenerTest.java", - "android/junit/src/org/chromium/base/jank_tracker/FrameMetricsStoreTest.java", - "android/junit/src/org/chromium/base/jank_tracker/JankActivityTrackerTest.java", - "android/junit/src/org/chromium/base/jank_tracker/JankMetricCalculatorTest.java", - "android/junit/src/org/chromium/base/jank_tracker/JankMetricUMARecorderTest.java", - "android/junit/src/org/chromium/base/jank_tracker/JankReportingRunnableTest.java", - "android/junit/src/org/chromium/base/jank_tracker/JankReportingSchedulerTest.java", "android/junit/src/org/chromium/base/library_loader/LinkerTest.java", "android/junit/src/org/chromium/base/memory/MemoryPressureMonitorTest.java", "android/junit/src/org/chromium/base/memory/MemoryPurgeManagerTest.java",
diff --git a/base/android/jank_metric_uma_recorder.cc b/base/android/jank_metric_uma_recorder.cc deleted file mode 100644 index 826bb9b1..0000000 --- a/base/android/jank_metric_uma_recorder.cc +++ /dev/null
@@ -1,99 +0,0 @@ -// Copyright 2021 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/android/jank_metric_uma_recorder.h" - -#include <cstdint> - -#include "base/android/jni_android.h" -#include "base/android/jni_array.h" -#include "base/android/jni_string.h" -#include "base/base_jni_headers/JankMetricUMARecorder_jni.h" -#include "base/metrics/histogram_functions.h" -#include "base/strings/strcat.h" -#include "base/time/time.h" -#include "base/trace_event/base_tracing.h" -#include "base/tracing_buildflags.h" - -namespace base { -namespace android { - -namespace { - -void AddFrameToTrace(int64_t timestamp_ns, int64_t durations_ns) { -#if BUILDFLAG(ENABLE_BASE_TRACING) - if (timestamp_ns < 0) - return; - auto t = perfetto::Track(static_cast<uint64_t>(timestamp_ns)); - TRACE_EVENT_BEGIN( - "ui", "AndroidFrameVsync", t, [&](perfetto::EventContext ctx) { - ctx.event()->set_timestamp_absolute_us(timestamp_ns / 1000); - }); - TRACE_EVENT_END("ui", t, [&](perfetto::EventContext ctx) { - ctx.event()->set_timestamp_absolute_us((timestamp_ns + durations_ns) / - 1000); - }); -#endif // BUILDFLAG(ENABLE_BASE_TRACING) -} - -} // namespace - -// This function is called from Java with JNI, it's declared in -// base/base_jni_headers/JankMetricUMARecorder_jni.h which is an autogenerated -// header. The actual implementation is in RecordJankMetrics for simpler -// testing. -void JNI_JankMetricUMARecorder_RecordJankMetrics( - JNIEnv* env, - const base::android::JavaParamRef<jstring>& java_scenario_name, - const base::android::JavaParamRef<jlongArray>& java_timestamps_ns, - const base::android::JavaParamRef<jlongArray>& java_durations_ns, - const base::android::JavaParamRef<jlongArray>& java_jank_bursts_ns, - jint java_missed_frames) { - RecordJankMetrics(env, java_scenario_name, java_timestamps_ns, - java_durations_ns, java_jank_bursts_ns, java_missed_frames); -} - -void RecordJankMetrics( - JNIEnv* env, - const base::android::JavaParamRef<jstring>& java_scenario_name, - const base::android::JavaParamRef<jlongArray>& java_timestamps_ns, - const base::android::JavaParamRef<jlongArray>& java_durations_ns, - const base::android::JavaParamRef<jlongArray>& java_jank_bursts_ns, - jint java_missed_frames) { - std::string scenario_name = ConvertJavaStringToUTF8(env, java_scenario_name); - std::vector<int64_t> timestamps_ns; - std::vector<int64_t> durations_ns; - std::vector<int64_t> jank_bursts_ns; - - JavaLongArrayToInt64Vector(env, java_timestamps_ns, ×tamps_ns); - JavaLongArrayToInt64Vector(env, java_durations_ns, &durations_ns); - JavaLongArrayToInt64Vector(env, java_jank_bursts_ns, &jank_bursts_ns); - - std::string frame_duration_histogram_name = - base::StrCat({"Android.Jank.FrameDuration.", scenario_name}); - std::string jank_burst_histogram_name = - base::StrCat({"Android.Jank.JankBursts.", scenario_name}); - std::string missed_frames_histogram_name = - base::StrCat({"Android.Jank.MissedFrames.", scenario_name}); - - for (size_t i = 0; i < timestamps_ns.size(); ++i) { - AddFrameToTrace(timestamps_ns[i], durations_ns[i]); - } - - for (const int64_t frame_duration_ns : durations_ns) { - base::UmaHistogramTimes(frame_duration_histogram_name, - base::Nanoseconds(frame_duration_ns)); - } - - for (const int64_t jank_burst_duration_ns : jank_bursts_ns) { - base::UmaHistogramTimes(jank_burst_histogram_name, - base::Nanoseconds(jank_burst_duration_ns)); - } - - base::UmaHistogramCounts1000(missed_frames_histogram_name, - java_missed_frames); -} - -} // namespace android -} // namespace base \ No newline at end of file
diff --git a/base/android/jank_metric_uma_recorder.h b/base/android/jank_metric_uma_recorder.h deleted file mode 100644 index 743e1a1f..0000000 --- a/base/android/jank_metric_uma_recorder.h +++ /dev/null
@@ -1,24 +0,0 @@ -// Copyright 2021 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_ANDROID_JANK_METRIC_UMA_RECORDER_H_ -#define BASE_ANDROID_JANK_METRIC_UMA_RECORDER_H_ - -#include "base/android/jni_android.h" -#include "base/base_export.h" - -namespace base { -namespace android { - -BASE_EXPORT void RecordJankMetrics( - JNIEnv* env, - const base::android::JavaParamRef<jstring>& java_scenario_name, - const base::android::JavaParamRef<jlongArray>& java_timestamps_ns, - const base::android::JavaParamRef<jlongArray>& java_durations_ns, - const base::android::JavaParamRef<jlongArray>& java_jank_bursts_ns, - jint java_missed_frames); - -} // namespace android -} // namespace base -#endif // BASE_ANDROID_JANK_METRIC_UMA_RECORDER_H_
diff --git a/base/android/jank_metric_uma_recorder_unittest.cc b/base/android/jank_metric_uma_recorder_unittest.cc deleted file mode 100644 index 3df4cf7f..0000000 --- a/base/android/jank_metric_uma_recorder_unittest.cc +++ /dev/null
@@ -1,106 +0,0 @@ -// Copyright 2021 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/android/jank_metric_uma_recorder.h" - -#include <jni.h> - -#include <cstddef> -#include <cstdint> - -#include "base/android/jni_android.h" -#include "base/android/jni_array.h" -#include "base/android/jni_string.h" -#include "base/metrics/histogram.h" -#include "base/test/metrics/histogram_tester.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -using ::testing::ElementsAre; - -namespace base { -namespace android { -namespace { - -jlongArray GenerateJavaLongArray(JNIEnv* env, - const int64_t long_array[], - const size_t array_length) { - ScopedJavaLocalRef<jlongArray> java_long_array = - ToJavaLongArray(env, long_array, array_length); - - return java_long_array.Release(); -} - -const int64_t kTimestampsNs[] = { - 100'000'000, 116'000'000, 132'000'000, 148'000'000, - 164'000'000, 180'000'000, 196'000'000, 212'000'000, -}; - -// Durations are received in nanoseconds, but are recorded to UMA in -// milliseconds. -const int64_t kDurations[] = { - 1'000'000, // 1ms - 2'000'000, // 2ms - 30'000'000, // 30ms - 10'000'000, // 10ms - 60'000'000, // 60ms - 1'000'000, // 1ms - 1'000'000, // 1ms - 20'000'000, // 20ms -}; -const size_t kDurationsLen = std::size(kDurations); - -static_assert(std::size(kDurations) == std::size(kTimestampsNs), - "Length of timestamps and durations should be equal."); - -// Jank bursts are calculated based on durations. -const int64_t kJankBursts[] = { - 100'000'000, // 100ms - 20'000'000, // 20ms -}; -const size_t kJankBurstsLen = std::size(kJankBursts); - -} // namespace - -TEST(JankMetricUMARecorder, TestUMARecording) { - HistogramTester histogram_tester; - - JNIEnv* env = AttachCurrentThread(); - - jstring java_scenario_name = - ConvertUTF8ToJavaString(env, "PeriodicReporting").Release(); - jlongArray java_timestamps = - GenerateJavaLongArray(env, kTimestampsNs, kDurationsLen); - jlongArray java_durations = - GenerateJavaLongArray(env, kDurations, kDurationsLen); - jlongArray java_jank_bursts = - GenerateJavaLongArray(env, kJankBursts, kJankBurstsLen); - - RecordJankMetrics( - env, - /* java_scenario_name= */ - base::android::JavaParamRef<jstring>(env, java_scenario_name), - /* java_timestamps_ns= */ - base::android::JavaParamRef<jlongArray>(env, java_timestamps), - /* java_durations_ns= */ - base::android::JavaParamRef<jlongArray>(env, java_durations), - /* java_jank_bursts_ns=*/ - base::android::JavaParamRef<jlongArray>(env, java_jank_bursts), - /* java_missed_frames = */ 2); - - EXPECT_THAT(histogram_tester.GetAllSamples( - "Android.Jank.FrameDuration.PeriodicReporting"), - ElementsAre(Bucket(1, 3), Bucket(2, 1), Bucket(10, 1), - Bucket(20, 1), Bucket(29, 1), Bucket(57, 1))); - - EXPECT_THAT(histogram_tester.GetAllSamples( - "Android.Jank.JankBursts.PeriodicReporting"), - ElementsAre(Bucket(20, 1), Bucket(96, 1))); - - histogram_tester.ExpectUniqueSample( - "Android.Jank.MissedFrames.PeriodicReporting", 2, 1); -} - -} // namespace android -} // namespace base \ No newline at end of file
diff --git a/base/android/java/src/org/chromium/base/jank_tracker/DummyJankTracker.java b/base/android/java/src/org/chromium/base/jank_tracker/DummyJankTracker.java deleted file mode 100644 index 2b0b6c6..0000000 --- a/base/android/java/src/org/chromium/base/jank_tracker/DummyJankTracker.java +++ /dev/null
@@ -1,16 +0,0 @@ -// Copyright 2021 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.base.jank_tracker; - -/** - * Dummy implementation of JankTracker. - */ -public class DummyJankTracker implements JankTracker { - @Override - public void startTrackingScenario(int scenario) {} - - @Override - public void finishTrackingScenario(int scenario) {} -}
diff --git a/base/android/java/src/org/chromium/base/jank_tracker/FrameMetrics.java b/base/android/java/src/org/chromium/base/jank_tracker/FrameMetrics.java deleted file mode 100644 index 977beed0..0000000 --- a/base/android/java/src/org/chromium/base/jank_tracker/FrameMetrics.java +++ /dev/null
@@ -1,26 +0,0 @@ -// Copyright 2021 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.base.jank_tracker; - -/** - * Container for individual frame metrics as reported by Android's FrameMetrics API. - */ -class FrameMetrics { - public final Long[] timestampsNs; - public final Long[] durationsNs; - public final Integer[] skippedFrames; - - public FrameMetrics(Long[] timestampsNs, Long[] durationsNs, Integer[] skippedFrames) { - this.timestampsNs = timestampsNs; - this.durationsNs = durationsNs; - this.skippedFrames = skippedFrames; - } - - public FrameMetrics() { - this.timestampsNs = new Long[0]; - this.durationsNs = new Long[0]; - this.skippedFrames = new Integer[0]; - } -}
diff --git a/base/android/java/src/org/chromium/base/jank_tracker/FrameMetricsListener.java b/base/android/java/src/org/chromium/base/jank_tracker/FrameMetricsListener.java deleted file mode 100644 index e0273b9..0000000 --- a/base/android/java/src/org/chromium/base/jank_tracker/FrameMetricsListener.java +++ /dev/null
@@ -1,58 +0,0 @@ -// Copyright 2021 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.base.jank_tracker; - -import android.os.Build.VERSION_CODES; -import android.view.FrameMetrics; -import android.view.Window; -import android.view.Window.OnFrameMetricsAvailableListener; - -import androidx.annotation.RequiresApi; - -import java.util.concurrent.atomic.AtomicBoolean; - -/** - * This class receives OnFrameMetricsAvailableListener.onFrameMetricsAvailable() callbacks and - * records frame durations in a FrameMetricsStore instance. Recording can be toggled from any - * thread, but the actual recording occurs in the thread specified when this is attached to a window - * with addOnFrameMetricsAvailableListener(). This class only adds data to the provided - * FrameMetricsStore instance, its owner must clear it to avoid OOMs. - */ -@RequiresApi(api = VERSION_CODES.N) -class FrameMetricsListener implements OnFrameMetricsAvailableListener { - private final FrameMetricsStore mFrameMetricsStore; - private final AtomicBoolean mIsRecording; - - FrameMetricsListener(FrameMetricsStore frameMetricsStore) { - mFrameMetricsStore = frameMetricsStore; - mIsRecording = new AtomicBoolean(false); - } - - /** - * Toggles recording into JankMetricsStore, can be invoked from any thread. - * @param isRecording - */ - public void setIsListenerRecording(boolean isRecording) { - mIsRecording.set(isRecording); - } - - @RequiresApi(api = VERSION_CODES.N) - @Override - public void onFrameMetricsAvailable( - Window window, FrameMetrics frameMetrics, int dropCountSinceLastInvocation) { - if (!mIsRecording.get()) { - return; - } - - long frameTotalDurationNs = frameMetrics.getMetric(FrameMetrics.TOTAL_DURATION); - - // The total frame duration is considered from the intended VSYNC time till the actual - // presentation time. - long timestampNs = frameMetrics.getMetric(FrameMetrics.INTENDED_VSYNC_TIMESTAMP); - - mFrameMetricsStore.addFrameMeasurement( - timestampNs, frameTotalDurationNs, dropCountSinceLastInvocation); - } -} \ No newline at end of file
diff --git a/base/android/java/src/org/chromium/base/jank_tracker/FrameMetricsStore.java b/base/android/java/src/org/chromium/base/jank_tracker/FrameMetricsStore.java deleted file mode 100644 index 73d3137..0000000 --- a/base/android/java/src/org/chromium/base/jank_tracker/FrameMetricsStore.java +++ /dev/null
@@ -1,192 +0,0 @@ -// Copyright 2021 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.base.jank_tracker; - -import androidx.annotation.VisibleForTesting; - -import org.chromium.build.BuildConfig; - -import java.util.ArrayList; -import java.util.HashMap; - -import javax.annotation.concurrent.GuardedBy; - -/** - * This class stores timestamps and frame durations related to different jank scenarios (e.g. - * Opening omnibox, Opening tab switcher). Scenarios are tracked by calling {@Link - * #startTrackingScenario} and {@Link #stopTrackingScenario}. {@Link #stopTrackingScenario} returns - * a FrameMetrics object with the timestamp and duration of all frames drawn between the start and - * end of the specified scenario. - * - * Multiple scenarios can be tracked simultaneously without duplicating data, and frame data is - * cleared as needed when scenarios end. - */ -class FrameMetricsStore { - // Guards access to the fields below. - private final Object mLock = new Object(); - - // Array of timestamps stored in nanoseconds, they represent the moment when each frame - // finished drawing, must always be the same size as mTotalDurationsNs. - @GuardedBy("mLock") - private final ArrayList<Long> mTimestampsNs = new ArrayList<>(); - - // Array of total durations stored in nanoseconds, they represent how long each frame took to - // draw, must always be the same size as mTimestampsNs. - @GuardedBy("mLock") - private final ArrayList<Long> mTotalDurationsNs = new ArrayList<>(); - - // Number of frames that FrameMetrics was unable to report on, due to excessive activity on its - // handler thread. - @GuardedBy("mLock") - private final ArrayList<Integer> mSkippedFrames = new ArrayList<>(); - - // Map of jank scenarios being currently tracked and the timestamp of the frame before tracking - // began. Each key corresponds to a JankScenario and each value corresponds to a timestamp - // present in mTimestampsNs, or 0 in case the scenario tracking started before any frames were - // recorded. If empty then no scenarios are being tracked, so calls to addFrameMeasurement won't - // store anything. - @GuardedBy("mLock") - private final HashMap<Integer, Long> mScenarioPreviousFrameTimestampNs = new HashMap<>(); - - /** - * Records a timestamp and total draw duration for a single frame. - */ - void addFrameMeasurement(long timestampNs, long totalDurationNs, int skippedFrames) { - synchronized (mLock) { - if (mScenarioPreviousFrameTimestampNs.isEmpty()) { - return; - } - - mTimestampsNs.add(timestampNs); - mTotalDurationsNs.add(totalDurationNs); - mSkippedFrames.add(skippedFrames); - } - } - - void startTrackingScenario(@JankScenario int scenario) { - synchronized (mLock) { - // Ignore multiple calls to startTrackingScenario without corresponding - // stopTrackingScenario calls. - if (mScenarioPreviousFrameTimestampNs.containsKey(scenario)) { - return; - } - - // Scenarios are tracked based on the latest stored timestamp to allow fast lookups - // (find index of [timestamp] vs find first index that's >= [timestamp]). In case there - // are no stored timestamps then we hardcode the scenario's starting timestamp to 0L, - // this is handled as a special case in stopTrackingScenario by returning all stored - // frames. - Long startingTimestamp = 0L; - if (!mTimestampsNs.isEmpty()) { - startingTimestamp = mTimestampsNs.get(mTimestampsNs.size() - 1); - } - - mScenarioPreviousFrameTimestampNs.put(scenario, startingTimestamp); - } - } - - FrameMetrics stopTrackingScenario(@JankScenario int scenario) { - synchronized (mLock) { - // Get the timestamp of the latest frame before startTrackingScenario was called. This - // can be null if tracking never started for scenario, or 0L if tracking started when no - // frames were stored. - Long previousFrameTimestamp = mScenarioPreviousFrameTimestampNs.remove(scenario); - - // If stopTrackingScenario is called without a corresponding startTrackingScenario then - // return an empty FrameMetrics object. - if (previousFrameTimestamp == null) { - return new FrameMetrics(); - } - - int startingIndex; - // Starting timestamp may be 0 if a scenario starts without any frames stored, in this - // case return all frames. - if (previousFrameTimestamp == 0) { - startingIndex = 0; - } else { - startingIndex = mTimestampsNs.indexOf(previousFrameTimestamp); - // The scenario starts with the frame after the tracking timestamp. - startingIndex++; - - // If startingIndex is out of bounds then we haven't recorded any frames since - // tracking started, return an empty FrameMetrics object. - if (startingIndex >= mTimestampsNs.size()) { - return new FrameMetrics(); - } - } - - // Ending index is exclusive, so this is not out of bounds. - int endingIndex = mTimestampsNs.size(); - int scenarioFrameCount = endingIndex - startingIndex; - - Long[] timestamps = mTimestampsNs.subList(startingIndex, endingIndex) - .toArray(new Long[scenarioFrameCount]); - Long[] durations = mTotalDurationsNs.subList(startingIndex, endingIndex) - .toArray(new Long[scenarioFrameCount]); - Integer[] skippedFrames = mSkippedFrames.subList(startingIndex, endingIndex) - .toArray(new Integer[scenarioFrameCount]); - - FrameMetrics frameMetrics = new FrameMetrics(timestamps, durations, skippedFrames); - removeUnusedFrames(); - - return frameMetrics; - } - } - - @VisibleForTesting - FrameMetrics getAllStoredMetricsForTesting() { - synchronized (mLock) { - Long[] timestamps = mTimestampsNs.toArray(new Long[mTimestampsNs.size()]); - Long[] durations = mTotalDurationsNs.toArray(new Long[mTotalDurationsNs.size()]); - Integer[] skippedFrames = mSkippedFrames.toArray(new Integer[mSkippedFrames.size()]); - - FrameMetrics frameMetrics = new FrameMetrics(timestamps, durations, skippedFrames); - - return frameMetrics; - } - } - - @GuardedBy("mLock") - private void removeUnusedFrames() { - if (mScenarioPreviousFrameTimestampNs.isEmpty()) { - mTimestampsNs.clear(); - mTotalDurationsNs.clear(); - mSkippedFrames.clear(); - return; - } - - long firstUsedTimestamp = findFirstUsedTimestamp(); - // If the earliest timestamp tracked is 0 then that scenario contains every frame - // stored, so we shouldn't delete anything. - if (firstUsedTimestamp == 0L) { - return; - } - - int firstUsedIndex = mTimestampsNs.indexOf(firstUsedTimestamp); - if (firstUsedIndex == -1) { - if (BuildConfig.ENABLE_ASSERTS) { - throw new IllegalStateException("Timestamp for tracked scenario not found"); - } - // This shouldn't happen. - return; - } - - mTimestampsNs.subList(0, firstUsedIndex).clear(); - mTotalDurationsNs.subList(0, firstUsedIndex).clear(); - mSkippedFrames.subList(0, firstUsedIndex).clear(); - } - - @GuardedBy("mLock") - private long findFirstUsedTimestamp() { - long firstTimestamp = Long.MAX_VALUE; - for (long timestamp : mScenarioPreviousFrameTimestampNs.values()) { - if (timestamp < firstTimestamp) { - firstTimestamp = timestamp; - } - } - - return firstTimestamp; - } -} \ No newline at end of file
diff --git a/base/android/java/src/org/chromium/base/jank_tracker/JankActivityTracker.java b/base/android/java/src/org/chromium/base/jank_tracker/JankActivityTracker.java deleted file mode 100644 index c92408d..0000000 --- a/base/android/java/src/org/chromium/base/jank_tracker/JankActivityTracker.java +++ /dev/null
@@ -1,112 +0,0 @@ -// Copyright 2021 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.base.jank_tracker; - -import android.app.Activity; -import android.os.Build.VERSION_CODES; - -import androidx.annotation.RequiresApi; - -import org.chromium.base.ActivityState; -import org.chromium.base.ApplicationStatus; -import org.chromium.base.ApplicationStatus.ActivityStateListener; -import org.chromium.base.ThreadUtils.ThreadChecker; -import org.chromium.base.lifetime.DestroyChecker; - -import java.lang.ref.WeakReference; - -/** - * This class takes an Activity and attaches a FrameMetricsListener to it, in addition it controls - * periodic jank metric reporting and frame metric recording based on the Activity's lifecycle - * events. - */ -@RequiresApi(api = VERSION_CODES.N) -class JankActivityTracker implements ActivityStateListener { - private final FrameMetricsListener mFrameMetricsListener; - private final JankReportingScheduler mReportingScheduler; - private final ThreadChecker mThreadChecker = new ThreadChecker(); - private final DestroyChecker mDestroyChecker = new DestroyChecker(); - - private WeakReference<Activity> mActivityReference; - - JankActivityTracker(Activity context, FrameMetricsListener listener, - JankReportingScheduler reportingScheduler) { - mActivityReference = new WeakReference<>(context); - mFrameMetricsListener = listener; - mReportingScheduler = reportingScheduler; - } - - void initialize() { - assertValidState(); - Activity activity = mActivityReference.get(); - if (activity != null) { - ApplicationStatus.registerStateListenerForActivity(this, activity); - @ActivityState - int activityState = ApplicationStatus.getStateForActivity(activity); - onActivityStateChange(activity, activityState); - activity.getWindow().addOnFrameMetricsAvailableListener( - mFrameMetricsListener, mReportingScheduler.getOrCreateHandler()); - } - } - - void destroy() { - mThreadChecker.assertOnValidThread(); - ApplicationStatus.unregisterActivityStateListener(this); - stopMetricRecording(); - stopReportingTimer(); - Activity activity = mActivityReference.get(); - if (activity != null) { - activity.getWindow().removeOnFrameMetricsAvailableListener(mFrameMetricsListener); - } - mDestroyChecker.destroy(); - } - - private void startReportingTimer() { - assertValidState(); - mReportingScheduler.startReportingPeriodicMetrics(); - } - - private void stopReportingTimer() { - assertValidState(); - mReportingScheduler.stopReportingPeriodicMetrics(); - } - - private void startMetricRecording() { - assertValidState(); - mFrameMetricsListener.setIsListenerRecording(true); - } - - private void stopMetricRecording() { - assertValidState(); - mFrameMetricsListener.setIsListenerRecording(false); - } - - private void assertValidState() { - mThreadChecker.assertOnValidThread(); - mDestroyChecker.checkNotDestroyed(); - } - - @Override - public void onActivityStateChange(Activity activity, @ActivityState int newState) { - assertValidState(); - switch (newState) { - case ActivityState.STARTED: // Intentional fallthrough. - case ActivityState.RESUMED: - startReportingTimer(); - startMetricRecording(); - break; - case ActivityState.PAUSED: - // This method can be called at any moment safely, we want to report metrics even - // when the activity is paused. - startReportingTimer(); - stopMetricRecording(); - break; - case ActivityState.STOPPED: - stopMetricRecording(); - stopReportingTimer(); - break; - } - } -}
diff --git a/base/android/java/src/org/chromium/base/jank_tracker/JankMetricCalculator.java b/base/android/java/src/org/chromium/base/jank_tracker/JankMetricCalculator.java deleted file mode 100644 index c6fa69f..0000000 --- a/base/android/java/src/org/chromium/base/jank_tracker/JankMetricCalculator.java +++ /dev/null
@@ -1,179 +0,0 @@ -// Copyright 2021 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.base.jank_tracker; - -import java.util.ArrayList; - -/** - * This class calculates a jank burst metric. - * - * Jank bursts are periods with janky frames in a quick succession. A non-janky frame may be - * included in this measurement if it's preceded and succeeded by janky frames, as long as the three - * frames were drawn in a quick succession (called 'consecutive' in this file). Jank bursts are - * delimited by either a succession (2 or more) of non-janky frames or a period of inactivity - * (defined by JANK_BURST_CONSECUTIVE_FRAME_THRESHOLD_MS). - * - * Example: X = Janky frame. O = Non-janky frame. - * - * O - * O - * X <- Jank burst 1 starts here. - * X - * O <- This frame is not janky, but as the adjacent frames are janky we include it. - * X <- Jank burst 1 ends here. - * O - * O - * X <- Jank burst 2 starts here. - * X <- Jank burst 2 ends here. - * 500 ms later... - * X <- Jank burst 3 starts here. Because some time passed between the last frame and this one - * we assume their jankyness was related to different events/animations. - * X <- Jank burst 3 ends here. - * O - * O - * - * In this example the jank burst metric would report 3 values, which are the sum of the frame - * duration of all frames inside a jank burst, including the first and last frames. - */ -class JankMetricCalculator { - private static final long NANOSECONDS_PER_MILLISECOND = 1_000_000; - - // Threshold in milliseconds to distinguish janky and non-janky frames. Any frames whose - // duration is greater than this number are considered janky. Ideally this number would depend - // on the device's refresh rate, but for now we assume the device runs at 60hz. - private static final long JANK_THRESHOLD_NS = 16 * NANOSECONDS_PER_MILLISECOND; - - // Maximum duration between frames to consider them consecutive. This is used to split jank - // bursts when 2 janky frames are separated by an idle period. - private static final long JANK_BURST_CONSECUTIVE_FRAME_THRESHOLD_NS = - 50 * NANOSECONDS_PER_MILLISECOND; - - /** - * Returns an array of all recorded jank bursts measured in nanoseconds (see class doc for - * details). - */ - private static long[] calculateJankBurstDurationsNs(long[] timestampsNs, long[] durationsNs) { - assert timestampsNs.length == durationsNs.length; - ArrayList<Long> jankBurstDurationsNs = new ArrayList<>(); - long currentJankBurstDurationNs = 0; - for (int i = 0; i < timestampsNs.length; i++) { - // If there's an existing jank burst, but the current frame is not consecutive - // compared to the last then we end the burst. - if (i > 0 && currentJankBurstDurationNs > 0 - && !areFramesConsecutive(i - 1, i, timestampsNs, durationsNs)) { - jankBurstDurationsNs.add(currentJankBurstDurationNs); - currentJankBurstDurationNs = 0; - } - - long currentFrameDurationNs = durationsNs[i]; - - // If the frame is janky we start or continue the jank burst. - if (isFrameJanky(i, durationsNs)) { - currentJankBurstDurationNs += currentFrameDurationNs; - } else { - if (currentJankBurstDurationNs > 0) { - // If the frame is not janky, but there's a jank burst and the adjacent - // frames are consecutive and janky then we count this frame's duration in - // the burst. - if (areFramesConsecutive(i - 1, i, timestampsNs, durationsNs) - && areFramesConsecutive(i, i + 1, timestampsNs, durationsNs) - && isFrameJanky(i + 1, durationsNs)) { - currentJankBurstDurationNs += currentFrameDurationNs; - } else { - // If the frame is not janky and the next frame is not janky or consecutive - // then we end the burst. - jankBurstDurationsNs.add(currentJankBurstDurationNs); - currentJankBurstDurationNs = 0; - } - } - } - } - - // TODO(salg): Jank bursts may spread across measurements, consider removing this and - // continuing the jank burst after we record more frames. - if (currentJankBurstDurationNs > 0) { - jankBurstDurationsNs.add(currentJankBurstDurationNs); - } - - return longArrayToPrimitiveArray( - jankBurstDurationsNs.toArray(new Long[jankBurstDurationsNs.size()])); - } - - /** - * Returns a new object with metrics for all frames recorded since started or clear() was - * called. - */ - static JankMetrics calculateJankMetrics(FrameMetrics frameMetrics) { - long[] timestampsNs; - long[] totalDurationsNs; - int skippedFrames; - - timestampsNs = longArrayToPrimitiveArray(frameMetrics.timestampsNs); - totalDurationsNs = longArrayToPrimitiveArray(frameMetrics.durationsNs); - skippedFrames = sumArray(frameMetrics.skippedFrames); - - long[] jankBursts = calculateJankBurstDurationsNs(timestampsNs, totalDurationsNs); - - return new JankMetrics(timestampsNs, totalDurationsNs, jankBursts, skippedFrames); - } - - /** - * Checks if the frame at frameIndex is janky (i.e. Its duration is greater than 16 ms). Returns - * false if frameIndex is out of bounds. - */ - private static boolean isFrameJanky(int frameIndex, long[] durationsNs) { - if (frameIndex < 0 || frameIndex >= durationsNs.length) return false; - - long frameDurationNs = durationsNs[frameIndex]; - - return frameDurationNs > JANK_THRESHOLD_NS; - } - - /** - * Checks if the frame at secondFrameIndex was drawn immediately after the frame at - * firstFrameIndex (with a margin of 50ms defined in JANK_BURST_CONSECUTIVE_FRAME_THRESHOLD_MS). - * Timestamps are recorded at the end of each frame, so we compare the end of the first frame - * and the beginning of the second frame. If either index is out of bounds then we return false. - */ - private static boolean areFramesConsecutive( - int firstFrameIndex, int secondFrameIndex, long[] timestampsNs, long[] durationsNs) { - assert firstFrameIndex < secondFrameIndex; - assert timestampsNs.length == durationsNs.length; - if (firstFrameIndex < 0 || secondFrameIndex < 0) { - return false; - } - if (firstFrameIndex >= timestampsNs.length || secondFrameIndex >= timestampsNs.length) { - return false; - } - - long firstFrameEndNs = timestampsNs[firstFrameIndex]; - - long secondFrameEndNs = timestampsNs[secondFrameIndex]; - long secondFrameDurationNs = durationsNs[secondFrameIndex]; - long secondFrameStartNs = secondFrameEndNs - secondFrameDurationNs; - - long timeBetweenFramesNs = secondFrameStartNs - firstFrameEndNs; - - return (timeBetweenFramesNs < JANK_BURST_CONSECUTIVE_FRAME_THRESHOLD_NS); - } - - private static long[] longArrayToPrimitiveArray(Long[] longArray) { - long[] primitiveArray = new long[longArray.length]; - for (int i = 0; i < longArray.length; i++) { - primitiveArray[i] = longArray[i].longValue(); - } - - return primitiveArray; - } - - private static int sumArray(Integer[] input) { - int sum = 0; - for (Integer i : input) { - sum += i; - } - - return sum; - } -} \ No newline at end of file
diff --git a/base/android/java/src/org/chromium/base/jank_tracker/JankMetricUMARecorder.java b/base/android/java/src/org/chromium/base/jank_tracker/JankMetricUMARecorder.java deleted file mode 100644 index 4f22a8ba..0000000 --- a/base/android/java/src/org/chromium/base/jank_tracker/JankMetricUMARecorder.java +++ /dev/null
@@ -1,57 +0,0 @@ -// Copyright 2021 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.base.jank_tracker; - -import androidx.annotation.VisibleForTesting; - -import org.chromium.base.annotations.JNINamespace; -import org.chromium.base.annotations.NativeMethods; - -/** - * Sends Android jank metrics to native to be recorded using UMA. - */ -@JNINamespace("base::android") -public class JankMetricUMARecorder { - public static void recordJankMetricsToUMA(JankMetrics metric, @JankScenario int scenario) { - if (metric == null) { - return; - } - - JankMetricUMARecorderJni.get().recordJankMetrics(scenarioToString(scenario), - metric.timestampsNs, metric.durationsNs, metric.jankBurstsNs, metric.skippedFrames); - } - - // Convert an enum value to string to use as an UMA histogram name, changes to strings should be - // reflected in android/histograms.xml. - public static String scenarioToString(@JankScenario int scenario) { - switch (scenario) { - case JankScenario.PERIODIC_REPORTING: - return "Total"; - case JankScenario.OMNIBOX_FOCUS: - return "OmniboxFocus"; - case JankScenario.NEW_TAB_PAGE: - return "NewTabPage"; - case JankScenario.STARTUP: - return "Startup"; - case JankScenario.TAB_SWITCHER: - return "TabSwitcher"; - case JankScenario.OPEN_LINK_IN_NEW_TAB: - return "OpenLinkInNewTab"; - case JankScenario.START_SURFACE_HOMEPAGE: - return "StartSurfaceHomepage"; - case JankScenario.START_SURFACE_TAB_SWITCHER: - return "StartSurfaceTabSwitcher"; - default: - throw new IllegalArgumentException("Invalid scenario value"); - } - } - - @NativeMethods - @VisibleForTesting - public interface Natives { - void recordJankMetrics(String scenarioName, long[] timestampsNs, long[] durationsNs, - long[] jankBurstsNs, int missedFrames); - } -}
diff --git a/base/android/java/src/org/chromium/base/jank_tracker/JankMetrics.java b/base/android/java/src/org/chromium/base/jank_tracker/JankMetrics.java deleted file mode 100644 index 9509c26..0000000 --- a/base/android/java/src/org/chromium/base/jank_tracker/JankMetrics.java +++ /dev/null
@@ -1,24 +0,0 @@ -// Copyright 2021 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.base.jank_tracker; - -/** - * This class is a container for jank metrics, which are processed FrameMetrics ready to be uploaded - * to UMA. - */ -class JankMetrics { - public final long[] timestampsNs; - public final long[] durationsNs; - public final long[] jankBurstsNs; - public final int skippedFrames; - - public JankMetrics( - long[] timestampsNs, long[] durationsNs, long[] jankBurstsNs, int skippedFrames) { - this.timestampsNs = timestampsNs; - this.durationsNs = durationsNs; - this.jankBurstsNs = jankBurstsNs; - this.skippedFrames = skippedFrames; - } -}
diff --git a/base/android/java/src/org/chromium/base/jank_tracker/JankReportingRunnable.java b/base/android/java/src/org/chromium/base/jank_tracker/JankReportingRunnable.java deleted file mode 100644 index b6c4f4ea..0000000 --- a/base/android/java/src/org/chromium/base/jank_tracker/JankReportingRunnable.java +++ /dev/null
@@ -1,43 +0,0 @@ -// Copyright 2021 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.base.jank_tracker; - -/** - * This runnable receives a FrameMetricsStore instance and starts/stops tracking a given scenario. - * When a scenario stops it takes its metrics and sends them to native to be recorded in UMA. - * This is executed by JankReportingScheduler on its own thread. - */ -class JankReportingRunnable implements Runnable { - private final FrameMetricsStore mMetricsStore; - private final @JankScenario int mScenario; - private final boolean mIsStartingTracking; - - JankReportingRunnable(FrameMetricsStore metricsStore, @JankScenario int scenario, - boolean isStartingTracking) { - mMetricsStore = metricsStore; - mScenario = scenario; - mIsStartingTracking = isStartingTracking; - } - - @Override - public void run() { - if (mIsStartingTracking) { - mMetricsStore.startTrackingScenario(mScenario); - } else { - FrameMetrics frames = mMetricsStore.stopTrackingScenario(mScenario); - if (frames == null || frames.timestampsNs.length == 0) { - return; - } - - // Confirm that the current call context is valid. - // Debug builds will assert and fail; release builds will optimize this out. - JankMetricUMARecorderJni.get(); - - JankMetrics metrics = JankMetricCalculator.calculateJankMetrics(frames); - // TODO(salg@): Cache metrics in case native takes >30s to initialize. - JankMetricUMARecorder.recordJankMetricsToUMA(metrics, mScenario); - } - } -}
diff --git a/base/android/java/src/org/chromium/base/jank_tracker/JankReportingScheduler.java b/base/android/java/src/org/chromium/base/jank_tracker/JankReportingScheduler.java deleted file mode 100644 index e249ec6..0000000 --- a/base/android/java/src/org/chromium/base/jank_tracker/JankReportingScheduler.java +++ /dev/null
@@ -1,94 +0,0 @@ -// Copyright 2021 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.base.jank_tracker; - -import android.os.Handler; -import android.os.HandlerThread; - -import androidx.annotation.Nullable; - -import org.chromium.base.TraceEvent; - -import java.util.concurrent.atomic.AtomicBoolean; - -/** - * This class receives requests to start and stop jank scenario tracking and runs them in a - * HandlerThread it creates. In addition it handles the recording of periodic jank metrics. - */ -class JankReportingScheduler { - private static final long PERIODIC_METRIC_DELAY_MS = 30_000; - private static final long TRACE_EVENT_TRACK_ID = 84186319646187624L; - private final FrameMetricsStore mFrameMetricsStore; - - JankReportingScheduler(FrameMetricsStore frameMetricsStore) { - mFrameMetricsStore = frameMetricsStore; - } - - private final Runnable mPeriodicMetricReporter = new Runnable() { - @Override - public void run() { - finishTrackingScenario(JankScenario.PERIODIC_REPORTING); - - if (mIsPeriodicReporterLooping.get()) { - startTrackingScenario(JankScenario.PERIODIC_REPORTING); - getOrCreateHandler().postDelayed(mPeriodicMetricReporter, PERIODIC_METRIC_DELAY_MS); - } - } - }; - - @Nullable - protected HandlerThread mHandlerThread; - @Nullable - private Handler mHandler; - private final AtomicBoolean mIsPeriodicReporterLooping = new AtomicBoolean(false); - - // The string added is a static string. - @SuppressWarnings("NoDynamicStringsInTraceEventCheck") - void startTrackingScenario(@JankScenario int scenario) { - // Make a unique ID for each scenario for tracing. - TraceEvent.startAsync("JankCUJ:" + JankMetricUMARecorder.scenarioToString(scenario), - TRACE_EVENT_TRACK_ID + scenario); - getOrCreateHandler().post(new JankReportingRunnable( - mFrameMetricsStore, scenario, /* isStartingTracking= */ true)); - } - - // The string added is a static string. - @SuppressWarnings("NoDynamicStringsInTraceEventCheck") - void finishTrackingScenario(@JankScenario int scenario) { - TraceEvent.finishAsync("JankCUJ:" + JankMetricUMARecorder.scenarioToString(scenario), - TRACE_EVENT_TRACK_ID + scenario); - getOrCreateHandler().post(new JankReportingRunnable( - mFrameMetricsStore, scenario, /* isStartingTracking= */ false)); - } - - protected Handler getOrCreateHandler() { - if (mHandler == null) { - mHandlerThread = new HandlerThread("Jank-Tracker"); - mHandlerThread.start(); - mHandler = new Handler(mHandlerThread.getLooper()); - } - return mHandler; - } - - void startReportingPeriodicMetrics() { - // If mIsPeriodicReporterLooping was already true then there's no need to post another task. - if (mIsPeriodicReporterLooping.getAndSet(true)) { - return; - } - startTrackingScenario(JankScenario.PERIODIC_REPORTING); - getOrCreateHandler().postDelayed(mPeriodicMetricReporter, PERIODIC_METRIC_DELAY_MS); - } - - void stopReportingPeriodicMetrics() { - // Disable mPeriodicMetricReporter looping, and return early if it was already disabled. - if (!mIsPeriodicReporterLooping.getAndSet(false)) { - return; - } - // Remove any existing mPeriodicMetricReporter delayed tasks. - getOrCreateHandler().removeCallbacks(mPeriodicMetricReporter); - // Run mPeriodicMetricReporter one last time immediately. - getOrCreateHandler().post(mPeriodicMetricReporter); - } -} \ No newline at end of file
diff --git a/base/android/java/src/org/chromium/base/jank_tracker/JankScenario.java b/base/android/java/src/org/chromium/base/jank_tracker/JankScenario.java deleted file mode 100644 index a73fdb6..0000000 --- a/base/android/java/src/org/chromium/base/jank_tracker/JankScenario.java +++ /dev/null
@@ -1,29 +0,0 @@ -// Copyright 2021 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.base.jank_tracker; - -import androidx.annotation.IntDef; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * A list of jank scenarios to be tracked, each scenario corresponds to a specific user journey - * except by PERIODIC_REPORTING, which runs constantly and is uploaded every 30s. - */ -@IntDef({JankScenario.PERIODIC_REPORTING, JankScenario.OMNIBOX_FOCUS, JankScenario.NEW_TAB_PAGE, - JankScenario.STARTUP, JankScenario.TAB_SWITCHER, JankScenario.OPEN_LINK_IN_NEW_TAB, - JankScenario.START_SURFACE_HOMEPAGE, JankScenario.START_SURFACE_TAB_SWITCHER}) -@Retention(RetentionPolicy.SOURCE) -public @interface JankScenario { - int PERIODIC_REPORTING = 1; - int OMNIBOX_FOCUS = 2; - int NEW_TAB_PAGE = 3; - int STARTUP = 4; - int TAB_SWITCHER = 5; - int OPEN_LINK_IN_NEW_TAB = 6; - int START_SURFACE_HOMEPAGE = 7; - int START_SURFACE_TAB_SWITCHER = 8; -}
diff --git a/base/android/java/src/org/chromium/base/jank_tracker/JankTracker.java b/base/android/java/src/org/chromium/base/jank_tracker/JankTracker.java deleted file mode 100644 index a7a3c11..0000000 --- a/base/android/java/src/org/chromium/base/jank_tracker/JankTracker.java +++ /dev/null
@@ -1,27 +0,0 @@ -// Copyright 2021 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.base.jank_tracker; - -/** - * Interface for Android UI jank tracking. - */ -public interface JankTracker { - /** - * Starts tracking UI jank for a specific use scenario (e.g. Tab switcher, Omnibox, etc.), - * calling this method more than once without calling {@code finishTrackingScenario} won't do - * anything. - * @param scenario A value from {@link JankScenario} that specifies a use scenario. - */ - void startTrackingScenario(@JankScenario int scenario); - - /** - * Finishes tracking UI jank for a use scenario (e.g. Tab switcher, Omnibox, etc.). Histograms - * for that scenario (e.g. Android.Jank.FrameDuration.Omnibox) are recorded immediately after - * calling this method. Calling this method without calling {@code startTrackingScenario} - * beforehand won't do anything. - * @param scenario A value from {@link JankScenario} that specifies a use scenario. - */ - void finishTrackingScenario(@JankScenario int scenario); -}
diff --git a/base/android/java/src/org/chromium/base/jank_tracker/JankTrackerImpl.java b/base/android/java/src/org/chromium/base/jank_tracker/JankTrackerImpl.java deleted file mode 100644 index f2bfe2f2..0000000 --- a/base/android/java/src/org/chromium/base/jank_tracker/JankTrackerImpl.java +++ /dev/null
@@ -1,64 +0,0 @@ -// Copyright 2021 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.base.jank_tracker; - -import android.app.Activity; -import android.os.Build; - -/** - * Class for recording janky frame metrics for a specific Activity. - * - * It should be constructed when the activity is created, recording starts and stops automatically - * based on activity state. When the activity is being destroyed {@link #destroy()} should be called - * to clear the activity state observer. All methods should be called from the UI thread. - */ -public class JankTrackerImpl implements JankTracker { - private static final boolean IS_TRACKING_ENABLED = - Build.VERSION.SDK_INT >= Build.VERSION_CODES.N; - - private final JankActivityTracker mActivityTracker; - private final JankReportingScheduler mReportingScheduler; - - /** - * Creates a new JankTracker instance tracking UI rendering of an activity. Metric recording - * starts when the activity starts, and it's paused when the activity stops. - */ - public JankTrackerImpl(Activity activity) { - if (!IS_TRACKING_ENABLED) { - mActivityTracker = null; - mReportingScheduler = null; - return; - } - - FrameMetricsStore metricsStore = new FrameMetricsStore(); - FrameMetricsListener metricsListener = new FrameMetricsListener(metricsStore); - mReportingScheduler = new JankReportingScheduler(metricsStore); - mActivityTracker = new JankActivityTracker(activity, metricsListener, mReportingScheduler); - mActivityTracker.initialize(); - } - - @Override - public void startTrackingScenario(@JankScenario int scenario) { - if (!IS_TRACKING_ENABLED) return; - - mReportingScheduler.startTrackingScenario(scenario); - } - - @Override - public void finishTrackingScenario(@JankScenario int scenario) { - if (!IS_TRACKING_ENABLED) return; - - mReportingScheduler.finishTrackingScenario(scenario); - } - - /** - * Stops listening for Activity state changes. - */ - public void destroy() { - if (!IS_TRACKING_ENABLED) return; - - mActivityTracker.destroy(); - } -}
diff --git a/base/android/junit/src/org/chromium/base/jank_tracker/FrameMetricsListenerTest.java b/base/android/junit/src/org/chromium/base/jank_tracker/FrameMetricsListenerTest.java deleted file mode 100644 index c8c27d44..0000000 --- a/base/android/junit/src/org/chromium/base/jank_tracker/FrameMetricsListenerTest.java +++ /dev/null
@@ -1,59 +0,0 @@ -// Copyright 2021 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.base.jank_tracker; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.when; - -import android.view.FrameMetrics; - -import org.junit.Assert; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.base.test.BaseRobolectricTestRunner; - -/** - * Tests for FrameMetricsListener. - */ -@RunWith(BaseRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class FrameMetricsListenerTest { - @Test - public void testMetricRecording_OffByDefault() { - FrameMetricsStore store = new FrameMetricsStore(); - FrameMetricsListener metricsListener = new FrameMetricsListener(store); - FrameMetrics frameMetrics = mock(FrameMetrics.class); - - store.startTrackingScenario(JankScenario.PERIODIC_REPORTING); - when(frameMetrics.getMetric(FrameMetrics.TOTAL_DURATION)).thenReturn(10_000_000L); - - metricsListener.onFrameMetricsAvailable(null, frameMetrics, 0); - - // By default metrics shouldn't be logged. - Assert.assertEquals( - 0, store.stopTrackingScenario(JankScenario.PERIODIC_REPORTING).durationsNs.length); - verifyNoMoreInteractions(frameMetrics); - } - - @Test - public void testMetricRecording_EnableRecording() { - FrameMetricsStore store = new FrameMetricsStore(); - - FrameMetricsListener metricsListener = new FrameMetricsListener(store); - FrameMetrics frameMetrics = mock(FrameMetrics.class); - - store.startTrackingScenario(JankScenario.PERIODIC_REPORTING); - when(frameMetrics.getMetric(FrameMetrics.TOTAL_DURATION)).thenReturn(10_000_000L); - - metricsListener.setIsListenerRecording(true); - metricsListener.onFrameMetricsAvailable(null, frameMetrics, 0); - - Assert.assertArrayEquals(new Long[] {10_000_000L}, - store.stopTrackingScenario(JankScenario.PERIODIC_REPORTING).durationsNs); - } -}
diff --git a/base/android/junit/src/org/chromium/base/jank_tracker/FrameMetricsStoreTest.java b/base/android/junit/src/org/chromium/base/jank_tracker/FrameMetricsStoreTest.java deleted file mode 100644 index 456745f..0000000 --- a/base/android/junit/src/org/chromium/base/jank_tracker/FrameMetricsStoreTest.java +++ /dev/null
@@ -1,217 +0,0 @@ -// Copyright 2021 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.base.jank_tracker; - -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.base.test.BaseRobolectricTestRunner; - -/** - * Tests for FrameMetricsStore. - */ -@RunWith(BaseRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class FrameMetricsStoreTest { - @Test - public void addFrameMeasurementTest() { - FrameMetricsStore store = new FrameMetricsStore(); - - store.startTrackingScenario(JankScenario.PERIODIC_REPORTING); - - store.addFrameMeasurement(1_000_000_000L, 10_000_000L, 0); - store.addFrameMeasurement(1_020_000_000L, 12_000_000L, 1); - store.addFrameMeasurement(1_040_000_000L, 20_000_000L, 2); - store.addFrameMeasurement(1_060_000_000L, 8_000_000L, 0); - - FrameMetrics scenarioMetrics = store.stopTrackingScenario(JankScenario.PERIODIC_REPORTING); - - assertArrayEquals( - new Long[] {1_000_000_000L, 1_020_000_000L, 1_040_000_000L, 1_060_000_000L}, - scenarioMetrics.timestampsNs); - assertArrayEquals(new Long[] {10_000_000L, 12_000_000L, 20_000_000L, 8_000_000L}, - scenarioMetrics.durationsNs); - assertArrayEquals(new Integer[] {0, 1, 2, 0}, scenarioMetrics.skippedFrames); - } - - @Test - public void addFrameMeasurementTest_MultipleScenarios() { - JankMetricCalculator measurement = new JankMetricCalculator(); - - FrameMetricsStore store = new FrameMetricsStore(); - - store.startTrackingScenario(JankScenario.PERIODIC_REPORTING); - - store.addFrameMeasurement(1_000_000_000L, 10_000_000L, 0); - store.addFrameMeasurement(1_020_000_000L, 12_000_000L, 0); - - FrameMetrics periodicReportingMetrics = - store.stopTrackingScenario(JankScenario.PERIODIC_REPORTING); - store.startTrackingScenario(JankScenario.OMNIBOX_FOCUS); - - store.addFrameMeasurement(1_040_000_000L, 20_000_000L, 0); - store.addFrameMeasurement(1_060_000_000L, 8_000_000L, 0); - - FrameMetrics omniboxMetrics = store.stopTrackingScenario(JankScenario.OMNIBOX_FOCUS); - - assertArrayEquals( - new Long[] {10_000_000L, 12_000_000L}, periodicReportingMetrics.durationsNs); - assertArrayEquals(new Long[] {20_000_000L, 8_000_000L}, omniboxMetrics.durationsNs); - } - - @Test - public void addFrameMeasurement_MultipleOverlappingScenarios() { - JankMetricCalculator measurement = new JankMetricCalculator(); - - FrameMetricsStore store = new FrameMetricsStore(); - - store.addFrameMeasurement(1_000_000_000L, 15_000_000L, 0); - - store.startTrackingScenario(JankScenario.PERIODIC_REPORTING); - - store.addFrameMeasurement(1_020_000_000L, 15_000_000L, 0); - store.addFrameMeasurement(1_040_000_000L, 50_000_000L, 0); - store.addFrameMeasurement(1_060_000_000L, 30_000_000L, 0); - - store.startTrackingScenario(JankScenario.OMNIBOX_FOCUS); - - store.addFrameMeasurement(1_080_000_000L, 10_000_000L, 0); - store.addFrameMeasurement(1_100_000_000L, 30_000_000L, 0); - - FrameMetrics periodicReportingMetrics = - store.stopTrackingScenario(JankScenario.PERIODIC_REPORTING); - - store.addFrameMeasurement(1_120_000_000L, 10_000_000L, 0); - - FrameMetrics omniboxMetrics = store.stopTrackingScenario(JankScenario.OMNIBOX_FOCUS); - - assertArrayEquals( - new Long[] {15_000_000L, 50_000_000L, 30_000_000L, 10_000_000L, 30_000_000L}, - periodicReportingMetrics.durationsNs); - assertArrayEquals( - new Long[] {10_000_000L, 30_000_000L, 10_000_000L}, omniboxMetrics.durationsNs); - } - - @Test - public void addFrameMeasurementTest_MultipleStartCallsAreIgnored() { - JankMetricCalculator measurement = new JankMetricCalculator(); - - FrameMetricsStore store = new FrameMetricsStore(); - - store.startTrackingScenario(JankScenario.PERIODIC_REPORTING); - - store.addFrameMeasurement(1_000_000_000L, 10_000_000L, 0); - store.addFrameMeasurement(1_020_000_000L, 12_000_000L, 0); - - // Any duplicate calls to startTracking should be ignored. - store.startTrackingScenario(JankScenario.PERIODIC_REPORTING); - - store.addFrameMeasurement(1_040_000_000L, 20_000_000L, 0); - - store.startTrackingScenario(JankScenario.PERIODIC_REPORTING); - - store.addFrameMeasurement(1_060_000_000L, 8_000_000L, 0); - - FrameMetrics periodicReportingMetrics = - store.stopTrackingScenario(JankScenario.PERIODIC_REPORTING); - - // The returned metrics should begin at the first call to startTrackingScenario. - assertArrayEquals(new Long[] {10_000_000L, 12_000_000L, 20_000_000L, 8_000_000L}, - periodicReportingMetrics.durationsNs); - } - - @Test - public void stopTrackingScenario_StopWithoutAnyFrames() { - JankMetricCalculator measurement = new JankMetricCalculator(); - - FrameMetricsStore store = new FrameMetricsStore(); - - store.startTrackingScenario(JankScenario.PERIODIC_REPORTING); - FrameMetrics periodicReportingMetrics = - store.stopTrackingScenario(JankScenario.PERIODIC_REPORTING); - - store.startTrackingScenario(JankScenario.OMNIBOX_FOCUS); - FrameMetrics omniboxMetrics = store.stopTrackingScenario(JankScenario.OMNIBOX_FOCUS); - - assertEquals(0, periodicReportingMetrics.durationsNs.length); - assertEquals(0, omniboxMetrics.durationsNs.length); - } - - @Test - public void stopTrackingScenario_EmptyScenarioAfterOneFrame() { - JankMetricCalculator measurement = new JankMetricCalculator(); - - FrameMetricsStore store = new FrameMetricsStore(); - - // Start a scenario just to start recording. - store.startTrackingScenario(JankScenario.OMNIBOX_FOCUS); - - // Add a frame measurement. - store.addFrameMeasurement(1_060_000_000L, 8_000_000L, 0); - - // Start and stop tracking scenario. - store.startTrackingScenario(JankScenario.PERIODIC_REPORTING); - FrameMetrics periodicReportingMetrics = - store.stopTrackingScenario(JankScenario.PERIODIC_REPORTING); - - // The resulting metrics should be empty. - assertEquals(0, periodicReportingMetrics.durationsNs.length); - } - - @Test - public void stopTrackingScenario_StopWithoutStartingReturnsEmptyMetrics() { - JankMetricCalculator measurement = new JankMetricCalculator(); - - FrameMetricsStore store = new FrameMetricsStore(); - - FrameMetrics periodicReportingMetrics = - store.stopTrackingScenario(JankScenario.PERIODIC_REPORTING); - - FrameMetrics omniboxMetrics = store.stopTrackingScenario(JankScenario.OMNIBOX_FOCUS); - - assertEquals(0, periodicReportingMetrics.durationsNs.length); - assertEquals(0, omniboxMetrics.durationsNs.length); - } - - @Test - public void stopTrackingScenario_ClearsUnneededFrames() { - FrameMetricsStore store = new FrameMetricsStore(); - - store.addFrameMeasurement(1_000_000_000L, 15_000_000L, 0); - - store.startTrackingScenario(JankScenario.PERIODIC_REPORTING); - - store.addFrameMeasurement(1_020_000_000L, 15_000_000L, 0); - store.addFrameMeasurement(1_040_000_000L, 50_000_000L, 0); - // This frame should be kept after PERIODIC_REPORTING ends because OMNIBOX_FOCUS uses its - // timestamp to track the scenario's start. - store.addFrameMeasurement(1_060_000_000L, 33_333_333L, 0); - - store.startTrackingScenario(JankScenario.OMNIBOX_FOCUS); - - store.addFrameMeasurement(1_080_000_000L, 10_000_000L, 0); - store.addFrameMeasurement(1_100_000_000L, 30_000_000L, 0); - - store.stopTrackingScenario(JankScenario.PERIODIC_REPORTING); - FrameMetrics storedMetricsAfterPeriodic = store.getAllStoredMetricsForTesting(); - - store.addFrameMeasurement(1_120_000_000L, 10_000_000L, 0); - - store.stopTrackingScenario(JankScenario.OMNIBOX_FOCUS); - FrameMetrics storedMetricsAfterOmnibox = store.getAllStoredMetricsForTesting(); - - // When we stop tracking periodic reporting we should remove all frames that aren't used by - // any other scenarios. - assertArrayEquals(new Long[] {33_333_333L, 10_000_000L, 30_000_000L}, - storedMetricsAfterPeriodic.durationsNs); - // When we stop tracking omnibox there are no other scenarios being tracked, so we clear all - // frame data. - assertEquals(0, storedMetricsAfterOmnibox.durationsNs.length); - } -}
diff --git a/base/android/junit/src/org/chromium/base/jank_tracker/JankActivityTrackerTest.java b/base/android/junit/src/org/chromium/base/jank_tracker/JankActivityTrackerTest.java deleted file mode 100644 index a4e05b4..0000000 --- a/base/android/junit/src/org/chromium/base/jank_tracker/JankActivityTrackerTest.java +++ /dev/null
@@ -1,157 +0,0 @@ -// Copyright 2021 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.base.jank_tracker; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.atLeastOnce; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import android.app.Activity; -import android.view.Window; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.InOrder; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.MockitoAnnotations; - -import org.chromium.base.ActivityState; -import org.chromium.base.ApplicationStatus; -import org.chromium.base.test.BaseRobolectricTestRunner; - -/** - * Tests for JankActivityTracker. - */ -@RunWith(BaseRobolectricTestRunner.class) -public class JankActivityTrackerTest { - - @Mock - private Activity mActivity; - - @Mock - private Window mWindow; - - @Mock - private FrameMetricsListener mFrameMetricsListener; - - @Mock - private JankReportingScheduler mJankReportingScheduler; - - JankActivityTracker createJankActivityTracker(Activity activity) { - JankActivityTracker tracker = - new JankActivityTracker(activity, mFrameMetricsListener, mJankReportingScheduler); - - return tracker; - } - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - - when(mActivity.getWindow()).thenReturn(mWindow); - - ApplicationStatus.onStateChangeForTesting(mActivity, ActivityState.CREATED); - } - - @Test - public void jankTrackerTest_TestInitialize() { - JankActivityTracker jankActivityTracker = createJankActivityTracker(mActivity); - jankActivityTracker.initialize(); - - // Verify that we are listening to frame metrics. - // Initialize also starts listening to activity lifecycle events, but that's harder to - // verify. - verify(mWindow).addOnFrameMetricsAvailableListener(any(), any()); - } - - @Test - public void jankTrackerTest_TestActivityResume() { - JankActivityTracker jankActivityTracker = createJankActivityTracker(mActivity); - jankActivityTracker.initialize(); - - ApplicationStatus.onStateChangeForTesting(mActivity, ActivityState.STARTED); - ApplicationStatus.onStateChangeForTesting(mActivity, ActivityState.RESUMED); - - // When an activity resumes we start reporting periodic metrics. - verify(mJankReportingScheduler, atLeastOnce()).startReportingPeriodicMetrics(); - verify(mJankReportingScheduler, never()).stopReportingPeriodicMetrics(); - - // When an activity resumes we start recording metrics. - verify(mFrameMetricsListener, atLeastOnce()).setIsListenerRecording(true); - } - - @Test - public void jankTrackerTest_TestActivityPause() { - JankActivityTracker jankActivityTracker = createJankActivityTracker(mActivity); - jankActivityTracker.initialize(); - - ApplicationStatus.onStateChangeForTesting(mActivity, ActivityState.STARTED); - ApplicationStatus.onStateChangeForTesting(mActivity, ActivityState.RESUMED); - ApplicationStatus.onStateChangeForTesting(mActivity, ActivityState.PAUSED); - - // When an activity pauses the reporting task should still be looping. - verify(mJankReportingScheduler, atLeastOnce()).startReportingPeriodicMetrics(); - verify(mJankReportingScheduler, never()).stopReportingPeriodicMetrics(); - - InOrder orderVerifier = Mockito.inOrder(mFrameMetricsListener); - - orderVerifier.verify(mFrameMetricsListener, atLeastOnce()).setIsListenerRecording(true); - // When an activity pauses we stop recording metrics. - orderVerifier.verify(mFrameMetricsListener).setIsListenerRecording(false); - } - - @Test - public void jankTrackerTest_TestActivityStop() { - JankActivityTracker jankActivityTracker = createJankActivityTracker(mActivity); - jankActivityTracker.initialize(); - - ApplicationStatus.onStateChangeForTesting(mActivity, ActivityState.STARTED); - ApplicationStatus.onStateChangeForTesting(mActivity, ActivityState.RESUMED); - ApplicationStatus.onStateChangeForTesting(mActivity, ActivityState.PAUSED); - ApplicationStatus.onStateChangeForTesting(mActivity, ActivityState.STOPPED); - - // When an activity stops we stop reporting periodic metrics. - InOrder schedulerOrderVerifier = Mockito.inOrder(mJankReportingScheduler); - schedulerOrderVerifier.verify(mJankReportingScheduler, atLeastOnce()) - .startReportingPeriodicMetrics(); - schedulerOrderVerifier.verify(mJankReportingScheduler).stopReportingPeriodicMetrics(); - } - - @Test - public void jankTrackerTest_TestAttachTrackerOnResumedActivity() { - // Modify the activity's state before attaching JankActivityTracker. - ApplicationStatus.onStateChangeForTesting(mActivity, ActivityState.STARTED); - ApplicationStatus.onStateChangeForTesting(mActivity, ActivityState.RESUMED); - - JankActivityTracker jankActivityTracker = createJankActivityTracker(mActivity); - jankActivityTracker.initialize(); - - // Verify that JankActivityTracker is running as expected for the Resumed state. - // Periodic metric reporting should be enabled. - verify(mJankReportingScheduler).startReportingPeriodicMetrics(); - // Metric recording should be enabled. - verify(mFrameMetricsListener).setIsListenerRecording(true); - } - - @Test - public void jankTrackerTest_TestOutOfOrderStateChange() { - JankActivityTracker jankActivityTracker = createJankActivityTracker(mActivity); - jankActivityTracker.initialize(); - - // Move the activity from STOPPED to RESUMED without calling STARTED. - ApplicationStatus.onStateChangeForTesting(mActivity, ActivityState.STOPPED); - ApplicationStatus.onStateChangeForTesting(mActivity, ActivityState.RESUMED); - - // Verify that JankActivityTracker is running as expected for the Resumed state. - // Reporting task should be running and looping. - verify(mJankReportingScheduler).startReportingPeriodicMetrics(); - // Metric recording should be enabled. - verify(mFrameMetricsListener).setIsListenerRecording(true); - } -}
diff --git a/base/android/junit/src/org/chromium/base/jank_tracker/JankMetricCalculatorTest.java b/base/android/junit/src/org/chromium/base/jank_tracker/JankMetricCalculatorTest.java deleted file mode 100644 index f7a0ec4..0000000 --- a/base/android/junit/src/org/chromium/base/jank_tracker/JankMetricCalculatorTest.java +++ /dev/null
@@ -1,107 +0,0 @@ -// Copyright 2021 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.base.jank_tracker; - -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.base.test.BaseRobolectricTestRunner; - -/** - * Tests for JankMetricCalculator. - */ -@RunWith(BaseRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class JankMetricCalculatorTest { - @Test - public void getJankBurstDurationsTest() { - FrameMetricsStore store = new FrameMetricsStore(); - store.startTrackingScenario(JankScenario.PERIODIC_REPORTING); - - store.addFrameMeasurement(1_000_000_000L, 15_000_000L, 1); - store.addFrameMeasurement(1_020_000_000L, 15_000_000L, 0); - store.addFrameMeasurement(1_040_000_000L, 50_000_000L, 1); // Burst starts here. - store.addFrameMeasurement(1_060_000_000L, 30_000_000L, 1); - store.addFrameMeasurement(1_080_000_000L, 10_000_000L, 2); - store.addFrameMeasurement(1_120_000_000L, 30_000_000L, 0); // Burst ends here. - store.addFrameMeasurement(1_100_000_000L, 10_000_000L, 0); - - FrameMetrics frameMetrics = store.stopTrackingScenario(JankScenario.PERIODIC_REPORTING); - JankMetrics jankMetrics = JankMetricCalculator.calculateJankMetrics(frameMetrics); - - assertArrayEquals(new long[] {120_000_000L}, jankMetrics.jankBurstsNs); - assertEquals(5, jankMetrics.skippedFrames); - } - - @Test - public void getJankBurstDurationsTest_TwoBursts() { - FrameMetricsStore store = new FrameMetricsStore(); - store.startTrackingScenario(JankScenario.PERIODIC_REPORTING); - - store.addFrameMeasurement(1_000_000_000L, 50_000_000L, 0); // Burst starts here. - store.addFrameMeasurement(1_020_000_000L, 50_000_000L, 0); - store.addFrameMeasurement(1_040_000_000L, 10_000_000L, 0); - store.addFrameMeasurement(1_060_000_000L, 50_000_000L, 0); // Burst ends here. - store.addFrameMeasurement(1_080_000_000L, 10_000_000L, 0); - store.addFrameMeasurement(1_100_000_000L, 10_000_000L, 0); - store.addFrameMeasurement(1_120_000_000L, 50_000_000L, 0); // Burst starts here. - store.addFrameMeasurement(1_140_000_000L, 50_000_000L, 0); - store.addFrameMeasurement(1_160_000_000L, 50_000_000L, 0); // Burst ends here. - - FrameMetrics frameMetrics = store.stopTrackingScenario(JankScenario.PERIODIC_REPORTING); - JankMetrics jankMetrics = JankMetricCalculator.calculateJankMetrics(frameMetrics); - - assertArrayEquals(new long[] {160_000_000L, 150_000_000L}, jankMetrics.jankBurstsNs); - } - - @Test - public void getJankBurstDurationsTest_OneLongBurst() { - FrameMetricsStore store = new FrameMetricsStore(); - store.startTrackingScenario(JankScenario.PERIODIC_REPORTING); - - store.addFrameMeasurement(1_000_000_000L, 50_000_000L, 0); // Burst starts here. - store.addFrameMeasurement(1_020_000_000L, 10_000_000L, 0); - store.addFrameMeasurement(1_040_000_000L, 50_000_000L, 0); - store.addFrameMeasurement(1_060_000_000L, 10_000_000L, 0); - store.addFrameMeasurement(1_080_000_000L, 50_000_000L, 0); - store.addFrameMeasurement(1_100_000_000L, 10_000_000L, 0); - store.addFrameMeasurement(1_120_000_000L, 50_000_000L, 0); - store.addFrameMeasurement(1_140_000_000L, 10_000_000L, 0); - store.addFrameMeasurement(1_160_000_000L, 50_000_000L, 0); // Burst ends here. - - FrameMetrics frameMetrics = store.stopTrackingScenario(JankScenario.PERIODIC_REPORTING); - JankMetrics jankMetrics = JankMetricCalculator.calculateJankMetrics(frameMetrics); - - assertArrayEquals(new long[] {290_000_000L}, jankMetrics.jankBurstsNs); - } - - @Test - public void getJankBurstDurationsTest_ThreeBursts_WithNonConsecutiveFrames() { - FrameMetricsStore store = new FrameMetricsStore(); - store.startTrackingScenario(JankScenario.PERIODIC_REPORTING); - - store.addFrameMeasurement(1_000_000_000L, 50_000_000L, 0); // Burst starts here. - store.addFrameMeasurement(1_020_000_000L, 50_000_000L, 0); - store.addFrameMeasurement(1_040_000_000L, 50_000_000L, 0); // Burst ends here. - store.addFrameMeasurement( - 2_000_000_000L, 50_000_000L, 0); // Burst starts here (~1000ms passed). - store.addFrameMeasurement(2_020_000_000L, 50_000_000L, 0); - store.addFrameMeasurement(2_040_000_000L, 10_000_000L, 0); - store.addFrameMeasurement(2_060_000_000L, 50_000_000L, 0); // Burst ends here. - store.addFrameMeasurement(3_000_000_000L, 10_000_000L, 0); - store.addFrameMeasurement(3_020_000_000L, 50_000_000L, 0); // Burst starts and ends here. - store.addFrameMeasurement(3_040_000_000L, 10_000_000L, 0); - - FrameMetrics frameMetrics = store.stopTrackingScenario(JankScenario.PERIODIC_REPORTING); - JankMetrics jankMetrics = JankMetricCalculator.calculateJankMetrics(frameMetrics); - - assertArrayEquals( - new long[] {150_000_000L, 160_000_000L, 50_000_000L}, jankMetrics.jankBurstsNs); - } -}
diff --git a/base/android/junit/src/org/chromium/base/jank_tracker/JankMetricUMARecorderTest.java b/base/android/junit/src/org/chromium/base/jank_tracker/JankMetricUMARecorderTest.java deleted file mode 100644 index c316788..0000000 --- a/base/android/junit/src/org/chromium/base/jank_tracker/JankMetricUMARecorderTest.java +++ /dev/null
@@ -1,54 +0,0 @@ -// Copyright 2021 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.base.jank_tracker; - -import static org.mockito.Mockito.verify; - -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.robolectric.annotation.Config; - -import org.chromium.base.test.BaseRobolectricTestRunner; -import org.chromium.base.test.util.JniMocker; - -/** - * Tests for JankMetricUMARecorder. - */ -@RunWith(BaseRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class JankMetricUMARecorderTest { - @Rule - public JniMocker mocker = new JniMocker(); - - @Mock - JankMetricUMARecorder.Natives mNativeMock; - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - mocker.mock(JankMetricUMARecorderJni.TEST_HOOKS, mNativeMock); - } - - @Test - public void testRecordMetricsToNative() { - long[] timestampsNs = new long[] {1_000_000_000L, 2_000_000_000L, 3_000_000_000L}; - long[] durationsNs = new long[] {5_000_000L, 8_000_000L, 30_000_000L}; - long[] jankBurstsNs = new long[] {30_000L}; - int missedFrames = 3; - - JankMetrics metric = new JankMetrics(timestampsNs, durationsNs, jankBurstsNs, missedFrames); - - JankMetricUMARecorder.recordJankMetricsToUMA(metric, JankScenario.OMNIBOX_FOCUS); - - // Ensure that the relevant fields are sent down to native. - verify(mNativeMock) - .recordJankMetrics( - "OmniboxFocus", timestampsNs, durationsNs, jankBurstsNs, missedFrames); - } -}
diff --git a/base/android/junit/src/org/chromium/base/jank_tracker/JankReportingRunnableTest.java b/base/android/junit/src/org/chromium/base/jank_tracker/JankReportingRunnableTest.java deleted file mode 100644 index 5925b6ec..0000000 --- a/base/android/junit/src/org/chromium/base/jank_tracker/JankReportingRunnableTest.java +++ /dev/null
@@ -1,91 +0,0 @@ -// Copyright 2021 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.base.jank_tracker; - -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; - -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.MockitoAnnotations; - -import org.chromium.base.test.BaseRobolectricTestRunner; -import org.chromium.base.test.util.JniMocker; - -/** - * Tests for JankReportingRunnable. - */ -@RunWith(BaseRobolectricTestRunner.class) -public class JankReportingRunnableTest { - @Rule - public JniMocker mocker = new JniMocker(); - - @Mock - JankMetricUMARecorder.Natives mNativeMock; - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - mocker.mock(JankMetricUMARecorderJni.TEST_HOOKS, mNativeMock); - } - - @Test - public void testStartTracking() { - FrameMetricsStore metricsStore = Mockito.spy(new FrameMetricsStore()); - - JankReportingRunnable reportingRunnable = new JankReportingRunnable( - metricsStore, JankScenario.TAB_SWITCHER, /* isStartingTracking= */ true); - reportingRunnable.run(); - - verify(metricsStore).startTrackingScenario(JankScenario.TAB_SWITCHER); - verifyNoMoreInteractions(metricsStore); - } - - @Test - public void testStopTracking() { - FrameMetricsStore metricsStore = Mockito.spy(new FrameMetricsStore()); - - JankReportingRunnable startReportingRunnable = new JankReportingRunnable( - metricsStore, JankScenario.TAB_SWITCHER, /* isStartingTracking= */ true); - startReportingRunnable.run(); - - metricsStore.addFrameMeasurement(1_000_000L, 1_000L, 1); - - JankReportingRunnable stopReportingRunnable = new JankReportingRunnable( - metricsStore, JankScenario.TAB_SWITCHER, /* isStartingTracking= */ false); - stopReportingRunnable.run(); - - verify(metricsStore).startTrackingScenario(JankScenario.TAB_SWITCHER); - verify(metricsStore).stopTrackingScenario(JankScenario.TAB_SWITCHER); - - verify(mNativeMock) - .recordJankMetrics("TabSwitcher", new long[] {1_000_000L}, new long[] {1_000L}, - new long[0], 1); - } - - @Test - public void testStopTracking_emptyStoreShouldntRecordAnything() { - // Create a store but don't add any measurements. - FrameMetricsStore metricsStore = Mockito.spy(new FrameMetricsStore()); - - JankReportingRunnable startReportingRunnable = new JankReportingRunnable( - metricsStore, JankScenario.TAB_SWITCHER, /* isStartingTracking= */ true); - startReportingRunnable.run(); - - JankReportingRunnable stopReportingRunnable = new JankReportingRunnable( - metricsStore, JankScenario.TAB_SWITCHER, /* isStartingTracking= */ false); - stopReportingRunnable.run(); - - verify(metricsStore).startTrackingScenario(JankScenario.TAB_SWITCHER); - verify(metricsStore).stopTrackingScenario(JankScenario.TAB_SWITCHER); - - // Native shouldn't be called when there are no measurements. - verifyNoMoreInteractions(mNativeMock); - } -}
diff --git a/base/android/junit/src/org/chromium/base/jank_tracker/JankReportingSchedulerTest.java b/base/android/junit/src/org/chromium/base/jank_tracker/JankReportingSchedulerTest.java deleted file mode 100644 index b4dc16b..0000000 --- a/base/android/junit/src/org/chromium/base/jank_tracker/JankReportingSchedulerTest.java +++ /dev/null
@@ -1,146 +0,0 @@ -// Copyright 2021 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.base.jank_tracker; - -import static org.mockito.Mockito.verify; - -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.InOrder; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.MockitoAnnotations; -import org.robolectric.annotation.LooperMode; -import org.robolectric.shadow.api.Shadow; -import org.robolectric.shadows.ShadowLooper; - -import org.chromium.base.test.BaseRobolectricTestRunner; - -/** - * Tests for JankReportingScheduler. - */ -@RunWith(BaseRobolectricTestRunner.class) -@LooperMode(LooperMode.Mode.LEGACY) -public class JankReportingSchedulerTest { - ShadowLooper mShadowLooper; - - @Mock - private FrameMetricsStore mFrameMetricsStore; - - JankReportingScheduler createJankReportingScheduler() { - JankReportingScheduler scheduler = new JankReportingScheduler(mFrameMetricsStore); - mShadowLooper = Shadow.extract(scheduler.getOrCreateHandler().getLooper()); - - return scheduler; - } - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - } - - @Test - public void jankScenarioTracking_startTracking() { - JankReportingScheduler jankReportingScheduler = createJankReportingScheduler(); - - jankReportingScheduler.startTrackingScenario(JankScenario.NEW_TAB_PAGE); - - // Starting tracking posts a task to begin recording metrics in FrameMetricsStore. - mShadowLooper.runOneTask(); - - verify(mFrameMetricsStore).startTrackingScenario(JankScenario.NEW_TAB_PAGE); - } - - @Test - public void jankScenarioTracking_startAndStopTracking() { - JankReportingScheduler jankReportingScheduler = createJankReportingScheduler(); - - jankReportingScheduler.startTrackingScenario(JankScenario.NEW_TAB_PAGE); - jankReportingScheduler.finishTrackingScenario(JankScenario.NEW_TAB_PAGE); - - // Starting tracking posts a task to begin recording metrics in FrameMetricsStore. - mShadowLooper.runOneTask(); - // Stopping tracking posts a task to finish tracking and upload the calculated metrics. - mShadowLooper.runOneTask(); - - InOrder orderVerifier = Mockito.inOrder(mFrameMetricsStore); - - // After both tasks we should have started and stopped tracking the periodic reporting - // scenario. - orderVerifier.verify(mFrameMetricsStore).startTrackingScenario(JankScenario.NEW_TAB_PAGE); - orderVerifier.verify(mFrameMetricsStore).stopTrackingScenario(JankScenario.NEW_TAB_PAGE); - - Assert.assertFalse(mShadowLooper.getScheduler().areAnyRunnable()); - } - - @Test - public void jankReportingSchedulerTest_StartPeriodicReporting() { - JankReportingScheduler jankReportingScheduler = createJankReportingScheduler(); - - jankReportingScheduler.startReportingPeriodicMetrics(); - - // When periodic reporting is enabled a task is immediately posted to begin tracking. - mShadowLooper.runOneTask(); - // Then a delayed task is posted for the reporting loop. - mShadowLooper.runOneTask(); - // The reporting loop task posts an immediate task to stop tracking and record the data. - mShadowLooper.runOneTask(); - - InOrder orderVerifier = Mockito.inOrder(mFrameMetricsStore); - - // After both tasks we should have started and stopped tracking the periodic reporting - // scenario. - orderVerifier.verify(mFrameMetricsStore) - .startTrackingScenario(JankScenario.PERIODIC_REPORTING); - orderVerifier.verify(mFrameMetricsStore) - .stopTrackingScenario(JankScenario.PERIODIC_REPORTING); - - // There should be another task posted to continue the loop. - Assert.assertTrue(mShadowLooper.getScheduler().areAnyRunnable()); - } - - @Test - public void jankReportingSchedulerTest_StopPeriodicReporting() { - JankReportingScheduler jankReportingScheduler = createJankReportingScheduler(); - - jankReportingScheduler.startReportingPeriodicMetrics(); - - // Run tracking initialization task. - mShadowLooper.runOneTask(); - // Run the first reporting loop (delayed 30s). - mShadowLooper.runOneTask(); - // Run task to stop tracking 1st loop and record data. - mShadowLooper.runOneTask(); - // Run task to start tracking the 2nd reporting loop. - mShadowLooper.runOneTask(); - - jankReportingScheduler.stopReportingPeriodicMetrics(); - - // Stopping periodic metric recording posts a reporting loop task immediately to stop - // tracking and record results. - mShadowLooper.runOneTask(); - // The reporting loop task posts another immediate task to stop tracking and report data. - mShadowLooper.runOneTask(); - - InOrder orderVerifier = Mockito.inOrder(mFrameMetricsStore); - - // This start/stop pair corresponds to the first reporting period. - orderVerifier.verify(mFrameMetricsStore) - .startTrackingScenario(JankScenario.PERIODIC_REPORTING); - orderVerifier.verify(mFrameMetricsStore) - .stopTrackingScenario(JankScenario.PERIODIC_REPORTING); - - // Stopping reporting forces an immediate report of recorded frames, if any. - orderVerifier.verify(mFrameMetricsStore) - .startTrackingScenario(JankScenario.PERIODIC_REPORTING); - orderVerifier.verify(mFrameMetricsStore) - .stopTrackingScenario(JankScenario.PERIODIC_REPORTING); - - // There should not be another task posted to continue the loop. - Assert.assertFalse(mShadowLooper.getScheduler().areAnyRunnable()); - } -}
diff --git a/build/config/fuchsia/OWNERS b/build/config/fuchsia/OWNERS index afdc62e9..565fda1e 100644 --- a/build/config/fuchsia/OWNERS +++ b/build/config/fuchsia/OWNERS
@@ -1,4 +1,5 @@ file://build/fuchsia/OWNERS -per-file *.cmx=set noparent -per-file *.cmx=file://build/fuchsia/SECURITY_OWNERS +chonggu@google.com +rohpavone@chromium.org +zijiehe@google.com
diff --git a/build/config/fuchsia/test/OWNERS b/build/config/fuchsia/test/OWNERS index 50a4d58..ac711c0 100644 --- a/build/config/fuchsia/test/OWNERS +++ b/build/config/fuchsia/test/OWNERS
@@ -1,11 +1,7 @@ file://build/fuchsia/OWNERS -per-file *.test-cmx=set noparent -per-file *.test-cmx=ddorwin@chromium.org -per-file *.test-cmx=wez@chromium.org per-file *.test-cml=set noparent per-file *.test-cml=ddorwin@chromium.org per-file *.test-cml=wez@chromium.org # Please prefer the above when possible. -per-file *.test-cmx=file://build/fuchsia/SECURITY_OWNERS per-file *.test-cml=file://build/fuchsia/SECURITY_OWNERS
diff --git a/build/fuchsia/OWNERS b/build/fuchsia/OWNERS index 64bca9e..887630d4 100644 --- a/build/fuchsia/OWNERS +++ b/build/fuchsia/OWNERS
@@ -4,14 +4,14 @@ # reviewer is added automatically. Thank you. ddorwin@chromium.org -fdegans@chromium.org grt@chromium.org -kmarshall@chromium.org sergeyu@chromium.org wez@chromium.org -per-file linux.sdk.sha1=chromium-autoroll@skia-public.iam.gserviceaccount.com -per-file mac.sdk.sha1=chromium-autoroll@skia-public.iam.gserviceaccount.com +per-file *.py=chonggu@google.com +per-file *.py=rohpavone@chromium.org +per-file *.py=zijiehe@google.com + per-file linux_internal.sdk.sha1=chromium-internal-autoroll@skia-corp.google.com.iam.gserviceaccount.com per-file SECURITY_OWNERS=set noparent
diff --git a/build/fuchsia/test/OWNERS b/build/fuchsia/test/OWNERS index ea44fd1..90b7846 100644 --- a/build/fuchsia/test/OWNERS +++ b/build/fuchsia/test/OWNERS
@@ -1,2 +1,3 @@ chonggu@google.com +rohpavone@chromium.org zijiehe@google.com
diff --git a/build/fuchsia/update_images.py b/build/fuchsia/update_images.py index f8aa019..5251f98e 100755 --- a/build/fuchsia/update_images.py +++ b/build/fuchsia/update_images.py
@@ -215,7 +215,6 @@ parser.add_argument( '--allow-override', default=True, - action=argparse.BooleanOptionalAction, type=bool, help='Whether sdk_override.txt can be used for fetching the image, if ' 'it exists.')
diff --git a/cc/input/input_handler.cc b/cc/input/input_handler.cc index 8feb736..05b22d81 100644 --- a/cc/input/input_handler.cc +++ b/cc/input/input_handler.cc
@@ -127,7 +127,7 @@ bool unification_enabled = base::FeatureList::IsEnabled(features::kScrollUnification); - if (target_element_id && !scroll_state->main_thread_hit_tested_reasons()) { + if (target_element_id && !scroll_state->is_main_thread_hit_tested()) { TRACE_EVENT_INSTANT0("cc", "Latched scroll node provided", TRACE_EVENT_SCOPE_THREAD); // If the caller passed in an element_id we can skip all the hit-testing @@ -154,7 +154,7 @@ // scroll in the given direction. This mode is only used when scroll // unification is enabled and the targeted scroller comes back from a // main thread hit test. - DCHECK(scroll_state->main_thread_hit_tested_reasons()); + DCHECK(scroll_state->data()->is_main_thread_hit_tested); DCHECK(unification_enabled); starting_node = scroll_tree.FindNodeFromElementId(target_element_id); @@ -177,7 +177,7 @@ compositor_delegate_->DeviceScaleFactor()); if (unification_enabled) { - if (scroll_state->main_thread_hit_tested_reasons()) { + if (scroll_state->data()->is_main_thread_hit_tested) { // The client should have discarded the scroll when the hit test came // back with an invalid element id. If we somehow get here, we should // drop the scroll as continuing could cause us to infinitely bounce @@ -199,9 +199,7 @@ TRACE_EVENT_SCOPE_THREAD); scroll_status.thread = InputHandler::ScrollThread::SCROLL_ON_IMPL_THREAD; - DCHECK(scroll_hit_test.main_thread_hit_test_reasons); - scroll_status.main_thread_hit_test_reasons = - scroll_hit_test.main_thread_hit_test_reasons; + scroll_status.needs_main_thread_hit_test = true; return scroll_status; } @@ -327,7 +325,7 @@ // Since we provided an ElementId, there should never be a need to perform a // hit test. - DCHECK(!scroll_status.main_thread_hit_test_reasons); + DCHECK(!scroll_status.needs_main_thread_hit_test); return scroll_status; } @@ -1465,8 +1463,6 @@ // this, we have to get a hit test from the main thread. if (!IsInitialScrollHitTestReliable(layer_impl, scroller_layer)) { TRACE_EVENT_INSTANT0("cc", "Failed Hit Test", TRACE_EVENT_SCOPE_THREAD); - result.main_thread_hit_test_reasons = - MainThreadScrollingReason::kFailedHitTest; return result; } @@ -1476,8 +1472,6 @@ // failure. if (ActiveTree().PointHitsNonFastScrollableRegion(device_viewport_point, *layer_impl)) { - result.main_thread_hit_test_reasons = - MainThreadScrollingReason::kNonFastScrollableRegion; return result; } }
diff --git a/cc/input/input_handler.h b/cc/input/input_handler.h index 4ad1b7e..4589fd7 100644 --- a/cc/input/input_handler.h +++ b/cc/input/input_handler.h
@@ -207,16 +207,31 @@ InputHandler& operator=(const InputHandler&) = delete; struct ScrollStatus { + ScrollStatus() = default; + ScrollStatus(ScrollThread thread, uint32_t main_thread_scrolling_reasons) + : thread(thread), + main_thread_scrolling_reasons(main_thread_scrolling_reasons) {} + ScrollStatus(ScrollThread thread, + uint32_t main_thread_scrolling_reasons, + bool needs_main_thread_hit_test) + : thread(thread), + main_thread_scrolling_reasons(main_thread_scrolling_reasons), + needs_main_thread_hit_test(needs_main_thread_hit_test) {} ScrollThread thread = ScrollThread::SCROLL_ON_IMPL_THREAD; // This should be set to nonzero iff `thread` is SCROLL_ON_MAIN_THREAD. uint32_t main_thread_scrolling_reasons = MainThreadScrollingReason::kNotScrollingOnMain; + // TODO(crbug.com/1155758): This is a temporary workaround for GuestViews + // as they create viewport nodes and want to bubble scroll if the + // viewport cannot scroll in the given delta directions. There should be + // a parameter to ThreadInputHandler to specify whether unused delta is + // consumed by the viewport or bubbles to the parent. + bool viewport_cannot_scroll = false; - // Used only in scroll unification. If nonzero, it tells the caller that - // the input handler detected a case where it cannot reliably target a - // scroll node and needs the main thread to perform a hit test. - uint32_t main_thread_hit_test_reasons = - MainThreadScrollingReason::kNotScrollingOnMain; + // Used only in scroll unification. Tells the caller that the input handler + // detected a case where it cannot reliably target a scroll node and needs + // the main thread to perform a hit test. + bool needs_main_thread_hit_test = false; // Used only in scroll unification. A nonzero value means we have performed // the scroll (i.e. updated the offset in the scroll tree) on the compositor @@ -226,15 +241,7 @@ // from the MainThreadScrollingReason enum. (Unification avoids setting // main_thread_scrolling_reasons, to keep that field consistent with // semantics of ScrollThread::SCROLL_ON_IMPL_THREAD.) - uint32_t main_thread_repaint_reasons = - MainThreadScrollingReason::kNotScrollingOnMain; - - // TODO(crbug.com/1155758): This is a temporary workaround for GuestViews - // as they create viewport nodes and want to bubble scroll if the - // viewport cannot scroll in the given delta directions. There should be - // a parameter to ThreadInputHandler to specify whether unused delta is - // consumed by the viewport or bubbles to the parent. - bool viewport_cannot_scroll = false; + uint32_t main_thread_repaint_reasons = 0; }; enum class TouchStartOrMoveEventListenerType { @@ -631,8 +638,6 @@ struct ScrollHitTestResult { raw_ptr<ScrollNode> scroll_node; bool hit_test_successful; - uint32_t main_thread_hit_test_reasons = - MainThreadScrollingReason::kNotScrollingOnMain; }; ScrollHitTestResult HitTestScrollNode( const gfx::PointF& device_viewport_point) const;
diff --git a/cc/input/scroll_state.h b/cc/input/scroll_state.h index 85cf70b..4b67824 100644 --- a/cc/input/scroll_state.h +++ b/cc/input/scroll_state.h
@@ -93,8 +93,8 @@ return data_.current_native_scrolling_element(); } - uint32_t main_thread_hit_tested_reasons() const { - return data_.main_thread_hit_tested_reasons; + bool is_main_thread_hit_tested() const { + return data_.is_main_thread_hit_tested; } ScrollStateData* data() { return &data_; }
diff --git a/cc/input/scroll_state_data.cc b/cc/input/scroll_state_data.cc index 54c0e2b..24dfd0a 100644 --- a/cc/input/scroll_state_data.cc +++ b/cc/input/scroll_state_data.cc
@@ -26,7 +26,8 @@ delta_granularity(ui::ScrollGranularity::kScrollByPrecisePixel), caused_scroll_x(false), caused_scroll_y(false), - is_scroll_chain_cut(false) {} + is_scroll_chain_cut(false), + is_main_thread_hit_tested(false) {} ScrollStateData::ScrollStateData(const ScrollStateData&) = default;
diff --git a/cc/input/scroll_state_data.h b/cc/input/scroll_state_data.h index 39a8f87..00b7fb9b 100644 --- a/cc/input/scroll_state_data.h +++ b/cc/input/scroll_state_data.h
@@ -8,7 +8,6 @@ #include <stdint.h> #include "cc/cc_export.h" -#include "cc/input/main_thread_scrolling_reason.h" #include "cc/trees/property_tree.h" #include "ui/events/types/scroll_types.h" @@ -73,10 +72,9 @@ void set_current_native_scrolling_element(ElementId element_id); // Used in scroll unification to specify that a scroll state has been hit - // tested on the main thread. If this is nonzero, the hit test result will be + // tested on the main thread. If this is true, the hit test result will be // placed in the current_native_scrolling_element_. - uint32_t main_thread_hit_tested_reasons = - MainThreadScrollingReason::kNotScrollingOnMain; + bool is_main_thread_hit_tested; private: // The id of the last native element to respond to a scroll, or 0 if none
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc index cc26eda15..74d79c90 100644 --- a/cc/trees/layer_tree_host_impl_unittest.cc +++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -571,8 +571,7 @@ ui::ScrollInputType::kWheel); if (base::FeatureList::IsEnabled(features::kScrollUnification)) { ASSERT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread); - ASSERT_EQ(MainThreadScrollingReason::kFailedHitTest, - status.main_thread_hit_test_reasons); + ASSERT_TRUE(status.needs_main_thread_hit_test); } else { ASSERT_EQ(ScrollThread::SCROLL_ON_MAIN_THREAD, status.thread); ASSERT_EQ(MainThreadScrollingReason::kFailedHitTest, @@ -587,8 +586,7 @@ ui::ScrollInputType::kWheel); if (base::FeatureList::IsEnabled(features::kScrollUnification)) { ASSERT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread); - ASSERT_EQ(MainThreadScrollingReason::kFailedHitTest, - status.main_thread_hit_test_reasons); + ASSERT_TRUE(status.needs_main_thread_hit_test); } else { ASSERT_EQ(ScrollThread::SCROLL_ON_MAIN_THREAD, status.thread); ASSERT_EQ(MainThreadScrollingReason::kFailedHitTest, @@ -1350,8 +1348,7 @@ scroll_state.get(), ui::ScrollInputType::kWheel); if (base::FeatureList::IsEnabled(features::kScrollUnification)) { EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread); - EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain, - status.main_thread_hit_test_reasons); + EXPECT_FALSE(status.needs_main_thread_hit_test); EXPECT_EQ( MainThreadScrollingReason::kThreadedScrollingDisabled, host_impl_->CurrentlyScrollingNode()->main_thread_scrolling_reasons); @@ -1679,10 +1676,7 @@ ui::ScrollInputType::kWheel); if (base::FeatureList::IsEnabled(features::kScrollUnification)) { EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread); - EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain, - status.main_thread_scrolling_reasons); - EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain, - status.main_thread_hit_test_reasons); + EXPECT_FALSE(status.needs_main_thread_hit_test); EXPECT_EQ( MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects, host_impl_->CurrentlyScrollingNode()->main_thread_scrolling_reasons); @@ -1699,10 +1693,7 @@ ui::ScrollInputType::kTouchscreen); if (base::FeatureList::IsEnabled(features::kScrollUnification)) { EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread); - EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain, - status.main_thread_scrolling_reasons); - EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain, - status.main_thread_hit_test_reasons); + EXPECT_FALSE(status.needs_main_thread_hit_test); EXPECT_EQ( MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects, host_impl_->CurrentlyScrollingNode()->main_thread_scrolling_reasons); @@ -1761,8 +1752,7 @@ EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread); EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain, status.main_thread_scrolling_reasons); - EXPECT_EQ(MainThreadScrollingReason::kFailedHitTest, - status.main_thread_hit_test_reasons); + EXPECT_TRUE(status.needs_main_thread_hit_test); } else { EXPECT_EQ(ScrollThread::SCROLL_ON_MAIN_THREAD, status.thread); EXPECT_EQ(MainThreadScrollingReason::kFailedHitTest, @@ -1916,8 +1906,7 @@ EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread); EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain, status.main_thread_scrolling_reasons); - EXPECT_EQ(MainThreadScrollingReason::kNonFastScrollableRegion, - status.main_thread_hit_test_reasons); + EXPECT_TRUE(status.needs_main_thread_hit_test); } else { EXPECT_EQ(ScrollThread::SCROLL_ON_MAIN_THREAD, status.thread); EXPECT_EQ(MainThreadScrollingReason::kNonFastScrollableRegion, @@ -1933,8 +1922,7 @@ EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread); EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain, status.main_thread_scrolling_reasons); - EXPECT_EQ(MainThreadScrollingReason::kNonFastScrollableRegion, - status.main_thread_hit_test_reasons); + EXPECT_TRUE(status.needs_main_thread_hit_test); } else { EXPECT_EQ(ScrollThread::SCROLL_ON_MAIN_THREAD, status.thread); EXPECT_EQ(MainThreadScrollingReason::kNonFastScrollableRegion, @@ -1999,8 +1987,7 @@ EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread); EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain, status.main_thread_scrolling_reasons); - EXPECT_EQ(MainThreadScrollingReason::kNonFastScrollableRegion, - status.main_thread_hit_test_reasons); + EXPECT_TRUE(status.needs_main_thread_hit_test); } else { EXPECT_EQ(ScrollThread::SCROLL_ON_MAIN_THREAD, status.thread); EXPECT_EQ(MainThreadScrollingReason::kNonFastScrollableRegion, @@ -2029,8 +2016,7 @@ EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread); EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain, status.main_thread_scrolling_reasons); - EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain, - status.main_thread_hit_test_reasons); + EXPECT_FALSE(status.needs_main_thread_hit_test); GetInputHandler().ScrollUpdate(UpdateState(gfx::Point(), gfx::Vector2d(0, 1), ui::ScrollInputType::kWheel) @@ -2047,8 +2033,7 @@ EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread); EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain, status.main_thread_scrolling_reasons); - EXPECT_EQ(MainThreadScrollingReason::kNonFastScrollableRegion, - status.main_thread_hit_test_reasons); + EXPECT_TRUE(status.needs_main_thread_hit_test); } else { EXPECT_EQ(ScrollThread::SCROLL_ON_MAIN_THREAD, status.thread); EXPECT_EQ(MainThreadScrollingReason::kNonFastScrollableRegion, @@ -2107,8 +2092,7 @@ ASSERT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread); ASSERT_EQ(MainThreadScrollingReason::kNotScrollingOnMain, status.main_thread_scrolling_reasons); - ASSERT_EQ(MainThreadScrollingReason::kNonFastScrollableRegion, - status.main_thread_hit_test_reasons); + ASSERT_TRUE(status.needs_main_thread_hit_test); } else { ASSERT_EQ(ScrollThread::SCROLL_ON_MAIN_THREAD, status.thread); ASSERT_EQ(MainThreadScrollingReason::kNonFastScrollableRegion, @@ -2163,8 +2147,7 @@ EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread); EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain, status.main_thread_scrolling_reasons); - EXPECT_EQ(MainThreadScrollingReason::kNonFastScrollableRegion, - status.main_thread_hit_test_reasons); + EXPECT_TRUE(status.needs_main_thread_hit_test); } else { EXPECT_EQ(ScrollThread::SCROLL_ON_MAIN_THREAD, status.thread); EXPECT_EQ(MainThreadScrollingReason::kNonFastScrollableRegion, @@ -2239,8 +2222,7 @@ ASSERT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread); ASSERT_EQ(MainThreadScrollingReason::kNotScrollingOnMain, status.main_thread_scrolling_reasons); - ASSERT_EQ(MainThreadScrollingReason::kFailedHitTest, - status.main_thread_hit_test_reasons); + ASSERT_TRUE(status.needs_main_thread_hit_test); } else { ASSERT_EQ(ScrollThread::SCROLL_ON_MAIN_THREAD, status.thread); ASSERT_EQ(MainThreadScrollingReason::kFailedHitTest, @@ -2296,8 +2278,7 @@ EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread); EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain, status.main_thread_scrolling_reasons); - EXPECT_EQ(MainThreadScrollingReason::kFailedHitTest, - status.main_thread_hit_test_reasons); + EXPECT_TRUE(status.needs_main_thread_hit_test); } else { EXPECT_EQ(ScrollThread::SCROLL_ON_MAIN_THREAD, status.thread); EXPECT_EQ(MainThreadScrollingReason::kFailedHitTest, @@ -2358,8 +2339,7 @@ ASSERT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread); ASSERT_EQ(MainThreadScrollingReason::kNotScrollingOnMain, status.main_thread_scrolling_reasons); - ASSERT_EQ(MainThreadScrollingReason::kNonFastScrollableRegion, - status.main_thread_hit_test_reasons); + ASSERT_TRUE(status.needs_main_thread_hit_test); } else { ASSERT_EQ(ScrollThread::SCROLL_ON_MAIN_THREAD, status.thread); ASSERT_EQ(MainThreadScrollingReason::kNonFastScrollableRegion, @@ -2414,8 +2394,7 @@ EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread); EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain, status.main_thread_scrolling_reasons); - EXPECT_EQ(MainThreadScrollingReason::kNonFastScrollableRegion, - status.main_thread_hit_test_reasons); + EXPECT_TRUE(status.needs_main_thread_hit_test); } else { EXPECT_EQ(ScrollThread::SCROLL_ON_MAIN_THREAD, status.thread); EXPECT_EQ(MainThreadScrollingReason::kNonFastScrollableRegion, @@ -2508,8 +2487,7 @@ EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread); EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain, status.main_thread_scrolling_reasons); - EXPECT_EQ(MainThreadScrollingReason::kFailedHitTest, - status.main_thread_hit_test_reasons); + EXPECT_TRUE(status.needs_main_thread_hit_test); } else { EXPECT_EQ(ScrollThread::SCROLL_ON_MAIN_THREAD, status.thread); EXPECT_EQ(MainThreadScrollingReason::kFailedHitTest, @@ -3400,8 +3378,7 @@ // We don't have a layer for the scroller but we didn't hit a non-fast // scrolling region or fail hit testing the layer - we don't need a main // thread hit test in this case. - EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain, - status.main_thread_hit_test_reasons); + EXPECT_FALSE(status.needs_main_thread_hit_test); } else { EXPECT_EQ(ScrollThread::SCROLL_ON_MAIN_THREAD, status.thread); EXPECT_EQ(MainThreadScrollingReason::kNoScrollingLayer, @@ -8288,15 +8265,10 @@ ui::ScrollInputType::kWheel); if (base::FeatureList::IsEnabled(features::kScrollUnification)) { EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread); - EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain, - status.main_thread_scrolling_reasons); - EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain, - status.main_thread_hit_test_reasons); + EXPECT_FALSE(status.needs_main_thread_hit_test); EXPECT_EQ( MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects, host_impl_->CurrentlyScrollingNode()->main_thread_scrolling_reasons); - EXPECT_EQ(MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects, - status.main_thread_repaint_reasons); } else { // Scrolling fails because the content layer is asking to be scrolled on the // main thread. @@ -11978,8 +11950,7 @@ ui::ScrollInputType::kWheel); if (base::FeatureList::IsEnabled(features::kScrollUnification)) { EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread); - EXPECT_EQ(MainThreadScrollingReason::kFailedHitTest, - status.main_thread_hit_test_reasons); + EXPECT_TRUE(status.needs_main_thread_hit_test); } else { EXPECT_EQ(ScrollThread::SCROLL_ON_MAIN_THREAD, status.thread); EXPECT_EQ(MainThreadScrollingReason::kFailedHitTest, @@ -12022,8 +11993,7 @@ ui::ScrollInputType::kWheel); if (base::FeatureList::IsEnabled(features::kScrollUnification)) { EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread); - EXPECT_EQ(MainThreadScrollingReason::kFailedHitTest, - status.main_thread_hit_test_reasons); + EXPECT_TRUE(status.needs_main_thread_hit_test); } else { EXPECT_EQ(ScrollThread::SCROLL_ON_MAIN_THREAD, status.thread); EXPECT_EQ(MainThreadScrollingReason::kFailedHitTest, @@ -17899,9 +17869,8 @@ ScrollStatus status = GetInputHandler().ScrollBegin( scroll_state.get(), ui::ScrollInputType::kWheel); - if (status.main_thread_hit_test_reasons) { + if (status.needs_main_thread_hit_test) to_be_continued_scroll_begin_ = std::move(scroll_state); - } return status; } @@ -17914,8 +17883,7 @@ std::move(to_be_continued_scroll_begin_); scroll_state->data()->set_current_native_scrolling_element(element_id); - scroll_state->data()->main_thread_hit_tested_reasons = - MainThreadScrollingReason::kFailedHitTest; + scroll_state->data()->is_main_thread_hit_tested = true; return GetInputHandler().ScrollBegin(scroll_state.get(), ui::ScrollInputType::kWheel); @@ -18009,8 +17977,7 @@ ScrollStatus status = ScrollBegin(gfx::Vector2d(0, 10)); EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread); - EXPECT_EQ(MainThreadScrollingReason::kNonFastScrollableRegion, - status.main_thread_hit_test_reasons); + EXPECT_TRUE(status.needs_main_thread_hit_test); // The scroll hasn't started yet though. EXPECT_FALSE(CurrentlyScrollingNode()); @@ -18023,8 +17990,7 @@ ScrollStatus status = ContinuedScrollBegin(ScrollerElementId()); EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread); - EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain, - status.main_thread_hit_test_reasons); + EXPECT_FALSE(status.needs_main_thread_hit_test); EXPECT_TRUE(CurrentlyScrollingNode()); EXPECT_EQ(ScrollerNode(), CurrentlyScrollingNode()); @@ -18069,8 +18035,7 @@ { ScrollStatus status = ScrollBegin(gfx::Vector2d(0, 10)); - ASSERT_EQ(MainThreadScrollingReason::kNonFastScrollableRegion, - status.main_thread_hit_test_reasons); + ASSERT_TRUE(status.needs_main_thread_hit_test); status = ContinuedScrollBegin(ScrollerElementId()); // Since the hit tested scroller in ContinuedScrollBegin was fully @@ -18144,8 +18109,7 @@ { ScrollStatus status = ScrollBegin(gfx::Vector2d(0, 10)); EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread); - EXPECT_EQ(MainThreadScrollingReason::kFailedHitTest, - status.main_thread_hit_test_reasons); + EXPECT_TRUE(status.needs_main_thread_hit_test); } // Resolving the hit test should allow the scroller underneath to scroll as @@ -18153,8 +18117,7 @@ { ScrollStatus status = ContinuedScrollBegin(ScrollerElementId()); EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread); - EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain, - status.main_thread_hit_test_reasons); + EXPECT_FALSE(status.needs_main_thread_hit_test); EXPECT_TRUE(CurrentlyScrollingNode()); EXPECT_EQ(ScrollerNode(), CurrentlyScrollingNode()); @@ -18171,8 +18134,7 @@ { ScrollStatus status = ScrollBegin(gfx::Vector2d(0, 10)); EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread); - EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain, - status.main_thread_hit_test_reasons); + EXPECT_FALSE(status.needs_main_thread_hit_test); } } @@ -18199,9 +18161,8 @@ // test parameter. { ScrollStatus status = ScrollBegin(gfx::Vector2d(0, 10)); - if (status.main_thread_hit_test_reasons) { + if (status.needs_main_thread_hit_test) ContinuedScrollBegin(ScrollerElementId()); - } ASSERT_EQ(ScrollerNode(), CurrentlyScrollingNode());
diff --git a/cc/trees/layer_tree_host_unittest_scroll.cc b/cc/trees/layer_tree_host_unittest_scroll.cc index dd5adcd..c9d0e87 100644 --- a/cc/trees/layer_tree_host_unittest_scroll.cc +++ b/cc/trees/layer_tree_host_unittest_scroll.cc
@@ -1613,8 +1613,7 @@ ui::ScrollInputType::kTouchscreen); if (base::FeatureList::IsEnabled(features::kScrollUnification)) { EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread); - EXPECT_EQ(MainThreadScrollingReason::kNonFastScrollableRegion, - status.main_thread_hit_test_reasons); + EXPECT_TRUE(status.needs_main_thread_hit_test); impl->GetInputHandler().ScrollEnd(); } else { EXPECT_EQ(ScrollThread::SCROLL_ON_MAIN_THREAD, status.thread); @@ -1626,8 +1625,7 @@ BeginState(gfx::Point(21, 21), gfx::Vector2dF(0, 1)).get(), ui::ScrollInputType::kTouchscreen); EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread); - EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain, - status.main_thread_hit_test_reasons); + EXPECT_FALSE(status.needs_main_thread_hit_test); EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain, status.main_thread_scrolling_reasons); @@ -1689,9 +1687,7 @@ &scroll_state, ui::ScrollInputType::kTouchscreen); if (base::FeatureList::IsEnabled(features::kScrollUnification)) { EXPECT_EQ(impl->CurrentlyScrollingNode(), scroller_scroll_node); - EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain, - status.main_thread_hit_test_reasons); - ; + EXPECT_FALSE(status.needs_main_thread_hit_test); } else { // Despite the fact that we hit the scroller, which has no main thread // scrolling reason, we still must fallback to main thread scrolling due @@ -1714,9 +1710,7 @@ &scroll_state, ui::ScrollInputType::kTouchscreen); if (base::FeatureList::IsEnabled(features::kScrollUnification)) { EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread); - EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain, - status.main_thread_hit_test_reasons); - ; + EXPECT_FALSE(status.needs_main_thread_hit_test); EXPECT_EQ(impl->CurrentlyScrollingNode(), impl->OuterViewportScrollNode()); } else { @@ -2821,9 +2815,7 @@ // Hitting a non fast region should request a hit test from the main // thread. EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread); - EXPECT_EQ(MainThreadScrollingReason::kNonFastScrollableRegion, - status.main_thread_hit_test_reasons); - ; + EXPECT_TRUE(status.needs_main_thread_hit_test); impl->GetInputHandler().ScrollEnd(); } else { // Prior to scroll unification, this forces scrolling to the main @@ -2842,9 +2834,7 @@ ui::ScrollInputType::kTouchscreen); if (base::FeatureList::IsEnabled(features::kScrollUnification)) { EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread); - EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain, - status.main_thread_hit_test_reasons); - ; + EXPECT_FALSE(status.needs_main_thread_hit_test); } else { EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread); EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain, @@ -2864,9 +2854,7 @@ // layer is scrollable from the compositor thread so no need to involve // the main thread. EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread); - EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain, - status.main_thread_hit_test_reasons); - ; + EXPECT_FALSE(status.needs_main_thread_hit_test); EXPECT_EQ(scroll_node, impl->CurrentlyScrollingNode()); impl->GetInputHandler().ScrollEnd(); } else {
diff --git a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinator.java b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinator.java index 55715f332..a5a0f29 100644 --- a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinator.java +++ b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinator.java
@@ -23,7 +23,6 @@ import org.chromium.base.Log; import org.chromium.base.MathUtils; import org.chromium.base.ObserverList; -import org.chromium.base.jank_tracker.JankTracker; import org.chromium.base.library_loader.LibraryLoader; import org.chromium.base.metrics.RecordHistogram; import org.chromium.base.supplier.ObservableSupplier; @@ -262,7 +261,6 @@ * @param tabCreatorManager Manages {@link Tab} creation. * @param menuOrKeyboardActionController allows access to menu or keyboard actions. * @param multiWindowModeStateDispatcher Gives access to the multi window mode state. - * @param jankTracker Measures jank while feed or tab switcher are visible. * @param toolbarSupplier Supplies the {@link Toolbar}. * @param backPressManager {@link BackPressManager} to handle back press. * @param incognitoReauthControllerSupplier {@link OneshotSupplier<IncognitoReauthController>} @@ -288,8 +286,7 @@ @NonNull TabCreatorManager tabCreatorManager, @NonNull MenuOrKeyboardActionController menuOrKeyboardActionController, @NonNull MultiWindowModeStateDispatcher multiWindowModeStateDispatcher, - @NonNull JankTracker jankTracker, @NonNull Supplier<Toolbar> toolbarSupplier, - BackPressManager backPressManager, + @NonNull Supplier<Toolbar> toolbarSupplier, BackPressManager backPressManager, @NonNull OneshotSupplier<IncognitoReauthController> incognitoReauthControllerSupplier, @NonNull OnClickListener tabSwitcherClickHandler) { mConstructedTimeNs = SystemClock.elapsedRealtimeNanos(); @@ -361,7 +358,7 @@ mTasksSurface != null ? this::initializeSecondaryTasksSurface : null, mIsStartSurfaceEnabled, mActivity, mBrowserControlsManager, this::isActivityFinishingOrDestroyed, excludeQueryTiles, - startSurfaceOneshotSupplier, hadWarmStart, jankTracker, initializeMVTilesRunnable, + startSurfaceOneshotSupplier, hadWarmStart, initializeMVTilesRunnable, mParentTabSupplier, logoContainerView, mGridTabSwitcher == null ? backPressManager : null, feedPlaceholderParentView, mActivityLifecycleDispatcher, tabSwitcherClickHandler);
diff --git a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceDelegate.java b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceDelegate.java index 7a725a57..19c275b 100644 --- a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceDelegate.java +++ b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceDelegate.java
@@ -11,7 +11,6 @@ import androidx.annotation.NonNull; -import org.chromium.base.jank_tracker.JankTracker; import org.chromium.base.supplier.OneshotSupplier; import org.chromium.base.supplier.OneshotSupplierImpl; import org.chromium.base.supplier.Supplier; @@ -67,10 +66,9 @@ */ public static Layout createTabSwitcherAndStartSurfaceLayout(Context context, LayoutUpdateHost updateHost, LayoutRenderHost renderHost, StartSurface startSurface, - JankTracker jankTracker, ViewGroup tabSwitcherScrimAnchor, - ScrimCoordinator scrimCoordinator) { + ViewGroup tabSwitcherScrimAnchor, ScrimCoordinator scrimCoordinator) { return new TabSwitcherAndStartSurfaceLayout(context, updateHost, renderHost, startSurface, - jankTracker, tabSwitcherScrimAnchor, scrimCoordinator); + tabSwitcherScrimAnchor, scrimCoordinator); } /** @@ -100,7 +98,6 @@ * @param tabCreatorManager Manages creation of tabs. * @param menuOrKeyboardActionController allows access to menu or keyboard actions. * @param multiWindowModeStateDispatcher Gives access to the multi window mode state. - * @param jankTracker Measures jank while tab switcher is visible. * @param toolbarSupplier Supplies the {@link Toolbar}. * @param backPressManager {@link BackPressManager} to handle back press gesture. * @param incognitoReauthControllerSupplier {@link OneshotSupplier<IncognitoReauthController>} @@ -127,8 +124,7 @@ @NonNull TabCreatorManager tabCreatorManager, @NonNull MenuOrKeyboardActionController menuOrKeyboardActionController, @NonNull MultiWindowModeStateDispatcher multiWindowModeStateDispatcher, - @NonNull JankTracker jankTracker, @NonNull Supplier<Toolbar> toolbarSupplier, - BackPressManager backPressManager, + @NonNull Supplier<Toolbar> toolbarSupplier, BackPressManager backPressManager, @NonNull OneshotSupplier<IncognitoReauthController> incognitoReauthControllerSupplier, @NonNull OnClickListener tabSwitcherClickHandler) { return new StartSurfaceCoordinator(activity, scrimCoordinator, sheetController, @@ -137,7 +133,7 @@ browserControlsManager, snackbarManager, shareDelegateSupplier, omniboxStubSupplier, tabContentManager, modalDialogManager, chromeActivityNativeDelegate, activityLifecycleDispatcher, tabCreatorManager, menuOrKeyboardActionController, - multiWindowModeStateDispatcher, jankTracker, toolbarSupplier, backPressManager, + multiWindowModeStateDispatcher, toolbarSupplier, backPressManager, incognitoReauthControllerSupplier, tabSwitcherClickHandler); } }
diff --git a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceMediator.java b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceMediator.java index d930981a..f8f2820 100644 --- a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceMediator.java +++ b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceMediator.java
@@ -50,8 +50,6 @@ import org.chromium.base.CallbackController; import org.chromium.base.ObserverList; import org.chromium.base.ThreadUtils; -import org.chromium.base.jank_tracker.JankScenario; -import org.chromium.base.jank_tracker.JankTracker; import org.chromium.base.metrics.RecordHistogram; import org.chromium.base.metrics.RecordUserAction; import org.chromium.base.supplier.ObservableSupplier; @@ -138,7 +136,6 @@ private final boolean mExcludeQueryTiles; private final Runnable mInitializeMVTilesRunnable; private final Supplier<Tab> mParentTabSupplier; - private final JankTracker mJankTracker; private final ObservableSupplierImpl<Boolean> mBackPressChangedSupplier = new ObservableSupplierImpl<>(); private final CallbackController mCallbackController = new CallbackController(); @@ -232,9 +229,9 @@ BrowserControlsStateProvider browserControlsStateProvider, ActivityStateChecker activityStateChecker, boolean excludeQueryTiles, OneshotSupplier<StartSurface> startSurfaceSupplier, boolean hadWarmStart, - JankTracker jankTracker, Runnable initializeMVTilesRunnable, - Supplier<Tab> parentTabSupplier, View logoContainerView, - @Nullable BackPressManager backPressManager, ViewGroup feedPlaceholderParentView, + Runnable initializeMVTilesRunnable, Supplier<Tab> parentTabSupplier, + View logoContainerView, @Nullable BackPressManager backPressManager, + ViewGroup feedPlaceholderParentView, ActivityLifecycleDispatcher activityLifecycleDispatcher, OnClickListener tabSwitcherClickHandler) { mTabSwitcherContainer = tabSwitcherContainer; @@ -251,7 +248,6 @@ mExcludeQueryTiles = excludeQueryTiles; mStartSurfaceSupplier = startSurfaceSupplier; mHadWarmStart = hadWarmStart; - mJankTracker = jankTracker; mLaunchOrigin = NewTabPageLaunchOrigin.UNKNOWN; mInitializeMVTilesRunnable = initializeMVTilesRunnable; mParentTabSupplier = parentTabSupplier; @@ -615,9 +611,6 @@ // This should only be called for single or carousel tab switcher. mController.showTabSwitcherView(animate); - // TODO(crbug.com/1315676): Record - // mJankTracker.finishTrackingScenario(START_SURFACE_HOMEPAGE) when layout changes, maybe in - // LayoutManager. RecordUserAction.record("StartSurface.Shown"); RecordUserAction.record("StartSurface.SinglePane.Home"); mayRecordHomepageSessionBegin(); @@ -678,23 +671,6 @@ } notifyStateChange(); - // Start/Stop tracking jank for Homepage and Tab switcher. It is okay if finish or start are - // called multiple times consecutively. - switch (mStartSurfaceState) { - case StartSurfaceState.NOT_SHOWN: - mJankTracker.finishTrackingScenario(JankScenario.START_SURFACE_HOMEPAGE); - mJankTracker.finishTrackingScenario(JankScenario.START_SURFACE_TAB_SWITCHER); - break; - case StartSurfaceState.SHOWN_HOMEPAGE: - mJankTracker.startTrackingScenario(JankScenario.START_SURFACE_HOMEPAGE); - mJankTracker.finishTrackingScenario(JankScenario.START_SURFACE_TAB_SWITCHER); - break; - case StartSurfaceState.SHOWN_TABSWITCHER: - mJankTracker.finishTrackingScenario(JankScenario.START_SURFACE_HOMEPAGE); - mJankTracker.startTrackingScenario(JankScenario.START_SURFACE_TAB_SWITCHER); - break; - } - setLaunchOrigin(launchOrigin); // Metrics collection if (mStartSurfaceState == StartSurfaceState.SHOWN_HOMEPAGE) {
diff --git a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/TabSwitcherAndStartSurfaceLayout.java b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/TabSwitcherAndStartSurfaceLayout.java index fc24112..e1af1ad 100644 --- a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/TabSwitcherAndStartSurfaceLayout.java +++ b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/TabSwitcherAndStartSurfaceLayout.java
@@ -21,8 +21,6 @@ import org.chromium.base.Log; import org.chromium.base.TraceEvent; -import org.chromium.base.jank_tracker.JankScenario; -import org.chromium.base.jank_tracker.JankTracker; import org.chromium.base.metrics.RecordHistogram; import org.chromium.base.metrics.RecordUserAction; import org.chromium.base.supplier.Supplier; @@ -90,7 +88,6 @@ private TabListSceneLayer mSceneLayer; private final StartSurface mStartSurface; - private final JankTracker mJankTracker; private final TabSwitcherViewObserver mTabSwitcherObserver; @Nullable private final ViewGroup mScrimAnchor; @@ -127,14 +124,13 @@ private PerfListener mPerfListenerForTesting; public TabSwitcherAndStartSurfaceLayout(Context context, LayoutUpdateHost updateHost, - LayoutRenderHost renderHost, StartSurface startSurface, JankTracker jankTracker, + LayoutRenderHost renderHost, StartSurface startSurface, ViewGroup tabSwitcherScrimAnchor, ScrimCoordinator scrimCoordinator) { super(context, updateHost, renderHost); mDummyLayoutTab = createLayoutTab(Tab.INVALID_TAB_ID, false); mDummyLayoutTab.setShowToolbar(true); mStartSurface = startSurface; mStartSurface.setOnTabSelectingListener(this::onTabSelecting); - mJankTracker = jankTracker; mScrimAnchor = tabSwitcherScrimAnchor; mScrimCoordinator = scrimCoordinator; @@ -249,13 +245,6 @@ private void show(long time, boolean animate, boolean isShowingStartSurfaceHomepage) { super.show(time, animate); - // When shown on StartSurface jank is tracked under - // JankScenario.START_SURFACE_TAB_SWITCHER and it's started/stopped on - // StartSurfaceMediator. - if (!StartSurfaceConfiguration.isStartSurfaceFlagEnabled()) { - mJankTracker.startTrackingScenario(JankScenario.TAB_SWITCHER); - } - // Lazy initialization if needed. mStartSurface.initialize(); @@ -414,12 +403,6 @@ try (TraceEvent e = TraceEvent.scoped("StartSurfaceLayout.DoneHiding")) { super.doneHiding(); RecordUserAction.record("MobileExitStackView"); - // When shown on StartSurface jank is tracked under - // JankScenario.START_SURFACE_TAB_SWITCHER and it's started/stopped on - // StartSurfaceMediator. - if (!StartSurfaceConfiguration.isStartSurfaceFlagEnabled()) { - mJankTracker.finishTrackingScenario(JankScenario.TAB_SWITCHER); - } } }
diff --git a/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/InstantStartFeedTest.java b/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/InstantStartFeedTest.java index 0f1be1c..ddf4aca2 100644 --- a/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/InstantStartFeedTest.java +++ b/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/InstantStartFeedTest.java
@@ -34,12 +34,9 @@ import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; -import org.chromium.base.jank_tracker.JankMetricUMARecorder; -import org.chromium.base.jank_tracker.JankMetricUMARecorderJni; import org.chromium.base.library_loader.LibraryLoader; import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.CriteriaHelper; @@ -86,12 +83,8 @@ @Rule public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule(); - @Mock - JankMetricUMARecorder.Natives mJankRecorderNativeMock; - @Before public void setUp() { - mJniMocker.mock(JankMetricUMARecorderJni.TEST_HOOKS, mJankRecorderNativeMock); ReturnToChromeUtil.setSkipInitializationCheckForTesting(true); }
diff --git a/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/InstantStartTabSwitcherTest.java b/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/InstantStartTabSwitcherTest.java index 446049e..fa50f1c 100644 --- a/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/InstantStartTabSwitcherTest.java +++ b/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/InstantStartTabSwitcherTest.java
@@ -46,13 +46,10 @@ import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; import org.chromium.base.MathUtils; -import org.chromium.base.jank_tracker.JankMetricUMARecorder; -import org.chromium.base.jank_tracker.JankMetricUMARecorderJni; import org.chromium.base.metrics.RecordHistogram; import org.chromium.base.test.params.ParameterAnnotations; import org.chromium.base.test.params.ParameterAnnotations.UseMethodParameter; @@ -130,9 +127,6 @@ @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule(); - @Mock - JankMetricUMARecorder.Natives mJankRecorderNativeMock; - /** * {@link ParameterProvider} used for parameterized test that provides whether it's single tab * switcher or carousel tab switcher and whether last visited tab is a search result page. @@ -152,7 +146,6 @@ @Before public void setUp() { - mJniMocker.mock(JankMetricUMARecorderJni.TEST_HOOKS, mJankRecorderNativeMock); ReturnToChromeUtil.setSkipInitializationCheckForTesting(true); }
diff --git a/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/InstantStartTest.java b/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/InstantStartTest.java index 1409828..0b30ba54 100644 --- a/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/InstantStartTest.java +++ b/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/InstantStartTest.java
@@ -34,7 +34,6 @@ import org.junit.Test; import org.junit.rules.ErrorCollector; import org.junit.runner.RunWith; -import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; @@ -42,8 +41,6 @@ import org.chromium.base.Callback; import org.chromium.base.NativeLibraryLoadedStatus; import org.chromium.base.SysUtils; -import org.chromium.base.jank_tracker.JankMetricUMARecorder; -import org.chromium.base.jank_tracker.JankMetricUMARecorderJni; import org.chromium.base.library_loader.LibraryLoader; import org.chromium.base.metrics.RecordHistogram; import org.chromium.base.test.util.CommandLineFlags; @@ -134,12 +131,8 @@ @Rule public SuggestionsDependenciesRule mSuggestionsDeps = new SuggestionsDependenciesRule(); - @Mock - JankMetricUMARecorder.Natives mJankRecorderNativeMock; - @Before public void setUp() { - mJniMocker.mock(JankMetricUMARecorderJni.TEST_HOOKS, mJankRecorderNativeMock); ReturnToChromeUtil.setSkipInitializationCheckForTesting(true); }
diff --git a/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinatorUnitTestRule.java b/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinatorUnitTestRule.java index a92c779..f696431 100644 --- a/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinatorUnitTestRule.java +++ b/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinatorUnitTestRule.java
@@ -26,7 +26,6 @@ import org.chromium.base.ApplicationStatus; import org.chromium.base.FeatureList; import org.chromium.base.FeatureListJni; -import org.chromium.base.jank_tracker.DummyJankTracker; import org.chromium.base.library_loader.LibraryLoader; import org.chromium.base.supplier.ObservableSupplierImpl; import org.chromium.base.supplier.OneshotSupplierImpl; @@ -272,9 +271,8 @@ Mockito.mock(ChromeActivityNativeDelegate.class), new ActivityLifecycleDispatcherImpl(mActivity), new MockTabCreatorManager(), Mockito.mock(MenuOrKeyboardActionController.class), - new MultiWindowModeStateDispatcherImpl(mActivity), new DummyJankTracker(), - new ObservableSupplierImpl<>(), new BackPressManager(), - mIncognitoReauthControllerSupplier, null); + new MultiWindowModeStateDispatcherImpl(mActivity), new ObservableSupplierImpl<>(), + new BackPressManager(), mIncognitoReauthControllerSupplier, null); Assert.assertFalse(LibraryLoader.getInstance().isLoaded()); when(mLibraryLoader.isInitialized()).thenReturn(true);
diff --git a/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/StartSurfaceMediatorUnitTest.java b/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/StartSurfaceMediatorUnitTest.java index 0a3a3de0..acd3b49 100644 --- a/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/StartSurfaceMediatorUnitTest.java +++ b/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/StartSurfaceMediatorUnitTest.java
@@ -74,7 +74,6 @@ import org.robolectric.annotation.Config; import org.chromium.base.ContextUtils; -import org.chromium.base.jank_tracker.DummyJankTracker; import org.chromium.base.supplier.ObservableSupplierImpl; import org.chromium.base.supplier.OneshotSupplier; import org.chromium.base.supplier.Supplier; @@ -1864,7 +1863,7 @@ hasTasksView ? mSecondaryTasksSurfaceInitializer : null, isStartSurfaceEnabled, ContextUtils.getApplicationContext(), mBrowserControlsStateProvider, mActivityStateChecker, true /* excludeQueryTiles */, mStartSurfaceSupplier, - hadWarmStart, new DummyJankTracker(), + hadWarmStart, hasTasksView || hasTabSwitcherModule ? mInitializeMVTilesRunnable : null, mParentTabSupplier, mLogoContainerView, mBackPressManager, null /* feedPlaceholderParentView */, mActivityLifecycleDispatcher,
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabManagementDelegate.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabManagementDelegate.java index dfa354a..ff41c320 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabManagementDelegate.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabManagementDelegate.java
@@ -12,7 +12,6 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import org.chromium.base.jank_tracker.JankTracker; import org.chromium.base.supplier.ObservableSupplier; import org.chromium.base.supplier.OneshotSupplier; import org.chromium.base.supplier.Supplier; @@ -68,8 +67,8 @@ * @return The {@link TabSwitcherLayout}. */ Layout createTabSwitcherLayout(Context context, LayoutUpdateHost updateHost, - LayoutRenderHost renderHost, TabSwitcher tabSwitcher, JankTracker jankTracker, - ViewGroup tabSwitcherScrimAnchor, ScrimCoordinator scrimCoordinator); + LayoutRenderHost renderHost, TabSwitcher tabSwitcher, ViewGroup tabSwitcherScrimAnchor, + ScrimCoordinator scrimCoordinator); /** * Create the {@link TabSwitcher} to display Tabs in grid.
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabManagementDelegateImpl.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabManagementDelegateImpl.java index 77f8f18..7e3c3763 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabManagementDelegateImpl.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabManagementDelegateImpl.java
@@ -11,7 +11,6 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import org.chromium.base.jank_tracker.JankTracker; import org.chromium.base.supplier.ObservableSupplier; import org.chromium.base.supplier.OneshotSupplier; import org.chromium.base.supplier.Supplier; @@ -45,9 +44,9 @@ public class TabManagementDelegateImpl implements TabManagementDelegate { @Override public Layout createTabSwitcherLayout(Context context, LayoutUpdateHost updateHost, - LayoutRenderHost renderHost, TabSwitcher tabSwitcher, JankTracker jankTracker, - ViewGroup tabSwitcherScrimAnchor, ScrimCoordinator scrimCoordinator) { - return new TabSwitcherLayout(context, updateHost, renderHost, tabSwitcher, jankTracker, + LayoutRenderHost renderHost, TabSwitcher tabSwitcher, ViewGroup tabSwitcherScrimAnchor, + ScrimCoordinator scrimCoordinator) { + return new TabSwitcherLayout(context, updateHost, renderHost, tabSwitcher, tabSwitcherScrimAnchor, scrimCoordinator); }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherLayout.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherLayout.java index 5eff80bf..d0c8e90 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherLayout.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherLayout.java
@@ -21,8 +21,6 @@ import org.chromium.base.Log; import org.chromium.base.TraceEvent; -import org.chromium.base.jank_tracker.JankScenario; -import org.chromium.base.jank_tracker.JankTracker; import org.chromium.base.metrics.RecordHistogram; import org.chromium.base.metrics.RecordUserAction; import org.chromium.base.supplier.Supplier; @@ -86,7 +84,6 @@ private TabListSceneLayer mSceneLayer; private final TabSwitcher mTabSwitcher; - private final JankTracker mJankTracker; private final TabSwitcher.Controller mController; private final TabSwitcherViewObserver mTabSwitcherObserver; @Nullable @@ -118,7 +115,7 @@ private PerfListener mPerfListenerForTesting; public TabSwitcherLayout(Context context, LayoutUpdateHost updateHost, - LayoutRenderHost renderHost, TabSwitcher tabSwitcher, JankTracker jankTracker, + LayoutRenderHost renderHost, TabSwitcher tabSwitcher, @Nullable ViewGroup tabSwitcherScrimAnchor, @Nullable ScrimCoordinator scrimCoordinator) { super(context, updateHost, renderHost); @@ -128,7 +125,6 @@ mController = mTabSwitcher.getController(); mTabSwitcher.setOnTabSelectingListener(this::onTabSelecting); mGridTabListDelegate = mTabSwitcher.getTabListDelegate(); - mJankTracker = jankTracker; mScrimAnchor = tabSwitcherScrimAnchor; mScrimCoordinator = scrimCoordinator; @@ -221,8 +217,6 @@ try (TraceEvent e = TraceEvent.scoped(TRACE_SHOW_TAB_SWITCHER)) { super.show(time, animate); - mJankTracker.startTrackingScenario(JankScenario.TAB_SWITCHER); - // Keep the current tab in mLayoutTabs even if we are not going to show the shrinking // animation so that thumbnail taking is not blocked. LayoutTab sourceLayoutTab = createLayoutTab( @@ -335,7 +329,6 @@ try (TraceEvent e = TraceEvent.scoped(TRACE_DONE_HIDING_TAB_SWITCHER)) { super.doneHiding(); RecordUserAction.record("MobileExitStackView"); - mJankTracker.finishTrackingScenario(JankScenario.TAB_SWITCHER); } }
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/PriceAlertsMessageCardTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/PriceAlertsMessageCardTest.java index 144a145..95d41bc2e 100644 --- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/PriceAlertsMessageCardTest.java +++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/PriceAlertsMessageCardTest.java
@@ -53,6 +53,7 @@ import org.chromium.base.test.util.MinAndroidSdkLevel; import org.chromium.base.test.util.Restriction; import org.chromium.chrome.browser.ChromeTabbedActivity; +import org.chromium.chrome.browser.commerce.ShoppingFeatures; import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.flags.ChromeSwitches; import org.chromium.chrome.browser.price_tracking.PriceDropNotificationManager; @@ -84,7 +85,7 @@ public class PriceAlertsMessageCardTest { // clang-format on private static final String BASE_PARAMS = - "force-fieldtrial-params=Study.Group:enable_price_notification/true" + "force-fieldtrial-params=Study.Group:enable_price_tracking/true" + "/implicit_subscriptions_enabled/true"; private static final String ACTION_APP_NOTIFICATION_SETTINGS = "android.settings.APP_NOTIFICATION_SETTINGS"; @@ -110,6 +111,7 @@ mMockNotificationManager = new MockNotificationManagerProxy(); PriceDropNotificationManagerImpl.setNotificationManagerForTesting(mMockNotificationManager); mPriceDropNotificationManager = PriceDropNotificationManagerFactory.create(); + ShoppingFeatures.setShoppingListEligibleForTesting(true); mActivityTestRule.startMainActivityOnBlankPage(); CriteriaHelper.pollUiThread( @@ -123,6 +125,7 @@ } PriceTrackingFeatures.setIsSignedInAndSyncEnabledForTesting(null); PriceDropNotificationManagerImpl.setNotificationManagerForTesting(null); + ShoppingFeatures.setShoppingListEligibleForTesting(null); ActivityTestUtils.clearActivityOrientation(mActivityTestRule.getActivity()); Intents.release(); } @@ -132,7 +135,6 @@ @CommandLineFlags.Add({BASE_PARAMS}) public void testMessageCardShowing() { final ChromeTabbedActivity cta = mActivityTestRule.getActivity(); - assertTrue(PriceTrackingFeatures.isPriceDropNotificationEligible()); assertTrue(PriceTrackingUtilities.isPriceAlertsMessageCardEnabled()); enterTabSwitcher(cta); @@ -145,7 +147,6 @@ @CommandLineFlags.Add({BASE_PARAMS}) public void testMessageCardNotShowing_MessageDisabled() { final ChromeTabbedActivity cta = mActivityTestRule.getActivity(); - assertTrue(PriceTrackingFeatures.isPriceDropNotificationEligible()); PriceTrackingUtilities.disablePriceAlertsMessageCard(); assertFalse(PriceTrackingUtilities.isPriceAlertsMessageCardEnabled()); @@ -158,7 +159,6 @@ @CommandLineFlags.Add({BASE_PARAMS}) public void testMessageCardNotShowing_InIncognito() { final ChromeTabbedActivity cta = mActivityTestRule.getActivity(); - assertTrue(PriceTrackingFeatures.isPriceDropNotificationEligible()); assertTrue(PriceTrackingUtilities.isPriceAlertsMessageCardEnabled()); createTabs(cta, true, 1); @@ -169,26 +169,11 @@ @Test @MediumTest - @CommandLineFlags.Add({"force-fieldtrial-params=Study.Group:enable_price_notification/false" - + "/implicit_subscriptions_enabled/true"}) - public void - testMessageCardNotShowing_NotificationParameterDisabled() { - final ChromeTabbedActivity cta = mActivityTestRule.getActivity(); - assertFalse(PriceTrackingFeatures.isPriceDropNotificationEligible()); - assertFalse(PriceTrackingUtilities.isPriceAlertsMessageCardEnabled()); - - enterTabSwitcher(cta); - onView(withId(R.id.large_message_card_item)).check(doesNotExist()); - } - - @Test - @MediumTest - @CommandLineFlags.Add({"force-fieldtrial-params=Study.Group:enable_price_notification/true" + @CommandLineFlags.Add({"force-fieldtrial-params=Study.Group:enable_price_tracking/true" + "/implicit_subscriptions_enabled/false"}) public void testMessageCardNotShowing_ImplicitSubscriptionsParameterDisabled() { final ChromeTabbedActivity cta = mActivityTestRule.getActivity(); - assertTrue(PriceTrackingFeatures.isPriceDropNotificationEligible()); assertFalse(PriceTrackingUtilities.isPriceAlertsMessageCardEnabled()); enterTabSwitcher(cta);
diff --git a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/PriceMessageServiceUnitTest.java b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/PriceMessageServiceUnitTest.java index 792fdac..276ef84 100644 --- a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/PriceMessageServiceUnitTest.java +++ b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/PriceMessageServiceUnitTest.java
@@ -82,7 +82,7 @@ FeatureList.TestValues testValues = new FeatureList.TestValues(); testValues.addFeatureFlagOverride(ChromeFeatureList.COMMERCE_PRICE_TRACKING, true); testValues.addFieldTrialParamOverride(ChromeFeatureList.COMMERCE_PRICE_TRACKING, - PriceTrackingFeatures.PRICE_NOTIFICATION_PARAM, "true"); + PriceTrackingFeatures.PRICE_TRACKING_PARAM, "true"); testValues.addFieldTrialParamOverride(ChromeFeatureList.COMMERCE_PRICE_TRACKING, CommerceSubscriptionsServiceConfig.IMPLICIT_SUBSCRIPTIONS_ENABLED_PARAM, "true"); FeatureList.setTestValues(testValues);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java index d92bb3f..7fff9253 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -43,7 +43,6 @@ import org.chromium.base.MemoryPressureListener; import org.chromium.base.ThreadUtils; import org.chromium.base.TraceEvent; -import org.chromium.base.jank_tracker.JankTrackerImpl; import org.chromium.base.library_loader.LibraryLoader; import org.chromium.base.metrics.RecordHistogram; import org.chromium.base.metrics.RecordUserAction; @@ -329,10 +328,6 @@ // This is the cached value of mIntentHandler#shouldIgnoreIntent and shouldn't be read directly. // Use #shouldIgnoreIntent instead. private Boolean mShouldIgnoreIntent; - /* - * Listens to FrameMetrics and records jank metrics. - */ - private JankTrackerImpl mJankTracker; // Supplier for a dependency to inform about the type of intent used to launch Chrome. private OneshotSupplierImpl<ToolbarIntentMetadata> mIntentMetadataOneshotSupplier = @@ -687,7 +682,7 @@ // clang-format off mLayoutManager = new LayoutManagerChromePhone(compositorViewHolder, mContentContainer, mStartSurfaceSupplier, mTabSwitcherSupplier, getTabContentManagerSupplier(), - mRootUiCoordinator::getTopUiThemeColorProvider, mJankTracker); + mRootUiCoordinator::getTopUiThemeColorProvider); mLayoutStateProviderSupplier.set(mLayoutManager); // clang-format on } @@ -704,8 +699,8 @@ ViewGroup tabSwitcherViewHolder = findViewById(R.id.tab_switcher_view_holder); mLayoutManager = new LayoutManagerChromeTablet(compositorViewHolder, mContentContainer, mStartSurfaceSupplier, mTabSwitcherSupplier, getTabContentManagerSupplier(), - mRootUiCoordinator::getTopUiThemeColorProvider, mJankTracker, - tabSwitcherViewHolder, mRootUiCoordinator.getScrimCoordinator(), + mRootUiCoordinator::getTopUiThemeColorProvider, tabSwitcherViewHolder, + mRootUiCoordinator.getScrimCoordinator(), getLifecycleDispatcher(), () -> createAndSetStartSurfaceForTablet()); mLayoutStateProviderSupplier.set(mLayoutManager); // clang-format on @@ -737,7 +732,7 @@ getTabContentManager(), getModalDialogManager(), /* chromeActivityNativeDelegate= */ this, getLifecycleDispatcher(), getTabCreatorManagerSupplier().get(), getMenuOrKeyboardActionController(), - getMultiWindowModeStateDispatcher(), mJankTracker, getToolbarManager()::getToolbar, + getMultiWindowModeStateDispatcher(), getToolbarManager()::getToolbar, mBackPressManager, mRootUiCoordinator.getIncognitoReauthControllerSupplier(), v -> onTabSwitcherClicked()); } @@ -1710,11 +1705,6 @@ @Override public void performPreInflationStartup() { - // Create JankTracker before invoking super, because the parent class will invoke - // createRootUiCoordinator(...), which in our case requires the JankTracker to already have - // been created. - mJankTracker = new JankTrackerImpl(this); - super.performPreInflationStartup(); // Decide whether to record startup UMA histograms. This is done early in the main @@ -1743,8 +1733,8 @@ getContextualSearchManagerSupplier(), getTabModelSelectorSupplier(), mStartSurfaceSupplier, mTabSwitcherSupplier, mIntentMetadataOneshotSupplier, mLayoutStateProviderSupplier, mStartSurfaceParentTabSupplier, - getBrowserControlsManager(), getWindowAndroid(), mJankTracker, - getLifecycleDispatcher(), getLayoutManagerSupplier(), + getBrowserControlsManager(), getWindowAndroid(), getLifecycleDispatcher(), + getLayoutManagerSupplier(), /* menuOrKeyboardActionController= */ this, this::getActivityThemeColor, getModalDialogManagerSupplier(), /* appMenuBlocker= */ this, this::supportsAppMenu, this::supportsFindInPage, @@ -2002,7 +1992,7 @@ getCompositorViewHolderSupplier(), getModalDialogManagerSupplier(), this::getSnackbarManager, getBrowserControlsManager(), getActivityTabProvider(), getLifecycleDispatcher(), getWindowAndroid(), this::getLastUserInteractionTime, - this::hadWarmStart, mJankTracker, getToolbarManager()::getToolbar); + this::hadWarmStart, getToolbarManager()::getToolbar); } return mTabDelegateFactory; } @@ -2743,11 +2733,6 @@ mStartupPaintPreviewHelperSupplier.destroy(); } - if (mJankTracker != null) { - mJankTracker.destroy(); - mJankTracker = null; - } - IncognitoTabHostRegistry.getInstance().unregister(mIncognitoTabHost); TabObscuringHandler tabObscuringHandler = getTabObscuringHandler();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/TabbedModeTabDelegateFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/TabbedModeTabDelegateFactory.java index 3c41fe11..dcee1f4d 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/TabbedModeTabDelegateFactory.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/TabbedModeTabDelegateFactory.java
@@ -6,7 +6,6 @@ import android.app.Activity; -import org.chromium.base.jank_tracker.JankTracker; import org.chromium.base.supplier.Supplier; import org.chromium.chrome.browser.app.tab_activity_glue.ActivityTabWebContentsDelegateAndroid; import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider; @@ -68,7 +67,6 @@ private final WindowAndroid mWindowAndroid; private final Supplier<Long> mLastUserInteractionTimeSupplier; private final BooleanSupplier mHadWarmStartSupplier; - private final JankTracker mJankTracker; private final Supplier<Toolbar> mToolbarSupplier; private NativePageFactory mNativePageFactory; @@ -88,7 +86,7 @@ BrowserControlsManager browserControlsManager, Supplier<Tab> currentTabSupplier, ActivityLifecycleDispatcher lifecycleDispatcher, WindowAndroid windowAndroid, Supplier<Long> lastUserInteractionTimeSupplier, BooleanSupplier hadWarmStartSupplier, - JankTracker jankTracker, Supplier<Toolbar> toolbarSupplier) { + Supplier<Toolbar> toolbarSupplier) { mActivity = activity; mAppBrowserControlsVisibilityDelegate = appBrowserControlsVisibilityDelegate; mShareDelegateSupplier = shareDelegateSupplier; @@ -110,7 +108,6 @@ mWindowAndroid = windowAndroid; mLastUserInteractionTimeSupplier = lastUserInteractionTimeSupplier; mHadWarmStartSupplier = hadWarmStartSupplier; - mJankTracker = jankTracker; mToolbarSupplier = toolbarSupplier; } @@ -152,7 +149,7 @@ mBrowserControlsManager, mCurrentTabSupplier, mSnackbarManagerSupplier, mLifecycleDispatcher, mTabModelSelectorSupplier.get(), mShareDelegateSupplier, mWindowAndroid, mLastUserInteractionTimeSupplier, mHadWarmStartSupplier, - mJankTracker, mToolbarSupplier); + mToolbarSupplier); } return mNativePageFactory.createNativePage(url, candidatePage, tab); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java index 11fa3e6..bacd488 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java
@@ -47,7 +47,6 @@ import org.chromium.base.StrictModeContext; import org.chromium.base.SysUtils; import org.chromium.base.TraceEvent; -import org.chromium.base.jank_tracker.DummyJankTracker; import org.chromium.base.memory.MemoryPurgeManager; import org.chromium.base.metrics.RecordHistogram; import org.chromium.base.metrics.RecordUserAction; @@ -522,7 +521,7 @@ getTabModelSelectorSupplier(), new OneshotSupplierImpl<>(), new OneshotSupplierImpl<>(), new OneshotSupplierImpl<>(), new OneshotSupplierImpl<>(), () -> null, mBrowserControlsManagerSupplier.get(), - getWindowAndroid(), new DummyJankTracker(), getLifecycleDispatcher(), + getWindowAndroid(), getLifecycleDispatcher(), getLayoutManagerSupplier(), /* menuOrKeyboardActionController= */ this, this::getActivityThemeColor, getModalDialogManagerSupplier(), /* appMenuBlocker= */ this, this::supportsAppMenu, this::supportsFindInPage,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChrome.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChrome.java index d0bd1a7..fe3aa2a 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChrome.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChrome.java
@@ -8,12 +8,10 @@ import android.view.MotionEvent; import android.view.ViewGroup; -import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import org.chromium.base.Callback; -import org.chromium.base.jank_tracker.JankTracker; import org.chromium.base.metrics.RecordUserAction; import org.chromium.base.supplier.ObservableSupplier; import org.chromium.base.supplier.Supplier; @@ -99,7 +97,6 @@ * otherwise will use the accessibility overview layout. * @param tabContentManagerSupplier Supplier of the {@link TabContentManager} instance. * @param topUiThemeColorProvider {@link ThemeColorProvider} for top UI. - * @param jankTracker Tracker for surface jank. * @param tabSwitcherScrimAnchor {@link ViewGroup} used by tab switcher layout to show scrim * when overview is visible. * @param scrimCoordinator {@link ScrimCoordinator} to show/hide scrim. @@ -107,7 +104,7 @@ public LayoutManagerChrome(LayoutManagerHost host, ViewGroup contentContainer, Supplier<StartSurface> startSurfaceSupplier, Supplier<TabSwitcher> tabSwitcherSupplier, ObservableSupplier<TabContentManager> tabContentManagerSupplier, - Supplier<TopUiThemeColorProvider> topUiThemeColorProvider, JankTracker jankTracker, + Supplier<TopUiThemeColorProvider> topUiThemeColorProvider, ViewGroup tabSwitcherScrimAnchor, ScrimCoordinator scrimCoordinator) { super(host, contentContainer, tabContentManagerSupplier, topUiThemeColorProvider); @@ -136,11 +133,11 @@ if (ReturnToChromeUtil.isStartSurfaceRefactorEnabled(context)) { if (startSurfaceSupplier.hasValue() || tabSwitcherSupplier.hasValue()) { createOverviewLayout(startSurfaceSupplier.get(), tabSwitcherSupplier.get(), - jankTracker, scrimCoordinator, tabSwitcherScrimAnchor); + scrimCoordinator, tabSwitcherScrimAnchor); } } else if (startSurfaceSupplier.hasValue()) { - createOverviewLayout(startSurfaceSupplier.get(), /*tabSwitcher=*/null, jankTracker, - scrimCoordinator, tabSwitcherScrimAnchor); + createOverviewLayout(startSurfaceSupplier.get(), /*tabSwitcher=*/null, scrimCoordinator, + tabSwitcherScrimAnchor); } } @@ -150,13 +147,12 @@ * is disabled. * @param tabSwitcher An interface to talk to the Grid Tab Switcher when Start surface refactor * is enabled. - * @param jankTracker Jank tracker. * @param scrimCoordinator scrim coordinator for GTS * @param tabSwitcherScrimAnchor scrim anchor view for GTS */ protected void createOverviewLayout(@Nullable StartSurface startSurface, - @Nullable TabSwitcher tabSwitcher, @NonNull JankTracker jankTracker, - ScrimCoordinator scrimCoordinator, ViewGroup tabSwitcherScrimAnchor) { + @Nullable TabSwitcher tabSwitcher, ScrimCoordinator scrimCoordinator, + ViewGroup tabSwitcherScrimAnchor) { assert mOverviewLayout == null && mTabSwitcherLayout == null && mStartSurfaceHomeLayout == null && TabUiFeatureUtilities.isGridTabSwitcherEnabled(mHost.getContext()); @@ -173,7 +169,7 @@ assert tabManagementDelegate != null; mTabSwitcherLayout = tabManagementDelegate.createTabSwitcherLayout(context, this, - renderHost, tabSwitcher, jankTracker, tabSwitcherScrimAnchor, scrimCoordinator); + renderHost, tabSwitcher, tabSwitcherScrimAnchor, scrimCoordinator); if (startSurface != null) { mStartSurfaceHomeLayout = StartSurfaceDelegate.createStartSurfaceHomeLayout( @@ -182,8 +178,7 @@ } else { assert startSurface != null; mOverviewLayout = StartSurfaceDelegate.createTabSwitcherAndStartSurfaceLayout(context, - this, renderHost, startSurface, jankTracker, tabSwitcherScrimAnchor, - scrimCoordinator); + this, renderHost, startSurface, tabSwitcherScrimAnchor, scrimCoordinator); } if (DeviceFormFactor.isNonMultiDisplayContextOnTablet(mHost.getContext())) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromePhone.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromePhone.java index 32ede0c..33ee520 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromePhone.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromePhone.java
@@ -7,7 +7,6 @@ import android.content.Context; import android.view.ViewGroup; -import org.chromium.base.jank_tracker.JankTracker; import org.chromium.base.supplier.ObservableSupplier; import org.chromium.base.supplier.Supplier; import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager; @@ -43,14 +42,13 @@ * otherwise will use the accessibility overview layout. * @param tabContentManagerSupplier Supplier of the {@link TabContentManager} instance. * @param topUiThemeColorProvider {@link ThemeColorProvider} for top UI. - * @param jankTracker tracker for surface jank. */ public LayoutManagerChromePhone(LayoutManagerHost host, ViewGroup contentContainer, Supplier<StartSurface> startSurfaceSupplier, Supplier<TabSwitcher> tabSwitcherSupplier, ObservableSupplier<TabContentManager> tabContentManagerSupplier, - Supplier<TopUiThemeColorProvider> topUiThemeColorProvider, JankTracker jankTracker) { + Supplier<TopUiThemeColorProvider> topUiThemeColorProvider) { super(host, contentContainer, startSurfaceSupplier, tabSwitcherSupplier, - tabContentManagerSupplier, topUiThemeColorProvider, jankTracker, null, null); + tabContentManagerSupplier, topUiThemeColorProvider, null, null); } @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromeTablet.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromeTablet.java index 23428d5..3fff848 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromeTablet.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromeTablet.java
@@ -6,7 +6,6 @@ import android.view.ViewGroup; -import org.chromium.base.jank_tracker.JankTracker; import org.chromium.base.supplier.ObservableSupplier; import org.chromium.base.supplier.Supplier; import org.chromium.chrome.browser.compositor.LayerTitleCache; @@ -35,7 +34,6 @@ */ public class LayoutManagerChromeTablet extends LayoutManagerChrome { // Tab Switcher - private final JankTracker mJankTracker; private final ScrimCoordinator mScrimCoordinator; private final Callable<ViewGroup> mCreateStartSurfaceCallable; // Tab Strip @@ -65,7 +63,6 @@ * Start surface refactor is enabled. * @param tabContentManagerSupplier Supplier of the {@link TabContentManager} instance. * @param topUiThemeColorProvider {@link ThemeColorProvider} for top UI. - * @param jankTracker Tracker for surface jank. * @param tabSwitcherViewHolder {@link ViewGroup} used by tab switcher layout to show scrim * when overview is visible. * @param scrimCoordinator {@link ScrimCoordinator} to show/hide scrim. @@ -76,18 +73,17 @@ public LayoutManagerChromeTablet(LayoutManagerHost host, ViewGroup contentContainer, Supplier<StartSurface> startSurfaceSupplier, Supplier<TabSwitcher> tabSwitcherSupplier, ObservableSupplier<TabContentManager> tabContentManagerSupplier, - Supplier<TopUiThemeColorProvider> topUiThemeColorProvider, JankTracker jankTracker, + Supplier<TopUiThemeColorProvider> topUiThemeColorProvider, ViewGroup tabSwitcherViewHolder, ScrimCoordinator scrimCoordinator, ActivityLifecycleDispatcher lifecycleDispatcher, Callable<ViewGroup> delayedStartSurfaceCallable) { super(host, contentContainer, startSurfaceSupplier, tabSwitcherSupplier, - tabContentManagerSupplier, topUiThemeColorProvider, jankTracker, - tabSwitcherViewHolder, scrimCoordinator); + tabContentManagerSupplier, topUiThemeColorProvider, tabSwitcherViewHolder, + scrimCoordinator); mStartSurfaceSupplier = startSurfaceSupplier; mTabSwitcherSupplier = tabSwitcherSupplier; mTabStripLayoutHelperManager = new StripLayoutHelperManager(host.getContext(), host, this, mHost.getLayoutRenderHost(), () -> mLayerTitleCache, lifecycleDispatcher); - mJankTracker = jankTracker; mScrimCoordinator = scrimCoordinator; mCreateStartSurfaceCallable = delayedStartSurfaceCallable; addSceneOverlay(mTabStripLayoutHelperManager); @@ -158,7 +154,7 @@ if (!mStartSurfaceSupplier.hasValue() && !mTabSwitcherSupplier.hasValue()) { final ViewGroup containerView = mCreateStartSurfaceCallable.call(); createOverviewLayout(mStartSurfaceSupplier.get(), mTabSwitcherSupplier.get(), - mJankTracker, mScrimCoordinator, containerView); + mScrimCoordinator, containerView); mThemeColorObserver = (color, shouldAnimate) -> containerView.setBackgroundColor(color); mTopUiThemeColorProvider = getTopUiThemeColorProvider().get();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabRootUiCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabRootUiCoordinator.java index 441a0e6..0e7143e 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabRootUiCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabRootUiCoordinator.java
@@ -15,7 +15,6 @@ import org.chromium.base.Callback; import org.chromium.base.IntentUtils; -import org.chromium.base.jank_tracker.DummyJankTracker; import org.chromium.base.supplier.ObservableSupplier; import org.chromium.base.supplier.OneShotCallback; import org.chromium.base.supplier.OneshotSupplierImpl; @@ -169,7 +168,7 @@ contextualSearchManagerSupplier, tabModelSelectorSupplier, new OneshotSupplierImpl<>(), new OneshotSupplierImpl<>(), new OneshotSupplierImpl<>(), new OneshotSupplierImpl<>(), () -> null, - browserControlsManager, windowAndroid, new DummyJankTracker(), + browserControlsManager, windowAndroid, activityLifecycleDispatcher, layoutManagerSupplier, menuOrKeyboardActionController, activityThemeColorSupplier, modalDialogManagerSupplier, appMenuBlocker, supportsAppMenuSupplier, supportsFindInPage, tabCreatorManagerSupplier,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/native_page/NativePageFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/native_page/NativePageFactory.java index fd15eb2b..f695919 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/native_page/NativePageFactory.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/native_page/NativePageFactory.java
@@ -11,7 +11,6 @@ import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; -import org.chromium.base.jank_tracker.JankTracker; import org.chromium.base.supplier.DestroyableObservableSupplier; import org.chromium.base.supplier.Supplier; import org.chromium.chrome.browser.app.download.home.DownloadPage; @@ -62,7 +61,6 @@ private final WindowAndroid mWindowAndroid; private final Supplier<Long> mLastUserInteractionTimeSupplier; private final BooleanSupplier mHadWarmStartSupplier; - private final JankTracker mJankTracker; private final Supplier<Toolbar> mToolbarSupplier; private NewTabPageUma mNewTabPageUma; @@ -78,7 +76,7 @@ @NonNull Supplier<ShareDelegate> shareDelegateSupplier, @NonNull WindowAndroid windowAndroid, @NonNull Supplier<Long> lastUserInteractionTimeSupplier, - @NonNull BooleanSupplier hadWarmStartSupplier, @NonNull JankTracker jankTracker, + @NonNull BooleanSupplier hadWarmStartSupplier, @NonNull Supplier<Toolbar> toolbarSupplier) { mActivity = activity; mBottomSheetController = sheetController; @@ -91,7 +89,6 @@ mWindowAndroid = windowAndroid; mLastUserInteractionTimeSupplier = lastUserInteractionTimeSupplier; mHadWarmStartSupplier = hadWarmStartSupplier; - mJankTracker = jankTracker; mToolbarSupplier = toolbarSupplier; } @@ -100,7 +97,7 @@ mNativePageBuilder = new NativePageBuilder(mActivity, this::getNewTabPageUma, mBottomSheetController, mBrowserControlsManager, mCurrentTabSupplier, mSnackbarManagerSupplier, mLifecycleDispatcher, mTabModelSelector, - mShareDelegateSupplier, mWindowAndroid, mJankTracker, mToolbarSupplier); + mShareDelegateSupplier, mWindowAndroid, mToolbarSupplier); } return mNativePageBuilder; } @@ -126,7 +123,6 @@ private final TabModelSelector mTabModelSelector; private final Supplier<ShareDelegate> mShareDelegateSupplier; private final WindowAndroid mWindowAndroid; - private final JankTracker mJankTracker; private final Supplier<Toolbar> mToolbarSupplier; public NativePageBuilder(Activity activity, Supplier<NewTabPageUma> uma, @@ -135,7 +131,7 @@ Supplier<SnackbarManager> snackbarManagerSupplier, ActivityLifecycleDispatcher lifecycleDispatcher, TabModelSelector tabModelSelector, Supplier<ShareDelegate> shareDelegateSupplier, WindowAndroid windowAndroid, - JankTracker jankTracker, Supplier<Toolbar> toolbarSupplier) { + Supplier<Toolbar> toolbarSupplier) { mActivity = activity; mUma = uma; mBottomSheetController = sheetController; @@ -146,7 +142,6 @@ mTabModelSelector = tabModelSelector; mShareDelegateSupplier = shareDelegateSupplier; mWindowAndroid = windowAndroid; - mJankTracker = jankTracker; mToolbarSupplier = toolbarSupplier; } @@ -159,7 +154,7 @@ mSnackbarManagerSupplier.get(), mLifecycleDispatcher, mTabModelSelector, DeviceFormFactor.isWindowOnTablet(mWindowAndroid), mUma.get(), ColorUtils.inNightMode(mActivity), nativePageHost, tab, url, - mBottomSheetController, mShareDelegateSupplier, mWindowAndroid, mJankTracker, + mBottomSheetController, mShareDelegateSupplier, mWindowAndroid, mToolbarSupplier, new SettingsLauncherImpl()); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java index 91b328be..94dfa38f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java
@@ -27,8 +27,6 @@ import org.chromium.base.ObserverList; import org.chromium.base.TimeUtils; import org.chromium.base.TraceEvent; -import org.chromium.base.jank_tracker.JankScenario; -import org.chromium.base.jank_tracker.JankTracker; import org.chromium.base.metrics.RecordHistogram; import org.chromium.base.metrics.RecordUserAction; import org.chromium.base.supplier.Supplier; @@ -125,7 +123,6 @@ private final ActivityLifecycleDispatcher mActivityLifecycleDispatcher; private final String mTitle; - private final JankTracker mJankTracker; private Context mContext; private final int mBackgroundColor; protected final NewTabPageManagerImpl mNewTabPageManager; @@ -341,7 +338,6 @@ * @param bottomSheetController The controller for bottom sheets, used by the feed. * @param shareDelegateSupplier Supplies the Delegate used to open SharingHub. * @param windowAndroid The containing window of this page. - * @param jankTracker {@link JankTracker} object to measure jankiness while NTP is visible. * @param toolbarSupplier Supplies the {@link Toolbar}. * @param settingsLauncher {@link SettingsLauncher} object to launch settings fragments. */ @@ -352,8 +348,7 @@ NativePageHost nativePageHost, Tab tab, String url, BottomSheetController bottomSheetController, Supplier<ShareDelegate> shareDelegateSupplier, WindowAndroid windowAndroid, - JankTracker jankTracker, Supplier<Toolbar> toolbarSupplier, - SettingsLauncher settingsLauncher) { + Supplier<Toolbar> toolbarSupplier, SettingsLauncher settingsLauncher) { mConstructedTimeNs = System.nanoTime(); TraceEvent.begin(TAG); @@ -362,7 +357,6 @@ mActivityLifecycleDispatcher = lifecycleDispatcher; mTab = tab; mNewTabPageUma = uma; - mJankTracker = jankTracker; mToolbarSupplier = toolbarSupplier; mMostVisitedTileClickObservers = new ObserverList<>(); mBrowserControlsStateProvider = browserControlsStateProvider; @@ -408,19 +402,6 @@ } @Override - public void onInteractabilityChanged(Tab tab, boolean isInteractable) { - // We start/stop tracking based on InteractabilityChanged in addition to - // Shown/Hidden because those events don't trigger for switching to tab switcher, we - // don't rely solely on this event because it doeesn't trigger when the user - // navigates to a website. - if (isInteractable) { - mJankTracker.startTrackingScenario(JankScenario.NEW_TAB_PAGE); - } else { - mJankTracker.finishTrackingScenario(JankScenario.NEW_TAB_PAGE); - } - } - - @Override public void onLoadUrl(Tab tab, LoadUrlParams params, int loadType) { mNewTabPageLayout.onLoadUrl(UrlUtilities.isNTPUrl(tab.getUrl())); } @@ -798,7 +779,6 @@ private void recordNTPShown() { mLastShownTimeNs = System.nanoTime(); RecordUserAction.record("MobileNTPShown"); - mJankTracker.startTrackingScenario(JankScenario.NEW_TAB_PAGE); SuggestionsMetrics.recordSurfaceVisible(); FeatureNotificationUtils.registerIPHCallback(FeatureType.VOICE_SEARCH, @@ -807,7 +787,6 @@ /** Records UMA for the NTP being hidden and the time spent on it. */ private void recordNTPHidden() { - mJankTracker.finishTrackingScenario(JankScenario.NEW_TAB_PAGE); RecordHistogram.recordMediumTimesHistogram("NewTabPage.TimeSpent", (System.nanoTime() - mLastShownTimeNs) / TimeUtils.NANOSECONDS_PER_MILLISECOND); SuggestionsMetrics.recordSurfaceHidden();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java index fcb5fc2..c4ce3d9 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java
@@ -25,7 +25,6 @@ import org.chromium.base.Callback; import org.chromium.base.IntentUtils; import org.chromium.base.Log; -import org.chromium.base.jank_tracker.DummyJankTracker; import org.chromium.base.metrics.RecordUserAction; import org.chromium.base.supplier.ObservableSupplierImpl; import org.chromium.base.supplier.OneshotSupplierImpl; @@ -245,7 +244,7 @@ /*saveOfflineButtonState=*/(tab) -> false, /*omniboxUma*/(url, transition, isNtp) -> {}, TabWindowManagerSingleton::getInstance, /*bookmarkState=*/(url) -> false, - VoiceToolbarButtonController::isToolbarMicEnabled, new DummyJankTracker(), + VoiceToolbarButtonController::isToolbarMicEnabled, /*merchantTrustSignalsCoordinatorSupplier=*/null, new ActionChipsDelegateImpl(this, new OneshotSupplierImpl<>(), getModalDialogManagerSupplier()), null,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/share/ShareHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/share/ShareHelper.java index ab39b9b..d5b154fe 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/share/ShareHelper.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/share/ShareHelper.java
@@ -58,8 +58,8 @@ "android.intent.extra.CHOOSER_CUSTOM_ACTIONS"; private static final String INTENT_EXTRA_CHOOSER_MODIFY_SHARE_ACTION = "android.intent.extra.CHOOSER_MODIFY_SHARE_ACTION"; - // A generous number used to allocate requestCode for pending intent used by custom actions. - private static final int MAX_CUSTOM_ACTION_SUPPORTED = 10; + // The max number of custom actions supported for custom actions. + private static final int MAX_CUSTOM_ACTION_SUPPORTED = 5; private static final int CUSTOM_ACTION_REQUEST_CODE_BASE = 112; @VisibleForTesting static final String EXTRA_SHARE_CUSTOM_ACTION = "EXTRA_SHARE_CUSTOM_ACTION";
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java index 8383708..e09f98f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java
@@ -15,7 +15,6 @@ import org.chromium.base.CallbackController; import org.chromium.base.CommandLine; import org.chromium.base.TraceEvent; -import org.chromium.base.jank_tracker.JankTracker; import org.chromium.base.supplier.ObservableSupplier; import org.chromium.base.supplier.ObservableSupplierImpl; import org.chromium.base.supplier.OneShotCallback; @@ -78,7 +77,6 @@ import org.chromium.chrome.browser.omnibox.UrlFocusChangeListener; import org.chromium.chrome.browser.preferences.ChromePreferenceKeys; import org.chromium.chrome.browser.preferences.SharedPreferencesManager; -import org.chromium.chrome.browser.price_tracking.PriceTrackingFeatures; import org.chromium.chrome.browser.privacy_sandbox.PrivacySandboxDialogController; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.read_later.ReadLaterIPHController; @@ -227,7 +225,6 @@ * @param startSurfaceParentTabSupplier Supplies the parent tab for the StartSurface. * @param browserControlsManager Manages the browser controls. * @param windowAndroid The current {@link WindowAndroid}. - * @param jankTracker Tracks the jank in the app. * @param activityLifecycleDispatcher Allows observation of the activity lifecycle. * @param layoutManagerSupplier Supplies the {@link LayoutManager}. * @param menuOrKeyboardActionController Controls the menu or keyboard action controller. @@ -271,7 +268,7 @@ @NonNull OneshotSupplier<LayoutStateProvider> layoutStateProviderOneshotSupplier, @NonNull Supplier<Tab> startSurfaceParentTabSupplier, @NonNull BrowserControlsManager browserControlsManager, - @NonNull ActivityWindowAndroid windowAndroid, @NonNull JankTracker jankTracker, + @NonNull ActivityWindowAndroid windowAndroid, @NonNull ActivityLifecycleDispatcher activityLifecycleDispatcher, @NonNull ObservableSupplier<LayoutManagerImpl> layoutManagerSupplier, @NonNull MenuOrKeyboardActionController menuOrKeyboardActionController, @@ -301,7 +298,7 @@ contextualSearchManagerSupplier, tabModelSelectorSupplier, startSurfaceSupplier, tabSwitcherSupplier, intentMetadataOneshotSupplier, layoutStateProviderOneshotSupplier, startSurfaceParentTabSupplier, - browserControlsManager, windowAndroid, jankTracker, activityLifecycleDispatcher, + browserControlsManager, windowAndroid, activityLifecycleDispatcher, layoutManagerSupplier, menuOrKeyboardActionController, activityThemeColorSupplier, modalDialogManagerSupplier, appMenuBlocker, supportsAppMenuSupplier, supportsFindInPage, tabCreatorManagerSupplier, fullscreenManager, @@ -811,10 +808,6 @@ } private void initCommerceSubscriptionsService() { - if (!PriceTrackingFeatures.getPriceTrackingNotificationsEnabled()) { - return; - } - CommerceSubscriptionsServiceFactory factory = new CommerceSubscriptionsServiceFactory(); mCommerceSubscriptionsService = factory.getForLastUsedProfile(); mCommerceSubscriptionsService.initDeferredStartupForActivity(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java index 15ebd51..707470d 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
@@ -31,7 +31,6 @@ import org.chromium.base.Callback; import org.chromium.base.CallbackController; import org.chromium.base.TraceEvent; -import org.chromium.base.jank_tracker.JankTracker; import org.chromium.base.supplier.ObservableSupplier; import org.chromium.base.supplier.ObservableSupplierImpl; import org.chromium.base.supplier.OneshotSupplier; @@ -452,7 +451,6 @@ @NonNull Supplier<Boolean> isWarmOnResumeSupplier, @NonNull TabContentManager tabContentManager, @NonNull TabCreatorManager tabCreatorManager, @NonNull SnackbarManager snackbarManager, - JankTracker jankTracker, @NonNull Supplier<MerchantTrustSignalsCoordinator> merchantTrustSignalsCoordinatorSupplier, OneshotSupplier<TabReparentingController> tabReparentingControllerSupplier, @@ -667,7 +665,6 @@ return mToolbar.getCurrentOptionalButtonVariant() == AdaptiveToolbarButtonVariant.VOICE; }, - jankTracker, merchantTrustSignalsCoordinatorSupplier, actionChipsDelegate, mControlsVisibilityDelegate, ChromePureJavaExceptionReporter::reportJavaException, backPressManager,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ui/RootUiCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/ui/RootUiCoordinator.java index 333c6a8..f93c749b 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ui/RootUiCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ui/RootUiCoordinator.java
@@ -26,7 +26,6 @@ import org.chromium.base.Callback; import org.chromium.base.CallbackController; import org.chromium.base.TraceEvent; -import org.chromium.base.jank_tracker.JankTracker; import org.chromium.base.metrics.RecordUserAction; import org.chromium.base.supplier.ObservableSupplier; import org.chromium.base.supplier.ObservableSupplierImpl; @@ -191,7 +190,6 @@ MenuOrKeyboardActionController.MenuOrKeyboardActionHandler, AppMenuBlocker { protected final UnownedUserDataSupplier<TabObscuringHandler> mTabObscuringHandlerSupplier = new TabObscuringHandlerSupplier(); - private final JankTracker mJankTracker; protected AppCompatActivity mActivity; protected @Nullable AppMenuCoordinator mAppMenuCoordinator; @@ -330,7 +328,6 @@ * @param startSurfaceParentTabSupplier Supplies the parent tab for the StartSurface. * @param browserControlsManager Manages the browser controls. * @param windowAndroid The current {@link WindowAndroid}. - * @param jankTracker Tracks the jank in the app. * @param activityLifecycleDispatcher Allows observation of the activity lifecycle. * @param layoutManagerSupplier Supplies the {@link LayoutManager}. * @param menuOrKeyboardActionController Controls the menu or keyboard action controller. @@ -370,7 +367,7 @@ @NonNull OneshotSupplier<LayoutStateProvider> layoutStateProviderOneshotSupplier, @NonNull Supplier<Tab> startSurfaceParentTabSupplier, @NonNull BrowserControlsManager browserControlsManager, - @NonNull ActivityWindowAndroid windowAndroid, @NonNull JankTracker jankTracker, + @NonNull ActivityWindowAndroid windowAndroid, @NonNull ActivityLifecycleDispatcher activityLifecycleDispatcher, @NonNull ObservableSupplier<LayoutManagerImpl> layoutManagerSupplier, @NonNull MenuOrKeyboardActionController menuOrKeyboardActionController, @@ -392,7 +389,6 @@ @NonNull OneshotSupplier<TabReparentingController> tabReparentingControllerSupplier, @NonNull Supplier<EphemeralTabCoordinator> ephemeralTabCoordinatorSupplier, boolean initializeUiWithIncognitoColors, @Nullable BackPressManager backPressManager) { - mJankTracker = jankTracker; mCallbackController = new CallbackController(); mActivity = activity; mWindowAndroid = windowAndroid; @@ -1188,11 +1184,10 @@ mStatusBarColorController, mAppMenuDelegate, mActivityLifecycleDispatcher, mStartSurfaceParentTabSupplier, mBottomSheetController, mIsWarmOnResumeSupplier, mTabContentManagerSupplier.get(), mTabCreatorManagerSupplier.get(), - mSnackbarManagerSupplier.get(), mJankTracker, - getMerchantTrustSignalsCoordinatorSupplier(), mTabReparentingControllerSupplier, - mActionChipsDelegate, mEphemeralTabCoordinatorSupplier, - mInitializeUiWithIncognitoColors, mBackPressManager, - openHistoryClustersDelegate); + mSnackbarManagerSupplier.get(), getMerchantTrustSignalsCoordinatorSupplier(), + mTabReparentingControllerSupplier, mActionChipsDelegate, + mEphemeralTabCoordinatorSupplier, mInitializeUiWithIncognitoColors, + mBackPressManager, openHistoryClustersDelegate); if (!mSupportsAppMenuSupplier.getAsBoolean()) { mToolbarManager.getToolbar().disableMenuButton(); }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerTest.java index b0e46f3..0d6e89f 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerTest.java
@@ -42,7 +42,6 @@ import org.chromium.base.Log; import org.chromium.base.MathUtils; -import org.chromium.base.jank_tracker.DummyJankTracker; import org.chromium.base.supplier.ObservableSupplierImpl; import org.chromium.base.supplier.OneshotSupplierImpl; import org.chromium.base.supplier.Supplier; @@ -236,7 +235,7 @@ mManagerPhone = new LayoutManagerChromePhone(layoutManagerHost, container, mStartSurfaceSupplier, mIsStartSurfaceRefactorEnabled ? mTabSwitcherSupplier : new OneshotSupplierImpl<>(), - tabContentManagerSupplier, () -> mTopUiThemeColorProvider, new DummyJankTracker()); + tabContentManagerSupplier, () -> mTopUiThemeColorProvider); setUpLayouts();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/DetachedResourceRequestTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/DetachedResourceRequestTest.java index b17cee50..611defc 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/DetachedResourceRequestTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/DetachedResourceRequestTest.java
@@ -31,6 +31,7 @@ import org.chromium.base.task.TaskTraits; import org.chromium.base.test.util.CallbackHelper; import org.chromium.base.test.util.CriteriaHelper; +import org.chromium.base.test.util.DisabledTest; import org.chromium.base.test.util.HistogramWatcher; import org.chromium.chrome.browser.MockSafeBrowsingApiHandler; import org.chromium.chrome.browser.browserservices.verification.ChromeOriginVerifier; @@ -324,7 +325,7 @@ @Test @SmallTest @DisableFeatures(ChromeFeatureList.SPLIT_CACHE_BY_NETWORK_ISOLATION_KEY) - + @DisabledTest(message = "https://crbug.com/1431268") public void testSafeBrowsingMainResource() throws Exception { testSafeBrowsingMainResource(true /* afterNative */, false /* splitCacheEnabled */); } @@ -357,6 +358,7 @@ @Test @SmallTest @DisableFeatures(ChromeFeatureList.SPLIT_CACHE_BY_NETWORK_ISOLATION_KEY) + @DisabledTest(message = "https://crbug.com/1431268") public void testSafeBrowsingMainResourceBeforeNative() throws Exception { testSafeBrowsingMainResource(false /* afterNative */, false /* splitCacheEnabled */); }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/metrics/StartupLoadingMetricsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/metrics/StartupLoadingMetricsTest.java index cba49aff..53e9358 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/metrics/StartupLoadingMetricsTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/metrics/StartupLoadingMetricsTest.java
@@ -16,12 +16,9 @@ import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; -import org.chromium.base.jank_tracker.JankMetricUMARecorder; -import org.chromium.base.jank_tracker.JankMetricUMARecorderJni; import org.chromium.base.metrics.RecordHistogram; import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.CriteriaHelper; @@ -80,9 +77,6 @@ @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule(); - @Mock - JankMetricUMARecorder.Natives mJankRecorderNativeMock; - private String mTestPage; private String mTestPage2; private String mErrorPage; @@ -99,7 +93,6 @@ mTestPage2 = mTestServer.getURL(TEST_PAGE_2); mErrorPage = mTestServer.getURL(ERROR_PAGE); mSlowPage = mTestServer.getURL(SLOW_PAGE); - mJniMocker.mock(JankMetricUMARecorderJni.TEST_HOOKS, mJankRecorderNativeMock); } @After
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/TabUmaTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/TabUmaTest.java index a338a751..4a4dc80 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/TabUmaTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/TabUmaTest.java
@@ -15,7 +15,6 @@ import org.junit.runner.RunWith; import org.chromium.base.StrictModeContext; -import org.chromium.base.jank_tracker.DummyJankTracker; import org.chromium.base.metrics.RecordHistogram; import org.chromium.base.supplier.ObservableSupplierImpl; import org.chromium.base.test.util.Batch; @@ -89,7 +88,7 @@ cta.getModalDialogManagerSupplier(), cta::getSnackbarManager, cta.getBrowserControlsManager(), cta.getActivityTabProvider(), cta.getLifecycleDispatcher(), cta.getWindowAndroid(), - cta::getLastUserInteractionTime, cta::hadWarmStart, new DummyJankTracker(), + cta::getLastUserInteractionTime, cta::hadWarmStart, rootUiCoordinator.getToolbarManager()::getToolbar); // clang-format on }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/native_page/NativePageFactoryTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/native_page/NativePageFactoryTest.java index ef6b01d..d66acd4b 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/native_page/NativePageFactoryTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/native_page/NativePageFactoryTest.java
@@ -16,7 +16,6 @@ import org.junit.runner.RunWith; import org.robolectric.annotation.Config; -import org.chromium.base.jank_tracker.DummyJankTracker; import org.chromium.base.test.BaseRobolectricTestRunner; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.ui.native_page.NativePage; @@ -93,8 +92,7 @@ private static class MockNativePageBuilder extends NativePageFactory.NativePageBuilder { private MockNativePageBuilder() { - super(null, null, null, null, null, null, null, null, null, null, - new DummyJankTracker(), null); + super(null, null, null, null, null, null, null, null, null, null, null); } @Override @@ -120,8 +118,8 @@ @Before public void setUp() { - mNativePageFactory = new NativePageFactory(null, null, null, null, null, null, null, null, - null, null, null, new DummyJankTracker(), null); + mNativePageFactory = new NativePageFactory( + null, null, null, null, null, null, null, null, null, null, null, null); mNativePageFactory.setNativePageBuilderForTesting(new MockNativePageBuilder()); }
diff --git a/chrome/android/profiles/arm.newest.txt b/chrome/android/profiles/arm.newest.txt index c3c1cb1..1ea1244 100644 --- a/chrome/android/profiles/arm.newest.txt +++ b/chrome/android/profiles/arm.newest.txt
@@ -1 +1 @@ -chromeos-chrome-arm-114.0.5676.0_rc-r2-merged.afdo.bz2 +chromeos-chrome-arm-114.0.5697.0_rc-r1-merged.afdo.bz2
diff --git a/chrome/app/media_router_strings.grdp b/chrome/app/media_router_strings.grdp index 56462d5..029f6e79 100644 --- a/chrome/app/media_router_strings.grdp +++ b/chrome/app/media_router_strings.grdp
@@ -126,6 +126,15 @@ <message name="IDS_MEDIA_ROUTER_PRESENTATION_ROUTE_DESCRIPTION" desc="Description shown to indicate that a website is being presented to another display."> Presenting (<ph name="PAGE_ORIGIN">$1<ex>example.com</ex></ph>) </message> + <message name="IDS_MEDIA_ROUTER_SINK_VIEW_PAUSE" desc="Label for a button that, when pressed, pauses a Cast mirroring session"> + Pause + </message> + <message name="IDS_MEDIA_ROUTER_SINK_VIEW_RESUME" desc="Label for a button that, when pressed, resumes a Cast mirroring session"> + Resume + </message> + <message name="IDS_MEDIA_ROUTER_SINK_VIEW_STOP" desc="Label for a button that, when pressed, stops casting to a Cast device. Should be consistent with IDS_MEDIA_ROUTER_STOP_CASTING."> + Stop + </message> <!-- Media Remoting Dialog --> <message name="IDS_MEDIA_ROUTER_REMOTING_DIALOG_TITLE" desc="Title text shown at the top of the dialog asking the user whether they want to enable the Media Remoting feature. Media Remoting is a feature that can be enabled during a Cast session for improved playback.">
diff --git a/chrome/app/media_router_strings_grdp/IDS_MEDIA_ROUTER_SINK_VIEW_PAUSE.png.sha1 b/chrome/app/media_router_strings_grdp/IDS_MEDIA_ROUTER_SINK_VIEW_PAUSE.png.sha1 new file mode 100644 index 0000000..a5cca7d --- /dev/null +++ b/chrome/app/media_router_strings_grdp/IDS_MEDIA_ROUTER_SINK_VIEW_PAUSE.png.sha1
@@ -0,0 +1 @@ +49a666f8cb44244e6dc7490a2857ae55822bfa39 \ No newline at end of file
diff --git a/chrome/app/media_router_strings_grdp/IDS_MEDIA_ROUTER_SINK_VIEW_RESUME.png.sha1 b/chrome/app/media_router_strings_grdp/IDS_MEDIA_ROUTER_SINK_VIEW_RESUME.png.sha1 new file mode 100644 index 0000000..4aef475 --- /dev/null +++ b/chrome/app/media_router_strings_grdp/IDS_MEDIA_ROUTER_SINK_VIEW_RESUME.png.sha1
@@ -0,0 +1 @@ +adef89a90fc009073f6e3550b54644e390854cfa \ No newline at end of file
diff --git a/chrome/app/media_router_strings_grdp/IDS_MEDIA_ROUTER_SINK_VIEW_STOP.png.sha1 b/chrome/app/media_router_strings_grdp/IDS_MEDIA_ROUTER_SINK_VIEW_STOP.png.sha1 new file mode 100644 index 0000000..1240f0d95 --- /dev/null +++ b/chrome/app/media_router_strings_grdp/IDS_MEDIA_ROUTER_SINK_VIEW_STOP.png.sha1
@@ -0,0 +1 @@ +ebe5c20e0058460c187f922791060399832cf466 \ No newline at end of file
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index f3c279b..0e464d49 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -1591,28 +1591,6 @@ std::size(kOmniboxInspireMeWith10Mixed), nullptr}}; #endif // BUILDFLAG(IS_ANDROID) -const FeatureEntry::FeatureParam kOmniboxBookmarkPathsReplaceTitle[] = { - {"OmniboxBookmarkPathsUiReplaceTitle", "true"}}; -const FeatureEntry::FeatureParam kOmniboxBookmarkPathsReplaceUrl[] = { - {"OmniboxBookmarkPathsUiReplaceUrl", "true"}}; -const FeatureEntry::FeatureParam kOmniboxBookmarkPathsAppendAfterTitle[] = { - {"OmniboxBookmarkPathsUiAppendAfterTitle", "true"}}; -const FeatureEntry::FeatureParam kOmniboxBookmarkPathsDynamicReplaceUrl[] = { - {"OmniboxBookmarkPathsUiDynamicReplaceUrl", "true"}}; - -const FeatureEntry::FeatureVariation kOmniboxBookmarkPathsVariations[] = { - {"Default UI (Title - URL)", {}, 0, nullptr}, - {"Replace title (Path/Title - URL)", kOmniboxBookmarkPathsReplaceTitle, - std::size(kOmniboxBookmarkPathsReplaceTitle), nullptr}, - {"Replace URL (Title - Path)", kOmniboxBookmarkPathsReplaceUrl, - std::size(kOmniboxBookmarkPathsReplaceUrl), nullptr}, - {"Append after title (Title : Path - URL)", - kOmniboxBookmarkPathsAppendAfterTitle, - std::size(kOmniboxBookmarkPathsAppendAfterTitle), nullptr}, - {"Dynamic Replace URL (Title - Path|URL)", - kOmniboxBookmarkPathsDynamicReplaceUrl, - std::size(kOmniboxBookmarkPathsDynamicReplaceUrl), nullptr}}; - const FeatureEntry::FeatureParam kOmniboxSquareSuggestionIconFavicons[] = { {"OmniboxSquareSuggestIconIcons", "true"}}; const FeatureEntry::FeatureParam kOmniboxSquareSuggestionIconAnswers[] = { @@ -3778,9 +3756,6 @@ flag_descriptions::kAdaptiveChargingForTestingName, flag_descriptions::kAdaptiveChargingForTestingDescription, kOsCrOS, FEATURE_VALUE_TYPE(ash::features::kAdaptiveChargingForTesting)}, - {"ash-bento-bar", flag_descriptions::kBentoBarName, - flag_descriptions::kBentoBarDescription, kOsCrOS, - FEATURE_VALUE_TYPE(ash::features::kBentoBar)}, {"ash-capture-mode-demo-tools", flag_descriptions::kCaptureModeDemoToolsName, flag_descriptions::kCaptureModeDemoToolsDescription, kOsCrOS, @@ -4823,6 +4798,10 @@ flag_descriptions::kShareSheetMigrationAndroidName, flag_descriptions::kShareSheetMigrationAndroidDescription, kOsAndroid, FEATURE_VALUE_TYPE(chrome::android::kShareSheetMigrationAndroid)}, + {"share-sheet-custom-actions-polish", + flag_descriptions::kShareSheetCustomActionsPolishName, + flag_descriptions::kShareSheetCustomActionsPolishDescription, kOsAndroid, + FEATURE_VALUE_TYPE(chrome::android::kShareSheetCustomActionsPolish)}, #endif // BUILDFLAG(IS_ANDROID) {"disallow-doc-written-script-loads", @@ -5753,12 +5732,6 @@ flag_descriptions::kOmniboxKeepSecondaryZeroSuggestDescription, kOsAll, FEATURE_VALUE_TYPE(omnibox::kKeepSecondaryZeroSuggest)}, - {"omnibox-bookmark-paths", flag_descriptions::kOmniboxBookmarkPathsName, - flag_descriptions::kOmniboxBookmarkPathsDescription, kOsAll, - FEATURE_WITH_PARAMS_VALUE_TYPE(omnibox::kBookmarkPaths, - kOmniboxBookmarkPathsVariations, - "OmniboxBundledExperimentV1")}, - {"omnibox-short-bookmark-suggestions", flag_descriptions::kOmniboxShortBookmarkSuggestionsName, flag_descriptions::kOmniboxShortBookmarkSuggestionsDescription, kOsAll, @@ -7490,9 +7463,6 @@ flag_descriptions::kReleaseNotesNotificationAllChannelsDescription, kOsCrOS, FEATURE_VALUE_TYPE(ash::features::kReleaseNotesNotificationAllChannels)}, - {"release-track-ui", flag_descriptions::kReleaseTrackUiName, - flag_descriptions::kReleaseTrackUiDescription, kOsCrOS, - FEATURE_VALUE_TYPE(ash::features::kReleaseTrackUi)}, {"use-stork-smds-server-address", flag_descriptions::kUseStorkSmdsServerAddressName, flag_descriptions::kUseStorkSmdsServerAddressDescription, kOsCrOS,
diff --git a/chrome/browser/android/omnibox/autocomplete_controller_android.cc b/chrome/browser/android/omnibox/autocomplete_controller_android.cc index fd39b87..432819b 100644 --- a/chrome/browser/android/omnibox/autocomplete_controller_android.cc +++ b/chrome/browser/android/omnibox/autocomplete_controller_android.cc
@@ -356,7 +356,7 @@ if (web_contents) { if (auto* search_prefetch_service = SearchPrefetchServiceFactory::GetForProfile(profile_)) { - search_prefetch_service->OnURLOpenedFromOmnibox(&log, web_contents); + search_prefetch_service->OnURLOpenedFromOmnibox(&log); } // Record the value if prerender for search suggestion was not started.
diff --git a/chrome/browser/ash/arc/input_overlay/ui/action_edit_button.cc b/chrome/browser/ash/arc/input_overlay/ui/action_edit_button.cc index 00517dc..7312b76b 100644 --- a/chrome/browser/ash/arc/input_overlay/ui/action_edit_button.cc +++ b/chrome/browser/ash/arc/input_overlay/ui/action_edit_button.cc
@@ -44,8 +44,8 @@ ActionEditButton::ActionEditButton(PressedCallback callback) : views::ImageButton(std::move(callback)) { - auto dots_icon = gfx::CreateVectorIcon( - ash::kPersistentDesksBarVerticalDotsIcon, kDotsIconSize, kDotsIconColor); + auto dots_icon = gfx::CreateVectorIcon(ash::kVerticalDotsIcon, kDotsIconSize, + kDotsIconColor); SetImage(views::Button::STATE_NORMAL, dots_icon); SetAccessibleName(base::UTF8ToUTF16(GetClassName())); SetSize(gfx::Size(kDotsButtonSize, kDotsButtonSize));
diff --git a/chrome/browser/ash/arc/input_overlay/ui/action_view.h b/chrome/browser/ash/arc/input_overlay/ui/action_view.h index 4d3ec09..74911d9 100644 --- a/chrome/browser/ash/arc/input_overlay/ui/action_view.h +++ b/chrome/browser/ash/arc/input_overlay/ui/action_view.h
@@ -5,7 +5,6 @@ #ifndef CHROME_BROWSER_ASH_ARC_INPUT_OVERLAY_UI_ACTION_VIEW_H_ #define CHROME_BROWSER_ASH_ARC_INPUT_OVERLAY_UI_ACTION_VIEW_H_ -#include "ash/wm/desks/persistent_desks_bar/persistent_desks_bar_button.h" #include "base/memory/raw_ptr.h" #include "chrome/browser/ash/arc/input_overlay/actions/action.h" #include "chrome/browser/ash/arc/input_overlay/constants.h"
diff --git a/chrome/browser/ash/login/oobe_quick_start/connectivity/target_device_connection_broker_impl.cc b/chrome/browser/ash/login/oobe_quick_start/connectivity/target_device_connection_broker_impl.cc index f3beab69..433989f 100644 --- a/chrome/browser/ash/login/oobe_quick_start/connectivity/target_device_connection_broker_impl.cc +++ b/chrome/browser/ash/login/oobe_quick_start/connectivity/target_device_connection_broker_impl.cc
@@ -43,6 +43,10 @@ // Boolean field indicating to Smart Setup whether the client is Quick Start. constexpr uint8_t kEndpointInfoIsQuickStart = 1; +// Boolean field indicating whether the target device supports LSKF +// verification. +constexpr uint8_t kEndpointInfoPreferTargetUserVerification = 0; + constexpr size_t kMaxEndpointInfoDisplayNameLength = 18; // The Advertising Id field has a fixed width of 10 bytes, but contains a @@ -258,18 +262,20 @@ // The EndpointInfo consists of the following fields: // - EndpointInfo version number, 1 byte // - Display name, max 18 bytes (see GetEndpointInfoDisplayNameBytes()) -// - Advertisement data, 13 bytes, base64 encoded: +// - Advertisement data, 60 bytes, base64 encoded: // - Verification Style, byte[0] // - Device Type, byte[1] // - Advertising Id, byte[2-11], 10 UTF-8 bytes. (See RandomSessionId) // - isQuickStart, byte[12], =1 for Quick Start. +// - preferTargetUserVerification, byte[13], =0 for ChromeOS. +// - Pad with zeros to 60 bytes. Extra space reserved for futureproofing. std::vector<uint8_t> TargetDeviceConnectionBrokerImpl::GenerateEndpointInfo() { std::string session_id = random_session_id_.ToString(); std::vector<uint8_t> display_name_bytes = GetEndpointInfoDisplayNameBytes(random_session_id_); std::vector<uint8_t> advertisement_data; - advertisement_data.reserve(13); + advertisement_data.reserve(60); advertisement_data.push_back(kEndpointInfoVerificationStyle); advertisement_data.push_back(kEndpointInfoDeviceType); advertisement_data.insert(advertisement_data.end(), session_id.begin(), @@ -281,6 +287,11 @@ advertisement_data.push_back(0); } advertisement_data.push_back(kEndpointInfoIsQuickStart); + advertisement_data.push_back(kEndpointInfoPreferTargetUserVerification); + while (advertisement_data.size() < 60) { + // Reserve 60 bytes for the advertisement data for futureproofing. + advertisement_data.push_back(0); + } std::vector<uint8_t> advertisement_data_b64 = Base64EncodeOmitPadding(advertisement_data);
diff --git a/chrome/browser/ash/login/oobe_quick_start/connectivity/target_device_connection_broker_impl_unittest.cc b/chrome/browser/ash/login/oobe_quick_start/connectivity/target_device_connection_broker_impl_unittest.cc index 9457d2a9..956dcfc 100644 --- a/chrome/browser/ash/login/oobe_quick_start/connectivity/target_device_connection_broker_impl_unittest.cc +++ b/chrome/browser/ash/login/oobe_quick_start/connectivity/target_device_connection_broker_impl_unittest.cc
@@ -501,14 +501,13 @@ // before proceeding. std::vector<uint8_t> advertising_info = Base64DecodeForgiving( base::span<uint8_t>(endpoint_info.begin() + i, endpoint_info.end())); + ASSERT_EQ(advertising_info.size(), 60u); i = 0; - ASSERT_GT(advertising_info.size(), i); uint8_t verification_style = advertising_info[i]; EXPECT_EQ(kEndpointInfoVerificationStyle, verification_style); i++; - ASSERT_GT(advertising_info.size(), i); uint8_t device_type = advertising_info[i]; EXPECT_EQ(kEndpointInfoDeviceType, device_type); i++; @@ -516,7 +515,6 @@ // Parse the RandomSessionId. The field is fixed-width, but contains a string // that may not occupy the full length, in which case there will be a null // terminator. - ASSERT_GE(advertising_info.size(), i + kEndpointInfoRandomSessionIdLength); std::string session_id = GetRandomSessionId().ToString(); for (size_t k = i; k < i + kEndpointInfoRandomSessionIdLength; k++) { if (advertising_info[k] == 0) { @@ -526,12 +524,12 @@ } i += kEndpointInfoRandomSessionIdLength; - ASSERT_GT(advertising_info.size(), i); uint8_t is_quick_start = advertising_info[i]; EXPECT_EQ(1u, is_quick_start); + i++; - // There should be no more endpoint info after the isQuickStart field. - EXPECT_EQ(advertising_info.size(), i + 1); + uint8_t prefer_target_user_verification = advertising_info[i]; + EXPECT_EQ(0u, prefer_target_user_verification); } INSTANTIATE_TEST_SUITE_P(TargetDeviceConnectionBrokerImplTest,
diff --git a/chrome/browser/ash/web_applications/personalization_app/personalization_app_wallpaper_provider_impl.cc b/chrome/browser/ash/web_applications/personalization_app/personalization_app_wallpaper_provider_impl.cc index 794fb9a..0b089000 100644 --- a/chrome/browser/ash/web_applications/personalization_app/personalization_app_wallpaper_provider_impl.cc +++ b/chrome/browser/ash/web_applications/personalization_app/personalization_app_wallpaper_provider_impl.cc
@@ -165,7 +165,7 @@ // user's wallpaper is being set. base::ThreadPool::PostTaskAndReplyWithResult( FROM_HERE, - {base::TaskPriority::USER_VISIBLE, + {base::MayBlock(), base::TaskPriority::USER_VISIBLE, base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}, base::BindOnce(&GetPreviewWallpaper), std::move(callback)); }
diff --git a/chrome/browser/autofill/captured_sites_test_utils.cc b/chrome/browser/autofill/captured_sites_test_utils.cc index fb1ecca9..ca96acf 100644 --- a/chrome/browser/autofill/captured_sites_test_utils.cc +++ b/chrome/browser/autofill/captured_sites_test_utils.cc
@@ -1229,6 +1229,8 @@ } else if (base::CompareCaseInsensitiveASCII(*type, "waitFor") == 0) { if (!ExecuteWaitForStateAction(std::move(action))) return false; + } else if (base::CompareCaseInsensitiveASCII(*type, "breakpoint") == 0) { + execution_state.limit = execution_state.index + 1; } else { ADD_FAILURE() << "Unrecognized action type: " << *type; }
diff --git a/chrome/browser/bookmarks/chrome_bookmark_client.cc b/chrome/browser/bookmarks/chrome_bookmark_client.cc index 73e9302..26d7e33 100644 --- a/chrome/browser/bookmarks/chrome_bookmark_client.cc +++ b/chrome/browser/bookmarks/chrome_bookmark_client.cc
@@ -15,7 +15,6 @@ #include "components/bookmarks/browser/bookmark_model.h" #include "components/bookmarks/browser/bookmark_node.h" #include "components/bookmarks/browser/bookmark_storage.h" -#include "components/bookmarks/common/bookmark_features.h" #include "components/bookmarks/managed/managed_bookmark_service.h" #include "components/bookmarks/managed/managed_bookmark_util.h" #include "components/favicon/core/favicon_util.h" @@ -47,8 +46,7 @@ } } -ChromeBookmarkClient::~ChromeBookmarkClient() { -} +ChromeBookmarkClient::~ChromeBookmarkClient() = default; void ChromeBookmarkClient::Init(bookmarks::BookmarkModel* model) { if (managed_bookmark_service_) @@ -87,40 +85,14 @@ if (!url_db) return; - static const bool kTypedUrlsMapEnabled = - base::FeatureList::IsEnabled(bookmarks::kTypedUrlsMap); - if (kTypedUrlsMapEnabled) { - // Create a map mapping each `GURL` to its typed count. This isn't cached - // since the in memory DB is updated as the user navigates and updating this - // as well seems like overkill. - std::map<const GURL, int> typed_counts; - history::URLDatabase::URLEnumerator history_enum; - // Only need significant URLs, i.e. a superset of URls with >0 typed count, - // since URLs not in `typed_counts` default to 0 typed count anyway. - url_db->InitURLEnumeratorForSignificant(&history_enum); - for (history::URLRow row; history_enum.GetNextURL(&row);) { - if (row.typed_count() > 0) - typed_counts[row.url()] = row.typed_count(); - } - - // Use the map to assign typed counts to `url_typed_count_map`. - for (auto& url_typed_count_pair : *url_typed_count_map) { - if (typed_counts.count(*url_typed_count_pair.first)) { - url_typed_count_pair.second = - typed_counts.count(*url_typed_count_pair.first); - } - } - - } else { - for (auto& url_typed_count_pair : *url_typed_count_map) { - // The in-memory URLDatabase might not cache all URLRows, but it - // guarantees to contain those with `typed_count` > 0. Thus, if we cannot - // fetch the URLRow, it is safe to assume that its `typed_count` is 0. - history::URLRow url_row; - const GURL* url = url_typed_count_pair.first; - if (url && url_db->GetRowForURL(*url, &url_row)) - url_typed_count_pair.second = url_row.typed_count(); - } + for (auto& url_typed_count_pair : *url_typed_count_map) { + // The in-memory URLDatabase might not cache all URLRows, but it + // guarantees to contain those with `typed_count` > 0. Thus, if we cannot + // fetch the URLRow, it is safe to assume that its `typed_count` is 0. + history::URLRow url_row; + const GURL* url = url_typed_count_pair.first; + if (url && url_db->GetRowForURL(*url, &url_row)) + url_typed_count_pair.second = url_row.typed_count(); } }
diff --git a/chrome/browser/commerce/price_tracking/android/java/src/org/chromium/chrome/browser/price_tracking/PriceDropNotificationManagerImpl.java b/chrome/browser/commerce/price_tracking/android/java/src/org/chromium/chrome/browser/price_tracking/PriceDropNotificationManagerImpl.java index f22537c..9aa89c8 100644 --- a/chrome/browser/commerce/price_tracking/android/java/src/org/chromium/chrome/browser/price_tracking/PriceDropNotificationManagerImpl.java +++ b/chrome/browser/commerce/price_tracking/android/java/src/org/chromium/chrome/browser/price_tracking/PriceDropNotificationManagerImpl.java
@@ -32,6 +32,7 @@ import org.chromium.chrome.browser.bookmarks.BookmarkModel; import org.chromium.chrome.browser.bookmarks.BookmarkModelObserver; import org.chromium.chrome.browser.browserservices.intents.WebappConstants; +import org.chromium.chrome.browser.commerce.ShoppingFeatures; import org.chromium.chrome.browser.commerce.ShoppingServiceFactory; import org.chromium.chrome.browser.document.ChromeLauncherActivity; import org.chromium.chrome.browser.init.ChromeBrowserInitializer; @@ -162,13 +163,15 @@ @Override public boolean isEnabled() { - return PriceTrackingFeatures.getPriceTrackingNotificationsEnabled(); + return true; } @Override public boolean canPostNotification() { - if (!areAppNotificationsEnabled() - || !PriceTrackingFeatures.isPriceDropNotificationEligible()) { + // Currently we only post notifications for explicit price tracking which is gated by the + // "shopping list" feature flag. When we start implicit price tracking, we should use a + // separate flag and add the check on it here. + if (!areAppNotificationsEnabled() || !ShoppingFeatures.isShoppingListEligible()) { return false; } @@ -184,7 +187,7 @@ @Override public boolean canPostNotificationWithMetricsRecorded() { - if (!PriceTrackingFeatures.isPriceDropNotificationEligible()) return false; + if (!ShoppingFeatures.isShoppingListEligible()) return false; boolean isSystemNotificationEnabled = areAppNotificationsEnabled(); RecordHistogram.recordBooleanHistogram( NOTIFICATION_ENABLED_HISTOGRAM, isSystemNotificationEnabled);
diff --git a/chrome/browser/commerce/price_tracking/android/java/src/org/chromium/chrome/browser/price_tracking/PriceTrackingFeatures.java b/chrome/browser/commerce/price_tracking/android/java/src/org/chromium/chrome/browser/price_tracking/PriceTrackingFeatures.java index 0627d03..01257c4 100644 --- a/chrome/browser/commerce/price_tracking/android/java/src/org/chromium/chrome/browser/price_tracking/PriceTrackingFeatures.java +++ b/chrome/browser/commerce/price_tracking/android/java/src/org/chromium/chrome/browser/price_tracking/PriceTrackingFeatures.java
@@ -20,8 +20,6 @@ @VisibleForTesting public static final String PRICE_TRACKING_PARAM = "enable_price_tracking"; @VisibleForTesting - public static final String PRICE_NOTIFICATION_PARAM = "enable_price_notification"; - @VisibleForTesting public static final String ALLOW_DISABLE_PRICE_ANNOTATIONS_PARAM = "allow_disable_price_annotations"; @VisibleForTesting @@ -44,17 +42,6 @@ } /** - * @return whether or not price tracking notifications are enabled. - */ - public static boolean getPriceTrackingNotificationsEnabled() { - if (FeatureList.isInitialized()) { - return ChromeFeatureList.getFieldTrialParamByFeatureAsBoolean( - ChromeFeatureList.COMMERCE_PRICE_TRACKING, PRICE_NOTIFICATION_PARAM, false); - } - return false; - } - - /** * @return Whether the price tracking feature is eligible to work. Now it is used to determine * whether the menu item "track prices" is visible and whether the tab has {@link * TabProperties#SHOPPING_PERSISTED_TAB_DATA_FETCHER}. @@ -70,14 +57,7 @@ * @return Whether the price tracking feature is enabled and available for use. */ public static boolean isPriceTrackingEnabled() { - return getPriceTrackingEnabled() || getPriceTrackingNotificationsEnabled(); - } - - /** - * @return Whether the price drop notification is eligible to work. - */ - public static boolean isPriceDropNotificationEligible() { - return isPriceTrackingEligible() && getPriceTrackingNotificationsEnabled(); + return getPriceTrackingEnabled(); } private static boolean isSignedIn() {
diff --git a/chrome/browser/commerce/price_tracking/android/java/src/org/chromium/chrome/browser/price_tracking/PriceTrackingUtilities.java b/chrome/browser/commerce/price_tracking/android/java/src/org/chromium/chrome/browser/price_tracking/PriceTrackingUtilities.java index dd39d31..b758917 100644 --- a/chrome/browser/commerce/price_tracking/android/java/src/org/chromium/chrome/browser/price_tracking/PriceTrackingUtilities.java +++ b/chrome/browser/commerce/price_tracking/android/java/src/org/chromium/chrome/browser/price_tracking/PriceTrackingUtilities.java
@@ -99,8 +99,7 @@ * PriceDropNotificationManager#canPostNotification()}. */ public static boolean isPriceAlertsMessageCardEnabled() { - return PriceTrackingFeatures.isPriceDropNotificationEligible() - && isImplicitSubscriptionsEnabled() + return isImplicitSubscriptionsEnabled() && SHARED_PREFERENCES_MANAGER.readBoolean( PRICE_ALERTS_MESSAGE_CARD, PriceTrackingFeatures.isPriceTrackingEnabled()); }
diff --git a/chrome/browser/commerce/price_tracking/android/javatests/src/org/chromium/chrome/browser/price_tracking/PriceDropNotificationManagerTest.java b/chrome/browser/commerce/price_tracking/android/javatests/src/org/chromium/chrome/browser/price_tracking/PriceDropNotificationManagerTest.java index 01c45f0..304e7ce 100644 --- a/chrome/browser/commerce/price_tracking/android/javatests/src/org/chromium/chrome/browser/price_tracking/PriceDropNotificationManagerTest.java +++ b/chrome/browser/commerce/price_tracking/android/javatests/src/org/chromium/chrome/browser/price_tracking/PriceDropNotificationManagerTest.java
@@ -42,6 +42,7 @@ import org.chromium.base.test.util.CommandLineFlags; import org.chromium.chrome.browser.bookmarks.BookmarkModel; import org.chromium.chrome.browser.browserservices.intents.WebappConstants; +import org.chromium.chrome.browser.commerce.ShoppingFeatures; import org.chromium.chrome.browser.commerce.ShoppingServiceFactory; import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.flags.ChromeSwitches; @@ -68,8 +69,7 @@ @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, "enable-features=" + ChromeFeatureList.COMMERCE_PRICE_TRACKING + "<Study", "force-fieldtrials=Study/Group", - "force-fieldtrial-params=Study.Group:enable_price_notification/true" - + "/user_managed_notification_max_number/2"}) + "force-fieldtrial-params=Study.Group:user_managed_notification_max_number/2"}) @Features.DisableFeatures({ChromeFeatureList.START_SURFACE_ANDROID}) public class PriceDropNotificationManagerTest { // clang-format on @@ -115,6 +115,7 @@ PriceDropNotificationManagerImpl.setBookmarkModelForTesting(mMockBookmarkModel); ShoppingServiceFactory.setShoppingServiceForTesting(mMockShoppingService); Profile.setLastUsedProfileForTesting(mMockProfile); + ShoppingFeatures.setShoppingListEligibleForTesting(true); } @After @@ -123,6 +124,7 @@ mPriceDropNotificationManager.deleteChannelForTesting(); } PriceDropNotificationManagerImpl.setNotificationManagerForTesting(null); + ShoppingFeatures.setShoppingListEligibleForTesting(null); } private void verifyClickIntent(Intent intent) { @@ -144,8 +146,7 @@ @MediumTest public void testCanPostNotification_FeatureDisabled() { mMockNotificationManager.setNotificationsEnabled(true); - PriceTrackingFeatures.setIsSignedInAndSyncEnabledForTesting(false); - assertFalse(PriceTrackingFeatures.isPriceTrackingEligible()); + ShoppingFeatures.setShoppingListEligibleForTesting(false); assertFalse(mPriceDropNotificationManager.canPostNotification()); assertFalse(mPriceDropNotificationManager.canPostNotificationWithMetricsRecorded()); } @@ -164,7 +165,6 @@ @MediumTest public void testCanPostNotificaton() { PriceTrackingFeatures.setIsSignedInAndSyncEnabledForTesting(true); - assertTrue(PriceTrackingFeatures.isPriceTrackingEligible()); mMockNotificationManager.setNotificationsEnabled(true); assertTrue(mPriceDropNotificationManager.areAppNotificationsEnabled());
diff --git a/chrome/browser/commerce/subscriptions/android/BUILD.gn b/chrome/browser/commerce/subscriptions/android/BUILD.gn index a7e5931c..2291470a 100644 --- a/chrome/browser/commerce/subscriptions/android/BUILD.gn +++ b/chrome/browser/commerce/subscriptions/android/BUILD.gn
@@ -16,6 +16,7 @@ "//base:jni_java", "//build/android:build_java", "//chrome/browser/android/lifecycle:java", + "//chrome/browser/commerce/android:java", "//chrome/browser/commerce/price_tracking/android:java", "//chrome/browser/endpoint_fetcher:java", "//chrome/browser/flags:java",
diff --git a/chrome/browser/commerce/subscriptions/android/java/src/org/chromium/chrome/browser/subscriptions/CommerceSubscriptionsService.java b/chrome/browser/commerce/subscriptions/android/java/src/org/chromium/chrome/browser/subscriptions/CommerceSubscriptionsService.java index bd9d47bf9..893618a 100644 --- a/chrome/browser/commerce/subscriptions/android/java/src/org/chromium/chrome/browser/subscriptions/CommerceSubscriptionsService.java +++ b/chrome/browser/commerce/subscriptions/android/java/src/org/chromium/chrome/browser/subscriptions/CommerceSubscriptionsService.java
@@ -12,7 +12,6 @@ import org.chromium.chrome.browser.preferences.ChromePreferenceKeys; import org.chromium.chrome.browser.preferences.SharedPreferencesManager; import org.chromium.chrome.browser.price_tracking.PriceDropNotificationManager; -import org.chromium.chrome.browser.price_tracking.PriceTrackingFeatures; import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.components.commerce.core.ShoppingService; @@ -92,7 +91,7 @@ } mSharedPreferencesManager.writeLong( CHROME_MANAGED_SUBSCRIPTIONS_TIMESTAMP, System.currentTimeMillis()); - if (!PriceTrackingFeatures.isPriceDropNotificationEligible()) return; + if (!mShoppingService.isShoppingListEligible()) return; recordMetricsForEligibleAccount(); if (mImplicitPriceDropSubscriptionsManager != null) { mImplicitPriceDropSubscriptionsManager.initializeSubscriptions();
diff --git a/chrome/browser/commerce/subscriptions/test/android/java/src/org/chromium/chrome/browser/subscriptions/CommerceSubscriptionsServiceUnitTest.java b/chrome/browser/commerce/subscriptions/test/android/java/src/org/chromium/chrome/browser/subscriptions/CommerceSubscriptionsServiceUnitTest.java index 77a7f32..6f1e0a4a 100644 --- a/chrome/browser/commerce/subscriptions/test/android/java/src/org/chromium/chrome/browser/subscriptions/CommerceSubscriptionsServiceUnitTest.java +++ b/chrome/browser/commerce/subscriptions/test/android/java/src/org/chromium/chrome/browser/subscriptions/CommerceSubscriptionsServiceUnitTest.java
@@ -9,6 +9,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -32,6 +33,7 @@ import org.chromium.base.metrics.UmaRecorderHolder; import org.chromium.base.test.BaseRobolectricTestRunner; import org.chromium.base.test.util.JniMocker; +import org.chromium.chrome.browser.commerce.ShoppingFeatures; import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher; import org.chromium.chrome.browser.lifecycle.PauseResumeWithNativeObserver; @@ -105,10 +107,11 @@ mTestValues = new FeatureList.TestValues(); mTestValues.addFeatureFlagOverride(ChromeFeatureList.COMMERCE_PRICE_TRACKING, true); - mTestValues.addFieldTrialParamOverride(ChromeFeatureList.COMMERCE_PRICE_TRACKING, - PriceTrackingFeatures.PRICE_NOTIFICATION_PARAM, "true"); FeatureList.setTestValues(mTestValues); + ShoppingFeatures.setShoppingListEligibleForTesting(true); + doReturn(true).when(mShoppingService).isShoppingListEligible(); + mMockNotificationManager = new MockNotificationManagerProxy(); mMockNotificationManager.setNotificationsEnabled(false); PriceDropNotificationManagerImpl.setNotificationManagerForTesting(mMockNotificationManager); @@ -126,6 +129,7 @@ @After public void tearDown() { PriceDropNotificationManagerImpl.setNotificationManagerForTesting(null); + ShoppingFeatures.setShoppingListEligibleForTesting(null); } @Test @@ -169,9 +173,7 @@ @Test @SmallTest public void testOnResume_FeatureDisabled() { - mTestValues.addFieldTrialParamOverride(ChromeFeatureList.COMMERCE_PRICE_TRACKING, - PriceTrackingFeatures.PRICE_NOTIFICATION_PARAM, "false"); - FeatureList.setTestValues(mTestValues); + doReturn(false).when(mShoppingService).isShoppingListEligible(); setupTestOnResume(); assertThat(RecordHistogram.getHistogramTotalCountForTesting(
diff --git a/chrome/browser/component_updater/pki_metadata_component_installer.cc b/chrome/browser/component_updater/pki_metadata_component_installer.cc index 860be16..404c6d7a 100644 --- a/chrome/browser/component_updater/pki_metadata_component_installer.cc +++ b/chrome/browser/component_updater/pki_metadata_component_installer.cc
@@ -138,8 +138,10 @@ cert_verifier::mojom::ChromeRootStore::New( base::as_bytes(base::make_span(chrome_root_store_bytes))); content::GetCertVerifierServiceFactory()->UpdateChromeRootStore( - std::move(root_store_ptr)); - NotifyChromeRootStoreConfigured(); + std::move(root_store_ptr), + base::BindOnce(&PKIMetadataComponentInstallerService:: + NotifyChromeRootStoreConfigured, + weak_factory_.GetWeakPtr())); } void PKIMetadataComponentInstallerService::NotifyChromeRootStoreConfigured() {
diff --git a/chrome/browser/extensions/service_worker_apitest.cc b/chrome/browser/extensions/service_worker_apitest.cc index 4f1d7268..3922cc8 100644 --- a/chrome/browser/extensions/service_worker_apitest.cc +++ b/chrome/browser/extensions/service_worker_apitest.cc
@@ -2566,34 +2566,27 @@ EXPECT_TRUE(moved_tab_listener.WaitUntilSatisfied()); } -// TODO(crbug.com/1319942): Test flaky on Linux. -#if BUILDFLAG(IS_LINUX) -#define MAYBE_PRE_WebRequestAfterRestart DISABLED_PRE_WebRequestAfterRestart -#define MAYBE_WebRequestAfterRestart DISABLED_WebRequestAfterRestart -#else -#define MAYBE_PRE_WebRequestAfterRestart PRE_WebRequestAfterRestart -#define MAYBE_WebRequestAfterRestart DISABLED_WebRequestAfterRestart -#endif +constexpr char kListenerAdded[] = "listener-added"; +using ServiceWorkerWebRequestEarlyListenerTest = + ServiceWorkerWithEarlyMessageListenerTest<kListenerAdded>; -IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, - MAYBE_PRE_WebRequestAfterRestart) { - ExtensionTestMessageListener event_added_listener("listener-added"); - +IN_PROC_BROWSER_TEST_F(ServiceWorkerWebRequestEarlyListenerTest, + PRE_WebRequestAfterRestart) { base::FilePath extension_path = test_data_dir_.AppendASCII("service_worker") .AppendASCII("worker_based_background") .AppendASCII("web_request_after_restart"); const Extension* extension = LoadExtension(extension_path, {.wait_for_registration_stored = true}); ASSERT_TRUE(extension); - EXPECT_TRUE(event_added_listener.WaitUntilSatisfied()); + EXPECT_TRUE(WaitForMessage()); } // After browser restarts, this test step ensures that navigating a tab fires // the webRequest listener. -IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, - MAYBE_WebRequestAfterRestart) { - ExtensionTestMessageListener event_added_listener("listener-added"); - EXPECT_TRUE(event_added_listener.WaitUntilSatisfied()); +IN_PROC_BROWSER_TEST_F(ServiceWorkerWebRequestEarlyListenerTest, + WebRequestAfterRestart) { + // Wait for the page to load. + EXPECT_TRUE(WaitForMessage()); // Navigate and expect the listener in the extension to be triggered. ResultCatcher catcher; ASSERT_TRUE(ui_test_utils::NavigateToURL(
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index dc166d04..5c167f9 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -348,11 +348,6 @@ "expiry_milestone": 112 }, { - "name": "ash-bento-bar", - "owners": [ "minch", "janetmac" ], - "expiry_milestone": 116 - }, - { "name": "ash-capture-mode-demo-tools", "owners": [ "michelefan", "gzadina" ], "expiry_milestone": 122 @@ -6401,11 +6396,6 @@ "expiry_milestone": -1 }, { - "name": "release-track-ui", - "owners": [ "rtinkoff", "cros-status-area-eng@google.com" ], - "expiry_milestone": 114 - }, - { "name": "remove-crash-infobar", "owners": [ "justincohen", "bling-flags@google.com"], "expiry_milestone": 115 @@ -6638,6 +6628,11 @@ "expiry_milestone": 118 }, { + "name": "share-sheet-custom-actions-polish", + "owners": [ "wenyufu" ], + "expiry_milestone": 121 + }, + { "name": "share-sheet-migration-android", "owners": [ "wenyufu" ], "expiry_milestone": 121
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index 63971204..42a10cb 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -646,11 +646,6 @@ "If enabled, allow pages to enter back/forward cache even if a screen " "reader is in use. The page might still not be cached for other reasons."; -const char kBentoBarName[] = "Persistent desks bar"; -const char kBentoBarDescription[] = - "Showing a persistent desks bar at the top of the screen in clamshell mode " - "when there are more than one desk."; - const char kBiometricReauthForPasswordFillingName[] = "Biometric reauth for password filling"; const char kBiometricReauthForPasswordFillingDescription[] = @@ -2073,12 +2068,6 @@ "When enabled, use Assistant for omnibox voice query recognition instead of" " Android's built-in voice recognition service. Only works on Android."; -const char kOmniboxBookmarkPathsName[] = "Omnibox Bookmark Paths"; -const char kOmniboxBookmarkPathsDescription[] = - "Allows inputs to match with bookmark paths. E.g. 'planets jupiter' can " - "suggest a bookmark titled 'Jupiter' with URL " - "'en.wikipedia.org/wiki/Jupiter' located in a path containing 'planet.'"; - const char kOmniboxCacheSuggestionResourcesName[] = "Omnibox cache suggestion resources"; const char kOmniboxCacheSuggestionResourcesDescription[] = @@ -4127,6 +4116,12 @@ "When enabled, sets the market URL for use in testing the update menu " "item."; +const char kShareSheetCustomActionsPolishName[] = + "Share sheet custom actions polish"; +const char kShareSheetCustomActionsPolishDescription[] = + "Polish Chrome provided custom actions for share sheet including dropping " + "low engagement actions, and shuffle the ordering. Android only."; + const char kShareSheetMigrationAndroidName[] = "Share sheet refactor Android"; const char kShareSheetMigrationAndroidDescription[] = "When enabled, use the Android OS share sheet."; @@ -6127,10 +6122,6 @@ const char kReleaseNotesNotificationAllChannelsDescription[] = "Enables the release notes notification for all ChromeOS channels"; -const char kReleaseTrackUiName[] = "Release track system tray UI"; -const char kReleaseTrackUiDescription[] = - "Enables the release track UI in the system tray"; - extern const char kRenderArcNotificationsByChromeName[] = "Render ARC notifications by ChromeOS"; extern const char kRenderArcNotificationsByChromeDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index 39a942bed..a46d951 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -348,9 +348,6 @@ extern const char kEnableBackForwardCacheForScreenReaderName[]; extern const char kEnableBackForwardCacheForScreenReaderDescription[]; -extern const char kBentoBarName[]; -extern const char kBentoBarDescription[]; - extern const char kBiometricReauthForPasswordFillingName[]; extern const char kBiometricReauthForPasswordFillingDescription[]; @@ -1166,9 +1163,6 @@ extern const char kOmniboxAssistantVoiceSearchName[]; extern const char kOmniboxAssistantVoiceSearchDescription[]; -extern const char kOmniboxBookmarkPathsName[]; -extern const char kOmniboxBookmarkPathsDescription[]; - extern const char kOmniboxCacheSuggestionResourcesName[]; extern const char kOmniboxCacheSuggestionResourcesDescription[]; @@ -2371,6 +2365,9 @@ extern const char kSetMarketUrlForTestingName[]; extern const char kSetMarketUrlForTestingDescription[]; +extern const char kShareSheetCustomActionsPolishName[]; +extern const char kShareSheetCustomActionsPolishDescription[]; + extern const char kShareSheetMigrationAndroidName[]; extern const char kShareSheetMigrationAndroidDescription[]; @@ -3522,9 +3519,6 @@ extern const char kReleaseNotesNotificationAllChannelsName[]; extern const char kReleaseNotesNotificationAllChannelsDescription[]; -extern const char kReleaseTrackUiName[]; -extern const char kReleaseTrackUiDescription[]; - extern const char kRenderArcNotificationsByChromeName[]; extern const char kRenderArcNotificationsByChromeDescription[];
diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc index 06187f91..94b67411 100644 --- a/chrome/browser/flags/android/chrome_feature_list.cc +++ b/chrome/browser/flags/android/chrome_feature_list.cc
@@ -291,6 +291,7 @@ &kFeedPositionAndroid, &kSearchResumptionModuleAndroid, &kShareSheetMigrationAndroid, + &kShareSheetCustomActionsPolish, &kShouldIgnoreIntentSkipInternalCheck, &kSpecialLocaleWrapper, &kSpecialUserDecision, @@ -948,6 +949,10 @@ "ShowScrollableMVTOnNTPAndroid", base::FEATURE_DISABLED_BY_DEFAULT); +BASE_FEATURE(kShareSheetCustomActionsPolish, + "ShareSheetCustomActionsPolish", + base::FEATURE_DISABLED_BY_DEFAULT); + BASE_FEATURE(kShareSheetMigrationAndroid, "ShareSheetMigrationAndroid", base::FEATURE_DISABLED_BY_DEFAULT);
diff --git a/chrome/browser/flags/android/chrome_feature_list.h b/chrome/browser/flags/android/chrome_feature_list.h index bd90baf..c39dfe5c 100644 --- a/chrome/browser/flags/android/chrome_feature_list.h +++ b/chrome/browser/flags/android/chrome_feature_list.h
@@ -154,6 +154,7 @@ BASE_DECLARE_FEATURE(kSafeModeForCachedFlags); BASE_DECLARE_FEATURE(kSearchResumptionModuleAndroid); BASE_DECLARE_FEATURE(kShouldIgnoreIntentSkipInternalCheck); +BASE_DECLARE_FEATURE(kShareSheetCustomActionsPolish); BASE_DECLARE_FEATURE(kShareSheetMigrationAndroid); BASE_DECLARE_FEATURE(kSpecialLocaleWrapper); BASE_DECLARE_FEATURE(kSpecialUserDecision);
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java index 0905bff7..4958621 100644 --- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java +++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
@@ -460,6 +460,7 @@ public static final String SEARCH_RESUMPTION_MODULE_ANDROID = "SearchResumptionModuleAndroid"; public static final String SHOULD_IGNORE_INTENT_SKIP_INTERNAL_CHECK = "ShouldIgnoreIntentSkipInternalCheck"; + public static final String SHARE_SHEET_CUSTOM_ACTIONS_POLISH = "ShareSheetCustomActionsPolish"; public static final String SHARE_SHEET_MIGRATION_ANDROID = "ShareSheetMigrationAndroid"; public static final String SEND_TAB_TO_SELF_SIGNIN_PROMO = "SendTabToSelfSigninPromo"; public static final String SEND_TAB_TO_SELF_V2 = "SendTabToSelfV2";
diff --git a/chrome/browser/media/router/media_router_feature.cc b/chrome/browser/media/router/media_router_feature.cc index b2f5c6e..e0cd6be 100644 --- a/chrome/browser/media/router/media_router_feature.cc +++ b/chrome/browser/media/router/media_router_feature.cc
@@ -61,6 +61,9 @@ BASE_FEATURE(kFallbackToAudioTabMirroring, "FallbackToAudioTabMirroring", base::FEATURE_ENABLED_BY_DEFAULT); +BASE_FEATURE(kCastDialogStopButton, + "CastDialogStopButton", + base::FEATURE_DISABLED_BY_DEFAULT); #if BUILDFLAG(IS_CHROMEOS) BASE_FEATURE(kGlobalMediaControlsCastStartStop, "GlobalMediaControlsCastStartStop",
diff --git a/chrome/browser/media/router/media_router_feature.h b/chrome/browser/media/router/media_router_feature.h index 6a88842..03e15d47 100644 --- a/chrome/browser/media/router/media_router_feature.h +++ b/chrome/browser/media/router/media_router_feature.h
@@ -60,6 +60,10 @@ // fall back to audio tab mirroring when casting from the Global Media Controls. BASE_DECLARE_FEATURE(kFallbackToAudioTabMirroring); +// If enabled, a separate 'stop' button is shown for connected sinks in the Cast +// dialog instead of the entire sink button being a stop button. +BASE_DECLARE_FEATURE(kCastDialogStopButton); + // Registers |kMediaRouterCastAllowAllIPs| with local state pref |registry|. void RegisterLocalStatePrefs(PrefRegistrySimple* registry);
diff --git a/chrome/browser/metrics/variations/chrome_variations_service_client.cc b/chrome/browser/metrics/variations/chrome_variations_service_client.cc index 3ec4691..831d9bc5 100644 --- a/chrome/browser/metrics/variations/chrome_variations_service_client.cc +++ b/chrome/browser/metrics/variations/chrome_variations_service_client.cc
@@ -7,7 +7,6 @@ #include "base/feature_list.h" #include "build/build_config.h" #include "build/chromeos_buildflags.h" -#include "build/config/chromebox_for_meetings/buildflags.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/google/google_brand.h" #include "chrome/browser/metrics/variations/google_groups_updater_service_factory.h" @@ -95,15 +94,6 @@ #endif } -variations::Study::FormFactor -ChromeVariationsServiceClient::GetCurrentFormFactor() { -#if BUILDFLAG(PLATFORM_CFM) - return variations::Study::MEET_DEVICE; -#else - return variations::VariationsServiceClient::GetCurrentFormFactor(); -#endif -} - bool ChromeVariationsServiceClient::IsEnterprise() { #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) return base::IsEnterpriseDevice();
diff --git a/chrome/browser/metrics/variations/chrome_variations_service_client.h b/chrome/browser/metrics/variations/chrome_variations_service_client.h index daed8430..2644b0a 100644 --- a/chrome/browser/metrics/variations/chrome_variations_service_client.h +++ b/chrome/browser/metrics/variations/chrome_variations_service_client.h
@@ -32,7 +32,6 @@ scoped_refptr<network::SharedURLLoaderFactory> GetURLLoaderFactory() override; network_time::NetworkTimeTracker* GetNetworkTimeTracker() override; bool OverridesRestrictParameter(std::string* parameter) override; - variations::Study::FormFactor GetCurrentFormFactor() override; bool IsEnterprise() override; std::unique_ptr<variations::SeedResponse> TakeSeedFromNativeVariationsSeedStore() override;
diff --git a/chrome/browser/nearby_sharing/certificates/BUILD.gn b/chrome/browser/nearby_sharing/certificates/BUILD.gn index b15ed8f0..d0c46d6 100644 --- a/chrome/browser/nearby_sharing/certificates/BUILD.gn +++ b/chrome/browser/nearby_sharing/certificates/BUILD.gn
@@ -35,6 +35,7 @@ "//chrome/browser/nearby_sharing/logging", "//chrome/browser/nearby_sharing/proto", "//chromeos/ash/components/nearby/common/client", + "//chromeos/ash/components/nearby/common/proto", "//chromeos/ash/components/nearby/common/scheduling", "//chromeos/ash/services/nearby/public/mojom", "//components/leveldb_proto", @@ -60,6 +61,7 @@ ":certificates", "//base", "//chrome/browser/nearby_sharing/proto", + "//chromeos/ash/components/nearby/common/proto", "//chromeos/ash/services/nearby/public/mojom", "//components/leveldb_proto", "//components/prefs", @@ -90,6 +92,7 @@ "//chrome/browser/nearby_sharing/local_device_data:test_support", "//chrome/browser/nearby_sharing/proto", "//chromeos/ash/components/nearby/common/client", + "//chromeos/ash/components/nearby/common/proto", "//chromeos/ash/components/nearby/common/scheduling:test_support", "//chromeos/ash/services/nearby/public/mojom", "//components/leveldb_proto:test_support",
diff --git a/chrome/browser/nearby_sharing/certificates/nearby_share_certificate_storage_impl.cc b/chrome/browser/nearby_sharing/certificates/nearby_share_certificate_storage_impl.cc index e6783938..0386117 100644 --- a/chrome/browser/nearby_sharing/certificates/nearby_share_certificate_storage_impl.cc +++ b/chrome/browser/nearby_sharing/certificates/nearby_share_certificate_storage_impl.cc
@@ -128,7 +128,7 @@ return merged; } -base::Time TimestampToTime(nearbyshare::proto::Timestamp timestamp) { +base::Time TimestampToTime(ash::nearby::proto::Timestamp timestamp) { return base::Time::UnixEpoch() + base::Seconds(timestamp.seconds()) + base::Nanoseconds(timestamp.nanos()); }
diff --git a/chrome/browser/nearby_sharing/certificates/nearby_share_certificate_storage_impl_unittest.cc b/chrome/browser/nearby_sharing/certificates/nearby_share_certificate_storage_impl_unittest.cc index 91a4b2a..6b69ee3 100644 --- a/chrome/browser/nearby_sharing/certificates/nearby_share_certificate_storage_impl_unittest.cc +++ b/chrome/browser/nearby_sharing/certificates/nearby_share_certificate_storage_impl_unittest.cc
@@ -120,7 +120,7 @@ return certs; } -base::Time TimestampToTime(nearbyshare::proto::Timestamp timestamp) { +base::Time TimestampToTime(ash::nearby::proto::Timestamp timestamp) { return base::Time::UnixEpoch() + base::Seconds(timestamp.seconds()) + base::Nanoseconds(timestamp.nanos()); }
diff --git a/chrome/browser/nearby_sharing/certificates/nearby_share_decrypted_public_certificate.cc b/chrome/browser/nearby_sharing/certificates/nearby_share_decrypted_public_certificate.cc index bbd50e4f..95102ef 100644 --- a/chrome/browser/nearby_sharing/certificates/nearby_share_decrypted_public_certificate.cc +++ b/chrome/browser/nearby_sharing/certificates/nearby_share_decrypted_public_certificate.cc
@@ -9,7 +9,7 @@ #include "chrome/browser/nearby_sharing/certificates/common.h" #include "chrome/browser/nearby_sharing/certificates/constants.h" #include "chrome/browser/nearby_sharing/logging/logging.h" -#include "chrome/browser/nearby_sharing/proto/timestamp.pb.h" +#include "chromeos/ash/components/nearby/common/proto/timestamp.pb.h" #include "crypto/aead.h" #include "crypto/encryptor.h" #include "crypto/hmac.h"
diff --git a/chrome/browser/nearby_sharing/certificates/nearby_share_private_certificate.cc b/chrome/browser/nearby_sharing/certificates/nearby_share_private_certificate.cc index 02c51b0..0f9fc567 100644 --- a/chrome/browser/nearby_sharing/certificates/nearby_share_private_certificate.cc +++ b/chrome/browser/nearby_sharing/certificates/nearby_share_private_certificate.cc
@@ -17,7 +17,7 @@ #include "chrome/browser/nearby_sharing/certificates/constants.h" #include "chrome/browser/nearby_sharing/common/nearby_share_switches.h" #include "chrome/browser/nearby_sharing/logging/logging.h" -#include "chrome/browser/nearby_sharing/proto/timestamp.pb.h" +#include "chromeos/ash/components/nearby/common/proto/timestamp.pb.h" #include "crypto/aead.h" #include "crypto/ec_private_key.h" #include "crypto/ec_signature_creator.h"
diff --git a/chrome/browser/nearby_sharing/certificates/test_util.cc b/chrome/browser/nearby_sharing/certificates/test_util.cc index 48cad4bd..fe4319c5 100644 --- a/chrome/browser/nearby_sharing/certificates/test_util.cc +++ b/chrome/browser/nearby_sharing/certificates/test_util.cc
@@ -8,7 +8,7 @@ #include "base/no_destructor.h" #include "chrome/browser/nearby_sharing/certificates/constants.h" -#include "chrome/browser/nearby_sharing/proto/timestamp.pb.h" +#include "chromeos/ash/components/nearby/common/proto/timestamp.pb.h" #include "device/bluetooth/public/cpp/bluetooth_address.h" namespace {
diff --git a/chrome/browser/nearby_sharing/logging/BUILD.gn b/chrome/browser/nearby_sharing/logging/BUILD.gn index 5be04a2..866d2595 100644 --- a/chrome/browser/nearby_sharing/logging/BUILD.gn +++ b/chrome/browser/nearby_sharing/logging/BUILD.gn
@@ -14,6 +14,7 @@ deps = [ "//base", "//chrome/browser/nearby_sharing/common", + "//chromeos/ash/components/nearby/common/proto", ] } @@ -37,5 +38,6 @@ deps = [ "//base", "//chrome/browser/nearby_sharing/proto", + "//chromeos/ash/components/nearby/common/proto", ] }
diff --git a/chrome/browser/nearby_sharing/logging/proto_to_dictionary_conversion.cc b/chrome/browser/nearby_sharing/logging/proto_to_dictionary_conversion.cc index 48651254..b38688d 100644 --- a/chrome/browser/nearby_sharing/logging/proto_to_dictionary_conversion.cc +++ b/chrome/browser/nearby_sharing/logging/proto_to_dictionary_conversion.cc
@@ -76,7 +76,7 @@ } base::Value::Dict TimestampToReadableDictionary( - const nearbyshare::proto::Timestamp& timestamp) { + const ash::nearby::proto::Timestamp& timestamp) { base::Value::Dict dict; dict.Set("seconds", base::NumberToString(timestamp.seconds())); dict.Set("nanos", base::NumberToString(timestamp.nanos())); @@ -167,7 +167,7 @@ } base::Value::Dict FieldMaskToReadableDictionary( - const nearbyshare::proto::FieldMask& mask) { + const ash::nearby::proto::FieldMask& mask) { base::Value::Dict dict; base::Value::List paths_list; for (const auto& path : mask.paths()) {
diff --git a/chrome/browser/nearby_sharing/logging/proto_to_dictionary_conversion.h b/chrome/browser/nearby_sharing/logging/proto_to_dictionary_conversion.h index 11a6331..927d0b97 100644 --- a/chrome/browser/nearby_sharing/logging/proto_to_dictionary_conversion.h +++ b/chrome/browser/nearby_sharing/logging/proto_to_dictionary_conversion.h
@@ -10,9 +10,9 @@ #include "chrome/browser/nearby_sharing/proto/contact_rpc.pb.h" #include "chrome/browser/nearby_sharing/proto/device_rpc.pb.h" #include "chrome/browser/nearby_sharing/proto/encrypted_metadata.pb.h" -#include "chrome/browser/nearby_sharing/proto/field_mask.pb.h" #include "chrome/browser/nearby_sharing/proto/rpc_resources.pb.h" -#include "chrome/browser/nearby_sharing/proto/timestamp.pb.h" +#include "chromeos/ash/components/nearby/common/proto/field_mask.pb.h" +#include "chromeos/ash/components/nearby/common/proto/timestamp.pb.h" // Converts Nearby Share protos to readable, JSON-style dictionaries. base::Value::Dict ListPublicCertificatesRequestToReadableDictionary( @@ -22,7 +22,7 @@ base::Value::Dict PublicCertificateToReadableDictionary( const nearbyshare::proto::PublicCertificate& certificate); base::Value::Dict TimestampToReadableDictionary( - const nearbyshare::proto::Timestamp& timestamp); + const ash::nearby::proto::Timestamp& timestamp); base::Value::Dict ListContactPeopleRequestToReadableDictionary( const nearbyshare::proto::ListContactPeopleRequest& request); base::Value::Dict ListContactPeopleResponseToReadableDictionary( @@ -38,7 +38,7 @@ base::Value::Dict ContactToReadableDictionary( const nearbyshare::proto::Contact& contact); base::Value::Dict FieldMaskToReadableDictionary( - const nearbyshare::proto::FieldMask& mask); + const ash::nearby::proto::FieldMask& mask); base::Value::Dict UpdateDeviceResponseToReadableDictionary( const nearbyshare::proto::UpdateDeviceResponse& response); base::Value::Dict EncryptedMetadataToReadableDictionary(
diff --git a/chrome/browser/nearby_sharing/proto/BUILD.gn b/chrome/browser/nearby_sharing/proto/BUILD.gn index d92e33d..57637af 100644 --- a/chrome/browser/nearby_sharing/proto/BUILD.gn +++ b/chrome/browser/nearby_sharing/proto/BUILD.gn
@@ -7,15 +7,16 @@ assert(is_chromeos, "Nearby Share is CrOS only") proto_library("proto") { + proto_in_dir = "//" sources = [ "certificate_rpc.proto", "contact_rpc.proto", "device_rpc.proto", "encrypted_metadata.proto", - "field_mask.proto", "rpc_resources.proto", - "timestamp.proto", ] + + link_deps = [ "//chromeos/ash/components/nearby/common/proto" ] } proto_library("tachyon_proto") {
diff --git a/chrome/browser/nearby_sharing/proto/certificate_rpc.proto b/chrome/browser/nearby_sharing/proto/certificate_rpc.proto index e443337..37b06952 100644 --- a/chrome/browser/nearby_sharing/proto/certificate_rpc.proto +++ b/chrome/browser/nearby_sharing/proto/certificate_rpc.proto
@@ -12,7 +12,7 @@ option optimize_for = LITE_RUNTIME; -import "rpc_resources.proto"; +import "chrome/browser/nearby_sharing/proto/rpc_resources.proto"; // Request to list public certificate objects. message ListPublicCertificatesRequest {
diff --git a/chrome/browser/nearby_sharing/proto/contact_rpc.proto b/chrome/browser/nearby_sharing/proto/contact_rpc.proto index 2abeda5..9662ab7 100644 --- a/chrome/browser/nearby_sharing/proto/contact_rpc.proto +++ b/chrome/browser/nearby_sharing/proto/contact_rpc.proto
@@ -12,7 +12,7 @@ option optimize_for = LITE_RUNTIME; -import "rpc_resources.proto"; +import "chrome/browser/nearby_sharing/proto/rpc_resources.proto"; // Request to list ContactRecord of a user. message ListContactPeopleRequest {
diff --git a/chrome/browser/nearby_sharing/proto/device_rpc.proto b/chrome/browser/nearby_sharing/proto/device_rpc.proto index 489fb262..4a15b51 100644 --- a/chrome/browser/nearby_sharing/proto/device_rpc.proto +++ b/chrome/browser/nearby_sharing/proto/device_rpc.proto
@@ -12,8 +12,8 @@ option optimize_for = LITE_RUNTIME; -import "rpc_resources.proto"; -import "field_mask.proto"; +import "chrome/browser/nearby_sharing/proto/rpc_resources.proto"; +import "chromeos/ash/components/nearby/common/proto/field_mask.proto"; // The request used to register a [location.nearby.sharing.proto.Device] // with the server. @@ -24,7 +24,7 @@ // The FieldMask for updating specific columns in device table. For the // 'FieldMask' definition, see // https://developers.google.com/protocol-buffers/docs/reference/google.protobuf#fieldmask - FieldMask update_mask = 2; + ash.nearby.proto.FieldMask update_mask = 2; } // The response for UpdateDeviceRequest.
diff --git a/chrome/browser/nearby_sharing/proto/field_mask.proto b/chrome/browser/nearby_sharing/proto/field_mask.proto deleted file mode 100644 index 24343b49..0000000 --- a/chrome/browser/nearby_sharing/proto/field_mask.proto +++ /dev/null
@@ -1,43 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Copied from -// https://cs.chromium.org/chromium/src/third_party/protobuf/src/google/protobuf/field_mask.proto?rcl=b51864c7aae4372308052b9fd5c1913ceeee3884 - -syntax = "proto3"; - -package nearbyshare.proto; - -option optimize_for = LITE_RUNTIME; - -message FieldMask { - // The set of field mask paths. - repeated string paths = 1; -}
diff --git a/chrome/browser/nearby_sharing/proto/rpc_resources.proto b/chrome/browser/nearby_sharing/proto/rpc_resources.proto index d0ecbb6..49c8f65 100644 --- a/chrome/browser/nearby_sharing/proto/rpc_resources.proto +++ b/chrome/browser/nearby_sharing/proto/rpc_resources.proto
@@ -12,7 +12,7 @@ option optimize_for = LITE_RUNTIME; -import "timestamp.proto"; +import "chromeos/ash/components/nearby/common/proto/timestamp.proto"; // A SharedCertificate contains a secret key used when recognizing another // user's BLE advertisement and a public key used when establishing an encrypted @@ -35,10 +35,10 @@ bytes public_key = 3; // The time that certificate validity begins. - Timestamp start_time = 4; + ash.nearby.proto.Timestamp start_time = 4; // The time that certificate validity ends. - Timestamp end_time = 5; + ash.nearby.proto.Timestamp end_time = 5; // Indicates if this public certificate is only for selected contacts. bool for_selected_contacts = 6;
diff --git a/chrome/browser/nearby_sharing/proto/timestamp.proto b/chrome/browser/nearby_sharing/proto/timestamp.proto deleted file mode 100644 index 3b71ffee..0000000 --- a/chrome/browser/nearby_sharing/proto/timestamp.proto +++ /dev/null
@@ -1,51 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Copied from -// https://cs.chromium.org/chromium/src/third_party/protobuf/src/google/protobuf/timestamp.proto?rcl=b51864c7aae4372308052b9fd5c1913ceeee3884 - -syntax = "proto3"; - -package nearbyshare.proto; - -option optimize_for = LITE_RUNTIME; - -message Timestamp { - // Represents seconds of UTC time since Unix epoch - // 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to - // 9999-12-31T23:59:59Z inclusive. - int64 seconds = 1; - - // Non-negative fractions of a second at nanosecond resolution. Negative - // second values with fractions must still have non-negative nanos values - // that count forward in time. Must be from 0 to 999,999,999 - // inclusive. - int32 nanos = 2; -}
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc index a0456047..f4dcd6f 100644 --- a/chrome/browser/prefs/browser_prefs.cc +++ b/chrome/browser/prefs/browser_prefs.cc
@@ -814,6 +814,12 @@ const char kEasyUnlockHardlockState[] = "easy_unlock.hardlock_state"; #endif // BUILDFLAG(IS_CHROMEOS_ASH) +// Deprecated 04/2023. +#if BUILDFLAG(IS_CHROMEOS_ASH) +const char kBentoBarEnabled[] = "ash.bento_bar.enabled"; +const char kUserHasUsedDesksRecently[] = "ash.user_has_used_desks_recently"; +#endif // BUILDFLAG(IS_CHROMEOS_ASH) + // Register local state used only for migration (clearing or moving to a new // key). void RegisterLocalStatePrefsForMigration(PrefRegistrySimple* registry) { @@ -1103,6 +1109,12 @@ #if BUILDFLAG(IS_WIN) registry->RegisterBooleanPref(kWebAuthnLastOperationWasNativeAPI, false); #endif + +// Deprecated 04/2023. +#if BUILDFLAG(IS_CHROMEOS_ASH) + registry->RegisterBooleanPref(kBentoBarEnabled, false); + registry->RegisterBooleanPref(kUserHasUsedDesksRecently, false); +#endif // BUILDFLAG(IS_CHROMEOS_ASH) } } // namespace @@ -2141,6 +2153,12 @@ profile_prefs->ClearPref(kWebAuthnLastOperationWasNativeAPI); #endif +// Added 04/2023. +#if BUILDFLAG(IS_CHROMEOS_ASH) + profile_prefs->ClearPref(kBentoBarEnabled); + profile_prefs->ClearPref(kUserHasUsedDesksRecently); +#endif // BUILDFLAG(IS_CHROMEOS_ASH) + // Please don't delete the following line. It is used by PRESUBMIT.py. // END_MIGRATE_OBSOLETE_PROFILE_PREFS
diff --git a/chrome/browser/preloading/prefetch/search_prefetch/field_trial_settings.cc b/chrome/browser/preloading/prefetch/search_prefetch/field_trial_settings.cc index 5c45897..7aea33d 100644 --- a/chrome/browser/preloading/prefetch/search_prefetch/field_trial_settings.cc +++ b/chrome/browser/preloading/prefetch/search_prefetch/field_trial_settings.cc
@@ -97,7 +97,7 @@ BASE_FEATURE(kSearchPrefetchOnlyAllowDefaultMatchPreloading, "SearchPrefetchOnlyAllowDefaultMatchPreloading", - base::FEATURE_DISABLED_BY_DEFAULT); + base::FEATURE_ENABLED_BY_DEFAULT); bool OnlyAllowDefaultMatchPreloading() { return base::FeatureList::IsEnabled(
diff --git a/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_browser_test_base.cc b/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_browser_test_base.cc index 728c0fe..465b3e9 100644 --- a/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_browser_test_base.cc +++ b/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_browser_test_base.cc
@@ -429,5 +429,6 @@ match.keyword = base::UTF8ToUTF16(original_query); if (prefetch_hint) match.RecordAdditionalInfo("should_prefetch", "true"); + match.allowed_to_be_default_match = true; return match; }
diff --git a/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service.cc b/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service.cc index 3e95879..180201c 100644 --- a/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service.cc +++ b/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service.cc
@@ -360,12 +360,10 @@ return true; } -void SearchPrefetchService::OnURLOpenedFromOmnibox( - OmniboxLog* log, - content::WebContents* web_contents) { - DCHECK(web_contents); - if (!log) +void SearchPrefetchService::OnURLOpenedFromOmnibox(OmniboxLog* log) { + if (!log) { return; + } const GURL& opened_url = log->final_destination_url; auto& match = log->result->match_at(log->selected_index);
diff --git a/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service.h b/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service.h index d88300e..fbb7d9cb 100644 --- a/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service.h +++ b/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service.h
@@ -207,8 +207,7 @@ // If the navigation URL matches with a prefetch that can be served, this // function marks that prefetch as clicked to prevent deletion when omnibox // closes. - void OnURLOpenedFromOmnibox(OmniboxLog* log, - content::WebContents* web_contents); + void OnURLOpenedFromOmnibox(OmniboxLog* log); // Fires all timers. void FireAllExpiryTimerForTesting();
diff --git a/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service_browsertest.cc b/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service_browsertest.cc index 70a81979..ae71c0e 100644 --- a/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service_browsertest.cc +++ b/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service_browsertest.cc
@@ -65,7 +65,6 @@ namespace { constexpr char kOmniboxSuggestPrefetchQuery[] = "porgs"; -constexpr char kOmniboxSuggestPrefetchSecondItemQuery[] = "porgsandwich"; constexpr char kOmniboxSuggestNonPrefetchQuery[] = "puffins"; constexpr char kOmniboxErrorQuery[] = "502_on_prefetch"; constexpr char16_t kOmniboxSuggestNonPrefetchQuery16[] = u"puffins"; @@ -1918,54 +1917,6 @@ } IN_PROC_BROWSER_TEST_P(SearchPrefetchServiceEnabledBrowserTest, - OmniboxEditTriggersPrefetchForSecondMatch) { - // phi being set to one causes the order of prefetch suggest to be different. - // This should still prefetch a result for the |kOmniboxSuggestPrefetchQuery|. - AddNewSuggestionRule( - kOmniboxSuggestPrefetchQuery, - {kOmniboxSuggestPrefetchQuery, kOmniboxSuggestPrefetchSecondItemQuery}, - /*prefetch_index=*/1, /*prerender_index=*/-1); - auto* search_prefetch_service = - SearchPrefetchServiceFactory::GetForProfile(browser()->profile()); - std::string search_terms = kOmniboxSuggestPrefetchQuery; - - // Trigger an omnibox suggest fetch that has a prefetch hint. - AutocompleteInput input( - base::ASCIIToUTF16(search_terms), metrics::OmniboxEventProto::BLANK, - ChromeAutocompleteSchemeClassifier(browser()->profile())); - LocationBar* location_bar = browser()->window()->GetLocationBar(); - OmniboxView* omnibox = location_bar->GetOmniboxView(); - AutocompleteController* autocomplete_controller = - omnibox->model()->autocomplete_controller(); - - // Prevent the stop timer from killing the hints fetch early. - autocomplete_controller->SetStartStopTimerDurationForTesting( - base::Seconds(10)); - autocomplete_controller->Start(input); - - ui_test_utils::WaitForAutocompleteDone(browser()); - EXPECT_TRUE(autocomplete_controller->done()); - GURL canonical_search_url = GetCanonicalSearchURL( - autocomplete_controller->result().match_at(1).destination_url); - WaitUntilStatusChangesTo(canonical_search_url, - SearchPrefetchStatus::kComplete); - auto prefetch_status = - search_prefetch_service->GetSearchPrefetchStatusForTesting( - canonical_search_url); - ASSERT_TRUE(prefetch_status.has_value()); - EXPECT_EQ(SearchPrefetchStatus::kComplete, prefetch_status.value()); - - ASSERT_TRUE(ui_test_utils::NavigateToURL( - browser(), - GetSearchServerQueryURL(kOmniboxSuggestPrefetchSecondItemQuery))); - - auto inner_html = GetDocumentInnerHTML(); - - EXPECT_FALSE(base::Contains(inner_html, "regular")); - EXPECT_TRUE(base::Contains(inner_html, "prefetch")); -} - -IN_PROC_BROWSER_TEST_P(SearchPrefetchServiceEnabledBrowserTest, RemovingMatchCancelsInFlight) { set_service_deferral_type( SearchPreloadTestResponseDeferralType::kDeferHeader); @@ -3783,7 +3734,7 @@ std::string search_terms = kOmniboxErrorQuery; std::string user_input = "terms"; AddNewSuggestionRule(user_input, {user_input, search_terms}, - /*prefetch_index=*/1, /*prerender_index=*/-1); + /*prefetch_index=*/-1, /*prerender_index=*/-1); // Trigger an omnibox suggest fetch that does not have a prefetch hint. AutocompleteInput input( @@ -3801,9 +3752,12 @@ ui_test_utils::WaitForAutocompleteDone(browser()); EXPECT_TRUE(autocomplete_controller->done()); - GURL canonical_search_url = GetCanonicalSearchURL( - autocomplete_controller->result().match_at(1).destination_url); + GURL prefetch_url = GetSearchServerQueryURL(search_terms); + GURL canonical_search_url = GetCanonicalSearchURL(prefetch_url); + + EXPECT_TRUE(search_prefetch_service->MaybePrefetchURL(prefetch_url, + GetWebContents())); WaitUntilStatusChangesTo(canonical_search_url, SearchPrefetchStatus::kRequestFailed); auto prefetch_status = @@ -3829,7 +3783,7 @@ std::string search_terms = "terms of service"; std::string user_input = "terms"; AddNewSuggestionRule(user_input, {user_input, search_terms}, - /*prefetch_index=*/1, /*prerender_index=*/-1); + /*prefetch_index=*/-1, /*prerender_index=*/-1); // Trigger an omnibox suggest fetch that does not have a prefetch hint. AutocompleteInput input( @@ -3847,8 +3801,12 @@ ui_test_utils::WaitForAutocompleteDone(browser()); EXPECT_TRUE(autocomplete_controller->done()); - GURL canonical_search_url = GetCanonicalSearchURL( - autocomplete_controller->result().match_at(1).destination_url); + + GURL prefetch_url = GetSearchServerQueryURL(search_terms); + GURL canonical_search_url = GetCanonicalSearchURL(prefetch_url); + + EXPECT_TRUE(search_prefetch_service->MaybePrefetchURL(prefetch_url, + GetWebContents())); WaitUntilStatusChangesTo(canonical_search_url, SearchPrefetchStatus::kComplete);
diff --git a/chrome/browser/preloading/prefetch/search_prefetch/search_preload_unified_browsertest.cc b/chrome/browser/preloading/prefetch/search_prefetch/search_preload_unified_browsertest.cc index 07f1b19b..d090ebe 100644 --- a/chrome/browser/preloading/prefetch/search_prefetch/search_preload_unified_browsertest.cc +++ b/chrome/browser/preloading/prefetch/search_prefetch/search_preload_unified_browsertest.cc
@@ -280,6 +280,7 @@ metrics::OmniboxEventProto::BLANK, ChromeAutocompleteSchemeClassifier( chrome_test_utils::GetProfile(this))); + AutocompleteMatch autocomplete_match = CreateSearchSuggestionMatch( original_query, search_terms, prerender_hint, prefetch_hint); AutocompleteResult autocomplete_result; @@ -384,6 +385,7 @@ if (prefetch_hint == PrefetchHint::kEnabled) { match.RecordAdditionalInfo("should_prefetch", "true"); } + match.allowed_to_be_default_match = true; return match; } @@ -477,13 +479,18 @@ Preloading_Prediction::kEntryName, content::test::kPreloadingPredictionUkmMetrics); EXPECT_EQ(attempt_ukm_entries.size(), 2u); - EXPECT_EQ(prediction_ukm_entries.size(), 1u); + EXPECT_EQ(prediction_ukm_entries.size(), 2u); // Prerender should succeed and should be used for the next navigation. std::vector<UkmEntry> expected_prediction_entries = { prediction_entry_builder().BuildEntry(ukm_source_id, /*confidence=*/80, /*accurate_prediction=*/true), + std::make_unique<content::test::PreloadingPredictionUkmEntryBuilder>( + chrome_preloading_predictor::kOmniboxSearchSuggestDefaultMatch) + ->BuildEntry(ukm_source_id, + /*confidence=*/80, + /*accurate_prediction=*/true), }; std::vector<UkmEntry> expected_attempt_entries = { attempt_entry_builder().BuildEntry(
diff --git a/chrome/browser/resources/new_tab_page/realbox/realbox.html b/chrome/browser/resources/new_tab_page/realbox/realbox.html index a4cbc43..8cd5a298 100644 --- a/chrome/browser/resources/new_tab_page/realbox/realbox.html +++ b/chrome/browser/resources/new_tab_page/realbox/realbox.html
@@ -227,8 +227,8 @@ can-show-secondary-side="[[canShowSecondarySide]]" had-secondary-side="{{hadSecondarySide}}" has-secondary-side="{{hasSecondarySide}}" - on-result-repaint="onResultRepaint_" on-match-focusin="onMatchFocusin_" - on-match-click="onMatchClick_" on-match-remove="onMatchRemove_" - on-header-focusin="onHeaderFocusin_" hidden$="[[!matchesAreVisible]]"> + on-match-focusin="onMatchFocusin_" on-match-click="onMatchClick_" + on-match-remove="onMatchRemove_" on-header-focusin="onHeaderFocusin_" + hidden$="[[!matchesAreVisible]]"> </cr-realbox-dropdown> </div>
diff --git a/chrome/browser/resources/new_tab_page/realbox/realbox.ts b/chrome/browser/resources/new_tab_page/realbox/realbox.ts index 4a9b5dbe..e6ecdedf 100644 --- a/chrome/browser/resources/new_tab_page/realbox/realbox.ts +++ b/chrome/browser/resources/new_tab_page/realbox/realbox.ts
@@ -125,15 +125,6 @@ //======================================================================== /** - * The time of the first character insert operation that has not yet been - * painted in milliseconds. Used to measure the realbox responsiveness. - */ - charTypedTime_: { - type: Number, - value: 0, - }, - - /** * Whether user is deleting text in the input. Used to prevent the default * match from offering inline autocompletion. */ @@ -234,7 +225,6 @@ matchSearchbox: boolean; realboxLensSearchEnabled: boolean; singleColoredIcons: boolean; - private charTypedTime_: number; private inputAriaLive_: string; private isDeletingInput_: boolean; private lastIgnoredEnterEvent_: KeyboardEvent|null; @@ -384,18 +374,11 @@ this.updateInput_({text: inputValue, inline: ''}); - const charTyped = !this.isDeletingInput_ && !!inputValue.trim(); - // If a character has been typed, update |charTypedTime_|. Otherwise reset - // it. If |charTypedTime_| is not 0, there's a pending typed character for - // which the results have not been painted yet. In that case, keep the - // earlier time. - this.charTypedTime_ = - charTyped ? this.charTypedTime_ || window.performance.now() : 0; - // If a character has been typed, mark 'CharTyped'. Otherwise clear it. If // 'CharTyped' mark already exists, there's a pending typed character for // which the results have not been painted yet. In that case, keep the // earlier mark. + const charTyped = !this.isDeletingInput_ && !!inputValue.trim(); const metricsReporter = MetricsReporterImpl.getInstance(); if (charTyped) { if (!metricsReporter.hasLocalMark('CharTyped')) { @@ -442,11 +425,6 @@ inline: this.lastInput_.inline.substr(1), }); - // If |charTypedTime_| is not 0, there's a pending typed character for - // which the results have not been painted yet. In that case, keep the - // earlier time. - this.charTypedTime_ = this.charTypedTime_ || window.performance.now(); - // If 'CharTyped' mark already exists, there's a pending typed character // for which the results have not been painted yet. In that case, keep the // earlier mark. @@ -660,17 +638,6 @@ this.pageHandler_.deleteAutocompleteMatch(e.detail); } - /** - * @param e Event containing the result repaint time. - */ - private onResultRepaint_(e: CustomEvent<number>) { - if (this.charTypedTime_) { - this.pageHandler_.logCharTypedToRepaintLatency( - mojoTimeDelta(e.detail - this.charTypedTime_)); - this.charTypedTime_ = 0; - } - } - private onVoiceSearchClick_() { this.dispatchEvent(new Event('open-voice-search')); }
diff --git a/chrome/browser/resources/settings/BUILD.gn b/chrome/browser/resources/settings/BUILD.gn index 38f2816..9122fb8 100644 --- a/chrome/browser/resources/settings/BUILD.gn +++ b/chrome/browser/resources/settings/BUILD.gn
@@ -202,6 +202,8 @@ "site_settings/chooser_exception_list.ts", "site_settings/site_details_permission_device_entry.ts", "site_settings/edit_exception_dialog.ts", + "site_settings/file_system_site_entry.ts", + "site_settings/file_system_site_entry_item.ts", "site_settings/file_system_site_list.ts", "site_settings/media_picker.ts", "site_settings/review_notification_permissions.ts",
diff --git a/chrome/browser/resources/settings/chromeos/device_page/keyboard_remap_modifier_key_row.ts b/chrome/browser/resources/settings/chromeos/device_page/keyboard_remap_modifier_key_row.ts index 6155d7b6..8c2d889 100644 --- a/chrome/browser/resources/settings/chromeos/device_page/keyboard_remap_modifier_key_row.ts +++ b/chrome/browser/resources/settings/chromeos/device_page/keyboard_remap_modifier_key_row.ts
@@ -178,7 +178,7 @@ this.keyMapTargets = [ { value: ModifierKey.kMeta, - name: this.metaKeyLabel, + name: this.i18n('keyboardKeySearch'), }, { value: ModifierKey.kControl,
diff --git a/chrome/browser/resources/settings/chromeos/device_page/per_device_keyboard_remap_keys.html b/chrome/browser/resources/settings/chromeos/device_page/per_device_keyboard_remap_keys.html index a5bd666..a15ef53 100644 --- a/chrome/browser/resources/settings/chromeos/device_page/per_device_keyboard_remap_keys.html +++ b/chrome/browser/resources/settings/chromeos/device_page/per_device_keyboard_remap_keys.html
@@ -20,7 +20,7 @@ default-remappings="[[defaultRemappings]]" key="[[modifierKey.kMeta]]" id="metaKey" meta-key="[[keyboard.metaKey]]" - aria-label="$i18n{keyboardKeyLauncher}" + aria-label="$i18n{keyboardKeySearch}" pref="{{fakeMetaPref}}"> </keyboard-remap-modifier-key-row> <keyboard-remap-modifier-key-row
diff --git a/chrome/browser/resources/settings/lazy_load.ts b/chrome/browser/resources/settings/lazy_load.ts index 5f5f8f8..7795af4 100644 --- a/chrome/browser/resources/settings/lazy_load.ts +++ b/chrome/browser/resources/settings/lazy_load.ts
@@ -34,6 +34,8 @@ import './privacy_page/security_keys_phones_dialog.js'; import './privacy_page/security_page.js'; import './site_settings/all_sites.js'; +import './site_settings/file_system_site_entry.js'; +import './site_settings/file_system_site_entry_item.js'; import './site_settings/file_system_site_list.js'; import './site_settings_page/site_settings_page.js'; import './site_settings/category_default_setting.js'; @@ -213,7 +215,9 @@ export {ChooserExceptionListEntryElement} from './site_settings/chooser_exception_list_entry.js'; export {ChooserType, ContentSetting, ContentSettingsTypes, CookieControlsMode, CookiesExceptionType, NotificationSetting, SITE_EXCEPTION_WILDCARD, SiteSettingSource, SortMethod} from './site_settings/constants.js'; export {SettingsEditExceptionDialogElement} from './site_settings/edit_exception_dialog.js'; -export {FileSystemSiteListElement, OriginFileSystemGrants} from './site_settings/file_system_site_list.js'; +export {FileSystemSiteEntryElement} from './site_settings/file_system_site_entry.js'; +export {FileSystemSiteEntryItemElement} from './site_settings/file_system_site_entry_item.js'; +export {FileSystemGrant, FileSystemSiteListElement, OriginFileSystemGrants} from './site_settings/file_system_site_list.js'; export {AppHandlerEntry, AppProtocolEntry, HandlerEntry, ProtocolEntry, ProtocolHandlersElement} from './site_settings/protocol_handlers.js'; export {SettingsReviewNotificationPermissionsElement} from './site_settings/review_notification_permissions.js'; export {SettingsCategoryDefaultRadioGroupElement} from './site_settings/settings_category_default_radio_group.js';
diff --git a/chrome/browser/resources/settings/site_settings/file_system_site_entry.html b/chrome/browser/resources/settings/site_settings/file_system_site_entry.html new file mode 100644 index 0000000..76de032 --- /dev/null +++ b/chrome/browser/resources/settings/site_settings/file_system_site_entry.html
@@ -0,0 +1,42 @@ +<style include="cr-shared-style settings-shared"> + .dropdown-row { + align-items: center; + display: flex; + } +</style> + +<div class="list-frame"> + <div class="dropdown-row"> + <site-favicon url="[[grantsPerOrigin.origin]]"></site-favicon> + <cr-expand-button id="dropdownButton" class="cr-row" + expanded="{{expanded_}}"> + [[grantsPerOrigin.origin]] + </cr-expand-button> + </div> + <iron-collapse id="collapseChild" expand-icon="cr:arrow-drop-down" + collapse-icon="cr:arrow-drop-up" opened="[[expanded_]]" no-animation + no-hover> + <!-- Edit Grants --> + <div> + <div hidden$="[[!grantsPerOrigin.editGrants.length]]"> + $i18n{siteSettingsFileSystemSiteListEditHeader} + </div> + <template is="dom-repeat" items="[[grantsPerOrigin.editGrants]]" + as="editGrant"> + <file-system-site-entry-item grant="[[editGrant]]"> + </file-system-site-entry-item> + </template> + </div> + <!-- View Grants --> + <div> + <div hidden$="[[!grantsPerOrigin.viewGrants.length]]"> + $i18n{siteSettingsFileSystemSiteListViewHeader} + </div> + <template is="dom-repeat" items="[[grantsPerOrigin.viewGrants]]" + as="viewGrant"> + <file-system-site-entry-item grant="[[viewGrant]]"> + </file-system-site-entry-item> + </template> + </div> + </iron-collapse> +</div> \ No newline at end of file
diff --git a/chrome/browser/resources/settings/site_settings/file_system_site_entry.ts b/chrome/browser/resources/settings/site_settings/file_system_site_entry.ts new file mode 100644 index 0000000..49fb7b7 --- /dev/null +++ b/chrome/browser/resources/settings/site_settings/file_system_site_entry.ts
@@ -0,0 +1,57 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview + * 'file-system-site-entry' is an element representing a single origin's + * permission grant(s), granted via the File System Access API. + */ +import 'chrome://resources/cr_elements/cr_expand_button/cr_expand_button.js'; +import 'chrome://resources/cr_elements/cr_shared_style.css.js'; +import 'chrome://resources/polymer/v3_0/iron-collapse/iron-collapse.js'; +import './file_system_site_entry_item.js'; +import '../settings_shared.css.js'; +import '../site_favicon.js'; + +import {CrExpandButtonElement} from 'chrome://resources/cr_elements/cr_expand_button/cr_expand_button.js'; +import {IronCollapseElement} from 'chrome://resources/polymer/v3_0/iron-collapse/iron-collapse.js'; +import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; + +import {getTemplate} from './file_system_site_entry.html.js'; +import {OriginFileSystemGrants} from './file_system_site_list.js'; + +export interface FileSystemSiteEntryElement { + $: { + collapseChild: IronCollapseElement, + dropdownButton: CrExpandButtonElement, + }; +} + +export class FileSystemSiteEntryElement extends PolymerElement { + static get is() { + return 'file-system-site-entry'; + } + + static get template() { + return getTemplate(); + } + + static get properties() { + return { + /** + * An Object representing an origin and its associated permission grants. + */ + grantsPerOrigin: Object, + }; + } + grantsPerOrigin: OriginFileSystemGrants; +} +declare global { + interface HTMLElementTagNameMap { + 'file-system-site-entry': FileSystemSiteEntryElement; + } +} + +customElements.define( + FileSystemSiteEntryElement.is, FileSystemSiteEntryElement);
diff --git a/chrome/browser/resources/settings/site_settings/file_system_site_entry_item.html b/chrome/browser/resources/settings/site_settings/file_system_site_entry_item.html new file mode 100644 index 0000000..ae02fe20 --- /dev/null +++ b/chrome/browser/resources/settings/site_settings/file_system_site_entry_item.html
@@ -0,0 +1,10 @@ +<style include="cr-shared-style settings-shared"></style> +<div class="start row-aligned list-item"> + <cr-icon-button class$="cr-icon [[getClassForListItem_(grant)]]"> + </cr-icon-button> + <div class="site-representation middle text-elide"> + <span class="display-name url-directionality text-elide"> + [[grant.displayName]] + </span> + </div> +</div> \ No newline at end of file
diff --git a/chrome/browser/resources/settings/site_settings/file_system_site_entry_item.ts b/chrome/browser/resources/settings/site_settings/file_system_site_entry_item.ts new file mode 100644 index 0000000..1b4de93 --- /dev/null +++ b/chrome/browser/resources/settings/site_settings/file_system_site_entry_item.ts
@@ -0,0 +1,51 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview + * 'file-system-site-entry-item' is an element representing a single + * permission grant for a given origin, granted via the File System Access API. + */ +import 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.js'; +import 'chrome://resources/cr_elements/cr_shared_style.css.js'; +import '../settings_shared.css.js'; + +import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; + +import {getTemplate} from './file_system_site_entry_item.html.js'; +import {FileSystemGrant} from './file_system_site_list.js'; + +export class FileSystemSiteEntryItemElement extends PolymerElement { + static get is() { + return 'file-system-site-entry-item'; + } + + static get template() { + return getTemplate(); + } + + static get properties() { + return { + /** + * An Object representing an origin and its associated permission grants. + */ + grant: Object, + }; + } + + grant: FileSystemGrant; + + private getClassForListItem_(): string { + return this.grant.isDirectory ? 'icon-folder-open' : 'icon-file'; + } +} + +declare global { + interface HTMLElementTagNameMap { + 'file-system-site-entry-item': FileSystemSiteEntryItemElement; + } +} + +customElements.define( + FileSystemSiteEntryItemElement.is, FileSystemSiteEntryItemElement);
diff --git a/chrome/browser/resources/settings/site_settings/file_system_site_list.html b/chrome/browser/resources/settings/site_settings/file_system_site_list.html index da46546..52caa51 100644 --- a/chrome/browser/resources/settings/site_settings/file_system_site_list.html +++ b/chrome/browser/resources/settings/site_settings/file_system_site_list.html
@@ -1,18 +1,4 @@ -<template is="dom-repeat" items="[[allowedGrants_]]" - as="allowedGrantsPerOrigin"> - <h2>[[allowedGrantsPerOrigin.origin]]</h2> - <div> - <h3>$i18n{siteSettingsFileSystemSiteListEditHeader}</h3> - <template is="dom-repeat" items="[[allowedGrantsPerOrigin.editGrants]]" - as="editGrant"> - <div class="display-name">[[editGrant.displayName]]</div> - </template> - </div> - <div> - <h3>$i18n{siteSettingsFileSystemSiteListViewHeader}</h3> - <template is="dom-repeat" items="[[allowedGrantsPerOrigin.viewGrants]]" - as="viewGrant"> - <div class="display-name">[[viewGrant.displayName]]</div> - </template> - </div> +<template is="dom-repeat" items="[[allowedGrants_]]" as="grantsPerOrigin"> + <file-system-site-entry grants-per-origin="[[grantsPerOrigin]]"> + </file-system-site-entry> </template> \ No newline at end of file
diff --git a/chrome/browser/resources/settings/site_settings/file_system_site_list.ts b/chrome/browser/resources/settings/site_settings/file_system_site_list.ts index d6a91df..f2c68ed2 100644 --- a/chrome/browser/resources/settings/site_settings/file_system_site_list.ts +++ b/chrome/browser/resources/settings/site_settings/file_system_site_list.ts
@@ -7,6 +7,7 @@ * 'file-system-site-list' is an element representing a list of origin-specific * permission entries for the File System Access API. */ +import './file_system_site_entry.js'; import {EventTracker} from 'chrome://resources/js/event_tracker.js'; import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; @@ -18,7 +19,7 @@ import {SiteSettingsMixin} from './site_settings_mixin.js'; import {RawFileSystemGrant} from './site_settings_prefs_browser_proxy.js'; -interface FileSystemGrant { +export interface FileSystemGrant { isDirectory: boolean; displayName: string; // Might be a shortened file path origin: string;
diff --git a/chrome/browser/sessions/session_restore.cc b/chrome/browser/sessions/session_restore.cc index b49e948..5cfac7c6 100644 --- a/chrome/browser/sessions/session_restore.cc +++ b/chrome/browser/sessions/session_restore.cc
@@ -12,6 +12,7 @@ #include <memory> #include <set> #include <string> +#include <utility> #include "base/command_line.h" #include "base/containers/flat_map.h" @@ -65,6 +66,8 @@ #include "chrome/browser/ui/startup/startup_browser_creator.h" #include "chrome/browser/ui/startup/startup_tab.h" #include "chrome/browser/ui/startup/startup_types.h" +#include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_keyed_service.h" +#include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_service_factory.h" #include "chrome/browser/ui/tabs/tab_group.h" #include "chrome/browser/ui/tabs/tab_group_model.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" @@ -674,15 +677,7 @@ // 6. Tabs will be grouped appropriately in RestoreTabsToBrowser. Now // restore the groups' visual data. - if (browser->tab_strip_model()->SupportsTabGroups()) { - TabGroupModel* group_model = browser->tab_strip_model()->group_model(); - for (auto& session_tab_group : (*i)->tab_groups) { - TabGroup* model_tab_group = - group_model->GetTabGroup(new_group_ids.at(session_tab_group->id)); - DCHECK(model_tab_group); - model_tab_group->SetVisualData(session_tab_group->visual_data); - } - } + RestoreTabGroupMetadata(browser, new_group_ids, (*i)->tab_groups); // 7. Notify SessionService of restored tabs, so they can be saved to the // current session. @@ -777,8 +772,9 @@ // each tab where the most recent tab will have its time set to |now| // and the rest of the tabs will have theirs set earlier by the same // delta as they originally had. - for (int i = 0; i < static_cast<int>(window.tabs.size()); ++i) { - const sessions::SessionTab& tab = *(window.tabs[i]); + for (const std::unique_ptr<sessions::SessionTab>& session_tab : + window.tabs) { + const sessions::SessionTab& tab = *session_tab; if (tab.last_active_time > latest_last_active_time) latest_last_active_time = tab.last_active_time; } @@ -882,6 +878,40 @@ web_contents)); } + void RestoreTabGroupMetadata( + const Browser* browser, + const base::flat_map<tab_groups::TabGroupId, tab_groups::TabGroupId>& + new_group_ids, + const std::vector<std::unique_ptr<sessions::SessionTabGroup>>& + tab_groups) { + if (!browser->tab_strip_model()->SupportsTabGroups()) { + return; + } + + TabGroupModel* group_model = browser->tab_strip_model()->group_model(); + SavedTabGroupKeyedService* const saved_tab_group_keyed_service = + base::FeatureList::IsEnabled(features::kTabGroupsSave) + ? SavedTabGroupServiceFactory::GetForProfile(browser->profile()) + : nullptr; + + for (const std::unique_ptr<sessions::SessionTabGroup>& session_tab_group : + tab_groups) { + if (session_tab_group->saved_guid.has_value() && + saved_tab_group_keyed_service) { + const base::GUID& saved_guid = + base::GUID::ParseLowercase(session_tab_group->saved_guid.value()); + + saved_tab_group_keyed_service->StoreLocalToSavedId( + saved_guid, new_group_ids.at(session_tab_group->id)); + } + + TabGroup* model_tab_group = + group_model->GetTabGroup(new_group_ids.at(session_tab_group->id)); + CHECK(model_tab_group); + model_tab_group->SetVisualData(session_tab_group->visual_data); + } + } + Browser* CreateRestoredBrowser( Browser::Type type, gfx::Rect bounds, @@ -1201,10 +1231,11 @@ bool SessionRestore::IsRestoring(const Profile* profile) { if (active_session_restorers == nullptr) return false; - for (auto it = active_session_restorers->begin(); - it != active_session_restorers->end(); ++it) { - if ((*it)->profile() == profile) + for (SessionRestoreImpl* const active_session_restorer : + *active_session_restorers) { + if (active_session_restorer->profile() == profile) { return true; + } } return false; } @@ -1213,10 +1244,11 @@ bool SessionRestore::IsRestoringSynchronously() { if (!active_session_restorers) return false; - for (auto it = active_session_restorers->begin(); - it != active_session_restorers->end(); ++it) { - if ((*it)->synchronous()) + for (const SessionRestoreImpl* const active_session_restorer : + *active_session_restorers) { + if (active_session_restorer->synchronous()) { return true; + } } return false; }
diff --git a/chrome/browser/sessions/session_service.cc b/chrome/browser/sessions/session_service.cc index 95cb08e0..6b5b8b9 100644 --- a/chrome/browser/sessions/session_service.cc +++ b/chrome/browser/sessions/session_service.cc
@@ -278,7 +278,8 @@ void SessionService::SetTabGroupMetadata( SessionID window_id, const tab_groups::TabGroupId& group_id, - const tab_groups::TabGroupVisualData* visual_data) { + const tab_groups::TabGroupVisualData* visual_data, + const absl::optional<std::string> saved_guid) { if (!ShouldTrackChangesToWindow(window_id)) return; @@ -287,8 +288,8 @@ base::Contains(window_closing_ids_, window_id)) return; - ScheduleCommand( - sessions::CreateTabGroupMetadataUpdateCommand(group_id, visual_data)); + ScheduleCommand(sessions::CreateTabGroupMetadataUpdateCommand( + group_id, visual_data, std::move(saved_guid))); } void SessionService::AddTabExtraData(SessionID window_id,
diff --git a/chrome/browser/sessions/session_service.h b/chrome/browser/sessions/session_service.h index c0f233a..d59c0c0b 100644 --- a/chrome/browser/sessions/session_service.h +++ b/chrome/browser/sessions/session_service.h
@@ -100,9 +100,11 @@ // Updates the metadata associated with a tab group. |window_id| should be // the window where the group currently resides. Note that a group can't be // split between multiple windows. - void SetTabGroupMetadata(SessionID window_id, - const tab_groups::TabGroupId& group_id, - const tab_groups::TabGroupVisualData* visual_data); + void SetTabGroupMetadata( + SessionID window_id, + const tab_groups::TabGroupId& group_id, + const tab_groups::TabGroupVisualData* visual_data, + const absl::optional<std::string> saved_guid = absl::nullopt); void AddTabExtraData(SessionID window_id, SessionID tab_id,
diff --git a/chrome/browser/sessions/session_service_base.cc b/chrome/browser/sessions/session_service_base.cc index dae84a7..7a304ec 100644 --- a/chrome/browser/sessions/session_service_base.cc +++ b/chrome/browser/sessions/session_service_base.cc
@@ -11,6 +11,7 @@ #include <vector> #include "base/command_line.h" +#include "base/feature_list.h" #include "base/functional/bind.h" #include "base/functional/callback_helpers.h" #include "base/task/sequenced_task_runner.h" @@ -26,8 +27,11 @@ #include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/startup/startup_browser_creator.h" +#include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_keyed_service.h" +#include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_service_factory.h" #include "chrome/browser/ui/tabs/tab_group.h" #include "chrome/browser/ui/tabs/tab_group_model.h" +#include "chrome/browser/ui/ui_features.h" #include "components/sessions/content/content_serialized_navigation_builder.h" #include "components/sessions/content/session_tab_helper.h" #include "components/sessions/core/command_storage_manager.h" @@ -616,12 +620,28 @@ TabStripModel* tab_strip = browser->tab_strip_model(); if (tab_strip->SupportsTabGroups()) { TabGroupModel* group_model = tab_strip->group_model(); + const SavedTabGroupKeyedService* const saved_tab_group_keyed_service = + base::FeatureList::IsEnabled(features::kTabGroupsSave) + ? SavedTabGroupServiceFactory::GetForProfile(browser->profile()) + : nullptr; + for (const tab_groups::TabGroupId& group_id : group_model->ListTabGroups()) { const tab_groups::TabGroupVisualData* visual_data = group_model->GetTabGroup(group_id)->visual_data(); + + absl::optional<std::string> saved_guid; + if (saved_tab_group_keyed_service) { + const SavedTabGroup* const saved_group = + saved_tab_group_keyed_service->model()->Get(group_id); + if (saved_group) { + saved_guid = saved_group->saved_guid().AsLowercaseString(); + } + } + command_storage_manager()->AppendRebuildCommand( - sessions::CreateTabGroupMetadataUpdateCommand(group_id, visual_data)); + sessions::CreateTabGroupMetadataUpdateCommand(group_id, visual_data, + std::move(saved_guid))); } }
diff --git a/chrome/browser/sessions/session_service_unittest.cc b/chrome/browser/sessions/session_service_unittest.cc index ab53a8c3..1ba59d1 100644 --- a/chrome/browser/sessions/session_service_unittest.cc +++ b/chrome/browser/sessions/session_service_unittest.cc
@@ -1200,6 +1200,8 @@ tab_groups::TabGroupColorId::kBlue), tab_groups::TabGroupVisualData(u"Bar", tab_groups::TabGroupColorId::kGreen)}; + const std::array<absl::optional<std::string>, kNumGroups> saved_guids = { + base::GUID::GenerateRandomV4().AsLowercaseString(), absl::nullopt}; // Create |kNumGroups| tab groups, each with one tab. for (int group_ndx = 0; group_ndx < kNumGroups; ++group_ndx) { @@ -1207,7 +1209,8 @@ CreateTabWithTestNavigationData(window_id, group_ndx); service()->SetTabGroup(window_id, tab_id, group_ids[group_ndx]); service()->SetTabGroupMetadata(window_id, group_ids[group_ndx], - &visual_data[group_ndx]); + &visual_data[group_ndx], + saved_guids[group_ndx]); } std::vector<std::unique_ptr<sessions::SessionWindow>> windows; @@ -1228,6 +1231,12 @@ const tab_groups::TabGroupId group_id = group_ids[group_ndx]; ASSERT_TRUE(base::Contains(tab_groups, group_id)); EXPECT_EQ(visual_data[group_ndx], tab_groups[group_id]->visual_data); + if (tab_groups[group_id]->saved_guid.has_value()) { + EXPECT_EQ(saved_guids[group_ndx], + tab_groups[group_id]->saved_guid.value()); + } else { + EXPECT_EQ(absl::nullopt, tab_groups[group_id]->saved_guid); + } } }
diff --git a/chrome/browser/share/android/java/res/layout/screenshot_share_sheet.xml b/chrome/browser/share/android/java/res/layout/screenshot_share_sheet.xml index dbe52b1..4ab0c07b 100644 --- a/chrome/browser/share/android/java/res/layout/screenshot_share_sheet.xml +++ b/chrome/browser/share/android/java/res/layout/screenshot_share_sheet.xml
@@ -40,7 +40,6 @@ android:layout_height="56dp" android:layout_marginStart="36dp" android:layout_marginEnd="36dp" - android:weightSum="4" android:orientation="horizontal" android:gravity="bottom" android:layout_gravity="start|bottom">
diff --git a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/ChromeProvidedSharingOptionsProviderBase.java b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/ChromeProvidedSharingOptionsProviderBase.java index 1a840dee..670f430 100644 --- a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/ChromeProvidedSharingOptionsProviderBase.java +++ b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/ChromeProvidedSharingOptionsProviderBase.java
@@ -250,23 +250,21 @@ maybeAddQrCodeFirstPartyOption(); return; } - if (ChromeFeatureList.isEnabled(ChromeFeatureList.WEBNOTES_STYLIZE)) { - mOrderedFirstPartyOptions.add(createWebNotesStylizeFirstPartyOption()); + if (ChromeFeatureList.isEnabled(ChromeFeatureList.SHARE_SHEET_CUSTOM_ACTIONS_POLISH)) { + maybeAddLongScreenshotFirstPartyOption(); + maybeAddPrintFirstPartyOption(); + maybeAddSendTabToSelfFirstPartyOption(); + maybeAddQrCodeFirstPartyOption(); + } else { + maybeAddWebStyleNotesFirstPartyOption(); + maybeAddScreenshotFirstPartyOption(); + maybeAddLongScreenshotFirstPartyOption(); + maybeAddCopyFirstPartyOption(); + maybeAddSendTabToSelfFirstPartyOption(); + maybeAddQrCodeFirstPartyOption(); + maybeAddPrintFirstPartyOption(); + mOrderedFirstPartyOptions.add(createSaveImageFirstPartyOption()); } - maybeAddScreenshotFirstPartyOption(); - maybeAddLongScreenshotFirstPartyOption(); - - mOrderedFirstPartyOptions.add(createCopyLinkFirstPartyOption()); - mOrderedFirstPartyOptions.add(createCopyGifFirstPartyOption()); - mOrderedFirstPartyOptions.add(createCopyImageFirstPartyOption()); - mOrderedFirstPartyOptions.add(createCopyFirstPartyOption()); - mOrderedFirstPartyOptions.add(createCopyTextFirstPartyOption()); - maybeAddSendTabToSelfFirstPartyOption(); - maybeAddQrCodeFirstPartyOption(); - if (mTabProvider.hasValue() && UserPrefs.get(mProfile).getBoolean(Pref.PRINTING_ENABLED)) { - mOrderedFirstPartyOptions.add(createPrintingFirstPartyOption()); - } - mOrderedFirstPartyOptions.add(createSaveImageFirstPartyOption()); } private void maybeAddSendTabToSelfFirstPartyOption() { @@ -301,6 +299,26 @@ } } + private void maybeAddPrintFirstPartyOption() { + if (mTabProvider.hasValue() && UserPrefs.get(mProfile).getBoolean(Pref.PRINTING_ENABLED)) { + mOrderedFirstPartyOptions.add(createPrintingFirstPartyOption()); + } + } + + protected void maybeAddWebStyleNotesFirstPartyOption() { + if (ChromeFeatureList.isEnabled(ChromeFeatureList.WEBNOTES_STYLIZE)) { + mOrderedFirstPartyOptions.add(createWebNotesStylizeFirstPartyOption()); + } + } + + protected void maybeAddCopyFirstPartyOption() { + mOrderedFirstPartyOptions.add(createCopyLinkFirstPartyOption()); + mOrderedFirstPartyOptions.add(createCopyGifFirstPartyOption()); + mOrderedFirstPartyOptions.add(createCopyImageFirstPartyOption()); + mOrderedFirstPartyOptions.add(createCopyFirstPartyOption()); + mOrderedFirstPartyOptions.add(createCopyTextFirstPartyOption()); + } + private FirstPartyOption createCopyLinkFirstPartyOption() { return new FirstPartyOptionBuilder( ContentType.LINK_PAGE_VISIBLE, ContentType.LINK_PAGE_NOT_VISIBLE) @@ -433,7 +451,7 @@ .build(); } - protected FirstPartyOption createWebNotesStylizeFirstPartyOption() { + private FirstPartyOption createWebNotesStylizeFirstPartyOption() { String title = mShareParams.getTitle(); return new FirstPartyOptionBuilder(ContentType.HIGHLIGHTED_TEXT) .setIcon(R.drawable.webnote, R.string.sharing_webnotes_create_card)
diff --git a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/android_share_sheet/AndroidCustomActionProvider.java b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/android_share_sheet/AndroidCustomActionProvider.java index 9325757c..bb175f3c 100644 --- a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/android_share_sheet/AndroidCustomActionProvider.java +++ b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/android_share_sheet/AndroidCustomActionProvider.java
@@ -20,14 +20,17 @@ import org.chromium.chrome.browser.share.ChromeCustomShareAction; import org.chromium.chrome.browser.share.ChromeProvidedSharingOptionsProviderBase; import org.chromium.chrome.browser.share.ChromeShareExtras; +import org.chromium.chrome.browser.share.ChromeShareExtras.DetailedContentType; import org.chromium.chrome.browser.share.ShareContentTypeHelper; import org.chromium.chrome.browser.share.ShareContentTypeHelper.ContentType; import org.chromium.chrome.browser.share.link_to_text.LinkToTextCoordinator; +import org.chromium.chrome.browser.share.long_screenshots.LongScreenshotsCoordinator; import org.chromium.chrome.browser.share.share_sheet.ChromeOptionShareCallback; import org.chromium.chrome.browser.share.share_sheet.ShareSheetLinkToggleCoordinator.LinkToggleState; import org.chromium.chrome.browser.tab.Tab; import org.chromium.components.browser_ui.bottomsheet.BottomSheetController; import org.chromium.components.browser_ui.share.ShareParams; +import org.chromium.components.feature_engagement.EventConstants; import org.chromium.components.feature_engagement.Tracker; import org.chromium.ui.base.WindowAndroid; @@ -39,16 +42,18 @@ */ class AndroidCustomActionProvider extends ChromeProvidedSharingOptionsProviderBase implements ChromeCustomShareAction.Provider { - private final List<ChromeCustomShareAction> mCustomActions = new ArrayList<>(); - private static final String USER_ACTION_SHARE_HIGHLIGHT_TEXT_WITH_LINK = "SharingHubAndroid.AndroidShareHighlightText.WithLink"; private static final String USER_ACTION_SHARE_HIGHLIGHT_TEXT_WITHOUT_LINK = "SharingHubAndroid.AndroidShareHighlightText.WithoutLink"; + private static final String USER_ACTION_LONG_SCREENSHOT_NO_EDITOR_SELECTED = + "SharingHubAndroid.LongScreenshotSelected.NoEditor"; + private static final Integer MAX_ACTION_SUPPORTED = 5; private final ChromeShareExtras mChromeShareExtras; @Nullable private final LinkToTextCoordinator mLinkToTextCoordinator; + private final List<ChromeCustomShareAction> mCustomActions = new ArrayList<>(); private @Nullable ChromeCustomShareAction mModifyAction; @@ -102,7 +107,7 @@ List<FirstPartyOption> options = getFirstPartyOptions( ShareContentTypeHelper.getContentTypes(params, chromeShareExtras), chromeShareExtras.getDetailedContentType(), isMultiWindow); - + assert options.size() <= MAX_ACTION_SUPPORTED; for (var option : options) { mCustomActions.add(shareActionFromFirstPartyOption(option)); } @@ -136,13 +141,31 @@ return null; } - // TODO(https://crbug/1410201): Support long screenshot. @Nullable @Override protected FirstPartyOption createLongScreenshotsFirstPartyOption() { - return null; + return new FirstPartyOptionBuilder(ContentType.LINK_PAGE_VISIBLE, ContentType.TEXT, + ContentType.HIGHLIGHTED_TEXT, ContentType.IMAGE) + .setDetailedContentTypesToDisableFor(DetailedContentType.WEB_NOTES) + .setIcon(R.drawable.long_screenshot, R.string.sharing_long_screenshot) + .setFeatureNameForMetrics(USER_ACTION_LONG_SCREENSHOT_NO_EDITOR_SELECTED) + .setDisableForMultiWindow(true) + .setOnClickCallback((view) -> { + mFeatureEngagementTracker.notifyEvent(EventConstants.SHARE_SCREENSHOT_SELECTED); + LongScreenshotsCoordinator coordinator = + LongScreenshotsCoordinator.create(mActivity, mTabProvider.get(), mUrl, + mChromeOptionShareCallback, mBottomSheetController, null); + coordinator.captureScreenshot(); + }) + .build(); } + @Override + protected void maybeAddWebStyleNotesFirstPartyOption() {} + + @Override + protected void maybeAddCopyFirstPartyOption() {} + private FirstPartyOption createShareHighlightTextWithLink() { return new FirstPartyOptionBuilder(ContentType.HIGHLIGHTED_TEXT) .setIcon(R.drawable.link, R.string.sharing_include_link)
diff --git a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/android_share_sheet/AndroidShareSheetController.java b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/android_share_sheet/AndroidShareSheetController.java index 58cb519..c7d8a68 100644 --- a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/android_share_sheet/AndroidShareSheetController.java +++ b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/android_share_sheet/AndroidShareSheetController.java
@@ -128,13 +128,14 @@ mController, params, mPrintCallback, isIncognito, this, TrackerFactory.getTrackerForProfile(profile), params.getUrl(), profile, chromeShareExtras, isInMultiWindow, mLinkToTextCoordinator); - if (actionProvider.getCustomActions().size() > 0) { + if (actionProvider.getCustomActions().size() > 0 + || actionProvider.getModifyShareAction() != null) { provider = actionProvider; } } // TODO(https://crbug.com/1421783): Maybe fallback to Chrome's share sheet properly. - if (provider == null || provider.getCustomActions().size() == 0) { + if (provider == null) { Log.i(TAG, "No custom actions provided."); }
diff --git a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/screenshot/ScreenshotCoordinator.java b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/screenshot/ScreenshotCoordinator.java index 0cb31270..3aabfad 100644 --- a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/screenshot/ScreenshotCoordinator.java +++ b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/screenshot/ScreenshotCoordinator.java
@@ -119,7 +119,7 @@ ScreenshotShareSheetDialogCoordinator shareSheet = new ScreenshotShareSheetDialogCoordinator(mActivity, mDialog, mScreenshot, mWindowAndroid, mShareUrl, mChromeOptionShareCallback, - this::retryInstallEditor); + mImageEditorModuleProvider == null ? null : this::retryInstallEditor); shareSheet.showShareSheet(); mScreenshot = null; } @@ -129,10 +129,7 @@ * @param onSuccess Runnable to run on success. */ protected void retryInstallEditor(Runnable onSuccess) { - if (mImageEditorModuleProvider == null) { - // If the module does not exist, nothing to do. - return; - } + assert mImageEditorModuleProvider != null; if (mImageEditorModuleProvider.isModuleInstalled()) { launchEditor(); return;
diff --git a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/screenshot/ScreenshotShareSheetCoordinator.java b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/screenshot/ScreenshotShareSheetCoordinator.java index 5238b98..b20a5658 100644 --- a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/screenshot/ScreenshotShareSheetCoordinator.java +++ b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/screenshot/ScreenshotShareSheetCoordinator.java
@@ -7,6 +7,8 @@ import android.content.Context; import android.graphics.Bitmap; +import androidx.annotation.Nullable; + import org.chromium.base.Callback; import org.chromium.chrome.browser.share.share_sheet.ChromeOptionShareCallback; import org.chromium.ui.base.WindowAndroid; @@ -40,7 +42,8 @@ public ScreenshotShareSheetCoordinator(Context context, Bitmap screenshot, Runnable closeDialogRunnable, ScreenshotShareSheetView screenshotShareSheetView, WindowAndroid windowAndroid, String shareUrl, - ChromeOptionShareCallback shareSheetCallback, Callback<Runnable> installCallback) { + ChromeOptionShareCallback shareSheetCallback, + @Nullable Callback<Runnable> installCallback) { ArrayList<PropertyKey> allProperties = new ArrayList<>(Arrays.asList(ScreenshotShareSheetViewProperties.ALL_KEYS)); mModel = new PropertyModel(allProperties);
diff --git a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/screenshot/ScreenshotShareSheetDialog.java b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/screenshot/ScreenshotShareSheetDialog.java index 6c21fa1..33d5e57 100644 --- a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/screenshot/ScreenshotShareSheetDialog.java +++ b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/screenshot/ScreenshotShareSheetDialog.java
@@ -9,6 +9,7 @@ import android.graphics.Bitmap; import android.os.Bundle; +import androidx.annotation.Nullable; import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.DialogFragment; @@ -26,7 +27,7 @@ private WindowAndroid mWindowAndroid; private String mShareUrl; private ChromeOptionShareCallback mChromeOptionShareCallback; - private Callback<Runnable> mInstallCallback; + private @Nullable Callback<Runnable> mInstallCallback; /** * The ScreenshotShareSheetDialog constructor. @@ -43,7 +44,7 @@ */ public void init(Bitmap screenshot, WindowAndroid windowAndroid, String shareUrl, ChromeOptionShareCallback chromeOptionShareCallback, - Callback<Runnable> installCallback) { + @Nullable Callback<Runnable> installCallback) { mScreenshot = screenshot; mInstallCallback = installCallback; mWindowAndroid = windowAndroid;
diff --git a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/screenshot/ScreenshotShareSheetMediator.java b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/screenshot/ScreenshotShareSheetMediator.java index 5f63bb26..e0b28a5 100644 --- a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/screenshot/ScreenshotShareSheetMediator.java +++ b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/screenshot/ScreenshotShareSheetMediator.java
@@ -8,6 +8,8 @@ import android.graphics.Bitmap; import android.net.Uri; +import androidx.annotation.Nullable; + import org.chromium.base.Callback; import org.chromium.chrome.R; import org.chromium.chrome.browser.share.ChromeShareExtras; @@ -34,7 +36,7 @@ private final Context mContext; private final Runnable mSaveRunnable; private final Runnable mCloseDialogRunnable; - private final Callback<Runnable> mInstallCallback; + private final @Nullable Callback<Runnable> mInstallCallback; private final ChromeOptionShareCallback mChromeOptionShareCallback; private final WindowAndroid mWindowAndroid; private final String mShareUrl; @@ -54,7 +56,7 @@ ScreenshotShareSheetMediator(Context context, PropertyModel propertyModel, Runnable closeDialogRunnable, Runnable saveRunnable, WindowAndroid windowAndroid, String shareUrl, ChromeOptionShareCallback chromeOptionShareCallback, - Callback<Runnable> installCallback) { + @Nullable Callback<Runnable> installCallback) { mCloseDialogRunnable = closeDialogRunnable; mSaveRunnable = saveRunnable; mContext = context; @@ -63,6 +65,8 @@ mShareUrl = shareUrl; mChromeOptionShareCallback = chromeOptionShareCallback; mInstallCallback = installCallback; + mModel.set(ScreenshotShareSheetViewProperties.SCREENSHOT_EDIT_DISABLED, + mInstallCallback == null); mModel.set(ScreenshotShareSheetViewProperties.NO_ARG_OPERATION_LISTENER, operation -> { performNoArgOperation(operation); }); } @@ -87,6 +91,7 @@ ScreenshotShareSheetMetrics.ScreenshotShareSheetAction.DELETE); mCloseDialogRunnable.run(); } else if (NoArgOperation.INSTALL == operation) { + assert mInstallCallback != null; ScreenshotShareSheetMetrics.logScreenshotAction( ScreenshotShareSheetMetrics.ScreenshotShareSheetAction.EDIT); mInstallCallback.onResult(mCloseDialogRunnable);
diff --git a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/screenshot/ScreenshotShareSheetView.java b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/screenshot/ScreenshotShareSheetView.java index 9dc2061..a87db628 100644 --- a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/screenshot/ScreenshotShareSheetView.java +++ b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/screenshot/ScreenshotShareSheetView.java
@@ -62,4 +62,9 @@ Drawable drawable = new BitmapDrawable(bitmap); screenshotImageView.setImageDrawable(drawable); } + + public void setEditButtonDisabled(boolean disabled) { + View editButton = findViewById(R.id.edit); + editButton.setVisibility(disabled ? View.GONE : View.VISIBLE); + } }
diff --git a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/screenshot/ScreenshotShareSheetViewBinder.java b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/screenshot/ScreenshotShareSheetViewBinder.java index d9051dc..92da8f3 100644 --- a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/screenshot/ScreenshotShareSheetViewBinder.java +++ b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/screenshot/ScreenshotShareSheetViewBinder.java
@@ -17,6 +17,9 @@ } else if (ScreenshotShareSheetViewProperties.SCREENSHOT_BITMAP == propertyKey) { view.updateScreenshotBitmap( model.get(ScreenshotShareSheetViewProperties.SCREENSHOT_BITMAP)); + } else if (ScreenshotShareSheetViewProperties.SCREENSHOT_EDIT_DISABLED == propertyKey) { + view.setEditButtonDisabled( + model.get(ScreenshotShareSheetViewProperties.SCREENSHOT_EDIT_DISABLED)); } } }
diff --git a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/screenshot/ScreenshotShareSheetViewProperties.java b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/screenshot/ScreenshotShareSheetViewProperties.java index 6ee39a7..2839b10 100644 --- a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/screenshot/ScreenshotShareSheetViewProperties.java +++ b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/screenshot/ScreenshotShareSheetViewProperties.java
@@ -10,6 +10,7 @@ import org.chromium.base.Callback; import org.chromium.ui.modelutil.PropertyKey; +import org.chromium.ui.modelutil.PropertyModel.WritableBooleanPropertyKey; import org.chromium.ui.modelutil.PropertyModel.WritableObjectPropertyKey; import java.lang.annotation.Retention; @@ -25,6 +26,9 @@ public static final WritableObjectPropertyKey<Bitmap> SCREENSHOT_BITMAP = new WritableObjectPropertyKey<>(); + + public static final WritableBooleanPropertyKey SCREENSHOT_EDIT_DISABLED = + new WritableBooleanPropertyKey(); /** * Set of operations that don't require additional arguments. If a callback requires an * argument, it should defined separately. @@ -39,6 +43,6 @@ int INSTALL = 4; } - public static final PropertyKey[] ALL_KEYS = - new PropertyKey[] {NO_ARG_OPERATION_LISTENER, SCREENSHOT_BITMAP}; + public static final PropertyKey[] ALL_KEYS = new PropertyKey[] { + NO_ARG_OPERATION_LISTENER, SCREENSHOT_BITMAP, SCREENSHOT_EDIT_DISABLED}; }
diff --git a/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/android_share_sheet/AndroidShareSheetControllerUnitTest.java b/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/android_share_sheet/AndroidShareSheetControllerUnitTest.java index d01bad53..c55757092 100644 --- a/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/android_share_sheet/AndroidShareSheetControllerUnitTest.java +++ b/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/android_share_sheet/AndroidShareSheetControllerUnitTest.java
@@ -93,6 +93,7 @@ * Test for {@link AndroidShareSheetController} and {@link AndroidCustomActionProvider}. */ @RunWith(BaseRobolectricTestRunner.class) +@Features.EnableFeatures({ChromeFeatureList.SHARE_SHEET_CUSTOM_ACTIONS_POLISH}) @Features.DisableFeatures( {ChromeFeatureList.WEBNOTES_STYLIZE, ChromeFeatureList.SEND_TAB_TO_SELF_SIGNIN_PROMO}) @Config(shadows = {ShadowShareImageFileUtils.class, ShadowGURL.class}) @@ -105,6 +106,12 @@ private static final String KEY_CHOOSER_ACTION_NAME = "name"; private static final String KEY_CHOOSER_ACTION_ACTION = "action"; private static final String SELECTOR_FOR_LINK_TO_TEXT = "selector"; + + private static final String USER_ACTION_SEND_TAB_TO_SELF_SELECTED = + "SharingHubAndroid.SendTabToSelfSelected"; + private static final String USER_ACTION_QR_CODE_SELECTED = "SharingHubAndroid.QRCodeSelected"; + private static final String USER_ACTION_PRINT_SELECTED = "SharingHubAndroid.PrintSelected"; + private static final Uri TEST_WEB_FAVICON_PREVIEW_URI = Uri.parse("content://test.web.favicon.preview"); private static final Uri TEST_FALLBACK_FAVICON_PREVIEW_URI = @@ -206,6 +213,10 @@ Intent intent = Shadows.shadowOf((Activity) mActivity).peekNextStartedActivity(); Assert.assertNotNull("Custom action is empty.", intent.getParcelableArrayExtra(INTENT_EXTRA_CHOOSER_CUSTOM_ACTIONS)); + + assertCustomActions(intent, R.string.sharing_long_screenshot, + R.string.print_share_activity_title, R.string.send_tab_to_self_share_activity_title, + R.string.qr_code_share_icon_label); } @Test @@ -295,6 +306,28 @@ } @Test + @Config(shadows = {ShadowChooserActionHelper.class, ShadowBuildCompatForU.class}) + public void shareImageWithCustomActions() { + Uri testImageUri = Uri.parse("content://test.image.uri"); + ShareParams params = new ShareParams.Builder(mWindow, "", "") + .setFileContentType("image/png") + .setSingleImageUri(testImageUri) + .setBypassFixingDomDistillerUrl(true) + .build(); + ChromeShareExtras chromeShareExtras = + new ChromeShareExtras.Builder() + .setDetailedContentType(DetailedContentType.IMAGE) + .setContentUrl(JUnitTestGURLs.getGURL(JUnitTestGURLs.GOOGLE_URL)) + .setImageSrcUrl(JUnitTestGURLs.getGURL(JUnitTestGURLs.GOOGLE_URL_DOGS)) + .build(); + mController.showShareSheet(params, chromeShareExtras, 1L); + + Intent intent = Shadows.shadowOf((Activity) mActivity).peekNextStartedActivity(); + assertCustomActions(intent, R.string.sharing_long_screenshot, + R.string.send_tab_to_self_share_activity_title, R.string.qr_code_share_icon_label); + } + + @Test public void shareTextWithPreviewFavicon() { HistogramWatcher watcher = HistogramWatcher.newSingleRecordWatcher("Sharing.PreparePreviewFaviconDuration"); @@ -370,6 +403,9 @@ "\"highlight\"\n " + JUnitTestGURLs.TEXT_FRAGMENT_URL, shareIntent.getStringExtra(Intent.EXTRA_TEXT)); + assertCustomActions(chooserIntent, R.string.sharing_long_screenshot, + R.string.send_tab_to_self_share_activity_title, R.string.qr_code_share_icon_label); + // Toggle the modify action again, link is removed from text. runModifyActionFromChooserIntent(chooserIntent); Intent chooserIntent2 = Shadows.shadowOf((Activity) mActivity).peekNextStartedActivity(); @@ -377,6 +413,8 @@ Assert.assertEquals("Text being shared is different.", "highlight", shareIntent2.getStringExtra(Intent.EXTRA_TEXT)); + assertCustomActions(chooserIntent2, R.string.sharing_long_screenshot); + // Toggle the modify action again, link is reattached with the text. runModifyActionFromChooserIntent(chooserIntent2); Intent chooserIntent3 = Shadows.shadowOf((Activity) mActivity).peekNextStartedActivity(); @@ -404,6 +442,27 @@ ShadowLooper.idleMainLooper(); } + private void assertCustomActions(Intent chooserIntent, Integer... expectedStringRes) { + Parcelable[] actions = + chooserIntent.getParcelableArrayExtra(INTENT_EXTRA_CHOOSER_CUSTOM_ACTIONS); + StringBuilder actualStringBuilder = new StringBuilder(); + for (Parcelable action : actions) { + String name = ((Bundle) action).getString(KEY_CHOOSER_ACTION_NAME); + actualStringBuilder.append(",").append(name); + } + + StringBuilder expectedStringBuilder = new StringBuilder(); + for (int stringRes : expectedStringRes) { + String name = ContextUtils.getApplicationContext().getString(stringRes); + expectedStringBuilder.append(",").append(name); + } + + String actualString = actualStringBuilder.toString(); + String expectedString = expectedStringBuilder.toString(); + Assert.assertEquals( + "Actions and/or the order does not match.", expectedString, actualString); + } + /** * Test implementation to build a ChooserAction. */
diff --git a/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ChromeProvidedSharingOptionsProviderTest.java b/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ChromeProvidedSharingOptionsProviderTest.java index e79695f1..32b64fd4 100644 --- a/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ChromeProvidedSharingOptionsProviderTest.java +++ b/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ChromeProvidedSharingOptionsProviderTest.java
@@ -75,7 +75,8 @@ @RunWith(BaseRobolectricTestRunner.class) @EnableFeatures({ChromeFeatureList.WEBNOTES_STYLIZE}) @DisableFeatures({ChromeFeatureList.UPCOMING_SHARING_FEATURES, - ChromeFeatureList.SEND_TAB_TO_SELF_SIGNIN_PROMO}) + ChromeFeatureList.SEND_TAB_TO_SELF_SIGNIN_PROMO, + ChromeFeatureList.SHARE_SHEET_CUSTOM_ACTIONS_POLISH}) @Config(shadows = ShadowGURL.class) public class ChromeProvidedSharingOptionsProviderTest { @Rule
diff --git a/chrome/browser/ssl/https_upgrades_browsertest.cc b/chrome/browser/ssl/https_upgrades_browsertest.cc index 0ca416f..113c549 100644 --- a/chrome/browser/ssl/https_upgrades_browsertest.cc +++ b/chrome/browser/ssl/https_upgrades_browsertest.cc
@@ -36,6 +36,7 @@ #include "content/public/test/content_browser_test_utils.h" #include "content/public/test/content_mock_cert_verifier.h" #include "content/public/test/test_navigation_observer.h" +#include "content/public/test/url_loader_interceptor.h" #include "net/dns/mock_host_resolver.h" #include "net/test/cert_test_util.h" #include "net/test/embedded_test_server/embedded_test_server.h" @@ -303,6 +304,60 @@ 1); } +// Test that HTTPS Upgrades are skipped for non-publicly routable (RFC1918/4193) +// IP address hostnames, but HTTPS-First Mode should still apply. +IN_PROC_BROWSER_TEST_P(HttpsUpgradesBrowserTest, + NonRoutableIPAddress_ShouldNotUpgrade) { + // This test is only interesting for HTTPS-Upgrades and HTTPS-First Mode. + if (!IsHttpUpgradingEnabled()) { + return; + } + + // Disable the testing port configuration, as this test doesn't use the + // EmbeddedTestServer. + HttpsUpgradesInterceptor::SetHttpsPortForTesting(0); + HttpsUpgradesInterceptor::SetHttpPortForTesting(0); + + // Set up an interceptor because the test server can't listen on private IPs. + GURL local_ip_url("http://192.168.0.1/simple.html"); + auto url_loader_interceptor = + content::URLLoaderInterceptor::ServeFilesFromDirectoryAtOrigin( + GetChromeTestDataDir().MaybeAsASCII(), + local_ip_url.GetWithEmptyPath()); + + auto* contents = browser()->tab_strip_model()->GetActiveWebContents(); + + if (IsHttpInterstitialEnabled()) { + // HFM should attempt the upgrade, fail, and fallback to the interstitial. + EXPECT_FALSE(content::NavigateToURL(contents, local_ip_url)); + EXPECT_TRUE( + chrome_browser_interstitials::IsShowingHttpsFirstModeInterstitial( + contents)); + + // Verify that upgrade events were recorded because an upgrade was attempted + // and failed. + histograms()->ExpectTotalCount(kEventHistogram, 3); + histograms()->ExpectBucketCount( + kEventHistogram, + security_interstitials::https_only_mode::Event::kUpgradeAttempted, 1); + histograms()->ExpectBucketCount( + kEventHistogram, + security_interstitials::https_only_mode::Event::kUpgradeFailed, 1); + histograms()->ExpectBucketCount( + kEventHistogram, + security_interstitials::https_only_mode::Event::kUpgradeTimedOut, 1); + } else { + // If HFM is not enabled, HTTPS-Upgrades should not attempt to upgrade the + // navigation. + EXPECT_TRUE(content::NavigateToURL(contents, local_ip_url)); + histograms()->ExpectTotalCount(kEventHistogram, 0); + } + + histograms()->ExpectBucketCount( + kNavigationRequestSecurityLevelHistogram, + NavigationRequestSecurityLevel::kNonUniqueHostname, 1); +} + // If the user navigates to a non-unique hostname, the navigation should be // upgraded, but record insecure metrics. IN_PROC_BROWSER_TEST_P(HttpsUpgradesBrowserTest, NonUniqueHost_RecordsMetrics) {
diff --git a/chrome/browser/ssl/https_upgrades_interceptor.cc b/chrome/browser/ssl/https_upgrades_interceptor.cc index 685d3b40..91671f2 100644 --- a/chrome/browser/ssl/https_upgrades_interceptor.cc +++ b/chrome/browser/ssl/https_upgrades_interceptor.cc
@@ -261,6 +261,21 @@ if (net::IsHostnameNonUnique(tentative_resource_request.url.host())) { RecordNavigationRequestSecurityLevel( NavigationRequestSecurityLevel::kNonUniqueHostname); + + // For HTTPS-Upgrades, skip attempting to upgrade non-routable IP address + // literals (i.e., RFC1918/4193) as they can't get publicly-trusted + // certificates. + // + // HTTPS-First Mode does not exempt these hosts in order to ensure that + // Chrome shows the HTTP interstitial before navigation to them. + // Potentially, these could fast-fail instead and skip directly to the + // interstitial. + if (base::FeatureList::IsEnabled(features::kHttpsUpgrades) && + !http_interstitial_enabled_ && + tentative_resource_request.url.HostIsIPAddress()) { + std::move(callback).Run({}); + return; + } } // Check whether this host would be upgraded to HTTPS by HSTS. This requires a
diff --git a/chrome/browser/sync/test/integration/two_client_web_apps_integration_test_mac_win_linux.cc b/chrome/browser/sync/test/integration/two_client_web_apps_integration_test_mac_win_linux.cc index 1055687..5b5e765 100644 --- a/chrome/browser/sync/test/integration/two_client_web_apps_integration_test_mac_win_linux.cc +++ b/chrome/browser/sync/test/integration/two_client_web_apps_integration_test_mac_win_linux.cc
@@ -145,31 +145,6 @@ helper_.CheckTabCreated(Number::kOne); } -// TODO(crbug.com/1427296): Mac LaunchFromPlatformShortcut behavior does not -// match other platforms. -#if BUILDFLAG(IS_MAC) -#define MAYBE_WAI_29StandaloneBrowser_11Standalone_7Standalone_40Client2_45Standalone_1Standalone_22One \ - DISABLED_WAI_29StandaloneBrowser_11Standalone_7Standalone_40Client2_45Standalone_1Standalone_22One -#else -#define MAYBE_WAI_29StandaloneBrowser_11Standalone_7Standalone_40Client2_45Standalone_1Standalone_22One \ - WAI_29StandaloneBrowser_11Standalone_7Standalone_40Client2_45Standalone_1Standalone_22One -#endif -IN_PROC_BROWSER_TEST_F( - WebAppIntegration, - MAYBE_WAI_29StandaloneBrowser_11Standalone_7Standalone_40Client2_45Standalone_1Standalone_22One) { - // Test contents are generated by script. Please do not modify! - // See `docs/webapps/why-is-this-test-failing.md` or - // `docs/webapps/integration-testing-framework` for more info. - // Sheriffs: Disabling this test is supported. - helper_.CreateShortcut(Site::kStandalone, WindowOptions::kBrowser); - helper_.CheckAppInListTabbed(Site::kStandalone); - helper_.CheckPlatformShortcutAndIcon(Site::kStandalone); - helper_.SwitchProfileClients(ProfileClient::kClient2); - helper_.CheckAppInListNotLocallyInstalled(Site::kStandalone); - helper_.LaunchFromPlatformShortcut(Site::kStandalone); - helper_.CheckTabCreated(Number::kOne); -} - IN_PROC_BROWSER_TEST_F( WebAppIntegration, WAI_29StandaloneBrowser_11Standalone_7Standalone_40Client2_45Standalone_41_10Standalone_42_45Standalone) { @@ -466,34 +441,6 @@ helper_.CheckWindowCreated(); } -// TODO(crbug.com/1427296): Mac LaunchFromPlatformShortcut behavior does not -// match other platforms. -#if BUILDFLAG(IS_MAC) -#define MAYBE_WAI_29StandaloneWindowed_24_12Standalone_7Standalone_112StandaloneNotShown_40Client2_45Standalone_1Standalone_22One \ - DISABLED_WAI_29StandaloneWindowed_24_12Standalone_7Standalone_112StandaloneNotShown_40Client2_45Standalone_1Standalone_22One -#else -#define MAYBE_WAI_29StandaloneWindowed_24_12Standalone_7Standalone_112StandaloneNotShown_40Client2_45Standalone_1Standalone_22One \ - WAI_29StandaloneWindowed_24_12Standalone_7Standalone_112StandaloneNotShown_40Client2_45Standalone_1Standalone_22One -#endif -IN_PROC_BROWSER_TEST_F( - WebAppIntegration, - MAYBE_WAI_29StandaloneWindowed_24_12Standalone_7Standalone_112StandaloneNotShown_40Client2_45Standalone_1Standalone_22One) { - // Test contents are generated by script. Please do not modify! - // See `docs/webapps/why-is-this-test-failing.md` or - // `docs/webapps/integration-testing-framework` for more info. - // Sheriffs: Disabling this test is supported. - helper_.CreateShortcut(Site::kStandalone, WindowOptions::kWindowed); - helper_.CheckWindowCreated(); - helper_.CheckAppInListWindowed(Site::kStandalone); - helper_.CheckPlatformShortcutAndIcon(Site::kStandalone); - helper_.CheckWindowControlsOverlayToggle(Site::kStandalone, - IsShown::kNotShown); - helper_.SwitchProfileClients(ProfileClient::kClient2); - helper_.CheckAppInListNotLocallyInstalled(Site::kStandalone); - helper_.LaunchFromPlatformShortcut(Site::kStandalone); - helper_.CheckTabCreated(Number::kOne); -} - IN_PROC_BROWSER_TEST_F( WebAppIntegration, WAI_29StandaloneWindowed_24_12Standalone_7Standalone_112StandaloneNotShown_40Client2_45Standalone_10Standalone_15Standalone_40Client1_15Standalone) { @@ -772,34 +719,6 @@ helper_.CheckWindowCreated(); } -// TODO(crbug.com/1427296): Mac LaunchFromPlatformShortcut behavior does not -// match other platforms. -#if BUILDFLAG(IS_MAC) -#define MAYBE_WAI_31Standalone_24_12Standalone_7Standalone_112StandaloneNotShown_40Client2_45Standalone_1Standalone_22One \ - DISABLED_WAI_31Standalone_24_12Standalone_7Standalone_112StandaloneNotShown_40Client2_45Standalone_1Standalone_22One -#else -#define MAYBE_WAI_31Standalone_24_12Standalone_7Standalone_112StandaloneNotShown_40Client2_45Standalone_1Standalone_22One \ - WAI_31Standalone_24_12Standalone_7Standalone_112StandaloneNotShown_40Client2_45Standalone_1Standalone_22One -#endif -IN_PROC_BROWSER_TEST_F( - WebAppIntegration, - MAYBE_WAI_31Standalone_24_12Standalone_7Standalone_112StandaloneNotShown_40Client2_45Standalone_1Standalone_22One) { - // Test contents are generated by script. Please do not modify! - // See `docs/webapps/why-is-this-test-failing.md` or - // `docs/webapps/integration-testing-framework` for more info. - // Sheriffs: Disabling this test is supported. - helper_.InstallOmniboxIcon(InstallableSite::kStandalone); - helper_.CheckWindowCreated(); - helper_.CheckAppInListWindowed(Site::kStandalone); - helper_.CheckPlatformShortcutAndIcon(Site::kStandalone); - helper_.CheckWindowControlsOverlayToggle(Site::kStandalone, - IsShown::kNotShown); - helper_.SwitchProfileClients(ProfileClient::kClient2); - helper_.CheckAppInListNotLocallyInstalled(Site::kStandalone); - helper_.LaunchFromPlatformShortcut(Site::kStandalone); - helper_.CheckTabCreated(Number::kOne); -} - IN_PROC_BROWSER_TEST_F( WebAppIntegration, WAI_31Standalone_24_12Standalone_7Standalone_112StandaloneNotShown_40Client2_45Standalone_10Standalone_15Standalone_40Client1_15Standalone) { @@ -1078,34 +997,6 @@ helper_.CheckWindowCreated(); } -// TODO(crbug.com/1427296): Mac LaunchFromPlatformShortcut behavior does not -// match other platforms. -#if BUILDFLAG(IS_MAC) -#define MAYBE_WAI_47Standalone_24_12Standalone_7Standalone_112StandaloneNotShown_40Client2_45Standalone_1Standalone_22One \ - DISABLED_WAI_47Standalone_24_12Standalone_7Standalone_112StandaloneNotShown_40Client2_45Standalone_1Standalone_22One -#else -#define MAYBE_WAI_47Standalone_24_12Standalone_7Standalone_112StandaloneNotShown_40Client2_45Standalone_1Standalone_22One \ - WAI_47Standalone_24_12Standalone_7Standalone_112StandaloneNotShown_40Client2_45Standalone_1Standalone_22One -#endif -IN_PROC_BROWSER_TEST_F( - WebAppIntegration, - MAYBE_WAI_47Standalone_24_12Standalone_7Standalone_112StandaloneNotShown_40Client2_45Standalone_1Standalone_22One) { - // Test contents are generated by script. Please do not modify! - // See `docs/webapps/why-is-this-test-failing.md` or - // `docs/webapps/integration-testing-framework` for more info. - // Sheriffs: Disabling this test is supported. - helper_.InstallMenuOption(InstallableSite::kStandalone); - helper_.CheckWindowCreated(); - helper_.CheckAppInListWindowed(Site::kStandalone); - helper_.CheckPlatformShortcutAndIcon(Site::kStandalone); - helper_.CheckWindowControlsOverlayToggle(Site::kStandalone, - IsShown::kNotShown); - helper_.SwitchProfileClients(ProfileClient::kClient2); - helper_.CheckAppInListNotLocallyInstalled(Site::kStandalone); - helper_.LaunchFromPlatformShortcut(Site::kStandalone); - helper_.CheckTabCreated(Number::kOne); -} - IN_PROC_BROWSER_TEST_F( WebAppIntegration, WAI_47Standalone_24_12Standalone_7Standalone_112StandaloneNotShown_40Client2_45Standalone_10Standalone_15Standalone_40Client1_15Standalone) {
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index 6d616f9..3470da1 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -4857,6 +4857,8 @@ "views/media_router/cast_dialog_no_sinks_view.h", "views/media_router/cast_dialog_sink_button.cc", "views/media_router/cast_dialog_sink_button.h", + "views/media_router/cast_dialog_sink_view.cc", + "views/media_router/cast_dialog_sink_view.h", "views/media_router/cast_dialog_view.cc", "views/media_router/cast_dialog_view.h", "views/media_router/cast_toolbar_button.cc",
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/LocationBarCoordinator.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/LocationBarCoordinator.java index 06c30233..95d4bd87 100644 --- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/LocationBarCoordinator.java +++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/LocationBarCoordinator.java
@@ -17,7 +17,6 @@ import org.chromium.base.Callback; import org.chromium.base.CallbackController; -import org.chromium.base.jank_tracker.JankTracker; import org.chromium.base.supplier.ObservableSupplier; import org.chromium.base.supplier.OneshotSupplierImpl; import org.chromium.base.supplier.Supplier; @@ -139,7 +138,6 @@ * @param tabWindowManagerSupplier Supplier of glue-level TabWindowManager object. * @param bookmarkState State of a URL bookmark state. * @param isToolbarMicEnabledSupplier Whether toolbar mic is enabled or not. - * @param jankTracker Tracks UI jank. * @param merchantTrustSignalsCoordinatorSupplier Supplier of {@link * MerchantTrustSignalsCoordinator}. Can be null if a store icon shouldn't be shown, * such as when called from a search activity. @@ -162,7 +160,7 @@ @NonNull SaveOfflineButtonState saveOfflineButtonState, @NonNull OmniboxUma omniboxUma, @NonNull Supplier<TabWindowManager> tabWindowManagerSupplier, @NonNull BookmarkState bookmarkState, - @NonNull BooleanSupplier isToolbarMicEnabledSupplier, JankTracker jankTracker, + @NonNull BooleanSupplier isToolbarMicEnabledSupplier, @Nullable Supplier<MerchantTrustSignalsCoordinator> merchantTrustSignalsCoordinatorSupplier, @NonNull ActionChipsDelegate actionChipsDelegate, @@ -208,8 +206,8 @@ mOmniboxDropdownEmbedderImpl, mUrlCoordinator, modalDialogManagerSupplier, activityTabSupplier, shareDelegateSupplier, locationBarDataProvider, profileObservableSupplier, bringTabToFrontCallback, tabWindowManagerSupplier, - bookmarkState, jankTracker, actionChipsDelegate, - omniboxSuggestionsDropdownScrollListener, openHistoryClustersDelegate); + bookmarkState, actionChipsDelegate, omniboxSuggestionsDropdownScrollListener, + openHistoryClustersDelegate); StatusView statusView = mLocationBarLayout.findViewById(R.id.location_bar_status); mStatusCoordinator = new StatusCoordinator(isTabletWindow(), statusView, mUrlCoordinator, locationBarDataProvider, templateUrlServiceSupplier, searchEngineLogoUtils,
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteCoordinator.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteCoordinator.java index 4dc4983..b4563b9 100644 --- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteCoordinator.java +++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteCoordinator.java
@@ -19,7 +19,6 @@ import org.chromium.base.Callback; import org.chromium.base.ObserverList; import org.chromium.base.StrictModeContext; -import org.chromium.base.jank_tracker.JankTracker; import org.chromium.base.supplier.ObservableSupplier; import org.chromium.base.supplier.Supplier; import org.chromium.chrome.browser.omnibox.LocationBarDataProvider; @@ -90,8 +89,7 @@ @NonNull ObservableSupplier<Profile> profileObservableSupplier, @NonNull Callback<Tab> bringToForegroundCallback, @NonNull Supplier<TabWindowManager> tabWindowManagerSupplier, - @NonNull BookmarkState bookmarkState, @NonNull JankTracker jankTracker, - @NonNull ActionChipsDelegate actionChipsDelegate, + @NonNull BookmarkState bookmarkState, @NonNull ActionChipsDelegate actionChipsDelegate, @NonNull OmniboxSuggestionsDropdownScrollListener scrollListener, @NonNull OpenHistoryClustersDelegate openHistoryClustersDelegate) { mParent = parent; @@ -108,7 +106,7 @@ mMediator = new AutocompleteMediator(context, controllerProvider, delegate, urlBarEditingTextProvider, listModel, new Handler(), modalDialogManagerSupplier, activityTabSupplier, shareDelegateSupplier, locationBarDataProvider, - bringToForegroundCallback, tabWindowManagerSupplier, bookmarkState, jankTracker, + bringToForegroundCallback, tabWindowManagerSupplier, bookmarkState, actionChipsDelegate, openHistoryClustersDelegate); mMediator.initDefaultProcessors();
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java index 3baf15f5..d291b9f 100644 --- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java +++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java
@@ -22,8 +22,6 @@ import org.chromium.base.Callback; import org.chromium.base.ThreadUtils; import org.chromium.base.TraceEvent; -import org.chromium.base.jank_tracker.JankScenario; -import org.chromium.base.jank_tracker.JankTracker; import org.chromium.base.metrics.RecordUserAction; import org.chromium.base.supplier.Supplier; import org.chromium.chrome.browser.flags.ChromeFeatureList; @@ -89,7 +87,6 @@ private final @NonNull DropdownItemViewInfoListManager mDropdownViewInfoListManager; private final @NonNull Callback<Tab> mBringTabToFrontCallback; private final @NonNull Supplier<TabWindowManager> mTabWindowManagerSupplier; - private final @NonNull JankTracker mJankTracker; private final @NonNull Runnable mClearFocusCallback; private @NonNull AutocompleteResult mAutocompleteResult = AutocompleteResult.EMPTY_RESULT; @@ -172,15 +169,13 @@ @NonNull LocationBarDataProvider locationBarDataProvider, @NonNull Callback<Tab> bringTabToFrontCallback, @NonNull Supplier<TabWindowManager> tabWindowManagerSupplier, - @NonNull BookmarkState bookmarkState, @NonNull JankTracker jankTracker, - @NonNull ActionChipsDelegate actionChipsDelegate, + @NonNull BookmarkState bookmarkState, @NonNull ActionChipsDelegate actionChipsDelegate, @NonNull OpenHistoryClustersDelegate openHistoryClustersDelegate) { mContext = context; mControllerProvider = controllerProvider; mDelegate = delegate; mUrlBarEditingTextProvider = textProvider; mListPropertyModel = listPropertyModel; - mJankTracker = jankTracker; mModalDialogManagerSupplier = modalDialogManagerSupplier; mHandler = handler; mDataProvider = locationBarDataProvider; @@ -328,7 +323,6 @@ mOmniboxFocusResultedInNavigation = false; mSuggestionsListScrolled = false; mUrlFocusTime = System.currentTimeMillis(); - mJankTracker.startTrackingScenario(JankScenario.OMNIBOX_FOCUS); if (!OmniboxFeatures.shouldRemoveExcessiveRecycledViewClearCalls()) { setSuggestionVisibilityState(SuggestionVisibilityState.PENDING_ALLOW); @@ -352,7 +346,6 @@ } } else { stopMeasuringSuggestionRequestToUiModelTime(); - mJankTracker.finishTrackingScenario(JankScenario.OMNIBOX_FOCUS); cancelAutocompleteRequests(); SuggestionsMetrics.recordOmniboxFocusResultedInNavigation( mOmniboxFocusResultedInNavigation);
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediatorUnitTest.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediatorUnitTest.java index 04251e00..da144bb3 100644 --- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediatorUnitTest.java +++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediatorUnitTest.java
@@ -40,7 +40,6 @@ import org.chromium.base.ActivityState; import org.chromium.base.ContextUtils; -import org.chromium.base.jank_tracker.DummyJankTracker; import org.chromium.base.metrics.RecordHistogram; import org.chromium.base.supplier.ObservableSupplierImpl; import org.chromium.base.test.BaseRobolectricTestRunner; @@ -134,7 +133,7 @@ mAutocompleteDelegate, mTextStateProvider, mListModel, new Handler(), () -> mModalDialogManager, null, null, mLocationBarDataProvider, tab -> {}, mTabWindowManagerSupplier, url -> false, - new DummyJankTracker(), mActionChipsDelegate, mOpenHistoryClustersDelegate); + mActionChipsDelegate, mOpenHistoryClustersDelegate); mMediator.setAutocompleteProfile(mProfile); }); // clang-format on
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhone.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhone.java index 4b6dc6a..40107c9 100644 --- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhone.java +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhone.java
@@ -144,7 +144,7 @@ private TextView mUrlBar; protected View mUrlActionContainer; protected ImageView mToolbarShadow; - private OptionalButtonCoordinator mOptionalButton; + private OptionalButtonCoordinator mOptionalButtonCoordinator; private boolean mOptionalButtonUsesTint; private boolean mShouldShowModernizeVisualUpdate; @@ -395,8 +395,8 @@ if (mCurrentLocationBarColor == color) return; mCurrentLocationBarColor = color; mLocationBarBackground.setTint(color); - if (mOptionalButton != null) { - mOptionalButton.setBackgroundColorFilter(color); + if (mOptionalButtonCoordinator != null) { + mOptionalButtonCoordinator.setBackgroundColorFilter(color); } } @@ -630,7 +630,7 @@ @VisibleForTesting void setOptionalButtonCoordinatorForTesting( OptionalButtonCoordinator optionalButtonCoordinator) { - mOptionalButton = optionalButtonCoordinator; + mOptionalButtonCoordinator = optionalButtonCoordinator; } @SuppressLint("RtlHardcoded") @@ -941,7 +941,7 @@ */ @VisibleForTesting float getLocationBarWidthOffsetForOptionalButton() { - float widthChange = mOptionalButton.getViewWidth(); + float widthChange = mOptionalButtonCoordinator.getViewWidth(); // When the optional button is the only visible button after the location bar and the // button is hidden mToolbarSidePadding is used for the padding after the location bar. @@ -1327,12 +1327,13 @@ // some cases (e.g. the first frame of the showing animation) the view may be visible with a // width of zero. Calling draw in this state results in drawing the inner ImageButton when // it's not supposed to. (See https://crbug.com/1422176 for an example of this happening). - if (mOptionalButton != null && mOptionalButton.getViewVisibility() != View.GONE - && mOptionalButton.getViewWidth() != 0) { + if (mOptionalButtonCoordinator != null + && mOptionalButtonCoordinator.getViewVisibility() != View.GONE + && mOptionalButtonCoordinator.getViewWidth() != 0) { canvas.save(); - ViewUtils.translateCanvasToView( - mToolbarButtonsContainer, mOptionalButton.getViewForDrawing(), canvas); - mOptionalButton.getViewForDrawing().draw(canvas); + ViewUtils.translateCanvasToView(mToolbarButtonsContainer, + mOptionalButtonCoordinator.getViewForDrawing(), canvas); + mOptionalButtonCoordinator.getViewForDrawing().draw(canvas); canvas.restore(); } @@ -1713,8 +1714,8 @@ } } - if (mOptionalButton != null && mOptionalButtonUsesTint) { - mOptionalButton.setIconForegroundColor(tint); + if (mOptionalButtonCoordinator != null && mOptionalButtonUsesTint) { + mOptionalButtonCoordinator.setIconForegroundColor(tint); } // TODO(amaralp): Have the LocationBar listen to tint changes. @@ -2082,7 +2083,7 @@ mUrlFocusLayoutAnimator.cancel(); mUrlFocusLayoutAnimator = null; } - if (mOptionalButtonAnimationRunning) mOptionalButton.cancelTransition(); + if (mOptionalButtonAnimationRunning) mOptionalButtonCoordinator.cancelTransition(); List<Animator> animators = new ArrayList<>(); if (hasFocus) { @@ -2465,7 +2466,7 @@ } private void initializeOptionalButton() { - if (mOptionalButton == null) { + if (mOptionalButtonCoordinator == null) { ViewStub optionalButtonStub = findViewById(R.id.optional_button_stub); if (optionalButtonStub == null) { @@ -2497,17 +2498,18 @@ Profile profile = Profile.getLastUsedRegularProfile(); Tracker featureEngagementTracker = TrackerFactory.getTrackerForProfile(profile); - mOptionalButton = new OptionalButtonCoordinator(optionalButton, userEducationHelper, - /* transitionRoot= */ mToolbarButtonsContainer, isAnimationAllowedPredicate, - featureEngagementTracker); + mOptionalButtonCoordinator = + new OptionalButtonCoordinator(optionalButton, userEducationHelper, + /* transitionRoot= */ mToolbarButtonsContainer, + isAnimationAllowedPredicate, featureEngagementTracker); // Set the button's background to the same color as the URL bar background. This color // is only used when showing dynamic actions. - mOptionalButton.setBackgroundColorFilter(mCurrentLocationBarColor); - mOptionalButton.setOnBeforeHideTransitionCallback( + mOptionalButtonCoordinator.setBackgroundColorFilter(mCurrentLocationBarColor); + mOptionalButtonCoordinator.setOnBeforeHideTransitionCallback( () -> mLayoutLocationBarWithoutExtraButton = true); - mOptionalButton.setTransitionStartedCallback(transitionType -> { + mOptionalButtonCoordinator.setTransitionStartedCallback(transitionType -> { mOptionalButtonAnimationRunning = true; keepControlsShownForAnimation(); @@ -2524,7 +2526,7 @@ break; } }); - mOptionalButton.setTransitionFinishedCallback(transitionType -> { + mOptionalButtonCoordinator.setTransitionFinishedCallback(transitionType -> { // If we are done expanding the transition chip then don't re-enable hiding browser // controls, as we'll begin the collapse transition soon. if (transitionType == TransitionType.EXPANDING_ACTION_CHIP) { @@ -2547,18 +2549,18 @@ mButtonData = buttonData; ButtonSpec buttonSpec = mButtonData.getButtonSpec(); - if (mOptionalButton == null) { + if (mOptionalButtonCoordinator == null) { initializeOptionalButton(); } mOptionalButtonUsesTint = buttonSpec.getSupportsTinting(); - mOptionalButton.updateButton(buttonData); + mOptionalButtonCoordinator.updateButton(buttonData); if (mOptionalButtonUsesTint) { - mOptionalButton.setIconForegroundColor(getTint()); + mOptionalButtonCoordinator.setIconForegroundColor(getTint()); } else { - mOptionalButton.setIconForegroundColor(null); + mOptionalButtonCoordinator.setIconForegroundColor(null); } } @@ -2572,19 +2574,20 @@ @Override void hideOptionalButton() { mButtonData = null; - if (mOptionalButton == null || mOptionalButton.getViewVisibility() == View.GONE + if (mOptionalButtonCoordinator == null + || mOptionalButtonCoordinator.getViewVisibility() == View.GONE || mLayoutLocationBarWithoutExtraButton) { return; } - mOptionalButton.hideButton(); + mOptionalButtonCoordinator.hideButton(); } @Override @VisibleForTesting public View getOptionalButtonViewForTesting() { - if (mOptionalButton != null) { - return mOptionalButton.getButtonViewForTesting(); + if (mOptionalButtonCoordinator != null) { + return mOptionalButtonCoordinator.getButtonViewForTesting(); } return null;
diff --git a/chrome/browser/ui/ash/chrome_shell_delegate.cc b/chrome/browser/ui/ash/chrome_shell_delegate.cc index 42c61717..1b3119d 100644 --- a/chrome/browser/ui/ash/chrome_shell_delegate.cc +++ b/chrome/browser/ui/ash/chrome_shell_delegate.cc
@@ -108,8 +108,6 @@ chrome::FeedbackSource ToChromeFeedbackSource( ash::ShellDelegate::FeedbackSource source) { switch (source) { - case ash::ShellDelegate::FeedbackSource::kBentoBar: - return chrome::FeedbackSource::kFeedbackSourceBentoBar; case ash::ShellDelegate::FeedbackSource::kWindowLayoutMenu: return chrome::FeedbackSource::kFeedbackSourceWindowLayoutMenu; }
diff --git a/chrome/browser/ui/ash/desks/desks_client_browsertest.cc b/chrome/browser/ui/ash/desks/desks_client_browsertest.cc index d7799ee..6c5f92b 100644 --- a/chrome/browser/ui/ash/desks/desks_client_browsertest.cc +++ b/chrome/browser/ui/ash/desks/desks_client_browsertest.cc
@@ -21,6 +21,7 @@ #include "ash/wm/desks/desk.h" #include "ash/wm/desks/desks_controller.h" #include "ash/wm/desks/desks_test_util.h" +#include "ash/wm/desks/templates/saved_desk_controller.h" #include "ash/wm/desks/templates/saved_desk_metrics_util.h" #include "ash/wm/desks/templates/saved_desk_presenter.h" #include "ash/wm/desks/templates/saved_desk_test_util.h" @@ -3384,3 +3385,106 @@ // Verify that the admin templates is removed. EXPECT_FALSE(ContainUuidInTemplates(admin_template_uuid, GetDeskTemplates())); } + +class AdminTemplateTest : public extensions::PlatformAppBrowserTest { + public: + AdminTemplateTest() + : scoped_feature_list_(ash::features::kAppLaunchAutomation) { + // Suppress the multitask menu nudge as we'll be checking the stacking order + // and the count of the active desk children. + chromeos::MultitaskMenuNudgeController::SetSuppressNudgeForTesting(true); + } + AdminTemplateTest(const AdminTemplateTest&) = delete; + AdminTemplateTest& operator=(const AdminTemplateTest&) = delete; + ~AdminTemplateTest() override = default; + + // The definition of an admin template for a test. + struct AdminTemplateDefinition { + struct WindowDefinition { + std::vector<std::string> urls; + }; + + std::vector<WindowDefinition> windows; + }; + + // Creates an admin template with the windows and URLs given by `definition`. + std::unique_ptr<ash::DeskTemplate> CreateAdminTemplate( + const AdminTemplateDefinition& definition) { + // Common set of bounds to use for now. Later, get from `definition`. + base::Value::List bounds; + for (int b : {100, 50, 400, 300}) { + bounds.Append(b); + } + + base::Value::Dict windows; + for (size_t i = 0; i != definition.windows.size(); ++i) { + base::Value::Dict window; + window.Set("title", "Chrome"); + window.Set("window_state_type", 0); + window.Set("bounds", bounds.Clone()); + + base::Value::List urls; + for (const std::string& url : definition.windows[i].urls) { + urls.Append(url); + } + window.Set("urls", std::move(urls)); + + windows.Set(base::NumberToString(i + 1), std::move(window)); + } + + base::Value::Dict root; + root.Set(app_constants::kChromeAppId, std::move(windows)); + + auto admin_template = std::make_unique<ash::DeskTemplate>( + base::GUID::GenerateRandomV4(), ash::DeskTemplateSource::kPolicy, + "Admin template", base::Time::Now(), ash::DeskTemplateType::kTemplate); + + admin_template->set_desk_restore_data( + std::make_unique<app_restore::RestoreData>( + base::Value(std::move(root)))); + + return admin_template; + } + + private: + base::test::ScopedFeatureList scoped_feature_list_; +}; + +// TODO(b/273803538): Add tests for lacros. +IN_PROC_BROWSER_TEST_F(AdminTemplateTest, LaunchAdminTemplate) { + // Launch an admin template with a single browser. Verifies that a browser was + // actually launched. + auto admin_template = + CreateAdminTemplate({.windows = {{.urls = {kExampleUrl1}}}}); + ASSERT_NE(admin_template, nullptr); + + base::GUID template_uuid = admin_template->uuid(); + + auto* saved_desk_controller = ash::Shell::Get()->saved_desk_controller(); + ash::SavedDeskControllerTestApi(saved_desk_controller) + .SetAdminTemplate(std::move(admin_template)); + + saved_desk_controller->LaunchAdminTemplate(template_uuid); + + // Verify that there are two browsers (one from the suite and one from the + // test), and verify that our launched browser is stacked on top. + Browser* new_browser = FindLaunchedBrowserByURLs({GURL(kExampleUrl1)}); + ASSERT_TRUE(new_browser); + + aura::Window* old_browser_window = browser()->window()->GetNativeWindow(); + aura::Window* new_browser_window = new_browser->window()->GetNativeWindow(); + + // Both browsers should be on the same desk. + ASSERT_EQ(old_browser_window->parent(), new_browser_window->parent()); + + // Verify that the new browser window is stacked in front of the + // existing. Children are ordered from bottommost to topmost. We therefore + // expect the new window to have an index that is higher than the old. + const auto& container = new_browser_window->parent()->children(); + size_t new_index = + base::ranges::find(container, new_browser_window) - container.begin(); + size_t old_index = + base::ranges::find(container, old_browser_window) - container.begin(); + + EXPECT_GT(new_index, old_index); +}
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc index c25dd6c..996be10 100644 --- a/chrome/browser/ui/browser.cc +++ b/chrome/browser/ui/browser.cc
@@ -130,6 +130,7 @@ #include "chrome/browser/ui/tab_dialogs.h" #include "chrome/browser/ui/tab_helpers.h" #include "chrome/browser/ui/tab_modal_confirm_dialog.h" +#include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_service_factory.h" #include "chrome/browser/ui/tabs/tab_enums.h" #include "chrome/browser/ui/tabs/tab_group.h" #include "chrome/browser/ui/tabs/tab_group_model.h" @@ -1243,8 +1244,22 @@ tab_strip_model_->group_model() ->GetTabGroup(change.group) ->visual_data(); + const SavedTabGroupKeyedService* const saved_tab_group_keyed_service = + base::FeatureList::IsEnabled(features::kTabGroupsSave) + ? SavedTabGroupServiceFactory::GetForProfile(profile_) + : nullptr; + absl::optional<std::string> saved_guid; + + if (saved_tab_group_keyed_service) { + const SavedTabGroup* const saved_group = + saved_tab_group_keyed_service->model()->Get(change.group); + if (saved_group) { + saved_guid = saved_group->saved_guid().AsLowercaseString(); + } + } + session_service->SetTabGroupMetadata(session_id(), change.group, - visual_data); + visual_data, std::move(saved_guid)); } } else if (change.type == TabGroupChange::kClosed) { sessions::TabRestoreService* tab_restore_service =
diff --git a/chrome/browser/ui/browser.h b/chrome/browser/ui/browser.h index e03d772..23a838b 100644 --- a/chrome/browser/ui/browser.h +++ b/chrome/browser/ui/browser.h
@@ -1106,32 +1106,40 @@ // Shared code between Reload() and ReloadBypassingCache(). void ReloadInternal(WindowOpenDisposition disposition, bool bypass_cache); + // See comment on SupportsWindowFeatureImpl for info on `check_can_support`. bool NormalBrowserSupportsWindowFeature(WindowFeature feature, bool check_can_support) const; + // See comment on SupportsWindowFeatureImpl for info on `check_can_support`. bool PopupBrowserSupportsWindowFeature(WindowFeature feature, bool check_can_support) const; + // See comment on SupportsWindowFeatureImpl for info on `check_can_support`. bool AppPopupBrowserSupportsWindowFeature(WindowFeature feature, bool check_can_support) const; + // See comment on SupportsWindowFeatureImpl for info on `check_can_support`. bool AppBrowserSupportsWindowFeature(WindowFeature feature, bool check_can_support) const; #if BUILDFLAG(IS_CHROMEOS_ASH) + // See comment on SupportsWindowFeatureImpl for info on `check_can_support`. bool CustomTabBrowserSupportsWindowFeature(WindowFeature feature) const; #endif + // See comment on SupportsWindowFeatureImpl for info on `check_can_support`. bool PictureInPictureBrowserSupportsWindowFeature( WindowFeature feature, bool check_can_support) const; // Implementation of SupportsWindowFeature and CanSupportWindowFeature. If - // |check_fullscreen| is true, the set of features reflect the actual state of - // the browser, otherwise the set of features reflect the possible state of - // the browser. + // `check_can_support` is true, this method returns true if this type of + // browser can ever support `feature`, under any conditions; if + // `check_can_support` is false, it returns true if the browser *in its + // current state* (e.g. whether or not it is currently fullscreen) supports + // `feature`. bool SupportsWindowFeatureImpl(WindowFeature feature, - bool check_fullscreen) const; + bool check_can_support) const; // Resets |bookmark_bar_state_| based on the active tab. Notifies the // BrowserWindow if necessary.
diff --git a/chrome/browser/ui/chrome_pages.h b/chrome/browser/ui/chrome_pages.h index e73ef80..d6ab951 100644 --- a/chrome/browser/ui/chrome_pages.h +++ b/chrome/browser/ui/chrome_pages.h
@@ -96,7 +96,7 @@ kFeedbackSourceCameraApp, kFeedbackSourceCaptureMode, kFeedbackSourceChromeLabs, - kFeedbackSourceBentoBar, + kFeedbackSourceBentoBar_DEPRECATED, kFeedbackSourceQuickAnswers, kFeedbackSourceWhatsNew, kFeedbackSourceConnectivityDiagnostics,
diff --git a/chrome/browser/ui/omnibox/chrome_omnibox_client.cc b/chrome/browser/ui/omnibox/chrome_omnibox_client.cc index 8394064..ca295f0 100644 --- a/chrome/browser/ui/omnibox/chrome_omnibox_client.cc +++ b/chrome/browser/ui/omnibox/chrome_omnibox_client.cc
@@ -397,7 +397,7 @@ if (web_contents) { if (SearchPrefetchService* search_prefetch_service = SearchPrefetchServiceFactory::GetForProfile(profile_)) { - search_prefetch_service->OnURLOpenedFromOmnibox(log, web_contents); + search_prefetch_service->OnURLOpenedFromOmnibox(log); } auto* prerender_manager = PrerenderManager::FromWebContents(web_contents); @@ -433,9 +433,6 @@ // chrome::OpenUpdateChromeDialog because that call is intended for use // by the delayed-update/auto-nag system, possibly presenting dialogs // that don't apply when the goal is immediate relaunch & update. - // TODO(orinj): Ensure that this is the correct way to handle - // explicitly requested update regardless of the kind of update ready. - // See comments at https://crrev.com/c/1281162 for context. base::RecordAction(base::UserMetricsAction("UpdateChrome")); browser->window()->ShowUpdateChromeDialog(); }
diff --git a/chrome/browser/ui/tabs/existing_tab_group_sub_menu_model.cc b/chrome/browser/ui/tabs/existing_tab_group_sub_menu_model.cc index 153b1c5a..7a472d2 100644 --- a/chrome/browser/ui/tabs/existing_tab_group_sub_menu_model.cc +++ b/chrome/browser/ui/tabs/existing_tab_group_sub_menu_model.cc
@@ -178,11 +178,6 @@ return false; } -std::u16string ExistingTabGroupSubMenuModel::GetLabelAt(size_t index) const { - return ui::EscapeMenuLabelAmpersands( - ExistingBaseSubMenuModel::GetLabelAt(index)); -} - void ExistingTabGroupSubMenuModel::ExecuteExistingCommand(size_t target_index) { DCHECK_LE(size_t(target_index), target_index_to_group_mapping_.size()); TabGroupModel* group_model = model()->group_model();
diff --git a/chrome/browser/ui/tabs/existing_tab_group_sub_menu_model.h b/chrome/browser/ui/tabs/existing_tab_group_sub_menu_model.h index b379b823..3fd79ab 100644 --- a/chrome/browser/ui/tabs/existing_tab_group_sub_menu_model.h +++ b/chrome/browser/ui/tabs/existing_tab_group_sub_menu_model.h
@@ -35,9 +35,6 @@ int context_index, TabMenuModelDelegate* tab_menu_model_delegate); - // ExistingBaseSubMenuModel: - std::u16string GetLabelAt(size_t index) const override; - // Used for testing. void ExecuteExistingCommandForTesting(size_t target_index);
diff --git a/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_controller.h b/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_controller.h index e1a3f02..5f5e110 100644 --- a/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_controller.h +++ b/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_controller.h
@@ -30,6 +30,12 @@ // group id and web content tokens. virtual void DisconnectLocalTabGroup( const tab_groups::TabGroupId& group_id) = 0; + + // Begins listening to the Tab Group in the TabStrip. Adds the local tab group + // id and web content tokens. + virtual void ConnectLocalTabGroup( + const tab_groups::TabGroupId& local_group_id, + const base::GUID& saved_group_guid) = 0; }; #endif // CHROME_BROWSER_UI_TABS_SAVED_TAB_GROUPS_SAVED_TAB_GROUP_CONTROLLER_H_
diff --git a/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_keyed_service.cc b/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_keyed_service.cc index 04f2e83..f417886 100644 --- a/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_keyed_service.cc +++ b/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_keyed_service.cc
@@ -18,10 +18,13 @@ #include "chrome/common/channel_info.h" #include "components/saved_tab_groups/saved_tab_group_model.h" #include "components/saved_tab_groups/saved_tab_group_sync_bridge.h" +#include "components/saved_tab_groups/saved_tab_group_tab.h" #include "components/sync/base/model_type.h" #include "components/sync/base/report_unrecoverable_error.h" #include "components/sync/model/client_tag_based_model_type_processor.h" #include "components/sync/model/model_type_store_service.h" +#include "components/tab_groups/tab_group_id.h" +#include "components/tab_groups/tab_group_visual_data.h" #include "content/public/browser/web_contents.h" namespace { @@ -39,7 +42,15 @@ SavedTabGroupKeyedService::SavedTabGroupKeyedService(Profile* profile) : profile_(profile), listener_(model(), profile), - bridge_(model(), GetStoreFactory(), CreateChangeProcessor()) {} + bridge_(model(), GetStoreFactory(), CreateChangeProcessor()) { + model()->AddObserver(this); + + // Perform the necessary setup, if the model is already loaded before we start + // observing it. Otherwise, the model will notify us when it has loaded. + if (model()->is_loaded()) { + SavedTabGroupModelLoaded(); + } +} SavedTabGroupKeyedService::~SavedTabGroupKeyedService() = default; @@ -49,6 +60,14 @@ ->GetStoreFactory(); } +void SavedTabGroupKeyedService::StoreLocalToSavedId( + const base::GUID& saved_guid, + const tab_groups::TabGroupId local_group_id) { + CHECK(!model()->is_loaded()); + saved_guid_to_local_group_id_mapping_.emplace_back(saved_guid, + local_group_id); +} + void SavedTabGroupKeyedService::OpenSavedTabGroupInBrowser( Browser* browser, const base::GUID& saved_group_guid) { @@ -131,24 +150,18 @@ // Update the saved tab group to link to the local group id. model_.OnGroupOpenedInTabStrip(saved_group->saved_guid(), tab_group_id); - TabGroup* const group = + TabGroup* const tab_group = tab_strip_model_for_creation->group_model()->GetTabGroup(tab_group_id); // Activate the first tab in the tab group. - absl::optional<int> first_tab = group->GetFirstTab(); + absl::optional<int> first_tab = tab_group->GetFirstTab(); DCHECK(first_tab.has_value()); tab_strip_model_for_creation->ActivateTabAt(first_tab.value()); - // Update the group to use the saved title and color. - tab_groups::TabGroupVisualData visual_data(saved_group->title(), - saved_group->color(), - /*is_collapsed=*/false); - // Set the groups visual data after the tab strip is in its final state. This - // ensures the tab group's bounds are correctly set. crbug/1408814. - group->SetVisualData(visual_data, /*is_customized=*/true); - listener_.ConnectToLocalTabGroup(*model_.Get(saved_group_guid), local_and_saved_tab_mapping); + + UpdateTabGroupVisualData(tab_group, saved_group); } void SavedTabGroupKeyedService::SaveGroup( @@ -214,3 +227,73 @@ // Stop listening to the current tab group and notify observers. model_.OnGroupClosedInTabStrip(group_id); } + +void SavedTabGroupKeyedService::ConnectLocalTabGroup( + const tab_groups::TabGroupId& local_group_id, + const base::GUID& saved_guid) { + const TabStripModel* tab_strip_model = + GetTabStripModelWithTabGroupId(local_group_id); + TabGroup* const tab_group = + tab_strip_model->group_model()->GetTabGroup(local_group_id); + CHECK(tab_group); + + const gfx::Range& tab_range = tab_group->ListTabs(); + const SavedTabGroup* const saved_group = model_.Get(saved_guid); + CHECK(saved_group); + CHECK(tab_range.length() == saved_group->saved_tabs().size()); + + std::vector<std::pair<content::WebContents*, base::GUID>> + web_contents_to_guid_mapping; + + for (size_t i = tab_range.start(); i < tab_range.end(); ++i) { + content::WebContents* web_contents = tab_strip_model->GetWebContentsAt(i); + CHECK(web_contents); + + const size_t saved_tab_index = i - tab_range.start(); + const SavedTabGroupTab& saved_tab = + saved_group->saved_tabs()[saved_tab_index]; + + web_contents_to_guid_mapping.emplace_back(web_contents, + saved_tab.saved_tab_guid()); + } + + listener_.ConnectToLocalTabGroup(*model_.Get(saved_guid), + std::move(web_contents_to_guid_mapping)); + + UpdateTabGroupVisualData(tab_group, saved_group); +} + +void SavedTabGroupKeyedService::SavedTabGroupModelLoaded() { + for (const auto& [saved_guid, local_group_id] : + saved_guid_to_local_group_id_mapping_) { + model_.OnGroupOpenedInTabStrip(saved_guid, local_group_id); + ConnectLocalTabGroup(local_group_id, saved_guid); + } + + // SavedTabGroupModelLoaded is only called once when the model is initially + // loaded. As such we can stop oberserving the model and assume that all of + // the data in `saved_guid_to_local_group_id_mapping_` has been used. + model_.RemoveObserver(this); + saved_guid_to_local_group_id_mapping_.clear(); + CHECK(saved_guid_to_local_group_id_mapping_.empty()); +} + +const TabStripModel* SavedTabGroupKeyedService::GetTabStripModelWithTabGroupId( + const tab_groups::TabGroupId& local_group_id) { + const Browser* const browser = + listener_.GetBrowserWithTabGroupId(local_group_id); + CHECK(browser); + return browser->tab_strip_model(); +} + +void SavedTabGroupKeyedService::UpdateTabGroupVisualData( + TabGroup* const tab_group, + const SavedTabGroup* saved_group) { + // Update the group to use the saved title and color. + const tab_groups::TabGroupVisualData visual_data( + saved_group->title(), saved_group->color(), /*is_collapsed=*/false); + + // Set the groups visual data after the tab strip is in its final state. This + // ensures the tab group's bounds are correctly set. crbug/1408814. + tab_group->SetVisualData(visual_data, /*is_customized=*/true); +}
diff --git a/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_keyed_service.h b/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_keyed_service.h index 28044bdc..1883a0a 100644 --- a/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_keyed_service.h +++ b/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_keyed_service.h
@@ -14,11 +14,13 @@ #include "components/tab_groups/tab_group_id.h" class Profile; +class TabGroup; // Serves to instantiate and own the SavedTabGroup infrastructure for the // browser. class SavedTabGroupKeyedService : public KeyedService, - public SavedTabGroupController { + public SavedTabGroupController, + public SavedTabGroupModelObserver { public: explicit SavedTabGroupKeyedService(Profile* profile); SavedTabGroupKeyedService(const SavedTabGroupKeyedService&) = delete; @@ -32,14 +34,33 @@ SavedTabGroupSyncBridge* bridge() { return &bridge_; } Profile* profile() { return profile_; } + // Populates `saved_guid_to_local_group_id_mapping_` with a pair to link once + // SavedTabGroupModelLoaded is called. + void StoreLocalToSavedId(const base::GUID& saved_guid, + const tab_groups::TabGroupId local_group_id); + // SavedTabGroupController void OpenSavedTabGroupInBrowser(Browser* browser, const base::GUID& saved_group_guid) override; void SaveGroup(const tab_groups::TabGroupId& group_id) override; void UnsaveGroup(const tab_groups::TabGroupId& group_id) override; void DisconnectLocalTabGroup(const tab_groups::TabGroupId& group_id) override; + void ConnectLocalTabGroup(const tab_groups::TabGroupId& group_id, + const base::GUID& saved_group_guid) override; + + // SavedTabGroupModelObserver + void SavedTabGroupModelLoaded() override; private: + // Returns a pointer to the TabStripModel which contains `local_group_id`. + const TabStripModel* GetTabStripModelWithTabGroupId( + const tab_groups::TabGroupId& local_group_id); + + // Notifies observers that `tab_group`'s visual data was changed using data + // found in `saved_group`. + void UpdateTabGroupVisualData(TabGroup* const tab_group, + const SavedTabGroup* saved_group); + // Returns the ModelTypeStoreFactory tied to the current profile. syncer::OnceModelTypeStoreFactory GetStoreFactory(); @@ -55,6 +76,13 @@ // Stores SavedTabGroup data to the disk and to sync if enabled. SavedTabGroupSyncBridge bridge_; + + // Keeps track of the ids of session restored tab groups that were once saved + // in order to link them together again once the SavedTabGroupModelLoaded is + // called. After the model is loaded, this variable is emptied to conserve + // memory. + std::vector<std::pair<base::GUID, tab_groups::TabGroupId>> + saved_guid_to_local_group_id_mapping_; }; #endif // CHROME_BROWSER_UI_TABS_SAVED_TAB_GROUPS_SAVED_TAB_GROUP_KEYED_SERVICE_H_
diff --git a/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_keyed_service_unittest.cc b/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_keyed_service_unittest.cc index db2f49f..753fd31 100644 --- a/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_keyed_service_unittest.cc +++ b/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_keyed_service_unittest.cc
@@ -7,6 +7,7 @@ #include <memory> #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_keyed_service.h" +#include "chrome/browser/ui/tabs/tab_group_model.h" #include "chrome/test/base/browser_with_test_window_test.h" #include "chrome/test/base/testing_profile.h" #include "components/tab_groups/tab_group_id.h" @@ -153,3 +154,73 @@ EXPECT_EQ(2u, tab_token_mapping.size()); EXPECT_TRUE(tab_token_mapping.contains(added_tab)); } + +TEST_F(SavedTabGroupKeyedServiceUnitTest, + KeyedServiceLinksTabIdsToGuidsWhenModelIsLoaded) { + Browser* browser_1 = AddBrowser(); + ASSERT_EQ(0, browser_1->tab_strip_model()->count()); + + // Add 4 tabs to the browser. + for (size_t i = 0; i < 4; ++i) { + AddTabToBrowser(browser_1, 0); + } + + ASSERT_EQ(4, browser_1->tab_strip_model()->count()); + + const tab_groups::TabGroupId tab_group_id_1 = + browser_1->tab_strip_model()->AddToNewGroup({0}); + const tab_groups::TabGroupId tab_group_id_2 = + browser_1->tab_strip_model()->AddToNewGroup({1, 2}); + const tab_groups::TabGroupId tab_group_id_3 = + browser_1->tab_strip_model()->AddToNewGroup({3}); + + const base::GUID guid_1 = base::GUID::GenerateRandomV4(); + const base::GUID guid_2 = base::GUID::GenerateRandomV4(); + + // Store the guid to tab_group_id association in the keyed service. We should + // expect at the end of the test, `tab_group_id_3` has no association with the + // SavedTabGroupModel at all. + service()->StoreLocalToSavedId(guid_1, tab_group_id_1); + service()->StoreLocalToSavedId(guid_2, tab_group_id_2); + + // Populate the SavedTabGroupModel with some test data to simulate the browser + // loading in persisted data on startup. + std::vector<SavedTabGroupTab> group_1_tabs = { + SavedTabGroupTab(GURL("chrome://newtab"), u"New Tab", guid_1)}; + std::vector<SavedTabGroupTab> group_2_tabs = { + SavedTabGroupTab(GURL("chrome://newtab"), u"New Tab", guid_2), + SavedTabGroupTab(GURL("chrome://newtab"), u"New Tab", guid_2)}; + + SavedTabGroup saved_group_1(u"Group 1", tab_groups::TabGroupColorId::kGrey, + std::move(group_1_tabs), guid_1); + SavedTabGroup saved_group_2(u"Group 2", tab_groups::TabGroupColorId::kRed, + std::move(group_2_tabs), guid_2); + service()->model()->Add(saved_group_1); + service()->model()->Add(saved_group_2); + + // Notify the KeyedService that the SavedTabGroupModel has loaded all local + // data triggered by the completion of SavedTabGroupModel::LoadStoredEntries. + service()->model()->LoadStoredEntries({}); + + // Retrieve the 2 saved groups from the model. + SavedTabGroupModel* model = service()->model(); + const SavedTabGroup* retrieved_saved_group_1 = model->Get(guid_1); + const SavedTabGroup* retrieved_saved_group_2 = model->Get(guid_2); + + // Verify saved group 1 and 2 have the correct tab group id. + ASSERT_TRUE(retrieved_saved_group_1); + ASSERT_TRUE(retrieved_saved_group_1->local_group_id().has_value()); + EXPECT_EQ(tab_group_id_1, retrieved_saved_group_1->local_group_id().value()); + + ASSERT_TRUE(retrieved_saved_group_2); + ASSERT_TRUE(retrieved_saved_group_2->local_group_id().has_value()); + EXPECT_EQ(tab_group_id_2, retrieved_saved_group_2->local_group_id().value()); + + // Expect the model can locate tab group ids for group 1 and 2 but not + // group 3. + EXPECT_TRUE(model->Contains(tab_group_id_1)); + EXPECT_TRUE(model->Contains(tab_group_id_2)); + EXPECT_FALSE(model->Contains(tab_group_id_3)); + + EXPECT_DEATH(service()->StoreLocalToSavedId(guid_1, tab_group_id_1), ""); +}
diff --git a/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_interactive_uitest.cc b/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_interactive_uitest.cc index d3e3e19..a74f782 100644 --- a/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_interactive_uitest.cc +++ b/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_interactive_uitest.cc
@@ -37,7 +37,6 @@ void SetUp() override { scoped_feature_list_.InitWithFeatures({features::kTabGroupsSave}, {}); - set_open_about_blank_on_browser_launch(true); InteractiveBrowserTest::SetUp(); } @@ -55,10 +54,10 @@ MoveMouseTo(kTabToHover)); } - MultiStep HoverFirstTabGroupHeader() { + MultiStep HoverTabGroupHeaderAt(int index) { const char kTabGroupHeaderToHover[] = "Tab group header to hover"; return Steps(NameDescendantViewByType<TabGroupHeader>( - kBrowserViewElementId, kTabGroupHeaderToHover, 0), + kBrowserViewElementId, kTabGroupHeaderToHover, index), MoveMouseTo(kTabGroupHeaderToHover)); }
diff --git a/chrome/browser/ui/views/download/bubble/download_bubble_row_view.cc b/chrome/browser/ui/views/download/bubble/download_bubble_row_view.cc index ef42b7b..2ef525d 100644 --- a/chrome/browser/ui/views/download/bubble/download_bubble_row_view.cc +++ b/chrome/browser/ui/views/download/bubble/download_bubble_row_view.cc
@@ -335,7 +335,8 @@ DownloadBubbleRowListView* row_list_view, DownloadBubbleUIController* bubble_controller, DownloadBubbleNavigationHandler* navigation_handler, - Browser* browser) + Browser* browser, + int fixed_width) : model_(std::move(model)), context_menu_( std::make_unique<DownloadShelfContextMenuView>(model_->GetWeakPtr(), @@ -355,7 +356,8 @@ FROM_HERE, base::Minutes(1), base::BindRepeating(&DownloadBubbleRowView::UpdateStatusText, - base::Unretained(this))) { + base::Unretained(this))), + fixed_width_(fixed_width) { model_->SetDelegate(this); SetBorder(views::CreateEmptyBorder(GetLayoutInsets(DOWNLOAD_ROW))); @@ -579,13 +581,7 @@ } gfx::Size DownloadBubbleRowView::CalculatePreferredSize() const { - // TODO(crbug.com/1349528): The size constraint is not passed down from the - // views tree in the first round of layout, so setting a fixed width to bound - // the view. This is assuming that the row view is loaded inside a bubble. It - // will break if the row view is loaded inside a different parent view. - int fixed_width = ChromeLayoutProvider::Get()->GetDistanceMetric( - views::DISTANCE_BUBBLE_PREFERRED_WIDTH); - return {fixed_width, GetHeightForWidth(fixed_width)}; + return {fixed_width_, GetHeightForWidth(fixed_width_)}; } void DownloadBubbleRowView::AddLayerToRegion(ui::Layer* layer,
diff --git a/chrome/browser/ui/views/download/bubble/download_bubble_row_view.h b/chrome/browser/ui/views/download/bubble/download_bubble_row_view.h index 584a75c..a13ab86c 100644 --- a/chrome/browser/ui/views/download/bubble/download_bubble_row_view.h +++ b/chrome/browser/ui/views/download/bubble/download_bubble_row_view.h
@@ -45,7 +45,8 @@ DownloadBubbleRowListView* row_list_view, DownloadBubbleUIController* bubble_controller, DownloadBubbleNavigationHandler* navigation_handler, - Browser* browser); + Browser* browser, + int fixed_width); DownloadBubbleRowView(const DownloadBubbleRowView&) = delete; DownloadBubbleRowView& operator=(const DownloadBubbleRowView&) = delete; ~DownloadBubbleRowView() override; @@ -253,6 +254,12 @@ // Tracks tasks requesting file icons. base::CancelableTaskTracker cancelable_task_tracker_; + // TODO(crbug.com/1349528): The size constraint is not passed down from the + // views tree in the first round of layout, so setting a fixed width to bound + // the view. This is assuming that the row view is loaded inside a bubble. It + // will break if the row view is loaded inside a different parent view. + const int fixed_width_; + base::WeakPtrFactory<DownloadBubbleRowView> weak_factory_{this}; };
diff --git a/chrome/browser/ui/views/download/bubble/download_bubble_row_view_unittest.cc b/chrome/browser/ui/views/download/bubble/download_bubble_row_view_unittest.cc index 24e5b1f..6c744605 100644 --- a/chrome/browser/ui/views/download/bubble/download_bubble_row_view_unittest.cc +++ b/chrome/browser/ui/views/download/bubble/download_bubble_row_view_unittest.cc
@@ -6,6 +6,7 @@ #include "chrome/app/chrome_command_ids.h" #include "chrome/browser/download/download_item_model.h" +#include "chrome/browser/ui/views/chrome_layout_provider.h" #include "chrome/browser/ui/views/frame/browser_view.h" #include "chrome/browser/ui/views/frame/test_with_browser_view.h" #include "chrome/browser/ui/views/toolbar/toolbar_view.h" @@ -46,11 +47,14 @@ browser_view()->toolbar()->download_button(); row_list_view_ = std::make_unique<DownloadBubbleRowListView>( /*is_partial_view=*/true, browser()); + const int bubble_width = ChromeLayoutProvider::Get()->GetDistanceMetric( + views::DISTANCE_BUBBLE_PREFERRED_WIDTH); row_view_ = std::make_unique<DownloadBubbleRowView>( DownloadItemModel::Wrap( &download_item_, std::make_unique<DownloadUIModel::BubbleStatusTextBuilder>()), - row_list_view_.get(), button->bubble_controller(), button, browser()); + row_list_view_.get(), button->bubble_controller(), button, browser(), + bubble_width); } void FastForward(base::TimeDelta time) {
diff --git a/chrome/browser/ui/views/download/bubble/download_bubble_security_view_unittest.cc b/chrome/browser/ui/views/download/bubble/download_bubble_security_view_unittest.cc index 3ab25041..c527b23 100644 --- a/chrome/browser/ui/views/download/bubble/download_bubble_security_view_unittest.cc +++ b/chrome/browser/ui/views/download/bubble/download_bubble_security_view_unittest.cc
@@ -9,6 +9,7 @@ #include "chrome/browser/download/download_item_warning_data.h" #include "chrome/browser/download/download_ui_model.h" #include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/views/chrome_layout_provider.h" #include "chrome/browser/ui/views/download/bubble/download_bubble_row_view.h" #include "chrome/browser/ui/views/download/bubble/download_toolbar_button_view.h" #include "chrome/common/chrome_switches.h" @@ -86,9 +87,12 @@ row_list_view_ = std::make_unique<DownloadBubbleRowListView>( /*is_partial_view=*/true, browser_.get()); + const int bubble_width = ChromeLayoutProvider::Get()->GetDistanceMetric( + views::DISTANCE_BUBBLE_PREFERRED_WIDTH); row_view_ = std::make_unique<DownloadBubbleRowView>( DownloadItemModel::Wrap(&download_item_), row_list_view_.get(), - bubble_controller_.get(), bubble_navigator_.get(), browser_.get()); + bubble_controller_.get(), bubble_navigator_.get(), browser_.get(), + bubble_width); } void TearDown() override {
diff --git a/chrome/browser/ui/views/download/bubble/download_toolbar_button_view.cc b/chrome/browser/ui/views/download/bubble/download_toolbar_button_view.cc index 6d64f01..32c67c1 100644 --- a/chrome/browser/ui/views/download/bubble/download_toolbar_button_view.cc +++ b/chrome/browser/ui/views/download/bubble/download_toolbar_button_view.cc
@@ -532,12 +532,14 @@ is_primary_partial_view_, browser_, base::BindOnce(&DownloadToolbarButtonView::DeactivateAutoClose, base::Unretained(this))); + const int bubble_width = ChromeLayoutProvider::Get()->GetDistanceMetric( + views::DISTANCE_BUBBLE_PREFERRED_WIDTH); for (DownloadUIModel::DownloadUIModelPtr& model : model_list) { // raw pointer is safe as the toolbar owns the bubble, which owns an // individual row view. row_list_view->AddChildView(std::make_unique<DownloadBubbleRowView>( std::move(model), row_list_view.get(), bubble_controller_.get(), this, - browser_)); + browser_, bubble_width)); } auto scroll_view = std::make_unique<views::ScrollView>();
diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.cc b/chrome/browser/ui/views/location_bar/location_bar_view.cc index 4ba290c9..774e59c 100644 --- a/chrome/browser/ui/views/location_bar/location_bar_view.cc +++ b/chrome/browser/ui/views/location_bar/location_bar_view.cc
@@ -589,12 +589,20 @@ // Additionally, the text should be indented further if a chip is visible // and the lock icon is hidden. This is treated separately, because the // indentation constant has a distinct value. - if (chip_controller_ && chip_controller_->chip()->GetVisible() && - ShouldChipOverrideLocationIcon()) { + if (ShouldChipOverrideLocationIcon()) { constexpr int kTextIndentLocationBarIconOverriddenDp = 8; leading_edit_item_padding += kTextIndentLocationBarIconOverriddenDp; } + // CR23 location bar icons have solid borders. Add padding between their + // borders and the omnibox so that they don't touch/overlap. Pre-CR23 icons & + // the keyword text (both before and after CR23) don't have solid borders; + // they instead have invisible borders that provide sufficient padding. Don't + // add any more padding in those cases, as then the whitespace would be too + // large. + if (features::IsChromeRefresh2023() && !ShouldShowKeywordBubble()) + leading_edit_item_padding += 5; + // We always subtract the left padding of the OmniboxView itself to allow for // an extended I-beam click target without affecting actual layout. leading_edit_item_padding -= omnibox_view_->GetInsets().left();
diff --git a/chrome/browser/ui/views/location_bar/location_icon_view.cc b/chrome/browser/ui/views/location_bar/location_icon_view.cc index b63902e..20515ec 100644 --- a/chrome/browser/ui/views/location_bar/location_icon_view.cc +++ b/chrome/browser/ui/views/location_bar/location_icon_view.cc
@@ -373,17 +373,13 @@ // the bubble should be smaller, so use an empty border to shrink down the // content bounds so the background gets painted correctly. if (features::IsChromeRefresh2023()) { - if (ShouldShowLabel() && !ShouldShowSeparator()) { + gfx::Insets insets = GetLayoutInsets(LOCATION_BAR_PAGE_INFO_ICON_PADDING); + if (ShouldShowLabel()) { // An extra space between chip's label and right edge. const int kExtraRightPadding = 4; - gfx::Insets insets = GetLayoutInsets(LOCATION_BAR_PAGE_INFO_ICON_PADDING); insets.set_right(insets.right() + kExtraRightPadding); - SetBorder(views::CreateEmptyBorder(insets)); - } else { - SetBorder(views::CreateEmptyBorder(gfx::Insets::VH( - GetLayoutInsets(LOCATION_BAR_PAGE_INFO_ICON_PADDING).top(), - GetLayoutInsets(LOCATION_BAR_PAGE_INFO_ICON_PADDING).left()))); } + SetBorder(views::CreateEmptyBorder(insets)); } else { IconLabelBubbleView::UpdateBorder(); }
diff --git a/chrome/browser/ui/views/media_router/cast_dialog_metrics.cc b/chrome/browser/ui/views/media_router/cast_dialog_metrics.cc index 2fe2c260..8fafc40 100644 --- a/chrome/browser/ui/views/media_router/cast_dialog_metrics.cc +++ b/chrome/browser/ui/views/media_router/cast_dialog_metrics.cc
@@ -190,6 +190,11 @@ media_router::MediaRouterMetrics::RecordDeviceCount(sink_buttons.size()); } +void CastDialogMetrics::OnRecordSinkCount( + const std::vector<raw_ptr<CastDialogSinkView>>& sink_views) { + media_router::MediaRouterMetrics::RecordDeviceCount(sink_views.size()); +} + void CastDialogMetrics::MaybeRecordFirstAction(MediaRouterUserAction action) { if (first_action_recorded_) return;
diff --git a/chrome/browser/ui/views/media_router/cast_dialog_metrics.h b/chrome/browser/ui/views/media_router/cast_dialog_metrics.h index 299253b1..ff701d7 100644 --- a/chrome/browser/ui/views/media_router/cast_dialog_metrics.h +++ b/chrome/browser/ui/views/media_router/cast_dialog_metrics.h
@@ -9,6 +9,7 @@ #include "chrome/browser/ui/media_router/media_cast_mode.h" #include "chrome/browser/ui/media_router/ui_media_sink.h" #include "chrome/browser/ui/views/media_router/cast_dialog_sink_button.h" +#include "chrome/browser/ui/views/media_router/cast_dialog_sink_view.h" #include "components/media_router/browser/media_router_metrics.h" #include "components/media_router/common/media_sink.h" @@ -61,6 +62,8 @@ // Records the number of sinks, which may be 0. void OnRecordSinkCount( const std::vector<CastDialogSinkButton*>& sink_buttons); + void OnRecordSinkCount( + const std::vector<raw_ptr<CastDialogSinkView>>& sink_views); private: // Records the first user action if it hasn't already been recorded.
diff --git a/chrome/browser/ui/views/media_router/cast_dialog_metrics_unittest.cc b/chrome/browser/ui/views/media_router/cast_dialog_metrics_unittest.cc index 4acecb7..ae2a80a 100644 --- a/chrome/browser/ui/views/media_router/cast_dialog_metrics_unittest.cc +++ b/chrome/browser/ui/views/media_router/cast_dialog_metrics_unittest.cc
@@ -97,6 +97,26 @@ buttons.size(), 1); } +TEST_F(CastDialogMetricsTest, OnRecordSinkCountSinkView) { + UIMediaSink sink1{mojom::MediaRouteProviderId::CAST}; + UIMediaSink sink2{mojom::MediaRouteProviderId::CAST}; + UIMediaSink sink3{mojom::MediaRouteProviderId::DIAL}; + CastDialogSinkView sink_view1{ + &profile_, sink1, views::Button::PressedCallback(), + views::Button::PressedCallback(), views::Button::PressedCallback()}; + CastDialogSinkView sink_view2{ + &profile_, sink2, views::Button::PressedCallback(), + views::Button::PressedCallback(), views::Button::PressedCallback()}; + CastDialogSinkView sink_view3{ + &profile_, sink3, views::Button::PressedCallback(), + views::Button::PressedCallback(), views::Button::PressedCallback()}; + std::vector<raw_ptr<CastDialogSinkView>> sink_views{&sink_view1, &sink_view2, + &sink_view3}; + metrics_.OnRecordSinkCount(sink_views); + tester_.ExpectUniqueSample(MediaRouterMetrics::kHistogramUiDeviceCount, + sink_views.size(), 1); +} + TEST_F(CastDialogMetricsTest, RecordFirstAction) { metrics_.OnStopCasting(true); metrics_.OnCastModeSelected();
diff --git a/chrome/browser/ui/views/media_router/cast_dialog_sink_view.cc b/chrome/browser/ui/views/media_router/cast_dialog_sink_view.cc new file mode 100644 index 0000000..b22a5846 --- /dev/null +++ b/chrome/browser/ui/views/media_router/cast_dialog_sink_view.cc
@@ -0,0 +1,214 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/views/media_router/cast_dialog_sink_view.h" + +#include "chrome/app/vector_icons/vector_icons.h" +#include "chrome/browser/media/router/discovery/access_code/access_code_cast_feature.h" +#include "chrome/browser/media/router/media_router_feature.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/views/chrome_layout_provider.h" +#include "chrome/browser/ui/views/media_router/cast_dialog_helper.h" +#include "chrome/browser/ui/views/media_router/cast_dialog_sink_button.h" +#include "chrome/grit/generated_resources.h" +#include "components/vector_icons/vector_icons.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/metadata/metadata_impl_macros.h" +#include "ui/gfx/paint_vector_icon.h" +#include "ui/views/background.h" +#include "ui/views/border.h" +#include "ui/views/layout/box_layout.h" +#include "ui/views/layout/flex_layout.h" +#include "ui/views/style/typography.h" +#include "ui/views/vector_icons.h" +#include "ui/views/view_class_properties.h" + +namespace { + +std::unique_ptr<views::ImageView> CreateConnectedIconView( + media_router::UIMediaSink sink) { + auto icon_view = std::make_unique<views::ImageView>(); + icon_view->SetImage(ui::ImageModel::FromVectorIcon( + *media_router::CastDialogSinkButton::GetVectorIcon(sink), + ui::kColorAccent, media_router::kPrimaryIconSize)); + icon_view->SetBorder( + views::CreateEmptyBorder(media_router::kPrimaryIconBorder)); + return icon_view; +} + +std::unique_ptr<views::StyledLabel> CreateTitle( + const media_router::UIMediaSink& sink) { + auto title = std::make_unique<views::StyledLabel>(); + title->SetText(sink.friendly_name); + title->SizeToFit(0); + return title; +} + +std::unique_ptr<views::Label> CreateSubtitle( + const media_router::UIMediaSink& sink) { + auto subtitle = std::make_unique<views::Label>(sink.GetStatusTextForDisplay(), + views::style::CONTEXT_BUTTON, + views::style::STYLE_SECONDARY); + subtitle->SetHorizontalAlignment(gfx::ALIGN_LEFT); + subtitle->SetAutoColorReadabilityEnabled(false); + return subtitle; +} + +} // namespace + +namespace media_router { + +CastDialogSinkView::CastDialogSinkView( + Profile* profile, + const UIMediaSink& sink, + views::Button::PressedCallback sink_pressed_callback, + views::Button::PressedCallback stop_pressed_callback, + views::Button::PressedCallback freeze_pressed_callback) + : profile_(profile), sink_(sink) { + SetLayoutManager(std::make_unique<views::BoxLayout>( + views::BoxLayout::Orientation::kVertical)); + + // If the sink is connected, and one of the features that allow new UI is + // enabled, then add labels and buttons. Else, default to a + // CastDialogSinkButton. + if (sink.state == UIMediaSinkState::CONNECTED && + (IsAccessCodeCastFreezeUiEnabled(profile_) || + base::FeatureList::IsEnabled(kCastDialogStopButton))) { + // When sink is connected, the sink view looks like this: + // + // *----------------------------------* + // | | Title | + // | Icon |---------------------------| Label View + // | | Subtitle | + // |----------------------------------| + // | | Button 1 | Button 2 | Buttons View + // *----------------------------------* + AddChildView(CreateLabelView(sink)); + AddChildView( + CreateButtonsView(stop_pressed_callback, freeze_pressed_callback)); + } else { + cast_sink_button_ = AddChildView( + std::make_unique<CastDialogSinkButton>(sink_pressed_callback, sink)); + } +} + +std::unique_ptr<views::View> CastDialogSinkView::CreateLabelView( + const UIMediaSink& sink) { + // The spacing and padding needed to mimic the layout of the icon and labels + // from the CastDialogSinkButton, which is implemented as a HoverButton. + const int horizontal_padding = ChromeLayoutProvider::Get()->GetDistanceMetric( + views::DISTANCE_BUTTON_HORIZONTAL_PADDING); + const int icon_label_spacing = ChromeLayoutProvider::Get()->GetDistanceMetric( + views::DISTANCE_RELATED_LABEL_HORIZONTAL); + const int vertical_spacing = ChromeLayoutProvider::Get()->GetDistanceMetric( + DISTANCE_CONTROL_LIST_VERTICAL) / + 2; + + auto label_container = std::make_unique<views::View>(); + auto* manager = + label_container->SetLayoutManager(std::make_unique<views::BoxLayout>( + views::BoxLayout::Orientation::kHorizontal, + gfx::Insets::VH(0, horizontal_padding), icon_label_spacing)); + manager->set_cross_axis_alignment( + views::BoxLayout::CrossAxisAlignment::kCenter); + + // Add icon. + label_container->AddChildView(CreateConnectedIconView(sink)); + + // Create the wrapper so labels can stack. + auto label_wrapper = std::make_unique<views::View>(); + title_ = label_wrapper->AddChildView(CreateTitle(sink)); + subtitle_ = label_wrapper->AddChildView(CreateSubtitle(sink)); + + // Set wrapper properties. + label_wrapper->SetLayoutManager(std::make_unique<views::FlexLayout>()) + ->SetOrientation(views::LayoutOrientation::kVertical) + .SetMainAxisAlignment(views::LayoutAlignment::kCenter); + label_wrapper->SetProperty( + views::kFlexBehaviorKey, + views::FlexSpecification(views::MinimumFlexSizeRule::kScaleToZero, + views::MaximumFlexSizeRule::kUnbounded)); + label_wrapper->SetProperty(views::kMarginsKey, + gfx::Insets::VH(vertical_spacing, 0)); + label_wrapper->SetCanProcessEventsWithinSubtree(false); + label_container->AddChildView(std::move(label_wrapper)); + + return label_container; +} + +std::unique_ptr<views::View> CastDialogSinkView::CreateButtonsView( + views::Button::PressedCallback stop_pressed_callback, + views::Button::PressedCallback freeze_pressed_callback) { + const int button_spacing = ChromeLayoutProvider::Get()->GetDistanceMetric( + views::DISTANCE_RELATED_BUTTON_HORIZONTAL); + + // Ensure the buttons stack next to each other and are aligned properly. + auto button_container = std::make_unique<views::View>(); + auto* manager = + button_container->SetLayoutManager(std::make_unique<views::BoxLayout>( + views::BoxLayout::Orientation::kHorizontal)); + manager->set_main_axis_alignment(views::BoxLayout::MainAxisAlignment::kEnd); + // Set spacing between the buttons, if there is more than one. + manager->set_between_child_spacing(button_spacing); + + // Set the top margin to be a negative value that matches the vertical spacing + // at the bottom of the label view. The vertical spacing is important in the + // label view so the icon view is properly centered. However, we also want no + // spacing between the label subtitle and the buttons. + button_container->SetProperty( + views::kMarginsKey, + gfx::Insets::TLBR(-ChromeLayoutProvider::Get()->GetDistanceMetric( + DISTANCE_CONTROL_LIST_VERTICAL) / + 2, + 0, 0, button_spacing)); + + // `can_freeze` should only ever be set to true if freeze ui is enabled, but + // sanity check here anyways. Freeze button will also not show if the route is + // not freezable. + if (IsAccessCodeCastFreezeUiEnabled(profile_) && + sink_.freeze_info.can_freeze) { + auto freeze_button = std::make_unique<views::MdTextButton>( + freeze_pressed_callback, + l10n_util::GetStringUTF16(sink_.freeze_info.is_frozen + ? IDS_MEDIA_ROUTER_SINK_VIEW_RESUME + : IDS_MEDIA_ROUTER_SINK_VIEW_PAUSE)); + freeze_button->SetStyle(views::MdTextButton::Style::kText); + freeze_button_ = button_container->AddChildView(std::move(freeze_button)); + } + + // Always create the stop button, since at this point we know the sink is + // connected. + auto stop_button = std::make_unique<views::MdTextButton>( + stop_pressed_callback, + l10n_util::GetStringUTF16(IDS_MEDIA_ROUTER_SINK_VIEW_STOP)); + stop_button->SetStyle(views::MdTextButton::Style::kText); + stop_button_ = button_container->AddChildView(std::move(stop_button)); + + return button_container; +} + +void CastDialogSinkView::RequestFocus() { + if (cast_sink_button_) { + cast_sink_button_->RequestFocus(); + } +} + +void CastDialogSinkView::SetEnabledState(bool enabled) { + if (cast_sink_button_) { + cast_sink_button_->SetEnabled(enabled); + } + if (stop_button_) { + stop_button_->SetEnabled(enabled); + } + if (freeze_button_) { + freeze_button_->SetEnabled(enabled); + } +} + +CastDialogSinkView::~CastDialogSinkView() = default; + +BEGIN_METADATA(CastDialogSinkView, views::View) +END_METADATA + +} // namespace media_router
diff --git a/chrome/browser/ui/views/media_router/cast_dialog_sink_view.h b/chrome/browser/ui/views/media_router/cast_dialog_sink_view.h new file mode 100644 index 0000000..33dea566 --- /dev/null +++ b/chrome/browser/ui/views/media_router/cast_dialog_sink_view.h
@@ -0,0 +1,84 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_VIEWS_MEDIA_ROUTER_CAST_DIALOG_SINK_VIEW_H_ +#define CHROME_BROWSER_UI_VIEWS_MEDIA_ROUTER_CAST_DIALOG_SINK_VIEW_H_ + +#include "base/memory/raw_ptr.h" +#include "chrome/browser/ui/media_router/ui_media_sink.h" +#include "chrome/browser/ui/views/media_router/cast_dialog_sink_button.h" +#include "ui/base/metadata/metadata_header_macros.h" +#include "ui/views/controls/button/button.h" +#include "ui/views/controls/button/md_text_button.h" +#include "ui/views/controls/image_view.h" +#include "ui/views/controls/label.h" +#include "ui/views/controls/styled_label.h" +#include "ui/views/view.h" + +class Profile; + +namespace media_router { + +// CastDialogSinkView is a view for the cast dialog that contains buttons for +// interacting with a cast sink. +// +// If the sink is not connected, the view contains CastDialogSinkButton, which +// calls `sink_pressed_callback` when pressed. +// +// If the sink is connected (actively casting), then the view contains a label +// which consists of an icon, device friendly name, and status text that mimics +// the look of the label in a CastDialogSinkButton. Additionally, the view +// contains buttons which trigger actions on the sink. The stop_button_ triggers +// `stop_pressed_callback` when pressed, and the freeze_button_ triggers +// `freeze_pressed_callback` when pressed. +class CastDialogSinkView : public views::View { + public: + METADATA_HEADER(CastDialogSinkView); + CastDialogSinkView(Profile* profile, + const UIMediaSink& sink, + views::Button::PressedCallback sink_pressed_callback, + views::Button::PressedCallback stop_pressed_callback, + views::Button::PressedCallback freeze_pressed_callback); + CastDialogSinkView(const CastDialogSinkView&) = delete; + CastDialogSinkView& operator=(const CastDialogSinkView) = delete; + ~CastDialogSinkView() override; + + // views::View SetEnabled(bool enabled) cannot be overridden. + void SetEnabledState(bool enabled); + + // views::View: + void RequestFocus() override; + + const UIMediaSink& sink() const { return sink_; } + + // Used only for testing: + CastDialogSinkButton* cast_sink_button_for_test() { + return cast_sink_button_; + } + views::MdTextButton* freeze_button_for_test() { return freeze_button_; } + views::MdTextButton* stop_button_for_test() { return stop_button_; } + views::StyledLabel* title_for_test() { return title_; } + views::Label* subtitle_for_test() { return subtitle_; } + void set_sink_for_test(const UIMediaSink& sink) { sink_ = sink; } + + private: + std::unique_ptr<views::View> CreateButtonsView( + views::Button::PressedCallback stop_pressed_callback, + views::Button::PressedCallback freeze_pressed_callback); + std::unique_ptr<views::View> CreateLabelView(const UIMediaSink& sink); + + const raw_ptr<Profile> profile_; + UIMediaSink sink_; + + raw_ptr<CastDialogSinkButton> cast_sink_button_ = nullptr; + raw_ptr<views::MdTextButton> freeze_button_ = nullptr; + raw_ptr<views::MdTextButton> stop_button_ = nullptr; + + raw_ptr<views::StyledLabel> title_ = nullptr; + raw_ptr<views::Label> subtitle_ = nullptr; +}; + +} // namespace media_router + +#endif // CHROME_BROWSER_UI_VIEWS_MEDIA_ROUTER_CAST_DIALOG_SINK_VIEW_H_
diff --git a/chrome/browser/ui/views/media_router/cast_dialog_sink_view_unittest.cc b/chrome/browser/ui/views/media_router/cast_dialog_sink_view_unittest.cc new file mode 100644 index 0000000..552db2f --- /dev/null +++ b/chrome/browser/ui/views/media_router/cast_dialog_sink_view_unittest.cc
@@ -0,0 +1,224 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/views/media_router/cast_dialog_sink_view.h" + +#include "base/test/scoped_feature_list.h" +#include "chrome/browser/media/router/discovery/access_code/access_code_cast_feature.h" +#include "chrome/browser/media/router/media_router_feature.h" +#include "chrome/grit/generated_resources.h" +#include "chrome/test/base/testing_profile.h" +#include "chrome/test/views/chrome_views_test_base.h" +#include "components/prefs/pref_service.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/base/l10n/l10n_util.h" + +namespace media_router { +namespace { + +UIMediaSink CreateAvailableSink() { + UIMediaSink sink{mojom::MediaRouteProviderId::CAST}; + sink.id = "sink_available"; + sink.state = UIMediaSinkState::AVAILABLE; + sink.cast_modes = {TAB_MIRROR}; + sink.friendly_name = u"Example tv"; + return sink; +} + +UIMediaSink CreateNonfreezableSink() { + UIMediaSink sink{mojom::MediaRouteProviderId::CAST}; + sink.id = "sink_connected"; + sink.state = UIMediaSinkState::CONNECTED; + sink.status_text = u"status text 1"; + sink.cast_modes = {TAB_MIRROR}; + sink.route = MediaRoute("route_id", MediaSource("https://example.com"), + sink.id, "", true); + return sink; +} + +UIMediaSink CreateFreezableSink() { + UIMediaSink sink{mojom::MediaRouteProviderId::CAST}; + sink.id = "sink_connected"; + sink.state = UIMediaSinkState::CONNECTED; + sink.status_text = u"status text 2"; + sink.cast_modes = {TAB_MIRROR}; + sink.route = MediaRoute("route_id", MediaSource("https://example.com"), + sink.id, "", true); + sink.freeze_info.can_freeze = true; + return sink; +} + +UIMediaSink CreateFreezableFrozenSink() { + UIMediaSink sink{mojom::MediaRouteProviderId::CAST}; + sink.id = "sink_connected"; + sink.state = UIMediaSinkState::CONNECTED; + sink.cast_modes = {TAB_MIRROR}; + sink.route = MediaRoute("route_id", MediaSource("https://example.com"), + sink.id, "", true); + sink.freeze_info.can_freeze = true; + sink.freeze_info.is_frozen = true; + return sink; +} + +} // namespace + +class CastDialogSinkViewTest : public ChromeViewsTestBase { + public: + CastDialogSinkViewTest() = default; + + CastDialogSinkViewTest(const CastDialogSinkViewTest&) = delete; + CastDialogSinkViewTest& operator=(const CastDialogSinkViewTest&) = delete; + + ~CastDialogSinkViewTest() override = default; + + protected: + TestingProfile profile_; +}; + +// If the correct policies are not set, then CastDialogSinkView should only +// contain a CastSinkButton. +TEST_F(CastDialogSinkViewTest, CastSinkButton) { + UIMediaSink sink_1 = CreateAvailableSink(); + CastDialogSinkView sink_view_1( + &profile_, sink_1, views::Button::PressedCallback(), + views::Button::PressedCallback(), views::Button::PressedCallback()); + EXPECT_NE(nullptr, sink_view_1.cast_sink_button_for_test()); + EXPECT_EQ(nullptr, sink_view_1.freeze_button_for_test()); + EXPECT_EQ(nullptr, sink_view_1.stop_button_for_test()); + EXPECT_EQ(nullptr, sink_view_1.title_for_test()); + EXPECT_EQ(nullptr, sink_view_1.subtitle_for_test()); + + UIMediaSink sink_2 = CreateNonfreezableSink(); + CastDialogSinkView sink_view_2( + &profile_, sink_2, views::Button::PressedCallback(), + views::Button::PressedCallback(), views::Button::PressedCallback()); + EXPECT_NE(nullptr, sink_view_2.cast_sink_button_for_test()); + EXPECT_EQ(nullptr, sink_view_2.freeze_button_for_test()); + EXPECT_EQ(nullptr, sink_view_2.stop_button_for_test()); + EXPECT_EQ(nullptr, sink_view_2.title_for_test()); + EXPECT_EQ(nullptr, sink_view_2.subtitle_for_test()); + + UIMediaSink sink_3 = CreateFreezableSink(); + CastDialogSinkView sink_view_3( + &profile_, sink_3, views::Button::PressedCallback(), + views::Button::PressedCallback(), views::Button::PressedCallback()); + EXPECT_NE(nullptr, sink_view_3.cast_sink_button_for_test()); + EXPECT_EQ(nullptr, sink_view_3.freeze_button_for_test()); + EXPECT_EQ(nullptr, sink_view_3.stop_button_for_test()); + EXPECT_EQ(nullptr, sink_view_3.title_for_test()); + EXPECT_EQ(nullptr, sink_view_3.subtitle_for_test()); +} + +TEST_F(CastDialogSinkViewTest, FreezableSink) { + // Enable the proper features / prefs. + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndEnableFeature(features::kAccessCodeCastFreezeUI); + profile_.GetPrefs()->SetBoolean(prefs::kAccessCodeCastEnabled, true); + + UIMediaSink sink_1 = CreateFreezableSink(); + CastDialogSinkView sink_view_1( + &profile_, sink_1, views::Button::PressedCallback(), + views::Button::PressedCallback(), views::Button::PressedCallback()); + EXPECT_EQ(nullptr, sink_view_1.cast_sink_button_for_test()); + EXPECT_NE(nullptr, sink_view_1.freeze_button_for_test()); + EXPECT_NE(nullptr, sink_view_1.stop_button_for_test()); + EXPECT_NE(nullptr, sink_view_1.title_for_test()); + EXPECT_NE(nullptr, sink_view_1.subtitle_for_test()); + EXPECT_EQ(sink_1.friendly_name, sink_view_1.title_for_test()->GetText()); + EXPECT_EQ(sink_1.status_text, sink_view_1.subtitle_for_test()->GetText()); + EXPECT_EQ(l10n_util::GetStringUTF16(IDS_MEDIA_ROUTER_SINK_VIEW_STOP), + sink_view_1.stop_button_for_test()->GetText()); + EXPECT_EQ(l10n_util::GetStringUTF16(IDS_MEDIA_ROUTER_SINK_VIEW_PAUSE), + sink_view_1.freeze_button_for_test()->GetText()); + + UIMediaSink sink_2 = CreateFreezableFrozenSink(); + CastDialogSinkView sink_view_2( + &profile_, sink_2, views::Button::PressedCallback(), + views::Button::PressedCallback(), views::Button::PressedCallback()); + EXPECT_EQ(nullptr, sink_view_2.cast_sink_button_for_test()); + EXPECT_NE(nullptr, sink_view_2.freeze_button_for_test()); + EXPECT_NE(nullptr, sink_view_2.stop_button_for_test()); + EXPECT_NE(nullptr, sink_view_2.title_for_test()); + EXPECT_NE(nullptr, sink_view_2.subtitle_for_test()); + EXPECT_EQ(l10n_util::GetStringUTF16(IDS_MEDIA_ROUTER_SINK_VIEW_RESUME), + sink_view_2.freeze_button_for_test()->GetText()); +} + +TEST_F(CastDialogSinkViewTest, NonfreezableSink) { + // Enable the proper features / prefs. + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndEnableFeature(features::kAccessCodeCastFreezeUI); + profile_.GetPrefs()->SetBoolean(prefs::kAccessCodeCastEnabled, true); + + UIMediaSink sink = CreateNonfreezableSink(); + CastDialogSinkView sink_view( + &profile_, sink, views::Button::PressedCallback(), + views::Button::PressedCallback(), views::Button::PressedCallback()); + EXPECT_EQ(nullptr, sink_view.cast_sink_button_for_test()); + EXPECT_EQ(nullptr, sink_view.freeze_button_for_test()); + EXPECT_NE(nullptr, sink_view.stop_button_for_test()); + EXPECT_NE(nullptr, sink_view.title_for_test()); + EXPECT_NE(nullptr, sink_view.subtitle_for_test()); +} + +TEST_F(CastDialogSinkViewTest, SetEnabledState) { + // Enable the proper features / prefs. + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndEnableFeature(features::kAccessCodeCastFreezeUI); + profile_.GetPrefs()->SetBoolean(prefs::kAccessCodeCastEnabled, true); + + UIMediaSink sink_1 = CreateAvailableSink(); + CastDialogSinkView sink_view_1( + &profile_, sink_1, views::Button::PressedCallback(), + views::Button::PressedCallback(), views::Button::PressedCallback()); + + EXPECT_TRUE(sink_view_1.cast_sink_button_for_test()->GetEnabled()); + sink_view_1.SetEnabledState(false); + EXPECT_FALSE(sink_view_1.cast_sink_button_for_test()->GetEnabled()); + sink_view_1.SetEnabledState(true); + EXPECT_TRUE(sink_view_1.cast_sink_button_for_test()->GetEnabled()); + + UIMediaSink sink_2 = CreateFreezableSink(); + CastDialogSinkView sink_view_2( + &profile_, sink_2, views::Button::PressedCallback(), + views::Button::PressedCallback(), views::Button::PressedCallback()); + + EXPECT_TRUE(sink_view_2.stop_button_for_test()->GetEnabled()); + sink_view_2.SetEnabledState(false); + EXPECT_FALSE(sink_view_2.stop_button_for_test()->GetEnabled()); + sink_view_2.SetEnabledState(true); + EXPECT_TRUE(sink_view_2.stop_button_for_test()->GetEnabled()); +} + +// If only the StopButton feature is enabled, then CastDialogSinkView will show +// the stop button, but not a freeze button. +TEST_F(CastDialogSinkViewTest, StopButton) { + // Enable the proper features / prefs. + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndEnableFeature(kCastDialogStopButton); + + UIMediaSink sink_1 = CreateNonfreezableSink(); + CastDialogSinkView sink_view_1( + &profile_, sink_1, views::Button::PressedCallback(), + views::Button::PressedCallback(), views::Button::PressedCallback()); + EXPECT_EQ(nullptr, sink_view_1.cast_sink_button_for_test()); + EXPECT_EQ(nullptr, sink_view_1.freeze_button_for_test()); + EXPECT_NE(nullptr, sink_view_1.stop_button_for_test()); + EXPECT_NE(nullptr, sink_view_1.title_for_test()); + EXPECT_NE(nullptr, sink_view_1.subtitle_for_test()); + + // Even though the sink is freezable, kAccessCodeCastFreezeUI is not enabled + // so the freeze button should be a nullptr. + UIMediaSink sink_2 = CreateFreezableSink(); + CastDialogSinkView sink_view_2( + &profile_, sink_2, views::Button::PressedCallback(), + views::Button::PressedCallback(), views::Button::PressedCallback()); + EXPECT_EQ(nullptr, sink_view_2.cast_sink_button_for_test()); + EXPECT_EQ(nullptr, sink_view_2.freeze_button_for_test()); + EXPECT_NE(nullptr, sink_view_2.stop_button_for_test()); + EXPECT_NE(nullptr, sink_view_2.title_for_test()); + EXPECT_NE(nullptr, sink_view_2.subtitle_for_test()); +} + +} // namespace media_router
diff --git a/chrome/browser/ui/views/media_router/cast_dialog_view.cc b/chrome/browser/ui/views/media_router/cast_dialog_view.cc index d837dfa3..37938d8a 100644 --- a/chrome/browser/ui/views/media_router/cast_dialog_view.cc +++ b/chrome/browser/ui/views/media_router/cast_dialog_view.cc
@@ -26,7 +26,7 @@ #include "chrome/browser/ui/views/frame/top_container_view.h" #include "chrome/browser/ui/views/media_router/cast_dialog_access_code_cast_button.h" #include "chrome/browser/ui/views/media_router/cast_dialog_no_sinks_view.h" -#include "chrome/browser/ui/views/media_router/cast_dialog_sink_button.h" +#include "chrome/browser/ui/views/media_router/cast_dialog_sink_view.h" #include "chrome/browser/ui/webui/access_code_cast/access_code_cast_dialog.h" #include "chrome/grit/generated_resources.h" #include "components/access_code_cast/common/access_code_cast_metrics.h" @@ -221,7 +221,7 @@ // The dtor of |scroll_view_| removes it from the dialog. delete scroll_view_; scroll_view_ = nullptr; - sink_buttons_.clear(); + sink_views_.clear(); } no_sinks_view_ = new CastDialogNoSinksView(profile_); AddChildView(no_sinks_view_.get()); @@ -243,16 +243,17 @@ void CastDialogView::RestoreSinkListState() { if (selected_sink_index_ && - selected_sink_index_.value() < sink_buttons_.size()) { - CastDialogSinkButton* sink_button = - sink_buttons_.at(selected_sink_index_.value()); + selected_sink_index_.value() < sink_views_.size()) { + CastDialogSinkView* sink_view = + sink_views_.at(selected_sink_index_.value()); // Focus on the sink so that the screen reader reads its label, which has // likely been updated. - sink_button->RequestFocus(); + sink_view->RequestFocus(); // If the state became AVAILABLE, the screen reader no longer needs to read // the label until the user selects a sink again. - if (sink_button->sink().state == UIMediaSinkState::AVAILABLE) + if (sink_view->sink().state == UIMediaSinkState::AVAILABLE) { selected_sink_index_.reset(); + } } views::ScrollBar* scroll_bar = @@ -264,17 +265,21 @@ } void CastDialogView::PopulateScrollView(const std::vector<UIMediaSink>& sinks) { - sink_buttons_.clear(); + sink_views_.clear(); auto sink_list_view = std::make_unique<views::View>(); sink_list_view->SetLayoutManager(std::make_unique<views::BoxLayout>( views::BoxLayout::Orientation::kVertical)); for (size_t i = 0; i < sinks.size(); i++) { - auto* sink_button = - sink_list_view->AddChildView(std::make_unique<CastDialogSinkButton>( + auto* sink_view = + sink_list_view->AddChildView(std::make_unique<CastDialogSinkView>( + profile_, sinks.at(i), base::BindRepeating(&CastDialogView::SinkPressed, base::Unretained(this), i), - sinks.at(i))); - sink_buttons_.push_back(sink_button); + base::BindRepeating(&CastDialogView::StopPressed, + base::Unretained(this), i), + base::BindRepeating(&CastDialogView::FreezePressed, + base::Unretained(this), i))); + sink_views_.push_back(sink_view); } scroll_view_->SetContents(std::move(sink_list_view)); @@ -314,7 +319,7 @@ selected_sink_index_ = index; // sink() may get invalidated during CastDialogController::StartCasting() // due to a model update, so make a copy here. - const UIMediaSink sink = sink_buttons_.at(index)->sink(); + const UIMediaSink sink = sink_views_.at(index)->sink(); if (sink.route) { metrics_.OnStopCasting(sink.route->is_local()); // StopCasting() may trigger a model update and invalidate |sink|. @@ -331,6 +336,42 @@ } } +void CastDialogView::StopPressed(size_t index) { + if (!controller_) { + return; + } + selected_sink_index_ = index; + const UIMediaSink sink = sink_views_.at(index)->sink(); + if (!sink.route) { + return; + } + metrics_.OnStopCasting(sink.route->is_local()); + // StopCasting() may trigger a model update and invalidate |sink|. + controller_->StopCasting(sink.route->media_route_id()); +} + +void CastDialogView::FreezePressed(size_t index) { + if (!controller_) { + return; + } + selected_sink_index_ = index; + const UIMediaSink sink = sink_views_.at(index)->sink(); + if (!sink.route) { + return; + } + // If the route cannot be frozen / unfrozen, then the freeze button should + // not be shown at all. Even so, return early just in case the callback is + // triggered unexpectedly. + if (!sink.freeze_info.can_freeze) { + return; + } + if (sink.freeze_info.is_frozen) { + controller_->UnfreezeRoute(sink.route->media_route_id()); + } else { /* is_frozen == false */ + controller_->FreezeRoute(sink.route->media_route_id()); + } +} + void CastDialogView::MaybeSizeToContents() { // The widget may be null if this is called while the dialog is opening. if (GetWidget()) @@ -359,11 +400,12 @@ void CastDialogView::DisableUnsupportedSinks() { // Go through the AVAILABLE sinks and enable or disable them depending on // whether they support the selected cast mode. - for (CastDialogSinkButton* sink_button : sink_buttons_) { - if (sink_button->sink().state != UIMediaSinkState::AVAILABLE) + for (CastDialogSinkView* sink_view : sink_views_) { + if (sink_view->sink().state != UIMediaSinkState::AVAILABLE) { continue; - const bool enable = GetCastModeToUse(sink_button->sink()).has_value(); - sink_button->SetEnabled(enable); + } + const bool enable = GetCastModeToUse(sink_view->sink()).has_value(); + sink_view->SetEnabledState(enable); } } @@ -378,7 +420,7 @@ } void CastDialogView::RecordSinkCount() { - metrics_.OnRecordSinkCount(sink_buttons_); + metrics_.OnRecordSinkCount(sink_views_); } bool CastDialogView::IsAccessCodeCastingEnabled() const {
diff --git a/chrome/browser/ui/views/media_router/cast_dialog_view.h b/chrome/browser/ui/views/media_router/cast_dialog_view.h index d44d4e003..bc1adf4 100644 --- a/chrome/browser/ui/views/media_router/cast_dialog_view.h +++ b/chrome/browser/ui/views/media_router/cast_dialog_view.h
@@ -30,7 +30,7 @@ namespace media_router { -class CastDialogSinkButton; +class CastDialogSinkView; enum class MediaRouterDialogActivationLocation; struct UIMediaSink; @@ -85,8 +85,8 @@ void KeepShownForTesting(); // Called by tests. - const std::vector<CastDialogSinkButton*>& sink_buttons_for_test() const { - return sink_buttons_; + const std::vector<raw_ptr<CastDialogSinkView>>& sink_views_for_test() const { + return sink_views_; } views::ScrollView* scroll_view_for_test() { return scroll_view_; } views::View* no_sinks_view_for_test() { return no_sinks_view_; } @@ -133,6 +133,8 @@ void SelectSource(SourceType source); void SinkPressed(size_t index); + void StopPressed(size_t index); + void FreezePressed(size_t index); void MaybeSizeToContents(); @@ -163,8 +165,8 @@ // the sources menu. SourceType selected_source_ = SourceType::kTab; - // Contains references to sink buttons in the order they appear. - std::vector<CastDialogSinkButton*> sink_buttons_; + // Contains references to sink views in the order they appear. + std::vector<raw_ptr<CastDialogSinkView>> sink_views_; raw_ptr<CastDialogController> controller_;
diff --git a/chrome/browser/ui/views/media_router/cast_dialog_view_unittest.cc b/chrome/browser/ui/views/media_router/cast_dialog_view_unittest.cc index 9680519..3bed88d0 100644 --- a/chrome/browser/ui/views/media_router/cast_dialog_view_unittest.cc +++ b/chrome/browser/ui/views/media_router/cast_dialog_view_unittest.cc
@@ -24,7 +24,7 @@ #include "chrome/browser/ui/views/chrome_layout_provider.h" #include "chrome/browser/ui/views/controls/hover_button.h" #include "chrome/browser/ui/views/media_router/cast_dialog_coordinator.h" -#include "chrome/browser/ui/views/media_router/cast_dialog_sink_button.h" +#include "chrome/browser/ui/views/media_router/cast_dialog_sink_view.h" #include "chrome/grit/generated_resources.h" #include "chrome/test/base/testing_profile.h" #include "chrome/test/views/chrome_views_test_base.h" @@ -68,6 +68,31 @@ return sink; } +UIMediaSink CreateFreezableSink() { + UIMediaSink sink{mojom::MediaRouteProviderId::CAST}; + sink.id = "sink_freezable"; + sink.state = UIMediaSinkState::CONNECTED; + sink.cast_modes = {TAB_MIRROR}; + sink.route = + MediaRoute("route_id_freezable", MediaSource("https://example.com"), + sink.id, "", true); + sink.freeze_info.can_freeze = true; + return sink; +} + +UIMediaSink CreateFreezableFrozenSink() { + UIMediaSink sink{mojom::MediaRouteProviderId::CAST}; + sink.id = "sink_freezable_frozen"; + sink.state = UIMediaSinkState::CONNECTED; + sink.cast_modes = {TAB_MIRROR}; + sink.route = + MediaRoute("route_id_freezable_frozen", + MediaSource("https://example.com"), sink.id, "", true); + sink.freeze_info.can_freeze = true; + sink.freeze_info.is_frozen = true; + return sink; +} + CastDialogModel CreateModelWithSinks(std::vector<UIMediaSink> sinks) { CastDialogModel model; model.set_dialog_header(u"Dialog header"); @@ -123,17 +148,28 @@ } void SinkPressedAtIndex(int index) { + NotifyButtonOfClick(sink_views().at(index)->cast_sink_button_for_test()); + } + + void StopPressedAtIndex(int index) { + NotifyButtonOfClick(sink_views().at(index)->stop_button_for_test()); + } + + void FreezePressedAtIndex(int index) { + NotifyButtonOfClick(sink_views().at(index)->freeze_button_for_test()); + } + + void NotifyButtonOfClick(views::Button* button) { ui::MouseEvent mouse_event(ui::ET_MOUSE_PRESSED, gfx::Point(0, 0), gfx::Point(0, 0), ui::EventTimeForNow(), 0, 0); - views::test::ButtonTestApi(sink_buttons().at(index)) - .NotifyClick(mouse_event); + views::test::ButtonTestApi(button).NotifyClick(mouse_event); // The request to cast/stop is sent asynchronously, so we must call // RunUntilIdle(). base::RunLoop().RunUntilIdle(); } - const std::vector<CastDialogSinkButton*>& sink_buttons() { - return dialog_->sink_buttons_for_test(); + const std::vector<raw_ptr<CastDialogSinkView>>& sink_views() { + return dialog_->sink_views_for_test(); } views::ScrollView* scroll_view() { return dialog_->scroll_view_for_test(); } @@ -182,6 +218,23 @@ SinkPressedAtIndex(0); } +TEST_F(CastDialogViewTest, FreezeUiStartCasting) { + // Enable the proper features / prefs. + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndEnableFeature(features::kAccessCodeCastFreezeUI); + profile_.GetPrefs()->SetBoolean(prefs::kAccessCodeCastEnabled, true); + + std::vector<UIMediaSink> media_sinks = {CreateAvailableSink(), + CreateAvailableSink()}; + media_sinks[0].id = "sink0"; + media_sinks[1].id = "sink1"; + CastDialogModel model = CreateModelWithSinks(std::move(media_sinks)); + InitializeDialogWithModel(model); + + EXPECT_CALL(controller_, StartCasting(model.media_sinks()[0].id, TAB_MIRROR)); + SinkPressedAtIndex(0); +} + TEST_F(CastDialogViewTest, StopCasting) { CastDialogModel model = CreateModelWithSinks({CreateAvailableSink(), CreateConnectedSink()}); @@ -191,6 +244,65 @@ SinkPressedAtIndex(1); } +TEST_F(CastDialogViewTest, FreezeUiStopCasting) { + // Enable the proper features / prefs. + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndEnableFeature(features::kAccessCodeCastFreezeUI); + profile_.GetPrefs()->SetBoolean(prefs::kAccessCodeCastEnabled, true); + + CastDialogModel model = CreateModelWithSinks({CreateConnectedSink()}); + InitializeDialogWithModel(model); + + EXPECT_CALL(controller_, + StopCasting(model.media_sinks()[0].route->media_route_id())) + .Times(1); + StopPressedAtIndex(0); +} + +TEST_F(CastDialogViewTest, FreezeRoute) { + // Enable the proper features / prefs. + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndEnableFeature(features::kAccessCodeCastFreezeUI); + profile_.GetPrefs()->SetBoolean(prefs::kAccessCodeCastEnabled, true); + + CastDialogModel model = CreateModelWithSinks( + {CreateFreezableSink(), CreateFreezableFrozenSink()}); + InitializeDialogWithModel(model); + + EXPECT_CALL(controller_, + FreezeRoute(model.media_sinks()[0].route->media_route_id())) + .Times(1); + EXPECT_CALL(controller_, + UnfreezeRoute(model.media_sinks()[1].route->media_route_id())) + .Times(1); + FreezePressedAtIndex(0); + FreezePressedAtIndex(1); +} + +TEST_F(CastDialogViewTest, FreezeNoRoute) { + // Enable the proper features / prefs. + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndEnableFeature(features::kAccessCodeCastFreezeUI); + profile_.GetPrefs()->SetBoolean(prefs::kAccessCodeCastEnabled, true); + + CastDialogModel model = CreateModelWithSinks({CreateFreezableSink()}); + InitializeDialogWithModel(model); + + // Now that the CastDialogSinkView has been created with the proper buttons, + // change the associated sink. This simulates an edge case where a sink may + // change status while the CastDialogSinkView has not been destroyed. + sink_views().at(0)->set_sink_for_test(CreateAvailableSink()); + + // When there is no associated route, FreezePressed should be a no-op. + EXPECT_CALL(controller_, + FreezeRoute(model.media_sinks()[0].route->media_route_id())) + .Times(0); + EXPECT_CALL(controller_, + UnfreezeRoute(model.media_sinks()[0].route->media_route_id())) + .Times(0); + FreezePressedAtIndex(0); +} + TEST_F(CastDialogViewTest, ClearIssue) { std::vector<UIMediaSink> media_sinks = {CreateAvailableSink()}; media_sinks[0].issue = @@ -259,15 +371,15 @@ sources_menu_model()->ActivatedAt(1); // Sink at index 0 doesn't support desktop mirroring, so it should be // disabled. - EXPECT_FALSE(sink_buttons().at(0)->GetEnabled()); - EXPECT_TRUE(sink_buttons().at(1)->GetEnabled()); + EXPECT_FALSE(sink_views().at(0)->cast_sink_button_for_test()->GetEnabled()); + EXPECT_TRUE(sink_views().at(1)->cast_sink_button_for_test()->GetEnabled()); test_api.NotifyClick(CreateMouseEvent()); EXPECT_EQ(CastDialogView::kTab, sources_menu_model()->GetCommandIdAt(0)); sources_menu_model()->ActivatedAt(0); // Both sinks support tab or presentation casting, so they should be enabled. - EXPECT_TRUE(sink_buttons().at(0)->GetEnabled()); - EXPECT_TRUE(sink_buttons().at(1)->GetEnabled()); + EXPECT_TRUE(sink_views().at(0)->cast_sink_button_for_test()->GetEnabled()); + EXPECT_TRUE(sink_views().at(1)->cast_sink_button_for_test()->GetEnabled()); } TEST_F(CastDialogViewTest, ShowNoDeviceView) {
diff --git a/chrome/browser/ui/views/performance_controls/high_efficiency_chip_view_browsertest.cc b/chrome/browser/ui/views/performance_controls/high_efficiency_chip_view_browsertest.cc index 4f55183..a60d660 100644 --- a/chrome/browser/ui/views/performance_controls/high_efficiency_chip_view_browsertest.cc +++ b/chrome/browser/ui/views/performance_controls/high_efficiency_chip_view_browsertest.cc
@@ -34,11 +34,13 @@ #include "content/public/test/mock_navigation_handle.h" #include "net/dns/mock_host_resolver.h" #include "ui/base/page_transition_types.h" +#include "ui/events/base_event_utils.h" #include "ui/views/animation/ink_drop.h" #include "ui/views/animation/ink_drop_state.h" #include "ui/views/controls/styled_label.h" #include "ui/views/interaction/element_tracker_views.h" #include "ui/views/interaction/interaction_test_util_views.h" +#include "ui/views/test/button_test_api.h" #include "ui/views/test/widget_test.h" #include "ui/views/widget/any_widget_observer.h" @@ -234,3 +236,28 @@ EXPECT_TRUE(current_state == views::InkDropState::HIDDEN || current_state == views::InkDropState::DEACTIVATED); } + +IN_PROC_BROWSER_TEST_F(HighEfficiencyChipViewBrowserTest, + ShowAndHideInkDropOnDialog) { + PageActionIconView* chip = GetHighEfficiencyChipView(); + ui::MouseEvent press(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), + ui::EventTimeForNow(), 0, 0); + views::test::ButtonTestApi test_api(chip); + + DiscardTabAt(0); + chrome::SelectNumberedTab(browser(), 0); + + EXPECT_EQ(GetInkDropState(), views::InkDropState::HIDDEN); + + // Open bubble + test_api.NotifyClick(press); + + EXPECT_EQ(GetInkDropState(), views::InkDropState::ACTIVATED); + + test_api.NotifyClick(press); + + views::InkDropState current_state = GetInkDropState(); + // The deactivated state is HIDDEN on Mac but DEACTIVATED on Linux. + EXPECT_TRUE(current_state == views::InkDropState::HIDDEN || + current_state == views::InkDropState::DEACTIVATED); +}
diff --git a/chrome/browser/ui/views/performance_controls/high_efficiency_chip_view_unittest.cc b/chrome/browser/ui/views/performance_controls/high_efficiency_chip_view_unittest.cc index 17ec60d6..1c693be 100644 --- a/chrome/browser/ui/views/performance_controls/high_efficiency_chip_view_unittest.cc +++ b/chrome/browser/ui/views/performance_controls/high_efficiency_chip_view_unittest.cc
@@ -29,8 +29,6 @@ #include "ui/base/text/bytes_formatting.h" #include "ui/events/event_utils.h" #include "ui/events/types/event_type.h" -#include "ui/views/animation/ink_drop.h" -#include "ui/views/animation/ink_drop_state.h" #include "ui/views/controls/label.h" #include "ui/views/controls/styled_label.h" #include "ui/views/interaction/element_tracker_views.h" @@ -109,12 +107,6 @@ ->GetIconView(PageActionIconType::kHighEfficiency); } - views::InkDropState GetInkDropState() { - return views::InkDrop::Get(GetPageActionIconView()) - ->GetInkDrop() - ->GetTargetInkDropState(); - } - template <class T> T* GetDialogLabel(ui::ElementIdentifier identifier) { const ui::ElementContext context = @@ -212,35 +204,6 @@ HighEfficiencyBubbleActionType::kDismiss, 1); } -// When the dialog is closed, the ink drop should hide. -TEST_F(HighEfficiencyChipViewTest, ShouldShowAndHideInkDrop) { - SetTabDiscardState(0, true); - - PageActionIconView* view = GetPageActionIconView(); - EXPECT_EQ(GetInkDropState(), views::InkDropState::HIDDEN); - - ui::MouseEvent press(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), - ui::EventTimeForNow(), 0, 0); - ui::MouseEvent release(ui::ET_MOUSE_RELEASED, gfx::Point(), gfx::Point(), - ui::EventTimeForNow(), 0, 0); - views::test::ButtonTestApi test_api(view); - // Open bubble - test_api.NotifyClick(press); - test_api.NotifyClick(release); - EXPECT_EQ(GetInkDropState(), views::InkDropState::ACTIVATED); - - // Close bubble - test_api.NotifyClick(press); - - // TODO(drubery): This assertion fails on Mac after - // https://crrev.com/c/4348483 since the bubble no longer takes out an - // ScopedAnchorHighlight because it is never made visible. The test setup - // needs to be updated so that the bubble is visible. -#if !BUILDFLAG(IS_MAC) - EXPECT_EQ(GetInkDropState(), views::InkDropState::HIDDEN); -#endif -} - // A link should be rendered within the dialog. TEST_F(HighEfficiencyChipViewTest, ShouldRenderLinkInDialog) { SetTabDiscardState(0, true);
diff --git a/chrome/browser/ui/views/toolbar/chrome_labs_bubble_view.cc b/chrome/browser/ui/views/toolbar/chrome_labs_bubble_view.cc index 6681199..f466602f 100644 --- a/chrome/browser/ui/views/toolbar/chrome_labs_bubble_view.cc +++ b/chrome/browser/ui/views/toolbar/chrome_labs_bubble_view.cc
@@ -22,8 +22,10 @@ #include "ui/base/l10n/l10n_util.h" #include "ui/base/metadata/metadata_header_macros.h" #include "ui/base/metadata/metadata_impl_macros.h" +#include "ui/base/ui_base_features.h" #include "ui/color/color_id.h" #include "ui/gfx/color_palette.h" +#include "ui/gfx/geometry/rounded_corners_f.h" #include "ui/views/accessibility/view_accessibility.h" #include "ui/views/background.h" #include "ui/views/border.h" @@ -115,7 +117,8 @@ // for sizing as suggested as an initial fix by UI. Discuss a more formal // solution. constexpr int kMaxChromeLabsHeightDp = 448; - auto scroll_view = std::make_unique<views::ScrollView>(); + auto scroll_view = std::make_unique<views::ScrollView>( + views::ScrollView::ScrollWithLayers::kEnabled); // TODO(elainechien): Check with UI whether we want to draw overflow // indicator. scroll_view->SetDrawOverflowIndicator(false); @@ -133,6 +136,10 @@ views::INSETS_DIALOG))) .Build()); scroll_view->ClipHeightTo(0, kMaxChromeLabsHeightDp); + const int corner_radius = views::LayoutProvider::Get()->GetCornerRadiusMetric( + views::ShapeContextTokens::kDialogRadius); + scroll_view->SetViewportRoundedCornerRadius( + gfx::RoundedCornersF(0.0f, 0.0f, corner_radius, corner_radius)); AddChildView(std::move(scroll_view)); /* base::Unretained is safe here because NotifyRestartCallback will notify a
diff --git a/chrome/browser/ui/webui/realbox/realbox_handler.cc b/chrome/browser/ui/webui/realbox/realbox_handler.cc index d06b4827a..8ed6d60 100644 --- a/chrome/browser/ui/webui/realbox/realbox_handler.cc +++ b/chrome/browser/ui/webui/realbox/realbox_handler.cc
@@ -16,6 +16,7 @@ #include "build/branding_buildflags.h" #include "build/build_config.h" #include "build/chromeos_buildflags.h" +#include "chrome/browser/autocomplete/autocomplete_classifier_factory.h" #include "chrome/browser/autocomplete/chrome_autocomplete_provider_client.h" #include "chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.h" #include "chrome/browser/bookmarks/bookmark_model_factory.h" @@ -39,6 +40,7 @@ #include "components/omnibox/browser/autocomplete_match.h" #include "components/omnibox/browser/autocomplete_match_type.h" #include "components/omnibox/browser/autocomplete_result.h" +#include "components/omnibox/browser/omnibox_client.h" #include "components/omnibox/browser/omnibox_event_global_tracker.h" #include "components/omnibox/browser/omnibox_log.h" #include "components/omnibox/browser/omnibox_prefs.h" @@ -61,7 +63,6 @@ #include "ui/base/webui/resource_path.h" #include "ui/base/webui/web_ui_util.h" #include "ui/base/window_open_disposition_utils.h" -#include "ui/gfx/vector_icon_types.h" #include "ui/resources/grit/webui_resources.h" namespace { @@ -351,6 +352,116 @@ return variations_base64url; } +// TODO(crbug.com/1431513): Consider inheriting from `ChromeOmniboxClient` +// to avoid reimplementation of methods like `OnBookmarkLaunched`. +class RealboxOmniboxClient : public OmniboxClient { + public: + explicit RealboxOmniboxClient(Profile* profile, + content::WebContents* web_contents); + ~RealboxOmniboxClient() override; + + // OmniboxClient: + std::unique_ptr<AutocompleteProviderClient> CreateAutocompleteProviderClient() + override; + bool IsPasteAndGoEnabled() const override; + SessionID GetSessionID() const override; + bookmarks::BookmarkModel* GetBookmarkModel() override; + TemplateURLService* GetTemplateURLService() override; + const AutocompleteSchemeClassifier& GetSchemeClassifier() const override; + AutocompleteClassifier* GetAutocompleteClassifier() override; + bool ShouldDefaultTypedNavigationsToHttps() const override; + int GetHttpsPortForTesting() const override; + bool IsUsingFakeHttpsForHttpsUpgradeTesting() const override; + gfx::Image GetSizedIcon(const gfx::VectorIcon& vector_icon_type, + SkColor vector_icon_color) const override; + gfx::Image GetFaviconForPageUrl( + const GURL& page_url, + FaviconFetchedCallback on_favicon_fetched) override; + void OnBookmarkLaunched() override; + void OnURLOpenedFromOmnibox(OmniboxLog* log) override; + + private: + raw_ptr<Profile> profile_; + raw_ptr<content::WebContents> web_contents_; + ChromeAutocompleteSchemeClassifier scheme_classifier_; +}; + +RealboxOmniboxClient::RealboxOmniboxClient(Profile* profile, + content::WebContents* web_contents) + : profile_(profile), + web_contents_(web_contents), + scheme_classifier_(ChromeAutocompleteSchemeClassifier(profile)) {} + +RealboxOmniboxClient::~RealboxOmniboxClient() = default; + +std::unique_ptr<AutocompleteProviderClient> +RealboxOmniboxClient::CreateAutocompleteProviderClient() { + return std::make_unique<ChromeAutocompleteProviderClient>(profile_); +} + +bool RealboxOmniboxClient::IsPasteAndGoEnabled() const { + return false; +} + +SessionID RealboxOmniboxClient::GetSessionID() const { + return sessions::SessionTabHelper::IdForTab(web_contents_); +} + +bookmarks::BookmarkModel* RealboxOmniboxClient::GetBookmarkModel() { + return BookmarkModelFactory::GetForBrowserContext(profile_); +} + +TemplateURLService* RealboxOmniboxClient::GetTemplateURLService() { + return TemplateURLServiceFactory::GetForProfile(profile_); +} + +const AutocompleteSchemeClassifier& RealboxOmniboxClient::GetSchemeClassifier() + const { + return scheme_classifier_; +} + +AutocompleteClassifier* RealboxOmniboxClient::GetAutocompleteClassifier() { + return AutocompleteClassifierFactory::GetForProfile(profile_); +} + +bool RealboxOmniboxClient::ShouldDefaultTypedNavigationsToHttps() const { + return false; +} + +int RealboxOmniboxClient::GetHttpsPortForTesting() const { + return 0; +} + +bool RealboxOmniboxClient::IsUsingFakeHttpsForHttpsUpgradeTesting() const { + return false; +} + +gfx::Image RealboxOmniboxClient::GetSizedIcon( + const gfx::VectorIcon& vector_icon_type, + SkColor vector_icon_color) const { + return gfx::Image(); +} + +gfx::Image RealboxOmniboxClient::GetFaviconForPageUrl( + const GURL& page_url, + FaviconFetchedCallback on_favicon_fetched) { + return gfx::Image(); +} + +void RealboxOmniboxClient::OnBookmarkLaunched() { + RecordBookmarkLaunch(BookmarkLaunchLocation::kOmnibox, + profile_metrics::GetBrowserProfileType(profile_)); +} + +void RealboxOmniboxClient::OnURLOpenedFromOmnibox(OmniboxLog* log) { + if (auto* search_prefetch_service = + SearchPrefetchServiceFactory::GetForProfile(profile_)) { + search_prefetch_service->OnURLOpenedFromOmnibox(log); + } + predictors::AutocompleteActionPredictorFactory::GetForProfile(profile_) + ->OnOmniboxOpenedUrl(*log); +} + } // namespace // static @@ -543,6 +654,20 @@ page_handler_(this, std::move(pending_page_handler)) { controller_emitter_observation_.Observe( AutocompleteControllerEmitter::GetForBrowserContext(profile_)); + + edit_model_ = std::make_unique<OmniboxEditModel>( + /*view=*/nullptr, /*edit_model_delegate=*/this, + std::make_unique<RealboxOmniboxClient>(profile_, web_contents_)); + edit_model_->set_autocomplete_controller( + std::make_unique<AutocompleteController>( + std::make_unique<ChromeAutocompleteProviderClient>(profile_), + AutocompleteClassifier::DefaultOmniboxProviders())); + + AutocompleteControllerEmitter* emitter = + AutocompleteControllerEmitter::GetForBrowserContext(profile_); + if (emitter) { + autocomplete_controller()->AddObserver(emitter); + } } RealboxHandler::~RealboxHandler() = default; @@ -554,25 +679,14 @@ void RealboxHandler::QueryAutocomplete(const std::u16string& input, bool prevent_inline_autocomplete) { - if (!autocomplete_controller_) { - autocomplete_controller_ = std::make_unique<AutocompleteController>( - std::make_unique<ChromeAutocompleteProviderClient>(profile_), - AutocompleteClassifier::DefaultOmniboxProviders()); - - AutocompleteControllerEmitter* emitter = - AutocompleteControllerEmitter::GetForBrowserContext(profile_); - if (emitter) { - autocomplete_controller_->AddObserver(emitter); - } - } - // TODO(tommycli): We use the input being empty as a signal we are requesting // on-focus suggestions. It would be nice if we had a more explicit signal. bool is_on_focus = input.empty(); // Early exit if a query is already in progress for on focus inputs. - if (!autocomplete_controller_->done() && is_on_focus) + if (!autocomplete_controller()->done() && is_on_focus) { return; + } if (time_user_first_modified_realbox_.is_null() && !is_on_focus) time_user_first_modified_realbox_ = base::TimeTicks::Now(); @@ -591,14 +705,11 @@ autocomplete_input.set_prefer_keyword(false); autocomplete_input.set_allow_exact_keyword_match(false); - autocomplete_controller_->Start(autocomplete_input); + autocomplete_controller()->Start(autocomplete_input); } void RealboxHandler::StopAutocomplete(bool clear_result) { - if (!autocomplete_controller_) - return; - - autocomplete_controller_->Stop(clear_result); + autocomplete_controller()->Stop(clear_result); if (clear_result) time_user_first_modified_realbox_ = base::TimeTicks(); @@ -614,141 +725,28 @@ bool ctrl_key, bool meta_key, bool shift_key) { - if (!autocomplete_controller_ || - autocomplete_controller_->result().size() <= line) { + if (line >= autocomplete_controller()->result().size()) { + NOTREACHED(); return; } - - AutocompleteMatch match(autocomplete_controller_->result().match_at(line)); - // If an action takes over the whole match, it will be the primary action. - const OmniboxAction* action = match.GetPrimaryAction(); - if (action && action->TakesOverMatch()) { - return ExecuteAction(line, base::TimeTicks::Now(), mouse_button, alt_key, - ctrl_key, meta_key, shift_key); - } - - if (match.destination_url != url) { - // TODO(https://crbug.com/1020025): this could be malice or staleness. - // Either way: don't navigate. - return; - } - - // TODO(crbug.com/1041129): The following logic for recording Omnibox metrics - // is largely copied from SearchTabHelper::OpenAutocompleteMatch(). Make sure - // any changes here is reflected there until one code path is obsolete. - - const auto now = base::TimeTicks::Now(); - base::TimeDelta elapsed_time_since_first_autocomplete_query = - now - time_user_first_modified_realbox_; - autocomplete_controller_ - ->UpdateMatchDestinationURLWithAdditionalAssistedQueryStats( - elapsed_time_since_first_autocomplete_query, &match); - - LOCAL_HISTOGRAM_BOOLEAN("Omnibox.EventCount", true); - - UMA_HISTOGRAM_MEDIUM_TIMES("Omnibox.FocusToOpenTimeAnyPopupState3", - time_elapsed_since_last_focus); - - if (ui::PageTransitionTypeIncludingQualifiersIs(match.transition, - ui::PAGE_TRANSITION_TYPED)) { - navigation_metrics::RecordOmniboxURLNavigation(match.destination_url); - } - // The following histogram should be recorded for both TYPED and pasted - // URLs, but should still exclude reloads. - if (ui::PageTransitionTypeIncludingQualifiersIs(match.transition, - ui::PAGE_TRANSITION_TYPED) || - ui::PageTransitionTypeIncludingQualifiersIs(match.transition, - ui::PAGE_TRANSITION_LINK)) { - net::cookie_util::RecordCookiePortOmniboxHistograms(match.destination_url); - } - - SuggestionAnswer::LogAnswerUsed(match.answer); - - TemplateURLService* template_url_service = - TemplateURLServiceFactory::GetForProfile(profile_); - if (template_url_service && - template_url_service->IsSearchResultsPageFromDefaultSearchProvider( - match.destination_url)) { - // Note: will always be false for the realbox. - UMA_HISTOGRAM_BOOLEAN("Omnibox.Search.OffTheRecord", - profile_->IsOffTheRecord()); - base::RecordAction( - base::UserMetricsAction("OmniboxDestinationURLIsSearchOnDSP")); - } - - AutocompleteMatch::LogSearchEngineUsed(match, template_url_service); - - auto* bookmark_model = BookmarkModelFactory::GetForBrowserContext(profile_); - if (bookmark_model->IsBookmarked(match.destination_url)) { - RecordBookmarkLaunch(BookmarkLaunchLocation::kOmnibox, - profile_metrics::GetBrowserProfileType(profile_)); - } - - const AutocompleteInput& input = autocomplete_controller_->input(); - WindowOpenDisposition disposition = ui::DispositionFromClick( + const base::TimeTicks timestamp = base::TimeTicks::Now(); + const WindowOpenDisposition disposition = ui::DispositionFromClick( /*middle_button=*/mouse_button == 1, alt_key, ctrl_key, meta_key, shift_key); - - base::TimeDelta default_time_delta = base::Milliseconds(-1); - - if (time_user_first_modified_realbox_.is_null()) - elapsed_time_since_first_autocomplete_query = default_time_delta; - - base::TimeDelta elapsed_time_since_last_change_to_default_match = - !autocomplete_controller_->last_time_default_match_changed().is_null() - ? now - autocomplete_controller_->last_time_default_match_changed() - : default_time_delta; - - OmniboxLog log( - /*text=*/input.focus_type() != - metrics::OmniboxFocusType::INTERACTION_DEFAULT - ? std::u16string() - : input.text(), - /*just_deleted_text=*/input.prevent_inline_autocomplete(), - /*input_type=*/input.type(), - /*in_keyword_mode=*/false, - /*entry_method=*/metrics::OmniboxEventProto::INVALID, - /*is_popup_open=*/are_matches_showing, - /*selected_index=*/line, - /*disposition=*/disposition, - /*is_paste_and_go=*/false, - /*tab_id=*/sessions::SessionTabHelper::IdForTab(web_contents_), - /*current_page_classification=*/metrics::OmniboxEventProto::NTP_REALBOX, - /*elapsed_time_since_user_first_modified_omnibox=*/ - elapsed_time_since_first_autocomplete_query, - /*completed_length=*/match.allowed_to_be_default_match - ? match.inline_autocompletion.length() - : std::u16string::npos, - /*elapsed_time_since_last_change_to_default_match=*/ - elapsed_time_since_last_change_to_default_match, - /*result=*/autocomplete_controller_->result(), match.destination_url, - /*is_incognito=*/profile_->IsOffTheRecord()); - autocomplete_controller_->AddProviderAndTriggeringLogs(&log); - - OmniboxEventGlobalTracker::GetInstance()->OnURLOpened(&log); - - if (auto* search_prefetch_service = - SearchPrefetchServiceFactory::GetForProfile(profile_)) { - search_prefetch_service->OnURLOpenedFromOmnibox(&log, web_contents_); - } - predictors::AutocompleteActionPredictorFactory::GetForProfile(profile_) - ->OnOmniboxOpenedUrl(log); - - web_contents_->OpenURL( - content::OpenURLParams(match.destination_url, content::Referrer(), - disposition, match.transition, false)); + edit_model_->OpenSelection(OmniboxPopupSelection(line), timestamp, + disposition); } void RealboxHandler::OnNavigationLikely( uint8_t line, omnibox::mojom::NavigationPredictor navigation_predictor) { - if (!autocomplete_controller_ || - autocomplete_controller_->result().size() <= line) { + if (autocomplete_controller()->result().size() <= line) { + NOTREACHED(); return; } if (auto* search_prefetch_service = SearchPrefetchServiceFactory::GetForProfile(profile_)) { - AutocompleteMatch match(autocomplete_controller_->result().match_at(line)); + AutocompleteMatch match(autocomplete_controller()->result().match_at(line)); search_prefetch_service->OnNavigationLikely( line, match, navigation_predictor, web_contents_); } @@ -765,44 +763,35 @@ const AutocompleteMatch&, const AutocompleteMatch&, IDNA2008DeviationCharacter) { - web_contents_->OpenURL(content::OpenURLParams( - destination_url, content::Referrer(), disposition, transition, false)); + // TODO(crbug.com/1431513): Cull this method and simplify base interfaces. + NOTREACHED(); } void RealboxHandler::DeleteAutocompleteMatch(uint8_t line) { - if (!autocomplete_controller_ || - autocomplete_controller_->result().size() <= line || - !autocomplete_controller_->result().match_at(line).SupportsDeletion()) { + if (autocomplete_controller()->result().size() <= line || + !autocomplete_controller()->result().match_at(line).SupportsDeletion()) { + NOTREACHED(); return; } - const auto& match = autocomplete_controller_->result().match_at(line); + const auto& match = autocomplete_controller()->result().match_at(line); if (match.SupportsDeletion()) { - autocomplete_controller_->Stop(false); - autocomplete_controller_->DeleteMatch(match); + autocomplete_controller()->Stop(false); + autocomplete_controller()->DeleteMatch(match); } } void RealboxHandler::ToggleSuggestionGroupIdVisibility( int32_t suggestion_group_id) { - if (!autocomplete_controller_) { - return; - } - const auto& group_id = omnibox::GroupIdForNumber(suggestion_group_id); DCHECK_NE(omnibox::GROUP_INVALID, group_id); const bool current_visibility = - autocomplete_controller_->result().IsSuggestionGroupHidden( + autocomplete_controller()->result().IsSuggestionGroupHidden( profile_->GetPrefs(), group_id); - autocomplete_controller_->result().SetSuggestionGroupHidden( + autocomplete_controller()->result().SetSuggestionGroupHidden( profile_->GetPrefs(), group_id, !current_visibility); } -void RealboxHandler::LogCharTypedToRepaintLatency(base::TimeDelta latency) { - UMA_HISTOGRAM_TIMES("NewTabPage.Realbox.CharTypedToRepaintLatency.ToPaint", - latency); -} - void RealboxHandler::ExecuteAction(uint8_t line, base::TimeTicks match_selection_timestamp, uint8_t mouse_button, @@ -810,35 +799,26 @@ bool ctrl_key, bool meta_key, bool shift_key) { - if (!autocomplete_controller_ || - autocomplete_controller_->result().size() <= line) { + if (line >= autocomplete_controller()->result().size()) { + NOTREACHED(); return; } - + const WindowOpenDisposition disposition = ui::DispositionFromClick( + /*middle_button=*/mouse_button == 1, alt_key, ctrl_key, meta_key, + shift_key); const AutocompleteMatch& match = - autocomplete_controller_->result().match_at(line); - const OmniboxAction* action = match.GetPrimaryAction(); - if (action) { - WindowOpenDisposition disposition = ui::DispositionFromClick( - /*middle_button=*/mouse_button == 1, alt_key, ctrl_key, meta_key, - shift_key); - // TODO(tommycli): Add recording of action shown in the realbox when the - // user uses the realbox to go somewhere OTHER than executing an action. - action->RecordActionShown(line, /*executed=*/true); - OmniboxAction::ExecutionContext context( - *(autocomplete_controller_->autocomplete_provider_client()), - base::BindOnce(&RealboxHandler::OpenURL, - weak_ptr_factory_.GetWeakPtr()), - match_selection_timestamp, disposition); - action->Execute(context); - } else if (match.has_tab_match.value_or(false)) { - WindowOpenDisposition disposition = WindowOpenDisposition::SWITCH_TO_TAB; - ui::PageTransition transition = ui::PageTransitionFromInt( - match.transition | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR); - web_contents_->OpenURL( - content::OpenURLParams(match.destination_url, content::Referrer(), - disposition, transition, false)); - } + autocomplete_controller()->result().match_at(line); + // Realbox currently only supports one action button and gives preference to + // actions over tab switch, but the omnibox shows tab switch button first. + // This disparity can be eliminated once realbox supports multiple + // actions on a button row. + const bool has_action = match.GetPrimaryAction() != nullptr; + DCHECK(has_action || match.has_tab_match.value_or(false)); + OmniboxPopupSelection selection( + line, has_action + ? OmniboxPopupSelection::LineState::FOCUSED_BUTTON_ACTION + : OmniboxPopupSelection::LineState::FOCUSED_BUTTON_TAB_SWITCH); + edit_model_->OpenSelection(selection, match_selection_timestamp, disposition); } void RealboxHandler::OnResultChanged(AutocompleteController* controller, @@ -848,7 +828,7 @@ } // Update the omnibox if the controller does not belong to the realbox. - if (controller != autocomplete_controller_.get()) { + if (controller != autocomplete_controller()) { if (base::FeatureList::IsEnabled(omnibox::kWebUIOmniboxPopup)) { page_->OmniboxAutocompleteResultChanged(CreateAutocompleteResult( controller->input().text(), controller->result(), @@ -860,16 +840,16 @@ // Update the realbox only if the controller belongs to the realbox. page_->AutocompleteResultChanged(CreateAutocompleteResult( - autocomplete_controller_->input().text(), - autocomplete_controller_->result(), + autocomplete_controller()->input().text(), + autocomplete_controller()->result(), BookmarkModelFactory::GetForBrowserContext(profile_), profile_->GetPrefs())); - if (autocomplete_controller_->done()) { + if (autocomplete_controller()->done()) { if (SearchPrefetchService* search_prefetch_service = SearchPrefetchServiceFactory::GetForProfile(profile_)) { search_prefetch_service->OnResultChanged( - web_contents_, autocomplete_controller_->result()); + web_contents_, autocomplete_controller()->result()); } } } @@ -877,3 +857,104 @@ void RealboxHandler::SelectMatchAtLine(size_t old_line, size_t new_line) { page_->SelectMatchAtLine(new_line); } + +// OmniboxEditModelDelegate: +void RealboxHandler::OnAutocompleteAccept( + const GURL& destination_url, + TemplateURLRef::PostContent* post_content, + WindowOpenDisposition disposition, + ui::PageTransition transition, + AutocompleteMatchType::Type match_type, + base::TimeTicks match_selection_timestamp, + bool destination_url_entered_without_scheme, + const std::u16string& text, + const AutocompleteMatch& match, + const AutocompleteMatch& alternative_nav_match, + IDNA2008DeviationCharacter deviation_char_in_hostname) { + destination_url_ = destination_url; + post_content_ = post_content; + disposition_ = disposition; + transition_ = transition; + match_selection_timestamp_ = match_selection_timestamp; + destination_url_entered_without_scheme_ = + destination_url_entered_without_scheme; + + web_contents_->OpenURL(content::OpenURLParams( + destination_url_, content::Referrer(), disposition_, transition_, false)); +} + +void RealboxHandler::OnInputInProgress(bool in_progress) {} + +void RealboxHandler::OnChanged() {} + +void RealboxHandler::OnPopupVisibilityChanged() {} + +LocationBarModel* RealboxHandler::GetLocationBarModel() { + return this; +} + +const LocationBarModel* RealboxHandler::GetLocationBarModel() const { + return this; +} + +// LocationBarModel: +// Note, the implementation here is mostly not needed but the +// `OmniboxEditModelDelegate` implementation currently needs to +// provide a full working instance and some parts are used. +std::u16string RealboxHandler::GetFormattedFullURL() const { + return u""; +} + +std::u16string RealboxHandler::GetURLForDisplay() const { + return u""; +} + +GURL RealboxHandler::GetURL() const { + return GURL(); +} + +security_state::SecurityLevel RealboxHandler::GetSecurityLevel() const { + return security_state::SecurityLevel::NONE; +} + +net::CertStatus RealboxHandler::GetCertStatus() const { + return 0; +} + +metrics::OmniboxEventProto::PageClassification +RealboxHandler::GetPageClassification(OmniboxFocusSource focus_source, + bool is_prefetch) { + return metrics::OmniboxEventProto::NTP_REALBOX; +} + +const gfx::VectorIcon& RealboxHandler::GetVectorIcon() const { + return vector_icon_; +} + +std::u16string RealboxHandler::GetSecureDisplayText() const { + return u""; +} + +std::u16string RealboxHandler::GetSecureAccessibilityText() const { + return u""; +} + +bool RealboxHandler::ShouldDisplayURL() const { + return false; +} + +bool RealboxHandler::IsOfflinePage() const { + return false; +} + +bool RealboxHandler::ShouldPreventElision() const { + return false; +} + +bool RealboxHandler::ShouldUseUpdatedConnectionSecurityIndicators() const { + return false; +} + +AutocompleteController* RealboxHandler::autocomplete_controller() const { + return edit_model_->autocomplete_controller(); +}
diff --git a/chrome/browser/ui/webui/realbox/realbox_handler.h b/chrome/browser/ui/webui/realbox/realbox_handler.h index e676a1a..f5e4c5c 100644 --- a/chrome/browser/ui/webui/realbox/realbox_handler.h +++ b/chrome/browser/ui/webui/realbox/realbox_handler.h
@@ -13,11 +13,15 @@ #include "base/time/time.h" #include "components/omnibox/browser/autocomplete_controller.h" #include "components/omnibox/browser/autocomplete_controller_emitter.h" +#include "components/omnibox/browser/location_bar_model.h" #include "components/omnibox/browser/omnibox.mojom.h" +#include "components/omnibox/browser/omnibox_edit_model.h" +#include "components/omnibox/browser/omnibox_edit_model_delegate.h" #include "components/url_formatter/spoof_checks/idna_metrics.h" #include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/cpp/bindings/receiver.h" #include "mojo/public/cpp/bindings/remote.h" +#include "ui/gfx/vector_icon_types.h" class GURL; class MetricsReporter; @@ -28,13 +32,11 @@ class WebUIDataSource; } // namespace content -namespace gfx { -struct VectorIcon; -} // namespace gfx - // Handles bidirectional communication between NTP realbox JS and the browser. class RealboxHandler : public omnibox::mojom::PageHandler, - public AutocompleteController::Observer { + public AutocompleteController::Observer, + public OmniboxEditModelDelegate, + public LocationBarModel { public: enum class FocusState { // kNormal means the row is focused, and Enter key navigates to the match. @@ -80,7 +82,6 @@ bool shift_key) override; void DeleteAutocompleteMatch(uint8_t line) override; void ToggleSuggestionGroupIdVisibility(int32_t suggestion_group_id) override; - void LogCharTypedToRepaintLatency(base::TimeDelta latency) override; void ExecuteAction(uint8_t line, base::TimeTicks match_selection_timestamp, uint8_t mouse_button, @@ -111,10 +112,49 @@ void SelectMatchAtLine(size_t old_line, size_t new_line); + // OmniboxEditModelDelegate: + void OnAutocompleteAccept( + const GURL& destination_url, + TemplateURLRef::PostContent* post_content, + WindowOpenDisposition disposition, + ui::PageTransition transition, + AutocompleteMatchType::Type match_type, + base::TimeTicks match_selection_timestamp, + bool destination_url_entered_without_scheme, + const std::u16string& text, + const AutocompleteMatch& match, + const AutocompleteMatch& alternative_nav_match, + IDNA2008DeviationCharacter deviation_char_in_hostname = + IDNA2008DeviationCharacter::kNone) override; + void OnInputInProgress(bool in_progress) override; + void OnChanged() override; + void OnPopupVisibilityChanged() override; + LocationBarModel* GetLocationBarModel() override; + const LocationBarModel* GetLocationBarModel() const override; + + // LocationBarModel: + std::u16string GetFormattedFullURL() const override; + std::u16string GetURLForDisplay() const override; + GURL GetURL() const override; + security_state::SecurityLevel GetSecurityLevel() const override; + net::CertStatus GetCertStatus() const override; + metrics::OmniboxEventProto::PageClassification GetPageClassification( + OmniboxFocusSource focus_source, + bool is_prefetch = false) override; + const gfx::VectorIcon& GetVectorIcon() const override; + std::u16string GetSecureDisplayText() const override; + std::u16string GetSecureAccessibilityText() const override; + bool ShouldDisplayURL() const override; + bool IsOfflinePage() const override; + bool ShouldPreventElision() const override; + bool ShouldUseUpdatedConnectionSecurityIndicators() const override; + private: + AutocompleteController* autocomplete_controller() const; + raw_ptr<Profile> profile_; raw_ptr<content::WebContents> web_contents_; - std::unique_ptr<AutocompleteController> autocomplete_controller_; + std::unique_ptr<OmniboxEditModel> edit_model_; base::ScopedObservation<AutocompleteControllerEmitter, AutocompleteController::Observer> controller_emitter_observation_{this}; @@ -124,6 +164,9 @@ mojo::Remote<omnibox::mojom::Page> page_; mojo::Receiver<omnibox::mojom::PageHandler> page_handler_; + // This is unused, it's just needed for LocationBarModel implementation. + gfx::VectorIcon vector_icon_{nullptr, 0u, ""}; + base::WeakPtrFactory<RealboxHandler> weak_ptr_factory_{this}; };
diff --git a/chrome/browser/ui/webui/realbox/realbox_handler_browsertest.cc b/chrome/browser/ui/webui/realbox/realbox_handler_browsertest.cc index a83bb40..dac5ff2 100644 --- a/chrome/browser/ui/webui/realbox/realbox_handler_browsertest.cc +++ b/chrome/browser/ui/webui/realbox/realbox_handler_browsertest.cc
@@ -173,7 +173,7 @@ content::test::PrerenderHostRegistryObserver registry_observer( *GetWebContents()); - std::string input_query = "pre"; + std::string input_query = "prerender"; std::string search_terms = "prerender"; AddNewSuggestionRule(input_query, {search_terms}, /*prefetch_index=*/0, /*prerender_index=*/0);
diff --git a/chrome/browser/ui/webui/settings/about_handler.cc b/chrome/browser/ui/webui/settings/about_handler.cc index b1cd9af..ab6b211 100644 --- a/chrome/browser/ui/webui/settings/about_handler.cc +++ b/chrome/browser/ui/webui/settings/about_handler.cc
@@ -686,7 +686,8 @@ ash::eol_incentive_util::EolIncentiveType::kEolPassedRecently || eolIncentiveType == ash::eol_incentive_util::EolIncentiveType::kEolPassed) && - has_eol_passed); + has_eol_passed && + base::FeatureList::IsEnabled(ash::features::kEolIncentiveSettings)); eol_incentive_shows_offer_ = (ash::features::kEolIncentiveParam.Get() != ash::features::EolIncentiveParam::kNoOffer &&
diff --git a/chrome/build/lacros64.pgo.txt b/chrome/build/lacros64.pgo.txt index 90ef9194..e54f31e 100644 --- a/chrome/build/lacros64.pgo.txt +++ b/chrome/build/lacros64.pgo.txt
@@ -1 +1 @@ -chrome-chromeos-amd64-generic-main-1680879718-7c54ef17bded0f0cafabc03bd72c761a5e448cb1.profdata +chrome-chromeos-amd64-generic-main-1680897573-fc68ce7f3eecaa1eb43665da7e7673f814edc8cc.profdata
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt index e94233e6..67849092 100644 --- a/chrome/build/linux.pgo.txt +++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@ -chrome-linux-main-1680868649-a080d7bbf9e44dfd5a82f6d79fe8d5abd538f293.profdata +chrome-linux-main-1680890360-b9944e06ce12f9ad4eefc35699b61f3fdc7fa658.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt index e42f2c9..ac81f337 100644 --- a/chrome/build/mac-arm.pgo.txt +++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@ -chrome-mac-arm-main-1680879718-bb15a1d1cfa3cabb8a0bf1598ff72f9cdb5065ec.profdata +chrome-mac-arm-main-1680904715-100678c14cc0c6817e7c38cbfddd2dca8a4f8a79.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt index 63795f86..9adb29e 100644 --- a/chrome/build/win32.pgo.txt +++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@ -chrome-win32-main-1680873567-575d10612343ebbf37d74b5db118e18559c862d3.profdata +chrome-win32-main-1680890360-6888111736cc2509711fc611a13f9f4d52e153d8.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt index c0420ae7..a149097e 100644 --- a/chrome/build/win64.pgo.txt +++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@ -chrome-win64-main-1680873567-b473a7caae0cf187dac95d766680cd0bd4dffb12.profdata +chrome-win64-main-1680890360-852603c65339f7bf2badd6fb01d48cadc1b6cd5f.profdata
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 94f33ad..b0528c8 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -8981,6 +8981,7 @@ "../browser/ui/views/media_router/cast_dialog_metrics_unittest.cc", "../browser/ui/views/media_router/cast_dialog_no_sinks_view_unittest.cc", "../browser/ui/views/media_router/cast_dialog_sink_button_unittest.cc", + "../browser/ui/views/media_router/cast_dialog_sink_view_unittest.cc", "../browser/ui/views/media_router/cast_dialog_view_unittest.cc", "../browser/ui/views/media_router/cast_toolbar_button_unittest.cc", "../browser/ui/views/media_router/web_contents_display_observer_view_unittest.cc",
diff --git a/chrome/test/data/webui/new_tab_page/realbox/realbox_test.ts b/chrome/test/data/webui/new_tab_page/realbox/realbox_test.ts index 1248971a..05a906f7 100644 --- a/chrome/test/data/webui/new_tab_page/realbox/realbox_test.ts +++ b/chrome/test/data/webui/new_tab_page/realbox/realbox_test.ts
@@ -1881,93 +1881,7 @@ // Test Responsiveness Metrics //============================================================================ - test('responsiveness metric is being recorded', async () => { - realbox.$.input.value = 'he'; - realbox.$.input.dispatchEvent(new InputEvent('input')); - - // The responsiveness metric is not recorded until the results are painted. - assertEquals( - 0, testProxy.handler.getCallCount('logCharTypedToRepaintLatency')); - - let matches = [createSearchMatch()]; - testProxy.callbackRouterRemote.autocompleteResultChanged({ - input: mojoString16(realbox.$.input.value.trimStart()), - matches, - suggestionGroupsMap: {}, - }); - await testProxy.callbackRouterRemote.$.flushForTesting(); - assertTrue(areMatchesShowing()); - - // The responsiveness metric is recorded once the results are painted. - await testProxy.handler.whenCalled('logCharTypedToRepaintLatency') - .then((args) => { - assertTrue(args.timeDelta.microseconds > 0); - }); - assertEquals( - 1, testProxy.handler.getCallCount('logCharTypedToRepaintLatency')); - - testProxy.handler.reset(); - - // Delete the last character. - realbox.$.input.value = 'h'; - realbox.$.input.dispatchEvent(new InputEvent('input')); - - matches = [createSearchMatch({ - allowedToBeDefaultMatch: true, - inlineAutocompletion: mojoString16('ello'), - })]; - testProxy.callbackRouterRemote.autocompleteResultChanged({ - input: mojoString16(realbox.$.input.value.trimStart()), - matches, - suggestionGroupsMap: {}, - }); - await testProxy.callbackRouterRemote.$.flushForTesting(); - assertTrue(areMatchesShowing()); - - // The responsiveness metric is not recorded when characters are deleted. - assertEquals( - 0, testProxy.handler.getCallCount('logCharTypedToRepaintLatency')); - - testProxy.handler.reset(); - - assertEquals('hello', realbox.$.input.value); - const start = realbox.$.input.selectionStart!; - const end = realbox.$.input.selectionEnd!; - assertEquals('ello', realbox.$.input.value.substring(start, end)); - - // Type the next character of the inline autocompletion. - const keyEvent = new KeyboardEvent('keydown', { - bubbles: true, - cancelable: true, - composed: true, // So it propagates across shadow DOM boundary. - key: 'e', - }); - realbox.$.input.dispatchEvent(keyEvent); - assertTrue(keyEvent.defaultPrevented); - - matches = [createSearchMatch({ - allowedToBeDefaultMatch: true, - inlineAutocompletion: mojoString16('llo'), - })]; - testProxy.callbackRouterRemote.autocompleteResultChanged({ - input: mojoString16('he'), - matches, - suggestionGroupsMap: {}, - }); - await testProxy.callbackRouterRemote.$.flushForTesting(); - assertTrue(areMatchesShowing()); - - // The responsiveness metric is recorded when the default match has - // inline autocompletion. - await testProxy.handler.whenCalled('logCharTypedToRepaintLatency') - .then((args) => { - assertTrue(args.timeDelta.microseconds > 0); - }); - assertEquals( - 1, testProxy.handler.getCallCount('logCharTypedToRepaintLatency')); - }); - - test('new responsiveness metrics are being recorded', async () => { + test('responsiveness metrics are being recorded', async () => { realbox.$.input.value = 'he'; realbox.$.input.dispatchEvent(new InputEvent('input'));
diff --git a/chrome/test/data/webui/new_tab_page/realbox/test_realbox_browser_proxy.ts b/chrome/test/data/webui/new_tab_page/realbox/test_realbox_browser_proxy.ts index c35c5ac..9a4e214 100644 --- a/chrome/test/data/webui/new_tab_page/realbox/test_realbox_browser_proxy.ts +++ b/chrome/test/data/webui/new_tab_page/realbox/test_realbox_browser_proxy.ts
@@ -20,7 +20,6 @@ super([ 'deleteAutocompleteMatch', 'executeAction', - 'logCharTypedToRepaintLatency', 'onNavigationLikely', 'openAutocompleteMatch', 'queryAutocomplete', @@ -51,10 +50,6 @@ }); } - logCharTypedToRepaintLatency(timeDelta: TimeDelta) { - this.methodCalled('logCharTypedToRepaintLatency', {timeDelta}); - } - openAutocompleteMatch( line: number, url: Url, areMatchesShowing: boolean, timeElapsedSinceLastFocus: TimeDelta, mouseButton: number,
diff --git a/chrome/test/data/webui/settings/BUILD.gn b/chrome/test/data/webui/settings/BUILD.gn index dbda164..bc0a325 100644 --- a/chrome/test/data/webui/settings/BUILD.gn +++ b/chrome/test/data/webui/settings/BUILD.gn
@@ -41,6 +41,8 @@ "downloads_page_test.ts", "dropdown_menu_tests.ts", "extension_controlled_indicator_tests.ts", + "file_system_site_entry_tests.ts", + "file_system_site_entry_item_tests.ts", "file_system_site_list_tests.ts", "help_page_test.ts", "idle_load_tests.ts",
diff --git a/chrome/test/data/webui/settings/OWNERS b/chrome/test/data/webui/settings/OWNERS index 4b6a8d5..ad7c7bbf 100644 --- a/chrome/test/data/webui/settings/OWNERS +++ b/chrome/test/data/webui/settings/OWNERS
@@ -5,6 +5,7 @@ per-file clear_browsing_data_test.ts=sauski@google.com per-file do_not_track_toggle_test.ts=sauski@google.com per-file do_not_track_toggle_test.ts=sauski@google.com +per-file file_system_*=sauski@google.com per-file metrics_reporting_tests.ts=sauski@google.com per-file personalization_options_test.ts=sauski@google.com per-file privacy_page_test.ts=sauski@google.com,rainhard@chromium.org,sideyilmaz@chromium.org
diff --git a/chrome/test/data/webui/settings/cr_settings_browsertest.js b/chrome/test/data/webui/settings/cr_settings_browsertest.js index 62dba05d..72dbb25 100644 --- a/chrome/test/data/webui/settings/cr_settings_browsertest.js +++ b/chrome/test/data/webui/settings/cr_settings_browsertest.js
@@ -925,7 +925,9 @@ ['DownloadsPage', 'downloads_page_test.js'], ['DropdownMenu', 'dropdown_menu_tests.js'], ['ExtensionControlledIndicator', 'extension_controlled_indicator_tests.js'], - ['FileSystemSettings', 'file_system_site_list_tests.js'], + ['FileSystemSettingsList', 'file_system_site_list_tests.js'], + ['FileSystemSettingsListEntries', 'file_system_site_entry_tests.js'], + ['FileSystemSettingsListEntryItems', 'file_system_site_entry_item_tests.js'], ['HelpPage', 'help_page_test.js'], ['PasswordView', 'password_view_test.js'], ['PasswordsExportDialog', 'passwords_export_dialog_test.js'],
diff --git a/chrome/test/data/webui/settings/file_system_site_entry_item_tests.ts b/chrome/test/data/webui/settings/file_system_site_entry_item_tests.ts new file mode 100644 index 0000000..bcc2070 --- /dev/null +++ b/chrome/test/data/webui/settings/file_system_site_entry_item_tests.ts
@@ -0,0 +1,73 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// clang-format off +import 'chrome://settings/lazy_load.js'; + +import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; +import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {FileSystemGrant, FileSystemSiteEntryItemElement} from 'chrome://settings/lazy_load.js'; +import {CrSettingsPrefs} from 'chrome://settings/settings.js'; +import {assertTrue} from 'chrome://webui-test/chai_assert.js'; + +// clang-format on + +suite( + 'FileSystemSettings_EnablePersistentPermissions_SiteEntryItem_DirGrant', + function() { + let testElement: FileSystemSiteEntryItemElement; + const origin: string = 'https://a.com/'; + const directoryFilePath: string = 'a/'; + const TEST_FILE_SYSTEM_DIRECTORY_GRANT: FileSystemGrant = { + origin: origin, + filePath: directoryFilePath, + displayName: directoryFilePath, + isDirectory: true, + }; + const filePath: string = 'a/b'; + const TEST_FILE_SYSTEM_FILE_GRANT: FileSystemGrant = { + origin: origin, + filePath: filePath, + displayName: filePath, + isDirectory: false, + }; + + suiteSetup(function() { + CrSettingsPrefs.setInitialized(); + + loadTimeData.overrideValues({ + showPersistentPermissions: true, + }); + }); + + // Initialize the file-system-site-entry-item element for a directory + // grant. + setup(function() { + document.body.innerHTML = window.trustedTypes!.emptyHTML; + testElement = document.createElement('file-system-site-entry-item'); + document.body.appendChild(testElement); + }); + + test('FileSystemSiteListEntryItemsPopulated', function() { + testElement.grant = TEST_FILE_SYSTEM_DIRECTORY_GRANT; + flush(); + const directoryGrantDisplayName = + testElement.shadowRoot!.querySelector('.display-name'); + assertTrue(!!directoryGrantDisplayName); + const icon = testElement.shadowRoot!.querySelector('cr-icon-button'); + assertTrue(!!icon); + assertTrue(icon.classList.contains('icon-folder-open')); + }); + + test('FileSystemSiteListEntryItemsPopulated', function() { + testElement.grant = TEST_FILE_SYSTEM_FILE_GRANT; + flush(); + const fileGrantDisplayName = + testElement.shadowRoot!.querySelector('.display-name'); + assertTrue(!!fileGrantDisplayName); + const icon = testElement.shadowRoot!.querySelector('cr-icon-button'); + assertTrue(!!icon); + assertTrue(icon.classList.contains('icon-file')); + }); + });
diff --git a/chrome/test/data/webui/settings/file_system_site_entry_tests.ts b/chrome/test/data/webui/settings/file_system_site_entry_tests.ts new file mode 100644 index 0000000..12fc9ac --- /dev/null +++ b/chrome/test/data/webui/settings/file_system_site_entry_tests.ts
@@ -0,0 +1,102 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// clang-format off +import 'chrome://settings/lazy_load.js'; + +import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; +import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {FileSystemGrant, FileSystemSiteEntryElement, OriginFileSystemGrants} from 'chrome://settings/lazy_load.js'; +import {CrSettingsPrefs} from 'chrome://settings/settings.js'; +import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js'; + +// clang-format on +suite('FileSystemSettings_EnablePersistentPermissions', function() { + let testElement: FileSystemSiteEntryElement; + + suiteSetup(function() { + CrSettingsPrefs.setInitialized(); + + loadTimeData.overrideValues({ + showPersistentPermissions: true, + }); + }); + + // Initialize the file-system-site-list element. + setup(function() { + document.body.innerHTML = window.trustedTypes!.emptyHTML; + testElement = new FileSystemSiteEntryElement(); + document.body.appendChild(testElement); + }); + + test('FileSystemSiteListEntriesPopulated', function() { + const origin: string = 'https://a.com/'; + const filePath1: string = 'a/b'; + const filePath2: string = 'a/b/c'; + const filePath3: string = 'e/f'; + const directoryFilePath1: string = 'g/h/'; + const directoryFilePath2: string = 'i/'; + + const TEST_FILE_SYSTEM_FILE_WRITE_GRANT1: FileSystemGrant = { + origin: origin, + filePath: filePath1, + displayName: filePath1, + isDirectory: false, + }; + const TEST_FILE_SYSTEM_FILE_WRITE_GRANT2: FileSystemGrant = { + origin: origin, + filePath: filePath2, + displayName: filePath2, + isDirectory: false, + }; + const TEST_FILE_SYSTEM_FILE_READ_GRANT: FileSystemGrant = { + origin: origin, + filePath: filePath3, + displayName: filePath3, + isDirectory: false, + }; + const TEST_FILE_SYSTEM_DIRECTORY_READ_GRANT: FileSystemGrant = { + origin: origin, + filePath: directoryFilePath1, + displayName: directoryFilePath1, + isDirectory: true, + }; + const TEST_FILE_SYSTEM_DIRECTORY_WRITE_GRANT: FileSystemGrant = { + origin: origin, + filePath: directoryFilePath2, + displayName: directoryFilePath2, + isDirectory: true, + }; + const TEST_FILE_SYSTEM_GRANTS_PER_ORIGIN: OriginFileSystemGrants = { + origin: origin, + viewGrants: [ + TEST_FILE_SYSTEM_DIRECTORY_READ_GRANT, + TEST_FILE_SYSTEM_FILE_READ_GRANT, + ], + editGrants: [ + TEST_FILE_SYSTEM_DIRECTORY_WRITE_GRANT, + TEST_FILE_SYSTEM_FILE_WRITE_GRANT1, + TEST_FILE_SYSTEM_FILE_WRITE_GRANT2, + ], + }; + testElement.grantsPerOrigin = TEST_FILE_SYSTEM_GRANTS_PER_ORIGIN; + flush(); + + // The dropdown button opens the dropdown list. + testElement.$.dropdownButton.click(); + const collapseChild = testElement.$.collapseChild; + + assertTrue(collapseChild!.opened); + flush(); + + // Ensure that the `collapseChild` element is populated as expected. + assertEquals( + 5, + collapseChild!.querySelectorAll('file-system-site-entry-item').length); + + // The dropdown button closes the dropdown list if tapped when opened. + testElement.$.dropdownButton.click(); + assertFalse(collapseChild!.opened); + }); +});
diff --git a/chrome/test/data/webui/settings/file_system_site_list_tests.ts b/chrome/test/data/webui/settings/file_system_site_list_tests.ts index 6c09ff6..af8322188 100644 --- a/chrome/test/data/webui/settings/file_system_site_list_tests.ts +++ b/chrome/test/data/webui/settings/file_system_site_list_tests.ts
@@ -3,7 +3,7 @@ // found in the LICENSE file. // clang-format off -import 'chrome://settings/settings.js'; +import 'chrome://settings/lazy_load.js'; import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; @@ -26,10 +26,6 @@ }); }); - suiteTeardown(function() { - CrSettingsPrefs.resetForTesting(); - }); - // Initialize the file-system-site-list element. setup(function() { document.body.innerHTML = window.trustedTypes!.emptyHTML; @@ -39,40 +35,23 @@ document.body.appendChild(testElement); }); - teardown(function() { - testElement.remove(); - Router.getInstance().resetRouteForTesting(); - }); - function navigateToFileSystemSettingsPage() { Router.getInstance().navigateTo(routes.SITE_SETTINGS_FILE_SYSTEM_WRITE); } test('FileSystemSiteListPopulated', async function() { const origin: string = 'https://a.com/'; + const origin2: string = 'https://b.com/'; const filePath1: string = 'a/b'; const filePath2: string = 'a/b/c'; - const filePath3: string = 'e/f'; const directoryFilePath1: string = 'g/h/'; const directoryFilePath2: string = 'i/'; - const TEST_FILE_SYSTEM_FILE_WRITE_GRANT1: RawFileSystemGrant = { + const TEST_FILE_SYSTEM_DIRECTORY_WRITE_GRANT: RawFileSystemGrant = { origin: origin, - filePath: filePath1, + filePath: directoryFilePath2, isWritable: true, - isDirectory: false, - }; - const TEST_FILE_SYSTEM_FILE_WRITE_GRANT2: RawFileSystemGrant = { - origin: origin, - filePath: filePath2, - isWritable: true, - isDirectory: false, - }; - const TEST_FILE_SYSTEM_FILE_READ_GRANT: RawFileSystemGrant = { - origin: origin, - filePath: filePath3, - isWritable: false, - isDirectory: false, + isDirectory: true, }; const TEST_FILE_SYSTEM_DIRECTORY_READ_GRANT: RawFileSystemGrant = { origin: origin, @@ -80,61 +59,43 @@ isWritable: false, isDirectory: true, }; - const TEST_FILE_SYSTEM_DIRECTORY_WRITE_GRANT: RawFileSystemGrant = { - origin: origin, - filePath: directoryFilePath2, + const TEST_FILE_SYSTEM_FILE_READ_GRANT: RawFileSystemGrant = { + origin: origin2, + filePath: filePath2, + isWritable: false, + isDirectory: false, + }; + const TEST_FILE_SYSTEM_FILE_WRITE_GRANT: RawFileSystemGrant = { + origin: origin2, + filePath: filePath1, isWritable: true, - isDirectory: true, + isDirectory: false, }; - browserProxy.setFileSystemGrants([{ - origin: origin, - directoryReadGrants: [TEST_FILE_SYSTEM_DIRECTORY_READ_GRANT], - directoryWriteGrants: [TEST_FILE_SYSTEM_DIRECTORY_WRITE_GRANT], - fileReadGrants: [TEST_FILE_SYSTEM_FILE_READ_GRANT], - fileWriteGrants: [ - TEST_FILE_SYSTEM_FILE_WRITE_GRANT1, - TEST_FILE_SYSTEM_FILE_WRITE_GRANT2, - ], - }]); - - // File paths listed in the order that they are displayed on the UI: - // (For all grants listed in the ordering below, are in the order they - // are listed in `setFileSystemGrants` above). - // File write grants -> directory write grants -> file read grants -> - // directory read grants. - const allFilePathsInDisplayOrder: string[] = [ - filePath1, - filePath2, - directoryFilePath2, - filePath3, - directoryFilePath1, - ]; + browserProxy.setFileSystemGrants([ + { + origin: origin, + directoryReadGrants: [TEST_FILE_SYSTEM_DIRECTORY_READ_GRANT], + directoryWriteGrants: [TEST_FILE_SYSTEM_DIRECTORY_WRITE_GRANT], + fileReadGrants: [], + fileWriteGrants: [], + }, + { + origin: origin2, + directoryReadGrants: [], + directoryWriteGrants: [], + fileReadGrants: [TEST_FILE_SYSTEM_FILE_READ_GRANT], + fileWriteGrants: [TEST_FILE_SYSTEM_FILE_WRITE_GRANT], + }, + ]); navigateToFileSystemSettingsPage(); await browserProxy.whenCalled('getFileSystemGrants'); flush(); // Ensure that the list container element is populated. - // The number of h2 elements displayed on the page equals the number of - // origins with allowed permission grants. - const fileSystemOriginsWithAllowedGrants = - testElement.shadowRoot!.querySelectorAll('h2'); - assertEquals(1, fileSystemOriginsWithAllowedGrants.length); - - // The number of elements with the `display-name` class attribute - // equals the number of file paths associated with an - // allowed permission grant for a given origin. - const fileSystemAllowedGrants = - testElement.shadowRoot!.querySelectorAll('div.display-name'); - assertEquals( - allFilePathsInDisplayOrder.length, fileSystemAllowedGrants.length); - - // The values of the data displayed on the page are as expected. - for (let i = 0; i < fileSystemAllowedGrants.length; i++) { - assertEquals( - allFilePathsInDisplayOrder[i], - fileSystemAllowedGrants[i]!.textContent); - } + const fileSystemSiteEntries = + testElement.shadowRoot!.querySelectorAll('file-system-site-entry'); + assertEquals(2, fileSystemSiteEntries.length); }); }); \ No newline at end of file
diff --git a/chrome/test/media_router/media_router_cast_ui_for_test.cc b/chrome/test/media_router/media_router_cast_ui_for_test.cc index 23fd9d2..d3ee244 100644 --- a/chrome/test/media_router/media_router_cast_ui_for_test.cc +++ b/chrome/test/media_router/media_router_cast_ui_for_test.cc
@@ -166,24 +166,23 @@ return; } - const std::vector<CastDialogSinkButton*>& sink_buttons = - dialog_view->sink_buttons_for_test(); + const std::vector<raw_ptr<CastDialogSinkView>>& sink_views = + dialog_view->sink_views_for_test(); if (base::ranges::any_of( - sink_buttons, [&, this](CastDialogSinkButton* sink_button) { + sink_views, [&, this](CastDialogSinkView* sink_view) { switch (watch_type_) { case WatchType::kSink: - return sink_button->sink().friendly_name == + return sink_view->sink().friendly_name == base::UTF8ToUTF16(*watch_sink_name_); case WatchType::kSinkAvailable: - return sink_button->sink().friendly_name == + return sink_view->sink().friendly_name == base::UTF8ToUTF16(*watch_sink_name_) && - sink_button->sink().state == - UIMediaSinkState::AVAILABLE && - sink_button->GetEnabled(); + sink_view->sink().state == UIMediaSinkState::AVAILABLE && + sink_view->GetEnabled(); case WatchType::kAnyIssue: - return sink_button->sink().issue.has_value(); + return sink_view->sink().issue.has_value(); case WatchType::kAnyRoute: - return sink_button->sink().route.has_value(); + return sink_view->sink().route.has_value(); case WatchType::kNone: case WatchType::kDialogShown: case WatchType::kDialogHidden: @@ -214,9 +213,9 @@ const std::string& sink_name) const { const CastDialogView* dialog_view = GetDialogView(); CHECK(dialog_view); - const std::vector<CastDialogSinkButton*>& sink_buttons = - dialog_view->sink_buttons_for_test(); - return GetSinkButtonWithName(sink_buttons, sink_name); + const std::vector<raw_ptr<CastDialogSinkView>>& sink_views = + dialog_view->sink_views_for_test(); + return GetSinkButtonWithName(sink_views, sink_name); } void MediaRouterCastUiForTest::ObserveDialog(
diff --git a/chrome/test/media_router/media_router_ui_for_test_base.cc b/chrome/test/media_router/media_router_ui_for_test_base.cc index 6ddabe2..0035180 100644 --- a/chrome/test/media_router/media_router_ui_for_test_base.cc +++ b/chrome/test/media_router/media_router_ui_for_test_base.cc
@@ -60,17 +60,17 @@ // static CastDialogSinkButton* MediaRouterUiForTestBase::GetSinkButtonWithName( - const std::vector<CastDialogSinkButton*>& sink_buttons, + const std::vector<raw_ptr<CastDialogSinkView>>& sink_views, const std::string& sink_name) { - auto it = base::ranges::find(sink_buttons, base::UTF8ToUTF16(sink_name), - [](CastDialogSinkButton* sink_button) { - return sink_button->sink().friendly_name; + auto it = base::ranges::find(sink_views, base::UTF8ToUTF16(sink_name), + [](CastDialogSinkView* sink_view) { + return sink_view->sink().friendly_name; }); - if (it == sink_buttons.end()) { - NOTREACHED() << "Sink button not found for sink: " << sink_name; + if (it == sink_views.end()) { + NOTREACHED() << "Sink view not found for sink: " << sink_name; return nullptr; } else { - return *it; + return it->get()->cast_sink_button_for_test(); } }
diff --git a/chrome/test/media_router/media_router_ui_for_test_base.h b/chrome/test/media_router/media_router_ui_for_test_base.h index 39fe152ef..490ca53a 100644 --- a/chrome/test/media_router/media_router_ui_for_test_base.h +++ b/chrome/test/media_router/media_router_ui_for_test_base.h
@@ -83,7 +83,7 @@ void StopCasting(views::View* sink_button); static CastDialogSinkButton* GetSinkButtonWithName( - const std::vector<CastDialogSinkButton*>& sink_buttons, + const std::vector<raw_ptr<CastDialogSinkView>>& sink_buttons, const std::string& sink_name); virtual views::View* GetSinkButton(const std::string& sink_name) const = 0;
diff --git a/chrome/test/webapps/coverage/coverage_cros.tsv b/chrome/test/webapps/coverage/coverage_cros.tsv index bfd9c64..1c1a77f8 100644 --- a/chrome/test/webapps/coverage/coverage_cros.tsv +++ b/chrome/test/webapps/coverage/coverage_cros.tsv
@@ -385,7 +385,6 @@ install_omnibox_icon_Standalone🌕 navigate_pwa_Standalone_MinimalUi🌕 open_in_chrome🌕 check_tab_created_One🌕 install_menu_option_Standalone🌕 navigate_pwa_Standalone_MinimalUi🌕 open_in_chrome🌕 check_tab_created_One🌕 create_shortcut_Standalone_Browser🌕 switch_profile_clients_Client2🌕 launch_from_chrome_apps_Standalone🌓 check_tab_created_One🌕 -create_shortcut_Standalone_Browser🌕 switch_profile_clients_Client2🌕 launch_from_platform_shortcut_Standalone🌑 check_tab_created_One🌑 create_shortcut_Standalone_Windowed🌕 switch_profile_clients_Client2🌕 uninstall_from_list_Standalone🌕 check_app_not_in_list_Standalone🌓 create_shortcut_Standalone_Browser🌕 switch_profile_clients_Client2🌕 uninstall_from_list_Standalone🌕 check_app_not_in_list_Standalone🌓 install_omnibox_icon_Standalone🌕 switch_profile_clients_Client2🌕 uninstall_from_list_Standalone🌕 check_app_not_in_list_Standalone🌓
diff --git a/chrome/test/webapps/coverage/coverage_linux.tsv b/chrome/test/webapps/coverage/coverage_linux.tsv index 0f4b70a4..63313f5e6 100644 --- a/chrome/test/webapps/coverage/coverage_linux.tsv +++ b/chrome/test/webapps/coverage/coverage_linux.tsv
@@ -688,15 +688,11 @@ install_menu_option_Standalone🌕 switch_profile_clients_Client2🌕 install_locally_Standalone🌓 launch_from_chrome_apps_Standalone🌓 check_window_created🌕 install_menu_option_Standalone🌕 switch_profile_clients_Client2🌕 install_locally_Standalone🌓 launch_from_platform_shortcut_Standalone🌓 check_window_created🌕 create_shortcut_Standalone_Browser🌕 switch_profile_clients_Client2🌕 launch_from_chrome_apps_Standalone🌓 check_tab_created_One🌕 -create_shortcut_Standalone_Browser🌕 switch_profile_clients_Client2🌕 launch_from_platform_shortcut_Standalone🌓 check_tab_created_One🌕 create_shortcut_Standalone_Browser🌕 switch_profile_clients_Client2🌕 install_locally_Standalone🌓 launch_from_chrome_apps_Standalone🌓 check_tab_created_One🌕 create_shortcut_Standalone_Browser🌕 switch_profile_clients_Client2🌕 install_locally_Standalone🌓 launch_from_platform_shortcut_Standalone🌓 check_tab_created_One🌕 create_shortcut_Standalone_Windowed🌕 switch_profile_clients_Client2🌕 launch_from_chrome_apps_Standalone🌓 check_tab_created_One🌕 -create_shortcut_Standalone_Windowed🌕 switch_profile_clients_Client2🌕 launch_from_platform_shortcut_Standalone🌓 check_tab_created_One🌕 install_omnibox_icon_Standalone🌕 switch_profile_clients_Client2🌕 launch_from_chrome_apps_Standalone🌓 check_tab_created_One🌕 -install_omnibox_icon_Standalone🌕 switch_profile_clients_Client2🌕 launch_from_platform_shortcut_Standalone🌓 check_tab_created_One🌕 install_menu_option_Standalone🌕 switch_profile_clients_Client2🌕 launch_from_chrome_apps_Standalone🌓 check_tab_created_One🌕 -install_menu_option_Standalone🌕 switch_profile_clients_Client2🌕 launch_from_platform_shortcut_Standalone🌓 check_tab_created_One🌕 create_shortcut_Standalone_Windowed🌕 switch_profile_clients_Client2🌕 uninstall_from_list_Standalone🌕 check_app_not_in_list_Standalone🌕 create_shortcut_Standalone_Browser🌕 switch_profile_clients_Client2🌕 uninstall_from_list_Standalone🌕 check_app_not_in_list_Standalone🌕 install_omnibox_icon_Standalone🌕 switch_profile_clients_Client2🌕 uninstall_from_list_Standalone🌕 check_app_not_in_list_Standalone🌕
diff --git a/chrome/test/webapps/coverage/coverage_mac.tsv b/chrome/test/webapps/coverage/coverage_mac.tsv index 7a106cd..7e70764 100644 --- a/chrome/test/webapps/coverage/coverage_mac.tsv +++ b/chrome/test/webapps/coverage/coverage_mac.tsv
@@ -694,15 +694,11 @@ install_menu_option_Standalone🌕 switch_profile_clients_Client2🌕 install_locally_Standalone🌓 launch_from_chrome_apps_Standalone🌓 check_window_created🌕 install_menu_option_Standalone🌕 switch_profile_clients_Client2🌕 install_locally_Standalone🌓 launch_from_platform_shortcut_Standalone🌑 check_window_created🌑 create_shortcut_Standalone_Browser🌕 switch_profile_clients_Client2🌕 launch_from_chrome_apps_Standalone🌓 check_tab_created_One🌕 -create_shortcut_Standalone_Browser🌕 switch_profile_clients_Client2🌕 launch_from_platform_shortcut_Standalone🌑 check_tab_created_One🌑 create_shortcut_Standalone_Browser🌕 switch_profile_clients_Client2🌕 install_locally_Standalone🌓 launch_from_chrome_apps_Standalone🌓 check_tab_created_One🌕 create_shortcut_Standalone_Browser🌕 switch_profile_clients_Client2🌕 install_locally_Standalone🌓 launch_from_platform_shortcut_Standalone🌑 check_tab_created_One🌑 create_shortcut_Standalone_Windowed🌕 switch_profile_clients_Client2🌕 launch_from_chrome_apps_Standalone🌓 check_tab_created_One🌕 -create_shortcut_Standalone_Windowed🌕 switch_profile_clients_Client2🌕 launch_from_platform_shortcut_Standalone🌑 check_tab_created_One🌑 install_omnibox_icon_Standalone🌕 switch_profile_clients_Client2🌕 launch_from_chrome_apps_Standalone🌓 check_tab_created_One🌕 -install_omnibox_icon_Standalone🌕 switch_profile_clients_Client2🌕 launch_from_platform_shortcut_Standalone🌑 check_tab_created_One🌑 install_menu_option_Standalone🌕 switch_profile_clients_Client2🌕 launch_from_chrome_apps_Standalone🌓 check_tab_created_One🌕 -install_menu_option_Standalone🌕 switch_profile_clients_Client2🌕 launch_from_platform_shortcut_Standalone🌑 check_tab_created_One🌑 create_shortcut_Standalone_Windowed🌕 switch_profile_clients_Client2🌕 uninstall_from_list_Standalone🌕 check_app_not_in_list_Standalone🌕 create_shortcut_Standalone_Browser🌕 switch_profile_clients_Client2🌕 uninstall_from_list_Standalone🌕 check_app_not_in_list_Standalone🌕 install_omnibox_icon_Standalone🌕 switch_profile_clients_Client2🌕 uninstall_from_list_Standalone🌕 check_app_not_in_list_Standalone🌕
diff --git a/chrome/test/webapps/coverage/coverage_win.tsv b/chrome/test/webapps/coverage/coverage_win.tsv index 93acf718..254481e 100644 --- a/chrome/test/webapps/coverage/coverage_win.tsv +++ b/chrome/test/webapps/coverage/coverage_win.tsv
@@ -688,15 +688,11 @@ install_menu_option_Standalone🌕 switch_profile_clients_Client2🌕 install_locally_Standalone🌓 launch_from_chrome_apps_Standalone🌓 check_window_created🌕 install_menu_option_Standalone🌕 switch_profile_clients_Client2🌕 install_locally_Standalone🌓 launch_from_platform_shortcut_Standalone🌓 check_window_created🌕 create_shortcut_Standalone_Browser🌕 switch_profile_clients_Client2🌕 launch_from_chrome_apps_Standalone🌓 check_tab_created_One🌕 -create_shortcut_Standalone_Browser🌕 switch_profile_clients_Client2🌕 launch_from_platform_shortcut_Standalone🌓 check_tab_created_One🌕 create_shortcut_Standalone_Browser🌕 switch_profile_clients_Client2🌕 install_locally_Standalone🌓 launch_from_chrome_apps_Standalone🌓 check_tab_created_One🌕 create_shortcut_Standalone_Browser🌕 switch_profile_clients_Client2🌕 install_locally_Standalone🌓 launch_from_platform_shortcut_Standalone🌓 check_tab_created_One🌕 create_shortcut_Standalone_Windowed🌕 switch_profile_clients_Client2🌕 launch_from_chrome_apps_Standalone🌓 check_tab_created_One🌕 -create_shortcut_Standalone_Windowed🌕 switch_profile_clients_Client2🌕 launch_from_platform_shortcut_Standalone🌓 check_tab_created_One🌕 install_omnibox_icon_Standalone🌕 switch_profile_clients_Client2🌕 launch_from_chrome_apps_Standalone🌓 check_tab_created_One🌕 -install_omnibox_icon_Standalone🌕 switch_profile_clients_Client2🌕 launch_from_platform_shortcut_Standalone🌓 check_tab_created_One🌕 install_menu_option_Standalone🌕 switch_profile_clients_Client2🌕 launch_from_chrome_apps_Standalone🌓 check_tab_created_One🌕 -install_menu_option_Standalone🌕 switch_profile_clients_Client2🌕 launch_from_platform_shortcut_Standalone🌓 check_tab_created_One🌕 create_shortcut_Standalone_Windowed🌕 switch_profile_clients_Client2🌕 uninstall_from_list_Standalone🌕 check_app_not_in_list_Standalone🌕 create_shortcut_Standalone_Browser🌕 switch_profile_clients_Client2🌕 uninstall_from_list_Standalone🌕 check_app_not_in_list_Standalone🌕 install_omnibox_icon_Standalone🌕 switch_profile_clients_Client2🌕 uninstall_from_list_Standalone🌕 check_app_not_in_list_Standalone🌕
diff --git a/chrome/test/webapps/data/critical_user_journeys.md b/chrome/test/webapps/data/critical_user_journeys.md index 67aa5b83..93f924c 100644 --- a/chrome/test/webapps/data/critical_user_journeys.md +++ b/chrome/test/webapps/data/critical_user_journeys.md
@@ -168,9 +168,9 @@ | WML | install_or_shortcut_by_user_windowed(NotPromotable) | switch_profile_clients | install_locally(NotPromotable) | navigate_browser(NotPromotable) | check_launch_icon_shown | | WML | install_or_shortcut_by_user(NotPromotable) | switch_profile_clients | install_locally(NotPromotable) | check_platform_shortcut_and_icon(NotPromotable) | | WML | install_or_shortcut_by_user_windowed | switch_profile_clients | install_locally | launch | check_window_created | -| WMLC | install_or_shortcut_by_user_tabbed | switch_profile_clients | launch_from_shortcut_or_list | check_tab_created(One) | +| WMLC | install_or_shortcut_by_user_tabbed | switch_profile_clients | launch_from_chrome_apps | check_tab_created(One) | | WML | install_or_shortcut_by_user_tabbed | switch_profile_clients | install_locally | launch_from_shortcut_or_list | check_tab_created(One) | -| WML | install_or_shortcut_by_user_windowed | switch_profile_clients | launch_from_shortcut_or_list | check_tab_created(One) | +| WML | install_or_shortcut_by_user_windowed | switch_profile_clients | launch_from_chrome_apps | check_tab_created(One) | | WMLC | install_or_shortcut_by_user | switch_profile_clients | uninstall_from_list | check_app_not_in_list | | WMLC | install_or_shortcut_by_user | switch_profile_clients | uninstall_from_list | switch_profile_clients(Client1) | check_app_not_in_list | | WML | install_or_shortcut_by_user | switch_profile_clients | check_app_in_list_not_locally_installed |
diff --git a/chrome/updater/app/app_server_unittest.cc b/chrome/updater/app/app_server_unittest.cc index fa7928b8..51dd9dd 100644 --- a/chrome/updater/app/app_server_unittest.cc +++ b/chrome/updater/app/app_server_unittest.cc
@@ -27,8 +27,6 @@ using testing::Invoke; using testing::Return; -// TODO(crbug.com/1281935): Fix these test cases to work for mac. -#if !BUILDFLAG(IS_MAC) namespace updater { namespace { @@ -74,7 +72,15 @@ class AppServerTestCase : public testing::Test { public: - void SetUp() override { ClearPrefs(); } + void SetUp() override { +// TODO(crbug.com/1428653): Fix these test cases to work for mac system scope. +#if BUILDFLAG(IS_MAC) + if (GetTestScope() == UpdaterScope::kSystem) { + GTEST_SKIP(); + } +#endif // BUILDFLAG(IS_MAC) + ClearPrefs(); + } private: base::test::TaskEnvironment environment_; @@ -239,4 +245,3 @@ } } // namespace updater -#endif // !BUILDFLAG(IS_MAC)
diff --git a/chrome/updater/crash_reporter.cc b/chrome/updater/crash_reporter.cc index 285758be..918aae3 100644 --- a/chrome/updater/crash_reporter.cc +++ b/chrome/updater/crash_reporter.cc
@@ -22,12 +22,14 @@ #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" #include "chrome/updater/constants.h" +#include "chrome/updater/external_constants.h" #include "chrome/updater/updater_branding.h" #include "chrome/updater/updater_scope.h" #include "chrome/updater/util/util.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/crashpad/crashpad/client/crashpad_client.h" #include "third_party/crashpad/crashpad/handler/handler_main.h" +#include "url/gurl.h" namespace updater { namespace { @@ -86,11 +88,13 @@ annotations["prod"] = CRASH_PRODUCT_NAME; crashpad::CrashpadClient& client = GetCrashpadClient(); - if (!client.StartHandler(handler_path, *database_path, - /*metrics_dir=*/base::FilePath(), CRASH_UPLOAD_URL, - annotations, MakeCrashHandlerArgs(updater_scope), - /*restartable=*/true, - /*asynchronous_start=*/false)) { + if (!client.StartHandler( + handler_path, *database_path, + /*metrics_dir=*/base::FilePath(), + CreateExternalConstants()->CrashUploadURL().possibly_invalid_spec(), + annotations, MakeCrashHandlerArgs(updater_scope), + /*restartable=*/true, + /*asynchronous_start=*/false)) { VLOG(1) << "Failed to start handler."; return; }
diff --git a/chrome/updater/test/integration_test_commands.h b/chrome/updater/test/integration_test_commands.h index e3f27820..66f125c6 100644 --- a/chrome/updater/test/integration_test_commands.h +++ b/chrome/updater/test/integration_test_commands.h
@@ -28,7 +28,9 @@ class IntegrationTestCommands : public base::RefCountedThreadSafe<IntegrationTestCommands> { public: - virtual void EnterTestMode(const GURL& url) const = 0; + virtual void EnterTestMode(const GURL& update_url, + const GURL& crash_upload_url, + const GURL& device_management_url) const = 0; virtual void ExitTestMode() const = 0; virtual void SetGroupPolicies(const base::Value::Dict& values) const = 0; virtual void Clean() const = 0; @@ -81,6 +83,7 @@ virtual void RunWake(int exit_code) const = 0; virtual void RunWakeAll() const = 0; virtual void RunWakeActive(int exit_code) const = 0; + virtual void RunCrashMe() const = 0; virtual void CheckForUpdate(const std::string& app_id) const = 0; virtual void Update(const std::string& app_id,
diff --git a/chrome/updater/test/integration_test_commands_system.cc b/chrome/updater/test/integration_test_commands_system.cc index dcc338a..1e4c6d2 100644 --- a/chrome/updater/test/integration_test_commands_system.cc +++ b/chrome/updater/test/integration_test_commands_system.cc
@@ -86,8 +86,13 @@ RunCommand("expect_candidate_uninstalled"); } - void EnterTestMode(const GURL& url) const override { - RunCommand("enter_test_mode", {Param("url", url.spec())}); + void EnterTestMode(const GURL& update_url, + const GURL& crash_upload_url, + const GURL& device_management_url) const override { + RunCommand("enter_test_mode", + {Param("update_url", update_url.spec()), + Param("crash_upload_url", crash_upload_url.spec()), + Param("device_management_url", device_management_url.spec())}); } void ExitTestMode() const override { RunCommand("exit_test_mode"); } @@ -211,6 +216,8 @@ {Param("exit_code", base::NumberToString(expected_exit_code))}); } + void RunCrashMe() const override { RunCommand("run_crash_me", {}); } + void CheckForUpdate(const std::string& app_id) const override { RunCommand("check_for_update", {Param("app_id", app_id)}); }
diff --git a/chrome/updater/test/integration_test_commands_user.cc b/chrome/updater/test/integration_test_commands_user.cc index 020fbfd..a9e3c96 100644 --- a/chrome/updater/test/integration_test_commands_user.cc +++ b/chrome/updater/test/integration_test_commands_user.cc
@@ -65,8 +65,11 @@ updater::test::ExpectCandidateUninstalled(updater_scope_); } - void EnterTestMode(const GURL& url) const override { - updater::test::EnterTestMode(url); + void EnterTestMode(const GURL& update_url, + const GURL& crash_upload_url, + const GURL& device_management_url) const override { + updater::test::EnterTestMode(update_url, crash_upload_url, + device_management_url); } void ExitTestMode() const override { @@ -186,6 +189,10 @@ updater::test::RunWakeAll(updater_scope_); } + void RunCrashMe() const override { + updater::test::RunCrashMe(updater_scope_); + } + void RunWakeActive(int exit_code) const override { updater::test::RunWakeActive(updater_scope_, exit_code); }
diff --git a/chrome/updater/test/integration_tests.cc b/chrome/updater/test/integration_tests.cc index 3254cdd..a5df9da 100644 --- a/chrome/updater/test/integration_tests.cc +++ b/chrome/updater/test/integration_tests.cc
@@ -6,6 +6,7 @@ #include <memory> #include <string> +#include "base/files/file_enumerator.h" #include "base/files/file_path.h" #include "base/functional/bind.h" #include "base/functional/callback_helpers.h" @@ -30,8 +31,10 @@ #include "chrome/updater/test/server.h" #include "chrome/updater/test_scope.h" #include "chrome/updater/update_service.h" +#include "chrome/updater/updater_branding.h" #include "chrome/updater/updater_version.h" #include "chrome/updater/util/unittest_util.h" +#include "chrome/updater/util/util.h" #include "testing/gtest/include/gtest/gtest.h" #include "url/gurl.h" @@ -100,7 +103,9 @@ ASSERT_NO_FATAL_FAILURE(ExpectClean()); // TODO(crbug.com/1233612) - reenable the code when system tests pass. // SetUpTestService(); - ASSERT_NO_FATAL_FAILURE(EnterTestMode(GURL("http://localhost:1234"))); + ASSERT_NO_FATAL_FAILURE(EnterTestMode(GURL("http://localhost:1234"), + GURL("http://localhost:1235"), + GURL("http://localhost:1236"))); #endif #if BUILDFLAG(IS_LINUX) // On LUCI the XDG_RUNTIME_DIR and DBUS_SESSION_BUS_ADDRESS environment @@ -172,7 +177,12 @@ void ExpectClean() { test_commands_->ExpectClean(); } - void EnterTestMode(const GURL& url) { test_commands_->EnterTestMode(url); } + void EnterTestMode(const GURL& update_url, + const GURL& crash_upload_url, + const GURL& device_management_url) { + test_commands_->EnterTestMode(update_url, crash_upload_url, + device_management_url); + } void ExitTestMode() { test_commands_->ExitTestMode(); } @@ -296,6 +306,8 @@ test_commands_->RunWakeAll(); } + void RunCrashMe() { test_commands_->RunCrashMe(); } + void RunWakeActive(int exit_code) { ASSERT_TRUE(WaitForUpdaterExit()); test_commands_->RunWakeActive(exit_code); @@ -1137,6 +1149,50 @@ ASSERT_NO_FATAL_FAILURE(Uninstall()); } +TEST_F(IntegrationTest, CrashUsageStatsEnabled) { +#if BUILDFLAG(IS_WIN) && defined(ADDRESS_SANITIZER) + GTEST_SKIP() << "Crash tests disabled for Win ASAN."; +#else + ScopedServer test_server(test_commands_); + ASSERT_NO_FATAL_FAILURE(Install()); + ASSERT_NO_FATAL_FAILURE(ExpectInstalled()); + ASSERT_TRUE(WaitForUpdaterExit()); + + const std::string response; + + // TODO(crbug.com/1430233): Add a predicate to verify the crash report + // contents. This is blocked by crbug.com/1430878. + test_server.ExpectOnce( + {GetRequestPathPredicate( + base::StringPrintf(R"(%s\?product=%s&version=%s&guid=.*)", + test_server.crash_report_path().c_str(), + CRASH_PRODUCT_NAME, kUpdaterVersion)), + GetRequestHeaderPredicate("User-Agent", R"(Crashpad/.*)"), + GetRequestHeaderPredicate( + "Content-Type", + R"(multipart/form-data; boundary=---MultipartBoundary.*---)")}, + response); + ExpectUninstallPing(&test_server); + RunCrashMe(); + ASSERT_TRUE(WaitForUpdaterExit()); + + // Delete the dmp files generated by this test, so `ExpectNoCrashes` won't + // complain at TearDown. + absl::optional<base::FilePath> database_path( + GetCrashDatabasePath(GetTestScope())); + if (database_path || base::PathExists(*database_path)) { + base::FileEnumerator it(*database_path, true, base::FileEnumerator::FILES, + FILE_PATH_LITERAL("*.dmp"), + base::FileEnumerator::FolderSearchPolicy::ALL); + for (base::FilePath name = it.Next(); !name.empty(); name = it.Next()) { + VLOG(0) << "Deleting file at: " << name; + EXPECT_TRUE(base::DeleteFile(name)); + } + } + ASSERT_NO_FATAL_FAILURE(Uninstall()); +#endif +} + #if BUILDFLAG(IS_WIN) class IntegrationTestLegacyUpdate3Web : public IntegrationTest { public:
diff --git a/chrome/updater/test/integration_tests_helper.cc b/chrome/updater/test/integration_tests_helper.cc index 49ceb03..e8e0bba 100644 --- a/chrome/updater/test/integration_tests_helper.cc +++ b/chrome/updater/test/integration_tests_helper.cc
@@ -254,7 +254,10 @@ // function (which should be declared in integration_tests_impl.h), and // then use the With* helper functions to provide its arguments. {"clean", WithSystemScope(Wrap(&Clean))}, - {"enter_test_mode", WithSwitch("url", Wrap(&EnterTestMode))}, + {"enter_test_mode", + WithSwitch("device_management_url", + WithSwitch("crash_upload_url", + WithSwitch("update_url", Wrap(&EnterTestMode))))}, {"exit_test_mode", WithSystemScope(Wrap(&ExitTestMode))}, {"set_group_policies", WithSwitch("values", Wrap(&SetGroupPolicies))}, {"fill_log", WithSystemScope(Wrap(&FillLog))}, @@ -313,6 +316,7 @@ {"run_wake_all", WithSystemScope(Wrap(&RunWakeAll))}, {"run_wake_active", WithSwitch("exit_code", WithSystemScope(Wrap(&RunWakeActive)))}, + {"run_crash_me", WithSystemScope(Wrap(&RunCrashMe))}, {"update", WithSwitch("install_data_index", (WithSwitch("app_id", WithSystemScope(Wrap(&Update)))))},
diff --git a/chrome/updater/test/integration_tests_impl.cc b/chrome/updater/test/integration_tests_impl.cc index b58726a..fd646b5 100644 --- a/chrome/updater/test/integration_tests_impl.cc +++ b/chrome/updater/test/integration_tests_impl.cc
@@ -147,80 +147,82 @@ GetHashHex(update_file).c_str()); } -base::RepeatingCallback<bool(const std::string&)> GetScopePredicate( - UpdaterScope scope) { - return base::BindLambdaForTesting([scope](const std::string& request_body) { - const bool is_match = [&scope, &request_body]() { - const absl::optional<base::Value> doc = - base::JSONReader::Read(request_body); - if (!doc || !doc->is_dict()) { - return false; - } - const base::Value::Dict* object_request = - doc->GetDict().FindDict("request"); - if (!object_request) { - return false; - } - absl::optional<bool> ismachine = object_request->FindBool("ismachine"); - if (!ismachine.has_value()) { - return false; - } - switch (scope) { - case UpdaterScope::kSystem: - return *ismachine; - case UpdaterScope::kUser: - return !*ismachine; - } - }(); - if (!is_match) { - ADD_FAILURE() << R"(Request does not match "ismachine": )" - << request_body; - } - return is_match; - }); +ScopedServer::RequestMatcherPredicate GetScopePredicate(UpdaterScope scope) { + return base::BindLambdaForTesting( + [scope](const net::test_server::HttpRequest& request) { + const bool is_match = [&scope, &request]() { + const absl::optional<base::Value> doc = + base::JSONReader::Read(request.content); + if (!doc || !doc->is_dict()) { + return false; + } + const base::Value::Dict* object_request = + doc->GetDict().FindDict("request"); + if (!object_request) { + return false; + } + absl::optional<bool> ismachine = + object_request->FindBool("ismachine"); + if (!ismachine.has_value()) { + return false; + } + switch (scope) { + case UpdaterScope::kSystem: + return *ismachine; + case UpdaterScope::kUser: + return !*ismachine; + } + }(); + if (!is_match) { + ADD_FAILURE() << R"(Request does not match "ismachine": )" + << request.content; + } + return is_match; + }); } -base::RepeatingCallback<bool(const std::string&)> MatchAppPriority( +ScopedServer::RequestMatcherPredicate MatchAppPriority( const std::string& app_id, UpdateService::Priority priority) { - return base::BindLambdaForTesting([app_id, priority]( - const std::string& request_body) { - const bool is_match = [&app_id, priority, &request_body]() { - const absl::optional<base::Value> doc = - base::JSONReader::Read(request_body); - if (!doc || !doc->is_dict()) { - return false; - } - const base::Value::List* app_list = - doc->GetDict().FindListByDottedPath("request.app"); - if (!app_list) { - return false; - } - for (const base::Value& app : *app_list) { - if (const auto* dict = app.GetIfDict()) { - if (const auto* appid = dict->FindString("appid"); *appid == app_id) { - if (const auto* install_source = - dict->FindString("installsource")) { - return (*install_source == "ondemand") == - (priority == UpdateService::Priority::kForeground); + return base::BindLambdaForTesting( + [app_id, priority](const net::test_server::HttpRequest& request) { + const bool is_match = [&app_id, priority, &request]() { + const absl::optional<base::Value> doc = + base::JSONReader::Read(request.content); + if (!doc || !doc->is_dict()) { + return false; + } + const base::Value::List* app_list = + doc->GetDict().FindListByDottedPath("request.app"); + if (!app_list) { + return false; + } + for (const base::Value& app : *app_list) { + if (const auto* dict = app.GetIfDict()) { + if (const auto* appid = dict->FindString("appid"); + *appid == app_id) { + if (const auto* install_source = + dict->FindString("installsource")) { + return (*install_source == "ondemand") == + (priority == UpdateService::Priority::kForeground); + } + } } } + return priority != UpdateService::Priority::kForeground; + }(); + if (!is_match) { + ADD_FAILURE() << R"(Request does not match "appid", "priority: )" + << request.content; } - } - return priority != UpdateService::Priority::kForeground; - }(); - if (!is_match) { - ADD_FAILURE() << R"(Request does not match "ismachine": )" - << request_body; - } - return is_match; - }); + return is_match; + }); } void RunUpdaterWithSwitch(const base::Version& version, UpdaterScope scope, const std::string& command, - int expected_exit_code) { + absl::optional<int> expected_exit_code) { const absl::optional<base::FilePath> installed_executable_path = GetVersionedInstallDirectory(scope, version) ->Append(GetExecutableRelativePath()); @@ -230,7 +232,9 @@ command_line.AppendSwitch(command); int exit_code = -1; Run(scope, command_line, &exit_code); - ASSERT_EQ(exit_code, expected_exit_code); + if (expected_exit_code) { + ASSERT_EQ(exit_code, expected_exit_code.value()); + } } void ExpectUpdateCheckSequence(UpdaterScope scope, @@ -248,18 +252,20 @@ // First request: update check. test_server->ExpectOnce( - {base::BindRepeating( + {GetRequestPathPredicate(test_server->update_path()), + base::BindRepeating( RequestMatcherRegex, base::StringPrintf(R"(.*"appid":"%s".*)", app_id.c_str())), GetScopePredicate(scope), MatchAppPriority(app_id, priority)}, - GetUpdateResponse(app_id, "", test_server->base_url().spec(), to_version, - crx_path, kDoNothingCRXRun, {})); + GetUpdateResponse(app_id, "", test_server->update_url().spec(), + to_version, crx_path, kDoNothingCRXRun, {})); // Second request: event ping with an error because the update check response // is ignored by the client: // {errorCategory::kService, ServiceError::CHECK_FOR_UPDATE_ONLY} test_server->ExpectOnce( - {base::BindRepeating( + {GetRequestPathPredicate(test_server->update_path()), + base::BindRepeating( RequestMatcherRegex, base::StringPrintf(R"(.*"errorcat":4,"errorcode":4,)" R"("eventresult":0,"eventtype":%d,)" @@ -286,7 +292,8 @@ // First request: update check. test_server->ExpectOnce( - {base::BindRepeating( + {GetRequestPathPredicate(test_server->update_path()), + base::BindRepeating( RequestMatcherRegex, base::StringPrintf(R"(.*"appid":"%s".*)", app_id.c_str())), base::BindRepeating( @@ -301,7 +308,7 @@ : "")), GetScopePredicate(scope), MatchAppPriority(app_id, priority)}, GetUpdateResponse(app_id, install_data_index, - test_server->base_url().spec(), to_version, crx_path, + test_server->update_url().spec(), to_version, crx_path, kDoNothingCRXRun, {})); // Second request: update download. @@ -312,7 +319,8 @@ // Third request: event ping. test_server->ExpectOnce( - {base::BindRepeating( + {GetRequestPathPredicate(test_server->update_path()), + base::BindRepeating( RequestMatcherRegex, base::StringPrintf(R"(.*"eventresult":1,"eventtype":%d,)" R"("nextversion":"%s","previousversion":"%s".*)", @@ -324,6 +332,46 @@ } // namespace +ScopedServer::RequestMatcherPredicate GetRequestPathPredicate( + const std::string& expected_path_regex) { + return base::BindLambdaForTesting( + [expected_path_regex](const net::test_server::HttpRequest& request) { + if (!re2::RE2::FullMatch(request.relative_url, expected_path_regex)) { + ADD_FAILURE() << "Request path [" << request.relative_url + << "], did not match expected path regex [" + << expected_path_regex << "]."; + return false; + } + return true; + }); +} + +ScopedServer::RequestMatcherPredicate GetRequestHeaderPredicate( + const std::string& header_name, + const std::string& expected_header_regex) { + return base::BindLambdaForTesting( + [header_name, + expected_header_regex](const net::test_server::HttpRequest& request) { + re2::RE2::Options opt; + opt.set_case_sensitive(false); + net::test_server::HttpRequest::HeaderMap::const_iterator it = + request.headers.find(header_name); + if (it == request.headers.end()) { + ADD_FAILURE() << "Request header '" << header_name + << "' not found, expected regex " + << expected_header_regex; + return false; + } else if (!re2::RE2::FullMatch(it->second, + re2::RE2(expected_header_regex, opt))) { + ADD_FAILURE() << "Request header '" << it->first << "' = '" + << it->second << "', did not match expected regex " + << expected_header_regex; + return false; + } + return true; + }); +} + void ExitTestMode(UpdaterScope scope) { DeleteFileAndEmptyParentDirectories(GetOverrideFilePath(scope)); } @@ -494,6 +542,11 @@ RunUpdaterWithSwitch(active_version, scope, kWakeSwitch, expected_exit_code); } +void RunCrashMe(UpdaterScope scope) { + RunUpdaterWithSwitch(base::Version(kUpdaterVersion), scope, kCrashMeSwitch, + absl::nullopt); +} + void CheckForUpdate(UpdaterScope scope, const std::string& app_id) { scoped_refptr<UpdateService> update_service = CreateUpdateServiceProxy(scope); base::RunLoop loop; @@ -660,13 +713,13 @@ } bool RequestMatcherRegex(const std::string& request_body_regex, - const std::string& request_body) { + const net::test_server::HttpRequest& request) { re2::RE2::Options opt; opt.set_case_sensitive(false); - if (!re2::RE2::PartialMatch(request_body, + if (!re2::RE2::PartialMatch(request.content, re2::RE2(request_body_regex, opt))) { - VLOG(0) << "Request match failed."; - ADD_FAILURE() << "Request with body: " << request_body + VLOG(0) << "Request content match failed."; + ADD_FAILURE() << "Request with body: " << request.content << " did not match expected regex " << request_body_regex; return false; } @@ -675,7 +728,8 @@ void ExpectUninstallPing(UpdaterScope scope, ScopedServer* test_server) { test_server->ExpectOnce( - {base::BindRepeating(RequestMatcherRegex, R"(.*"eventtype":4.*)"), + {GetRequestPathPredicate(test_server->update_path()), + base::BindRepeating(RequestMatcherRegex, R"(.*"eventtype":4.*)"), GetScopePredicate(scope)}, ")]}'\n"); } @@ -688,12 +742,13 @@ // First request: update check. test_server->ExpectOnce( - {base::BindRepeating( + {GetRequestPathPredicate(test_server->update_path()), + base::BindRepeating( RequestMatcherRegex, base::StringPrintf(R"(.*"appid":"%s".*)", kUpdaterAppId)), GetScopePredicate(scope)}, GetUpdateResponse( - kUpdaterAppId, "", test_server->base_url().spec(), + kUpdaterAppId, "", test_server->update_url().spec(), base::Version(kUpdaterVersion), crx_path, kSelfUpdateCRXRun, base::StrCat({"--update", IsSystemInstall(scope) ? " --system" : "", " --", kEnableLoggingSwitch, " --", @@ -708,7 +763,8 @@ // Third request: event ping. test_server->ExpectOnce( - {base::BindRepeating( + {GetRequestPathPredicate(test_server->update_path()), + base::BindRepeating( RequestMatcherRegex, base::StringPrintf(R"(.*"eventresult":1,"eventtype":3,)" R"("nextversion":"%s",.*)",
diff --git a/chrome/updater/test/integration_tests_impl.h b/chrome/updater/test/integration_tests_impl.h index f157d71..624f5fc 100644 --- a/chrome/updater/test/integration_tests_impl.h +++ b/chrome/updater/test/integration_tests_impl.h
@@ -13,6 +13,7 @@ #include "base/files/scoped_temp_dir.h" #include "base/values.h" #include "build/build_config.h" +#include "chrome/updater/test/server.h" #include "chrome/updater/update_service.h" #include "third_party/abseil-cpp/absl/types/optional.h" @@ -24,6 +25,14 @@ class Version; } // namespace base +namespace net { +namespace test_server { + +struct HttpRequest; + +} // namespace test_server +} // namespace net + namespace updater { enum class UpdaterScope; } // namespace updater @@ -35,8 +44,6 @@ kCreateInstalledApp = 1, }; -class ScopedServer; - // Returns the path to the updater installer program (in the build output // directory). This is typically the updater setup, or the updater itself for // the platforms where a setup program is not provided. @@ -64,9 +71,10 @@ // test. void ExpectClean(UpdaterScope scope); -// Places the updater into test mode (use `url` as the update server and disable -// CUP). -void EnterTestMode(const GURL& url); +// Places the updater into test mode (redirect server URLs and disable CUP). +void EnterTestMode(const GURL& update_url, + const GURL& crash_upload_url, + const GURL& device_management_url); // Takes the updater our of the test mode by deleting the external constants // JSON file. @@ -113,6 +121,9 @@ // active, rather than kUpdaterVersion. void RunWakeActive(UpdaterScope scope, int exit_code); +// Starts an updater process with switch `--crash-me`. +void RunCrashMe(UpdaterScope scope); + // Invokes the active instance's UpdateService::Update (via RPC) for an app. void Update(UpdaterScope scope, const std::string& app_id, @@ -189,6 +200,17 @@ [[nodiscard]] bool WaitForUpdaterExit(UpdaterScope scope); +// Returns a predicate which returns true if the `expected_path_regex` fully +// matches the request path. +[[nodiscard]] ScopedServer::RequestMatcherPredicate GetRequestPathPredicate( + const std::string& expected_path_regex); + +// Returns a predicate which returns true if the `expected_header_regex` fully +// matches the specified header in request. +[[nodiscard]] ScopedServer::RequestMatcherPredicate GetRequestHeaderPredicate( + const std::string& header_name, + const std::string& expected_header_regex); + #if BUILDFLAG(IS_WIN) void ExpectInterfacesRegistered(UpdaterScope scope); void ExpectMarshalInterfaceSucceeds(UpdaterScope scope); @@ -221,9 +243,10 @@ // links, or dot dot. int CountDirectoryFiles(const base::FilePath& dir); -// Returns true if the `request_body_regex` partially matches `request_body`. +// Returns true if the `request_body_regex` partially matches the request +// content. [[nodiscard]] bool RequestMatcherRegex(const std::string& request_body_regex, - const std::string& request_body); + const net::test_server::HttpRequest&); void ExpectSelfUpdateSequence(UpdaterScope scope, ScopedServer* test_server);
diff --git a/chrome/updater/test/integration_tests_linux.cc b/chrome/updater/test/integration_tests_linux.cc index 224b2b1..0175b6e3 100644 --- a/chrome/updater/test/integration_tests_linux.cc +++ b/chrome/updater/test/integration_tests_linux.cc
@@ -138,9 +138,13 @@ EXPECT_FALSE(SystemdUnitsInstalled(scope)); } -void EnterTestMode(const GURL& url) { +void EnterTestMode(const GURL& update_url, + const GURL& crash_upload_url, + const GURL& device_management_url) { ASSERT_TRUE(ExternalConstantsBuilder() - .SetUpdateURL({url.spec()}) + .SetUpdateURL({update_url.spec()}) + .SetCrashUploadURL(crash_upload_url.spec()) + .SetDeviceManagementURL(device_management_url.spec()) .SetUseCUP(false) .SetInitialDelay(base::Milliseconds(100)) .SetServerKeepAliveTime(base::Seconds(1))
diff --git a/chrome/updater/test/integration_tests_mac.mm b/chrome/updater/test/integration_tests_mac.mm index 9caf52d..3b2bbac 100644 --- a/chrome/updater/test/integration_tests_mac.mm +++ b/chrome/updater/test/integration_tests_mac.mm
@@ -93,9 +93,13 @@ return GetExecutablePath(); } -void EnterTestMode(const GURL& url) { +void EnterTestMode(const GURL& update_url, + const GURL& crash_upload_url, + const GURL& device_management_url) { ASSERT_TRUE(ExternalConstantsBuilder() - .SetUpdateURL(std::vector<std::string>{url.spec()}) + .SetUpdateURL(std::vector<std::string>{update_url.spec()}) + .SetCrashUploadURL(crash_upload_url.spec()) + .SetDeviceManagementURL(device_management_url.spec()) .SetUseCUP(false) .SetInitialDelay(base::Milliseconds(100)) .SetServerKeepAliveTime(base::Seconds(1))
diff --git a/chrome/updater/test/integration_tests_win.cc b/chrome/updater/test/integration_tests_win.cc index 84379e62..1b4d001 100644 --- a/chrome/updater/test/integration_tests_win.cc +++ b/chrome/updater/test/integration_tests_win.cc
@@ -617,9 +617,13 @@ VLOG(0) << __func__ << " end."; } -void EnterTestMode(const GURL& url) { +void EnterTestMode(const GURL& update_url, + const GURL& crash_upload_url, + const GURL& device_management_url) { ASSERT_TRUE(ExternalConstantsBuilder() - .SetUpdateURL(std::vector<std::string>{url.spec()}) + .SetUpdateURL(std::vector<std::string>{update_url.spec()}) + .SetCrashUploadURL(crash_upload_url.spec()) + .SetDeviceManagementURL(device_management_url.spec()) .SetUseCUP(false) .SetInitialDelay(base::Milliseconds(100)) .SetCrxVerifierFormat(crx_file::VerifierFormat::CRX3)
diff --git a/chrome/updater/test/server.cc b/chrome/updater/test/server.cc index 2e41830..35c08ba 100644 --- a/chrome/updater/test/server.cc +++ b/chrome/updater/test/server.cc
@@ -8,9 +8,12 @@ #include <memory> #include <string> #include <utility> +#include <vector> #include "base/logging.h" #include "base/ranges/algorithm.h" +#include "base/strings/string_util.h" +#include "base/strings/stringprintf.h" #include "chrome/updater/test/integration_test_commands.h" #include "chrome/updater/test/integration_tests_impl.h" #include "net/http/http_status_code.h" @@ -21,6 +24,32 @@ namespace updater { namespace test { +namespace { + +std::string SerializeRequest(const net::test_server::HttpRequest& request) { + std::vector<std::string> request_strs; + + request_strs.push_back("Request:"); + request_strs.push_back( + base::StringPrintf("Path: %s", request.relative_url.c_str())); + request_strs.push_back("Headers: {"); + for (auto& header : request.headers) { + request_strs.push_back(base::StringPrintf( + " %s: %s", header.first.c_str(), header.second.c_str())); + } + request_strs.push_back("}"); + + if (request.has_content) { + request_strs.push_back("Content:"); + request_strs.push_back(request.content); + } else { + request_strs.push_back("Content: <no content>"); + } + + return base::JoinString(request_strs, "\n "); +} + +} // namespace ScopedServer::ScopedServer( scoped_refptr<IntegrationTestCommands> integration_test_commands) @@ -30,16 +59,18 @@ &ScopedServer::HandleRequest, base::Unretained(this))); EXPECT_TRUE((test_server_handle_ = test_server_->StartAndReturnHandle())); - integration_test_commands_->EnterTestMode(test_server_->base_url()); + integration_test_commands_->EnterTestMode(update_url(), crash_upload_url(), + device_management_url()); } ScopedServer::~ScopedServer() { for (const auto& request_matcher : request_matchers_) { // Forces `request_matcher` to log to help debugging, unless the - // predicate matches "..." string in the request. + // predicate matches the empty request. ADD_FAILURE() << "Unmet expectation: "; - base::ranges::for_each( - request_matcher, [](RequestMatcherPredicate pred) { pred.Run("..."); }); + base::ranges::for_each(request_matcher, [](RequestMatcherPredicate pred) { + pred.Run(net::test_server::HttpRequest()); + }); } } @@ -51,20 +82,20 @@ std::unique_ptr<net::test_server::HttpResponse> ScopedServer::HandleRequest( const net::test_server::HttpRequest& request) { - VLOG(0) << "HandleRequest: " << request.content; + VLOG(0) << "Handle " << SerializeRequest(request); auto response = std::make_unique<net::test_server::BasicHttpResponse>(); if (request_matchers_.empty()) { VLOG(0) << "Unexpected request."; - ADD_FAILURE() << "Unexpected request: " << request.content; + ADD_FAILURE() << "Unexpected " << SerializeRequest(request); response->set_code(net::HTTP_INTERNAL_SERVER_ERROR); return response; } if (!base::ranges::all_of(request_matchers_.front(), [&request](RequestMatcherPredicate pred) { - return pred.Run(request.content); + return pred.Run(request); })) { VLOG(0) << "Request did not match."; - ADD_FAILURE() << "Request did not match: " << request.content; + ADD_FAILURE() << "Unmatched " << SerializeRequest(request); response->set_code(net::HTTP_INTERNAL_SERVER_ERROR); return response; }
diff --git a/chrome/updater/test/server.h b/chrome/updater/test/server.h index dc52bac..833e702 100644 --- a/chrome/updater/test/server.h +++ b/chrome/updater/test/server.h
@@ -11,7 +11,6 @@ #include "base/functional/callback_forward.h" #include "base/memory/scoped_refptr.h" -#include "chrome/updater/test/integration_test_commands.h" #include "net/test/embedded_test_server/embedded_test_server.h" class GURL; @@ -28,11 +27,13 @@ namespace updater { namespace test { +class IntegrationTestCommands; + class ScopedServer { public: - // Defines a generic predicate to match expectations for a `request_body`. + // Defines a generic predicate to match expectations for a request. using RequestMatcherPredicate = - base::RepeatingCallback<bool(const std::string& request_body)>; + base::RepeatingCallback<bool(const net::test_server::HttpRequest&)>; // Defines a sequence of predicates which all must pass in order to match // a request. This allows for combining several predicates when matching a @@ -62,7 +63,18 @@ void ExpectOnce(RequestMatcher request_matcher, const std::string& response_body); - const GURL& base_url() const { return test_server_->base_url(); } + std::string update_path() const { return "/update"; } + GURL update_url() const { return test_server_->GetURL(update_path()); } + + std::string crash_report_path() const { return "/crash"; } + GURL crash_upload_url() const { + return test_server_->GetURL(crash_report_path()); + } + + std::string device_management_path() const { return "/dmapi"; } + GURL device_management_url() const { + return test_server_->GetURL(device_management_path()); + } private: std::unique_ptr<net::test_server::HttpResponse> HandleRequest(
diff --git a/chromeos/ash/components/nearby/common/proto/BUILD.gn b/chromeos/ash/components/nearby/common/proto/BUILD.gn new file mode 100644 index 0000000..685d3960 --- /dev/null +++ b/chromeos/ash/components/nearby/common/proto/BUILD.gn
@@ -0,0 +1,16 @@ +# Copyright 2023 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//build/config/chromeos/ui_mode.gni") +import("//third_party/protobuf/proto_library.gni") + +assert(is_chromeos_ash, "Non-Chrome-OS builds must not depend on //ash") + +proto_library("proto") { + proto_in_dir = "//" + sources = [ + "field_mask.proto", + "timestamp.proto", + ] +}
diff --git a/chromeos/ash/components/nearby/common/proto/field_mask.proto b/chromeos/ash/components/nearby/common/proto/field_mask.proto new file mode 100644 index 0000000..5584aa0 --- /dev/null +++ b/chromeos/ash/components/nearby/common/proto/field_mask.proto
@@ -0,0 +1,23 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Keep in sync with +// //third_party/protobuf/src/google/protobuf/field_mask.proto +// Last copied at crrev/c/2545204. + +syntax = "proto3"; + +package ash.nearby.proto; + +option optimize_for = LITE_RUNTIME; + +// //third_party/protobuf/src/google/protobuf/field_mask.proto cannot be +// directly imported to Chrome because it is not in the `protobuf_lite` source +// and the `protobuf_full` source cannot be included in Chrome because of it's +// large size. Therefore, this copies the proto which is small and stable to be +// used across the codebase. +message FieldMask { + // The set of field mask paths. + repeated string paths = 1; +}
diff --git a/chromeos/ash/components/nearby/common/proto/timestamp.proto b/chromeos/ash/components/nearby/common/proto/timestamp.proto new file mode 100644 index 0000000..f29c7e3 --- /dev/null +++ b/chromeos/ash/components/nearby/common/proto/timestamp.proto
@@ -0,0 +1,31 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Keep in sync with +// //third_party/protobuf/src/google/protobuf/field_mask.proto +// Last copied at crrev/c/2545204. + +syntax = "proto3"; + +package ash.nearby.proto; + +option optimize_for = LITE_RUNTIME; + +// //third_party/protobuf/src/google/protobuf/timestamp.proto cannot be +// directly imported to Chrome because it is not in the `protobuf_lite` source +// and the `protobuf_full` source cannot be included in Chrome because of it's +// large size. Therefore, this copies the proto which is small and stable to be +// used across the codebase. +message Timestamp { + // Represents seconds of UTC time since Unix epoch + // 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to + // 9999-12-31T23:59:59Z inclusive. + int64 seconds = 1; + + // Non-negative fractions of a second at nanosecond resolution. Negative + // second values with fractions must still have non-negative nanos values + // that count forward in time. Must be from 0 to 999,999,999 + // inclusive. + int32 nanos = 2; +}
diff --git a/chromeos/ash/components/nearby/presence/BUILD.gn b/chromeos/ash/components/nearby/presence/BUILD.gn index f8fe585..677f767 100644 --- a/chromeos/ash/components/nearby/presence/BUILD.gn +++ b/chromeos/ash/components/nearby/presence/BUILD.gn
@@ -20,6 +20,7 @@ "//ash/public/cpp", "//base", "//chrome/browser/profiles:profile", + "//chromeos/ash/components/nearby/presence/proto", "//components/keyed_service/content:content", "//components/keyed_service/core", "//components/pref_registry:pref_registry",
diff --git a/chromeos/ash/components/nearby/presence/proto/BUILD.gn b/chromeos/ash/components/nearby/presence/proto/BUILD.gn new file mode 100644 index 0000000..53c365f7 --- /dev/null +++ b/chromeos/ash/components/nearby/presence/proto/BUILD.gn
@@ -0,0 +1,19 @@ +# Copyright 2023 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//build/config/chromeos/ui_mode.gni") +import("//third_party/protobuf/proto_library.gni") + +assert(is_chromeos_ash, "Non-Chrome-OS builds must not depend on //ash") + +proto_library("proto") { + proto_in_dir = "//" + sources = [ + "list_public_certificates_rpc.proto", + "rpc_resources.proto", + "update_device_rpc.proto", + ] + + link_deps = [ "//chromeos/ash/components/nearby/common/proto" ] +}
diff --git a/chromeos/ash/components/nearby/presence/proto/list_public_certificates_rpc.proto b/chromeos/ash/components/nearby/presence/proto/list_public_certificates_rpc.proto new file mode 100644 index 0000000..8d2a4fb --- /dev/null +++ b/chromeos/ash/components/nearby/presence/proto/list_public_certificates_rpc.proto
@@ -0,0 +1,47 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Keep in sync with +// http://google3/google/internal/location/nearby/presence/v1/rpcs/certificates.proto +// Messages not used in Chrome have been omitted. Last copied at cl/460540069. + +syntax = "proto3"; + +package ash.nearby.proto; + +option optimize_for = LITE_RUNTIME; + +import "chromeos/ash/components/nearby/presence/proto/rpc_resources.proto"; + +// Request to list public certificate objects. +message ListPublicCertificatesRequest { + // Required. The resource name determines which public certificates to list. + // The special prefix "users/me" lists the requester's own share targets. This + // is of the format "users/*/devices/*". + string parent = 1; + + // Optional limit on the number of ShareTarget objects to check for + // PublicCertificates for the response. Further PublicCertificates items may + // be obtained by including the page_token in a subsequent request. If this is + // not set or zero, a reasonable default value (2000) is used. + int32 page_size = 2; + + // Optional pagination token, returned earlier via + // [ListPublicCertificatesResponse.next_page_token] + string page_token = 3; + + // Optional. Represents certificates already available on local device. + repeated bytes secret_ids = 4; +} + +// Response that contains the public certificates available to calling device. +message ListPublicCertificatesResponse { + // Optional. A token to retrieve the next page of results when used in + // [ListPublicCertificatesRequest]. + string next_page_token = 1; + + // Optional. Public certificates allowed to be accessed by the calling local + // device. + repeated PublicCertificate public_certificates = 2; +}
diff --git a/chromeos/ash/components/nearby/presence/proto/rpc_resources.proto b/chromeos/ash/components/nearby/presence/proto/rpc_resources.proto new file mode 100644 index 0000000..e40a038 --- /dev/null +++ b/chromeos/ash/components/nearby/presence/proto/rpc_resources.proto
@@ -0,0 +1,139 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Keep in sync with +// http://google3/google/internal/location/nearby/presence/v1/resources.proto +// Messages not used in Chrome have been omitted. Last copied at cl/428736503. + +syntax = "proto3"; + +package ash.nearby.proto; + +option optimize_for = LITE_RUNTIME; + +import "chromeos/ash/components/nearby/common/proto/timestamp.proto"; + +// An enum type how trust is specified. +enum TrustType { + TRUST_TYPE_UNSPECIFIED = 0; + + // The same user itself. + TRUST_TYPE_PRIVATE = 1; + + // The user selects the contact from its contact list. + TRUST_TYPE_TRUSTED = 2; +} + +// A PublicCertificate contains a secret key used when recognizing another +// user's BLE advertisement and a public key used when establishing an encrypted +// connection. +// +// How a Certificate is distributed is determined by who is on a user's contact +// list. For example, if Will adds Ryan to his contact list, Ryan will have a +// ShareTarget with Will's Certificate attached to it. +// NextId=11 +message PublicCertificate { + // The secret (symmetric) identifier used when identifying the ShareTarget's + // BLE advertisement. + bytes secret_id = 1; + + // The secret (symmetric) key is used to decrypt the name field of the + // ShareTarget's BLE advertisement. + bytes secret_key = 2; + + // The public key is used to create a secure connection with the ShareTarget. + bytes public_key = 3; + + // The time that certificate validity begins. + Timestamp start_time = 4; + + // The time that certificate validity ends. + Timestamp end_time = 5; + + // The encrypted metadata in bytes, contains personal information of the + // device/user who created this certificate. Needs to be decrypted into bytes, + // and converted back to EncryptedMetadata object to access fields. + // Definition of this object see: + // location/nearby/presence/proto/contact_certificates.proto + bytes encrypted_metadata_bytes = 6; + + // The tag for verifying metadata_encryption_key. + bytes metadata_encryption_key_tag = 7; + + // The trust type, see the comments in the enum TrustType. + TrustType trust_type = 8; +} + +// A member of a contact list. This is not inlined on the recommendation of +// http://go/apidosdonts##19-make-repeated-fields-messages-not-scalar-types +// NextId=3 +message Contact { + // NextId=4 + message Identifier { + oneof identifier { + string phone_number = 1; + string account_name = 2; + } + } + + // Required. The identifier of a contact can be an obfuscated gaia id, a phone + // number, or an email account name. + Identifier identifier = 1; + + // The trust type, see the comments in the enum TrustType. + TrustType trust_type = 2; +} + +// A contact record from People backend. +// NextId=7 +message ContactRecord { + // The type of the ContactRecord. + enum Type { + // The source of the contact is unknown. + UNKNOWN = 0; + + // The source of the contact is from google (i.e. google.com/contacts). + GOOGLE_CONTACT = 1; + + // The source of the contact is from a device. + DEVICE_CONTACT = 2; + } + + // The stable id of this contact record. + string id = 1; + + // The contact record's name. + string person_name = 2; + + // The URL of an image displayed to the user when selecting a share + // target. + string image_url = 3; + + // A list of phone numbers and emails under this contact record. + repeated Contact.Identifier identifiers = 4; + + // The type of the ContactRecord. + Type type = 5; +} + +// Consists of editable data inside of a device. +// NextId=5 +message Device { + // Required. The resource name of this contact Device. This is of the format + // 'users/<user-id>/devices/<device-id>'. + // The special prefix 'users/me' uses the + // identity of the requester. + string name = 1; + + // The device name to show members of this contact. Ex: "Joe's Pixel" + string display_name = 2; + + // Users that this user has added to indicate that they may see this + // user as a ShareTarget when this user is nearby. + repeated Contact contacts = 3; + + // The public certificates generated and uploaded from local device, to be + // shared with contacts. + repeated PublicCertificate public_certificates = 4; +}
diff --git a/chromeos/ash/components/nearby/presence/proto/update_device_rpc.proto b/chromeos/ash/components/nearby/presence/proto/update_device_rpc.proto new file mode 100644 index 0000000..56815d2 --- /dev/null +++ b/chromeos/ash/components/nearby/presence/proto/update_device_rpc.proto
@@ -0,0 +1,45 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Keep in sync with +// http://google3/google/internal/location/nearby/presence/v1/rpcs/devices.proto +// Messages not used in Chrome have been omitted. Last copied at cl/460540069. + +syntax = "proto3"; + +package ash.nearby.proto; + +option optimize_for = LITE_RUNTIME; + +import "chromeos/ash/components/nearby/presence/proto/rpc_resources.proto"; +import "chromeos/ash/components/nearby/common/proto/field_mask.proto"; + +// The request used to register a [location.nearby.presence.proto.Device] +// with the server. +message UpdateDeviceRequest { + Device device = 1; + + // The FieldMask for updating specific columns in device table. For the + // 'FieldMask' definition, see + // https://developers.google.com/protocol-buffers/docs/reference/google.protobuf#fieldmask + FieldMask update_mask = 2; +} + +// The response for UpdateDeviceRequest. +message UpdateDeviceResponse { + // The [Device] to be returned. + Device device = 1; + + // Optional. The user's name as displayed to the user when selecting a share + // target. Ex: "Will Harmon" + string person_name = 2; + + // Optional. The URL of an image displayed to the user when selecting a share + // target. + string image_url = 3; + + // Optional. A hash like value to determine if the profile image has changed + // or not. Note, the image_url can change for the same image. + string image_token = 4; +}
diff --git a/chromeos/ash/components/network/hotspot_enabled_state_notifier.h b/chromeos/ash/components/network/hotspot_enabled_state_notifier.h index a4ec4d87..54e2fba 100644 --- a/chromeos/ash/components/network/hotspot_enabled_state_notifier.h +++ b/chromeos/ash/components/network/hotspot_enabled_state_notifier.h
@@ -33,6 +33,7 @@ observer); private: + friend class HotspotNotifierTest; HotspotEnabledStateNotifier(HotspotStateHandler* hotspot_state_handler, HotspotController* hotspot_controller);
diff --git a/chromeos/ash/services/hotspot_config/public/cpp/BUILD.gn b/chromeos/ash/services/hotspot_config/public/cpp/BUILD.gn index cebba03..9f887419 100644 --- a/chromeos/ash/services/hotspot_config/public/cpp/BUILD.gn +++ b/chromeos/ash/services/hotspot_config/public/cpp/BUILD.gn
@@ -19,6 +19,8 @@ testonly = true sources = [ + "cros_hotspot_config_test_helper.cc", + "cros_hotspot_config_test_helper.h", "cros_hotspot_config_test_observer.cc", "cros_hotspot_config_test_observer.h", "hotspot_enabled_state_test_observer.cc", @@ -35,5 +37,6 @@ deps = [ "//chromeos/ash/components/network", "//chromeos/ash/services/hotspot_config", + "//chromeos/ash/services/hotspot_config:in_process_hotspot_config", ] }
diff --git a/chromeos/ash/services/hotspot_config/public/cpp/cros_hotspot_config_test_helper.cc b/chromeos/ash/services/hotspot_config/public/cpp/cros_hotspot_config_test_helper.cc new file mode 100644 index 0000000..d27b6e2e --- /dev/null +++ b/chromeos/ash/services/hotspot_config/public/cpp/cros_hotspot_config_test_helper.cc
@@ -0,0 +1,29 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chromeos/ash/services/hotspot_config/public/cpp/cros_hotspot_config_test_helper.h" + +#include "chromeos/ash/services/hotspot_config/in_process_instance.h" + +namespace ash::hotspot_config { + +CrosHotspotConfigTestHelper::CrosHotspotConfigTestHelper() { + cros_hotspot_config_impl_ = std::make_unique<CrosHotspotConfig>(); + OverrideInProcessInstanceForTesting(cros_hotspot_config_impl_.get()); +} + +CrosHotspotConfigTestHelper::~CrosHotspotConfigTestHelper() { + Shutdown(); +} + +void CrosHotspotConfigTestHelper::Shutdown() { + OverrideInProcessInstanceForTesting(nullptr); + cros_hotspot_config_impl_.reset(); +} + +void CrosHotspotConfigTestHelper::EnableHotspot() { + cros_hotspot_config_impl_->EnableHotspot(base::DoNothing()); +} + +} // namespace ash::hotspot_config
diff --git a/chromeos/ash/services/hotspot_config/public/cpp/cros_hotspot_config_test_helper.h b/chromeos/ash/services/hotspot_config/public/cpp/cros_hotspot_config_test_helper.h new file mode 100644 index 0000000..610ab4a --- /dev/null +++ b/chromeos/ash/services/hotspot_config/public/cpp/cros_hotspot_config_test_helper.h
@@ -0,0 +1,43 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROMEOS_ASH_SERVICES_HOTSPOT_CONFIG_PUBLIC_CPP_CROS_HOTSPOT_CONFIG_TEST_HELPER_H_ +#define CHROMEOS_ASH_SERVICES_HOTSPOT_CONFIG_PUBLIC_CPP_CROS_HOTSPOT_CONFIG_TEST_HELPER_H_ + +#include <memory> +#include "chromeos/ash/services/hotspot_config/cros_hotspot_config.h" + +namespace ash { + +namespace hotspot_config { + +class CrosHotspotConfig; + +// Helper for tests which need a CrosHotspotConfig service interface. +class CrosHotspotConfigTestHelper { + public: + // Default constructor for unit tests. + CrosHotspotConfigTestHelper(); + + CrosHotspotConfigTestHelper(const CrosHotspotConfigTestHelper&) = delete; + CrosHotspotConfigTestHelper& operator=(const CrosHotspotConfigTestHelper&) = + delete; + + ~CrosHotspotConfigTestHelper(); + + void EnableHotspot(); + + protected: + // Called in |~CrosHotspotConfigTestHelper()| to destroy + // cros_hotspot_config_impl_. + void Shutdown(); + + std::unique_ptr<CrosHotspotConfig> cros_hotspot_config_impl_; +}; + +} // namespace hotspot_config + +} // namespace ash + +#endif // CHROMEOS_ASH_SERVICES_HOTSPOT_CONFIG_PUBLIC_CPP_CROS_HOTSPOT_CONFIG_TEST_HELPER_H_
diff --git a/components/app_restore/restore_data.h b/components/app_restore/restore_data.h index f65e965..356129a9 100644 --- a/components/app_restore/restore_data.h +++ b/components/app_restore/restore_data.h
@@ -192,6 +192,9 @@ const AppIdToLaunchList& app_id_to_launch_list() const { return app_id_to_launch_list_; } + AppIdToLaunchList& mutable_app_id_to_launch_list() { + return app_id_to_launch_list_; + } void set_removing_desk_guid(const base::Uuid& removing_desk_guid) { removing_desk_guid_ = removing_desk_guid;
diff --git a/components/bookmarks/browser/bookmark_model.cc b/components/bookmarks/browser/bookmark_model.cc index 644965be..290581f 100644 --- a/components/bookmarks/browser/bookmark_model.cc +++ b/components/bookmarks/browser/bookmark_model.cc
@@ -916,16 +916,15 @@ std::vector<TitledUrlMatch> BookmarkModel::GetBookmarksMatching( const std::u16string& query, size_t max_count, - query_parser::MatchingAlgorithm matching_algorithm, - bool match_ancestor_titles) { + query_parser::MatchingAlgorithm matching_algorithm) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (!loaded_) { return {}; } - return titled_url_index_->GetResultsMatching( - query, max_count, matching_algorithm, match_ancestor_titles); + return titled_url_index_->GetResultsMatching(query, max_count, + matching_algorithm); } void BookmarkModel::ClearStore() { @@ -1023,7 +1022,6 @@ const base::TimeDelta load_duration = base::TimeTicks::Now() - details->load_start(); metrics::RecordTimeToLoadAtStartup(load_duration); - titled_url_index_->RecordMemoryUsage(); // Notify our direct observers. for (BookmarkModelObserver& observer : observers_) {
diff --git a/components/bookmarks/browser/bookmark_model.h b/components/bookmarks/browser/bookmark_model.h index 87b779a..265a662 100644 --- a/components/bookmarks/browser/bookmark_model.h +++ b/components/bookmarks/browser/bookmark_model.h
@@ -36,7 +36,7 @@ namespace base { class FilePath; -} +} // namespace base namespace favicon_base { struct FaviconImageResult; @@ -292,14 +292,12 @@ const base::Time delete_end); // Returns up to |max_count| bookmarks containing each term from |query| in - // either the title, URL, or, if |match_ancestor_titles| is true, the titles - // of ancestors. |matching_algorithm| determines the algorithm used by - // QueryParser internally to parse |query|. + // either the title, URL, or the titles of ancestors. |matching_algorithm| + // determines the algorithm used by QueryParser internally to parse |query|. std::vector<TitledUrlMatch> GetBookmarksMatching( const std::u16string& query, size_t max_count, - query_parser::MatchingAlgorithm matching_algorithm, - bool match_ancestor_titles = false); + query_parser::MatchingAlgorithm matching_algorithm); // Sets the store to NULL, making it so the BookmarkModel does not persist // any changes to disk. This is only useful during testing to speed up @@ -315,8 +313,7 @@ const std::string& value); void SetNodeMetaInfoMap(const BookmarkNode* node, const BookmarkNode::MetaInfoMap& meta_info_map); - void DeleteNodeMetaInfo(const BookmarkNode* node, - const std::string& key); + void DeleteNodeMetaInfo(const BookmarkNode* node, const std::string& key); // Sets/deletes local meta info of |node|. void SetNodeUnsyncedMetaInfo(const BookmarkNode* node, @@ -343,8 +340,7 @@ // http://www.google.com/favicon.ico) have changed. It is valid to call // OnFaviconsChanged() with non-empty |page_urls| and an empty |icon_url| and // vice versa. - void OnFaviconsChanged(const std::set<GURL>& page_urls, - const GURL& icon_url); + void OnFaviconsChanged(const std::set<GURL>& page_urls, const GURL& icon_url); // Returns the client used by this BookmarkModel. BookmarkClient* client() const { return client_.get(); }
diff --git a/components/bookmarks/browser/bookmark_model_unittest.cc b/components/bookmarks/browser/bookmark_model_unittest.cc index 500d7e1..140a58a 100644 --- a/components/bookmarks/browser/bookmark_model_unittest.cc +++ b/components/bookmarks/browser/bookmark_model_unittest.cc
@@ -61,27 +61,27 @@ const std::string input_title; const std::string expected_title; } url_whitespace_test_cases[] = { - {"foobar", "foobar"}, - // Newlines. - {"foo\nbar", "foo bar"}, - {"foo\n\nbar", "foo bar"}, - {"foo\n\n\nbar", "foo bar"}, - {"foo\r\nbar", "foo bar"}, - {"foo\r\n\r\nbar", "foo bar"}, - {"\nfoo\nbar\n", " foo bar "}, - // Spaces should not collapse. - {"foo bar", "foo bar"}, - {" foo bar ", " foo bar "}, - {" foo bar ", " foo bar "}, - // Tabs. - {"\tfoo\tbar\t", " foo bar "}, - {"\tfoo bar\t", " foo bar "}, - // Mixed cases. - {"\tfoo\nbar\t", " foo bar "}, - {"\tfoo\r\nbar\t", " foo bar "}, - {" foo\tbar\n", " foo bar "}, - {"\t foo \t bar \t", " foo bar "}, - {"\n foo\r\n\tbar\n \t", " foo bar "}, + {"foobar", "foobar"}, + // Newlines. + {"foo\nbar", "foo bar"}, + {"foo\n\nbar", "foo bar"}, + {"foo\n\n\nbar", "foo bar"}, + {"foo\r\nbar", "foo bar"}, + {"foo\r\n\r\nbar", "foo bar"}, + {"\nfoo\nbar\n", " foo bar "}, + // Spaces should not collapse. + {"foo bar", "foo bar"}, + {" foo bar ", " foo bar "}, + {" foo bar ", " foo bar "}, + // Tabs. + {"\tfoo\tbar\t", " foo bar "}, + {"\tfoo bar\t", " foo bar "}, + // Mixed cases. + {"\tfoo\nbar\t", " foo bar "}, + {"\tfoo\r\nbar\t", " foo bar "}, + {" foo\tbar\n", " foo bar "}, + {"\t foo \t bar \t", " foo bar "}, + {"\n foo\r\n\tbar\n \t", " foo bar "}, }; // Test cases used to test the removal of extra whitespace when adding @@ -90,27 +90,27 @@ const std::string input_title; const std::string expected_title; } title_whitespace_test_cases[] = { - {"foobar", "foobar"}, - // Newlines. - {"foo\nbar", "foo bar"}, - {"foo\n\nbar", "foo bar"}, - {"foo\n\n\nbar", "foo bar"}, - {"foo\r\nbar", "foo bar"}, - {"foo\r\n\r\nbar", "foo bar"}, - {"\nfoo\nbar\n", " foo bar "}, - // Spaces. - {"foo bar", "foo bar"}, - {" foo bar ", " foo bar "}, - {" foo bar ", " foo bar "}, - // Tabs. - {"\tfoo\tbar\t", " foo bar "}, - {"\tfoo bar\t", " foo bar "}, - // Mixed cases. - {"\tfoo\nbar\t", " foo bar "}, - {"\tfoo\r\nbar\t", " foo bar "}, - {" foo\tbar\n", " foo bar "}, - {"\t foo \t bar \t", " foo bar "}, - {"\n foo\r\n\tbar\n \t", " foo bar "}, + {"foobar", "foobar"}, + // Newlines. + {"foo\nbar", "foo bar"}, + {"foo\n\nbar", "foo bar"}, + {"foo\n\n\nbar", "foo bar"}, + {"foo\r\nbar", "foo bar"}, + {"foo\r\n\r\nbar", "foo bar"}, + {"\nfoo\nbar\n", " foo bar "}, + // Spaces. + {"foo bar", "foo bar"}, + {" foo bar ", " foo bar "}, + {" foo bar ", " foo bar "}, + // Tabs. + {"\tfoo\tbar\t", " foo bar "}, + {"\tfoo bar\t", " foo bar "}, + // Mixed cases. + {"\tfoo\nbar\t", " foo bar "}, + {"\tfoo\r\nbar\t", " foo bar "}, + {" foo\tbar\n", " foo bar "}, + {"\t foo \t bar \t", " foo bar "}, + {"\n foo\r\n\tbar\n \t", " foo bar "}, }; class ScopedBookmarkUndoDelegate : public BookmarkUndoDelegate { @@ -216,9 +216,9 @@ // NOTE: each name must be unique, and folders are assigned a unique title by // way of an increasing integer. void PopulateNodeFromString(const std::string& description, TestNode* parent) { - std::vector<std::string> elements = base::SplitString( - description, base::kWhitespaceASCII, - base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); + std::vector<std::string> elements = + base::SplitString(description, base::kWhitespaceASCII, + base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); size_t index = 0; PopulateNodeImpl(elements, &index, parent); } @@ -315,8 +315,7 @@ : parent_node_id(parent->id()), index(index), node_id(node->id()) {} bool operator==(const NodeRemovalDetail& other) const { - return parent_node_id == other.parent_node_id && - index == other.index && + return parent_node_id == other.parent_node_id && index == other.index && node_id == other.node_id; } @@ -438,12 +437,20 @@ } void ClearCounts() { - added_count_ = moved_count_ = removed_count_ = changed_count_ = - reordered_count_ = extensive_changes_beginning_count_ = - extensive_changes_ended_count_ = all_bookmarks_removed_ = - before_remove_count_ = before_change_count_ = before_reorder_count_ = - before_remove_all_count_ = grouped_changes_beginning_count_ = - grouped_changes_ended_count_ = 0; + added_count_ = 0; + moved_count_ = 0; + removed_count_ = 0; + changed_count_ = 0; + reordered_count_ = 0; + extensive_changes_beginning_count_ = 0; + extensive_changes_ended_count_ = 0; + all_bookmarks_removed_ = 0; + before_remove_count_ = 0; + before_change_count_ = 0; + before_reorder_count_ = 0; + before_remove_all_count_ = 0; + grouped_changes_beginning_count_ = 0; + grouped_changes_ended_count_ = 0; } void AssertObserverCount(int added_count, @@ -474,9 +481,8 @@ EXPECT_EQ(extensive_changes_ended_count, extensive_changes_ended_count_); } - void AssertGroupedChangesObserverCount( - int grouped_changes_beginning_count, - int grouped_changes_ended_count) { + void AssertGroupedChangesObserverCount(int grouped_changes_beginning_count, + int grouped_changes_ended_count) { EXPECT_EQ(grouped_changes_beginning_count, grouped_changes_beginning_count_); EXPECT_EQ(grouped_changes_ended_count, grouped_changes_ended_count_); @@ -833,8 +839,8 @@ size_t permanent_node_count = model_->root_node()->children().size(); NodeRemovalDetail expected_node_removal_details[] = { - NodeRemovalDetail(bookmark_bar_node, 1, url_node), - NodeRemovalDetail(bookmark_bar_node, 0, folder), + NodeRemovalDetail(bookmark_bar_node, 1, url_node), + NodeRemovalDetail(bookmark_bar_node, 0, folder), }; model_->SetUndoDelegate(this); @@ -1015,12 +1021,10 @@ // Should update the index. auto matches = model_->GetBookmarksMatching( - u"folder foo", /*max_count=*/1, query_parser::MatchingAlgorithm::DEFAULT, - /*match_ancestor_titles= */ true); + u"folder foo", /*max_count=*/1, query_parser::MatchingAlgorithm::DEFAULT); EXPECT_TRUE(matches.empty()); matches = model_->GetBookmarksMatching( - u"golder foo", /*max_count=*/1, query_parser::MatchingAlgorithm::DEFAULT, - /*match_ancestor_titles= */ true); + u"golder foo", /*max_count=*/1, query_parser::MatchingAlgorithm::DEFAULT); ASSERT_EQ(matches.size(), 1u); EXPECT_EQ(matches[0].node, node); EXPECT_EQ(matches[0].node->GetTitledUrlNodeUrl(), url); @@ -1080,8 +1084,7 @@ EXPECT_EQ(node, folder1->children().front().get()); auto matches = model_->GetBookmarksMatching( - u"folder foo", /*max_count=*/1, query_parser::MatchingAlgorithm::DEFAULT, - /*match_ancestor_titles= */ true); + u"folder foo", /*max_count=*/1, query_parser::MatchingAlgorithm::DEFAULT); EXPECT_EQ(matches[0].node, node); // And remove the folder. @@ -1135,12 +1138,10 @@ EXPECT_EQ(folder2->children().front().get(), node); auto matches = model_->GetBookmarksMatching( - u"folder foo", /*max_count=*/1, query_parser::MatchingAlgorithm::DEFAULT, - /*match_ancestor_titles= */ true); + u"folder foo", /*max_count=*/1, query_parser::MatchingAlgorithm::DEFAULT); EXPECT_TRUE(matches.empty()); matches = model_->GetBookmarksMatching( - u"golder foo", /*max_count=*/1, query_parser::MatchingAlgorithm::DEFAULT, - /*match_ancestor_titles= */ true); + u"golder foo", /*max_count=*/1, query_parser::MatchingAlgorithm::DEFAULT); EXPECT_EQ(matches[0].node, node); matches.clear(); @@ -1157,13 +1158,11 @@ EXPECT_EQ(folder1->children().front().get(), node); matches = model_->GetBookmarksMatching( - u"folder foo", /*max_count=*/1, query_parser::MatchingAlgorithm::DEFAULT, - /*match_ancestor_titles= */ true); + u"folder foo", /*max_count=*/1, query_parser::MatchingAlgorithm::DEFAULT); EXPECT_EQ(matches[0].node, node); matches.clear(); matches = model_->GetBookmarksMatching( - u"golder foo", /*max_count=*/1, query_parser::MatchingAlgorithm::DEFAULT, - /*match_ancestor_titles= */ true); + u"golder foo", /*max_count=*/1, query_parser::MatchingAlgorithm::DEFAULT); EXPECT_TRUE(matches.empty()); } @@ -1193,17 +1192,14 @@ // Should update the index. auto matches = model_->GetBookmarksMatching( - u"folder foo", /*max_count=*/1, query_parser::MatchingAlgorithm::DEFAULT, - /*match_ancestor_titles= */ true); + u"folder foo", /*max_count=*/1, query_parser::MatchingAlgorithm::DEFAULT); EXPECT_TRUE(matches.empty()); matches = model_->GetBookmarksMatching( - u"golder foo", /*max_count=*/1, query_parser::MatchingAlgorithm::DEFAULT, - /*match_ancestor_titles= */ true); + u"golder foo", /*max_count=*/1, query_parser::MatchingAlgorithm::DEFAULT); EXPECT_EQ(matches[0].node, node); matches.clear(); matches = model_->GetBookmarksMatching( - u"holder foo", /*max_count=*/1, query_parser::MatchingAlgorithm::DEFAULT, - /*match_ancestor_titles= */ true); + u"holder foo", /*max_count=*/1, query_parser::MatchingAlgorithm::DEFAULT); EXPECT_EQ(matches[0].node, node); matches.clear(); } @@ -1258,9 +1254,10 @@ node_to_copy = root->children()[4].get(); model_->Copy(node_to_copy, root, 1); actual_model_string = test::ModelStringFromNode(root); - EXPECT_EQ("a 2:[ e 1:[ b d c ] f 1:[ b d c ] g ] d 1:[ b d c ] " - "d 2:[ e 1:[ b d c ] f 1:[ b d c ] g ] h d ", - actual_model_string); + EXPECT_EQ( + "a 2:[ e 1:[ b d c ] f 1:[ b d c ] g ] d 1:[ b d c ] " + "d 2:[ e 1:[ b d c ] f 1:[ b d c ] g ] h d ", + actual_model_string); } // Tests the default node if no bookmarks have been added yet @@ -1595,21 +1592,14 @@ const GURL url("http://foo.com"); const BookmarkNode* node = model_->AddURL(folder, 0, title, url); - // Should not match paths by default. - auto matches = model_->GetBookmarksMatching( - u"folder foo", /*max_count=*/1, query_parser::MatchingAlgorithm::DEFAULT); - EXPECT_TRUE(matches.empty()); - // Should not match incorrect paths. - matches = model_->GetBookmarksMatching( - u"golder foo", /*max_count=*/1, query_parser::MatchingAlgorithm::DEFAULT, - /*match_ancestor_titles= */ true); + auto matches = model_->GetBookmarksMatching( + u"golder foo", /*max_count=*/1, query_parser::MatchingAlgorithm::DEFAULT); EXPECT_TRUE(matches.empty()); // Should match correct paths. matches = model_->GetBookmarksMatching( - u"folder foo", /*max_count=*/1, query_parser::MatchingAlgorithm::DEFAULT, - /*match_ancestor_titles= */ true); + u"folder foo", /*max_count=*/1, query_parser::MatchingAlgorithm::DEFAULT); EXPECT_EQ(matches[0].node, node); } @@ -1773,13 +1763,10 @@ // Structure of the children of the synced node. const std::string mobile_contents; } data[] = { - // See PopulateNodeFromString for a description of these strings. - { "", "" }, - { "a", "b" }, - { "a [ b ]", "" }, - { "", "[ b ] a [ c [ d e [ f ] ] ]" }, - { "a [ b ]", "" }, - { "a b c [ d e [ f ] ]", "g h i [ j k [ l ] ]"}, + // See PopulateNodeFromString for a description of these strings. + {"", ""}, {"a", "b"}, + {"a [ b ]", ""}, {"", "[ b ] a [ c [ d e [ f ] ] ]"}, + {"a [ b ]", ""}, {"a b c [ d e [ f ] ]", "g h i [ j k [ l ] ]"}, }; std::unique_ptr<BookmarkModel> model; for (size_t i = 0; i < std::size(data); ++i) { @@ -1820,24 +1807,22 @@ // favicon is asynchronously loaded when BookmarkModel::GetFavicon() is // called. void OnFaviconLoaded(BookmarkNode* node, const GURL& icon_url) { - SkBitmap bitmap; - bitmap.allocN32Pixels(16, 16); - bitmap.eraseColor(SK_ColorBLUE); - gfx::Image image = gfx::Image::CreateFrom1xBitmap(bitmap); + SkBitmap bitmap; + bitmap.allocN32Pixels(16, 16); + bitmap.eraseColor(SK_ColorBLUE); + gfx::Image image = gfx::Image::CreateFrom1xBitmap(bitmap); - favicon_base::FaviconImageResult image_result; - image_result.image = image; - image_result.icon_url = icon_url; - model_->OnFaviconDataAvailable(node, image_result); + favicon_base::FaviconImageResult image_result; + image_result.image = image; + image_result.icon_url = icon_url; + model_->OnFaviconDataAvailable(node, image_result); } bool WasNodeUpdated(const BookmarkNode* node) { return base::Contains(updated_nodes_, node); } - void ClearUpdatedNodes() { - updated_nodes_.clear(); - } + void ClearUpdatedNodes() { updated_nodes_.clear(); } protected: void BookmarkModelLoaded(BookmarkModel* model, bool ids_reassigned) override { @@ -1873,8 +1858,7 @@ void BookmarkAllUserNodesRemoved( BookmarkModel* model, - const std::set<GURL>& removed_urls) override { - } + const std::set<GURL>& removed_urls) override {} std::unique_ptr<BookmarkModel> model_; std::vector<const BookmarkNode*> updated_nodes_;
diff --git a/components/bookmarks/browser/titled_url_index.cc b/components/bookmarks/browser/titled_url_index.cc index 908068b4..cc16580 100644 --- a/components/bookmarks/browser/titled_url_index.cc +++ b/components/bookmarks/browser/titled_url_index.cc
@@ -16,8 +16,6 @@ #include "base/i18n/case_conversion.h" #include "base/i18n/unicodestring.h" #include "base/logging.h" -#include "base/metrics/histogram_functions.h" -#include "base/metrics/histogram_macros.h" #include "base/ranges/algorithm.h" #include "base/stl_util.h" #include "base/strings/utf_offset_string_conversions.h" @@ -47,41 +45,22 @@ TitledUrlIndex::~TitledUrlIndex() = default; -void TitledUrlIndex::RecordMemoryUsage() const { - const auto index_size = base::trace_event::EstimateMemoryUsage(index_); - const auto path_index_size = - base::trace_event::EstimateMemoryUsage(path_index_); - - base::UmaHistogramMemoryKB("Bookmarks.Memory.TitledUrlIndex", - index_size + path_index_size); - base::UmaHistogramMemoryKB("Bookmarks.Memory.TitledUrlIndex.TitleAndUrlIndex", - index_size); - base::UmaHistogramMemoryKB("Bookmarks.Memory.TitledUrlIndex.PathIndex", - path_index_size); -} - void TitledUrlIndex::SetNodeSorter( std::unique_ptr<TitledUrlNodeSorter> sorter) { sorter_ = std::move(sorter); } void TitledUrlIndex::Add(const TitledUrlNode* node) { - SCOPED_UMA_HISTOGRAM_TIMER_MICROS("Bookmarks.UpdateTitledUrlIndex.Add"); for (const std::u16string& term : ExtractIndexTerms(node)) RegisterNode(term, node); } void TitledUrlIndex::Remove(const TitledUrlNode* node) { - SCOPED_UMA_HISTOGRAM_TIMER_MICROS("Bookmarks.UpdateTitledUrlIndex.Remove"); for (const std::u16string& term : ExtractIndexTerms(node)) UnregisterNode(term, node); } void TitledUrlIndex::AddPath(const TitledUrlNode* node) { - if (!index_paths_) - return; - - SCOPED_UMA_HISTOGRAM_TIMER_MICROS("Bookmarks.UpdateTitledUrlIndex.AddPath"); for (const std::u16string& term : ExtractQueryWords(Normalize(node->GetTitledUrlNodeTitle()))) { path_index_[term]++; @@ -89,11 +68,6 @@ } void TitledUrlIndex::RemovePath(const TitledUrlNode* node) { - if (!index_paths_) - return; - - SCOPED_UMA_HISTOGRAM_TIMER_MICROS( - "Bookmarks.UpdateTitledUrlIndex.RemovePath"); for (const std::u16string& term : ExtractQueryWords(Normalize(node->GetTitledUrlNodeTitle()))) { // `path_index_.count(term)` should be > 0, since nodes can't be @@ -107,51 +81,19 @@ std::vector<TitledUrlMatch> TitledUrlIndex::GetResultsMatching( const std::u16string& input_query, size_t max_count, - query_parser::MatchingAlgorithm matching_algorithm, - bool match_ancestor_titles) { - SCOPED_UMA_HISTOGRAM_TIMER("Bookmarks.GetResultsMatching.Timing.Total"); + query_parser::MatchingAlgorithm matching_algorithm) { const std::u16string query = Normalize(input_query); std::vector<std::u16string> terms = ExtractQueryWords(query); - base::UmaHistogramExactLinear("Bookmarks.GetResultsMatching.Terms.TermsCount", - terms.size(), 16); if (terms.empty()) return {}; - for (const std::u16string& term : terms) { - base::UmaHistogramExactLinear( - "Bookmarks.GetResultsMatching.Terms.TermLength", term.size(), 16); - } - // When |match_ancestor_titles| is true, |matches| shouldn't exclude nodes - // that don't match every query term, as the query terms may match in the - // ancestors. |MatchTitledUrlNodeWithQuery()| below will filter out nodes that - // neither match nor ancestor-match every query term. - TitledUrlNodeSet matches; - { - SCOPED_UMA_HISTOGRAM_TIMER( - "Bookmarks.GetResultsMatching.Timing.RetrievingNodes"); - static const size_t kMaxNodes = kLimitNumNodesForBookmarkSearchCount.Get(); - matches = match_ancestor_titles - ? RetrieveNodesMatchingAnyTerms(terms, matching_algorithm, - kMaxNodes) - : RetrieveNodesMatchingAllTerms(terms, matching_algorithm); - } - base::UmaHistogramBoolean("Bookmarks.GetResultsMatching.AnyTermApproach.Used", - match_ancestor_titles); - base::UmaHistogramCounts10000("Bookmarks.GetResultsMatching.Nodes.Count", - matches.size()); - // Slice by 3, the default value of - // `kShortBookmarkSuggestionsByTotalInputLengthThreshold`. Shorter inputs will - // likely have many fewer nodes than longer queries. - if (input_query.size() < 3) { - base::UmaHistogramCounts10000( - "Bookmarks.GetResultsMatching.Nodes.Count." - "InputsShorterThan3CharsLong", - matches.size()); - } else { - base::UmaHistogramCounts10000( - "Bookmarks.GetResultsMatching.Nodes.Count.InputsAtLeast3CharsLong", - matches.size()); - } + // `matches` shouldn't exclude nodes that don't match every query term, as the + // query terms may match in the ancestors. `MatchTitledUrlNodeWithQuery()` + // below will filter out nodes that neither match nor ancestor-match every + // query term. + static const size_t kMaxNodes = 1000; + TitledUrlNodeSet matches = + RetrieveNodesMatchingAnyTerms(terms, matching_algorithm, kMaxNodes); if (matches.empty()) return {}; @@ -166,14 +108,8 @@ query_parser::QueryParser::ParseQueryNodes(query, matching_algorithm, &query_nodes); - std::vector<TitledUrlMatch> results = MatchTitledUrlNodesWithQuery( - sorted_nodes, query_nodes, terms, max_count, match_ancestor_titles); - - // In practice, `max_count`, is always 50 (`kMaxBookmarkMatches`), so - // `results.size()` is at most 50. - base::UmaHistogramExactLinear( - "Bookmarks.GetResultsMatching.Matches.ReturnedCount", results.size(), 51); - return results; + return MatchTitledUrlNodesWithQuery(sorted_nodes, query_nodes, terms, + max_count); } // static @@ -199,8 +135,6 @@ void TitledUrlIndex::SortMatches(const TitledUrlNodeSet& matches, TitledUrlNodes* sorted_nodes) const { - SCOPED_UMA_HISTOGRAM_TIMER( - "Bookmarks.GetResultsMatching.Timing.SortingNodes"); if (sorter_) { sorter_->SortMatches(matches, sorted_nodes); } else { @@ -212,35 +146,27 @@ const TitledUrlNodes& nodes, const query_parser::QueryNodeVector& query_nodes, const std::vector<std::u16string>& query_terms, - size_t max_count, - bool match_ancestor_titles) { - SCOPED_UMA_HISTOGRAM_TIMER( - "Bookmarks.GetResultsMatching.Timing.CreatingMatches"); + size_t max_count) { // The highest typed counts should be at the beginning of the `matches` vector // so that the best matches will always be included in the results. The loop // that calculates match relevance in // `HistoryContentsProvider::ConvertResults()` will run backwards to assure // higher relevance will be attributed to the best matches. std::vector<TitledUrlMatch> matches; - int nodes_considered = 0; for (TitledUrlNodes::const_iterator i = nodes.begin(); i != nodes.end() && matches.size() < max_count; ++i) { - absl::optional<TitledUrlMatch> match = MatchTitledUrlNodeWithQuery( - *i, query_nodes, query_terms, match_ancestor_titles); + absl::optional<TitledUrlMatch> match = + MatchTitledUrlNodeWithQuery(*i, query_nodes, query_terms); if (match) matches.emplace_back(std::move(match).value()); - ++nodes_considered; } - base::UmaHistogramCounts10000( - "Bookmarks.GetResultsMatching.Matches.ConsideredCount", nodes_considered); return matches; } absl::optional<TitledUrlMatch> TitledUrlIndex::MatchTitledUrlNodeWithQuery( const TitledUrlNode* node, const query_parser::QueryNodeVector& query_nodes, - const std::vector<std::u16string>& query_terms, - bool match_ancestor_titles) { + const std::vector<std::u16string>& query_terms) { if (!node) { return absl::nullopt; } @@ -258,48 +184,40 @@ const std::u16string clean_url = CleanUpUrlForMatching(node->GetTitledUrlNodeUrl(), &adjustments); std::vector<std::u16string> lower_ancestor_titles; - if (match_ancestor_titles) { - base::ranges::transform( - node->GetTitledUrlNodeAncestorTitles(), - std::back_inserter(lower_ancestor_titles), - [](const auto& ancestor_title) { - return base::i18n::ToLower(Normalize(std::u16string(ancestor_title))); - }); - } + base::ranges::transform( + node->GetTitledUrlNodeAncestorTitles(), + std::back_inserter(lower_ancestor_titles), + [](const auto& ancestor_title) { + return base::i18n::ToLower(Normalize(std::u16string(ancestor_title))); + }); // Check if the input approximately matches the node. This is less strict than // the following check; it will return false positives. But it's also much // faster, so if it returns false, early exit and avoid the expensive - // `ExtractQueryWords()` calls. This is only necessary if - // `match_ancestor_titles` is true; otherwise, the previous search done before - // calling `MatchTitledUrlNodeWithQuery()` would have already done this. - if (match_ancestor_titles && approximate_node_match_) { - bool approximate_match = - base::ranges::all_of(query_terms, [&](const auto& word) { - if (lower_title.find(word) != std::u16string::npos) + // `ExtractQueryWords()` calls. + bool approximate_match = + base::ranges::all_of(query_terms, [&](const auto& word) { + if (lower_title.find(word) != std::u16string::npos) + return true; + if (clean_url.find(word) != std::u16string::npos) + return true; + for (const auto& ancestor_title : lower_ancestor_titles) { + if (ancestor_title.find(word) != std::u16string::npos) return true; - if (clean_url.find(word) != std::u16string::npos) - return true; - for (const auto& ancestor_title : lower_ancestor_titles) { - if (ancestor_title.find(word) != std::u16string::npos) - return true; - } + } - return false; - }); - if (!approximate_match) - return absl::nullopt; - } + return false; + }); + if (!approximate_match) + return absl::nullopt; // If `node` passed the approximate check above, to the more accurate check. query_parser::QueryWordVector title_words, url_words, ancestor_words; query_parser::QueryParser::ExtractQueryWords(clean_url, &url_words); query_parser::QueryParser::ExtractQueryWords(lower_title, &title_words); - if (match_ancestor_titles) { - for (const auto& ancestor_title : lower_ancestor_titles) { - query_parser::QueryParser::ExtractQueryWords(ancestor_title, - &ancestor_words); - } + for (const auto& ancestor_title : lower_ancestor_titles) { + query_parser::QueryParser::ExtractQueryWords(ancestor_title, + &ancestor_words); } query_parser::Snippet::MatchPositions title_matches, url_matches; @@ -310,7 +228,7 @@ const bool has_url_matches = query_node->HasMatchIn(url_words, &url_matches); const bool has_ancestor_matches = - match_ancestor_titles && query_node->HasMatchIn(ancestor_words, false); + query_node->HasMatchIn(ancestor_words, false); query_has_ancestor_matches = query_has_ancestor_matches || has_ancestor_matches; if (!has_title_matches && !has_url_matches && !has_ancestor_matches) @@ -365,20 +283,18 @@ if (terms.size() == 1) return RetrieveNodesMatchingAllTerms(terms, matching_algorithm); - if (index_paths_) { - // If any term does not match a path, short circuit the expensive union - // and simply resort to the `RetrieveNodesMatchingAllTerms()` intersection - // of the terms not matching any path. The results are guaranteed to be the - // same, since all terms must either title, URL, or path match; but there'll - // be much fewer nodes returned. - std::vector<std::u16string> terms_not_path; - base::ranges::copy_if(terms, std::back_inserter(terms_not_path), - [&](const std::u16string& term) { - return !DoesTermMatchPath(term, matching_algorithm); - }); - if (!terms_not_path.empty()) - return RetrieveNodesMatchingAllTerms(terms_not_path, matching_algorithm); - } + // If any term does not match a path, short circuit the expensive union + // and simply resort to the `RetrieveNodesMatchingAllTerms()` intersection + // of the terms not matching any path. The results are guaranteed to be the + // same, since all terms must either title, URL, or path match; but there'll + // be much fewer nodes returned. + std::vector<std::u16string> terms_not_path; + base::ranges::copy_if(terms, std::back_inserter(terms_not_path), + [&](const std::u16string& term) { + return !DoesTermMatchPath(term, matching_algorithm); + }); + if (!terms_not_path.empty()) + return RetrieveNodesMatchingAllTerms(terms_not_path, matching_algorithm); std::vector<TitledUrlNodes> matches_per_term; bool some_term_had_empty_matches = false; @@ -388,17 +304,11 @@ // folder. TitledUrlNodes term_matches = RetrieveNodesMatchingTerm(term, matching_algorithm); - base::UmaHistogramCounts1000( - "Bookmarks.GetResultsMatching.AnyTermApproach.NodeCountPerTerm", - term_matches.size()); if (term_matches.empty()) some_term_had_empty_matches = true; else matches_per_term.push_back(std::move(term_matches)); } - base::UmaHistogramExactLinear( - "Bookmarks.GetResultsMatching.AnyTermApproach.TermsUnionedCount", - matches_per_term.size(), 16); // Sort `matches_per_term` least frequent first. This prevents terms like // 'https', which match a lot of nodes, from wasting `max_nodes` capacity. @@ -419,9 +329,6 @@ if (matches.size() == max_nodes) break; } - base::UmaHistogramCounts10000( - "Bookmarks.GetResultsMatching.AnyTermApproach.NodeCountAnyTerms", - matches.size()); // Append all nodes that match every input term. This is necessary because // with the `max_nodes` threshold above, it's possible that `matches` is @@ -444,13 +351,8 @@ DCHECK(all_term_matches == RetrieveNodesMatchingAllTerms(terms, matching_algorithm)); } - base::UmaHistogramCounts1000( - "Bookmarks.GetResultsMatching.AnyTermApproach.NodeCountAllTerms", - all_term_matches.size()); matches.insert(all_term_matches.begin(), all_term_matches.end()); - base::UmaHistogramCounts10000( - "Bookmarks.GetResultsMatching.AnyTermApproach.NodeCount", matches.size()); return TitledUrlNodeSet(matches.begin(), matches.end()); }
diff --git a/components/bookmarks/browser/titled_url_index.h b/components/bookmarks/browser/titled_url_index.h index 6e58efd..38191e46 100644 --- a/components/bookmarks/browser/titled_url_index.h +++ b/components/bookmarks/browser/titled_url_index.h
@@ -16,7 +16,6 @@ #include "base/containers/flat_set.h" #include "base/feature_list.h" #include "components/bookmarks/browser/titled_url_node_sorter.h" -#include "components/bookmarks/common/bookmark_features.h" #include "components/query_parser/query_parser.h" #include "third_party/abseil-cpp/absl/types/optional.h" @@ -46,10 +45,6 @@ ~TitledUrlIndex(); - // Records to UMA histograms sizes of `index_` and `path_index_`; called once - // at startup. - void RecordMemoryUsage() const; - void SetNodeSorter(std::unique_ptr<TitledUrlNodeSorter> sorter); // Invoked when a title/URL pair has been added to the model. @@ -64,15 +59,14 @@ // Invoked when a folder has been removed from the model. void RemovePath(const TitledUrlNode* node); - // Returns up to |max_count| of matches containing each term from the text - // |query| in either the title, URL, or, if |match_ancestor_titles| is true, - // the titles of ancestor nodes. |matching_algorithm| determines the algorithm - // used by QueryParser internally to parse |query|. + // Returns up to `max_count` of matches containing each term from the text + // `query` in either the title, URL, or the titles of ancestor nodes. + // `matching_algorithm` determines the algorithm used by QueryParser + // internally to parse `query`. std::vector<TitledUrlMatch> GetResultsMatching( const std::u16string& query, size_t max_count, - query_parser::MatchingAlgorithm matching_algorithm, - bool match_ancestor_titles); + query_parser::MatchingAlgorithm matching_algorithm); // Returns a normalized version of the UTF16 string `text`. If it fails to // normalize the string, returns `text` itself as a best-effort. @@ -95,16 +89,14 @@ const TitledUrlNodes& nodes, const query_parser::QueryNodeVector& query_nodes, const std::vector<std::u16string>& query_terms, - size_t max_count, - bool match_ancestor_titles); + size_t max_count); // Finds |query_nodes| matches in |node| and returns a TitledUrlMatch // containing |node| and the matches. absl::optional<TitledUrlMatch> MatchTitledUrlNodeWithQuery( const TitledUrlNode* node, const query_parser::QueryNodeVector& query_nodes, - const std::vector<std::u16string>& query_terms, - bool match_ancestor_titles); + const std::vector<std::u16string>& query_terms); // Return matches for the specified |terms|. This is an intersection of each // term's matches. @@ -164,13 +156,6 @@ std::map<std::u16string, size_t> path_index_; std::unique_ptr<TitledUrlNodeSorter> sorter_; - - // Cached as a member variables as they're read up to 3000 times per omnibox - // keystroke and `IsEnabled()` is too expensive to call that frequently. - const bool approximate_node_match_ = - base::FeatureList::IsEnabled(kApproximateNodeMatch); - const bool index_paths_ = - base::FeatureList::IsEnabled(bookmarks::kIndexPaths); }; } // namespace bookmarks
diff --git a/components/bookmarks/browser/titled_url_index_unittest.cc b/components/bookmarks/browser/titled_url_index_unittest.cc index 508bb43..a6c153e7 100644 --- a/components/bookmarks/browser/titled_url_index_unittest.cc +++ b/components/bookmarks/browser/titled_url_index_unittest.cc
@@ -14,12 +14,10 @@ #include "base/strings/string_split.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" -#include "base/test/metrics/histogram_tester.h" #include "base/test/scoped_feature_list.h" #include "components/bookmarks/browser/titled_url_match.h" #include "components/bookmarks/browser/titled_url_node.h" #include "components/bookmarks/browser/typed_count_sorter.h" -#include "components/bookmarks/common/bookmark_features.h" #include "components/bookmarks/test/test_bookmark_client.h" #include "components/query_parser/query_parser.h" #include "testing/gtest/include/gtest/gtest.h" @@ -29,16 +27,6 @@ namespace bookmarks { namespace { -// Helper to create vector of buckets. Each `pairs` are structured -// `{min sample, count}`. -std::vector<base::Bucket> CreateBuckets( - const std::vector<std::pair<int, int>>& pairs) { - std::vector<base::Bucket> buckets; - for (const auto& pair : pairs) - buckets.emplace_back(pair.first, pair.second); - return buckets; -} - // Used for sorting in combination with TypedCountSorter. class BookmarkClientMock : public TestBookmarkClient { public: @@ -117,7 +105,7 @@ query_parser::QueryParser::ParseQueryNodes( query, query_parser::MatchingAlgorithm::ALWAYS_PREFIX_SEARCH, &query_nodes); - return MatchTitledUrlNodeWithQuery(&node, query_nodes, query_terms, true); + return MatchTitledUrlNodeWithQuery(&node, query_nodes, query_terms); } }; @@ -159,13 +147,10 @@ return {owned_nodes_.back().get(), owned_path_nodes_.back().get()}; } - std::vector<TitledUrlMatch> GetResultsMatching( - const std::string& query, - size_t max_count, - bool match_ancestor_titles = false) { + std::vector<TitledUrlMatch> GetResultsMatching(const std::string& query, + size_t max_count) { return index_->GetResultsMatching(UTF8ToUTF16(query), max_count, - query_parser::MatchingAlgorithm::DEFAULT, - match_ancestor_titles); + query_parser::MatchingAlgorithm::DEFAULT); } void ExpectMatches(const std::string& query, @@ -182,7 +167,7 @@ query_parser::MatchingAlgorithm matching_algorithm, const std::vector<std::string>& expected_titles) { std::vector<TitledUrlMatch> matches = index_->GetResultsMatching( - UTF8ToUTF16(query), 1000, matching_algorithm, false); + UTF8ToUTF16(query), 1000, matching_algorithm); ASSERT_EQ(expected_titles.size(), matches.size()); for (const std::string& expected_title : expected_titles) { bool found = false; @@ -226,15 +211,8 @@ void VerifyRetrieveNodesMatchingAnyTerms( const std::string& query, - const std::vector<int> expected_node_indexes, - bool histogram_any_term_approach_used, - int histogram_terms_unioned_count, - const std::vector<std::pair<int, int>>& histogram_term_node_counts, - int histogram_any_terms_nodes, - int histogram_all_terms_nodes, - int histogram_joint_nodes) { + const std::vector<int> expected_node_indexes) { SCOPED_TRACE("Query: " + query); - base::HistogramTester histogram_tester; std::vector<std::u16string> terms = base::SplitString(base::UTF8ToUTF16(query), u" ", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); @@ -249,39 +227,6 @@ base::UTF16ToUTF8(owned_nodes_[index]->GetTitledUrlNodeTitle())); EXPECT_TRUE(matches.contains(owned_nodes_[index].get())); } - - // Verify histograms. - if (histogram_any_term_approach_used) { - histogram_tester.ExpectUniqueSample( - "Bookmarks.GetResultsMatching.AnyTermApproach.TermsUnionedCount", - histogram_terms_unioned_count, 1); - EXPECT_EQ( - CreateBuckets(histogram_term_node_counts), - histogram_tester.GetAllSamples("Bookmarks.GetResultsMatching." - "AnyTermApproach.NodeCountPerTerm")); - histogram_tester.ExpectUniqueSample( - "Bookmarks.GetResultsMatching.AnyTermApproach.NodeCountAnyTerms", - histogram_any_terms_nodes, 1); - histogram_tester.ExpectUniqueSample( - "Bookmarks.GetResultsMatching.AnyTermApproach.NodeCountAllTerms", - histogram_all_terms_nodes, 1); - histogram_tester.ExpectUniqueSample( - "Bookmarks.GetResultsMatching.AnyTermApproach.NodeCount", - histogram_joint_nodes, 1); - } else { - // If AnyTermApproach wasn't used, then other histograms shouldn't be - // recorded. - histogram_tester.ExpectTotalCount( - "Bookmarks.GetResultsMatching.AnyTermApproach.TermsUnionedCount", 0); - histogram_tester.ExpectTotalCount( - "Bookmarks.GetResultsMatching.AnyTermApproach.NodeCountPerTerm", 0); - histogram_tester.ExpectTotalCount( - "Bookmarks.GetResultsMatching.AnyTermApproach.NodeCountAnyTerms", 0); - histogram_tester.ExpectTotalCount( - "Bookmarks.GetResultsMatching.AnyTermApproach.NodeCountAllTerms", 0); - histogram_tester.ExpectTotalCount( - "Bookmarks.GetResultsMatching.AnyTermApproach.NodeCount", 0); - } } TitledUrlIndexFake* index() { return index_.get(); } @@ -605,16 +550,12 @@ // Makes sure index is updated when a node is removed. TEST_F(TitledUrlIndexTest, Remove_PathIndex) { - base::test::ScopedFeatureList feature_list{kIndexPaths}; - ResetNodes(); - auto* parent_dir = AddNode("foo", GURL("http://foo"), "folder").second; - ASSERT_EQ(0u, GetResultsMatching("foo folder", 10).size()); - ASSERT_EQ(1U, GetResultsMatching("foo folder", 10, true).size()); + ASSERT_EQ(1U, GetResultsMatching("foo folder", 10).size()); index()->RemovePath(parent_dir); - ASSERT_EQ(0U, GetResultsMatching("foo folder", 10, true).size()); - ASSERT_EQ(1U, GetResultsMatching("foo", 10, true).size()); + ASSERT_EQ(0U, GetResultsMatching("foo folder", 10).size()); + ASSERT_EQ(1U, GetResultsMatching("foo", 10).size()); } // Makes sure no more than max queries is returned. @@ -691,9 +632,6 @@ } TEST_F(TitledUrlIndexTest, MatchTitledUrlNodeWithQuery_ApproximateNodeMatch) { - base::test::ScopedFeatureList feature_list{kApproximateNodeMatch}; - ResetNodes(); - // When the query matches the node, should return non `nullopt`. EXPECT_TRUE(index()->MatchTitledUrlNodeWithQuery(u"matching", u"match")); // When the query approximately matches the node, should return `nullopt`. @@ -733,149 +671,93 @@ }; } -TEST_F(TitledUrlIndexTest, RetrieveNodesMatchingAnyTerms) { - base::test::ScopedFeatureList feature_list; - feature_list.InitAndDisableFeature(kIndexPaths); +TEST_F(TitledUrlIndexTest, RetrieveNodesMatchingAnyTerms_PathMatch) { ResetNodes(); - AddNode("term1 term2 other xyz ab", GURL("http://foo.com")); + AddNode("no_match", GURL("http://no_match.com"), "path commo"); + AddNode("common1", GURL("http://foo.com")); + AddNode("common2", GURL("http://foo.com")); + AddNode("common3", GURL("http://foo.com")); + AddNode("common4", GURL("http://foo.com")); - // Should return matches if any input terms match, even if not all node - // terms match. - VerifyRetrieveNodesMatchingAnyTerms("term not", {0}, true, 1, - {{0, 1}, {2, 1}}, 1, 0, 1); + // Should return match even if an input term does not match, as long as it's + // in the path index. + VerifyRetrieveNodesMatchingAnyTerms("term path", {0}); + // Should not return matches if any input term is neither matching nor in the + // path index. + VerifyRetrieveNodesMatchingAnyTerms("term not", {}); + + // If any input term is not in the path index, should do full matching (i.e. + // all input terms need to be non-path matched). + VerifyRetrieveNodesMatchingAnyTerms("term common", {}); + // If all input terms are in the path index, only 1 input term needs to + // non-path match. + VerifyRetrieveNodesMatchingAnyTerms("comm path", {2, 3, 4}); + // Should not return duplicate matches. - VerifyRetrieveNodesMatchingAnyTerms("term term1 term2", {0}, true, 3, - {{1, 2}, {2, 1}}, 1, 0, 1); + VerifyRetrieveNodesMatchingAnyTerms("term term1 term2", {0}); + // Should not early exit when there are no intermediate matches. - VerifyRetrieveNodesMatchingAnyTerms("not term", {0}, true, 1, - {{0, 1}, {2, 1}}, 1, 0, 1); - // Should not match midword. - VerifyRetrieveNodesMatchingAnyTerms("ther ther", {}, true, 0, {{0, 2}}, 0, 0, - 0); + VerifyRetrieveNodesMatchingAnyTerms("path comm", {2, 3, 4}); + + // Should not match midword ('ther' in 'other'). + VerifyRetrieveNodesMatchingAnyTerms("ther ther", {}); + // Short input terms should only return exact matches. - VerifyRetrieveNodesMatchingAnyTerms("xy xy", {}, true, 0, {{0, 2}}, 0, 0, 0); - VerifyRetrieveNodesMatchingAnyTerms("ab ab", {0}, true, 2, {{1, 2}}, 1, 0, 1); + VerifyRetrieveNodesMatchingAnyTerms("xy xy", {}); + VerifyRetrieveNodesMatchingAnyTerms("ab ab", {0}); - // Should short-circuit to `RetrieveNodesMatchingAllTerms()` if the input - // contains just 1 term. - VerifyRetrieveNodesMatchingAnyTerms("x", {}, false, 0, {}, 0, 0, 0); - // Should short-circuit to `RetrieveNodesMatchingAllTerms()` if at least 1 - // term doesn't path match. -} - -TEST_F(TitledUrlIndexTest, RetrieveNodesMatchingAnyTerms_MaxNodes) { - base::test::ScopedFeatureList feature_list; - feature_list.InitAndDisableFeature(kIndexPaths); - ResetNodes(); - - AddNode("common11", GURL("http://foo.com")); - AddNode("common12", GURL("http://foo.com")); - AddNode("common13 uncommon", GURL("http://foo.com")); - AddNode("common21 uncommon1", GURL("http://foo.com")); - AddNode("common22 uncommon1", GURL("http://foo.com")); - AddNode("common23 uncommon1", GURL("http://foo.com")); - - // Should not look for all-term matches if at least 1 term matches at most - // `max_nodes`. - VerifyRetrieveNodesMatchingAnyTerms("uncommon1 uncommon1", {3, 4, 5}, true, 2, - {{3, 2}}, 3, 0, 3); - // Like above, but even if some terms match more than `max_nodes`. Should - // look for per term matches even after `max_nodes` matches have been - // found. - VerifyRetrieveNodesMatchingAnyTerms("common uncommon1", {3, 4, 5}, true, 2, - {{3, 1}, {6, 1}}, 3, 0, 3); - // Should look for all-term matches if all terms match more than - // `ma_nodes`. - VerifyRetrieveNodesMatchingAnyTerms("uncommon uncommon", {2, 3, 4, 5}, true, - 2, {{4, 2}}, 3, 4, 4); - VerifyRetrieveNodesMatchingAnyTerms("common common", {0, 1, 2, 3, 4, 5}, true, - 2, {{6, 2}}, 3, 6, 6); - VerifyRetrieveNodesMatchingAnyTerms("common uncommon", {2, 3, 4, 5}, true, 2, - {{4, 1}, {6, 1}}, 3, 4, 4); - VerifyRetrieveNodesMatchingAnyTerms("common x", {0, 1, 2}, true, 1, - {{0, 1}, {6, 1}}, 3, 0, 3); - // Should not crash if no term has matches. - VerifyRetrieveNodesMatchingAnyTerms("x x", {}, true, 0, {{0, 2}}, 0, 0, 0); + // Allows complete title/URL matches to exceed `max_nodes` (3 in tests). + VerifyRetrieveNodesMatchingAnyTerms("commo commo", {2, 3, 4, 5}); } TEST_F(TitledUrlIndexTest, RetrieveNodesMatchingAnyTerms_PathIndex) { - base::test::ScopedFeatureList feature_list{kIndexPaths}; - ResetNodes(); AddNode("term1 term2 other xyz ab", GURL("http://foo.com"), "parent"); AddNode("term1 term3", GURL("http://foo.com"), "parent2"); - // Should not return matches if any of the input terms are neither path nor - // title/URL matches. - VerifyRetrieveNodesMatchingAnyTerms("term2 term2 not", {}, false, 0, {}, 0, 0, - 0); - // When short-circuiting to matching all terms, should not intersect with path // matching terms, only non-path matching terms. + // Should intersect 'term1' matches only, returning both nodes, even though // the 1st node doesn't match 'parent2'. - VerifyRetrieveNodesMatchingAnyTerms("term1 parent2", {0, 1}, false, 0, {}, 0, - 0, 0); + VerifyRetrieveNodesMatchingAnyTerms("term1 parent2", {0, 1}); // Should intersect 'term1' and 'term2' matches returning the 1st node, // even though it doesn't match 'parent2'. - VerifyRetrieveNodesMatchingAnyTerms("term1 term2 parent2", {0}, false, 0, {}, - 0, 0, 0); + VerifyRetrieveNodesMatchingAnyTerms("term1 term2 parent2", {0}); // Should intersect 'term2' and 'term3' matches returning 0 nodes. - VerifyRetrieveNodesMatchingAnyTerms("term2 term3 parent", {}, false, 0, {}, 0, - 0, 0); + VerifyRetrieveNodesMatchingAnyTerms("term2 term3 parent", {}); } TEST_F(TitledUrlIndexTest, GetResultsMatchingAncestors) { - base::test::ScopedFeatureList feature_list; - feature_list.InitAndDisableFeature(bookmarks::kIndexPaths); - ResetNodes(); - TitledUrlNode* node = AddNode("leaf pare", GURL("http://foo.com"), "parent").first; struct TestData { const std::string query; - const bool match_ancestor_titles; const bool should_be_retrieved; const bool should_have_ancestor_match; - const bool histogram_any_term_approach_used; - const int histogram_terms_count; - const std::vector<std::pair<int, int>> histogram_term_lengths; - const bool histogram_matched_node; } data[] = { - // Should exclude matches with ancestor matches when - // `match_ancestor_titles` is false. - {"leaf parent", false, false, false, false, 2, {{4, 1}, {6, 1}}, false}, // Should allow ancestor matches when `match_ancestor_titles` is true. - {"leaf parent", true, true, true, true, 2, {{4, 1}, {6, 1}}, true}, + {"leaf parent", true, true}, // Should not early exit when there are no accumulated non-ancestor // matches. - {"parent leaf", true, true, true, true, 2, {{4, 1}, {6, 1}}, true}, + {"parent leaf", true, true}, // Should still require at least 1 non-ancestor match when // `match_ancestor_titles` is true. - {"parent parent", true, false, false, true, 2, {{6, 2}}, false}, + {"parent parent", false, false}, // Should set `has_ancestor_match` to true even if a term matched both an // ancestor and title/URL. - {"pare", true, true, true, true, 1, {{4, 1}}, true}, + {"pare", true, true}, // Short inputs should only match exact title or ancestor terms. - {"pa pa", true, false, false, true, 2, {{2, 2}}, false}, + {"pa pa", false, false}, // Should not return matches if a term matches neither the title nor // ancestor. - {"leaf not parent", - true, - false, - false, - true, - 3, - {{3, 1}, {4, 1}, {6, 1}}, - true}, + {"leaf not parent", false, false}, }; for (const TestData& test_data : data) { SCOPED_TRACE("Query: " + test_data.query); - base::HistogramTester histogram_tester; - auto matches = GetResultsMatching(test_data.query, 10, - test_data.match_ancestor_titles); + auto matches = GetResultsMatching(test_data.query, 10); // Verify whether the match. if (test_data.should_be_retrieved) { @@ -885,97 +767,7 @@ test_data.should_have_ancestor_match); } else EXPECT_TRUE(matches.empty()); - - // Verify histograms. - histogram_tester.ExpectUniqueSample( - "Bookmarks.GetResultsMatching.Terms.TermsCount", - test_data.histogram_terms_count, 1); - EXPECT_EQ(CreateBuckets(test_data.histogram_term_lengths), - histogram_tester.GetAllSamples( - "Bookmarks.GetResultsMatching.Terms.TermLength")); - histogram_tester.ExpectUniqueSample( - "Bookmarks.GetResultsMatching.AnyTermApproach.Used", - test_data.histogram_any_term_approach_used, 1); - histogram_tester.ExpectUniqueSample( - "Bookmarks.GetResultsMatching.Nodes.Count", - test_data.histogram_matched_node, 1); - if (test_data.query.size() < 3) { - histogram_tester.ExpectUniqueSample( - "Bookmarks.GetResultsMatching.Nodes.Count." - "InputsShorterThan3CharsLong", - test_data.histogram_matched_node, 1); - histogram_tester.ExpectTotalCount( - "Bookmarks.GetResultsMatching.Nodes.Count.InputsAtLeast3CharsLong", - 0); - } else { - histogram_tester.ExpectUniqueSample( - "Bookmarks.GetResultsMatching.Nodes.Count.InputsAtLeast3CharsLong", - test_data.histogram_matched_node, 1); - histogram_tester.ExpectTotalCount( - "Bookmarks.GetResultsMatching.Nodes.Count." - "InputsShorterThan3CharsLong", - 0); - } - if (test_data.histogram_matched_node) { - histogram_tester.ExpectUniqueSample( - "Bookmarks.GetResultsMatching.Matches.ConsideredCount", 1, 1); - } else { - histogram_tester.ExpectTotalCount( - "Bookmarks.GetResultsMatching.Matches.ConsideredCount", 0); - } - if (test_data.should_be_retrieved) { - histogram_tester.ExpectUniqueSample( - "Bookmarks.GetResultsMatching.Matches.ReturnedCount", 1, 1); - } else if (test_data.histogram_matched_node) { - histogram_tester.ExpectUniqueSample( - "Bookmarks.GetResultsMatching.Matches.ReturnedCount", 0, 1); - } else { - histogram_tester.ExpectTotalCount( - "Bookmarks.GetResultsMatching.Matches.ReturnedCount", 0); - } - EXPECT_EQ(histogram_tester - .GetAllSamples("Bookmarks.GetResultsMatching.Timing.Total") - .size(), - 1u); - EXPECT_EQ(histogram_tester - .GetAllSamples( - "Bookmarks.GetResultsMatching.Timing.RetrievingNodes") - .size(), - 1u); - if (test_data.histogram_matched_node) { - EXPECT_EQ( - histogram_tester - .GetAllSamples("Bookmarks.GetResultsMatching.Timing.SortingNodes") - .size(), - 1u); - EXPECT_EQ(histogram_tester - .GetAllSamples( - "Bookmarks.GetResultsMatching.Timing.CreatingMatches") - .size(), - 1u); - } else { - histogram_tester.ExpectTotalCount( - "Bookmarks.GetResultsMatching.Timing.SortingNodes", 0); - histogram_tester.ExpectTotalCount( - "Bookmarks.GetResultsMatching.Timing.CreatingMatches", 0); - } }; - - { - // With an empty input, most histograms should not be logged. - base::HistogramTester histogram_tester; - auto matches = GetResultsMatching("", 10, true); - EXPECT_EQ(histogram_tester - .GetAllSamples("Bookmarks.GetResultsMatching.Timing.Total") - .size(), - 1u); - histogram_tester.ExpectUniqueSample( - "Bookmarks.GetResultsMatching.Terms.TermsCount", 0, 1); - histogram_tester.ExpectTotalCount( - "Bookmarks.GetResultsMatching.Terms.TermLength", 0); - histogram_tester.ExpectTotalCount( - "Bookmarks.GetResultsMatching.Timing.RetrievingNodes", 0); - } } } // namespace
diff --git a/components/bookmarks/common/bookmark_features.cc b/components/bookmarks/common/bookmark_features.cc index ecfe5e8e..ef84c28a 100644 --- a/components/bookmarks/common/bookmark_features.cc +++ b/components/bookmarks/common/bookmark_features.cc
@@ -8,62 +8,6 @@ namespace bookmarks { -constexpr auto kEnabledByDefaultDesktopOnly = -#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS) - base::FEATURE_DISABLED_BY_DEFAULT; -#else - base::FEATURE_ENABLED_BY_DEFAULT; -#endif - -// If enabled, uses an approximate pre-check to determine if an input matches a -// particular bookmark index node. This pre-check is faster than the more -// accurate check, but it returns false positives; therefore, it's only a -// precursor to and not a replacement for the real check. Does nothing if -// `omnibox::kBookmarkPaths` is disabled. -BASE_FEATURE(kApproximateNodeMatch, - "BookmarkApproximateNodeMatch", - kEnabledByDefaultDesktopOnly); - -// If enabled, uses an alternative approach to loading typed counts for URLs -// when fetching bookmark matches for the bookmark provider. -// - When disabled, for each matching bookmark, it runs 1 SQL query to look up -// its typed count by URL, which is indexed and therefore runs O(n * log(m)), -// where n is the # of bookmark matches, and m is the # of URLs. -// - When enabled, reads all URLs from the DB in 1 scan and stores them to a -// `std::map`. Then for each matching bookmark, it looks up the URL in the -// map. This is O(n*log(m) + m) runtime and requires O(m) additional space. -// This map isn't cached since the DB changes as the user visits and deletes -// visits; and propagating those changes to the cached map would add -// complexity. -BASE_FEATURE(kTypedUrlsMap, - "BookmarkTypedUrlsMap", - base::FEATURE_DISABLED_BY_DEFAULT); - -// If enabled, further limits the maximum number of nodes to fetch when looking -// for bookmark nodes that match any input term. When disabled, the limit is -// 3000, which was picked to be very lax; it should rarely be reached and avoids -// only extreme latency but still allows noticeable latency. Does nothing when -// `omnibox::kBookmarkPaths` is disabled. -BASE_FEATURE(kLimitNumNodesForBookmarkSearch, - "BookmarkLimitNumNodesForBookmarkSearch", - kEnabledByDefaultDesktopOnly); - -// See `kLimitNumNodesForBookmarkSearch`. -const base::FeatureParam<int> kLimitNumNodesForBookmarkSearchCount( - &kLimitNumNodesForBookmarkSearch, - "BookmarkLimitNumNodesForBookmarkSearchCount", - 1000); - -// If enabled, creates and uses a lightweight (compared to the existing -// `TitledUrlIndex`). The index maps the terms in paths and the number of paths -// containing those terms. It's updated on folder rename, creation, and -// deletion. It's not updated when bookmarks or folders are moved. It's used to -// short circuit unioning per-term matches when matching paths, as intersecting -// results in much fewer nodes and processing. Should be disabled if -// `omnibox::kBookmarkPaths` is disabled; otherwise, it'll create the index -// unnecessarily. -BASE_FEATURE(kIndexPaths, "BookmarkIndexPaths", kEnabledByDefaultDesktopOnly); - // If enabled, there will be two different BookmarkModel instances per profile: // one instance for "profile" bookmarks and another instance for "account" // bookmarks. See https://crbug.com/1404250 for details.
diff --git a/components/bookmarks/common/bookmark_features.h b/components/bookmarks/common/bookmark_features.h index e6b17bc..d418d6cf 100644 --- a/components/bookmarks/common/bookmark_features.h +++ b/components/bookmarks/common/bookmark_features.h
@@ -10,15 +10,6 @@ namespace bookmarks { -BASE_DECLARE_FEATURE(kApproximateNodeMatch); - -BASE_DECLARE_FEATURE(kTypedUrlsMap); - -BASE_DECLARE_FEATURE(kLimitNumNodesForBookmarkSearch); -extern const base::FeatureParam<int> kLimitNumNodesForBookmarkSearchCount; - -BASE_DECLARE_FEATURE(kIndexPaths); - BASE_DECLARE_FEATURE(kEnableBookmarksAccountStorage); } // namespace bookmarks
diff --git a/components/cast/message_port/fuchsia/message_port_fuchsia.cc b/components/cast/message_port/fuchsia/message_port_fuchsia.cc index 58acc3f..9890965 100644 --- a/components/cast/message_port/fuchsia/message_port_fuchsia.cc +++ b/components/cast/message_port/fuchsia/message_port_fuchsia.cc
@@ -28,8 +28,8 @@ // MessagePortFuchsia implementation. fidl::InterfaceHandle<::fuchsia::web::MessagePort> TakeClientHandle() final { - DCHECK(!receiver_); - DCHECK(port_.is_bound()); + CHECK(!receiver_); + CHECK(port_.is_bound()); return port_.Unbind(); } @@ -41,8 +41,8 @@ // MessagePort implementation. void SetReceiver(cast_api_bindings::MessagePort::Receiver* receiver) final { - DCHECK(receiver); - DCHECK(!receiver_); + CHECK(receiver); + CHECK(!receiver_); receiver_ = receiver; port_.set_error_handler( [this](zx_status_t status) { MessagePortFuchsia::OnZxError(status); }); @@ -101,8 +101,8 @@ } void ReadNextMessage() { - DCHECK(receiver_); - DCHECK(port_); + CHECK(receiver_); + CHECK(port_); port_->ReceiveMessage( fit::bind_member(this, &MessagePortFuchsiaClient::OnMessageReady)); @@ -140,8 +140,8 @@ // MessagePort implementation. void SetReceiver(cast_api_bindings::MessagePort::Receiver* receiver) final { - DCHECK(receiver); - DCHECK(!receiver_); + CHECK(receiver); + CHECK(!receiver_); receiver_ = receiver; binding_.set_error_handler( [this](zx_status_t status) { MessagePortFuchsia::OnZxError(status); }); @@ -233,7 +233,7 @@ } MessagePortFuchsia* MessagePortFuchsia::FromMessagePort(MessagePort* port) { - DCHECK(port); + CHECK(port); // This is safe because there is one MessagePort implementation per platform // and this is called internally to the implementation. return static_cast<MessagePortFuchsia*>(port); @@ -253,7 +253,7 @@ MessagePortFuchsia* port_fuchsia = FromMessagePort(port.get()); PortType port_type = port_fuchsia->port_type_; - DCHECK_EQ(expected_port_type, port_type) + CHECK_EQ(expected_port_type, port_type) << "Only one implementation of MessagePortFuchsia can be transmitted " "in the same message."; if (expected_port_type != port_type) { @@ -294,7 +294,7 @@ absl::optional<fuchsia::web::FrameError> MessagePortFuchsia::ExtractAndHandleMessageFromFidl( fuchsia::web::WebMessage message) { - DCHECK(receiver_); + CHECK(receiver_); if (!message.has_data()) { return fuchsia::web::FrameError::NO_DATA_IN_MESSAGE; } @@ -334,7 +334,7 @@ } void MessagePortFuchsia::ReportPipeError() { - DCHECK(receiver_); + CHECK(receiver_); receiver_->OnPipeError(); } @@ -346,7 +346,7 @@ bool MessagePortFuchsia::PostMessageWithTransferables( base::StringPiece message, std::vector<std::unique_ptr<MessagePort>> ports) { - DCHECK(receiver_); + CHECK(receiver_); message_queue_.emplace_back(CreateWebMessage(message, std::move(ports))); // Start draining the queue if it was empty beforehand.
diff --git a/components/cast/message_port/fuchsia/message_port_fuchsia.h b/components/cast/message_port/fuchsia/message_port_fuchsia.h index 5b4d89c..59b4008 100644 --- a/components/cast/message_port/fuchsia/message_port_fuchsia.h +++ b/components/cast/message_port/fuchsia/message_port_fuchsia.h
@@ -82,7 +82,7 @@ base::StringPiece message, std::vector<std::unique_ptr<MessagePort>> ports) final; - cast_api_bindings::MessagePort::Receiver* receiver_; + cast_api_bindings::MessagePort::Receiver* receiver_ = nullptr; base::circular_deque<fuchsia::web::WebMessage> message_queue_; private:
diff --git a/components/cronet/ios/Cronet.mm b/components/cronet/ios/Cronet.mm index 1e4f587..190cbbed 100644 --- a/components/cronet/ios/Cronet.mm +++ b/components/cronet/ios/Cronet.mm
@@ -86,6 +86,8 @@ return net::OK; } void SetConfig(const Config& config) override {} + void AddObserver(Observer* observer) override {} + void RemoveObserver(Observer* observer) override {} }; // net::HTTPProtocolHandlerDelegate for Cronet.
diff --git a/components/global_media_controls/public/views/media_item_ui_view.cc b/components/global_media_controls/public/views/media_item_ui_view.cc index 08110706..ddfeb6ed 100644 --- a/components/global_media_controls/public/views/media_item_ui_view.cc +++ b/components/global_media_controls/public/views/media_item_ui_view.cc
@@ -120,64 +120,65 @@ } swipeable_container_ = AddChildView(std::move(swipeable_container)); - gfx::Size dismiss_button_size = - is_cros_ ? kCrOSDismissButtonSize : kDismissButtonSize; - if (base::FeatureList::IsEnabled(media::kGlobalMediaControlsModernUI)) - dismiss_button_size = kModernDismissButtonSize; - - auto dismiss_button_placeholder = std::make_unique<views::View>(); - dismiss_button_placeholder->SetPreferredSize(dismiss_button_size); - dismiss_button_placeholder->SetLayoutManager( - std::make_unique<views::FillLayout>()); - dismiss_button_placeholder_ = dismiss_button_placeholder.get(); - - auto dismiss_button_container = std::make_unique<views::View>(); - dismiss_button_container->SetPreferredSize(dismiss_button_size); - dismiss_button_container->SetLayoutManager( - std::make_unique<views::FillLayout>()); - dismiss_button_container->SetVisible(false); - dismiss_button_container_ = dismiss_button_placeholder_->AddChildView( - std::move(dismiss_button_container)); - - auto dismiss_button = std::make_unique<DismissButton>(base::BindRepeating( - &MediaItemUIView::DismissNotification, base::Unretained(this))); - dismiss_button->SetPreferredSize(dismiss_button_size); - dismiss_button->SetTooltipText(l10n_util::GetStringUTF16( - IDS_GLOBAL_MEDIA_CONTROLS_DISMISS_ICON_TOOLTIP_TEXT)); - dismiss_button_ = - dismiss_button_container_->AddChildView(std::move(dismiss_button)); - UpdateDismissButtonIcon(); - std::unique_ptr<media_message_center::MediaNotificationView> view; if (use_cros_updated_ui) { DCHECK(theme.has_value()); view = std::make_unique<media_message_center::MediaNotificationViewAshImpl>( - this, std::move(item), std::move(dismiss_button_placeholder), - theme.value(), media_display_page.value()); - } else if (base::FeatureList::IsEnabled( - media::kGlobalMediaControlsModernUI)) { - footer_view_ = footer_view_.get(); - view = - std::make_unique<media_message_center::MediaNotificationViewModernImpl>( - this, std::move(item), std::move(dismiss_button_placeholder), - std::move(footer_view), kModernUIWidth, theme); - SetPreferredSize(kModernUISize); + this, std::move(item), theme.value(), media_display_page.value()); } else { - view = std::make_unique<media_message_center::MediaNotificationViewImpl>( - this, std::move(item), std::move(dismiss_button_placeholder), - std::u16string(), kWidth, /*should_show_icon=*/false, theme); + gfx::Size dismiss_button_size = + is_cros_ ? kCrOSDismissButtonSize : kDismissButtonSize; + if (base::FeatureList::IsEnabled(media::kGlobalMediaControlsModernUI)) { + dismiss_button_size = kModernDismissButtonSize; + } - UpdateFooterView(std::move(footer_view)); - SetPreferredSize(kNormalSize); + auto dismiss_button_placeholder = std::make_unique<views::View>(); + dismiss_button_placeholder->SetPreferredSize(dismiss_button_size); + dismiss_button_placeholder->SetLayoutManager( + std::make_unique<views::FillLayout>()); + dismiss_button_placeholder_ = dismiss_button_placeholder.get(); + + auto dismiss_button_container = std::make_unique<views::View>(); + dismiss_button_container->SetPreferredSize(dismiss_button_size); + dismiss_button_container->SetLayoutManager( + std::make_unique<views::FillLayout>()); + dismiss_button_container->SetVisible(false); + dismiss_button_container_ = dismiss_button_placeholder_->AddChildView( + std::move(dismiss_button_container)); + + auto dismiss_button = std::make_unique<DismissButton>(base::BindRepeating( + &MediaItemUIView::DismissNotification, base::Unretained(this))); + dismiss_button->SetPreferredSize(dismiss_button_size); + dismiss_button->SetTooltipText(l10n_util::GetStringUTF16( + IDS_GLOBAL_MEDIA_CONTROLS_DISMISS_ICON_TOOLTIP_TEXT)); + dismiss_button_ = + dismiss_button_container_->AddChildView(std::move(dismiss_button)); + UpdateDismissButtonIcon(); + + slide_out_controller_ = + std::make_unique<views::SlideOutController>(this, this); + + if (base::FeatureList::IsEnabled(media::kGlobalMediaControlsModernUI)) { + footer_view_ = footer_view_.get(); + view = std::make_unique< + media_message_center::MediaNotificationViewModernImpl>( + this, std::move(item), std::move(dismiss_button_placeholder), + std::move(footer_view), kModernUIWidth, theme); + SetPreferredSize(kModernUISize); + } else { + view = std::make_unique<media_message_center::MediaNotificationViewImpl>( + this, std::move(item), std::move(dismiss_button_placeholder), + std::u16string(), kWidth, /*should_show_icon=*/false, theme); + + UpdateFooterView(std::move(footer_view)); + SetPreferredSize(kNormalSize); + } } view_ = swipeable_container_->AddChildView(std::move(view)); UpdateDeviceSelector(std::move(device_selector_view)); ForceExpandedState(); - - slide_out_controller_ = - std::make_unique<views::SlideOutController>(this, this); } MediaItemUIView::~MediaItemUIView() { @@ -375,6 +376,10 @@ } void MediaItemUIView::UpdateDismissButtonIcon() { + if (!dismiss_button_) { + return; + } + int icon_size = is_cros_ ? kCrOSDismissButtonIconSize : kDismissButtonIconSize; if (base::FeatureList::IsEnabled(media::kGlobalMediaControlsModernUI)) @@ -386,6 +391,10 @@ } void MediaItemUIView::UpdateDismissButtonBackground() { + if (!dismiss_button_container_) { + return; + } + if (!has_artwork_) { dismiss_button_container_->SetBackground(nullptr); return; @@ -396,6 +405,10 @@ } void MediaItemUIView::UpdateDismissButtonVisibility() { + if (!dismiss_button_container_) { + return; + } + bool has_focus = false; if (GetFocusManager()) { views::View* focused_view = GetFocusManager()->GetFocusedView();
diff --git a/components/history/core/browser/history_backend_unittest.cc b/components/history/core/browser/history_backend_unittest.cc index c40085cd..1f1f2a9 100644 --- a/components/history/core/browser/history_backend_unittest.cc +++ b/components/history/core/browser/history_backend_unittest.cc
@@ -599,9 +599,9 @@ auto enumerator = url_db->CreateKeywordSearchTermVisitEnumerator(keyword_id, prefix); KeywordSearchTermVisitList matching_terms; - GetAutocompleteSearchTermsFromEnumerator( - *enumerator, /*count=*/SIZE_MAX, /*ignore_duplicate_visits=*/true, - SearchTermRankingPolicy::kRecency, &matching_terms); + GetAutocompleteSearchTermsFromEnumerator(*enumerator, /*count=*/SIZE_MAX, + SearchTermRankingPolicy::kRecency, + &matching_terms); return matching_terms.size(); }
diff --git a/components/history/core/browser/keyword_search_term.h b/components/history/core/browser/keyword_search_term.h index 85fed96..abfda7c 100644 --- a/components/history/core/browser/keyword_search_term.h +++ b/components/history/core/browser/keyword_search_term.h
@@ -36,8 +36,8 @@ // Used for URLs that have a search term associated with them. struct KeywordSearchTermRow { KeywordSearchTermRow() = default; - KeywordSearchTermRow(const KeywordSearchTermRow& other) = default; - ~KeywordSearchTermRow() = default; + KeywordSearchTermRow(KeywordSearchTermRow&& other) = default; + KeywordSearchTermRow& operator=(KeywordSearchTermRow&& other) = default; KeywordID keyword_id{0}; // ID of the keyword. URLID url_id{0}; // ID of the url. @@ -56,7 +56,6 @@ delete; KeywordSearchTermVisitEnumerator& operator=( const KeywordSearchTermVisitEnumerator&) = delete; - ~KeywordSearchTermVisitEnumerator() = default; // Returns the next search term visit or nullptr if no more visits are left.
diff --git a/components/history/core/browser/keyword_search_term_util.cc b/components/history/core/browser/keyword_search_term_util.cc index 8430b72..f1963a6 100644 --- a/components/history/core/browser/keyword_search_term_util.cc +++ b/components/history/core/browser/keyword_search_term_util.cc
@@ -28,22 +28,21 @@ return recency_boost * day_score; } -// Returns whether two search terms are identical, i.e., have the same +// Returns whether two search terms are identical - i.e., they have the same // normalized search terms. -bool IsSameSearchTerm(const KeywordSearchTermVisit& search_term_visit, - const KeywordSearchTermVisit& other_search_term_visit) { - return search_term_visit.normalized_term == - other_search_term_visit.normalized_term; +bool IsSameSearchTerm(const KeywordSearchTermVisit& lhs, + const KeywordSearchTermVisit& rhs) { + return lhs.normalized_term == rhs.normalized_term; } -// Return whether a visit to a search term constitutes a duplicate visit, i.e., -// a visit to the same search term in an interval smaller than +// Return whether a visit to a search term constitutes a duplicative visit - +// i.e., a visit to the same search term in an interval smaller than // kAutocompleteDuplicateVisitIntervalThreshold. // Called with identical search terms only. i.e., IsSameSearchTerm() is true. -bool IsDuplicateVisit(const KeywordSearchTermVisit& search_term_visit, - const KeywordSearchTermVisit& other_search_term_visit) { - return search_term_visit.last_visit_time - - other_search_term_visit.last_visit_time <= +bool IsDuplicativeVisitToSearchTerm(const KeywordSearchTermVisit& lhs, + const KeywordSearchTermVisit& rhs) { + DCHECK(IsSameSearchTerm(lhs, rhs)); + return lhs.last_visit_time - rhs.last_visit_time <= kAutocompleteDuplicateVisitIntervalThreshold; } @@ -54,10 +53,11 @@ // Returns whether two search term visits are in the same timeslot. // Called with identical search terms only. i.e., IsSameSearchTerm() is true. -bool IsSameTimeslot(const KeywordSearchTermVisit& search_term_visit, - const KeywordSearchTermVisit& other_search_term_visit) { - return VisitTimeToTimeslot(search_term_visit.last_visit_time) == - VisitTimeToTimeslot(other_search_term_visit.last_visit_time); +bool IsInSameTimeslot(const KeywordSearchTermVisit& lhs, + const KeywordSearchTermVisit& rhs) { + DCHECK(IsSameSearchTerm(lhs, rhs)); + return VisitTimeToTimeslot(lhs.last_visit_time) == + VisitTimeToTimeslot(rhs.last_visit_time); } } // namespace @@ -84,51 +84,48 @@ return frequency_powered * recency_decayed; } -// SearchTermHelper ------------------------------------------------------------ +// AutocompleteSearchTermHelper ------------------------------------------------ -// A helper class to return keyword search terms with visit counts accumulated -// across visits for use as prefix or zero-prefix suggestions in the omnibox. -class SearchTermHelper { +// A helper class to aggregate keyword search term visits returned by the +// `KeywordSearchTermVisitEnumerator` into unique search terms with +// `visit_count` aggregated across the visits for use as prefix or zero-prefix +// suggestions in the omnibox. +class AutocompleteSearchTermHelper { public: - SearchTermHelper() = default; + AutocompleteSearchTermHelper() = default; + AutocompleteSearchTermHelper(const AutocompleteSearchTermHelper&) = delete; + AutocompleteSearchTermHelper& operator=(const AutocompleteSearchTermHelper&) = + delete; + ~AutocompleteSearchTermHelper() = default; - SearchTermHelper(const SearchTermHelper&) = delete; - SearchTermHelper& operator=(const SearchTermHelper&) = delete; - - ~SearchTermHelper() = default; - - // |enumerator| enumerates keyword search term visits from the URLDatabase. - // |ignore_duplicate_visits| specifies whether duplicative visits to a search - // term should be ignored. - std::unique_ptr<KeywordSearchTermVisit> GetNextSearchTermFromEnumerator( - KeywordSearchTermVisitEnumerator& enumerator, - bool ignore_duplicate_visits) { - // |next_visit| acts as the fast pointer and |last_search_term_| acts as the - // slow pointer accumulating the search term visit counts across visits. + // `enumerator` enumerates keyword search term visits from the URLDatabase. + std::unique_ptr<KeywordSearchTermVisit> GetNextUniqueSearchTermFromEnumerator( + KeywordSearchTermVisitEnumerator& enumerator) { + // `next_visit` acts as the fast pointer and `last_search_term_` acts as the + // slow pointer aggregating the search term visit counts across visits. while (auto next_visit = enumerator.GetNextVisit()) { if (last_search_term_ && IsSameSearchTerm(*next_visit, *last_search_term_)) { - // Ignore duplicative visits, if applicable. - if (ignore_duplicate_visits && - IsDuplicateVisit(*next_visit, *last_search_term_)) { + // Ignore duplicative visits. + if (IsDuplicativeVisitToSearchTerm(*next_visit, *last_search_term_)) { continue; } // Encountered the same search term: - // 1. Move |last_search_term_| forward. + // 1. Move `last_search_term_` forward. // 2. Add up the search term visit count. int visit_count = last_search_term_->visit_count; last_search_term_ = std::move(next_visit); last_search_term_->visit_count += visit_count; } else if (last_search_term_) { - // Encountered a new search term and |last_search_term_| has a value: - // 1. Move |last_search_term_| forward. - // 2. Return the old |last_search_term_|. + // Encountered a new search term: + // 1. Move `last_search_term_` forward. + // 2. Return the old `last_search_term_`. auto search_term_to_return = std::move(last_search_term_); last_search_term_ = std::move(next_visit); return search_term_to_return; } else { - // Encountered a new search term and |last_search_term_| has no value: - // 1. Move |last_search_term_| forward. + // Encountered the first search term: + // 1. Move `last_search_term_` forward. last_search_term_ = std::move(next_visit); } } @@ -144,13 +141,12 @@ void GetAutocompleteSearchTermsFromEnumerator( KeywordSearchTermVisitEnumerator& enumerator, const size_t count, - bool ignore_duplicate_visits, SearchTermRankingPolicy ranking_policy, KeywordSearchTermVisitList* search_terms) { - SearchTermHelper helper; + AutocompleteSearchTermHelper helper; const base::Time now = base::Time::Now(); - while (auto search_term = helper.GetNextSearchTermFromEnumerator( - enumerator, ignore_duplicate_visits)) { + while (auto search_term = + helper.GetNextUniqueSearchTermFromEnumerator(enumerator)) { if (ranking_policy == SearchTermRankingPolicy::kFrecency) { search_term->score = GetFrecencyScore(search_term->visit_count, search_term->last_visit_time, now); @@ -172,40 +168,40 @@ // MostRepeatedSearchTermHelper ------------------------------------------------ -// A helper class to return keyword search terms with frecency scores -// accumulated across days for use in the Most Visited tiles. +// A helper class to aggregate keyword search term visits returned by the +// `KeywordSearchTermVisitEnumerator` into unique search terms with +// `visit_count` and `score` aggregated across the days of visit for use in the +// Most Visited tiles. class MostRepeatedSearchTermHelper { public: MostRepeatedSearchTermHelper() = default; - MostRepeatedSearchTermHelper(const MostRepeatedSearchTermHelper&) = delete; MostRepeatedSearchTermHelper& operator=(const MostRepeatedSearchTermHelper&) = delete; - ~MostRepeatedSearchTermHelper() = default; - // |enumerator| enumerates keyword search term visits from the URLDatabase. - // |now| is the time used to score the search term. - std::unique_ptr<KeywordSearchTermVisit> GetNextSearchTermFromEnumerator( + // `enumerator` enumerates keyword search term visits from the URLDatabase. + // `now` is used to score the unique search terms across the days of visit. + std::unique_ptr<KeywordSearchTermVisit> GetNextUniqueSearchTermFromEnumerator( KeywordSearchTermVisitEnumerator& enumerator, base::Time now) { - const bool ignore_duplicate_visits = + const bool ignore_duplicative_visits = kRepeatableQueriesIgnoreDuplicateVisits.Get(); - // |next_visit| acts as the fast pointer and |last_search_term_| acts as the + // `next_visit` acts as the fast pointer and `last_search_term_` acts as the // slow pointer accumulating the search term score across visits. while (auto next_visit = enumerator.GetNextVisit()) { bool is_same_search_term = last_search_term_ && IsSameSearchTerm(*next_visit, *last_search_term_); if (is_same_search_term && - IsSameTimeslot(*next_visit, *last_search_term_)) { + IsInSameTimeslot(*next_visit, *last_search_term_)) { // Ignore duplicative visits, if applicable. - if (ignore_duplicate_visits && - IsDuplicateVisit(*next_visit, *last_search_term_)) { + if (ignore_duplicative_visits && + IsDuplicativeVisitToSearchTerm(*next_visit, *last_search_term_)) { continue; } - // The same timeslot for the same search term: - // 1. Move |last_search_term_| forward. + // Encountered the same timeslot for the same search term: + // 1. Move `last_search_term_` forward. // 2. Add up the search term visit count in the timeslot. // 3. Carry over the search term score. int visit_count = last_search_term_->visit_count; @@ -217,13 +213,13 @@ } else if (is_same_search_term) { // Ignore duplicative visits, if applicable. - if (ignore_duplicate_visits && - IsDuplicateVisit(*next_visit, *last_search_term_)) { + if (ignore_duplicative_visits && + IsDuplicativeVisitToSearchTerm(*next_visit, *last_search_term_)) { continue; } - // A new timeslot for the same search term: + // Encountered a new timeslot for the same search term: // 1. Update the search term score by adding the last timeslot's score. - // 2. Move |last_search_term_| forward. + // 2. Move `last_search_term_` forward. // 3. Carry over the search term score. double score = last_search_term_->score.value_or(0.0) + @@ -234,10 +230,10 @@ last_search_term_->score = score; } else if (last_search_term_) { - // Encountered a new search term and |last_search_term_| has a value: + // Encountered a new search term: // 1. Update the search term score by adding the last timeslot's score. - // 2. Move |last_search_term_| forward. - // 3. Return the old |last_search_term_|. + // 2. Move `last_search_term_` forward. + // 3. Return the old `last_search_term_`. double score = last_search_term_->score.value_or(0.0) + GetMostVisitedFrecencyScore( @@ -248,13 +244,13 @@ last_search_term_ = std::move(next_visit); return search_term_to_return; } else { - // Encountered a new search term and |last_search_term_| has no value: - // 1. Move |last_search_term_| forward. + // Encountered the first search term: + // 1. Move `last_search_term_` forward. last_search_term_ = std::move(next_visit); } } - // |last_search_term_| has a value: + // `last_search_term_` has a value: // 1. Update the search term score by adding the last timeslot's score. if (last_search_term_) { double score = @@ -280,7 +276,7 @@ MostRepeatedSearchTermHelper helper; const base::Time now = base::Time::Now(); while (auto search_term = - helper.GetNextSearchTermFromEnumerator(enumerator, now)) { + helper.GetNextUniqueSearchTermFromEnumerator(enumerator, now)) { // Exclude searches that have not been repeated in some time. if (now - search_term->last_visit_time > base::Days(kRepeatableQueriesMaxAgeDays.Get())) {
diff --git a/components/history/core/browser/keyword_search_term_util.h b/components/history/core/browser/keyword_search_term_util.h index a82ff3d..15b4b70c 100644 --- a/components/history/core/browser/keyword_search_term_util.h +++ b/components/history/core/browser/keyword_search_term_util.h
@@ -34,29 +34,24 @@ // that are more frequent and more recent (see go/local-zps-frecency-ranking). double GetFrecencyScore(int visit_count, base::Time visit_time, base::Time now); -// Returns up to `count` keyword search terms ordered by descending recency or -// frecency scores for use as prefix or zero-prefix suggestions in the omnibox -// respectively. -// `enumerator` enumerates keyword search term visits from the URLDatabase. It -// must return visits ordered first by `normalized_term` and then by -// `last_visit_time` in ascending order, i.e., from the oldest to the newest. -// `ignore_duplicate_visits` specifies whether duplicative visits to a search -// term should be ignored. A duplicative visit is defined as a visit to the -// same search term in an interval smaller than -// kAutocompleteDuplicateVisitIntervalThreshold. `ranking_policy` specifies -// how the returned keyword search terms should be ordered. +// Returns up to `count` unique keyword search terms ordered by descending +// recency or frecency scores for use in the omnibox. +// - `enumerator` must enumerate keyword search term visits from the URLDatabase +// ordered first by `normalized_term` and then by `last_visit_time` in +// ascending order, i.e., from the oldest to the newest. +// - `ranking_policy` specifies how the returned keyword search terms should be +// ordered. void GetAutocompleteSearchTermsFromEnumerator( KeywordSearchTermVisitEnumerator& enumerator, const size_t count, - bool ignore_duplicate_visits, SearchTermRankingPolicy ranking_policy, KeywordSearchTermVisitList* search_terms); -// Returns up to `count` keyword search terms ordered by descending frecency -// scores accumulated across days for use in the Most Visited tiles. -// `enumerator` enumerates keyword search term visits from the URLDatabase. It -// must return visits ordered first by `normalized_term` and then by -// `last_visit_time` in ascending order, i.e., from the oldest to the newest. +// Returns up to `count` unique keyword search terms ordered by descending +// frecency scores for use in the Most Visited tiles. +// - `enumerator` must enumerate keyword search term visits from the URLDatabase +// ordered first by `normalized_term` and then by `last_visit_time` in +// ascending order, i.e., from the oldest to the newest. void GetMostRepeatedSearchTermsFromEnumerator( KeywordSearchTermVisitEnumerator& enumerator, const size_t count,
diff --git a/components/history/core/browser/url_database.cc b/components/history/core/browser/url_database.cc index bcb37bc..4141467 100644 --- a/components/history/core/browser/url_database.cc +++ b/components/history/core/browser/url_database.cc
@@ -558,7 +558,7 @@ row.keyword_id = statement.ColumnInt64(0); row.term = term; row.normalized_term = statement.ColumnString16(2); - rows->push_back(row); + rows->push_back(std::move(row)); } return true; }
diff --git a/components/history/core/browser/url_database_unittest.cc b/components/history/core/browser/url_database_unittest.cc index 016c90d..d6bedae 100644 --- a/components/history/core/browser/url_database_unittest.cc +++ b/components/history/core/browser/url_database_unittest.cc
@@ -224,9 +224,9 @@ auto enumerator_1 = CreateKeywordSearchTermVisitEnumerator(keyword_id, u"f"); ASSERT_TRUE(enumerator_1); KeywordSearchTermVisitList matches; - GetAutocompleteSearchTermsFromEnumerator( - *enumerator_1, /*count=*/SIZE_MAX, /*ignore_duplicate_visits=*/false, - SearchTermRankingPolicy::kRecency, &matches); + GetAutocompleteSearchTermsFromEnumerator(*enumerator_1, /*count=*/SIZE_MAX, + SearchTermRankingPolicy::kRecency, + &matches); ASSERT_EQ(2U, matches.size()); EXPECT_EQ(u"Food", matches[0]->term); EXPECT_EQ(u"food", matches[0]->normalized_term); @@ -243,8 +243,7 @@ ASSERT_TRUE(enumerator_2); matches.clear(); GetAutocompleteSearchTermsFromEnumerator( - *enumerator_2, /*count=*/1U, /*ignore_duplicate_visits=*/false, - SearchTermRankingPolicy::kRecency, &matches); + *enumerator_2, /*count=*/1U, SearchTermRankingPolicy::kRecency, &matches); ASSERT_EQ(1U, matches.size()); EXPECT_EQ(u"Food", matches[0]->term); EXPECT_EQ(u"food", matches[0]->normalized_term); @@ -267,9 +266,9 @@ auto enumerator_3 = CreateKeywordSearchTermVisitEnumerator(keyword_id, u"f"); ASSERT_TRUE(enumerator_3); matches.clear(); - GetAutocompleteSearchTermsFromEnumerator( - *enumerator_3, /*count=*/SIZE_MAX, /*ignore_duplicate_visits=*/false, - SearchTermRankingPolicy::kRecency, &matches); + GetAutocompleteSearchTermsFromEnumerator(*enumerator_3, /*count=*/SIZE_MAX, + SearchTermRankingPolicy::kRecency, + &matches); ASSERT_EQ(0U, matches.size()); ASSERT_FALSE(GetKeywordSearchTermRow(foo_url_3_id, &keyword_search_term_row)); @@ -327,9 +326,9 @@ auto enumerator_1 = CreateKeywordSearchTermVisitEnumerator(keyword_id); ASSERT_TRUE(enumerator_1); KeywordSearchTermVisitList matches; - GetAutocompleteSearchTermsFromEnumerator( - *enumerator_1, /*count=*/SIZE_MAX, /*ignore_duplicate_visits=*/true, - SearchTermRankingPolicy::kFrecency, &matches); + GetAutocompleteSearchTermsFromEnumerator(*enumerator_1, /*count=*/SIZE_MAX, + SearchTermRankingPolicy::kFrecency, + &matches); ASSERT_EQ(2U, matches.size()); EXPECT_EQ(u"FOO", matches[0]->term); EXPECT_EQ(u"foo", matches[0]->normalized_term); @@ -345,9 +344,9 @@ auto enumerator_2 = CreateKeywordSearchTermVisitEnumerator(keyword_id); ASSERT_TRUE(enumerator_2); matches.clear(); - GetAutocompleteSearchTermsFromEnumerator( - *enumerator_2, /*count=*/1U, /*ignore_duplicate_visits=*/true, - SearchTermRankingPolicy::kFrecency, &matches); + GetAutocompleteSearchTermsFromEnumerator(*enumerator_2, /*count=*/1U, + SearchTermRankingPolicy::kFrecency, + &matches); ASSERT_EQ(1U, matches.size()); EXPECT_EQ(u"FOO", matches[0]->term); EXPECT_EQ(u"foo", matches[0]->normalized_term); @@ -371,9 +370,9 @@ auto enumerator_3 = CreateKeywordSearchTermVisitEnumerator(keyword_id); ASSERT_TRUE(enumerator_3); matches.clear(); - GetAutocompleteSearchTermsFromEnumerator( - *enumerator_3, /*count=*/SIZE_MAX, /*ignore_duplicate_visits=*/true, - SearchTermRankingPolicy::kFrecency, &matches); + GetAutocompleteSearchTermsFromEnumerator(*enumerator_3, /*count=*/SIZE_MAX, + SearchTermRankingPolicy::kFrecency, + &matches); ASSERT_EQ(0U, matches.size()); ASSERT_FALSE(GetKeywordSearchTermRow(foo_url_3_id, &keyword_search_term_row)); @@ -517,9 +516,9 @@ auto enumerator = CreateKeywordSearchTermVisitEnumerator(1, u"visit"); ASSERT_TRUE(enumerator); matches.clear(); - GetAutocompleteSearchTermsFromEnumerator( - *enumerator, /*count=*/SIZE_MAX, /*ignore_duplicate_visits=*/false, - SearchTermRankingPolicy::kRecency, &matches); + GetAutocompleteSearchTermsFromEnumerator(*enumerator, /*count=*/SIZE_MAX, + SearchTermRankingPolicy::kRecency, + &matches); ASSERT_EQ(0U, matches.size()); }
diff --git a/components/media_message_center/media_notification_view_ash_impl.cc b/components/media_message_center/media_notification_view_ash_impl.cc index 589330b..6ee4a1d 100644 --- a/components/media_message_center/media_notification_view_ash_impl.cc +++ b/components/media_message_center/media_notification_view_ash_impl.cc
@@ -32,13 +32,13 @@ constexpr auto kBorderInsets = gfx::Insets::TLBR(16, 8, 8, 8); constexpr auto kMainRowInsets = gfx::Insets::VH(0, 8); constexpr auto kInfoColumnInsets = gfx::Insets::TLBR(0, 8, 0, 0); +constexpr auto kPlayPauseContainerInsets = gfx::Insets::VH(8, 0); constexpr auto kProgressViewInsets = gfx::Insets::VH(0, 14); constexpr auto kSourceLabelInsets = gfx::Insets::TLBR(0, 0, 10, 0); constexpr int kMainSeparator = 12; constexpr int kMainRowSeparator = 8; constexpr int kMediaInfoSeparator = 4; -constexpr int kPlayPauseContainerSeparator = 8; constexpr int kPlayPauseIconSize = 26; constexpr int kControlsIconSize = 20; constexpr int kBackgroundCornerRadius = 12; @@ -112,12 +112,10 @@ MediaNotificationViewAshImpl::MediaNotificationViewAshImpl( MediaNotificationContainer* container, base::WeakPtr<MediaNotificationItem> item, - std::unique_ptr<views::View> dismiss_button, NotificationTheme theme, MediaDisplayPage media_display_page) : container_(container), item_(std::move(item)), theme_(theme) { DCHECK(container_); - DCHECK(dismiss_button); DCHECK(item_); SetBorder(views::CreateEmptyBorder(kBorderInsets)); @@ -189,14 +187,11 @@ // |play_pause_container| holds the play/pause button and dismiss button. auto* play_pause_container = - main_row->AddChildView(std::make_unique<views::View>()); - play_pause_container - ->SetLayoutManager(std::make_unique<views::BoxLayout>( - views::BoxLayout::Orientation::kVertical, gfx::Insets(), - kPlayPauseContainerSeparator)) - ->set_cross_axis_alignment(views::BoxLayout::CrossAxisAlignment::kEnd); + main_row->AddChildView(std::make_unique<views::BoxLayoutView>()); + play_pause_container->SetInsideBorderInsets(kPlayPauseContainerInsets); + play_pause_container->SetCrossAxisAlignment( + views::BoxLayout::CrossAxisAlignment::kEnd); - play_pause_container->AddChildView(std::move(dismiss_button)); play_pause_button_ = CreateMediaButton(play_pause_container, MediaSessionAction::kPlay); play_pause_button_->SetBackground(views::CreateRoundedRectBackground(
diff --git a/components/media_message_center/media_notification_view_ash_impl.h b/components/media_message_center/media_notification_view_ash_impl.h index 2e48aa6b..18f8f65 100644 --- a/components/media_message_center/media_notification_view_ash_impl.h +++ b/components/media_message_center/media_notification_view_ash_impl.h
@@ -45,7 +45,6 @@ MediaNotificationViewAshImpl(MediaNotificationContainer* container, base::WeakPtr<MediaNotificationItem> item, - std::unique_ptr<views::View> dismiss_button, NotificationTheme theme, MediaDisplayPage media_display_page); MediaNotificationViewAshImpl(const MediaNotificationViewAshImpl&) = delete;
diff --git a/components/media_message_center/media_notification_view_ash_impl_unittest.cc b/components/media_message_center/media_notification_view_ash_impl_unittest.cc index 9765b5f..9eccc7a 100644 --- a/components/media_message_center/media_notification_view_ash_impl_unittest.cc +++ b/components/media_message_center/media_notification_view_ash_impl_unittest.cc
@@ -84,8 +84,8 @@ std::unique_ptr<MediaNotificationViewAshImpl> CreateView( MediaDisplayPage media_display_page) { return std::make_unique<MediaNotificationViewAshImpl>( - container_.get(), item_->GetWeakPtr(), std::make_unique<views::View>(), - NotificationTheme(), media_display_page); + container_.get(), item_->GetWeakPtr(), NotificationTheme(), + media_display_page); } void EnableAllActions() {
diff --git a/components/omnibox/browser/bookmark_provider.cc b/components/omnibox/browser/bookmark_provider.cc index f40eb5a..6fdd322 100644 --- a/components/omnibox/browser/bookmark_provider.cc +++ b/components/omnibox/browser/bookmark_provider.cc
@@ -22,7 +22,6 @@ #include "components/omnibox/browser/omnibox_triggered_feature_service.h" #include "components/omnibox/browser/scoring_functor.h" #include "components/omnibox/browser/titled_url_match_utils.h" -#include "components/omnibox/common/omnibox_features.h" #include "components/prefs/pref_service.h" #include "third_party/metrics_proto/omnibox_focus_type.pb.h" #include "third_party/metrics_proto/omnibox_input_type.pb.h" @@ -141,46 +140,10 @@ std::vector<TitledUrlMatch> BookmarkProvider::GetMatchesWithBookmarkPaths( const AutocompleteInput& input, size_t kMaxBookmarkMatches) { - // Determining whether the |kBookmarkPaths| feature had, or would have had, an - // impact for counterfactual logging is expensive as it requires invoking - // |BookmarkModel::GetBookmarksMatching()| twice. Therefore, the param - // |kBookmarkPathsCounterfactual| determines whether to counterfactual log: - // - When empty, counterfactual logging won't occur. - // - When set to "control" counterfactual logging will occur like usual; i.e. - // path matched bookmarks won't be returned but will be compared to - // determine if the feature triggered. - // - When set to "enabled", counterfactual logging will occur and path matched - // bookmarks will be returned. - std::string counterfactual = - OmniboxFieldTrial::kBookmarkPathsCounterfactual.Get(); - - bool match_paths = base::FeatureList::IsEnabled(omnibox::kBookmarkPaths) && - counterfactual != "control"; - query_parser::MatchingAlgorithm matching_algorithm = GetMatchingAlgorithm(input); - - if (counterfactual.empty()) { - return local_or_syncable_bookmark_model_->GetBookmarksMatching( - input.text(), kMaxBookmarkMatches, matching_algorithm, match_paths); - } - - std::vector<TitledUrlMatch> matches_without_paths = - local_or_syncable_bookmark_model_->GetBookmarksMatching( - input.text(), kMaxBookmarkMatches, matching_algorithm); - std::vector<TitledUrlMatch> matches_with_paths = - local_or_syncable_bookmark_model_->GetBookmarksMatching( - input.text(), kMaxBookmarkMatches, matching_algorithm, true); - DCHECK_LE(matches_without_paths.size(), matches_with_paths.size()); - - // It's unnecessary to compare the matches themselves because all - // |matches_without_paths| should be contained in |matches_with_paths|. - if (matches_without_paths.size() != matches_with_paths.size()) { - client_->GetOmniboxTriggeredFeatureService()->FeatureTriggered( - OmniboxTriggeredFeatureService::Feature::kBookmarkPaths); - } - - return match_paths ? matches_with_paths : matches_without_paths; + return local_or_syncable_bookmark_model_->GetBookmarksMatching( + input.text(), kMaxBookmarkMatches, matching_algorithm); } query_parser::MatchingAlgorithm BookmarkProvider::GetMatchingAlgorithm(
diff --git a/components/omnibox/browser/bookmark_provider.h b/components/omnibox/browser/bookmark_provider.h index 0feebf2e..0436116 100644 --- a/components/omnibox/browser/bookmark_provider.h +++ b/components/omnibox/browser/bookmark_provider.h
@@ -52,8 +52,7 @@ void DoAutocomplete(const AutocompleteInput& input); // Get the matches from |local_or_syncable_bookmark_model_| using the - // appropriate matching algorithm, determined by |GetMatchingAlgorithm()|, and - // path matching algorithm, determined by the |kBookmarkPaths| base::feature. + // appropriate matching algorithm, determined by |GetMatchingAlgorithm()|. std::vector<bookmarks::TitledUrlMatch> GetMatchesWithBookmarkPaths( const AutocompleteInput& input, size_t kMaxBookmarkMatches);
diff --git a/components/omnibox/browser/bookmark_provider_unittest.cc b/components/omnibox/browser/bookmark_provider_unittest.cc index 591c8f4d..8050864 100644 --- a/components/omnibox/browser/bookmark_provider_unittest.cc +++ b/components/omnibox/browser/bookmark_provider_unittest.cc
@@ -727,53 +727,10 @@ auto short_feature = OmniboxTriggeredFeatureService::Feature:: kShortBookmarkSuggestionsByTotalInputLength; - auto paths_feature = OmniboxTriggeredFeatureService::Feature::kBookmarkPaths; - { - // When the feature is off, should not return path matched bookmarks nor - // trigger counterfactual logging. - SCOPED_TRACE("feature disabled"); - base::test::ScopedFeatureList feature_list; - feature_list.InitAndDisableFeature(omnibox::kBookmarkPaths); - TestNumMatchesAndTriggeredFeature("carefully other", 0, {short_feature}); - } - - { - // When enabled without counterfactual logging, should return path matched - // bookmark but not trigger counterfactual logging even it path matched. - SCOPED_TRACE("feature enabled without counterfactual"); - base::test::ScopedFeatureList feature_list; - feature_list.InitAndEnableFeature(omnibox::kBookmarkPaths); - TestNumMatchesAndTriggeredFeature("carefully other", 1, {short_feature}); - } - - { - // When enabled with "control" counterfactual logging, should not return - // path matched bookmarks but trigger counterfactual logging if it path - // matched. - SCOPED_TRACE("feature enabled with control counterfactual"); - base::test::ScopedFeatureList feature_list; - feature_list.InitAndEnableFeatureWithParameters( - omnibox::kBookmarkPaths, - {{OmniboxFieldTrial::kBookmarkPathsCounterfactual.name, "control"}}); - TestNumMatchesAndTriggeredFeature("carefully", 1, {short_feature}); - TestNumMatchesAndTriggeredFeature("carefully other", 0, - {short_feature, paths_feature}); - } - - { - // When enabled with "enabled" counterfactual logging, should return path - // matched bookmarks and trigger counterfactual logging if it path - // matched. - SCOPED_TRACE("feature enabled with enabled counterfactual"); - base::test::ScopedFeatureList feature_list; - feature_list.InitAndEnableFeatureWithParameters( - omnibox::kBookmarkPaths, - {{OmniboxFieldTrial::kBookmarkPathsCounterfactual.name, "enabled"}}); - TestNumMatchesAndTriggeredFeature("carefully", 1, {short_feature}); - TestNumMatchesAndTriggeredFeature("carefully other", 1, - {short_feature, paths_feature}); - } + // Should return path matched bookmark. + SCOPED_TRACE("feature enabled without counterfactual"); + TestNumMatchesAndTriggeredFeature("carefully other", 1, {short_feature}); } // Make sure that user input is trimmed correctly for starter pack keyword mode.
diff --git a/components/omnibox/browser/local_history_zero_suggest_provider.cc b/components/omnibox/browser/local_history_zero_suggest_provider.cc index 22902c3e..9ac412f1 100644 --- a/components/omnibox/browser/local_history_zero_suggest_provider.cc +++ b/components/omnibox/browser/local_history_zero_suggest_provider.cc
@@ -204,8 +204,8 @@ template_url_service->GetDefaultSearchProvider()->id()); if (enumerator) { history::GetAutocompleteSearchTermsFromEnumerator( - *enumerator, max_matches_, /*ignore_duplicate_visits=*/true, - history::SearchTermRankingPolicy::kFrecency, &results); + *enumerator, max_matches_, history::SearchTermRankingPolicy::kFrecency, + &results); } DCHECK_LE(results.size(), max_matches_); base::UmaHistogramTimes(
diff --git a/components/omnibox/browser/local_history_zero_suggest_provider_unittest.cc b/components/omnibox/browser/local_history_zero_suggest_provider_unittest.cc index e4126fe4..06b7696 100644 --- a/components/omnibox/browser/local_history_zero_suggest_provider_unittest.cc +++ b/components/omnibox/browser/local_history_zero_suggest_provider_unittest.cc
@@ -509,7 +509,7 @@ default_search_provider()->id()); ASSERT_TRUE(enumerator_1); history::GetAutocompleteSearchTermsFromEnumerator( - *enumerator_1, /*count=*/SIZE_MAX, /*ignore_duplicate_visits=*/false, + *enumerator_1, /*count=*/SIZE_MAX, history::SearchTermRankingPolicy::kFrecency, &visits); EXPECT_EQ(1U, visits.size()); EXPECT_EQ(u"not to be deleted", visits[0]->normalized_term); @@ -521,7 +521,7 @@ other_search_provider->id()); ASSERT_TRUE(enumerator_2); history::GetAutocompleteSearchTermsFromEnumerator( - *enumerator_2, /*count=*/SIZE_MAX, /*ignore_duplicate_visits=*/false, + *enumerator_2, /*count=*/SIZE_MAX, history::SearchTermRankingPolicy::kFrecency, &visits); EXPECT_EQ(1U, visits.size()); EXPECT_EQ(u"hello world", visits[0]->normalized_term);
diff --git a/components/omnibox/browser/omnibox.mojom b/components/omnibox/browser/omnibox.mojom index 58b259f..55682d6 100644 --- a/components/omnibox/browser/omnibox.mojom +++ b/components/omnibox/browser/omnibox.mojom
@@ -134,9 +134,6 @@ // to appear in the results if they currently are not allowed to or to prevent // them from appearing in the results if they are currently permitted to. ToggleSuggestionGroupIdVisibility(int32 suggestion_group_id); - // Logs the time it took in milliseconds since the first character (in a - // series of characters) was typed until Autocomplete results were painted. - LogCharTypedToRepaintLatency(mojo_base.mojom.TimeDelta latency); // Executes the Pedal Action. match_selection_timestamp is the number of // microseconds since Jan. 1, 1970 (ECMAScript epoch). ExecuteAction(uint8 line,
diff --git a/components/omnibox/browser/omnibox_edit_model.cc b/components/omnibox/browser/omnibox_edit_model.cc index 62e5389..5f1d7d7 100644 --- a/components/omnibox/browser/omnibox_edit_model.cc +++ b/components/omnibox/browser/omnibox_edit_model.cc
@@ -299,7 +299,7 @@ // popup is closed. std::u16string user_text; if (user_input_in_progress_) { - const std::u16string display_text = view_->GetText(); + const std::u16string display_text = GetText(); if (!MaybePrependKeyword(display_text).empty()) user_text = display_text; // Else case is user deleted all the text. The expectation (which matches @@ -321,7 +321,9 @@ // view regardless of whether there is saved state. ResetDisplayTexts(); - view_->RevertAll(); + if (view_) { + view_->RevertAll(); + } // Restore the autocomplete controller's input, or clear it if this is a new // tab. input_ = state ? state->autocomplete_input : AutocompleteInput(); @@ -349,8 +351,9 @@ if (state->user_input_in_progress) { // NOTE: Be sure to set keyword-related state AFTER invoking // SetUserText(), as SetUserText() clears the keyword state. - if (!state->user_text.empty() || !state->keyword.empty()) + if ((!state->user_text.empty() || !state->keyword.empty()) && view_) { view_->SetUserText(state->user_text, false); + } keyword_ = state->keyword; is_keyword_hint_ = state->is_keyword_hint; keyword_mode_entry_method_ = state->keyword_mode_entry_method; @@ -361,7 +364,9 @@ InternalSetUserText(state->user_text); // We let the View manage restoring the cursor position afterwards. - view_->SetWindowTextAndCaretPos(state->user_text, 0, false, false); + if (view_) { + view_->SetWindowTextAndCaretPos(state->user_text, 0, false, false); + } } } @@ -447,17 +452,20 @@ // No need to unelide if we are already displaying the full URL. LocationBarModel* location_bar_model = delegate()->GetLocationBarModel(); - if (view_->GetText() == location_bar_model->GetFormattedFullURL()) + if (GetText() == location_bar_model->GetFormattedFullURL()) { return false; + } // Set the user text to the unelided URL, but don't change // |user_input_in_progress_|. This is to save the unelided URL on tab switch. InternalSetUserText(url_for_editing_); - view_->SetWindowTextAndCaretPos(url_for_editing_, 0, false, false); + if (view_) { + view_->SetWindowTextAndCaretPos(url_for_editing_, 0, false, false); - // Select all in reverse to ensure the beginning of the URL is shown. - view_->SelectAll(true /* reversed */); + // Select all in reverse to ensure the beginning of the URL is shown. + view_->SelectAll(true /* reversed */); + } return true; } @@ -595,13 +603,15 @@ bool OmniboxEditModel::ShouldShowCurrentPageIcon() const { // If the popup is open, don't show the current page's icon. The caller is // instead expected to show the current match's icon. - if (PopupIsOpen()) + if (PopupIsOpen()) { return false; + } // On the New Tab Page, the omnibox textfield is empty. We want to display // the default search provider favicon instead of the NTP security icon. - if (view_->GetText().empty()) + if (GetText().empty()) { return false; + } // If user input is not in progress, always show the current page's icon. if (!user_input_in_progress()) @@ -609,8 +619,7 @@ // If user input is in progress, keep showing the current page's icon so long // as the text matches the current page's URL, elided or unelided. - return view_->GetText() == display_text_ || - view_->GetText() == url_for_editing_; + return GetText() == display_text_ || GetText() == url_for_editing_; } void OmniboxEditModel::UpdateInput(bool has_selected_text, @@ -660,14 +669,18 @@ keyword_mode_entry_method_ = OmniboxEventProto::INVALID; has_temporary_text_ = false; size_t start, end; - view_->GetSelectionBounds(&start, &end); + if (view_) { + view_->GetSelectionBounds(&start, &end); + } current_match_ = AutocompleteMatch(); // First home the cursor, so view of text is scrolled to left, then correct // it. |SetCaretPos()| doesn't scroll the text, so doing that first wouldn't // accomplish anything. std::u16string current_permanent_url = GetPermanentDisplayText(); - view_->SetWindowTextAndCaretPos(current_permanent_url, 0, false, true); - view_->SetCaretPos(std::min(current_permanent_url.length(), start)); + if (view_) { + view_->SetWindowTextAndCaretPos(current_permanent_url, 0, false, true); + view_->SetCaretPos(std::min(current_permanent_url.length(), start)); + } client_->OnRevert(); } @@ -676,6 +689,9 @@ const std::u16string input_text = MaybePrependKeyword(user_text_); size_t start, cursor_position; + // This method currently only works when there's a view, but ideally the + // model should be primary for determining such state. + CHECK(view_); view_->GetSelectionBounds(&start, &cursor_position); // For keyword searches, the text that AutocompleteInput expects is @@ -763,7 +779,9 @@ base::TimeTicks match_selection_timestamp) { DCHECK(CanPasteAndGo(text)); - view_->RevertAll(); + if (view_) { + view_->RevertAll(); + } AutocompleteMatch match; GURL alternate_nav_url; ClassifyString(text, &match, &alternate_nav_url); @@ -800,7 +818,7 @@ keyword_mode_entry_method_ = entry_method; std::u16string display_text = - user_input_in_progress_ ? view_->GetText() : std::u16string(); + user_input_in_progress_ ? GetText() : std::u16string(); size_t caret_pos = display_text.length(); if (entry_method == OmniboxEventProto::QUESTION_MARK) { display_text.erase(0, 1); @@ -808,9 +826,12 @@ } InternalSetUserText(display_text); - view_->SetWindowTextAndCaretPos(display_text, caret_pos, true, false); - if (entry_method == OmniboxEventProto::KEYBOARD_SHORTCUT) - view_->SelectAll(false); + if (view_) { + view_->SetWindowTextAndCaretPos(display_text, caret_pos, true, false); + if (entry_method == OmniboxEventProto::KEYBOARD_SHORTCUT) { + view_->SelectAll(false); + } + } EmitEnteredKeywordModeHistogram(entry_method, default_search_provider); } @@ -831,8 +852,6 @@ return; } - DCHECK(popup_view_); - const AutocompleteMatch& match = result().match_at(selection.line); if (selection.state == OmniboxPopupSelection::FOCUSED_BUTTON_HEADER) { @@ -909,16 +928,19 @@ // which we don't want to switch back to when exiting keyword mode; see // comments in ClearKeyword(). const AutocompleteMatch& match = CurrentMatch(nullptr); - if (user_text_.empty()) { - // Ensure the current selection is saved before showing keyword mode - // so that moving to another line and then reverting the text will restore - // the current state properly. - view_->OnTemporaryTextMaybeChanged(MaybeStripKeyword(match.fill_into_edit), - match, !has_temporary_text_, true); - } else { - view_->OnTemporaryTextMaybeChanged(user_text_, match, !has_temporary_text_, - true); - view_->UpdatePopup(); + if (view_) { + if (user_text_.empty()) { + // Ensure the current selection is saved before showing keyword mode + // so that moving to another line and then reverting the text will restore + // the current state properly. + view_->OnTemporaryTextMaybeChanged( + MaybeStripKeyword(match.fill_into_edit), match, !has_temporary_text_, + true); + } else { + view_->OnTemporaryTextMaybeChanged(user_text_, match, + !has_temporary_text_, true); + view_->UpdatePopup(); + } } base::RecordAction(base::UserMetricsAction("AcceptedKeywordHint")); @@ -930,7 +952,7 @@ } void OmniboxEditModel::AcceptTemporaryTextAsUserText() { - InternalSetUserText(view_->GetText()); + InternalSetUserText(GetText()); has_temporary_text_ = false; if (user_input_in_progress_ || !in_revert_) @@ -938,8 +960,9 @@ } void OmniboxEditModel::ClearKeyword() { - if (!is_keyword_selected()) + if (!is_keyword_selected() || !view_) { return; + } TRACE_EVENT0("omnibox", "OmniboxEditModel::ClearKeyword"); autocomplete_controller()->Stop(false); @@ -1045,7 +1068,9 @@ void OmniboxEditModel::ClearAdditionalText() { TRACE_EVENT0("omnibox", "OmniboxEditModel::ClearAdditionalText"); - view_->SetAdditionalText(std::u16string()); + if (view_) { + view_->SetAdditionalText(std::u16string()); + } } void OmniboxEditModel::OnSetFocus(bool control_down) { @@ -1089,7 +1114,7 @@ // Send the textfield contents exactly as-is, as otherwise the verbatim // match can be wrong. The full page URL is anyways in set_current_url(). // Don't attempt to use https as the default scheme for these requests. - input_ = AutocompleteInput(view_->GetText(), GetPageClassification(), + input_ = AutocompleteInput(GetText(), GetPageClassification(), client_->GetSchemeClassifier(), /*should_use_https_as_default_scheme=*/false, client_->GetHttpsPortForTesting(), @@ -1129,7 +1154,9 @@ paste_state_ = NONE; control_key_state_ = UP; #if BUILDFLAG(IS_WIN) - view_->HideImeIfNeeded(); + if (view_) { + view_->HideImeIfNeeded(); + } #endif } @@ -1150,7 +1177,9 @@ // we clear it. if (client_->CurrentPageExists() && !client_->IsLoading()) { client_->DiscardNonCommittedNavigations(); - view_->Update(); + if (view_) { + view_->Update(); + } } // Close the popup if it's open. @@ -1158,7 +1187,9 @@ PopupIsOpen()) { base::UmaHistogramEnumeration(kOmniboxEscapeHistogramName, OmniboxEscapeAction::kClosePopup); - view_->CloseOmniboxPopup(); + if (view_) { + view_->CloseOmniboxPopup(); + } return true; } @@ -1174,8 +1205,10 @@ // unnecessary. However, that's not always the case (see // `user_input_in_progress_` comment in the header). DCHECK(!popup_was_open || user_input_was_in_progress || user_text_.empty()); - view_->RevertAll(); - view_->SelectAll(true); + if (view_) { + view_->RevertAll(); + view_->SelectAll(true); + } if (user_input_was_in_progress || popup_was_open) { base::UmaHistogramEnumeration( kOmniboxEscapeHistogramName, @@ -1294,7 +1327,9 @@ // the popup immediately. if (!user_input_in_progress_) InternalSetUserText(url_for_editing_); - view_->UpdatePopup(); + if (view_) { + view_->UpdatePopup(); + } return true; } return false; @@ -1349,7 +1384,9 @@ has_temporary_text_ = true; inline_autocompletion_.clear(); prefix_autocompletion_.clear(); - view_->OnInlineAutocompleteTextCleared(); + if (view_) { + view_->OnInlineAutocompleteTextCleared(); + } } // Arrowing around the popup cancels control-enter. ConsumeCtrlKey(); @@ -1364,17 +1401,21 @@ base::FeatureList::IsEnabled(omnibox::kRedoCurrentMatch) ? current_match_ : CurrentMatch(nullptr); - view_->OnTemporaryTextMaybeChanged( - MaybeStripKeyword(temporary_text), match, - save_original_selection && original_user_text_with_keyword_.empty(), - true); + if (view_) { + view_->OnTemporaryTextMaybeChanged( + MaybeStripKeyword(temporary_text), match, + save_original_selection && original_user_text_with_keyword_.empty(), + true); + } return; } inline_autocompletion_ = inline_autocompletion; prefix_autocompletion_ = prefix_autocompletion; if (inline_autocompletion_.empty() && prefix_autocompletion_.empty()) { - view_->OnInlineAutocompleteTextCleared(); + if (view_) { + view_->OnInlineAutocompleteTextCleared(); + } } const std::u16string& user_text = @@ -1397,7 +1438,9 @@ // that case the RevertTemporaryTextAndPopup() call below will reset the // caret or selection correctly so the caret positioning we do here won't // matter. - view_->SetWindowTextAndCaretPos(user_text, 0, false, true); + if (view_) { + view_->SetWindowTextAndCaretPos(user_text, 0, false, true); + } } else { std::u16string display_text; std::vector<gfx::Range> selections = {}; @@ -1405,12 +1448,15 @@ selections.emplace_back( display_text.size(), user_text.length() + prefix_autocompletion_.length()); - if (prefix_autocompletion_.length()) + if (prefix_autocompletion_.length()) { selections.emplace_back(0, prefix_autocompletion_.length()); - view_->OnInlineAutocompleteTextMaybeChanged(display_text, selections, - prefix_autocompletion_, - inline_autocompletion_); - view_->SetAdditionalText(additional_text); + } + if (view_) { + view_->OnInlineAutocompleteTextMaybeChanged(display_text, selections, + prefix_autocompletion_, + inline_autocompletion_); + view_->SetAdditionalText(additional_text); + } } // We need to invoke OnChanged in case the destination url changed (as could // happen when control is toggled). @@ -1464,7 +1510,7 @@ if (!state_changes.text_differs && (!state_changes.selection_differs || (inline_autocompletion_.empty() && prefix_autocompletion_.empty()))) { - if (state_changes.keyword_differs) { + if (state_changes.keyword_differs && view_) { // We won't need the below logic for creating a keyword by a space at the // end or in the middle, or by typing a '?', but we do need to update the // popup view because the keyword can change without the text changing, @@ -1496,7 +1542,9 @@ no_selection && CreatedKeywordSearchByInsertingSpaceInMiddle( *state_changes.old_text, user_text_, state_changes.new_sel_start); - view_->UpdatePopup(); + if (view_) { + view_->UpdatePopup(); + } if (allow_exact_keyword_match_) { keyword_mode_entry_method_ = OmniboxEventProto::SPACE_IN_MIDDLE; const TemplateURL* turl = @@ -1576,7 +1624,9 @@ "Omnibox.CutOrCopyAllText"; void OmniboxEditModel::SetAccessibilityLabel(const AutocompleteMatch& match) { - view_->SetAccessibilityLabel(view_->GetText(), match, true); + if (view_) { + view_->SetAccessibilityLabel(view_->GetText(), match, true); + } } void OmniboxEditModel::InternalSetUserText(const std::u16string& text) { @@ -1585,7 +1635,9 @@ just_deleted_text_ = false; inline_autocompletion_.clear(); prefix_autocompletion_.clear(); - view_->OnInlineAutocompleteTextCleared(); + if (view_) { + view_->OnInlineAutocompleteTextCleared(); + } } std::u16string OmniboxEditModel::MaybeStripKeyword( @@ -1649,7 +1701,7 @@ user_input_in_progress() ? (base::FeatureList::IsEnabled(omnibox::kRedoCurrentMatch) ? user_text_ - : view_->GetText()) + : GetText()) : url_for_editing_; client_->GetAutocompleteClassifier()->Classify( @@ -1674,14 +1726,16 @@ // 2. If there's no default match at all. // // The original selection will be restored in OnRevertTemporaryText() below. - if (!user_input_in_progress_ || !result().default_match()) { + if ((!user_input_in_progress_ || !result().default_match()) && view_) { view_->SetWindowTextAndCaretPos(input_.text(), /*caret_pos=*/0, /*update_popup=*/false, /*notify_text_changed=*/true); } - const AutocompleteMatch& match = CurrentMatch(nullptr); - view_->OnRevertTemporaryText(match.fill_into_edit, match); + if (view_) { + const AutocompleteMatch& match = CurrentMatch(nullptr); + view_->OnRevertTemporaryText(match.fill_into_edit, match); + } } bool OmniboxEditModel::ShouldPreventElision() const { @@ -2099,7 +2153,7 @@ // URL instead of the elided URL to avoid HTTPS downgrading. std::u16string text_for_desired_tld_navigation = input_.text(); if (has_temporary_text_) { - text_for_desired_tld_navigation = view_->GetText(); + text_for_desired_tld_navigation = GetText(); } else if (!user_input_in_progress()) { text_for_desired_tld_navigation = url_for_editing_; } @@ -2200,7 +2254,7 @@ DCHECK_LT(selection.action_index, match.actions.size()); match.actions[selection.action_index]->Execute(context); - { + if (view_) { // This block resets omnibox to unedited state and closes popup, which // may not seem necessary in cases of navigation but makes sense for // taking Pedal actions in general. @@ -2370,7 +2424,6 @@ IDNA2008DeviationCharacter deviation_char_in_hostname = IDNA2008DeviationCharacter::kNone; - TemplateURLService* service = client_->GetTemplateURLService(); TemplateURL* template_url = match.GetTemplateURL(service, false); if (template_url) { @@ -2382,7 +2435,7 @@ // Don't increment usage count for extension keywords. if (client_->ProcessExtensionKeyword(input_text, template_url, match, disposition)) { - if (disposition != WindowOpenDisposition::NEW_BACKGROUND_TAB) { + if (disposition != WindowOpenDisposition::NEW_BACKGROUND_TAB && view_) { view_->RevertAll(); } return; @@ -2444,7 +2497,7 @@ } } - if (disposition != WindowOpenDisposition::NEW_BACKGROUND_TAB) { + if (disposition != WindowOpenDisposition::NEW_BACKGROUND_TAB && view_) { base::AutoReset<bool> tmp(&in_revert_, true); view_->RevertAll(); // Revert the box to its unedited state. } @@ -2597,8 +2650,9 @@ const bool was_caret_visible = is_caret_visible(); focus_state_ = state; if (focus_state_ != OMNIBOX_FOCUS_NONE && - is_caret_visible() != was_caret_visible) + is_caret_visible() != was_caret_visible && view_) { view_->ApplyCaretVisibility(); + } client_->OnFocusChanged(focus_state_, reason); } @@ -2618,3 +2672,13 @@ } } } + +std::u16string OmniboxEditModel::GetText() const { + // Once the model owns primary text, the check for `view_` won't be needed. + if (view_) { + return view_->GetText(); + } else { + NOTREACHED(); + return u""; + } +}
diff --git a/components/omnibox/browser/omnibox_edit_model.h b/components/omnibox/browser/omnibox_edit_model.h index 3f2c960..4e0f751f 100644 --- a/components/omnibox/browser/omnibox_edit_model.h +++ b/components/omnibox/browser/omnibox_edit_model.h
@@ -635,12 +635,19 @@ // changes. void OnFaviconFetched(const GURL& page_url, const gfx::Image& icon); + // Returns view text if there is a view. Until the model is made the primary + // data source, this should not be called when there's no view. + std::u16string GetText() const; + // NOTE: |client_| must outlive |omnibox_controller_|, as the latter has a // reference to the former. std::unique_ptr<OmniboxClient> client_; std::unique_ptr<OmniboxController> omnibox_controller_; + // This may be null if the model is instantiated by the Realbox. Ideally, + // the model should not depend so much on the view as a primary data source, + // and the view should accurately reflect model state as source of truth. raw_ptr<OmniboxView> view_; raw_ptr<OmniboxEditModelDelegate> edit_model_delegate_;
diff --git a/components/omnibox/browser/omnibox_field_trial.cc b/components/omnibox/browser/omnibox_field_trial.cc index 371d43bb..afb26ff 100644 --- a/components/omnibox/browser/omnibox_field_trial.cc +++ b/components/omnibox/browser/omnibox_field_trial.cc
@@ -927,13 +927,6 @@ "ShortBookmarkSuggestionsByTotalInputLengthThreshold", 3); -// Bookmark paths. - -const base::FeatureParam<std::string> kBookmarkPathsCounterfactual( - &omnibox::kBookmarkPaths, - "OmniboxBookmarkPathsCounterfactual", - ""); - // Shortcut Expanding bool IsShortcutExpandingEnabled() {
diff --git a/components/omnibox/browser/omnibox_field_trial.h b/components/omnibox/browser/omnibox_field_trial.h index 8eb0cce..fdbd113 100644 --- a/components/omnibox/browser/omnibox_field_trial.h +++ b/components/omnibox/browser/omnibox_field_trial.h
@@ -544,9 +544,6 @@ extern const base::FeatureParam<int> kShortBookmarkSuggestionsByTotalInputLengthThreshold; -// Bookmark paths. -extern const base::FeatureParam<std::string> kBookmarkPathsCounterfactual; - // Shortcut Expanding. bool IsShortcutExpandingEnabled();
diff --git a/components/omnibox/browser/omnibox_triggered_feature_service.h b/components/omnibox/browser/omnibox_triggered_feature_service.h index f552836..61e6828 100644 --- a/components/omnibox/browser/omnibox_triggered_feature_service.h +++ b/components/omnibox/browser/omnibox_triggered_feature_service.h
@@ -19,7 +19,7 @@ // corresponding entry should be added in the UMA histograms. enum class Feature { kRichAutocompletion = 0, - kBookmarkPaths = 1, + // kBookmarkPaths = 1, // Obsolete, launched and logging code removed. kShortBookmarkSuggestionsByTotalInputLength = 2, kFuzzyUrlSuggestions = 3, kHistoryClusterSuggestion = 4,
diff --git a/components/omnibox/browser/omnibox_triggered_feature_service_unittest.cc b/components/omnibox/browser/omnibox_triggered_feature_service_unittest.cc index 05e087c..5da54b72 100644 --- a/components/omnibox/browser/omnibox_triggered_feature_service_unittest.cc +++ b/components/omnibox/browser/omnibox_triggered_feature_service_unittest.cc
@@ -45,11 +45,11 @@ TEST_F(OmniboxTriggeredFeatureServiceTest, TwoFeaturesTriggered) { service_.FeatureTriggered( - OmniboxTriggeredFeatureService::Feature::kBookmarkPaths); + OmniboxTriggeredFeatureService::Feature::kRemoteSearchFeature); service_.FeatureTriggered(OmniboxTriggeredFeatureService::Feature:: kShortBookmarkSuggestionsByTotalInputLength); RecordAndExpectFeatures( - {OmniboxTriggeredFeatureService::Feature::kBookmarkPaths, + {OmniboxTriggeredFeatureService::Feature::kRemoteSearchFeature, OmniboxTriggeredFeatureService::Feature:: kShortBookmarkSuggestionsByTotalInputLength}); @@ -131,14 +131,14 @@ TEST_F(OmniboxTriggeredFeatureServiceTest, ResetInput) { service_.FeatureTriggered( - OmniboxTriggeredFeatureService::Feature::kBookmarkPaths); + OmniboxTriggeredFeatureService::Feature::kRemoteSearchFeature); service_.ResetInput(); service_.FeatureTriggered(OmniboxTriggeredFeatureService::Feature:: kShortBookmarkSuggestionsByTotalInputLength); RecordAndExpectFeatures( {OmniboxTriggeredFeatureService::Feature:: kShortBookmarkSuggestionsByTotalInputLength}, - {OmniboxTriggeredFeatureService::Feature::kBookmarkPaths, + {OmniboxTriggeredFeatureService::Feature::kRemoteSearchFeature, OmniboxTriggeredFeatureService::Feature:: kShortBookmarkSuggestionsByTotalInputLength}); }
diff --git a/components/omnibox/browser/search_provider.cc b/components/omnibox/browser/search_provider.cc index 6f3b5e3..1d7cedf 100644 --- a/components/omnibox/browser/search_provider.cc +++ b/components/omnibox/browser/search_provider.cc
@@ -684,8 +684,7 @@ default_url->id(), input_.text()); if (enumerator) { history::GetAutocompleteSearchTermsFromEnumerator( - *enumerator, num_matches, /*ignore_duplicate_visits=*/true, - history::SearchTermRankingPolicy::kRecency, + *enumerator, num_matches, history::SearchTermRankingPolicy::kRecency, &raw_default_history_results_); } DCHECK_LE(raw_default_history_results_.size(), num_matches); @@ -696,8 +695,7 @@ keyword_url->id(), keyword_input_.text()); if (enumerator) { history::GetAutocompleteSearchTermsFromEnumerator( - *enumerator, num_matches, /*ignore_duplicate_visits=*/true, - history::SearchTermRankingPolicy::kRecency, + *enumerator, num_matches, history::SearchTermRankingPolicy::kRecency, &raw_keyword_history_results_); } DCHECK_LE(raw_keyword_history_results_.size(), num_matches);
diff --git a/components/omnibox/browser/titled_url_match_utils.cc b/components/omnibox/browser/titled_url_match_utils.cc index d9a5997..a51d91d4 100644 --- a/components/omnibox/browser/titled_url_match_utils.cc +++ b/components/omnibox/browser/titled_url_match_utils.cc
@@ -16,7 +16,6 @@ #include "components/omnibox/browser/history_provider.h" #include "components/omnibox/browser/omnibox_field_trial.h" #include "components/omnibox/browser/url_prefix.h" -#include "components/omnibox/common/omnibox_features.h" #include "components/query_parser/snippet.h" #include "components/url_formatter/url_formatter.h" @@ -75,11 +74,8 @@ // Display the URL only if the input matches the URL but not the path. // Otherwise, display the path, even if the input matches both or neither. - // Except if kBookmarkPaths is disabled, in which case, always display the - // URL. - bool show_path = base::FeatureList::IsEnabled(omnibox::kBookmarkPaths) && - (titled_url_match.has_ancestor_match || - titled_url_match.url_match_positions.empty()); + bool show_path = titled_url_match.has_ancestor_match || + titled_url_match.url_match_positions.empty(); match.contents = show_path ? path : formatted_url; // The path can become stale (when the bookmark is moved). So persist the URL // instead when creating shortcuts.
diff --git a/components/omnibox/browser/titled_url_match_utils_unittest.cc b/components/omnibox/browser/titled_url_match_utils_unittest.cc index cb1cdb80..aefacb40 100644 --- a/components/omnibox/browser/titled_url_match_utils_unittest.cc +++ b/components/omnibox/browser/titled_url_match_utils_unittest.cc
@@ -107,7 +107,8 @@ {3, ACMatchClassification::URL}, }; ACMatchClassifications expected_description_class = { - {0, ACMatchClassification::MATCH}, {3, ACMatchClassification::NONE}, + {0, ACMatchClassification::MATCH}, + {3, ACMatchClassification::NONE}, }; std::u16string expected_inline_autocompletion(u"gle.com"); @@ -252,13 +253,11 @@ } TEST_F(TitledUrlMatchUtilsTest, EmptyInlineAutocompletion) { - base::test::ScopedFeatureList feature_list; - feature_list.InitAndDisableFeature({omnibox::kBookmarkPaths}); - // The search term matches the title but not the URL. Since there is no URL - // match, the inline autocompletion string will be empty. + // Since there is no URL prefix match, the inline autocompletion string will + // be empty. std::u16string input_text(u"goo"); std::u16string match_title(u"Email by Google"); - GURL match_url("http://www.gmail.com/"); + GURL match_url("http://www.gmail.com/google"); AutocompleteMatchType::Type type = AutocompleteMatchType::BOOKMARK_TITLE; int relevance = 123; int bookmark_count = 3; @@ -267,7 +266,8 @@ bookmarks::TitledUrlMatch titled_url_match; titled_url_match.node = &node; titled_url_match.title_match_positions = {{9, 12}}; - titled_url_match.url_match_positions = {}; + titled_url_match.url_match_positions = {{21, 24}}; + titled_url_match.has_ancestor_match = false; scoped_refptr<FakeAutocompleteProvider> provider = new FakeAutocompleteProvider(AutocompleteProvider::Type::TYPE_BOOKMARK); @@ -280,9 +280,13 @@ titled_url_match, type, relevance, bookmark_count, provider.get(), classifier, input, fixed_up_input); + // 'goo' in 'gmail.com/google' ACMatchClassifications expected_contents_class = { {0, ACMatchClassification::URL}, + {10, ACMatchClassification::URL | ACMatchClassification::MATCH}, + {13, ACMatchClassification::URL}, }; + // 'goo' in 'Email by Google' ACMatchClassifications expected_description_class = { {0, ACMatchClassification::NONE}, {9, ACMatchClassification::MATCH}, @@ -293,7 +297,7 @@ EXPECT_EQ(type, autocomplete_match.type); EXPECT_EQ(relevance, autocomplete_match.relevance); EXPECT_EQ(match_url, autocomplete_match.destination_url); - EXPECT_EQ(u"gmail.com", autocomplete_match.contents); + EXPECT_EQ(u"gmail.com/google", autocomplete_match.contents); EXPECT_TRUE(base::ranges::equal(expected_contents_class, autocomplete_match.contents_class)) << "EXPECTED: " << ACMatchClassificationsAsString(expected_contents_class) @@ -302,7 +306,7 @@ EXPECT_EQ(match_title, autocomplete_match.description); EXPECT_TRUE(base::ranges::equal(expected_description_class, autocomplete_match.description_class)); - EXPECT_EQ(u"www.gmail.com", autocomplete_match.fill_into_edit); + EXPECT_EQ(u"www.gmail.com/google", autocomplete_match.fill_into_edit); EXPECT_FALSE(autocomplete_match.allowed_to_be_default_match); EXPECT_TRUE(autocomplete_match.inline_autocompletion.empty()); } @@ -341,35 +345,8 @@ expected_description); }; - // Invokes |test()| with the 4 combinations of |has_url_match| true|false x - // |has_ancestor_match| true|false. - auto test_with_and_without_url_and_ancestor_matches = - [&](std::string title, std::string url, std::string expected_contents, - std::string expected_description) { - for (bool has_url_match : {false, true}) { - for (bool has_ancestor_match : {false, true}) { - test(title, url, has_url_match, has_ancestor_match, - expected_contents, expected_description); - } - } - }; - - { - base::test::ScopedFeatureList feature_list; - feature_list.InitAndDisableFeature({omnibox::kBookmarkPaths}); - SCOPED_TRACE("Feature disabled"); - test_with_and_without_url_and_ancestor_matches("title", "https://url.com", - "url.com", "title"); - } - { - SCOPED_TRACE("Feature enabled"); - base::test::ScopedFeatureList feature_list; - feature_list.InitAndEnableFeature(omnibox::kBookmarkPaths); - test("title", "https://url.com", false, false, "grandparent/parent", - "title"); - test("title", "https://url.com", true, false, "url.com", "title"); - test("title", "https://url.com", false, true, "grandparent/parent", - "title"); - test("title", "https://url.com", true, true, "grandparent/parent", "title"); - } + test("title", "https://url.com", false, false, "grandparent/parent", "title"); + test("title", "https://url.com", true, false, "url.com", "title"); + test("title", "https://url.com", false, true, "grandparent/parent", "title"); + test("title", "https://url.com", true, true, "grandparent/parent", "title"); }
diff --git a/components/omnibox/common/omnibox_features.cc b/components/omnibox/common/omnibox_features.cc index c23019d5..44971b8 100644 --- a/components/omnibox/common/omnibox_features.cc +++ b/components/omnibox/common/omnibox_features.cc
@@ -300,15 +300,6 @@ "OmniboxShortBookmarkSuggestionsByTotalInputLength", base::FEATURE_ENABLED_BY_DEFAULT); -// If enabled, inputs may match bookmark paths. These path matches won't -// contribute to scoring. E.g. 'planets jupiter' can suggest a bookmark titled -// 'Jupiter' with URL 'en.wikipedia.org/wiki/Jupiter' located in a path -// containing 'planet.' -// TODO(manukh): Clean up 4/4/23 when m112 reaches stable. -BASE_FEATURE(kBookmarkPaths, - "OmniboxBookmarkPaths", - base::FEATURE_ENABLED_BY_DEFAULT); - // If enabled, when updating or creating a shortcut, the last word of the input // is expanded, if possible, to a complete word in the suggestion description. BASE_FEATURE(kShortcutExpanding,
diff --git a/components/omnibox/common/omnibox_features.h b/components/omnibox/common/omnibox_features.h index bd77d9c..adf9191 100644 --- a/components/omnibox/common/omnibox_features.h +++ b/components/omnibox/common/omnibox_features.h
@@ -74,7 +74,6 @@ BASE_DECLARE_FEATURE(kDisableCGIParamMatching); BASE_DECLARE_FEATURE(kShortBookmarkSuggestions); BASE_DECLARE_FEATURE(kShortBookmarkSuggestionsByTotalInputLength); -BASE_DECLARE_FEATURE(kBookmarkPaths); BASE_DECLARE_FEATURE(kShortcutExpanding); BASE_DECLARE_FEATURE(kShortcutBoost); // TODO(crbug.com/1202964): Clean up feature flag used in staged roll-out of
diff --git a/components/pdf/renderer/pdf_accessibility_tree.cc b/components/pdf/renderer/pdf_accessibility_tree.cc index 2131bb3..67148229 100644 --- a/components/pdf/renderer/pdf_accessibility_tree.cc +++ b/components/pdf/renderer/pdf_accessibility_tree.cc
@@ -234,8 +234,8 @@ } } -void FinishStaticNode(ui::AXNodeData** static_text_node, - std::string* static_text) { +void BuildStaticNode(ui::AXNodeData** static_text_node, + std::string* static_text) { // If we're in the middle of building a static text node, finish it before // moving on to the next object. if (*static_text_node) { @@ -377,7 +377,7 @@ } } -ui::AXNodeData* CreateNode( +ui::AXNodeData* CreateAndAppendNode( ax::mojom::Role role, ax::mojom::Restriction restriction, content::RenderAccessibility* render_accessibility, @@ -410,9 +410,9 @@ ui::AXNodeData* pdf_root_node) { // Create a status node that conveys a notification message and add it under // the PDF root node as the first node. - ui::AXNodeData* node_ptr = - CreateNode(ax::mojom::Role::kStatus, ax::mojom::Restriction::kReadOnly, - render_accessibility, nodes); + ui::AXNodeData* node_ptr = CreateAndAppendNode( + ax::mojom::Role::kStatus, ax::mojom::Restriction::kReadOnly, + render_accessibility, nodes); // Set the origin of this status node to be offscreen with a 1x1 rectangle as // this status node doesn't have a visual element. The origin of the doc is // (0, 0), so setting (-1, -1) will make this node offscreen. @@ -543,7 +543,7 @@ // `text_run_index`, then push the link node in the paragraph. if (IsObjectWithRangeInTextRun(links_, current_link_index_, text_run_index)) { - FinishStaticNode(&static_text_node, &static_text); + BuildStaticNode(&static_text_node, &static_text); const chrome_pdf::AccessibilityLinkInfo& link = links_[current_link_index_++]; AddLinkToParaNode(link, para_node, &previous_on_line_node, @@ -554,34 +554,34 @@ } else if (IsObjectInTextRun(images_, current_image_index_, text_run_index)) { - FinishStaticNode(&static_text_node, &static_text); + BuildStaticNode(&static_text_node, &static_text); AddImageToParaNode(images_[current_image_index_++], para_node, &text_run_index); continue; } else if (IsObjectWithRangeInTextRun( highlights_, current_highlight_index_, text_run_index)) { - FinishStaticNode(&static_text_node, &static_text); + BuildStaticNode(&static_text_node, &static_text); AddHighlightToParaNode(highlights_[current_highlight_index_++], para_node, &previous_on_line_node, &text_run_index); } else if (IsObjectInTextRun(text_fields_, current_text_field_index_, text_run_index) && pdf_forms_enabled) { - FinishStaticNode(&static_text_node, &static_text); + BuildStaticNode(&static_text_node, &static_text); AddTextFieldToParaNode(text_fields_[current_text_field_index_++], para_node, &text_run_index); continue; } else if (IsObjectInTextRun(buttons_, current_button_index_, text_run_index) && pdf_forms_enabled) { - FinishStaticNode(&static_text_node, &static_text); + BuildStaticNode(&static_text_node, &static_text); AddButtonToParaNode(buttons_[current_button_index_++], para_node, &text_run_index); continue; } else if (IsObjectInTextRun(choice_fields_, current_choice_field_index_, text_run_index) && pdf_forms_enabled) { - FinishStaticNode(&static_text_node, &static_text); + BuildStaticNode(&static_text_node, &static_text); AddChoiceFieldToParaNode(choice_fields_[current_choice_field_index_++], para_node, &text_run_index); continue; @@ -631,14 +631,14 @@ } if (text_run_index == text_runs_.size() - 1) { - FinishStaticNode(&static_text_node, &static_text); + BuildStaticNode(&static_text_node, &static_text); break; } if (!previous_on_line_node) { if (BreakParagraph(text_runs_, text_run_index, paragraph_spacing_threshold_)) { - FinishStaticNode(&static_text_node, &static_text); + BuildStaticNode(&static_text_node, &static_text); para_node = nullptr; } } @@ -670,9 +670,9 @@ } ui::AXNodeData* CreateParagraphNode(float font_size) { - ui::AXNodeData* para_node = CreateNode(ax::mojom::Role::kParagraph, - ax::mojom::Restriction::kReadOnly, - render_accessibility_, nodes_); + ui::AXNodeData* para_node = CreateAndAppendNode( + ax::mojom::Role::kParagraph, ax::mojom::Restriction::kReadOnly, + render_accessibility_, nodes_); para_node->AddBoolAttribute(ax::mojom::BoolAttribute::kIsLineBreakingObject, true); @@ -691,7 +691,7 @@ ui::AXNodeData* CreateStaticTextNode( const chrome_pdf::PageCharacterIndex& page_char_index) { - ui::AXNodeData* static_text_node = CreateNode( + ui::AXNodeData* static_text_node = CreateAndAppendNode( ax::mojom::Role::kStaticText, ax::mojom::Restriction::kReadOnly, render_accessibility_, nodes_); static_text_node->SetNameFrom(ax::mojom::NameFrom::kContents); @@ -702,7 +702,7 @@ ui::AXNodeData* CreateInlineTextBoxNode( const chrome_pdf::AccessibilityTextRunInfo& text_run, const chrome_pdf::PageCharacterIndex& page_char_index) { - ui::AXNodeData* inline_text_box_node = CreateNode( + ui::AXNodeData* inline_text_box_node = CreateAndAppendNode( ax::mojom::Role::kInlineTextBox, ax::mojom::Restriction::kReadOnly, render_accessibility_, nodes_); inline_text_box_node->SetNameFrom(ax::mojom::NameFrom::kContents); @@ -746,9 +746,9 @@ ui::AXNodeData* CreateLinkNode( const chrome_pdf::AccessibilityLinkInfo& link) { - ui::AXNodeData* link_node = - CreateNode(ax::mojom::Role::kLink, ax::mojom::Restriction::kReadOnly, - render_accessibility_, nodes_); + ui::AXNodeData* link_node = CreateAndAppendNode( + ax::mojom::Role::kLink, ax::mojom::Restriction::kReadOnly, + render_accessibility_, nodes_); link_node->AddStringAttribute(ax::mojom::StringAttribute::kUrl, link.url); link_node->AddStringAttribute(ax::mojom::StringAttribute::kName, @@ -764,9 +764,9 @@ ui::AXNodeData* CreateImageNode( const chrome_pdf::AccessibilityImageInfo& image) { - ui::AXNodeData* image_node = - CreateNode(ax::mojom::Role::kImage, ax::mojom::Restriction::kReadOnly, - render_accessibility_, nodes_); + ui::AXNodeData* image_node = CreateAndAppendNode( + ax::mojom::Role::kImage, ax::mojom::Restriction::kReadOnly, + render_accessibility_, nodes_); if (image.alt_text.empty()) { image_node->AddStringAttribute( @@ -782,7 +782,7 @@ ui::AXNodeData* CreateHighlightNode( const chrome_pdf::AccessibilityHighlightInfo& highlight) { - ui::AXNodeData* highlight_node = CreateNode( + ui::AXNodeData* highlight_node = CreateAndAppendNode( ax::mojom::Role::kPdfActionableHighlight, ax::mojom::Restriction::kReadOnly, render_accessibility_, nodes_); @@ -800,16 +800,16 @@ ui::AXNodeData* CreatePopupNoteNode( const chrome_pdf::AccessibilityHighlightInfo& highlight) { - ui::AXNodeData* popup_note_node = - CreateNode(ax::mojom::Role::kNote, ax::mojom::Restriction::kReadOnly, - render_accessibility_, nodes_); + ui::AXNodeData* popup_note_node = CreateAndAppendNode( + ax::mojom::Role::kNote, ax::mojom::Restriction::kReadOnly, + render_accessibility_, nodes_); popup_note_node->AddStringAttribute( ax::mojom::StringAttribute::kRoleDescription, l10n_util::GetStringUTF8(IDS_AX_ROLE_DESCRIPTION_PDF_POPUP_NOTE)); popup_note_node->relative_bounds.bounds = highlight.bounds; - ui::AXNodeData* static_popup_note_text_node = CreateNode( + ui::AXNodeData* static_popup_note_text_node = CreateAndAppendNode( ax::mojom::Role::kStaticText, ax::mojom::Restriction::kReadOnly, render_accessibility_, nodes_); @@ -829,8 +829,8 @@ ? ax::mojom::Restriction::kReadOnly : ax::mojom::Restriction::kNone; ui::AXNodeData* text_field_node = - CreateNode(ax::mojom::Role::kTextField, restriction, - render_accessibility_, nodes_); + CreateAndAppendNode(ax::mojom::Role::kTextField, restriction, + render_accessibility_, nodes_); text_field_node->AddStringAttribute(ax::mojom::StringAttribute::kName, text_field.name); @@ -851,8 +851,8 @@ ? ax::mojom::Restriction::kReadOnly : ax::mojom::Restriction::kNone; ui::AXNodeData* button_node = - CreateNode(GetRoleForButtonType(button.type), restriction, - render_accessibility_, nodes_); + CreateAndAppendNode(GetRoleForButtonType(button.type), restriction, + render_accessibility_, nodes_); button_node->AddStringAttribute(ax::mojom::StringAttribute::kName, button.name); button_node->AddState(ax::mojom::State::kFocusable); @@ -882,8 +882,8 @@ const chrome_pdf::AccessibilityChoiceFieldOptionInfo& choice_field_option, ax::mojom::Restriction restriction) { ui::AXNodeData* listbox_option_node = - CreateNode(ax::mojom::Role::kListBoxOption, restriction, - render_accessibility_, nodes_); + CreateAndAppendNode(ax::mojom::Role::kListBoxOption, restriction, + render_accessibility_, nodes_); listbox_option_node->AddStringAttribute(ax::mojom::StringAttribute::kName, choice_field_option.name); @@ -902,7 +902,7 @@ ax::mojom::Restriction restriction = choice_field.is_read_only ? ax::mojom::Restriction::kReadOnly : ax::mojom::Restriction::kNone; - ui::AXNodeData* listbox_node = CreateNode( + ui::AXNodeData* listbox_node = CreateAndAppendNode( ax::mojom::Role::kListBox, restriction, render_accessibility_, nodes_); if (choice_field.type != chrome_pdf::ChoiceFieldType::kComboBox) { @@ -944,8 +944,8 @@ ax::mojom::Role input_role = choice_field.has_editable_text_box ? ax::mojom::Role::kTextFieldWithComboBox : ax::mojom::Role::kComboBoxMenuButton; - ui::AXNodeData* combobox_input_node = - CreateNode(input_role, restriction, render_accessibility_, nodes_); + ui::AXNodeData* combobox_input_node = CreateAndAppendNode( + input_role, restriction, render_accessibility_, nodes_); combobox_input_node->AddStringAttribute(ax::mojom::StringAttribute::kName, choice_field.name); for (const chrome_pdf::AccessibilityChoiceFieldOptionInfo& option : @@ -973,8 +973,8 @@ ? ax::mojom::Restriction::kReadOnly : ax::mojom::Restriction::kNone; ui::AXNodeData* combobox_node = - CreateNode(ax::mojom::Role::kComboBoxGrouping, restriction, - render_accessibility_, nodes_); + CreateAndAppendNode(ax::mojom::Role::kComboBoxGrouping, restriction, + render_accessibility_, nodes_); ui::AXNodeData* input_element = CreateComboboxInputNode(choice_field, restriction); ui::AXNodeData* list_element = @@ -1190,9 +1190,9 @@ // If we don't have a paragraph node, create a new one. if (!para_node) { - para_node = CreateNode(ax::mojom::Role::kParagraph, - ax::mojom::Restriction::kReadOnly, - render_accessibility_, nodes_); + para_node = CreateAndAppendNode(ax::mojom::Role::kParagraph, + ax::mojom::Restriction::kReadOnly, + render_accessibility_, nodes_); page_node_->child_ids.push_back(para_node->id); } // Push all the links not anchored to any text run to the last paragraph. @@ -1513,9 +1513,9 @@ ClearAccessibilityNodes(); page_count_ = doc_info.page_count; - doc_node_ = - CreateNode(ax::mojom::Role::kPdfRoot, ax::mojom::Restriction::kReadOnly, - render_accessibility, &nodes_); + doc_node_ = CreateAndAppendNode(ax::mojom::Role::kPdfRoot, + ax::mojom::Restriction::kReadOnly, + render_accessibility, &nodes_); doc_node_->AddState(ax::mojom::State::kFocusable); doc_node_->AddStringAttribute(ax::mojom::StringAttribute::kName, l10n_util::GetPluralStringFUTF8( @@ -1579,9 +1579,9 @@ CHECK_LT(page_index, page_count_); ++next_page_index_; - ui::AXNodeData* page_node = - CreateNode(ax::mojom::Role::kRegion, ax::mojom::Restriction::kReadOnly, - render_accessibility, &nodes_); + ui::AXNodeData* page_node = CreateAndAppendNode( + ax::mojom::Role::kRegion, ax::mojom::Restriction::kReadOnly, + render_accessibility, &nodes_); page_node->AddStringAttribute( ax::mojom::StringAttribute::kName, l10n_util::GetPluralStringFUTF8(IDS_PDF_PAGE_INDEX, page_index + 1)); @@ -1615,7 +1615,7 @@ #endif // BUILDFLAG(ENABLE_SCREEN_AI_SERVICE) if (page_index == page_count_ - 1) - Finish(); + UnserializeNodes(); } void PdfAccessibilityTree::AddPageContent( @@ -1641,7 +1641,7 @@ tree_builder.BuildPageTree(); } -void PdfAccessibilityTree::Finish() { +void PdfAccessibilityTree::UnserializeNodes() { content::RenderAccessibility* render_accessibility = GetRenderAccessibilityIfEnabled(); if (!render_accessibility) @@ -1668,13 +1668,20 @@ base::UmaHistogramBoolean("Accessibility.PDF.HasAccessibleText", did_get_a_text_run_); +#if BUILDFLAG(ENABLE_SCREEN_AI_SERVICE) + did_unserialize_nodes_once_ = true; +#endif // BUILDFLAG(ENABLE_SCREEN_AI_SERVICE) } #if BUILDFLAG(ENABLE_SCREEN_AI_SERVICE) -void PdfAccessibilityTree::FinishWithStatus() { +void PdfAccessibilityTree::SetOcrCompleteStatus() { VLOG(2) << "Performing OCR on PDF is complete."; SetStatusMessage(IDS_PDF_OCR_COMPLETED); + if (!did_unserialize_nodes_once_) { + return; + } + ui::AXTreeUpdate update; update.root_id = doc_node_->id; update.nodes.push_back(*doc_node_); @@ -1911,13 +1918,14 @@ DCHECK_NE(num_remaining_ocr_requests_, 0u); bool is_last_ocr_request = --num_remaining_ocr_requests_ == 0u; + // TODO(crbug.com/1393069): Investigate more to understand cases in which + // OCR gave no results and update the status node with a relevant message. + if (is_last_ocr_request) { + SetOcrCompleteStatus(); + } + if (child_tree_id == ui::AXTreeIDUnknown()) { VLOG(1) << "Empty OCR data received."; - // TODO(crbug.com/1393069): Investigate more to understand cases in which - // OCR gave no results and update the status node with a relevant message. - if (is_last_ocr_request) { - FinishWithStatus(); - } return; } @@ -1937,10 +1945,9 @@ if (!render_accessibility) return; - ui::AXTreeUpdate update; - ui::AXNodeData* page_node = - CreateNode(ax::mojom::Role::kRegion, ax::mojom::Restriction::kReadOnly, - render_accessibility, &nodes_); + ui::AXNodeData* page_node = CreateAndAppendNode( + ax::mojom::Role::kRegion, ax::mojom::Restriction::kReadOnly, + render_accessibility, &nodes_); page_node->AddBoolAttribute(ax::mojom::BoolAttribute::kIsPageBreakingObject, true); // TODO(crbug.com/1278249): add an attribute to indicate that this node is @@ -1968,16 +1975,21 @@ DCHECK_EQ(num_erased, 1); (*parent_node_iter)->child_ids.push_back(page_node->id); + if (!did_unserialize_nodes_once_) { + return; + } + + // Create AXTreeUpdate only after `tree_` being unserialized in + // UnserializeNodes(). Otherwise, it may try updating a AXNodeData that is + // not existed in `tree_`, which will lead to an error. + ui::AXTreeUpdate update; update.node_id_to_clear = image_node_id; update.root_id = doc_node_->id; update.nodes.push_back(**parent_node_iter); update.nodes.push_back(*page_node); - if (!tree_.Unserialize(update)) + if (!tree_.Unserialize(update)) { LOG(FATAL) << tree_.error(); - - if (is_last_ocr_request) { - FinishWithStatus(); } render_accessibility->SetPluginTreeSource(this);
diff --git a/components/pdf/renderer/pdf_accessibility_tree.h b/components/pdf/renderer/pdf_accessibility_tree.h index 678f50b..f494f5cb 100644 --- a/components/pdf/renderer/pdf_accessibility_tree.h +++ b/components/pdf/renderer/pdf_accessibility_tree.h
@@ -173,12 +173,12 @@ // Called after the data for all pages in the PDF have been received. // Finishes assembling a complete accessibility tree and grafts it // onto the host tree. - void Finish(); + void UnserializeNodes(); #if BUILDFLAG(ENABLE_SCREEN_AI_SERVICE) // Called after the OCR data for all images in the PDF have been received. - // Finishes updating the status node. - void FinishWithStatus(); + // Set the status node with the OCR completion message. + void SetOcrCompleteStatus(); // Set the status node's message. void SetStatusMessage(int message_id); @@ -269,6 +269,10 @@ std::unique_ptr<PdfOcrService> ocr_service_; // The number of remaining OCR service requests. uint32_t num_remaining_ocr_requests_ = 0; + // Flag that will be switched on when UnserializeNodes() is called. This flag + // will be used to check if an initial AXTreeUpdate with `nodes_` has been + // unserialized into `tree_`. + bool did_unserialize_nodes_once_ = false; #endif // BUILDFLAG(ENABLE_SCREEN_AI_SERVICE) base::WeakPtrFactory<PdfAccessibilityTree> weak_ptr_factory_{this};
diff --git a/components/saved_tab_groups/saved_tab_group_model.cc b/components/saved_tab_groups/saved_tab_group_model.cc index 993755ad..9f62ecf5 100644 --- a/components/saved_tab_groups/saved_tab_group_model.cc +++ b/components/saved_tab_groups/saved_tab_group_model.cc
@@ -453,6 +453,11 @@ } } + is_loaded_ = true; + for (auto& observer : observers_) { + observer.SavedTabGroupModelLoaded(); + } + return tabs_missing_groups; }
diff --git a/components/saved_tab_groups/saved_tab_group_model.h b/components/saved_tab_groups/saved_tab_group_model.h index 4723a05..17c903d 100644 --- a/components/saved_tab_groups/saved_tab_group_model.h +++ b/components/saved_tab_groups/saved_tab_group_model.h
@@ -36,6 +36,8 @@ } std::vector<SavedTabGroup> saved_tab_groups() { return saved_tab_groups_; } + bool is_loaded() { return is_loaded_; } + // Returns the index of the SavedTabGroup if it exists in the vector. Else // absl::nullopt. absl::optional<int> GetIndexOf( @@ -165,6 +167,10 @@ // Obsevers of the model. base::ObserverList<SavedTabGroupModelObserver>::Unchecked observers_; + // True when SavedTabGroupModel::LoadStoredEntries has finished, false + // otherwise. + bool is_loaded_ = false; + // Storage of all saved tab groups in the order they are displayed. The // position of the groups must maintain sorted order as sync may not propagate // an entire update completely leaving us with missing groups / gaps between
diff --git a/components/saved_tab_groups/saved_tab_group_model_observer.h b/components/saved_tab_groups/saved_tab_group_model_observer.h index 314d7f0c..f1c1b678 100644 --- a/components/saved_tab_groups/saved_tab_group_model_observer.h +++ b/components/saved_tab_groups/saved_tab_group_model_observer.h
@@ -55,6 +55,12 @@ const base::Uuid& group_guid, const absl::optional<base::Uuid>& tab_guid = absl::nullopt) {} + // Called when SavedTabGroupModel::LoadStoredEntries has finished loading. + // This is currently used to notify the SavedTabGroupKeyedService to link any + // tabs restore through session restore to the corresponding SavedTabGroup + // metadata in the SavedTabGroupModel. + virtual void SavedTabGroupModelLoaded() {} + protected: SavedTabGroupModelObserver() = default; virtual ~SavedTabGroupModelObserver() = default;
diff --git a/components/search/ntp_features.cc b/components/search/ntp_features.cc index 8270c7a..ddc4ee9 100644 --- a/components/search/ntp_features.cc +++ b/components/search/ntp_features.cc
@@ -316,7 +316,7 @@ const char kNtpDriveModuleExperimentGroupParam[] = "NtpDriveModuleExperimentGroupParam"; const char kNtpHistoryClustersModuleDataParam[] = - "NtpRecipeTasksModuleDataParam"; + "NtpHistoryClustersModuleDataParam"; const char kNtpMiddleSlotPromoDismissalParam[] = "NtpMiddleSlotPromoDismissalParam"; const char kNtpPhotosModuleDataParam[] = "NtpPhotosModuleDataParam";
diff --git a/components/sessions/core/session_service_commands.cc b/components/sessions/core/session_service_commands.cc index 43dd28a..88dd4b2 100644 --- a/components/sessions/core/session_service_commands.cc +++ b/components/sessions/core/session_service_commands.cc
@@ -670,6 +670,23 @@ std::ignore = iter.ReadBool(&is_collapsed); group->visual_data = tab_groups::TabGroupVisualData(title, color_int, is_collapsed); + + // The |is_saved| boolean was added in M113 to save the saved state of a + // tab group. Previous versions may not have this stored. + bool is_saved = false; + std::ignore = iter.ReadBool(&is_saved); + + if (is_saved) { + // The |saved_guid| boolean was added in M113 to save the guid of a + // tab group. Previous version may not have this stored. + std::string saved_guid; + if (!iter.ReadString(&saved_guid)) { + return; + } + + group->saved_guid = saved_guid; + } + break; } @@ -991,7 +1008,8 @@ std::unique_ptr<SessionCommand> CreateTabGroupMetadataUpdateCommand( const tab_groups::TabGroupId group, - const tab_groups::TabGroupVisualData* visual_data) { + const tab_groups::TabGroupVisualData* visual_data, + const absl::optional<std::string> saved_guid) { base::Pickle pickle; WriteTokenToPickle(&pickle, group.token()); pickle.WriteString16(visual_data->title()); @@ -999,6 +1017,14 @@ // This boolean was added in M88 to save the collapsed state. pickle.WriteBool(visual_data->is_collapsed()); + + // This booleans was added in M113 to save the saved state of a tab group. + pickle.WriteBool(saved_guid.has_value()); + if (saved_guid.has_value()) { + // This string was added in M113 to save the guid of a tab group. + pickle.WriteString(saved_guid.value()); + } + return std::make_unique<SessionCommand>(kCommandSetTabGroupMetadata2, pickle); }
diff --git a/components/sessions/core/session_service_commands.h b/components/sessions/core/session_service_commands.h index 85bed7d..c4c9ffc 100644 --- a/components/sessions/core/session_service_commands.h +++ b/components/sessions/core/session_service_commands.h
@@ -50,7 +50,8 @@ SESSIONS_EXPORT std::unique_ptr<SessionCommand> CreateTabGroupMetadataUpdateCommand( const tab_groups::TabGroupId group, - const tab_groups::TabGroupVisualData* visual_data); + const tab_groups::TabGroupVisualData* visual_data, + const absl::optional<std::string> saved_guid = absl::nullopt); SESSIONS_EXPORT std::unique_ptr<SessionCommand> CreatePinnedStateCommand( SessionID tab_id, bool is_pinned);
diff --git a/components/sessions/core/session_types.h b/components/sessions/core/session_types.h index 92dffc453..e1e0349 100644 --- a/components/sessions/core/session_types.h +++ b/components/sessions/core/session_types.h
@@ -131,6 +131,10 @@ tab_groups::TabGroupId id; tab_groups::TabGroupVisualData visual_data; + + // Used to notify the SavedTabGroupModel that this restore group was once + // saved and should track any changes made on the group. + absl::optional<std::string> saved_guid; }; // SessionWindow -------------------------------------------------------------
diff --git a/components/url_formatter/spoof_checks/idn_spoof_checker.cc b/components/url_formatter/spoof_checks/idn_spoof_checker.cc index 2f2ab83b..a6d45e3 100644 --- a/components/url_formatter/spoof_checks/idn_spoof_checker.cc +++ b/components/url_formatter/spoof_checks/idn_spoof_checker.cc
@@ -387,15 +387,22 @@ return Result::kDeviationCharacters; } - // Disallow Icelandic confusables for domains outside Iceland's ccTLD (.is). + // Disallow Icelandic confusables for domains outside Icelandic and Faroese + // ccTLD (.is, .fo). Faroese keyboard layout doesn't contain letter ⟨þ⟩, but + // we don't separate it here to avoid technical complexity, and because + // Faroese speakers are more likely to notice spoofs containing ⟨þ⟩ than other + // language speakers. if (label_string.length() > 1 && top_level_domain != "is" && - icelandic_characters_.containsSome(label_string)) + top_level_domain != "fo" && + icelandic_characters_.containsSome(label_string)) { return Result::kTLDSpecificCharacters; + } // Disallow Latin Schwa (U+0259) for domains outside Azerbaijan's ccTLD (.az). if (label_string.length() > 1 && top_level_domain != "az" && - label_string.indexOf("É™") != -1) + label_string.indexOf("É™") != -1) { return Result::kTLDSpecificCharacters; + } // Disallow middle dot (U+00B7) when unsafe. if (HasUnsafeMiddleDot(label_string, top_level_domain)) {
diff --git a/components/url_formatter/spoof_checks/idn_spoof_checker_unittest.cc b/components/url_formatter/spoof_checks/idn_spoof_checker_unittest.cc index c933520..f4eb71dc 100644 --- a/components/url_formatter/spoof_checks/idn_spoof_checker_unittest.cc +++ b/components/url_formatter/spoof_checks/idn_spoof_checker_unittest.cc
@@ -955,11 +955,12 @@ // U+05D7 can look like Latin n in many fonts. {"xn--ceba.com", u"\u05d7\u05d7.com", kUnsafe}, - // U+00FE (þ) and U+00F0 (ð) are only allowed under the .is TLD. + // U+00FE (þ) and U+00F0 (ð) are only allowed under the .is and .fo TLDs. {"xn--acdef-wva.com", u"a\u00fecdef.com", kUnsafe}, {"xn--mnpqr-jta.com", u"mn\u00f0pqr.com", kUnsafe}, {"xn--acdef-wva.is", u"a\u00fecdef.is", kSafe}, {"xn--mnpqr-jta.is", u"mn\u00f0pqr.is", kSafe}, + {"xn--mnpqr-jta.fo", u"mn\u00f0pqr.fo", kSafe}, // U+0259 (É™) is only allowed under the .az TLD. {"xn--xample-vyc.com", u"\u0259xample.com", kUnsafe},
diff --git a/components/variations/cros/BUILD.gn b/components/variations/cros/BUILD.gn index 2493c71..9a3cf40c 100644 --- a/components/variations/cros/BUILD.gn +++ b/components/variations/cros/BUILD.gn
@@ -42,6 +42,7 @@ "//base", "//base/test:test_support", "//build:branding_buildflags", + "//build/config/chromebox_for_meetings:buildflags", "//components/test:test_support", "//components/variations", "//testing/gmock",
diff --git a/components/variations/cros/evaluate_seed.cc b/components/variations/cros/evaluate_seed.cc index 2065e16..818078f 100644 --- a/components/variations/cros/evaluate_seed.cc +++ b/components/variations/cros/evaluate_seed.cc
@@ -21,47 +21,73 @@ namespace { constexpr char kSafeSeedSwitch[] = "use-safe-seed"; constexpr char kEnterpriseEnrolledSwitch[] = "enterprise-enrolled"; -const char kFakeVariationsChannel[] = "fake-variations-channel"; } // namespace -// Get the active channel, if applicable. -Study::Channel GetChannel(const base::CommandLine* command_line) { - std::string channel; - if (command_line->HasSwitch(kFakeVariationsChannel)) { - channel = command_line->GetSwitchValueASCII(kFakeVariationsChannel); - } -#if BUILDFLAG(GOOGLE_CHROME_BRANDING) - else if (base::SysInfo::GetLsbReleaseValue(crosapi::kChromeOSReleaseTrack, - &channel)) { - // do nothing; we successfully got channel. - } -#endif // BUILDFLAG(GOOGLE_CHROME_BRANDING) - else { - // We didn't get the channel. - return Study::UNKNOWN; - } - - return ConvertProductChannelToStudyChannel(crosapi::ChannelToEnum(channel)); +base::Version CrosVariationsServiceClient::GetVersionForSimulation() { + // TODO(mutexlox): Get the version that will be used on restart instead of + // the current version IF this is necessary. (We may not need simulations for + // early-boot experiments.) + // See ChromeVariationsServiceClient::GetVersionForSimulation. + return version_info::GetVersion(); } -std::unique_ptr<ClientFilterableState> GetClientFilterableState( - const base::CommandLine* command_line) { - bool enterprise_enrolled = command_line->HasSwitch(kEnterpriseEnrolledSwitch); +scoped_refptr<network::SharedURLLoaderFactory> +CrosVariationsServiceClient::GetURLLoaderFactory() { + // Do not load any data on CrOS early boot. This function is only called to + // fetch a new seed, and we should not fetch new seeds in evaluate_seed. + return nullptr; +} - // TODO(b/263975722): Fill in the rest of ClientFilterableState. +network_time::NetworkTimeTracker* +CrosVariationsServiceClient::GetNetworkTimeTracker() { + // Do not load any data on CrOS early boot; evaluate_seed should not load new + // seeds. + return nullptr; +} + +bool CrosVariationsServiceClient::OverridesRestrictParameter( + std::string* parameter) { + // TODO(b/263975722): Implement. + return false; +} + +// Get the active channel, if applicable. +version_info::Channel CrosVariationsServiceClient::GetChannel() { +#if BUILDFLAG(GOOGLE_CHROME_BRANDING) + std::string channel; + if (base::SysInfo::GetLsbReleaseValue(crosapi::kChromeOSReleaseTrack, + &channel)) { + return crosapi::ChannelToEnum(channel); + } +#endif // BUILDFLAG(GOOGLE_CHROME_BRANDING) + return version_info::Channel::UNKNOWN; +} + +bool CrosVariationsServiceClient::IsEnterprise() { + return base::CommandLine::ForCurrentProcess()->HasSwitch( + kEnterpriseEnrolledSwitch); +} + +std::unique_ptr<ClientFilterableState> GetClientFilterableState() { + CrosVariationsServiceClient client; + + // TODO(b/263975722): Properly use VariationsServiceClient and + // VariationsFieldTrialCreator::GetClientFilterableStateForVersion. auto state = std::make_unique<ClientFilterableState>( base::BindOnce([](bool enrolled) { return enrolled; }, - enterprise_enrolled), + client.IsEnterprise()), base::BindOnce([] { return base::flat_set<uint64_t>(); })); - state->channel = GetChannel(command_line); + state->channel = + ConvertProductChannelToStudyChannel(client.GetChannelForVariations()); + state->form_factor = client.GetCurrentFormFactor(); + return state; } -absl::optional<SafeSeed> GetSafeSeedData(const base::CommandLine* command_line, - FILE* stream) { +absl::optional<SafeSeed> GetSafeSeedData(FILE* stream) { featured::SeedDetails safe_seed; - if (command_line->HasSwitch(kSafeSeedSwitch)) { + if (base::CommandLine::ForCurrentProcess()->HasSwitch(kSafeSeedSwitch)) { // Read safe seed from |stream|. std::string safe_seed_data; if (!base::ReadStreamToString(stream, &safe_seed_data)) { @@ -78,15 +104,14 @@ return SafeSeed{false, safe_seed}; } -int EvaluateSeedMain(const base::CommandLine* command_line, FILE* stream) { - absl::optional<SafeSeed> safe_seed = GetSafeSeedData(command_line, stream); +int EvaluateSeedMain(FILE* stream) { + absl::optional<SafeSeed> safe_seed = GetSafeSeedData(stream); if (!safe_seed.has_value()) { LOG(ERROR) << "Failed to read seed from stdin"; return EXIT_FAILURE; } - std::unique_ptr<ClientFilterableState> state = - GetClientFilterableState(command_line); + std::unique_ptr<ClientFilterableState> state = GetClientFilterableState(); // TODO(b/263975722): Implement this binary. (void)state;
diff --git a/components/variations/cros/evaluate_seed.h b/components/variations/cros/evaluate_seed.h index 7ed290a..beef5061 100644 --- a/components/variations/cros/evaluate_seed.h +++ b/components/variations/cros/evaluate_seed.h
@@ -13,28 +13,53 @@ #include "base/command_line.h" #include "components/variations/client_filterable_state.h" #include "components/variations/cros/featured.pb.h" +#include "components/variations/service/variations_service_client.h" #include "third_party/abseil-cpp/absl/types/optional.h" namespace variations::evaluate_seed { -// Retrieve a ClientFilterableState struct based on the given |command_line|. -std::unique_ptr<ClientFilterableState> GetClientFilterableState( - const base::CommandLine* command_line); +class CrosVariationsServiceClient : public VariationsServiceClient { + public: + CrosVariationsServiceClient() = default; + + CrosVariationsServiceClient(const CrosVariationsServiceClient&) = delete; + CrosVariationsServiceClient& operator=(const CrosVariationsServiceClient&) = + delete; + + base::Version GetVersionForSimulation() override; + + scoped_refptr<network::SharedURLLoaderFactory> GetURLLoaderFactory() override; + + network_time::NetworkTimeTracker* GetNetworkTimeTracker() override; + + bool OverridesRestrictParameter(std::string* parameter) override; + + bool IsEnterprise() override; + + // Multi-profile early-boot experiments are not supported. + void RemoveGoogleGroupsFromPrefsForDeletedProfiles( + PrefService* local_state) override {} + + private: + version_info::Channel GetChannel() override; +}; + +// Retrieve a ClientFilterableState struct based on process's command-line. +std::unique_ptr<ClientFilterableState> GetClientFilterableState(); struct SafeSeed { bool use_safe_seed = false; featured::SeedDetails seed_data; }; -// Read the safe seed data from |stream|, if and only if the |command_line| +// Read the safe seed data from |stream|, if and only if the command-line // indicates that we should use the safe seed. -absl::optional<SafeSeed> GetSafeSeedData(const base::CommandLine* command_line, - FILE* stream); +absl::optional<SafeSeed> GetSafeSeedData(FILE* stream); // Evaluate the seed state, writing serialized computed output to stdout. // Reads a proto from |stream| for data like safe seed. // Return values are standard for main methods (EXIT_SUCCESS / EXIT_FAILURE). -int EvaluateSeedMain(const base::CommandLine* command_line, FILE* stream); +int EvaluateSeedMain(FILE* stream); } // namespace variations::evaluate_seed
diff --git a/components/variations/cros/evaluate_seed_main.cc b/components/variations/cros/evaluate_seed_main.cc index cc0d473..bd2a9fa 100644 --- a/components/variations/cros/evaluate_seed_main.cc +++ b/components/variations/cros/evaluate_seed_main.cc
@@ -15,7 +15,5 @@ base::AtExitManager exit_manager; base::CommandLine::Init(argc, argv); - const base::CommandLine* command_line = - base::CommandLine::ForCurrentProcess(); - return variations::evaluate_seed::EvaluateSeedMain(command_line, stdin); + return variations::evaluate_seed::EvaluateSeedMain(stdin); }
diff --git a/components/variations/cros/evaluate_seed_unittest.cc b/components/variations/cros/evaluate_seed_unittest.cc index c64d5376..16ecf2d 100644 --- a/components/variations/cros/evaluate_seed_unittest.cc +++ b/components/variations/cros/evaluate_seed_unittest.cc
@@ -7,6 +7,7 @@ #include "base/strings/strcat.h" #include "base/test/scoped_chromeos_version_info.h" #include "build/branding_buildflags.h" +#include "build/config/chromebox_for_meetings/buildflags.h" #include "components/variations/client_filterable_state.h" #include "components/variations/cros/featured.pb.h" #include "testing/gmock/include/gmock/gmock.h" @@ -24,16 +25,15 @@ } TEST(VariationsCrosEvaluateSeed, GetClientFilterable_Enrolled) { - base::CommandLine command_line({"evaluate_seed", "--enterprise-enrolled"}); - std::unique_ptr<ClientFilterableState> state = - GetClientFilterableState(&command_line); + base::CommandLine::ForCurrentProcess()->InitFromArgv( + {"evaluate_seed", "--enterprise-enrolled"}); + std::unique_ptr<ClientFilterableState> state = GetClientFilterableState(); EXPECT_TRUE(state->IsEnterprise()); } TEST(VariationsCrosEvaluateSeed, GetClientFilterable_NotEnrolled) { - base::CommandLine command_line({"evaluate_seed"}); - std::unique_ptr<ClientFilterableState> state = - GetClientFilterableState(&command_line); + base::CommandLine::ForCurrentProcess()->InitFromArgv({"evaluate_seed"}); + std::unique_ptr<ClientFilterableState> state = GetClientFilterableState(); EXPECT_FALSE(state->IsEnterprise()); } @@ -51,11 +51,10 @@ TEST_P(VariationsCrosEvaluateSeedGetChannel, GetClientFilterableState_Channel_Override) { - base::CommandLine command_line( - {"evaluate_seed", base::StrCat({"--fake-variations-channel=", - GetParam().channel_name, "-channel"})}); - std::unique_ptr<ClientFilterableState> state = - GetClientFilterableState(&command_line); + base::CommandLine::ForCurrentProcess()->InitFromArgv( + {"evaluate_seed", + base::StrCat({"--fake-variations-channel=", GetParam().channel_name})}); + std::unique_ptr<ClientFilterableState> state = GetClientFilterableState(); EXPECT_EQ(GetParam().channel, state->channel); } @@ -69,18 +68,16 @@ const base::Time lsb_release_time(base::Time::FromDoubleT(12345.6)); base::test::ScopedChromeOSVersionInfo lsb_info(lsb_release, lsb_release_time); - base::CommandLine command_line({"evaluate_seed"}); - std::unique_ptr<ClientFilterableState> state = - GetClientFilterableState(&command_line); + base::CommandLine::ForCurrentProcess()->InitFromArgv({"evaluate_seed"}); + std::unique_ptr<ClientFilterableState> state = GetClientFilterableState(); EXPECT_EQ(GetParam().channel, state->channel); } #else // BUILDFLAG(GOOGLE_CHROME_BRANDING) // Verify that we use unknown channel on non-branded builds. TEST(VariationsCrosEvaluateSeed, GetClientFilterableState_Channel_NotBranded) { - base::CommandLine command_line({"evaluate_seed"}); - std::unique_ptr<ClientFilterableState> state = - GetClientFilterableState(&command_line); + base::CommandLine::ForCurrentProcess()->InitFromArgv({"evaluate_seed"}); + std::unique_ptr<ClientFilterableState> state = GetClientFilterableState(); EXPECT_EQ(Study::UNKNOWN, state->channel); } #endif // BUILDFLAG(GOOGLE_CHROME_BRANDING) @@ -97,6 +94,20 @@ return info.param.test_name; }); +#if BUILDFLAG(PLATFORM_CFM) +TEST(VariationsCrosEvaluateSeed, GetClientFilterableState_FormFactor) { + base::CommandLine::ForCurrentProcess()->InitFromArgv({"evaluate_seed"}); + std::unique_ptr<ClientFilterableState> state = GetClientFilterableState(); + EXPECT_EQ(Study::MEET_DEVICE, state->form_factor); +} +#else // BUILDFLAG(PLATFORM_CFM) +TEST(VariationsCrosEvaluateSeed, GetClientFilterableState_FormFactor) { + base::CommandLine::ForCurrentProcess()->InitFromArgv({"evaluate_seed"}); + std::unique_ptr<ClientFilterableState> state = GetClientFilterableState(); + EXPECT_EQ(Study::DESKTOP, state->form_factor); +} +#endif // BUILDFLAG(PLATFORM_CFM) + // Should ignore data if flag is off. TEST(VariationsCrosEvaluateSeed, GetSafeSeedData_Off) { featured::SeedDetails safe_seed; @@ -106,8 +117,8 @@ FILE* stream = fmemopen(text.data(), text.size(), "r"); ASSERT_NE(stream, nullptr); - base::CommandLine command_line({"evaluate_seed"}); - auto data = GetSafeSeedData(&command_line, stream); + base::CommandLine::ForCurrentProcess()->InitFromArgv({"evaluate_seed"}); + auto data = GetSafeSeedData(stream); featured::SeedDetails empty_seed; ASSERT_TRUE(data.has_value()); EXPECT_FALSE(data.value().use_safe_seed); @@ -123,8 +134,9 @@ FILE* stream = fmemopen(text.data(), text.size(), "r"); ASSERT_NE(stream, nullptr); - base::CommandLine command_line({"evaluate_seed", "--use-safe-seed"}); - auto data = GetSafeSeedData(&command_line, stream); + base::CommandLine::ForCurrentProcess()->InitFromArgv( + {"evaluate_seed", "--use-safe-seed"}); + auto data = GetSafeSeedData(stream); ASSERT_TRUE(data.has_value()); EXPECT_TRUE(data.value().use_safe_seed); EXPECT_THAT(data.value().seed_data, EqualsProto(safe_seed)); @@ -139,8 +151,8 @@ FILE* stream = fmemopen(text.data(), text.size(), "w"); ASSERT_NE(stream, nullptr); - base::CommandLine command_line({"evaluate_seed"}); - auto data = GetSafeSeedData(&command_line, stream); + base::CommandLine::ForCurrentProcess()->InitFromArgv({"evaluate_seed"}); + auto data = GetSafeSeedData(stream); featured::SeedDetails empty_seed; ASSERT_TRUE(data.has_value()); EXPECT_FALSE(data.value().use_safe_seed); @@ -156,8 +168,9 @@ FILE* stream = fmemopen(text.data(), text.size(), "w"); ASSERT_NE(stream, nullptr); - base::CommandLine command_line({"evaluate_seed", "--use-safe-seed"}); - auto data = GetSafeSeedData(&command_line, stream); + base::CommandLine::ForCurrentProcess()->InitFromArgv( + {"evaluate_seed", "--use-safe-seed"}); + auto data = GetSafeSeedData(stream); EXPECT_FALSE(data.has_value()); } @@ -167,26 +180,29 @@ FILE* stream = fmemopen(text.data(), text.size(), "r"); ASSERT_NE(stream, nullptr); - base::CommandLine command_line({"evaluate_seed", "--use-safe-seed"}); - auto data = GetSafeSeedData(&command_line, stream); + base::CommandLine::ForCurrentProcess()->InitFromArgv( + {"evaluate_seed", "--use-safe-seed"}); + auto data = GetSafeSeedData(stream); ASSERT_FALSE(data.has_value()); } // If flag is on and reading fails, should return nullopt. TEST(VariationsCrosEvaluateSeed, GetSafeSeedData_On_FailRead_Null) { - base::CommandLine command_line({"evaluate_seed", "--use-safe-seed"}); - auto data = GetSafeSeedData(&command_line, nullptr); + base::CommandLine::ForCurrentProcess()->InitFromArgv( + {"evaluate_seed", "--use-safe-seed"}); + auto data = GetSafeSeedData(nullptr); EXPECT_FALSE(data.has_value()); } TEST(VariationsCrosEvaluateSeed, Main_NoFlag) { - base::CommandLine command_line({"evaluate_seed"}); - EXPECT_EQ(0, EvaluateSeedMain(&command_line, nullptr)); + base::CommandLine::ForCurrentProcess()->InitFromArgv({"evaluate_seed"}); + EXPECT_EQ(0, EvaluateSeedMain(nullptr)); } TEST(VariationsCrosEvaluateSeed, Main_NoStdin) { - base::CommandLine command_line({"evaluate_seed", "--use-safe-seed"}); - EXPECT_EQ(1, EvaluateSeedMain(&command_line, nullptr)); + base::CommandLine::ForCurrentProcess()->InitFromArgv( + {"evaluate_seed", "--use-safe-seed"}); + EXPECT_EQ(1, EvaluateSeedMain(nullptr)); } } // namespace variations::evaluate_seed
diff --git a/components/variations/service/BUILD.gn b/components/variations/service/BUILD.gn index a5ff8a82..06b12890 100644 --- a/components/variations/service/BUILD.gn +++ b/components/variations/service/BUILD.gn
@@ -55,6 +55,7 @@ "//base", "//build:branding_buildflags", "//build:chromeos_buildflags", + "//build/config/chromebox_for_meetings:buildflags", "//components/encrypted_messages", "//components/keyed_service/core", "//components/language/core/browser",
diff --git a/components/variations/service/variations_service_client.cc b/components/variations/service/variations_service_client.cc index 369b18d..28dde5dd 100644 --- a/components/variations/service/variations_service_client.cc +++ b/components/variations/service/variations_service_client.cc
@@ -8,6 +8,7 @@ #include "base/logging.h" #include "base/notreached.h" #include "base/system/sys_info.h" +#include "build/config/chromebox_for_meetings/buildflags.h" #include "components/variations/variations_switches.h" #include "ui/base/device_form_factor.h" @@ -34,6 +35,9 @@ } Study::FormFactor VariationsServiceClient::GetCurrentFormFactor() { +#if BUILDFLAG(PLATFORM_CFM) + return variations::Study::MEET_DEVICE; +#else switch (ui::GetDeviceFormFactor()) { case ui::DEVICE_FORM_FACTOR_PHONE: return Study::PHONE; @@ -44,6 +48,7 @@ } NOTREACHED(); return Study::DESKTOP; +#endif // BUILDFLAG(PLATFORM_CFM) } std::unique_ptr<SeedResponse>
diff --git a/content/browser/network_service_instance_impl.cc b/content/browser/network_service_instance_impl.cc index 4d580959..92e2a32 100644 --- a/content/browser/network_service_instance_impl.cc +++ b/content/browser/network_service_instance_impl.cc
@@ -766,19 +766,6 @@ cert_verifier::mojom::CertVerifierServiceFactory* g_cert_verifier_service_factory_for_testing = nullptr; -mojo::PendingRemote<cert_verifier::mojom::CertVerifierService> -GetNewCertVerifierServiceRemote( - cert_verifier::mojom::CertVerifierServiceFactory* - cert_verifier_service_factory, - cert_verifier::mojom::CertVerifierCreationParamsPtr creation_params) { - mojo::PendingRemote<cert_verifier::mojom::CertVerifierService> - cert_verifier_remote; - cert_verifier_service_factory->GetNewCertVerifier( - cert_verifier_remote.InitWithNewPipeAndPassReceiver(), - std::move(creation_params)); - return cert_verifier_remote; -} - void RunInProcessCertVerifierServiceFactory( cert_verifier::mojom::CertVerifierServiceParamsPtr params, mojo::PendingReceiver<cert_verifier::mojom::CertVerifierServiceFactory> @@ -849,10 +836,18 @@ network::mojom::CertVerifierServiceRemoteParamsPtr GetCertVerifierParams( cert_verifier::mojom::CertVerifierCreationParamsPtr cert_verifier_creation_params) { + mojo::PendingRemote<cert_verifier::mojom::CertVerifierService> + cert_verifier_remote; + mojo::PendingReceiver<cert_verifier::mojom::CertVerifierServiceClient> + cert_verifier_client; + + GetCertVerifierServiceFactory()->GetNewCertVerifier( + cert_verifier_remote.InitWithNewPipeAndPassReceiver(), + cert_verifier_client.InitWithNewPipeAndPassRemote(), + std::move(cert_verifier_creation_params)); + return network::mojom::CertVerifierServiceRemoteParams::New( - GetNewCertVerifierServiceRemote( - GetCertVerifierServiceFactory(), - std::move(cert_verifier_creation_params))); + std::move(cert_verifier_remote), std::move(cert_verifier_client)); } void SetCertVerifierServiceFactoryForTesting(
diff --git a/content/browser/web_package/signed_exchange_handler_unittest.cc b/content/browser/web_package/signed_exchange_handler_unittest.cc index 3e332756..a8f2c36d 100644 --- a/content/browser/web_package/signed_exchange_handler_unittest.cc +++ b/content/browser/web_package/signed_exchange_handler_unittest.cc
@@ -155,6 +155,8 @@ std::unique_ptr<net::CertVerifier::Request>* out_req, const net::NetLogWithSource& net_log)); MOCK_METHOD1(SetConfig, void(const net::CertVerifier::Config& config)); + MOCK_METHOD1(AddObserver, void(Observer* observer)); + MOCK_METHOD1(RemoveObserver, void(Observer* observer)); }; class MockCTPolicyEnforcer : public net::CTPolicyEnforcer {
diff --git a/content/public/android/java/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityImpl.java b/content/public/android/java/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityImpl.java index d6c0ee0..cbb7138 100644 --- a/content/public/android/java/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityImpl.java +++ b/content/public/android/java/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityImpl.java
@@ -317,7 +317,9 @@ @Override public void onDisabled() { assert mNativeObj != 0 : "Native code is not initialized, but disable was called."; - + assert ContentFeatureList.isEnabled( + ContentFeatureList.AUTO_DISABLE_ACCESSIBILITY_V2) + : "Disable was called, but Auto-disable accessibility is not enabled."; // If the Auto-disable timer has expired, begin disabling the renderer, and clearing // the Java-side caches. // TODO(mschillaci): This will not re-enable for a Blink event. Fix.
diff --git a/content/public/test/test_cert_verifier_service_factory.cc b/content/public/test/test_cert_verifier_service_factory.cc index af674c27..d6836a0 100644 --- a/content/public/test/test_cert_verifier_service_factory.cc +++ b/content/public/test/test_cert_verifier_service_factory.cc
@@ -39,6 +39,7 @@ void TestCertVerifierServiceFactoryImpl::GetNewCertVerifier( mojo::PendingReceiver<mojom::CertVerifierService> receiver, + mojo::PendingRemote<mojom::CertVerifierServiceClient> client, mojom::CertVerifierCreationParamsPtr creation_params) { if (!delegate_) { InitDelegate(); @@ -46,6 +47,7 @@ GetNewCertVerifierParams params; params.receiver = std::move(receiver); + params.client = std::move(client); params.creation_params = std::move(creation_params); captured_params_.push_front(std::move(params)); @@ -58,7 +60,10 @@ #if BUILDFLAG(CHROME_ROOT_STORE_SUPPORTED) void TestCertVerifierServiceFactoryImpl::UpdateChromeRootStore( - mojom::ChromeRootStorePtr new_root_store) {} + mojom::ChromeRootStorePtr new_root_store, + UpdateChromeRootStoreCallback callback) { + std::move(callback).Run(); +} void TestCertVerifierServiceFactoryImpl::GetChromeRootStoreInfo( GetChromeRootStoreInfoCallback callback) { @@ -79,6 +84,7 @@ GetNewCertVerifierParams params = std::move(captured_params_.back()); captured_params_.pop_back(); delegate_remote_->GetNewCertVerifier(std::move(params.receiver), + std::move(params.client), std::move(params.creation_params)); }
diff --git a/content/public/test/test_cert_verifier_service_factory.h b/content/public/test/test_cert_verifier_service_factory.h index 21f1ecff..5bb080e 100644 --- a/content/public/test/test_cert_verifier_service_factory.h +++ b/content/public/test/test_cert_verifier_service_factory.h
@@ -41,18 +41,21 @@ ~GetNewCertVerifierParams(); mojo::PendingReceiver<mojom::CertVerifierService> receiver; + mojo::PendingRemote<mojom::CertVerifierServiceClient> client; mojom::CertVerifierCreationParamsPtr creation_params; }; // mojom::CertVerifierServiceFactory implementation: void GetNewCertVerifier( mojo::PendingReceiver<mojom::CertVerifierService> receiver, + mojo::PendingRemote<mojom::CertVerifierServiceClient> client, mojom::CertVerifierCreationParamsPtr creation_params) override; void GetServiceParamsForTesting( GetServiceParamsForTestingCallback callback) override; #if BUILDFLAG(CHROME_ROOT_STORE_SUPPORTED) - void UpdateChromeRootStore(mojom::ChromeRootStorePtr new_root_store) override; + void UpdateChromeRootStore(mojom::ChromeRootStorePtr new_root_store, + UpdateChromeRootStoreCallback callback) override; void GetChromeRootStoreInfo(GetChromeRootStoreInfoCallback callback) override; #endif
diff --git a/docs/speed/metrics_changelog/2023_04_lcp.md b/docs/speed/metrics_changelog/2023_04_lcp.md index faa66ed..b628499 100644 --- a/docs/speed/metrics_changelog/2023_04_lcp.md +++ b/docs/speed/metrics_changelog/2023_04_lcp.md
@@ -1,4 +1,4 @@ -# Largest Contentul Paint change in Chrome 112 to ignore low-entropy images +# Largest Contentful Paint change in Chrome 112 to ignore low-entropy images In Chrome 112, LCP will begin to ignore images with very low content relative to their display sizes. @@ -28,4 +28,4 @@ This change was launched to Chrome users starting on roughly April 6, 2023, and was rolled out to existing Chrome installs. This roughly coincides with Chrome 112, although previous versions (back to Chrome 109) will also pick -up this change. \ No newline at end of file +up this change.
diff --git a/fuchsia_web/runners/BUILD.gn b/fuchsia_web/runners/BUILD.gn index 5878dc3..cba15c3 100644 --- a/fuchsia_web/runners/BUILD.gn +++ b/fuchsia_web/runners/BUILD.gn
@@ -70,8 +70,10 @@ "//third_party/fuchsia-sdk/sdk/fidl/fuchsia.component.decl:fuchsia.component.decl_cpp", "//third_party/fuchsia-sdk/sdk/fidl/fuchsia.diagnostics:fuchsia.diagnostics_hlcpp", "//third_party/fuchsia-sdk/sdk/fidl/fuchsia.legacymetrics:fuchsia.legacymetrics_hlcpp", + "//third_party/fuchsia-sdk/sdk/fidl/fuchsia.media.sessions2:fuchsia.media.sessions2_cpp_hlcpp_conversion", "//third_party/fuchsia-sdk/sdk/fidl/fuchsia.mem:fuchsia.mem_hlcpp", "//third_party/fuchsia-sdk/sdk/fidl/fuchsia.ui.app:fuchsia.ui.app_cpp_wire", + "//third_party/fuchsia-sdk/sdk/pkg/component_incoming_cpp", "//third_party/fuchsia-sdk/sdk/pkg/scenic_cpp", "//third_party/fuchsia-sdk/sdk/pkg/sys_cpp", "//url", @@ -79,6 +81,7 @@ public_deps = [ ":common", + "./cast/fidl:fidl_cpp", "./cast/fidl:fidl_hlcpp", "//third_party/fuchsia-sdk/sdk/fidl/fuchsia.component.resolution:fuchsia.component.resolution_cpp", "//third_party/fuchsia-sdk/sdk/fidl/fuchsia.component.runner:fuchsia.component.runner_hlcpp",
diff --git a/fuchsia_web/runners/cast/application_controller_impl.cc b/fuchsia_web/runners/cast/application_controller_impl.cc index 5bac3730..a9954a7 100644 --- a/fuchsia_web/runners/cast/application_controller_impl.cc +++ b/fuchsia_web/runners/cast/application_controller_impl.cc
@@ -4,48 +4,69 @@ #include "fuchsia_web/runners/cast/application_controller_impl.h" -#include <fuchsia/diagnostics/cpp/fidl.h> +#include <fidl/fuchsia.media.sessions2/cpp/hlcpp_conversion.h> +#include <lib/async/default.h> #include <utility> #include "base/check.h" #include "base/fuchsia/fuchsia_logging.h" +#include "base/strings/string_piece.h" ApplicationControllerImpl::ApplicationControllerImpl( fuchsia::web::Frame* frame, - chromium::cast::ApplicationContext* context) - : binding_(this), frame_(frame) { + fidl::Client<chromium_cast::ApplicationContext>& context) + : frame_(frame) { DCHECK(context); DCHECK(frame_); - context->SetApplicationController(binding_.NewBinding()); - - binding_.set_error_handler([](zx_status_t status) { - if (status != ZX_ERR_PEER_CLOSED && status != ZX_ERR_CANCELED) { - ZX_LOG(WARNING, status) << "Application bindings connection dropped."; - } - }); + auto application_controller_endpoints = + fidl::CreateEndpoints<chromium_cast::ApplicationController>(); + ZX_CHECK(application_controller_endpoints.is_ok(), + application_controller_endpoints.status_value()); + binding_.emplace(async_get_default_dispatcher(), + std::move(application_controller_endpoints->server), this, + [](fidl::UnbindInfo info) { + LOG_IF(WARNING, info.status() != ZX_ERR_PEER_CLOSED && + info.status() != ZX_ERR_CANCELED) + << "Unbound from chromium.cast.ApplicationController: " + << info; + }); + auto result = context->SetApplicationController( + {{.controller = std::move(application_controller_endpoints->client)}}); + LOG_IF(ERROR, result.is_error()) + << base::FidlMethodResultErrorMessage(result, "SetApplicationController"); } ApplicationControllerImpl::~ApplicationControllerImpl() = default; -void ApplicationControllerImpl::SetTouchInputEnabled(bool enable) { +void ApplicationControllerImpl::SetTouchInputEnabled( + ApplicationControllerImpl::SetTouchInputEnabledRequest& request, + ApplicationControllerImpl::SetTouchInputEnabledCompleter::Sync& completer) { + auto allow_input_state = request.enable() + ? fuchsia::web::AllowInputState::ALLOW + : fuchsia::web::AllowInputState::DENY; frame_->ConfigureInputTypes(fuchsia::web::InputTypes::GESTURE_TAP | fuchsia::web::InputTypes::GESTURE_DRAG, - (enable ? fuchsia::web::AllowInputState::ALLOW - : fuchsia::web::AllowInputState::DENY)); + allow_input_state); } void ApplicationControllerImpl::GetMediaPlayer( - fidl::InterfaceRequest<fuchsia::media::sessions2::Player> request) { - frame_->GetMediaPlayer(std::move(request)); + ApplicationControllerImpl::GetMediaPlayerRequest& request, + ApplicationControllerImpl::GetMediaPlayerCompleter::Sync& completer) { + frame_->GetMediaPlayer(fidl::NaturalToHLCPP(request.request())); } -void ApplicationControllerImpl::SetBlockMediaLoading(bool blocked) { - frame_->SetBlockMediaLoading(blocked); +void ApplicationControllerImpl::SetBlockMediaLoading( + ApplicationControllerImpl::SetBlockMediaLoadingRequest& request, + ApplicationControllerImpl::SetBlockMediaLoadingCompleter::Sync& completer) { + frame_->SetBlockMediaLoading(request.blocked()); } void ApplicationControllerImpl::GetPrivateMemorySize( - GetPrivateMemorySizeCallback callback) { - frame_->GetPrivateMemorySize(std::move(callback)); + ApplicationControllerImpl::GetPrivateMemorySizeCompleter::Sync& completer) { + frame_->GetPrivateMemorySize( + [completer = completer.ToAsync()](uint64_t private_memory_size) mutable { + completer.Reply(private_memory_size); + }); }
diff --git a/fuchsia_web/runners/cast/application_controller_impl.h b/fuchsia_web/runners/cast/application_controller_impl.h index a98047871..12df41d1 100644 --- a/fuchsia_web/runners/cast/application_controller_impl.h +++ b/fuchsia_web/runners/cast/application_controller_impl.h
@@ -5,18 +5,20 @@ #ifndef FUCHSIA_WEB_RUNNERS_CAST_APPLICATION_CONTROLLER_IMPL_H_ #define FUCHSIA_WEB_RUNNERS_CAST_APPLICATION_CONTROLLER_IMPL_H_ -#include <chromium/cast/cpp/fidl.h> -#include <fuchsia/diagnostics/cpp/fidl.h> +#include <fidl/chromium.cast/cpp/fidl.h> #include <fuchsia/media/sessions2/cpp/fidl.h> #include <fuchsia/web/cpp/fidl.h> #include <lib/fidl/cpp/binding.h> #include <lib/fidl/cpp/interface_request.h> +#include "third_party/abseil-cpp/absl/types/optional.h" + class ApplicationControllerImpl final - : public chromium::cast::ApplicationController { + : public fidl::Server<chromium_cast::ApplicationController> { public: - ApplicationControllerImpl(fuchsia::web::Frame* frame, - chromium::cast::ApplicationContext* context); + ApplicationControllerImpl( + fuchsia::web::Frame* frame, + fidl::Client<chromium_cast::ApplicationContext>& context); ApplicationControllerImpl(const ApplicationControllerImpl&) = delete; ApplicationControllerImpl& operator=(const ApplicationControllerImpl&) = @@ -25,16 +27,21 @@ ~ApplicationControllerImpl() override; protected: - // chromium::cast::ApplicationController implementation. - void SetTouchInputEnabled(bool enable) override; - void GetMediaPlayer( - ::fidl::InterfaceRequest<fuchsia::media::sessions2::Player> request) - override; - void SetBlockMediaLoading(bool blocked) override; - void GetPrivateMemorySize(GetPrivateMemorySizeCallback callback) override; + // chromium_cast::ApplicationController implementation. + void SetTouchInputEnabled( + SetTouchInputEnabledRequest& request, + SetTouchInputEnabledCompleter::Sync& completer) override; + void GetMediaPlayer(GetMediaPlayerRequest& request, + GetMediaPlayerCompleter::Sync& completer) override; + void SetBlockMediaLoading( + SetBlockMediaLoadingRequest& request, + SetBlockMediaLoadingCompleter::Sync& completer) override; + void GetPrivateMemorySize( + GetPrivateMemorySizeCompleter::Sync& completer) override; private: - fidl::Binding<chromium::cast::ApplicationController> binding_; + absl::optional<fidl::ServerBinding<chromium_cast::ApplicationController>> + binding_; fuchsia::web::Frame* const frame_; };
diff --git a/fuchsia_web/runners/cast/application_controller_impl_unittest.cc b/fuchsia_web/runners/cast/application_controller_impl_unittest.cc index f0f53ef..fcc0819 100644 --- a/fuchsia_web/runners/cast/application_controller_impl_unittest.cc +++ b/fuchsia_web/runners/cast/application_controller_impl_unittest.cc
@@ -5,15 +5,15 @@ #include <chromium/cast/cpp/fidl.h> #include <fuchsia/web/cpp/fidl.h> #include <fuchsia/web/cpp/fidl_test_base.h> -#include <lib/fidl/cpp/binding.h> +#include <lib/async/default.h> #include <string> #include <utility> +#include "base/fuchsia/fuchsia_logging.h" #include "base/logging.h" #include "base/test/task_environment.h" #include "base/test/test_future.h" -#include "fuchsia_web/common/test/fit_adapter.h" #include "fuchsia_web/runners/cast/application_controller_impl.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -38,13 +38,22 @@ (GetPrivateMemorySizeCallback callback)); }; -class ApplicationControllerImplTest : public chromium::cast::ApplicationContext, - public testing::Test { +class ApplicationControllerImplTest + : public fidl::Server<chromium_cast::ApplicationContext>, + public testing::Test { public: - ApplicationControllerImplTest() - : application_context_binding_(this), - application_context_(application_context_binding_.NewBinding().Bind()), - application_(&frame_, application_context_.get()) { + ApplicationControllerImplTest() { + auto application_context_endpoints = + fidl::CreateEndpoints<chromium_cast::ApplicationContext>(); + ZX_CHECK(application_context_endpoints.is_ok(), + application_context_endpoints.status_value()); + application_context_binding_.emplace( + async_get_default_dispatcher(), + std::move(application_context_endpoints->server), this, + [](fidl::UnbindInfo info) { ADD_FAILURE(); }); + application_context_.Bind(std::move(application_context_endpoints->client), + async_get_default_dispatcher()); + application_.emplace(&frame_, application_context_); base::RunLoop run_loop; wait_for_controller_callback_ = run_loop.QuitClosure(); run_loop.Run(); @@ -57,16 +66,18 @@ ~ApplicationControllerImplTest() override = default; protected: - // chromium::cast::ApplicationContext implementation. - void GetMediaSessionId(GetMediaSessionIdCallback callback) final { + // chromium_cast::ApplicationContext implementation. + void GetMediaSessionId(GetMediaSessionIdCompleter::Sync& completer) final { NOTREACHED(); + completer.Reply({}); } void SetApplicationController( - fidl::InterfaceHandle<chromium::cast::ApplicationController> application) - final { + SetApplicationControllerRequest& request, + SetApplicationControllerCompleter::Sync& ignored_completer) final { EXPECT_TRUE(wait_for_controller_callback_); - application_ptr_ = application.Bind(); + application_client_.Bind(std::move(request.controller()), + async_get_default_dispatcher()); std::move(wait_for_controller_callback_).Run(); } @@ -74,12 +85,12 @@ base::test::SingleThreadTaskEnvironment::MainThreadType::IO}; MockFrame frame_; - fidl::Binding<chromium::cast::ApplicationContext> + absl::optional<fidl::ServerBinding<chromium_cast::ApplicationContext>> application_context_binding_; - chromium::cast::ApplicationContextPtr application_context_; - ApplicationControllerImpl application_; + fidl::Client<chromium_cast::ApplicationContext> application_context_; + absl::optional<ApplicationControllerImpl> application_; - chromium::cast::ApplicationControllerPtr application_ptr_; + fidl::Client<chromium_cast::ApplicationController> application_client_; base::OnceClosure wait_for_controller_callback_; }; @@ -98,9 +109,9 @@ fuchsia::web::AllowInputState::DENY)) .WillOnce(InvokeWithoutArgs([&run_loop]() { run_loop.Quit(); })); - application_ptr_->SetTouchInputEnabled(true); - application_ptr_->SetTouchInputEnabled(true); - application_ptr_->SetTouchInputEnabled(false); + EXPECT_TRUE(application_client_->SetTouchInputEnabled(true).is_ok()); + EXPECT_TRUE(application_client_->SetTouchInputEnabled(true).is_ok()); + EXPECT_TRUE(application_client_->SetTouchInputEnabled(false).is_ok()); run_loop.Run(); } @@ -113,12 +124,17 @@ [](chromium::cast::ApplicationController::GetPrivateMemorySizeCallback callback) { callback(kMockSize); }); - base::test::TestFuture<uint64_t> result; - application_ptr_->GetPrivateMemorySize( - CallbackToFitFunction(result.GetCallback())); - ASSERT_TRUE(result.Wait()); - - EXPECT_EQ(result.Get(), kMockSize); + base::RunLoop loop; + application_client_->GetPrivateMemorySize().Then( + [quit_closure = loop.QuitClosure(), + kMockSize](fidl::Result< + chromium_cast::ApplicationController::GetPrivateMemorySize>& + result) { + ASSERT_TRUE(result.is_ok()); + EXPECT_EQ(result->size_bytes(), kMockSize); + quit_closure.Run(); + }); + loop.Run(); } } // namespace
diff --git a/fuchsia_web/runners/cast/cast_component.cc b/fuchsia_web/runners/cast/cast_component.cc index a3995b9..359b284 100644 --- a/fuchsia_web/runners/cast/cast_component.cc +++ b/fuchsia_web/runners/cast/cast_component.cc
@@ -4,7 +4,7 @@ #include "fuchsia_web/runners/cast/cast_component.h" -#include <chromium/cast/cpp/fidl.h> +#include <lib/async/default.h> #include <lib/fidl/cpp/binding.h> #include <lib/ui/scenic/cpp/view_ref_pair.h> @@ -80,7 +80,8 @@ initial_url_rewrite_rules_( std::move(params.initial_url_rewrite_rules.value())), api_bindings_client_(std::move(params.api_bindings_client)), - application_context_(params.application_context.Bind()), + application_context_(std::move(params.application_context), + async_get_default_dispatcher()), media_settings_(std::move(params.media_settings.value())), headless_disconnect_watch_(FROM_HERE) { base::AutoReset<bool> constructor_active_reset(&constructor_active_, true); @@ -150,7 +151,7 @@ } application_controller_ = std::make_unique<ApplicationControllerImpl>( - frame(), application_context_.get()); + frame(), application_context_); // Apply application-specific web permissions to the fuchsia.web.Frame. if (application_config_.has_permissions()) { @@ -194,7 +195,9 @@ // to be notified with `exit_code` set to `ZX_OK`. All other `exit_code` // values, or failure to report one, indicate teardown due to error. if (application_controller_) { - application_context_->OnApplicationExit(exit_code); + auto result = application_context_->OnApplicationExit(exit_code); + LOG_IF(ERROR, result.is_error()) + << base::FidlMethodResultErrorMessage(result, "OnApplicationExit"); } // frame() is about to be destroyed, so there is no need to perform cleanup
diff --git a/fuchsia_web/runners/cast/cast_component.h b/fuchsia_web/runners/cast/cast_component.h index 11eba0f..aedb978 100644 --- a/fuchsia_web/runners/cast/cast_component.h +++ b/fuchsia_web/runners/cast/cast_component.h
@@ -52,8 +52,7 @@ // Parameters asynchronously initialized by PendingCastComponent. std::unique_ptr<ApiBindingsClient> api_bindings_client; chromium::cast::ApplicationConfig application_config; - fidl::InterfaceHandle<chromium::cast::ApplicationContext> - application_context; + fidl::ClientEnd<chromium_cast::ApplicationContext> application_context; absl::optional<std::vector<fuchsia::web::UrlRequestRewriteRule>> initial_url_rewrite_rules; absl::optional<fuchsia::web::FrameMediaSettings> media_settings; @@ -115,7 +114,7 @@ std::unique_ptr<NamedMessagePortConnectorFuchsia> connector_; std::unique_ptr<ApiBindingsClient> api_bindings_client_; std::unique_ptr<ApplicationControllerImpl> application_controller_; - chromium::cast::ApplicationContextPtr application_context_; + fidl::Client<chromium_cast::ApplicationContext> application_context_; fuchsia::web::FrameMediaSettings media_settings_; zx::eventpair headless_view_token_;
diff --git a/fuchsia_web/runners/cast/pending_cast_component.cc b/fuchsia_web/runners/cast/pending_cast_component.cc index 7bde760..6c2f7f2 100644 --- a/fuchsia_web/runners/cast/pending_cast_component.cc +++ b/fuchsia_web/runners/cast/pending_cast_component.cc
@@ -4,7 +4,11 @@ #include "fuchsia_web/runners/cast/pending_cast_component.h" +#include <fidl/fuchsia.io/cpp/hlcpp_conversion.h> +#include <lib/async/default.h> + #include "base/check.h" +#include "base/fuchsia/fuchsia_component_connect.h" #include "base/fuchsia/fuchsia_logging.h" #include "base/fuchsia/process_context.h" #include "base/functional/bind.h" @@ -16,7 +20,11 @@ fidl::InterfaceRequest<fuchsia::component::runner::ComponentController> controller_request, base::StringPiece app_id) - : delegate_(delegate), app_id_(app_id) { + : delegate_(delegate), + app_id_(app_id), + application_context_error_handler_(base::BindRepeating( + &PendingCastComponent::OnApplicationContextFidlError, + base::Unretained(this))) { DCHECK(startup_context); DCHECK(controller_request); @@ -55,6 +63,8 @@ } params_.application_config = std::move(application_config); + fidl::ClientEnd<fuchsia_io::Directory> startup_context_svc_dir = + fidl::HLCPPToNatural(params_.startup_context->svc()->CloneChannel()); // Request custom API bindings from the component's Agent. params_.api_bindings_client = std::make_unique<ApiBindingsClient>( @@ -83,14 +93,19 @@ MaybeLaunchComponent(); }); + auto application_context_client_end = + base::fuchsia_component::ConnectAt<chromium_cast::ApplicationContext>( + startup_context_svc_dir.borrow()); + if (application_context_client_end.is_error()) { + LOG(ERROR) << base::FidlConnectionErrorMessage( + application_context_client_end); + return; + } // Connect to the component-specific ApplicationContext to retrieve the // media-session identifier assigned to this instance. - application_context_ = params_.startup_context->svc() - ->Connect<chromium::cast::ApplicationContext>(); - application_context_.set_error_handler([this](zx_status_t status) { - ZX_LOG(ERROR, status) << "ApplicationContext disconnected."; - delegate_->CancelPendingComponent(this); - }); + application_context_.Bind(std::move(application_context_client_end.value()), + async_get_default_dispatcher(), + &application_context_error_handler_); if (params_.application_config.has_audio_renderer_usage()) { DCHECK(!params_.media_settings); @@ -100,14 +115,25 @@ } else { // If `audio_renderer_usage` is not specified then `AudioConsumer` is used // for that app. We need to fetch `session_id` in that case. - application_context_->GetMediaSessionId([this](uint64_t session_id) { - DCHECK(!params_.media_settings); - params_.media_settings = fuchsia::web::FrameMediaSettings{}; - if (session_id > 0) - params_.media_settings->set_audio_consumer_session_id(session_id); + application_context_->GetMediaSessionId().Then( + [this]( + fidl::Result<chromium_cast::ApplicationContext::GetMediaSessionId>& + result) { + DCHECK(!params_.media_settings); + if (result.is_error()) { + LOG(ERROR) << base::FidlMethodResultErrorMessage( + result, "GetMediaSessionId"); + delegate_->CancelPendingComponent(this); + return; + } + params_.media_settings = fuchsia::web::FrameMediaSettings{}; + if (result->media_session_id() > 0) { + params_.media_settings->set_audio_consumer_session_id( + result->media_session_id()); + } - MaybeLaunchComponent(); - }); + MaybeLaunchComponent(); + }); } } @@ -126,7 +152,18 @@ // user-after-free of |this|. params_.url_rewrite_rules_provider.set_error_handler(nullptr); - params_.application_context = application_context_.Unbind(); + auto result = application_context_.UnbindMaybeGetEndpoint(); + if (result.is_error()) { + ZX_LOG(ERROR, result.error_value().status()); + return; + } + params_.application_context = std::move(result.value()); delegate_->LaunchPendingComponent(this, std::move(params_)); } + +void PendingCastComponent::OnApplicationContextFidlError( + fidl::UnbindInfo error) { + ZX_LOG(ERROR, error.status()) << "ApplicationContext disconnected."; + delegate_->CancelPendingComponent(this); +}
diff --git a/fuchsia_web/runners/cast/pending_cast_component.h b/fuchsia_web/runners/cast/pending_cast_component.h index f3090e8..6bb17c5 100644 --- a/fuchsia_web/runners/cast/pending_cast_component.h +++ b/fuchsia_web/runners/cast/pending_cast_component.h
@@ -5,12 +5,13 @@ #ifndef FUCHSIA_WEB_RUNNERS_CAST_PENDING_CAST_COMPONENT_H_ #define FUCHSIA_WEB_RUNNERS_CAST_PENDING_CAST_COMPONENT_H_ -#include <chromium/cast/cpp/fidl.h> +#include <fidl/chromium.cast/cpp/fidl.h> #include <fuchsia/component/runner/cpp/fidl.h> #include <lib/fidl/cpp/interface_request.h> #include <memory> +#include "base/fuchsia/fidl_event_handler.h" #include "base/strings/string_piece.h" #include "fuchsia_web/runners/cast/cast_component.h" @@ -64,6 +65,8 @@ // Has no effect if |params_| are not yet complete. void MaybeLaunchComponent(); + void OnApplicationContextFidlError(fidl::UnbindInfo error); + // Reference to the Delegate which manages |this|. Delegate* const delegate_; @@ -74,7 +77,9 @@ CastComponent::Params params_; // Used to receive the media session Id and ApplicationConfig. - chromium::cast::ApplicationContextPtr application_context_; + fidl::Client<chromium_cast::ApplicationContext> application_context_; + base::FidlErrorEventHandler<chromium_cast::ApplicationContext> + application_context_error_handler_; chromium::cast::ApplicationConfigManagerPtr application_config_manager_; };
diff --git a/google_apis/gcm/tools/mcs_probe.cc b/google_apis/gcm/tools/mcs_probe.cc index 8dd0559..f43c833 100644 --- a/google_apis/gcm/tools/mcs_probe.cc +++ b/google_apis/gcm/tools/mcs_probe.cc
@@ -163,6 +163,8 @@ return net::OK; } void SetConfig(const Config& config) override {} + void AddObserver(Observer* observer) override {} + void RemoveObserver(Observer* observer) override {} }; class MCSProbeAuthPreferences : public net::HttpAuthPreferences {
diff --git a/infra/config/dev/subprojects/chromium/ci.star b/infra/config/dev/subprojects/chromium/ci.star index 5f80a8f..c263b9d3 100644 --- a/infra/config/dev/subprojects/chromium/ci.star +++ b/infra/config/dev/subprojects/chromium/ci.star
@@ -128,6 +128,18 @@ ) ci_builder( + name = "linux-rel-jammy-dev", + builder_spec = builder_config.builder_spec( + gclient_config = builder_config.gclient_config(config = "chromium"), + chromium_config = builder_config.chromium_config( + config = "chromium", + apply_configs = ["mb"], + build_config = builder_config.build_config.RELEASE, + ), + ), +) + +ci_builder( name = "linux-ssd-rel-dev", description_html = "Ensures builders are using available local SSDs", builder_spec = builder_config.builder_spec(
diff --git a/infra/config/dev/subprojects/chromium/consoles/chromium.swarm.star b/infra/config/dev/subprojects/chromium/consoles/chromium.swarm.star index 7e63938d..041b2b74 100644 --- a/infra/config/dev/subprojects/chromium/consoles/chromium.swarm.star +++ b/infra/config/dev/subprojects/chromium/consoles/chromium.swarm.star
@@ -9,6 +9,7 @@ entries = [ luci.console_view_entry(builder = "ci/android-pie-arm64-rel-dev"), luci.console_view_entry(builder = "ci/linux-rel-dev"), + luci.console_view_entry(builder = "ci/linux-rel-jammy-dev"), luci.console_view_entry(builder = "ci/linux-ssd-rel-dev"), luci.console_view_entry(builder = "ci/mac-rel-dev"), luci.console_view_entry(builder = "ci/mac-arm-rel-dev"),
diff --git a/infra/config/generated/builders/ci/android-12l-x64-dbg-tests/properties.json b/infra/config/generated/builders/ci/android-12l-x64-dbg-tests/properties.json index b2f7648..95ff4df 100644 --- a/infra/config/generated/builders/ci/android-12l-x64-dbg-tests/properties.json +++ b/infra/config/generated/builders/ci/android-12l-x64-dbg-tests/properties.json
@@ -95,5 +95,8 @@ ] }, "builder_group": "chromium.android", - "recipe": "chromium" + "recipe": "chromium", + "sheriff_rotations": [ + "android" + ] } \ No newline at end of file
diff --git a/infra/config/generated/luci/cr-buildbucket-dev.cfg b/infra/config/generated/luci/cr-buildbucket-dev.cfg index d1f34957..ce3d7ac8 100644 --- a/infra/config/generated/luci/cr-buildbucket-dev.cfg +++ b/infra/config/generated/luci/cr-buildbucket-dev.cfg
@@ -193,11 +193,100 @@ description_html: "Test description. <b>Test HTML</b>." } builders { + name: "linux-rel-jammy-dev" + swarming_host: "chromium-swarm-dev.appspot.com" + dimensions: "cpu:x86-64" + dimensions: "os:Ubuntu-22.04" + exe { + cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build" + cipd_version: "refs/heads/main" + cmd: "luciexe" + } + properties: + '{' + ' "$build/chromium_tests_builder_config": {' + ' "builder_config": {' + ' "builder_db": {' + ' "entries": [' + ' {' + ' "builder_id": {' + ' "bucket": "ci",' + ' "builder": "linux-rel-jammy-dev",' + ' "project": "chromium"' + ' },' + ' "builder_spec": {' + ' "builder_group": "chromium.dev",' + ' "execution_mode": "COMPILE_AND_TEST",' + ' "legacy_chromium_config": {' + ' "apply_configs": [' + ' "mb"' + ' ],' + ' "build_config": "Release",' + ' "config": "chromium"' + ' },' + ' "legacy_gclient_config": {' + ' "config": "chromium"' + ' }' + ' }' + ' }' + ' ]' + ' },' + ' "builder_ids": [' + ' {' + ' "bucket": "ci",' + ' "builder": "linux-rel-jammy-dev",' + ' "project": "chromium"' + ' }' + ' ]' + ' }' + ' },' + ' "$build/reclient": {' + ' "instance": "rbe-chromium-trusted",' + ' "jobs": 250,' + ' "metrics_project": "chromium-reclient-metrics"' + ' },' + ' "$recipe_engine/resultdb/test_presentation": {' + ' "column_keys": [],' + ' "grouping_keys": [' + ' "status",' + ' "v.test_suite"' + ' ]' + ' },' + ' "builder_group": "chromium.dev",' + ' "recipe": "swarming/staging"' + '}' + execution_timeout_secs: 10800 + build_numbers: YES + service_account: "chromium-ci-builder-dev@chops-service-accounts.iam.gserviceaccount.com" + experiments { + key: "luci.recipes.use_python3" + value: 100 + } + resultdb { + enable: true + bq_exports { + project: "chrome-luci-data" + dataset: "chromium_staging" + table: "ci_test_results" + test_results {} + } + bq_exports { + project: "chrome-luci-data" + dataset: "chromium_staging" + table: "ci_text_artifacts" + text_artifacts {} + } + history_options { + use_invocation_timestamp: true + } + } + } + builders { name: "linux-ssd-rel-dev" swarming_host: "chromium-swarm-dev.appspot.com" dimensions: "builder:linux-ssd-rel-dev" dimensions: "cpu:x86-64" - dimensions: "os:Ubuntu-18.04" + dimensions: "os:Ubuntu-22.04" exe { cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build" cipd_version: "refs/heads/main"
diff --git a/infra/config/generated/luci/cr-buildbucket.cfg b/infra/config/generated/luci/cr-buildbucket.cfg index 1a2e030a..eb4d7c3 100644 --- a/infra/config/generated/luci/cr-buildbucket.cfg +++ b/infra/config/generated/luci/cr-buildbucket.cfg
@@ -23897,9 +23897,12 @@ ' },' ' "builder_group": "chromium.android",' ' "led_builder_is_bootstrapped": true,' - ' "recipe": "chromium"' + ' "recipe": "chromium",' + ' "sheriff_rotations": [' + ' "android"' + ' ]' '}' - execution_timeout_secs: 14400 + execution_timeout_secs: 10800 build_numbers: YES service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com" experiments {
diff --git a/infra/config/generated/luci/luci-milo-dev.cfg b/infra/config/generated/luci/luci-milo-dev.cfg index 1856870..716892c 100644 --- a/infra/config/generated/luci/luci-milo-dev.cfg +++ b/infra/config/generated/luci/luci-milo-dev.cfg
@@ -17,6 +17,9 @@ name: "buildbucket/luci.chromium.ci/linux-rel-dev" } builders { + name: "buildbucket/luci.chromium.ci/linux-rel-jammy-dev" + } + builders { name: "buildbucket/luci.chromium.ci/linux-ssd-rel-dev" } builders {
diff --git a/infra/config/generated/luci/luci-scheduler-dev.cfg b/infra/config/generated/luci/luci-scheduler-dev.cfg index f32dca7..2e841043 100644 --- a/infra/config/generated/luci/luci-scheduler-dev.cfg +++ b/infra/config/generated/luci/luci-scheduler-dev.cfg
@@ -23,6 +23,15 @@ } } job { + id: "linux-rel-jammy-dev" + realm: "ci" + buildbucket { + server: "cr-buildbucket-dev.appspot.com" + bucket: "ci" + builder: "linux-rel-jammy-dev" + } +} +job { id: "linux-ssd-rel-dev" realm: "ci" buildbucket { @@ -72,6 +81,7 @@ realm: "ci" triggers: "android-pie-arm64-rel-dev" triggers: "linux-rel-dev" + triggers: "linux-rel-jammy-dev" triggers: "linux-ssd-rel-dev" triggers: "mac-arm-rel-dev" triggers: "mac-rel-dev"
diff --git a/infra/config/generated/sheriff-rotations/android.txt b/infra/config/generated/sheriff-rotations/android.txt index cf33e59..e30dc78 100644 --- a/infra/config/generated/sheriff-rotations/android.txt +++ b/infra/config/generated/sheriff-rotations/android.txt
@@ -14,6 +14,7 @@ ci/Nougat Phone Tester ci/android-10-arm64-rel ci/android-12-x64-rel +ci/android-12l-x64-dbg-tests ci/android-androidx-packager ci/android-bfcache-rel ci/android-binary-size-generator
diff --git a/infra/config/lib/linux-default.json b/infra/config/lib/linux-default.json index 1fe063a..d35caee 100644 --- a/infra/config/lib/linux-default.json +++ b/infra/config/lib/linux-default.json
@@ -1,4 +1,8 @@ { + "ci": { + "linux-rel-jammy-dev": "Ubuntu-22.04", + "linux-ssd-rel-dev": "Ubuntu-22.04" + }, "try": { "linux-rel": "Ubuntu-22.04", "linux_chromium_tsan_rel_ng": "Ubuntu-22.04"
diff --git a/infra/config/subprojects/chromium/ci/chromium.android.star b/infra/config/subprojects/chromium/ci/chromium.android.star index df3572d..6a73fc8 100644 --- a/infra/config/subprojects/chromium/ci/chromium.android.star +++ b/infra/config/subprojects/chromium/ci/chromium.android.star
@@ -615,13 +615,10 @@ ), build_gs_bucket = "chromium-android-archive", ), - sheriff_rotations = args.ignore_default(None), console_view_entry = consoles.console_view_entry( category = "tester|tablet", short_name = "12L", ), - # TODO: This can be reduced when builder works. - execution_timeout = 4 * time.hour, ) ci.builder(
diff --git a/ios/chrome/browser/ui/authentication/signin/advanced_settings_signin/BUILD.gn b/ios/chrome/browser/ui/authentication/signin/advanced_settings_signin/BUILD.gn index e7db428..dabec88a 100644 --- a/ios/chrome/browser/ui/authentication/signin/advanced_settings_signin/BUILD.gn +++ b/ios/chrome/browser/ui/authentication/signin/advanced_settings_signin/BUILD.gn
@@ -92,6 +92,7 @@ "//ios/chrome/browser/signin:fake_system_identity", "//ios/chrome/browser/ui/authentication:eg_test_support+eg2", "//ios/chrome/browser/ui/authentication/signin/advanced_settings_signin:constants", + "//ios/chrome/browser/ui/authentication/unified_consent:constants", "//ios/chrome/browser/ui/bookmarks:eg_test_support+eg2", "//ios/chrome/browser/ui/content_suggestions:feature_flags", "//ios/chrome/browser/ui/recent_tabs:recent_tabs_ui_constants",
diff --git a/ios/chrome/browser/ui/authentication/signin/advanced_settings_signin/advanced_settings_signin_egtest.mm b/ios/chrome/browser/ui/authentication/signin/advanced_settings_signin/advanced_settings_signin_egtest.mm index 030dea4..1ade38f 100644 --- a/ios/chrome/browser/ui/authentication/signin/advanced_settings_signin/advanced_settings_signin_egtest.mm +++ b/ios/chrome/browser/ui/authentication/signin/advanced_settings_signin/advanced_settings_signin_egtest.mm
@@ -11,6 +11,7 @@ #import "ios/chrome/browser/ui/authentication/signin_earl_grey.h" #import "ios/chrome/browser/ui/authentication/signin_earl_grey_ui_test_util.h" #import "ios/chrome/browser/ui/authentication/signin_matchers.h" +#import "ios/chrome/browser/ui/authentication/unified_consent/unified_consent_constants.h" #import "ios/chrome/browser/ui/bookmarks/bookmark_earl_grey.h" #import "ios/chrome/browser/ui/bookmarks/bookmark_earl_grey_ui.h" #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_feature.h" @@ -114,14 +115,17 @@ // Open the sync passphrase editor through the sign-in flow. [ChromeEarlGreyUI openSettingsMenu]; [ChromeEarlGreyUI tapSettingsMenuButton:PrimarySignInButton()]; - [[EarlGrey selectElementWithMatcher:SettingsLink()] performAction:grey_tap()]; - [[EarlGrey - selectElementWithMatcher:grey_allOf( - grey_kindOfClassName(@"UILabel"), - grey_accessibilityLabel( - l10n_util::GetNSString( - IDS_IOS_MANAGE_SYNC_ENCRYPTION)), - nil)] performAction:grey_tap()]; + [[[EarlGrey selectElementWithMatcher:SettingsLink()] + usingSearchAction:grey_scrollInDirection(kGREYDirectionDown, 200) + onElementWithMatcher:grey_accessibilityID( + kUnifiedConsentScrollViewIdentifier)] + performAction:grey_tap()]; + [[[EarlGrey selectElementWithMatcher:grey_accessibilityID( + kEncryptionAccessibilityIdentifier)] + usingSearchAction:grey_scrollInDirection(kGREYDirectionDown, 200) + onElementWithMatcher:grey_accessibilityID( + kManageSyncTableViewAccessibilityIdentifier)] + performAction:grey_tap()]; [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(l10n_util::GetNSString( IDS_SYNC_FULL_ENCRYPTION_DATA))]
diff --git a/ios/chrome/browser/ui/bring_android_tabs/bring_android_tabs_prompt_bottom_message_provider.swift b/ios/chrome/browser/ui/bring_android_tabs/bring_android_tabs_prompt_bottom_message_provider.swift index 44c9f7e..4610f9a 100644 --- a/ios/chrome/browser/ui/bring_android_tabs/bring_android_tabs_prompt_bottom_message_provider.swift +++ b/ios/chrome/browser/ui/bring_android_tabs/bring_android_tabs_prompt_bottom_message_provider.swift
@@ -16,10 +16,10 @@ // command invocation. weak var commandHandler: BringAndroidTabsCommands? // Number of active tabs from Android. - let tabsCount: Int32 + let tabsCount: Int init(tabsCount: Int) { - self.tabsCount = Int32(tabsCount) + self.tabsCount = tabsCount } // View controller that manages this view. Should be added to the view
diff --git a/ios/chrome/browser/ui/bring_android_tabs/bring_android_tabs_prompt_bottom_message_view.swift b/ios/chrome/browser/ui/bring_android_tabs/bring_android_tabs_prompt_bottom_message_view.swift index b599f5e..72e5faee6 100644 --- a/ios/chrome/browser/ui/bring_android_tabs/bring_android_tabs_prompt_bottom_message_view.swift +++ b/ios/chrome/browser/ui/bring_android_tabs/bring_android_tabs_prompt_bottom_message_view.swift
@@ -15,7 +15,7 @@ // The view object for "Bring Android Tabs" bottom message prompt. struct BringAndroidTabsPromptBottomMessageView: View { // Number of tabs brought from Android. - let tabsCount: Int32 + let tabsCount: Int // Provider object for the view. weak var provider: BringAndroidTabsPromptBottomMessageProvider? @@ -31,14 +31,14 @@ spacing: kTextVerticalSpacing - kPromptInnerPadding ) { Text( - L10NUtils.pluralString( - forMessageId: IDS_IOS_BRING_ANDROID_TABS_PROMPT_TITLE, + L10nUtils.pluralString( + messageId: IDS_IOS_BRING_ANDROID_TABS_PROMPT_TITLE, number: self.tabsCount) ) .font(.body) Text( - L10NUtils.pluralString( - forMessageId: IDS_IOS_BRING_ANDROID_TABS_PROMPT_SUBTITLE, + L10nUtils.pluralString( + messageId: IDS_IOS_BRING_ANDROID_TABS_PROMPT_SUBTITLE, number: self.tabsCount) ) .font(.footnote) @@ -56,8 +56,8 @@ Button(action: self.review) { HStack { Text( - L10NUtils.pluralString( - forMessageId: + L10nUtils.pluralString( + messageId: IDS_IOS_BRING_ANDROID_TABS_PROMPT_REVIEW_TABS_BUTTON_BOTTOM_MESSAGE, number: self.tabsCount)) Spacer()
diff --git a/ios/chrome/browser/ui/bring_android_tabs/bring_android_tabs_prompt_confirmation_alert_view_controller.swift b/ios/chrome/browser/ui/bring_android_tabs/bring_android_tabs_prompt_confirmation_alert_view_controller.swift index 51c7a8b..fb9ac05 100644 --- a/ios/chrome/browser/ui/bring_android_tabs/bring_android_tabs_prompt_confirmation_alert_view_controller.swift +++ b/ios/chrome/browser/ui/bring_android_tabs/bring_android_tabs_prompt_confirmation_alert_view_controller.swift
@@ -22,10 +22,10 @@ // invocation. weak var commandHandler: BringAndroidTabsCommands? // Number of active tabs from Android. - private let tabsCount: Int32 + private let tabsCount: Int init(tabsCount: Int) { - self.tabsCount = Int32(tabsCount) + self.tabsCount = tabsCount } override func viewDidLoad() { @@ -37,21 +37,21 @@ self.customSpacingAfterImage = kSpacingAfterImage self.helpButtonAvailable = false self.showDismissBarButton = false - self.titleString = L10NUtils.pluralString( - forMessageId: IDS_IOS_BRING_ANDROID_TABS_PROMPT_TITLE, + self.titleString = L10nUtils.pluralString( + messageId: IDS_IOS_BRING_ANDROID_TABS_PROMPT_TITLE, number: self.tabsCount) self.titleTextStyle = .title2 - self.subtitleString = L10NUtils.pluralString( - forMessageId: IDS_IOS_BRING_ANDROID_TABS_PROMPT_SUBTITLE, + self.subtitleString = L10nUtils.pluralString( + messageId: IDS_IOS_BRING_ANDROID_TABS_PROMPT_SUBTITLE, number: self.tabsCount) - self.primaryActionString = L10NUtils.pluralString( - forMessageId: IDS_IOS_BRING_ANDROID_TABS_PROMPT_OPEN_TABS_BUTTON, + self.primaryActionString = L10nUtils.pluralString( + messageId: IDS_IOS_BRING_ANDROID_TABS_PROMPT_OPEN_TABS_BUTTON, number: self.tabsCount) - self.secondaryActionString = L10NUtils.pluralString( - forMessageId: IDS_IOS_BRING_ANDROID_TABS_CANCEL_BUTTON, + self.secondaryActionString = L10nUtils.pluralString( + messageId: IDS_IOS_BRING_ANDROID_TABS_CANCEL_BUTTON, number: self.tabsCount) - self.tertiaryActionString = L10NUtils.pluralString( - forMessageId: + self.tertiaryActionString = L10nUtils.pluralString( + messageId: IDS_IOS_BRING_ANDROID_TABS_PROMPT_REVIEW_TABS_BUTTON_CONFIRMATION_ALERT, number: self.tabsCount) super.viewDidLoad()
diff --git a/ios/chrome/browser/ui/popup_menu/overflow_menu/overflow_menu_action_row.swift b/ios/chrome/browser/ui/popup_menu/overflow_menu/overflow_menu_action_row.swift index 07680e0..10bb7d7 100644 --- a/ios/chrome/browser/ui/popup_menu/overflow_menu/overflow_menu_action_row.swift +++ b/ios/chrome/browser/ui/popup_menu/overflow_menu/overflow_menu_action_row.swift
@@ -81,8 +81,8 @@ height: OverflowMenuActionRow.newLabelIconWidth ) .overlay { - if let newLabelString = L10NUtils.stringWithFixup( - forMessageId: IDS_IOS_NEW_LABEL_FEATURE_BADGE) + if let newLabelString = L10nUtils.stringWithFixup( + messageId: IDS_IOS_NEW_LABEL_FEATURE_BADGE) { Text(newLabelString) .font(.system(size: 10, weight: .bold, design: .rounded))
diff --git a/ios/chrome/browser/ui/popup_menu/overflow_menu/overflow_menu_destination_view.swift b/ios/chrome/browser/ui/popup_menu/overflow_menu/overflow_menu_destination_view.swift index a0f677a..48346c2c 100644 --- a/ios/chrome/browser/ui/popup_menu/overflow_menu/overflow_menu_destination_view.swift +++ b/ios/chrome/browser/ui/popup_menu/overflow_menu/overflow_menu_destination_view.swift
@@ -145,8 +145,8 @@ .frame(width: Dimensions.newLabelBadgeWidth, height: Dimensions.newLabelBadgeWidth) .offset(x: newBadgeOffsetX, y: newBadgeOffsetY) .overlay { - if let newLabelString = L10NUtils.stringWithFixup( - forMessageId: IDS_IOS_NEW_LABEL_FEATURE_BADGE) + if let newLabelString = L10nUtils.stringWithFixup( + messageId: IDS_IOS_NEW_LABEL_FEATURE_BADGE) { Text(newLabelString) .font(.system(size: 10, weight: .bold, design: .rounded)) @@ -260,12 +260,12 @@ return [ destination.name, destination.badge == .error - ? L10NUtils.stringWithFixup( - forMessageId: IDS_IOS_ITEM_ACCOUNT_ERROR_BADGE_ACCESSIBILITY_HINT) : nil, + ? L10nUtils.stringWithFixup( + messageId: IDS_IOS_ITEM_ACCOUNT_ERROR_BADGE_ACCESSIBILITY_HINT) : nil, destination.badge == .promo - ? L10NUtils.stringWithFixup(forMessageId: IDS_IOS_NEW_ITEM_ACCESSIBILITY_HINT) : nil, + ? L10nUtils.stringWithFixup(messageId: IDS_IOS_NEW_ITEM_ACCESSIBILITY_HINT) : nil, destination.badge == .new - ? L10NUtils.stringWithFixup(forMessageId: IDS_IOS_TOOLS_MENU_CELL_NEW_FEATURE_BADGE) : nil, + ? L10nUtils.stringWithFixup(messageId: IDS_IOS_TOOLS_MENU_CELL_NEW_FEATURE_BADGE) : nil, ].compactMap { $0 }.joined(separator: ", ") }
diff --git a/ios/chrome/browser/ui/settings/safety_check/safety_check_table_view_controller.swift b/ios/chrome/browser/ui/settings/safety_check/safety_check_table_view_controller.swift index dbf0a860..5a08768 100644 --- a/ios/chrome/browser/ui/settings/safety_check/safety_check_table_view_controller.swift +++ b/ios/chrome/browser/ui/settings/safety_check/safety_check_table_view_controller.swift
@@ -74,7 +74,7 @@ override func viewDidLoad() { super.viewDidLoad() self.tableView.accessibilityIdentifier = SafetyCheckTableViewController.accessibilityIdentifier - self.title = L10NUtils.string(forMessageId: IDS_OPTIONS_ADVANCED_SECTION_TITLE_SAFETY_CHECK) + self.title = L10nUtils.string(messageId: IDS_OPTIONS_ADVANCED_SECTION_TITLE_SAFETY_CHECK) } // MARK: SafetyCheckConsumer
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/inactive_tabs_button.swift b/ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/inactive_tabs_button.swift index ec5d6d8..3fb32df 100644 --- a/ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/inactive_tabs_button.swift +++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/inactive_tabs_button.swift
@@ -74,7 +74,7 @@ /// Displays the button title. @ViewBuilder private func title() -> some View { - Text(L10NUtils.string(forMessageId: IDS_IOS_INACTIVE_TABS_BUTTON_TITLE)) + Text(L10nUtils.string(messageId: IDS_IOS_INACTIVE_TABS_BUTTON_TITLE)) .foregroundColor(.white) } @@ -83,8 +83,8 @@ private func subtitle() -> some View { if let daysThreshold = state.daysThreshold { Text( - L10NUtils.formatString( - forMessageId: IDS_IOS_INACTIVE_TABS_BUTTON_SUBTITLE, + L10nUtils.formatString( + messageId: IDS_IOS_INACTIVE_TABS_BUTTON_SUBTITLE, argument: String(daysThreshold)) ) .font(.caption2)
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/inactive_tabs_preamble_header.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/inactive_tabs_preamble_header.mm index a935d65..045820b 100644 --- a/ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/inactive_tabs_preamble_header.mm +++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/inactive_tabs_preamble_header.mm
@@ -65,7 +65,7 @@ // Update the text view's attributed text. NSString* argument = [NSString stringWithFormat:@"%@", @(daysThreshold)]; NSString* text = - [L10NUtils formatStringForMessageId:IDS_IOS_INACTIVE_TABS_PREAMBLE + [L10nUtils formatStringForMessageID:IDS_IOS_INACTIVE_TABS_PREAMBLE argument:argument]; NSDictionary* attributes = @{ NSForegroundColorAttributeName : [UIColor colorNamed:kTextSecondaryColor],
diff --git a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1 index aa534f2..ca16230 100644 --- a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1 +++ b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@ -5c46053a99abbc8a5e790046f258a2430c2336e2 \ No newline at end of file +cbaa239782383d2e72c6fe049d299a9c9f88dd47 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1 index ec71bc9..1271a43 100644 --- a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1 +++ b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@ -9d2748983ecc4914ac01c8bacefe3d803629cff1 \ No newline at end of file +2649413e4e9bbfba7712b85991df56a1ef22a326 \ No newline at end of file
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 03c019d..7f34845 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 @@ -6d4206127c066ddc9b6e6c139e82ab73f8d90548 \ No newline at end of file +ba04a45b18c5a970771d7877b3f95eb513b5cff4 \ 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 09e46d9..7da3683 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 @@ -8f01f643697502e9fbf14745a031e5fe8a78c841 \ No newline at end of file +bb173adcaacf259eb81a041661b067ec4e33dc45 \ 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 ed98d49..5bc60e9 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 @@ -07267de2d55083787701a2030808d8d69c0dbfe1 \ No newline at end of file +9e94d828cbabbe9c2f2d52eadda4ef31e1af0066 \ 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 8d6c5bc8..36f893bc 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 @@ -e9aaecd89dd18fa56427a10b082f22619d39eadb \ No newline at end of file +58f114d01b9381d115a8602727eacc020c916d7a \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1 index 99cc70b8..11dccdd 100644 --- a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -9f7b53044c51e7a699a14628fabe14c45af88eea \ No newline at end of file +6264e04acda12357240de2c49fafc17671793c89 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1 index 7ae1c48..1633042d 100644 --- a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -2b9779b29bb5ccdd83a0296b6a43d50287a0a3d1 \ No newline at end of file +d4e07b8801337bc26aa0a44a6cede63fc0cf4b03 \ 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 a162faa..537c8ab 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 @@ -e8ee1fdbb01264d8332592997a9dea60bcd9d823 \ No newline at end of file +1cdfe1e82eb8dc6bd37f341c49d1c4e6fb1c9540 \ 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 7b2b661..412f645 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 @@ -be188868038668a1b9d251a43468bbd37ed9579b \ No newline at end of file +01e7da9ea93f8cf18da0b15909edb1a1d0f41c5b \ 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 89e790c..1bf235cb 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 @@ -b8c7e905b58cae8edca24c4ff8228e67ae6ed36e \ No newline at end of file +9954b857bc2d41c667742e5938fbdca1ab09df66 \ 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 ae301ef..c298e39 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 @@ -23f9930feae0aa1fdc921a561649c9f311fd51bd \ No newline at end of file +6b299c717929d2b2f150ba708349989930c9850f \ No newline at end of file
diff --git a/media/base/media_switches.cc b/media/base/media_switches.cc index b09f99d..2846d0f 100644 --- a/media/base/media_switches.cc +++ b/media/base/media_switches.cc
@@ -1232,7 +1232,13 @@ // Spawn utility processes to perform hardware decode acceleration instead of // using the GPU process. const base::Feature MEDIA_EXPORT kUseOutOfProcessVideoDecoding{ - "UseOutOfProcessVideoDecoding", base::FEATURE_DISABLED_BY_DEFAULT}; + "UseOutOfProcessVideoDecoding", +#if BUILDFLAG(IS_CHROMEOS_LACROS) + base::FEATURE_ENABLED_BY_DEFAULT +#else + base::FEATURE_DISABLED_BY_DEFAULT +#endif +}; #endif // BUILDFLAG(ALLOW_OOP_VIDEO_DECODER) #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) @@ -1264,11 +1270,11 @@ #endif ); -// Use SequencedTaskRunner for each MojoVideoEncodeAcceleratorService. Replaces +// Use TaskRunner for each MojoVideoEncodeAcceleratorService. Replaces // per-accelerator encoding task runner. -BASE_FEATURE(kUseSequencedTaskRunnerForMojoVEAService, - "UseSequencedTaskRunnerForMojoVEAService", -#if BUILDFLAG(IS_APPLE) +BASE_FEATURE(kUseTaskRunnerForMojoVEAService, + "kUseTaskRunnerForMojoVEAService", +#if BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_WIN) base::FEATURE_ENABLED_BY_DEFAULT #else base::FEATURE_DISABLED_BY_DEFAULT
diff --git a/media/base/media_switches.h b/media/base/media_switches.h index 87d1edfa..1041309 100644 --- a/media/base/media_switches.h +++ b/media/base/media_switches.h
@@ -415,7 +415,7 @@ MEDIA_EXPORT BASE_DECLARE_FEATURE(kUseMojoVideoDecoderForPepper); MEDIA_EXPORT BASE_DECLARE_FEATURE(kUseSequencedTaskRunnerForMediaService); MEDIA_EXPORT BASE_DECLARE_FEATURE(kUseSequencedTaskRunnerForMojoVEAProvider); -MEDIA_EXPORT BASE_DECLARE_FEATURE(kUseSequencedTaskRunnerForMojoVEAService); +MEDIA_EXPORT BASE_DECLARE_FEATURE(kUseTaskRunnerForMojoVEAService); #if BUILDFLAG(IS_FUCHSIA) MEDIA_EXPORT BASE_DECLARE_FEATURE(kFuchsiaMediacodecVideoEncoder);
diff --git a/media/filters/BUILD.gn b/media/filters/BUILD.gn index 69c989df..9a209d41 100644 --- a/media/filters/BUILD.gn +++ b/media/filters/BUILD.gn
@@ -247,6 +247,8 @@ sources += [ "hls_data_source_provider.cc", "hls_data_source_provider.h", + "hls_manifest_demuxer_engine.cc", + "hls_manifest_demuxer_engine.h", "manifest_demuxer.cc", "manifest_demuxer.h", ] @@ -402,7 +404,10 @@ } if (enable_hls_demuxer) { - sources += [ "hls_data_source_provider_unittest.cc" ] + sources += [ + "hls_data_source_provider_unittest.cc", + "manifest_demuxer_unittest.cc", + ] } if (media_use_ffmpeg) {
diff --git a/media/filters/demuxer_manager.cc b/media/filters/demuxer_manager.cc index 245c603..25db5bc 100644 --- a/media/filters/demuxer_manager.cc +++ b/media/filters/demuxer_manager.cc
@@ -21,6 +21,7 @@ #include "url/gurl.h" #if BUILDFLAG(ENABLE_HLS_DEMUXER) +#include "media/filters/hls_manifest_demuxer_engine.h" #include "media/filters/manifest_demuxer.h" #endif // BUILDFLAG(ENABLE_HLS_DEMUXER) @@ -153,7 +154,13 @@ DCHECK(client_); } -DemuxerManager::~DemuxerManager() = default; +DemuxerManager::~DemuxerManager() { + // ManifestDemuxer has multiple outstanding weak pointers bound to the media + // thread, and needs to be deleted there. + if (GetDemuxerType() == DemuxerType::kManifestDemuxer) { + media_task_runner_->DeleteSoon(FROM_HERE, std::move(demuxer_)); + } +} void DemuxerManager::InvalidateWeakPtrs() { weak_factory_.InvalidateWeakPtrs(); @@ -573,9 +580,9 @@ #if BUILDFLAG(ENABLE_HLS_DEMUXER) std::unique_ptr<Demuxer> DemuxerManager::CreateHlsDemuxer() { - return std::make_unique<ManifestDemuxer>(media_task_runner_, - client_->GetHlsDataSourceProvider(), - loaded_url_, media_log_.get()); + auto player_impl = std::make_unique<HlsManifestDemuxerEngine>(); + return std::make_unique<ManifestDemuxer>( + media_task_runner_, std::move(player_impl), media_log_.get()); } #endif
diff --git a/media/filters/hls_data_source_provider.h b/media/filters/hls_data_source_provider.h index 11d8cdd..daee452c 100644 --- a/media/filters/hls_data_source_provider.h +++ b/media/filters/hls_data_source_provider.h
@@ -26,10 +26,10 @@ } // namespace -class HlsDemuxer; +class HlsManifestDemuxerEngine; -// Interface which can provide HlsDemuxer with data, respecting byterange -// boundaries. +// Interface which can provide HlsManifestDemuxerEngine with data, respecting +// byterange boundaries. class MEDIA_EXPORT HlsDataSource { public: enum class ReadStatusCodes : StatusCodeType { @@ -72,19 +72,20 @@ const absl::optional<size_t> size_; }; -// Interface which can provide the HlsDemuxer with data sources, given a URI and -// an optional byterange. This interface should be used via +// Interface which can provide the HlsManifestDemuxerEngine with data sources, +// given a URI and an optional byterange. This interface should be used via // `base::SequenceBound` to proxy requests across the media thread and the main // thread. class MEDIA_EXPORT HlsDataSourceProvider { public: virtual ~HlsDataSourceProvider(); - // Sets the owning HlsDemuxer for this HlsDataSourceProvider. + // Sets the owning HlsManifestDemuxerEngine for this HlsDataSourceProvider. // This may only be called once. - virtual void SetOwner(HlsDemuxer*) = 0; + virtual void SetOwner(HlsManifestDemuxerEngine*) = 0; - // API allowing an HlsDemuxer to make requests for external data. + // API allowing an HlsManifestDemuxerEngine to make requests for external + // data. using RequestCb = base::OnceCallback<void(std::unique_ptr<HlsDataSource>)>; virtual void RequestDataSource(GURL uri, absl::optional<hls::types::ByteRange> range,
diff --git a/media/filters/hls_manifest_demuxer_engine.cc b/media/filters/hls_manifest_demuxer_engine.cc new file mode 100644 index 0000000..376e04f --- /dev/null +++ b/media/filters/hls_manifest_demuxer_engine.cc
@@ -0,0 +1,75 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "media/filters/hls_manifest_demuxer_engine.h" + +#include <vector> + +#include "base/logging.h" +#include "base/memory/scoped_refptr.h" +#include "base/task/bind_post_task.h" +#include "base/task/sequenced_task_runner.h" +#include "base/time/time.h" +#include "media/base/media_log.h" +#include "media/base/media_track.h" +#include "media/base/pipeline_status.h" +#include "media/filters/manifest_demuxer.h" +#include "media/formats/hls/audio_rendition.h" +#include "media/formats/hls/media_playlist.h" +#include "media/formats/hls/multivariant_playlist.h" +#include "media/formats/hls/types.h" +#include "media/formats/hls/variant_stream.h" +#include "third_party/abseil-cpp/absl/types/optional.h" + +namespace media { + +HlsManifestDemuxerEngine::~HlsManifestDemuxerEngine() = default; +HlsManifestDemuxerEngine::HlsManifestDemuxerEngine() = default; + +std::string HlsManifestDemuxerEngine::GetName() const { + return "HlsManifestDemuxer"; +} + +void HlsManifestDemuxerEngine::Initialize(ManifestDemuxerEngineHost* host, + PipelineStatusCallback status_cb) { + std::move(status_cb).Run(PIPELINE_ERROR_INVALID_STATE); +} + +void HlsManifestDemuxerEngine::OnTimeUpdate(base::TimeDelta time, + double playback_rate, + ManifestDemuxer::DelayCallback cb) { + std::move(cb).Run(kNoTimestamp); +} + +bool HlsManifestDemuxerEngine::Seek(base::TimeDelta time) { + // TODO(crbug/1266991) + NOTIMPLEMENTED(); + return true; +} + +void HlsManifestDemuxerEngine::StartWaitingForSeek() { + // TODO(crbug/1266991) + NOTIMPLEMENTED(); +} + +void HlsManifestDemuxerEngine::AbortPendingReads() { + // TODO(crbug/1266991) + NOTIMPLEMENTED(); +} + +bool HlsManifestDemuxerEngine::IsSeekable() { + NOTIMPLEMENTED(); + return true; +} + +int64_t HlsManifestDemuxerEngine::GetMemoryUsage() const { + return 0; +} + +void HlsManifestDemuxerEngine::Stop() { + // TODO(crbug/1266991) + NOTIMPLEMENTED(); +} + +} // namespace media
diff --git a/media/filters/hls_manifest_demuxer_engine.h b/media/filters/hls_manifest_demuxer_engine.h new file mode 100644 index 0000000..c6b9b2f --- /dev/null +++ b/media/filters/hls_manifest_demuxer_engine.h
@@ -0,0 +1,43 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MEDIA_FILTERS_HLS_MANIFEST_DEMUXER_ENGINE_H_ +#define MEDIA_FILTERS_HLS_MANIFEST_DEMUXER_ENGINE_H_ + +#include <vector> + +#include "base/time/time.h" +#include "media/base/media_export.h" +#include "media/base/pipeline_status.h" +#include "media/filters/hls_data_source_provider.h" +#include "media/filters/manifest_demuxer.h" + +namespace media { + +// A HLS-Parser/Player implementation of ManifestDemuxer's Engine interface. +// This will use the HLS parsers and rendition selectors to fetch and parse +// playlists, followed by fetching and appending media segments. +class MEDIA_EXPORT HlsManifestDemuxerEngine : public ManifestDemuxer::Engine { + public: + HlsManifestDemuxerEngine(); + + // ManifestDemuxer::Engine implementation. + ~HlsManifestDemuxerEngine() override; + std::string GetName() const override; + void Initialize(ManifestDemuxerEngineHost* host, + PipelineStatusCallback status_cb) override; + void OnTimeUpdate(base::TimeDelta time, + double playback_rate, + ManifestDemuxer::DelayCallback cb) override; + bool Seek(base::TimeDelta time) override; + void StartWaitingForSeek() override; + void AbortPendingReads() override; + bool IsSeekable() override; + int64_t GetMemoryUsage() const override; + void Stop() override; +}; + +} // namespace media + +#endif // MEDIA_FILTERS_HLS_MANIFEST_DEMUXER_ENGINE_H_
diff --git a/media/filters/manifest_demuxer.cc b/media/filters/manifest_demuxer.cc index 7a866825..92fcf1f 100644 --- a/media/filters/manifest_demuxer.cc +++ b/media/filters/manifest_demuxer.cc
@@ -8,6 +8,7 @@ #include "base/logging.h" #include "base/memory/scoped_refptr.h" +#include "base/task/bind_post_task.h" #include "base/task/sequenced_task_runner.h" #include "base/time/time.h" #include "media/base/container_names.h" @@ -15,6 +16,11 @@ #include "media/base/media_log.h" #include "media/base/media_track.h" #include "media/base/pipeline_status.h" +#include "media/formats/hls/audio_rendition.h" +#include "media/formats/hls/media_playlist.h" +#include "media/formats/hls/multivariant_playlist.h" +#include "media/formats/hls/types.h" +#include "media/formats/hls/variant_stream.h" #include "third_party/abseil-cpp/absl/types/optional.h" namespace media { @@ -57,21 +63,18 @@ return stream_->SupportsConfigChanges(); } -ManifestDemuxer::ManifestDemuxer( - scoped_refptr<base::SequencedTaskRunner> media_task_runner_, - base::SequenceBound<HlsDataSourceProvider> data_source_provider, - GURL root_playlist_uri, - MediaLog* media_log) - : media_log_(media_log), media_task_runner_(std::move(media_task_runner_)) { - // TODO(crbug/1266991): Save `data_source_provider` to make requests for media - // content. - DCHECK(data_source_provider); -} - ManifestDemuxer::~ManifestDemuxer() { DCHECK(media_task_runner_->RunsTasksInCurrentSequence()); } +ManifestDemuxer::ManifestDemuxer( + scoped_refptr<base::SequencedTaskRunner> media_task_runner, + std::unique_ptr<ManifestDemuxer::Engine> impl, + MediaLog* media_log) + : media_log_(media_log->Clone()), + media_task_runner_(std::move(media_task_runner)), + impl_(std::move(impl)) {} + std::vector<DemuxerStream*> ManifestDemuxer::GetAllStreams() { DCHECK(media_task_runner_->RunsTasksInCurrentSequence()); @@ -99,7 +102,7 @@ } std::string ManifestDemuxer::GetDisplayName() const { - return "ManifestDemuxer"; + return impl_->GetName(); } DemuxerType ManifestDemuxer::GetDemuxerType() const { @@ -109,8 +112,9 @@ void ManifestDemuxer::Initialize(DemuxerHost* host, PipelineStatusCallback status_cb) { DCHECK(media_task_runner_->RunsTasksInCurrentSequence()); - // TODO(crbug/1266991): Save `host` for error handling. + DCHECK(!pending_init_); + host_ = host; pending_init_ = std::move(status_cb); chunk_demuxer_ = std::make_unique<ChunkDemuxer>( base::BindOnce(&ManifestDemuxer::OnChunkDemuxerOpened, @@ -124,51 +128,104 @@ chunk_demuxer_->Initialize( host, base::BindOnce(&ManifestDemuxer::OnChunkDemuxerInitialized, weak_factory_.GetWeakPtr())); + + impl_->Initialize(this, base::BindOnce(&ManifestDemuxer::OnEngineInitialized, + weak_factory_.GetWeakPtr())); } void ManifestDemuxer::AbortPendingReads() { DCHECK(media_task_runner_->RunsTasksInCurrentSequence()); chunk_demuxer_->AbortPendingReads(); + impl_->AbortPendingReads(); } void ManifestDemuxer::StartWaitingForSeek(base::TimeDelta seek_time) { DCHECK(media_task_runner_->RunsTasksInCurrentSequence()); chunk_demuxer_->StartWaitingForSeek(seek_time); + impl_->StartWaitingForSeek(); } void ManifestDemuxer::CancelPendingSeek(base::TimeDelta seek_time) { DCHECK(media_task_runner_->RunsTasksInCurrentSequence()); - DVLOG(1) << __func__ << "(seek_time=" << seek_time.InMicroseconds() << "us)"; - // TODO(crbug/1266991): Time remapping. - // TODO(crbug/1266991): Let the wrapped ChunkDemuxer know to cancel pending - // seek for `seek_time`. + // TODO(crbug/1266991): In the current implementation, if a seek happens while + // another seek is pending, the first seek is allowed to finish before + // starting the second seek. As a result, there isn't really a good way to + // cancel a pending one, so we don't do anything. + NOTIMPLEMENTED(); } void ManifestDemuxer::Seek(base::TimeDelta time, PipelineStatusCallback status_cb) { DCHECK(media_task_runner_->RunsTasksInCurrentSequence()); + CHECK(!pending_seek_); + + pending_seek_ = std::move(status_cb); media_time_ = time; - // TODO(crbug/1266991): Seek the wrapped ChunkDemuxer. - std::move(status_cb).Run(PIPELINE_ERROR_ABORT); + // Seeks and periodic updates are considered to be events. No two events may + // be running at the same time. Seeks still need to happen however, so a seek + // should be stored for later. + if (has_pending_event_) { + return; + } + + SeekInternal(); +} + +void ManifestDemuxer::SeekInternal() { + DCHECK(media_task_runner_->RunsTasksInCurrentSequence()); + + // SeekInternal can be delayed and potentially called after a pending event + // finishes. Pending events should not restart playback which was stopped + // prior to the seek being requested, so we can check that it's still 0. + CHECK_EQ(current_playback_rate_, 0); + + has_pending_event_ = true; + + // Cancel any outstanding events, we don't want them interrupting us. + cancelable_next_event_.Cancel(); + + // ManifestDemuxer::Engine::Seek returns true if it cleared data from + // ChunkDemuxer and needs a new call to `OnTimeUpdate`. If this is the + // case, ChunkDemuxer won't finish it's seek process until new data is + // appended as a result of the player event. However it's possible for that + // data to come in chunks, so ChunkDemuxer might think it's ready to finish + // it's seek when only some of the data has come in. As a result, we have to + // wait for both `OnChunkDemuxerSeeked` AND `OnEngineSeekComplete` to finish. + // Each of them will check |seek_waiting_on_engine_|, the first will clear the + // flag, and the second will notice the cleared flag and finish the seek + // process. + seek_waiting_on_engine_ = impl_->Seek(media_time_); + + chunk_demuxer_->Seek(media_time_, + base::BindOnce(&ManifestDemuxer::OnChunkDemuxerSeeked, + weak_factory_.GetWeakPtr())); + + if (seek_waiting_on_engine_) { + TriggerEventWithTime(base::BindOnce(&ManifestDemuxer::OnEngineSeekComplete, + weak_factory_.GetWeakPtr()), + media_time_); + } } bool ManifestDemuxer::IsSeekable() const { DCHECK(media_task_runner_->RunsTasksInCurrentSequence()); // The underlying wrapping ChunkDemuxer is seekable. - return true; + return impl_->IsSeekable(); } void ManifestDemuxer::Stop() { DCHECK(media_task_runner_->RunsTasksInCurrentSequence()); + impl_->Stop(); chunk_demuxer_->Stop(); + impl_.reset(); chunk_demuxer_.reset(); + cancelable_next_event_.Cancel(); } base::TimeDelta ManifestDemuxer::GetStartTime() const { DCHECK(media_task_runner_->RunsTasksInCurrentSequence()); - // TODO(crbug/1266991): Is any time remapping of HLS start time necessary - // here? + // TODO(crbug/1266991): Support time remapping for streams that start > 0. return base::TimeDelta(); } @@ -181,15 +238,16 @@ // And should wrapped ChunkDemuxer's enforcement that any specified (non-null) // offset across multiple ChunkDemuxer::OnSourceInitDone() match be relaxed if // its wrapped by an HLS demuxer which might ignore those offsets? - return base::Time(); + return chunk_demuxer_->GetTimelineOffset(); } int64_t ManifestDemuxer::GetMemoryUsage() const { DCHECK(media_task_runner_->RunsTasksInCurrentSequence()); // TODO(crbug/1266991): Consider other potential significant memory usage - // here, if the data sources, playlist parser(s), rendition metadata or - // timeline managers are significant memory consumers. - return chunk_demuxer_->GetMemoryUsage(); + // here of the player impl. + int64_t demuxer_usage = chunk_demuxer_ ? chunk_demuxer_->GetMemoryUsage() : 0; + int64_t impl_usage = impl_ ? impl_->GetMemoryUsage() : 0; + return demuxer_usage + impl_usage; } absl::optional<container_names::MediaContainerName> @@ -218,22 +276,182 @@ std::move(change_completed_cb)); } -void ManifestDemuxer::OnChunkDemuxerInitialized(PipelineStatus init_status) { +void ManifestDemuxer::SetPlaybackRate(double rate) { DCHECK(media_task_runner_->RunsTasksInCurrentSequence()); - DCHECK(pending_init_); - std::move(pending_init_).Run(std::move(init_status)); + bool rate_increase = rate > current_playback_rate_; + current_playback_rate_ = rate; + if (!rate_increase || pending_seek_ || has_pending_event_) { + return; + } + + // If the playback rate increased and there isn't already something pending, + // cancel the next event and set a new one. + cancelable_next_event_.Cancel(); + TriggerEvent(); +} + +void ManifestDemuxer::OnError(PipelineStatus error) { + DCHECK(media_task_runner_->RunsTasksInCurrentSequence()); + cancelable_next_event_.Cancel(); + + if (pending_init_) { + std::move(pending_init_).Run(std::move(error).AddHere()); + return; + } + + if (pending_seek_) { + std::move(pending_seek_).Run(std::move(error).AddHere()); + return; + } + + host_->OnDemuxerError(std::move(error).AddHere()); + Stop(); +} + +ChunkDemuxer* ManifestDemuxer::GetChunkDemuxerForTesting() { + DCHECK(media_task_runner_->RunsTasksInCurrentSequence()); + return chunk_demuxer_.get(); } void ManifestDemuxer::OnChunkDemuxerOpened() { DCHECK(media_task_runner_->RunsTasksInCurrentSequence()); - // TODO(crbug/1266991): Implement. - NOTIMPLEMENTED(); + demuxer_opened_ = true; + MaybeCompleteInitialize(); } -void ManifestDemuxer::OnProgress() { +void ManifestDemuxer::OnProgress() {} + +void ManifestDemuxer::OnEngineInitialized(PipelineStatus status) { DCHECK(media_task_runner_->RunsTasksInCurrentSequence()); - // TODO(crbug/1266991): Implement. - NOTIMPLEMENTED(); + if (!status.is_ok()) { + OnError(std::move(status).AddHere()); + return; + } + engine_impl_ready_ = true; + MaybeCompleteInitialize(); +} + +void ManifestDemuxer::MaybeCompleteInitialize() { + DCHECK(media_task_runner_->RunsTasksInCurrentSequence()); + if (!demuxer_opened_ || !engine_impl_ready_) { + return; + } + + TriggerEvent(); +} + +void ManifestDemuxer::TriggerEvent() { + DCHECK(media_task_runner_->RunsTasksInCurrentSequence()); + auto queue_next_event = base::BindOnce( + &ManifestDemuxer::OnEngineEventFinished, weak_factory_.GetWeakPtr()); + TriggerEventWithTime(std::move(queue_next_event), media_time_); +} + +void ManifestDemuxer::TriggerEventWithTime(DelayCallback cb, + base::TimeDelta current_time) { + DCHECK(media_task_runner_->RunsTasksInCurrentSequence()); + has_pending_event_ = true; + impl_->OnTimeUpdate(current_time, current_playback_rate_, + base::BindPostTask(media_task_runner_, std::move(cb))); +} + +void ManifestDemuxer::OnEngineEventFinished(base::TimeDelta delay) { + DCHECK(media_task_runner_->RunsTasksInCurrentSequence()); + + // There should always be an outstanding player event when this method is + // called. Player events get set in the Trigger methods, which happen as part + // of the time-based player loop, and as part of the seek process. + CHECK(has_pending_event_); + has_pending_event_ = false; + + // If there is a pending seek, execute it now. Seeking always calls + // |OnEngineEventFinished| when it is finished. + if (pending_seek_) { + SeekInternal(); + return; + } + + if (delay != kNoTimestamp) { + // Schedule an event to take place again after a delay. + cancelable_next_event_.Reset(base::BindOnce(&ManifestDemuxer::TriggerEvent, + weak_factory_.GetWeakPtr())); + media_task_runner_->PostDelayedTask( + FROM_HERE, cancelable_next_event_.callback(), delay); + } +} + +void ManifestDemuxer::OnChunkDemuxerInitialized(PipelineStatus init_status) { + DCHECK(media_task_runner_->RunsTasksInCurrentSequence()); + + if (!pending_init_) { + OnError(std::move(init_status)); + return; + } + std::move(pending_init_).Run(std::move(init_status)); +} + +void ManifestDemuxer::OnChunkDemuxerSeeked(PipelineStatus seek_status) { + DCHECK(media_task_runner_->RunsTasksInCurrentSequence()); + + if (!pending_seek_) { + OnError(std::move(seek_status)); + return; + } + + if (!seek_status.is_ok()) { + // If the seek is an error, then don't bother waiting for the + // OnEngineSeekComplete call, just unset the flag and exit now. + seek_waiting_on_engine_ = false; + std::move(pending_seek_).Run(std::move(seek_status)); + return; + } + + if (seek_waiting_on_engine_) { + // If this flag was set, then there is a simultaneous wait for both + // OnChunkDemuxerSeeked and OnEngineSeekComplete, and we were called first. + // We should set the flag back to false, so that OnEngineSeekComplete can + // finish the seeking process. + seek_waiting_on_engine_ = false; + return; + } + + // Complete the seek with an ok-status. This function already handles non-ok + // status results above. + CompletePendingSeek(); +} + +void ManifestDemuxer::OnEngineSeekComplete(base::TimeDelta delay_time) { + DCHECK(media_task_runner_->RunsTasksInCurrentSequence()); + + if (!pending_seek_) { + // OnChunkDemuxerSeeked returned earlier with an error, so we don't have + // anything to do. Make sure that the seek waiting flag was cleaned up. + CHECK_EQ(seek_waiting_on_engine_, false); + return; + } + + if (seek_waiting_on_engine_) { + // If the flag is still set, we were called before OnChunkDemuxerSeeked. + // Set the flag back to false, so that when OnChunkDemuxerSeeked is called, + // it will finish up and execute the pending_seek_ callback. + seek_waiting_on_engine_ = false; + return; + } + + // Complete the seek with an ok-status. If the chunk demuxer had failed to + // seek, it would have already posted the `pending_seek_` call with its + // failure status. + CompletePendingSeek(); +} + +void ManifestDemuxer::CompletePendingSeek() { + DCHECK(media_task_runner_->RunsTasksInCurrentSequence()); + + CHECK(pending_seek_); + std::move(pending_seek_).Run(OkStatus()); + + // Schedule a new event ASAP to populate data. + OnEngineEventFinished(base::Seconds(0)); } void ManifestDemuxer::OnEncryptedMediaData(EmeInitDataType type,
diff --git a/media/filters/manifest_demuxer.h b/media/filters/manifest_demuxer.h index bf98d02..a5c1055 100644 --- a/media/filters/manifest_demuxer.h +++ b/media/filters/manifest_demuxer.h
@@ -7,6 +7,7 @@ #include <vector> +#include "base/cancelable_callback.h" #include "base/containers/flat_map.h" #include "base/memory/scoped_refptr.h" #include "base/task/sequenced_task_runner.h" @@ -28,23 +29,78 @@ // Declared and defined in manifest_demuxer.cc. class ManifestDemuxerStream; -class MEDIA_EXPORT ManifestDemuxer final : public Demuxer { +// This class provides an interface for ManifestDemuxer::Engine to talk to +// ManifestDemuxer about the internal ChunkDemuxer, without allowing it to call +// any of the methods that the pipeline uses, like Seek or Stop. +class MEDIA_EXPORT ManifestDemuxerEngineHost { public: - explicit ManifestDemuxer( - scoped_refptr<base::SequencedTaskRunner> task_runner, - base::SequenceBound<HlsDataSourceProvider> data_source_provider, - GURL root_playlist_uri, - MediaLog* media_log); - ~ManifestDemuxer() override; - ManifestDemuxer(const ManifestDemuxer&) = delete; - ManifestDemuxer(ManifestDemuxer&&) = delete; - ManifestDemuxer& operator=(const ManifestDemuxer&) = delete; - ManifestDemuxer& operator=(ManifestDemuxer&&) = delete; + virtual ~ManifestDemuxerEngineHost() {} - // `media::MediaResource` implementation - std::vector<DemuxerStream*> GetAllStreams() override; + // Handle errors. + virtual void OnError(PipelineStatus error); +}; + +// A Demuxer designed to allow implementation of media demuxers which don't +// rely on raw media data alone, such as HLS or DASH. This demuxer owns an +// implementation of an engine and handles the seeking and event dispatching +// for the engine so that it can focus on keeping internal manifest states up +// to date. +class MEDIA_EXPORT ManifestDemuxer : public Demuxer, ManifestDemuxerEngineHost { + public: + using DelayCallback = base::OnceCallback<void(base::TimeDelta)>; + + class Engine { + public: + virtual ~Engine() {} + + // Set for the engine, such as fetching manifests or content. + virtual void Initialize(ManifestDemuxerEngineHost* demuxer, + PipelineStatusCallback status_cb) = 0; + + // Get the name of the engine impl. + virtual std::string GetName() const = 0; + + // A tick signal indicating that the state of the engine should be + // checked. `time` is the current player time. `playback_rate` is the + // current playback rate. `loaded_ranges` is the current set of loaded + // ranges in the chunk demuxer. `cb` should be called with the amount of + // time to delay until the next event is requested. + virtual void OnTimeUpdate(base::TimeDelta time, + double playback_rate, + DelayCallback cb) = 0; + + // A synchronous seek, mostly intended to reset parts of the chunk + // demuxer. returns whether the chunk demuxer needs more data. + virtual bool Seek(base::TimeDelta time) = 0; + + // Start waiting for seek, usually means canceling outstanding events + // and network fetches. + virtual void StartWaitingForSeek() = 0; + + // Abort any pending reads, parses, or network requests. + virtual void AbortPendingReads() = 0; + + // Returns whether this engine supports seeking. Some live stream content + // can't be seeked. + virtual bool IsSeekable() = 0; + + // Gets the memory usage of the engine. + virtual int64_t GetMemoryUsage() const = 0; + + // Stop demuxing and clean up pending CBs. + virtual void Stop() = 0; + }; + + // ManifestDemuxer takes and keeps ownership of `impl` for the lifetime of + // both. + ManifestDemuxer(scoped_refptr<base::SequencedTaskRunner> media_task_runner, + std::unique_ptr<Engine> impl, + MediaLog* media_log); + + ~ManifestDemuxer() override; // `media::Demuxer` implementation + std::vector<DemuxerStream*> GetAllStreams() override; std::string GetDisplayName() const override; DemuxerType GetDemuxerType() const override; void Initialize(DemuxerHost* host, PipelineStatusCallback status_cb) override; @@ -57,19 +113,28 @@ base::TimeDelta GetStartTime() const override; base::Time GetTimelineOffset() const override; int64_t GetMemoryUsage() const override; - void SetPlaybackRate(double rate) override {} - + void SetPlaybackRate(double rate) override; absl::optional<container_names::MediaContainerName> GetContainerForMetrics() const override; void OnEnabledAudioTracksChanged(const std::vector<MediaTrack::Id>& track_ids, base::TimeDelta curr_time, TrackChangeCB change_completed_cb) override; - void OnSelectedVideoTrackChanged(const std::vector<MediaTrack::Id>& track_ids, base::TimeDelta curr_time, TrackChangeCB change_completed_cb) override; + // `ManifestDemuxerEngineHost` implementation + void OnError(PipelineStatus status) override; + + // Allow unit tests to grab the chunk demuxer. + ChunkDemuxer* GetChunkDemuxerForTesting(); + bool has_pending_seek_for_testing() const { return !pending_seek_.is_null(); } + bool has_pending_event_for_testing() const { return has_pending_event_; } + bool has_next_task_for_testing() const { + return !cancelable_next_event_.IsCancelled(); + } + private: // This wrapper class allows us to capture the results of Read() and use // DecoderBuffer timestamps to update the current media time within the @@ -92,7 +157,7 @@ private: WrapperReadCb read_cb_; - DemuxerStream* stream_; + base::raw_ptr<DemuxerStream> stream_; }; void OnChunkDemuxerInitialized(PipelineStatus init_status); @@ -104,19 +169,45 @@ DemuxerStream::Status status, DemuxerStream::DecoderBufferVector buffers); + // Helper for the `Seek` call, so that returning from an event when a seek + // is pending can continue the seek process. + void SeekInternal(); + void OnChunkDemuxerSeeked(PipelineStatus seek_status); + void OnEngineSeekComplete(base::TimeDelta delay_time); + void CompletePendingSeek(); + + // Allows for both the chunk demuxer and the engine to be required for + // initialization. + void OnEngineInitialized(PipelineStatus status); + void MaybeCompleteInitialize(); + + // Trigger the next event, and based on it's expected delay, post a + // cancellable callback to TriggerEvent again. + void TriggerEvent(); + void TriggerEventWithTime(DelayCallback cb, base::TimeDelta current_time); + void OnEngineEventFinished(base::TimeDelta delay_time); + std::unique_ptr<MediaLog> media_log_; scoped_refptr<base::SequencedTaskRunner> media_task_runner_; // Pending callbacks. + PipelineStatusCallback pending_seek_; PipelineStatusCallback pending_init_; + // Engine implementation + std::unique_ptr<Engine> impl_; + // Wrapped chunk demuxer that actually does the parsing and demuxing of the // raw data we feed it. std::unique_ptr<ChunkDemuxer> chunk_demuxer_; + base::raw_ptr<DemuxerHost> host_; // Updated by seek, and by updates from outgoing frames. base::TimeDelta media_time_ = base::Seconds(0); + // Playback rate helps calculate how often we should check for new data. + double current_playback_rate_ = 0.0; + // Keeps a map of demuxer streams to their wrapper implementations which // can be used to set the current media time. ChunkDemuxer's streams live // forever due to the use of raw pointers in the pipeline, so these must @@ -124,6 +215,21 @@ base::flat_map<DemuxerStream*, std::unique_ptr<ManifestDemuxerStream>> streams_; + // Flags for the two part asynchronous initialization process. + bool demuxer_opened_ = false; + bool engine_impl_ready_ = false; + + // Flag for the two-cb wait for finishing a seek. + bool seek_waiting_on_engine_ = false; + + // Pending an event. Don't trigger a new event chain while one is in + // progress. + bool has_pending_event_ = false; + + // A pending "next event" callback, which can be canceled in the case of a + // seek or a playback rate change. + base::CancelableOnceClosure cancelable_next_event_; + base::WeakPtrFactory<ManifestDemuxer> weak_factory_{this}; };
diff --git a/media/filters/manifest_demuxer_unittest.cc b/media/filters/manifest_demuxer_unittest.cc new file mode 100644 index 0000000..91ddb46 --- /dev/null +++ b/media/filters/manifest_demuxer_unittest.cc
@@ -0,0 +1,238 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <stdint.h> + +#include "base/test/gmock_callback_support.h" +#include "base/test/task_environment.h" +#include "base/threading/thread.h" +#include "media/base/media_track.h" +#include "media/base/media_util.h" +#include "media/base/mock_demuxer_host.h" +#include "media/base/mock_media_log.h" +#include "media/base/test_data_util.h" +#include "media/filters/manifest_demuxer.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace media { +using ::base::test::RunOnceCallback; +using ::testing::_; +using ::testing::NiceMock; +using ::testing::Return; +using ::testing::SaveArg; + +// Define a mock implementation of ManifestDemuxer::Engine for testing. +class MockEngine : public ManifestDemuxer::Engine { + public: + MOCK_METHOD(void, + Initialize, + (ManifestDemuxerEngineHost * demuxer, + PipelineStatusCallback status_cb), + (override)); + MOCK_METHOD(std::string, GetName, (), (const, override)); + MOCK_METHOD(void, + OnTimeUpdate, + (base::TimeDelta time, + double playback_rate, + ManifestDemuxer::DelayCallback cb), + (override)); + MOCK_METHOD(bool, Seek, (base::TimeDelta time), (override)); + MOCK_METHOD(void, StartWaitingForSeek, (), (override)); + MOCK_METHOD(void, AbortPendingReads, (), (override)); + MOCK_METHOD(bool, IsSeekable, (), (override)); + MOCK_METHOD(int64_t, GetMemoryUsage, (), (const, override)); + MOCK_METHOD(void, Stop, (), (override)); +}; + +// Fixture for ManifestDemuxer tests. +class ManifestDemuxerTest : public ::testing::Test { + public: + ManifestDemuxerTest() + : media_log_(std::make_unique<NiceMock<media::MockMediaLog>>()), + mock_host_(std::make_unique<NiceMock<MockDemuxerHost>>()) { + auto mock_engine = std::make_unique<MockEngine>(); + mock_engine_ = mock_engine.get(); + manifest_demuxer_ = std::make_unique<ManifestDemuxer>( + task_environment_.GetMainThreadTaskRunner(), std::move(mock_engine), + media_log_.get()); + } + + ~ManifestDemuxerTest() override { + manifest_demuxer_->GetChunkDemuxerForTesting()->MarkEndOfStream( + PIPELINE_OK); + manifest_demuxer_.reset(); + base::RunLoop().RunUntilIdle(); + } + + MOCK_METHOD(void, MockInitComplete, (PipelineStatus status), ()); + MOCK_METHOD(void, MockSeekComplete, (PipelineStatus status), ()); + + void CreateIdAndAppendInitSegment(const std::string& id) { + auto* demuxer = manifest_demuxer_->GetChunkDemuxerForTesting(); + DCHECK_EQ(demuxer->AddId(id, "video/webm", "vorbis,vp8"), + ChunkDemuxer::Status::kOk); + + demuxer->SetTracksWatcher( + id, base::BindRepeating([](std::unique_ptr<MediaTracks>) {})); + demuxer->SetParseWarningCallback( + id, base::BindRepeating([](SourceBufferParseWarning) {})); + + scoped_refptr<DecoderBuffer> bear1 = ReadTestDataFile("bear-320x240.webm"); + DCHECK(demuxer->AppendToParseBuffer(id, bear1->data(), bear1->data_size())); + for (;;) { + base::TimeDelta start = base::Seconds(0), end = base::Seconds(10), offset; + auto result = demuxer->RunSegmentParserLoop(id, start, end, &offset); + if (result != StreamParser::ParseStatus::kSuccessHasMoreData) { + DCHECK_EQ(result, StreamParser::ParseStatus::kSuccess); + return; + } + } + } + + void InitializeDemuxer() { + // Chunk demuxer won't finish initialization until content starts being + // added, and we don't have any mock content at this point. + EXPECT_CALL(*this, MockInitComplete(_)).Times(1); + + // Mark the engine as initialized successfully. + EXPECT_CALL(*mock_engine_, Initialize(_, _)) + .WillOnce(RunOnceCallback<1>(media::PIPELINE_OK)); + + manifest_demuxer_->Initialize( + mock_host_.get(), base::BindOnce(&ManifestDemuxerTest::MockInitComplete, + base::Unretained(this))); + CreateIdAndAppendInitSegment("test"); + } + + protected: + base::test::TaskEnvironment task_environment_; + std::unique_ptr<MediaLog> media_log_; + std::unique_ptr<MockDemuxerHost> mock_host_; + base::raw_ptr<MockEngine> mock_engine_; + std::unique_ptr<ManifestDemuxer> manifest_demuxer_; +}; + +TEST_F(ManifestDemuxerTest, InitializeStartsTimeUpdate) { + // When the engine is initialized and the chunk demuxer is opened + // (not initialized), the |OnTimeUpdate| events start coming in. + // posting `kNoTimestamp` back to this callback signals that we won't delay + // and get another event. + EXPECT_CALL(*mock_engine_, OnTimeUpdate(_, _, _)) + .WillOnce(RunOnceCallback<2>(kNoTimestamp)); + InitializeDemuxer(); + + task_environment_.RunUntilIdle(); + ASSERT_FALSE(manifest_demuxer_->has_next_task_for_testing()); +} + +TEST_F(ManifestDemuxerTest, PlaybackRateChangeUpTriggersTimeUpdate) { + ManifestDemuxer::DelayCallback delay_cb; + EXPECT_CALL(*mock_engine_, OnTimeUpdate(_, _, _)) + .WillRepeatedly([&delay_cb](base::TimeDelta, double, + ManifestDemuxer::DelayCallback cb) { + delay_cb = std::move(cb); + }); + + // Initializing the demuxer will cause a time update event at time = 0. + InitializeDemuxer(); + ASSERT_TRUE(!!delay_cb); + + // Setting the playback rate up while there is a pending event should do + // nothing. + EXPECT_CALL(*mock_engine_, OnTimeUpdate(_, _, _)).Times(0); + manifest_demuxer_->SetPlaybackRate(0.2); + + // Respond to the loop, but request no new events. + std::move(delay_cb).Run(kNoTimestamp); + task_environment_.RunUntilIdle(); + + // Setting the playback rate up again while there is not pending event + // should trigger a new event. + EXPECT_CALL(*mock_engine_, OnTimeUpdate(_, _, _)) + .WillRepeatedly([&delay_cb](base::TimeDelta, double, + ManifestDemuxer::DelayCallback cb) { + delay_cb = std::move(cb); + }); + manifest_demuxer_->SetPlaybackRate(0.4); + task_environment_.RunUntilIdle(); + ASSERT_TRUE(!!delay_cb); + + // Respond to the loop, but request no new events. + std::move(delay_cb).Run(kNoTimestamp); + task_environment_.RunUntilIdle(); + + // Setting the playback rate down should not trigger a new event, even + // while there is no event pending. + EXPECT_CALL(*mock_engine_, OnTimeUpdate(_, _, _)).Times(0); + manifest_demuxer_->SetPlaybackRate(0.2); + + task_environment_.RunUntilIdle(); + ASSERT_FALSE(manifest_demuxer_->has_next_task_for_testing()); +} + +TEST_F(ManifestDemuxerTest, OnTimeUpdateUninterruptedBySeek) { + ManifestDemuxer::DelayCallback delay_cb; + EXPECT_CALL(*mock_engine_, OnTimeUpdate(_, _, _)) + .WillRepeatedly([&delay_cb](base::TimeDelta, double, + ManifestDemuxer::DelayCallback cb) { + delay_cb = std::move(cb); + }); + InitializeDemuxer(); + ASSERT_TRUE(!!delay_cb); + + // a pending event is set, which won't be cleared until `delay_cb` is + // executed. + ASSERT_FALSE(manifest_demuxer_->has_pending_seek_for_testing()); + ASSERT_TRUE(manifest_demuxer_->has_pending_event_for_testing()); + + // Seek won't be called until we post delay_cb. + EXPECT_CALL(*mock_engine_, Seek(_)).Times(0); + EXPECT_CALL(*mock_engine_, StartWaitingForSeek()).Times(1); + EXPECT_CALL(*this, MockSeekComplete(_)).Times(0); + manifest_demuxer_->StartWaitingForSeek(base::Seconds(1)); + manifest_demuxer_->Seek(base::Seconds(1), + base::BindOnce(&ManifestDemuxerTest::MockSeekComplete, + base::Unretained(this))); + + // we not have a pending seek and a pending event. + ASSERT_TRUE(manifest_demuxer_->has_pending_seek_for_testing()); + ASSERT_TRUE(manifest_demuxer_->has_pending_event_for_testing()); + + // Return from the pending event. The pending seek will start, which will + // kick off an async call to the chunk demuxer. We can make the engine + // also request a new event to be called, which means that delay_cb will be + // set again. + EXPECT_CALL(*mock_engine_, Seek(_)).WillOnce(Return(true)); + std::move(delay_cb).Run(base::Seconds(10)); + task_environment_.RunUntilIdle(); + + // There is still a pending seek, and we now have a new event. + ASSERT_TRUE(!!delay_cb); + ASSERT_TRUE(manifest_demuxer_->has_pending_seek_for_testing()); + ASSERT_TRUE(manifest_demuxer_->has_pending_event_for_testing()); + + // Executing this delay CB will trigger the seek to finish, since chunk + // demuxer has already finished it's seek. After the seek is finished, it + // will kick off another event, making the pending event check true and + // causing a new `delay_cb` to be set. + EXPECT_CALL(*this, MockSeekComplete(_)).Times(1); + std::move(delay_cb).Run(base::Seconds(10)); + task_environment_.RunUntilIdle(); + ASSERT_FALSE(manifest_demuxer_->has_pending_seek_for_testing()); + ASSERT_TRUE(manifest_demuxer_->has_pending_event_for_testing()); + + // Running this event with no timestamp will cause the event loop to no longer + // run. Only kicking off a seek or playback rate change will re-trigger it. + ASSERT_TRUE(!!delay_cb); + std::move(delay_cb).Run(kNoTimestamp); + task_environment_.RunUntilIdle(); + ASSERT_FALSE(manifest_demuxer_->has_pending_seek_for_testing()); + ASSERT_FALSE(manifest_demuxer_->has_pending_event_for_testing()); + + task_environment_.RunUntilIdle(); + ASSERT_FALSE(manifest_demuxer_->has_next_task_for_testing()); +} + +} // namespace media
diff --git a/media/gpu/mac/vt_video_decode_accelerator_mac.cc b/media/gpu/mac/vt_video_decode_accelerator_mac.cc index 2db565c..d79a289 100644 --- a/media/gpu/mac/vt_video_decode_accelerator_mac.cc +++ b/media/gpu/mac/vt_video_decode_accelerator_mac.cc
@@ -69,6 +69,11 @@ namespace { +// Controls whether InitializeVideoToolboxInternal() does preload or not. +BASE_FEATURE(kSkipVideoToolboxPreload, + "SkipVideoToolboxPreload", + base::FEATURE_DISABLED_BY_DEFAULT); + // Parameter sets vector contain all PPSs/SPSs(/VPSs) using ParameterSets = std::vector<base::span<const uint8_t>>; @@ -350,6 +355,15 @@ // session fails, hardware decoding will be disabled (Initialize() will always // return false). bool InitializeVideoToolboxInternal() { + if (base::FeatureList::IsEnabled(kSkipVideoToolboxPreload)) { + // When skipping preload we still need to register vp9, otherwise it won't + // work at all. + if (__builtin_available(macOS 11.0, *)) { + VTRegisterSupplementalVideoDecoderIfAvailable(kCMVideoCodecType_VP9); + } + return true; + } + VTDecompressionOutputCallbackRecord callback = {0}; base::ScopedCFTypeRef<VTDecompressionSessionRef> session; gfx::Size configured_size;
diff --git a/media/gpu/v4l2/test/v4l2_stateless_decoder.cc b/media/gpu/v4l2/test/v4l2_stateless_decoder.cc index 5a1e03b..1b6ff040 100644 --- a/media/gpu/v4l2/test/v4l2_stateless_decoder.cc +++ b/media/gpu/v4l2/test/v4l2_stateless_decoder.cc
@@ -184,7 +184,12 @@ return EXIT_FAILURE; } - dec->Initialize(); + // TODO(b/277338563): Decoders are going to be using a lazy initilization + // that occurs during decode time. Once all the decoders support that, + // the call to |Initialize| will be removed from here. + if (dec->needs_init) { + dec->Initialize(); + } for (int i = 0; i < n_frames || n_frames == 0; i++) { LOG(INFO) << "Frame " << i << "...";
diff --git a/media/gpu/v4l2/test/video_decoder.cc b/media/gpu/v4l2/test/video_decoder.cc index 936fbfd..f64ee50 100644 --- a/media/gpu/v4l2/test/video_decoder.cc +++ b/media/gpu/v4l2/test/video_decoder.cc
@@ -39,10 +39,17 @@ VideoDecoder::VideoDecoder(std::unique_ptr<V4L2IoctlShim> v4l2_ioctl, std::unique_ptr<V4L2Queue> OUTPUT_queue, std::unique_ptr<V4L2Queue> CAPTURE_queue) - : v4l2_ioctl_(std::move(v4l2_ioctl)), + : needs_init(true), + v4l2_ioctl_(std::move(v4l2_ioctl)), OUTPUT_queue_(std::move(OUTPUT_queue)), CAPTURE_queue_(std::move(CAPTURE_queue)) {} +VideoDecoder::VideoDecoder(std::unique_ptr<V4L2IoctlShim> v4l2_ioctl, + gfx::Size display_resolution) + : needs_init(false), + v4l2_ioctl_(std::move(v4l2_ioctl)), + display_resolution_(display_resolution) {} + VideoDecoder::~VideoDecoder() = default; void VideoDecoder::NegotiateCAPTUREFormat() { @@ -104,7 +111,7 @@ << fmt.fmt.pix_mp.num_planes; } -void VideoDecoder::Initialize() { +void VideoDecoder::Initialize(bool resolution_changed) { // TODO(stevecho): remove VIDIOC_ENUM_FRAMESIZES ioctl call // after b/193237015 is resolved. if (!v4l2_ioctl_->EnumFrameSizes(OUTPUT_queue_->fourcc())) @@ -120,7 +127,7 @@ // If there is a dynamic resolution change, the Initialization sequence will // be performed again, minus the allocation of OUTPUT queue buffers. - if (IsResolutionChanged()) { + if (resolution_changed) { v4l2_ioctl_->ReqBufsWithCount(CAPTURE_queue_, number_of_buffers_in_capture_queue_); } else { @@ -144,9 +151,61 @@ v4l2_ioctl_->StreamOn(CAPTURE_queue_->type()); } +void VideoDecoder::CreateOUTPUTQueue(uint32_t compressed_fourcc) { + // TODO(stevecho): might need to consider using more than 1 file descriptor + // (fd) & buffer with the output queue for 4K60 requirement. + // https://buganizer.corp.google.com/issues/202214561#comment31 + OUTPUT_queue_ = std::make_unique<V4L2Queue>( + V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, display_resolution_, V4L2_MEMORY_MMAP, + kNumberOfBuffersInOutputQueue); + OUTPUT_queue_->set_fourcc(compressed_fourcc); + + // TODO(stevecho): remove VIDIOC_ENUM_FRAMESIZES ioctl call + // after b/193237015 is resolved. + if (!v4l2_ioctl_->EnumFrameSizes(OUTPUT_queue_->fourcc())) { + LOG(INFO) << "EnumFrameSizes for OUTPUT queue failed."; + } + + v4l2_ioctl_->SetFmt(OUTPUT_queue_); + v4l2_ioctl_->ReqBufs(OUTPUT_queue_); + v4l2_ioctl_->QueryAndMmapQueueBuffers(OUTPUT_queue_); + + int media_request_fd; + v4l2_ioctl_->MediaIocRequestAlloc(&media_request_fd); + + OUTPUT_queue_->set_media_request_fd(media_request_fd); + + v4l2_ioctl_->StreamOn(OUTPUT_queue_->type()); +} + +void VideoDecoder::CreateCAPTUREQueue(uint32_t num_buffers) { + // TODO(stevecho): enable V4L2_MEMORY_DMABUF memory for CAPTURE queue. + // |num_planes| represents separate memory buffers, not planes for Y, U, V. + // https://www.kernel.org/doc/html/v5.10/userspace-api/media/v4l/pixfmt-v4l2-mplane.html#c.V4L.v4l2_plane_pix_format + CAPTURE_queue_ = std::make_unique<V4L2Queue>( + V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, gfx::Size(0, 0), V4L2_MEMORY_MMAP, + num_buffers); + + NegotiateCAPTUREFormat(); + + LOG_ASSERT(gfx::Rect(CAPTURE_queue_->resolution()) + .Contains(gfx::Rect(OUTPUT_queue_->resolution()))) + << "Display size is not contained within the coded size. DRC?"; + + v4l2_ioctl_->ReqBufs(CAPTURE_queue_); + v4l2_ioctl_->QueryAndMmapQueueBuffers(CAPTURE_queue_); + // Only 1 CAPTURE buffer is needed for 1st key frame decoding. Remaining + // CAPTURE buffers will be queued after that. + if (!v4l2_ioctl_->QBuf(CAPTURE_queue_, 0)) { + LOG(FATAL) << "VIDIOC_QBUF failed for CAPTURE queue."; + } + + v4l2_ioctl_->StreamOn(CAPTURE_queue_->type()); +} + // Follows the dynamic resolution change sequence described in // https://www.kernel.org/doc/html/latest/userspace-api/media/v4l/dev-stateless-decoder.html#dynamic-resolution-change -VideoDecoder::Result VideoDecoder::HandleDynamicResolutionChange( +void VideoDecoder::HandleDynamicResolutionChange( const gfx::Size& new_resolution) { // Call VIDIOC_STREAMOFF() on both the OUTPUT and CAPTURE queues. v4l2_ioctl_->StreamOff(OUTPUT_queue_->type()); @@ -164,10 +223,7 @@ OUTPUT_queue_->set_resolution(new_resolution); // Perform the initialization sequence again - Initialize(); - is_resolution_changed_ = false; - - return VideoDecoder::kOk; + Initialize(/* resolution_changed*/ true); } void VideoDecoder::ConvertToYUV(std::vector<uint8_t>& dest_y,
diff --git a/media/gpu/v4l2/test/video_decoder.h b/media/gpu/v4l2/test/video_decoder.h index 734d2d86..0ea44e2 100644 --- a/media/gpu/v4l2/test/video_decoder.h +++ b/media/gpu/v4l2/test/video_decoder.h
@@ -36,6 +36,9 @@ std::unique_ptr<V4L2Queue> OUTPUT_queue, std::unique_ptr<V4L2Queue> CAPTURE_queue); + VideoDecoder(std::unique_ptr<V4L2IoctlShim> v4l2_ioctl, + gfx::Size display_resolution); + virtual ~VideoDecoder(); VideoDecoder(const VideoDecoder&) = delete; @@ -43,7 +46,10 @@ // Initializes setup needed for decoding. // https://www.kernel.org/doc/html/v5.10/userspace-api/media/v4l/dev-stateless-decoder.html#initialization - void Initialize(); + void Initialize(bool is_resolution_changed = false); + + void CreateOUTPUTQueue(uint32_t compressed_fourcc); + void CreateCAPTUREQueue(uint32_t num_buffers); virtual Result DecodeNextFrame(std::vector<uint8_t>& y_plane, std::vector<uint8_t>& u_plane, @@ -53,21 +59,21 @@ // Handles dynamic resolution change with new resolution parsed from frame // header. - VideoDecoder::Result HandleDynamicResolutionChange( - const gfx::Size& new_resolution); + void HandleDynamicResolutionChange(const gfx::Size& new_resolution); // Returns whether the last decoded frame was visible. bool LastDecodedFrameVisible() const { return last_decoded_frame_visible_; } - // Returns whether there is a dynamic resolution change. - bool IsResolutionChanged() const { return is_resolution_changed_; } - // Converts raw YUV of decoded frame data to PNG. static std::vector<uint8_t> ConvertYUVToPNG(uint8_t* y_plane, uint8_t* u_plane, uint8_t* v_plane, const gfx::Size& size); + // Temporary variable to specify that the older, + // non split initialization should be use. + const bool needs_init; + protected: void NegotiateCAPTUREFormat(); @@ -92,11 +98,11 @@ // Whether the last decoded frame was visible. bool last_decoded_frame_visible_ = false; - // Whether there is a dynamic support change. - bool is_resolution_changed_ = false; - // Number of buffers in CAPTURE queue varied by different codecs. uint32_t number_of_buffers_in_capture_queue_; + + // resolution from the bitstream header + gfx::Size display_resolution_; }; } // namespace v4l2_test
diff --git a/media/gpu/v4l2/test/vp8_decoder.cc b/media/gpu/v4l2/test/vp8_decoder.cc index e0d557e..83bb4e8 100644 --- a/media/gpu/v4l2/test/vp8_decoder.cc +++ b/media/gpu/v4l2/test/vp8_decoder.cc
@@ -551,21 +551,18 @@ break; } - if (frame_hdr.IsKeyframe()) { - is_resolution_changed_ = - frame_hdr.width != OUTPUT_queue_->resolution().width() || - frame_hdr.height != OUTPUT_queue_->resolution().height(); - } else { - frame_hdr.width = OUTPUT_queue_->resolution().width(); - frame_hdr.height = OUTPUT_queue_->resolution().height(); - } - - if (IsResolutionChanged()) { + const bool resolution_changed = + frame_hdr.width != OUTPUT_queue_->resolution().width() || + frame_hdr.height != OUTPUT_queue_->resolution().height(); + if (frame_hdr.IsKeyframe() && resolution_changed) { const gfx::Size new_resolution(frame_hdr.width, frame_hdr.height); LOG_ASSERT(!new_resolution.IsEmpty()) << "New key frame resolution is empty."; HandleDynamicResolutionChange(new_resolution); + } else { + frame_hdr.width = OUTPUT_queue_->resolution().width(); + frame_hdr.height = OUTPUT_queue_->resolution().height(); } VLOG_IF(2, !frame_hdr.show_frame) << "Not displaying frame";
diff --git a/media/gpu/v4l2/test/vp9_decoder.cc b/media/gpu/v4l2/test/vp9_decoder.cc index 97618b9f..0f1c97fe 100644 --- a/media/gpu/v4l2/test/vp9_decoder.cc +++ b/media/gpu/v4l2/test/vp9_decoder.cc
@@ -25,6 +25,7 @@ namespace media { namespace v4l2_test { +constexpr uint32_t kDriverCodecFourcc = V4L2_PIX_FMT_VP9_FRAME; constexpr uint32_t kNumberOfBuffersInCaptureQueue = 10; @@ -137,11 +138,8 @@ Vp9Decoder::Vp9Decoder(std::unique_ptr<IvfParser> ivf_parser, std::unique_ptr<V4L2IoctlShim> v4l2_ioctl, - std::unique_ptr<V4L2Queue> OUTPUT_queue, - std::unique_ptr<V4L2Queue> CAPTURE_queue) - : VideoDecoder::VideoDecoder(std::move(v4l2_ioctl), - std::move(OUTPUT_queue), - std::move(CAPTURE_queue)), + gfx::Size display_resolution) + : VideoDecoder::VideoDecoder(std::move(v4l2_ioctl), display_resolution), ivf_parser_(std::move(ivf_parser)), vp9_parser_( std::make_unique<Vp9Parser>(/*parsing_compressed_header=*/true)), @@ -165,8 +163,6 @@ // static std::unique_ptr<Vp9Decoder> Vp9Decoder::Create( const base::MemoryMappedFile& stream) { - constexpr uint32_t kDriverCodecFourcc = V4L2_PIX_FMT_VP9_FRAME; - VLOG(2) << "Attempting to create decoder with codec " << media::FourccToString(kDriverCodecFourcc); @@ -197,28 +193,12 @@ return nullptr; } - LOG(INFO) << "Ivf file header: " << file_header.width << " x " - << file_header.height; + gfx::Size display_resolution = + gfx::Size(file_header.width, file_header.height); + LOG(INFO) << "Ivf file header: " << display_resolution.ToString(); - // TODO(stevecho): might need to consider using more than 1 file descriptor - // (fd) & buffer with the output queue for 4K60 requirement. - // https://buganizer.corp.google.com/issues/202214561#comment31 - auto OUTPUT_queue = std::make_unique<V4L2Queue>( - V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, - gfx::Size(file_header.width, file_header.height), V4L2_MEMORY_MMAP, - kNumberOfBuffersInOutputQueue); - OUTPUT_queue->set_fourcc(kDriverCodecFourcc); - - // TODO(stevecho): enable V4L2_MEMORY_DMABUF memory for CAPTURE queue. - // https://www.kernel.org/doc/html/v5.10/userspace-api/media/v4l/pixfmt-v4l2-mplane.html#c.V4L.v4l2_plane_pix_format - auto CAPTURE_queue = std::make_unique<V4L2Queue>( - V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, - gfx::Size(file_header.width, file_header.height), V4L2_MEMORY_MMAP, - kNumberOfBuffersInCaptureQueue); - - return base::WrapUnique( - new Vp9Decoder(std::move(ivf_parser), std::move(v4l2_ioctl), - std::move(OUTPUT_queue), std::move(CAPTURE_queue))); + return base::WrapUnique(new Vp9Decoder( + std::move(ivf_parser), std::move(v4l2_ioctl), display_resolution)); } std::set<int> Vp9Decoder::RefreshReferenceSlots( @@ -467,6 +447,10 @@ break; } + if (!OUTPUT_queue_) { + CreateOUTPUTQueue(kDriverCodecFourcc); + } + VLOG_IF(2, !frame_hdr.show_frame) << "not displaying frame"; last_decoded_frame_visible_ = frame_hdr.show_frame; @@ -506,6 +490,10 @@ v4l2_ioctl_->MediaRequestIocQueue(OUTPUT_queue_); + if (!CAPTURE_queue_) { + CreateCAPTUREQueue(kNumberOfBuffersInCaptureQueue); + } + uint32_t buffer_id; v4l2_ioctl_->DQBuf(CAPTURE_queue_, &buffer_id);
diff --git a/media/gpu/v4l2/test/vp9_decoder.h b/media/gpu/v4l2/test/vp9_decoder.h index 1d6c2b9a..92b99d7 100644 --- a/media/gpu/v4l2/test/vp9_decoder.h +++ b/media/gpu/v4l2/test/vp9_decoder.h
@@ -49,8 +49,7 @@ private: Vp9Decoder(std::unique_ptr<IvfParser> ivf_parser, std::unique_ptr<V4L2IoctlShim> v4l2_ioctl, - std::unique_ptr<V4L2Queue> OUTPUT_queue, - std::unique_ptr<V4L2Queue> CAPTURE_queue); + gfx::Size display_resolution); // Reads next frame from IVF stream and its size into |vp9_frame_header| // and |size| respectively.
diff --git a/media/gpu/windows/media_foundation_video_encode_accelerator_win.cc b/media/gpu/windows/media_foundation_video_encode_accelerator_win.cc index 45fd08c..a162aba 100644 --- a/media/gpu/windows/media_foundation_video_encode_accelerator_win.cc +++ b/media/gpu/windows/media_foundation_video_encode_accelerator_win.cc
@@ -43,19 +43,20 @@ #include "third_party/libyuv/include/libyuv.h" #include "ui/gfx/color_space_win.h" #include "ui/gfx/gpu_memory_buffer.h" + #if BUILDFLAG(ENABLE_LIBAOM) #include "media/gpu/windows/av1_video_rate_control_wrapper.h" #include "third_party/libaom/source/libaom/av1/ratectrl_rtc.h" #endif -#define NOTIFY_RETURN_ON_FAILURE(cond, log, ret) \ - do { \ - if (cond) { \ - SetState(kError); \ - MEDIA_LOG(ERROR, media_log.get()) << log; \ - NotifyError(kPlatformFailureError); \ - return ret; \ - } \ +#define NOTIFY_RETURN_ON_FAILURE(cond, log, ret) \ + do { \ + if (cond) { \ + SetState(kError); \ + MEDIA_LOG(ERROR, media_log_) << log; \ + client_->NotifyError(kPlatformFailureError); \ + return ret; \ + } \ } while (0) #define NOTIFY_RETURN_ON_HR_FAILURE(hresult, log, ret) \ @@ -64,22 +65,21 @@ namespace media { namespace { -const uint32_t kDefaultGOPLength = 3000; -const uint32_t kDefaultTargetBitrate = 5000000u; -const VideoEncodeAccelerator::SupportedRateControlMode kSupportedProfileModes = - VideoEncodeAccelerator::kConstantMode | - VideoEncodeAccelerator::kVariableMode; -const size_t kMaxFrameRateNumerator = 30; -const size_t kMaxFrameRateDenominator = 1; -const size_t kMaxResolutionWidth = 1920; -const size_t kMaxResolutionHeight = 1088; -const size_t kMinResolutionWidth = 32; -const size_t kMinResolutionHeight = 32; -const size_t kNumInputBuffers = 3; +constexpr uint32_t kDefaultGOPLength = 3000; +constexpr uint32_t kDefaultTargetBitrate = 5000000u; +const auto kSupportedProfileModes = VideoEncodeAccelerator::kConstantMode | + VideoEncodeAccelerator::kVariableMode; +constexpr size_t kMaxFrameRateNumerator = 30; +constexpr size_t kMaxFrameRateDenominator = 1; +constexpr size_t kMaxResolutionWidth = 1920; +constexpr size_t kMaxResolutionHeight = 1088; +constexpr size_t kMinResolutionWidth = 32; +constexpr size_t kMinResolutionHeight = 32; +constexpr size_t kNumInputBuffers = 3; // Media Foundation uses 100 nanosecond units for time, see // https://msdn.microsoft.com/en-us/library/windows/desktop/ms697282(v=vs.85).aspx. -const size_t kOneMicrosecondInMFSampleTimeUnits = 10; -const size_t kPrefixNALLocatedBytePos = 3; +constexpr size_t kOneMicrosecondInMFSampleTimeUnits = 10; +constexpr size_t kPrefixNALLocatedBytePos = 3; constexpr uint64_t kH264MaxQp = 51; constexpr uint64_t kVP9MaxQp = 63; constexpr uint64_t kAV1MaxQp = 63; @@ -433,17 +433,9 @@ const gpu::GpuPreferences& gpu_preferences, const gpu::GpuDriverBugWorkarounds& gpu_workarounds, CHROME_LUID luid) - : state_(kUninitialized), - frame_rate_(kMaxFrameRateNumerator / kMaxFrameRateDenominator), - bitrate_allocation_(Bitrate::Mode::kConstant), - input_required_(false), - main_client_task_runner_(base::SequencedTaskRunner::GetCurrentDefault()), - encoder_thread_task_runner_(base::ThreadPool::CreateCOMSTATaskRunner( - {}, - base::SingleThreadTaskRunnerThreadMode::DEDICATED)), + : task_runner_(base::SingleThreadTaskRunner::GetCurrentDefault()), luid_(luid) { - DETACH_FROM_SEQUENCE(encode_sequence_checker_); - encoder_weak_ptr_ = encoder_task_weak_factory_.GetWeakPtr(); + weak_ptr_ = weak_factory_.GetWeakPtr(); bitrate_allocation_.SetBitrate(0, 0, kDefaultTargetBitrate); } @@ -452,7 +444,6 @@ DVLOG(3) << __func__; DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(async_callback_ref_.IsOne()); - DCHECK(!encoder_task_weak_factory_.HasWeakPtrs()); } VideoEncodeAccelerator::SupportedProfiles @@ -482,6 +473,7 @@ VideoEncodeAccelerator::SupportedProfiles MediaFoundationVideoEncodeAccelerator::GetSupportedProfilesForCodec( VideoCodec codec) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); SupportedProfiles profiles; if (codec == VideoCodec::kHEVC) { @@ -583,10 +575,11 @@ std::unique_ptr<MediaLog> media_log) { DVLOG(3) << __func__ << ": " << config.AsHumanReadableString(); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + media_log_ = std::move(media_log); if (PIXEL_FORMAT_I420 != config.input_format && PIXEL_FORMAT_NV12 != config.input_format) { - MEDIA_LOG(ERROR, media_log.get()) + MEDIA_LOG(ERROR, media_log_) << "Input format not supported= " << VideoPixelFormatToString(config.input_format); return false; @@ -596,7 +589,7 @@ config.output_profile <= H264PROFILE_MAX) { if (GetH264VProfile(config.output_profile, config.is_constrained_h264) == eAVEncH264VProfile_unknown) { - MEDIA_LOG(ERROR, media_log.get()) + MEDIA_LOG(ERROR, media_log_) << "Output profile not supported = " << config.output_profile; return false; } @@ -604,7 +597,7 @@ } else if (config.output_profile >= VP9PROFILE_MIN && config.output_profile <= VP9PROFILE_MAX) { if (GetVP9VProfile(config.output_profile) == eAVEncVP9VProfile_unknown) { - MEDIA_LOG(ERROR, media_log.get()) + MEDIA_LOG(ERROR, media_log_) << "Output profile not supported = " << config.output_profile; return false; } @@ -616,19 +609,17 @@ } if (codec_ == VideoCodec::kUnknown) { - MEDIA_LOG(ERROR, media_log.get()) + MEDIA_LOG(ERROR, media_log_) << "Output profile not supported = " << config.output_profile; return false; } if (config.HasSpatialLayer()) { - MEDIA_LOG(ERROR, media_log.get()) << "MediaFoundation does not support " - "spatial layer encoding."; + MEDIA_LOG(ERROR, media_log_) << "MediaFoundation does not support " + "spatial layer encoding."; return false; } - main_client_weak_factory_ = - std::make_unique<base::WeakPtrFactory<Client>>(client); - main_client_ = main_client_weak_factory_->GetWeakPtr(); + client_ = client; input_visible_size_ = config.input_visible_size; if (config.initial_framerate.has_value() && config.initial_framerate.value()) frame_rate_ = config.initial_framerate.value(); @@ -668,28 +659,12 @@ } } - encoder_thread_task_runner_->PostTask( - FROM_HERE, - base::BindOnce( - &MediaFoundationVideoEncodeAccelerator::EncoderInitializeTask, - encoder_weak_ptr_, config, std::move(media_log))); - - return true; -} - -void MediaFoundationVideoEncodeAccelerator::EncoderInitializeTask( - const Config& config, - std::unique_ptr<MediaLog> media_log) { - DVLOG(3) << __func__; - DCHECK_CALLED_ON_VALID_SEQUENCE(encode_sequence_checker_); - SetState(kInitializing); - HRESULT hr = S_OK; IMFActivate** pp_activates = nullptr; uint32_t encoder_count = EnumerateHardwareEncoders(codec_, &pp_activates); NOTIFY_RETURN_ON_FAILURE(encoder_count == 0, - "Failed finding a hardware encoder MFT.", ); + "Failed finding a hardware encoder MFT.", false); bool activated = ActivateAsyncEncoder(pp_activates, encoder_count, config.is_constrained_h264); @@ -708,23 +683,23 @@ } NOTIFY_RETURN_ON_FAILURE( - !activated, "Failed activating an async hardware encoder MFT.", ); - NOTIFY_RETURN_ON_FAILURE(!SetEncoderModes(), - "Failed to set encoder modes.", ); + !activated, "Failed activating an async hardware encoder MFT.", false); + NOTIFY_RETURN_ON_FAILURE(!SetEncoderModes(), "Failed to set encoder modes.", + false); NOTIFY_RETURN_ON_FAILURE( !InitializeInputOutputParameters(config.output_profile, config.is_constrained_h264), - "Failed to set input/output param.", ); + "Failed to set input/output param.", false); - hr = MFCreateSample(&input_sample_); - NOTIFY_RETURN_ON_HR_FAILURE(hr, "Failed to create sample", ); + auto hr = MFCreateSample(&input_sample_); + NOTIFY_RETURN_ON_HR_FAILURE(hr, "Failed to create sample", false); - if (media::IsMediaFoundationD3D11VideoCaptureEnabled()) { - MEDIA_LOG(INFO, media_log.get()) + if (IsMediaFoundationD3D11VideoCaptureEnabled()) { + MEDIA_LOG(INFO, media_log_) << "Preferred DXGI device " << luid_.HighPart << ":" << luid_.LowPart; dxgi_device_manager_ = DXGIDeviceManager::Create(luid_); NOTIFY_RETURN_ON_FAILURE(!dxgi_device_manager_, - "Failed to create DXGIDeviceManager", ); + "Failed to create DXGIDeviceManager", false); auto mf_dxgi_device_manager = dxgi_device_manager_->GetMFDXGIDeviceManager(); hr = encoder_->ProcessMessage( @@ -733,26 +708,28 @@ // If HMFT rejects setting D3D manager, fallback to non-D3D11 encoding. if (FAILED(hr)) { dxgi_resource_mapping_required_ = true; - MEDIA_LOG(INFO, media_log.get()) + MEDIA_LOG(INFO, media_log_) << "Couldn't set DXGIDeviceManager, fallback to non-D3D11 encoding"; } } hr = encoder_->QueryInterface(IID_PPV_ARGS(&event_generator_)); - NOTIFY_RETURN_ON_HR_FAILURE(hr, "Couldn't get event generator", ); + NOTIFY_RETURN_ON_HR_FAILURE(hr, "Couldn't get event generator", false); event_generator_->BeginGetEvent(this, nullptr); // Start the asynchronous processing model hr = encoder_->ProcessMessage(MFT_MESSAGE_COMMAND_FLUSH, 0); NOTIFY_RETURN_ON_HR_FAILURE( - hr, "Couldn't set ProcessMessage MFT_MESSAGE_COMMAND_FLUSH", ); + hr, "Couldn't set ProcessMessage MFT_MESSAGE_COMMAND_FLUSH", false); hr = encoder_->ProcessMessage(MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, 0); NOTIFY_RETURN_ON_HR_FAILURE( - hr, "Couldn't set ProcessMessage MFT_MESSAGE_NOTIFY_BEGIN_STREAMING", ); + hr, "Couldn't set ProcessMessage MFT_MESSAGE_NOTIFY_BEGIN_STREAMING", + false); hr = encoder_->ProcessMessage(MFT_MESSAGE_NOTIFY_START_OF_STREAM, 0); NOTIFY_RETURN_ON_HR_FAILURE( - hr, "Couldn't set ProcessMessage MFT_MESSAGE_NOTIFY_START_OF_STREAM", ); + hr, "Couldn't set ProcessMessage MFT_MESSAGE_NOTIFY_START_OF_STREAM", + false); encoder_info_.implementation_name = "MediaFoundationVideoEncodeAccelerator"; // Currently, MFVEA does not support odd resolution well. The implementation @@ -776,6 +753,8 @@ constexpr uint8_t kFullFramerate = 255; encoder_info_.fps_allocation[0] = {kFullFramerate}; } + + return true; } void MediaFoundationVideoEncodeAccelerator::Encode( @@ -784,11 +763,24 @@ DVLOG(3) << __func__; DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - encoder_thread_task_runner_->PostTask( - FROM_HERE, - base::BindOnce(&MediaFoundationVideoEncodeAccelerator::EncodeTask, - encoder_weak_ptr_, - MakeInput(std::move(frame), force_keyframe))); + if (state_ != kEncoding && state_ != kInitializing) { + DVLOG(3) << "Abandon input frame for video encoder."; + return; + } + + pending_input_queue_.push_back(MakeInput(std::move(frame), force_keyframe)); + + // Before the first time |input_required_| is toggled on, the HMFT is not yet + // ready receiving inputs. + if (!input_required_) { + return; + } + + auto first_input = std::move(pending_input_queue_.front()); + pending_input_queue_.pop_front(); + auto hr = ProcessInput(std::move(first_input)); + NOTIFY_RETURN_ON_HR_FAILURE(hr, "Failed to encode pending frame.", ); + input_required_ = false; } void MediaFoundationVideoEncodeAccelerator::UseOutputBitstreamBuffer( @@ -799,27 +791,40 @@ if (buffer.size() < bitstream_buffer_size_) { DLOG(ERROR) << "Output BitstreamBuffer isn't big enough: " << buffer.size() << " vs. " << bitstream_buffer_size_; - NotifyError(kInvalidArgumentError); + client_->NotifyError(kInvalidArgumentError); return; } + // After mapping, |region| is no longer necessary and it can be destroyed. + // |mapping| will keep the shared memory region open. auto region = buffer.TakeRegion(); auto mapping = region.Map(); - if (!mapping.IsValid()) { - DLOG(ERROR) << "Failed mapping shared memory."; - NotifyError(kPlatformFailureError); + NOTIFY_RETURN_ON_FAILURE(!mapping.IsValid(), + "Failed mapping shared memory.", ); + + auto buffer_ref = std::make_unique<BitstreamBufferRef>( + buffer.id(), std::move(mapping), buffer.size()); + + if (encoder_output_queue_.empty()) { + bitstream_buffer_queue_.push_back(std::move(buffer_ref)); return; } - // After mapping, |region| is no longer necessary and it can be - // destroyed. |mapping| will keep the shared memory region open. - std::unique_ptr<BitstreamBufferRef> buffer_ref( - new BitstreamBufferRef(buffer.id(), std::move(mapping), buffer.size())); - encoder_thread_task_runner_->PostTask( - FROM_HERE, - base::BindOnce( - &MediaFoundationVideoEncodeAccelerator::UseOutputBitstreamBufferTask, - encoder_weak_ptr_, std::move(buffer_ref))); + auto encode_output = std::move(encoder_output_queue_.front()); + encoder_output_queue_.pop_front(); + memcpy(buffer_ref->mapping.memory(), encode_output->memory(), + encode_output->size()); + + BitstreamBufferMetadata md(encode_output->size(), encode_output->keyframe, + encode_output->capture_timestamp); + if (encode_output->frame_qp) { + md.qp = *encode_output->frame_qp; + } + if (temporal_scalable_coding()) { + md.h264.emplace().temporal_idx = encode_output->temporal_layer_id; + } + + client_->BitstreamBufferReady(buffer_ref->id, md); } void MediaFoundationVideoEncodeAccelerator::RequestEncodingParametersChange( @@ -831,13 +836,11 @@ VideoBitrateAllocation allocation(bitrate.mode()); allocation.SetBitrate(0, 0, bitrate.target_bps()); - if (bitrate.mode() == Bitrate::Mode::kVariable) + if (bitrate.mode() == Bitrate::Mode::kVariable) { allocation.SetPeakBps(bitrate.peak_bps()); + } - encoder_thread_task_runner_->PostTask( - FROM_HERE, base::BindOnce(&MediaFoundationVideoEncodeAccelerator:: - RequestEncodingParametersChangeTask, - encoder_weak_ptr_, allocation, framerate)); + RequestEncodingParametersChange(allocation, framerate); } void MediaFoundationVideoEncodeAccelerator::RequestEncodingParametersChange( @@ -847,31 +850,50 @@ << ": framerate=" << framerate; DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - encoder_thread_task_runner_->PostTask( - FROM_HERE, - base::BindOnce(&MediaFoundationVideoEncodeAccelerator:: - RequestEncodingParametersChangeTask, - encoder_weak_ptr_, bitrate_allocation, framerate)); + DCHECK(imf_output_media_type_); + DCHECK(imf_input_media_type_); + DCHECK(encoder_); + RETURN_ON_FAILURE( + bitrate_allocation.GetMode() == bitrate_allocation_.GetMode(), + "Invalid bitrate mode", ); + framerate = + base::clamp(framerate, 1u, static_cast<uint32_t>(kMaxFrameRateNumerator)); + + if (framerate == frame_rate_ && bitrate_allocation == bitrate_allocation_) { + return; + } + + bitrate_allocation_ = bitrate_allocation; + frame_rate_ = framerate; + // For SW BRC we don't reconfigure the encoder. + if (rate_ctrl_) { + rate_ctrl_->UpdateRateControl(CreateRateControllerConfig( + bitrate_allocation_, input_visible_size_, frame_rate_, + /*num_temporal_layers=*/1, codec_)); + return; + } + + VARIANT var; + var.vt = VT_UI4; + var.ulVal = AdjustBitrateToFrameRate(bitrate_allocation_.GetSumBps(), + configured_frame_rate_, framerate); + HRESULT hr = codec_api_->SetValue(&CODECAPI_AVEncCommonMeanBitRate, &var); + RETURN_ON_HR_FAILURE(hr, "Couldn't update mean bitrate", ); + + if (bitrate_allocation_.GetMode() == Bitrate::Mode::kVariable) { + var.ulVal = AdjustBitrateToFrameRate(bitrate_allocation_.GetPeakBps(), + configured_frame_rate_, framerate); + hr = codec_api_->SetValue(&CODECAPI_AVEncCommonMaxBitRate, &var); + RETURN_ON_HR_FAILURE(hr, "Couldn't set max bitrate", ); + } } void MediaFoundationVideoEncodeAccelerator::Destroy() { DVLOG(3) << __func__; DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - // Cancel all callbacks. - main_client_weak_factory_.reset(); - - // MF resources need to be cleaned up on |encoder_thread_task_runner_|, - // but the object itself is supposed to be deleted on this runner, so when - // DestroyTask() is done we schedule deletion of |this| - auto delete_self = [](MediaFoundationVideoEncodeAccelerator* self) { - delete self; - }; - encoder_thread_task_runner_->PostTaskAndReply( - FROM_HERE, - base::BindOnce(&MediaFoundationVideoEncodeAccelerator::DestroyTask, - encoder_weak_ptr_), - base::BindOnce(delete_self, base::Unretained(this))); + SetState(kClosing); + ReleaseEncoderResources(); + delete this; } bool MediaFoundationVideoEncodeAccelerator::IsGpuFrameResizeSupported() { @@ -883,7 +905,7 @@ uint32_t encoder_count, bool is_constrained_h264) { DVLOG(3) << __func__; - DCHECK_CALLED_ON_VALID_SEQUENCE(encode_sequence_checker_); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); // Try to create the encoder with priority according to merit value. HRESULT hr = E_FAIL; @@ -973,7 +995,7 @@ bool MediaFoundationVideoEncodeAccelerator::InitializeInputOutputParameters( VideoCodecProfile output_profile, bool is_constrained_h264) { - DCHECK_CALLED_ON_VALID_SEQUENCE(encode_sequence_checker_); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(encoder_); DWORD input_count = 0; @@ -1069,7 +1091,7 @@ } bool MediaFoundationVideoEncodeAccelerator::SetEncoderModes() { - DCHECK_CALLED_ON_VALID_SEQUENCE(encode_sequence_checker_); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(encoder_); HRESULT hr = encoder_.As(&codec_api_); @@ -1142,43 +1164,10 @@ return true; } -void MediaFoundationVideoEncodeAccelerator::NotifyError( - VideoEncodeAccelerator::Error error) { - main_client_task_runner_->PostTask( - FROM_HERE, base::BindOnce(&Client::NotifyError, main_client_, error)); -} - -void MediaFoundationVideoEncodeAccelerator::EncodeTask(PendingInput input) { - DVLOG(3) << __func__; - DCHECK_CALLED_ON_VALID_SEQUENCE(encode_sequence_checker_); - - HRESULT hr = E_FAIL; - if (state_ != kEncoding && state_ != kInitializing) { - DVLOG(3) << "Abandon input frame for video encoder."; - return; - } - pending_input_queue_.push_back(std::move(input)); - - // Before the first time |input_required_| is toggled on, the - // HMFT is not yet ready receiving inputs. - if (input_required_) { - PendingInput first_input = std::move(pending_input_queue_.front()); - pending_input_queue_.pop_front(); - hr = ProcessInput(std::move(first_input)); - if (FAILED(hr)) { - DLOG(ERROR) << "Failed to encode pending frame."; - SetState(kError); - NotifyError(kPlatformFailureError); - return; - } - input_required_ = false; - } -} - HRESULT MediaFoundationVideoEncodeAccelerator::ProcessInput( PendingInput input) { DVLOG(3) << __func__; - DCHECK_CALLED_ON_VALID_SEQUENCE(encode_sequence_checker_); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); auto timestamp = input.frame->timestamp(); HRESULT hr = PopulateInputSampleBuffer(std::move(input.frame)); @@ -1223,6 +1212,7 @@ HRESULT MediaFoundationVideoEncodeAccelerator::PopulateInputSampleBuffer( scoped_refptr<VideoFrame> frame) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (frame->storage_type() != VideoFrame::StorageType::STORAGE_GPU_MEMORY_BUFFER && !frame->IsMappable()) { @@ -1327,6 +1317,7 @@ // from that is currently used for encoding. HRESULT MediaFoundationVideoEncodeAccelerator::CopyInputSampleBufferFromGpu( const VideoFrame& frame) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_EQ(frame.storage_type(), VideoFrame::StorageType::STORAGE_GPU_MEMORY_BUFFER); DCHECK(frame.HasGpuMemoryBuffer()); @@ -1405,6 +1396,7 @@ // Handle case where video frame is backed by a GPU texture HRESULT MediaFoundationVideoEncodeAccelerator::PopulateInputSampleBufferGpu( scoped_refptr<VideoFrame> frame) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_EQ(frame->storage_type(), VideoFrame::StorageType::STORAGE_GPU_MEMORY_BUFFER); DCHECK(frame->HasGpuMemoryBuffer()); @@ -1467,6 +1459,7 @@ int MediaFoundationVideoEncodeAccelerator::AssignTemporalIdBySvcSpec( bool keyframe) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); int result = 0; if (keyframe) @@ -1497,6 +1490,7 @@ size_t size, int* temporal_id, bool keyframe) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); *temporal_id = 0; // H264, HEVC, VP9 and AV1 have hardware SVC support on windows. H264 can @@ -1557,7 +1551,7 @@ void MediaFoundationVideoEncodeAccelerator::ProcessOutput() { DVLOG(3) << __func__; - DCHECK_CALLED_ON_VALID_SEQUENCE(encode_sequence_checker_); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); MFT_OUTPUT_DATA_BUFFER output_data_buffer = {0}; output_data_buffer.dwStreamID = output_stream_id_; @@ -1614,9 +1608,7 @@ } } if (!encoder_info_sent_ || should_notify_encoder_info_change) { - main_client_task_runner_->PostTask( - FROM_HERE, base::BindOnce(&Client::NotifyEncoderInfoChange, - main_client_, encoder_info_)); + client_->NotifyEncoderInfoChange(encoder_info_); encoder_info_sent_ = true; } // Bits 0-15: Default QP. @@ -1633,7 +1625,7 @@ int temporal_id = 0; if (!AssignTemporalId(output_buffer, size, &temporal_id, keyframe)) { DLOG(ERROR) << "Parse temporalId failed."; - NotifyError(VideoEncodeAccelerator::Error::kPlatformFailureError); + client_->NotifyError(VideoEncodeAccelerator::Error::kPlatformFailureError); return; } if (rate_ctrl_) { @@ -1668,8 +1660,7 @@ } // Immediately return encoded buffer with BitstreamBuffer to client. - std::unique_ptr<MediaFoundationVideoEncodeAccelerator::BitstreamBufferRef> - buffer_ref = std::move(bitstream_buffer_queue_.front()); + auto buffer_ref = std::move(bitstream_buffer_queue_.front()); bitstream_buffer_queue_.pop_front(); { @@ -1690,36 +1681,21 @@ md.qp = static_cast<int32_t>(frame_qp); } - if (temporalScalableCoding()) { + if (temporal_scalable_coding()) { if (codec_ == VideoCodec::kH264) { md.h264.emplace().temporal_idx = temporal_id; } else if (codec_ == VideoCodec::kHEVC) { md.h265.emplace().temporal_idx = temporal_id; } } - main_client_task_runner_->PostTask( - FROM_HERE, base::BindOnce(&Client::BitstreamBufferReady, main_client_, - buffer_ref->id, md)); -} -void MediaFoundationVideoEncodeAccelerator::OnInitCompleted() { - DCHECK_CALLED_ON_VALID_SEQUENCE(encode_sequence_checker_); - - DVLOG(3) << "Encoder is ready to accept input."; - SetState(kEncoding); + client_->BitstreamBufferReady(buffer_ref->id, md); } void MediaFoundationVideoEncodeAccelerator::MediaEventHandler( MediaEventType event_type) { DVLOG(3) << __func__; - DCHECK_CALLED_ON_VALID_SEQUENCE(encode_sequence_checker_); - - // Not necessary to acquire lock for destroy_initiated_ as - // only encoder thread updates it. - if (in_shutdown_) { - DVLOG(3) << "Ignoring events from MFT during shutdown."; - return; - } + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(event_generator_); switch (event_type) { @@ -1727,14 +1703,9 @@ if (state_ == kInitializing) { // HMFT is not ready for receiving inputs until the first // METransformNeedInput event is published. - main_client_task_runner_->PostTaskAndReply( - FROM_HERE, - base::BindOnce(&Client::RequireBitstreamBuffers, main_client_, - kNumInputBuffers, input_visible_size_, - bitstream_buffer_size_), - base::BindOnce( - &MediaFoundationVideoEncodeAccelerator::OnInitCompleted, - encoder_weak_ptr_)); + client_->RequireBitstreamBuffers(kNumInputBuffers, input_visible_size_, + bitstream_buffer_size_); + SetState(kEncoding); input_required_ = true; } else if (state_ == kEncoding) { // If there're already pending inputs in queue, that needs to @@ -1746,7 +1717,7 @@ if (FAILED(hr)) { DLOG(ERROR) << "Failed to encode pending frame."; SetState(kError); - NotifyError(kPlatformFailureError); + client_->NotifyError(kPlatformFailureError); return; } input_required_ = false; @@ -1766,105 +1737,20 @@ event_generator_->BeginGetEvent(this, nullptr); } -void MediaFoundationVideoEncodeAccelerator::UseOutputBitstreamBufferTask( - std::unique_ptr<BitstreamBufferRef> buffer_ref) { - DVLOG(3) << __func__; - DCHECK_CALLED_ON_VALID_SEQUENCE(encode_sequence_checker_); - - // If there is already EncodeOutput waiting, copy its output first. - if (!encoder_output_queue_.empty()) { - std::unique_ptr<MediaFoundationVideoEncodeAccelerator::EncodeOutput> - encode_output = std::move(encoder_output_queue_.front()); - encoder_output_queue_.pop_front(); - memcpy(buffer_ref->mapping.memory(), encode_output->memory(), - encode_output->size()); - - BitstreamBufferMetadata md(encode_output->size(), encode_output->keyframe, - encode_output->capture_timestamp); - if (encode_output->frame_qp) { - md.qp = *encode_output->frame_qp; - } - if (temporalScalableCoding()) - md.h264.emplace().temporal_idx = encode_output->temporal_layer_id; - main_client_task_runner_->PostTask( - FROM_HERE, base::BindOnce(&Client::BitstreamBufferReady, main_client_, - buffer_ref->id, md)); - return; - } - - bitstream_buffer_queue_.push_back(std::move(buffer_ref)); -} - -void MediaFoundationVideoEncodeAccelerator::RequestEncodingParametersChangeTask( - const VideoBitrateAllocation& bitrate_allocation, - uint32_t framerate) { - DVLOG(3) << __func__; - DCHECK_CALLED_ON_VALID_SEQUENCE(encode_sequence_checker_); - DCHECK(imf_output_media_type_); - DCHECK(imf_input_media_type_); - DCHECK(encoder_); - RETURN_ON_FAILURE( - bitrate_allocation.GetMode() == bitrate_allocation_.GetMode(), - "Invalid bitrate mode", ); - framerate = - base::clamp(framerate, 1u, static_cast<uint32_t>(kMaxFrameRateNumerator)); - - if (framerate == frame_rate_ && bitrate_allocation == bitrate_allocation_) - return; - - bitrate_allocation_ = bitrate_allocation; - frame_rate_ = framerate; - // For SW BRC we don't reconfigure the encoder. - if (rate_ctrl_) { - rate_ctrl_->UpdateRateControl(CreateRateControllerConfig( - bitrate_allocation_, input_visible_size_, frame_rate_, - /*num_temporal_layers=*/1, codec_)); - return; - } - - VARIANT var; - var.vt = VT_UI4; - var.ulVal = AdjustBitrateToFrameRate(bitrate_allocation_.GetSumBps(), - configured_frame_rate_, framerate); - HRESULT hr = codec_api_->SetValue(&CODECAPI_AVEncCommonMeanBitRate, &var); - RETURN_ON_HR_FAILURE(hr, "Couldn't update mean bitrate", ); - - if (bitrate_allocation_.GetMode() == Bitrate::Mode::kVariable) { - var.ulVal = AdjustBitrateToFrameRate(bitrate_allocation_.GetPeakBps(), - configured_frame_rate_, framerate); - hr = codec_api_->SetValue(&CODECAPI_AVEncCommonMaxBitRate, &var); - RETURN_ON_HR_FAILURE(hr, "Couldn't set max bitrate", ); - } -} - void MediaFoundationVideoEncodeAccelerator::SetState(State state) { - DCHECK_CALLED_ON_VALID_SEQUENCE(encode_sequence_checker_); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DVLOG(3) << "Setting state to: " << state; state_ = state; } -void MediaFoundationVideoEncodeAccelerator::DestroyTask() { - DVLOG(3) << __func__; - DCHECK_CALLED_ON_VALID_SEQUENCE(encode_sequence_checker_); - SetState(kClosing); - - { - base::AutoLock lock(destroy_lock_); - in_shutdown_ = true; - } - // Cancel all encoder thread callbacks. - encoder_task_weak_factory_.InvalidateWeakPtrs(); - - ReleaseEncoderResources(); -} - void MediaFoundationVideoEncodeAccelerator::ReleaseEncoderResources() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); bitstream_buffer_queue_.clear(); pending_input_queue_.clear(); encoder_output_queue_.clear(); - if (activate_.Get() != nullptr) { + if (activate_) { activate_->ShutdownObject(); activate_->Release(); activate_.Reset(); @@ -1880,6 +1766,7 @@ HRESULT MediaFoundationVideoEncodeAccelerator::InitializeD3DVideoProcessing( ID3D11Texture2D* input_texture) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); D3D11_TEXTURE2D_DESC input_desc = {}; input_texture->GetDesc(&input_desc); if (vp_desc_.InputWidth == input_desc.Width && @@ -1966,6 +1853,7 @@ HRESULT MediaFoundationVideoEncodeAccelerator::PerformD3DScaling( ID3D11Texture2D* input_texture) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); HRESULT hr = InitializeD3DVideoProcessing(input_texture); RETURN_ON_HR_FAILURE(hr, "Couldn't initialize D3D video processing", hr); @@ -2046,34 +1934,25 @@ HRESULT MediaFoundationVideoEncodeAccelerator::Invoke( IMFAsyncResult* pAsyncResult) { - HRESULT hr = S_OK; Microsoft::WRL::ComPtr<IMFMediaEvent> media_event; + RETURN_IF_FAILED(event_generator_->EndGetEvent(pAsyncResult, &media_event)); + MediaEventType event_type = MEUnknown; - - { - // Prevent event fetching on MFT shutdown. - base::AutoLock lock(destroy_lock_); - if (in_shutdown_) { - DVLOG(3) << "Ignoring events from MFT during shutdown."; - return S_OK; - } - - RETURN_IF_FAILED(event_generator_->EndGetEvent(pAsyncResult, &media_event)); - } - RETURN_IF_FAILED(media_event->GetType(&event_type)); + HRESULT hr = S_OK; media_event->GetStatus(&hr); if (FAILED(hr)) { DLOG(ERROR) << "GetStatus() failed."; return hr; } - encoder_thread_task_runner_->PostTask( + // Invoke() is called on some random OS thread, so we must post to our event + // handler since MediaFoundationVideoEncodeAccelerator is single threaded. + task_runner_->PostTask( FROM_HERE, base::BindOnce(&MediaFoundationVideoEncodeAccelerator::MediaEventHandler, - encoder_weak_ptr_, event_type)); - + weak_ptr_, event_type)); return hr; } @@ -2088,9 +1967,9 @@ HRESULT MediaFoundationVideoEncodeAccelerator::QueryInterface(REFIID riid, void** ppv) { - static const QITAB qit[] = { + static const QITAB kQI[] = { QITABENT(MediaFoundationVideoEncodeAccelerator, IMFAsyncCallback), {0}}; - return QISearch(this, qit, riid, ppv); + return QISearch(this, kQI, riid, ppv); } } // namespace media
diff --git a/media/gpu/windows/media_foundation_video_encode_accelerator_win.h b/media/gpu/windows/media_foundation_video_encode_accelerator_win.h index b636110..1e135c1 100644 --- a/media/gpu/windows/media_foundation_video_encode_accelerator_win.h +++ b/media/gpu/windows/media_foundation_video_encode_accelerator_win.h
@@ -126,16 +126,9 @@ // Initializes encoder parameters for real-time use. bool SetEncoderModes(); - // Helper function to notify the client of an error on - // |main_client_task_runner_|. - void NotifyError(VideoEncodeAccelerator::Error error); - - // Set the encoder state to |state| on |encoder_thread_task_runner_|. + // Set the encoder state to |state|. void SetState(State state); - // Encoding task to be run on |encoder_thread_task_runner_|. - void EncodeTask(PendingInput input); - // Processes the input video frame for the encoder. HRESULT ProcessInput(PendingInput input); @@ -153,30 +146,14 @@ int AssignTemporalIdBySvcSpec(bool keyframe); - bool temporalScalableCoding() { return num_temporal_layers_ > 1; } + bool temporal_scalable_coding() const { return num_temporal_layers_ > 1; } - // Checks for and copies encoded output on |encoder_thread_task_runner_|. + // Checks for and copies encoded output. void ProcessOutput(); // Asynchronous event handler void MediaEventHandler(MediaEventType event_type); - // Inserts the output buffers for reuse on |encoder_thread_task_runner_|. - void UseOutputBitstreamBufferTask( - std::unique_ptr<BitstreamBufferRef> buffer_ref); - - // Changes encode parameters on |encoder_thread_task_runner_|. - void RequestEncodingParametersChangeTask( - const VideoBitrateAllocation& bitrate_allocation, - uint32_t framerate); - - // Destroys encode session on |encoder_thread_task_runner_|. - void DestroyTask(); - - // Initialize the encoder on |encoder_thread_task_runner_|. - void EncoderInitializeTask(const Config& config, - std::unique_ptr<MediaLog> media_log); - // Releases resources encoder holds. void ReleaseEncoderResources(); @@ -186,8 +163,10 @@ // Perform D3D11 scaling operation HRESULT PerformD3DScaling(ID3D11Texture2D* input_texture); - // Callback when the encoder is ready for accepting input. - void OnInitCompleted(); + // Used to post tasks from the IMFMediaEvent::Invoke() method. + scoped_refptr<base::SingleThreadTaskRunner> task_runner_; + + std::unique_ptr<MediaLog> media_log_; // Bitstream buffers ready to be used to return encoded output as a FIFO. base::circular_deque<std::unique_ptr<BitstreamBufferRef>> @@ -204,7 +183,7 @@ uint32_t outputs_since_keyframe_count_ = 0; // Encoder state. Encode tasks will only run in kEncoding state. - State state_; + State state_ = kUninitialized; // This parser is used to assign temporalId. H264Parser h264_parser_; @@ -213,14 +192,14 @@ #endif gfx::Size input_visible_size_; - size_t bitstream_buffer_size_; - uint32_t frame_rate_; + size_t bitstream_buffer_size_ = 0u; + uint32_t frame_rate_ = 30; // For recording configured frame rate as we don't dynamically change it. // The default value here will be overridden during initialization. uint32_t configured_frame_rate_ = 30; // Bitrate allocation in bps. - VideoBitrateAllocation bitrate_allocation_; - bool low_latency_mode_; + VideoBitrateAllocation bitrate_allocation_{Bitrate::Mode::kConstant}; + bool low_latency_mode_ = false; int num_temporal_layers_ = 1; // Codec type used for encoding. @@ -231,7 +210,7 @@ // Group of picture length for encoded output stream, indicates the // distance between two key frames. - uint32_t gop_length_; + uint32_t gop_length_ = 0u; // Video encoder info that includes accelerator name, QP validity, etc. VideoEncoderInfo encoder_info_; @@ -243,13 +222,13 @@ Microsoft::WRL::ComPtr<IMFMediaEventGenerator> event_generator_; base::AtomicRefCount async_callback_ref_{1}; - DWORD input_stream_id_; - DWORD output_stream_id_; + DWORD input_stream_id_ = 0u; + DWORD output_stream_id_ = 0u; Microsoft::WRL::ComPtr<IMFMediaType> imf_input_media_type_; Microsoft::WRL::ComPtr<IMFMediaType> imf_output_media_type_; - bool input_required_; + bool input_required_ = false; Microsoft::WRL::ComPtr<IMFSample> input_sample_; Microsoft::WRL::ComPtr<IMFSample> output_sample_; @@ -263,18 +242,9 @@ Microsoft::WRL::ComPtr<ID3D11VideoProcessorOutputView> vp_output_view_; // To expose client callbacks from VideoEncodeAccelerator. - // NOTE: all calls to this object *MUST* be executed on - // |main_client_task_runner_|. - base::WeakPtr<Client> main_client_; - std::unique_ptr<base::WeakPtrFactory<Client>> main_client_weak_factory_; - scoped_refptr<base::SequencedTaskRunner> main_client_task_runner_; + Client* client_ = nullptr; SEQUENCE_CHECKER(sequence_checker_); - // This thread services tasks posted from the VEA API entry points - // and runs them on a thread that can do heavy work and call MF COM interface. - scoped_refptr<base::SingleThreadTaskRunner> encoder_thread_task_runner_; - SEQUENCE_CHECKER(encode_sequence_checker_); - // DXGI device manager for handling hardware input textures scoped_refptr<DXGIDeviceManager> dxgi_device_manager_; // Mapping of dxgi resource needed when HMFT rejects setting D3D11 manager. @@ -292,17 +262,11 @@ // Bitrate controller for CBR encoding. std::unique_ptr<VideoRateControlWrapper> rate_ctrl_; - // Lock to prevent calls to MFT from workqueue when it is in destroy process. - base::Lock destroy_lock_; - - // Indicates whether DestroyTask has been invoked. - bool in_shutdown_ = false; - // Declared last to ensure that all weak pointers are invalidated before // other destructors run. - base::WeakPtr<MediaFoundationVideoEncodeAccelerator> encoder_weak_ptr_; - base::WeakPtrFactory<MediaFoundationVideoEncodeAccelerator> - encoder_task_weak_factory_{this}; + base::WeakPtr<MediaFoundationVideoEncodeAccelerator> weak_ptr_; + base::WeakPtrFactory<MediaFoundationVideoEncodeAccelerator> weak_factory_{ + this}; }; } // namespace media
diff --git a/media/mojo/services/mojo_video_encode_accelerator_provider.cc b/media/mojo/services/mojo_video_encode_accelerator_provider.cc index 2fc77195..e250a7a4 100644 --- a/media/mojo/services/mojo_video_encode_accelerator_provider.cc +++ b/media/mojo/services/mojo_video_encode_accelerator_provider.cc
@@ -71,8 +71,12 @@ &MojoVideoEncodeAcceleratorService::Create, std::move(receiver), create_vea_callback_, gpu_preferences_, gpu_workarounds_, gpu_device_); - if (base::FeatureList::IsEnabled(kUseSequencedTaskRunnerForMojoVEAService)) { + if (base::FeatureList::IsEnabled(kUseTaskRunnerForMojoVEAService)) { +#if BUILDFLAG(IS_WIN) + base::ThreadPool::CreateCOMSTATaskRunner({base::MayBlock()}) +#else base::ThreadPool::CreateSequencedTaskRunner({base::MayBlock()}) +#endif ->PostTask(FROM_HERE, std::move(create_service_cb)); } else { std::move(create_service_cb).Run();
diff --git a/mojo/public/cpp/bindings/array_traits.h b/mojo/public/cpp/bindings/array_traits.h index 2e23802a..e5a8992 100644 --- a/mojo/public/cpp/bindings/array_traits.h +++ b/mojo/public/cpp/bindings/array_traits.h
@@ -64,6 +64,9 @@ // // // Returning false results in deserialization failure and causes the // // message pipe receiving it to be disconnected. +// // Note that mojo does not require that Resize preserve the original +// // elements in `input` it merely has to set the size of `input` to +// // `size`. // static bool Resize(Container<T>& input, size_t size); // }; //
diff --git a/mojo/public/cpp/bindings/array_traits_stl.h b/mojo/public/cpp/bindings/array_traits_stl.h index b9b65ff4..9ee8b8d6 100644 --- a/mojo/public/cpp/bindings/array_traits_stl.h +++ b/mojo/public/cpp/bindings/array_traits_stl.h
@@ -8,12 +8,14 @@ #include <array> #include <map> #include <set> +#include <type_traits> #include <unordered_set> #include <vector> #include "base/containers/flat_set.h" #include "base/memory/raw_ptr_exclusion.h" #include "mojo/public/cpp/bindings/array_traits.h" +#include "mojo/public/cpp/bindings/lib/default_construct_tag_internal.h" namespace mojo { @@ -72,16 +74,18 @@ } static inline bool Resize(std::vector<T>& input, size_t size) { - // Instead of calling std::vector<T>::resize() directly, this is a hack to - // make compilers happy. Some compilers (e.g., Mac, Android, Linux MSan) - // currently don't allow resizing types like - // std::vector<std::vector<MoveOnlyType>>. - // Because the deserialization code doesn't care about the original contents - // of |input|, we discard them directly. - // - // The "inline" keyword of this method matters. Without it, we have observed - // significant perf regression with some tests on Mac. crbug.com/631415 - if (input.size() != size) { + if (input.size() == size) { + return true; + } + + if constexpr (std::is_constructible_v<T, ::mojo::DefaultConstruct::Tag>) { + std::vector<T> temp; + temp.reserve(size); + for (size_t i = 0; i < size; ++i) { + temp.emplace_back(internal::DefaultConstructTag()); + } + input.swap(temp); + } else { std::vector<T> temp(size); input.swap(temp); }
diff --git a/mojo/public/cpp/bindings/array_traits_web_vector.h b/mojo/public/cpp/bindings/array_traits_web_vector.h index cbb020f..de01b83 100644 --- a/mojo/public/cpp/bindings/array_traits_web_vector.h +++ b/mojo/public/cpp/bindings/array_traits_web_vector.h
@@ -5,6 +5,8 @@ #ifndef MOJO_PUBLIC_CPP_BINDINGS_ARRAY_TRAITS_WEB_VECTOR_H_ #define MOJO_PUBLIC_CPP_BINDINGS_ARRAY_TRAITS_WEB_VECTOR_H_ +#include <algorithm> + #include "mojo/public/cpp/bindings/array_traits.h" #include "third_party/blink/public/platform/web_vector.h" @@ -43,10 +45,9 @@ } static bool Resize(blink::WebVector<U>& input, size_t size) { - // WebVector DCHECKs if the new size is larger than capacity(). Call - // reserve() first to be safe. - input.reserve(size); - input.resize(size); + blink::WebVector<U> temp(size); + using std::swap; + swap(input, temp); return true; } };
diff --git a/mojo/public/cpp/bindings/array_traits_wtf_vector.h b/mojo/public/cpp/bindings/array_traits_wtf_vector.h index 16461e88..a64f124b 100644 --- a/mojo/public/cpp/bindings/array_traits_wtf_vector.h +++ b/mojo/public/cpp/bindings/array_traits_wtf_vector.h
@@ -48,7 +48,8 @@ static bool Resize(WTF::Vector<U, InlineCapacity>& input, size_t size) { if (!base::IsValueInRangeForNumericType<wtf_size_t>(size)) return false; - input.resize(static_cast<wtf_size_t>(size)); + WTF::Vector<U, InlineCapacity> temp(static_cast<wtf_size_t>(size)); + input.swap(temp); return true; } };
diff --git a/mojo/public/cpp/bindings/tests/default_construct_unittest.cc b/mojo/public/cpp/bindings/tests/default_construct_unittest.cc index 90d8859..c33f1884 100644 --- a/mojo/public/cpp/bindings/tests/default_construct_unittest.cc +++ b/mojo/public/cpp/bindings/tests/default_construct_unittest.cc
@@ -24,6 +24,25 @@ std::move(callback).Run(in); } + void TestMethodWithMap(const base::flat_map<uint8_t, TestStruct>& in, + uint8_t idx, + TestMethodWithMapCallback callback) override { + std::move(callback).Run(in.at(idx)); + } + + void TestMethodWithArray(const std::vector<TestStruct>& in, + uint8_t idx, + TestMethodWithArrayCallback callback) override { + std::move(callback).Run(in.at(idx)); + } + + void TestMethodWithFixedArray( + const std::vector<TestStruct>& in, + uint8_t idx, + TestMethodWithFixedArrayCallback callback) override { + std::move(callback).Run(in.at(idx)); + } + private: mojo::Receiver<mojom::TestInterface> receiver_; }; @@ -46,6 +65,54 @@ run_loop.Run(); } +TEST_F(DefaultConstructTest, Map) { + mojo::Remote<mojom::TestInterface> remote; + TestInterface instance(remote.BindNewPipeAndPassReceiver()); + + base::RunLoop run_loop; + base::flat_map<uint8_t, TestStruct> test_map = {{1u, TestStruct(42)}}; + + remote->TestMethodWithMap( + std::move(test_map), 1u, + base::BindLambdaForTesting([&](const TestStruct& out) { + EXPECT_EQ(out.value(), 42); + run_loop.Quit(); + })); + run_loop.Run(); +} + +TEST_F(DefaultConstructTest, Array) { + mojo::Remote<mojom::TestInterface> remote; + TestInterface instance(remote.BindNewPipeAndPassReceiver()); + + base::RunLoop run_loop; + std::vector<TestStruct> test_vec = {TestStruct(42), TestStruct(43)}; + + remote->TestMethodWithArray( + std::move(test_vec), 1u, + base::BindLambdaForTesting([&](const TestStruct& out) { + EXPECT_EQ(out.value(), 43); + run_loop.Quit(); + })); + run_loop.Run(); +} + +TEST_F(DefaultConstructTest, FixedArray) { + mojo::Remote<mojom::TestInterface> remote; + TestInterface instance(remote.BindNewPipeAndPassReceiver()); + + base::RunLoop run_loop; + std::vector<TestStruct> test_vec = {TestStruct(42), TestStruct(43)}; + + remote->TestMethodWithFixedArray( + std::move(test_vec), 0u, + base::BindLambdaForTesting([&](const TestStruct& out) { + EXPECT_EQ(out.value(), 42); + run_loop.Quit(); + })); + run_loop.Run(); +} + // Ensures that a non-typemapped type with a field typemapped to a type without // a public default constructor initializes that field using // `mojo::internal::DefaultConstructTraits::Create()` (crbug.com/1385587). Note
diff --git a/mojo/public/cpp/bindings/tests/default_construct_unittest.test-mojom b/mojo/public/cpp/bindings/tests/default_construct_unittest.test-mojom index cbc49df5..0677f73 100644 --- a/mojo/public/cpp/bindings/tests/default_construct_unittest.test-mojom +++ b/mojo/public/cpp/bindings/tests/default_construct_unittest.test-mojom
@@ -16,4 +16,10 @@ interface TestInterface { TestMethod(TestStruct in) => (TestStruct out); + + TestMethodWithMap(map<uint8, TestStruct> in, uint8 idx) => (TestStruct out); + + TestMethodWithArray(array<TestStruct> in, uint8 idx) => (TestStruct out); + + TestMethodWithFixedArray(array<TestStruct, 2> in, uint8 idx) => (TestStruct out); };
diff --git a/net/cert/caching_cert_verifier.cc b/net/cert/caching_cert_verifier.cc index 181288d..67e95c70 100644 --- a/net/cert/caching_cert_verifier.cc +++ b/net/cert/caching_cert_verifier.cc
@@ -24,11 +24,13 @@ CachingCertVerifier::CachingCertVerifier(std::unique_ptr<CertVerifier> verifier) : verifier_(std::move(verifier)), cache_(kMaxCacheEntries) { + verifier_->AddObserver(this); CertDatabase::GetInstance()->AddObserver(this); } CachingCertVerifier::~CachingCertVerifier() { CertDatabase::GetInstance()->RemoveObserver(this); + verifier_->RemoveObserver(this); } int CachingCertVerifier::Verify(const CertVerifier::RequestParams& params, @@ -68,6 +70,14 @@ ClearCache(); } +void CachingCertVerifier::AddObserver(CertVerifier::Observer* observer) { + verifier_->AddObserver(observer); +} + +void CachingCertVerifier::RemoveObserver(CertVerifier::Observer* observer) { + verifier_->RemoveObserver(observer); +} + CachingCertVerifier::CachedResult::CachedResult() = default; CachingCertVerifier::CachedResult::~CachedResult() = default; @@ -169,6 +179,11 @@ CacheValidityPeriod(start_time, start_time + base::Seconds(kTTLSecs))); } +void CachingCertVerifier::OnCertVerifierChanged() { + config_id_++; + ClearCache(); +} + void CachingCertVerifier::OnCertDBChanged() { config_id_++; ClearCache();
diff --git a/net/cert/caching_cert_verifier.h b/net/cert/caching_cert_verifier.h index aab0b2c..4078af6e 100644 --- a/net/cert/caching_cert_verifier.h +++ b/net/cert/caching_cert_verifier.h
@@ -35,6 +35,7 @@ // above for meaningful changes and the practical utility of being able to // cache results when they're not expected to change. class NET_EXPORT CachingCertVerifier : public CertVerifier, + public CertVerifier::Observer, public CertDatabase::Observer { public: // Creates a CachingCertVerifier that will use |verifier| to perform the @@ -54,13 +55,17 @@ std::unique_ptr<Request>* out_req, const NetLogWithSource& net_log) override; void SetConfig(const Config& config) override; + void AddObserver(CertVerifier::Observer* observer) override; + void RemoveObserver(CertVerifier::Observer* observer) override; private: FRIEND_TEST_ALL_PREFIXES(CachingCertVerifierTest, CacheHit); FRIEND_TEST_ALL_PREFIXES(CachingCertVerifierTest, CacheHitCTResultsCached); - FRIEND_TEST_ALL_PREFIXES(CachingCertVerifierTest, Visitor); - FRIEND_TEST_ALL_PREFIXES(CachingCertVerifierTest, AddsEntries); FRIEND_TEST_ALL_PREFIXES(CachingCertVerifierTest, DifferentCACerts); + FRIEND_TEST_ALL_PREFIXES(CachingCertVerifierCacheClearingTest, + CacheClearedSyncVerification); + FRIEND_TEST_ALL_PREFIXES(CachingCertVerifierCacheClearingTest, + CacheClearedAsyncVerification); // CachedResult contains the result of a certificate verification. struct NET_EXPORT_PRIVATE CachedResult { @@ -118,6 +123,9 @@ const CertVerifyResult& verify_result, int error); + // CertVerifier::Observer methods: + void OnCertVerifierChanged() override; + // CertDatabase::Observer methods: void OnCertDBChanged() override;
diff --git a/net/cert/caching_cert_verifier_unittest.cc b/net/cert/caching_cert_verifier_unittest.cc index 81cd7aa..8331be4a 100644 --- a/net/cert/caching_cert_verifier_unittest.cc +++ b/net/cert/caching_cert_verifier_unittest.cc
@@ -4,10 +4,14 @@ #include "net/cert/caching_cert_verifier.h" +#include <memory> + #include "base/files/file_path.h" #include "base/memory/ref_counted.h" +#include "base/test/task_environment.h" #include "net/base/net_errors.h" #include "net/base/test_completion_callback.h" +#include "net/cert/cert_database.h" #include "net/cert/cert_verifier.h" #include "net/cert/cert_verify_result.h" #include "net/cert/mock_cert_verifier.h" @@ -189,4 +193,166 @@ ASSERT_EQ(2u, verifier_.GetCacheSize()); } +TEST_F(CachingCertVerifierTest, ObserverIsForwarded) { + auto mock_cert_verifier = std::make_unique<MockCertVerifier>(); + MockCertVerifier* mock_cert_verifier_ptr = mock_cert_verifier.get(); + CachingCertVerifier cache_verifier(std::move(mock_cert_verifier)); + + CertVerifierObserverCounter observer_(&cache_verifier); + EXPECT_EQ(observer_.change_count(), 0u); + // A CertVerifierChanged event on the wrapped verifier should be forwarded to + // observers registered on CachingCertVerifier. + mock_cert_verifier_ptr->SimulateOnCertVerifierChanged(); + EXPECT_EQ(observer_.change_count(), 1u); +} + +namespace { +enum class ChangeType { + kSetConfig, + kCertVerifierChanged, + kCertDBChanged, +}; +} // namespace + +class CachingCertVerifierCacheClearingTest + : public testing::TestWithParam<ChangeType> { + public: + CachingCertVerifierCacheClearingTest() { + auto mock_cert_verifier = std::make_unique<MockCertVerifier>(); + mock_verifier_ = mock_cert_verifier.get(); + verifier_ = + std::make_unique<CachingCertVerifier>(std::move(mock_cert_verifier)); + } + + ChangeType change_type() const { return GetParam(); } + + void DoCacheClearingAction() { + switch (change_type()) { + case ChangeType::kSetConfig: + verifier_->SetConfig({}); + break; + case ChangeType::kCertVerifierChanged: + mock_verifier_->SimulateOnCertVerifierChanged(); + break; + case ChangeType::kCertDBChanged: + CertDatabase::GetInstance()->NotifyObserversCertDBChanged(); + base::RunLoop().RunUntilIdle(); + break; + } + } + + protected: + base::test::SingleThreadTaskEnvironment task_environment_; + std::unique_ptr<CachingCertVerifier> verifier_; + raw_ptr<MockCertVerifier> mock_verifier_; +}; + +TEST_P(CachingCertVerifierCacheClearingTest, CacheClearedSyncVerification) { + base::FilePath certs_dir = GetTestCertsDirectory(); + scoped_refptr<X509Certificate> test_cert( + ImportCertFromFile(certs_dir, "ok_cert.pem")); + ASSERT_TRUE(test_cert.get()); + + mock_verifier_->set_async(false); + + int error; + CertVerifyResult verify_result; + TestCompletionCallback callback; + std::unique_ptr<CertVerifier::Request> request; + + error = verifier_->Verify( + CertVerifier::RequestParams(test_cert, "www.example.com", 0, + /*ocsp_response=*/std::string(), + /*sct_list=*/std::string()), + &verify_result, callback.callback(), &request, NetLogWithSource()); + ASSERT_TRUE(IsCertificateError(error)); + ASSERT_EQ(1u, verifier_->requests()); + ASSERT_EQ(0u, verifier_->cache_hits()); + ASSERT_EQ(1u, verifier_->GetCacheSize()); + + DoCacheClearingAction(); + ASSERT_EQ(0u, verifier_->GetCacheSize()); + + error = verifier_->Verify( + CertVerifier::RequestParams(test_cert, "www.example.com", 0, + /*ocsp_response=*/std::string(), + /*sct_list=*/std::string()), + &verify_result, callback.callback(), &request, NetLogWithSource()); + ASSERT_TRUE(IsCertificateError(error)); + ASSERT_FALSE(request); + ASSERT_EQ(2u, verifier_->requests()); + ASSERT_EQ(0u, verifier_->cache_hits()); + ASSERT_EQ(1u, verifier_->GetCacheSize()); +} + +TEST_P(CachingCertVerifierCacheClearingTest, CacheClearedAsyncVerification) { + base::FilePath certs_dir = GetTestCertsDirectory(); + scoped_refptr<X509Certificate> test_cert( + ImportCertFromFile(certs_dir, "ok_cert.pem")); + ASSERT_TRUE(test_cert.get()); + + mock_verifier_->set_async(true); + + int error; + CertVerifyResult verify_result; + TestCompletionCallback callback; + std::unique_ptr<CertVerifier::Request> request; + + error = verifier_->Verify( + CertVerifier::RequestParams(test_cert, "www.example.com", 0, + /*ocsp_response=*/std::string(), + /*sct_list=*/std::string()), + &verify_result, callback.callback(), &request, NetLogWithSource()); + ASSERT_EQ(ERR_IO_PENDING, error); + ASSERT_TRUE(request); + ASSERT_EQ(1u, verifier_->requests()); + ASSERT_EQ(0u, verifier_->cache_hits()); + ASSERT_EQ(0u, verifier_->GetCacheSize()); + + DoCacheClearingAction(); + ASSERT_EQ(0u, verifier_->GetCacheSize()); + + error = callback.WaitForResult(); + ASSERT_TRUE(IsCertificateError(error)); + // Async result should not have been cached since it was from a verification + // started before the config changed. + ASSERT_EQ(0u, verifier_->GetCacheSize()); + + error = verifier_->Verify( + CertVerifier::RequestParams(test_cert, "www.example.com", 0, + /*ocsp_response=*/std::string(), + /*sct_list=*/std::string()), + &verify_result, callback.callback(), &request, NetLogWithSource()); + ASSERT_EQ(ERR_IO_PENDING, error); + ASSERT_TRUE(request); + ASSERT_EQ(2u, verifier_->requests()); + ASSERT_EQ(0u, verifier_->cache_hits()); + ASSERT_EQ(0u, verifier_->GetCacheSize()); + + error = callback.WaitForResult(); + ASSERT_TRUE(IsCertificateError(error)); + // New async result should be cached since it was from a verification started + // after the config changed. + ASSERT_EQ(1u, verifier_->GetCacheSize()); + + // Verify again. Result should be synchronous this time since it will get the + // cached result. + error = verifier_->Verify( + CertVerifier::RequestParams(test_cert, "www.example.com", 0, + /*ocsp_response=*/std::string(), + /*sct_list=*/std::string()), + &verify_result, callback.callback(), &request, NetLogWithSource()); + ASSERT_TRUE(IsCertificateError(error)); + ASSERT_FALSE(request); + ASSERT_EQ(3u, verifier_->requests()); + ASSERT_EQ(1u, verifier_->cache_hits()); + ASSERT_EQ(1u, verifier_->GetCacheSize()); +} + +INSTANTIATE_TEST_SUITE_P(All, + CachingCertVerifierCacheClearingTest, + testing::Values(ChangeType::kSetConfig, + ChangeType::kCertVerifierChanged, + ChangeType::kCertDBChanged)); + } // namespace net
diff --git a/net/cert/cert_and_ct_verifier.cc b/net/cert/cert_and_ct_verifier.cc index 8be4131..7957fe0 100644 --- a/net/cert/cert_and_ct_verifier.cc +++ b/net/cert/cert_and_ct_verifier.cc
@@ -54,6 +54,14 @@ cert_verifier_->SetConfig(config); } +void CertAndCTVerifier::AddObserver(Observer* observer) { + cert_verifier_->AddObserver(observer); +} + +void CertAndCTVerifier::RemoveObserver(Observer* observer) { + cert_verifier_->RemoveObserver(observer); +} + void CertAndCTVerifier::OnCertVerifyComplete(const RequestParams& params, CompletionOnceCallback callback, CertVerifyResult* verify_result,
diff --git a/net/cert/cert_and_ct_verifier.h b/net/cert/cert_and_ct_verifier.h index 4308e20..42890cf 100644 --- a/net/cert/cert_and_ct_verifier.h +++ b/net/cert/cert_and_ct_verifier.h
@@ -37,6 +37,8 @@ std::unique_ptr<Request>* out_req, const NetLogWithSource& net_log) override; void SetConfig(const Config& config) override; + void AddObserver(Observer* observer) override; + void RemoveObserver(Observer* observer) override; private: void OnCertVerifyComplete(const RequestParams& params,
diff --git a/net/cert/cert_and_ct_verifier_unittest.cc b/net/cert/cert_and_ct_verifier_unittest.cc index ddb4387..b796f05 100644 --- a/net/cert/cert_and_ct_verifier_unittest.cc +++ b/net/cert/cert_and_ct_verifier_unittest.cc
@@ -342,4 +342,19 @@ ASSERT_EQ(0u, verify_result.scts.size()); } +TEST_F(CertAndCTVerifierTest, ObserverIsForwarded) { + auto mock_cert_verifier_owner = std::make_unique<MockCertVerifier>(); + MockCertVerifier* mock_cert_verifier = mock_cert_verifier_owner.get(); + + CertAndCTVerifier cert_and_ct_verifier(std::move(mock_cert_verifier_owner), + std::make_unique<FakeCTVerifier>()); + + CertVerifierObserverCounter observer(&cert_and_ct_verifier); + EXPECT_EQ(observer.change_count(), 0u); + // A CertVerifierChanged event on the wrapped verifier should be forwarded to + // observers registered on CertAndCTVerifier. + mock_cert_verifier->SimulateOnCertVerifierChanged(); + EXPECT_EQ(observer.change_count(), 1u); +} + } // namespace net
diff --git a/net/cert/cert_verifier.h b/net/cert/cert_verifier.h index 7fcd661..1bb43f2 100644 --- a/net/cert/cert_verifier.h +++ b/net/cert/cert_verifier.h
@@ -10,6 +10,7 @@ #include <vector> #include "base/memory/scoped_refptr.h" +#include "base/observer_list_types.h" #include "base/strings/string_piece.h" #include "net/base/completion_once_callback.h" #include "net/base/hash_value.h" @@ -29,6 +30,19 @@ // CertVerifiers can handle multiple requests at a time. class NET_EXPORT CertVerifier { public: + class NET_EXPORT Observer : public base::CheckedObserver { + public: + // Called when the certificate verifier changes internal configuration. + // Observers can use this method to invalidate caches that incorporate + // previous trust decisions. + // + // This method will not be called on `CertVerifier::SetConfig`. It is + // assumed that callers will know to clear their caches when calling the + // function. https://crbug.com/1427326 tracks migrating `SetConfig` to this + // mechanism. + virtual void OnCertVerifierChanged() = 0; + }; + struct NET_EXPORT Config { Config(); Config(const Config&); @@ -200,6 +214,13 @@ // explicitly manage. virtual void SetConfig(const Config& config) = 0; + // Add an observer to be notified when the CertVerifier has changed. + // RemoveObserver() must be called before |observer| is destroyed. + virtual void AddObserver(Observer* observer) = 0; + + // Remove an observer added with AddObserver(). + virtual void RemoveObserver(Observer* observer) = 0; + // Creates a CertVerifier implementation that verifies certificates using // the preferred underlying cryptographic libraries. |cert_net_fetcher| may // not be used, depending on the platform.
diff --git a/net/cert/coalescing_cert_verifier.cc b/net/cert/coalescing_cert_verifier.cc index 8fb4d3e..ef3622bab 100644 --- a/net/cert/coalescing_cert_verifier.cc +++ b/net/cert/coalescing_cert_verifier.cc
@@ -380,9 +380,13 @@ CoalescingCertVerifier::CoalescingCertVerifier( std::unique_ptr<CertVerifier> verifier) - : verifier_(std::move(verifier)) {} + : verifier_(std::move(verifier)) { + verifier_->AddObserver(this); +} -CoalescingCertVerifier::~CoalescingCertVerifier() = default; +CoalescingCertVerifier::~CoalescingCertVerifier() { + verifier_->RemoveObserver(this); +} int CoalescingCertVerifier::Verify( const RequestParams& params, @@ -424,13 +428,17 @@ } void CoalescingCertVerifier::SetConfig(const CertVerifier::Config& config) { - ++config_id_; verifier_->SetConfig(config); - for (auto& job : joinable_jobs_) { - inflight_jobs_.emplace_back(std::move(job.second)); - } - joinable_jobs_.clear(); + IncrementGenerationAndMakeCurrentJobsUnjoinable(); +} + +void CoalescingCertVerifier::AddObserver(Observer* observer) { + verifier_->AddObserver(observer); +} + +void CoalescingCertVerifier::RemoveObserver(Observer* observer) { + verifier_->RemoveObserver(observer); } CoalescingCertVerifier::Job* CoalescingCertVerifier::FindJob( @@ -459,4 +467,15 @@ return; } +void CoalescingCertVerifier::IncrementGenerationAndMakeCurrentJobsUnjoinable() { + for (auto& job : joinable_jobs_) { + inflight_jobs_.emplace_back(std::move(job.second)); + } + joinable_jobs_.clear(); +} + +void CoalescingCertVerifier::OnCertVerifierChanged() { + IncrementGenerationAndMakeCurrentJobsUnjoinable(); +} + } // namespace net
diff --git a/net/cert/coalescing_cert_verifier.h b/net/cert/coalescing_cert_verifier.h index 2135e69..aa8a7fb 100644 --- a/net/cert/coalescing_cert_verifier.h +++ b/net/cert/coalescing_cert_verifier.h
@@ -27,7 +27,8 @@ // complete, but any new requests will not be seen as matching, even if they // share the same parameters. This ensures configuration changes propagate // "immediately" for all new requests. -class NET_EXPORT CoalescingCertVerifier : public CertVerifier { +class NET_EXPORT CoalescingCertVerifier : public CertVerifier, + public CertVerifier::Observer { public: // Create a new verifier that will forward calls to |verifier|, coalescing // any in-flight, not-yet-completed calls to Verify(). @@ -45,6 +46,8 @@ std::unique_ptr<CertVerifier::Request>* out_req, const NetLogWithSource& net_log) override; void SetConfig(const CertVerifier::Config& config) override; + void AddObserver(Observer* observer) override; + void RemoveObserver(Observer* observer) override; uint64_t requests_for_testing() const { return requests_; } uint64_t inflight_joins_for_testing() const { return inflight_joins_; } @@ -58,6 +61,10 @@ // Otherwise, returns nullptr, meaning a new Job should be started. Job* FindJob(const RequestParams& params); void RemoveJob(Job* job); + void IncrementGenerationAndMakeCurrentJobsUnjoinable(); + + // CertVerifier::Observer methods: + void OnCertVerifierChanged() override; // Contains the set of Jobs for which an active verification is taking // place and which can be used for new requests (e.g. the config is the @@ -70,7 +77,6 @@ std::unique_ptr<CertVerifier> verifier_; - uint32_t config_id_ = 0; uint64_t requests_ = 0; uint64_t inflight_joins_ = 0; };
diff --git a/net/cert/coalescing_cert_verifier_unittest.cc b/net/cert/coalescing_cert_verifier_unittest.cc index cd72ff6..fc3a9c9 100644 --- a/net/cert/coalescing_cert_verifier_unittest.cc +++ b/net/cert/coalescing_cert_verifier_unittest.cc
@@ -187,6 +187,84 @@ histograms.ExpectTotalCount("Net.CertVerifier_First_Job_Latency", 1); } +// Test that the underlying CertVerifier changing configurations and triggering +// an OnCertVerifierChanged notification between Requests prevents the second +// Request from being attached to the first Request. There should be two +// Requests to the underlying CertVerifier, and the correct results should be +// received by each. +TEST_F(CoalescingCertVerifierTest, DoesNotJoinAfterUnderlyingVerifierChange) { + scoped_refptr<X509Certificate> test_cert( + ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem")); + ASSERT_TRUE(test_cert); + + base::HistogramTester histograms; + + CertVerifyResult fake_result; + fake_result.verified_cert = test_cert; + + std::unique_ptr<MockCertVerifier> mock_verifier_owner = + std::make_unique<MockCertVerifier>(); + MockCertVerifier* mock_verifier = mock_verifier_owner.get(); + mock_verifier->set_async(true); // Always complete via PostTask + mock_verifier->AddResultForCert(test_cert, fake_result, OK); + + CoalescingCertVerifier verifier(std::move(mock_verifier_owner)); + + mock_verifier->SimulateOnCertVerifierChanged(); + + CertVerifier::RequestParams request_params(test_cert, "www.example.com", 0, + /*ocsp_response=*/std::string(), + /*sct_list=*/std::string()); + + CertVerifyResult result1, result2; + TestCompletionCallback callback1, callback2; + std::unique_ptr<CertVerifier::Request> request1, request2; + + // Start an (asynchronous) initial request. + int error = verifier.Verify(request_params, &result1, callback1.callback(), + &request1, NetLogWithSource()); + ASSERT_THAT(error, IsError(ERR_IO_PENDING)); + EXPECT_TRUE(request1); + + // Change the configuration, and change the result to to simulate the + // configuration change affecting behavior. + mock_verifier->SimulateOnCertVerifierChanged(); + mock_verifier->ClearRules(); + mock_verifier->AddResultForCert(test_cert, fake_result, ERR_CERT_REVOKED); + + // Start a second request; this should not join the first request, as the + // config is different. + error = verifier.Verify(request_params, &result2, callback2.callback(), + &request2, NetLogWithSource()); + ASSERT_THAT(error, IsError(ERR_IO_PENDING)); + EXPECT_TRUE(request2); + + // Ensure a total of two requests were started, and neither were joined. + EXPECT_EQ(2u, verifier.requests_for_testing()); + EXPECT_EQ(0u, verifier.inflight_joins_for_testing()); + + // Make sure both results completed. + EXPECT_THAT(callback1.WaitForResult(), IsOk()); + EXPECT_THAT(callback2.WaitForResult(), IsError(ERR_CERT_REVOKED)); + + // There should have been two separate Jobs. + histograms.ExpectTotalCount("Net.CertVerifier_Job_Latency", 2); + histograms.ExpectTotalCount("Net.CertVerifier_First_Job_Latency", 1); +} + +TEST_F(CoalescingCertVerifierTest, ObserverIsForwarded) { + auto mock_cert_verifier_owner = std::make_unique<MockCertVerifier>(); + MockCertVerifier* mock_cert_verifier = mock_cert_verifier_owner.get(); + CoalescingCertVerifier verifier(std::move(mock_cert_verifier_owner)); + + CertVerifierObserverCounter observer_(&verifier); + EXPECT_EQ(observer_.change_count(), 0u); + // A CertVerifierChanged event on the wrapped verifier should be forwarded to + // observers registered on CoalescingCertVerifier. + mock_cert_verifier->SimulateOnCertVerifierChanged(); + EXPECT_EQ(observer_.change_count(), 1u); +} + // Test that when two Requests are attached to the same Job, it's safe to // delete the second Request while processing the response to the first. The // second Request should not cause the second callback to be called.
diff --git a/net/cert/mock_cert_verifier.cc b/net/cert/mock_cert_verifier.cc index 8bd3a5a..a908602 100644 --- a/net/cert/mock_cert_verifier.cc +++ b/net/cert/mock_cert_verifier.cc
@@ -107,6 +107,14 @@ return ERR_IO_PENDING; } +void MockCertVerifier::AddObserver(Observer* observer) { + observers_.AddObserver(observer); +} + +void MockCertVerifier::RemoveObserver(Observer* observer) { + observers_.RemoveObserver(observer); +} + void MockCertVerifier::AddResultForCert(scoped_refptr<X509Certificate> cert, const CertVerifyResult& verify_result, int rv) { @@ -125,6 +133,12 @@ rules_.clear(); } +void MockCertVerifier::SimulateOnCertVerifierChanged() { + for (Observer& observer : observers_) { + observer.OnCertVerifierChanged(); + } +} + int MockCertVerifier::VerifyImpl(const RequestParams& params, CertVerifyResult* verify_result) { for (const Rule& rule : rules_) { @@ -143,4 +157,15 @@ return default_result_; } +CertVerifierObserverCounter::CertVerifierObserverCounter( + CertVerifier* verifier) { + obs_.Observe(verifier); +} + +CertVerifierObserverCounter::~CertVerifierObserverCounter() = default; + +void CertVerifierObserverCounter::OnCertVerifierChanged() { + change_count_++; +} + } // namespace net
diff --git a/net/cert/mock_cert_verifier.h b/net/cert/mock_cert_verifier.h index 84e15a19..5f7ce90 100644 --- a/net/cert/mock_cert_verifier.h +++ b/net/cert/mock_cert_verifier.h
@@ -9,6 +9,8 @@ #include <memory> #include "base/callback_list.h" +#include "base/observer_list.h" +#include "base/scoped_observation.h" #include "net/base/completion_once_callback.h" #include "net/cert/cert_verifier.h" #include "net/cert/cert_verify_result.h" @@ -34,6 +36,8 @@ std::unique_ptr<Request>* out_req, const NetLogWithSource& net_log) override; void SetConfig(const Config& config) override {} + void AddObserver(Observer* observer) override; + void RemoveObserver(Observer* observer) override; // Sets the default return value for Verify() for certificates/hosts that do // not have explicit results added via the AddResult*() methods. @@ -62,6 +66,9 @@ // Clear all existing rules. void ClearRules(); + // Notify any registered observers of an OnCertVerifierChanged event. + void SimulateOnCertVerifierChanged(); + private: struct Rule; using RuleList = std::list<Rule>; @@ -75,6 +82,23 @@ bool async_ = false; base::OnceClosureList request_list_; + base::ObserverList<Observer> observers_; +}; + +class CertVerifierObserverCounter : public CertVerifier::Observer { + public: + explicit CertVerifierObserverCounter(CertVerifier* verifier); + ~CertVerifierObserverCounter() override; + + // CertVerifier::Observer implementation: + void OnCertVerifierChanged() override; + + unsigned change_count() const { return change_count_; } + + private: + base::ScopedObservation<CertVerifier, CertVerifier::Observer> obs_{this}; + + unsigned change_count_ = 0; }; } // namespace net
diff --git a/net/cert/multi_threaded_cert_verifier.cc b/net/cert/multi_threaded_cert_verifier.cc index dd02ec0..6270a17c9 100644 --- a/net/cert/multi_threaded_cert_verifier.cc +++ b/net/cert/multi_threaded_cert_verifier.cc
@@ -244,6 +244,7 @@ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); verify_proc_ = verify_proc_factory_->CreateCertVerifyProc( std::move(cert_net_fetcher), root_store_data); + NotifyCertVerifierChanged(); } void MultiThreadedCertVerifier::SetConfig(const CertVerifier::Config& config) { @@ -286,4 +287,21 @@ config_.crl_set = CRLSet::BuiltinCRLSet(); } +void MultiThreadedCertVerifier::AddObserver(Observer* observer) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + observers_.AddObserver(observer); +} + +void MultiThreadedCertVerifier::RemoveObserver(Observer* observer) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + observers_.RemoveObserver(observer); +} + +void MultiThreadedCertVerifier::NotifyCertVerifierChanged() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + for (Observer& observer : observers_) { + observer.OnCertVerifierChanged(); + } +} + } // namespace net
diff --git a/net/cert/multi_threaded_cert_verifier.h b/net/cert/multi_threaded_cert_verifier.h index 642f4ad..382c236 100644 --- a/net/cert/multi_threaded_cert_verifier.h +++ b/net/cert/multi_threaded_cert_verifier.h
@@ -13,6 +13,7 @@ #include "base/containers/linked_list.h" #include "base/memory/scoped_refptr.h" +#include "base/observer_list.h" #include "base/threading/thread_checker.h" #include "crypto/crypto_buildflags.h" #include "net/base/net_export.h" @@ -53,6 +54,8 @@ std::unique_ptr<Request>* out_req, const NetLogWithSource& net_log) override; void SetConfig(const CertVerifier::Config& config) override; + void AddObserver(Observer* observer) override; + void RemoveObserver(Observer* observer) override; void UpdateChromeRootStoreData( scoped_refptr<CertNetFetcher> cert_net_fetcher, const ChromeRootStoreData* root_store_data) override; @@ -60,6 +63,10 @@ private: class InternalRequest; + // Notify the |observers_| of an OnCertVerifierChanged event. + void NotifyCertVerifierChanged(); + + base::ObserverList<Observer> observers_; Config config_; scoped_refptr<CertVerifyProc> verify_proc_; scoped_refptr<CertVerifyProcFactory> verify_proc_factory_;
diff --git a/net/cert/multi_threaded_cert_verifier_unittest.cc b/net/cert/multi_threaded_cert_verifier_unittest.cc index 3a7351d..7d4a97a 100644 --- a/net/cert/multi_threaded_cert_verifier_unittest.cc +++ b/net/cert/multi_threaded_cert_verifier_unittest.cc
@@ -14,6 +14,7 @@ #include "net/base/test_completion_callback.h" #include "net/cert/cert_verify_proc.h" #include "net/cert/cert_verify_result.h" +#include "net/cert/mock_cert_verifier.h" #include "net/cert/x509_certificate.h" #include "net/log/net_log_with_source.h" #include "net/test/cert_test_util.h" @@ -299,16 +300,22 @@ // Tests swapping in new Chrome Root Store Data. TEST_F(MultiThreadedCertVerifierTest, VerifyProcChangeChromeRootStore) { + CertVerifierObserverCounter observer_counter(verifier_.get()); + base::FilePath certs_dir = GetTestCertsDirectory(); scoped_refptr<X509Certificate> test_cert( ImportCertFromFile(certs_dir, "ok_cert.pem")); ASSERT_TRUE(test_cert); + EXPECT_EQ(observer_counter.change_count(), 0u); + EXPECT_CALL(*mock_new_verify_proc_, VerifyInternal(_, _, _, _, _, _, _, _, _)) .WillRepeatedly( DoAll(SetCertVerifyRevokedResult(), Return(ERR_CERT_REVOKED))); verifier_->UpdateChromeRootStoreData(nullptr, nullptr); + EXPECT_EQ(observer_counter.change_count(), 1u); + CertVerifyResult verify_result; TestCompletionCallback callback; std::unique_ptr<CertVerifier::Request> request;
diff --git a/net/cert/trial_comparison_cert_verifier.cc b/net/cert/trial_comparison_cert_verifier.cc index 072c2ae9..33d67688 100644 --- a/net/cert/trial_comparison_cert_verifier.cc +++ b/net/cert/trial_comparison_cert_verifier.cc
@@ -481,9 +481,17 @@ primary_verify_proc_factory)), trial_verifier_(std::make_unique<MultiThreadedCertVerifier>( trial_verify_proc, - trial_verify_proc_factory)) {} + trial_verify_proc_factory)) { + primary_verifier_->AddObserver(this); + primary_reverifier_->AddObserver(this); + trial_verifier_->AddObserver(this); +} -TrialComparisonCertVerifier::~TrialComparisonCertVerifier() = default; +TrialComparisonCertVerifier::~TrialComparisonCertVerifier() { + primary_verifier_->RemoveObserver(this); + primary_reverifier_->RemoveObserver(this); + trial_verifier_->RemoveObserver(this); +} int TrialComparisonCertVerifier::Verify(const RequestParams& params, CertVerifyResult* verify_result, @@ -513,9 +521,21 @@ trial_verifier_->SetConfig(config); // Notify all in-process jobs that the underlying configuration has changed. - for (auto& job : jobs_) { - job->OnConfigChanged(); - } + NotifyJobsOfConfigChange(); +} + +void TrialComparisonCertVerifier::AddObserver( + CertVerifier::Observer* observer) { + // Let primary_verifier_ handle the observer lists rather than creating + // another one in TrialComparisonCertVerifier. From the perspective of the + // caller, the primary_verifier is the only one that it would care about + // changes to. + primary_verifier_->AddObserver(observer); +} + +void TrialComparisonCertVerifier::RemoveObserver( + CertVerifier::Observer* observer) { + primary_verifier_->RemoveObserver(observer); } void TrialComparisonCertVerifier::UpdateChromeRootStoreData( @@ -526,11 +546,10 @@ primary_reverifier_->UpdateChromeRootStoreData(cert_net_fetcher, root_store_data); trial_verifier_->UpdateChromeRootStoreData(cert_net_fetcher, root_store_data); - // Treat a possible proc change as a configuration change. Notify all - // in-process jobs that the underlying configuration has changed. - for (auto& job : jobs_) { - job->OnConfigChanged(); - } + // The TrialComparisonCertVerifier is registered as an observer of the + // underlying verifiers, and so the OnCertVerifierChanged method should be + // triggered to call NotifyJobsOfConfigChange, so it isn't explicitly called + // here. } void TrialComparisonCertVerifier::RemoveJob(Job* job_ptr) { @@ -541,4 +560,14 @@ jobs_.erase(it); } +void TrialComparisonCertVerifier::NotifyJobsOfConfigChange() { + for (auto& job : jobs_) { + job->OnConfigChanged(); + } +} + +void TrialComparisonCertVerifier::OnCertVerifierChanged() { + NotifyJobsOfConfigChange(); +} + } // namespace net
diff --git a/net/cert/trial_comparison_cert_verifier.h b/net/cert/trial_comparison_cert_verifier.h index 7bd5eb6..4a75052 100644 --- a/net/cert/trial_comparison_cert_verifier.h +++ b/net/cert/trial_comparison_cert_verifier.h
@@ -29,7 +29,8 @@ // back to the caller via a ReportCallback, allowing the caller to further // examine the differences. class NET_EXPORT TrialComparisonCertVerifier - : public CertVerifierWithUpdatableProc { + : public CertVerifierWithUpdatableProc, + public CertVerifier::Observer { public: using ReportCallback = base::RepeatingCallback<void( const std::string& hostname, @@ -88,6 +89,8 @@ std::unique_ptr<Request>* out_req, const NetLogWithSource& net_log) override; void SetConfig(const Config& config) override; + void AddObserver(Observer* observer) override; + void RemoveObserver(Observer* observer) override; void UpdateChromeRootStoreData( scoped_refptr<CertNetFetcher> cert_net_fetcher, const ChromeRootStoreData* root_store_data) override; @@ -101,6 +104,10 @@ CertVerifier* trial_verifier() const { return trial_verifier_.get(); } void RemoveJob(Job* job_ptr); + void NotifyJobsOfConfigChange(); + + // CertVerifier::Observer methods: + void OnCertVerifierChanged() override; // Whether the trial is allowed. bool allowed_ = false;
diff --git a/net/cert/trial_comparison_cert_verifier_unittest.cc b/net/cert/trial_comparison_cert_verifier_unittest.cc index afde301..b60f9b1f 100644 --- a/net/cert/trial_comparison_cert_verifier_unittest.cc +++ b/net/cert/trial_comparison_cert_verifier_unittest.cc
@@ -19,6 +19,7 @@ #include "net/cert/cert_verify_proc.h" #include "net/cert/cert_verify_result.h" #include "net/cert/ev_root_ca_metadata.h" +#include "net/cert/mock_cert_verifier.h" #include "net/cert/trial_comparison_cert_verifier_util.h" #include "net/cert/x509_certificate.h" #include "net/cert/x509_util.h" @@ -345,6 +346,21 @@ base::HistogramTester histograms_; }; +TEST_F(TrialComparisonCertVerifierTest, ObserverIsCalledOnCRSUpdate) { + std::vector<TrialReportInfo> reports; + TrialComparisonCertVerifier verifier( + base::MakeRefCounted<NotCalledCertVerifyProc>(), + SwapWithNotCalledProcFactory(), + base::MakeRefCounted<NotCalledCertVerifyProc>(), + SwapWithNotCalledProcFactory(), + base::BindRepeating(&RecordTrialReport, &reports)); + + CertVerifierObserverCounter observer_(&verifier); + EXPECT_EQ(observer_.change_count(), 0u); + verifier.UpdateChromeRootStoreData(nullptr, nullptr); + EXPECT_EQ(observer_.change_count(), 1u); +} + TEST_F(TrialComparisonCertVerifierTest, InitiallyDisallowed) { CertVerifyResult dummy_result; dummy_result.verified_cert = cert_chain_1_;
diff --git a/net/quic/crypto/proof_verifier_chromium_test.cc b/net/quic/crypto/proof_verifier_chromium_test.cc index 1065aa9..060b79c 100644 --- a/net/quic/crypto/proof_verifier_chromium_test.cc +++ b/net/quic/crypto/proof_verifier_chromium_test.cc
@@ -64,6 +64,8 @@ return ERR_FAILED; } void SetConfig(const Config& config) override {} + void AddObserver(Observer* observer) override {} + void RemoveObserver(Observer* observer) override {} }; // A mock CTPolicyEnforcer that returns a custom verification result.
diff --git a/net/socket/ssl_client_socket_unittest.cc b/net/socket/ssl_client_socket_unittest.cc index 8c83b35..bf31df8 100644 --- a/net/socket/ssl_client_socket_unittest.cc +++ b/net/socket/ssl_client_socket_unittest.cc
@@ -1368,6 +1368,8 @@ } void SetConfig(const Config& config) override {} + void AddObserver(Observer* observer) override {} + void RemoveObserver(Observer* observer) override {} private: class HangingRequest : public Request {
diff --git a/remoting/protocol/ssl_hmac_channel_authenticator.cc b/remoting/protocol/ssl_hmac_channel_authenticator.cc index 43ea4b7..5dc9a72 100644 --- a/remoting/protocol/ssl_hmac_channel_authenticator.cc +++ b/remoting/protocol/ssl_hmac_channel_authenticator.cc
@@ -85,6 +85,8 @@ return net::ERR_CERT_INVALID; } void SetConfig(const Config& config) override {} + void AddObserver(Observer* observer) override {} + void RemoveObserver(Observer* observer) override {} }; // Implements net::StreamSocket interface on top of P2PStreamSocket to be passed
diff --git a/services/cert_verifier/cert_verifier_service.cc b/services/cert_verifier/cert_verifier_service.cc index c592e530..6c94247 100644 --- a/services/cert_verifier/cert_verifier_service.cc +++ b/services/cert_verifier/cert_verifier_service.cc
@@ -82,15 +82,18 @@ CertVerifierServiceImpl::CertVerifierServiceImpl( std::unique_ptr<net::CertVerifierWithUpdatableProc> verifier, mojo::PendingReceiver<mojom::CertVerifierService> receiver, + mojo::PendingRemote<mojom::CertVerifierServiceClient> client, scoped_refptr<CertNetFetcherURLLoader> cert_net_fetcher) : verifier_(std::move(verifier)), receiver_(this, std::move(receiver)), + client_(std::move(client)), cert_net_fetcher_(std::move(cert_net_fetcher)) { // base::Unretained is safe because |this| owns |receiver_|, so deleting // |this| will prevent |receiver_| from calling this callback. receiver_.set_disconnect_handler( base::BindRepeating(&CertVerifierServiceImpl::OnDisconnectFromService, base::Unretained(this))); + verifier_->AddObserver(this); } // Note: this object owns the underlying CertVerifier, which owns all of the @@ -98,6 +101,7 @@ // mojo::Remote<CertVerifierRequest> objects, so destroying this object cancels // the verifications and all the callbacks. CertVerifierServiceImpl::~CertVerifierServiceImpl() { + verifier_->RemoveObserver(this); if (cert_net_fetcher_) cert_net_fetcher_->Shutdown(); } @@ -187,6 +191,10 @@ } } +void CertVerifierServiceImpl::OnCertVerifierChanged() { + client_->OnCertVerifierChanged(); +} + void CertVerifierServiceImpl::OnDisconnectFromService() { if (service_factory_impl_) { service_factory_impl_->RemoveService(this);
diff --git a/services/cert_verifier/cert_verifier_service.h b/services/cert_verifier/cert_verifier_service.h index 374b528..d372dd9 100644 --- a/services/cert_verifier/cert_verifier_service.h +++ b/services/cert_verifier/cert_verifier_service.h
@@ -34,11 +34,13 @@ namespace internal { // This class will delete itself upon disconnection of its Mojo receiver. -class CertVerifierServiceImpl : public mojom::CertVerifierService { +class CertVerifierServiceImpl : public mojom::CertVerifierService, + public net::CertVerifier::Observer { public: explicit CertVerifierServiceImpl( std::unique_ptr<net::CertVerifierWithUpdatableProc> verifier, mojo::PendingReceiver<mojom::CertVerifierService> receiver, + mojo::PendingRemote<mojom::CertVerifierServiceClient> client, scoped_refptr<CertNetFetcherURLLoader> cert_net_fetcher); // mojom::CertVerifierService implementation: @@ -67,10 +69,14 @@ private: ~CertVerifierServiceImpl() override; + // CertVerifier::Observer methods: + void OnCertVerifierChanged() override; + void OnDisconnectFromService(); std::unique_ptr<net::CertVerifierWithUpdatableProc> verifier_; mojo::Receiver<mojom::CertVerifierService> receiver_; + mojo::Remote<mojom::CertVerifierServiceClient> client_; scoped_refptr<CertNetFetcherURLLoader> cert_net_fetcher_; base::WeakPtr<cert_verifier::CertVerifierServiceFactoryImpl> service_factory_impl_;
diff --git a/services/cert_verifier/cert_verifier_service_factory.cc b/services/cert_verifier/cert_verifier_service_factory.cc index 35d3078..70df8ff 100644 --- a/services/cert_verifier/cert_verifier_service_factory.cc +++ b/services/cert_verifier/cert_verifier_service_factory.cc
@@ -7,6 +7,7 @@ #include <memory> #include "base/functional/bind.h" +#include "base/functional/callback_helpers.h" #include "base/logging.h" #include "base/memory/raw_ptr.h" #include "base/memory/scoped_refptr.h" @@ -42,6 +43,7 @@ internal::CertVerifierServiceImpl* GetNewCertVerifierImpl( mojom::CertVerifierServiceParams* impl_params, mojo::PendingReceiver<mojom::CertVerifierService> receiver, + mojo::PendingRemote<mojom::CertVerifierServiceClient> client, mojom::CertVerifierCreationParamsPtr creation_params, const net::ChromeRootStoreData* root_store_data, scoped_refptr<CertNetFetcherURLLoader>* out_cert_net_fetcher) { @@ -70,9 +72,9 @@ *out_cert_net_fetcher = cert_net_fetcher; // The service will delete itself upon disconnection. - return new internal::CertVerifierServiceImpl(std::move(cert_verifier), - std::move(receiver), - std::move(cert_net_fetcher)); + return new internal::CertVerifierServiceImpl( + std::move(cert_verifier), std::move(receiver), std::move(client), + std::move(cert_net_fetcher)); } #if BUILDFLAG(CHROME_ROOT_STORE_SUPPORTED) @@ -114,16 +116,17 @@ void CertVerifierServiceFactoryImpl::GetNewCertVerifier( mojo::PendingReceiver<mojom::CertVerifierService> receiver, + mojo::PendingRemote<mojom::CertVerifierServiceClient> client, mojom::CertVerifierCreationParamsPtr creation_params) { net::ChromeRootStoreData* root_store_data = nullptr; #if BUILDFLAG(CHROME_ROOT_STORE_SUPPORTED) root_store_data = base::OptionalToPtr(root_store_data_); #endif - internal::CertVerifierServiceImpl* service_impl = - GetNewCertVerifierImpl(service_params_.get(), std::move(receiver), - std::move(creation_params), root_store_data, - /*out_cert_net_fetcher=*/nullptr); + internal::CertVerifierServiceImpl* service_impl = GetNewCertVerifierImpl( + service_params_.get(), std::move(receiver), std::move(client), + std::move(creation_params), root_store_data, + /*out_cert_net_fetcher=*/nullptr); verifier_services_.insert(service_impl); service_impl->SetCertVerifierServiceFactory(weak_factory_.GetWeakPtr()); @@ -136,16 +139,21 @@ void CertVerifierServiceFactoryImpl::GetNewCertVerifierForTesting( mojo::PendingReceiver<mojom::CertVerifierService> receiver, + mojo::PendingRemote<mojom::CertVerifierServiceClient> client, mojom::CertVerifierCreationParamsPtr creation_params, scoped_refptr<CertNetFetcherURLLoader>* cert_net_fetcher_ptr) { GetNewCertVerifierImpl(service_params_.get(), std::move(receiver), - std::move(creation_params), + std::move(client), std::move(creation_params), /*root_store_data=*/nullptr, cert_net_fetcher_ptr); } #if BUILDFLAG(CHROME_ROOT_STORE_SUPPORTED) void CertVerifierServiceFactoryImpl::UpdateChromeRootStore( - mojom::ChromeRootStorePtr new_root_store) { + mojom::ChromeRootStorePtr new_root_store, + UpdateChromeRootStoreCallback callback) { + // Ensure the callback is run regardless which return path is used. + base::ScopedClosureRunner scoped_callback_runner(std::move(callback)); + if (new_root_store->serialized_proto_root_store.size() == 0) { LOG(ERROR) << "Empty serialized RootStore proto"; return;
diff --git a/services/cert_verifier/cert_verifier_service_factory.h b/services/cert_verifier/cert_verifier_service_factory.h index 553e237..6c94ec7 100644 --- a/services/cert_verifier/cert_verifier_service_factory.h +++ b/services/cert_verifier/cert_verifier_service_factory.h
@@ -43,6 +43,7 @@ // mojom::CertVerifierServiceFactory implementation: void GetNewCertVerifier( mojo::PendingReceiver<mojom::CertVerifierService> receiver, + mojo::PendingRemote<mojom::CertVerifierServiceClient> client, mojom::CertVerifierCreationParamsPtr creation_params) override; void GetServiceParamsForTesting( GetServiceParamsForTestingCallback callback) override; @@ -52,12 +53,14 @@ // CertNetFetcherURLLoader is in use. void GetNewCertVerifierForTesting( mojo::PendingReceiver<mojom::CertVerifierService> receiver, + mojo::PendingRemote<mojom::CertVerifierServiceClient> client, mojom::CertVerifierCreationParamsPtr creation_params, scoped_refptr<CertNetFetcherURLLoader>* cert_net_fetcher_ptr); #if BUILDFLAG(CHROME_ROOT_STORE_SUPPORTED) // mojom::CertVerifierServiceFactory implementation: - void UpdateChromeRootStore(mojom::ChromeRootStorePtr new_root_store) override; + void UpdateChromeRootStore(mojom::ChromeRootStorePtr new_root_store, + UpdateChromeRootStoreCallback callback) override; void GetChromeRootStoreInfo(GetChromeRootStoreInfoCallback callback) override; #endif
diff --git a/services/cert_verifier/cert_verifier_service_factory_unittest.cc b/services/cert_verifier/cert_verifier_service_factory_unittest.cc index ca3f429..86fbd4dd2 100644 --- a/services/cert_verifier/cert_verifier_service_factory_unittest.cc +++ b/services/cert_verifier/cert_verifier_service_factory_unittest.cc
@@ -60,6 +60,18 @@ net::CertVerifyResult result; int net_error; }; + +class DummyCVServiceClient : public mojom::CertVerifierServiceClient { + public: + DummyCVServiceClient() : client_(this) {} + + // mojom::CertVerifierServiceClient implementation: + void OnCertVerifierChanged() override { changed_count_++; } + + unsigned changed_count_ = 0; + mojo::Receiver<mojom::CertVerifierServiceClient> client_; +}; + } // namespace TEST(CertVerifierServiceFactoryTest, GetNewCertVerifier) { @@ -76,11 +88,13 @@ cv_service_factory_remote.BindNewPipeAndPassReceiver()); mojo::Remote<mojom::CertVerifierService> cv_service_remote; + mojo::PendingReceiver<mojom::CertVerifierServiceClient> cv_service_client; mojom::CertVerifierCreationParamsPtr cv_creation_params = mojom::CertVerifierCreationParams::New(); cv_service_factory_remote->GetNewCertVerifier( cv_service_remote.BindNewPipeAndPassReceiver(), + cv_service_client.InitWithNewPipeAndPassRemote(), std::move(cv_creation_params)); base::RunLoop request_completed_run_loop; @@ -140,14 +154,21 @@ cv_service_factory_remote.BindNewPipeAndPassReceiver()); // Feed factory the new Chrome Root Store. - cv_service_factory_impl.UpdateChromeRootStore(std::move(root_store_ptr)); + { + base::RunLoop update_run_loop; + cv_service_factory_impl.UpdateChromeRootStore( + std::move(root_store_ptr), update_run_loop.QuitClosure()); + update_run_loop.Run(); + } mojo::Remote<mojom::CertVerifierService> cv_service_remote; + DummyCVServiceClient cv_service_client; mojom::CertVerifierCreationParamsPtr cv_creation_params = mojom::CertVerifierCreationParams::New(); cv_service_factory_remote->GetNewCertVerifier( cv_service_remote.BindNewPipeAndPassReceiver(), + cv_service_client.client_.BindNewPipeAndPassRemote(), std::move(cv_creation_params)); base::RunLoop request_completed_run_loop; @@ -169,6 +190,9 @@ request_completed_run_loop.Run(); ASSERT_EQ(dummy_cv_service_req.net_error, net::OK); + // Update happened before the CertVerifier was created, no change observers + // should have been notified. + EXPECT_EQ(cv_service_client.changed_count_, 0u); } // Test that an existing CertVerifierService will use an updated Chrome Root @@ -194,11 +218,13 @@ cv_service_factory_remote.BindNewPipeAndPassReceiver()); mojo::Remote<mojom::CertVerifierService> cv_service_remote; + DummyCVServiceClient cv_service_client; mojom::CertVerifierCreationParamsPtr cv_creation_params = mojom::CertVerifierCreationParams::New(); cv_service_factory_remote->GetNewCertVerifier( cv_service_remote.BindNewPipeAndPassReceiver(), + cv_service_client.client_.BindNewPipeAndPassRemote(), std::move(cv_creation_params)); // Try request, it should fail because we haven't updated the Root Store yet. @@ -225,6 +251,8 @@ ASSERT_TRUE(dummy_cv_service_req.result.cert_status & net::CERT_STATUS_AUTHORITY_INVALID); } + // No updates should have happened yet. + EXPECT_EQ(cv_service_client.changed_count_, 0u); // Create updated Chrome Root Store with just the root cert from above. chrome_root_store::RootStore root_store_proto; @@ -238,7 +266,12 @@ base::as_bytes(base::make_span(proto_serialized))); // Feed factory the new Chrome Root Store. - cv_service_factory_impl.UpdateChromeRootStore(std::move(root_store_ptr)); + { + base::RunLoop update_run_loop; + cv_service_factory_impl.UpdateChromeRootStore( + std::move(root_store_ptr), update_run_loop.QuitClosure()); + update_run_loop.Run(); + } // Try request, it should succeed. { @@ -261,6 +294,9 @@ request_completed_run_loop.Run(); ASSERT_EQ(dummy_cv_service_req.net_error, net::OK); } + + // Update should have been notified. + EXPECT_EQ(cv_service_client.changed_count_, 1u); } TEST(CertVerifierServiceFactoryTest, OldRootStoreUpdateIgnored) { @@ -296,14 +332,21 @@ cv_service_factory_remote.BindNewPipeAndPassReceiver()); // Feed factory the new Chrome Root Store. - cv_service_factory_impl.UpdateChromeRootStore(std::move(root_store_ptr)); + { + base::RunLoop update_run_loop; + cv_service_factory_impl.UpdateChromeRootStore( + std::move(root_store_ptr), update_run_loop.QuitClosure()); + update_run_loop.Run(); + } mojo::Remote<mojom::CertVerifierService> cv_service_remote; + DummyCVServiceClient cv_service_client; mojom::CertVerifierCreationParamsPtr cv_creation_params = mojom::CertVerifierCreationParams::New(); cv_service_factory_remote->GetNewCertVerifier( cv_service_remote.BindNewPipeAndPassReceiver(), + cv_service_client.client_.BindNewPipeAndPassRemote(), std::move(cv_creation_params)); base::RunLoop request_completed_run_loop; @@ -328,6 +371,8 @@ ASSERT_EQ(dummy_cv_service_req.net_error, net::ERR_CERT_AUTHORITY_INVALID); ASSERT_TRUE(dummy_cv_service_req.result.cert_status & net::CERT_STATUS_AUTHORITY_INVALID); + // Update was ignored, so no change observers should have been notified. + EXPECT_EQ(cv_service_client.changed_count_, 0u); } TEST(CertVerifierServiceFactoryTest, BadRootStoreUpdateIgnored) { @@ -362,14 +407,21 @@ cv_service_factory_remote.BindNewPipeAndPassReceiver()); // Feed factory the new Chrome Root Store. - cv_service_factory_impl.UpdateChromeRootStore(std::move(root_store_ptr)); + { + base::RunLoop update_run_loop; + cv_service_factory_impl.UpdateChromeRootStore( + std::move(root_store_ptr), update_run_loop.QuitClosure()); + update_run_loop.Run(); + } mojo::Remote<mojom::CertVerifierService> cv_service_remote; + DummyCVServiceClient cv_service_client; mojom::CertVerifierCreationParamsPtr cv_creation_params = mojom::CertVerifierCreationParams::New(); cv_service_factory_remote->GetNewCertVerifier( cv_service_remote.BindNewPipeAndPassReceiver(), + cv_service_client.client_.BindNewPipeAndPassRemote(), std::move(cv_creation_params)); // Initial request should succeed. @@ -410,8 +462,12 @@ base::as_bytes(base::make_span(proto_serialized))); // Feed factory the new Chrome Root Store. - cv_service_factory_impl.UpdateChromeRootStore( - std::move(invalid_root_store_ptr)); + { + base::RunLoop update_run_loop; + cv_service_factory_impl.UpdateChromeRootStore( + std::move(invalid_root_store_ptr), update_run_loop.QuitClosure()); + update_run_loop.Run(); + } { base::RunLoop request_completed_run_loop; @@ -444,8 +500,12 @@ base::as_bytes(base::make_span(proto_serialized))); // Feed factory the new Chrome Root Store. - cv_service_factory_impl.UpdateChromeRootStore( - std::move(empty_root_store_ptr)); + { + base::RunLoop update_run_loop; + cv_service_factory_impl.UpdateChromeRootStore( + std::move(empty_root_store_ptr), update_run_loop.QuitClosure()); + update_run_loop.Run(); + } { base::RunLoop request_completed_run_loop; @@ -469,6 +529,8 @@ // Request should be OK because root store update was ignored. ASSERT_EQ(dummy_cv_service_req.net_error, net::OK); } + // Update was ignored, so no change observers should have been notified. + EXPECT_EQ(cv_service_client.changed_count_, 0u); } void GetRootStoreInfo(cert_verifier::mojom::ChromeRootStoreInfoPtr* return_ptr, @@ -503,7 +565,12 @@ cv_service_factory_remote.BindNewPipeAndPassReceiver()); // Feed factory the new Chrome Root Store. - cv_service_factory_impl.UpdateChromeRootStore(std::move(root_store_ptr)); + { + base::RunLoop update_run_loop; + cv_service_factory_impl.UpdateChromeRootStore( + std::move(root_store_ptr), update_run_loop.QuitClosure()); + update_run_loop.Run(); + } cert_verifier::mojom::ChromeRootStoreInfoPtr info_ptr; base::RunLoop request_completed_run_loop;
diff --git a/services/cert_verifier/cert_verifier_service_unittest.cc b/services/cert_verifier/cert_verifier_service_unittest.cc index af6a251..8f633ea6 100644 --- a/services/cert_verifier/cert_verifier_service_unittest.cc +++ b/services/cert_verifier/cert_verifier_service_unittest.cc
@@ -101,6 +101,11 @@ return net::ERR_IO_PENDING; } void SetConfig(const Config& config) override { config_ = config; } + void AddObserver(Observer* observer) override { + EXPECT_FALSE(observer_); + observer_ = observer; + } + void RemoveObserver(Observer* observer) override { observer_ = nullptr; } void UpdateChromeRootStoreData( scoped_refptr<net::CertNetFetcher> cert_net_fetcher, const net::ChromeRootStoreData* root_store_data) override {} @@ -138,6 +143,8 @@ const net::CertVerifier::Config* config() const { return &config_; } + CertVerifier::Observer* GetObserver() { return observer_; } + private: std::map<net::CertVerifier::RequestParams, DummyRequest*> dummy_requests_; std::set<net::CertVerifier::RequestParams> sync_response_params_; @@ -149,6 +156,7 @@ request_netlogs_; net::CertVerifier::Config config_; + raw_ptr<CertVerifier::Observer> observer_ = nullptr; }; struct DummyCVServiceRequest : public mojom::CertVerifierRequest { @@ -164,7 +172,8 @@ int net_error; }; -class CertVerifierServiceTest : public PlatformTest { +class CertVerifierServiceTest : public PlatformTest, + public mojom::CertVerifierServiceClient { public: struct RequestInfo { RequestInfo(net::CertVerifier::RequestParams request_params_p, @@ -190,11 +199,13 @@ }; // Wraps a DummyCertVerifier with a CertVerifierServiceImpl. - CertVerifierServiceTest() : dummy_cv_(new DummyCertVerifier) { + CertVerifierServiceTest() + : cv_service_client_(this), dummy_cv_(new DummyCertVerifier) { // NOTE: CertVerifierServiceImpl is self-deleting. (void)new internal::CertVerifierServiceImpl( base::WrapUnique(dummy_cv_.get()), cv_service_remote_.BindNewPipeAndPassReceiver(), + cv_service_client_.BindNewPipeAndPassRemote(), /*cert_net_fetcher=*/nullptr); } @@ -268,10 +279,19 @@ DummyCertVerifier* dummy_cv() { return dummy_cv_; } void set_dummy_cv(DummyCertVerifier* cv) { dummy_cv_ = cv; } + unsigned cv_service_client_changed_count() const { + return cv_service_client_changed_count_; + } + + // mojom::CertVerifierServiceClient implementation: + void OnCertVerifierChanged() override { cv_service_client_changed_count_++; } + private: base::test::TaskEnvironment task_environment_; mojo::Remote<mojom::CertVerifierService> cv_service_remote_; + mojo::Receiver<mojom::CertVerifierServiceClient> cv_service_client_; + unsigned cv_service_client_changed_count_ = 0; raw_ptr<DummyCertVerifier> dummy_cv_; }; } // namespace @@ -365,4 +385,21 @@ ASSERT_TRUE(dummy_cv()->config()->disable_symantec_enforcement); } +// CertVerifierService should register an Observer on the underlying +// CertVerifier and when that observer is notified, it should proxy the +// notifications to the CertVerifierServiceClient. +TEST_F(CertVerifierServiceTest, ObserverIsRegistered) { + ASSERT_TRUE(dummy_cv()->GetObserver()); + + EXPECT_EQ(cv_service_client_changed_count(), 0u); + + dummy_cv()->GetObserver()->OnCertVerifierChanged(); + task_environment()->RunUntilIdle(); + EXPECT_EQ(cv_service_client_changed_count(), 1u); + + dummy_cv()->GetObserver()->OnCertVerifierChanged(); + task_environment()->RunUntilIdle(); + EXPECT_EQ(cv_service_client_changed_count(), 2u); +} + } // namespace cert_verifier
diff --git a/services/cert_verifier/integration_tests/network_context_unittest.cc b/services/cert_verifier/integration_tests/network_context_unittest.cc index b6c6ab2..3a30fa7 100644 --- a/services/cert_verifier/integration_tests/network_context_unittest.cc +++ b/services/cert_verifier/integration_tests/network_context_unittest.cc
@@ -29,14 +29,18 @@ namespace cert_verifier { namespace { -mojo::PendingRemote<mojom::CertVerifierService> GetNewCertVerifierServiceRemote( +network::mojom::CertVerifierServiceRemoteParamsPtr +GetNewCertVerifierServiceRemoteParams( mojom::CertVerifierServiceFactory* cert_verifier_service_factory, mojom::CertVerifierCreationParamsPtr creation_params) { mojo::PendingRemote<mojom::CertVerifierService> cert_verifier_remote; + mojo::PendingReceiver<mojom::CertVerifierServiceClient> cert_verifier_client; cert_verifier_service_factory->GetNewCertVerifier( cert_verifier_remote.InitWithNewPipeAndPassReceiver(), + cert_verifier_client.InitWithNewPipeAndPassRemote(), std::move(creation_params)); - return cert_verifier_remote; + return network::mojom::CertVerifierServiceRemoteParams::New( + std::move(cert_verifier_remote), std::move(cert_verifier_client)); } } // namespace @@ -74,12 +78,9 @@ } // Create a cert verifier service. - auto cert_verifier_service_remote = GetNewCertVerifierServiceRemote( + return GetNewCertVerifierServiceRemoteParams( cert_verifier_service_factory_.get(), std::move(cert_verifier_creation_params)); - - return network::mojom::CertVerifierServiceRemoteParams::New( - std::move(cert_verifier_service_remote)); } virtual mojom::CertVerifierServiceParamsPtr GetCertVerifierServiceParams() {
diff --git a/services/cert_verifier/integration_tests/network_service_unittest.cc b/services/cert_verifier/integration_tests/network_service_unittest.cc index ed7f706..e8a95331 100644 --- a/services/cert_verifier/integration_tests/network_service_unittest.cc +++ b/services/cert_verifier/integration_tests/network_service_unittest.cc
@@ -13,6 +13,7 @@ #include "base/test/scoped_feature_list.h" #include "base/test/task_environment.h" #include "build/build_config.h" +#include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/cpp/bindings/pending_remote.h" #include "net/base/test_completion_callback.h" #include "net/cert/asn1_util.h" @@ -61,10 +62,12 @@ network::mojom::NetworkContextParamsPtr CreateNetworkContextParams() { mojo::PendingRemote<mojom::CertVerifierService> cv_service_remote; + mojo::PendingReceiver<mojom::CertVerifierServiceClient> cv_service_client; // Create a cert verifier service. cert_verifier_service_impl_.GetNewCertVerifierForTesting( cv_service_remote.InitWithNewPipeAndPassReceiver(), + cv_service_client.InitWithNewPipeAndPassRemote(), mojom::CertVerifierCreationParams::New(), &cert_net_fetcher_url_loader_); @@ -72,7 +75,7 @@ network::mojom::NetworkContextParams::New(); params->cert_verifier_params = network::mojom::CertVerifierServiceRemoteParams::New( - std::move(cv_service_remote)); + std::move(cv_service_remote), std::move(cv_service_client)); // Use a fixed proxy config, to avoid dependencies on local network // configuration. params->initial_proxy_config =
diff --git a/services/cert_verifier/integration_tests/ssl_config_service_mojo_unittest.cc b/services/cert_verifier/integration_tests/ssl_config_service_mojo_unittest.cc index 05ef596..d5f6424a 100644 --- a/services/cert_verifier/integration_tests/ssl_config_service_mojo_unittest.cc +++ b/services/cert_verifier/integration_tests/ssl_config_service_mojo_unittest.cc
@@ -46,10 +46,12 @@ network::mojom::NetworkContextParamsPtr CreateNetworkContextParams() { mojo::PendingRemote<mojom::CertVerifierService> cv_service_remote; + mojo::PendingReceiver<mojom::CertVerifierServiceClient> cv_service_client; // Create a cert verifier service. cert_verifier_service_impl_.GetNewCertVerifierForTesting( cv_service_remote.InitWithNewPipeAndPassReceiver(), + cv_service_client.InitWithNewPipeAndPassRemote(), mojom::CertVerifierCreationParams::New(), &cert_net_fetcher_url_loader_); @@ -57,7 +59,7 @@ network::mojom::NetworkContextParams::New(); params->cert_verifier_params = network::mojom::CertVerifierServiceRemoteParams::New( - std::move(cv_service_remote)); + std::move(cv_service_remote), std::move(cv_service_client)); // Use a fixed proxy config, to avoid dependencies on local network // configuration. params->initial_proxy_config =
diff --git a/services/cert_verifier/public/mojom/cert_verifier_service_factory.mojom b/services/cert_verifier/public/mojom/cert_verifier_service_factory.mojom index e81a42c..373d90e 100644 --- a/services/cert_verifier/public/mojom/cert_verifier_service_factory.mojom +++ b/services/cert_verifier/public/mojom/cert_verifier_service_factory.mojom
@@ -68,18 +68,20 @@ // CertVerifierService's, which have their own underlying CertVerifier's // underneath. interface CertVerifierServiceFactory { - // Gets a new CertVerifierFactory, which //net code can interface with using + // Gets a new CertVerifierService, which //net code can interface with using // cert_verifier::MojoCertVerifier. GetNewCertVerifier(pending_receiver<CertVerifierService> receiver, + pending_remote<CertVerifierServiceClient> client, CertVerifierCreationParams? creation_params); // Returns the parameters that the service was configured with. GetServiceParamsForTesting() => (CertVerifierServiceParams service_params); // Updates the ChromeRootStore used by the CertVerifierServiceFactory with a - // new version. + // new version. The callback will be run once the update has been processed + // (regardless if it was updated successfully or the update was ignored.) [EnableIf=is_chrome_root_store_supported] - UpdateChromeRootStore(ChromeRootStore new_root_store); + UpdateChromeRootStore(ChromeRootStore new_root_store) => (); // Returns information about the current Chrome Root Store. [EnableIf=is_chrome_root_store_supported]
diff --git a/services/cert_verifier/trial_comparison_cert_verifier_mojo.cc b/services/cert_verifier/trial_comparison_cert_verifier_mojo.cc index 0cf52660..a4fe13b 100644 --- a/services/cert_verifier/trial_comparison_cert_verifier_mojo.cc +++ b/services/cert_verifier/trial_comparison_cert_verifier_mojo.cc
@@ -111,6 +111,14 @@ trial_comparison_cert_verifier_->SetConfig(config); } +void TrialComparisonCertVerifierMojo::AddObserver(Observer* observer) { + trial_comparison_cert_verifier_->AddObserver(observer); +} + +void TrialComparisonCertVerifierMojo::RemoveObserver(Observer* observer) { + trial_comparison_cert_verifier_->RemoveObserver(observer); +} + void TrialComparisonCertVerifierMojo::UpdateChromeRootStoreData( scoped_refptr<net::CertNetFetcher> cert_net_fetcher, const net::ChromeRootStoreData* root_store_data) {
diff --git a/services/cert_verifier/trial_comparison_cert_verifier_mojo.h b/services/cert_verifier/trial_comparison_cert_verifier_mojo.h index 0b8c815a..36497cf 100644 --- a/services/cert_verifier/trial_comparison_cert_verifier_mojo.h +++ b/services/cert_verifier/trial_comparison_cert_verifier_mojo.h
@@ -66,6 +66,8 @@ std::unique_ptr<Request>* out_req, const net::NetLogWithSource& net_log) override; void SetConfig(const Config& config) override; + void AddObserver(Observer* observer) override; + void RemoveObserver(Observer* observer) override; void UpdateChromeRootStoreData( scoped_refptr<net::CertNetFetcher> cert_net_fetcher, const net::ChromeRootStoreData* root_store_data) override;
diff --git a/services/cert_verifier/trial_comparison_cert_verifier_mojo_unittest.cc b/services/cert_verifier/trial_comparison_cert_verifier_mojo_unittest.cc index aeb32b2..a7de42b 100644 --- a/services/cert_verifier/trial_comparison_cert_verifier_mojo_unittest.cc +++ b/services/cert_verifier/trial_comparison_cert_verifier_mojo_unittest.cc
@@ -11,6 +11,7 @@ #include "net/cert/cert_verify_proc.h" #include "net/cert/cert_verify_proc_builtin.h" #include "net/cert/cert_verify_result.h" +#include "net/cert/mock_cert_verifier.h" #include "net/der/encode_values.h" #include "net/der/parse_values.h" #include "net/net_buildflags.h" @@ -129,6 +130,28 @@ ~NotCalledProcFactory() override = default; }; +class SwapWithNewProcFactory : public net::CertVerifyProcFactory { + public: + explicit SwapWithNewProcFactory(scoped_refptr<net::CertVerifyProc> new_proc) + : verify_proc_(std::move(new_proc)) {} + + scoped_refptr<net::CertVerifyProc> CreateCertVerifyProc( + scoped_refptr<net::CertNetFetcher> cert_net_fetcher, + const net::ChromeRootStoreData* root_store_data) override { + return verify_proc_; + } + + protected: + ~SwapWithNewProcFactory() override = default; + + scoped_refptr<net::CertVerifyProc> verify_proc_; +}; + +scoped_refptr<net::CertVerifyProcFactory> SwapWithNotCalledProcFactory() { + return base::MakeRefCounted<SwapWithNewProcFactory>( + base::MakeRefCounted<NotCalledCertVerifyProc>()); +} + } // namespace TEST(TrialComparisonCertVerifierMojoTest, SendReportDebugInfo) { @@ -252,3 +275,24 @@ EXPECT_EQ(time, report.debug_info->trial_verification_time); EXPECT_EQ("20190927221108Z", report.debug_info->trial_der_verification_time); } + +TEST(TrialComparisonCertVerifierMojoTest, ObserverIsCalledOnCRSUpdate) { + base::test::TaskEnvironment scoped_task_environment; + + mojo::PendingRemote< + cert_verifier::mojom::TrialComparisonCertVerifierReportClient> + report_client_remote; + FakeReportClient report_client( + report_client_remote.InitWithNewPipeAndPassReceiver()); + cert_verifier::TrialComparisonCertVerifierMojo tccvm( + true, {}, std::move(report_client_remote), + base::MakeRefCounted<NotCalledCertVerifyProc>(), + SwapWithNotCalledProcFactory(), + base::MakeRefCounted<NotCalledCertVerifyProc>(), + SwapWithNotCalledProcFactory()); + + net::CertVerifierObserverCounter observer_(&tccvm); + EXPECT_EQ(observer_.change_count(), 0u); + tccvm.UpdateChromeRootStoreData(nullptr, nullptr); + EXPECT_EQ(observer_.change_count(), 1u); +}
diff --git a/services/network/cert_verifier_with_trust_anchors.cc b/services/network/cert_verifier_with_trust_anchors.cc index 8a02282..40028af 100644 --- a/services/network/cert_verifier_with_trust_anchors.cc +++ b/services/network/cert_verifier_with_trust_anchors.cc
@@ -113,4 +113,12 @@ orig_config_, trust_anchors_, untrusted_authorities_)); } +void CertVerifierWithTrustAnchors::AddObserver(Observer* observer) { + delegate_->AddObserver(observer); +} + +void CertVerifierWithTrustAnchors::RemoveObserver(Observer* observer) { + delegate_->RemoveObserver(observer); +} + } // namespace network
diff --git a/services/network/cert_verifier_with_trust_anchors.h b/services/network/cert_verifier_with_trust_anchors.h index 674d59a..e49fd5d 100644 --- a/services/network/cert_verifier_with_trust_anchors.h +++ b/services/network/cert_verifier_with_trust_anchors.h
@@ -58,6 +58,8 @@ std::unique_ptr<Request>* out_req, const net::NetLogWithSource& net_log) override; void SetConfig(const Config& config) override; + void AddObserver(Observer* observer) override; + void RemoveObserver(Observer* observer) override; private: net::CertVerifier::Config orig_config_;
diff --git a/services/network/cert_verifier_with_trust_anchors_unittest.cc b/services/network/cert_verifier_with_trust_anchors_unittest.cc index 9048f834..16accf2 100644 --- a/services/network/cert_verifier_with_trust_anchors_unittest.cc +++ b/services/network/cert_verifier_with_trust_anchors_unittest.cc
@@ -72,6 +72,12 @@ mock_cert_verifier_.SetConfig(config); } + void AddObserver(Observer* observer) override { + mock_cert_verifier_.AddObserver(observer); + } + void RemoveObserver(Observer* observer) override { + mock_cert_verifier_.RemoveObserver(observer); + } private: scoped_refptr<net::X509Certificate> server_cert_;
diff --git a/services/network/ignore_errors_cert_verifier.cc b/services/network/ignore_errors_cert_verifier.cc index bfe7149c..3df73409 100644 --- a/services/network/ignore_errors_cert_verifier.cc +++ b/services/network/ignore_errors_cert_verifier.cc
@@ -120,6 +120,14 @@ verifier_->SetConfig(config); } +void IgnoreErrorsCertVerifier::AddObserver(Observer* observer) { + verifier_->AddObserver(observer); +} + +void IgnoreErrorsCertVerifier::RemoveObserver(Observer* observer) { + verifier_->RemoveObserver(observer); +} + void IgnoreErrorsCertVerifier::SetAllowlistForTesting( const SPKIHashSet& allowlist) { allowlist_ = allowlist;
diff --git a/services/network/ignore_errors_cert_verifier.h b/services/network/ignore_errors_cert_verifier.h index 1052d9a8..539a229 100644 --- a/services/network/ignore_errors_cert_verifier.h +++ b/services/network/ignore_errors_cert_verifier.h
@@ -54,6 +54,8 @@ std::unique_ptr<Request>* out_req, const net::NetLogWithSource& net_log) override; void SetConfig(const Config& config) override; + void AddObserver(Observer* observer) override; + void RemoveObserver(Observer* observer) override; private: friend class IgnoreErrorsCertVerifierTest;
diff --git a/services/network/network_context.cc b/services/network/network_context.cc index 8eb64ae..b7579e5 100644 --- a/services/network/network_context.cc +++ b/services/network/network_context.cc
@@ -210,6 +210,18 @@ return; g_cert_verifier_for_testing->SetConfig(config); } + void AddObserver(Observer* observer) override { + if (!g_cert_verifier_for_testing) { + return; + } + g_cert_verifier_for_testing->AddObserver(observer); + } + void RemoveObserver(Observer* observer) override { + if (!g_cert_verifier_for_testing) { + return; + } + g_cert_verifier_for_testing->RemoveObserver(observer); + } }; // Predicate function to determine if the given |domain| matches the @@ -2198,6 +2210,8 @@ // process. cert_verifier = std::make_unique<cert_verifier::MojoCertVerifier>( std::move(params_->cert_verifier_params->cert_verifier_service), + std::move(params_->cert_verifier_params + ->cert_verifier_service_client_receiver), std::move(url_loader_factory_for_cert_net_fetcher), base::BindRepeating( &NetworkContext::CreateURLLoaderFactoryForCertNetFetcher,
diff --git a/services/network/public/cpp/cert_verifier/mojo_cert_verifier.cc b/services/network/public/cpp/cert_verifier/mojo_cert_verifier.cc index b84a344..c2fa8dae 100644 --- a/services/network/public/cpp/cert_verifier/mojo_cert_verifier.cc +++ b/services/network/public/cpp/cert_verifier/mojo_cert_verifier.cc
@@ -98,10 +98,12 @@ MojoCertVerifier::MojoCertVerifier( mojo::PendingRemote<mojom::CertVerifierService> mojo_cert_verifier, + mojo::PendingReceiver<mojom::CertVerifierServiceClient> client_receiver, mojo::PendingRemote<network::mojom::URLLoaderFactory> url_loader_factory, base::RepeatingCallback<void( mojo::PendingReceiver<network::mojom::URLLoaderFactory>)> reconnector) - : mojo_cert_verifier_(std::move(mojo_cert_verifier)) { + : mojo_cert_verifier_(std::move(mojo_cert_verifier)), + client_receiver_(this, std::move(client_receiver)) { mojo::PendingRemote<mojom::URLLoaderFactoryConnector> reconnector_remote; reconnector_ = std::make_unique<MojoReconnector>( @@ -138,6 +140,20 @@ mojo_cert_verifier_->SetConfig(config); } +void MojoCertVerifier::AddObserver(Observer* observer) { + observers_.AddObserver(observer); +} + +void MojoCertVerifier::RemoveObserver(Observer* observer) { + observers_.RemoveObserver(observer); +} + +void MojoCertVerifier::OnCertVerifierChanged() { + for (Observer& observer : observers_) { + observer.OnCertVerifierChanged(); + } +} + void MojoCertVerifier::FlushForTesting() { mojo_cert_verifier_.FlushForTesting(); }
diff --git a/services/network/public/cpp/cert_verifier/mojo_cert_verifier.h b/services/network/public/cpp/cert_verifier/mojo_cert_verifier.h index ac0038a9..6d9ce733 100644 --- a/services/network/public/cpp/cert_verifier/mojo_cert_verifier.h +++ b/services/network/public/cpp/cert_verifier/mojo_cert_verifier.h
@@ -6,7 +6,9 @@ #define SERVICES_NETWORK_PUBLIC_CPP_CERT_VERIFIER_MOJO_CERT_VERIFIER_H_ #include "base/functional/callback_forward.h" +#include "base/observer_list.h" #include "mojo/public/cpp/bindings/pending_receiver.h" +#include "mojo/public/cpp/bindings/receiver.h" #include "mojo/public/cpp/bindings/remote.h" #include "net/base/completion_once_callback.h" #include "net/base/net_export.h" @@ -20,7 +22,8 @@ // Implementation of net::CertVerifier that proxies across a Mojo interface to // verify certificates. -class MojoCertVerifier : public net::CertVerifier { +class MojoCertVerifier : public net::CertVerifier, + public mojom::CertVerifierServiceClient { public: using ReconnectURLLoaderFactory = base::RepeatingCallback<void( mojo::PendingReceiver<network::mojom::URLLoaderFactory>)>; @@ -30,6 +33,7 @@ // connect a new URLLoaderFactory. MojoCertVerifier( mojo::PendingRemote<mojom::CertVerifierService> mojo_cert_verifier, + mojo::PendingReceiver<mojom::CertVerifierServiceClient> client_receiver, mojo::PendingRemote<network::mojom::URLLoaderFactory> url_loader_factory, ReconnectURLLoaderFactory reconnector); ~MojoCertVerifier() override; @@ -41,6 +45,11 @@ std::unique_ptr<net::CertVerifier::Request>* out_req, const net::NetLogWithSource& net_log) override; void SetConfig(const net::CertVerifier::Config& config) override; + void AddObserver(Observer* observer) override; + void RemoveObserver(Observer* observer) override; + + // mojom::CertVerifierServiceClient implementation: + void OnCertVerifierChanged() override; // Flushes the underlying Mojo pipe. void FlushForTesting(); @@ -49,7 +58,9 @@ class MojoReconnector; mojo::Remote<mojom::CertVerifierService> mojo_cert_verifier_; + mojo::Receiver<mojom::CertVerifierServiceClient> client_receiver_; std::unique_ptr<MojoReconnector> reconnector_; + base::ObserverList<Observer> observers_; }; } // namespace cert_verifier
diff --git a/services/network/public/cpp/cert_verifier/mojo_cert_verifier_unittest.cc b/services/network/public/cpp/cert_verifier/mojo_cert_verifier_unittest.cc index dd41f44..bb04306 100644 --- a/services/network/public/cpp/cert_verifier/mojo_cert_verifier_unittest.cc +++ b/services/network/public/cpp/cert_verifier/mojo_cert_verifier_unittest.cc
@@ -50,6 +50,15 @@ return url_loader_factory; } +class CertVerifierObserverWaiter : public net::CertVerifier::Observer { + public: + void OnCertVerifierChanged() override { run_loop_.Quit(); } + void Wait() { run_loop_.Run(); } + + private: + base::RunLoop run_loop_; +}; + class MojoCertVerifierTest : public PlatformTest { public: MojoCertVerifierTest() @@ -57,6 +66,7 @@ cv_service_receiver_(&dummy_cv_service_), mojo_cert_verifier_( cv_service_receiver_.BindNewPipeAndPassRemote(), + cv_service_client_.BindNewPipeAndPassReceiver(), CreateUnconnectedURLLoaderFactory(), base::BindRepeating(&MojoCertVerifierTest::ReconnectCb, base::Unretained(this))) { @@ -153,6 +163,10 @@ EXPECT_EQ(start_time, std::get<2>(received_netlogsources_[params])); } + void SimulateClientOnCertVerifierChanged() { + cv_service_client_->OnCertVerifierChanged(); + } + private: std::map<net::CertVerifier::RequestParams, mojo::Remote<mojom::CertVerifierRequest>> @@ -165,6 +179,7 @@ MojoCertVerifierTest::DummyCVService dummy_cv_service_; mojo::Receiver<mojom::CertVerifierService> cv_service_receiver_; + mojo::Remote<mojom::CertVerifierServiceClient> cv_service_client_; MojoCertVerifier mojo_cert_verifier_; @@ -369,4 +384,15 @@ run_loop.Run(); } +// Tests that a OnCertVerifierChanged message received from the +// CertVerifierServiceClient creates notifications to the +// CertVerifier::Observers registered with CertVerifier::AddObserver. +TEST_F(MojoCertVerifierTest, ClientOnCertVerifierChangedIsProxiedToObservers) { + CertVerifierObserverWaiter observer; + mojo_cert_verifier()->AddObserver(&observer); + SimulateClientOnCertVerifierChanged(); + observer.Wait(); + mojo_cert_verifier()->RemoveObserver(&observer); +} + } // namespace cert_verifier
diff --git a/services/network/public/mojom/cert_verifier_service.mojom b/services/network/public/mojom/cert_verifier_service.mojom index 535320f..23a7dd4f 100644 --- a/services/network/public/mojom/cert_verifier_service.mojom +++ b/services/network/public/mojom/cert_verifier_service.mojom
@@ -21,6 +21,7 @@ // Temporary config struct--this should eventually be deleted as the network // service has no reason to know about this config. +// TODO(https://crbug.com/1427326): remove this. struct CertVerifierConfig { bool enable_rev_checking; bool require_rev_checking_local_anchors; @@ -64,6 +65,14 @@ SetConfig(CertVerifierConfig config); }; +// Receives events from the CertVerifierService. +interface CertVerifierServiceClient { + // Called when the certificate verifier changes internal configuration. + // Observers can use this method to invalidate caches that incorporate + // previous trust decisions. + OnCertVerifierChanged(); +}; + // An interface for a CertVerifierService to pass results to the client of the // service. If the client closes this request, that will imply cancellation of // the cert verification.
diff --git a/services/network/public/mojom/network_context.mojom b/services/network/public/mojom/network_context.mojom index 4a8acae..6bfc03f 100644 --- a/services/network/public/mojom/network_context.mojom +++ b/services/network/public/mojom/network_context.mojom
@@ -135,6 +135,10 @@ // A pipe to the CertVerifierService. pending_remote<cert_verifier.mojom.CertVerifierService>? cert_verifier_service; + + // Receives notifications of changes to the CertVerifier. + pending_receiver<cert_verifier.mojom.CertVerifierServiceClient>? + cert_verifier_service_client_receiver; }; // Client to update the custom proxy config.
diff --git a/services/network/ssl_config_service_mojo_unittest.cc b/services/network/ssl_config_service_mojo_unittest.cc index 1f17f49..3fc3fb5 100644 --- a/services/network/ssl_config_service_mojo_unittest.cc +++ b/services/network/ssl_config_service_mojo_unittest.cc
@@ -97,6 +97,8 @@ void SetConfig(const Config& config) override { set_config_calls_.AddValue(config); } + void AddObserver(Observer* observer) override {} + void RemoveObserver(Observer* observer) override {} // Waits for a SSLConfig change. The first time it's called, waits for the // first change, if one hasn't been observed already, the second time, waits
diff --git a/services/network/test/fake_test_cert_verifier_params_factory.cc b/services/network/test/fake_test_cert_verifier_params_factory.cc index 2128c5e..93cdc6e 100644 --- a/services/network/test/fake_test_cert_verifier_params_factory.cc +++ b/services/network/test/fake_test_cert_verifier_params_factory.cc
@@ -28,10 +28,13 @@ mojom::CertVerifierServiceRemoteParamsPtr FakeTestCertVerifierParamsFactory::GetCertVerifierParams() { mojo::PendingRemote<cert_verifier::mojom::CertVerifierService> cv_remote; + mojo::PendingReceiver<cert_verifier::mojom::CertVerifierServiceClient> + cv_client; mojo::MakeSelfOwnedReceiver( std::make_unique<FakeTestCertVerifierParamsFactory>(), cv_remote.InitWithNewPipeAndPassReceiver()); - return mojom::CertVerifierServiceRemoteParams::New(std::move(cv_remote)); + return mojom::CertVerifierServiceRemoteParams::New(std::move(cv_remote), + std::move(cv_client)); } void FakeTestCertVerifierParamsFactory::Verify(
diff --git a/services/network/tls_socket_factory.cc b/services/network/tls_socket_factory.cc index baa4e40..cc9a79e 100644 --- a/services/network/tls_socket_factory.cc +++ b/services/network/tls_socket_factory.cc
@@ -44,6 +44,8 @@ return net::OK; } void SetConfig(const Config& config) override {} + void AddObserver(Observer* observer) override {} + void RemoveObserver(Observer* observer) override {} }; } // namespace
diff --git a/testing/buildbot/chromium.dev.json b/testing/buildbot/chromium.dev.json index f34a4a81..2cdedbc2 100644 --- a/testing/buildbot/chromium.dev.json +++ b/testing/buildbot/chromium.dev.json
@@ -113,7 +113,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { - "cores": "2", + "cores": "8", "os": "Ubuntu-18.04" } ], @@ -165,7 +165,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { - "cores": "2", + "cores": "8", "os": "Ubuntu-18.04" } ], @@ -176,6 +176,132 @@ } ] }, + "linux-rel-jammy-dev": { + "gtest_tests": [ + { + "merge": { + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "8", + "os": "Ubuntu-22.04" + } + ], + "service_account": "chromium-tester-dev@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "base_unittests", + "test_id_prefix": "ninja://base:base_unittests/" + }, + { + "merge": { + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "8", + "os": "Ubuntu-22.04" + } + ], + "service_account": "chromium-tester-dev@chops-service-accounts.iam.gserviceaccount.com", + "shards": 8 + }, + "test": "browser_tests", + "test_id_prefix": "ninja://chrome/test:browser_tests/" + }, + { + "merge": { + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "8", + "os": "Ubuntu-22.04" + } + ], + "service_account": "chromium-tester-dev@chops-service-accounts.iam.gserviceaccount.com", + "shards": 5 + }, + "test": "content_browsertests", + "test_id_prefix": "ninja://content/test:content_browsertests/" + }, + { + "merge": { + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "2", + "os": "Ubuntu-22.04" + } + ], + "service_account": "chromium-tester-dev@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "content_unittests", + "test_id_prefix": "ninja://content/test:content_unittests/" + }, + { + "merge": { + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "8", + "os": "Ubuntu-22.04" + } + ], + "service_account": "chromium-tester-dev@chops-service-accounts.iam.gserviceaccount.com", + "shards": 3 + }, + "test": "interactive_ui_tests", + "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/" + }, + { + "merge": { + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "8", + "os": "Ubuntu-22.04" + } + ], + "service_account": "chromium-tester-dev@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "net_unittests", + "test_id_prefix": "ninja://net:net_unittests/" + }, + { + "merge": { + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cores": "2", + "os": "Ubuntu-22.04" + } + ], + "service_account": "chromium-tester-dev@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "unit_tests", + "test_id_prefix": "ninja://chrome/test:unit_tests/" + } + ] + }, "linux-ssd-rel-dev": {}, "mac-arm-rel-dev": { "gtest_tests": [
diff --git a/testing/buildbot/chromium.perf.json b/testing/buildbot/chromium.perf.json index aa953dc..2cc98a1 100644 --- a/testing/buildbot/chromium.perf.json +++ b/testing/buildbot/chromium.perf.json
@@ -2,15 +2,6 @@ "AAAAA1 AUTOGENERATED FILE DO NOT EDIT": {}, "AAAAA2 See //tools/perf/generate_perf_data to make changes": {}, "android-builder-perf": { - "additional_compile_targets": [ - "microdump_stackwalk", - "system_webview_google_apk", - "android_tools", - "dump_syms", - "push_apps_to_background_apk", - "system_webview_apk", - "system_webview_shell_apk" - ], "isolated_scripts": [ { "args": [], @@ -154,17 +145,7 @@ } ] }, - "android-builder-perf-pgo": { - "additional_compile_targets": [ - "microdump_stackwalk", - "system_webview_google_apk", - "android_tools", - "dump_syms", - "push_apps_to_background_apk", - "system_webview_apk", - "system_webview_shell_apk" - ] - }, + "android-builder-perf-pgo": {}, "android-go-perf": { "isolated_scripts": [ { @@ -1209,14 +1190,6 @@ ] }, "android_arm64-builder-perf": { - "additional_compile_targets": [ - "microdump_stackwalk", - "system_webview_google_apk", - "android_tools", - "push_apps_to_background_apk", - "system_webview_apk", - "system_webview_shell_apk" - ], "isolated_scripts": [ { "args": [], @@ -1388,16 +1361,7 @@ } ] }, - "android_arm64-builder-perf-pgo": { - "additional_compile_targets": [ - "microdump_stackwalk", - "system_webview_google_apk", - "android_tools", - "push_apps_to_background_apk", - "system_webview_apk", - "system_webview_shell_apk" - ] - }, + "android_arm64-builder-perf-pgo": {}, "chromecast-linux-builder-perf": { "additional_compile_targets": [ "cast_shell"
diff --git a/testing/buildbot/chromium.perf.pinpoint.json b/testing/buildbot/chromium.perf.pinpoint.json index eddc89e..a29a2cb1 100644 --- a/testing/buildbot/chromium.perf.pinpoint.json +++ b/testing/buildbot/chromium.perf.pinpoint.json
@@ -1,28 +1,8 @@ { "AAAAA1 AUTOGENERATED FILE DO NOT EDIT": {}, "AAAAA2 See //tools/perf/generate_perf_data to make changes": {}, - "android-builder-perf": { - "additional_compile_targets": [ - "microdump_stackwalk", - "system_webview_google_apk", - "android_tools", - "dump_syms", - "push_apps_to_background_apk", - "system_webview_apk", - "system_webview_shell_apk" - ] - }, - "android-builder-perf-pgo": { - "additional_compile_targets": [ - "microdump_stackwalk", - "system_webview_google_apk", - "android_tools", - "dump_syms", - "push_apps_to_background_apk", - "system_webview_apk", - "system_webview_shell_apk" - ] - }, + "android-builder-perf": {}, + "android-builder-perf-pgo": {}, "android-go-perf": { "isolated_scripts": [ { @@ -1066,26 +1046,8 @@ } ] }, - "android_arm64-builder-perf": { - "additional_compile_targets": [ - "microdump_stackwalk", - "system_webview_google_apk", - "android_tools", - "push_apps_to_background_apk", - "system_webview_apk", - "system_webview_shell_apk" - ] - }, - "android_arm64-builder-perf-pgo": { - "additional_compile_targets": [ - "microdump_stackwalk", - "system_webview_google_apk", - "android_tools", - "push_apps_to_background_apk", - "system_webview_apk", - "system_webview_shell_apk" - ] - }, + "android_arm64-builder-perf": {}, + "android_arm64-builder-perf-pgo": {}, "chromecast-linux-builder-perf": { "additional_compile_targets": [ "cast_shell"
diff --git a/testing/buildbot/mixins.pyl b/testing/buildbot/mixins.pyl index 232a16d5..fd99acab 100644 --- a/testing/buildbot/mixins.pyl +++ b/testing/buildbot/mixins.pyl
@@ -704,6 +704,13 @@ }, }, }, + 'linux-jammy': { + 'swarming': { + 'dimensions': { + 'os': 'Ubuntu-22.04', + }, + }, + }, # TODO(crbug.com/1260217): Remove the xenial mixin once the MSAN bots have # migrated to focal. 'linux-xenial': {
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl index ace24a3..46b65a4 100644 --- a/testing/buildbot/test_suite_exceptions.pyl +++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -2198,6 +2198,15 @@ '--test-launcher-filter-file=../../testing/buildbot/filters/fuchsia.lsan.content_unittests.filter', ], }, + 'linux-rel-dev': { + 'swarming': { + 'dimension_sets': [ + { + 'cores': '8', + }, + ], + }, + }, }, }, 'context_lost_validating_tests': { @@ -3960,6 +3969,15 @@ 'shards': 2, }, }, + 'linux-rel-dev': { + 'swarming': { + 'dimension_sets': [ + { + 'cores': '8', + }, + ], + }, + }, 'mac-rel-cft': { 'swarming': { 'inverse_quickrun_shards': 2,
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl index 3e93258..946a598 100644 --- a/testing/buildbot/waterfalls.pyl +++ b/testing/buildbot/waterfalls.pyl
@@ -2599,6 +2599,14 @@ 'gtest_tests': 'chromium_dev_linux_gtests', }, }, + 'linux-rel-jammy-dev': { + 'mixins': [ + 'linux-jammy', + ], + 'test_suites': { + 'gtest_tests': 'chromium_dev_linux_gtests', + }, + }, 'linux-ssd-rel-dev': { 'mixins': [ 'linux-bionic',
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index 9e90fc46..06c580c 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -335,7 +335,6 @@ }, "enable_features": [ "RequestDesktopSiteExceptions", - "RequestDesktopSiteExceptionsDowngrade", "RequestDesktopSitePerSiteIph" ], "disable_features": [ @@ -353,7 +352,6 @@ }, "enable_features": [ "RequestDesktopSiteExceptions", - "RequestDesktopSiteExceptionsDowngrade", "RequestDesktopSitePerSiteIph" ], "disable_features": [ @@ -365,6 +363,21 @@ ] } ], + "AndroidRdsDomainSettingsDowngrade": [ + { + "platforms": [ + "android" + ], + "experiments": [ + { + "name": "Enabled", + "enable_features": [ + "RequestDesktopSiteExceptionsDowngrade" + ] + } + ] + } + ], "AndroidScrollOptimizations": [ { "platforms": [ @@ -3885,38 +3898,6 @@ ] } ], - "DesktopOmniboxBookmarkPaths": [ - { - "platforms": [ - "android", - "chromeos", - "chromeos_lacros", - "fuchsia", - "ios", - "linux", - "mac", - "windows" - ], - "experiments": [ - { - "name": "Enabled", - "params": { - "BookmarkLimitNumNodesForBookmarkSearchCount": "500", - "OmniboxBookmarkPathsUiDynamicReplaceUrl": "true", - "ShortBookmarkSuggestionsByTotalInputLengthThreshold": "3" - }, - "enable_features": [ - "BookmarkApproximateNodeMatch", - "BookmarkIndexPaths", - "BookmarkLimitNumNodesForBookmarkSearch", - "BookmarkTypedUrlsMap", - "OmniboxBookmarkPaths", - "OmniboxShortBookmarkSuggestionsByTotalInputLength" - ] - } - ] - } - ], "DesktopOmniboxDriveDenoise": [ { "platforms": [ @@ -7297,6 +7278,7 @@ "Journeys", "JourneysLabel", "JourneysOmniboxAction", + "JourneysPersistCachesToPrefs", "PageContentAnnotations", "PageEntitiesPageContentAnnotations" ] @@ -7347,6 +7329,26 @@ ] } ], + "JourneysPersistCachesToPrefs": [ + { + "platforms": [ + "chromeos", + "chromeos_lacros", + "fuchsia", + "linux", + "mac", + "windows" + ], + "experiments": [ + { + "name": "Enabled_20230327", + "enable_features": [ + "JourneysPersistCachesToPrefs" + ] + } + ] + } + ], "JourneysSuggestionRow": [ { "platforms": [ @@ -11345,26 +11347,6 @@ ] } ], - "SearchPrefetchOnlyAllowDefaultMatchPreloading": [ - { - "platforms": [ - "android", - "chromeos", - "chromeos_lacros", - "linux", - "mac", - "windows" - ], - "experiments": [ - { - "name": "Enabled", - "enable_features": [ - "SearchPrefetchOnlyAllowDefaultMatchPreloading" - ] - } - ] - } - ], "SearchPrefetchSkipsCancel": [ { "platforms": [
diff --git a/third_party/blink/public/common/input/web_gesture_event.h b/third_party/blink/public/common/input/web_gesture_event.h index 889e607..16a5540f3 100644 --- a/third_party/blink/public/common/input/web_gesture_event.h +++ b/third_party/blink/public/common/input/web_gesture_event.h
@@ -107,14 +107,14 @@ // True if this event is generated from a mousewheel or scrollbar. // Synthetic GSB(s) are ignored by the blink::ElasticOverscrollController. bool synthetic; - // If true, this event will be used for cursor control instead of - // scrolling. the entire scroll sequence will be used for cursor control. - bool cursor_control; - // If nonzero, this event has been hit tested by the main thread and the + // If true, this event has been hit tested by the main thread and the // result is stored in scrollable_area_element_id. Used only in scroll // unification when the event is sent back the the compositor for a // second time after the main thread hit test is complete. - uint32_t main_thread_hit_tested_reasons; + bool main_thread_hit_tested; + // If true, this event will be used for cursor control instead of + // scrolling. the entire scroll sequence will be used for cursor control. + bool cursor_control; } scroll_begin; struct {
diff --git a/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc b/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc index 9bd1f83..ab0751f 100644 --- a/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc +++ b/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc
@@ -3532,10 +3532,7 @@ if (injected_type == WebInputEvent::Type::kGestureScrollBegin) { gesture_event->data.scroll_begin.scrollable_area_element_id = scrollable_area_element_id.GetInternalValue(); - gesture_event->data.scroll_begin.main_thread_hit_tested_reasons = - device == WebGestureDevice::kScrollbar - ? cc::MainThreadScrollingReason::kScrollbarScrolling - : cc::MainThreadScrollingReason::kFailedHitTest; + gesture_event->data.scroll_begin.main_thread_hit_tested = true; } // Notifies TestWebFrameWidget of the injected event. Does nothing outside
diff --git a/third_party/blink/renderer/core/html/forms/html_field_set_element.cc b/third_party/blink/renderer/core/html/forms/html_field_set_element.cc index 97ee0a20..e31daf7 100644 --- a/third_party/blink/renderer/core/html/forms/html_field_set_element.cc +++ b/third_party/blink/renderer/core/html/forms/html_field_set_element.cc
@@ -115,6 +115,18 @@ focused_element->blur(); } +void HTMLFieldSetElement::AncestorDisabledStateWasChanged() { + if (RuntimeEnabledFeatures::NonReentrantFieldSetDisableEnabled()) { + ancestor_disabled_state_ = AncestorDisabledState::kUnknown; + // Do not re-enter HTMLFieldSetElement::DisabledAttributeChanged(), so that + // we only invalidate this element's own disabled state and do not traverse + // the descendants. + HTMLFormControlElement::DisabledAttributeChanged(); + } else { + HTMLFormControlElement::AncestorDisabledStateWasChanged(); + } +} + void HTMLFieldSetElement::ChildrenChanged(const ChildrenChange& change) { HTMLFormControlElement::ChildrenChanged(change); Element* focused_element = nullptr;
diff --git a/third_party/blink/renderer/core/html/forms/html_field_set_element.h b/third_party/blink/renderer/core/html/forms/html_field_set_element.h index 7b5b788..03a83906 100644 --- a/third_party/blink/renderer/core/html/forms/html_field_set_element.h +++ b/third_party/blink/renderer/core/html/forms/html_field_set_element.h
@@ -44,6 +44,7 @@ protected: void DisabledAttributeChanged() override; + void AncestorDisabledStateWasChanged() override; private: bool IsEnumeratable() const override { return true; }
diff --git a/third_party/blink/renderer/core/html/forms/listed_element.h b/third_party/blink/renderer/core/html/forms/listed_element.h index 98e9bba..ee68268 100644 --- a/third_party/blink/renderer/core/html/forms/listed_element.h +++ b/third_party/blink/renderer/core/html/forms/listed_element.h
@@ -152,7 +152,7 @@ // This should be called in Node::DidMoveToDocument(). void DidMoveToNewDocument(Document& old_document); // This is for HTMLFieldSetElement class. - void AncestorDisabledStateWasChanged(); + virtual void AncestorDisabledStateWasChanged(); // https://html.spec.whatwg.org/C/#concept-element-disabled bool IsActuallyDisabled() const; @@ -202,6 +202,10 @@ // FIELDSET ancestors. mutable bool may_have_fieldset_ancestor_ = true; + enum class AncestorDisabledState { kUnknown, kEnabled, kDisabled }; + mutable AncestorDisabledState ancestor_disabled_state_ = + AncestorDisabledState::kUnknown; + private: void UpdateAncestorDisabledState() const; void SetFormAttributeTargetObserver(FormAttributeTargetObserver*); @@ -233,10 +237,6 @@ bool is_element_disabled_ : 1; bool is_readonly_ : 1; - enum class AncestorDisabledState { kUnknown, kEnabled, kDisabled }; - mutable AncestorDisabledState ancestor_disabled_state_ = - AncestorDisabledState::kUnknown; - enum class DataListAncestorState { kUnknown, kInsideDataList,
diff --git a/third_party/blink/renderer/core/page/scrolling/scroll_metrics_test.cc b/third_party/blink/renderer/core/page/scrolling/scroll_metrics_test.cc index 3daa237..e7e6a848d 100644 --- a/third_party/blink/renderer/core/page/scrolling/scroll_metrics_test.cc +++ b/third_party/blink/renderer/core/page/scrolling/scroll_metrics_test.cc
@@ -159,8 +159,7 @@ if (base::FeatureList::IsEnabled(::features::kScrollUnification)) { // cc reports the below reasons because #box is not composited. EXPECT_TOUCH_BUCKET( - BucketIndex(cc::MainThreadScrollingReason::kNonFastScrollableRegion), - 1); + BucketIndex(cc::MainThreadScrollingReason::kFailedHitTest), 1); EXPECT_TOUCH_BUCKET( BucketIndex(cc::MainThreadScrollingReason::kNotOpaqueForTextAndLCDText), 1); @@ -196,8 +195,7 @@ if (base::FeatureList::IsEnabled(::features::kScrollUnification)) { // cc reports the below reasons because #box is not composited. EXPECT_WHEEL_BUCKET( - BucketIndex(cc::MainThreadScrollingReason::kNonFastScrollableRegion), - 1); + BucketIndex(cc::MainThreadScrollingReason::kFailedHitTest), 1); EXPECT_WHEEL_BUCKET( BucketIndex(cc::MainThreadScrollingReason::kNotOpaqueForTextAndLCDText), 1); @@ -245,8 +243,7 @@ if (base::FeatureList::IsEnabled(::features::kScrollUnification)) { // cc reports the below reasons because #box is not composited. EXPECT_WHEEL_BUCKET( - BucketIndex(cc::MainThreadScrollingReason::kNonFastScrollableRegion), - 1); + BucketIndex(cc::MainThreadScrollingReason::kFailedHitTest), 1); EXPECT_WHEEL_BUCKET( BucketIndex(cc::MainThreadScrollingReason::kNotOpaqueForTextAndLCDText), 1); @@ -308,8 +305,7 @@ if (base::FeatureList::IsEnabled(::features::kScrollUnification)) { // cc reports the below reasons because #box is not composited. EXPECT_WHEEL_BUCKET( - BucketIndex(cc::MainThreadScrollingReason::kNonFastScrollableRegion), - 1); + BucketIndex(cc::MainThreadScrollingReason::kFailedHitTest), 1); EXPECT_WHEEL_BUCKET( BucketIndex(cc::MainThreadScrollingReason::kNotOpaqueForTextAndLCDText), 1); @@ -346,14 +342,13 @@ if (base::FeatureList::IsEnabled(::features::kScrollUnification)) { // The overflow: hidden element is still a non-fast scroll region, so cc // reports the following for the second scroll: - // kNonFastScrollableRegion + // kFailedHitTest // kScrollingOnMainForAnyReason // // Since #box is overflow: hidden, the hit test returns the viewport, and // so we do not log kNoScrollingLayer again. EXPECT_WHEEL_BUCKET( - BucketIndex(cc::MainThreadScrollingReason::kNonFastScrollableRegion), - 1); + BucketIndex(cc::MainThreadScrollingReason::kFailedHitTest), 1); EXPECT_WHEEL_BUCKET( cc::MainThreadScrollingReason::kScrollingOnMainForAnyReason, 1); EXPECT_WHEEL_TOTAL(2);
diff --git a/third_party/blink/renderer/core/page/scrolling/scrolling_test.cc b/third_party/blink/renderer/core/page/scrolling/scrolling_test.cc index 28ac21b6..72e10ec 100644 --- a/third_party/blink/renderer/core/page/scrolling/scrolling_test.cc +++ b/third_party/blink/renderer/core/page/scrolling/scrolling_test.cc
@@ -1114,11 +1114,6 @@ } TEST_P(ScrollingTest, WheelEventRegionUpdatedOnSubscrollerScrollChange) { - if (RuntimeEnabledFeatures::CompositeScrollAfterPaintEnabled()) { - // TODO(crbug.com/1414885): Fix wheel_event_region. - return; - } - SetPreferCompositingToLCDText(false); LoadHTML(R"HTML( <style> @@ -1376,11 +1371,6 @@ } TEST_P(ScrollingTest, NonFastScrollableRegionWithBorder) { - if (RuntimeEnabledFeatures::CompositeScrollAfterPaintEnabled()) { - // TODO(crbug.com/1414885): Fix non_fast_scrollable_region. - return; - } - SetPreferCompositingToLCDText(false); LoadHTML(R"HTML( <!DOCTYPE html> @@ -1405,11 +1395,6 @@ } TEST_P(ScrollingTest, ElementRegionCaptureData) { - if (RuntimeEnabledFeatures::CompositeScrollAfterPaintEnabled()) { - // TODO(crbug.com/1414885): Fix this test. - return; - } - LoadHTML(R"HTML( <head> <style type="text/css"> @@ -1605,11 +1590,6 @@ } TEST_P(ScrollingTest, NestedIFramesMainThreadScrollingRegion) { - if (RuntimeEnabledFeatures::CompositeScrollAfterPaintEnabled()) { - // TODO(crbug.com/1414885): Fix non_fast_scrollable_region. - return; - } - // This page has an absolute IFRAME. It contains a scrollable child DIV // that's nested within an intermediate IFRAME. SetPreferCompositingToLCDText(false); @@ -2260,10 +2240,6 @@ // scroller with an inset box shadow, and ensuring that scroller generates a // compositor scroll node with the proper noncomposited reasons set. TEST_P(UnifiedScrollingSimTest, ScrollNodeForEmbeddedScrollers) { - if (RuntimeEnabledFeatures::CompositeScrollAfterPaintEnabled()) { - // TODO(crbug.com/1414885): Fix this test. - return; - } if (!base::FeatureList::IsEnabled(::features::kScrollUnification)) { // This test requires scroll unification. return;
diff --git a/third_party/blink/renderer/core/paint/paint_and_raster_invalidation_test.cc b/third_party/blink/renderer/core/paint/paint_and_raster_invalidation_test.cc index ab54bb1..2d672c8 100644 --- a/third_party/blink/renderer/core/paint/paint_and_raster_invalidation_test.cc +++ b/third_party/blink/renderer/core/paint/paint_and_raster_invalidation_test.cc
@@ -404,10 +404,6 @@ } TEST_P(PaintAndRasterInvalidationTest, NonCompositedLayoutViewResize) { - if (RuntimeEnabledFeatures::CompositeScrollAfterPaintEnabled()) { - // TODO(crbug.com/1414885): Fix this test. - return; - } ScopedPreferNonCompositedScrollingForTest non_composited_scrolling(true); SetBodyInnerHTML(R"HTML( @@ -426,13 +422,14 @@ )HTML"); UpdateAllLifecyclePhasesForTest(); Element* iframe = GetDocument().getElementById("iframe"); + LayoutView* iframe_layout_view = ChildDocument().View()->GetLayoutView(); Element* content = ChildDocument().getElementById("content"); EXPECT_EQ(kBackgroundPaintInContentsSpace, - content->GetLayoutObject() - ->View() - ->ComputeBackgroundPaintLocationIfComposited()); - EXPECT_EQ(kBackgroundPaintInBorderBoxSpace, - content->GetLayoutObject()->View()->GetBackgroundPaintLocation()); + iframe_layout_view->ComputeBackgroundPaintLocationIfComposited()); + EXPECT_EQ(RuntimeEnabledFeatures::CompositeScrollAfterPaintEnabled() + ? kBackgroundPaintInContentsSpace + : kBackgroundPaintInBorderBoxSpace, + iframe_layout_view->GetBackgroundPaintLocation()); // Resize the content. GetDocument().View()->SetTracksRasterInvalidations(true); @@ -448,7 +445,11 @@ UpdateAllLifecyclePhasesForTest(); // The iframe doesn't have anything visible by itself, so we only issue // raster invalidation for the frame contents. - const auto* client = content->GetLayoutObject()->View(); + const auto* client = + RuntimeEnabledFeatures::CompositeScrollAfterPaintEnabled() + ? &iframe_layout_view->GetScrollableArea() + ->GetScrollingBackgroundDisplayItemClient() + : iframe_layout_view; EXPECT_THAT( GetRasterInvalidationTracking()->Invalidations(), UnorderedElementsAre(RasterInvalidationInfo{ @@ -460,12 +461,7 @@ TEST_P(PaintAndRasterInvalidationTest, FullInvalidationWithHTMLTransform) { GetDocument().documentElement()->setAttribute(html_names::kStyleAttr, "transform: scale(0.5)"); - const DisplayItemClient* client = - &GetDocument() - .View() - ->GetLayoutView() - ->GetScrollableArea() - ->GetScrollingBackgroundDisplayItemClient(); + const DisplayItemClient& client = ViewScrollingBackgroundClient(); UpdateAllLifecyclePhasesForTest(); GetDocument().View()->SetTracksRasterInvalidations(true); @@ -475,19 +471,15 @@ EXPECT_THAT( GetRasterInvalidationTracking()->Invalidations(), UnorderedElementsAre( - RasterInvalidationInfo{client->Id(), client->DebugName(), + RasterInvalidationInfo{client.Id(), client.DebugName(), gfx::Rect(0, 0, 500, 500), PaintInvalidationReason::kBackground}, - RasterInvalidationInfo{client->Id(), client->DebugName(), + RasterInvalidationInfo{client.Id(), client.DebugName(), gfx::Rect(0, 0, 500, 500), PaintInvalidationReason::kBackground})); } TEST_P(PaintAndRasterInvalidationTest, NonCompositedLayoutViewGradientResize) { - if (RuntimeEnabledFeatures::CompositeScrollAfterPaintEnabled()) { - // TODO(crbug.com/1414885): Fix this test. - return; - } ScopedPreferNonCompositedScrollingForTest non_composited_scrolling(true); SetBodyInnerHTML(R"HTML( @@ -510,17 +502,37 @@ )HTML"); UpdateAllLifecyclePhasesForTest(); Element* iframe = GetDocument().getElementById("iframe"); + const auto* iframe_layout_view = ChildDocument().View()->GetLayoutView(); Element* content = ChildDocument().getElementById("content"); // Resize the content. GetDocument().View()->SetTracksRasterInvalidations(true); content->setAttribute(html_names::kStyleAttr, "height: 500px"); UpdateAllLifecyclePhasesForTest(); - const auto* client = content->GetLayoutObject()->View(); - EXPECT_THAT(GetRasterInvalidationTracking()->Invalidations(), - UnorderedElementsAre(RasterInvalidationInfo{ - client->Id(), client->DebugName(), gfx::Rect(0, 0, 100, 100), - PaintInvalidationReason::kBackground})); + const auto* client = + RuntimeEnabledFeatures::CompositeScrollAfterPaintEnabled() + ? &iframe_layout_view->GetScrollableArea() + ->GetScrollingBackgroundDisplayItemClient() + : iframe_layout_view; + if (RuntimeEnabledFeatures::CompositeScrollAfterPaintEnabled()) { + // The two invalidations are for the old background and the new background. + // The rects are the same because they are clipped by the layer bounds. + EXPECT_THAT( + GetRasterInvalidationTracking()->Invalidations(), + UnorderedElementsAre( + RasterInvalidationInfo{client->Id(), client->DebugName(), + gfx::Rect(0, 0, 100, 100), + PaintInvalidationReason::kBackground}, + RasterInvalidationInfo{client->Id(), client->DebugName(), + gfx::Rect(0, 0, 100, 100), + PaintInvalidationReason::kBackground})); + } else { + EXPECT_THAT( + GetRasterInvalidationTracking()->Invalidations(), + UnorderedElementsAre(RasterInvalidationInfo{ + client->Id(), client->DebugName(), gfx::Rect(0, 0, 100, 100), + PaintInvalidationReason::kBackground})); + } GetDocument().View()->SetTracksRasterInvalidations(false); // Resize the iframe. @@ -529,10 +541,23 @@ UpdateAllLifecyclePhasesForTest(); // The iframe doesn't have anything visible by itself, so we only issue // raster invalidation for the frame contents. - EXPECT_THAT(GetRasterInvalidationTracking()->Invalidations(), - UnorderedElementsAre(RasterInvalidationInfo{ - client->Id(), client->DebugName(), gfx::Rect(0, 0, 100, 200), - PaintInvalidationReason::kBackground})); + if (RuntimeEnabledFeatures::CompositeScrollAfterPaintEnabled()) { + EXPECT_THAT( + GetRasterInvalidationTracking()->Invalidations(), + UnorderedElementsAre( + RasterInvalidationInfo{client->Id(), client->DebugName(), + gfx::Rect(0, 100, 100, 100), + PaintInvalidationReason::kIncremental}, + RasterInvalidationInfo{client->Id(), client->DebugName(), + gfx::Rect(0, 0, 100, 200), + PaintInvalidationReason::kBackground})); + } else { + EXPECT_THAT( + GetRasterInvalidationTracking()->Invalidations(), + UnorderedElementsAre(RasterInvalidationInfo{ + client->Id(), client->DebugName(), gfx::Rect(0, 0, 100, 200), + PaintInvalidationReason::kBackground})); + } GetDocument().View()->SetTracksRasterInvalidations(false); } @@ -652,11 +677,6 @@ TEST_P(PaintAndRasterInvalidationTest, NonCompositedBackgroundAttachmentLocalResize) { - if (RuntimeEnabledFeatures::CompositeScrollAfterPaintEnabled()) { - // TODO(crbug.com/1414885): Fix this test. - return; - } - SetUpHTML(*this); Element* target = GetDocument().getElementById("target"); auto* object = target->GetLayoutBox(); @@ -669,7 +689,9 @@ UpdateAllLifecyclePhasesForTest(); EXPECT_EQ(kBackgroundPaintInContentsSpace, object->ComputeBackgroundPaintLocationIfComposited()); - EXPECT_EQ(kBackgroundPaintInBorderBoxSpace, + EXPECT_EQ(RuntimeEnabledFeatures::CompositeScrollAfterPaintEnabled() + ? kBackgroundPaintInContentsSpace + : kBackgroundPaintInBorderBoxSpace, object->GetBackgroundPaintLocation()); // Resize the content.
diff --git a/third_party/blink/renderer/platform/media/hls_data_source_provider_impl.cc b/third_party/blink/renderer/platform/media/hls_data_source_provider_impl.cc index 444e2e5..66697a80 100644 --- a/third_party/blink/renderer/platform/media/hls_data_source_provider_impl.cc +++ b/third_party/blink/renderer/platform/media/hls_data_source_provider_impl.cc
@@ -127,7 +127,8 @@ tick_clock); } -void HlsDataSourceProviderImpl::SetOwner(media::HlsDemuxer* owner) { +void HlsDataSourceProviderImpl::SetOwner( + media::HlsManifestDemuxerEngine* owner) { DCHECK(main_task_runner_->BelongsToCurrentThread()); DCHECK(!owner_ && owner); owner_ = owner;
diff --git a/third_party/blink/renderer/platform/media/hls_data_source_provider_impl.h b/third_party/blink/renderer/platform/media/hls_data_source_provider_impl.h index 1f4c3c74..ec2d82f 100644 --- a/third_party/blink/renderer/platform/media/hls_data_source_provider_impl.h +++ b/third_party/blink/renderer/platform/media/hls_data_source_provider_impl.h
@@ -32,9 +32,9 @@ scoped_refptr<base::SequencedTaskRunner> media_task_runner, const base::TickClock* tick_clock); - void SetOwner(media::HlsDemuxer* owner) override; + void SetOwner(media::HlsManifestDemuxerEngine* owner) override; - // |media::HlsDemuxer::DataSourceProvider| implementation + // |media::HlsManifestDemuxerEngine::DataSourceProvider| implementation void RequestDataSource(GURL uri, absl::optional<media::hls::types::ByteRange> range, RequestCb callback) override; @@ -64,7 +64,7 @@ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_; scoped_refptr<base::SequencedTaskRunner> media_task_runner_; std::unique_ptr<BufferedDataSourceHostImpl> buffered_data_source_host_; - media::HlsDemuxer* owner_ = nullptr; + media::HlsManifestDemuxerEngine* owner_ = nullptr; // Set of all active `MultiBufferDataSource`s belonging to the // `HlsDataSourceImpl`s created by this provider. This uses a
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5 index b65e6d7..3a94dbf 100644 --- a/third_party/blink/renderer/platform/runtime_enabled_features.json5 +++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -2291,6 +2291,12 @@ base_feature: "none", }, { + // Kill switch for crbug.com/1427047 fix. + // TODO(xiaochengh): Remove in M117. + name: "NonReentrantFieldSetDisable", + status: "stable", + }, + { name: "NotificationConstructor", // Android won't be able to reliably support non-persistent notifications, the // intended behavior for which is in flux by itself.
diff --git a/third_party/blink/renderer/platform/widget/input/input_handler_proxy.cc b/third_party/blink/renderer/platform/widget/input/input_handler_proxy.cc index 83b52be..ebeb76ca 100644 --- a/third_party/blink/renderer/platform/widget/input/input_handler_proxy.cc +++ b/third_party/blink/renderer/platform/widget/input/input_handler_proxy.cc
@@ -79,14 +79,14 @@ // If the target scroller comes from a main thread hit test, we're in // scroll unification. - scroll_state_data.main_thread_hit_tested_reasons = - event.data.scroll_begin.main_thread_hit_tested_reasons; - DCHECK(!event.data.scroll_begin.main_thread_hit_tested_reasons || + scroll_state_data.is_main_thread_hit_tested = + event.data.scroll_begin.main_thread_hit_tested; + DCHECK(!event.data.scroll_begin.main_thread_hit_tested || base::FeatureList::IsEnabled(::features::kScrollUnification)); } else { // If a main thread hit test didn't yield a target we should have // discarded this event before this point. - DCHECK(!event.data.scroll_begin.main_thread_hit_tested_reasons); + DCHECK(!event.data.scroll_begin.main_thread_hit_tested); } break; @@ -386,14 +386,11 @@ DCHECK(base::FeatureList::IsEnabled(::features::kScrollUnification)); DCHECK_EQ(event->Event().GetType(), WebGestureEvent::Type::kGestureScrollBegin); - DCHECK(scroll_begin_main_thread_hit_test_reasons_); + DCHECK(hit_testing_scroll_begin_on_main_thread_); DCHECK(currently_active_gesture_device_); DCHECK(input_handler_); - uint32_t main_thread_hit_test_reasons = - scroll_begin_main_thread_hit_test_reasons_; - scroll_begin_main_thread_hit_test_reasons_ = - cc::MainThreadScrollingReason::kNotScrollingOnMain; + hit_testing_scroll_begin_on_main_thread_ = false; // HandleGestureScrollBegin has logic to end an existing scroll when an // unexpected scroll begin arrives. We currently think we're in a scroll @@ -406,8 +403,7 @@ if (hit_test_result) { gesture_event->data.scroll_begin.scrollable_area_element_id = hit_test_result.GetInternalValue(); - gesture_event->data.scroll_begin.main_thread_hit_tested_reasons = - main_thread_hit_test_reasons; + gesture_event->data.scroll_begin.main_thread_hit_tested = true; if (metrics) { // The event is going to be re-processed on the compositor thread; so, @@ -520,7 +516,7 @@ // Block flushing the compositor gesture event queue while there's an async // scroll begin hit test outstanding. We'll flush the queue when the hit test // responds. - if (scroll_begin_main_thread_hit_test_reasons_) { + if (hit_testing_scroll_begin_on_main_thread_) { DCHECK(base::FeatureList::IsEnabled(::features::kScrollUnification)); return false; } @@ -848,7 +844,7 @@ void InputHandlerProxy::RecordScrollBegin( WebGestureDevice device, uint32_t reasons_from_scroll_begin, - uint32_t main_thread_hit_tested_reasons, + bool was_main_thread_hit_tested, uint32_t main_thread_repaint_reasons) { if (device != WebGestureDevice::kTouchpad && device != WebGestureDevice::kScrollbar && @@ -876,7 +872,7 @@ disposition.has_value() && disposition == DID_NOT_HANDLE; bool blocked_on_main_at_begin = - blocked_on_main_thread_handler || main_thread_hit_tested_reasons; + blocked_on_main_thread_handler || was_main_thread_hit_tested; auto scroll_start_state = RecordScrollingThread( is_compositor_scroll, blocked_on_main_at_begin, device); @@ -892,7 +888,9 @@ ? cc::MainThreadScrollingReason::kWheelEventHandlerRegion : cc::MainThreadScrollingReason::kTouchEventHandlerRegion); } - reportable_reasons |= main_thread_hit_tested_reasons; + if (was_main_thread_hit_tested) { + reportable_reasons |= cc::MainThreadScrollingReason::kFailedHitTest; + } // With scroll unification, we never scroll "on main" from the perspective // of cc::InputHandler, but we still want to log reasons if the user will not @@ -991,17 +989,16 @@ // If we need a hit test from the main thread, we'll reinject this scroll // begin event once the hit test is complete so avoid everything below for // now, it'll be run on the second iteration. - if (scroll_status.main_thread_hit_test_reasons) { + if (scroll_status.needs_main_thread_hit_test) { DCHECK(base::FeatureList::IsEnabled(::features::kScrollUnification)); - scroll_begin_main_thread_hit_test_reasons_ = - scroll_status.main_thread_hit_test_reasons; + hit_testing_scroll_begin_on_main_thread_ = true; return REQUIRES_MAIN_THREAD_HIT_TEST; } if (scroll_status.thread != ScrollThread::SCROLL_IGNORED) { RecordScrollBegin(gesture_event.SourceDevice(), scroll_status.main_thread_scrolling_reasons, - scroll_state.main_thread_hit_tested_reasons(), + scroll_state.is_main_thread_hit_tested(), scroll_status.main_thread_repaint_reasons); }
diff --git a/third_party/blink/renderer/platform/widget/input/input_handler_proxy.h b/third_party/blink/renderer/platform/widget/input/input_handler_proxy.h index e8ca90d3..a0c340d 100644 --- a/third_party/blink/renderer/platform/widget/input/input_handler_proxy.h +++ b/third_party/blink/renderer/platform/widget/input/input_handler_proxy.h
@@ -322,7 +322,7 @@ void RecordScrollBegin(blink::WebGestureDevice device, uint32_t reasons_from_scroll_begin, - uint32_t main_thread_hit_tested_reasons, + bool was_main_thread_hit_tested, uint32_t main_thread_repaint_reasons); bool HasQueuedEventsReadyForDispatch(); @@ -401,14 +401,13 @@ bool skip_touch_filter_discrete_ = false; bool skip_touch_filter_all_ = false; - // This is set when the input handler proxy has requested that the client + // This bit is set when the input handler proxy has requested that the client // perform a hit test for a scroll begin on the main thread. During that // time, scroll updates need to be queued. The reply from the main thread // will come by calling ContinueScrollBeginAfterMainThreadHitTest where the // queue will be flushed and this bit cleared. Used only in scroll // unification. - uint32_t scroll_begin_main_thread_hit_test_reasons_ = - cc::MainThreadScrollingReason::kNotScrollingOnMain; + bool hit_testing_scroll_begin_on_main_thread_ = false; // This bit can be used to disable event attribution in cases where the // hit test information is unnecessary (e.g. tests).
diff --git a/third_party/blink/renderer/platform/widget/input/input_handler_proxy_unittest.cc b/third_party/blink/renderer/platform/widget/input/input_handler_proxy_unittest.cc index 9011d68..598e185 100644 --- a/third_party/blink/renderer/platform/widget/input/input_handler_proxy_unittest.cc +++ b/third_party/blink/renderer/platform/widget/input/input_handler_proxy_unittest.cc
@@ -317,25 +317,25 @@ return point; } -const cc::InputHandler::ScrollStatus kImplThreadScrollState{ +const cc::InputHandler::ScrollStatus kImplThreadScrollState( cc::InputHandler::ScrollThread::SCROLL_ON_IMPL_THREAD, - cc::MainThreadScrollingReason::kNotScrollingOnMain}; + cc::MainThreadScrollingReason::kNotScrollingOnMain); -const cc::InputHandler::ScrollStatus kRequiresMainThreadHitTestState{ +const cc::InputHandler::ScrollStatus kRequiresMainThreadHitTestState( cc::InputHandler::ScrollThread::SCROLL_ON_IMPL_THREAD, cc::MainThreadScrollingReason::kNotScrollingOnMain, - cc::MainThreadScrollingReason::kNonFastScrollableRegion}; + /*needs_main_thread_hit_test=*/true); constexpr auto kSampleMainThreadScrollingReason = cc::MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects; -const cc::InputHandler::ScrollStatus kMainThreadScrollState{ +const cc::InputHandler::ScrollStatus kMainThreadScrollState( cc::InputHandler::ScrollThread::SCROLL_ON_MAIN_THREAD, - kSampleMainThreadScrollingReason}; + kSampleMainThreadScrollingReason); -const cc::InputHandler::ScrollStatus kScrollIgnoredScrollState{ +const cc::InputHandler::ScrollStatus kScrollIgnoredScrollState( cc::InputHandler::ScrollThread::SCROLL_IGNORED, - cc::MainThreadScrollingReason::kNotScrollingOnMain}; + cc::MainThreadScrollingReason::kNotScrollingOnMain); } // namespace @@ -2041,8 +2041,7 @@ WebInputEvent::Type::kGestureScrollBegin, WebInputEvent::kNoModifiers, TimeForInputEvents(), WebGestureDevice::kTouchpad); gsb->data.scroll_begin.scrollable_area_element_id = 0; - gsb->data.scroll_begin.main_thread_hit_tested_reasons = - cc::MainThreadScrollingReason::kNotScrollingOnMain; + gsb->data.scroll_begin.main_thread_hit_tested = false; gsb->data.scroll_begin.delta_x_hint = 0; gsb->data.scroll_begin.delta_y_hint = 10; gsb->data.scroll_begin.pointer_count = 0; @@ -2087,8 +2086,7 @@ } bool MainThreadHitTestInProgress() const { - return input_handler_proxy_.scroll_begin_main_thread_hit_test_reasons_ != - cc::MainThreadScrollingReason::kNotScrollingOnMain; + return input_handler_proxy_.hit_testing_scroll_begin_on_main_thread_; } void BeginFrame() { @@ -2268,9 +2266,7 @@ mock_input_handler_, ScrollBegin( AllOf(Property(&ScrollState::target_element_id, Eq(ElementId())), - Property( - &ScrollState::main_thread_hit_tested_reasons, - Eq(cc::MainThreadScrollingReason::kNotScrollingOnMain))), + Property(&ScrollState::is_main_thread_hit_tested, Eq(false))), _)) .WillOnce(Return(kRequiresMainThreadHitTestState)); DispatchEvent(ScrollBegin()); @@ -2287,9 +2283,7 @@ mock_input_handler_, ScrollBegin( AllOf(Property(&ScrollState::target_element_id, Eq(kHitTestResult)), - Property(&ScrollState::main_thread_hit_tested_reasons, - Eq(cc::MainThreadScrollingReason:: - kNonFastScrollableRegion))), + Property(&ScrollState::is_main_thread_hit_tested, Eq(true))), _)) .Times(1); @@ -3754,8 +3748,7 @@ VERIFY_AND_RESET_MOCKS(); gesture_.data.scroll_begin.scrollable_area_element_id = 1; - gesture_.data.scroll_begin.main_thread_hit_tested_reasons = - cc::MainThreadScrollingReason::kNonFastScrollableRegion; + gesture_.data.scroll_begin.main_thread_hit_tested = true; EXPECT_CALL(mock_input_handler_, ScrollBegin(_, _)) .WillOnce(testing::Return(kImplThreadScrollState)); @@ -3772,7 +3765,7 @@ VERIFY_AND_RESET_MOCKS(); EXPECT_MAIN_THREAD_WHEEL_SCROLL_SAMPLE( - cc::MainThreadScrollingReason::kNonFastScrollableRegion); + cc::MainThreadScrollingReason::kFailedHitTest); } TEST_P(InputHandlerProxyMainThreadScrollingReasonTest,
diff --git a/third_party/blink/tools/blinkpy/tool/commands/lint_wpt.py b/third_party/blink/tools/blinkpy/tool/commands/lint_wpt.py index 33b0b48c..cb35116 100644 --- a/third_party/blink/tools/blinkpy/tool/commands/lint_wpt.py +++ b/third_party/blink/tools/blinkpy/tool/commands/lint_wpt.py
@@ -7,16 +7,20 @@ import io import logging import optparse -from typing import List, Optional, Tuple +import pathlib +import urllib.parse +from typing import Iterator, List, Optional, Tuple from blinkpy.common import path_finder from blinkpy.common.host import Host from blinkpy.tool.commands.command import Command +from blinkpy.w3c.wpt_manifest import WPTManifest path_finder.bootstrap_wpt_imports() from tools.lint import lint as wptlint from tools.lint import rules from wptrunner import wptmanifest +from wptrunner.wptmanifest import node as wptnode _log = logging.getLogger(__name__) @@ -37,6 +41,35 @@ """ +class MetadataUnsortedSection(MetadataRule): + name = 'META-UNSORTED-SECTION' + description = ('Section contains unsorted keys or subsection headings: ' + '%(predecessor)r should precede %(successor)r') + to_fix = """ + Within a block (indentation level), all keys must precede all headings, and + keys must be sorted lexographically amongst themselves (and likewise for + headings). + """ + + +class MetadataEmptySection(MetadataRule): + name = 'META-EMPTY-SECTION' + description = 'Empty section can be removed: %(heading)r' + to_fix = """ + A section without keys or subsections has no effect and should be removed. + The (sub)tests represented by empty sections default to enabled and + all-pass. + """ + + +class MetadataUnknownTest(MetadataRule): + name = 'META-UNKNOWN-TEST' + description = 'Test ID does not exist: %(test)r' + to_fix = """ + Check that the top-level section headings are not misspelled. + """ + + LintError = Tuple[str, str, str, Optional[int]] @@ -84,19 +117,80 @@ def check_metadata(self, repo_root: str, path: str, metadata_file: io.BytesIO) -> List[LintError]: - if not self._is_metadata_file(repo_root, path): + # TODO(crbug.com/1406669): Check `__dir__.ini` too for relevant rules. + manifest = self._manifest(repo_root) + if not self._is_metadata_file(manifest, path): return [] try: ast = wptmanifest.parse(metadata_file) except wptmanifest.parser.ParseError as error: context = {'detail': error.detail} return [MetadataBadSyntax.error(path, context, error.line)] - # TODO(crbug.com/1406669): Implement remaining rules. - return [] + return [ + *self._check_metadata_sorted(path, ast), + *self._check_metadata_nonempty_sections(path, ast), + *self._check_metadata_valid_test_ids(path, ast, manifest), + # TODO(crbug.com/1406669): Implement remaining rules. + ] - def _is_metadata_file(self, repo_root: str, path: str) -> bool: - test_path, extension = self._fs.splitext(path) + def _check_metadata_sorted(self, path: str, + node: wptnode.Node) -> Iterator[LintError]: + if not isinstance(node, wptnode.DataNode): + return + sort_key = lambda child: (isinstance(child, wptnode.DataNode), child. + data or '') + sorted_children = sorted(node.children, key=sort_key) + for child, sorted_child in zip(node.children, sorted_children): + if child is not sorted_child: + # The original line numbers are lost after parsing, and + # attempting to rediscover them with diffing seems fragile and + # potentially inaccurate. Therefore, instead of reporting a line + # number, show the exact contents of the first pair of + # out-of-order lines. This is probably more helpful anyway. + context = { + 'predecessor': _format_node(sorted_child), + 'successor': _format_node(child), + } + yield MetadataUnsortedSection.error(path, context) + # Only report one error per block to avoid spam. + break + for child in node.children: + yield from self._check_metadata_sorted(path, child) + + def _check_metadata_nonempty_sections( + self, path: str, node: wptnode.Node) -> Iterator[LintError]: + if not isinstance(node, wptnode.DataNode): + return + if not node.children: + context = {'heading': _format_node(node)} + yield MetadataEmptySection.error(path, context) + for child in node.children: + yield from self._check_metadata_nonempty_sections(path, child) + + def _check_metadata_valid_test_ids( + self, + path: str, + node: wptnode.Node, + manifest: WPTManifest, + ) -> Iterator[LintError]: + for child in node.children: + if isinstance(child, wptnode.DataNode): + assert child.data + # Intentionally replaces the basename in `path`. + test_id = urllib.parse.urljoin( + pathlib.Path(path).as_posix(), child.data) + if not manifest.is_test_url(test_id): + yield MetadataUnknownTest.error(path, {'test': test_id}) + + def _manifest(self, repo_root: str) -> WPTManifest: wpt_dir = self._fs.normpath( self._fs.relpath(repo_root, self._finder.path_from_web_tests())) - manifest = self._default_port.wpt_manifest(wpt_dir) + return self._default_port.wpt_manifest(wpt_dir) + + def _is_metadata_file(self, manifest: WPTManifest, path: str) -> bool: + test_path, extension = self._fs.splitext(path) return extension == '.ini' and manifest.is_test_file(test_path) + + +def _format_node(node: wptnode.Node) -> str: + return wptmanifest.serialize(node).splitlines()[0].strip()
diff --git a/third_party/blink/tools/blinkpy/tool/commands/lint_wpt_unittest.py b/third_party/blink/tools/blinkpy/tool/commands/lint_wpt_unittest.py index f9ff7c5..de211d1 100644 --- a/third_party/blink/tools/blinkpy/tool/commands/lint_wpt_unittest.py +++ b/third_party/blink/tools/blinkpy/tool/commands/lint_wpt_unittest.py
@@ -36,11 +36,13 @@ 'd933fd981d4a33ba82fb2b000234859bdda1494e', [None, {}], ], - 'multiglob.https.any.js': [ - 'd6498c3e388e0c637830fa080cca78b0ab0e5305', - ['dir/multiglob.https.any.html', {}], - ['dir/multiglob.https.any.worker.html', {}], - ], + 'dir': { + 'multiglob.https.any.js': [ + 'd6498c3e388e0c637830fa080cca78b0ab0e5305', + ['dir/multiglob.https.any.html', {}], + ['dir/multiglob.https.any.worker.html', {}], + ], + }, 'variant.html': [ 'b8db5972284d1ac6bbda0da81621d9bca5d04ee7', ['variant.html?foo=bar/abc', {}], @@ -92,6 +94,21 @@ path='wptrunner.blink.ini') self.assertEqual(errors, []) + def test_metadata_valid(self): + errors = self._check_metadata( + """\ + [variant.html?foo=bar/abc] + expected: FAIL + [variant.html?foo=baz] + disabled: never completes + expected: TIMEOUT + [subtest 1] + expected: TIMEOUT + [subtest 2] + expected: NOTRUN + """, 'variant.html.ini') + self.assertEqual(errors, []) + def test_metadata_bad_syntax(self): (error, ) = self._check_metadata("""\ [test.html] @@ -101,7 +118,81 @@ self.assertEqual(name, 'META-BAD-SYNTAX') self.assertEqual(path, 'test.html.ini') self.assertEqual( - 'WPT metadata file could not be parsed: Junk before EOL u', - description) + description, + 'WPT metadata file could not be parsed: Junk before EOL u') # Note the 1-indexed convention. self.assertEqual(line, 2) + + def test_metadata_unsorted_sections(self): + out_of_order_tests, out_of_order_subtests = self._check_metadata( + """\ + [variant.html?foo=baz] + expected: TIMEOUT + [subtest 2] + expected: NOTRUN + [subtest 1] + expected: TIMEOUT + + [variant.html?foo=bar/abc] + expected: TIMEOUT + """, 'variant.html.ini') + name, description, path, _ = out_of_order_tests + self.assertEqual(name, 'META-UNSORTED-SECTION') + self.assertEqual(path, 'variant.html.ini') + self.assertEqual( + description, + 'Section contains unsorted keys or subsection headings: ' + "'[variant.html?foo=bar/abc]' should precede " + "'[variant.html?foo=baz]'") + name, description, path, _ = out_of_order_subtests + self.assertEqual(name, 'META-UNSORTED-SECTION') + self.assertEqual(path, 'variant.html.ini') + self.assertEqual( + description, + 'Section contains unsorted keys or subsection headings: ' + "'[subtest 1]' should precede '[subtest 2]'") + + def test_metadata_empty_sections(self): + empty_subtest, empty_test = self._check_metadata( + """\ + [variant.html?foo=bar/abc] + [empty subtest] + + [variant.html?foo=baz] + """, 'variant.html.ini') + name, description, path, _ = empty_subtest + self.assertEqual(name, 'META-EMPTY-SECTION') + self.assertEqual(path, 'variant.html.ini') + self.assertEqual(description, + "Empty section can be removed: '[empty subtest]'") + name, description, path, _ = empty_test + self.assertEqual(name, 'META-EMPTY-SECTION') + self.assertEqual(path, 'variant.html.ini') + self.assertEqual( + description, + "Empty section can be removed: '[variant.html?foo=baz]'") + + def test_metadata_nonexistent_test(self): + error1, error2 = self._check_metadata( + """\ + [multiglob.https.any.html] + expected: ERROR + [multiglob.https.any.serviceworker.html] + expected: ERROR + [multiglob.https.any.sharedworker.html] + expected: ERROR + [multiglob.https.any.worker.html] + expected: ERROR + """, 'dir/multiglob.https.any.js.ini') + name, description, path, _ = error1 + self.assertEqual(name, 'META-UNKNOWN-TEST') + self.assertEqual(path, 'dir/multiglob.https.any.js.ini') + self.assertEqual( + description, 'Test ID does not exist: ' + "'dir/multiglob.https.any.serviceworker.html'") + name, description, path, _ = error2 + self.assertEqual(name, 'META-UNKNOWN-TEST') + self.assertEqual(path, 'dir/multiglob.https.any.js.ini') + self.assertEqual( + description, 'Test ID does not exist: ' + "'dir/multiglob.https.any.sharedworker.html'")
diff --git a/third_party/blink/tools/blinkpy/w3c/wpt_results_processor.py b/third_party/blink/tools/blinkpy/w3c/wpt_results_processor.py index ace6bb8..f31f88b 100644 --- a/third_party/blink/tools/blinkpy/w3c/wpt_results_processor.py +++ b/third_party/blink/tools/blinkpy/w3c/wpt_results_processor.py
@@ -699,7 +699,7 @@ artifacts_base_dir=self.fs.basename( self.artifacts_dir)) leaf = self._leaves[result.name] - if result.actual != ResultType.Pass: + if result.actual not in [ResultType.Pass, ResultType.Skip]: self._write_text_results(result.name, artifacts, result.actual_metadata, result.file_path) screenshots = (extra or {}).get('reftest_screenshots') or []
diff --git a/third_party/blink/tools/run_wpt_tests.py b/third_party/blink/tools/run_wpt_tests.py index 9afcf8f..8034eed 100755 --- a/third_party/blink/tools/run_wpt_tests.py +++ b/third_party/blink/tools/run_wpt_tests.py
@@ -397,6 +397,7 @@ # '--run-by-dir=0' so that tests can be more evenly distributed # among workers. options.fail_on_unexpected_pass = False + options.restart_on_unexpected = False options.restart_on_new_group = False options.run_by_dir = 0
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index 432cd602..573108c 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -875,10 +875,6 @@ crbug.com/1339051 [ Linux ] virtual/off-main-thread-css-paint/http/tests/csspaint/shadow-scale-with-page-zoom.html [ Failure ] -crbug.com/1414885 virtual/composite-scroll-after-paint/compositing/overflow/nested-render-surfaces-with-intervening-clip.html [ Failure ] -crbug.com/1414885 virtual/composite-scroll-after-paint/compositing/overflow/nested-render-surfaces.html [ Failure ] -crbug.com/1414885 virtual/composite-scroll-after-paint/scrollbars/listbox-scrollbar-combinations.html [ Failure ] - # ====== Paint team owned tests to here ====== # WPT speculative-parsing tests failing @@ -6709,3 +6705,6 @@ crbug.com/1416265 external/wpt/js-self-profiling/class-names.https.html [ Crash Pass ] crbug.com/1416265 external/wpt/js-self-profiling/cross-origin-script-no-cors.sub.html [ Crash Pass ] crbug.com/1416271 external/wpt/js-self-profiling/time-domain.window.html [ Crash Failure Pass ] + +# Flake 2023-04-07 +crbug.com/1431272 [ Win ] external/wpt/cookies/attributes/domain.sub.html [ Timeout Pass ]
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json index 7363ce0a..04c115c 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
@@ -268919,11 +268919,11 @@ "support": { ".cache": { "gitignore2.json": [ - "e37041b94f616eac59512a3fe8006d1ec7565ba1", + "5bf9ce69dad5202fcd7a09b4edcc1dca874e4637", [] ], "mtime.json": [ - "6612aefff2d3c679b0209866a8e45948a19cd990", + "369e2424a4945396d218184fee4ff57ade3cec99", [] ] }, @@ -287003,6 +287003,14 @@ [] ], "computed-margin-values": { + "flexbox-column-block-end-expected.txt": [ + "fac2ea6ac0b253c7869a38cac8fd045c80efc9cd", + [] + ], + "flexbox-column-block-end.html.ini": [ + "f57a4465fc351815743449f9557d907bb3af482e", + [] + ], "flexbox-column-block-start-expected.txt": [ "2744cb3e8742e557113613277ed667e0b4b6cd0f", [] @@ -287019,6 +287027,18 @@ "3507fb4e0cfb565160f0be55c1fb0ba9229065ac", [] ], + "flexbox-column-multi-line-block-end-expected.txt": [ + "906c67f9df4cc85aba9b1a6aa29bf50d0e85f61d", + [] + ], + "flexbox-column-multi-line-block-end.html.ini": [ + "f240a591913be09454698f0e743caccada4731b7", + [] + ], + "flexbox-column-multi-line-block-expected.txt": [ + "b68a40edccc7b1390b315bca450ffa15fb835990", + [] + ], "flexbox-column-multi-line-block-start-expected.txt": [ "ff439b422e932677ebb0d69a2d579d75f297c3fa", [] @@ -287027,6 +287047,10 @@ "95bd28e828154d7d9df3888cb8cc0a156b1545d1", [] ], + "flexbox-column-multi-line-block.html.ini": [ + "4298304d6dd8535ad663f8b7e20d697e9459b8c1", + [] + ], "flexbox-column-multi-line-inline-end-expected.txt": [ "996713014ca75f4cf1cd6b84633d1614fad1e134", [] @@ -287035,6 +287059,18 @@ "c8e1834793db927031b1443a73cf82d86558f210", [] ], + "flexbox-row-block-end-expected.txt": [ + "c356e0174246e0e8bcdacf4fdf6476cef26c7cfe", + [] + ], + "flexbox-row-block-end.html.ini": [ + "c043d05263d0b28a6afb2a2cfc917a4a6f4833b1", + [] + ], + "flexbox-row-block-expected.txt": [ + "ca44f7d5ad06bb563f1bf5d3093ccc8b21d89116", + [] + ], "flexbox-row-block-start-expected.txt": [ "15665df16442a84e3a3ed4533259c7977fb43840", [] @@ -287043,6 +287079,10 @@ "698ce340da867b1a44809638e911c01da5961ac2", [] ], + "flexbox-row-block.html.ini": [ + "4d37dd68a91a8729a8924022d3b4c728d0ad4107", + [] + ], "flexbox-row-inline-end-expected.txt": [ "72e40978824dc2f30ddfe90063d0825d77ad4fa9", [] @@ -287051,6 +287091,18 @@ "e43c3fe58c89a388c53c38f797d485ecaa6913a7", [] ], + "flexbox-row-multi-line-block-end-expected.txt": [ + "046ae10d600e28d1c5e35397c88fe7135293da42", + [] + ], + "flexbox-row-multi-line-block-end.html.ini": [ + "9a8cb6fc310d34c29f5d07604027c6b6d64457f6", + [] + ], + "flexbox-row-multi-line-block-expected.txt": [ + "03e67deb2c128998966d519ca84cb1112653cc32", + [] + ], "flexbox-row-multi-line-block-start-expected.txt": [ "2b9363e8f9ebcae0811fabd6289960a058f23212", [] @@ -287059,6 +287111,10 @@ "e2fea32ba8a1eab0e0d0591f38d7f72c1445340e", [] ], + "flexbox-row-multi-line-block.html.ini": [ + "1a6360e2ffe4131d19c76e07f77d318853e7b3d3", + [] + ], "flexbox-row-multi-line-inline-end-expected.txt": [ "856ae4a19a290244d9bc1ee93ac50ac0388ab6af", [] @@ -291865,6 +291921,10 @@ "163efd401c4d24ce205dc9c39431b79598a7fb6f", [] ], + "aspect-ratio-intrinsic-size-002.html.ini": [ + "45d27732d1dab694653e48e20c0f15b4b9ee61bf", + [] + ], "aspect-ratio-intrinsic-size-007-ref.html": [ "6d560db597fd312c69f14e90a2b74475dfe7a1a8", [] @@ -325410,6 +325470,10 @@ "8ca46ce015dd4ac01130fdd11f18dabc200afcc4", [] ], + "kind-of-widget-fallback-color-input-border-bottom-right-radius-001.html.ini": [ + "551231437dd9967e9aff80e496d7be9317fbd475", + [] + ], "kind-of-widget-fallback-color-input-border-bottom-style-001.html.ini": [ "781e3a390720e3062919d91b8b872054bbd0548f", [] @@ -325543,7 +325607,7 @@ [] ], "kind-of-widget-fallback-input-search-background-position-001.html.ini": [ - "99cd283bfdd9382c317c638a2dc731fb7e36e95e", + "133535d0d1baac683a2500f6d12aa1e02cbfc8e4", [] ], "kind-of-widget-fallback-input-search-border-bottom-style-001.html.ini": [ @@ -325634,6 +325698,10 @@ "9d37fdd0c88c9339108a74b2db534e9f58bb6697", [] ], + "kind-of-widget-fallback-input-search-text-border-bottom-right-radius-001.html.ini": [ + "ad56752051f70e9bf21f40b37ceb4bf60b3713fb", + [] + ], "kind-of-widget-fallback-input-search-text-border-bottom-style-001.html.ini": [ "97d3e9abbd45580da8e8d11ceb56891c87c8ee75", [] @@ -336123,7 +336191,7 @@ [] ], "overscroll-deltas.html.ini": [ - "34c5f53bdc4e416acfd7fd590cb0e68a97244737", + "007a415dbda34245605662eb3a729093404dd8ba", [] ], "overscroll-event-fired-to-scrolled-element.html.ini": [ @@ -336131,7 +336199,7 @@ [] ], "scroll_support.js": [ - "9b91b6b028cfd26d6e6a6b561761e75946c9143e", + "52c2f58723a2a39e9d652036d82d59475497c76e", [] ], "scrollend-event-fired-after-sequence-of-scrolls.tentative.html.ini": [ @@ -345963,6 +346031,12 @@ "33fe97a7d6100d1eeb31a71a972e4124d3b761d7", [] ], + "event-order": { + "before-load-hash-twice.html.ini": [ + "001a4e6b78d6e522a0d244a9c0a84f669908e555", + [] + ] + }, "persisted-user-state-restoration": { "resources": { "blank1.html": [ @@ -382719,7 +382793,7 @@ [] ], "helpers.js": [ - "728b098087e4ab3c67bb8cfd88126ffcf9f4315d", + "0a89c6d7f99374d66a827033e29476e379b624af", [] ], "requestStorageAccess-ABA.tentative.sub.https.window.js.ini": [ @@ -382764,7 +382838,7 @@ [] ], "embedded_responder.js": [ - "ab1ab30f6964130e6c4d09655c77cca3095596a4", + "634079289b01557189b1335ba7801c4eb6f6cc9b", [] ], "hasStorageAccess-ABA-iframe.https.html": [ @@ -384778,7 +384852,7 @@ [] ], "requestStorageAccessFor.sub.https.window.js.ini": [ - "f0f925ab226be3b289538a664f8d1504a01c5a15", + "cfb5c6c466b077d767acf5cff8b6ccb1bc8d723f", [] ], "resources": { @@ -384786,10 +384860,6 @@ "c9907203322112ffb01a50b09541e891250c4f5e", [] ], - "requestStorageAccess-integration-iframe.https.html": [ - "f4db5cf65ec6814036d40ab165b9705725df39fa", - [] - ], "requestStorageAccessFor-iframe.html": [ "050196dfdb9e66d2309a8f2286cb0a67eb34121b", [] @@ -387738,7 +387808,7 @@ [] ], "iframe-parent.html": [ - "021fffab68f5ae9fe2f72a6c3c0bf60a14b333c8", + "ec63045b4a0561d4119e6890195e15bc3b6410af", [] ], "iframe.html": [ @@ -387750,7 +387820,7 @@ [] ], "partitioned-parent.html": [ - "5dafce49657fbe948582cf3aead2decadad0fdc7", + "ec19c8dbaa69bb2d3b31c8c508f65f2bece23adb", [] ], "service-worker.js": [ @@ -391779,7 +391849,7 @@ [] ], "usbDevice-iframe.https.html.ini": [ - "2dfd92f2c609ba1e6c8bb499d0fcf83a85af5f31", + "21e89d3b0d38f59bacd6d1013a219d19047e3cc0", [] ] }, @@ -434454,6 +434524,13 @@ ], "margin-trim": { "computed-margin-values": { + "flexbox-column-block-end.html": [ + "ecc266378dde834b60266f5d7bdf29b2e9bf6ec0", + [ + null, + {} + ] + ], "flexbox-column-block-start.html": [ "6c760bb1f0912090952ef7266bf29f682ed999b7", [ @@ -434468,6 +434545,13 @@ {} ] ], + "flexbox-column-multi-line-block-end.html": [ + "61f11a9b31fee08a490994428d23a0d7cc50485f", + [ + null, + {} + ] + ], "flexbox-column-multi-line-block-start.html": [ "517619db49be1a7f42a7a48eea731dac1aeca008", [ @@ -434475,6 +434559,13 @@ {} ] ], + "flexbox-column-multi-line-block.html": [ + "e01067fbe2ad9a241ef3afc45cd9d43cc8cc4c52", + [ + null, + {} + ] + ], "flexbox-column-multi-line-inline-end.html": [ "4d3d5b5326cfcc301323226f5203bd91f440107e", [ @@ -434489,6 +434580,13 @@ {} ] ], + "flexbox-row-block-end.html": [ + "f5ca9854fe7e04a48b05d41338c720dab5083d0b", + [ + null, + {} + ] + ], "flexbox-row-block-start.html": [ "9597c9aa10fd7ca3940d16c5d201117240a38832", [ @@ -434496,6 +434594,13 @@ {} ] ], + "flexbox-row-block.html": [ + "6c35fa6ac22f5bd93a20f0e56882664f34d60c9c", + [ + null, + {} + ] + ], "flexbox-row-inline-end.html": [ "2c20625ed3811c861598d1d752afdf314043612d", [ @@ -434503,6 +434608,13 @@ {} ] ], + "flexbox-row-multi-line-block-end.html": [ + "f4c90c29f91b313b9bf8cc732a477e77ef12f95b", + [ + null, + {} + ] + ], "flexbox-row-multi-line-block-start.html": [ "c3190e1a93fff9b744f7834b8e2457e330296b0a", [ @@ -434510,6 +434622,13 @@ {} ] ], + "flexbox-row-multi-line-block.html": [ + "1db5680306b7814677839762bed4d8cc8755f576", + [ + null, + {} + ] + ], "flexbox-row-multi-line-inline-end.html": [ "8a59bc417175d6569876ecbb135d25cede0731b0", [ @@ -468748,7 +468867,7 @@ ] ], "overscroll-deltas.html": [ - "4d799294b80ff76955dc86db67daed7eabf74de0", + "21586322503d8507d8f20a7fd5f7d51844654325", [ null, { @@ -468840,7 +468959,7 @@ ] ], "scrollend-event-fired-to-document.html": [ - "65b4f0482a19defb6a4f7830bd3237d622ba7b3b", + "797c2eb53da0e31f848fbe5f26f656231d57fb45", [ null, { @@ -468858,7 +468977,7 @@ ] ], "scrollend-event-fired-to-window.html": [ - "02b541f6ebe73b07ad5cc5bceb7ad09da94b679d", + "faacf7e572cf1aa0e3fedfb0cdd5c10344e14dff", [ null, { @@ -468867,7 +468986,7 @@ ] ], "scrollend-event-for-user-scroll.html": [ - "64be25326724f0692285c8009f50ccacbdec49e3", + "561c90ca94c6af8c0335a962a16273e44c2d3717", [ null, { @@ -501842,7 +501961,7 @@ ] ], "join-leave-ad-interest-group.https.sub.window.js": [ - "9c8433219fdf8fda4ecfe05357472f666e235e1b", + "f4615d929e52df76e649688c36d1cbff30781078", [ "fledge/tentative/join-leave-ad-interest-group.https.sub.window.html", { @@ -503607,6 +503726,17 @@ "fs/opaque-origin.https.window.html", {} ] + ], + "root-name.https.any.js": [ + "650a7a64eef4b043df652b4cd27e1a2c120594bf", + [ + "fs/root-name.https.any.html", + {} + ], + [ + "fs/root-name.https.any.worker.html", + {} + ] ] }, "fullscreen": { @@ -603173,7 +603303,7 @@ ] ], "requestStorageAccess-cross-site-sibling-iframes.sub.https.window.js": [ - "5496e89670cfcf6d4c1dfce06507ff249112e7b7", + "c93673887c4dafe4a60f8cb00ad65c6203bd2376", [ "storage-access-api/requestStorageAccess-cross-site-sibling-iframes.sub.https.window.html", { @@ -610894,7 +611024,7 @@ ] ], "requestStorageAccessFor.sub.https.window.js": [ - "c573567084d9ae434b4c6eb3c8ad2dcb474b0042", + "e82cce699fab9b2d3cd6e8d928cc66850083658a", [ "top-level-storage-access-api/tentative/requestStorageAccessFor.sub.https.window.html", { @@ -621532,7 +621662,7 @@ ] ], "partitioned-web-locks.tentative.https.html": [ - "a426737f608e85ff4b1062a090d74648e5ad0933", + "2f166e67bc13cc4976dfd10f854880b8f07a0e50", [ null, {}
diff --git a/third_party/blink/web_tests/external/wpt/css/css-box/margin-trim/computed-margin-values/flexbox-column-block-end-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-box/margin-trim/computed-margin-values/flexbox-column-block-end-expected.txt new file mode 100644 index 0000000..fac2ea6 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-box/margin-trim/computed-margin-values/flexbox-column-block-end-expected.txt
@@ -0,0 +1,7 @@ +This is a testharness.js-based test. +PASS flexbox > item 1 +FAIL flexbox > item 2 assert_equals: +<item data-expected-margin-bottom="0" data-offset-y="68"></item> +margin-bottom expected "0" but got "10" +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/css/css-box/margin-trim/computed-margin-values/flexbox-column-block-end.html b/third_party/blink/web_tests/external/wpt/css/css-box/margin-trim/computed-margin-values/flexbox-column-block-end.html new file mode 100644 index 0000000..ecc2663 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-box/margin-trim/computed-margin-values/flexbox-column-block-end.html
@@ -0,0 +1,34 @@ +<!DOCTYPE html> +<html> +<head> +<link rel="author" href="mailto:sammy.gill@apple.com"> +<link rel="help" href="https://drafts.csswg.org/css-box-4/#margin-trim-flex"> +<meta name="assert" content="block-end trimmed margins should be reflected in computed style"> +<style> +flexbox { + display: flex; + flex-direction: column; + width: min-content; + margin-trim: block-end; +} +item { + display: block; + background-color: green; + width: 50px; + height: 50px; + margin-block-end: 10px; +} +</style> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/check-layout-th.js"></script> +</head> +<body onload="checkLayout('flexbox > item')"> +<div id="target"> +<flexbox> + <item data-expected-margin-bottom="10" data-offset-y="8"></item> + <item data-expected-margin-bottom="0" data-offset-y="68"></item> +</flexbox> +</div> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-box/margin-trim/computed-margin-values/flexbox-column-block-end.html.ini b/third_party/blink/web_tests/external/wpt/css/css-box/margin-trim/computed-margin-values/flexbox-column-block-end.html.ini new file mode 100644 index 0000000..f57a446 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-box/margin-trim/computed-margin-values/flexbox-column-block-end.html.ini
@@ -0,0 +1,3 @@ +[flexbox-column-block-end.html] + [flexbox > item 2] + expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-box/margin-trim/computed-margin-values/flexbox-column-multi-line-block-end-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-box/margin-trim/computed-margin-values/flexbox-column-multi-line-block-end-expected.txt new file mode 100644 index 0000000..906c67f --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-box/margin-trim/computed-margin-values/flexbox-column-multi-line-block-end-expected.txt
@@ -0,0 +1,11 @@ +This is a testharness.js-based test. +PASS flexbox > item 1 +FAIL flexbox > item 2 assert_equals: +<item data-offset-y="68" data-expected-margin-bottom="0"></item> +offsetTop expected 68 but got 8 +PASS flexbox > item 3 +FAIL flexbox > item 4 assert_equals: +<item data-offset-y="68" data-expected-margin-top="0"></item> +offsetTop expected 68 but got 8 +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/css/css-box/margin-trim/computed-margin-values/flexbox-column-multi-line-block-end.html b/third_party/blink/web_tests/external/wpt/css/css-box/margin-trim/computed-margin-values/flexbox-column-multi-line-block-end.html new file mode 100644 index 0000000..61f11a9 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-box/margin-trim/computed-margin-values/flexbox-column-multi-line-block-end.html
@@ -0,0 +1,38 @@ +<!DOCTYPE html> +<html> +<head> +<link rel="author" href="mailto:sammy.gill@apple.com"> +<link rel="help" href="https://drafts.csswg.org/css-box-4/#margin-trim-flex"> +<meta name="assert" content="block-end trimmed margins should be reflected in computed style"> +<style> +flexbox { + display: flex; + flex-direction: column; + flex-wrap: wrap; + width: 100px; + height: 110px; + margin-trim: block-end; +} +item { + display: block; + background-color: green; + width: 50px; + height: 50px; + margin-block-end: 10px; +} +</style> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/check-layout-th.js"></script> +</head> +<body onload="checkLayout('flexbox > item')"> +<div id="target"> +<flexbox> + <item data-offset-y="8" data-expected-margin-bottom="10"></item> + <item data-offset-y="68" data-expected-margin-bottom="0"></item> + <item data-offset-y="8" data-expected-margin-bottom="10"></item> + <item data-offset-y="68" data-expected-margin-top="0"></item> +</flexbox> +</div> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-box/margin-trim/computed-margin-values/flexbox-column-multi-line-block-end.html.ini b/third_party/blink/web_tests/external/wpt/css/css-box/margin-trim/computed-margin-values/flexbox-column-multi-line-block-end.html.ini new file mode 100644 index 0000000..f240a591 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-box/margin-trim/computed-margin-values/flexbox-column-multi-line-block-end.html.ini
@@ -0,0 +1,6 @@ +[flexbox-column-multi-line-block-end.html] + [flexbox > item 2] + expected: FAIL + + [flexbox > item 4] + expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-box/margin-trim/computed-margin-values/flexbox-column-multi-line-block-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-box/margin-trim/computed-margin-values/flexbox-column-multi-line-block-expected.txt new file mode 100644 index 0000000..b68a40ed --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-box/margin-trim/computed-margin-values/flexbox-column-multi-line-block-expected.txt
@@ -0,0 +1,15 @@ +This is a testharness.js-based test. +FAIL flexbox > item 1 assert_equals: +<item data-offset-y="8" data-expected-margin-top="0" data-expected-margin-bottom="10"></item> +offsetTop expected 8 but got 18 +FAIL flexbox > item 2 assert_equals: +<item data-offset-y="78" data-expected-margin-top="10" data-expected-margin-bottom="0"></item> +offsetTop expected 78 but got 18 +FAIL flexbox > item 3 assert_equals: +<item data-offset-y="8" data-expected-margin-top="0" data-expected-margin-bottom="10"></item> +offsetTop expected 8 but got 18 +FAIL flexbox > item 4 assert_equals: +<item data-offset-y="78" data-expected-margin-top="10" data-expected-margin-bottom="0"></item> +offsetTop expected 78 but got 18 +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/css/css-box/margin-trim/computed-margin-values/flexbox-column-multi-line-block.html b/third_party/blink/web_tests/external/wpt/css/css-box/margin-trim/computed-margin-values/flexbox-column-multi-line-block.html new file mode 100644 index 0000000..e01067f --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-box/margin-trim/computed-margin-values/flexbox-column-multi-line-block.html
@@ -0,0 +1,38 @@ +<!DOCTYPE html> +<html> +<head> +<link rel="author" href="mailto:sammy.gill@apple.com"> +<link rel="help" href="https://drafts.csswg.org/css-box-4/#margin-trim-flex"> +<meta name="assert" content="both trimmed block margins should be reflected in computed style"> +<style> +flexbox { + display: flex; + flex-direction: column; + flex-wrap: wrap; + width: 100px; + height: 120px; + margin-trim: block; +} +item { + display: block; + background-color: green; + width: 50px; + height: 50px; + margin-block: 10px; +} +</style> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/check-layout-th.js"></script> +</head> +<body onload="checkLayout('flexbox > item')"> +<div id="target"> +<flexbox> + <item data-offset-y="8" data-expected-margin-top="0" data-expected-margin-bottom="10"></item> + <item data-offset-y="78" data-expected-margin-top="10" data-expected-margin-bottom="0" ></item> + <item data-offset-y="8" data-expected-margin-top="0" data-expected-margin-bottom="10"></item> + <item data-offset-y="78" data-expected-margin-top="10" data-expected-margin-bottom="0"></item> +</flexbox> +</div> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-box/margin-trim/computed-margin-values/flexbox-column-multi-line-block.html.ini b/third_party/blink/web_tests/external/wpt/css/css-box/margin-trim/computed-margin-values/flexbox-column-multi-line-block.html.ini new file mode 100644 index 0000000..4298304d --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-box/margin-trim/computed-margin-values/flexbox-column-multi-line-block.html.ini
@@ -0,0 +1,12 @@ +[flexbox-column-multi-line-block.html] + [flexbox > item 1] + expected: FAIL + + [flexbox > item 2] + expected: FAIL + + [flexbox > item 3] + expected: FAIL + + [flexbox > item 4] + expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-box/margin-trim/computed-margin-values/flexbox-row-block-end-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-box/margin-trim/computed-margin-values/flexbox-row-block-end-expected.txt new file mode 100644 index 0000000..c356e01 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-box/margin-trim/computed-margin-values/flexbox-row-block-end-expected.txt
@@ -0,0 +1,12 @@ +This is a testharness.js-based test. +FAIL flexbox > item 1 assert_equals: +<item data-expected-margin-bottom="0"></item> +margin-bottom expected "0" but got "10" +FAIL flexbox > item 2 assert_equals: +<item data-expected-margin-bottom="0"></item> +margin-bottom expected "0" but got "-10" +FAIL flexbox > item 3 assert_equals: +<item data-expected-margin-bottom="0"></item> +margin-bottom expected "0" but got "63" +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/css/css-box/margin-trim/computed-margin-values/flexbox-row-block-end.html b/third_party/blink/web_tests/external/wpt/css/css-box/margin-trim/computed-margin-values/flexbox-row-block-end.html new file mode 100644 index 0000000..f5ca9854 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-box/margin-trim/computed-margin-values/flexbox-row-block-end.html
@@ -0,0 +1,43 @@ +<!DOCTYPE html> +<html> +<head> +<link rel="author" href="mailto:sammy.gill@apple.com"> +<link rel="help" href="https://drafts.csswg.org/css-box-4/#margin-trim-flex"> +<meta name="assert" content="block-end trimmed margins should be reflected in computed style"> +<style> +flexbox { + display: flex; + width: min-content; + margin-trim: block-end; +} +item { + display: block; + background-color: green; + width: 50px; + height: 50px; + margin-inline: 10px; +} +item:nth-child(1) { + margin-block-end: 10px; +} +item:nth-child(2) { + margin-block-end: -10px; +} +item:nth-child(3) { + margin-block-end: 30%; +} +</style> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/check-layout-th.js"></script> +</head> +<body onload="checkLayout('flexbox > item')"> +<div id="target"> +<flexbox> + <item data-expected-margin-bottom="0"></item> + <item data-expected-margin-bottom="0"></item> + <item data-expected-margin-bottom="0"></item> +</flexbox> +</div> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-box/margin-trim/computed-margin-values/flexbox-row-block-end.html.ini b/third_party/blink/web_tests/external/wpt/css/css-box/margin-trim/computed-margin-values/flexbox-row-block-end.html.ini new file mode 100644 index 0000000..c043d052 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-box/margin-trim/computed-margin-values/flexbox-row-block-end.html.ini
@@ -0,0 +1,9 @@ +[flexbox-row-block-end.html] + [flexbox > item 1] + expected: FAIL + + [flexbox > item 2] + expected: FAIL + + [flexbox > item 3] + expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-box/margin-trim/computed-margin-values/flexbox-row-block-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-box/margin-trim/computed-margin-values/flexbox-row-block-expected.txt new file mode 100644 index 0000000..ca44f7d --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-box/margin-trim/computed-margin-values/flexbox-row-block-expected.txt
@@ -0,0 +1,12 @@ +This is a testharness.js-based test. +FAIL flexbox > item 1 assert_equals: +<item data-expected-margin-top="0" data-expected-margin-bottom="0" data-offset-y="8"></item> +offsetTop expected 8 but got 18 +FAIL flexbox > item 2 assert_equals: +<item data-expected-margin-top="0" data-expected-margin-bottom="0" data-offset-y="8"></item> +offsetTop expected 8 but got -2 +FAIL flexbox > item 3 assert_equals: +<item data-expected-margin-top="0" data-expected-margin-bottom="0" data-offset-y="8"></item> +offsetTop expected 8 but got 71 +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/css/css-box/margin-trim/computed-margin-values/flexbox-row-block.html b/third_party/blink/web_tests/external/wpt/css/css-box/margin-trim/computed-margin-values/flexbox-row-block.html new file mode 100644 index 0000000..6c35fa6 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-box/margin-trim/computed-margin-values/flexbox-row-block.html
@@ -0,0 +1,43 @@ +<!DOCTYPE html> +<html> +<head> +<link rel="author" href="mailto:sammy.gill@apple.com"> +<link rel="help" href="https://drafts.csswg.org/css-box-4/#margin-trim-flex"> +<meta name="assert" content="both trimmed block margins should be reflected in computed style"> +<style> +flexbox { + display: flex; + width: min-content; + margin-trim: block; +} +item { + display: block; + background-color: green; + width: 50px; + height: 50px; + margin-inline: 10px; +} +item:nth-child(1) { + margin-block: 10px; +} +item:nth-child(2) { + margin-block: -10px; +} +item:nth-child(3) { + margin-block: 30%; +} +</style> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/check-layout-th.js"></script> +</head> +<body onload="checkLayout('flexbox > item')"> +<div id="target"> +<flexbox> + <item data-expected-margin-top="0" data-expected-margin-bottom="0" data-offset-y="8"></item> + <item data-expected-margin-top="0" data-expected-margin-bottom="0" data-offset-y="8"></item> + <item data-expected-margin-top="0" data-expected-margin-bottom="0" data-offset-y="8"></item> +</flexbox> +</div> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-box/margin-trim/computed-margin-values/flexbox-row-block.html.ini b/third_party/blink/web_tests/external/wpt/css/css-box/margin-trim/computed-margin-values/flexbox-row-block.html.ini new file mode 100644 index 0000000..4d37dd68 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-box/margin-trim/computed-margin-values/flexbox-row-block.html.ini
@@ -0,0 +1,9 @@ +[flexbox-row-block.html] + [flexbox > item 1] + expected: FAIL + + [flexbox > item 2] + expected: FAIL + + [flexbox > item 3] + expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-box/margin-trim/computed-margin-values/flexbox-row-multi-line-block-end-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-box/margin-trim/computed-margin-values/flexbox-row-multi-line-block-end-expected.txt new file mode 100644 index 0000000..046ae10 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-box/margin-trim/computed-margin-values/flexbox-row-multi-line-block-end-expected.txt
@@ -0,0 +1,11 @@ +This is a testharness.js-based test. +PASS flexbox > item 1 +PASS flexbox > item 2 +FAIL flexbox > item 3 assert_equals: +<item data-offset-y="68" data-expected-margin-bottom="0"></item> +margin-bottom expected "0" but got "10" +FAIL flexbox > item 4 assert_equals: +<item data-offset-y="68" data-expected-margin-bottom="0"></item> +margin-bottom expected "0" but got "10" +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/css/css-box/margin-trim/computed-margin-values/flexbox-row-multi-line-block-end.html b/third_party/blink/web_tests/external/wpt/css/css-box/margin-trim/computed-margin-values/flexbox-row-multi-line-block-end.html new file mode 100644 index 0000000..f4c90c2 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-box/margin-trim/computed-margin-values/flexbox-row-multi-line-block-end.html
@@ -0,0 +1,36 @@ +<!DOCTYPE html> +<html> +<head> +<link rel="author" href="mailto:sammy.gill@apple.com"> +<link rel="help" href="https://drafts.csswg.org/css-box-4/#margin-trim-flex"> +<meta name="assert" content="block-end trimmed margins should be reflected in computed style"> +<style> +flexbox { + display: flex; + flex-wrap: wrap; + width: 100px; + margin-trim: block-end; +} +item { + display: block; + background-color: green; + width: 50px; + height: 50px; + margin-block-end: 10px; +} +</style> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/check-layout-th.js"></script> +</head> +<body onload="checkLayout('flexbox > item')"> +<div id="target"> +<flexbox> + <item data-offset-y="8" data-expected-margin-bottom="10"></item> + <item data-offset-y="8" data-expected-margin-bottom="10"></item> + <item data-offset-y="68" data-expected-margin-bottom="0"></item> + <item data-offset-y="68" data-expected-margin-bottom="0"></item> +</flexbox> +</div> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-box/margin-trim/computed-margin-values/flexbox-row-multi-line-block-end.html.ini b/third_party/blink/web_tests/external/wpt/css/css-box/margin-trim/computed-margin-values/flexbox-row-multi-line-block-end.html.ini new file mode 100644 index 0000000..9a8cb6f --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-box/margin-trim/computed-margin-values/flexbox-row-multi-line-block-end.html.ini
@@ -0,0 +1,6 @@ +[flexbox-row-multi-line-block-end.html] + [flexbox > item 3] + expected: FAIL + + [flexbox > item 4] + expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-box/margin-trim/computed-margin-values/flexbox-row-multi-line-block-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-box/margin-trim/computed-margin-values/flexbox-row-multi-line-block-expected.txt new file mode 100644 index 0000000..03e67de --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-box/margin-trim/computed-margin-values/flexbox-row-multi-line-block-expected.txt
@@ -0,0 +1,15 @@ +This is a testharness.js-based test. +FAIL flexbox > item 1 assert_equals: +<item data-expected-margin-top="0" data-expected-margin-bottom="10" data-offset-y="8"></item> +offsetTop expected 8 but got 18 +FAIL flexbox > item 2 assert_equals: +<item data-expected-margin-top="0" data-expected-margin-bottom="10" data-offset-y="8"></item> +offsetTop expected 8 but got 18 +FAIL flexbox > item 3 assert_equals: +<item data-expected-margin-top="10" data-expected-margin-bottom="0" data-offset-y="78"></item> +offsetTop expected 78 but got 88 +FAIL flexbox > item 4 assert_equals: +<item data-expected-margin-top="10" data-expected-margin-bottom="0" data-offset-y="78"></item> +offsetTop expected 78 but got 88 +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/css/css-box/margin-trim/computed-margin-values/flexbox-row-multi-line-block.html b/third_party/blink/web_tests/external/wpt/css/css-box/margin-trim/computed-margin-values/flexbox-row-multi-line-block.html new file mode 100644 index 0000000..1db5680 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-box/margin-trim/computed-margin-values/flexbox-row-multi-line-block.html
@@ -0,0 +1,37 @@ +<!DOCTYPE html> +<html> +<head> +<link rel="author" href="mailto:sammy.gill@apple.com"> +<link rel="help" href="https://drafts.csswg.org/css-box-4/#margin-trim-flex"> +<meta name="assert" content="both trimmed block margins should be reflected in computed style"> +<style> +flexbox { + display: flex; + width: 100px; + flex-wrap: wrap; + margin-trim: block; +} +item { + display: block; + background-color: green; + width: 50px; + height: 50px; + margin-block: 10px; +} + +</style> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/check-layout-th.js"></script> +</head> +<body onload="checkLayout('flexbox > item')"> +<div id="target"> +<flexbox> + <item data-expected-margin-top="0" data-expected-margin-bottom="10" data-offset-y="8"></item> + <item data-expected-margin-top="0" data-expected-margin-bottom="10" data-offset-y="8"></item> + <item data-expected-margin-top="10" data-expected-margin-bottom="0" data-offset-y="78"></item> + <item data-expected-margin-top="10" data-expected-margin-bottom="0" data-offset-y="78"></item> +</flexbox> +</div> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-box/margin-trim/computed-margin-values/flexbox-row-multi-line-block.html.ini b/third_party/blink/web_tests/external/wpt/css/css-box/margin-trim/computed-margin-values/flexbox-row-multi-line-block.html.ini new file mode 100644 index 0000000..1a6360e2 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-box/margin-trim/computed-margin-values/flexbox-row-multi-line-block.html.ini
@@ -0,0 +1,12 @@ +[flexbox-row-multi-line-block.html] + [flexbox > item 1] + expected: FAIL + + [flexbox > item 2] + expected: FAIL + + [flexbox > item 3] + expected: FAIL + + [flexbox > item 4] + expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-flexbox/aspect-ratio-intrinsic-size-002.html.ini b/third_party/blink/web_tests/external/wpt/css/css-flexbox/aspect-ratio-intrinsic-size-002.html.ini new file mode 100644 index 0000000..45d2773 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-flexbox/aspect-ratio-intrinsic-size-002.html.ini
@@ -0,0 +1,3 @@ +[aspect-ratio-intrinsic-size-002.html] + expected: + if (product == "content_shell") and (os == "mac") and (port == "mac13-arm64"): FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-color-input-border-bottom-right-radius-001.html.ini b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-color-input-border-bottom-right-radius-001.html.ini new file mode 100644 index 0000000..5512314 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-color-input-border-bottom-right-radius-001.html.ini
@@ -0,0 +1,3 @@ +[kind-of-widget-fallback-color-input-border-bottom-right-radius-001.html] + expected: + if (product == "content_shell") and (os == "linux"): FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-search-background-position-001.html.ini b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-search-background-position-001.html.ini index 99cd283..133535d0 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-search-background-position-001.html.ini +++ b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-search-background-position-001.html.ini
@@ -1,3 +1,4 @@ [kind-of-widget-fallback-input-search-background-position-001.html] expected: + if (product == "content_shell") and (os == "mac") and (port == "mac13"): FAIL if product == "chrome": FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-search-text-border-bottom-right-radius-001.html.ini b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-search-text-border-bottom-right-radius-001.html.ini new file mode 100644 index 0000000..ad567520 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-search-text-border-bottom-right-radius-001.html.ini
@@ -0,0 +1,3 @@ +[kind-of-widget-fallback-input-search-text-border-bottom-right-radius-001.html] + expected: + if (product == "content_shell") and (os == "mac") and (port == "mac13"): FAIL
diff --git a/third_party/blink/web_tests/external/wpt/dom/events/scrolling/overscroll-deltas.html.ini b/third_party/blink/web_tests/external/wpt/dom/events/scrolling/overscroll-deltas.html.ini index 34c5f53..007a415 100644 --- a/third_party/blink/web_tests/external/wpt/dom/events/scrolling/overscroll-deltas.html.ini +++ b/third_party/blink/web_tests/external/wpt/dom/events/scrolling/overscroll-deltas.html.ini
@@ -1,3 +1,10 @@ [overscroll-deltas.html] expected: if product == "chrome": ERROR + [testing, horizontal] + expected: + if product == "chrome": FAIL + + [testing, vertical] + expected: + if product == "chrome": FAIL
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/history-traversal/event-order/before-load-hash-twice.html.ini b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/history-traversal/event-order/before-load-hash-twice.html.ini new file mode 100644 index 0000000..001a4e6b --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/history-traversal/event-order/before-load-hash-twice.html.ini
@@ -0,0 +1,4 @@ +[before-load-hash-twice.html] + [when changing hash twice, before load] + expected: + if (product == "content_shell") and (os == "mac") and (port == "mac13"): [FAIL, PASS]
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-fieldset-element/disabled-003.html b/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-fieldset-element/disabled-003.html new file mode 100644 index 0000000..de01eb5 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-fieldset-element/disabled-003.html
@@ -0,0 +1,39 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Disable nested fieldsets with focused element</title> +<link rel="help" href="https://html.spec.whatwg.org/multipage/#the-fieldset-element"> +<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1427047"> +<link rel="author" href="mailto:xiaochengh@chromium.org"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<div id=container1> + <fieldset id=target1> + <legend>foo</legend> + <fieldset> + <legend>bar</legend> + <input id=input1> + </fieldset> + </fieldset> +</div> +<script> +test(() => { + input1.focus(); + target1.disabled = true; + assert_not_equals(document.activeElement, input1); +}, 'Disable light-nested fieldsets should not crash'); +</script> + +<div id=container2></div> +<script> +test(() => { + let n = 100; + let markup = '<fieldset><legend>foo</legend>'.repeat(n) + + '<input id=input2>' + '</fieldset>'.repeat(n); + container2.innerHTML = markup; + input2.focus(); + container2.firstChild.disabled = true; + assert_not_equals(document.activeElement, input2); +}, 'Disable deep-nested fieldsets should not hang'); +</script> +
diff --git a/third_party/blink/web_tests/external/wpt/top-level-storage-access-api/tentative/requestStorageAccessFor.sub.https.window.js.ini b/third_party/blink/web_tests/external/wpt/top-level-storage-access-api/tentative/requestStorageAccessFor.sub.https.window.js.ini index f0f925ab2..cfb5c6c4 100644 --- a/third_party/blink/web_tests/external/wpt/top-level-storage-access-api/tentative/requestStorageAccessFor.sub.https.window.js.ini +++ b/third_party/blink/web_tests/external/wpt/top-level-storage-access-api/tentative/requestStorageAccessFor.sub.https.window.js.ini
@@ -1,21 +1,7 @@ [requestStorageAccessFor.sub.https.window.html] - expected: - if product == "chrome": ERROR - [[request-storage-access-integration\] document.requestStorageAccess() should be resolved without a user gesture with an existing top-level-storage-access permission] + [[same-origin-iframe\] Existing top-level storage access permission should not allow cookie access for the cross-site subresource requests made in a non-top-level context.] expected: if product == "chrome": FAIL - [[same-origin-frame\] Existing top-level storage access permission should not allow cookie access for the cross-site subresource requests made in a non-top-level context.] - expected: - if product == "chrome": NOTRUN - - [[same-origin-frame\] document.requestStorageAccessFor() should be rejected when called in an iframe] - expected: - if product == "chrome": NOTRUN - - [[same-origin-frame\] document.requestStorageAccessFor() should be rejected when called with no argument] - expected: - if product == "chrome": NOTRUN - [[top-level-context\] document.requestStorageAccessFor() should be resolved without a user gesture with an existing permission] expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/webusb/usbDevice-iframe.https.html.ini b/third_party/blink/web_tests/external/wpt/webusb/usbDevice-iframe.https.html.ini index 2dfd92f..21e89d3 100644 --- a/third_party/blink/web_tests/external/wpt/webusb/usbDevice-iframe.https.html.ini +++ b/third_party/blink/web_tests/external/wpt/webusb/usbDevice-iframe.https.html.ini
@@ -1,6 +1,7 @@ [usbDevice-iframe.https.html] expected: - if (product == "content_shell") and (os == "linux") and (flag_specific == "disable-site-isolation-trials"): [TIMEOUT, OK] + if (product == "content_shell") and (os == "linux") and (flag_specific == "disable-site-isolation-trials"): TIMEOUT + if (product == "content_shell") and (os == "linux") and (flag_specific == ""): TIMEOUT if product == "chrome": TIMEOUT [Connect event is not fired in iframe with usb disallowed.] expected:
diff --git a/third_party/blink/web_tests/virtual/composite-scroll-after-paint/compositing/overflow/nested-render-surfaces-expected.png b/third_party/blink/web_tests/virtual/composite-scroll-after-paint/compositing/overflow/nested-render-surfaces-expected.png new file mode 100644 index 0000000..561e143f --- /dev/null +++ b/third_party/blink/web_tests/virtual/composite-scroll-after-paint/compositing/overflow/nested-render-surfaces-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/virtual/composite-scroll-after-paint/compositing/overflow/nested-render-surfaces-with-intervening-clip-expected.png b/third_party/blink/web_tests/virtual/composite-scroll-after-paint/compositing/overflow/nested-render-surfaces-with-intervening-clip-expected.png new file mode 100644 index 0000000..006c785a --- /dev/null +++ b/third_party/blink/web_tests/virtual/composite-scroll-after-paint/compositing/overflow/nested-render-surfaces-with-intervening-clip-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/virtual/composite-scroll-after-paint/scrollbars/listbox-scrollbar-combinations-expected.png b/third_party/blink/web_tests/virtual/composite-scroll-after-paint/scrollbars/listbox-scrollbar-combinations-expected.png new file mode 100644 index 0000000..0ccecb0 --- /dev/null +++ b/third_party/blink/web_tests/virtual/composite-scroll-after-paint/scrollbars/listbox-scrollbar-combinations-expected.png Binary files differ
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl index c2e9ffcd..af90b9e1 100644 --- a/tools/mb/mb_config.pyl +++ b/tools/mb/mb_config.pyl
@@ -274,6 +274,7 @@ # These should be the same with 'Linux Builder'. 'linux-rel-dev': 'gpu_tests_release_bot_do_typecheck_reclient', + 'linux-rel-jammy-dev': 'gpu_tests_release_bot_do_typecheck_reclient', 'linux-ssd-rel-dev': 'gpu_tests_release_bot_do_typecheck_reclient', # This should be the same with 'Mac Builder'.
diff --git a/tools/mb/mb_config_expectations/chromium.dev.json b/tools/mb/mb_config_expectations/chromium.dev.json index 9c9e478..a66237c 100644 --- a/tools/mb/mb_config_expectations/chromium.dev.json +++ b/tools/mb/mb_config_expectations/chromium.dev.json
@@ -26,6 +26,17 @@ "use_remoteexec": true } }, + "linux-rel-jammy-dev": { + "gn_args": { + "dcheck_always_on": false, + "devtools_skip_typecheck": false, + "ffmpeg_branding": "Chrome", + "is_component_build": false, + "is_debug": false, + "proprietary_codecs": true, + "use_remoteexec": true + } + }, "linux-ssd-rel-dev": { "gn_args": { "dcheck_always_on": false,
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 63fd2c2..4d8ddc1f 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -25711,7 +25711,8 @@ <int value="4" label="Window on desk activated"/> <int value="5" label="Desk-switch 4-finger touchpad swipe"/> <int value="6" label="User switch in a multi-profile session"/> - <int value="7" label="User switch through the persistent desks bar"/> + <int value="7" + label="DEPRECATED: User switch through the persistent desks bar"/> <int value="8" label="User switch by launching a template"/> <int value="9" label="User switch via indexed keyboard shorcuts"/> <int value="10" label="User switch by restoring removed desk"/> @@ -42432,7 +42433,7 @@ <int value="15" label="Camera App"/> <int value="16" label="Capture Mode"/> <int value="17" label="Chrome Labs"/> - <int value="18" label="Bento Bar"/> + <int value="18" label="DEPRECATED: Bento Bar"/> <int value="19" label="Quick Answers"/> <int value="20" label="What's New"/> <int value="21" label="Connectivity Diagnostics"/> @@ -59997,6 +59998,7 @@ <int value="-1069453905" label="CCTModuleUseIntentExtras:disabled"/> <int value="-1068278508" label="InfoCardAcknowledgementTracking:disabled"/> <int value="-1068197506" label="EnhancedNetworkVoices:enabled"/> + <int value="-1068084507" label="ShareSheetCustomActionsPolish:enabled"/> <int value="-1067635248" label="SpeculativeResourcePrefetching:disabled"/> <int value="-1065887406" label="PictureInPictureV2:disabled"/> <int value="-1065227777" label="CrOSAutoSelect:disabled"/> @@ -60408,6 +60410,7 @@ label="ServiceWorkerSkipIgnorableFetchHandler:enabled"/> <int value="-852804781" label="WebViewSynthesizePageLoadOnlyOnInitialMainDocumentAccess:disabled"/> + <int value="-851924474" label="FastPairDebugMetadata:disabled"/> <int value="-850821337" label="WebContentsForceDark:enabled"/> <int value="-849792130" label="UserMediaCaptureOnFocus:disabled"/> <int value="-848691867" label="DesktopPWAWindowing:enabled"/> @@ -60534,6 +60537,7 @@ <int value="-776686417" label="SiteExplorationUi:disabled"/> <int value="-775952696" label="FeedStamp:enabled"/> <int value="-775321548" label="UseNewDoodleApi:disabled"/> + <int value="-774513654" label="ShareSheetCustomActionsPolish:disabled"/> <int value="-773238824" label="AutoplayWhitelistSettings:disabled"/> <int value="-772787642" label="MediaAppCustomColors:disabled"/> <int value="-772679248" label="MojoVideoEncodeAccelerator:enabled"/> @@ -62349,7 +62353,6 @@ <int value="222184258" label="AutofillEnforceMinRequiredFieldsForHeuristics:disabled"/> <int value="223075555" label="DisallowManagedProfileSignout:enabled"/> - <int value="223573347" label="BentoBar:disabled"/> <int value="223591010" label="CastMediaRouteProvider:enabled"/> <int value="223662457" label="BackgroundLoadingForDownloads:enabled"/> <int value="224019823" label="CompositeAfterPaint:enabled"/> @@ -63355,6 +63358,7 @@ <int value="767549069" label="ScreenTime:enabled"/> <int value="767970385" label="ResamplingScrollEvents:enabled"/> <int value="768287307" label="OmniboxCr2023Umbrella:enabled"/> + <int value="768675159" label="FastPairDebugMetadata:enabled"/> <int value="768855962" label="PaymentRequestBasicCard:enabled"/> <int value="770680432" label="DecodeLossyWebPImagesToYUV:enabled"/> <int value="772272625" label="simplify-https-indicator"/> @@ -64770,7 +64774,6 @@ label="ChromeHomePersonalizedOmniboxSuggestions:disabled"/> <int value="1568172566" label="OmniboxOnDeviceHeadProviderNonIncognito:disabled"/> - <int value="1569982806" label="BentoBar:enabled"/> <int value="1570178909" label="NewOverviewLayout:enabled"/> <int value="1571640975" label="EcheLauncherIconsInMoreAppsButton:enabled"/> <int value="1571998166" label="DetectingHeavyPages:disabled"/> @@ -78122,7 +78125,7 @@ <int value="3" label="Going from home launcher to overview"/> <int value="4" label="Pressing overview button"/> <int value="5" label="Long pressing overview button in split view mode"/> - <int value="6" label="Going from Bento bar to overview"/> + <int value="6" label="DEPRECATED: Going from Bento bar to overview"/> <int value="7" label="Three fingers swiping up on the trackpad"/> <int value="8" label="Entering overview through dev tools"/> <int value="9" label="Entering overview in tests"/>
diff --git a/tools/metrics/histograms/metadata/android/histograms.xml b/tools/metrics/histograms/metadata/android/histograms.xml index 350caab5..facf6f9 100644 --- a/tools/metrics/histograms/metadata/android/histograms.xml +++ b/tools/metrics/histograms/metadata/android/histograms.xml
@@ -56,25 +56,6 @@ <variant name="Waived" summary="strongest binding of Waived"/> </variants> -<variants name="JankMetricsScenarios"> - <variant name=".NewTabPage" summary="while NTP is open"/> - <variant name=".OmniboxFocus" summary="while Omnibox is focused"/> - <variant name=".OpenLinkInNewTab" - summary="while opening a link in a new tab using the long press menu"/> - <variant name=".StartSurfaceHomepage" - summary="while the homepage on start surface is visible"/> - <variant name=".StartSurfaceTabSwitcher" - summary="while the tab switcher on start surface is visible"/> - <variant name=".Startup" summary="while Chrome is starting"/> - <variant name=".TabSwitcher" summary="while Tab switcher is open"/> - <variant name=".Total" - summary="while ChromeTabbedActivity is resumed. However, there's an - unusual implementation detail: Individual frame durations are - measured in Java, and passed over to C++ for recording once - every 30 seconds. Thus, frames that occur near program - termination might be dropped from the data"/> -</variants> - <variants name="MessageIdentifiers"> <variant name=".AboutThisSite"/> <variant name=".AddToHomescreenIPH"/> @@ -1844,76 +1825,6 @@ </summary> </histogram> -<histogram name="Android.Jank.FrameDuration{Scenario}" units="ms" - expires_after="2022-06-30"> - <owner>salg@google.com</owner> - <owner>ssid@chromium.org</owner> - <summary> - Amount of time it takes to draw Android UI frames on ChromeTabbedActivity as - measured by Android's FrameMetrics API. Each frame's draw duration is stored - individually {Scenario}. - - The samples for this metric (Along with Android.Jank.JankBursts and - Android.Jank.MissedFrames) are manually passed from Java to C++ to be - recorded. This is done instead of recording in real time from Java due to - the large number of generated samples (potentially ~60 per second). - Recording them directly from Java would result in a JNI call for each sample - which could cause performance issues. - - FrameMetrics only reports frames with Android UI updates. An idle omnibox - would report only 2 frames per second due to the cursor blink animation. - Scrolling through a web page may record no frames if no Android UI (like the - address bar) updates. - </summary> - <token key="Scenario" variants="JankMetricsScenarios"/> -</histogram> - -<histogram name="Android.Jank.JankBursts{Scenario}" units="ms" - expires_after="2022-06-30"> - <owner>salg@google.com</owner> - <owner>ssid@chromium.org</owner> - <summary> - Recorded alongside Android.Jank.FrameDuration {Scenario}. Each sample - represents a jank burst: the total frame duration of one or many janky - frames drawn in quick succession. For example, the following sequence of - frame durations: [2ms, 100ms, 100ms, 100ms, 2ms, 2ms, 2ms, 100ms, 2ms] would - be recorded as 2 jank bursts: [300ms, 100ms]. - - Jank bursts may include non-janky frames if both adjacent frames are janky, - example: [2ms, 100ms, 100ms, 2ms, 100ms, 100ms, 2ms] would count as a single - jank burst: [402ms]. - - Jank bursts are started with a single janky frame, and end with either 2 or - more non-janky frames or a period of inactivity between janky frames - (>50ms). For example: [100ms, 100ms, (...500ms without new frames - later...), 100ms] would be recorded as 2 jank bursts: [200ms, 100ms]. The - third frame is counted separately because of the period of inactivity before - it indicates its jankyness is caused by a different event or animation. (see - go/clank-zero-browser-jank for more details). - </summary> - <token key="Scenario" variants="JankMetricsScenarios"/> -</histogram> - -<histogram name="Android.Jank.MissedFrames{Scenario}" units="frames" - expires_after="2022-06-30"> - <owner>salg@google.com</owner> - <owner>ssid@chromium.org</owner> - <summary> - Number of frames that Android's FrameMetrics API skipped reporting on - because of high main thread activity. This metric is recorded at the same - time as Android.Jank.* histograms {Scenario}. Each sample is the number of - frames that we didn't receive timings for, so their draw duration is not - recorded in the respective Android.Jank.FrameDuration.* histogram, and (even - if its duration was greater than 16ms) it is not counted in any - Android.Jank.JankyBursts.* samples. - - A high number of missed frames would mean that we are taking too long to - record frame metrics and that the other Android.Jank.* histograms may not be - accurate. - </summary> - <token key="Scenario" variants="JankMetricsScenarios"/> -</histogram> - <histogram name="Android.KernelVersion" enum="AndroidKernelVersion" expires_after="2023-08-27"> <owner>rsesek@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/ash/histograms.xml b/tools/metrics/histograms/metadata/ash/histograms.xml index b2b59eb9..59736437 100644 --- a/tools/metrics/histograms/metadata/ash/histograms.xml +++ b/tools/metrics/histograms/metadata/ash/histograms.xml
@@ -1837,6 +1837,9 @@ <histogram name="Ash.Desks.BentoBarEnabled" enum="Boolean" expires_after="2023-10-01"> + <obsolete> + Deprecated April 2023, the Bento Bar feature has been deleted. + </obsolete> <owner>minch@chromium.org</owner> <owner>janetmac@chromium.org</owner> <summary> @@ -1848,6 +1851,9 @@ <histogram name="Ash.Desks.BentoBarIsVisible" enum="Boolean" expires_after="2023-09-24"> + <obsolete> + Deprecated April 2023, the Bento Bar feature has been deleted. + </obsolete> <owner>minch@chromium.org</owner> <owner>janetmac@chromium.org</owner> <summary> @@ -2310,6 +2316,9 @@ <histogram name="Ash.Desks.UserHasUsedDesksRecently" enum="Boolean" expires_after="2023-10-01"> + <obsolete> + Deprecated April 2023, the Bento Bar feature has been deleted. + </obsolete> <owner>minch@chromium.org</owner> <owner>janetmac@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/bookmarks/OWNERS b/tools/metrics/histograms/metadata/bookmarks/OWNERS index daeacfd..84cc738 100644 --- a/tools/metrics/histograms/metadata/bookmarks/OWNERS +++ b/tools/metrics/histograms/metadata/bookmarks/OWNERS
@@ -2,6 +2,3 @@ # Prefer sending CLs to the owners listed below. # Use chromium-metrics-reviews@google.com as a backup. - -# For Bookmarks.GetResultsMatching.* histograms -manukh@chromium.org
diff --git a/tools/metrics/histograms/metadata/bookmarks/histograms.xml b/tools/metrics/histograms/metadata/bookmarks/histograms.xml index 6e74a1d8..dffa210 100644 --- a/tools/metrics/histograms/metadata/bookmarks/histograms.xml +++ b/tools/metrics/histograms/metadata/bookmarks/histograms.xml
@@ -329,364 +329,6 @@ <summary>How users add a new bookmark.</summary> </histogram> -<histogram name="Bookmarks.GetResultsMatching.AnyTermApproach.Used" - enum="Boolean" expires_after="2023-08-20"> - <owner>manukh@chromium.org</owner> - <owner>chrome-omnibox-team@google.com</owner> - <component>UI>Browser>Bookmarks</component> - <summary> - Bookmarks are indexed by the terms in their titles and URLs. The omnibox - bookmark provider uses this index to search for bookmarks that match the - user input. A summary of the approach is: - - 1) Split the user input into terms. - - 2) For each term, find the index nodes matching the term. Nodes are minimal - representations of bookmarks that will later be used to construct matches in - step 5. - - 3) Accumulate the nodes. - - 3a) If the omnibox is interested only in title and URL matches, or if less - than 2 terms are longer than a threshold, nodes are accumulated by - intersection; i.e. only nodes matching every term will be accumulated. - - 3b) If the omnibox is interested in path matches as well, nodes are - accumulated by union with a limit to avoid accumulating too many nodes. If - the limit is reached, intersection nodes will be appended and therefore - guaranteed to be included. - - 4) Sort the nodes. - - 5) Construct bookmark matches from the nodes and the user input. Not all - nodes will be converted to matches; there is both filtering and a cap. - - This process occurs each time the omnibox looks up bookmarks for an input; - approximately once per character the user types and occasionally at other - times, e.g. when the omnibox is focused. - - This histogram detects whether step 3a or 3b occurred. - - It is emitted exactly once per the omnibox's request for bookmark matches - with a non-empty input. - </summary> -</histogram> - -<histogram name="Bookmarks.GetResultsMatching.Terms.TermLength" - units="characters" expires_after="2023-08-20"> - <owner>manukh@chromium.org</owner> - <owner>chrome-omnibox-team@google.com</owner> - <component>UI>Browser>Bookmarks</component> - <summary> - Bookmarks are indexed by the terms in their titles and URLs. The omnibox - bookmark provider uses this index to search for bookmarks that match the - user input. A summary of the approach is: - - 1) Split the user input into terms. - - 2) For each term, find the index nodes matching the term. Nodes are minimal - representations of bookmarks that will later be used to construct matches in - step 5. - - 3) Accumulate the nodes. - - 3a) If the omnibox is interested only in title and URL matches, or if less - than 2 terms are longer than a threshold, nodes are accumulated by - intersection; i.e. only nodes matching every term will be accumulated. - - 3b) If the omnibox is interested in path matches as well, nodes are - accumulated by union with a limit to avoid accumulating too many nodes. If - the limit is reached, intersection nodes will be appended and therefore - guaranteed to be included. - - 4) Sort the nodes. - - 5) Construct bookmark matches from the nodes and the user input. Not all - nodes will be converted to matches; there is both filtering and a cap. - - This process occurs each time the omnibox looks up bookmarks for an input; - approximately once per character the user types and occasionally at other - times, e.g. when the omnibox is focused. - - This histogram measures the length of each term in step 1. It is emitted - once per term per the omnibox's request for bookmark matches with a - non-empty input. - </summary> -</histogram> - -<histogram name="Bookmarks.GetResultsMatching.{SubmetricMatchCounts}" - units="match counts" expires_after="2023-02-12"> - <owner>manukh@chromium.org</owner> - <owner>chrome-omnibox-team@google.com</owner> - <component>UI>Browser>Bookmarks</component> - <summary> - Bookmarks are indexed by the terms in their titles and URLs. The omnibox - bookmark provider uses this index to search for bookmarks that match the - user input. A summary of the approach is: - - 1) Split the user input into terms. - - 2) For each term, find the index nodes matching the term. Nodes are minimal - representations of bookmarks that will later be used to construct matches in - step 5. - - 3) Accumulate the nodes. - - 3a) If the omnibox is interested only in title and URL matches, or if less - than 2 terms are longer than a threshold, nodes are accumulated by - intersection; i.e. only nodes matching every term will be accumulated. - - 3b) If the omnibox is interested in path matches as well, nodes are - accumulated by union with a limit to avoid accumulating too many nodes. If - the limit is reached, intersection nodes will be appended and therefore - guaranteed to be included. - - 4) Sort the nodes. - - 5) Construct bookmark matches from the nodes and the user input. Not all - nodes will be converted to matches; there is both filtering and a cap. - - This process occurs each time the omnibox looks up bookmarks for an input; - approximately once per character the user types and occasionally at other - times, e.g. when the omnibox is focused. - - {SubmetricMatchCounts} - </summary> - <token key="SubmetricMatchCounts"> - <variant name="Matches.ConsideredCount" - summary="This histogram counts the matches considered in step 5. This - may be less than the number of nodes returned from step 3, - as there is a limit as to how many matches will be created. - This may more than that limit, as not every match considered - will be created. As deciding whether to create a match is - the computation-heavy part of the process, this histogram is - a good proxy of performance cost. It is emitted at most once - per the omnibox's request for bookmark matches; it won't be - emitted if step 3 matched no nodes."/> - <variant name="Matches.ReturnedCount" - summary="This histogram counts the matches created in step 5. This - may be less than the number of nodes returned from step 3, - as there is a limit as to how many matches will be created - and some matches will be filtered. It is emitted at most - once per the omnibox's request for bookmark matches; it - won't be emitted if step 3 matched no nodes."/> - </token> -</histogram> - -<histogram name="Bookmarks.GetResultsMatching.{SubmetricMs}" units="ms" - expires_after="2023-02-12"> - <owner>manukh@chromium.org</owner> - <owner>chrome-omnibox-team@google.com</owner> - <component>UI>Browser>Bookmarks</component> - <summary> - Bookmarks are indexed by the terms in their titles and URLs. The omnibox - bookmark provider uses this index to search for bookmarks that match the - user input. A summary of the approach is: - - 1) Split the user input into terms. - - 2) For each term, find the index nodes matching the term. Nodes are minimal - representations of bookmarks that will later be used to construct matches in - step 5. - - 3) Accumulate the nodes. - - 3a) If the omnibox is interested only in title and URL matches, or if less - than 2 terms are longer than a threshold, nodes are accumulated by - intersection; i.e. only nodes matching every term will be accumulated. - - 3b) If the omnibox is interested in path matches as well, nodes are - accumulated by union with a limit to avoid accumulating too many nodes. If - the limit is reached, intersection nodes will be appended and therefore - guaranteed to be included. - - 4) Sort the nodes. - - 5) Construct bookmark matches from the nodes and the user input. Not all - nodes will be converted to matches; there is both filtering and a cap. - - This process occurs each time the omnibox looks up bookmarks for an input; - approximately once per character the user types and occasionally at other - times, e.g. when the omnibox is focused. - - {SubmetricMs} - </summary> - <token key="SubmetricMs"> - <variant name="Timing.CreatingMatches" - summary="This histogram measures the time step 5 took. It is emitted - at most once per the omnibox's request for bookmark matches; - it won't be emitted if step 3 matched no nodes."/> - <variant name="Timing.RetrievingNodes" - summary="This histogram measures the time steps 2 and 3 took. It is - emitted exactly once per the omnibox's request for bookmark - matches with a non-empty input."/> - <variant name="Timing.SortingNodes" - summary="This histogram measures the time step 4 took. It is emitted - at most once per the omnibox's request for bookmark matches; - it won't be emitted if step 3 matched no nodes."/> - <variant name="Timing.Total" - summary="This histogram measures the time all steps took. It is - emitted exactly once per the omnibox's request for bookmark - matches with an empty or non-empty input."/> - </token> -</histogram> - -<histogram name="Bookmarks.GetResultsMatching.{SubmetricNodeCounts}" - units="node counts" expires_after="2023-02-12"> - <owner>manukh@chromium.org</owner> - <owner>chrome-omnibox-team@google.com</owner> - <component>UI>Browser>Bookmarks</component> - <summary> - Bookmarks are indexed by the terms in their titles and URLs. The omnibox - bookmark provider uses this index to search for bookmarks that match the - user input. A summary of the approach is: - - 1) Split the user input into terms. - - 2) For each term, find the index nodes matching the term. Nodes are minimal - representations of bookmarks that will later be used to construct matches in - step 5. - - 3) Accumulate the nodes. - - 3a) If the omnibox is interested only in title and URL matches, or if less - than 2 terms are longer than a threshold, nodes are accumulated by - intersection; i.e. only nodes matching every term will be accumulated. - - 3b) If the omnibox is interested in path matches as well, nodes are - accumulated by union with a limit to avoid accumulating too many nodes. If - the limit is reached, intersection nodes will be appended and therefore - guaranteed to be included. - - 4) Sort the nodes. - - 5) Construct bookmark matches from the nodes and the user input. Not all - nodes will be converted to matches; there is both filtering and a cap. - - This process occurs each time the omnibox looks up bookmarks for an input; - approximately once per character the user types and occasionally at other - times, e.g. when the omnibox is focused. - - {SubmetricNodeCounts} - </summary> - <token key="SubmetricNodeCounts"> - <variant name="AnyTermApproach.NodeCount" - summary="This histogram counts the unique nodes accumulated in step - 3b. It may be less than the count of nodes unioned since - those may contain duplicates. It may also be more than the - count of the nodes unioned since this also includes the - nodes intersected. It is emitted each time step 3b occurs; - at most once per the omnibox's request for bookmark matches."/> - <variant name="AnyTermApproach.NodeCountAllTerms" - summary="This histogram counts the nodes that match every term in - step 3b; i.e., the count of nodes intersected. The - intersected nodes will not contain duplicates but may - include nodes that were also unioned in step 3b. It is - emitted at most once each time step 3b occurs; step 3b - occurs at most once per the omnibox's request for bookmark - matches."/> - <variant name="AnyTermApproach.NodeCountAnyTerms" - summary="This histogram counts the nodes that match any term in step - 3b; i.e., the count of nodes unioned. The unioned nodes will - not contain duplicates if a node was matched by multiple - terms, or if a term matched the same node multiple times. As - mentioned above, terms that are too short will be skipped - during unioning, and unioning will stop once a node limit is - reached; those nodes won't be counted. It is emitted each - time step 3b occurs; at most once per the omnibox's request - for bookmark matches."/> - <variant name="AnyTermApproach.NodeCountPerTerm" - summary="This histogram counts the nodes matched for each term in - step 3b for unioning. Node matches for a term will not - include duplicates, but may include nodes matched by other - terms. As mentioned above, terms that are too short will be - skipped during unioning, and unioning will stop once a node - limit is reached; those nodes won't be counted. Terms that - match too many nodes will have those nodes counted. This - only counts nodes matched during unioning, not those matched - by intersections and appended after. It is emitted at most - once per term each time step 3b occurs; step 3b occurs at - most once per the omnibox's request for bookmark matches."/> - <variant name="Nodes.Count" - summary="This histogram counts the nodes returned from step 3. The - nodes will not contain duplicates. It is emitted exactly - once per the omnibox's request for bookmark matches with a - non-empty input."/> - <variant name="Nodes.Count.InputsAtLeast3CharsLong" - summary="This histogram counts the nodes returned from step 3 when - the input is at least 3 characters long. 3 is the default - value of - `kShortBookmarkSuggestionsByTotalInputLengthThreshold`; if - the corresponding feature is enabled, longer inputs are - expected to return many more nodes than shorter inputs.The - nodes will not contain duplicates. It is emitted at most - once per the omnibox's request for bookmark matches; it is - only emitted if the input is at least 3 characters long."/> - <variant name="Nodes.Count.InputsShorterThan3CharsLong" - summary="This histogram counts the nodes returned from step 3 when - the input is shorter than 3 characters. 3 is the default - value of - `kShortBookmarkSuggestionsByTotalInputLengthThreshold`; if - the corresponding feature is enabled, longer inputs are - expected to return many more nodes than shorter inputs.The - nodes will not contain duplicates. It is emitted at most - once per the omnibox's request for bookmark matches; it is - only emitted if the input is shorter than 3 characters but - not empty."/> - </token> -</histogram> - -<histogram name="Bookmarks.GetResultsMatching.{SubmetricTermCounts}" - units="term counts" expires_after="2023-02-12"> - <owner>manukh@chromium.org</owner> - <owner>chrome-omnibox-team@google.com</owner> - <component>UI>Browser>Bookmarks</component> - <summary> - Bookmarks are indexed by the terms in their titles and URLs. The omnibox - bookmark provider uses this index to search for bookmarks that match the - user input. A summary of the approach is: - - 1) Split the user input into terms. - - 2) For each term, find the index nodes matching the term. Nodes are minimal - representations of bookmarks that will later be used to construct matches in - step 5. - - 3) Accumulate the nodes. - - 3a) If the omnibox is interested only in title and URL matches nodes are - accumulated by intersection; i.e. only nodes matching every term will be - accumulated. - - 3b) If the omnibox is interested in path matches as well, nodes are - accumulated by union with a limit to avoid accumulating too many nodes. If - the limit is reached, intersection nodes will be appended and therefore - guaranteed to be included. - - 4) Sort the nodes. - - 5) Construct bookmark matches from the nodes and the user input. Not all - nodes will be converted to matches; there is both filtering and a cap. - - This process occurs each time the omnibox looks up bookmarks for an input; - approximately once per character the user types and occasionally at other - times, e.g. when the omnibox is focused. - - {SubmetricTermCounts} - </summary> - <token key="SubmetricTermCounts"> - <variant name="AnyTermApproach.TermsUnionedCount" - summary="This histogram counts the terms in step 3b. This excludes - terms not used for unioning; i.e. terms with no matches. It - is emitted each time step 3b occurs; at most once per the - omnibox's request for bookmark matches."/> - <variant name="Terms.TermsCount" - summary="This histogram counts the terms in step 1. It is emitted - exactly once per the omnibox's request for bookmark matches - with an empty or non-empty input."/> - </token> -</histogram> - <histogram name="Bookmarks.LaunchLocation" enum="BookmarkLaunchLocation" expires_after="2023-08-27"> <owner>ianwen@chromium.org</owner> @@ -694,33 +336,6 @@ <summary>Logs a UI location from which a bookmark is launched.</summary> </histogram> -<histogram name="Bookmarks.Memory.TitledUrlIndex{IndexSlice}" units="bytes" - expires_after="2023-02-12"> - <owner>manukh@chromium.org</owner> - <owner>chrome-omnibox-team@google.com</owner> - <component>UI>Browser>Bookmarks</component> - <summary> - The size of TitledUrlIndex at startup. Its indexes can grow or shrink after - startup as users edit bookmarks. But this is recorded only once at startup - and estimates index size across users, unbiased by users who make more - edits. - - TitledUrlIndex has 2 index, 1 mapping each term in bookmark titles and URLs - to a set of the containing bookmarks. The other mapping the set of path - terms to the count of occurrences in bookmark paths. - - {IndexSlice} - </summary> - <token key="IndexSlice"> - <variant name="" - summary="This slice records the sum of both indexes' sizes."/> - <variant name=".PathIndex" - summary="This histogram records the size of the path index."/> - <variant name=".TitleAndUrlIndex" - summary="This histogram records the size of the title and URL index."/> - </token> -</histogram> - <histogram name="Bookmarks.MultipleOpened.OpenBookmarkTimeInterval2.{BookmarkType}" units="ms" expires_after="2023-06-25">
diff --git a/tools/metrics/histograms/metadata/new_tab_page/histograms.xml b/tools/metrics/histograms/metadata/new_tab_page/histograms.xml index 483ee635..9f02c64 100644 --- a/tools/metrics/histograms/metadata/new_tab_page/histograms.xml +++ b/tools/metrics/histograms/metadata/new_tab_page/histograms.xml
@@ -1825,6 +1825,9 @@ <histogram name="NewTabPage.Realbox.CharTypedToRepaintLatency.ToPaint" units="ms" expires_after="2023-08-08"> + <obsolete> + Deprecated in M114 in favor of Realbox.CharTypedToRepaintLatency.ToPaint. + </obsolete> <owner>mahmadi@chromium.org</owner> <owner>tommycli@chromium.org</owner> <owner>chrome-desktop-ntp@google.com</owner>
diff --git a/tools/perf/core/perf_data_generator.py b/tools/perf/core/perf_data_generator.py index 41580ef..578950b4 100755 --- a/tools/perf/core/perf_data_generator.py +++ b/tools/perf/core/perf_data_generator.py
@@ -438,15 +438,6 @@ # issues, please contact johnchen@chromium.org. BUILDERS = { 'android-builder-perf': { - 'additional_compile_targets': [ - 'microdump_stackwalk', - 'system_webview_google_apk', - 'android_tools', - 'dump_syms', - 'push_apps_to_background_apk', - 'system_webview_apk', - 'system_webview_shell_apk', - ], 'tests': [ { 'name': 'resource_sizes_monochrome_minimal_apks', @@ -498,15 +489,6 @@ False, }, 'android-builder-perf-pgo': { - 'additional_compile_targets': [ - 'microdump_stackwalk', - 'system_webview_google_apk', - 'android_tools', - 'dump_syms', - 'push_apps_to_background_apk', - 'system_webview_apk', - 'system_webview_shell_apk', - ], 'dimension': { 'cpu': 'x86', 'os': 'Ubuntu-18.04', @@ -516,14 +498,6 @@ False, }, 'android_arm64-builder-perf': { - 'additional_compile_targets': [ - 'microdump_stackwalk', - 'system_webview_google_apk', - 'android_tools', - 'push_apps_to_background_apk', - 'system_webview_apk', - 'system_webview_shell_apk', - ], 'tests': [ { 'name': 'resource_sizes_monochrome_minimal_apks', @@ -583,14 +557,6 @@ False, }, 'android_arm64-builder-perf-pgo': { - 'additional_compile_targets': [ - 'microdump_stackwalk', - 'system_webview_google_apk', - 'android_tools', - 'push_apps_to_background_apk', - 'system_webview_apk', - 'system_webview_shell_apk', - ], 'dimension': { 'cpu': 'x86', 'os': 'Ubuntu-18.04',
diff --git a/ui/base/l10n/l10n_util_mac_bridge.h b/ui/base/l10n/l10n_util_mac_bridge.h index 186ef82..2f1a8dd 100644 --- a/ui/base/l10n/l10n_util_mac_bridge.h +++ b/ui/base/l10n/l10n_util_mac_bridge.h
@@ -7,17 +7,24 @@ #import <UIKit/UIKit.h> -// An ObjC wrapper around namespaced C++ l10n methods. -@interface L10NUtils : NSObject +typedef int MessageID; -+ (NSString*)stringForMessageId:(int)messageId; +// An Objective-C wrapper around namespaced C++ l10n methods. +@interface L10nUtils : NSObject -+ (NSString*)stringWithFixupForMessageId:(int)messageId; ++ (NSString*)stringForMessageID:(MessageID)messageID + NS_SWIFT_NAME(string(messageId:)); -+ (NSString*)formatStringForMessageId:(int)messageId - argument:(NSString*)argument; ++ (NSString*)stringWithFixupForMessageID:(MessageID)messageID + NS_SWIFT_NAME(stringWithFixup(messageId:)); -+ (NSString*)pluralStringForMessageId:(int)messageId number:(int)number; ++ (NSString*)formatStringForMessageID:(MessageID)messageID + argument:(NSString*)argument + NS_SWIFT_NAME(formatString(messageId:argument:)); + ++ (NSString*)pluralStringForMessageID:(MessageID)messageID + number:(NSInteger)number + NS_SWIFT_NAME(pluralString(messageId:number:)); @end
diff --git a/ui/base/l10n/l10n_util_mac_bridge.mm b/ui/base/l10n/l10n_util_mac_bridge.mm index fa50888..893f24a 100644 --- a/ui/base/l10n/l10n_util_mac_bridge.mm +++ b/ui/base/l10n/l10n_util_mac_bridge.mm
@@ -8,23 +8,24 @@ #import "ui/base/l10n/l10n_util_mac.h" #import "ui/base/l10n/l10n_util_mac_bridge.h" -@implementation L10NUtils +@implementation L10nUtils -+ (NSString*)stringForMessageId:(int)messageId { - return l10n_util::GetNSString(messageId); ++ (NSString*)stringForMessageID:(int)messageID { + return l10n_util::GetNSString(messageID); } -+ (NSString*)stringWithFixupForMessageId:(int)messageId { - return l10n_util::GetNSStringWithFixup(messageId); ++ (NSString*)stringWithFixupForMessageID:(int)messageID { + return l10n_util::GetNSStringWithFixup(messageID); } -+ (NSString*)formatStringForMessageId:(int)messageId ++ (NSString*)formatStringForMessageID:(int)messageID argument:(NSString*)argument { - return l10n_util::GetNSStringF(messageId, base::SysNSStringToUTF16(argument)); + return l10n_util::GetNSStringF(messageID, base::SysNSStringToUTF16(argument)); } -+ (NSString*)pluralStringForMessageId:(int)messageId number:(int)number { - return l10n_util::GetPluralNSStringF(messageId, number); ++ (NSString*)pluralStringForMessageID:(int)messageID number:(NSInteger)number { + int numberInt = static_cast<int>(number); + return l10n_util::GetPluralNSStringF(messageID, numberInt); } @end
diff --git a/ui/color/color_id.h b/ui/color/color_id.h index 782cc65..69d4b71f 100644 --- a/ui/color/color_id.h +++ b/ui/color/color_id.h
@@ -229,6 +229,8 @@ E_CPONLY(kColorAvatarIconIncognito) \ E_CPONLY(kColorBadgeBackground) \ E_CPONLY(kColorBadgeForeground) \ + E_CPONLY(kColorBadgeInCocoaMenuBackground) \ + E_CPONLY(kColorBadgeInCocoaMenuForeground) \ E_CPONLY(kColorBubbleBackground) \ E_CPONLY(kColorBubbleBorder) \ E_CPONLY(kColorBubbleBorderShadowLarge) \
diff --git a/ui/color/material_ui_color_mixer.cc b/ui/color/material_ui_color_mixer.cc index 35ba7bb..ea1f046 100644 --- a/ui/color/material_ui_color_mixer.cc +++ b/ui/color/material_ui_color_mixer.cc
@@ -26,6 +26,8 @@ mixer[kColorBadgeBackground] = {kColorSysTonalContainer}; mixer[kColorBadgeForeground] = {kColorSysOnTonalContainer}; + mixer[kColorBadgeInCocoaMenuBackground] = {kColorSysPrimary}; + mixer[kColorBadgeInCocoaMenuForeground] = {kColorSysOnPrimary}; mixer[kColorButtonBackground] = {kColorSysSurface}; mixer[kColorButtonBackgroundPressed] = GetResultingPaintColor({kColorSysStatePressed}, {kColorButtonBackground});
diff --git a/ui/color/ui_color_mixer.cc b/ui/color/ui_color_mixer.cc index d6b1fe8..e52dd23 100644 --- a/ui/color/ui_color_mixer.cc +++ b/ui/color/ui_color_mixer.cc
@@ -31,6 +31,8 @@ color_utils::kMinimumVisibleContrastRatio); mixer[kColorBadgeForeground] = GetColorWithMaxContrast(kColorButtonBackgroundProminent); + mixer[kColorBadgeInCocoaMenuBackground] = {kColorBadgeBackground}; + mixer[kColorBadgeInCocoaMenuForeground] = {kColorBadgeForeground}; mixer[kColorBubbleBackground] = {kColorPrimaryBackground}; mixer[kColorBubbleBorder] = {kColorMidground}; mixer[kColorBubbleBorderShadowLarge] = {SetAlpha(kColorShadowBase, 0x1A)};
diff --git a/ui/compositor/overscroll/scroll_input_handler.cc b/ui/compositor/overscroll/scroll_input_handler.cc index ac9904d..b744855 100644 --- a/ui/compositor/overscroll/scroll_input_handler.cc +++ b/ui/compositor/overscroll/scroll_input_handler.cc
@@ -70,7 +70,7 @@ // Falling back to the main thread should never be required when an explicit // ElementId is provided. - DCHECK(!result.main_thread_hit_test_reasons); + DCHECK(!result.needs_main_thread_hit_test); cc::ScrollState scroll_state = CreateScrollState(event, false); input_handler_weak_ptr_->ScrollUpdate(&scroll_state, base::TimeDelta());
diff --git a/ui/views/controls/menu/menu_controller_cocoa_delegate_impl.mm b/ui/views/controls/menu/menu_controller_cocoa_delegate_impl.mm index 2f69fea..bce0240 100644 --- a/ui/views/controls/menu/menu_controller_cocoa_delegate_impl.mm +++ b/ui/views/controls/menu/menu_controller_cocoa_delegate_impl.mm
@@ -43,7 +43,7 @@ DCHECK(color_provider); NSColor* badge_text_color = skia::SkColorToSRGBNSColor( - color_provider->GetColor(ui::kColorBadgeForeground)); + color_provider->GetColor(ui::kColorBadgeInCocoaMenuForeground)); NSDictionary* badge_attrs = @{ NSFontAttributeName : badge_font.GetNativeFont(), @@ -81,7 +81,8 @@ yRadius:badge_radius]; DCHECK(color_provider); NSColor* badge_color = skia::SkColorToSRGBNSColor( - color_provider->GetColor(ui::kColorBadgeBackground)); + color_provider->GetColor(ui::kColorBadgeInCocoaMenuBackground)); + [badge_color set]; [rounded_badge_rect fill];
diff --git a/ui/webui/resources/cr_components/omnibox/realbox_dropdown.ts b/ui/webui/resources/cr_components/omnibox/realbox_dropdown.ts index 4f94798..c6d4cc6 100644 --- a/ui/webui/resources/cr_components/omnibox/realbox_dropdown.ts +++ b/ui/webui/resources/cr_components/omnibox/realbox_dropdown.ts
@@ -206,12 +206,6 @@ } private onResultRepaint_() { - this.dispatchEvent(new CustomEvent('result-repaint', { - bubbles: true, - composed: true, - detail: window.performance.now(), - })); - const metricsReporter = MetricsReporterImpl.getInstance(); metricsReporter.measure('CharTyped') .then(duration => {
diff --git a/ui/webui/resources/cr_elements/cr_icons.css b/ui/webui/resources/cr_elements/cr_icons.css index 2e0890e..e24bbd8 100644 --- a/ui/webui/resources/cr_elements/cr_icons.css +++ b/ui/webui/resources/cr_elements/cr_icons.css
@@ -35,6 +35,10 @@ --cr-icon-image: url(chrome://resources/images/icon_edit.svg); } +.icon-file { + --cr-icon-image: url(chrome://resources/images/icon_filetype_generic.svg); +} + .icon-folder-open { --cr-icon-image: url(chrome://resources/images/icon_folder_open.svg); }
diff --git a/ui/webui/resources/images/BUILD.gn b/ui/webui/resources/images/BUILD.gn index 853ddb5..e6f6d39 100644 --- a/ui/webui/resources/images/BUILD.gn +++ b/ui/webui/resources/images/BUILD.gn
@@ -59,6 +59,7 @@ "icon_edit.svg", "icon_expand_less.svg", "icon_expand_more.svg", + "icon_filetype_generic.svg", "icon_folder_open.svg", "icon_journeys.svg", "icon_more_vert.svg",
diff --git a/ui/webui/resources/images/icon_filetype_generic.svg b/ui/webui/resources/images/icon_filetype_generic.svg new file mode 100644 index 0000000..ba78ddce --- /dev/null +++ b/ui/webui/resources/images/icon_filetype_generic.svg
@@ -0,0 +1,3 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"> + <path fill="#5f6368" d="M11 2l5 5v10a1 1 0 01-1 1H5a1 1 0 01-1-1V3a1 1 0 011-1h6zm-1 2H6v12h8V8h-4V4z"/> +</svg> \ No newline at end of file