diff --git a/DEPS b/DEPS index 5c6bd86..46c6ed4c 100644 --- a/DEPS +++ b/DEPS
@@ -295,23 +295,23 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. - 'src_internal_revision': '7964be3418696ef3ab1788b335ba0f6caf5917c5', + 'src_internal_revision': 'ce8575ab9f020c7b9f39a089d8d6c10f0ab34b59', # 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': '2e032998eb66b3dc42647871b0a2639f33abd196', + 'skia_revision': '3393a17d5fdcc6cf47862ec516b0ff3592850bea', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. - 'v8_revision': '9503e87cce58a06ea4bed24ea073f1f12c34b959', + 'v8_revision': '369e42eddbcbbdd259da17182c67fbe33c5170e6', # 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': '8c512f3e03d0d2fd21b4d55a7fc1becff9604a8e', + 'angle_revision': 'ef85f283434e5b26b672c39f050a0e2c8c655aef', # 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': '5fdf5e4c58918bd8ce3d8b9bd3b33755ebc26ab0', + 'swiftshader_revision': '155f095a8c6354d25c7bd062094cdff98ca9d6ae', # 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 CrossBench # and whatever else without interference from each other. - 'crossbench_revision': 'c9c52cc6dead7d399b602b116d124cfe53339d55', + 'crossbench_revision': '1009ebd5d406ddcaf346e48c10aea62d10326bda', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other. @@ -391,7 +391,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling devtools-frontend # and whatever else without interference from each other. - 'devtools_frontend_revision': '9e5dddf1ba1a8f1dbad8f55edb1b71970fc3832b', + 'devtools_frontend_revision': 'af5c09099862f7e4a4cd0ed131b2bd0369f5c5d1', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libprotobuf-mutator # and whatever else without interference from each other. @@ -427,7 +427,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ink_stroke_modeler # and whatever else without interference from each other. - 'ink_stroke_modeler_revision': '03db1ed37b8b10b47d62ed0fa142d198a3861689', + 'ink_stroke_modeler_revision': 'fe79520c9ad7d2d445d26d3c59fda6fc54eb4d5c', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ios_webkit # and whatever else without interference from each other. @@ -519,7 +519,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling llvm-libc # and whatever else without interference from each other. - 'llvm_libc_revision': 'c7b224d8e8261aa4ba880280349bca74c1a9a2e7', + 'llvm_libc_revision': '2be4a578cb2136558bc0070ffd38e0b1bafb34e9', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling llvm-libc # and whatever else without interference from each other. @@ -691,10 +691,10 @@ 'dep_type': 'gcs', 'objects': [ { - 'generation': 1748541682715337, - 'object_name': '6c924a8f88bb4731f3c2334c6ae5b5da47d5ca196ff571a91071f104dbacecad', - 'sha256sum': '6c924a8f88bb4731f3c2334c6ae5b5da47d5ca196ff571a91071f104dbacecad', - 'size_bytes': 20181372, + 'generation': 1749572829637587, + 'object_name': '5c8ef4067f41a625d81113a6292180acf4ef49a2ffe015c2779123c133b8e250', + 'sha256sum': '5c8ef4067f41a625d81113a6292180acf4ef49a2ffe015c2779123c133b8e250', + 'size_bytes': 20178952, }, ], }, @@ -1521,7 +1521,7 @@ 'src/clank': { 'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' + - '7a1ffc358fdcbfdc0be09cdf2b2462b7a5dc8cb2', + 'af5242eecbe2a033bcc8fcd7cbb89c09bf264dd8', 'condition': 'checkout_android and checkout_src_internal', }, @@ -1986,7 +1986,7 @@ # Tools used when building Chrome for Chrome OS. This affects both the Simple # Chrome workflow, as well as the chromeos-chrome ebuild. 'src/third_party/chromite': { - 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'dd0616580a90055b4b8aee7f82da48f7d8407906', + 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '0f33b29b972dfeba968b18e4ee9c34f5c80e7fa3', 'condition': 'checkout_chromeos', }, @@ -2564,7 +2564,7 @@ Var('pdfium_git') + '/pdfium.git' + '@' + Var('pdfium_revision'), 'src/third_party/perfetto': - Var('chromium_git') + '/external/github.com/google/perfetto.git' + '@' + '393c1529c36f43332b3d89f32aa5ee1e2493c2c1', + Var('chromium_git') + '/external/github.com/google/perfetto.git' + '@' + '717bd456079cad23a0d1d52f3f9e7628af0b17ac', 'src/base/tracing/test/data': { 'bucket': 'perfetto', @@ -2883,7 +2883,7 @@ 'dep_type': 'cipd', }, - 'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@e72c7b63fe81f659c6cf653fbf83bf4cc6d9e3a2', + 'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@ae1d44f55e826515a19a789f1ecbefe2099ed4f2', 'src/third_party/glslang/src': '{chromium_git}/external/github.com/KhronosGroup/glslang@ac1c686d562147c751a0c284f879499418beee46', 'src/third_party/spirv-cross/src': '{chromium_git}/external/github.com/KhronosGroup/SPIRV-Cross@b8fcf307f1f347089e3c46eb4451d27f32ebc8d3', 'src/third_party/spirv-headers/src': '{chromium_git}/external/github.com/KhronosGroup/SPIRV-Headers@3b9447dc98371e96b59a6225bd062a9867e1d203', @@ -2892,7 +2892,7 @@ 'src/third_party/vulkan-loader/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Loader@63b05d2b087952662623de7eddd44f2e57d71a1e', 'src/third_party/vulkan-tools/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Tools@fbe722654b7173da961398cf78bd4a62d1839b65', 'src/third_party/vulkan-utility-libraries/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Utility-Libraries@e48ae20a7938b01aee62806bfcdafe8a0883b1e4', - 'src/third_party/vulkan-validation-layers/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-ValidationLayers@f06294f4aaa84cbe64dcddebe3ad478692798707', + 'src/third_party/vulkan-validation-layers/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-ValidationLayers@3fd3381758c8f721bb3d395ecbf08b4d71d6ce6e', 'src/third_party/vulkan_memory_allocator': Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git' + '@' + '56300b29fbfcc693ee6609ddad3fdd5b7a449a21', @@ -2937,7 +2937,7 @@ Var('chromium_git') + '/webpagereplay.git' + '@' + Var('webpagereplay_revision'), 'src/third_party/webrtc': - Var('webrtc_git') + '/src.git' + '@' + '8305f8c14afeff1e81478a574f3fa76efafc43d5', + Var('webrtc_git') + '/src.git' + '@' + '0292d38b7f56a83c0838e63bde92fb7a47be0927', # Wuffs' canonical repository is at github.com/google/wuffs, but we use # Skia's mirror of Wuffs, the same as in upstream Skia's DEPS file. @@ -3070,7 +3070,7 @@ 'packages': [ { 'package': 'chromeos_internal/apps/help_app/app', - 'version': 'GgGpjjVoHpzoI543o6wAruhP9Rz9uEibZEU2ZZfHeREC', + 'version': 'tJ64F3BX8CXFwYr8YIAhk8sAQOJey7QUG5FpFPUMm3wC', }, ], 'condition': 'checkout_chromeos and checkout_src_internal', @@ -3081,7 +3081,7 @@ 'packages': [ { 'package': 'chromeos_internal/apps/media_app/app', - 'version': 'C4GVZJ05pW4G9oz1DLQIUlYUit90QbOB0kCUdyOqo6oC', + 'version': 'guosNmsRtBMM8lS4c-IPxH1cGRs3dMFWoDfOvCNpvg8C', }, ], 'condition': 'checkout_chromeos and checkout_src_internal', @@ -4723,7 +4723,7 @@ 'src/ios_internal': { 'url': Var('chrome_git') + '/chrome/ios_internal.git' + '@' + - 'dda9885a588fbcec1566158cdb2b401a374a989b', + 'a1191d44f93cda2981ea440a89ff41690d354fe6', 'condition': 'checkout_ios and checkout_src_internal', },
diff --git a/android_webview/browser/BUILD.gn b/android_webview/browser/BUILD.gn index 024caed..fabe122 100644 --- a/android_webview/browser/BUILD.gn +++ b/android_webview/browser/BUILD.gn
@@ -304,6 +304,7 @@ "//components/os_crypt/async/browser", "//components/page_load_metrics/browser", "//components/page_load_metrics/google/browser", + "//components/payments/content/android", "//components/permissions", "//components/policy:generated", "//components/policy/content/",
diff --git a/android_webview/browser/DEPS b/android_webview/browser/DEPS index 83284ef..c330288 100644 --- a/android_webview/browser/DEPS +++ b/android_webview/browser/DEPS
@@ -34,6 +34,7 @@ "+components/os_crypt/async", "+components/page_load_metrics/browser", "+components/page_load_metrics/google/browser", + "+components/payments/content/android/payment_feature_map.h", "+components/permissions", "+components/policy/core/browser", "+components/policy/core/common",
diff --git a/android_webview/browser/aw_field_trials.cc b/android_webview/browser/aw_field_trials.cc index 69be6d3..eee760db 100644 --- a/android_webview/browser/aw_field_trials.cc +++ b/android_webview/browser/aw_field_trials.cc
@@ -14,6 +14,7 @@ #include "base/path_service.h" #include "components/history/core/browser/features.h" #include "components/metrics/persistent_histograms.h" +#include "components/payments/content/android/payment_feature_map.h" #include "components/permissions/features.h" #include "components/safe_browsing/core/common/features.h" #include "components/translate/core/common/translate_util.h" @@ -111,6 +112,8 @@ aw_feature_overrides.DisableFeature(::features::kVulkan); aw_feature_overrides.DisableFeature(::features::kServiceWorkerPaymentApps); + aw_feature_overrides.EnableFeature( + ::payments::android::kAndroidPaymentIntentsOmitDeprecatedParameters); // WebView does not support overlay fullscreen yet for video overlays. aw_feature_overrides.DisableFeature(media::kOverlayFullscreenVideo);
diff --git a/android_webview/browser/prefetch/aw_prefetch_manager.cc b/android_webview/browser/prefetch/aw_prefetch_manager.cc index 22eeae3..b52a6be 100644 --- a/android_webview/browser/prefetch/aw_prefetch_manager.cc +++ b/android_webview/browser/prefetch/aw_prefetch_manager.cc
@@ -146,7 +146,8 @@ GetIsJavaScriptEnabledFromPrefetchParameters(env, prefetch_params), expected_no_vary_search, additional_headers, std::move(request_status_listener), base::Seconds(ttl_in_sec_), - /*should_append_variations_header=*/false); + /*should_append_variations_header=*/false, + /*should_disable_block_until_head_timeout=*/true); if (prefetch_handle) { return AddPrefetchHandle(std::move(prefetch_handle));
diff --git a/android_webview/common/aw_features.cc b/android_webview/common/aw_features.cc index 6a3fe35..b7749be 100644 --- a/android_webview/common/aw_features.cc +++ b/android_webview/common/aw_features.cc
@@ -170,6 +170,12 @@ "WebViewSkipInterceptsForPrefetch", base::FEATURE_ENABLED_BY_DEFAULT); +// Whether to skip `WebView::ContentsPreferredMinimumSize` within +// `AwRenderViewExt::UpdateContentsSize`. +BASE_FEATURE(kWebViewSkipPreferredSizeForContentsSize, + "WebViewSkipPreferredSizeForContentsSize", + base::FEATURE_ENABLED_BY_DEFAULT); + // Whether to use initial network state during initialization to speed up // startup. BASE_FEATURE(kWebViewUseInitialNetworkStateAtStartup,
diff --git a/android_webview/common/aw_features.h b/android_webview/common/aw_features.h index 10b9b49..b87126a5 100644 --- a/android_webview/common/aw_features.h +++ b/android_webview/common/aw_features.h
@@ -49,6 +49,7 @@ BASE_DECLARE_FEATURE(kWebViewSafeAreaIncludesSystemBars); BASE_DECLARE_FEATURE(kWebViewSeparateResourceContext); BASE_DECLARE_FEATURE(kWebViewSkipInterceptsForPrefetch); +BASE_DECLARE_FEATURE(kWebViewSkipPreferredSizeForContentsSize); BASE_DECLARE_FEATURE(kWebViewDoNotSendAccessibilityEventsOnGSU); BASE_DECLARE_FEATURE(kWebViewHyperlinkContextMenu); BASE_DECLARE_FEATURE(kCreateSpareRendererOnBrowserContextCreation);
diff --git a/android_webview/common/crash_reporter/crash_keys.cc b/android_webview/common/crash_reporter/crash_keys.cc index 7c6abe99..ab3f481f 100644 --- a/android_webview/common/crash_reporter/crash_keys.cc +++ b/android_webview/common/crash_reporter/crash_keys.cc
@@ -216,6 +216,7 @@ "SIFactory-GMBType", "SIFactory-SharedBwThreads", "SIFactory-Usage", + "SIFactory-Size", nullptr}; // clang-format on
diff --git a/android_webview/renderer/aw_render_view_ext.cc b/android_webview/renderer/aw_render_view_ext.cc index 9031fe4..5696ddf 100644 --- a/android_webview/renderer/aw_render_view_ext.cc +++ b/android_webview/renderer/aw_render_view_ext.cc
@@ -6,6 +6,7 @@ #include <map> +#include "android_webview/common/aw_features.h" #include "android_webview/common/mojom/frame.mojom.h" #include "base/containers/contains.h" #include "base/no_destructor.h" @@ -101,7 +102,9 @@ // Fall back to contentsPreferredMinimumSize if the mainFrame is reporting a // 0x0 size (this happens during initial load). - if (contents_size.IsEmpty()) { + if (contents_size.IsEmpty() && + !base::FeatureList::IsEnabled( + features::kWebViewSkipPreferredSizeForContentsSize)) { contents_size = webview->ContentsPreferredMinimumSize(); }
diff --git a/android_webview/support_library/boundary_interfaces/src/org/chromium/support_lib_boundary/util/Features.java b/android_webview/support_library/boundary_interfaces/src/org/chromium/support_lib_boundary/util/Features.java index 34e4ead..b61aed60 100644 --- a/android_webview/support_library/boundary_interfaces/src/org/chromium/support_lib_boundary/util/Features.java +++ b/android_webview/support_library/boundary_interfaces/src/org/chromium/support_lib_boundary/util/Features.java
@@ -301,7 +301,7 @@ // WebViewCompat.prerenderUrl // WebViewCompat.clearPrerender - public static final String PRERENDER_WITH_URL = "PRERENDER_URL_V2"; + public static final String PRERENDER_WITH_URL = "PRERENDER_URL_V3"; // WebStorageCompat.deleteBrowsingData // WebStorageCompat.deleteBrowsingDataForSite
diff --git a/android_webview/test/data/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt b/android_webview/test/data/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt index e768397..655591330 100644 --- a/android_webview/test/data/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt +++ b/android_webview/test/data/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -8537,6 +8537,69 @@ method constructor setter onaddsourcebuffer setter onremovesourcebuffer +interface SpeechGrammar + attribute @@toStringTag + getter src + getter weight + method constructor + setter src + setter weight +interface SpeechGrammarList + attribute @@toStringTag + getter length + method @@iterator + method addFromString + method addFromUri + method constructor + method item +interface SpeechRecognition : EventTarget + attribute @@toStringTag + getter continuous + getter grammars + getter interimResults + getter lang + getter maxAlternatives + getter onaudioend + getter onaudiostart + getter onend + getter onerror + getter onnomatch + getter onresult + getter onsoundend + getter onsoundstart + getter onspeechend + getter onspeechstart + getter onstart + method abort + method constructor + method start + method stop + setter continuous + setter grammars + setter interimResults + setter lang + setter maxAlternatives + setter onaudioend + setter onaudiostart + setter onend + setter onerror + setter onnomatch + setter onresult + setter onsoundend + setter onsoundstart + setter onspeechend + setter onspeechstart + setter onstart +interface SpeechRecognitionErrorEvent : Event + attribute @@toStringTag + getter error + getter message + method constructor +interface SpeechRecognitionEvent : Event + attribute @@toStringTag + getter resultIndex + getter results + method constructor interface StaticRange : AbstractRange attribute @@toStringTag method constructor @@ -10853,6 +10916,7 @@ attribute @@toStringTag getter src getter weight + method constructor setter src setter weight interface webkitSpeechGrammarList @@ -10861,6 +10925,7 @@ method @@iterator method addFromString method addFromUri + method constructor method item interface webkitSpeechRecognition : EventTarget attribute @@toStringTag @@ -10881,6 +10946,7 @@ getter onspeechstart getter onstart method abort + method constructor method start method stop setter continuous @@ -10903,10 +10969,12 @@ attribute @@toStringTag getter error getter message + method constructor interface webkitSpeechRecognitionEvent : Event attribute @@toStringTag getter resultIndex getter results + method constructor interface webkitURL static method canParse static method createObjectURL
diff --git a/android_webview/test/data/web_tests/webexposed/global-interface-listing-expected.txt b/android_webview/test/data/web_tests/webexposed/global-interface-listing-expected.txt index 03b0cd0..6e93f87 100644 --- a/android_webview/test/data/web_tests/webexposed/global-interface-listing-expected.txt +++ b/android_webview/test/data/web_tests/webexposed/global-interface-listing-expected.txt
@@ -9245,6 +9245,92 @@ method constructor setter onaddsourcebuffer setter onremovesourcebuffer +interface SpeechGrammar + attribute @@toStringTag + getter src + getter weight + method constructor + setter src + setter weight +interface SpeechGrammarList + attribute @@toStringTag + getter length + method @@iterator + method addFromString + method addFromUri + method constructor + method item +interface SpeechRecognition : EventTarget + static method available + static method install + attribute @@toStringTag + getter continuous + getter grammars + getter interimResults + getter lang + getter maxAlternatives + getter onaudioend + getter onaudiostart + getter onend + getter onerror + getter onnomatch + getter onresult + getter onsoundend + getter onsoundstart + getter onspeechend + getter onspeechstart + getter onstart + getter phrases + getter processLocally + method abort + method constructor + method start + method stop + setter continuous + setter grammars + setter interimResults + setter lang + setter maxAlternatives + setter onaudioend + setter onaudiostart + setter onend + setter onerror + setter onnomatch + setter onresult + setter onsoundend + setter onsoundstart + setter onspeechend + setter onspeechstart + setter onstart + setter phrases + setter processLocally +interface SpeechRecognitionContext + attribute @@toStringTag + getter phrases + method constructor + setter phrases +interface SpeechRecognitionErrorEvent : Event + attribute @@toStringTag + getter error + getter message + method constructor +interface SpeechRecognitionEvent : Event + attribute @@toStringTag + getter resultIndex + getter results + method constructor +interface SpeechRecognitionPhrase + attribute @@toStringTag + getter boost + getter phrase + method constructor +interface SpeechRecognitionPhraseList + attribute @@toStringTag + getter length + method addItem + method constructor + method item + method removeItem interface StaticRange : AbstractRange attribute @@toStringTag method constructor @@ -11706,6 +11792,7 @@ attribute @@toStringTag getter src getter weight + method constructor setter src setter weight interface webkitSpeechGrammarList @@ -11714,6 +11801,7 @@ method @@iterator method addFromString method addFromUri + method constructor method item interface webkitSpeechRecognition : EventTarget static method available @@ -11735,8 +11823,10 @@ getter onspeechend getter onspeechstart getter onstart + getter phrases getter processLocally method abort + method constructor method start method stop setter continuous @@ -11755,15 +11845,18 @@ setter onspeechend setter onspeechstart setter onstart + setter phrases setter processLocally interface webkitSpeechRecognitionError : Event attribute @@toStringTag getter error getter message + method constructor interface webkitSpeechRecognitionEvent : Event attribute @@toStringTag getter resultIndex getter results + method constructor interface webkitURL static method canParse static method createObjectURL
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc index c9ffe17d..ffcf1a3d 100644 --- a/ash/constants/ash_features.cc +++ b/ash/constants/ash_features.cc
@@ -2030,7 +2030,7 @@ // Enables a limit on the number of notifications that can show. BASE_FEATURE(kNotificationLimit, "NotificationLimit", - base::FEATURE_DISABLED_BY_DEFAULT); + base::FEATURE_ENABLED_BY_DEFAULT); // Enables Notifier Collision to allow popup notifications and tray bubbles not // overlap when showing on a display.
diff --git a/ash/login/ui/lock_contents_view.cc b/ash/login/ui/lock_contents_view.cc index d29d6a2..48b6930 100644 --- a/ash/login/ui/lock_contents_view.cc +++ b/ash/login/ui/lock_contents_view.cc
@@ -2449,8 +2449,7 @@ void LockContentsView::UpdateAccessiblePreviousAndNextFocus() { if (GetWidget() && GetWidget()->GetNativeWindow()) { Shelf* shelf = Shelf::ForWindow(GetWidget()->GetNativeWindow()); - ShelfWidget* shelf_widget = shelf->shelf_widget(); - GetViewAccessibility().SetNextFocus(shelf_widget); + GetViewAccessibility().SetNextFocus(shelf->login_shelf_widget()); GetViewAccessibility().SetPreviousFocus(shelf->GetStatusAreaWidget()); } else { GetViewAccessibility().SetNextFocus(nullptr);
diff --git a/ash/login/ui/lock_contents_view_unittest.cc b/ash/login/ui/lock_contents_view_unittest.cc index 8e86bcc..34a2338 100644 --- a/ash/login/ui/lock_contents_view_unittest.cc +++ b/ash/login/ui/lock_contents_view_unittest.cc
@@ -39,6 +39,7 @@ #include "ash/root_window_controller.h" #include "ash/session/session_controller_impl.h" #include "ash/shelf/login_shelf_view.h" +#include "ash/shelf/login_shelf_widget.h" #include "ash/shelf/shelf.h" #include "ash/shelf/shelf_navigation_widget.h" #include "ash/shelf/shelf_widget.h" @@ -518,7 +519,7 @@ // Check if the previous focus is set correctly to the shelf widget. EXPECT_EQ(delegate->GetViewAccessibility().GetPreviousWindowFocus(), Shelf::ForWindow(delegate->GetWidget()->GetNativeWindow()) - ->shelf_widget()); + ->login_shelf_widget()); } TEST_F(LockContentsViewKeyboardUnitTest, AutoLayoutSmallUsersListForKeyboard) { @@ -3356,7 +3357,7 @@ EXPECT_EQ(data.GetString16Attribute(ax::mojom::StringAttribute::kName), l10n_util::GetStringUTF16(IDS_ASH_LOGIN_SCREEN_ACCESSIBLE_NAME)); EXPECT_EQ(contents->GetViewAccessibility().GetNextWindowFocus(), - shelf->shelf_widget()); + shelf->login_shelf_widget()); EXPECT_EQ(contents->GetViewAccessibility().GetPreviousWindowFocus(), shelf->GetStatusAreaWidget()); } @@ -3374,7 +3375,7 @@ EXPECT_EQ(data.GetString16Attribute(ax::mojom::StringAttribute::kName), l10n_util::GetStringUTF16(IDS_ASH_LOCK_SCREEN_ACCESSIBLE_NAME)); EXPECT_EQ(contents->GetViewAccessibility().GetNextWindowFocus(), - shelf->shelf_widget()); + shelf->login_shelf_widget()); EXPECT_EQ(contents->GetViewAccessibility().GetPreviousWindowFocus(), shelf->GetStatusAreaWidget()); }
diff --git a/ash/public/cpp/BUILD.gn b/ash/public/cpp/BUILD.gn index 174b6be..c923b31 100644 --- a/ash/public/cpp/BUILD.gn +++ b/ash/public/cpp/BUILD.gn
@@ -296,8 +296,6 @@ "projector/speech_recognition_availability.h", "reauth_reason.h", "resize_shadow_type.h", - "rounded_corner_utils.cc", - "rounded_corner_utils.h", "rounded_image_view.cc", "rounded_image_view.h", "saved_desk_delegate.h",
diff --git a/ash/public/cpp/rounded_corner_utils.cc b/ash/public/cpp/rounded_corner_utils.cc deleted file mode 100644 index 782baa2..0000000 --- a/ash/public/cpp/rounded_corner_utils.cc +++ /dev/null
@@ -1,31 +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/public/cpp/rounded_corner_utils.h" - -#include "ui/aura/window.h" -#include "ui/compositor/layer.h" -#include "ui/compositor_extra/shadow.h" -#include "ui/gfx/geometry/rounded_corners_f.h" -#include "ui/wm/core/shadow_controller.h" - -namespace ash { - -void SetCornerRadius(aura::Window* shadow_window, - ui::Layer* layer, - int radius) { - const gfx::RoundedCornersF rounded_corner_radii(radius); - if (layer->rounded_corner_radii() != rounded_corner_radii) { - layer->SetRoundedCornerRadius(rounded_corner_radii); - } - if (!layer->is_fast_rounded_corner()) { - layer->SetIsFastRoundedCorner(true); - } - - ui::Shadow* shadow = wm::ShadowController::GetShadowForWindow(shadow_window); - if (shadow) - shadow->SetRoundedCornerRadius(radius); -} - -} // namespace ash
diff --git a/ash/public/cpp/rounded_corner_utils.h b/ash/public/cpp/rounded_corner_utils.h deleted file mode 100644 index 918dde7..0000000 --- a/ash/public/cpp/rounded_corner_utils.h +++ /dev/null
@@ -1,28 +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_PUBLIC_CPP_ROUNDED_CORNER_UTILS_H_ -#define ASH_PUBLIC_CPP_ROUNDED_CORNER_UTILS_H_ - -#include "ash/public/cpp/ash_public_export.h" - -namespace aura { -class Window; -} - -namespace ui { -class Layer; -} - -namespace ash { - -// Puts rounded corners with |radius| on |layer|, and on |shadow_window|'s -// shadow if it has one. Enables fast rounded corners on |layer|. -ASH_PUBLIC_EXPORT void SetCornerRadius(aura::Window* shadow_window, - ui::Layer* layer, - int radius); - -} // namespace ash - -#endif // ASH_PUBLIC_CPP_ROUNDED_CORNER_UTILS_H_
diff --git a/ash/system/status_area_widget_delegate.cc b/ash/system/status_area_widget_delegate.cc index 94b2ba2..8ea81c5 100644 --- a/ash/system/status_area_widget_delegate.cc +++ b/ash/system/status_area_widget_delegate.cc
@@ -14,6 +14,7 @@ #include "ash/public/cpp/shell_window_ids.h" #include "ash/root_window_controller.h" #include "ash/session/session_controller_impl.h" +#include "ash/shelf/login_shelf_widget.h" #include "ash/shelf/shelf.h" #include "ash/shelf/shelf_layout_manager.h" #include "ash/shelf/shelf_widget.h" @@ -155,20 +156,22 @@ return; } + Shelf* shelf = Shelf::ForWindow(GetWidget()->GetNativeWindow()); // If OOBE dialog is visible it should be the next accessible widget, // otherwise it should be LockScreen. if (!!LoginScreen::Get()->GetLoginWindowWidget() && LoginScreen::Get()->GetLoginWindowWidget()->IsVisible()) { GetViewAccessibility().SetNextFocus( LoginScreen::Get()->GetLoginWindowWidget()); + GetViewAccessibility().SetPreviousFocus(shelf->login_shelf_widget()); } else if (LockScreen::HasInstance()) { GetViewAccessibility().SetNextFocus(LockScreen::Get()->widget()); + GetViewAccessibility().SetPreviousFocus(shelf->login_shelf_widget()); } else { GetViewAccessibility().SetNextFocus(nullptr); + GetViewAccessibility().SetPreviousFocus(shelf->shelf_widget()); } - Shelf* shelf = Shelf::ForWindow(GetWidget()->GetNativeWindow()); - GetViewAccessibility().SetPreviousFocus(shelf->shelf_widget()); } views::View* StatusAreaWidgetDelegate::GetDefaultFocusableChild() {
diff --git a/base/containers/span.h b/base/containers/span.h index c98051c9..1125a8d 100644 --- a/base/containers/span.h +++ b/base/containers/span.h
@@ -15,7 +15,6 @@ #include <algorithm> #include <concepts> -#include <functional> #include <initializer_list> #include <iterator> #include <limits>
diff --git a/base/feature_list.cc b/base/feature_list.cc index aaa5d94..835119a 100644 --- a/base/feature_list.cc +++ b/base/feature_list.cc
@@ -361,18 +361,18 @@ } } -bool FeatureList::IsFeatureOverridden(const std::string& feature_name) const { +bool FeatureList::IsFeatureOverridden(std::string_view feature_name) const { return GetOverrideEntryByFeatureName(feature_name); } bool FeatureList::IsFeatureOverriddenFromCommandLine( - const std::string& feature_name) const { + std::string_view feature_name) const { const OverrideEntry* entry = GetOverrideEntryByFeatureName(feature_name); return entry && !entry->overridden_by_field_trial; } bool FeatureList::IsFeatureOverriddenFromCommandLine( - const std::string& feature_name, + std::string_view feature_name, OverrideState state) const { const OverrideEntry* entry = GetOverrideEntryByFeatureName(feature_name); return entry && !entry->overridden_by_field_trial &&
diff --git a/base/feature_list.h b/base/feature_list.h index 731ea5d..581ec3a 100644 --- a/base/feature_list.h +++ b/base/feature_list.h
@@ -367,18 +367,18 @@ // Returns true if the state of |feature_name| has been overridden (regardless // of whether the overridden value is the same as the default value) for any // reason (e.g. command line or field trial). - bool IsFeatureOverridden(const std::string& feature_name) const; + bool IsFeatureOverridden(std::string_view feature_name) const; // Returns true if the state of |feature_name| has been overridden via // |InitFromCommandLine()|. This includes features explicitly // disabled/enabled with --disable-features and --enable-features, as well as // any extra feature overrides that depend on command line switches. bool IsFeatureOverriddenFromCommandLine( - const std::string& feature_name) const; + std::string_view feature_name) const; // Returns true if the state |feature_name| has been overridden by // |InitFromCommandLine()| and the state matches |state|. - bool IsFeatureOverriddenFromCommandLine(const std::string& feature_name, + bool IsFeatureOverriddenFromCommandLine(std::string_view feature_name, OverrideState state) const; // Associates a field trial for reporting purposes corresponding to the
diff --git a/base/metrics/histogram_macros_internal.h b/base/metrics/histogram_macros_internal.h index 39b232b..daa5515 100644 --- a/base/metrics/histogram_macros_internal.h +++ b/base/metrics/histogram_macros_internal.h
@@ -28,16 +28,16 @@ template <typename Enum> requires(std::is_enum_v<Enum>) struct EnumSizeTraits { - static constexpr Enum Count() { + static constexpr uintmax_t Count() { if constexpr (requires { Enum::kMaxValue; }) { // Since the UMA histogram macros expect a value one larger than the max // defined enumerator value, add one. - return static_cast<Enum>(base::to_underlying(Enum::kMaxValue) + 1); + return static_cast<uintmax_t>(base::to_underlying(Enum::kMaxValue) + 1); } else { static_assert( sizeof(Enum) == 0, "enumerator must define kMaxValue enumerator to use this macro!"); - return Enum(); + return 0; } } };
diff --git a/base/metrics/statistics_recorder.cc b/base/metrics/statistics_recorder.cc index 6f612b3..0a6227c 100644 --- a/base/metrics/statistics_recorder.cc +++ b/base/metrics/statistics_recorder.cc
@@ -72,6 +72,18 @@ } StatisticsRecorder::ScopedHistogramSampleObserver:: + ScopedHistogramSampleObserver(std::string_view name, + base::RepeatingClosure callback) + : histogram_name_(name), + callback_( + base::IgnoreArgs<std::optional<uint64_t>, + std::string_view, + uint64_t, + HistogramBase::Sample32>(std::move(callback))) { + StatisticsRecorder::AddHistogramSampleObserver(histogram_name_, this); +} + +StatisticsRecorder::ScopedHistogramSampleObserver:: ~ScopedHistogramSampleObserver() { StatisticsRecorder::RemoveHistogramSampleObserver(histogram_name_, this); }
diff --git a/base/metrics/statistics_recorder.h b/base/metrics/statistics_recorder.h index 6c1ddcf..3b3f2dc8 100644 --- a/base/metrics/statistics_recorder.h +++ b/base/metrics/statistics_recorder.h
@@ -98,6 +98,8 @@ OnSampleCallback callback); explicit ScopedHistogramSampleObserver(std::string_view histogram_name, OnSampleWithEventCallback callback); + explicit ScopedHistogramSampleObserver(std::string_view histogram_name, + base::RepeatingClosure callback); ~ScopedHistogramSampleObserver(); private:
diff --git a/build/DEPS b/build/DEPS index 7ed926f..9bafc137 100644 --- a/build/DEPS +++ b/build/DEPS
@@ -98,10 +98,10 @@ 'dep_type': 'gcs', 'objects': [ { - 'generation': 1748541682715337, - 'object_name': '6c924a8f88bb4731f3c2334c6ae5b5da47d5ca196ff571a91071f104dbacecad', - 'sha256sum': '6c924a8f88bb4731f3c2334c6ae5b5da47d5ca196ff571a91071f104dbacecad', - 'size_bytes': 20181372, + 'generation': 1749572829637587, + 'object_name': '5c8ef4067f41a625d81113a6292180acf4ef49a2ffe015c2779123c133b8e250', + 'sha256sum': '5c8ef4067f41a625d81113a6292180acf4ef49a2ffe015c2779123c133b8e250', + 'size_bytes': 20178952, }, ], },
diff --git a/build/android/pylib/local/device/local_device_test_run.py b/build/android/pylib/local/device/local_device_test_run.py index 3ecdbcb..d3ef35b 100644 --- a/build/android/pylib/local/device/local_device_test_run.py +++ b/build/android/pylib/local/device/local_device_test_run.py
@@ -290,7 +290,7 @@ assert isinstance(test_name, str), 'Expecting a string.' hash_bytes = hashlib.sha256(test_name.encode('utf-8')).digest() # To speed thing up, only take the last 3 bytes - return int.from_bytes(hash_bytes[-3:]) + return int.from_bytes(hash_bytes[-3:], byteorder='big') # Sort by hash so we don't put all tests in a slow suite in the same shard. def _SortTests(self, tests):
diff --git a/build/config/ios/BUILD.gn b/build/config/ios/BUILD.gn index 3558c65..6a4195b1 100644 --- a/build/config/ios/BUILD.gn +++ b/build/config/ios/BUILD.gn
@@ -252,6 +252,10 @@ "Foundation.framework", "XCTest.framework", ] + + if (xcode_version_int >= 2600) { + framework_dirs = [ "$ios_sdk_path/System/Library/SubFrameworks" ] + } } # TODO(crbug.com/40911785): any target that uses this config will miscompile.
diff --git a/build/linux/sysroot_scripts/sysroots.json b/build/linux/sysroot_scripts/sysroots.json index 9759703..d6093b0 100644 --- a/build/linux/sysroot_scripts/sysroots.json +++ b/build/linux/sysroot_scripts/sysroots.json
@@ -42,7 +42,7 @@ "URL": "https://commondatastorage.googleapis.com/chrome-linux-sysroot" }, "trixie_riscv64": { - "Sha256Sum": "6c924a8f88bb4731f3c2334c6ae5b5da47d5ca196ff571a91071f104dbacecad", + "Sha256Sum": "5c8ef4067f41a625d81113a6292180acf4ef49a2ffe015c2779123c133b8e250", "SysrootDir": "debian_trixie_riscv64-sysroot", "Tarball": "debian_trixie_riscv64_sysroot.tar.xz", "URL": "https://commondatastorage.googleapis.com/chrome-linux-sysroot"
diff --git a/cc/layers/tile_display_layer_impl.h b/cc/layers/tile_display_layer_impl.h index 45957697..a112ced 100644 --- a/cc/layers/tile_display_layer_impl.h +++ b/cc/layers/tile_display_layer_impl.h
@@ -165,6 +165,14 @@ const Tiling* GetTilingForTesting(float scale_key) const; void DiscardResource(viz::ResourceId resource); + // For testing + std::optional<SkColor4f> solid_color_for_testing() const { + return solid_color_; + } + bool is_backdrop_filter_mask_for_testing() const { + return is_backdrop_filter_mask_; + } + private: std::optional<SkColor4f> solid_color_; bool is_backdrop_filter_mask_ = false;
diff --git a/cc/metrics/compositor_frame_reporter.cc b/cc/metrics/compositor_frame_reporter.cc index 80a4585d..b698c0f 100644 --- a/cc/metrics/compositor_frame_reporter.cc +++ b/cc/metrics/compositor_frame_reporter.cc
@@ -585,8 +585,7 @@ global_trackers_(trackers) { DCHECK(global_trackers_.dropped_frame_counter); DCHECK(global_trackers_.frame_sorter); - if (global_trackers_.dropped_frame_counter - ->first_contentful_paint_received()) { + if (global_trackers_.frame_sorter->first_contentful_paint_received()) { global_trackers_.frame_sorter->AddNewFrame(args); } if (scrolling_thread_ == FrameInfo::SmoothEffectDrivingThread::kCompositor) { @@ -979,8 +978,7 @@ } } global_trackers_.frame_sorter->AddFrameInfoToBuffer(frame_info); - if (global_trackers_.dropped_frame_counter - ->first_contentful_paint_received()) { + if (global_trackers_.frame_sorter->first_contentful_paint_received()) { // Delegates call to DFC->OnEndFrame. global_trackers_.frame_sorter->AddFrameResult(args_, frame_info); }
diff --git a/cc/metrics/compositor_frame_reporting_controller_unittest.cc b/cc/metrics/compositor_frame_reporting_controller_unittest.cc index 8822a92b..33cb503 100644 --- a/cc/metrics/compositor_frame_reporting_controller_unittest.cc +++ b/cc/metrics/compositor_frame_reporting_controller_unittest.cc
@@ -1548,8 +1548,8 @@ // Stop requesting frames, skip over a few frames, and submit + present // another frame. There should no new dropped frames. + frame_sorter_.Reset(/*reset_fcp=*/true); dropped_counter_.Reset(); - frame_sorter_.Reset(); reporting_controller_.OnStoppedRequestingBeginFrames(); for (uint32_t i = 0; i < kSkipFrames; ++i) IncrementCurrentId(); @@ -1650,6 +1650,7 @@ FrameSequenceTrackerType::kCompositorAnimation); EXPECT_EQ(tracker_collection_.GetSmoothThread(), thread_type_compositor); dropped_counter_.OnFirstContentfulPaintReceived(); + frame_sorter_.OnFirstContentfulPaintReceived(); // Submit and present two compositor frames. SimulatePresentCompositorFrame(); @@ -1793,6 +1794,7 @@ EXPECT_EQ(tracker_collection_.GetSmoothThread(), thread_type_main); dropped_counter_.OnFirstContentfulPaintReceived(); + frame_sorter_.OnFirstContentfulPaintReceived(); dropped_counter_.SetTimeFirstContentfulPaintReceivedForTesting( args_.frame_time); @@ -1837,6 +1839,7 @@ TEST_F(CompositorFrameReportingControllerTest, NoUpdateCompositorWithJankyMain) { dropped_counter_.OnFirstContentfulPaintReceived(); + frame_sorter_.OnFirstContentfulPaintReceived(); dropped_counter_.SetTimeFirstContentfulPaintReceivedForTesting( args_.frame_time);
diff --git a/cc/metrics/dropped_frame_counter_unittest.cc b/cc/metrics/dropped_frame_counter_unittest.cc index 8f39b058..dc89351 100644 --- a/cc/metrics/dropped_frame_counter_unittest.cc +++ b/cc/metrics/dropped_frame_counter_unittest.cc
@@ -674,8 +674,9 @@ DroppedFrameCounterLegacyMetricsTest::DroppedFrameCounterLegacyMetricsTest() { frame_sorter_.RemoveObserver(dropped_frame_counter_.get()); dropped_frame_counter_ = std::make_unique<DroppedFrameCounter>(); - frame_sorter_.Reset(); + frame_sorter_.Reset(/*reset_fcp=*/true); dropped_frame_counter_->OnFirstContentfulPaintReceived(); + frame_sorter_.OnFirstContentfulPaintReceived(); frame_sorter_.AddObserver(dropped_frame_counter_.get()); }
diff --git a/cc/metrics/frame_sequence_tracker_unittest.cc b/cc/metrics/frame_sequence_tracker_unittest.cc index 09c6ec0..bc3fa3c 100644 --- a/cc/metrics/frame_sequence_tracker_unittest.cc +++ b/cc/metrics/frame_sequence_tracker_unittest.cc
@@ -900,6 +900,7 @@ const uint64_t kNumFramesSkipped = 5; dfc_mock_.OnFirstContentfulPaintReceived(); + sorter_.OnFirstContentfulPaintReceived(); // Expect that kNumFramesSkipped are backfilled with the appropriate smooth // thread set. EXPECT_CALL(dfc_mock_, OnEndFrame(testing::_, testing::_))
diff --git a/cc/metrics/frame_sorter.cc b/cc/metrics/frame_sorter.cc index 559d718..1d5f3a80 100644 --- a/cc/metrics/frame_sorter.cc +++ b/cc/metrics/frame_sorter.cc
@@ -52,7 +52,7 @@ current_source_id_ < args.frame_id.source_id) { // The change in source_id can be as a result of crash on gpu process, // which invalidates existing pending frames (no ack is expected). - Reset(); + Reset(true); } if (!pending_frames_.empty()) { @@ -148,7 +148,7 @@ return it->second.is_dropped(); } -void FrameSorter::Reset() { +void FrameSorter::Reset(bool reset_fcp) { total_frames_ = 0; total_partial_ = 0; total_dropped_ = 0; @@ -167,6 +167,9 @@ } pending_frames_.clear(); ring_buffer_.Clear(); + if (reset_fcp) { + first_contentful_paint_received_ = false; + } } void FrameSorter::FlushFrames() { @@ -202,4 +205,9 @@ return static_cast<uint32_t>(throughput); } +void FrameSorter::OnFirstContentfulPaintReceived() { + DCHECK(!first_contentful_paint_received_); + first_contentful_paint_received_ = true; +} + } // namespace cc
diff --git a/cc/metrics/frame_sorter.h b/cc/metrics/frame_sorter.h index c723c779..dbe159c 100644 --- a/cc/metrics/frame_sorter.h +++ b/cc/metrics/frame_sorter.h
@@ -88,7 +88,13 @@ uint32_t GetAverageThroughput() const; - void Reset(); + void Reset(bool reset_fcp); + + void OnFirstContentfulPaintReceived(); + + bool first_contentful_paint_received() { + return first_contentful_paint_received_; + } private: void FlushFrames(); @@ -113,6 +119,7 @@ size_t total_dropped_ = 0; std::optional<uint64_t> current_source_id_; + bool first_contentful_paint_received_ = false; }; } // namespace cc
diff --git a/cc/metrics/frame_sorter_unittest.cc b/cc/metrics/frame_sorter_unittest.cc index 6fba78f..cadc893f 100644 --- a/cc/metrics/frame_sorter_unittest.cc +++ b/cc/metrics/frame_sorter_unittest.cc
@@ -101,7 +101,7 @@ IncreaseSourceId(); break; case 'R': - frame_sorter_.Reset(); + frame_sorter_.Reset(/*reset_fcp=*/true); break; } }
diff --git a/cc/mojo_embedder/viz_layer_context.cc b/cc/mojo_embedder/viz_layer_context.cc index 960eff6..9db1f20 100644 --- a/cc/mojo_embedder/viz_layer_context.cc +++ b/cc/mojo_embedder/viz_layer_context.cc
@@ -827,12 +827,16 @@ case mojom::LayerType::kPicture: { // kPicture layers become kTileDisplay layers in Viz. wire.type = mojom::LayerType::kTileDisplay; - PictureLayerImpl& picture_layer = static_cast<PictureLayerImpl&>(layer); - wire.is_backdrop_filter_mask = picture_layer.is_backdrop_filter_mask(); - + auto& picture_layer = static_cast<PictureLayerImpl&>(layer); + auto tile_display_extra = viz::mojom::TileDisplayLayerExtra::New(); if (picture_layer.GetRasterSource()->IsSolidColor()) { - wire.solid_color = picture_layer.GetRasterSource()->GetSolidColor(); + tile_display_extra->solid_color = + picture_layer.GetRasterSource()->GetSolidColor(); } + tile_display_extra->is_backdrop_filter_mask = + picture_layer.is_backdrop_filter_mask(); + wire.layer_extra = viz::mojom::LayerExtra::NewTileDisplayLayerExtra( + std::move(tile_display_extra)); SerializePictureLayerTileUpdates(picture_layer, resource_provider, context_provider, update.tilings); break;
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc index c047705..7910d13 100644 --- a/cc/trees/layer_tree_host_impl.cc +++ b/cc/trees/layer_tree_host_impl.cc
@@ -638,7 +638,8 @@ begin_main_frame_metrics->should_measure_smoothness) || commit_timeout)) { is_measuring_smoothness_ = true; - dropped_frame_counter_.OnFirstContentfulPaintReceived(); + frame_sorter_.OnFirstContentfulPaintReceived(); + dropped_frame_counter()->OnFirstContentfulPaintReceived(); } // Notify the browser controls manager that we have processed any @@ -3731,7 +3732,7 @@ has_valid_layer_tree_frame_sink_ = false; client_->DidLoseLayerTreeFrameSinkOnImplThread(); lag_tracking_manager_.Clear(); - frame_sorter_.Reset(); + frame_sorter_.Reset(/*reset_fcp=*/false); dropped_frame_counter_.ResetPendingFrames(base::TimeTicks::Now()); } @@ -4035,7 +4036,7 @@ if (!visible_) { auto now = base::TimeTicks::Now(); - frame_sorter_.Reset(); + frame_sorter_.Reset(/*reset_fcp=*/false); dropped_frame_counter_.ResetPendingFrames(now); // When page is invisible, throw away corresponding EventsMetrics since @@ -5968,7 +5969,7 @@ // case to occur. // The source id has already been associated to the URL. compositor_frame_reporting_controller_->SetSourceId(source_id); - frame_sorter_.Reset(); + frame_sorter_.Reset(/*reset_fcp=*/true); dropped_frame_counter_.Reset(); is_measuring_smoothness_ = false; }
diff --git a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingTestHelper.java b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingTestHelper.java index efee3606..f7e2c7b 100644 --- a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingTestHelper.java +++ b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingTestHelper.java
@@ -568,10 +568,11 @@ /** * Matches any {@link TextView} which applies a {@link PasswordTransformationMethod}. + * * @return The matcher checking the transformation method. */ public static Matcher<View> isTransformed() { - return new BoundedMatcher<View, TextView>(TextView.class) { + return new BoundedMatcher<>(TextView.class) { @Override public boolean matchesSafely(TextView textView) { return textView.getTransformationMethod() instanceof PasswordTransformationMethod;
diff --git a/chrome/android/features/tab_ui/BUILD.gn b/chrome/android/features/tab_ui/BUILD.gn index 17d989e..e82fe93 100644 --- a/chrome/android/features/tab_ui/BUILD.gn +++ b/chrome/android/features/tab_ui/BUILD.gn
@@ -22,6 +22,8 @@ "java/res/anim/iph_touch_point_background_alpha_animation.xml", "java/res/anim/iph_touch_point_background_animation.xml", "java/res/color-night/tab_hover_card_bg_color.xml", + "java/res/color/incognito_tab_highlight_card_bg_color.xml", + "java/res/color/tab_highlight_card_bg_color.xml", "java/res/color/tab_hover_card_bg_color.xml", "java/res/drawable/archived_tab_icon.xml", "java/res/drawable/chevron_right.xml", @@ -40,10 +42,12 @@ "java/res/drawable/phone_tab_switcher_empty_state_illustration_bottom_window.xml", "java/res/drawable/phone_tab_switcher_empty_state_illustration_cloud_left.xml", "java/res/drawable/phone_tab_switcher_empty_state_illustration_cloud_right.xml", + "java/res/drawable/phone_tab_switcher_empty_state_illustration_static.xml", "java/res/drawable/phone_tab_switcher_empty_state_illustration_top_window.xml", "java/res/drawable/price_card_background.xml", "java/res/drawable/price_card_scrim.xml", "java/res/drawable/tab_grid_card_background.xml", + "java/res/drawable/tab_grid_card_highlight.xml", "java/res/drawable/tab_grid_dialog_background.xml", "java/res/drawable/tab_grid_selection_list_icon.xml", "java/res/drawable/tab_group_color_background.xml",
diff --git a/chrome/android/features/tab_ui/java/res/color/incognito_tab_highlight_card_bg_color.xml b/chrome/android/features/tab_ui/java/res/color/incognito_tab_highlight_card_bg_color.xml new file mode 100644 index 0000000..f925e14 --- /dev/null +++ b/chrome/android/features/tab_ui/java/res/color/incognito_tab_highlight_card_bg_color.xml
@@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +Copyright 2025 The Chromium Authors +Use of this source code is governed by a BSD-style license that can be +found in the LICENSE file. +--> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item + android:color="@color/baseline_primary_80" + android:alpha="0.7"/> +</selector> \ No newline at end of file
diff --git a/chrome/android/features/tab_ui/java/res/color/tab_highlight_card_bg_color.xml b/chrome/android/features/tab_ui/java/res/color/tab_highlight_card_bg_color.xml new file mode 100644 index 0000000..b21edfa --- /dev/null +++ b/chrome/android/features/tab_ui/java/res/color/tab_highlight_card_bg_color.xml
@@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +Copyright 2025 The Chromium Authors +Use of this source code is governed by a BSD-style license that can be +found in the LICENSE file. +--> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item + android:color="?attr/colorPrimaryInverse" + android:alpha="0.7"/> +</selector> \ No newline at end of file
diff --git a/chrome/android/features/tab_ui/java/res/drawable/phone_tab_switcher_empty_state_illustration_static.xml b/chrome/android/features/tab_ui/java/res/drawable/phone_tab_switcher_empty_state_illustration_static.xml new file mode 100644 index 0000000..b234597 --- /dev/null +++ b/chrome/android/features/tab_ui/java/res/drawable/phone_tab_switcher_empty_state_illustration_static.xml
@@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +Copyright 2025 The Chromium Authors +Use of this source code is governed by a BSD-style license that can be +found in the LICENSE file. +--> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:autoMirrored="true" + android:width="130dp" + android:height="130dp" + android:viewportWidth="130" + android:viewportHeight="130"> + <path + android:pathData="M15,39.44C15,24.84 26.87,13 41.51,13H89.49C104.13,13 116,24.84 116,39.44C116,51.48 107.93,61.65 96.89,64.84C96.82,64.86 96.77,64.93 96.77,65C96.77,65.07 96.82,65.14 96.89,65.16C107.93,68.35 116,78.52 116,90.56C116,105.16 104.13,117 89.49,117H41.51C26.87,117 15,105.16 15,90.56C15,78.6 22.97,68.49 33.9,65.22C34,65.19 34.06,65.1 34.06,65C34.06,64.9 34,64.81 33.9,64.78C22.97,61.51 15,51.4 15,39.44Z" + android:fillColor="@color/empty_state_asset_bg_color"/> + <path + android:pathData="M55,39L87,39A8,8 0,0 1,95 47L95,95A8,8 0,0 1,87 103L55,103A8,8 0,0 1,47 95L47,47A8,8 0,0 1,55 39z" + android:fillColor="@color/empty_state_asset_outline_color_secondary"/> + <path + android:pathData="M53,53C53,51.9 53.9,51 55,51H87C88.1,51 89,51.9 89,53V95C89,96.1 88.1,97 87,97H55C53.9,97 53,96.1 53,95V53Z" + android:fillColor="@color/empty_state_asset_bg_color"/> + <path + android:pathData="M43,27L75,27A8,8 0,0 1,83 35L83,83A8,8 0,0 1,75 91L43,91A8,8 0,0 1,35 83L35,35A8,8 0,0 1,43 27z" + android:fillColor="@color/empty_state_asset_outline_color_primary"/> + <path + android:pathData="M43,39L75,39A2,2 0,0 1,77 41L77,83A2,2 0,0 1,75 85L43,85A2,2 0,0 1,41 83L41,41A2,2 0,0 1,43 39z" + android:fillColor="@color/empty_state_asset_bg_color"/> + <path + android:pathData="M45,33m-2,0a2,2 0,1 1,4 0a2,2 0,1 1,-4 0" + android:fillColor="@color/empty_state_asset_bg_color"/> + <path + android:pathData="M50,32L62,32A1,1 0,0 1,63 33L63,33A1,1 0,0 1,62 34L50,34A1,1 0,0 1,49 33L49,33A1,1 0,0 1,50 32z" + android:fillColor="@color/empty_state_asset_bg_color"/> +</vector>
diff --git a/chrome/android/features/tab_ui/java/res/drawable/tab_grid_card_highlight.xml b/chrome/android/features/tab_ui/java/res/drawable/tab_grid_card_highlight.xml new file mode 100644 index 0000000..1f5f65ad --- /dev/null +++ b/chrome/android/features/tab_ui/java/res/drawable/tab_grid_card_highlight.xml
@@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +Copyright 2025 The Chromium Authors +Use of this source code is governed by a BSD-style license that can be +found in the LICENSE file. +--> + +<shape xmlns:android="http://schemas.android.com/apk/res/android"> + <solid android:color="@color/tab_highlight_card_bg_color"/> + <corners android:radius="@dimen/tab_grid_card_highlight_bg_radius" /> +</shape> \ No newline at end of file
diff --git a/chrome/android/features/tab_ui/java/res/drawable/tablet_tab_switcher_empty_state_illustration.xml b/chrome/android/features/tab_ui/java/res/drawable/tablet_tab_switcher_empty_state_illustration.xml index 6420eb4..32aa3661 100644 --- a/chrome/android/features/tab_ui/java/res/drawable/tablet_tab_switcher_empty_state_illustration.xml +++ b/chrome/android/features/tab_ui/java/res/drawable/tablet_tab_switcher_empty_state_illustration.xml
@@ -1,70 +1,35 @@ <?xml version="1.0" encoding="utf-8"?> <!-- -Copyright 2023 The Chromium Authors +Copyright 2025 The Chromium Authors Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" android:autoMirrored="true" + android:width="130dp" android:height="130dp" - android:viewportHeight="130" android:viewportWidth="130" - android:width="130dp"> + android:viewportHeight="130"> <path - android:fillColor="@color/empty_state_icon_bg_color" - android:pathData="M74.19,76.52L31.3,33.63C20.9,23.23 28.27,5.46 42.97,5.46H93.87C98.25,5.46 102.45,7.2 105.54,10.29L122.98,27.73C129.43,34.17 129.43,44.62 122.98,51.07L97.53,76.52C91.08,82.96 80.64,82.96 74.19,76.52Z"/> + android:pathData="M15,39.44C15,24.84 26.87,13 41.51,13H89.49C104.13,13 116,24.84 116,39.44C116,51.48 107.93,61.65 96.89,64.84C96.82,64.86 96.77,64.93 96.77,65C96.77,65.07 96.82,65.14 96.89,65.16C107.93,68.35 116,78.52 116,90.56C116,105.16 104.13,117 89.49,117H41.51C26.87,117 15,105.16 15,90.56C15,78.6 22.97,68.49 33.9,65.22C34,65.19 34.06,65.1 34.06,65C34.06,64.9 34,64.81 33.9,64.78C22.97,61.51 15,51.4 15,39.44Z" + android:fillColor="@color/empty_state_asset_bg_color"/> <path - android:fillColor="@color/empty_state_icon_bg_color" - android:pathData="M55.81,52.48L98.7,95.37C109.1,105.77 101.73,123.54 87.03,123.54H36.13C31.75,123.54 27.55,121.81 24.46,118.71L7.02,101.27C0.57,94.83 0.57,84.38 7.02,77.93L32.47,52.48C38.92,46.04 49.37,46.04 55.81,52.48Z"/> + android:pathData="M46,45L97,45A8,8 0,0 1,105 53L105,89A8,8 0,0 1,97 97L46,97A8,8 0,0 1,38 89L38,53A8,8 0,0 1,46 45z" + android:fillColor="@color/empty_state_asset_outline_color_secondary"/> <path - android:pathData="M52,57L110,57A3,3 0,0 1,113 60L113,101A3,3 0,0 1,110 104L52,104A3,3 0,0 1,49 101L49,60A3,3 0,0 1,52 57z" - android:strokeColor="@color/empty_state_icon_color" - android:strokeWidth="2"/> + android:pathData="M46,57L97,57A2,2 0,0 1,99 59L99,89A2,2 0,0 1,97 91L46,91A2,2 0,0 1,44 89L44,59A2,2 0,0 1,46 57z" + android:fillColor="@color/empty_state_asset_bg_color"/> <path - android:pathData="M52,56.5L110,56.5A3.5,3.5 0,0 1,113.5 60L113.5,101A3.5,3.5 0,0 1,110 104.5L52,104.5A3.5,3.5 0,0 1,48.5 101L48.5,60A3.5,3.5 0,0 1,52 56.5z" - android:strokeColor="@color/empty_state_icon_bg_color" - android:strokeWidth="1"/> + android:pathData="M34,33L85,33A8,8 0,0 1,93 41L93,77A8,8 0,0 1,85 85L34,85A8,8 0,0 1,26 77L26,41A8,8 0,0 1,34 33z" + android:fillColor="@color/empty_state_asset_outline_color_primary"/> <path - android:fillColor="@color/empty_state_icon_color" - android:fillType="evenOdd" - android:pathData="M52,56C49.79,56 48,57.79 48,60V64H114V60C114,57.79 112.21,56 110,56H52Z"/> + android:pathData="M34,45L85,45A2,2 0,0 1,87 47L87,77A2,2 0,0 1,85 79L34,79A2,2 0,0 1,32 77L32,47A2,2 0,0 1,34 45z" + android:fillColor="@color/empty_state_asset_bg_color"/> <path - android:pathData="M20,25L78,25A3,3 0,0 1,81 28L81,69A3,3 0,0 1,78 72L20,72A3,3 0,0 1,17 69L17,28A3,3 0,0 1,20 25z" - android:strokeColor="@color/empty_state_icon_color" - android:strokeWidth="2"/> + android:pathData="M36,39m-2,0a2,2 0,1 1,4 0a2,2 0,1 1,-4 0" + android:fillColor="@color/empty_state_asset_bg_color"/> <path - android:pathData="M20,24.5L78,24.5A3.5,3.5 0,0 1,81.5 28L81.5,69A3.5,3.5 0,0 1,78 72.5L20,72.5A3.5,3.5 0,0 1,16.5 69L16.5,28A3.5,3.5 0,0 1,20 24.5z" - android:strokeColor="@color/empty_state_icon_color" - android:strokeWidth="1"/> - <path - android:fillColor="@color/empty_state_icon_color" - android:fillType="evenOdd" - android:pathData="M20,24C17.79,24 16,25.79 16,28V32H82V28C82,25.79 80.21,24 78,24H20Z"/> - <path - android:pathData="M36,40.5L94,40.5A3.5,3.5 0,0 1,97.5 44L97.5,85A3.5,3.5 0,0 1,94 88.5L36,88.5A3.5,3.5 0,0 1,32.5 85L32.5,44A3.5,3.5 0,0 1,36 40.5z" - android:strokeColor="@color/empty_state_icon_color" - android:strokeWidth="1"/> - <path - android:fillColor="@color/empty_state_icon_tabswitcher_bg_color" - android:pathData="M36,41L94,41A3,3 0,0 1,97 44L97,85A3,3 0,0 1,94 88L36,88A3,3 0,0 1,33 85L33,44A3,3 0,0 1,36 41z" - android:strokeColor="@color/empty_state_icon_color" - android:strokeWidth="2"/> - <path - android:fillColor="@color/empty_state_icon_color" - android:fillType="evenOdd" - android:pathData="M36,40C33.79,40 32,41.79 32,44V48H98V44C98,41.79 96.21,40 94,40H36Z"/> - <path - android:fillColor="@macro/default_bg_color_elev_0" - android:pathData="M36,42L38,42A1,1 0,0 1,39 43L39,45A1,1 0,0 1,38 46L36,46A1,1 0,0 1,35 45L35,43A1,1 0,0 1,36 42z"/> - <path - android:pathData="M94,43L92,45" - android:strokeColor="@macro/default_bg_color_elev_0" - android:strokeLineCap="round" - android:strokeWidth="2"/> - <path - android:pathData="M92,43L94,45" - android:strokeColor="@macro/default_bg_color_elev_0" - android:strokeLineCap="round" - android:strokeWidth="2"/> -</vector> \ No newline at end of file + android:pathData="M41,38L53,38A1,1 0,0 1,54 39L54,39A1,1 0,0 1,53 40L41,40A1,1 0,0 1,40 39L40,39A1,1 0,0 1,41 38z" + android:fillColor="@color/empty_state_asset_bg_color"/> +</vector>
diff --git a/chrome/android/features/tab_ui/java/res/layout/tab_grid_card_item_layout.xml b/chrome/android/features/tab_ui/java/res/layout/tab_grid_card_item_layout.xml index 68a1303..25e29ac 100644 --- a/chrome/android/features/tab_ui/java/res/layout/tab_grid_card_item_layout.xml +++ b/chrome/android/features/tab_ui/java/res/layout/tab_grid_card_item_layout.xml
@@ -19,88 +19,118 @@ android:importantForAccessibility="no" /> <!-- Main card content. --> - <FrameLayout + <androidx.constraintlayout.widget.ConstraintLayout android:id="@+id/content_view" android:layout_width="match_parent" android:layout_height="match_parent"> - <RelativeLayout - android:id="@+id/card_view" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:layout_gravity="center" - android:background="@drawable/tab_grid_card_background" - android:layout_margin="@dimen/tab_grid_card_margin"> - <ImageView - android:id="@+id/tab_favicon" - android:layout_height="@dimen/tab_grid_card_header_height" - android:layout_width="wrap_content" - android:layout_gravity="center_vertical" - android:paddingStart="@dimen/tab_grid_card_favicon_padding_start" - android:paddingEnd="@dimen/tab_grid_card_favicon_padding_end" - android:adjustViewBounds="true" - android:importantForAccessibility="no" /> - <FrameLayout - android:id="@+id/tab_group_color_view_container" - android:layout_height="@dimen/tab_grid_card_header_height" - android:layout_width="wrap_content" - android:layout_gravity="center_vertical" - android:layout_toEndOf="@id/tab_favicon" - android:paddingStart="@dimen/tab_grid_card_favicon_padding_start" - android:paddingEnd="@dimen/tab_grid_card_favicon_padding_end" - android:importantForAccessibility="no" - android:visibility="gone"/> - <TextView - android:id="@+id/tab_title" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_toEndOf="@id/tab_group_color_view_container" - android:layout_marginEnd="@dimen/tab_grid_card_title_end_margin" - android:requiresFadingEdge="horizontal" - android:fadingEdgeLength="@dimen/tab_grid_card_title_fading_length" - android:minHeight="@dimen/tab_grid_card_header_height" - android:gravity="center_vertical" - android:ellipsize="none" - android:singleLine="true" - android:textAppearance="@style/TextAppearance.TextMediumThick.Primary"/> - <org.chromium.chrome.browser.tab_ui.TabThumbnailView - android:id="@+id/tab_thumbnail" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:layout_below="@id/tab_title" - android:layout_marginLeft="@dimen/tab_grid_card_thumbnail_margin" - android:layout_marginRight="@dimen/tab_grid_card_thumbnail_margin" - android:layout_marginBottom="@dimen/tab_grid_card_thumbnail_margin" - android:gravity="center_horizontal" - android:scaleType="fitCenter" - android:adjustViewBounds="false" - android:importantForAccessibility="no" - app:cornerRadiusTopStart="@dimen/tab_grid_card_thumbnail_corner_radius_top" - app:cornerRadiusTopEnd="@dimen/tab_grid_card_thumbnail_corner_radius_top" - app:cornerRadiusBottomStart="@dimen/tab_grid_card_thumbnail_corner_radius_bottom" - app:cornerRadiusBottomEnd="@dimen/tab_grid_card_thumbnail_corner_radius_bottom"/> + <View + android:id="@+id/card_wrapper" + android:layout_width="0dp" + android:layout_height="0dp" + android:visibility="gone" + android:background="@drawable/tab_grid_card_background" + android:layout_marginHorizontal="@dimen/tab_grid_card_margin_wrapper" + android:layout_marginTop="@dimen/tab_grid_card_margin_wrapper" + android:layout_marginBottom="@dimen/tab_grid_card_margin_wrapper" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintEnd_toEndOf="parent"/> + <View + android:id="@+id/card_view" + android:layout_width="0dp" + android:layout_height="0dp" + android:layout_gravity="center" + android:background="@drawable/tab_grid_card_background" + android:layout_margin="@dimen/tab_grid_card_margin" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintEnd_toEndOf="parent" /> + <ImageView + android:id="@+id/tab_favicon" + android:layout_height="@dimen/tab_grid_card_header_height" + android:layout_width="wrap_content" + android:layout_gravity="center_vertical" + android:padding="@dimen/tab_grid_card_favicon_padding_start" + android:paddingEnd="@dimen/tab_grid_card_favicon_padding_end" + android:adjustViewBounds="true" + android:scaleType="fitCenter" + android:importantForAccessibility="no" + app:layout_constraintTop_toTopOf="@id/card_view" + app:layout_constraintStart_toStartOf="@id/card_view" /> + <FrameLayout + android:id="@+id/tab_group_color_view_container" + android:layout_height="@dimen/tab_grid_card_header_height" + android:layout_width="wrap_content" + android:layout_gravity="center_vertical" + android:layout_toEndOf="@id/tab_favicon" + app:layout_constraintTop_toTopOf="@id/card_view" + app:layout_constraintStart_toEndOf="@id/tab_favicon" + android:paddingStart="@dimen/tab_grid_card_favicon_padding_start" + android:paddingEnd="@dimen/tab_grid_card_favicon_padding_end" + android:importantForAccessibility="no" + android:visibility="gone"/> + <TextView + android:id="@+id/tab_title" + android:layout_width="0dp" + android:layout_height="@dimen/tab_grid_card_header_height" + app:layout_constraintTop_toTopOf="@id/card_view" + app:layout_constraintStart_toEndOf="@id/tab_group_color_view_container" + app:layout_constraintEnd_toEndOf="@+id/card_view" + android:layout_marginEnd="@dimen/tab_grid_card_title_end_margin" + android:requiresFadingEdge="horizontal" + android:fadingEdgeLength="@dimen/tab_grid_card_title_fading_length" + android:gravity="center_vertical" + android:ellipsize="none" + android:singleLine="true" + android:textAppearance="@style/TextAppearance.TextMediumThick.Primary"/> + <org.chromium.chrome.browser.tab_ui.TabThumbnailView + android:id="@+id/tab_thumbnail" + android:layout_width="0dp" + android:layout_height="0dp" + app:layout_constraintTop_toBottomOf="@id/tab_title" + app:layout_constraintBottom_toBottomOf="@id/card_view" + app:layout_constraintStart_toStartOf="@id/card_view" + app:layout_constraintEnd_toEndOf="@id/card_view" + android:layout_marginLeft="@dimen/tab_grid_card_thumbnail_margin" + android:layout_marginRight="@dimen/tab_grid_card_thumbnail_margin" + android:layout_marginBottom="@dimen/tab_grid_card_thumbnail_margin" + android:gravity="center_horizontal" + android:scaleType="fitCenter" + android:adjustViewBounds="false" + android:importantForAccessibility="no" + app:cornerRadiusTopStart="@dimen/tab_grid_card_thumbnail_corner_radius_top" + app:cornerRadiusTopEnd="@dimen/tab_grid_card_thumbnail_corner_radius_top" + app:cornerRadiusBottomStart="@dimen/tab_grid_card_thumbnail_corner_radius_bottom" + app:cornerRadiusBottomEnd="@dimen/tab_grid_card_thumbnail_corner_radius_bottom"/> - <!-- Legacy layout for price cards. To be removed in favor of tab_card_label. --> - <org.chromium.chrome.browser.tasks.tab_management.PriceCardView - android:id="@+id/price_info_box_outer" - android:layout_below="@id/tab_title" - android:background="@drawable/price_card_scrim" - android:layout_width="match_parent" - android:layout_height="56dp" - android:layout_marginStart="4dp" - android:visibility="gone"/> + <!-- Legacy layout for price cards. To be removed in favor of tab_card_label. --> + <org.chromium.chrome.browser.tasks.tab_management.PriceCardView + android:id="@+id/price_info_box_outer" + app:layout_constraintTop_toBottomOf="@id/tab_title" + app:layout_constraintStart_toStartOf="@id/card_view" + app:layout_constraintEnd_toEndOf="@id/card_view" + android:background="@drawable/price_card_scrim" + android:layout_width="0dp" + android:layout_height="56dp" + android:layout_marginStart="4dp" + android:visibility="gone"/> - <!-- New layout for labels including activity updates and price cards. --> - <ViewStub - android:id="@+id/tab_card_label_stub" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:minHeight="@dimen/tab_card_label_height" - android:layout_marginBottom="11dp" - android:layout_alignParentBottom="true" - android:layout_centerHorizontal="true" - android:inflatedId="@+id/tab_card_label" - android:layout="@layout/tab_card_label_layout" /> - </RelativeLayout> + <!-- New layout for labels including activity updates and price cards. --> + <ViewStub + android:id="@+id/tab_card_label_stub" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:minHeight="@dimen/tab_card_label_height" + android:layout_marginBottom="11dp" + android:layout_alignParentBottom="true" + app:layout_constraintBottom_toBottomOf="@id/card_view" + app:layout_constraintStart_toStartOf="@id/card_view" + app:layout_constraintEnd_toEndOf="@id/card_view" + android:layout_centerHorizontal="true" + android:inflatedId="@+id/tab_card_label" + android:layout="@layout/tab_card_label_layout" /> <!-- Close/Select button. This is outside the RelativeLayout so it can look like it is inside @@ -115,6 +145,8 @@ android:scaleType="center" android:layout_gravity="end" android:tint="@macro/default_icon_color" - tools:ignore="ContentDescription" /> - </FrameLayout> + android:importantForAccessibility="no" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintEnd_toEndOf="parent" /> + </androidx.constraintlayout.widget.ConstraintLayout> </merge>
diff --git a/chrome/android/features/tab_ui/java/res/values/colors.xml b/chrome/android/features/tab_ui/java/res/values/colors.xml index fe9c107..92bcfc41 100644 --- a/chrome/android/features/tab_ui/java/res/values/colors.xml +++ b/chrome/android/features/tab_ui/java/res/values/colors.xml
@@ -17,7 +17,6 @@ <!-- Incognito colors for theme refactor 2021. --> <!-- TODO(crbug.com/40774932): Use semantic colors for incognito. --> - <color name="incognito_tab_action_button_color">@color/baseline_neutral_variant_80</color> <color name="incognito_tab_action_button_selected_color">@color/baseline_primary_20</color> <color name="incognito_tab_group_hovered_bg_color">@color/default_bg_color_dark_elev_1_baseline</color>
diff --git a/chrome/android/features/tab_ui/java/res/values/dimens.xml b/chrome/android/features/tab_ui/java/res/values/dimens.xml index b2068b2..e2d7eb3 100644 --- a/chrome/android/features/tab_ui/java/res/values/dimens.xml +++ b/chrome/android/features/tab_ui/java/res/values/dimens.xml
@@ -45,9 +45,12 @@ <dimen name="incognito_reauth_promo_message_icon_height">52dp</dimen> <dimen name="tab_grid_card_bg_radius">24dp</dimen> + <dimen name="tab_grid_card_highlight_bg_radius">27dp</dimen> <dimen name="tab_grid_card_favicon_padding_start">11dp</dimen> <dimen name="tab_grid_card_favicon_padding_end">9dp</dimen> <dimen name="tab_grid_card_header_height">40dp</dimen> + <dimen name="tab_grid_card_margin_wrapper">3dp</dimen> + <!-- The tab card highlight size is equal to tab_grid_card_margin - tab_grid_card_margin_wrapper --> <dimen name="tab_grid_card_margin">8dp</dimen> <dimen name="tab_grid_card_between_card_padding">4dp</dimen> <dimen name="tab_grid_card_title_fading_length">20dp</dimen>
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridView.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridView.java index cb126f3..871125f 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridView.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridView.java
@@ -5,6 +5,7 @@ package org.chromium.chrome.browser.tasks.tab_management; import static org.chromium.chrome.browser.tasks.tab_management.TabListModel.CardProperties.BASE_ANIMATION_DURATION_MS; +import static org.chromium.chrome.browser.tasks.tab_management.TabUiThemeProvider.getTabCardHighlightBackgroundTintList; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -34,6 +35,7 @@ import org.chromium.chrome.browser.tasks.tab_management.TabProperties.TabActionState; import org.chromium.chrome.tab_ui.R; import org.chromium.components.browser_ui.widget.selectable_list.SelectableItemViewBase; +import org.chromium.ui.UiUtils; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -198,6 +200,23 @@ mActionButton.setImportantForAccessibility(accessibilityMode); } + void setIsHighlighted(boolean isHighlighted, boolean isIncognito) { + Drawable gridCardHighlightDrawable = null; + View cardWrapper = findViewById(R.id.card_wrapper); + if (isHighlighted) { + Context context = getContext(); + cardWrapper.setVisibility(VISIBLE); + gridCardHighlightDrawable = + UiUtils.getTintedDrawable( + context, + R.drawable.tab_grid_card_highlight, + getTabCardHighlightBackgroundTintList(context, isIncognito)); + } else { + cardWrapper.setVisibility(GONE); + } + cardWrapper.setBackground(gridCardHighlightDrawable); + } + private void setTabActionButtonCloseDrawable() { assert mTabActionState != TabActionState.UNSET;
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridViewBinder.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridViewBinder.java index 533a997..4c165c7 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridViewBinder.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridViewBinder.java
@@ -255,15 +255,22 @@ } else if (TabProperties.VISIBILITY == propertyKey) { view.setVisibility(model.get(TabProperties.VISIBILITY)); } else if (TabProperties.IS_SELECTED == propertyKey - || TabProperties.TAB_ACTION_BUTTON_DATA == propertyKey) { + || TabProperties.TAB_ACTION_BUTTON_DATA == propertyKey + || TabProperties.TAB_GROUP_CARD_COLOR == propertyKey) { ((TabGridView) view) .setTabActionButtonTint( TabUiThemeProvider.getActionButtonTintList( view.getContext(), model.get(TabProperties.IS_INCOGNITO), - model.get(TabProperties.IS_SELECTED))); + model.get(TabProperties.IS_SELECTED), + model.get(TabProperties.TAB_GROUP_CARD_COLOR))); } else if (TabProperties.TAB_CARD_LABEL_DATA == propertyKey) { updateTabCardLabel(view, model.get(TabProperties.TAB_CARD_LABEL_DATA)); + } else if (TabProperties.IS_HIGHLIGHTED == propertyKey) { + ((TabGridView) view) + .setIsHighlighted( + model.get(TabProperties.IS_HIGHLIGHTED), + model.get(TabProperties.IS_INCOGNITO)); } }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupsPaneUnitTest.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupsPaneUnitTest.java index 9078bf6..82b93bde 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupsPaneUnitTest.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupsPaneUnitTest.java
@@ -71,7 +71,7 @@ /** Unit tests for {@link TabGroupsPane}. */ @RunWith(BaseRobolectricTestRunner.class) -@EnableFeatures({ChromeFeatureList.TAB_GROUP_SYNC_ANDROID, ChromeFeatureList.DATA_SHARING}) +@EnableFeatures({ChromeFeatureList.DATA_SHARING}) @DisableFeatures(ChromeFeatureList.TAB_GROUP_ENTRY_POINTS_ANDROID) public class TabGroupsPaneUnitTest { @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule(); @@ -174,14 +174,6 @@ } @Test - @DisableFeatures(ChromeFeatureList.TAB_GROUP_SYNC_ANDROID) - public void testWithoutSyncFeature() { - doReturn(false).when(mTabGroupSyncFeaturesJniMock).isTabGroupSyncEnabled(mProfile); - mTabGroupsPane.notifyLoadHint(LoadHint.HOT); - assertNotEquals(0, mTabGroupsPane.getRootView().getChildCount()); - } - - @Test @EnableFeatures({ ChromeFeatureList.EDGE_TO_EDGE_BOTTOM_CHIN, ChromeFeatureList.DRAW_KEY_NATIVE_EDGE_TO_EDGE
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListEmptyCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListEmptyCoordinator.java index 5da4753a..d9f4810 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListEmptyCoordinator.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListEmptyCoordinator.java
@@ -197,6 +197,7 @@ return mIsListObserverAttached; } + // TODO(https://crbug.com/423697444): Clean up old animation class for GTS mobile. private boolean isDrawableForPhones(@DrawableRes int drawableResId) { return drawableResId == R.drawable.phone_tab_switcher_empty_state_illustration; }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabProperties.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabProperties.java index aaded76..4d30215 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabProperties.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabProperties.java
@@ -76,6 +76,9 @@ public static final WritableObjectPropertyKey<TabActionListener> TAB_LONG_CLICK_LISTENER = new WritableObjectPropertyKey<>(); + public static final WritableBooleanPropertyKey IS_HIGHLIGHTED = + new WritableBooleanPropertyKey(); + public static final WritableObjectPropertyKey<TabActionButtonData> TAB_ACTION_BUTTON_DATA = new WritableObjectPropertyKey<>(); @@ -195,6 +198,7 @@ SHOULD_SHOW_PRICE_DROP_TOOLTIP, HAS_NOTIFICATION_BUBBLE, TAB_CARD_LABEL_DATA, + IS_HIGHLIGHTED }, COMMON_KEYS_TAB_AND_GROUP_GRID);
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneCoordinator.java index 8b9b8fc..6a309a9e 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneCoordinator.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneCoordinator.java
@@ -79,6 +79,7 @@ import org.chromium.ui.modaldialog.ModalDialogManager; import org.chromium.ui.modelutil.PropertyModel; import org.chromium.ui.modelutil.PropertyModelChangeProcessor; +import org.chromium.ui.util.XrUtils; import org.chromium.ui.widget.ViewRectProvider; import java.util.List; @@ -87,6 +88,7 @@ /** Coordinator for a {@link TabSwitcherPaneBase}'s UI. */ public class TabSwitcherPaneCoordinator implements BackPressHandler { static final String COMPONENT_NAME = "GridTabSwitcher"; + static final int XR_FADING_EDGE_LENGTH_PX = 24; private final MessageUpdateObserver mMessageUpdateObserver = new MessageUpdateObserver() { @@ -325,7 +327,7 @@ int emptyImageResId = DeviceFormFactor.isNonMultiDisplayContextOnTablet(activity) ? R.drawable.tablet_tab_switcher_empty_state_illustration - : R.drawable.phone_tab_switcher_empty_state_illustration; + : R.drawable.phone_tab_switcher_empty_state_illustration_static; TabListCoordinator tabListCoordinator = new TabListCoordinator( mode, @@ -358,10 +360,17 @@ mTabListCoordinator = tabListCoordinator; tabListCoordinator.setOnLongPressTabItemEventListener(mLongPressItemEventListener); - mTabListOnScrollListener - .getYOffsetNonZeroSupplier() - .addObserver(setHairlineVisibilityCallback); TabListRecyclerView recyclerView = tabListCoordinator.getContainerView(); + + if (XrUtils.isXrDevice()) { + recyclerView.setVerticalFadingEdgeEnabled(true); + recyclerView.setFadingEdgeLength(XR_FADING_EDGE_LENGTH_PX); + } else { + mTabListOnScrollListener + .getYOffsetNonZeroSupplier() + .addObserver(setHairlineVisibilityCallback); + } + recyclerView.setVisibility(View.VISIBLE); recyclerView.setBackgroundColor(Color.TRANSPARENT); recyclerView.addOnScrollListener(mTabListOnScrollListener);
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabUiThemeProvider.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabUiThemeProvider.java index 496b4ce..7c54df8 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabUiThemeProvider.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabUiThemeProvider.java
@@ -70,22 +70,18 @@ * @return The {@link ColorStateList} for tab grid card action button. */ public static ColorStateList getActionButtonTintList( - Context context, boolean isIncognito, boolean isSelected) { - if (isIncognito) { - @ColorRes - int colorRes = - isSelected - ? R.color.incognito_tab_action_button_selected_color - : R.color.incognito_tab_action_button_color; - return AppCompatResources.getColorStateList(context, colorRes); - } else { - @ColorInt - int colorInt = - isSelected - ? MaterialColors.getColor(context, R.attr.colorOnPrimary, TAG) - : MaterialColors.getColor(context, R.attr.colorOnSurfaceVariant, TAG); - return ColorStateList.valueOf(colorInt); + Context context, + boolean isIncognito, + boolean isSelected, + @Nullable @TabGroupColorId Integer colorId) { + if (isSelected) { + return isIncognito + ? AppCompatResources.getColorStateList( + context, R.color.incognito_tab_action_button_selected_color) + : ColorStateList.valueOf( + MaterialColors.getColor(context, R.attr.colorOnPrimary, TAG)); } + return SurfaceColorUpdateUtils.getCardViewActionButtonColor(context, isIncognito, colorId); } /** @@ -99,7 +95,7 @@ */ public static ColorStateList getToggleActionButtonBackgroundTintList( Context context, boolean isIncognito, boolean isSelected) { - return getActionButtonTintList(context, isIncognito, isSelected); + return getActionButtonTintList(context, isIncognito, isSelected, /* colorId */ null); } /** @@ -314,6 +310,24 @@ } /** + * Returns the {@link ColorStateList} to use for tab card highlighting based on the incognito + * mode. + * + * @param context {@link Context} used to retrieve color. + * @param isIncognito Whether the color is used for incognito mode. + * @return The {@link ColorStateList} for the tab card highlight. + */ + public static ColorStateList getTabCardHighlightBackgroundTintList( + Context context, boolean isIncognito) { + int backgroundTint = + isIncognito + ? ContextCompat.getColor( + context, R.color.incognito_tab_highlight_card_bg_color) + : ContextCompat.getColor(context, R.color.tab_highlight_card_bg_color); + return ColorStateList.valueOf(backgroundTint); + } + + /** * Returns the text color for the strip tab hover card title based on the incognito mode. * * @param context {@link Context} used to retrieve color.
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabsSettings.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabsSettings.java index 0d1aff4..bdd0f02 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabsSettings.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabsSettings.java
@@ -19,7 +19,6 @@ import org.chromium.chrome.browser.auxiliary_search.AuxiliarySearchConfigManager; import org.chromium.chrome.browser.auxiliary_search.AuxiliarySearchControllerFactory; import org.chromium.chrome.browser.auxiliary_search.AuxiliarySearchUtils; -import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.preferences.ChromeSharedPreferences; import org.chromium.chrome.browser.preferences.Pref; import org.chromium.chrome.browser.settings.ChromeBaseSettingsFragment; @@ -81,9 +80,7 @@ ChromeSwitchPreference autoOpenSyncedTabGroupsSwitch = (ChromeSwitchPreference) findPreference(PREF_AUTO_OPEN_SYNCED_TAB_GROUPS_SWITCH); boolean isTabGroupSyncAutoOpenConfigurable = - TabGroupSyncFeatures.isTabGroupSyncEnabled(getProfile()) - && ChromeFeatureList.isEnabled( - ChromeFeatureList.TAB_GROUP_SYNC_AUTO_OPEN_KILL_SWITCH); + TabGroupSyncFeatures.isTabGroupSyncEnabled(getProfile()); if (!isTabGroupSyncAutoOpenConfigurable) { autoOpenSyncedTabGroupsSwitch.setVisible(false); return;
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabsSettingsUnitTest.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabsSettingsUnitTest.java index ce839a7..ea4b3c5 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabsSettingsUnitTest.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabsSettingsUnitTest.java
@@ -35,14 +35,11 @@ import org.mockito.junit.MockitoRule; import org.chromium.base.test.BaseRobolectricTestRunner; -import org.chromium.base.test.util.Features.DisableFeatures; -import org.chromium.base.test.util.Features.EnableFeatures; import org.chromium.base.test.util.HistogramWatcher; import org.chromium.chrome.browser.auxiliary_search.AuxiliarySearchConfigManager; import org.chromium.chrome.browser.auxiliary_search.AuxiliarySearchControllerFactory; import org.chromium.chrome.browser.auxiliary_search.AuxiliarySearchHooks; import org.chromium.chrome.browser.auxiliary_search.AuxiliarySearchUtils; -import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.preferences.ChromePreferenceKeys; import org.chromium.chrome.browser.preferences.ChromeSharedPreferences; import org.chromium.chrome.browser.preferences.Pref; @@ -62,10 +59,6 @@ /** Unit tests for {@link TabsSettings}. */ @RunWith(BaseRobolectricTestRunner.class) -@EnableFeatures({ - ChromeFeatureList.TAB_GROUP_SYNC_ANDROID, - ChromeFeatureList.TAB_GROUP_SYNC_AUTO_OPEN_KILL_SWITCH -}) public class TabsSettingsUnitTest { @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule(); @@ -164,25 +157,6 @@ } @Test - @DisableFeatures(ChromeFeatureList.TAB_GROUP_SYNC_ANDROID) - public void testTabGroupSyncSettingsHiddenWhenFeatureOff() { - doReturn(false).when(mTabGroupSyncFeaturesJniMock).isTabGroupSyncEnabled(mProfileMock); - TabsSettings tabsSettings = launchFragment(); - ChromeSwitchPreference autoOpenSyncedTabGroupsSwitch = - tabsSettings.findPreference(TabsSettings.PREF_AUTO_OPEN_SYNCED_TAB_GROUPS_SWITCH); - assertFalse(autoOpenSyncedTabGroupsSwitch.isVisible()); - } - - @Test - @DisableFeatures(ChromeFeatureList.TAB_GROUP_SYNC_AUTO_OPEN_KILL_SWITCH) - public void testTabGroupSyncSettingsHiddenWhenKillswitchEnabled() { - TabsSettings tabsSettings = launchFragment(); - ChromeSwitchPreference autoOpenSyncedTabGroupsSwitch = - tabsSettings.findPreference(TabsSettings.PREF_AUTO_OPEN_SYNCED_TAB_GROUPS_SWITCH); - assertFalse(autoOpenSyncedTabGroupsSwitch.isVisible()); - } - - @Test public void testArchiveSettingsTitleAndSummary() { TabArchiveSettings archiveSettings = new TabArchiveSettings(ChromeSharedPreferences.getInstance());
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/RecyclerViewMatcherUtils.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/RecyclerViewMatcherUtils.java index 04233c12..4315688 100644 --- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/RecyclerViewMatcherUtils.java +++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/RecyclerViewMatcherUtils.java
@@ -22,7 +22,7 @@ * @return A matcher that matches RecyclerView with its adapter item count. */ public static Matcher<View> adapterHasItemCount(int itemCount) { - return new BoundedMatcher<View, RecyclerView>(RecyclerView.class) { + return new BoundedMatcher<>(RecyclerView.class) { @Override protected boolean matchesSafely(RecyclerView recyclerView) { return recyclerView.getAdapter().getItemCount() == itemCount; @@ -39,16 +39,16 @@ * This view matcher matches a RecyclerView that has a view that matches the given view matcher * at the given adapter position. * - * First this matcher scrolls the RecyclerView to the given position and then matches with the - * given view matcher. + * <p>First this matcher scrolls the RecyclerView to the given position and then matches with + * the given view matcher. * * @param position The matches adapter position. * @param itemMatcher A view matcher to match. * @return A matcher that matches RecyclerView with its adapter item position and the given view - * matcher. + * matcher. */ public static Matcher<View> atPosition(int position, Matcher<View> itemMatcher) { - return new BoundedMatcher<View, RecyclerView>(RecyclerView.class) { + return new BoundedMatcher<>(RecyclerView.class) { @Override protected boolean matchesSafely(RecyclerView recyclerView) { recyclerView.scrollToPosition(position); @@ -74,11 +74,11 @@ * @param position The adapter position. * @param viewHolderMatcher A view holder to match. * @return A matcher that matches view at adapter position and matches the given viewHolder - * matcher. + * matcher. */ public static Matcher<View> atPositionWithViewHolder( int position, Matcher<RecyclerView.ViewHolder> viewHolderMatcher) { - return new BoundedMatcher<View, RecyclerView>(RecyclerView.class) { + return new BoundedMatcher<>(RecyclerView.class) { @Override protected boolean matchesSafely(RecyclerView recyclerView) { recyclerView.scrollToPosition(position);
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogTest.java index f8e1cc00..07efe3b 100644 --- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogTest.java +++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogTest.java
@@ -47,7 +47,6 @@ import static org.chromium.chrome.browser.flags.ChromeFeatureList.DATA_SHARING_JOIN_ONLY; import static org.chromium.chrome.browser.flags.ChromeFeatureList.NAV_BAR_COLOR_MATCHES_TAB_BACKGROUND; import static org.chromium.chrome.browser.flags.ChromeFeatureList.TAB_GROUP_PARITY_BOTTOM_SHEET_ANDROID; -import static org.chromium.chrome.browser.flags.ChromeFeatureList.TAB_GROUP_SYNC_ANDROID; import static org.chromium.chrome.browser.ntp.HomeSurfaceTestUtils.createTabStatesAndMetadataFile; import static org.chromium.chrome.browser.ntp.HomeSurfaceTestUtils.createThumbnailBitmapAndWriteToFile; import static org.chromium.chrome.browser.tasks.tab_management.TabUiTestHelper.addBlankTabs; @@ -1145,7 +1144,6 @@ @Test @MediumTest - @EnableFeatures({TAB_GROUP_SYNC_ANDROID}) @DisableIf.Build( sdk_is_less_than = Build.VERSION_CODES.TIRAMISU, supported_abis_includes = "x86_64", @@ -1771,7 +1769,6 @@ @Test @MediumTest @DisableIf.Device(DeviceFormFactor.TABLET) - @EnableFeatures({TAB_GROUP_SYNC_ANDROID}) public void testStripDialog_TabListEditorCloseAll_NoCustomHomepage() { ChromeTabbedActivity cta = sActivityTestRule.getActivity(); // Create a tab group with 2 tabs. @@ -1819,7 +1816,6 @@ @Test @MediumTest @DisableIf.Device(DeviceFormFactor.TABLET) - @EnableFeatures({TAB_GROUP_SYNC_ANDROID}) public void testStripDialog_TabListEditorCloseAll_CustomHomepage() { GURL url = new GURL( @@ -1970,7 +1966,6 @@ @Test @MediumTest @Feature({"RenderTest"}) - @EnableFeatures({TAB_GROUP_SYNC_ANDROID}) @RequiresRestart("Group creation modal dialog is sometimes persistent when dismissing") @ParameterAnnotations.UseMethodParameter(NightModeTestUtils.NightModeParams.class) @DisabledTest(message = "crbug.com/362762206, see also crbug.com/360072870")
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabListEditorTestingRobot.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabListEditorTestingRobot.java index aabdc42..9d4491a 100644 --- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabListEditorTestingRobot.java +++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabListEditorTestingRobot.java
@@ -66,7 +66,7 @@ * @return A view matcher that matches the item is selected. */ public static Matcher<View> itemIsSelected() { - return new BoundedMatcher<View, TabGridView>(TabGridView.class) { + return new BoundedMatcher<>(TabGridView.class) { private TabGridView mSelectableTabGridView; @Override
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabListViewHolderTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabListViewHolderTest.java index f0141d7..2dc1815 100644 --- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabListViewHolderTest.java +++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabListViewHolderTest.java
@@ -693,7 +693,8 @@ boolean isSelected = false; mGridModel.set(TabProperties.IS_SELECTED, isSelected); ColorStateList unselectedColorStateList = - TabUiThemeProvider.getActionButtonTintList(sActivity, isIncognito, isSelected); + TabUiThemeProvider.getActionButtonTintList( + sActivity, isIncognito, isSelected, /* colorId */ null); Assert.assertEquals( unselectedColorStateList, ImageViewCompat.getImageTintList(gridActionButton)); @@ -701,7 +702,8 @@ isSelected = true; mGridModel.set(TabProperties.IS_SELECTED, isSelected); ColorStateList selectedColorStateList = - TabUiThemeProvider.getActionButtonTintList(sActivity, isIncognito, isSelected); + TabUiThemeProvider.getActionButtonTintList( + sActivity, isIncognito, isSelected, /* colorId */ null); Assert.assertEquals( selectedColorStateList, ImageViewCompat.getImageTintList(gridActionButton)); }
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherLayoutTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherLayoutTest.java index 05b1596..8737546 100644 --- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherLayoutTest.java +++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherLayoutTest.java
@@ -74,7 +74,6 @@ import org.chromium.base.test.util.CriteriaHelper; import org.chromium.base.test.util.DisabledTest; import org.chromium.base.test.util.Features.DisableFeatures; -import org.chromium.base.test.util.Features.EnableFeatures; import org.chromium.base.test.util.HistogramWatcher; import org.chromium.base.test.util.Restriction; import org.chromium.chrome.browser.ChromeTabbedActivity; @@ -573,9 +572,6 @@ @Test @MediumTest - @EnableFeatures({ - ChromeFeatureList.TAB_GROUP_SYNC_ANDROID, - }) @DisabledTest(message = "crbug.com/360393681") public void testTabGroupOverflowMenuInTabSwitcher_ungroupAccept() { final ChromeTabbedActivity cta = mActivityTestRule.getActivity(); @@ -686,9 +682,6 @@ @Test @MediumTest - @EnableFeatures({ - ChromeFeatureList.TAB_GROUP_SYNC_ANDROID, - }) @DisabledTest(message = "Flaky - crbug.com/353463207") public void testTabGroupOverflowMenuInTabSwitcher_deleteGroupAccept() { final ChromeTabbedActivity cta = mActivityTestRule.getActivity(); @@ -721,9 +714,6 @@ @Test @MediumTest - @EnableFeatures({ - ChromeFeatureList.TAB_GROUP_SYNC_ANDROID, - }) @DisabledTest(message = "crbug.com/360393681") public void testTabGroupOverflowMenuInTabSwitcher_noDeleteIncognito() { final ChromeTabbedActivity cta = mActivityTestRule.getActivity(); @@ -761,9 +751,6 @@ @Test @MediumTest - @EnableFeatures({ - ChromeFeatureList.TAB_GROUP_SYNC_ANDROID, - }) @DisabledTest(message = "crbug.com/353463207") public void testTabGroupOverflowMenuInTabSwitcher_deleteGroupDecline() { final ChromeTabbedActivity cta = mActivityTestRule.getActivity(); @@ -796,9 +783,6 @@ @Test @MediumTest - @EnableFeatures({ - ChromeFeatureList.TAB_GROUP_SYNC_ANDROID, - }) @DisabledTest(message = "crbug.com/360393681") public void testTabGroupOverflowMenuInTabSwitcher_deleteGroupDoNotShowAgain() { final ChromeTabbedActivity cta = mActivityTestRule.getActivity(); @@ -877,9 +861,6 @@ @Test @MediumTest - @DisableFeatures({ - ChromeFeatureList.TAB_GROUP_SYNC_ANDROID, - }) public void testTabGroupDialogSingleTab() { final ChromeTabbedActivity cta = mActivityTestRule.getActivity(); createTabs(cta, false, 1); @@ -893,9 +874,6 @@ @Test @MediumTest - @DisableFeatures({ - ChromeFeatureList.TAB_GROUP_SYNC_ANDROID, - }) @DisabledTest(message = "crbug.com/360393681") public void testTabGroupOverflowMenuInTabSwitcher_deleteGroupNoShowSyncDisabled() { final ChromeTabbedActivity cta = mActivityTestRule.getActivity(); @@ -1499,7 +1477,7 @@ matches( RecyclerViewMatcherUtils.atPosition( position, - new BoundedMatcher<View, TabGridView>(TabGridView.class) { + new BoundedMatcher<>(TabGridView.class) { @Override protected boolean matchesSafely(
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabThumbnailViewRenderTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabThumbnailViewRenderTest.java index cae90b9..bd0800d 100644 --- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabThumbnailViewRenderTest.java +++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabThumbnailViewRenderTest.java
@@ -231,6 +231,6 @@ mTabCard.setTabActionButtonTint( TabUiThemeProvider.getActionButtonTintList( - mTabCard.getContext(), isIncognito, isSelected)); + mTabCard.getContext(), isIncognito, isSelected, /* colorId */ null)); } }
diff --git a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupVisualDataDialogManagerUnitTest.java b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupVisualDataDialogManagerUnitTest.java index 7378074..466b5578 100644 --- a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupVisualDataDialogManagerUnitTest.java +++ b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupVisualDataDialogManagerUnitTest.java
@@ -32,9 +32,7 @@ import org.chromium.base.Token; import org.chromium.base.test.BaseRobolectricTestRunner; -import org.chromium.base.test.util.Features.EnableFeatures; import org.chromium.chrome.browser.feature_engagement.TrackerFactory; -import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.sync.SyncServiceFactory; import org.chromium.chrome.browser.tab_group_sync.TabGroupSyncFeatures; @@ -100,7 +98,6 @@ } @Test - @EnableFeatures({ChromeFeatureList.TAB_GROUP_SYNC_ANDROID}) public void testVisualDataDialogDelegate_showDialog() { mTabGroupVisualDataDialogManager.showDialog( TAB_GROUP_ID, mTabGroupModelFilter, mDialogController); @@ -122,7 +119,6 @@ } @Test - @EnableFeatures({ChromeFeatureList.TAB_GROUP_SYNC_ANDROID}) public void testVisualDataDialogDelegate_doubleShowDismissed() { // Mock a double trigger for the creation dialog observer method for the same group action, // but show dialog is only called once. @@ -135,7 +131,6 @@ } @Test - @EnableFeatures({ChromeFeatureList.TAB_GROUP_SYNC_ANDROID}) public void testVisualDataDialog_descriptionTextNotSet() { // Set the opposite values for the conditional statement to be true. doReturn(true).when(mTabModel).isIncognitoBranded(); @@ -159,7 +154,6 @@ } @Test - @EnableFeatures({ChromeFeatureList.TAB_GROUP_SYNC_ANDROID}) public void testVisualDataDialog_descriptionTextSetButNotSyncing() { doReturn(false).when(mTabModel).isIncognitoBranded(); doReturn(true) @@ -188,7 +182,6 @@ } @Test - @EnableFeatures({ChromeFeatureList.TAB_GROUP_SYNC_ANDROID}) public void testVisualDataDialog_descriptionTextSetAndSyncing() { doReturn(false).when(mTabModel).isIncognitoBranded(); doReturn(true)
diff --git a/chrome/android/java/res/layout/custom_tabs_toolbar.xml b/chrome/android/java/res/layout/custom_tabs_toolbar.xml index c59bcd8..1fbaa36da 100644 --- a/chrome/android/java/res/layout/custom_tabs_toolbar.xml +++ b/chrome/android/java/res/layout/custom_tabs_toolbar.xml
@@ -142,19 +142,12 @@ android:layout_gravity="center_vertical|end" android:gravity="center_vertical" android:orientation="horizontal"> - <FrameLayout - android:id="@+id/optional_toolbar_button_wrapper" - android:layout_width="@dimen/toolbar_button_width" - android:layout_height="wrap_content" - android:visibility="gone" - tools:ignore="UselessParent"> - <ViewStub - android:id="@+id/optional_button_stub" - android:inflatedId="@+id/optional_toolbar_button_container" - android:layout_gravity="top" - android:visibility="gone" - style="@style/ToolbarHoverableButton" /> - </FrameLayout> + <ViewStub + android:id="@+id/optional_button_stub" + android:inflatedId="@+id/optional_toolbar_button_container" + android:layout_gravity="top" + android:visibility="gone" + style="@style/ToolbarHoverableButton" /> </LinearLayout> <!-- LINT.IfChange(MenuButton) -->
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 8bd4e29..e100ae4 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -744,12 +744,6 @@ public void onFinishingTabClosure( Tab tab, boolean shouldRemoveWindowWithZeroTabs) { closeIfNoTabsAndHomepageEnabled(false, shouldRemoveWindowWithZeroTabs); - - // On XR Devices when the last tab is closed then the Chrome instance is - // also closed. - if (XrUtils.isXrDevice()) { - mMultiInstanceManager.closeChromeWindowIfEmpty(mWindowId); - } } @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/DefaultBrowserInfo.java b/chrome/android/java/src/org/chromium/chrome/browser/DefaultBrowserInfo.java index e2571738..08533ce 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/DefaultBrowserInfo.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/DefaultBrowserInfo.java
@@ -47,7 +47,7 @@ synchronized (sDirCreationLock) { if (sDefaultBrowserFetcher == null) { sDefaultBrowserFetcher = - new BackgroundOnlyAsyncTask<ArrayList<String>>() { + new BackgroundOnlyAsyncTask<>() { @Override protected ArrayList<String> doInBackground() { Context context = ContextUtils.getApplicationContext();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java index 38cf61e..fc0f2022 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java
@@ -1358,7 +1358,7 @@ public static void setPendingReferrer(Intent intent, GURL url) { intent.putExtra(Intent.EXTRA_REFERRER, Uri.parse(url.getSpec())); intent.putExtra(IntentHandler.EXTRA_REFERRER_ID, ++sReferrerId); - sPendingReferrer = new Pair<Integer, String>(sReferrerId, url.getSpec()); + sPendingReferrer = new Pair<>(sReferrerId, url.getSpec()); } /** Clears any pending referrer data. */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/reorder/StripDragShadowView.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/reorder/StripDragShadowView.java index 72867ab..8ea64b14 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/reorder/StripDragShadowView.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/reorder/StripDragShadowView.java
@@ -17,11 +17,11 @@ import android.view.ViewGroup; import android.widget.FrameLayout; import android.widget.ImageView; -import android.widget.RelativeLayout; import android.widget.TextView; import androidx.annotation.ColorInt; import androidx.annotation.VisibleForTesting; +import androidx.constraintlayout.widget.ConstraintLayout; import org.chromium.base.supplier.Supplier; import org.chromium.chrome.R; @@ -158,8 +158,8 @@ // margin that matches the start padding of the favicon. This is not applicable in the xml // layout, because the tab_grid_card_item expects to have an action button that exists after // the title to handle this symmetry. - RelativeLayout.LayoutParams layoutParams = - (RelativeLayout.LayoutParams) mTitleView.getLayoutParams(); + ConstraintLayout.LayoutParams layoutParams = + (ConstraintLayout.LayoutParams) mTitleView.getLayoutParams(); int padding = getResources().getDimensionPixelSize(R.dimen.tab_grid_card_favicon_padding_start); layoutParams.setMarginEnd(padding);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchUma.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchUma.java index eceba22..bed08dd 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchUma.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchUma.java
@@ -138,15 +138,11 @@ static { final boolean unseen = false; final boolean seen = true; - Map<Pair<Boolean, Boolean>, Integer> codes = new HashMap<Pair<Boolean, Boolean>, Integer>(); - codes.put(new Pair<Boolean, Boolean>(seen, TAP), ResultsByGesture.SEEN_FROM_TAP); - codes.put(new Pair<Boolean, Boolean>(unseen, TAP), ResultsByGesture.NOT_SEEN_FROM_TAP); - codes.put( - new Pair<Boolean, Boolean>(seen, LONG_PRESS), - ResultsByGesture.SEEN_FROM_LONG_PRESS); - codes.put( - new Pair<Boolean, Boolean>(unseen, LONG_PRESS), - ResultsByGesture.NOT_SEEN_FROM_LONG_PRESS); + Map<Pair<Boolean, Boolean>, Integer> codes = new HashMap<>(); + codes.put(new Pair<>(seen, TAP), ResultsByGesture.SEEN_FROM_TAP); + codes.put(new Pair<>(unseen, TAP), ResultsByGesture.NOT_SEEN_FROM_TAP); + codes.put(new Pair<>(seen, LONG_PRESS), ResultsByGesture.SEEN_FROM_LONG_PRESS); + codes.put(new Pair<>(unseen, LONG_PRESS), ResultsByGesture.NOT_SEEN_FROM_LONG_PRESS); SEEN_BY_GESTURE_CODES = Collections.unmodifiableMap(codes); } @@ -558,12 +554,13 @@ /** * Gets the panel-seen code for the given parameters by doing a lookup in the seen-by-gesture * map. + * * @param wasPanelSeen Whether the panel was seen. * @param wasTap Whether the gesture that originally caused the panel to show was a Tap. * @return The code to write into a panel-seen histogram. */ private static int getPanelSeenByGestureStateCode(boolean wasPanelSeen, boolean wasTap) { - return SEEN_BY_GESTURE_CODES.get(new Pair<Boolean, Boolean>(wasPanelSeen, wasTap)); + return SEEN_BY_GESTURE_CODES.get(new Pair<>(wasPanelSeen, wasTap)); } /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabAppMenuPropertiesDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabAppMenuPropertiesDelegate.java index 87eb7816..9757b75 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabAppMenuPropertiesDelegate.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabAppMenuPropertiesDelegate.java
@@ -67,7 +67,7 @@ private final boolean mIsStartIconMenu; private final List<String> mMenuEntries; - private final Map<Integer, Integer> mItemIdToIndexMap = new HashMap<Integer, Integer>(); + private final Map<Integer, Integer> mItemIdToIndexMap = new HashMap<>(); private final Supplier<ContextualPageActionController> mContextualPageActionControllerSupplier; private boolean mHasClientPackage;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java index fc0de1e..7a477359 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java
@@ -757,7 +757,7 @@ if (TextUtils.isEmpty(title) || pendingIntent == null) { continue; } - mMenuEntries.add(new Pair<String, PendingIntent>(title, pendingIntent)); + mMenuEntries.add(new Pair<>(title, pendingIntent)); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java index 2ea1a03..a699e5f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java
@@ -8,7 +8,6 @@ import android.app.PendingIntent; import android.content.ComponentCallbacks2; -import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; import android.net.Uri; @@ -92,7 +91,6 @@ import org.chromium.components.user_prefs.UserPrefs; import org.chromium.components.variations.SyntheticTrialAnnotationMode; import org.chromium.content_public.browser.BrowserStartupController; -import org.chromium.content_public.browser.ChildProcessLauncherHelper; import org.chromium.content_public.browser.WebContents; import org.chromium.content_public.common.Referrer; import org.chromium.network.mojom.ReferrerPolicy; @@ -411,37 +409,36 @@ mClientManager.overridePackageNameForSessionForTesting(session, packageName); // IN-TEST } - /** Warmup activities that should only happen once. */ - private static void initializeBrowser(final Context context) { - ThreadUtils.assertOnUiThread(); - ChromeBrowserInitializer.getInstance().handleSynchronousStartupWithGpuWarmUp(); - ChildProcessLauncherHelper.warmUpOnAnyThread(context); + public boolean warmup() { + return warmup(null); } - public boolean warmup(long flags) { + public boolean warmup(Runnable completionCallback) { try (TraceEvent e = TraceEvent.scoped("CustomTabsConnection.warmup")) { - boolean success = warmupInternal(true, null); + boolean success = warmupInternal(completionCallback); logCall("warmup()", success); return success; } } /** - * @return Whether {@link CustomTabsConnection#warmup(long)} has been called. + * @return Whether native initialization has finished. */ public boolean hasWarmUpBeenFinished() { - return mWarmupHasBeenFinished.get(); + if (ChromeFeatureList.sCctFixWarmup.isEnabled()) { + return ChromeBrowserInitializer.getInstance().isFullBrowserInitialized(); + } else { + return mWarmupHasBeenFinished.get(); + } } /** * Starts as much as possible in anticipation of a future navigation. * - * @param mayCreateSpareWebContents true if warmup() can create a spare renderer. - * @param internalCallback callback to be called after all processes are finished. + * @param completionCallback callback to be called after all processes are finished. * @return true for success. */ - private boolean warmupInternal( - final boolean mayCreateSpareWebContents, Runnable internalCallback) { + private boolean warmupInternal(Runnable completionCallback) { // Here and in mayLaunchUrl(), don't do expensive work for background applications. if (!isCallerForegroundOrSelf()) return false; int uid = Binder.getCallingUid(); @@ -461,29 +458,43 @@ // 5. RequestThrottler first access has to be done only once. // (1) - if (!initialized) { + final boolean fixWarmupEnabled = ChromeFeatureList.sCctFixWarmup.isEnabled(); + boolean shouldStartBrowser = + fixWarmupEnabled + && !ChromeBrowserInitializer.getInstance().isFullBrowserInitialized(); + boolean legacyShouldStartBrowser = !fixWarmupEnabled && !initialized; + if (shouldStartBrowser || legacyShouldStartBrowser) { tasks.add( TaskTraits.UI_DEFAULT, () -> { try (TraceEvent e = TraceEvent.scoped("CustomTabsConnection.initializeBrowser()")) { - initializeBrowser(ContextUtils.getApplicationContext()); + ChromeBrowserInitializer.getInstance() + .handleSynchronousStartupWithGpuWarmUp(); ProcessInitializationHandler.getInstance().initNetworkChangeNotifier(); - mWarmupHasBeenFinished.set(true); + if (legacyShouldStartBrowser) mWarmupHasBeenFinished.set(true); } }); } // (2) - if (mayCreateSpareWebContents && !mHiddenTabHolder.hasHiddenTab()) { + if (!mHiddenTabHolder.hasHiddenTab()) { tasks.add( TaskTraits.UI_DEFAULT, () -> { - // Temporary fix for https://crbug.com/797832. - // TODO(lizeb): Properly fix instead of papering over the bug, this code - // should not be scheduled unless startup is done. See - // https://crbug.com/797832. - if (!BrowserStartupController.getInstance().isFullBrowserStarted()) return; + if (mHiddenTabHolder.hasHiddenTab()) return; + + // TODO(https://crbug.com/423415329): I'm pretty sure this is fixed, just + // rolling this out with the flagged change in case it isn't fixed. + if (!fixWarmupEnabled) { + // Temporary fix for https://crbug.com/797832. + // TODO(lizeb): Properly fix instead of papering over the bug, this code + // should not be scheduled unless startup is done. See + // https://crbug.com/797832. + if (!BrowserStartupController.getInstance().isFullBrowserStarted()) { + return; + } + } try (TraceEvent e = TraceEvent.scoped("CreateSpareWebContents")) { createSpareWebContents(ProfileManager.getLastUsedRegularProfile()); } @@ -525,7 +536,7 @@ }); } - tasks.add(TaskTraits.UI_DEFAULT, () -> notifyWarmupIsDone(uid, internalCallback)); + tasks.add(TaskTraits.UI_DEFAULT, () -> notifyWarmupIsDone(uid, completionCallback)); tasks.start(false); mWarmupTasks = tasks; return true; @@ -651,18 +662,14 @@ final int uid = Binder.getCallingUid(); - // Things below need the browser process to be initialized. - - // Forbids warmup() from creating a spare renderer, as prerendering wouldn't reuse - // it. Checking whether prerendering is enabled requires the native library to be loaded, - // which is not necessarily the case yet. - if (!warmupInternal(false, null)) return false; // Also does the foreground check. + if (!warmupInternal(null)) return false; if (!mClientManager.updateStatsAndReturnWhetherAllowed( session, uid, urlString, otherLikelyBundles != null)) { return false; } + // Run after the first chained warmup task completes and native is initialized. PostTask.postTask( TaskTraits.UI_DEFAULT, () -> { @@ -745,7 +752,7 @@ }; // (1) - warmupInternal(true, validateOrigin); + warmupInternal(validateOrigin); } @VisibleForTesting @@ -775,27 +782,33 @@ boolean retryIfNotLoaded) { ThreadUtils.assertOnUiThread(); try (TraceEvent e = TraceEvent.scoped("CustomTabsConnection.mayLaunchUrlOnUiThread")) { - // doMayLaunchUrlInternal() is always called once the native level initialization is - // done, at least the initial profile load. However, at that stage the startup callback - // may not have run, which causes ProfileManager.getLastUsedRegularProfile() to throw an - // exception. But the tasks have been posted by then, so reschedule ourselves, only - // once. - if (!BrowserStartupController.getInstance().isFullBrowserStarted()) { - if (retryIfNotLoaded) { - PostTask.postTask( - TaskTraits.UI_DEFAULT, - () -> { - doMayLaunchUrlOnUiThread( - lowConfidence, - session, - uid, - urlString, - extras, - otherLikelyBundles, - false); - }); + // TODO(https://crbug.com/423415329): I'm pretty sure this is fixed, just + // rolling this out with the flagged change in case it isn't fixed. + if (!ChromeFeatureList.sCctFixWarmup.isEnabled()) { + // doMayLaunchUrlInternal() is always called once the native level initialization is + // done, at least the initial profile load. However, at that stage the startup + // callback + // may not have run, which causes ProfileManager.getLastUsedRegularProfile() to + // throw an + // exception. But the tasks have been posted by then, so reschedule ourselves, only + // once. + if (!BrowserStartupController.getInstance().isFullBrowserStarted()) { + if (retryIfNotLoaded) { + PostTask.postTask( + TaskTraits.UI_DEFAULT, + () -> { + doMayLaunchUrlOnUiThread( + lowConfidence, + session, + uid, + urlString, + extras, + otherLikelyBundles, + false); + }); + } + return; } - return; } enableExperimentIdsIfNecessary(extras);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnectionServiceImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnectionServiceImpl.java index 3bced78..e3ed002 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnectionServiceImpl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnectionServiceImpl.java
@@ -52,7 +52,7 @@ @Override protected boolean warmup(long flags) { if (!isFirstRunDone()) return false; - return mConnection.warmup(flags); + return mConnection.warmup(); } @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/IncognitoCustomTabIntentDataProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/IncognitoCustomTabIntentDataProvider.java index 07c39497..4f0053f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/IncognitoCustomTabIntentDataProvider.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/IncognitoCustomTabIntentDataProvider.java
@@ -146,7 +146,7 @@ PendingIntent pendingIntent = IntentUtils.safeGetParcelable(bundle, CustomTabsIntent.KEY_PENDING_INTENT); if (TextUtils.isEmpty(title) || pendingIntent == null) continue; - mMenuEntries.add(new Pair<String, PendingIntent>(title, pendingIntent)); + mMenuEntries.add(new Pair<>(title, pendingIntent)); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/ButtonVisibilityRule.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/ButtonVisibilityRule.java index ba0d0e8..8b666c3 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/ButtonVisibilityRule.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/ButtonVisibilityRule.java
@@ -7,8 +7,10 @@ import android.util.SparseArray; import android.view.View; +import androidx.annotation.Nullable; import androidx.annotation.Px; +import org.chromium.base.Callback; import org.chromium.build.annotations.NullMarked; import org.chromium.chrome.browser.browserservices.intents.CustomButtonParams.ButtonType; import org.chromium.chrome.browser.customtabs.CustomTabIntentDataProvider.CustomTabsButtonState; @@ -56,6 +58,8 @@ // have ButtonType.OTHER. private final @ButtonType int mCustomType; + private final @Nullable Callback<Boolean> mUpdateCallback; + // Visibility of the button. It can be hidden either because there is no space (handled by // this class) or because of outside factors. private boolean mVisible; @@ -64,7 +68,12 @@ // Only the buttons suppressed get turned on later again. private boolean mSuppressed; - Button(View view, boolean visible, @ButtonType int customType) { + Button( + View view, + boolean visible, + @ButtonType int customType, + @Nullable Callback<Boolean> callback) { + mUpdateCallback = callback; mView = view; mVisible = visible; mCustomType = customType; @@ -136,7 +145,24 @@ int index, View view, boolean visible, @ButtonType int customType) { if (!mActivated) return; - mButtons.put(index, new Button(view, visible, customType)); + mButtons.put(index, new Button(view, visible, customType, null)); + if (mToolbarWidth > 0 && visible) refresh(); + } + + /** + * Add a button with a callback to be invoked when the visibility changes. + * + * @param index Index of the button. + * @param view {@link View} of the button to which the visibility is applied. + * @param visible {@code true} if the button is to be visible. + * @param callback {@link Callback} to be invoked when the visibility changes when the rule set + * is applied. + */ + public void addButtonWithCallback( + int index, View view, boolean visible, Callback<Boolean> callback) { + if (!mActivated) return; + + mButtons.put(index, new Button(view, visible, ButtonType.OTHER, callback)); if (mToolbarWidth > 0 && visible) refresh(); } @@ -175,6 +201,7 @@ button.mVisible = false; button.mView.setVisibility(View.GONE); button.mSuppressed = true; + if (button.mUpdateCallback != null) button.mUpdateCallback.onResult(false); urlBarWidth = getUrlBarWidth(); } adjustMinimizeButtonPriority(); @@ -194,6 +221,7 @@ minimize.mVisible = true; minimize.mSuppressed = false; minimize.mView.setVisibility(View.VISIBLE); + if (minimize.mUpdateCallback != null) minimize.mUpdateCallback.onResult(true); } } } @@ -213,6 +241,7 @@ button.mVisible = false; button.mSuppressed = true; button.mView.setVisibility(View.GONE); + if (button.mUpdateCallback != null) button.mUpdateCallback.onResult(false); return true; } return false; @@ -241,6 +270,7 @@ } else { button.mView.setVisibility(View.VISIBLE); button.mSuppressed = false; + if (button.mUpdateCallback != null) button.mUpdateCallback.onResult(true); } } adjustMinimizeButtonPriority();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbar.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbar.java index 1dfc5e9..9c918ab5 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbar.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbar.java
@@ -529,10 +529,10 @@ @Override protected void updateCustomActionButton(int index, Drawable drawable, String description) { - ImageButton button = - (ImageButton) - mCustomActionButtons.getChildAt( - mCustomActionButtons.getChildCount() - 1 - index); + // |index| -> childIndex should ignore the optional button always present at the end. + int childIndex = mCustomActionButtons.getChildCount() - 2 - index; + assert 0 <= childIndex && childIndex <= mCustomActionButtons.getChildCount() - 2; + ImageButton button = (ImageButton) mCustomActionButtons.getChildAt(childIndex); assert button != null; updateCustomActionButtonVisuals(button, drawable, description); } @@ -738,8 +738,8 @@ if (hasMultipleDevButtons()) return false; // 2) Optional button view may be made hidden due to width constraint. - View optionalButtonWrapper = findViewById(R.id.optional_toolbar_button_wrapper); - return optionalButtonWrapper.getVisibility() == View.VISIBLE; + View optionalButtonContainer = findViewById(R.id.optional_toolbar_button_container); + return optionalButtonContainer.getVisibility() == View.VISIBLE; } private boolean hasMultipleDevButtons() { @@ -1411,7 +1411,7 @@ optionalButtonStub.setLayoutResource(R.layout.optional_button_layout); View optionalButton = optionalButtonStub.inflate(); - var lp = (FrameLayout.LayoutParams) optionalButton.getLayoutParams(); + var lp = (LinearLayout.LayoutParams) optionalButton.getLayoutParams(); lp.width = getResources().getDimensionPixelSize(R.dimen.toolbar_button_width); optionalButton.setLayoutParams(lp); @@ -1471,9 +1471,13 @@ } CustomTabToolbar.this.requestLayout(); }); - View optionalButtonWrapper = findViewById(R.id.optional_toolbar_button_wrapper); - optionalButtonWrapper.setVisibility(View.VISIBLE); - mButtonVisibilityRule.addButton(ButtonId.MTB, optionalButtonWrapper, true); + View optionalButtonContainer = findViewById(R.id.optional_toolbar_button_container); + optionalButtonContainer.setVisibility(View.VISIBLE); + mButtonVisibilityRule.addButtonWithCallback( + ButtonId.MTB, + optionalButtonContainer, + true, + mOptionalButtonCoordinator::setCanChangeVisibility); return true; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/ChromeDownloadDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/download/ChromeDownloadDelegate.java index e196f2e6..9d8f8f9 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/ChromeDownloadDelegate.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/ChromeDownloadDelegate.java
@@ -82,7 +82,7 @@ // Check to see if we have an SDCard. String status = Environment.getExternalStorageState(); File fullDirPath = getDownloadDirectoryFullPath(); - return new Pair<String, File>(status, fullDirPath); + return new Pair<>(status, fullDirPath); } @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java index 70db86d1..57bbe5cc 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java
@@ -95,8 +95,7 @@ private static boolean sIsNetworkListenerDisabled; private static boolean sIsNetworkMetered; - private final HashMap<String, DownloadProgress> mDownloadProgressMap = - new HashMap<String, DownloadProgress>(4, 0.75f); + private final HashMap<String, DownloadProgress> mDownloadProgressMap = new HashMap<>(4, 0.75f); private final DownloadNotifier mDownloadNotifier; // Delay between UI updates. @@ -408,7 +407,7 @@ final DownloadItem item = progress.mDownloadItem; AsyncTask<Pair<Boolean, Boolean>> task = - new AsyncTask<Pair<Boolean, Boolean>>() { + new AsyncTask<>() { @Override public Pair<Boolean, Boolean> doInBackground() { boolean success =
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/OMADownloadHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/download/OMADownloadHandler.java index 2de9782..3a3b430 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/OMADownloadHandler.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/OMADownloadHandler.java
@@ -166,7 +166,7 @@ private final List<String> mTypes; OMAInfo() { - mDescription = new HashMap<String, String>(); + mDescription = new HashMap<>(); mTypes = new ArrayList<>(); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/dragdrop/ChromeTabDropDataAndroid.java b/chrome/android/java/src/org/chromium/chrome/browser/dragdrop/ChromeTabDropDataAndroid.java index 9507dba..deaa603 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/dragdrop/ChromeTabDropDataAndroid.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/dragdrop/ChromeTabDropDataAndroid.java
@@ -7,14 +7,15 @@ import android.content.ClipDescription; import android.content.Context; -import androidx.annotation.NonNull; - +import org.chromium.build.annotations.NullMarked; +import org.chromium.build.annotations.Nullable; import org.chromium.chrome.browser.tab.Tab; import org.chromium.ui.base.MimeTypeUtils; /** Chrome-specific drop data containing a {@link Tab}. */ +@NullMarked public class ChromeTabDropDataAndroid extends ChromeDropDataAndroid { - public final Tab tab; + public final @Nullable Tab tab; public final boolean isTabInGroup; ChromeTabDropDataAndroid(Builder builder) { @@ -31,11 +32,13 @@ @Override public boolean isIncognito() { - return tab.isIncognitoBranded(); + return tab != null && tab.isIncognitoBranded(); } @Override public String buildTabClipDataText(Context context) { + if (tab == null) return ""; + return tab.getUrl().getSpec(); } @@ -51,14 +54,14 @@ /** Builder for @{@link ChromeTabDropDataAndroid} instance. */ public static class Builder extends ChromeDropDataAndroid.Builder { - private Tab mTab; + private @Nullable Tab mTab; private boolean mIsTabInGroup; /** * @param tab to be set in clip data. * @return {@link ChromeTabDropDataAndroid.Builder} instance. */ - public Builder withTab(@NonNull Tab tab) { + public Builder withTab(Tab tab) { mTab = tab; return this; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/dragdrop/ChromeTabGroupDropDataAndroid.java b/chrome/android/java/src/org/chromium/chrome/browser/dragdrop/ChromeTabGroupDropDataAndroid.java index 33b00813..a8870ba 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/dragdrop/ChromeTabGroupDropDataAndroid.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/dragdrop/ChromeTabGroupDropDataAndroid.java
@@ -8,16 +8,16 @@ import android.content.Context; import android.text.TextUtils; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - +import org.chromium.build.annotations.NullMarked; +import org.chromium.build.annotations.Nullable; import org.chromium.chrome.browser.tabmodel.TabGroupMetadata; import org.chromium.chrome.browser.tabmodel.TabGroupTitleUtils; import org.chromium.ui.base.MimeTypeUtils; /** Chrome-specific drop data containing a {@link TabGroupMetadata}. */ +@NullMarked public class ChromeTabGroupDropDataAndroid extends ChromeDropDataAndroid { - @Nullable public final TabGroupMetadata tabGroupMetadata; + public final @Nullable TabGroupMetadata tabGroupMetadata; ChromeTabGroupDropDataAndroid(Builder builder) { super(builder); @@ -32,11 +32,12 @@ @Override public boolean isIncognito() { - return tabGroupMetadata.isIncognito; + return tabGroupMetadata != null && tabGroupMetadata.isIncognito; } @Override public String buildTabClipDataText(Context context) { + if (tabGroupMetadata == null) return ""; if (TextUtils.isEmpty(tabGroupMetadata.tabGroupTitle)) { return TabGroupTitleUtils.getDefaultTitle( context, tabGroupMetadata.tabIdsToUrls.size()); @@ -56,13 +57,13 @@ /** Builder for @{@link ChromeTabDropDataAndroid} instance. */ public static class Builder extends ChromeDropDataAndroid.Builder { - private TabGroupMetadata mTabGroupMetadata; + private @Nullable TabGroupMetadata mTabGroupMetadata; /** * @param tabGroupMetadata The {@link TabGroupMetadata} associated with the dragging group. * @return {@link ChromeTabGroupDropDataAndroid.Builder} instance. */ - public Builder withTabGroupMetadata(@NonNull TabGroupMetadata tabGroupMetadata) { + public Builder withTabGroupMetadata(TabGroupMetadata tabGroupMetadata) { mTabGroupMetadata = tabGroupMetadata; return this; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/feedback/ConnectivityTask.java b/chrome/android/java/src/org/chromium/chrome/browser/feedback/ConnectivityTask.java index bed12e5..f30e3fa 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/feedback/ConnectivityTask.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/feedback/ConnectivityTask.java
@@ -7,13 +7,14 @@ import android.os.SystemClock; import androidx.annotation.IntDef; -import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import org.chromium.base.Log; import org.chromium.base.ThreadUtils; import org.chromium.base.task.PostTask; import org.chromium.base.task.TaskTraits; +import org.chromium.build.annotations.NullMarked; +import org.chromium.build.annotations.Nullable; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.net.ConnectionType; import org.chromium.net.NetworkChangeNotifier; @@ -25,9 +26,10 @@ import java.util.Map; /** - * A utility class for checking if the device is currently connected to the Internet by using - * both available network stacks, and checking over both HTTP and HTTPS. + * A utility class for checking if the device is currently connected to the Internet by using both + * available network stacks, and checking over both HTTP and HTTPS. */ +@NullMarked public class ConnectivityTask { private static final String TAG = "feedback"; @@ -272,11 +274,11 @@ private final Map<Integer, Integer> mResult = new HashMap<>(); private final int mTimeoutMs; - private final ConnectivityResult mCallback; + private final @Nullable ConnectivityResult mCallback; private final long mStartCheckTimeMs; @VisibleForTesting - ConnectivityTask(Profile profile, int timeoutMs, ConnectivityResult callback) { + ConnectivityTask(Profile profile, int timeoutMs, @Nullable ConnectivityResult callback) { mTimeoutMs = timeoutMs; mCallback = callback; mStartCheckTimeMs = SystemClock.elapsedRealtime();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/findinpage/FindToolbar.java b/chrome/android/java/src/org/chromium/chrome/browser/findinpage/FindToolbar.java index 587821cb..d3a55b6 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/findinpage/FindToolbar.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/findinpage/FindToolbar.java
@@ -4,6 +4,9 @@ package org.chromium.chrome.browser.findinpage; +import static org.chromium.build.NullUtil.assertNonNull; +import static org.chromium.build.NullUtil.assumeNonNull; + import android.animation.Animator; import android.annotation.SuppressLint; import android.content.ClipData; @@ -28,7 +31,6 @@ import android.widget.TextView; import androidx.annotation.IntDef; -import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import androidx.core.view.accessibility.AccessibilityEventCompat; import androidx.core.view.inputmethod.EditorInfoCompat; @@ -37,6 +39,9 @@ import org.chromium.base.ThreadUtils; import org.chromium.base.supplier.ObservableSupplier; import org.chromium.base.supplier.ObservableSupplierImpl; +import org.chromium.build.annotations.Initializer; +import org.chromium.build.annotations.NullMarked; +import org.chromium.build.annotations.Nullable; import org.chromium.chrome.R; import org.chromium.chrome.browser.tab.EmptyTabObserver; import org.chromium.chrome.browser.tab.Tab; @@ -60,6 +65,7 @@ import java.lang.annotation.RetentionPolicy; /** A toolbar providing find in page functionality. */ +@NullMarked public class FindToolbar extends LinearLayout implements BackPressHandler { @IntDef({ FindLocationBarState.SHOWN, @@ -89,14 +95,14 @@ protected ImageButton mFindNextButton; protected View mDivider; - private FindResultBar mResultBar; + private @Nullable FindResultBar mResultBar; private TabModelSelector mTabModelSelector; - private Tab mCurrentTab; - private TabModel mCurrentTabModel; + private @Nullable Tab mCurrentTab; + private @Nullable TabModel mCurrentTabModel; private WindowAndroid mWindowAndroid; - private FindInPageBridge mFindInPageBridge; - private FindToolbarObserver mObserver; + private @Nullable FindInPageBridge mFindInPageBridge; + private @Nullable FindToolbarObserver mObserver; /** Most recently entered search text (globally, in non-incognito tabs). */ private String mLastUserSearch = ""; @@ -121,6 +127,7 @@ super(context, attrs); } + @Initializer void setFindToolbar(FindToolbar findToolbar) { mFindToolbar = findToolbar; } @@ -154,8 +161,10 @@ } // Identify how much of the original text should be replaced + var text = getText(); + assumeNonNull(text); int min = 0; - int max = getText().length(); + int max = text.length(); if (isFocused()) { final int selStart = getSelectionStart(); @@ -165,8 +174,8 @@ max = Math.max(0, Math.max(selStart, selEnd)); } - Selection.setSelection(getText(), max); - getText().replace(min, max, builder.toString()); + Selection.setSelection(text, max); + text.replace(min, max, builder.toString()); return true; } } @@ -174,7 +183,7 @@ } @Override - public InputConnection onCreateInputConnection(EditorInfo outAttrs) { + public @Nullable InputConnection onCreateInputConnection(EditorInfo outAttrs) { InputConnection connection = super.onCreateInputConnection(outAttrs); if (mFindToolbar.isIncognito()) { outAttrs.imeOptions |= EditorInfoCompat.IME_FLAG_NO_PERSONALIZED_LEARNING; @@ -253,7 +262,7 @@ @Override public void onFocusChange(View v, boolean hasFocus) { if (!hasFocus) { - if (mFindQuery.getText().length() > 0) { + if (assumeNonNull(mFindQuery.getText()).length() > 0) { mSearchKeyShouldTriggerSearch = true; } mWindowAndroid.getKeyboardDelegate().hideKeyboard(mFindQuery); @@ -347,6 +356,19 @@ mDivider = findViewById(R.id.find_separator); } + /** The find toolbar's container must provide access to its TabModel. */ + @Initializer + public void setTabModelSelector(TabModelSelector modelSelector) { + mTabModelSelector = modelSelector; + updateVisualsForTabModel(isIncognito()); + } + + /** Sets the WindowAndroid in which the find toolbar will be shown. Needed for animations. */ + @Initializer + public void setWindowAndroid(WindowAndroid windowAndroid) { + mWindowAndroid = windowAndroid; + } + @Override public @BackPressResult int handleBackPress() { int result = @@ -366,7 +388,7 @@ private void hideKeyboardAndStartFinding(boolean forward) { if (mFindInPageBridge == null) return; - final String findQuery = mFindQuery.getText().toString(); + final String findQuery = assumeNonNull(mFindQuery.getText()).toString(); if (findQuery.length() == 0) return; mWindowAndroid.getKeyboardDelegate().hideKeyboard(mFindQuery); @@ -412,7 +434,7 @@ private void onFindMatchRects(FindMatchRectsDetails matchRects) { if (mResultBar == null) return; - if (mFindQuery.getText().length() > 0) { + if (assumeNonNull(mFindQuery.getText()).length() > 0) { mResultBar.setMatchRects(matchRects.version, matchRects.rects, matchRects.activeRect); } else { // Since we don't issue a request for an empty string we never get a 'no rects' response @@ -485,7 +507,7 @@ && result.finalUpdate && !mFindInPageBridge .getPreviousFindText() - .startsWith(mFindQuery.getText().toString())) { + .startsWith(assumeNonNull(mFindQuery.getText()).toString())) { final boolean hapticFeedbackEnabled = Settings.System.getInt( context.getContentResolver(), @@ -508,17 +530,6 @@ : context.getString(R.string.accessible_find_in_page_no_results); } - /** The find toolbar's container must provide access to its TabModel. */ - public void setTabModelSelector(TabModelSelector modelSelector) { - mTabModelSelector = modelSelector; - updateVisualsForTabModel(isIncognito()); - } - - /** Sets the WindowAndroid in which the find toolbar will be shown. Needed for animations. */ - public void setWindowAndroid(WindowAndroid windowAndroid) { - mWindowAndroid = windowAndroid; - } - /** * Handles updating any visual elements of the find toolbar based on changes to the tab model. * @param isIncognito Whether the current tab model is incognito or not. @@ -574,9 +585,9 @@ for (TabModel model : mTabModelSelector.getModels()) { model.addObserver(mTabModelObserver); } - mCurrentTab = mTabModelSelector.getCurrentTab(); + mCurrentTab = assumeNonNull(mTabModelSelector.getCurrentTab()); mCurrentTab.addObserver(mTabObserver); - mFindInPageBridge = new FindInPageBridge(mCurrentTab.getWebContents()); + mFindInPageBridge = new FindInPageBridge(assertNonNull(mCurrentTab.getWebContents())); initializeFindText(); mFindQuery.requestFocus(); // The keyboard doesn't show itself automatically. @@ -609,6 +620,7 @@ } /** Logic for handling deactivating the find toolbar. */ + @SuppressWarnings("NullAway") protected void handleDeactivation(boolean clearSelection) { setResultsBarVisibility(false); @@ -684,7 +696,7 @@ } @VisibleForTesting - public FindResultBar getFindResultBar() { + public @Nullable FindResultBar getFindResultBar() { return mResultBar; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/NavigationHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/NavigationHandler.java index eaa6a686..04e66e7d 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/NavigationHandler.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/NavigationHandler.java
@@ -4,6 +4,8 @@ package org.chromium.chrome.browser.gesturenav; +import static org.chromium.build.NullUtil.assertNonNull; +import static org.chromium.build.NullUtil.assumeNonNull; import static org.chromium.chrome.browser.gesturenav.GestureNavigationProperties.ACTION; import static org.chromium.chrome.browser.gesturenav.GestureNavigationProperties.ALLOW_NAV; import static org.chromium.chrome.browser.gesturenav.GestureNavigationProperties.BUBBLE_OFFSET; @@ -22,11 +24,12 @@ import android.view.ViewGroup; import androidx.annotation.IntDef; -import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import org.chromium.base.Log; import org.chromium.base.supplier.Supplier; +import org.chromium.build.annotations.NullMarked; +import org.chromium.build.annotations.Nullable; import org.chromium.cc.input.BrowserControlsState; import org.chromium.chrome.browser.back_press.BackPressMetrics; import org.chromium.chrome.browser.gesturenav.BackActionDelegate.ActionType; @@ -49,6 +52,7 @@ * 3-button navigation mode. For gestural navigation mode, see {@link * ToolbarManager#OnBackPressHandler} */ +@NullMarked class NavigationHandler implements TouchEventObserver { // Width of a rectangluar area in dp on the left/right edge used for navigation. // Swipe beginning from a point within these rects triggers the operation. @@ -105,8 +109,8 @@ private GestureDetector mDetector; private final View.OnAttachStateChangeListener mAttachStateListener; private final BackActionDelegate mBackActionDelegate; - @Nullable private TabOnBackGestureHandler mTabOnBackGestureHandler; - private Tab mTab; + private @Nullable TabOnBackGestureHandler mTabOnBackGestureHandler; + private @Nullable Tab mTab; private final Supplier<Boolean> mWillNavigateSupplier; private @GestureState int mState; @@ -140,11 +144,12 @@ } @Override - public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { + public boolean onScroll( + @Nullable MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { // |onScroll| needs handling only after the state moved away from |NONE|. if (isStopped()) return true; return NavigationHandler.this.onScroll( - e1.getX(), distanceX, distanceY, e2.getX(), e2.getY()); + assumeNonNull(e1).getX(), distanceX, distanceY, e2.getX(), e2.getY()); } } @@ -300,6 +305,7 @@ mState = GestureState.DRAGGED; if (willUpdateTabHistory(forward)) { + assert mTab != null; if (GestureNavigationUtils.allowTransition(mTab, forward)) { if (TabOnBackGestureHandler.shouldAnimateNavigationTransition( forward, initiatingEdge)) { @@ -312,8 +318,9 @@ getProgress(), mInitiatingEdge, forward, false); } BackPressMetrics.recordNavStatusOnGestureStart( - mTab.getWebContents().hasUncommittedNavigationInPrimaryMainFrame(), - mTab.getWindowAndroid().getActivity().get().getWindow()); + assumeNonNull(mTab.getWebContents()) + .hasUncommittedNavigationInPrimaryMainFrame(), + assumeNonNull(mTab.getWindowAndroid().getActivity().get()).getWindow()); mStartNavDuringOngoingGesture = false; mBackGestureForTabHistoryInProgress = true; } @@ -355,6 +362,7 @@ // Delegate navigation to native side: supposed to be triggered after animation. return; } + assert mTab != null; if (forward) { // Session history may have changed since the beginning of the gesture such that it's no // longer possible to go forward. @@ -365,7 +373,7 @@ // Perform back action at the next UI thread execution. The back action can // potentially close the tab we're running on, which causes use-after-destroy // exception if the closing operation is performed synchronously. - mHandler.post(() -> mBackActionDelegate.onBackGesture(mTab)); + mHandler.post(() -> mBackActionDelegate.onBackGesture(assertNonNull(mTab))); } } @@ -377,6 +385,7 @@ private @CloseTarget int getCloseIndicator(boolean forward) { if (forward) return CloseTarget.NONE; + assert mTab != null; @ActionType int type = mBackActionDelegate.getBackActionType(mTab); if (type == ActionType.CLOSE_TAB) { return CloseTarget.TAB; @@ -414,9 +423,10 @@ boolean allowNav = endState == GestureEndState.INVOKE; // If the back gesture will update history, record the metrics. if (mBackGestureForTabHistoryInProgress) { + assumeNonNull(mTab); BackPressMetrics.recordNavStatusDuringGesture( mStartNavDuringOngoingGesture, - mTab.getWindowAndroid().getActivity().get().getWindow()); + assumeNonNull(mTab.getWindowAndroid().getActivity().get()).getWindow()); } mBackGestureForTabHistoryInProgress = false; mStartNavDuringOngoingGesture = false; @@ -503,6 +513,7 @@ } /** Performs cleanup upon destruction. */ + @SuppressWarnings("NullAway") void destroy() { if (mTab != null) { assert mTabObserver != null : "Always has a tab observer"; @@ -512,7 +523,7 @@ mDetector = null; } - TabOnBackGestureHandler getTabOnBackGestureHandlerForTesting() { + @Nullable TabOnBackGestureHandler getTabOnBackGestureHandlerForTesting() { return mTabOnBackGestureHandler; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/history/AppHistoryUmaRecorder.java b/chrome/android/java/src/org/chromium/chrome/browser/history/AppHistoryUmaRecorder.java index 562cbc1..8af22b8 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/history/AppHistoryUmaRecorder.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/history/AppHistoryUmaRecorder.java
@@ -4,7 +4,10 @@ package org.chromium.chrome.browser.history; +import org.chromium.build.annotations.NullMarked; + /** UMA/Histogram recorder for in-app history. */ +@NullMarked public class AppHistoryUmaRecorder extends HistoryUmaRecorder { private static final String APP_METRICS_PREFIX = "Android.AppHistoryPage.";
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryContentManager.java b/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryContentManager.java index fd21f34..c12089e 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryContentManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryContentManager.java
@@ -747,7 +747,7 @@ public AppInfo get(String appId) { assert appId != null; - if (mAppInfoMap == null) mAppInfoMap = new HashMap<String, AppInfo>(); + if (mAppInfoMap == null) mAppInfoMap = new HashMap<>(); AppInfo appInfo = mAppInfoMap.get(appId); if (appInfo == null) { try {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryDeletionBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryDeletionBridge.java index 81bf8eb..8a01bc62 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryDeletionBridge.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryDeletionBridge.java
@@ -13,10 +13,13 @@ import org.chromium.base.ObserverList; import org.chromium.base.ThreadUtils; import org.chromium.base.lifetime.Destroyable; +import org.chromium.build.annotations.NullMarked; +import org.chromium.build.annotations.Nullable; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.profiles.ProfileKeyedMap; /** The JNI bridge for Android to receive notifications about history deletions. */ +@NullMarked public class HistoryDeletionBridge implements Destroyable { /** * Allows derived class to listen to history deletions that pass through this bridge. The @@ -26,7 +29,7 @@ void onURLsDeleted(HistoryDeletionInfo historyDeletionInfo); } - private static ProfileKeyedMap<HistoryDeletionBridge> sProfileMap; + private static @Nullable ProfileKeyedMap<HistoryDeletionBridge> sProfileMap; /** Return the deletion bridge associated with the given {@link Profile}. */ public static HistoryDeletionBridge getForProfile(Profile profile) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/AutofillVirtualCardEnrollmentInfoBar.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/AutofillVirtualCardEnrollmentInfoBar.java index 814d0ae7..04ea05e 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/AutofillVirtualCardEnrollmentInfoBar.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/AutofillVirtualCardEnrollmentInfoBar.java
@@ -17,6 +17,9 @@ import org.jni_zero.CalledByNative; import org.jni_zero.NativeMethods; +import org.chromium.build.annotations.Initializer; +import org.chromium.build.annotations.NullMarked; +import org.chromium.build.annotations.Nullable; import org.chromium.chrome.R; import org.chromium.chrome.browser.ChromeStringConstants; import org.chromium.chrome.browser.autofill.AutofillUiUtils.IconSpecs; @@ -33,14 +36,15 @@ import java.util.LinkedList; /** An infobar for virtual card enrollment information. */ +@NullMarked public class AutofillVirtualCardEnrollmentInfoBar extends ConfirmInfoBar { private final long mNativeAutofillVirtualCardEnrollmentInfoBar; private Bitmap mIssuerIcon; private String mCardLabel; private int mIconDrawableId = -1; private final String mTitleText; - private String mDescriptionText; - private String mLearnMoreLinkText; + private @Nullable String mDescriptionText; + private @Nullable String mLearnMoreLinkText; private final LinkedList<LegalMessageLine> mGoogleLegalMessageLines = new LinkedList<>(); private final LinkedList<LegalMessageLine> mIssuerLegalMessageLines = new LinkedList<>(); @@ -109,6 +113,7 @@ * @param issuerIcon Bitmap image of the icon that will be shown for this credit card. * @param label The credit card label, for example "***1234". */ + @Initializer @CalledByNative private void addCardDetail(Bitmap issuerIcon, String label) { mIssuerIcon = issuerIcon;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/native_page/NativePageAssassin.java b/chrome/android/java/src/org/chromium/chrome/browser/native_page/NativePageAssassin.java index 7c28570..5abf532 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/native_page/NativePageAssassin.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/native_page/NativePageAssassin.java
@@ -35,8 +35,7 @@ * The most recently hidden tabs, limited to MAX_RECENT_TABS elements, ordered from oldest to * newest. Visible tabs are not included in this list. */ - private final ArrayList<WeakReference<Tab>> mRecentTabs = - new ArrayList<WeakReference<Tab>>(MAX_RECENT_TABS + 1); + private final ArrayList<WeakReference<Tab>> mRecentTabs = new ArrayList<>(MAX_RECENT_TABS + 1); private NativePageAssassin() {}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridge.java index e92cd35..fc2b9a9 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridge.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridge.java
@@ -140,8 +140,7 @@ // c) in the case the user choses to "Undo", we will only be able to restore the notification // they originally clicked "Unsubscribe" on. private static final Map<String, Map<String, Notification>> - sOriginsWithProvisionallyRevokedPermissions = - new HashMap<String, Map<String, Notification>>(); + sOriginsWithProvisionallyRevokedPermissions = new HashMap<>(); // The `realtimeMillis` timestamp corresponding to the last time the pre-native processing for // the `PRE_UNSUBSCRIBE` intent was started. Used to measure the time, as perceived by the user,
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 b8e273aa..e4a9762 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
@@ -647,7 +647,8 @@ mTab.getProfile(), windowAndroid, mIsTablet, - mTabStripHeightSupplier); + mTabStripHeightSupplier, + () -> mTemplateUrlService.getComposeplateUrl()); initializeHomeModules();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java index c6642d6..7243538f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java
@@ -31,10 +31,10 @@ import org.chromium.base.MathUtils; import org.chromium.base.TraceEvent; import org.chromium.base.supplier.ObservableSupplier; +import org.chromium.base.supplier.Supplier; import org.chromium.chrome.R; import org.chromium.chrome.browser.composeplate.ComposeplateCoordinator; import org.chromium.chrome.browser.composeplate.ComposeplateMetricsUtils; -import org.chromium.chrome.browser.composeplate.ComposeplateUtils; import org.chromium.chrome.browser.feed.FeedSurfaceScrollDelegate; import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.lens.LensEntryPoint; @@ -67,6 +67,7 @@ import org.chromium.ui.base.MimeTypeUtils; import org.chromium.ui.base.WindowAndroid; import org.chromium.ui.text.EmptyTextWatcher; +import org.chromium.url.GURL; /** * Layout for the new tab page. This positions the page elements in the correct vertical positions. @@ -148,6 +149,7 @@ private TextView mFakeSearchBoxEditText; private Callback<Logo> mOnLogoAvailableCallback; private boolean mIsComposeplateEnabled; + private Supplier<GURL> mComposeplateUrlSupplier; private OnClickListener mVoiceSearchButtonClickListener; private OnClickListener mLensButtonClickListener; private @Nullable ComposeplateCoordinator mComposeplateCoordinator; @@ -223,7 +225,8 @@ Profile profile, WindowAndroid windowAndroid, boolean isTablet, - ObservableSupplier<Integer> tabStripHeightSupplier) { + ObservableSupplier<Integer> tabStripHeightSupplier, + Supplier<GURL> composeplateUrlSupplier) { TraceEvent.begin(TAG + ".initialize()"); mScrollDelegate = scrollDelegate; mManager = manager; @@ -234,6 +237,9 @@ mIsTablet = isTablet; mTabStripHeightSupplier = tabStripHeightSupplier; mIsComposeplateEnabled = ChromeFeatureList.sAndroidComposeplate.isEnabled() && !mIsTablet; + if (mIsComposeplateEnabled) { + mComposeplateUrlSupplier = composeplateUrlSupplier; + } if (mIsTablet) { mDisplayStyleObserver = this::onDisplayStyleChanged; @@ -369,11 +375,16 @@ if (!mIsComposeplateEnabled) return; View.OnClickListener composeplateButtonClickListener = - v -> - mManager.getNativePageHost() - .loadUrl( - new LoadUrlParams(ComposeplateUtils.getComposeplateURL()), - /* incognito= */ false); + v -> { + if (!mComposeplateUrlSupplier.hasValue() + || mComposeplateUrlSupplier.get() == null) { + return; + } + mManager.getNativePageHost() + .loadUrl( + new LoadUrlParams(mComposeplateUrlSupplier.get()), + /* incognito= */ false); + }; mSearchBoxCoordinator.setComposeplateButtonClickListener( createEnhancedClickListener(composeplateButtonClickListener));
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java index da6992e9..44275e5 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java
@@ -740,7 +740,7 @@ LoadUrlParams loadUrlParams = new LoadUrlParams(url); if (!TextUtils.isEmpty(extraHeaderKey) && !TextUtils.isEmpty(extraHeaderValue)) { // Set both map-based and collapsed headers to support all use scenarios. - Map<String, String> headers = new HashMap<String, String>(); + Map<String, String> headers = new HashMap<>(); headers.put(extraHeaderKey, extraHeaderValue); loadUrlParams.setExtraHeaders(headers); loadUrlParams.setVerbatimHeaders(extraHeaderKey + ":" + extraHeaderValue);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/ServiceWorkerPaymentAppBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/ServiceWorkerPaymentAppBridge.java index a60bf82..77a61893 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/payments/ServiceWorkerPaymentAppBridge.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/ServiceWorkerPaymentAppBridge.java
@@ -90,8 +90,7 @@ new Runnable() { @Override public void run() { - callback.onGetServiceWorkerPaymentAppsInfo( - new HashMap<String, Pair<String, Bitmap>>()); + callback.onGetServiceWorkerPaymentAppsInfo(new HashMap<>()); } }); return; @@ -146,7 +145,7 @@ @CalledByNative private static Object createPaymentAppsInfo() { - return new HashMap<String, Pair<String, Bitmap>>(); + return new HashMap<>(); } @SuppressWarnings("unchecked")
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/TileRenderer.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/TileRenderer.java index b93b392..a8214dbd 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/TileRenderer.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/TileRenderer.java
@@ -106,7 +106,7 @@ /** Simple multimap from SiteSuggestion to SuggestionsTileView. */ private static class SuggestionsTileViewCache { private final Map<SiteSuggestion, LinkedList<SuggestionsTileView>> mStorage = - new HashMap<SiteSuggestion, LinkedList<SuggestionsTileView>>(); + new HashMap<>(); void put(SiteSuggestion key, @NonNull SuggestionsTileView value) { LinkedList<SuggestionsTileView> bucket = mStorage.get(key);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/BatchUploadCardPreference.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/BatchUploadCardPreference.java index 05f5544f..ce66574 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/BatchUploadCardPreference.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/BatchUploadCardPreference.java
@@ -63,11 +63,16 @@ /** Initialize the dependencies for the BatchUploadCardPreference and update the error card. */ @Initializer - public void initialize(Activity activity, Profile profile, ModalDialogManager dialogManager) { + public void initialize( + Activity activity, + Profile profile, + ModalDialogManager dialogManager, + OneshotSupplier<SnackbarManager> snackbarManagerSupplier) { mActivity = activity; mProfile = profile; mSyncService = SyncServiceFactory.getForProfile(mProfile); mDialogManager = dialogManager; + mSnackbarManagerSupplier = snackbarManagerSupplier; if (mSyncService != null) { mSyncService.addSyncStateChangedListener(this); } @@ -85,11 +90,6 @@ update(); } - public void setSnackbarManagerSupplier( - OneshotSupplier<SnackbarManager> snackbarManagerSupplier) { - mSnackbarManagerSupplier = snackbarManagerSupplier; - } - @Override public void onDetached() { super.onDetached();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/ManageSyncSettings.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/ManageSyncSettings.java index a512b13..a026395 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/ManageSyncSettings.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/ManageSyncSettings.java
@@ -475,8 +475,8 @@ mBatchUploadCardPreference.initialize( getActivity(), profile, - ((ModalDialogManagerHolder) getActivity()).getModalDialogManager()); - mBatchUploadCardPreference.setSnackbarManagerSupplier(mSnackbarManagerSupplier); + ((ModalDialogManagerHolder) getActivity()).getModalDialogManager(), + mSnackbarManagerSupplier); } private void setupAccountDataTypePreferences() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabCollectionTabModelImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabCollectionTabModelImpl.java index 190192d..5d07121 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabCollectionTabModelImpl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabCollectionTabModelImpl.java
@@ -308,6 +308,11 @@ @Override protected void openTabProgrammatically(GURL url, int index) {} + @Override + protected Tab[] getAllTabs() { + return new Tab[0]; + } + // TabGroupModelFilter overrides. @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelImpl.java index c13c2db6..e9832781 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelImpl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelImpl.java
@@ -1144,6 +1144,12 @@ index); } + @Override + public Tab[] getAllTabs() { + Tab[] tabs = new Tab[mTabs.size()]; + return mTabs.toArray(tabs); + } + @VisibleForTesting List<Tab> getTabsNavigatedInTimeWindow(long beginTimeMs, long endTimeMs) { List<Tab> tabList = new ArrayList<>();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelJniBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelJniBridge.java index 5ad6fce0..4c252d1 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelJniBridge.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelJniBridge.java
@@ -225,6 +225,9 @@ @CalledByNative protected abstract void openTabProgrammatically(GURL url, int index); + @CalledByNative + protected abstract Tab[] getAllTabs(); + @NativeMethods @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE) public interface Natives {
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 86167a3..ef9dde5 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
@@ -827,7 +827,8 @@ tabModelSelectorSupplier.get().getCurrentModelTabCountSupplier()); mProfileSupplier = profileSupplier; mIsNewTabPageCustomizationToolbarButtonEnabled = - ChromeFeatureList.sNewTabPageCustomization.isEnabled() + !DeviceFormFactor.isNonMultiDisplayContextOnTablet(mActivity) + && ChromeFeatureList.sNewTabPageCustomization.isEnabled() && ChromeFeatureList.sNewTabPageCustomizationToolbarButton.isEnabled(); ToolbarLayout toolbarLayout = mActivity.findViewById(R.id.toolbar); @@ -1004,8 +1005,7 @@ tab.getWindowAndroid().getActivity().get(), tab, tab.getProfile()); }; - if (!mIsNewTabPageCustomizationToolbarButtonEnabled - || DeviceFormFactor.isNonMultiDisplayContextOnTablet(mActivity)) { + if (!mIsNewTabPageCustomizationToolbarButtonEnabled) { View homeButton = controlContainer.findViewById(R.id.home_button); if (homeButton != null) { mHomeButtonCoordinator = @@ -1019,16 +1019,17 @@ } else { View homePageButtonsContainer = controlContainer.findViewById(R.id.home_page_buttons_layout); - - mHomePageButtonsCoordinator = - new HomePageButtonsCoordinator( - mActivity, - mProfileSupplier, - homePageButtonsContainer, - this::onHomeButtonMenuClick, - HomepagePolicyManager::isHomepageLocationManaged, - mBottomSheetController, - this::onHomePageButtonClick); + if (homePageButtonsContainer != null) { + mHomePageButtonsCoordinator = + new HomePageButtonsCoordinator( + mActivity, + mProfileSupplier, + homePageButtonsContainer, + this::onHomeButtonMenuClick, + HomepagePolicyManager::isHomepageLocationManaged, + mBottomSheetController, + this::onHomePageButtonClick); + } } ChromeImageButton backButton = mControlContainer.findViewById(R.id.back_button);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodViewBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodViewBridge.java index 706e5b9..a2db93e 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodViewBridge.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodViewBridge.java
@@ -19,6 +19,7 @@ import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.touch_to_fill.common.BottomSheetFocusHelper; import org.chromium.components.autofill.AutofillSuggestion; +import org.chromium.components.autofill.AutofillSuggestion.Payload; import org.chromium.components.autofill.LoyaltyCard; import org.chromium.components.autofill.SuggestionType; import org.chromium.components.browser_ui.bottomsheet.BottomSheetController; @@ -101,27 +102,21 @@ @JniType("std::u16string") String secondaryLabel, @JniType("std::u16string") String subLabel, @JniType("std::u16string") String secondarySubLabel, - @JniType("std::u16string") String labelContentDescription, @SuggestionType int suggestionType, GURL customIconUrl, int iconId, boolean applyDeactivatedStyle, - boolean shouldDisplayTermsAvailable, - @JniType("std::string") String guid, - boolean isLocalPaymentsMethod) { + Payload payload) { return new AutofillSuggestion.Builder() .setLabel(label) .setSecondaryLabel(secondaryLabel) .setSubLabel(subLabel) .setSecondarySubLabel(secondarySubLabel) - .setLabelContentDescription(labelContentDescription) .setSuggestionType(suggestionType) .setCustomIconUrl(customIconUrl) .setIconId(iconId) .setApplyDeactivatedStyle(applyDeactivatedStyle) - .setShouldDisplayTermsAvailable(shouldDisplayTermsAvailable) - .setGuid(guid) - .setIsLocalPaymentsMethod(isLocalPaymentsMethod) + .setPayload(payload) .build(); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkIntentDataProviderFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkIntentDataProviderFactory.java index 2ab14cb..9830126 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkIntentDataProviderFactory.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkIntentDataProviderFactory.java
@@ -627,12 +627,11 @@ /** * Extract the icon URLs and icon hashes from the WebAPK's meta data, and returns a map of these * {URL, hash} pairs. The icon URLs/icon hashes are stored in a single meta data tag in the - * WebAPK's AndroidManifest.xml as following: - * "URL1 hash1 URL2 hash2 URL3 hash3..." + * WebAPK's AndroidManifest.xml as following: "URL1 hash1 URL2 hash2 URL3 hash3..." */ @VisibleForTesting static Map<String, String> getIconUrlAndIconMurmur2HashMap(Bundle metaData) { - Map<String, String> iconUrlAndIconMurmur2HashMap = new HashMap<String, String>(); + Map<String, String> iconUrlAndIconMurmur2HashMap = new HashMap<>(); String iconUrlsAndIconMurmur2Hashes = metaData.getString(WebApkMetaDataKeys.ICON_URLS_AND_ICON_MURMUR2_HASHES); if (TextUtils.isEmpty(iconUrlsAndIconMurmur2Hashes)) return iconUrlAndIconMurmur2HashMap;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkUpdateDataFetcher.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkUpdateDataFetcher.java index 0f7428e..1a808b6 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkUpdateDataFetcher.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkUpdateDataFetcher.java
@@ -152,7 +152,7 @@ byte[][] shortcutIconData) { Context appContext = ContextUtils.getApplicationContext(); - HashMap<String, String> iconUrlToMurmur2HashMap = new HashMap<String, String>(); + HashMap<String, String> iconUrlToMurmur2HashMap = new HashMap<>(); for (String iconUrl : iconUrls) { String murmur2Hash = null; if (iconUrl.equals(primaryIconUrl)) {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/browsing_data/BrowsingDataRemoverIntegrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/browsing_data/BrowsingDataRemoverIntegrationTest.java index 66f99b0..e52e4a4d 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/browsing_data/BrowsingDataRemoverIntegrationTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/browsing_data/BrowsingDataRemoverIntegrationTest.java
@@ -76,7 +76,7 @@ @MediumTest public void testUnregisteringWebapps() throws Exception { // Register three web apps. - final HashMap<String, String> apps = new HashMap<String, String>(); + final HashMap<String, String> apps = new HashMap<>(); apps.put("webapp1", "https://www.google.com/index.html"); apps.put("webapp2", "https://www.chrome.com/foo/bar"); apps.put("webapp3", "http://example.com/");
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/overlays/strip/TabStripGroupContextMenuTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/overlays/strip/TabStripGroupContextMenuTest.java index ab134f6..4c16733 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/overlays/strip/TabStripGroupContextMenuTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/overlays/strip/TabStripGroupContextMenuTest.java
@@ -45,7 +45,6 @@ import org.chromium.base.test.util.CriteriaHelper; import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.Features; -import org.chromium.base.test.util.Features.EnableFeatures; import org.chromium.base.test.util.Restriction; import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.flags.ChromeSwitches; @@ -72,7 +71,6 @@ /** Instrumentation tests for tab strip group title long-press menu popup */ @RunWith(ChromeJUnit4ClassRunner.class) @Batch(Batch.PER_CLASS) -@EnableFeatures(ChromeFeatureList.TAB_GROUP_SYNC_ANDROID) // TODO(crbug.com/419289558): Re-enable color surface feature flags @Features.DisableFeatures({ ChromeFeatureList.ANDROID_SURFACE_COLOR_UPDATE,
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java index 0093d48b..ca497f8 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java
@@ -1025,7 +1025,7 @@ */ UserActionMonitor(Set<String> userActionPrefixes) { mUserActionPrefixes = userActionPrefixes; - mUserActionCounts = new HashMap<String, Integer>(); + mUserActionCounts = new HashMap<>(); for (String action : mUserActionPrefixes) { mUserActionCounts.put(action, 0); }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java index 62fe4c8..a70500a 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
@@ -1649,7 +1649,7 @@ var sessionHolder = new SessionHolder<>(token); connection.newSession(token); setCanUseHiddenTabForSession(sessionHolder, true); - connection.warmup(0); + connection.warmup(); // Needs the browser process to be initialized. ThreadUtils.runOnUiThreadBlocking(
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabsConnectionTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabsConnectionTest.java index 75eec6b..e71a301 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabsConnectionTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabsConnectionTest.java
@@ -242,7 +242,7 @@ @Restriction(RESTRICTION_TYPE_NON_LOW_END_DEVICE) @CommandLineFlags.Add(ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE) public void testOnlyOneHiddenTab() throws Exception { - Assert.assertTrue("Failed warmup()", mCustomTabsConnection.warmup(0)); + Assert.assertTrue("Failed warmup()", mCustomTabsConnection.warmup()); CustomTabsSessionToken token = CustomTabsSessionToken.createMockSessionTokenForTesting(); var sessionHolder = new SessionHolder<>(token); Assert.assertTrue("Failed newSession()", mCustomTabsConnection.newSession(token)); @@ -301,7 +301,7 @@ @Restriction(RESTRICTION_TYPE_NON_LOW_END_DEVICE) @CommandLineFlags.Add(ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE) public void testKillHiddenTabRenderer() throws Exception { - Assert.assertTrue("Failed warmup()", mCustomTabsConnection.warmup(0)); + Assert.assertTrue("Failed warmup()", mCustomTabsConnection.warmup()); CustomTabsSessionToken token = CustomTabsSessionToken.createMockSessionTokenForTesting(); var sessionHolder = new SessionHolder<>(token); Assert.assertTrue("Failed newSession()", mCustomTabsConnection.newSession(token)); @@ -436,12 +436,12 @@ prepareEmbeddedTestServer(); Context context = ApplicationProvider.getApplicationContext(); - Assert.assertTrue("Failed warmup()", mCustomTabsConnection.warmup(0)); + Assert.assertTrue("Failed warmup()", mCustomTabsConnection.warmup()); final OnEvaluateJavaScriptResultHelper JsHelper = new OnEvaluateJavaScriptResultHelper(); // Launch a custom tab and load the url. - Assert.assertTrue("Failed warmup()", mCustomTabsConnection.warmup(0)); + Assert.assertTrue("Failed warmup()", mCustomTabsConnection.warmup()); Intent intent = CustomTabsIntentTestUtils.createMinimalCustomTabIntent(context, mTestPageUrl); mCustomTabActivityTestRule.startCustomTabActivityWithIntent(intent); @@ -469,7 +469,7 @@ // Launch the first hidden tab. This tab should use a separate storage partition and // therefore shouldn't see the first cookie. - Assert.assertTrue("Failed warmup()", mCustomTabsConnection.warmup(0)); + Assert.assertTrue("Failed warmup()", mCustomTabsConnection.warmup()); Intent intent2 = CustomTabsIntentTestUtils.createMinimalCustomTabIntent(context, mTestPageUrl); var sessionHolder = SessionHolder.getSessionHolderFromIntent(intent2); @@ -571,7 +571,7 @@ // Finally, launch a third custom tab. Because there isn't an associated mayLaunchUrl this // custom tab will use the default storage partition and will access the first cookie. - Assert.assertTrue("Failed warmup()", mCustomTabsConnection.warmup(0)); + Assert.assertTrue("Failed warmup()", mCustomTabsConnection.warmup()); Intent intent3 = CustomTabsIntentTestUtils.createMinimalCustomTabIntent(context, mTestPageUrl); mCustomTabActivityTestRule.startCustomTabActivityWithIntent(intent3); @@ -882,11 +882,11 @@ newSessionWithWarmupWaiter(client, warmupWaiter); // Both sessions should be notified. - Assert.assertTrue(mCustomTabsConnection.warmup(0)); + Assert.assertTrue(mCustomTabsConnection.warmup()); warmupWaiter.waitForCallback(0, 2, 20, TimeUnit.SECONDS); // Notifications should be sent even if warmup() has already been called. - Assert.assertTrue(mCustomTabsConnection.warmup(0)); + Assert.assertTrue(mCustomTabsConnection.warmup()); warmupWaiter.waitForCallback(2, 2); } @@ -935,7 +935,7 @@ public void testPrefetchWithWarmup() throws Exception { prepareEmbeddedTestServer(); CustomTabsSessionToken token = CustomTabsSessionToken.createMockSessionTokenForTesting(); - Assert.assertTrue(mCustomTabsConnection.warmup(0)); + Assert.assertTrue(mCustomTabsConnection.warmup()); Assert.assertTrue(mCustomTabsConnection.newSession(token)); HistogramWatcher histogramWatcher =
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabsTestUtils.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabsTestUtils.java index 5c0c955..d586cf1 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabsTestUtils.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabsTestUtils.java
@@ -115,7 +115,7 @@ } } }); - Assert.assertTrue(connection.warmup(0)); + Assert.assertTrue(connection.warmup()); startupCallbackHelper.waitForCallback(0, 1, 20, TimeUnit.SECONDS); return connection; }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/dom_distiller/ReaderModeTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/dom_distiller/ReaderModeTest.java index 2d81069c..671d849 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/dom_distiller/ReaderModeTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/dom_distiller/ReaderModeTest.java
@@ -125,6 +125,7 @@ @Test @MediumTest + @DisabledTest(message = "https://crbug.com/423646543") public void testReaderModeInCct() throws TimeoutException { mDownloadTestRule.loadUrl(mURL); Tab originalTab = mDownloadTestRule.getActivity().getActivityTab(); @@ -148,6 +149,7 @@ @Test @MediumTest + @DisabledTest(message = "https://crbug.com/423646543") public void testReaderModeInCct_Downloaded() throws TimeoutException { mDownloadTestRule.loadUrl(mURL); Tab originalTab = mDownloadTestRule.getActivity().getActivityTab(); @@ -173,6 +175,7 @@ @Test @MediumTest + @DisabledTest(message = "https://crbug.com/423646543") public void testReaderModeInCct_Incognito() throws TimeoutException { mDownloadTestRule.loadUrl(mURL); openReaderModeInIncognitoCct(); @@ -412,7 +415,8 @@ is("chrome-distiller"))); ChromeTabUtils.waitForTabPageLoaded(tab, null); // Distiller Viewer load the content dynamically, so waitForTabPageLoaded() is not enough. - CriteriaHelper.pollUiThread(() -> Criteria.checkThat(tab.getTitle(), is(expectedTitle))); + CriteriaHelper.pollUiThreadLongTimeout( + null, () -> Criteria.checkThat(tab.getTitle(), is(expectedTitle))); String innerHtml = getInnerHtml(tab); assertThat(innerHtml).contains("article-header");
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadManagerServiceTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadManagerServiceTest.java index 2a83e03..f46f530c 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadManagerServiceTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadManagerServiceTest.java
@@ -78,8 +78,7 @@ } // Use MethodID for Integer values. - private final Queue<Pair<Integer, Object>> mExpectedCalls = - new ConcurrentLinkedQueue<Pair<Integer, Object>>(); + private final Queue<Pair<Integer, Object>> mExpectedCalls = new ConcurrentLinkedQueue<>(); public MockDownloadNotifier() { expect(MethodID.CLEAR_PENDING_DOWNLOADS, null); @@ -112,7 +111,7 @@ } static Pair<Integer, Object> getMethodSignature(@MethodID int methodId, Object param) { - return new Pair<Integer, Object>(methodId, param); + return new Pair<>(methodId, param); } void assertCorrectExpectedCall(@MethodID int methodId, Object param, boolean matchParams) {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/incognito/IncognitoDataTestUtils.java b/chrome/android/javatests/src/org/chromium/chrome/browser/incognito/IncognitoDataTestUtils.java index 0ed6fc4c..532cd67 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/incognito/IncognitoDataTestUtils.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/incognito/IncognitoDataTestUtils.java
@@ -241,7 +241,7 @@ }); }); - CustomTabsConnection.getInstance().warmup(0); + CustomTabsConnection.getInstance().warmup(); startUpCallback.waitForCallback(0); } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/RecentlyClosedBridgeTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/RecentlyClosedBridgeTest.java index 4dc17268..5e2712d 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/RecentlyClosedBridgeTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/RecentlyClosedBridgeTest.java
@@ -27,10 +27,8 @@ import org.chromium.base.test.util.CriteriaHelper; import org.chromium.base.test.util.DisableIf; import org.chromium.base.test.util.DisabledTest; -import org.chromium.base.test.util.Features.EnableFeatures; import org.chromium.base.test.util.RequiresRestart; import org.chromium.chrome.browser.ChromeTabbedActivity; -import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.flags.ChromeSwitches; import org.chromium.chrome.browser.profiles.ProfileManager; import org.chromium.chrome.browser.sync.SyncServiceFactory; @@ -997,7 +995,6 @@ /** Tests a hiding tab group is not saved when undoable. */ @Test @MediumTest - @EnableFeatures({ChromeFeatureList.TAB_GROUP_SYNC_ANDROID}) public void testNoRecentlyClosedEntry_ForHidingTabGroup_Undoable() { if (mTabGroupModelFilter == null) return; @@ -1024,7 +1021,6 @@ /** Tests a hiding tab group is not saved when not undoable. */ @Test @MediumTest - @EnableFeatures({ChromeFeatureList.TAB_GROUP_SYNC_ANDROID}) public void testNoRecentlyClosedEntry_ForHidingTabGroup_NotUndoable() { if (mTabGroupModelFilter == null) return;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeTest.java index 2a1574d..a6e7937 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeTest.java
@@ -645,7 +645,7 @@ () -> { mOfflinePageBridge.getPagesByNamespace( namespace, - new Callback<List<OfflinePageItem>>() { + new Callback<>() { @Override public void onResult(List<OfflinePageItem> pages) { result.addAll(pages);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflineTestUtil.java b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflineTestUtil.java index e17880a..353ec5ae 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflineTestUtil.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflineTestUtil.java
@@ -55,8 +55,7 @@ // Gets all available offline pages. public static List<OfflinePageItem> getAllPages() throws TimeoutException { - final AtomicReference<List<OfflinePageItem>> result = - new AtomicReference<List<OfflinePageItem>>(); + final AtomicReference<List<OfflinePageItem>> result = new AtomicReference<>(); final CallbackHelper callbackHelper = new CallbackHelper(); ThreadUtils.runOnUiThreadBlocking( () -> { @@ -104,8 +103,7 @@ // Returns all OfflineItems provided by the OfflineContentProvider. public static List<OfflineItem> getOfflineItems() throws TimeoutException { CallbackHelper finished = new CallbackHelper(); - final AtomicReference<ArrayList<OfflineItem>> result = - new AtomicReference<ArrayList<OfflineItem>>(); + final AtomicReference<ArrayList<OfflineItem>> result = new AtomicReference<>(); ThreadUtils.runOnUiThreadBlocking( () -> { OfflineContentAggregatorFactory.get()
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/password_manager/settings/PasswordSettingsTestHelper.java b/chrome/android/javatests/src/org/chromium/chrome/browser/password_manager/settings/PasswordSettingsTestHelper.java index 058a174..7cd9f55 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/password_manager/settings/PasswordSettingsTestHelper.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/password_manager/settings/PasswordSettingsTestHelper.java
@@ -175,7 +175,7 @@ * @return A Matcher to find a particular {@link ViewHolder} that contains certain text. */ static Matcher<ViewHolder> hasTextInViewHolder(String text) { - return new BoundedMatcher<ViewHolder, PreferenceViewHolder>(PreferenceViewHolder.class) { + return new BoundedMatcher<>(PreferenceViewHolder.class) { @Override public void describeTo(Description description) { description.appendText("has text: " + text);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/AndroidPaymentAppFinderTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/AndroidPaymentAppFinderTest.java index 921ff31..45dc4ba 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/AndroidPaymentAppFinderTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/AndroidPaymentAppFinderTest.java
@@ -186,7 +186,7 @@ // PaymentAppFactoryParams implementation. @Override public Map<String, PaymentDetailsModifier> getUnmodifiableModifiers() { - return Collections.unmodifiableMap(new HashMap<String, PaymentDetailsModifier>()); + return Collections.unmodifiableMap(new HashMap<>()); } // PaymentAppFactoryParams implementation.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/AndroidPaymentAppFinderUnitTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/AndroidPaymentAppFinderUnitTest.java index fe3353d..da37771a 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/AndroidPaymentAppFinderUnitTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/AndroidPaymentAppFinderUnitTest.java
@@ -56,7 +56,6 @@ import org.chromium.components.payments.intent.WebPaymentIntentHelper; import org.chromium.content_public.browser.WebContents; import org.chromium.content_public.browser.test.NativeLibraryTestUtils; -import org.chromium.payments.mojom.PaymentDetailsModifier; import org.chromium.payments.mojom.PaymentMethodData; import org.chromium.ui.base.ActivityWindowAndroid; import org.chromium.ui.base.IntentRequestTracker; @@ -172,8 +171,7 @@ Mockito.when(mParams.getTopLevelOrigin()).thenReturn("https://chromium.org"); Mockito.when(mParams.getPaymentRequestOrigin()).thenReturn("https://chromium.org"); Mockito.when(mParams.getCertificateChain()).thenReturn(null); - Mockito.when(mParams.getUnmodifiableModifiers()) - .thenReturn(new HashMap<String, PaymentDetailsModifier>()); + Mockito.when(mParams.getUnmodifiableModifiers()).thenReturn(new HashMap<>()); Mockito.when(mParams.getMayCrawl()).thenReturn(false); Mockito.when(mDelegate.getParams()).thenReturn(mParams); Mockito.when(mDelegate.getDialogController())
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/WebPaymentIntentHelperTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/WebPaymentIntentHelperTest.java index f5d3c407..20a8b0c 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/WebPaymentIntentHelperTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/WebPaymentIntentHelperTest.java
@@ -83,7 +83,7 @@ @SmallTest @Feature({"Payments"}) public void createPayIntentTest() throws Throwable { - Map<String, PaymentMethodData> methodDataMap = new HashMap<String, PaymentMethodData>(); + Map<String, PaymentMethodData> methodDataMap = new HashMap<>(); PaymentMethodData bobPayMethodData = new PaymentMethodData("bobPayMethod", "{\"key\":\"value\"}"); PaymentMethodData maxPayMethodData = new PaymentMethodData("maxPayMethod", "{}"); @@ -96,8 +96,7 @@ displayItems.add(new PaymentItem(new PaymentCurrencyAmount("CAD", "50"))); displayItems.add(new PaymentItem(new PaymentCurrencyAmount("CAD", "150"))); - Map<String, PaymentDetailsModifier> modifiers = - new HashMap<String, PaymentDetailsModifier>(); + Map<String, PaymentDetailsModifier> modifiers = new HashMap<>(); PaymentDetailsModifier bobPaymodifier = new PaymentDetailsModifier(total, bobPayMethodData); modifiers.put("bobPay", bobPaymodifier); @@ -221,7 +220,7 @@ @SmallTest @Feature({"Payments"}) public void createPayIntentDeprecatedExtraTest() throws Throwable { - Map<String, PaymentMethodData> methodDataMap = new HashMap<String, PaymentMethodData>(); + Map<String, PaymentMethodData> methodDataMap = new HashMap<>(); PaymentMethodData bobPayMethodData = new PaymentMethodData("method", "null"); methodDataMap.put("bobPay", bobPayMethodData); @@ -231,8 +230,7 @@ displayItems.add(new PaymentItem(new PaymentCurrencyAmount("CAD", "50"))); displayItems.add(new PaymentItem(new PaymentCurrencyAmount("CAD", "150"))); - Map<String, PaymentDetailsModifier> modifiers = - new HashMap<String, PaymentDetailsModifier>(); + Map<String, PaymentDetailsModifier> modifiers = new HashMap<>(); PaymentDetailsModifier modifier = new PaymentDetailsModifier(total, bobPayMethodData); modifiers.put("modifier_key", modifier); @@ -294,7 +292,7 @@ @SmallTest @Feature({"Payments"}) public void verifyRemoveDeprecatedFieldsFromPayIntent() throws Throwable { - Map<String, PaymentMethodData> methodDataMap = new HashMap<String, PaymentMethodData>(); + Map<String, PaymentMethodData> methodDataMap = new HashMap<>(); PaymentMethodData bobPayMethodData = new PaymentMethodData("method", "null"); methodDataMap.put("bobPay", bobPayMethodData); @@ -304,8 +302,7 @@ displayItems.add(new PaymentItem(new PaymentCurrencyAmount("CAD", "50"))); displayItems.add(new PaymentItem(new PaymentCurrencyAmount("CAD", "150"))); - Map<String, PaymentDetailsModifier> modifiers = - new HashMap<String, PaymentDetailsModifier>(); + Map<String, PaymentDetailsModifier> modifiers = new HashMap<>(); PaymentDetailsModifier modifier = new PaymentDetailsModifier(total, bobPayMethodData); modifiers.put("modifier_key", modifier); @@ -349,7 +346,7 @@ thrown.expect(IllegalArgumentException.class); thrown.expectMessage("paymentAppPackageName should not be null or empty."); - Map<String, PaymentMethodData> methodDataMap = new HashMap<String, PaymentMethodData>(); + Map<String, PaymentMethodData> methodDataMap = new HashMap<>(); PaymentMethodData bobPayMethodData = new PaymentMethodData("method", "null"); methodDataMap.put("bobPay", bobPayMethodData); @@ -379,7 +376,7 @@ thrown.expect(IllegalArgumentException.class); thrown.expectMessage("paymentAppActivityName should not be null or empty."); - Map<String, PaymentMethodData> methodDataMap = new HashMap<String, PaymentMethodData>(); + Map<String, PaymentMethodData> methodDataMap = new HashMap<>(); PaymentMethodData bobPayMethodData = new PaymentMethodData("method", "null"); methodDataMap.put("bobPay", bobPayMethodData); @@ -409,7 +406,7 @@ thrown.expect(IllegalArgumentException.class); thrown.expectMessage("id should not be null or empty."); - Map<String, PaymentMethodData> methodDataMap = new HashMap<String, PaymentMethodData>(); + Map<String, PaymentMethodData> methodDataMap = new HashMap<>(); PaymentMethodData bobPayMethodData = new PaymentMethodData("method", "null"); methodDataMap.put("bobPay", bobPayMethodData); @@ -439,7 +436,7 @@ thrown.expect(IllegalArgumentException.class); thrown.expectMessage("id should not be null or empty."); - Map<String, PaymentMethodData> methodDataMap = new HashMap<String, PaymentMethodData>(); + Map<String, PaymentMethodData> methodDataMap = new HashMap<>(); PaymentMethodData bobPayMethodData = new PaymentMethodData("method", "null"); methodDataMap.put("bobPay", bobPayMethodData); @@ -469,7 +466,7 @@ thrown.expect(IllegalArgumentException.class); thrown.expectMessage("merchantName should not be null."); - Map<String, PaymentMethodData> methodDataMap = new HashMap<String, PaymentMethodData>(); + Map<String, PaymentMethodData> methodDataMap = new HashMap<>(); PaymentMethodData bobPayMethodData = new PaymentMethodData("method", "null"); methodDataMap.put("bobPay", bobPayMethodData); @@ -496,7 +493,7 @@ @SmallTest @Feature({"Payments"}) public void emptyMerchantNameNoExceptionTest() throws Throwable { - Map<String, PaymentMethodData> methodDataMap = new HashMap<String, PaymentMethodData>(); + Map<String, PaymentMethodData> methodDataMap = new HashMap<>(); PaymentMethodData bobPayMethodData = new PaymentMethodData("method", "null"); methodDataMap.put("bobPay", bobPayMethodData); @@ -526,7 +523,7 @@ thrown.expect(IllegalArgumentException.class); thrown.expectMessage("schemelessOrigin should not be null or empty."); - Map<String, PaymentMethodData> methodDataMap = new HashMap<String, PaymentMethodData>(); + Map<String, PaymentMethodData> methodDataMap = new HashMap<>(); PaymentMethodData bobPayMethodData = new PaymentMethodData("method", "null"); methodDataMap.put("bobPay", bobPayMethodData); @@ -556,7 +553,7 @@ thrown.expect(IllegalArgumentException.class); thrown.expectMessage("schemelessOrigin should not be null or empty."); - Map<String, PaymentMethodData> methodDataMap = new HashMap<String, PaymentMethodData>(); + Map<String, PaymentMethodData> methodDataMap = new HashMap<>(); PaymentMethodData bobPayMethodData = new PaymentMethodData("method", "null"); methodDataMap.put("bobPay", bobPayMethodData); @@ -586,7 +583,7 @@ thrown.expect(IllegalArgumentException.class); thrown.expectMessage("schemelessIframeOrigin should not be null or empty."); - Map<String, PaymentMethodData> methodDataMap = new HashMap<String, PaymentMethodData>(); + Map<String, PaymentMethodData> methodDataMap = new HashMap<>(); PaymentMethodData bobPayMethodData = new PaymentMethodData("method", "null"); methodDataMap.put("bobPay", bobPayMethodData); @@ -616,7 +613,7 @@ thrown.expect(IllegalArgumentException.class); thrown.expectMessage("schemelessIframeOrigin should not be null or empty."); - Map<String, PaymentMethodData> methodDataMap = new HashMap<String, PaymentMethodData>(); + Map<String, PaymentMethodData> methodDataMap = new HashMap<>(); PaymentMethodData bobPayMethodData = new PaymentMethodData("method", "null"); methodDataMap.put("bobPay", bobPayMethodData); @@ -646,7 +643,7 @@ thrown.expect(IllegalArgumentException.class); thrown.expectMessage("certificateChain[0] should not be null."); - Map<String, PaymentMethodData> methodDataMap = new HashMap<String, PaymentMethodData>(); + Map<String, PaymentMethodData> methodDataMap = new HashMap<>(); PaymentMethodData bobPayMethodData = new PaymentMethodData("method", "null"); methodDataMap.put("bobPay", bobPayMethodData); @@ -679,7 +676,7 @@ thrown.expect(IllegalArgumentException.class); thrown.expectMessage("methodDataMap's entry value should not be null."); - Map<String, PaymentMethodData> methodDataMap = new HashMap<String, PaymentMethodData>(); + Map<String, PaymentMethodData> methodDataMap = new HashMap<>(); methodDataMap.put("bobPay", null); PaymentItem total = new PaymentItem(new PaymentCurrencyAmount("CAD", "200")); @@ -736,7 +733,7 @@ thrown.expect(IllegalArgumentException.class); thrown.expectMessage("methodDataMap should not be null or empty."); - Map<String, PaymentMethodData> methodDataMap = new HashMap<String, PaymentMethodData>(); + Map<String, PaymentMethodData> methodDataMap = new HashMap<>(); PaymentItem total = new PaymentItem(new PaymentCurrencyAmount("CAD", "200")); @@ -764,7 +761,7 @@ thrown.expect(IllegalArgumentException.class); thrown.expectMessage("total should not be null."); - Map<String, PaymentMethodData> methodDataMap = new HashMap<String, PaymentMethodData>(); + Map<String, PaymentMethodData> methodDataMap = new HashMap<>(); PaymentMethodData bobPayMethodData = new PaymentMethodData("method", "null"); methodDataMap.put("bobPay", bobPayMethodData); @@ -793,14 +790,13 @@ thrown.expect(IllegalArgumentException.class); thrown.expectMessage("PaymentDetailsModifier should not be null."); - Map<String, PaymentMethodData> methodDataMap = new HashMap<String, PaymentMethodData>(); + Map<String, PaymentMethodData> methodDataMap = new HashMap<>(); PaymentMethodData bobPayMethodData = new PaymentMethodData("method", "null"); methodDataMap.put("bobPay", bobPayMethodData); PaymentItem total = new PaymentItem(new PaymentCurrencyAmount("CAD", "200")); - Map<String, PaymentDetailsModifier> modifiers = - new HashMap<String, PaymentDetailsModifier>(); + Map<String, PaymentDetailsModifier> modifiers = new HashMap<>(); modifiers.put("bobPay", null); WebPaymentIntentHelper.createPayIntent( @@ -1146,7 +1142,7 @@ @SmallTest @Feature({"Payments"}) public void createIsReadyToPayIntentWithIdentity() throws Throwable { - Map<String, PaymentMethodData> methodDataMap = new HashMap<String, PaymentMethodData>(); + Map<String, PaymentMethodData> methodDataMap = new HashMap<>(); PaymentMethodData bobPayMethodData = new PaymentMethodData("bobPayMethod", "{\"key\":\"value\"}"); PaymentMethodData maxPayMethodData = new PaymentMethodData("maxPayMethod", "{}"); @@ -1202,7 +1198,7 @@ @SmallTest @Feature({"Payments"}) public void verifyDeprecatedFieldsInIsReadyToPayIntent() throws Throwable { - Map<String, PaymentMethodData> methodDataMap = new HashMap<String, PaymentMethodData>(); + Map<String, PaymentMethodData> methodDataMap = new HashMap<>(); PaymentMethodData bobPayMethodData = new PaymentMethodData("bobPayMethod", "{\"key\":\"value\"}"); PaymentMethodData maxPayMethodData = new PaymentMethodData("maxPayMethod", "{}"); @@ -1244,7 +1240,7 @@ @SmallTest @Feature({"Payments"}) public void verifyRemoveDeprecatedFieldsFromIsReadyToPayIntent() throws Throwable { - Map<String, PaymentMethodData> methodDataMap = new HashMap<String, PaymentMethodData>(); + Map<String, PaymentMethodData> methodDataMap = new HashMap<>(); PaymentMethodData bobPayMethodData = new PaymentMethodData("bobPayMethod", "{\"key\":\"value\"}"); PaymentMethodData maxPayMethodData = new PaymentMethodData("maxPayMethod", "{}"); @@ -1280,7 +1276,7 @@ @SmallTest @Feature({"Payments"}) public void createIsReadyToPayIntentWithoutIdentity() throws Throwable { - Map<String, PaymentMethodData> methodDataMap = new HashMap<String, PaymentMethodData>(); + Map<String, PaymentMethodData> methodDataMap = new HashMap<>(); PaymentMethodData bobPayMethodData = new PaymentMethodData("bobPayMethod", "{\"key\":\"value\"}"); PaymentMethodData maxPayMethodData = new PaymentMethodData("maxPayMethod", "{}"); @@ -1325,7 +1321,7 @@ thrown.expect(IllegalArgumentException.class); thrown.expectMessage("callerPackageName should not be null or empty."); - Map<String, PaymentMethodData> methodDataMap = new HashMap<String, PaymentMethodData>(); + Map<String, PaymentMethodData> methodDataMap = new HashMap<>(); PaymentMethodData bobPayMethodData = new PaymentMethodData("method", "null"); methodDataMap.put("bobPay", bobPayMethodData); @@ -1349,7 +1345,7 @@ thrown.expect(IllegalArgumentException.class); thrown.expectMessage("paymentAppPackageName should not be null or empty."); - Map<String, PaymentMethodData> methodDataMap = new HashMap<String, PaymentMethodData>(); + Map<String, PaymentMethodData> methodDataMap = new HashMap<>(); PaymentMethodData bobPayMethodData = new PaymentMethodData("method", "null"); methodDataMap.put("bobPay", bobPayMethodData); @@ -1373,7 +1369,7 @@ thrown.expect(IllegalArgumentException.class); thrown.expectMessage("paymentAppPackageName should not be null or empty."); - Map<String, PaymentMethodData> methodDataMap = new HashMap<String, PaymentMethodData>(); + Map<String, PaymentMethodData> methodDataMap = new HashMap<>(); PaymentMethodData bobPayMethodData = new PaymentMethodData("method", "null"); methodDataMap.put("bobPay", bobPayMethodData);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/searchwidget/SearchWidgetProviderTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/searchwidget/SearchWidgetProviderTest.java index ceca0ba..7899883a 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/searchwidget/SearchWidgetProviderTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/searchwidget/SearchWidgetProviderTest.java
@@ -71,7 +71,7 @@ @Override protected void updateAppWidget(int id, RemoteViews views) { - mViews.add(new Pair<Integer, RemoteViews>(id, views)); + mViews.add(new Pair<>(id, views)); } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/tab_restore/HistoricalTabSaverImplTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/tab_restore/HistoricalTabSaverImplTest.java index edd4911..27c04c7 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/tab_restore/HistoricalTabSaverImplTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/tab_restore/HistoricalTabSaverImplTest.java
@@ -146,7 +146,7 @@ TabRestoreServiceUtils.createTabEntry(mTabModel, frozenTab); - List<List<HistoricalEntry>> empty = new ArrayList<List<HistoricalEntry>>(); + List<List<HistoricalEntry>> empty = new ArrayList<>(); assertEntriesAre(empty); } @@ -233,7 +233,7 @@ Arrays.asList(new Tab[] {frozenTab0, frozenTab1})); TabRestoreServiceUtils.createTabOrGroupEntry(mTabModel, group); - List<List<HistoricalEntry>> empty = new ArrayList<List<HistoricalEntry>>(); + List<List<HistoricalEntry>> empty = new ArrayList<>(); assertEntriesAre(empty); } @@ -345,7 +345,7 @@ expectedEntries.add(new HistoricalEntry(frozenTab1)); TabRestoreServiceUtils.createWindowEntry(mTabModel, expectedEntries); - List<List<HistoricalEntry>> empty = new ArrayList<List<HistoricalEntry>>(); + List<List<HistoricalEntry>> empty = new ArrayList<>(); assertEntriesAre(empty); } @@ -395,7 +395,7 @@ @Test @MediumTest public void testCreateHistoricalTab_InvalidUrls() { - List<List<HistoricalEntry>> empty = new ArrayList<List<HistoricalEntry>>(); + List<List<HistoricalEntry>> empty = new ArrayList<>(); final Tab tab0 = mActivityTestRule.loadUrlInNewTab("about:blank", /* incognito= */ false); TabRestoreServiceUtils.createTabEntry(mTabModel, tab0); assertEntriesAre(empty); @@ -454,7 +454,7 @@ .getTabGroupModelFilter(false), Arrays.asList(newTab)); }); - List<List<HistoricalEntry>> empty = new ArrayList<List<HistoricalEntry>>(); + List<List<HistoricalEntry>> empty = new ArrayList<>(); assertEntriesAre(empty); runOnUiThreadBlocking(
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabModelImplTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabModelImplTest.java index 27b3194f..ca7082fc 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabModelImplTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabModelImplTest.java
@@ -32,6 +32,7 @@ import org.chromium.chrome.test.transit.AutoResetCtaTransitTestRule; import org.chromium.chrome.test.transit.ChromeTransitTestRules; import org.chromium.chrome.test.transit.Journeys; +import org.chromium.chrome.test.transit.ntp.RegularNewTabPageStation; import org.chromium.chrome.test.transit.page.WebPageStation; import org.chromium.url.GURL; @@ -186,8 +187,8 @@ public void testOpenTabProgrammatically() { ThreadUtils.runOnUiThreadBlocking( () -> { - TabModelImpl tabModel = - (TabModelImpl) + TabModelJniBridge tabModel = + (TabModelJniBridge) mActivityTestRule .getActivity() .getTabModelSelector() @@ -203,4 +204,25 @@ assertEquals(url, tab.getUrl()); }); } + + @Test + @SmallTest + public void testGetAllTabs() { + RegularNewTabPageStation secondTab = mPage.openNewTabFast(); + secondTab.openNewTabFast(); + + ThreadUtils.runOnUiThreadBlocking( + () -> { + TabModelJniBridge tabModel = + (TabModelJniBridge) + mActivityTestRule + .getActivity() + .getTabModelSelector() + .getModel(false); + + assertEquals(3, tabModel.getCount()); + Tab[] tabs = tabModel.getAllTabs(); + assertEquals(3, tabs.length); + }); + } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabPersistentStoreTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabPersistentStoreTest.java index b5e27ca..8763e95 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabPersistentStoreTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabPersistentStoreTest.java
@@ -113,10 +113,7 @@ @RunWith(ChromeJUnit4ClassRunner.class) @CommandLineFlags.Add(ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE) @DisableFeatures({ChromeFeatureList.ANDROID_TAB_DECLUTTER_RESCUE_KILLSWITCH}) -@EnableFeatures({ - ChromeFeatureList.TAB_GROUP_SYNC_ANDROID, - ChromeFeatureList.ANDROID_TAB_SKIP_SAVE_TABS_TASK_KILLSWITCH -}) +@EnableFeatures({ChromeFeatureList.ANDROID_TAB_SKIP_SAVE_TABS_TASK_KILLSWITCH}) public class TabPersistentStoreTest { // Test activity type that does not restore tab on cold restart. // Any type other than ActivityType.TABBED works.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/undo_tab_close_snackbar/UndoBarControllerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/undo_tab_close_snackbar/UndoBarControllerTest.java index 67c2043..6c6375e3 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/undo_tab_close_snackbar/UndoBarControllerTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/undo_tab_close_snackbar/UndoBarControllerTest.java
@@ -23,7 +23,6 @@ import org.chromium.base.test.util.Batch; import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Features.DisableFeatures; -import org.chromium.base.test.util.Features.EnableFeatures; import org.chromium.base.test.util.Restriction; import org.chromium.chrome.browser.ChromeTabbedActivity; import org.chromium.chrome.browser.flags.ChromeFeatureList; @@ -171,45 +170,6 @@ @Test @SmallTest - @DisableFeatures({ChromeFeatureList.TAB_GROUP_SYNC_ANDROID}) - public void testCloseTabGroup_Undo_SyncDisabled() throws Exception { - ChromeTabUtils.newTabFromMenu( - InstrumentationRegistry.getInstrumentation(), sActivityTestRule.getActivity()); - ThreadUtils.runOnUiThreadBlocking( - () -> { - mTabGroupModelFilter.mergeListOfTabsToGroup( - List.of(mTabModel.getTabAt(0), mTabModel.getTabAt(1)), - mTabModel.getTabAt(0), - /* notify= */ false); - }); - - assertNull(getCurrentSnackbar()); - assertEquals(2, mTabModel.getCount()); - assertEquals(1, mTabGroupModelFilter.getTabGroupCount()); - - ThreadUtils.runOnUiThreadBlocking( - () -> { - closeTabs( - TabClosureParams.closeTabs( - List.of(mTabModel.getTabAt(0), mTabModel.getTabAt(1))) - .build()); - }); - - Snackbar currentSnackbar = getCurrentSnackbar(); - assertSnackbarTextEqualsAllowingTruncation("2 tabs tab group closed"); - assertTrue(currentSnackbar.getController() instanceof UndoBarController); - assertEquals(0, mTabModel.getCount()); - - clickSnackbar(); - - assertNull(getCurrentSnackbar()); - assertEquals(2, mTabModel.getCount()); - assertEquals(1, mTabGroupModelFilter.getTabGroupCount()); - } - - @Test - @SmallTest - @EnableFeatures({ChromeFeatureList.TAB_GROUP_SYNC_ANDROID}) public void testCloseTabGroup_Undo() throws Exception { ChromeTabUtils.newTabFromMenu( InstrumentationRegistry.getInstrumentation(), sActivityTestRule.getActivity()); @@ -255,7 +215,6 @@ @Test @SmallTest - @EnableFeatures({ChromeFeatureList.TAB_GROUP_SYNC_ANDROID}) public void testCloseTabGroup_EmptyTitle_Undo() throws Exception { ChromeTabUtils.newTabFromMenu( InstrumentationRegistry.getInstrumentation(), sActivityTestRule.getActivity()); @@ -301,7 +260,6 @@ @Test @SmallTest - @EnableFeatures({ChromeFeatureList.TAB_GROUP_SYNC_ANDROID}) public void testDeleteTabGroup_Undo() throws Exception { ChromeTabUtils.newTabFromMenu( InstrumentationRegistry.getInstrumentation(), sActivityTestRule.getActivity()); @@ -339,7 +297,6 @@ @Test @SmallTest - @EnableFeatures({ChromeFeatureList.TAB_GROUP_SYNC_ANDROID}) public void testDeleteTabGroup_WithOtherTab_Undo() throws Exception { ChromeTabUtils.newTabFromMenu( InstrumentationRegistry.getInstrumentation(), sActivityTestRule.getActivity()); @@ -379,7 +336,6 @@ @Test @SmallTest - @EnableFeatures({ChromeFeatureList.TAB_GROUP_SYNC_ANDROID}) public void testCloseTabGroup_WithOtherTabs_Undo() throws Exception { ChromeTabUtils.newTabFromMenu( InstrumentationRegistry.getInstrumentation(), sActivityTestRule.getActivity()); @@ -421,7 +377,6 @@ @Test @SmallTest - @EnableFeatures({ChromeFeatureList.TAB_GROUP_SYNC_ANDROID}) public void testPartialDeleteTabGroup_Undo() throws Exception { ChromeTabUtils.newTabFromMenu( InstrumentationRegistry.getInstrumentation(), sActivityTestRule.getActivity()); @@ -464,7 +419,6 @@ @Test @SmallTest - @EnableFeatures({ChromeFeatureList.TAB_GROUP_SYNC_ANDROID}) public void testDeleteTabGroups_Undo() throws Exception { ChromeTabUtils.newTabFromMenu( InstrumentationRegistry.getInstrumentation(), sActivityTestRule.getActivity()); @@ -500,7 +454,6 @@ @Test @SmallTest - @EnableFeatures({ChromeFeatureList.TAB_GROUP_SYNC_ANDROID}) public void testCloseTabGroups_Undo() throws Exception { ChromeTabUtils.newTabFromMenu( InstrumentationRegistry.getInstrumentation(), sActivityTestRule.getActivity());
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerTest.java index b4d524d0..04d51f8 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerTest.java
@@ -286,7 +286,7 @@ creationData.name = WEBAPK_NAME; creationData.shortName = WEBAPK_SHORT_NAME; - creationData.iconUrlToMurmur2HashMap = new HashMap<String, String>(); + creationData.iconUrlToMurmur2HashMap = new HashMap<>(); creationData.iconUrlToMurmur2HashMap.put( mTestServer.getURL(WEBAPK_ICON_URL), WEBAPK_ICON_MURMUR2_HASH); @@ -448,7 +448,7 @@ CreationData creationData = defaultCreationData(); creationData.manifestUrl = mTestServer.getURL(WEBAPK_MANIFEST_WITH_MASKABLE_ICON_URL); - creationData.iconUrlToMurmur2HashMap = new HashMap<String, String>(); + creationData.iconUrlToMurmur2HashMap = new HashMap<>(); creationData.iconUrlToMurmur2HashMap.put( mTestServer.getURL("/chrome/test/data/banners/launcher-icon-4x.png"), "8692598279279335241");
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperTest.java index f665c35..8909ac3 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperTest.java
@@ -5050,7 +5050,7 @@ } @Test - @EnableFeatures({ChromeFeatureList.TAB_GROUP_SYNC_ANDROID, ChromeFeatureList.DATA_SHARING}) + @EnableFeatures({ChromeFeatureList.DATA_SHARING}) public void testTabGroupSyncIph_GroupTitleBubbleIph_ShowSequentially() { // Setup tab strip and group the first tab group. setupTabGroup(1, 2); @@ -5101,7 +5101,7 @@ } @Test - @EnableFeatures({ChromeFeatureList.TAB_GROUP_SYNC_ANDROID, ChromeFeatureList.DATA_SHARING}) + @EnableFeatures({ChromeFeatureList.DATA_SHARING}) public void testTabGroupSyncIph_TabBubbleIph_ShowSequentially() { // Setup tab strip and group the first tab group. setupTabGroup(0, 2); @@ -5153,7 +5153,7 @@ } @Test - @EnableFeatures({ChromeFeatureList.TAB_GROUP_SYNC_ANDROID, ChromeFeatureList.DATA_SHARING}) + @EnableFeatures({ChromeFeatureList.DATA_SHARING}) public void testTabGroupSyncIph_NotShowForCollaboration() { // Setup tab strip and group the first tab group. setupTabGroup(3, 5); @@ -5180,7 +5180,6 @@ } @Test - @EnableFeatures({ChromeFeatureList.TAB_GROUP_SYNC_ANDROID}) public void testTabGroupSyncIph_DismissOnOrientationChanged() { // Setup tab group and Tab Group Sync iph. setupTabGroup(4, 5);
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/TabStripIphControllerUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/TabStripIphControllerUnitTest.java index 309f35d3..6fb4ce5 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/TabStripIphControllerUnitTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/TabStripIphControllerUnitTest.java
@@ -30,13 +30,11 @@ import org.chromium.base.Token; import org.chromium.base.test.BaseRobolectricTestRunner; -import org.chromium.base.test.util.Features.EnableFeatures; import org.chromium.chrome.R; import org.chromium.chrome.browser.compositor.layouts.LayoutUpdateHost; import org.chromium.chrome.browser.compositor.overlays.strip.TabLoadTracker.TabLoadTrackerCallback; import org.chromium.chrome.browser.compositor.overlays.strip.TabStripIphController.IphType; import org.chromium.chrome.browser.feature_engagement.TrackerFactory; -import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.user_education.IphCommand; import org.chromium.chrome.browser.user_education.UserEducationHelper; import org.chromium.components.feature_engagement.FeatureConstants; @@ -46,7 +44,6 @@ /** Unit tests for {@link TabStripIphController}. */ @RunWith(BaseRobolectricTestRunner.class) @Config(manifest = Config.NONE) -@EnableFeatures({ChromeFeatureList.TAB_GROUP_SYNC_ANDROID}) public class TabStripIphControllerUnitTest { private static final float TAB_STRIP_HEIGHT = 40f; private static final float TAB_WIDTH = 150f;
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/feedback/FeedFeedbackCollectorTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/feedback/FeedFeedbackCollectorTest.java index aa6d1532..6fe7cf4 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/feedback/FeedFeedbackCollectorTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/feedback/FeedFeedbackCollectorTest.java
@@ -128,7 +128,7 @@ public void testFeedSynchronousData() { @SuppressWarnings("unchecked") Callback<FeedbackCollector> callback = mock(Callback.class); - Map<String, String> feedContext = new HashMap<String, String>(); + Map<String, String> feedContext = new HashMap<>(); feedContext.put(CARD_URL, THE_URL); feedContext.put(CARD_PUBLISHER, THE_PUBLISHER); feedContext.put(CARD_PUBLISHING_DATE, THE_PUBLISHING_DATE);
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeUnitTest.java index b29c661..b856bd6 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeUnitTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeUnitTest.java
@@ -264,7 +264,7 @@ private Callback<List<OfflinePageItem>> createMultipleItemCallback(final int itemCount) { return spy( - new Callback<List<OfflinePageItem>>() { + new Callback<>() { @Override public void onResult(List<OfflinePageItem> items) { assertNotNull(items);
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebApkSyncServiceTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebApkSyncServiceTest.java index 2fe65fba..650b137 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebApkSyncServiceTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebApkSyncServiceTest.java
@@ -191,7 +191,7 @@ @Test public void testGetIconsFallback() throws Exception { WebappIcon testIcon = new WebappIcon(); - Map<String, String> iconUrlAndIconMurmur2HashMap = new HashMap<String, String>(); + Map<String, String> iconUrlAndIconMurmur2HashMap = new HashMap<>(); iconUrlAndIconMurmur2HashMap.put(ICON_URL, ICON_MURMUR2_HASH); iconUrlAndIconMurmur2HashMap.put(ICON_URL2, ICON_MURMUR2_HASH); BrowserServicesIntentDataProvider intentDataProvider =
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebappRegistryTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebappRegistryTest.java index 80a646d0..6a3b2a4 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebappRegistryTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebappRegistryTest.java
@@ -864,7 +864,7 @@ WebappRegistry webApkRegistry = WebappRegistry.getInstance(); Map<String, BrowserServicesIntentDataProvider> expectedIntentDataProviders = - new HashMap<String, BrowserServicesIntentDataProvider>(); + new HashMap<>(); BrowserServicesIntentDataProvider intentDataProvider1 = new WebApkIntentDataProviderBuilder(testPackageName1, testStartUrl1)
diff --git a/chrome/android/profiles/arm.newest.txt b/chrome/android/profiles/arm.newest.txt index 402b747fb..54eda6a 100644 --- a/chrome/android/profiles/arm.newest.txt +++ b/chrome/android/profiles/arm.newest.txt
@@ -1 +1 @@ -chromeos-chrome-arm-139.0.7221.0_rc-r2-merged.afdo.bz2 +chromeos-chrome-arm-139.0.7230.0_rc-r1-merged.afdo.bz2
diff --git a/chrome/app/chromium_strings.grd b/chrome/app/chromium_strings.grd index 5deb4e6..5ea6e65 100644 --- a/chrome/app/chromium_strings.grd +++ b/chrome/app/chromium_strings.grd
@@ -2224,8 +2224,11 @@ </message> <!-- Advanced security settings --> - <message name="IDS_SETTINGS_SECURITY_V8_LINK_DESCRIPTION" desc="Description for the link row of the V8 security settings page."> - Turn on additional protection in Chromium’s JavaScript and WebAssembly engine + <message name="IDS_SETTINGS_SECURITY_JAVASCRIPT_OPTIMIZATION_LINK_ROW_ENABLED" desc="Description for the link row of the Javascript-optimization page when javascript-optimization is enabled."> + Speeds up sites with Chromium's V8 engine but makes Chromium slightly less resistant to attacks. This setting is on. + </message> + <message name="IDS_SETTINGS_SECURITY_JAVASCRIPT_OPTIMIZATION_LINK_ROW_DISABLED" desc="Description for the link row of the Javascript-optimization page when javascript-optimization is disabled."> + Speeds up sites with Chromium's V8 engine but makes Chromium slightly less resistant to attacks. This setting is off. </message> <message name="IDS_SETTINGS_SITE_SETTINGS_JAVASCRIPT_OPTIMIZER_DESCRIPTION" desc="Description of the JavaScript optimizer content setting."> V8 is Chromium’s JavaScript and WebAssembly engine used to improve site performance
diff --git a/chrome/app/chromium_strings_grd/IDS_SETTINGS_SECURITY_JAVASCRIPT_OPTIMIZATION_LINK_ROW_DISABLED.png.sha1 b/chrome/app/chromium_strings_grd/IDS_SETTINGS_SECURITY_JAVASCRIPT_OPTIMIZATION_LINK_ROW_DISABLED.png.sha1 new file mode 100644 index 0000000..9e6c4b5 --- /dev/null +++ b/chrome/app/chromium_strings_grd/IDS_SETTINGS_SECURITY_JAVASCRIPT_OPTIMIZATION_LINK_ROW_DISABLED.png.sha1
@@ -0,0 +1 @@ +3fd149a536f927a536185523a67d27099ae80469 \ No newline at end of file
diff --git a/chrome/app/chromium_strings_grd/IDS_SETTINGS_SECURITY_JAVASCRIPT_OPTIMIZATION_LINK_ROW_ENABLED.png.sha1 b/chrome/app/chromium_strings_grd/IDS_SETTINGS_SECURITY_JAVASCRIPT_OPTIMIZATION_LINK_ROW_ENABLED.png.sha1 new file mode 100644 index 0000000..8f223e4 --- /dev/null +++ b/chrome/app/chromium_strings_grd/IDS_SETTINGS_SECURITY_JAVASCRIPT_OPTIMIZATION_LINK_ROW_ENABLED.png.sha1
@@ -0,0 +1 @@ +95de8baedb793bb82c4f881ee59af4c0b3ef94e8 \ No newline at end of file
diff --git a/chrome/app/chromium_strings_grd/IDS_SETTINGS_SECURITY_V8_LINK_DESCRIPTION.png.sha1 b/chrome/app/chromium_strings_grd/IDS_SETTINGS_SECURITY_V8_LINK_DESCRIPTION.png.sha1 deleted file mode 100644 index 19f4f85..0000000 --- a/chrome/app/chromium_strings_grd/IDS_SETTINGS_SECURITY_V8_LINK_DESCRIPTION.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -e916f7d6b1fbfb986490bcb90acbac731fbf054e \ No newline at end of file
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 8a5df31b..5306761 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd
@@ -8472,6 +8472,10 @@ Reset to default </message> </if> + <!-- TODO(crbug.com/423679752): Make the following string translatable. --> + <message name="IDS_NTP_COMPOSE_ENTRYPOINT" desc="The text for the compose entrypoint in the searchbox on the New Tab Page." translateable="false"> + AI Mode + </message> <!-- NTP Modules --> <message name="IDS_NTP_MODULES_INFO_BUTTON_TITLE" desc="Text shown in tooltip of info button of an NTP module.">
diff --git a/chrome/app/google_chrome_strings.grd b/chrome/app/google_chrome_strings.grd index 321adf5..feda1798 100644 --- a/chrome/app/google_chrome_strings.grd +++ b/chrome/app/google_chrome_strings.grd
@@ -2244,8 +2244,11 @@ </message> <!-- Advanced security settings --> - <message name="IDS_SETTINGS_SECURITY_V8_LINK_DESCRIPTION" desc="Description for the link row of the V8 security settings page."> - Turn on additional protection in Chrome’s JavaScript and WebAssembly engine + <message name="IDS_SETTINGS_SECURITY_JAVASCRIPT_OPTIMIZATION_LINK_ROW_ENABLED" desc="Description for the link row of the Javascript-optimization page when javascript-optimization is enabled."> + Speeds up sites with Chrome's V8 engine but makes Chrome slightly less resistant to attacks. This setting is on. + </message> + <message name="IDS_SETTINGS_SECURITY_JAVASCRIPT_OPTIMIZATION_LINK_ROW_DISABLED" desc="Description for the link row of the Javascript-optimization page when javascript-optimization is disabled."> + Speeds up sites with Chrome's V8 engine but makes Chrome slightly less resistant to attacks. This setting is off. </message> <message name="IDS_SETTINGS_SITE_SETTINGS_JAVASCRIPT_OPTIMIZER_DESCRIPTION" desc="Description of the JavaScript optimizer content setting."> V8 is Chrome’s JavaScript and WebAssembly engine used to improve site performance
diff --git a/chrome/app/google_chrome_strings_grd/IDS_SETTINGS_SECURITY_JAVASCRIPT_OPTIMIZATION_LINK_ROW_DISABLED.png.sha1 b/chrome/app/google_chrome_strings_grd/IDS_SETTINGS_SECURITY_JAVASCRIPT_OPTIMIZATION_LINK_ROW_DISABLED.png.sha1 new file mode 100644 index 0000000..a78b4060 --- /dev/null +++ b/chrome/app/google_chrome_strings_grd/IDS_SETTINGS_SECURITY_JAVASCRIPT_OPTIMIZATION_LINK_ROW_DISABLED.png.sha1
@@ -0,0 +1 @@ +a86bdeb20e900b6944e38251b39d153f4e47062c \ No newline at end of file
diff --git a/chrome/app/google_chrome_strings_grd/IDS_SETTINGS_SECURITY_JAVASCRIPT_OPTIMIZATION_LINK_ROW_ENABLED.png.sha1 b/chrome/app/google_chrome_strings_grd/IDS_SETTINGS_SECURITY_JAVASCRIPT_OPTIMIZATION_LINK_ROW_ENABLED.png.sha1 new file mode 100644 index 0000000..06ad510 --- /dev/null +++ b/chrome/app/google_chrome_strings_grd/IDS_SETTINGS_SECURITY_JAVASCRIPT_OPTIMIZATION_LINK_ROW_ENABLED.png.sha1
@@ -0,0 +1 @@ +f2ebaf2a132dddfa7ca1bdfa7425adb627db19d0 \ No newline at end of file
diff --git a/chrome/app/google_chrome_strings_grd/IDS_SETTINGS_SECURITY_V8_LINK_DESCRIPTION.png.sha1 b/chrome/app/google_chrome_strings_grd/IDS_SETTINGS_SECURITY_V8_LINK_DESCRIPTION.png.sha1 deleted file mode 100644 index 19f4f85..0000000 --- a/chrome/app/google_chrome_strings_grd/IDS_SETTINGS_SECURITY_V8_LINK_DESCRIPTION.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -e916f7d6b1fbfb986490bcb90acbac731fbf054e \ No newline at end of file
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp index 4b18f04..4ff7abd8 100644 --- a/chrome/app/settings_strings.grdp +++ b/chrome/app/settings_strings.grdp
@@ -1958,8 +1958,8 @@ <message name="IDS_SETTINGS_SECURE_DNS_CUSTOM_CONNECTION_ERROR" desc="Error text for a custom secure DNS provider entry to which a probe connection fails"> Please verify that this is a valid provider or try again later </message> - <message name="IDS_SETTINGS_SECURITY_V8_LINK_TITLE" desc="Title for the link row to the V8 security settings."> - Manage V8 security + <message name="IDS_SETTINGS_SECURITY_JAVASCRIPT_OPTIMIZATION_LINK_TITLE" desc="Title for the link row to the V8 security settings."> + Manage JavaScript optimization & security </message> <message name="IDS_SETTINGS_CONTENT_SETTINGS" desc="Text of the button that takes a user to settings page thats allows users to modify site settings. Also the title of that settings page."> Content settings
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_SECURITY_JAVASCRIPT_OPTIMIZATION_LINK_TITLE.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_SECURITY_JAVASCRIPT_OPTIMIZATION_LINK_TITLE.png.sha1 new file mode 100644 index 0000000..a78b4060 --- /dev/null +++ b/chrome/app/settings_strings_grdp/IDS_SETTINGS_SECURITY_JAVASCRIPT_OPTIMIZATION_LINK_TITLE.png.sha1
@@ -0,0 +1 @@ +a86bdeb20e900b6944e38251b39d153f4e47062c \ No newline at end of file
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_SECURITY_V8_LINK_TITLE.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_SECURITY_V8_LINK_TITLE.png.sha1 deleted file mode 100644 index 19f4f85..0000000 --- a/chrome/app/settings_strings_grdp/IDS_SETTINGS_SECURITY_V8_LINK_TITLE.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -e916f7d6b1fbfb986490bcb90acbac731fbf054e \ No newline at end of file
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index c1f3f3df..a6f9290b 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -4174,6 +4174,8 @@ "resources_integrity.h", "safe_browsing/generated_safe_browsing_pref.cc", "safe_browsing/generated_safe_browsing_pref.h", + "safe_browsing/generated_security_settings_bundle_pref.cc", + "safe_browsing/generated_security_settings_bundle_pref.h", "send_tab_to_self/desktop_notification_handler.cc", "send_tab_to_self/desktop_notification_handler.h", "serial/web_serial_chooser_desktop.cc",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 75e470a..3e1a447d 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -11113,10 +11113,6 @@ flag_descriptions::kAndroidTabGroupsColorUpdateGM3Description, kOsAndroid, FEATURE_VALUE_TYPE(chrome::android::kAndroidTabGroupsColorUpdateGM3)}, - {"tab-group-sync-android", flag_descriptions::kTabGroupSyncAndroidName, - flag_descriptions::kTabGroupSyncAndroidDescription, kOsAndroid, - FEATURE_VALUE_TYPE(tab_groups::kTabGroupSyncAndroid)}, - {"tab-group-sync-disable-network-layer", flag_descriptions::kTabGroupSyncDisableNetworkLayerName, flag_descriptions::kTabGroupSyncDisableNetworkLayerDescription, kOsAndroid,
diff --git a/chrome/browser/android/browserservices/intents/java/src/org/chromium/chrome/browser/browserservices/intents/WebApkExtras.java b/chrome/browser/android/browserservices/intents/java/src/org/chromium/chrome/browser/browserservices/intents/WebApkExtras.java index 9588305..74c9d2ce 100644 --- a/chrome/browser/android/browserservices/intents/java/src/org/chromium/chrome/browser/browserservices/intents/WebApkExtras.java +++ b/chrome/browser/android/browserservices/intents/java/src/org/chromium/chrome/browser/browserservices/intents/WebApkExtras.java
@@ -115,7 +115,7 @@ /* manifestId= */ null, /* appKey= */ null, WebApkDistributor.OTHER, - new HashMap<String, String>() + new HashMap<>() /* iconUrlToMurmur2HashMap= */ , /* shareTarget= */ null, /* isSplashProvidedByWebApk= */ false,
diff --git a/chrome/browser/android/browserservices/intents/java/src/org/chromium/chrome/browser/browserservices/intents/WebappIntentUtilsTest.java b/chrome/browser/android/browserservices/intents/java/src/org/chromium/chrome/browser/browserservices/intents/WebappIntentUtilsTest.java index dc04fd8..dd230aa 100644 --- a/chrome/browser/android/browserservices/intents/java/src/org/chromium/chrome/browser/browserservices/intents/WebappIntentUtilsTest.java +++ b/chrome/browser/android/browserservices/intents/java/src/org/chromium/chrome/browser/browserservices/intents/WebappIntentUtilsTest.java
@@ -79,7 +79,7 @@ @Test public void testCopyStream() { { - ArrayList fromList = new ArrayList<Uri>(); + ArrayList fromList = new ArrayList<>(); fromList.add(Uri.parse("https://www.google.com/")); fromList.add(Uri.parse("https://www.blogspot.com/")); Intent fromIntent = new Intent();
diff --git a/chrome/browser/android/cookies/java/src/org/chromium/chrome/browser/cookies/CookiesFetcher.java b/chrome/browser/android/cookies/java/src/org/chromium/chrome/browser/cookies/CookiesFetcher.java index 61461a1..e5b1c2177 100644 --- a/chrome/browser/android/cookies/java/src/org/chromium/chrome/browser/cookies/CookiesFetcher.java +++ b/chrome/browser/android/cookies/java/src/org/chromium/chrome/browser/cookies/CookiesFetcher.java
@@ -173,7 +173,7 @@ @Override protected List<CanonicalCookie> doInBackground() { // Read cookies from disk on a background thread to avoid strict mode violations. - List<CanonicalCookie> cookies = new ArrayList<CanonicalCookie>(); + List<CanonicalCookie> cookies = new ArrayList<>(); DataInputStream in = null; try { Cipher cipher = mCipherFactory.getCipher(Cipher.DECRYPT_MODE);
diff --git a/chrome/browser/android/cookies/java/src/org/chromium/chrome/browser/cookies/CookiesFetcherTest.java b/chrome/browser/android/cookies/java/src/org/chromium/chrome/browser/cookies/CookiesFetcherTest.java index 424b9bb..bc58259 100644 --- a/chrome/browser/android/cookies/java/src/org/chromium/chrome/browser/cookies/CookiesFetcherTest.java +++ b/chrome/browser/android/cookies/java/src/org/chromium/chrome/browser/cookies/CookiesFetcherTest.java
@@ -69,7 +69,7 @@ mImportantFileWriterJni.writeFileAtomically( Mockito.anyString(), Mockito.any(byte[].class))) .thenAnswer( - new Answer<Boolean>() { + new Answer<>() { @Override public Boolean answer(InvocationOnMock invocation) { try (FileOutputStream stream =
diff --git a/chrome/browser/android/customtabs/branding/java/src/org/chromium/chrome/browser/customtabs/features/branding/MismatchNotificationData.java b/chrome/browser/android/customtabs/branding/java/src/org/chromium/chrome/browser/customtabs/features/branding/MismatchNotificationData.java index cbcfad1..f54d729 100644 --- a/chrome/browser/android/customtabs/branding/java/src/org/chromium/chrome/browser/customtabs/features/branding/MismatchNotificationData.java +++ b/chrome/browser/android/customtabs/branding/java/src/org/chromium/chrome/browser/customtabs/features/branding/MismatchNotificationData.java
@@ -79,7 +79,7 @@ accountData.put(appId, data); } else { // Create a new inner app -> data map if it doesn't exist. - accountData = new HashMap<String, AppUiData>(); + accountData = new HashMap<>(); accountData.put(appId, data); mDataMap.put(accountId, accountData); }
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/java/org/chromium/customtabsclient/MainActivity.java b/chrome/browser/android/examples/custom_tabs_client/src/java/org/chromium/customtabsclient/MainActivity.java index cfc43cd..a46038f 100644 --- a/chrome/browser/android/examples/custom_tabs_client/src/java/org/chromium/customtabsclient/MainActivity.java +++ b/chrome/browser/android/examples/custom_tabs_client/src/java/org/chromium/customtabsclient/MainActivity.java
@@ -517,7 +517,7 @@ } else { // TODO(crbug.com/40240792) Refactor the way ordering is stored so it's not mixed with // URLs - savedUrlSet = new HashSet<String>(); + savedUrlSet = new HashSet<>(); if (!TextUtils.isEmpty(url)) { savedUrlSet.add("1" + url); editor.putStringSet(SHARED_PREF_SITES, savedUrlSet); @@ -581,7 +581,7 @@ private void initializeColorSpinner() { Spinner colorSpinner = (Spinner) findViewById(R.id.color_spinner); - HashMap<String, String> colors = new HashMap<String, String>(); + HashMap<String, String> colors = new HashMap<>(); colors.put("Default", ""); colors.put("White (AGA Light)", "#ffffff"); colors.put("Orange", "#ef6c00"); @@ -602,7 +602,7 @@ } final ArrayAdapter<String> colorAdapter = - new ArrayAdapter<String>(this, 0, colorsArr) { + new ArrayAdapter<>(this, 0, colorsArr) { @Override public View getView( int position, @Nullable View convertView, ViewGroup parent) { @@ -804,7 +804,7 @@ } final ArrayAdapter<String> cctAdapter = - new ArrayAdapter<String>(this, 0, cctOptions) { + new ArrayAdapter<>(this, 0, cctOptions) { @Override public View getView( int position, @Nullable View convertView, ViewGroup parent) {
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/java/org/chromium/customtabsclient/SessionHelper.java b/chrome/browser/android/examples/custom_tabs_client/src/java/org/chromium/customtabsclient/SessionHelper.java index 97e10de..f9f82c83 100644 --- a/chrome/browser/android/examples/custom_tabs_client/src/java/org/chromium/customtabsclient/SessionHelper.java +++ b/chrome/browser/android/examples/custom_tabs_client/src/java/org/chromium/customtabsclient/SessionHelper.java
@@ -34,7 +34,7 @@ * @param session The current session. */ public static void setCurrentSession(@Nullable CustomTabsSession session) { - sCurrentSession = new WeakReference<CustomTabsSession>(session); + sCurrentSession = new WeakReference<>(session); } /** Returns the current {@link AuthTabSession} object. */ @@ -48,6 +48,6 @@ * @param session The current session. */ public static void setCurrentAuthSession(@Nullable AuthTabSession session) { - sCurrentAuthTabSession = new WeakReference<AuthTabSession>(session); + sCurrentAuthTabSession = new WeakReference<>(session); } }
diff --git a/chrome/browser/android/examples/partner_browser_customizations_provider/src/org/chromium/example/partnercustomizations/PartnerBookmarksProviderExample.java b/chrome/browser/android/examples/partner_browser_customizations_provider/src/org/chromium/example/partnercustomizations/PartnerBookmarksProviderExample.java index 318d856f..9ca4d3d 100644 --- a/chrome/browser/android/examples/partner_browser_customizations_provider/src/org/chromium/example/partnercustomizations/PartnerBookmarksProviderExample.java +++ b/chrome/browser/android/examples/partner_browser_customizations_provider/src/org/chromium/example/partnercustomizations/PartnerBookmarksProviderExample.java
@@ -64,8 +64,7 @@ private static final int URI_MATCH_BOOKMARKS_PARTNER_BOOKMARKS_FOLDER_ID = 1004; private static final UriMatcher URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH); - private static final Map<String, String> BOOKMARKS_PROJECTION_MAP = - new HashMap<String, String>(); + private static final Map<String, String> BOOKMARKS_PROJECTION_MAP = new HashMap<>(); // Default sort order for unsync'd bookmarks private static final String DEFAULT_BOOKMARKS_SORT_ORDER =
diff --git a/chrome/browser/apps/app_shim/app_shim_listener_browsertest.mm b/chrome/browser/apps/app_shim/app_shim_listener_browsertest.mm index ceb76ac9..c4b772d6 100644 --- a/chrome/browser/apps/app_shim/app_shim_listener_browsertest.mm +++ b/chrome/browser/apps/app_shim/app_shim_listener_browsertest.mm
@@ -15,6 +15,7 @@ #include "base/files/file_path.h" #include "base/files/file_util.h" #include "base/functional/bind.h" +#include "base/hash/md5.h" #include "base/path_service.h" #include "base/run_loop.h" #include "base/strings/strcat.h"
diff --git a/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/AutofillAddress.java b/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/AutofillAddress.java index 8d5dd14..7ed5284 100644 --- a/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/AutofillAddress.java +++ b/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/AutofillAddress.java
@@ -215,7 +215,7 @@ editTitleResId = R.string.payments_add_more_information; } - return new Pair<Integer, Integer>(editMessageResId, editTitleResId); + return new Pair<>(editMessageResId, editTitleResId); } /**
diff --git a/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/AutofillProfileBridge.java b/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/AutofillProfileBridge.java index ce99a9f..431707b 100644 --- a/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/AutofillProfileBridge.java +++ b/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/AutofillProfileBridge.java
@@ -47,7 +47,7 @@ collator.setStrength(Collator.PRIMARY); Collections.sort( countries, - new Comparator<DropdownKeyValue>() { + new Comparator<>() { @Override public int compare(DropdownKeyValue lhs, DropdownKeyValue rhs) { int result = collator.compare(lhs.getValue(), rhs.getValue()); @@ -73,7 +73,7 @@ collator.setStrength(Collator.PRIMARY); Collections.sort( adminAreas, - new Comparator<DropdownKeyValue>() { + new Comparator<>() { @Override public int compare(DropdownKeyValue lhs, DropdownKeyValue rhs) { // Sorted according to the admin area values, such as Quebec,
diff --git a/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/PersonalDataManager.java b/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/PersonalDataManager.java index 0ae39fa..6789f2e 100644 --- a/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/PersonalDataManager.java +++ b/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/PersonalDataManager.java
@@ -656,8 +656,7 @@ } private final PrefService mPrefService; - private final List<PersonalDataManagerObserver> mDataObservers = - new ArrayList<PersonalDataManagerObserver>(); + private final List<PersonalDataManagerObserver> mDataObservers = new ArrayList<>(); private long mPersonalDataManagerAndroid; @@ -737,7 +736,7 @@ private ArrayList<AutofillProfile> getProfilesWithLabels( String[] profileLabels, String[] profileGUIDs) { - ArrayList<AutofillProfile> profiles = new ArrayList<AutofillProfile>(profileGUIDs.length); + ArrayList<AutofillProfile> profiles = new ArrayList<>(profileGUIDs.length); for (int i = 0; i < profileGUIDs.length; i++) { AutofillProfile profile = new AutofillProfile( @@ -805,7 +804,7 @@ } private ArrayList<CreditCard> getCreditCards(String[] creditCardGUIDs) { - ArrayList<CreditCard> cards = new ArrayList<CreditCard>(creditCardGUIDs.length); + ArrayList<CreditCard> cards = new ArrayList<>(creditCardGUIDs.length); for (int i = 0; i < creditCardGUIDs.length; i++) { cards.add( PersonalDataManagerJni.get()
diff --git a/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/editors/AddressEditorMediator.java b/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/editors/AddressEditorMediator.java index ed71968..06b898e 100644 --- a/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/editors/AddressEditorMediator.java +++ b/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/editors/AddressEditorMediator.java
@@ -222,7 +222,7 @@ mCountryField.set( DROPDOWN_CALLBACK, - new Callback<String>() { + new Callback<>() { /** Update the list of fields according to the selected country. */ @Override public void onResult(String countryCode) {
diff --git a/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/editors/DropdownFieldAdapter.java b/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/editors/DropdownFieldAdapter.java index 817d6bf..ade34354 100644 --- a/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/editors/DropdownFieldAdapter.java +++ b/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/editors/DropdownFieldAdapter.java
@@ -26,27 +26,27 @@ /** * Creates an array adapter. * - * @param context The current context. - * @param resource The resource ID for a layout file containing a layout to use when - * instantiating views. + * @param context The current context. + * @param resource The resource ID for a layout file containing a layout to use when + * instantiating views. * @param textViewResourceId The id of the TextView within the layout resource to be populated. - * @param objects The objects to represent in the ListView. + * @param objects The objects to represent in the ListView. */ public DropdownFieldAdapter( Context context, int resource, int textViewResourceId, List<T> objects) { - super(context, resource, textViewResourceId, new ArrayList<T>(objects)); + super(context, resource, textViewResourceId, new ArrayList<>(objects)); } /** * Creates an array adapter. * - * @param context The current context. - * @param resource The resource ID for a layout file containing a layout to use when - * instantiating views. - * @param objects The objects to represent in the ListView. + * @param context The current context. + * @param resource The resource ID for a layout file containing a layout to use when + * instantiating views. + * @param objects The objects to represent in the ListView. */ public DropdownFieldAdapter(Context context, int resource, List<T> objects) { - super(context, resource, new ArrayList<T>(objects)); + super(context, resource, new ArrayList<>(objects)); } @Override
diff --git a/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/editors/DropdownFieldView.java b/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/editors/DropdownFieldView.java index 48f55484e..15996e0 100644 --- a/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/editors/DropdownFieldView.java +++ b/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/editors/DropdownFieldView.java
@@ -130,7 +130,7 @@ mHint = hint; if (mHint != null) { mAdapter = - new HintedDropDownAdapter<String>( + new HintedDropDownAdapter<>( mContext, R.layout.multiline_spinner_item, R.id.spinner_item, @@ -144,8 +144,7 @@ mAdapter.setDropDownViewResource(R.layout.payment_request_dropdown_item); } else { mAdapter = - new DropdownFieldAdapter<String>( - mContext, R.layout.multiline_spinner_item, values); + new DropdownFieldAdapter<>(mContext, R.layout.multiline_spinner_item, values); mAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); } mDropdown.setAdapter(mAdapter);
diff --git a/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/editors/EditorProperties.java b/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/editors/EditorProperties.java index 7396483..7899d2ab 100644 --- a/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/editors/EditorProperties.java +++ b/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/editors/EditorProperties.java
@@ -56,7 +56,7 @@ public static final ReadableObjectPropertyKey<String> EDITOR_TITLE = new ReadableObjectPropertyKey<>("editor_title"); public static final ReadableObjectPropertyKey<String> CUSTOM_DONE_BUTTON_TEXT = - new ReadableObjectPropertyKey<String>("custom_done_button_text"); + new ReadableObjectPropertyKey<>("custom_done_button_text"); public static final ReadableObjectPropertyKey<String> FOOTER_MESSAGE = new ReadableObjectPropertyKey<>("footer_message"); public static final ReadableObjectPropertyKey<String> DELETE_CONFIRMATION_TITLE =
diff --git a/chrome/browser/autofill/test/android/java/src/org/chromium/chrome/browser/autofill/AutofillTestHelper.java b/chrome/browser/autofill/test/android/java/src/org/chromium/chrome/browser/autofill/AutofillTestHelper.java index 6f27683..1a9625b3 100644 --- a/chrome/browser/autofill/test/android/java/src/org/chromium/chrome/browser/autofill/AutofillTestHelper.java +++ b/chrome/browser/autofill/test/android/java/src/org/chromium/chrome/browser/autofill/AutofillTestHelper.java
@@ -31,6 +31,7 @@ import org.chromium.components.autofill.AutofillProfile; import org.chromium.components.autofill.AutofillSuggestion; import org.chromium.components.autofill.IbanRecordType; +import org.chromium.components.autofill.PaymentsPayload; import org.chromium.components.autofill.SubKeyRequester; import org.chromium.components.autofill.SuggestionType; import org.chromium.components.autofill.VirtualCardEnrollmentState; @@ -510,19 +511,22 @@ boolean shouldDisplayTermsAvailable, String guid, boolean isLocalPaymentsMethod) { + PaymentsPayload payload = + new PaymentsPayload( + labelContentDescription, + shouldDisplayTermsAvailable, + guid, + isLocalPaymentsMethod); return new AutofillSuggestion.Builder() .setLabel(label) .setSecondaryLabel(secondaryLabel) .setSubLabel(subLabel) .setSecondarySubLabel(secondarySubLabel) - .setLabelContentDescription(labelContentDescription) .setSuggestionType(suggestionType) .setCustomIconUrl(customIconUrl) .setIconId(iconId) .setApplyDeactivatedStyle(applyDeactivatedStyle) - .setShouldDisplayTermsAvailable(shouldDisplayTermsAvailable) - .setGuid(guid) - .setIsLocalPaymentsMethod(isLocalPaymentsMethod) + .setPayload(payload) .build(); }
diff --git a/chrome/browser/autofill/test/android/java/src/org/chromium/chrome/browser/autofill/PersonalDataManagerTest.java b/chrome/browser/autofill/test/android/java/src/org/chromium/chrome/browser/autofill/PersonalDataManagerTest.java index 59ceb0b1..ca81473 100644 --- a/chrome/browser/autofill/test/android/java/src/org/chromium/chrome/browser/autofill/PersonalDataManagerTest.java +++ b/chrome/browser/autofill/test/android/java/src/org/chromium/chrome/browser/autofill/PersonalDataManagerTest.java
@@ -86,7 +86,7 @@ private static Matcher<Iban> ibanMatcher( final @IbanRecordType int recordType, final String nickname) { - return new TypeSafeMatcher<Iban>() { + return new TypeSafeMatcher<>() { @Override protected boolean matchesSafely(Iban iban) { return iban.getRecordType() == recordType && iban.getNickname().equals(nickname); @@ -655,7 +655,7 @@ mHelper.setProfile(profile3); mHelper.setProfile(profile4); - List<String> expectedLabels = new LinkedList<String>(); + List<String> expectedLabels = new LinkedList<>(); expectedLabels.add("123 Main, jm@example.com"); expectedLabels.add("123 Main, jm-work@example.com"); expectedLabels.add("1500 Second Ave, 90068");
diff --git a/chrome/browser/auxiliary_search/java/src/org/chromium/chrome/browser/auxiliary_search/AuxiliarySearchDonor.java b/chrome/browser/auxiliary_search/java/src/org/chromium/chrome/browser/auxiliary_search/AuxiliarySearchDonor.java index 7160393b..f3eb621 100644 --- a/chrome/browser/auxiliary_search/java/src/org/chromium/chrome/browser/auxiliary_search/AuxiliarySearchDonor.java +++ b/chrome/browser/auxiliary_search/java/src/org/chromium/chrome/browser/auxiliary_search/AuxiliarySearchDonor.java
@@ -575,7 +575,7 @@ ListenableFuture<Void> result = session.removeAsync("", spec); Futures.addCallback( result, - new FutureCallback<Void>() { + new FutureCallback<>() { @Override public void onSuccess(@Nullable Void result) { Callback.runNullSafe(onDeleteCompleteCallback, true);
diff --git a/chrome/browser/auxiliary_search/junit/src/org/chromium/chrome/browser/auxiliary_search/AuxiliarySearchDonorUnitTest.java b/chrome/browser/auxiliary_search/junit/src/org/chromium/chrome/browser/auxiliary_search/AuxiliarySearchDonorUnitTest.java index 554b296..c4da7e98 100644 --- a/chrome/browser/auxiliary_search/junit/src/org/chromium/chrome/browser/auxiliary_search/AuxiliarySearchDonorUnitTest.java +++ b/chrome/browser/auxiliary_search/junit/src/org/chromium/chrome/browser/auxiliary_search/AuxiliarySearchDonorUnitTest.java
@@ -352,12 +352,12 @@ @Test public void testOnSetSchemaResponseAvailable() { - List<MigrationFailure> migrationFailures = new ArrayList<MigrationFailure>(); + List<MigrationFailure> migrationFailures = new ArrayList<>(); migrationFailures.add(mMigrationFailure); SetSchemaResponse setSchemaResponse = new SetSchemaResponse.Builder().addMigrationFailures(migrationFailures).build(); - List<WebPage> pendingDocs = new ArrayList<WebPage>(); + List<WebPage> pendingDocs = new ArrayList<>(); WebPage webPage = new WebPage.Builder("namespace", "Id1").setUrl("Url1").build(); pendingDocs.add(webPage); mAuxiliarySearchDonor.setPendingDocumentsForTesting(pendingDocs);
diff --git a/chrome/browser/auxiliary_search/junit/src/org/chromium/chrome/browser/auxiliary_search/AuxiliarySearchProviderUnitTest.java b/chrome/browser/auxiliary_search/junit/src/org/chromium/chrome/browser/auxiliary_search/AuxiliarySearchProviderUnitTest.java index 31a2732..ee31f4a 100644 --- a/chrome/browser/auxiliary_search/junit/src/org/chromium/chrome/browser/auxiliary_search/AuxiliarySearchProviderUnitTest.java +++ b/chrome/browser/auxiliary_search/junit/src/org/chromium/chrome/browser/auxiliary_search/AuxiliarySearchProviderUnitTest.java
@@ -115,7 +115,7 @@ } private void compareTabs(List<Tab> expectedTabs, List<Tab> returnedTabs) { - HashSet<Integer> returnedTabsNumbers = new HashSet<Integer>(); + HashSet<Integer> returnedTabsNumbers = new HashSet<>(); for (Tab returnedTab : returnedTabs) { int returnedNumber = Integer.valueOf(returnedTab.getUrl().getSpec().substring(TAB_URL.length()));
diff --git a/chrome/browser/bookmarks/android/junit/src/org/chromium/chrome/browser/bookmarks/ImprovedBookmarkRowCoordinatorTest.java b/chrome/browser/bookmarks/android/junit/src/org/chromium/chrome/browser/bookmarks/ImprovedBookmarkRowCoordinatorTest.java index f2d95dc..30cc62d 100644 --- a/chrome/browser/bookmarks/android/junit/src/org/chromium/chrome/browser/bookmarks/ImprovedBookmarkRowCoordinatorTest.java +++ b/chrome/browser/bookmarks/android/junit/src/org/chromium/chrome/browser/bookmarks/ImprovedBookmarkRowCoordinatorTest.java
@@ -272,7 +272,7 @@ assertEquals(0, model.get(ImprovedBookmarkRowProperties.FOLDER_CHILD_COUNT)); assertNotNull(model.get(ImprovedBookmarkRowProperties.FOLDER_START_ICON_DRAWABLE)); assertEquals( - new Pair<Drawable, Drawable>(null, null), + new Pair<>(null, null), model.get(ImprovedBookmarkRowProperties.FOLDER_START_IMAGE_FOLDER_DRAWABLES).get()); }
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_constants.h b/chrome/browser/browsing_data/chrome_browsing_data_remover_constants.h index 1fe0349..dc53551 100644 --- a/chrome/browser/browsing_data/chrome_browsing_data_remover_constants.h +++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_constants.h
@@ -9,7 +9,6 @@ #include "build/build_config.h" #include "chrome/common/buildflags.h" -#include "content/public/browser/browsing_data_filter_builder.h" #include "content/public/browser/browsing_data_remover.h" #include "extensions/buildflags/buildflags.h"
diff --git a/chrome/browser/chrome_content_browser_client_receiver_bindings.cc b/chrome/browser/chrome_content_browser_client_receiver_bindings.cc index fee5306..cd2ad34 100644 --- a/chrome/browser/chrome_content_browser_client_receiver_bindings.cc +++ b/chrome/browser/chrome_content_browser_client_receiver_bindings.cc
@@ -79,6 +79,10 @@ #include "extensions/browser/extensions_browser_client.h" #endif +#if BUILDFLAG(ENABLE_EXTENSIONS) +#include "chrome/browser/extensions/chrome_extensions_browser_interface_binders.h" +#endif + #if BUILDFLAG(ENABLE_LIBRARY_CDMS) || BUILDFLAG(IS_WIN) #include "chrome/browser/media/cdm_document_service_impl.h" #endif // BUILDFLAG(ENABLE_LIBRARY_CDMS) || BUILDFLAG(IS_WIN) @@ -371,6 +375,22 @@ map->Add<blink::mojom::BadgeService>( base::BindRepeating(&BindBadgeServiceForServiceWorker)); #endif + +#if BUILDFLAG(ENABLE_EXTENSIONS) + const GURL& site = service_worker_version_info.scope; + if (!site.SchemeIs(extensions::kExtensionScheme)) { + return; + } + + auto* extension = extensions::ExtensionRegistry::Get(browser_context) + ->enabled_extensions() + .GetByID(site.host()); + if (!extension) { + return; + } + extensions::PopulateChromeServiceWorkerBindersForExtension( + map, browser_context, extension); +#endif } void ChromeContentBrowserClient::
diff --git a/chrome/browser/collaboration/android/java/src/org/chromium/chrome/browser/collaboration/CollaborationIntegrationTest.java b/chrome/browser/collaboration/android/java/src/org/chromium/chrome/browser/collaboration/CollaborationIntegrationTest.java index 83e3c9ea..c29c33b 100644 --- a/chrome/browser/collaboration/android/java/src/org/chromium/chrome/browser/collaboration/CollaborationIntegrationTest.java +++ b/chrome/browser/collaboration/android/java/src/org/chromium/chrome/browser/collaboration/CollaborationIntegrationTest.java
@@ -66,7 +66,7 @@ /** Instrumentation tests for {@link CollaborationService}. */ @RunWith(ChromeJUnit4ClassRunner.class) @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE}) -@EnableFeatures({ChromeFeatureList.DATA_SHARING, ChromeFeatureList.TAB_GROUP_SYNC_ANDROID}) +@EnableFeatures({ChromeFeatureList.DATA_SHARING}) @DoNotBatch(reason = "Tabs can't be closed reliably between tests.") // TODO(crbug.com/399444939) Re-enable on automotive devices if needed. // Only run on device non-auto and with valid Google services.
diff --git a/chrome/browser/collaboration/android/java/src/org/chromium/chrome/browser/collaboration/messaging/MessagingBackendServiceFactoryTest.java b/chrome/browser/collaboration/android/java/src/org/chromium/chrome/browser/collaboration/messaging/MessagingBackendServiceFactoryTest.java index e99a90b..3a3ba12f 100644 --- a/chrome/browser/collaboration/android/java/src/org/chromium/chrome/browser/collaboration/messaging/MessagingBackendServiceFactoryTest.java +++ b/chrome/browser/collaboration/android/java/src/org/chromium/chrome/browser/collaboration/messaging/MessagingBackendServiceFactoryTest.java
@@ -57,7 +57,7 @@ @Test @MediumTest - @EnableFeatures({ChromeFeatureList.TAB_GROUP_SYNC_ANDROID, ChromeFeatureList.DATA_SHARING}) + @EnableFeatures({ChromeFeatureList.DATA_SHARING}) public void testServiceCreation_RealService() throws TimeoutException { LibraryLoader.getInstance().ensureInitialized(); mActivityTestRule.startMainActivityOnBlankPage();
diff --git a/chrome/browser/collaboration/android/java/src/org/chromium/chrome/browser/collaboration/messaging/TestMessagingBackendService.java b/chrome/browser/collaboration/android/java/src/org/chromium/chrome/browser/collaboration/messaging/TestMessagingBackendService.java index 1891164..6ab68a5 100644 --- a/chrome/browser/collaboration/android/java/src/org/chromium/chrome/browser/collaboration/messaging/TestMessagingBackendService.java +++ b/chrome/browser/collaboration/android/java/src/org/chromium/chrome/browser/collaboration/messaging/TestMessagingBackendService.java
@@ -37,27 +37,27 @@ @NonNull public List<PersistentMessage> getMessagesForTab( EitherTabId tabId, Optional</* @PersistentNotificationType */ Integer> type) { - return new ArrayList<PersistentMessage>(); + return new ArrayList<>(); } @Override @NonNull public List<PersistentMessage> getMessagesForGroup( EitherGroupId groupId, Optional</* @PersistentNotificationType */ Integer> type) { - return new ArrayList<PersistentMessage>(); + return new ArrayList<>(); } @Override @NonNull public List<PersistentMessage> getMessages( Optional</* @PersistentNotificationType */ Integer> type) { - return new ArrayList<PersistentMessage>(); + return new ArrayList<>(); } @Override @NonNull public List<ActivityLogItem> getActivityLog(ActivityLogQueryParams params) { - return new ArrayList<ActivityLogItem>(); + return new ArrayList<>(); } @Override
diff --git a/chrome/browser/collaboration/messaging/messaging_backend_service_factory_unittest.cc b/chrome/browser/collaboration/messaging/messaging_backend_service_factory_unittest.cc index a721363..87ed63c 100644 --- a/chrome/browser/collaboration/messaging/messaging_backend_service_factory_unittest.cc +++ b/chrome/browser/collaboration/messaging/messaging_backend_service_factory_unittest.cc
@@ -23,9 +23,7 @@ scoped_feature_list_.InitWithFeatureStates( {{data_sharing::features::kDataSharingFeature, true}, // Required for desktop platforms. - {tab_groups::kTabGroupSyncServiceDesktopMigration, true}, - // Required for Android. - {tab_groups::kTabGroupSyncAndroid, true}}); + {tab_groups::kTabGroupSyncServiceDesktopMigration, true}}); } ~MessagingBackendServiceFactoryTest() override = default;
diff --git a/chrome/browser/commerce/coupons/android/junit/src/org/chromium/chrome/browser/commerce/coupons/DiscountsBottomSheetContentMediatorTest.java b/chrome/browser/commerce/coupons/android/junit/src/org/chromium/chrome/browser/commerce/coupons/DiscountsBottomSheetContentMediatorTest.java index bca40195..7ea0602 100644 --- a/chrome/browser/commerce/coupons/android/junit/src/org/chromium/chrome/browser/commerce/coupons/DiscountsBottomSheetContentMediatorTest.java +++ b/chrome/browser/commerce/coupons/android/junit/src/org/chromium/chrome/browser/commerce/coupons/DiscountsBottomSheetContentMediatorTest.java
@@ -91,7 +91,7 @@ @Test public void testRequestShowContent_emptyInfoList() { - setShoppingServiceGetDiscountInfoForUrl(new ArrayList<DiscountInfo>()); + setShoppingServiceGetDiscountInfoForUrl(new ArrayList<>()); mMediator.requestShowContent(mMockCallback); verify(mMockCallback).onResult(false); }
diff --git a/chrome/browser/commerce/merchant_viewer/android/javatests/src/org/chromium/chrome/browser/merchant_viewer/MerchantTrustBottomSheetCoordinatorTest.java b/chrome/browser/commerce/merchant_viewer/android/javatests/src/org/chromium/chrome/browser/merchant_viewer/MerchantTrustBottomSheetCoordinatorTest.java index a9e787e..b591072 100644 --- a/chrome/browser/commerce/merchant_viewer/android/javatests/src/org/chromium/chrome/browser/merchant_viewer/MerchantTrustBottomSheetCoordinatorTest.java +++ b/chrome/browser/commerce/merchant_viewer/android/javatests/src/org/chromium/chrome/browser/merchant_viewer/MerchantTrustBottomSheetCoordinatorTest.java
@@ -35,7 +35,6 @@ import org.chromium.base.test.util.Batch; import org.chromium.base.test.util.CommandLineFlags; import org.chromium.chrome.browser.flags.ChromeSwitches; -import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.test.ChromeBrowserTestRule; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; @@ -108,7 +107,7 @@ mMockDecorView, mMockMetrics, IntentRequestTracker.createFromActivity(sActivity), - new ObservableSupplierImpl<Profile>()); + new ObservableSupplierImpl<>()); }); mDetailsTabCoordinator.setMediatorForTesting(mMockMediator); requestOpenSheetAndVerify();
diff --git a/chrome/browser/commerce/merchant_viewer/android/javatests/src/org/chromium/chrome/browser/merchant_viewer/MerchantTrustMessageSchedulerTest.java b/chrome/browser/commerce/merchant_viewer/android/javatests/src/org/chromium/chrome/browser/merchant_viewer/MerchantTrustMessageSchedulerTest.java index 33843fc..23cdadf0 100644 --- a/chrome/browser/commerce/merchant_viewer/android/javatests/src/org/chromium/chrome/browser/merchant_viewer/MerchantTrustMessageSchedulerTest.java +++ b/chrome/browser/commerce/merchant_viewer/android/javatests/src/org/chromium/chrome/browser/merchant_viewer/MerchantTrustMessageSchedulerTest.java
@@ -265,9 +265,7 @@ doReturn(true).when(mockMessagesContext).isValid(); doReturn(mMockWebContents).when(mockMessagesContext).getWebContents(); - scheduler.setScheduledMessage( - new Pair<MerchantTrustMessageContext, PropertyModel>( - mockMessagesContext, mockPropteryModel)); + scheduler.setScheduledMessage(new Pair<>(mockMessagesContext, mockPropteryModel)); Assert.assertNotNull(scheduler.getScheduledMessageContext()); scheduler.clear(MessageClearReason.UNKNOWN); Assert.assertNull(scheduler.getScheduledMessageContext());
diff --git a/chrome/browser/commerce/merchant_viewer/android/javatests/src/org/chromium/chrome/browser/merchant_viewer/MerchantTrustSignalsCoordinatorTest.java b/chrome/browser/commerce/merchant_viewer/android/javatests/src/org/chromium/chrome/browser/merchant_viewer/MerchantTrustSignalsCoordinatorTest.java index 9221a24..cca821e3 100644 --- a/chrome/browser/commerce/merchant_viewer/android/javatests/src/org/chromium/chrome/browser/merchant_viewer/MerchantTrustSignalsCoordinatorTest.java +++ b/chrome/browser/commerce/merchant_viewer/android/javatests/src/org/chromium/chrome/browser/merchant_viewer/MerchantTrustSignalsCoordinatorTest.java
@@ -604,7 +604,7 @@ private void setMockTrustSignalsData(MerchantInfo merchantInfo) { doAnswer( - new Answer<Void>() { + new Answer<>() { @Override public Void answer(InvocationOnMock invocation) { Callback callback = (Callback) invocation.getArguments()[2]; @@ -618,7 +618,7 @@ private void setMockTrustSignalsEventData(String hostname, MerchantTrustSignalsEvent event) { doAnswer( - new Answer<Void>() { + new Answer<>() { @Override public Void answer(InvocationOnMock invocation) { Callback callback = (Callback) invocation.getArguments()[1];
diff --git a/chrome/browser/commerce/price_tracking/android/java/src/org/chromium/chrome/browser/price_tracking/PriceTrackingBottomSheetContentProperties.java b/chrome/browser/commerce/price_tracking/android/java/src/org/chromium/chrome/browser/price_tracking/PriceTrackingBottomSheetContentProperties.java index f608a5e..fff56eb 100644 --- a/chrome/browser/commerce/price_tracking/android/java/src/org/chromium/chrome/browser/price_tracking/PriceTrackingBottomSheetContentProperties.java +++ b/chrome/browser/commerce/price_tracking/android/java/src/org/chromium/chrome/browser/price_tracking/PriceTrackingBottomSheetContentProperties.java
@@ -18,6 +18,9 @@ public static final WritableObjectPropertyKey<String> PRICE_TRACKING_TITLE = new WritableObjectPropertyKey<>(); + public static final WritableObjectPropertyKey<String> PRICE_TRACKING_SUBTITLE = + new WritableObjectPropertyKey<>(); + public static final WritableObjectPropertyKey<String> PRICE_TRACKING_BUTTON_TEXT = new WritableObjectPropertyKey<>(); @@ -36,6 +39,7 @@ public static final PropertyKey[] ALL_KEYS = new PropertyKey[] { PRICE_TRACKING_TITLE, + PRICE_TRACKING_SUBTITLE, PRICE_TRACKING_BUTTON_TEXT, PRICE_TRACKING_BUTTON_ICON, PRICE_TRACKING_BUTTON_FOREGROUND_COLOR,
diff --git a/chrome/browser/component_updater/wasm_tts_engine_component_installer.cc b/chrome/browser/component_updater/wasm_tts_engine_component_installer.cc index 2808423..0bd5245 100644 --- a/chrome/browser/component_updater/wasm_tts_engine_component_installer.cc +++ b/chrome/browser/component_updater/wasm_tts_engine_component_installer.cc
@@ -35,9 +35,7 @@ const base::FilePath::CharType kOffscreenHtmlFileName[] = FILE_PATH_LITERAL("offscreen.html"); const base::FilePath::CharType kOffscreenCompiledFileName[] = - FILE_PATH_LITERAL("offscreen_compiled.html"); -const base::FilePath::CharType kBindingsTypeDeclarationFileName[] = - FILE_PATH_LITERAL("bindings_main.d.ts"); + FILE_PATH_LITERAL("offscreen_compiled.js"); const base::FilePath::CharType kBackgroundCompiledFileName[] = FILE_PATH_LITERAL("background_compiled.js"); #endif @@ -146,9 +144,9 @@ base::PathExists(install_dir.Append(kBindingsMainJsFileName)) && base::PathExists(install_dir.Append(kOffscreenHtmlFileName)) && base::PathExists(install_dir.Append(kOffscreenCompiledFileName)) && - base::PathExists( - install_dir.Append(kBindingsTypeDeclarationFileName)) && - base::PathExists(install_dir.Append(kBackgroundCompiledFileName)); + base::PathExists(install_dir.Append(kBackgroundCompiledFileName)) && + base::PathExists(install_dir.Append(kWorkletProcessorJsFileName)) && + base::PathExists(install_dir.Append(kVoicesJsonFileName)); } #endif return base::PathExists(install_dir.Append(kManifestFileName)) &&
diff --git a/chrome/browser/composeplate/android/BUILD.gn b/chrome/browser/composeplate/android/BUILD.gn index f2137cdb..b471171 100644 --- a/chrome/browser/composeplate/android/BUILD.gn +++ b/chrome/browser/composeplate/android/BUILD.gn
@@ -9,7 +9,6 @@ "java/src/org/chromium/chrome/browser/composeplate/ComposeplateCoordinator.java", "java/src/org/chromium/chrome/browser/composeplate/ComposeplateMetricsUtils.java", "java/src/org/chromium/chrome/browser/composeplate/ComposeplateProperties.java", - "java/src/org/chromium/chrome/browser/composeplate/ComposeplateUtils.java", "java/src/org/chromium/chrome/browser/composeplate/ComposeplateViewBinder.java", ] @@ -42,7 +41,6 @@ sources = [ "junit/src/org/chromium/chrome/browser/composeplate/ComposeplateCoordinatorUnitTest.java", "junit/src/org/chromium/chrome/browser/composeplate/ComposeplateMetricsUtilsUnitTest.java", - "junit/src/org/chromium/chrome/browser/composeplate/ComposeplateUtilsUnitTest.java", "junit/src/org/chromium/chrome/browser/composeplate/ComposeplateViewBinderUnitTest.java", ]
diff --git a/chrome/browser/composeplate/android/java/src/org/chromium/chrome/browser/composeplate/ComposeplateUtils.java b/chrome/browser/composeplate/android/java/src/org/chromium/chrome/browser/composeplate/ComposeplateUtils.java deleted file mode 100644 index 7024a68..0000000 --- a/chrome/browser/composeplate/android/java/src/org/chromium/chrome/browser/composeplate/ComposeplateUtils.java +++ /dev/null
@@ -1,30 +0,0 @@ -// Copyright 2025 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.composeplate; - -import org.chromium.build.annotations.NullMarked; -import org.chromium.chrome.browser.flags.ChromeFeatureList; -import org.chromium.url.GURL; - -/** Utility class for the composeplate view. */ -@NullMarked -public class ComposeplateUtils { - private static final String VALID_URL_PROTOCOL = "https://"; - - /** Returns the URL to open when clicking the composeplate view. */ - public static GURL getComposeplateURL() { - String url = ChromeFeatureList.sAndroidComposeplateButtonUrl.getValue(); - if (url == null || !url.startsWith(VALID_URL_PROTOCOL)) { - return new GURL(ChromeFeatureList.sAndroidComposeplateButtonUrl.getDefaultValue()); - } - - GURL gurl = new GURL(url); - if (gurl.isValid()) { - return gurl; - } - - return new GURL(ChromeFeatureList.sAndroidComposeplateButtonUrl.getDefaultValue()); - } -}
diff --git a/chrome/browser/composeplate/android/junit/src/org/chromium/chrome/browser/composeplate/ComposeplateUtilsUnitTest.java b/chrome/browser/composeplate/android/junit/src/org/chromium/chrome/browser/composeplate/ComposeplateUtilsUnitTest.java deleted file mode 100644 index 2de77a58..0000000 --- a/chrome/browser/composeplate/android/junit/src/org/chromium/chrome/browser/composeplate/ComposeplateUtilsUnitTest.java +++ /dev/null
@@ -1,46 +0,0 @@ -// Copyright 2025 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.composeplate; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.junit.MockitoJUnit; -import org.mockito.junit.MockitoRule; -import org.robolectric.annotation.Config; - -import org.chromium.base.test.BaseRobolectricTestRunner; -import org.chromium.chrome.browser.flags.ChromeFeatureList; -import org.chromium.url.GURL; - -/** Unit tests for {@link ComposeplateUtils}. */ -@RunWith(BaseRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class ComposeplateUtilsUnitTest { - @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule(); - - @Test - public void testGetComposeplateURL() { - String defaultUrl = "about:blank"; - GURL defaultGurl = new GURL(defaultUrl); - assertEquals(defaultUrl, ChromeFeatureList.sAndroidComposeplateButtonUrl.getDefaultValue()); - - ChromeFeatureList.sAndroidComposeplateButtonUrl.setForTesting("foo.com"); - assertTrue(defaultGurl.equals(ComposeplateUtils.getComposeplateURL())); - - String validUrl = "http://foo.com"; - GURL validGurl = new GURL(validUrl); - ChromeFeatureList.sAndroidComposeplateButtonUrl.setForTesting(validUrl); - assertTrue(defaultGurl.equals(ComposeplateUtils.getComposeplateURL())); - - validUrl = "https://foo.com"; - validGurl = new GURL(validUrl); - ChromeFeatureList.sAndroidComposeplateButtonUrl.setForTesting(validUrl); - assertTrue(validGurl.equals(ComposeplateUtils.getComposeplateURL())); - } -}
diff --git a/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/DownloadManagerBridge.java b/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/DownloadManagerBridge.java index e7a94e8..7ad36d1 100644 --- a/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/DownloadManagerBridge.java +++ b/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/DownloadManagerBridge.java
@@ -309,7 +309,7 @@ final String mimeType = MimeUtils.remapGenericMimeType(originalMimeType, originalUrl.getSpec(), fileName); AsyncTask<Long> task = - new AsyncTask<Long>() { + new AsyncTask<>() { @Override protected Long doInBackground() { long downloadId = DownloadConstants.INVALID_DOWNLOAD_ID;
diff --git a/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/MimeUtils.java b/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/MimeUtils.java index 6d402c0..77ab590 100644 --- a/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/MimeUtils.java +++ b/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/MimeUtils.java
@@ -38,7 +38,7 @@ // Mime types that Android can't handle when tries to open the file. Chrome may deduct a better // mime type based on file extension. private static final HashSet<String> GENERIC_MIME_TYPES = - new HashSet<String>( + new HashSet<>( Arrays.asList( "text/plain", "application/octet-stream", @@ -50,7 +50,7 @@ // Set will be more expensive to initialize, so use an ArrayList here. private static final List<String> MIME_TYPES_TO_OPEN = - new ArrayList<String>( + new ArrayList<>( Arrays.asList( MimeUtils.OMA_DOWNLOAD_DESCRIPTOR_MIME, "application/pdf",
diff --git a/chrome/browser/download/internal/android/java/res/drawable/downloads_empty_state_illustration.xml b/chrome/browser/download/internal/android/java/res/drawable/downloads_empty_state_illustration.xml index 4b6091a..8b55e6b 100644 --- a/chrome/browser/download/internal/android/java/res/drawable/downloads_empty_state_illustration.xml +++ b/chrome/browser/download/internal/android/java/res/drawable/downloads_empty_state_illustration.xml
@@ -1,29 +1,36 @@ <?xml version="1.0" encoding="utf-8"?> <!-- -Copyright 2023 The Chromium Authors +Copyright 2025 The Chromium Authors Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" android:autoMirrored="true" + android:width="130dp" android:height="130dp" - android:viewportHeight="130" android:viewportWidth="130" - android:width="130dp" > + android:viewportHeight="130"> <path - android:fillColor="@color/empty_state_icon_bg_color" - android:pathData="M20.29,110.66L20.29,110.66A47.07,47.07 90,0 1,20.29 44.09L44.09,20.29A47.07,47.07 90,0 1,110.66 20.29L110.66,20.29A47.07,47.07 90,0 1,110.66 86.86L86.86,110.66A47.07,47.07 90,0 1,20.29 110.66z"/> + android:pathData="M45.68,23.79C51.68,19.44 54.68,17.26 57.87,16.17C62.49,14.61 67.5,14.61 72.13,16.17C75.32,17.26 78.32,19.44 84.32,23.79L97.81,33.59C101.37,36.17 103.15,37.47 104.6,39.02C106.7,41.27 108.31,43.92 109.33,46.82C110.03,48.82 110.35,51 111,55.35L113.5,72.19C114.63,79.83 115.19,83.65 114.62,87.09C113.8,92.07 111.3,96.62 107.54,99.99C104.94,102.31 101.41,103.89 94.36,107.03L78.38,114.15C74.12,116.04 71.99,116.99 69.8,117.47C66.64,118.18 63.36,118.18 60.2,117.47C58.01,116.99 55.88,116.04 51.62,114.15L35.64,107.03C28.59,103.89 25.06,102.31 22.46,99.99C18.7,96.62 16.2,92.07 15.38,87.09C14.8,83.65 15.37,79.83 16.5,72.19L19,55.35C19.65,51 19.97,48.82 20.67,46.82C21.69,43.92 23.3,41.27 25.4,39.02C26.85,37.47 28.63,36.17 32.19,33.59L45.68,23.79Z" + android:fillColor="@color/empty_state_asset_bg_color"/> <path - android:pathData="M37,73.5V86C37,88.21 38.79,90 41,90H89C91.21,90 93,88.21 93,86V73.5" - android:strokeColor="@color/empty_state_icon_color" - android:strokeWidth="2"/> + android:pathData="M65,33V76" + android:strokeWidth="5" + android:fillColor="#00000000" + android:strokeColor="@color/empty_state_asset_outline_color_primary" + android:strokeLineCap="round"/> <path - android:pathData="M65,33V74.5" - android:strokeColor="@color/empty_state_icon_color" - android:strokeWidth="2"/> + android:pathData="M82,60.5L65,77.5L48,60.5" + android:strokeLineJoin="round" + android:strokeWidth="5" + android:fillColor="#00000000" + android:strokeColor="@color/empty_state_asset_outline_color_primary" + android:strokeLineCap="round"/> <path - android:pathData="M81,59L65.71,74.29C65.32,74.68 64.68,74.68 64.29,74.29L49,59" - android:strokeColor="@color/empty_state_icon_color" - android:strokeWidth="2"/> -</vector> \ No newline at end of file + android:pathData="M36,78V90C36,91.66 37.34,93 39,93H91C92.66,93 94,91.66 94,90V78" + android:strokeWidth="6" + android:fillColor="#00000000" + android:strokeColor="@color/empty_state_asset_outline_color_primary" + android:strokeLineCap="round"/> +</vector>
diff --git a/chrome/browser/download/internal/android/java/src/org/chromium/chrome/browser/download/home/DownloadActivityV2Test.java b/chrome/browser/download/internal/android/java/src/org/chromium/chrome/browser/download/home/DownloadActivityV2Test.java index 9b47976..f72a0af 100644 --- a/chrome/browser/download/internal/android/java/src/org/chromium/chrome/browser/download/home/DownloadActivityV2Test.java +++ b/chrome/browser/download/internal/android/java/src/org/chromium/chrome/browser/download/home/DownloadActivityV2Test.java
@@ -134,7 +134,7 @@ * @param text The text that the view holder has in its view hierarchy. */ private static Matcher<ViewHolder> hasTextInViewHolder(String text) { - return new BoundedMatcher<ViewHolder, ListItemViewHolder>(ListItemViewHolder.class) { + return new BoundedMatcher<>(ListItemViewHolder.class) { @Override public void describeTo(Description description) { description.appendText("has text: " + text);
diff --git a/chrome/browser/download/internal/android/java/src/org/chromium/chrome/browser/download/home/DownloadManagerCoordinatorImpl.java b/chrome/browser/download/internal/android/java/src/org/chromium/chrome/browser/download/home/DownloadManagerCoordinatorImpl.java index 385906f..2c20257 100644 --- a/chrome/browser/download/internal/android/java/src/org/chromium/chrome/browser/download/home/DownloadManagerCoordinatorImpl.java +++ b/chrome/browser/download/internal/android/java/src/org/chromium/chrome/browser/download/home/DownloadManagerCoordinatorImpl.java
@@ -75,7 +75,7 @@ mActivity = activity; mSettingsNavigation = settingsNavigation; mDeleteCoordinator = new DeleteUndoCoordinator(snackbarManager); - mSelectionDelegate = new SelectionDelegate<ListItem>(); + mSelectionDelegate = new SelectionDelegate<>(); mListCoordinator = new DateOrderedListCoordinator( mActivity,
diff --git a/chrome/browser/download/internal/android/java/src/org/chromium/chrome/browser/download/home/OfflineItemSource.java b/chrome/browser/download/internal/android/java/src/org/chromium/chrome/browser/download/home/OfflineItemSource.java index f22395ff..457f14d5 100644 --- a/chrome/browser/download/internal/android/java/src/org/chromium/chrome/browser/download/home/OfflineItemSource.java +++ b/chrome/browser/download/internal/android/java/src/org/chromium/chrome/browser/download/home/OfflineItemSource.java
@@ -98,7 +98,7 @@ // OfflineContentProvider.Observer implementation. @Override public void onItemsAdded(List<OfflineItem> items) { - Set<OfflineItem> addedItems = new HashSet<OfflineItem>(); + Set<OfflineItem> addedItems = new HashSet<>(); for (OfflineItem item : items) { if (mItems.containsKey(item.id)) { onItemUpdated(item, null);
diff --git a/chrome/browser/download/internal/android/java/src/org/chromium/chrome/browser/download/interstitial/DownloadInterstitialMediatorTest.java b/chrome/browser/download/internal/android/java/src/org/chromium/chrome/browser/download/interstitial/DownloadInterstitialMediatorTest.java index 58f275e..59899f8 100644 --- a/chrome/browser/download/internal/android/java/src/org/chromium/chrome/browser/download/interstitial/DownloadInterstitialMediatorTest.java +++ b/chrome/browser/download/internal/android/java/src/org/chromium/chrome/browser/download/interstitial/DownloadInterstitialMediatorTest.java
@@ -337,7 +337,7 @@ private final Map<Integer, Integer> mValues; UmaTestingHelper() { - mValues = new HashMap<Integer, Integer>(); + mValues = new HashMap<>(); } /**
diff --git a/chrome/browser/enterprise/data_protection/data_protection_navigation_observer.cc b/chrome/browser/enterprise/data_protection/data_protection_navigation_observer.cc index d3210ea4..dc16949 100644 --- a/chrome/browser/enterprise/data_protection/data_protection_navigation_observer.cc +++ b/chrome/browser/enterprise/data_protection/data_protection_navigation_observer.cc
@@ -208,7 +208,8 @@ Profile* profile, content::NavigationHandle* navigation_handle, Callback callback) { - if (!navigation_handle->IsInPrimaryMainFrame()) { + if (navigation_handle->IsSameDocument() || + !navigation_handle->IsInPrimaryMainFrame()) { return nullptr; }
diff --git a/chrome/browser/enterprise/data_protection/data_protection_navigation_observer_unittest.cc b/chrome/browser/enterprise/data_protection/data_protection_navigation_observer_unittest.cc index 28986c8a..36f0a10 100644 --- a/chrome/browser/enterprise/data_protection/data_protection_navigation_observer_unittest.cc +++ b/chrome/browser/enterprise/data_protection/data_protection_navigation_observer_unittest.cc
@@ -35,6 +35,7 @@ #include "components/safe_browsing/core/common/proto/realtimeapi.pb.h" #include "components/signin/public/identity_manager/identity_test_environment.h" #include "content/public/browser/web_contents.h" +#include "content/public/browser/web_contents_observer.h" #include "content/public/test/navigation_simulator.h" #include "content/public/test/test_renderer_host.h" #include "net/traffic_annotation/network_traffic_annotation_test_helper.h" @@ -551,6 +552,61 @@ } } +class SameDocumentNavigationWebContentsObserver + : public content::WebContentsObserver { + public: + explicit SameDocumentNavigationWebContentsObserver( + content::WebContents* web_contents, + FakeRealTimeUrlLookupService* lookup_service, + content::BrowserContext* browser_context) + : content::WebContentsObserver(web_contents), + lookup_service_(lookup_service), + browser_context_(browser_context) {} + + MOCK_METHOD(void, + DidFinishNavigation, + (content::NavigationHandle*), + (override)); + + void DidStartNavigation( + content::NavigationHandle* navigation_handle) override { + base::test::TestFuture<const UrlSettings&> future; + + FakeDataProtectionNavigationController controller( + web_contents(), lookup_service_, future.GetCallback()); + + auto navigation_observer = + DataProtectionNavigationObserver::CreateForNavigationIfNeeded( + &controller, Profile::FromBrowserContext(browser_context_), + navigation_handle, future.GetCallback()); + + ASSERT_EQ(navigation_observer, nullptr); + } + + private: + raw_ptr<content::WebContents> web_contents_; + raw_ptr<FakeRealTimeUrlLookupService> lookup_service_; + raw_ptr<content::BrowserContext> browser_context_; +}; + +TEST_F(DataProtectionNavigationObserverTest, + SkipSameDocumentNavigation_CreateForNavigationIfNeeded) { + SetContents(CreateTestWebContents()); + NavigateAndCommit(GURL("https://example.com")); + SameDocumentNavigationWebContentsObserver observer( + web_contents(), &lookup_service_, browser_context()); + + auto simulator = content::NavigationSimulator::CreateRendererInitiated( + GURL("https://example.com#fragment"), main_rfh()); + + // Ensure that the navigation callbacks are invoked, since the assertion is + // outside the test body. If DidFinishNavigation() was called, then it is + // guaranteed that DidStartNavigation() was called prior, thereby checking the + // same document assertion. + EXPECT_CALL(observer, DidFinishNavigation); + simulator->CommitSameDocument(); +} + TEST_F(DataProtectionNavigationObserverTest, SkipSpecialURLs_ApplyDataProtectionSettings) { SetContents(CreateTestWebContents());
diff --git a/chrome/browser/enterprise/idle/action_runner_unittest.cc b/chrome/browser/enterprise/idle/action_runner_unittest.cc index 89e689d..996d275 100644 --- a/chrome/browser/enterprise/idle/action_runner_unittest.cc +++ b/chrome/browser/enterprise/idle/action_runner_unittest.cc
@@ -15,7 +15,9 @@ #include "chrome/test/base/testing_profile.h" #include "components/enterprise/idle/idle_pref_names.h" #include "components/prefs/pref_service.h" +#include "content/public/browser/browsing_data_filter_builder.h" #include "content/public/browser/browsing_data_remover.h" +#include "content/public/browser/storage_partition_config.h" #include "content/public/test/browser_task_environment.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/extensions/api/messaging/messaging_apitest.cc b/chrome/browser/extensions/api/messaging/messaging_apitest.cc index c5a60f10..1a46e50d 100644 --- a/chrome/browser/extensions/api/messaging/messaging_apitest.cc +++ b/chrome/browser/extensions/api/messaging/messaging_apitest.cc
@@ -21,6 +21,7 @@ #include "base/strings/to_string.h" #include "base/strings/utf_string_conversions.h" #include "base/synchronization/waitable_event.h" +#include "base/test/scoped_feature_list.h" #include "base/values.h" #include "build/build_config.h" #include "chrome/browser/extensions/browsertest_util.h" @@ -47,6 +48,7 @@ #include "extensions/browser/process_manager.h" #include "extensions/common/api/runtime.h" #include "extensions/common/extension_builder.h" +#include "extensions/common/extension_features.h" #include "extensions/test/extension_test_message_listener.h" #include "extensions/test/result_catcher.h" #include "extensions/test/test_extension_dir.h" @@ -620,6 +622,41 @@ ASSERT_TRUE(result_catcher.GetNextResult()) << result_catcher.message(); } +class OnMessagePromiseReturnMessagingApiTest : public MessagingApiTest { + public: + OnMessagePromiseReturnMessagingApiTest() { + scoped_feature_list_.InitAndEnableFeature( + extensions_features::kRuntimeOnMessagePromiseReturnSupport); + } + + private: + base::test::ScopedFeatureList scoped_feature_list_; +}; + +// Runs multiple test scenarios for runtime.OnMessage() listeners returning +// various synchronous and asynchronous (promise or 'return true' callback) +// values. +IN_PROC_BROWSER_TEST_F(OnMessagePromiseReturnMessagingApiTest, + OnMessageReturnBehavior) { + ASSERT_TRUE(LoadExtension( + shared_test_data_dir().AppendASCII("messaging/on_message_promise"))); + + // Open example.com where content script is injected and runtime.sendMessage() + // is called. + ResultCatcher result_catcher; + ASSERT_TRUE(ui_test_utils::NavigateToURL( + browser(), embedded_test_server()->GetURL("/extensions/test_file.html"))); + + // Confirm content script response callback function is called with the + // expected value. + { + SCOPED_TRACE( + "waiting for content script message sender response callback to " + "receive response from background message listener"); + EXPECT_TRUE(result_catcher.GetNextResult()) << result_catcher.message(); + } +} + class ServiceWorkerMessagingApiTest : public MessagingApiTest { protected: ~ServiceWorkerMessagingApiTest() override = default;
diff --git a/chrome/browser/extensions/api/settings_private/generated_prefs.cc b/chrome/browser/extensions/api/settings_private/generated_prefs.cc index ef1a7c2..c1dfcc26 100644 --- a/chrome/browser/extensions/api/settings_private/generated_prefs.cc +++ b/chrome/browser/extensions/api/settings_private/generated_prefs.cc
@@ -14,6 +14,7 @@ #include "chrome/browser/extensions/api/settings_private/prefs_util_enums.h" #include "chrome/browser/password_manager/generated_password_leak_detection_pref.h" #include "chrome/browser/safe_browsing/generated_safe_browsing_pref.h" +#include "chrome/browser/safe_browsing/generated_security_settings_bundle_pref.h" #include "chrome/browser/ssl/generated_https_first_mode_pref.h" #include "chrome/common/extensions/api/settings_private.h" #include "components/content_settings/core/common/content_settings_types.h" @@ -103,6 +104,9 @@ std::make_unique<GeneratedPasswordLeakDetectionPref>(profile_); prefs_[safe_browsing::kGeneratedSafeBrowsingPref] = std::make_unique<safe_browsing::GeneratedSafeBrowsingPref>(profile_); + prefs_[safe_browsing::kGeneratedSecuritySettingsBundlePref] = + std::make_unique<safe_browsing::GeneratedSecuritySettingsBundlePref>( + profile_); prefs_[content_settings::kGeneratedNotificationPref] = std::make_unique< content_settings::GeneratedPermissionPromptingBehaviorPref>( profile_, ContentSettingsType::NOTIFICATIONS);
diff --git a/chrome/browser/extensions/api/settings_private/prefs_util.cc b/chrome/browser/extensions/api/settings_private/prefs_util.cc index 92e93bb..f075287 100644 --- a/chrome/browser/extensions/api/settings_private/prefs_util.cc +++ b/chrome/browser/extensions/api/settings_private/prefs_util.cc
@@ -27,6 +27,7 @@ #include "chrome/browser/prefs/session_startup_pref.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/safe_browsing/generated_safe_browsing_pref.h" +#include "chrome/browser/safe_browsing/generated_security_settings_bundle_pref.h" #include "chrome/browser/ssl/generated_https_first_mode_pref.h" #include "chrome/browser/ui/safety_hub/safety_hub_prefs.h" #include "chrome/browser/ui/tabs/tab_strip_prefs.h" @@ -374,6 +375,10 @@ settings_api::PrefType::kBoolean; (*s_allowlist)[::kGeneratedHttpsFirstModePref] = settings_api::PrefType::kNumber; + (*s_allowlist)[::prefs::kSecuritySettingsBundle] = + settings_api::PrefType::kNumber; + (*s_allowlist)[::safe_browsing::kGeneratedSecuritySettingsBundlePref] = + settings_api::PrefType::kNumber; // Tracking protection page (*s_allowlist)[::prefs::kCookieControlsMode] =
diff --git a/chrome/browser/extensions/background_xhr_browsertest.cc b/chrome/browser/extensions/background_xhr_browsertest.cc index a6f49d7..828429e 100644 --- a/chrome/browser/extensions/background_xhr_browsertest.cc +++ b/chrome/browser/extensions/background_xhr_browsertest.cc
@@ -42,6 +42,7 @@ #include "net/ssl/ssl_server_config.h" #include "net/test/embedded_test_server/embedded_test_server.h" #include "net/test/test_data_directory.h" +#include "services/network/public/cpp/ip_address_space_overrides_test_utils.h" #include "services/network/public/cpp/network_switches.h" #include "url/gurl.h" @@ -134,11 +135,8 @@ // subclasses need it in their own SetUpCommandLine functions. ASSERT_TRUE(embedded_test_server()->Start()); // Treat the test server as public to bypass Local Network Access checks. - command_line->AppendSwitchASCII( - network::switches::kIpAddressSpaceOverrides, - base::StringPrintf( - "%s=public", - embedded_test_server()->host_port_pair().ToString().c_str())); + network::AddPublicIpAddressSpaceOverrideToCommandLine( + *embedded_test_server(), *command_line); } void SetUpOnMainThread() override {
diff --git a/chrome/browser/extensions/chrome_extension_host_delegate.cc b/chrome/browser/extensions/chrome_extension_host_delegate.cc index 19838c5..08770953 100644 --- a/chrome/browser/extensions/chrome_extension_host_delegate.cc +++ b/chrome/browser/extensions/chrome_extension_host_delegate.cc
@@ -12,9 +12,6 @@ #include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h" #include "chrome/browser/picture_in_picture/picture_in_picture_window_manager.h" #include "chrome/browser/ui/prefs/prefs_tab_helper.h" -#include "extensions/browser/extension_host.h" -#include "extensions/browser/extension_registrar.h" -#include "extensions/browser/extension_system.h" #include "extensions/browser/extensions_browser_client.h" #include "extensions/common/extension.h" #include "extensions/common/extension_id.h" @@ -31,12 +28,6 @@ apps::AudioFocusWebContentsObserver::CreateForWebContents(web_contents); } -void ChromeExtensionHostDelegate::OnMainFrameCreatedForBackgroundPage( - ExtensionHost* host) { - ExtensionRegistrar::Get(host->browser_context()) - ->DidCreateMainFrameForBackgroundPage(host); -} - void ChromeExtensionHostDelegate::CreateTab( std::unique_ptr<content::WebContents> web_contents, const ExtensionId& extension_id,
diff --git a/chrome/browser/extensions/chrome_extension_host_delegate.h b/chrome/browser/extensions/chrome_extension_host_delegate.h index 9d3b635..e42a6be 100644 --- a/chrome/browser/extensions/chrome_extension_host_delegate.h +++ b/chrome/browser/extensions/chrome_extension_host_delegate.h
@@ -18,7 +18,6 @@ // ExtensionHostDelegate implementation. void OnExtensionHostCreated(content::WebContents* web_contents) override; - void OnMainFrameCreatedForBackgroundPage(ExtensionHost* host) override; void CreateTab(std::unique_ptr<content::WebContents> web_contents, const ExtensionId& extension_id, WindowOpenDisposition disposition,
diff --git a/chrome/browser/extensions/chrome_extensions_browser_interface_binders.cc b/chrome/browser/extensions/chrome_extensions_browser_interface_binders.cc index fc1b0f0..33c8f96 100644 --- a/chrome/browser/extensions/chrome_extensions_browser_interface_binders.cc +++ b/chrome/browser/extensions/chrome_extensions_browser_interface_binders.cc
@@ -11,6 +11,7 @@ #include "content/public/browser/browser_thread.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_process_host.h" +#include "content/public/browser/service_worker_version_base_info.h" #include "extensions/browser/api/mime_handler_private/mime_handler_private.h" #include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h" #include "extensions/common/api/mime_handler.mojom.h" @@ -83,17 +84,16 @@ #endif // BUILDFLAG(GOOGLE_CHROME_BRANDING) void BindLanguagePacks( - content::RenderFrameHost* render_frame_host, mojo::PendingReceiver<ash::language::mojom::LanguagePacks> receiver) { ash::language_packs::LanguagePacksImpl::GetInstance().BindReceiver( std::move(receiver)); } void BindGoogleTtsStream( - content::RenderFrameHost* render_frame_host, + content::BrowserContext* browser_context, mojo::PendingReceiver<chromeos::tts::mojom::GoogleTtsStream> receiver) { TtsEngineExtensionObserverChromeOSFactory::GetForProfile( - Profile::FromBrowserContext(render_frame_host->GetBrowserContext())) + Profile::FromBrowserContext(browser_context)) ->BindGoogleTtsStream(std::move(receiver)); } @@ -172,8 +172,10 @@ if (extension->id() == ash::extension_ime_util::kXkbExtensionId) { binder_map->Add<ash::ime::mojom::InputEngineManager>( base::BindRepeating(&BindInputEngineManager)); - binder_map->Add<ash::language::mojom::LanguagePacks>( - base::BindRepeating(&BindLanguagePacks)); + binder_map->Add<ash::language::mojom::LanguagePacks>(base::BindRepeating( + [](content::RenderFrameHost* frame_host, + mojo::PendingReceiver<ash::language::mojom::LanguagePacks> + receiver) { BindLanguagePacks(std::move(receiver)); })); binder_map->Add<chromeos::machine_learning::mojom::MachineLearningService>( base::BindRepeating(&BindMachineLearningService)); } @@ -230,10 +232,17 @@ } if (extension->id() == extension_misc::kGoogleSpeechSynthesisExtensionId) { - binder_map->Add<chromeos::tts::mojom::GoogleTtsStream>( - base::BindRepeating(&BindGoogleTtsStream)); - binder_map->Add<ash::language::mojom::LanguagePacks>( - base::BindRepeating(&BindLanguagePacks)); + binder_map->Add<chromeos::tts::mojom::GoogleTtsStream>(base::BindRepeating( + [](content::RenderFrameHost* frame_host, + mojo::PendingReceiver<chromeos::tts::mojom::GoogleTtsStream> + receiver) { + BindGoogleTtsStream(frame_host->GetBrowserContext(), + std::move(receiver)); + })); + binder_map->Add<ash::language::mojom::LanguagePacks>(base::BindRepeating( + [](content::RenderFrameHost* frame_host, + mojo::PendingReceiver<ash::language::mojom::LanguagePacks> + receiver) { BindLanguagePacks(std::move(receiver)); })); } // Limit the binding to EnhancedNetworkTts Extension. @@ -279,4 +288,27 @@ base::BindRepeating(&BindBeforeUnloadControl)); } +void PopulateChromeServiceWorkerBindersForExtension( + mojo::BinderMapWithContext<const content::ServiceWorkerVersionBaseInfo&>* + binder_map, + content::BrowserContext* browser_context, + const Extension* extension) { +#if BUILDFLAG(IS_CHROMEOS) + if (extension->id() == extension_misc::kGoogleSpeechSynthesisExtensionId) { + binder_map->Add<chromeos::tts::mojom::GoogleTtsStream>(base::BindRepeating( + [](content::BrowserContext* browser_context, + const content::ServiceWorkerVersionBaseInfo&, + mojo::PendingReceiver<chromeos::tts::mojom::GoogleTtsStream> + receiver) { + BindGoogleTtsStream(browser_context, std::move(receiver)); + }, + browser_context)); + binder_map->Add<ash::language::mojom::LanguagePacks>(base::BindRepeating( + [](const content::ServiceWorkerVersionBaseInfo&, + mojo::PendingReceiver<ash::language::mojom::LanguagePacks> + receiver) { BindLanguagePacks(std::move(receiver)); })); + } +#endif // BUILDFLAG(IS_CHROMEOS) +} + } // namespace extensions
diff --git a/chrome/browser/extensions/chrome_extensions_browser_interface_binders.h b/chrome/browser/extensions/chrome_extensions_browser_interface_binders.h index 72f18e9..b1e344b 100644 --- a/chrome/browser/extensions/chrome_extensions_browser_interface_binders.h +++ b/chrome/browser/extensions/chrome_extensions_browser_interface_binders.h
@@ -8,7 +8,9 @@ #include "mojo/public/cpp/bindings/binder_map.h" namespace content { +class BrowserContext; class RenderFrameHost; +struct ServiceWorkerVersionBaseInfo; } namespace extensions { @@ -20,6 +22,12 @@ content::RenderFrameHost* render_frame_host, const Extension* extension); +void PopulateChromeServiceWorkerBindersForExtension( + mojo::BinderMapWithContext<const content::ServiceWorkerVersionBaseInfo&>* + binder_map, + content::BrowserContext* browser_context, + const Extension* extension); + } // namespace extensions #endif // CHROME_BROWSER_EXTENSIONS_CHROME_EXTENSIONS_BROWSER_INTERFACE_BINDERS_H_
diff --git a/chrome/browser/extensions/desktop_android/desktop_android_extension_host_delegate.cc b/chrome/browser/extensions/desktop_android/desktop_android_extension_host_delegate.cc index bc9264c3..a3086a3 100644 --- a/chrome/browser/extensions/desktop_android/desktop_android_extension_host_delegate.cc +++ b/chrome/browser/extensions/desktop_android/desktop_android_extension_host_delegate.cc
@@ -18,9 +18,6 @@ void DesktopAndroidExtensionHostDelegate::OnExtensionHostCreated( content::WebContents* web_contents) {} -void DesktopAndroidExtensionHostDelegate::OnMainFrameCreatedForBackgroundPage( - ExtensionHost* host) {} - void DesktopAndroidExtensionHostDelegate::CreateTab( std::unique_ptr<content::WebContents> web_contents, const ExtensionId& extension_id,
diff --git a/chrome/browser/extensions/desktop_android/desktop_android_extension_host_delegate.h b/chrome/browser/extensions/desktop_android/desktop_android_extension_host_delegate.h index 012c517e..ed013f7 100644 --- a/chrome/browser/extensions/desktop_android/desktop_android_extension_host_delegate.h +++ b/chrome/browser/extensions/desktop_android/desktop_android_extension_host_delegate.h
@@ -21,7 +21,6 @@ // ExtensionHostDelegate: void OnExtensionHostCreated(content::WebContents* web_contents) override; - void OnMainFrameCreatedForBackgroundPage(ExtensionHost* host) override; void CreateTab(std::unique_ptr<content::WebContents> web_contents, const ExtensionId& extension_id, WindowOpenDisposition disposition,
diff --git a/chrome/browser/feedback/android/java/src/org/chromium/chrome/browser/feedback/LowEndDeviceFeedbackSource.java b/chrome/browser/feedback/android/java/src/org/chromium/chrome/browser/feedback/LowEndDeviceFeedbackSource.java index e45e107f..d4b0cc0d 100644 --- a/chrome/browser/feedback/android/java/src/org/chromium/chrome/browser/feedback/LowEndDeviceFeedbackSource.java +++ b/chrome/browser/feedback/android/java/src/org/chromium/chrome/browser/feedback/LowEndDeviceFeedbackSource.java
@@ -17,7 +17,7 @@ private final HashMap<String, String> mMap; LowEndDeviceFeedbackSource() { - mMap = new HashMap<String, String>(1); + mMap = new HashMap<>(1); mMap.put(LOW_END_DEVICE_KEY, Boolean.toString(SysUtils.isLowEndDevice())); }
diff --git a/chrome/browser/file_select_helper.cc b/chrome/browser/file_select_helper.cc index f03a163..442f428 100644 --- a/chrome/browser/file_select_helper.cc +++ b/chrome/browser/file_select_helper.cc
@@ -60,6 +60,7 @@ #else #include "chrome/browser/picture_in_picture/picture_in_picture_window_manager.h" #include "chrome/browser/picture_in_picture/scoped_disallow_picture_in_picture.h" +#include "chrome/browser/picture_in_picture/scoped_tuck_picture_in_picture.h" #endif // BUILDFLAG(IS_ANDROID) using blink::mojom::FileChooserFileInfo; @@ -614,6 +615,10 @@ ->ShouldFileDialogBlockPictureInPicture(web_contents_)) { scoped_disallow_picture_in_picture_ = std::make_unique<ScopedDisallowPictureInPicture>(); + } else if (PictureInPictureWindowManager::GetInstance() + ->ShouldFileDialogTuckPictureInPicture(web_contents_)) { + scoped_tuck_picture_in_picture_ = + std::make_unique<ScopedTuckPictureInPicture>(); } #endif // !BUILDFLAG(IS_ANDROID) @@ -791,6 +796,7 @@ #if !BUILDFLAG(IS_ANDROID) scoped_disallow_picture_in_picture_.reset(); + scoped_tuck_picture_in_picture_.reset(); #endif // !BUILDFLAG(IS_ANDROID) Release();
diff --git a/chrome/browser/file_select_helper.h b/chrome/browser/file_select_helper.h index e5b8c7d6..2025d39 100644 --- a/chrome/browser/file_select_helper.h +++ b/chrome/browser/file_select_helper.h
@@ -28,6 +28,7 @@ class Profile; class ScopedDisallowPictureInPicture; +class ScopedTuckPictureInPicture; namespace content { class FileSelectListener; @@ -334,6 +335,9 @@ // When not null, this prevents picture-in-picture windows from opening. std::unique_ptr<ScopedDisallowPictureInPicture> scoped_disallow_picture_in_picture_; + + // When not null, this tucks picture-in-picture windows out of the way. + std::unique_ptr<ScopedTuckPictureInPicture> scoped_tuck_picture_in_picture_; #endif // !BUILDFLAG(IS_ANDROID) #if BUILDFLAG(IS_CHROMEOS)
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index 50ecb6f..18c0763 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -5424,10 +5424,6 @@ const char kHistoryPaneAndroidDescription[] = "Enables showing a new pane in the hub that displays History."; -const char kTabGroupSyncAndroidName[] = "Tab Group Sync on Android"; -const char kTabGroupSyncAndroidDescription[] = - "Enables syncing of tab groups on Android with other devices."; - const char kTabGroupSyncDisableNetworkLayerName[] = "Tab Group Sync Disable Network Layer"; const char kTabGroupSyncDisableNetworkLayerDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index ab1e927c..016d068b 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -3183,9 +3183,6 @@ extern const char kTabGroupsForTabletsName[]; extern const char kTabGroupsForTabletsDescription[]; -extern const char kTabGroupSyncAndroidName[]; -extern const char kTabGroupSyncAndroidDescription[]; - extern const char kTabGroupSyncDisableNetworkLayerName[]; extern const char kTabGroupSyncDisableNetworkLayerDescription[];
diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc index 7f3a6628..ccfed8d 100644 --- a/chrome/browser/flags/android/chrome_feature_list.cc +++ b/chrome/browser/flags/android/chrome_feature_list.cc
@@ -250,6 +250,7 @@ &kCCTExtendTrustedCdnPublisher, &kCCTEphemeralMediaViewerExperiment, &kCCTEphemeralMode, + &kCCTFixWarmup, &kCCTFreInSameTask, &kCCTIncognitoAvailableToThirdParty, &kCCTIntentFeatureOverrides, @@ -458,8 +459,6 @@ &syncer::kWebApkBackupAndRestoreBackend, &syncer::kUnoPhase2FollowUp, &syncer::kSyncEnablePasswordsSyncErrorMessageAlternative, - &tab_groups::kTabGroupSyncAndroid, - &tab_groups::kTabGroupSyncAutoOpenKillSwitch, &tab_groups::kUseAlternateHistorySyncIllustration, &visited_url_ranking::features::kGroupSuggestionService, &visited_url_ranking::features::kVisitedURLRankingService, @@ -742,6 +741,8 @@ "CCTExtendTrustedCdnPublisher", base::FEATURE_ENABLED_BY_DEFAULT); +BASE_FEATURE(kCCTFixWarmup, "CCTFixWarmup", base::FEATURE_DISABLED_BY_DEFAULT); + BASE_FEATURE(kCCTFreInSameTask, "CCTFreInSameTask", base::FEATURE_ENABLED_BY_DEFAULT); @@ -1093,7 +1094,7 @@ BASE_FEATURE(kPowerSavingModeBroadcastReceiverInBackground, "PowerSavingModeBroadcastReceiverInBackground", - base::FEATURE_DISABLED_BY_DEFAULT); + base::FEATURE_ENABLED_BY_DEFAULT); BASE_FEATURE(kPreconnectOnTabCreation, "PreconnectOnTabCreation",
diff --git a/chrome/browser/flags/android/chrome_feature_list.h b/chrome/browser/flags/android/chrome_feature_list.h index 463bccf..e4ca705 100644 --- a/chrome/browser/flags/android/chrome_feature_list.h +++ b/chrome/browser/flags/android/chrome_feature_list.h
@@ -84,6 +84,7 @@ BASE_DECLARE_FEATURE(kCCTEphemeralMediaViewerExperiment); BASE_DECLARE_FEATURE(kCCTEphemeralMode); BASE_DECLARE_FEATURE(kCCTExtendTrustedCdnPublisher); +BASE_DECLARE_FEATURE(kCCTFixWarmup); BASE_DECLARE_FEATURE(kCCTFreInSameTask); BASE_DECLARE_FEATURE(kCCTIncognitoAvailableToThirdParty); BASE_DECLARE_FEATURE(kCCTIntentFeatureOverrides);
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 98595f0f..34bf2e1 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
@@ -295,6 +295,7 @@ "CCTEphemeralMediaViewerExperiment"; public static final String CCT_EPHEMERAL_MODE = "CCTEphemeralMode"; public static final String CCT_EXTEND_TRUSTED_CDN_PUBLISHER = "CCTExtendTrustedCdnPublisher"; + public static final String CCT_FIX_WARMUP = "CCTFixWarmup"; public static final String CCT_FRE_IN_SAME_TASK = "CCTFreInSameTask"; public static final String CCT_GOOGLE_BOTTOM_BAR = "CCTGoogleBottomBar"; public static final String CCT_GOOGLE_BOTTOM_BAR_VARIANT_LAYOUTS = @@ -593,9 +594,6 @@ public static final String TAB_GROUP_ENTRY_POINTS_ANDROID = "TabGroupEntryPointsAndroid"; public static final String TAB_GROUP_PARITY_BOTTOM_SHEET_ANDROID = "TabGroupParityBottomSheetAndroid"; - public static final String TAB_GROUP_SYNC_ANDROID = "TabGroupSyncAndroid"; - public static final String TAB_GROUP_SYNC_AUTO_OPEN_KILL_SWITCH = - "TabGroupSyncAutoOpenKillSwitch"; public static final String TABLET_TAB_STRIP_ANIMATION = "TabletTabStripAnimation"; public static final String TAB_STATE_FLAT_BUFFER = "TabStateFlatBuffer"; public static final String TAB_STRIP_CONTEXT_MENU = "TabStripContextMenuAndroid"; @@ -679,7 +677,10 @@ public static final CachedFlag sAndroidMinimalUiLargeScreen = newCachedFlag(ANDROID_MINIMAL_UI_LARGE_SCREEN, false, true); public static final CachedFlag sAndroidProgressBarVisualUpdate = - newCachedFlag(ANDROID_PROGRESS_BAR_VISUAL_UPDATE, false); + newCachedFlag( + ANDROID_PROGRESS_BAR_VISUAL_UPDATE, + /* defaultValue= */ false, + /* defaultValueInTests= */ true); public static final CachedFlag sAndroidSurfaceColorUpdate = newCachedFlag( ANDROID_SURFACE_COLOR_UPDATE, @@ -728,6 +729,9 @@ /* defaultValue= */ false, /* defaultValueInTests= */ true); public static final CachedFlag sCctEphemeralMode = newCachedFlag(CCT_EPHEMERAL_MODE, true); + public static final CachedFlag sCctFixWarmup = + newCachedFlag(CCT_FIX_WARMUP, /* defaultValue= */ false, + /* defaultValueInTests= */ true); public static final CachedFlag sCctFreInSameTask = newCachedFlag(CCT_FRE_IN_SAME_TASK, true); public static final CachedFlag sCctGoogleBottomBar = newCachedFlag( @@ -886,10 +890,7 @@ public static final CachedFlag sPostGetMyMemoryStateToBackground = newCachedFlag(POST_GET_MEMORY_PRESSURE_TO_BACKGROUND, true); public static final CachedFlag sPowerSavingModeBroadcastReceiverInBackground = - newCachedFlag( - POWER_SAVING_MODE_BROADCAST_RECEIVER_IN_BACKGROUND, - /* defaultValue= */ false, - /* defaultValueInTests= */ true); + newCachedFlag(POWER_SAVING_MODE_BROADCAST_RECEIVER_IN_BACKGROUND, true); public static final CachedFlag sPrefetchBrowserInitiatedTriggers = newCachedFlag(PREFETCH_BROWSER_INITIATED_TRIGGERS, true); public static final CachedFlag sPriceChangeModule = newCachedFlag(PRICE_CHANGE_MODULE, true); @@ -1003,6 +1004,7 @@ sCctBlockTouchesDuringEnterAnimation, sCctEphemeralMediaViewerExperiment, sCctEphemeralMode, + sCctFixWarmup, sCctFreInSameTask, sCctGoogleBottomBar, sCctGoogleBottomBarVariantLayouts, @@ -1271,10 +1273,6 @@ public static final BooleanCachedFeatureParam sAndroidBottomToolbarDefaultToTop = newBooleanCachedFeatureParam(ANDROID_BOTTOM_TOOLBAR, "default_to_top", true); - public static final StringCachedFeatureParam sAndroidComposeplateButtonUrl = - newStringCachedFeatureParam( - ANDROID_COMPOSEPLATE, "composeplate_button_url", "about:blank"); - public static final IntCachedFeatureParam sBackgroundThreadPoolFieldTrialConfig = newIntCachedFeatureParam(BACKGROUND_THREAD_POOL_FIELD_TRIAL, "config", 0); @@ -1594,7 +1592,6 @@ sAndroidAppIntegrationWithFaviconUseLargeFavicon, sAndroidAppIntegrationWithFaviconZeroStateFaviconNumber, sAndroidBottomToolbarDefaultToTop, - sAndroidComposeplateButtonUrl, sAndroidThemeModuleForceDependencies, sBackgroundThreadPoolFieldTrialConfig, sBatchTabRestoreBatchSize,
diff --git a/chrome/browser/google/google_brand_code_map_chromeos.cc b/chrome/browser/google/google_brand_code_map_chromeos.cc index de6ff148..aa6472c 100644 --- a/chrome/browser/google/google_brand_code_map_chromeos.cc +++ b/chrome/browser/google/google_brand_code_map_chromeos.cc
@@ -95,8 +95,10 @@ {"BDXJ", {"EWPX", "PXLS", "LPDD"}}, {"BERK", {"MKYF", "PKIJ", "KXBI"}}, {"BFAP", {"YPGH", "EZCK", "XGCO"}}, + {"BFCK", {"RERZ", "YCTE", "HQBW"}}, {"BKLL", {"DJXO", "KLUN", "DJNO"}}, {"BKQW", {"PGZL", "EJCE", "GQZS"}}, + {"BLUP", {"CUHP", "OBBJ", "XCVD"}}, {"BLXA", {"VLID", "JNUQ", "IKRB"}}, {"BMAD", {"HGZG", "AOPW", "RIVV"}}, {"BMNE", {"HLSA", "WXJQ", "TULR"}}, @@ -157,9 +159,11 @@ {"DUKI", {"FRGD", "SACE", "AAMW"}}, {"DUSQ", {"SCAG", "PXPE", "ABVO"}}, {"DUYG", {"TXYR", "CTVK", "MOYF"}}, + {"DVQN", {"NEMQ", "YJNN", "YHDD"}}, {"DVUG", {"HJHV", "KPAH", "DCQS"}}, {"DWCY", {"ZJQH", "JLCB", "QOAI"}}, {"DWSH", {"MGOR", "DWKX", "FBNY"}}, + {"DXJQ", {"MRUB", "AYVH", "RPTE"}}, {"DXVL", {"EBBY", "NMQL", "GTHA"}}, {"DXZT", {"WNSK", "WNDA", "DZWQ"}}, {"DYHT", {"YPAH", "NUKA", "EULJ"}}, @@ -204,6 +208,7 @@ {"FYEL", {"WSGO", "YYQV", "OWPY"}}, {"FYSO", {"HFDH", "WNPK", "ZTIK"}}, {"GBAV", {"FGCQ", "ENQH", "YLYR"}}, + {"GBTW", {"AWVL", "ZQWT", "RKMB"}}, {"GBWE", {"DKLE", "OUDI", "VWJC"}}, {"GBXM", {"ONLL", "YBJS", "SOVT"}}, {"GFMQ", {"DRLH", "HVWY", "OYYM"}}, @@ -238,6 +243,7 @@ {"HEXN", {"KMII", "PFZL", "RKZB"}}, {"HFAN", {"ZQNI", "RPSS", "VFHT"}}, {"HFKU", {"ILOF", "UXKA", "JQLI"}}, + {"HFQQ", {"ONPZ", "JNXK", "MVKD"}}, {"HFRG", {"YGYA", "IWET", "PSFN"}}, {"HGNV", {"NAFX", "USJN", "IQQJ"}}, {"HHRN", {"IGZW", "ICRP", "QQKJ"}}, @@ -339,6 +345,7 @@ {"KRTE", {"ILKK", "GNTB", "XFRA"}}, {"KTCO", {"CWKY", "KVCK", "MRJR"}}, {"KTLR", {"LCPY", "XBHO", "UZEJ"}}, + {"KVMZ", {"BKRZ", "AAMB", "NVNR"}}, {"KXUH", {"RIFT", "DZUO", "ZSEI"}}, {"KYVC", {"HWSA", "QAUI", "MMWP"}}, {"KYYP", {"PGTZ", "VRVC", "HDRK"}}, @@ -448,15 +455,18 @@ {"MDPZ", {"AHBA", "ENTF", "IIMC"}}, {"MEXL", {"JFMC", "LBVP", "DERH"}}, {"MEZV", {"FHLD", "UMYC", "QTUB"}}, + {"MHKF", {"FLXO", "JPQQ", "JMHN"}}, {"MLST", {"KBQX", "PEPX", "UGKW"}}, {"MMLE", {"YFDA", "YZRA", "EKCE"}}, {"MNFK", {"BFMJ", "APMV", "LPJQ"}}, {"MNQW", {"LCRH", "YVGU", "SJID"}}, {"MNZG", {"PPTP", "OFXE", "ROJJ"}}, {"MOIP", {"HCCZ", "PXCU", "MROE"}}, + {"MPMQ", {"AOST", "AJXV", "ROSR"}}, {"MQJY", {"FXNF", "HLWS", "YBMY"}}, {"MQUZ", {"MFAZ", "GBNW", "MRMS"}}, {"MRFF", {"VHZM", "CBXS", "WHGR"}}, + {"MTIA", {"FTVF", "DXNM", "GQPV"}}, {"MTYQ", {"ZGPO", "WDIP", "IBCS"}}, {"MXEQ", {"EKJV", "UWUR", "CPES"}}, {"MXUY", {"IRZH", "ADQR", "PCST"}}, @@ -477,6 +487,7 @@ {"NOMD", {"GZLV", "UNZR", "FVOP"}}, {"NPEC", {"BMGD", "YETH", "XAWJ"}}, {"NPXS", {"NTUT", "GHMK", "GQRP"}}, + {"NSSJ", {"LTOP", "PHLY", "EAUH"}}, {"NSXI", {"VYQS", "HGFQ", "SLFL"}}, {"NTBE", {"ARRB", "AELU", "HGEA"}}, {"NZRH", {"NOUG", "UDYG", "ZGAU"}}, @@ -496,6 +507,7 @@ {"OPNA", {"JDSG", "BCNO", "THKI"}}, {"OPUT", {"GXWE", "AYTE", "AWFR"}}, {"OQXD", {"PREP", "WHZV", "OPXS"}}, + {"OVGS", {"YEHA", "TIVU", "ZDHY"}}, {"OWAW", {"QWUQ", "YLVZ", "OHTJ"}}, {"OXAV", {"EMDD", "ODMX", "HRFR"}}, {"OYZI", {"WDBC", "NKZT", "QJZD"}}, @@ -539,6 +551,7 @@ {"QNDA", {"VFMY", "KTBL", "UOJY"}}, {"QOAX", {"ITAT", "RSMG", "IFBZ"}}, {"QPEQ", {"EHWX", "ROSZ", "MPXK"}}, + {"QPMG", {"EJOS", "ZVPP", "EKDI"}}, {"QQFU", {"ZUKV", "QBAU", "SIID"}}, {"QQKF", {"PRKZ", "BFPF", "WSQL"}}, {"QRII", {"NHZV", "AUJW", "NSZF"}}, @@ -572,6 +585,7 @@ {"RKRB", {"OPOY", "QMZZ", "FAGR"}}, {"RLGE", {"NTKV", "LOTA", "MJVG"}}, {"RNPH", {"TSIF", "ESCP", "GISR"}}, + {"ROVZ", {"HFRR", "AOVW", "VSIG"}}, {"ROZO", {"ZLVE", "PDAQ", "OYRW"}}, {"RPOG", {"DFCF", "QCSW", "HVUW"}}, {"RRAJ", {"GOMU", "UHWV", "NSSL"}},
diff --git a/chrome/browser/incognito/android/java/src/org/chromium/chrome/browser/incognito/reauth/IncognitoReauthControllerImpl.java b/chrome/browser/incognito/android/java/src/org/chromium/chrome/browser/incognito/reauth/IncognitoReauthControllerImpl.java index 57d240e..2f78f8e7 100644 --- a/chrome/browser/incognito/android/java/src/org/chromium/chrome/browser/incognito/reauth/IncognitoReauthControllerImpl.java +++ b/chrome/browser/incognito/android/java/src/org/chromium/chrome/browser/incognito/reauth/IncognitoReauthControllerImpl.java
@@ -127,7 +127,7 @@ // crash when accessing the pref. Therefore this callback is fired when the Profile is ready // which sets the |mProfile| and shows the re-auth dialog if required. private final Callback<Profile> mProfileSupplierCallback = - new Callback<Profile>() { + new Callback<>() { @Override public void onResult(Profile profile) { mProfile = profile;
diff --git a/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/AppLanguagePromoDialog.java b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/AppLanguagePromoDialog.java index 5464bb76..e950250e4 100644 --- a/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/AppLanguagePromoDialog.java +++ b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/AppLanguagePromoDialog.java
@@ -178,8 +178,8 @@ Collection<LanguageItem> topLanguages, Collection<LanguageItem> otherLanguages, LanguageItem currentLanguage) { - mTopLanguages = new ArrayList<LanguageItem>(topLanguages); - mOtherLanguages = new ArrayList<LanguageItem>(otherLanguages); + mTopLanguages = new ArrayList<>(topLanguages); + mOtherLanguages = new ArrayList<>(otherLanguages); mCurrentLanguage = currentLanguage; } @@ -390,7 +390,7 @@ languagesManager.getLanguageItem(AppLocaleUtils.getAppLanguagePref()); assert currentOverrideLanguage != null; LinkedHashSet<LanguageItem> uiLanguages = - new LinkedHashSet<LanguageItem>(languagesManager.getAllPossibleUiLanguages()); + new LinkedHashSet<>(languagesManager.getAllPossibleUiLanguages()); LinkedHashSet<LanguageItem> topLanguages = getTopLanguages(mProfile, uiLanguages, currentOverrideLanguage); uiLanguages.removeAll(topLanguages);
diff --git a/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/AppLocaleUtils.java b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/AppLocaleUtils.java index b965012..a03821a9 100644 --- a/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/AppLocaleUtils.java +++ b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/AppLocaleUtils.java
@@ -269,12 +269,12 @@ } /** - * Comparator that removes any country or script information from either language tag - * since they are not needed for locale availability checks. - * Example: "es-MX" and "es-ES" will evaluate as equal. + * Comparator that removes any country or script information from either language tag since they + * are not needed for locale availability checks. Example: "es-MX" and "es-ES" will evaluate as + * equal. */ private static final Comparator<String> BASE_LANGUAGE_COMPARATOR = - new Comparator<String>() { + new Comparator<>() { @Override public int compare(String a, String b) { String langA = LocaleUtils.toBaseLanguage(a);
diff --git a/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/FakeLanguageBridgeJni.java b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/FakeLanguageBridgeJni.java index e64f37a4..c07c992 100644 --- a/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/FakeLanguageBridgeJni.java +++ b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/FakeLanguageBridgeJni.java
@@ -14,7 +14,7 @@ private ArrayList<String> mULPLanguages; public FakeLanguageBridgeJni() { - mULPLanguages = new ArrayList<String>(); + mULPLanguages = new ArrayList<>(); } public void setULPLanguages(List<String> languageCodes) {
diff --git a/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/settings/LanguageItemListPreference.java b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/settings/LanguageItemListPreference.java index be065f1..fdf16505 100644 --- a/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/settings/LanguageItemListPreference.java +++ b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/settings/LanguageItemListPreference.java
@@ -76,7 +76,7 @@ private @Nullable String makeSummary() { if (mLanguageItemListDelegate == null) return null; int index = 0; - ArrayList<String> languageNames = new ArrayList<String>(); + ArrayList<String> languageNames = new ArrayList<>(); for (LanguageItem item : mLanguageItemListDelegate.getLanguageItems()) { if (++index > COLLECTION_SUMMARY_ITEM_LIMIT) break; languageNames.add(item.getDisplayName());
diff --git a/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/settings/LanguagesManager.java b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/settings/LanguagesManager.java index 77ca9de..2f3564d 100644 --- a/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/settings/LanguagesManager.java +++ b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/settings/LanguagesManager.java
@@ -211,11 +211,12 @@ /** * Get a list of LanguageItems that can be used as a Translate language but excluding * |codesToSkip|. The current Accept-Languages are added to the front of the list. + * * @param codesToSkip Collection of String language codes to exclude from the list. * @return List of LanguageItems. */ private List<LanguageItem> getPotentialTranslateLanguages(Collection<String> codesToSkip) { - HashSet<String> codesToSkipSet = new HashSet<String>(codesToSkip); + HashSet<String> codesToSkipSet = new HashSet<>(codesToSkip); LinkedHashSet<LanguageItem> results = new LinkedHashSet<>(); // Filter for translatable languages not in |codesToSkipSet|. Predicate<LanguageItem> filter =
diff --git a/chrome/browser/language/android/java/src/org/chromium/chrome/browser/translate/FakeTranslateBridgeJni.java b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/translate/FakeTranslateBridgeJni.java index 7501209..f3ffce18 100644 --- a/chrome/browser/language/android/java/src/org/chromium/chrome/browser/translate/FakeTranslateBridgeJni.java +++ b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/translate/FakeTranslateBridgeJni.java
@@ -45,7 +45,7 @@ Collection<String> neverLanguages, Collection<String> alwaysLanguages, String targetLanguage) { - mChromeLanguages = new TreeMap<String, LanguageItem>(); + mChromeLanguages = new TreeMap<>(); for (LanguageItem item : chromeLanguages) { mChromeLanguages.put(item.getDisplayName(), item); } @@ -58,7 +58,7 @@ /** Create a basic fake translate bridge with English as the default language. */ public FakeTranslateBridgeJni() { - mChromeLanguages = new TreeMap<String, LanguageItem>(); + mChromeLanguages = new TreeMap<>(); mUserAcceptLanguages = new ArrayList(Arrays.asList("en")); mDefaultUserAcceptLanguages = new LinkedHashSet(Arrays.asList("en")); mNeverLanguages = new HashSet(Arrays.asList("en"));
diff --git a/chrome/browser/lifetime/android/java/src/org/chromium/chrome/browser/lifetime/ApplicationLifetime.java b/chrome/browser/lifetime/android/java/src/org/chromium/chrome/browser/lifetime/ApplicationLifetime.java index 1fc92c1..e1d48a5 100644 --- a/chrome/browser/lifetime/android/java/src/org/chromium/chrome/browser/lifetime/ApplicationLifetime.java +++ b/chrome/browser/lifetime/android/java/src/org/chromium/chrome/browser/lifetime/ApplicationLifetime.java
@@ -21,10 +21,11 @@ void onTerminate(boolean restart); } - private static final ObserverList<Observer> sObservers = new ObserverList<Observer>(); + private static final ObserverList<Observer> sObservers = new ObserverList<>(); /** * Adds an observer to watch for application termination. + * * @param observer The observer to add. */ public static void addObserver(Observer observer) {
diff --git a/chrome/browser/metrics/startup_metrics_browsertest.cc b/chrome/browser/metrics/startup_metrics_browsertest.cc index 21e23a3..c28ebf1 100644 --- a/chrome/browser/metrics/startup_metrics_browsertest.cc +++ b/chrome/browser/metrics/startup_metrics_browsertest.cc
@@ -78,17 +78,15 @@ SCOPED_TRACE(histogram); // Continue if histograms was already recorded. - if (base::StatisticsRecorder::FindHistogram(histogram)) + if (base::StatisticsRecorder::FindHistogram(histogram)) { continue; + } // Else, wait until the histogram is recorded. base::RunLoop run_loop; auto histogram_observer = std::make_unique< base::StatisticsRecorder::ScopedHistogramSampleObserver>( - histogram, - base::BindLambdaForTesting( - [&](std::string_view histogram_name, uint64_t name_hash, - base::HistogramBase::Sample32 sample) { run_loop.Quit(); })); + histogram, run_loop.QuitClosure()); run_loop.Run(); } }
diff --git a/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/permissions/NotificationPermissionControllerTest.java b/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/permissions/NotificationPermissionControllerTest.java index a2d336c..1a65204 100644 --- a/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/permissions/NotificationPermissionControllerTest.java +++ b/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/permissions/NotificationPermissionControllerTest.java
@@ -66,7 +66,7 @@ @Rule public ActivityScenarioRule<TestActivity> mActivityScenarios = - new ActivityScenarioRule<TestActivity>(TestActivity.class); + new ActivityScenarioRule<>(TestActivity.class); private NotificationPermissionController createNotificationPermissionController( Activity activity) { @@ -384,7 +384,7 @@ TestRationaleDelegate rationaleDelegate = new TestRationaleDelegate(); TestAndroidPermissionDelegate permissionDelegate = new TestAndroidPermissionDelegate( - new WeakReference<Activity>(activity)); + new WeakReference<>(activity)); NotificationPermissionController notificationPermissionController = createNotificationPermissionController( rationaleDelegate, permissionDelegate);
diff --git a/chrome/browser/omaha/android/java/src/org/chromium/chrome/browser/omaha/XMLParser.java b/chrome/browser/omaha/android/java/src/org/chromium/chrome/browser/omaha/XMLParser.java index f568f0c..f1fc3f95 100644 --- a/chrome/browser/omaha/android/java/src/org/chromium/chrome/browser/omaha/XMLParser.java +++ b/chrome/browser/omaha/android/java/src/org/chromium/chrome/browser/omaha/XMLParser.java
@@ -37,8 +37,8 @@ public Node(@Nullable String tagName) { tag = tagName; - attributes = new HashMap<String, String>(); - children = new ArrayList<Node>(); + attributes = new HashMap<>(); + children = new ArrayList<>(); } } @@ -47,7 +47,7 @@ public XMLParser(String serverResponse) throws RequestFailureException { mRootNode = new Node(null); - mTagStack = new Stack<Node>(); + mTagStack = new Stack<>(); mTagStack.push(mRootNode); try {
diff --git a/chrome/browser/on_device_translation/on_device_translation_browsertest.cc b/chrome/browser/on_device_translation/on_device_translation_browsertest.cc index 53af467..52a5668 100644 --- a/chrome/browser/on_device_translation/on_device_translation_browsertest.cc +++ b/chrome/browser/on_device_translation/on_device_translation_browsertest.cc
@@ -65,23 +65,6 @@ namespace { -// Generated by: -// tools/origin_trials/generate_token.py --version 3 --expire-days 3650 \ -// https://translation-api.test TranslationAPI -// Token details: -// Version: 3 -// Origin: https://translation-api.test:443 -// Is Subdomain: None -// Is Third Party: None -// Usage Restriction: None -// Feature: TranslationAPI -// Expiry: 2045451101 (2034-10-26 04:51:41 UTC) -constexpr std::string_view kOriginTrialToken = - "Aydt1qwq7OUQa+NVUSW2n7PSlK9ukCz19p0IAah6P827eCHoiHUUks9mxWwyZd7tADQcEm3/eW" - "4K5+79dQUiOwIAAABheyJvcmlnaW4iOiAiaHR0cHM6Ly90cmFuc2xhdGlvbi1hcGkudGVzdDo0" - "NDMiLCAiZmVhdHVyZSI6ICJUcmFuc2xhdGlvbkFQSSIsICJleHBpcnkiOiAyMDQ1NDUxMTAxfQ" - "=="; - constexpr auto kLanguagePackKeys = base::MakeFixedFlatSet<LanguagePackKey>({ LanguagePackKey::kEn_Es, LanguagePackKey::kEn_Ja, LanguagePackKey::kAr_En, LanguagePackKey::kBn_En, @@ -2217,183 +2200,6 @@ EXPECT_EQ(TryCanTranslateInIframe(last_iframe), "available"); } -// Tests the behavior of the Origin Trial token for the Translation API. -class OnDeviceTranslationOriginTrialBrowserTest : public InProcessBrowserTest { - public: - OnDeviceTranslationOriginTrialBrowserTest() { - CHECK(tmp_dir_.CreateUniqueTempDir()); - } - ~OnDeviceTranslationOriginTrialBrowserTest() override = default; - - void SetUpCommandLine(base::CommandLine* command_line) override { - InProcessBrowserTest::SetUpCommandLine(command_line); - // Add the public key following: - // https://chromium.googlesource.com/chromium/src/+/HEAD/docs/origin_trials_integration.md#manual-testing. - command_line->AppendSwitchASCII( - "origin-trial-public-key", - "dRCs+TocuKkocNKa0AtZ4awrt9XKH2SQCI6o4FY6BNA="); - } - - void SetUpOnMainThread() override { - InProcessBrowserTest::SetUpOnMainThread(); - // Need to use URLLoaderInterceptor to test the behavior of Origin Trial. - url_loader_interceptor_.emplace(base::BindRepeating( - &OnDeviceTranslationOriginTrialBrowserTest::InterceptRequest)); - } - - void TearDownOnMainThread() override { url_loader_interceptor_.reset(); } - - protected: - const base::FilePath& GetTempDir() { return tmp_dir_.GetPath(); } - - // Injects the Origin Trial token into the page. - void InjectOriginTrialMetaTag() { - EXPECT_TRUE( - ExecJs(browser()->tab_strip_model()->GetActiveWebContents(), - base::StringPrintf(R"( - (() => { - const meta = document.createElement('meta'); - meta.httpEquiv = 'origin-trial'; - meta.content = '%s'; - document.head.appendChild(meta); - })() - )", - std::string(kOriginTrialToken).c_str()))); - } - - bool IsDefinedJs(std::string js_expression) { - return EvalJs(browser()->tab_strip_model()->GetActiveWebContents(), - base::StringPrintf("(%s) !== undefined", js_expression)) - .ExtractBool(); - } - - // Tests that `window.Translator.availability` and - // `window.Translator.availability` don't exist. - void ExpectAPIDisabled() { - if (!IsDefinedJs("window.Translator")) { - // `window.Translator` is not there, we're done. - return; - } - - // We expect to find the detection API but no translate API. - EXPECT_FALSE(IsDefinedJs("window.Translator.availability")); - EXPECT_FALSE(IsDefinedJs("window.Translator.create")); - } - - // Tests that `window.Translator.availability` and - // `window.Translator.availability` both exist. - void ExpectAPIEnabled() { - EXPECT_TRUE(IsDefinedJs("window.Translator")); - EXPECT_TRUE(IsDefinedJs("window.Translator.availability")); - EXPECT_TRUE(IsDefinedJs("window.Translator.create")); - } - - private: - // URLLoaderInterceptor callback - static bool InterceptRequest( - content::URLLoaderInterceptor::RequestParams* params) { - if (params->url_request.url.path() == "/blank.html") { - content::URLLoaderInterceptor::WriteResponse( - "HTTP/1.1 200 OK\nContent-Type: text/html; charset=utf-8\n\n", - "<body></body>", params->client.get(), - /*ssl_info=*/std::nullopt, params->url_request.url); - return true; - } else if (params->url_request.url.path() == "/ot_token_header.html") { - content::URLLoaderInterceptor::WriteResponse( - base::StrCat( - {"HTTP/1.1 200 OK\nContent-Type: text/html; charset=utf-8\n", - "Origin-Trial: ", kOriginTrialToken, "\n\n"}), - "<body></body>", params->client.get(), - /*ssl_info=*/std::nullopt, params->url_request.url); - return true; - } - return false; - } - - base::ScopedTempDir tmp_dir_; - std::optional<content::URLLoaderInterceptor> url_loader_interceptor_; -}; - -// Tests the behavior of the Origin Trial token meta tag for the Translation -// API. -IN_PROC_BROWSER_TEST_F(OnDeviceTranslationOriginTrialBrowserTest, - WithOriginTrialTokenMetaTag) { - MockComponentManager mock_component_manager(GetTempDir()); - CHECK(ui_test_utils::NavigateToURL( - browser(), GURL("https://translation-api.test/blank.html"))); - // The API is not available without the Origin Trial token. - ExpectAPIDisabled(); - // Inject the Origin Trial token into the page. - InjectOriginTrialMetaTag(); - // The API is available with the Origin Trial token. - ExpectAPIEnabled(); - - // Test the behavior of Translation API. - mock_component_manager.ExpectCallRegisterTranslateKitComponentAndInstall(); - mock_component_manager.ExpectCallRegisterLanguagePackComponentAndInstall( - {LanguagePackKey::kEn_Ja}); - TestSimpleTranslationWorks(browser(), "en", "ja"); -} - -// Tests the behavior of the Origin Trial token header for the Translation API. -IN_PROC_BROWSER_TEST_F(OnDeviceTranslationOriginTrialBrowserTest, - WithOriginTrialTokenHeader) { - MockComponentManager mock_component_manager(GetTempDir()); - // Navigate to the page with the Origin Trial token header. - CHECK(ui_test_utils::NavigateToURL( - browser(), GURL("https://translation-api.test/ot_token_header.html"))); - // The API is available when the Origin Trial token is in the header. - ExpectAPIEnabled(); - - // Test the behavior of Translation API. - mock_component_manager.ExpectCallRegisterTranslateKitComponentAndInstall(); - mock_component_manager.ExpectCallRegisterLanguagePackComponentAndInstall( - {LanguagePackKey::kEn_Ja}); - TestSimpleTranslationWorks(browser(), "en", "ja"); -} - -// Tests the behavior of the Origin Trial token when the kill switch is enabled. -class OnDeviceTranslationOriginTrialKillSwitchBrowserTest - : public OnDeviceTranslationOriginTrialBrowserTest { - public: - OnDeviceTranslationOriginTrialKillSwitchBrowserTest() { - // Disable the feature to enable the kill switch. - scoped_feature_list_.InitAndDisableFeature( - blink::features::kTranslationAPI); - } - ~OnDeviceTranslationOriginTrialKillSwitchBrowserTest() override = default; - - private: - base::test::ScopedFeatureList scoped_feature_list_; -}; - -// Tests the behavior of the Origin Trial token meta tag when the kill switch is -// enabled. -IN_PROC_BROWSER_TEST_F(OnDeviceTranslationOriginTrialKillSwitchBrowserTest, - WithOriginTrialTokenMetaTag) { - CHECK(ui_test_utils::NavigateToURL( - browser(), GURL("https://translation-api.test/blank.html"))); - // The API is not available when the kill switch is enabled. - ExpectAPIDisabled(); - // Inject the Origin Trial token into the page. - InjectOriginTrialMetaTag(); - // The API is not available when the kill switch is enabled even if the Origin - // Trial token is injected. - ExpectAPIDisabled(); -} - -// Tests the behavior of the Origin Trial token header when the kill switch is -// enabled. -IN_PROC_BROWSER_TEST_F(OnDeviceTranslationOriginTrialKillSwitchBrowserTest, - WithOriginTrialTokenHeader) { - // Navigate to the page with the Origin Trial token header. - CHECK(ui_test_utils::NavigateToURL( - browser(), GURL("https://translation-api.test/ot_token_header.html"))); - // The API is not available when the kill switch is enabled even if the Origin - // Trial token is in the header. - ExpectAPIDisabled(); -} - // Tests the behavior of when the command line flag "translate-kit-binary-path" // is provided. class OnDeviceTranslationBinaryPathCommandLineBrowserTest
diff --git a/chrome/browser/optimization_guide/android/java/src/org/chromium/chrome/browser/optimization_guide/OptimizationGuidePushNotificationManager.java b/chrome/browser/optimization_guide/android/java/src/org/chromium/chrome/browser/optimization_guide/OptimizationGuidePushNotificationManager.java index 4090b33..d93f7e63 100644 --- a/chrome/browser/optimization_guide/android/java/src/org/chromium/chrome/browser/optimization_guide/OptimizationGuidePushNotificationManager.java +++ b/chrome/browser/optimization_guide/android/java/src/org/chromium/chrome/browser/optimization_guide/OptimizationGuidePushNotificationManager.java
@@ -132,7 +132,7 @@ Iterator<String> cache_iter = cache.iterator(); - List<HintNotificationPayload> notifications = new ArrayList<HintNotificationPayload>(); + List<HintNotificationPayload> notifications = new ArrayList<>(); for (int i = 0; i < cache.size(); i++) { try { HintNotificationPayload payload = @@ -174,7 +174,7 @@ * types with overflowed caches are not included. */ public static List<OptimizationType> getOptTypesWithPushNotifications() { - List<OptimizationType> types = new ArrayList<OptimizationType>(); + List<OptimizationType> types = new ArrayList<>(); for (OptimizationType type : OptimizationType.values()) { Set<String> cache = ChromeSharedPreferences.getInstance().readStringSet(cacheKey(type)); if (cache != null && cache.size() > 0 && !checkForOverflow(cache)) { @@ -188,7 +188,7 @@ * Returns a list of all the optimization types that overflowed their push notification caches. */ public static List<OptimizationType> getOptTypesThatOverflowedPushNotifications() { - List<OptimizationType> overflows = new ArrayList<OptimizationType>(); + List<OptimizationType> overflows = new ArrayList<>(); for (OptimizationType type : OptimizationType.values()) { if (checkForOverflow(getStringCacheForOptimizationType(type))) { overflows.add(type);
diff --git a/chrome/browser/optimization_guide/android/java/src/org/chromium/chrome/browser/optimization_guide/OptimizationGuidePushNotificationManagerUnitTest.java b/chrome/browser/optimization_guide/android/java/src/org/chromium/chrome/browser/optimization_guide/OptimizationGuidePushNotificationManagerUnitTest.java index 807f656..4bb6876a 100644 --- a/chrome/browser/optimization_guide/android/java/src/org/chromium/chrome/browser/optimization_guide/OptimizationGuidePushNotificationManagerUnitTest.java +++ b/chrome/browser/optimization_guide/android/java/src/org/chromium/chrome/browser/optimization_guide/OptimizationGuidePushNotificationManagerUnitTest.java
@@ -92,7 +92,7 @@ OptimizationGuidePushNotificationManager.onPushNotification(NOTIFICATION_WITH_PAYLOAD); Assert.assertEquals( - new ArrayList<OptimizationType>(), + new ArrayList<>(), OptimizationGuidePushNotificationManager .getOptTypesThatOverflowedPushNotifications()); @@ -138,7 +138,7 @@ Assert.assertEquals(0, cached.length); Assert.assertEquals( - new ArrayList<OptimizationType>(), + new ArrayList<>(), OptimizationGuidePushNotificationManager.getOptTypesWithPushNotifications()); verify(mOptimizationGuideBridge, times(1)) @@ -153,7 +153,7 @@ OptimizationGuidePushNotificationManager.onPushNotification(NOTIFICATION_WITH_PAYLOAD); Assert.assertEquals( - new ArrayList<OptimizationType>(), + new ArrayList<>(), OptimizationGuidePushNotificationManager .getOptTypesThatOverflowedPushNotifications()); @@ -164,7 +164,7 @@ Assert.assertEquals(0, cached.length); Assert.assertEquals( - new ArrayList<OptimizationType>(), + new ArrayList<>(), OptimizationGuidePushNotificationManager.getOptTypesWithPushNotifications()); } @@ -216,7 +216,7 @@ .length); Assert.assertEquals( - new ArrayList<OptimizationType>(), + new ArrayList<>(), OptimizationGuidePushNotificationManager.getOptTypesWithPushNotifications()); } @@ -232,7 +232,7 @@ for (int i = 1; i <= overflowSize; i++) { Assert.assertEquals( String.format("Iteration %d", i), - new ArrayList<OptimizationType>(), + new ArrayList<>(), OptimizationGuidePushNotificationManager .getOptTypesThatOverflowedPushNotifications()); OptimizationGuidePushNotificationManager.onPushNotification( @@ -252,7 +252,7 @@ Assert.assertNull(cached); Assert.assertEquals( - new ArrayList<OptimizationType>(), + new ArrayList<>(), OptimizationGuidePushNotificationManager.getOptTypesWithPushNotifications()); OptimizationGuidePushNotificationManager.clearCacheForOptimizationType( @@ -264,7 +264,7 @@ Assert.assertEquals(0, cached.length); Assert.assertEquals( - new ArrayList<OptimizationType>(), + new ArrayList<>(), OptimizationGuidePushNotificationManager.getOptTypesWithPushNotifications()); } @@ -278,7 +278,7 @@ } Assert.assertEquals( - new ArrayList<OptimizationType>(), + new ArrayList<>(), OptimizationGuidePushNotificationManager .getOptTypesThatOverflowedPushNotifications()); @@ -324,7 +324,7 @@ Assert.assertEquals(0, cached.length); Assert.assertEquals( - new ArrayList<OptimizationType>(), + new ArrayList<>(), OptimizationGuidePushNotificationManager.getOptTypesWithPushNotifications()); } @@ -395,7 +395,7 @@ .writeStringSet( OptimizationGuidePushNotificationManager.cacheKey( OptimizationType.PERFORMANCE_HINTS), - new HashSet<String>( + new HashSet<>( Arrays.asList( Base64.encodeToString( new byte[] {1, 2, 3}, Base64.DEFAULT)))); @@ -433,7 +433,7 @@ .writeStringSet( OptimizationGuidePushNotificationManager.cacheKey( OptimizationType.PERFORMANCE_HINTS), - new HashSet<String>(Arrays.asList("="))); + new HashSet<>(Arrays.asList("="))); HintNotificationPayload[] cached = OptimizationGuidePushNotificationManager.getNotificationCacheForOptimizationType(
diff --git a/chrome/browser/optimization_guide/hints_fetcher_browsertest.cc b/chrome/browser/optimization_guide/hints_fetcher_browsertest.cc index ef90d61..f39e72d 100644 --- a/chrome/browser/optimization_guide/hints_fetcher_browsertest.cc +++ b/chrome/browser/optimization_guide/hints_fetcher_browsertest.cc
@@ -1865,16 +1865,8 @@ identity_test_env_adaptor_; }; -// TODO(crbug.com/423415283): Re-enable this test -#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) -#define MAYBE_HintsFetcherFetchesWithAccessToken \ - DISABLED_HintsFetcherFetchesWithAccessToken -#else -#define MAYBE_HintsFetcherFetchesWithAccessToken \ - HintsFetcherFetchesWithAccessToken -#endif IN_PROC_BROWSER_TEST_F(ProactivePersonalizationHintsFetcherBrowserTest, - MAYBE_HintsFetcherFetchesWithAccessToken) { + OnNavigationFetchesWithAccessToken) { SetNetworkConnectionOnline(); SetResponseType( optimization_guide::HintsFetcherRemoteResponseType::kSuccessful); @@ -1882,18 +1874,20 @@ ResetCountHintsRequestsReceived(); EnableSignin(); SetExpectedBearerAccessToken("Bearer access_token"); - ASSERT_TRUE( - ui_test_utils::NavigateToURL(browser(), search_results_page_url())); - base::flat_set<std::string> srp_request; - srp_request.insert(GURL(search_results_page_url()).host()); - srp_request.insert(GURL(search_results_page_url()).spec()); - SetExpectedHintsRequestForHostsAndUrls(srp_request); + GURL full_url = GURL("https://foo.com/test/"); + ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), full_url)); + + base::flat_set<std::string> expected_request; + expected_request.insert(full_url.host()); + expected_request.insert(full_url.spec()); + SetExpectedHintsRequestForHostsAndUrls(expected_request); EXPECT_EQ(1u, count_hints_requests_received()); } class ProactivePersonalizationHintsWrongOptimizationTypeFetcherBrowserTest : public ProactivePersonalizationHintsFetcherBrowserTest { + public: base::FieldTrialParams GetFieldTrialParams() override { return { {"allowed_optimization_types", "PERFORMANCE_HINTS"}, @@ -1901,17 +1895,9 @@ } }; -// TODO(crbug.com/423415283): Re-enable this test -#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) -#define MAYBE_HintsFetcherDoesNotFetchAccessToken \ - DISABLED_HintsFetcherDoesNotFetchAccessToken -#else -#define MAYBE_HintsFetcherDoesNotFetchAccessToken \ - HintsFetcherDoesNotFetchAccessToken -#endif IN_PROC_BROWSER_TEST_F( ProactivePersonalizationHintsWrongOptimizationTypeFetcherBrowserTest, - MAYBE_HintsFetcherDoesNotFetchAccessToken) { + OnNavigationDoesNotFetchAccessToken) { SetNetworkConnectionOnline(); SetResponseType( optimization_guide::HintsFetcherRemoteResponseType::kSuccessful); @@ -1919,12 +1905,13 @@ ResetCountHintsRequestsReceived(); EnableSignin(); SetExpectedBearerAccessToken(std::string()); - ASSERT_TRUE( - ui_test_utils::NavigateToURL(browser(), search_results_page_url())); - base::flat_set<std::string> srp_request; - srp_request.insert(GURL(search_results_page_url()).host()); - srp_request.insert(GURL(search_results_page_url()).spec()); - SetExpectedHintsRequestForHostsAndUrls(srp_request); + GURL full_url = GURL("https://foo.com/test/"); + ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), full_url)); + + base::flat_set<std::string> expected_request; + expected_request.insert(full_url.host()); + expected_request.insert(full_url.spec()); + SetExpectedHintsRequestForHostsAndUrls(expected_request); EXPECT_EQ(1u, count_hints_requests_received()); }
diff --git a/chrome/browser/os_crypt/app_bound_encryption_win_browsertest.cc b/chrome/browser/os_crypt/app_bound_encryption_win_browsertest.cc index fc50de1..bf64554f 100644 --- a/chrome/browser/os_crypt/app_bound_encryption_win_browsertest.cc +++ b/chrome/browser/os_crypt/app_bound_encryption_win_browsertest.cc
@@ -60,17 +60,15 @@ void WaitForHistogram(const std::string& histogram_name) { // Continue if histogram was already recorded. - if (base::StatisticsRecorder::FindHistogram(histogram_name)) + if (base::StatisticsRecorder::FindHistogram(histogram_name)) { return; + } // Else, wait until the histogram is recorded. base::RunLoop run_loop; auto histogram_observer = std::make_unique<base::StatisticsRecorder::ScopedHistogramSampleObserver>( - histogram_name, - base::BindLambdaForTesting( - [&](std::string_view histogram_name, uint64_t name_hash, - base::HistogramBase::Sample32 sample) { run_loop.Quit(); })); + histogram_name, run_loop.QuitClosure()); run_loop.Run(); }
diff --git a/chrome/browser/partnerbookmarks/android/java/src/org/chromium/chrome/browser/partnerbookmarks/PartnerBookmarksReader.java b/chrome/browser/partnerbookmarks/android/java/src/org/chromium/chrome/browser/partnerbookmarks/PartnerBookmarksReader.java index adcef3f..603de97 100644 --- a/chrome/browser/partnerbookmarks/android/java/src/org/chromium/chrome/browser/partnerbookmarks/PartnerBookmarksReader.java +++ b/chrome/browser/partnerbookmarks/android/java/src/org/chromium/chrome/browser/partnerbookmarks/PartnerBookmarksReader.java
@@ -289,7 +289,7 @@ } // Get a snapshot of the bookmarks. - LinkedHashMap<Long, PartnerBookmark> idMap = new LinkedHashMap<Long, PartnerBookmark>(); + LinkedHashMap<Long, PartnerBookmark> idMap = new LinkedHashMap<>(); HashSet<String> urlSet = new HashSet<>(); PartnerBookmark rootBookmarksFolder = createRootBookmarksFolderBookmark();
diff --git a/chrome/browser/partnercustomizations/java/src/org/chromium/chrome/browser/partnercustomizations/PartnerBrowserCustomizations.java b/chrome/browser/partnercustomizations/java/src/org/chromium/chrome/browser/partnercustomizations/PartnerBrowserCustomizations.java index 94d13b55..5567b101 100644 --- a/chrome/browser/partnercustomizations/java/src/org/chromium/chrome/browser/partnercustomizations/PartnerBrowserCustomizations.java +++ b/chrome/browser/partnercustomizations/java/src/org/chromium/chrome/browser/partnercustomizations/PartnerBrowserCustomizations.java
@@ -201,7 +201,7 @@ mIsInitialized = false; // Setup an initializing async task. final AsyncTask<Void> initializeAsyncTask = - new AsyncTask<Void>() { + new AsyncTask<>() { private boolean mHomepageUriChanged; @Override
diff --git a/chrome/browser/password_check/android/java/src/org/chromium/chrome/browser/password_check/CompromisedCredential.java b/chrome/browser/password_check/android/java/src/org/chromium/chrome/browser/password_check/CompromisedCredential.java index 7b1ad80..1b3fd81 100644 --- a/chrome/browser/password_check/android/java/src/org/chromium/chrome/browser/password_check/CompromisedCredential.java +++ b/chrome/browser/password_check/android/java/src/org/chromium/chrome/browser/password_check/CompromisedCredential.java
@@ -23,7 +23,7 @@ public class CompromisedCredential implements Parcelable { /** This static member is required to automagically deserialize credential parcels . */ public static final Parcelable.Creator<CompromisedCredential> CREATOR = - new Parcelable.Creator<CompromisedCredential>() { + new Parcelable.Creator<>() { @Override public CompromisedCredential createFromParcel(Parcel in) { final String signonRealm = in.readString();
diff --git a/chrome/browser/password_entry_edit/android/internal/java/src/org/chromium/chrome/browser/password_entry_edit/CredentialEditViewTest.java b/chrome/browser/password_entry_edit/android/internal/java/src/org/chromium/chrome/browser/password_entry_edit/CredentialEditViewTest.java index db0f3525..ebcbf18 100644 --- a/chrome/browser/password_entry_edit/android/internal/java/src/org/chromium/chrome/browser/password_entry_edit/CredentialEditViewTest.java +++ b/chrome/browser/password_entry_edit/android/internal/java/src/org/chromium/chrome/browser/password_entry_edit/CredentialEditViewTest.java
@@ -213,7 +213,7 @@ * @return The matcher checking the input type. */ private static Matcher<EditText> isVisiblePasswordInput(boolean shouldBeVisible) { - return new BaseMatcher<EditText>() { + return new BaseMatcher<>() { @Override public boolean matches(Object o) { EditText editText = (EditText) o;
diff --git a/chrome/browser/password_manager/android/add_username_dialog/java/src/org/chromium/chrome/browser/add_username_dialog/AddUsernameDialogBridgeTest.java b/chrome/browser/password_manager/android/add_username_dialog/java/src/org/chromium/chrome/browser/add_username_dialog/AddUsernameDialogBridgeTest.java index 16dc038..75cec0a7 100644 --- a/chrome/browser/password_manager/android/add_username_dialog/java/src/org/chromium/chrome/browser/add_username_dialog/AddUsernameDialogBridgeTest.java +++ b/chrome/browser/password_manager/android/add_username_dialog/java/src/org/chromium/chrome/browser/add_username_dialog/AddUsernameDialogBridgeTest.java
@@ -10,8 +10,6 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import android.content.Context; - import androidx.appcompat.app.AppCompatActivity; import org.junit.Before; @@ -70,7 +68,7 @@ @Test public void testDialogIsDismissedFromNative() { when(mWindowAndroid.getModalDialogManager()).thenReturn(mModalDialogManager); - when(mWindowAndroid.getContext()).thenReturn(new WeakReference<Context>(createActivity())); + when(mWindowAndroid.getContext()).thenReturn(new WeakReference<>(createActivity())); mBridge.showAddUsernameDialog("username"); assertThat(mModalDialogManager.getShownDialogModel()).isNotNull();
diff --git a/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordManagerHandlerProvider.java b/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordManagerHandlerProvider.java index 9fd76ab6..1b5da0ff5 100644 --- a/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordManagerHandlerProvider.java +++ b/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordManagerHandlerProvider.java
@@ -46,8 +46,7 @@ // This class is itself a PasswordListObserver, listening directly to a PasswordManagerHandler // implementation. But it also keeps a list of other observers, to which it forwards the events. - private final ObserverList<PasswordListObserver> mObservers = - new ObserverList<PasswordListObserver>(); + private final ObserverList<PasswordListObserver> mObservers = new ObserverList<>(); private PasswordManagerHandlerProvider(Profile profile) { mProfile = profile;
diff --git a/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PostPasswordMigrationSheetCoordinatorFactoryTest.java b/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PostPasswordMigrationSheetCoordinatorFactoryTest.java index 6619eb24..f04774f8 100644 --- a/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PostPasswordMigrationSheetCoordinatorFactoryTest.java +++ b/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PostPasswordMigrationSheetCoordinatorFactoryTest.java
@@ -43,7 +43,7 @@ @Before public void setUp() { Context context = RuntimeEnvironment.application.getApplicationContext(); - WeakReference<Context> weakContext = new WeakReference<Context>(context); + WeakReference<Context> weakContext = new WeakReference<>(context); when(mWindowAndroid.getContext()).thenReturn(weakContext); mPostPasswordMigrationSheetCoordinator = new PostPasswordMigrationSheetCoordinator( @@ -61,7 +61,7 @@ @Test public void testmaybeGetOrCreateReturnsNullWhenContextIsNull() { - when(mWindowAndroid.getContext()).thenReturn(new WeakReference<Context>(null)); + when(mWindowAndroid.getContext()).thenReturn(new WeakReference<>(null)); assertNull( PostPasswordMigrationSheetCoordinatorFactory .maybeGetOrCreatePostPasswordMigrationSheetCoordinator(
diff --git a/chrome/browser/password_manager/android/test_support/java/src/org/chromium/chrome/browser/password_manager/FakePasswordManagerHandler.java b/chrome/browser/password_manager/android/test_support/java/src/org/chromium/chrome/browser/password_manager/FakePasswordManagerHandler.java index 7e0de7d..6f187c6 100644 --- a/chrome/browser/password_manager/android/test_support/java/src/org/chromium/chrome/browser/password_manager/FakePasswordManagerHandler.java +++ b/chrome/browser/password_manager/android/test_support/java/src/org/chromium/chrome/browser/password_manager/FakePasswordManagerHandler.java
@@ -23,7 +23,7 @@ private final PasswordListObserver mObserver; // The faked contents of the password store to be displayed. - private ArrayList<SavedPasswordEntry> mSavedPasswords = new ArrayList<SavedPasswordEntry>(); + private ArrayList<SavedPasswordEntry> mSavedPasswords = new ArrayList<>(); // The faked contents of the saves password exceptions to be displayed. private ArrayList<String> mSavedPasswordExeptions = new ArrayList<>();
diff --git a/chrome/browser/permissions/prediction_based_permission_ui_selector.cc b/chrome/browser/permissions/prediction_based_permission_ui_selector.cc index 1aa0f9bb..1dc82b2c 100644 --- a/chrome/browser/permissions/prediction_based_permission_ui_selector.cc +++ b/chrome/browser/permissions/prediction_based_permission_ui_selector.cc
@@ -294,8 +294,9 @@ << static_cast<int>(relevance.value()); last_permission_request_relevance_ = relevance.value(); features.permission_relevance = relevance.value(); - base::UmaHistogramEnumeration("Permissions.AIv3.PermissionRequestRelevance", - features.permission_relevance); + + PermissionUmaUtil::RecordPermissionRequestRelevance( + request_metadata.request_type, features.permission_relevance, "AIv3"); } else { last_permission_request_relevance_ = PermissionRequestRelevance::kUnspecified; @@ -531,7 +532,7 @@ } features.permission_relevance = last_permission_request_relevance_.value(); PermissionUmaUtil::RecordPermissionRequestRelevance( - features.permission_relevance); + request_metadata.request_type, features.permission_relevance, "AIv1"); InquireServerModel(features, std::move(request_metadata), /*record_source=*/!response.has_value()); }
diff --git a/chrome/browser/picture_in_picture/BUILD.gn b/chrome/browser/picture_in_picture/BUILD.gn index 3d018a9..3e2eb8a 100644 --- a/chrome/browser/picture_in_picture/BUILD.gn +++ b/chrome/browser/picture_in_picture/BUILD.gn
@@ -36,9 +36,11 @@ "picture_in_picture_occlusion_observer.h", "picture_in_picture_occlusion_tracker.h", "picture_in_picture_occlusion_tracker_observer.h", + "picture_in_picture_window.h", "picture_in_picture_window_manager_uma_helper.h", "scoped_disallow_picture_in_picture.h", "scoped_picture_in_picture_occlusion_observation.h", + "scoped_tuck_picture_in_picture.h", ] public_deps += [ "//chrome/browser/ui/tabs:tab_strip_model_observer", @@ -102,6 +104,7 @@ "picture_in_picture_window_manager_uma_helper.cc", "scoped_disallow_picture_in_picture.cc", "scoped_picture_in_picture_occlusion_observation.cc", + "scoped_tuck_picture_in_picture.cc", ] deps += [ "//chrome/app:generated_resources",
diff --git a/chrome/browser/picture_in_picture/picture_in_picture_window.h b/chrome/browser/picture_in_picture/picture_in_picture_window.h new file mode 100644 index 0000000..f017e54 --- /dev/null +++ b/chrome/browser/picture_in_picture/picture_in_picture_window.h
@@ -0,0 +1,26 @@ +// Copyright 2025 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_PICTURE_IN_PICTURE_PICTURE_IN_PICTURE_WINDOW_H_ +#define CHROME_BROWSER_PICTURE_IN_PICTURE_PICTURE_IN_PICTURE_WINDOW_H_ + +// A PictureInPictureWindow is an always-on-top window that displays content to +// the user. There are two types of PictureInPictureWindows: video +// picture-in-picture windows (`VideoOverlayWindowViews`) and document +// picture-in-picture (`PictureInPictureBrowserFrameView`). This class has +// shared logic for both to be controlled directly by the +// PictureInPictureWindowManager. +class PictureInPictureWindow { + public: + // When `tuck` is true, this forces the PictureInPictureWindow to be tucked + // offscreen. When `tuck` is false, it returns the PictureInPictureWindow to + // its original position. + virtual void SetForcedTucking(bool tuck) = 0; + + protected: + PictureInPictureWindow() = default; + virtual ~PictureInPictureWindow() = default; +}; + +#endif // CHROME_BROWSER_PICTURE_IN_PICTURE_PICTURE_IN_PICTURE_WINDOW_H_
diff --git a/chrome/browser/picture_in_picture/picture_in_picture_window_manager.cc b/chrome/browser/picture_in_picture/picture_in_picture_window_manager.cc index 395f622..90346363 100644 --- a/chrome/browser/picture_in_picture/picture_in_picture_window_manager.cc +++ b/chrome/browser/picture_in_picture/picture_in_picture_window_manager.cc
@@ -28,6 +28,7 @@ // TODO(crbug.com/421608904): include auto_picture_in_picture_tab_helper for // Android. #include "chrome/browser/picture_in_picture/auto_picture_in_picture_tab_helper.h" +#include "chrome/browser/picture_in_picture/picture_in_picture_window.h" #include "media/base/media_switches.h" #include "net/base/url_util.h" #include "third_party/blink/public/common/features.h" @@ -733,6 +734,61 @@ number_of_existing_scoped_disallow_picture_in_pictures_--; } +void PictureInPictureWindowManager::OnPictureInPictureWindowShown( + PictureInPictureWindow* window) { + picture_in_picture_window_ = window; + if (IsPictureInPictureForceTucked()) { + picture_in_picture_window_->SetForcedTucking(true); + RecordPictureInPictureTucked(PictureInPictureTuckedType::kNewWindowTucked); + } +} + +void PictureInPictureWindowManager::OnPictureInPictureWindowHidden( + PictureInPictureWindow* window) { + if (picture_in_picture_window_ == window) { + picture_in_picture_window_ = nullptr; + } +} + +bool PictureInPictureWindowManager::ShouldFileDialogTuckPictureInPicture( + content::WebContents* owner_web_contents) { + if (!base::FeatureList::IsEnabled(media::kFileDialogsTuckPictureInPicture)) { + return false; + } + + // File dialogs opened inside document picture-in-picture windows should not + // tuck picture-in-picture. + if (pip_window_controller_ && + pip_window_controller_->GetChildWebContents() == owner_web_contents) { + return false; + } + + return true; +} + +void PictureInPictureWindowManager::OnScopedTuckPictureInPictureCreated( + base::PassKey<ScopedTuckPictureInPicture>) { + number_of_existing_scoped_tuck_picture_in_pictures_++; + if (picture_in_picture_window_) { + picture_in_picture_window_->SetForcedTucking(true); + RecordPictureInPictureTucked( + PictureInPictureTuckedType::kExistingWindowTucked); + } +} + +void PictureInPictureWindowManager::OnScopedTuckPictureInPictureDestroyed( + base::PassKey<ScopedTuckPictureInPicture>) { + CHECK_NE(number_of_existing_scoped_tuck_picture_in_pictures_, 0u); + number_of_existing_scoped_tuck_picture_in_pictures_--; + if (picture_in_picture_window_ && !IsPictureInPictureForceTucked()) { + picture_in_picture_window_->SetForcedTucking(false); + } +} + +bool PictureInPictureWindowManager::IsPictureInPictureForceTucked() const { + return number_of_existing_scoped_tuck_picture_in_pictures_ > 0; +} + void PictureInPictureWindowManager:: RecordDocumentPictureInPictureRequestedSizeMetrics( const blink::mojom::PictureInPictureWindowOptions& pip_options, @@ -782,6 +838,11 @@ base::UmaHistogramEnumeration("Media.PictureInPicture.Disallowed", type); } +void PictureInPictureWindowManager::RecordPictureInPictureTucked( + PictureInPictureTuckedType type) { + base::UmaHistogramEnumeration("Media.PictureInPicture.Tucked", type); +} + void PictureInPictureWindowManager::MaybeRecordPictureInPictureChanged( bool is_picture_in_picture) { if (!uma_helper_) {
diff --git a/chrome/browser/picture_in_picture/picture_in_picture_window_manager.h b/chrome/browser/picture_in_picture/picture_in_picture_window_manager.h index b629247..426d202 100644 --- a/chrome/browser/picture_in_picture/picture_in_picture_window_manager.h +++ b/chrome/browser/picture_in_picture/picture_in_picture_window_manager.h
@@ -36,7 +36,9 @@ #if !BUILDFLAG(IS_ANDROID) class PictureInPictureOcclusionTracker; +class PictureInPictureWindow; class ScopedDisallowPictureInPicture; +class ScopedTuckPictureInPicture; namespace views { class View; @@ -215,6 +217,32 @@ base::PassKey<ScopedDisallowPictureInPicture>); void OnScopedDisallowPictureInPictureDestroyed( base::PassKey<ScopedDisallowPictureInPicture>); + + // Called by a picture-in-picture window (either video picture-in-picture or + // document picture-in-picture) when it is opened. This allows us to + // communicate directly with the window for things that can't be handled + // through the PictureInPictureWindowController. + void OnPictureInPictureWindowShown(PictureInPictureWindow* window); + + // Called by a picture-in-picture window when it closes or hides to end the + // connection opened by a previous call to `OnPictureInPictureWindowShown`. + void OnPictureInPictureWindowHidden(PictureInPictureWindow* window); + + // Returns true if a file dialog opened by `owner_web_contents` should create + // a `ScopedTuckPictureInPicture` to tuck picture-in-picture. + bool ShouldFileDialogTuckPictureInPicture( + content::WebContents* owner_web_contents); + + // Called by `ScopedTuckPictureInPicture` to force-tuck any existing or future + // picture-in-picture windows until it's destroyed. + void OnScopedTuckPictureInPictureCreated( + base::PassKey<ScopedTuckPictureInPicture>); + void OnScopedTuckPictureInPictureDestroyed( + base::PassKey<ScopedTuckPictureInPicture>); + + // Returns true if picture-in-picture windows are currently force-tucked (e.g. + // due to a ScopedTuckPictureInPicture object existing). + bool IsPictureInPictureForceTucked() const; #endif // Returns true if picture-in-picture is currently disabled (e.g. due to a @@ -261,6 +289,23 @@ kMaxValue = kNewWindowClosed, }; // LINT.ThenChange(//tools/metrics/histograms/metadata/media/enums.xml:PictureInPictureDisallowedTypeEnum) + + // These values are persisted to logs. Entries should not be renumbered and + // numeric values should never be reused. + // + // LINT.IfChange(PictureInPictureTuckedType) + enum class PictureInPictureTuckedType { + // An existing picture-in-picture window was tucked because we started + // force-tucking picture-in-picture windows. + kExistingWindowTucked = 0, + + // A new picture-in-picture window was tucked because it was created while + // we were already force-tucking picture-in-picture windows. + kNewWindowTucked = 1, + + kMaxValue = kNewWindowTucked, + }; + // LINT.ThenChange(//tools/metrics/histograms/metadata/media/enums.xml:PictureInPictureTuckedTypeEnum) #endif // !BUILDFLAG(IS_ANDROID) // Create a Picture-in-Picture window and register it in order to be closed @@ -298,6 +343,10 @@ // Records whether a new or existing picture-in-picture window was closed due // to an existing ScopedDisallowPictureInPicture. void RecordPictureInPictureDisallowed(PictureInPictureDisallowedType type); + + // Records whether a new or existing picture-in-picture window was tucked due + // to an existing ScopedTuckPictureInPicture. + void RecordPictureInPictureTucked(PictureInPictureTuckedType type); #endif // !BUILDFLAG(IS_ANDROID) #if !BUILDFLAG(IS_ANDROID) @@ -333,6 +382,14 @@ // should be removed when that metric is removed. bool is_calculating_initial_document_pip_size_ = false; + // The number of `ScopedTuckPictureInPicture` objects currently in + // existence. If at least one exists, then picture-in-picture windows will be + // tucked. + uint32_t number_of_existing_scoped_tuck_picture_in_pictures_ = 0; + + // Pointer to the currently shown picture-in-picture window, if any. + raw_ptr<PictureInPictureWindow> picture_in_picture_window_ = nullptr; + std::unique_ptr<PictureInPictureWindowManagerUmaHelper> uma_helper_; #endif //! BUILDFLAG(IS_ANDROID)
diff --git a/chrome/browser/picture_in_picture/picture_in_picture_window_manager_unittest.cc b/chrome/browser/picture_in_picture/picture_in_picture_window_manager_unittest.cc index ef8e05f..aaa616e8 100644 --- a/chrome/browser/picture_in_picture/picture_in_picture_window_manager_unittest.cc +++ b/chrome/browser/picture_in_picture/picture_in_picture_window_manager_unittest.cc
@@ -20,8 +20,10 @@ #include "base/test/metrics/histogram_tester.h" #include "base/test/simple_test_tick_clock.h" #include "chrome/browser/picture_in_picture/auto_picture_in_picture_tab_helper.h" +#include "chrome/browser/picture_in_picture/picture_in_picture_window.h" #include "chrome/browser/picture_in_picture/picture_in_picture_window_manager_uma_helper.h" #include "chrome/browser/picture_in_picture/scoped_disallow_picture_in_picture.h" +#include "chrome/browser/picture_in_picture/scoped_tuck_picture_in_picture.h" #include "media/base/media_switches.h" #include "ui/views/bubble/bubble_dialog_delegate_view.h" #include "ui/views/view.h" @@ -65,6 +67,25 @@ MOCK_METHOD(std::optional<url::Origin>, GetOrigin, (), (override)); }; +#if !BUILDFLAG(IS_ANDROID) +class MockPictureInPictureWindow : public PictureInPictureWindow { + public: + MockPictureInPictureWindow() = default; + MockPictureInPictureWindow(const MockPictureInPictureWindow&) = delete; + MockPictureInPictureWindow& operator=(const MockPictureInPictureWindow&) = + delete; + ~MockPictureInPictureWindow() override = default; + + bool is_tucking() const { return is_tucking_; } + + // PictureInPictureWindow: + void SetForcedTucking(bool tuck) override { is_tucking_ = tuck; } + + private: + bool is_tucking_ = false; +}; +#endif // !BUILDFLAG(IS_ANDROID) + class PictureInPictureWindowManagerTest : public ChromeRenderViewHostTestHarness { public: @@ -475,6 +496,103 @@ } } +TEST_F(PictureInPictureWindowManagerTest, CanForceTuckPictureInPicture) { + { + // Force-tucking before opening a picture-in-picture window should tuck it. + auto tuck = std::make_unique<ScopedTuckPictureInPicture>(); + MockPictureInPictureWindow pip_window; + + PictureInPictureWindowManager::GetInstance()->OnPictureInPictureWindowShown( + &pip_window); + EXPECT_TRUE(pip_window.is_tucking()); + + tuck.reset(); + EXPECT_FALSE(pip_window.is_tucking()); + + PictureInPictureWindowManager::GetInstance() + ->OnPictureInPictureWindowHidden(&pip_window); + } + + { + // Force-tucking after opening a picture-in-picture window should tuck it. + MockPictureInPictureWindow pip_window; + PictureInPictureWindowManager::GetInstance()->OnPictureInPictureWindowShown( + &pip_window); + + EXPECT_FALSE(pip_window.is_tucking()); + auto tuck = std::make_unique<ScopedTuckPictureInPicture>(); + EXPECT_TRUE(pip_window.is_tucking()); + + tuck.reset(); + EXPECT_FALSE(pip_window.is_tucking()); + + PictureInPictureWindowManager::GetInstance() + ->OnPictureInPictureWindowHidden(&pip_window); + } + + { + MockPictureInPictureWindow pip_window; + { + ScopedTuckPictureInPicture tuck1; + + { + // Multiple ScopedTuckPictureInPicture should still tuck + // picture-in-picture windows. + ScopedTuckPictureInPicture tuck2; + + PictureInPictureWindowManager::GetInstance() + ->OnPictureInPictureWindowShown(&pip_window); + EXPECT_TRUE(pip_window.is_tucking()); + } + + // When one of them is destroyed but the other remains, it should still + // remain tucked. + EXPECT_TRUE(pip_window.is_tucking()); + } + + // Once both have been destroyed, picture-in-picture windows should be + // untucked. + EXPECT_FALSE(pip_window.is_tucking()); + + PictureInPictureWindowManager::GetInstance() + ->OnPictureInPictureWindowHidden(&pip_window); + } +} + +TEST_F(PictureInPictureWindowManagerTest, + ShouldFileDialogTuckPictureInPicture) { + PictureInPictureWindowManager::GetInstance()->EnterDocumentPictureInPicture( + web_contents(), child_web_contents()); + + { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature(media::kFileDialogsTuckPictureInPicture); + + // With the feature enabled, file dialogs that aren't on a document + // picture-in-picture window should tuck picture-in-picture windows. + EXPECT_TRUE(PictureInPictureWindowManager::GetInstance() + ->ShouldFileDialogTuckPictureInPicture(web_contents())); + EXPECT_FALSE( + PictureInPictureWindowManager::GetInstance() + ->ShouldFileDialogTuckPictureInPicture(child_web_contents())); + } + + { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndDisableFeature(media::kFileDialogsTuckPictureInPicture); + + // With the feature disabled, no file dialogs should tuck + // picture-in-picture windows. + EXPECT_FALSE(PictureInPictureWindowManager::GetInstance() + ->ShouldFileDialogTuckPictureInPicture(web_contents())); + EXPECT_FALSE( + PictureInPictureWindowManager::GetInstance() + ->ShouldFileDialogTuckPictureInPicture(child_web_contents())); + } + + PictureInPictureWindowManager::GetInstance()->ExitPictureInPicture(); +} + TEST_F(PictureInPictureWindowManagerTest, EnterAndCloseDocumentPip_NormalCloseDoesCommit) { base::SimpleTestTickClock test_clock;
diff --git a/chrome/browser/picture_in_picture/scoped_tuck_picture_in_picture.cc b/chrome/browser/picture_in_picture/scoped_tuck_picture_in_picture.cc new file mode 100644 index 0000000..3228b4f --- /dev/null +++ b/chrome/browser/picture_in_picture/scoped_tuck_picture_in_picture.cc
@@ -0,0 +1,19 @@ +// Copyright 2025 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/picture_in_picture/scoped_tuck_picture_in_picture.h" + +#include "chrome/browser/picture_in_picture/picture_in_picture_window_manager.h" + +ScopedTuckPictureInPicture::ScopedTuckPictureInPicture() { + PictureInPictureWindowManager::GetInstance() + ->OnScopedTuckPictureInPictureCreated( + base::PassKey<ScopedTuckPictureInPicture>()); +} + +ScopedTuckPictureInPicture::~ScopedTuckPictureInPicture() { + PictureInPictureWindowManager::GetInstance() + ->OnScopedTuckPictureInPictureDestroyed( + base::PassKey<ScopedTuckPictureInPicture>()); +}
diff --git a/chrome/browser/picture_in_picture/scoped_tuck_picture_in_picture.h b/chrome/browser/picture_in_picture/scoped_tuck_picture_in_picture.h new file mode 100644 index 0000000..ad68ff9 --- /dev/null +++ b/chrome/browser/picture_in_picture/scoped_tuck_picture_in_picture.h
@@ -0,0 +1,19 @@ +// Copyright 2025 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_PICTURE_IN_PICTURE_SCOPED_TUCK_PICTURE_IN_PICTURE_H_ +#define CHROME_BROWSER_PICTURE_IN_PICTURE_SCOPED_TUCK_PICTURE_IN_PICTURE_H_ + +// As long as at least one of these objects is alive, new and existing +// picture-in-picture windows will be tucked to the side of the screen. +class ScopedTuckPictureInPicture { + public: + ScopedTuckPictureInPicture(); + ScopedTuckPictureInPicture(const ScopedTuckPictureInPicture&) = delete; + ScopedTuckPictureInPicture& operator=(const ScopedTuckPictureInPicture&) = + delete; + ~ScopedTuckPictureInPicture(); +}; + +#endif // CHROME_BROWSER_PICTURE_IN_PICTURE_SCOPED_TUCK_PICTURE_IN_PICTURE_H_
diff --git a/chrome/browser/picture_in_picture/video_picture_in_picture_window_controller_browsertest.cc b/chrome/browser/picture_in_picture/video_picture_in_picture_window_controller_browsertest.cc index c7a17e4..bf800c2 100644 --- a/chrome/browser/picture_in_picture/video_picture_in_picture_window_controller_browsertest.cc +++ b/chrome/browser/picture_in_picture/video_picture_in_picture_window_controller_browsertest.cc
@@ -222,7 +222,11 @@ OverlayControlsBecomingVisibleObserver(views::View* controls_container, base::OnceClosure cb) : visibility_changed_callback_(std::move(cb)) { - observation_.Observe(controls_container); + if (controls_container->GetVisible()) { + std::move(visibility_changed_callback_).Run(); + } else { + observation_.Observe(controls_container); + } } OverlayControlsBecomingVisibleObserver( const OverlayControlsBecomingVisibleObserver&) = delete; @@ -402,8 +406,7 @@ // window has been moved. base::RunLoop run_loop; OverlayControlsBecomingVisibleObserver observer( - GetOverlayWindow()->GetControlsContainerView(), - base::BindLambdaForTesting([&] { run_loop.Quit(); })); + GetOverlayWindow()->GetControlsContainerView(), run_loop.QuitClosure()); run_loop.Run(); EXPECT_TRUE(GetOverlayWindow()->AreControlsVisible());
diff --git a/chrome/browser/profiles/android/java/src/org/chromium/chrome/browser/profiles/ProfileKeyedMapTest.java b/chrome/browser/profiles/android/java/src/org/chromium/chrome/browser/profiles/ProfileKeyedMapTest.java index 3817525..6b2bf9b 100644 --- a/chrome/browser/profiles/android/java/src/org/chromium/chrome/browser/profiles/ProfileKeyedMapTest.java +++ b/chrome/browser/profiles/android/java/src/org/chromium/chrome/browser/profiles/ProfileKeyedMapTest.java
@@ -42,7 +42,7 @@ @Test public void testReusesObjects() { - ProfileKeyedMap<Object> map = new ProfileKeyedMap<Object>(NO_REQUIRED_CLEANUP_ACTION); + ProfileKeyedMap<Object> map = new ProfileKeyedMap<>(NO_REQUIRED_CLEANUP_ACTION); Object obj1 = new Object(); Assert.assertEquals(obj1, map.getForProfile(mProfile1, (profile) -> obj1)); @@ -52,8 +52,7 @@ @Test public void testCleanupOnProfileDestruction() { Set<Object> destroyedObjects = new HashSet<>(); - ProfileKeyedMap<Object> map = - new ProfileKeyedMap<Object>((obj) -> destroyedObjects.add(obj)); + ProfileKeyedMap<Object> map = new ProfileKeyedMap<>((obj) -> destroyedObjects.add(obj)); Object obj1 = new Object(); Assert.assertEquals(obj1, map.getForProfile(mProfile1, (profile) -> obj1)); @@ -65,8 +64,7 @@ @Test public void testDestroy() { Set<Object> destroyedObjects = new HashSet<>(); - ProfileKeyedMap<Object> map = - new ProfileKeyedMap<Object>((obj) -> destroyedObjects.add(obj)); + ProfileKeyedMap<Object> map = new ProfileKeyedMap<>((obj) -> destroyedObjects.add(obj)); Object obj1 = new Object(); Assert.assertEquals(obj1, map.getForProfile(mProfile1, (profile) -> obj1)); @@ -82,11 +80,9 @@ @Test public void testMapsAreIndependent() { Set<Object> destroyedObjects = new HashSet<>(); - ProfileKeyedMap<Object> map1 = - new ProfileKeyedMap<Object>((obj) -> destroyedObjects.add(obj)); + ProfileKeyedMap<Object> map1 = new ProfileKeyedMap<>((obj) -> destroyedObjects.add(obj)); - ProfileKeyedMap<Object> map2 = - new ProfileKeyedMap<Object>((obj) -> destroyedObjects.add(obj)); + ProfileKeyedMap<Object> map2 = new ProfileKeyedMap<>((obj) -> destroyedObjects.add(obj)); Object obj1 = new Object(); Assert.assertEquals(obj1, map1.getForProfile(mProfile1, (profile) -> obj1)); @@ -121,7 +117,7 @@ @Test public void testProfileSelection_OWN_INSTANCE() { ProfileKeyedMap<Object> map = - new ProfileKeyedMap<Object>( + new ProfileKeyedMap<>( ProfileKeyedMap.ProfileSelection.OWN_INSTANCE, NO_REQUIRED_CLEANUP_ACTION); Object originalObj1 = new Object(); Object incognitoObj1 = new Object(); @@ -133,7 +129,7 @@ @Test public void testProfileSelection_REDIRECTED_TO_ORIGINAL() { ProfileKeyedMap<Object> map = - new ProfileKeyedMap<Object>( + new ProfileKeyedMap<>( ProfileKeyedMap.ProfileSelection.REDIRECTED_TO_ORIGINAL, NO_REQUIRED_CLEANUP_ACTION); Object originalObj1 = new Object();
diff --git a/chrome/browser/quick_delete/android/java/src/org/chromium/chrome/browser/quick_delete/QuickDeleteTabsFilter.java b/chrome/browser/quick_delete/android/java/src/org/chromium/chrome/browser/quick_delete/QuickDeleteTabsFilter.java index 6289af8..8e8a4faa 100644 --- a/chrome/browser/quick_delete/android/java/src/org/chromium/chrome/browser/quick_delete/QuickDeleteTabsFilter.java +++ b/chrome/browser/quick_delete/android/java/src/org/chromium/chrome/browser/quick_delete/QuickDeleteTabsFilter.java
@@ -126,8 +126,8 @@ } // Use a list here since the number of elements is likely to be small and outperform a set // most of the time. - List<Token> placeholderTabGroupIds = new ArrayList<Token>(); - List<Tab> placeholderExcludedTabList = new ArrayList<Tab>(); + List<Token> placeholderTabGroupIds = new ArrayList<>(); + List<Tab> placeholderExcludedTabList = new ArrayList<>(); for (LocalTabGroupId localId : destroyedGroups.collaborationGroupsDestroyed) { placeholderTabGroupIds.add(localId.tabGroupId); }
diff --git a/chrome/browser/readaloud/android/java/res/layout/readaloud_expanded_player_layout.xml b/chrome/browser/readaloud/android/java/res/layout/readaloud_expanded_player_layout.xml index d0f96b8..49a3535 100644 --- a/chrome/browser/readaloud/android/java/res/layout/readaloud_expanded_player_layout.xml +++ b/chrome/browser/readaloud/android/java/res/layout/readaloud_expanded_player_layout.xml
@@ -236,6 +236,7 @@ android:maxLines="1" android:layout_height="@dimen/readaloud_menu_buttons_width" android:layout_gravity="center_vertical" + android:gravity="center_vertical" android:textAppearance="@style/TextAppearance.TextAccentMediumThick" tools:ignore="ContentDescription" /> <!-- Note: contentDescription for playback speed button above is set in ExpandedPlayerSheetContent.java. -->
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/ReadAloudControllerUnitTest.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/ReadAloudControllerUnitTest.java index cb992c7e6..d337bd7 100644 --- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/ReadAloudControllerUnitTest.java +++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/ReadAloudControllerUnitTest.java
@@ -304,7 +304,7 @@ when(mRenderFrameHost.getGlobalRenderFrameHostId()).thenReturn(mGlobalRenderFrameHostId); mController.setHighlighterForTests(mHighlighter); mUserActionTester = new UserActionTester(); - mExtractorPromise = new Promise<Long>(); + mExtractorPromise = new Promise<>(); when(mExtractor.getDateModified(any())).thenReturn(mExtractorPromise); mExtractorPromise.fulfill(1234567123456L); ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/PlayerCoordinatorUnitTest.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/PlayerCoordinatorUnitTest.java index 74f4d6a4..1b11428b 100644 --- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/PlayerCoordinatorUnitTest.java +++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/PlayerCoordinatorUnitTest.java
@@ -42,14 +42,11 @@ import org.chromium.chrome.browser.readaloud.testing.MockPrefServiceHelper; import org.chromium.chrome.modules.readaloud.Playback; import org.chromium.chrome.modules.readaloud.PlaybackArgs.PlaybackMode; -import org.chromium.chrome.modules.readaloud.PlaybackArgs.PlaybackVoice; import org.chromium.chrome.modules.readaloud.PlaybackListener; import org.chromium.chrome.modules.readaloud.Player; import org.chromium.components.browser_ui.bottomsheet.BottomSheetController; import org.chromium.components.prefs.PrefService; -import java.util.List; - /** Unit tests for {@link PlayerCoordinator}. */ @Config(manifest = Config.NONE) @RunWith(BaseRobolectricTestRunner.class) @@ -110,9 +107,7 @@ ReadAloudPrefs.setSpeed(prefs, 2f); doReturn(prefs).when(mDelegate).getPrefService(); doReturn(Mockito.mock(LayoutManager.class)).when(mDelegate).getLayoutManager(); - doReturn(new ObservableSupplierImpl<List<PlaybackVoice>>()) - .when(mDelegate) - .getCurrentLanguageVoicesSupplier(); + doReturn(new ObservableSupplierImpl<>()).when(mDelegate).getCurrentLanguageVoicesSupplier(); doReturn(new ObservableSupplierImpl<>()).when(mDelegate).getVoiceIdSupplier(); doReturn(new ObservableSupplierImpl<>()).when(mDelegate).getPlaybackModeSelectionEnabled(); doReturn(new ObservableSupplierImpl<>()).when(mDelegate).getFeedbackTypeSupplier();
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/BUILD.gn b/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/BUILD.gn index cc0e503fc..83e167f 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/BUILD.gn +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/BUILD.gn
@@ -417,6 +417,7 @@ "background/input/smart_sticky_mode_test.js", "background/live_regions_test.js", "background/logging/log_store_test.js", + "background/math_handler_test.js", "background/output/output_test.js", "background/panel/i_search_test.js", "background/panel/panel_background_test.js",
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/background/background_test.js b/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/background/background_test.js index 79cf9ad..7c70bbf 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/background/background_test.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/background/background_test.js
@@ -1733,6 +1733,30 @@ await mockFeedback.replay(); }); +AX_TEST_F('ChromeVoxMV3BackgroundTest', 'MathMLContent', async function() { + const mockFeedback = this.createMockFeedback(); + const site = ` + <math> + <mfrac> + <mrow> + <mi>d</mi> + <mi>y</mi> + </mrow> + <mrow> + <mi>d</mi> + <mi>x</mi> + </mrow> + </mfrac> + <mo>=</mo> + </math> + `; + const root = await this.runWithLoadedTree(site); + mockFeedback.call(doCmd('nextObject')) + .expectSpeech('StartFraction d y Over d x EndFraction =') + .expectSpeech('Press up, down, left, or right to explore math'); + await mockFeedback.replay(); +}); + AX_TEST_F('ChromeVoxBackgroundTest', 'GestureGranularity', async function() { const mockFeedback = this.createMockFeedback(); const site = `
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/background/live_regions_test.js b/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/background/live_regions_test.js index 4f51b8e..be6c3b39 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/background/live_regions_test.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/background/live_regions_test.js
@@ -243,7 +243,7 @@ }, 50); </script> `); - const focusAfterNodeChange = setTimeout.bind(window, function() { + const focusAfterNodeChange = () => setTimeout(() => { root.firstChild.nextSibling.focus(); }, 1000); mockFeedback.call(focusAfterNodeChange)
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/background/math_handler.ts b/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/background/math_handler.ts index 084b7fb..41b5943 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/background/math_handler.ts +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/background/math_handler.ts
@@ -37,10 +37,14 @@ * @return Boolean indicating whether any math was spoken. */ speak(): boolean { - const mathml = this.node_.mathContent; + let mathml = this.node_.mathContent; if (!mathml) { return false; } + // Ensure it has a `math` root node. + if (!/^<math>${mathml}<\/math>$/.test(mathml)) { + mathml = '<math>' + mathml + '</math>'; + } let text: string|null = null;
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/background/math_handler_test.js b/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/background/math_handler_test.js new file mode 100644 index 0000000..5b88c26 --- /dev/null +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/background/math_handler_test.js
@@ -0,0 +1,77 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +GEN_INCLUDE(['../testing/chromevox_e2e_test_base.js']); + +/** + * Test fixture for MathHandler. + */ +ChromeVoxMV3MathHandlerTest = class extends ChromeVoxE2ETest { + /** @override */ + async setUpDeferred() { + await super.setUpDeferred(); + globalThis.MathHandler = TestImportManager().getImports().MathHandler; + } + + createMockNode(properties) { + return Object.assign( + { + state: {}, + children: [], + unclippedLocation: {left: 20, top: 10, width: 100, height: 50}, + location: {left: 20, top: 10, width: 100, height: 50}, + }, + properties); + } +}; + +AX_TEST_F( + 'ChromeVoxMV3MathHandlerTest', 'noMathRootInMathContent', async function() { + const mockFeedback = this.createMockFeedback(); + const math = this.createMockNode({ + role: chrome.automation.RoleType.MathMlMath, + mathContent: + '<mfrac><mrow><mi>d</mi><mi>y</mi></mrow><mrow><mi>d</mi>' + + '<mi>x</mi></mrow></mfrac><mo>=</mo>' + }); + const range = CursorRange.fromNode(math); + MathHandler.init(range); + mockFeedback.call(() => MathHandler.instance.speak()) + .expectSpeech('StartFraction d y Over d x EndFraction =') + .expectSpeech('Press up, down, left, or right to explore math'); + await mockFeedback.replay(); + }); + +AX_TEST_F( + 'ChromeVoxMV3MathHandlerTest', 'mathRootInMathContent', async function() { + const mockFeedback = this.createMockFeedback(); + const math = this.createMockNode({ + role: chrome.automation.RoleType.MathMlMath, + mathContent: '<math><mfrac><mrow><mi>d</mi><mi>y</mi></mrow><mrow>' + + '<mi>d</mi><mi>x</mi></mrow></mfrac><mo>=</mo></math>' + }); + const range = CursorRange.fromNode(math); + MathHandler.init(range); + mockFeedback.call(() => MathHandler.instance.speak()) + .expectSpeech('StartFraction d y Over d x EndFraction =') + .expectSpeech('Press up, down, left, or right to explore math'); + await mockFeedback.replay(); + }); + +AX_TEST_F( + 'ChromeVoxMV3MathHandlerTest', 'mathRootDoesntMatchRegexInMathContent', + async function() { + const mockFeedback = this.createMockFeedback(); + const math = this.createMockNode({ + role: chrome.automation.RoleType.MathMlMath, + mathContent: '<math id="42"><mfrac><mrow><mi>d</mi><mi>y</mi></mrow>' + + '<mrow><mi>d</mi><mi>x</mi></mrow></mfrac><mo>=</mo></math>' + }); + const range = CursorRange.fromNode(math); + MathHandler.init(range); + mockFeedback.call(() => MathHandler.instance.speak()) + .expectSpeech('StartFraction d y Over d x EndFraction =') + .expectSpeech('Press up, down, left, or right to explore math'); + await mockFeedback.replay(); + });
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/background/panel/i_search_test.js b/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/background/panel/i_search_test.js index 14d0680..86283743 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/background/panel/i_search_test.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/background/panel/i_search_test.js
@@ -9,11 +9,6 @@ * Test fixture for ISearch. */ ChromeVoxISearchTest = class extends ChromeVoxE2ETest { - /** @override */ - get runtimeDeps() { - return ['ISearch', 'ISearchHandler']; - } - get linksAndHeadingsDoc() { return ` <p>start</p>
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/testing/chromevox_e2e_test_base.js b/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/testing/chromevox_e2e_test_base.js index 87f12c9..32af48b5 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/testing/chromevox_e2e_test_base.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/testing/chromevox_e2e_test_base.js
@@ -16,17 +16,6 @@ ChromeVoxE2ETest = class extends E2ETestBase { constructor() { super(); - - if (this.runtimeDeps.length > 0) { - chrome.extension.getViews().forEach(view => { - this.runtimeDeps.forEach(dep => { - if (view[dep]) { - window[dep] = view[dep]; - } - }); - }); - } - this.originalOutputContextValues_ = {}; } @@ -125,14 +114,6 @@ gesture, opt_x, opt_y); } - /** - * Dependencies defined on a background window other than this one. - * @type {!Array<string>} - */ - get runtimeDeps() { - return []; - } - /** @override */ async setUpDeferred() { await super.setUpDeferred();
diff --git a/chrome/browser/resources/lens/overlay/lens_overlay_app.html b/chrome/browser/resources/lens/overlay/lens_overlay_app.html index 61834c4..5f68114 100644 --- a/chrome/browser/resources/lens/overlay/lens_overlay_app.html +++ b/chrome/browser/resources/lens/overlay/lens_overlay_app.html
@@ -479,7 +479,7 @@ tabindex="-1" show-error-state="{{showErrorState}}" page-content-type="[[pageContentType]]" - suggestion-count="[[searchboxSuggestionCount]]" + suggestion-count="[[searchboxSuggestionCount]]"> </cr-searchbox-ghost-loader> </div> <div id="translateButtonContainer" class="button-container">
diff --git a/chrome/browser/resources/new_tab_page/app.css b/chrome/browser/resources/new_tab_page/app.css index 454ae6b..60c2abb 100644 --- a/chrome/browser/resources/new_tab_page/app.css +++ b/chrome/browser/resources/new_tab_page/app.css
@@ -109,11 +109,19 @@ z-index: 1; } +:host([show-composebox_]) #content { + z-index: unset; +} + #logo { margin-bottom: 38px; z-index: 1; /* Needed so it layers on top of OneGoogleBar. */ } +:host([show-composebox_]) #logo { + z-index: 2; +} + #searchboxContainer { display: inherit; margin-bottom: 16px; @@ -251,7 +259,8 @@ ntp-composebox { --ntp-composebox-width: var(--ntp-search-box-width); - --ntp-composebox-background-color: var(--color-new-tab-page-background); + --ntp-composebox-background-color: + var(--color-new-tab-page-composebox-background); } ntp-composebox, @@ -263,6 +272,13 @@ z-index: 101; } +#composeboxScrim { + background: var(--color-new-tab-page-background); + inset: 0; + position: absolute; + z-index: 1; +} + #webstoreToast { padding: 16px; }
diff --git a/chrome/browser/resources/new_tab_page/app.html b/chrome/browser/resources/new_tab_page/app.html index 0c92a557..5b597ab 100644 --- a/chrome/browser/resources/new_tab_page/app.html +++ b/chrome/browser/resources/new_tab_page/app.html
@@ -20,14 +20,16 @@ <div id="searchboxContainer"> <cr-searchbox id="searchbox" ?is-dark="${this.isThemeDark_()}" ?color-source-is-baseline="${this.colorSourceIsBaseline}" + @open-composebox="${this.toggleComposebox_}" @open-lens-search="${this.onOpenLensSearch_}" @open-voice-search="${this.onOpenVoiceSearch_}" ?shown="${this.realboxShown_}" ?had-secondary-side="${this.realboxHadSecondarySide}" @had-secondary-side-changed="${this.onRealboxHadSecondarySideChanged_}" ?can-show-secondary-side="${this.realboxCanShowSecondarySide}"> </cr-searchbox> - ${this.showComposeBox_ ? html` - <ntp-composebox></ntp-composebox> + ${this.showComposebox_ ? html` + <ntp-composebox> + </ntp-composebox> ` : ''} ${this.showLensUploadDialog_ ? html` <ntp-lens-upload-dialog id="lensUploadDialog" @@ -106,6 +108,9 @@ <ntp-voice-search-overlay @close="${this.onVoiceSearchOverlayClose_}"> </ntp-voice-search-overlay> ` : ''} +${this.showComposebox_ ? html` + <div id="composeboxScrim" @click="${this.toggleComposebox_}"></div> +` : ''} <svg> <defs> <clipPath id="oneGoogleBarClipPath">
diff --git a/chrome/browser/resources/new_tab_page/app.ts b/chrome/browser/resources/new_tab_page/app.ts index e491126f..03fea12 100644 --- a/chrome/browser/resources/new_tab_page/app.ts +++ b/chrome/browser/resources/new_tab_page/app.ts
@@ -225,7 +225,10 @@ */ promoAndModulesLoaded_: {type: Boolean}, - showComposeBox_: {type: Boolean}, + showComposebox_: { + type: Boolean, + reflect: true, + }, showLensUploadDialog_: {type: Boolean}, @@ -265,7 +268,7 @@ accessor realboxHadSecondarySide: boolean = false; protected accessor realboxShown_: boolean = false; protected accessor showLensUploadDialog_: boolean = false; - protected accessor showComposeBox_: boolean = false; + protected accessor showComposebox_: boolean = false; protected accessor logoEnabled_: boolean = loadTimeData.getBoolean('logoEnabled'); protected accessor oneGoogleBarEnabled_: boolean = @@ -588,7 +591,8 @@ private computeRealboxShown_(): boolean { // Do not show the realbox if the upload dialog is showing. - return !!this.theme_ && !this.showLensUploadDialog_; + return !!this.theme_ && !this.showLensUploadDialog_ && + !this.showComposebox_; } private computePromoAndModulesLoaded_(): boolean { @@ -614,6 +618,10 @@ } } + protected toggleComposebox_() { + this.showComposebox_ = !this.showComposebox_; + } + protected onOpenVoiceSearch_() { this.showVoiceSearchOverlay_ = true; recordVoiceAction(VoiceAction.ACTIVATE_SEARCH_BOX);
diff --git a/chrome/browser/resources/new_tab_page/composebox/composebox.css b/chrome/browser/resources/new_tab_page/composebox/composebox.css index b6d314d..3df7903b 100644 --- a/chrome/browser/resources/new_tab_page/composebox/composebox.css +++ b/chrome/browser/resources/new_tab_page/composebox/composebox.css
@@ -4,16 +4,77 @@ /* #css_wrapper_metadata_start * #type=style-lit + * #import=//resources/cr_elements/cr_icons_lit.css.js * #scheme=relative + * #include=cr-icons-lit * #css_wrapper_metadata_end */ :host { - height: var(--ntp-composebox-height, 136px); + --input-bottom-spacing: 16px; + --text-input-top-spacing: 24px; + --text-input-right-spacing: 80px; + --input-left-spacing: 24px; + background-color: var(--ntp-composebox-background-color); + border-radius: 24px; + font-size: var(--cr-composebox-font-size, 18px); width: var(--ntp-composebox-width, 337px); } -#main { - background-color: var(--ntp-composebox-background-color); - height: 100%; +#composebox { + align-items: flex-end; + display: flex; + pointer-events: auto; + position: relative; + mask-image: linear-gradient(transparent 7px, black calc(var(--text-input-top-spacing) + 7px)); + min-height: 136px; + max-height: 254px; +} + +#inputContainer { + box-sizing: border-box; + display: flex; + flex-direction: column; + padding: 0 var(--text-input-right-spacing) var(--input-bottom-spacing) var(--input-left-spacing); + overflow: hidden; width: 100%; } + +#input { + animation: colorChange 3s infinite; + background-color: inherit; + border: none; + box-sizing: border-box; + caret-color: var(--caret-color); + display: block; + field-sizing: content; + font-family: inherit; + font-size: inherit; + line-height: 24px; + max-height: calc-size(fit-content, min(size, 196px)); + min-height: 48px; + outline: none; + padding: 0; + position: relative; + resize: none; + scrollbar-width: none; + width: 100%; +} + +@keyframes colorChange { + 0% { --caret-color: blue; } + 33% { --caret-color: red; } + 67% { --caret-color: orange; } + 100% { --caret-color: green; } +} + +#input::-webkit-search-decoration, +#input::-webkit-search-results-button, +#input::-webkit-search-results-decoration, +#input::-webkit-search-cancel-button{ + display: none; +} + +#imageUpload { + height: 48px; + width: 48px +}
diff --git a/chrome/browser/resources/new_tab_page/composebox/composebox.html.ts b/chrome/browser/resources/new_tab_page/composebox/composebox.html.ts index 0e1c340..82107f68 100644 --- a/chrome/browser/resources/new_tab_page/composebox/composebox.html.ts +++ b/chrome/browser/resources/new_tab_page/composebox/composebox.html.ts
@@ -9,23 +9,30 @@ export function getHtml(this: ComposeboxElement) { // clang-format off return html`<!--_html_template_start_--> -<div id="main"> + <div id="composebox"> + <div id="inputContainer"> + <textarea id="input" type="search" autocomplete="off" + spellcheck="false" placeholder="Ask Anything"></textarea> + <div id="imageUpload"></div> + </div> + </div> <ntp-composebox-file-carousel id="carousel" .files=${this.files}> </ntp-composebox-file-carousel> <!-- TODO(crbug.com/422561574): Style inputs. --> - <label for="imageUploader">Image Upload</label> + <label for="imageUploader" hidden>Image Upload</label> <input type="file" accept="${this.imageFileTypes_}" id="imageUploader" - @change="${this.onFileChange_}"> + @change="${this.onFileChange_}" + hidden> </input> - <label for="attachmentUploader">Attachment Upload</label> + <label for="attachmentUploader" hidden>Attachment Upload</label> <input type="file" accept="${this.attachmentFileTypes_}" id="attachmentUploader" - @change="${this.onFileChange_}"> + @change="${this.onFileChange_}" + hidden> </input> -</div> <!--_html_template_end_-->`; // clang-format on }
diff --git a/chrome/browser/resources/new_tab_page/composebox/composebox.ts b/chrome/browser/resources/new_tab_page/composebox/composebox.ts index 18e8e14..2004d14 100644 --- a/chrome/browser/resources/new_tab_page/composebox/composebox.ts +++ b/chrome/browser/resources/new_tab_page/composebox/composebox.ts
@@ -16,6 +16,7 @@ attachmentUploader: HTMLInputElement, carousel: ComposeboxFileCarouselElement, imageUploader: HTMLInputElement, + input: HTMLInputElement, }; }
diff --git a/chrome/browser/resources/settings/lazy_load.ts b/chrome/browser/resources/settings/lazy_load.ts index e0d41443..26c1bbe 100644 --- a/chrome/browser/resources/settings/lazy_load.ts +++ b/chrome/browser/resources/settings/lazy_load.ts
@@ -213,7 +213,7 @@ export {SetPinDialogPage, SettingsSecurityKeysSetPinDialogElement} from './privacy_page/security_keys_set_pin_dialog.js'; export {SecurityKeysSubpageElement} from './privacy_page/security_keys_subpage.js'; export {HttpsFirstModeSetting, SafeBrowsingSetting, SettingsSecurityPageElement} from './privacy_page/security_page.js'; -export {SettingsSecurityPageV2Element} from './privacy_page/security_page_v2.js'; +export {SecuritySettingsBundleSetting, SettingsSecurityPageV2Element} from './privacy_page/security_page_v2.js'; export {SettingsPrivacySandboxAdMeasurementSubpageElement} from './privacy_sandbox/privacy_sandbox_ad_measurement_subpage.js'; export {SettingsPrivacySandboxFledgeSubpageElement} from './privacy_sandbox/privacy_sandbox_fledge_subpage.js'; export {PrivacySandboxInterestItemElement} from './privacy_sandbox/privacy_sandbox_interest_item.js';
diff --git a/chrome/browser/resources/settings/privacy_page/security_page.html b/chrome/browser/resources/settings/privacy_page/security_page.html index 31218b7..26438ab 100644 --- a/chrome/browser/resources/settings/privacy_page/security_page.html +++ b/chrome/browser/resources/settings/privacy_page/security_page.html
@@ -268,9 +268,10 @@ </cr-link-row> </template> </if> - <cr-link-row id="v8SettingLink" class="hr" on-click="onV8SettingsClick_" - label="$i18n{securityV8LinkTitle}" - sub-label="$i18n{securityV8LinkDescription}" + <cr-link-row id="javascriptOptimizerSettingLink" class="hr" + on-click="onJavascriptOptimizerSettingsClick_" + label="$i18n{securityJavascriptOptimizerLinkTitle}" + sub-label="[[javascriptOptimizerSubLabel_]]" role-description="$i18n{subpageArrowRoleDescription}"> </cr-link-row> <template is="dom-if" if="[[enableSecurityKeysSubpage_]]">
diff --git a/chrome/browser/resources/settings/privacy_page/security_page.ts b/chrome/browser/resources/settings/privacy_page/security_page.ts index aa91727e..5d75881 100644 --- a/chrome/browser/resources/settings/privacy_page/security_page.ts +++ b/chrome/browser/resources/settings/privacy_page/security_page.ts
@@ -20,6 +20,7 @@ import {PrivacyPageBrowserProxyImpl} from '/shared/settings/privacy_page/privacy_page_browser_proxy.js'; import {HelpBubbleMixin} from 'chrome://resources/cr_components/help_bubble/help_bubble_mixin.js'; import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js'; +import {WebUiListenerMixin} from 'chrome://resources/cr_elements/web_ui_listener_mixin.js'; import {assert} from 'chrome://resources/js/assert.js'; import {EventTracker} from 'chrome://resources/js/event_tracker.js'; import {focusWithoutInk} from 'chrome://resources/js/focus_without_ink.js'; @@ -36,6 +37,10 @@ import {routes} from '../route.js'; import type {Route} from '../router.js'; import {RouteObserverMixin, Router} from '../router.js'; +import {ContentSettingsTypes} from '../site_settings/constants.js'; +import type {SiteSettingsPrefsBrowserProxy} from '../site_settings/site_settings_prefs_browser_proxy.js'; +import {SiteSettingsPrefsBrowserProxyImpl} from '../site_settings/site_settings_prefs_browser_proxy.js'; +import {isSettingEnabled} from '../site_settings/site_settings_util.js'; import type {SettingsCollapseRadioButtonElement} from './collapse_radio_button.js'; import {getTemplate} from './security_page.html.js'; @@ -75,8 +80,8 @@ }; } -const SettingsSecurityPageElementBase = - HelpBubbleMixin(RouteObserverMixin(I18nMixin(PrefsMixin(PolymerElement)))); +const SettingsSecurityPageElementBase = HelpBubbleMixin(RouteObserverMixin( + WebUiListenerMixin(I18nMixin(PrefsMixin(PolymerElement))))); export class SettingsSecurityPageElement extends SettingsSecurityPageElementBase { @@ -138,6 +143,11 @@ value: () => [HttpsFirstModeSetting.DISABLED], }, + javascriptOptimizerSubLabel_: { + type: String, + value: '', + }, + enableHttpsFirstModeNewSettings_: { type: Boolean, readOnly: true, @@ -234,6 +244,7 @@ declare private enableHashPrefixRealTimeLookups_: boolean; declare private httpsFirstModeUncheckedValues_: HttpsFirstModeSetting[]; declare private enableHttpsFirstModeNewSettings_: boolean; + declare private javascriptOptimizerSubLabel_: string; declare private lastFocusTime_: number|undefined; declare private totalTimeInFocus_: number; declare private lastInteraction_: SecurityPageInteraction; @@ -246,6 +257,8 @@ PrivacyPageBrowserProxyImpl.getInstance(); private metricsBrowserProxy_: MetricsBrowserProxy = MetricsBrowserProxyImpl.getInstance(); + private siteBrowserProxy_: SiteSettingsPrefsBrowserProxy = + SiteSettingsPrefsBrowserProxyImpl.getInstance(); private focusConfigChanged_(_newConfig: FocusConfig, oldConfig: FocusConfig) { assert(!oldConfig); @@ -262,8 +275,8 @@ if (routes.SITE_SETTINGS_JAVASCRIPT_OPTIMIZER) { this.focusConfig.set( routes.SITE_SETTINGS_JAVASCRIPT_OPTIMIZER.path, () => { - const toFocus = - this.shadowRoot!.querySelector<HTMLElement>('#v8SettingLink'); + const toFocus = this.shadowRoot!.querySelector<HTMLElement>( + '#javascriptOptimizerSettingLink'); assert(toFocus); focusWithoutInk(toFocus); }); @@ -300,6 +313,14 @@ // Initialize the last focus time on page load. this.lastFocusTime_ = HatsBrowserProxyImpl.getInstance().now(); + + this.addWebUiListener( + 'contentSettingCategoryChanged', (category: ContentSettingsTypes) => { + if (category === ContentSettingsTypes.JAVASCRIPT_OPTIMIZER) { + this.updateJavascriptOptimizerEnabledByDefault_(); + } + }); + this.updateJavascriptOptimizerEnabledByDefault_(); } /** @@ -390,6 +411,16 @@ this.$.safeBrowsingStandard.updateCollapsed(); } + private async updateJavascriptOptimizerEnabledByDefault_() { + const defaultValue = + await this.siteBrowserProxy_.getDefaultValueForContentType( + ContentSettingsTypes.JAVASCRIPT_OPTIMIZER); + this.javascriptOptimizerSubLabel_ = this.i18n( + isSettingEnabled(defaultValue.setting) ? + 'securityJavascriptOptimizerLinkRowLabelEnabled' : + 'securityJavascriptOptimizerLinkRowLabelDisabled'); + } + /** * Possibly displays the Safe Browsing disable dialog based on the users * selection. @@ -495,7 +526,7 @@ window.open(loadTimeData.getString('advancedProtectionURL')); } - private onV8SettingsClick_() { + private onJavascriptOptimizerSettingsClick_() { Router.getInstance().navigateTo(routes.SITE_SETTINGS_JAVASCRIPT_OPTIMIZER); }
diff --git a/chrome/browser/resources/settings/privacy_page/security_page_v2.html b/chrome/browser/resources/settings/privacy_page/security_page_v2.html index 2fdb6abe..57180f6 100644 --- a/chrome/browser/resources/settings/privacy_page/security_page_v2.html +++ b/chrome/browser/resources/settings/privacy_page/security_page_v2.html
@@ -1 +1,18 @@ -<h1 class="cr-title-text">Bundled Security Settings</h2> +<h1 class="cr-title-text">Bundled Security Settings</h1> +<settings-radio-group id="bundlesRadioGroup" + pref="{{prefs.generated.security_settings_bundle}}" + selectable-elements="cr-radio-button, settings-collapse-radio-button"> + <!-- TODO(crbug.com/423878094): Replace hardcoded strings. --> + <settings-collapse-radio-button id="securitySettingsBundleEnhanced" + name="[[securitySettingsBundleSettingEnum_.ENHANCED]]" + pref="[[prefs.generated.security_settings_bundle]]" + label="Enhanced Bundle" + no-automatic-collapse> + </settings-collapse-radio-button> + <settings-collapse-radio-button id="securitySettingsBundleStandard" + name="[[securitySettingsBundleSettingEnum_.STANDARD]]" + pref="[[prefs.generated.security_settings_bundle]]" + label="Standard Bundle" + no-automatic-collapse> + </settings-collapse-radio-button> +</settings-radio-group>
diff --git a/chrome/browser/resources/settings/privacy_page/security_page_v2.ts b/chrome/browser/resources/settings/privacy_page/security_page_v2.ts index c51416e..66b730d3 100644 --- a/chrome/browser/resources/settings/privacy_page/security_page_v2.ts +++ b/chrome/browser/resources/settings/privacy_page/security_page_v2.ts
@@ -5,8 +5,26 @@ import {PrefsMixin} from '/shared/settings/prefs/prefs_mixin.js'; import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import type {SettingsRadioGroupElement} from '../controls/settings_radio_group.js'; + +import type {SettingsCollapseRadioButtonElement} from './collapse_radio_button.js'; import {getTemplate} from './security_page_v2.html.js'; +/** Enumeration of all security settings bundle modes.*/ +// LINT.IfChange(SecuritySettingsBundleSetting) +export enum SecuritySettingsBundleSetting { + STANDARD = 0, + ENHANCED = 1, +} +// LINT.ThenChange(/chrome/browser/safe_browsing/generated_security_settings_bundle_pref.h:SecuritySettingsBundleSetting) +export interface SettingsSecurityPageV2Element { + $: { + securitySettingsBundleEnhanced: SettingsCollapseRadioButtonElement, + bundlesRadioGroup: SettingsRadioGroupElement, + securitySettingsBundleStandard: SettingsCollapseRadioButtonElement, + }; +} + const SettingsSecurityPageV2ElementBase = PrefsMixin(PolymerElement); export class SettingsSecurityPageV2Element extends @@ -18,6 +36,16 @@ static get template() { return getTemplate(); } + + static get properties() { + return { + /** Valid security settings bundle states.*/ + securitySettingsBundleSettingEnum_: { + type: Object, + value: SecuritySettingsBundleSetting, + }, + }; + } } declare global {
diff --git a/chrome/browser/safe_browsing/android/java/src/org/chromium/chrome/browser/safe_browsing/AdvancedProtectionMediatorTest.java b/chrome/browser/safe_browsing/android/java/src/org/chromium/chrome/browser/safe_browsing/AdvancedProtectionMediatorTest.java index eb219041..56e8ad2 100644 --- a/chrome/browser/safe_browsing/android/java/src/org/chromium/chrome/browser/safe_browsing/AdvancedProtectionMediatorTest.java +++ b/chrome/browser/safe_browsing/android/java/src/org/chromium/chrome/browser/safe_browsing/AdvancedProtectionMediatorTest.java
@@ -52,7 +52,7 @@ public class AdvancedProtectionMediatorTest { @Mock private WindowAndroid mWindowAndroid; @Mock private Context mContext; - private final WeakReference<Context> mWeakContext = new WeakReference<Context>(mContext); + private final WeakReference<Context> mWeakContext = new WeakReference<>(mContext); private final UnownedUserDataHost mWindowUserDataHost = new UnownedUserDataHost(); @Mock private ManagedMessageDispatcher mMessageDispatcher;
diff --git a/chrome/browser/safe_browsing/generated_security_settings_bundle_pref.cc b/chrome/browser/safe_browsing/generated_security_settings_bundle_pref.cc new file mode 100644 index 0000000..a73249df --- /dev/null +++ b/chrome/browser/safe_browsing/generated_security_settings_bundle_pref.cc
@@ -0,0 +1,75 @@ +// Copyright 2025 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/safe_browsing/generated_security_settings_bundle_pref.h" + +#include "base/types/cxx23_to_underlying.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/common/extensions/api/settings_private.h" +#include "components/prefs/pref_service.h" +#include "components/safe_browsing/core/common/safe_browsing_prefs.h" + +namespace settings_api = extensions::api::settings_private; + +namespace safe_browsing { + +const char kGeneratedSecuritySettingsBundlePref[] = + "generated.security_settings_bundle"; + +GeneratedSecuritySettingsBundlePref::GeneratedSecuritySettingsBundlePref( + Profile* profile) + : profile_(profile) { + user_prefs_registrar_.Init(profile->GetPrefs()); + user_prefs_registrar_.Add( + prefs::kSecuritySettingsBundle, + base::BindRepeating(&GeneratedSecuritySettingsBundlePref:: + OnSecuritySettingsBundlePreferencesChanged, + base::Unretained(this))); +} + +extensions::settings_private::SetPrefResult +GeneratedSecuritySettingsBundlePref::SetPref(const base::Value* value) { + if (!value->is_int()) { + return extensions::settings_private::SetPrefResult::PREF_TYPE_MISMATCH; + } + + auto selection = static_cast<int>(value->GetInt()); + + if (selection != static_cast<int>(SecuritySettingsBundleSetting::STANDARD) && + selection != static_cast<int>(SecuritySettingsBundleSetting::ENHANCED)) { + return extensions::settings_private::SetPrefResult::PREF_TYPE_MISMATCH; + } + // Update Security Settings Bundle preference to match selection. + profile_->GetPrefs()->SetInteger(prefs::kSecuritySettingsBundle, selection); + + return extensions::settings_private::SetPrefResult::SUCCESS; +} + +extensions::api::settings_private::PrefObject +GeneratedSecuritySettingsBundlePref::GetPrefObject() const { + extensions::api::settings_private::PrefObject pref_object; + pref_object.key = kGeneratedSecuritySettingsBundlePref; + pref_object.type = extensions::api::settings_private::PrefType::kNumber; + + auto security_settings_bundle_enabled = + profile_->GetPrefs()->GetInteger(prefs::kSecuritySettingsBundle); + + if (security_settings_bundle_enabled == + static_cast<int>(SecuritySettingsBundleSetting::ENHANCED)) { + pref_object.value = + base::Value(static_cast<int>(SecuritySettingsBundleSetting::ENHANCED)); + } else { + pref_object.value = + base::Value(static_cast<int>(SecuritySettingsBundleSetting::STANDARD)); + } + + return pref_object; +} + +void GeneratedSecuritySettingsBundlePref:: + OnSecuritySettingsBundlePreferencesChanged() { + NotifyObservers(kGeneratedSecuritySettingsBundlePref); +} + +} // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/generated_security_settings_bundle_pref.h b/chrome/browser/safe_browsing/generated_security_settings_bundle_pref.h new file mode 100644 index 0000000..983d263c --- /dev/null +++ b/chrome/browser/safe_browsing/generated_security_settings_bundle_pref.h
@@ -0,0 +1,55 @@ +// Copyright 2025 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_SAFE_BROWSING_GENERATED_SECURITY_SETTINGS_BUNDLE_PREF_H_ +#define CHROME_BROWSER_SAFE_BROWSING_GENERATED_SECURITY_SETTINGS_BUNDLE_PREF_H_ + +#include "base/memory/raw_ptr.h" +#include "chrome/browser/extensions/api/settings_private/generated_pref.h" +#include "chrome/browser/profiles/profile.h" +#include "components/prefs/pref_change_registrar.h" + +namespace safe_browsing { + +extern const char kGeneratedSecuritySettingsBundlePref[]; + +// Must be kept in sync with the SecuritySettingsBundle enum located in +// chrome/browser/resources/settings/privacy_page/security_page_v2.js. +// LINT.IfChange(SecuritySettingsBundleSetting) +enum class SecuritySettingsBundleSetting { + // Standard bundle with default settings. + STANDARD = 0, + // Enhanced bundle with most secure settings selected. + ENHANCED = 1, +}; +// LINT.ThenChange(/chrome/browser/resources/settings/privacy_page/security_page_v2.ts:SecuritySettingsBundleSetting) + +// A generated preference which represents the effective Security Settings +// Bundled state based on the underlying Security Settings Bundle preference. +// This preference allows the direct use of WebUI controls without exposing any +// logic responsible for coalescing the underlying Security Setting Bundled pref +// to front-end code. +class GeneratedSecuritySettingsBundlePref + : public extensions::settings_private::GeneratedPref { + public: + explicit GeneratedSecuritySettingsBundlePref(Profile* profile); + + // Generated Preference Interface. + extensions::settings_private::SetPrefResult SetPref( + const base::Value* value) override; + extensions::api::settings_private::PrefObject GetPrefObject() const override; + + // Fired when one of the bundle levels are changed. + void OnSecuritySettingsBundlePreferencesChanged(); + + private: + // Weak reference to the profile this preference is generated for. + const raw_ptr<Profile> profile_; + + PrefChangeRegistrar user_prefs_registrar_; +}; + +} // namespace safe_browsing + +#endif // CHROME_BROWSER_SAFE_BROWSING_GENERATED_SECURITY_SETTINGS_BUNDLE_PREF_H_
diff --git a/chrome/browser/safe_browsing/generated_security_settings_bundle_pref_unittest.cc b/chrome/browser/safe_browsing/generated_security_settings_bundle_pref_unittest.cc new file mode 100644 index 0000000..fb31399 --- /dev/null +++ b/chrome/browser/safe_browsing/generated_security_settings_bundle_pref_unittest.cc
@@ -0,0 +1,92 @@ +// Copyright 2025 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/safe_browsing/generated_security_settings_bundle_pref.h" + +#include <algorithm> + +#include "chrome/browser/extensions/api/settings_private/generated_pref_test_base.h" +#include "chrome/test/base/testing_profile.h" +#include "components/safe_browsing/core/common/safe_browsing_prefs.h" +#include "components/sync_preferences/testing_pref_service_syncable.h" +#include "content/public/test/browser_task_environment.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace settings_private = extensions::settings_private; + +namespace safe_browsing { + +namespace { + +// Sets the value of |generated_pref| to |pref_value| and then checks Security +// Bundled Settings preference value in |prefs| match the provided expected +// values. After preference has been set, the value of |generated_pref| is +// checked to ensure it has correctly updated to |pref_value|. +void ValidateGeneratedPrefSetting( + sync_preferences::TestingPrefServiceSyncable* prefs, + GeneratedSecuritySettingsBundlePref* generated_pref, + SecuritySettingsBundleSetting pref_value, + int security_settings_bundle_level) { + EXPECT_EQ( + generated_pref->SetPref( + std::make_unique<base::Value>(static_cast<int>(pref_value)).get()), + settings_private::SetPrefResult::SUCCESS); + EXPECT_EQ(prefs->GetUserPref(prefs::kSecuritySettingsBundle)->GetInt(), + security_settings_bundle_level); + EXPECT_EQ(static_cast<SecuritySettingsBundleSetting>( + generated_pref->GetPrefObject().value->GetInt()), + pref_value); +} + +} // namespace + +typedef settings_private::GeneratedPrefTestBase + GeneratedSecuritySettingsBundlePrefTest; + +TEST_F(GeneratedSecuritySettingsBundlePrefTest, UpdatePreference) { + // Validate that the generated Security Settings Bundle preference correctly + // updates the base Security Settings Bundle preference. + auto pref = std::make_unique<GeneratedSecuritySettingsBundlePref>(profile()); + + // Setup baseline profile preference state. + prefs()->SetDefaultPrefValue( + prefs::kSecuritySettingsBundle, + base::Value(static_cast<int>(SecuritySettingsBundleSetting::STANDARD))); + + // Check all possible settings both correctly update preferences and are + // correctly returned by the generated preference. + ValidateGeneratedPrefSetting(prefs(), pref.get(), + SecuritySettingsBundleSetting::ENHANCED, 1); + ValidateGeneratedPrefSetting(prefs(), pref.get(), + SecuritySettingsBundleSetting::STANDARD, 0); + + // Confirm that a type mismatch is reported as such. + EXPECT_EQ(pref->SetPref(std::make_unique<base::Value>(true).get()), + settings_private::SetPrefResult::PREF_TYPE_MISMATCH); + // Check a numerical value outside of the acceptable range. + EXPECT_EQ( + pref->SetPref( + std::make_unique<base::Value>( + static_cast<int>(SecuritySettingsBundleSetting::ENHANCED) + 1) + .get()), + settings_private::SetPrefResult::PREF_TYPE_MISMATCH); +} + +TEST_F(GeneratedSecuritySettingsBundlePrefTest, NotifyPrefUpdates) { + // Update source Security Settings Bundle preference and ensure an observer is + // fired. + auto pref = std::make_unique<GeneratedSecuritySettingsBundlePref>(profile()); + + settings_private::TestGeneratedPrefObserver test_observer; + pref->AddObserver(&test_observer); + + prefs()->SetUserPref(prefs::kSecuritySettingsBundle, + std::make_unique<base::Value>(static_cast<int>( + SecuritySettingsBundleSetting::ENHANCED))); + EXPECT_EQ(test_observer.GetUpdatedPrefName(), + kGeneratedSecuritySettingsBundlePref); + test_observer.Reset(); +} + +} // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/phishy_interaction_tracker_unittest.cc b/chrome/browser/safe_browsing/phishy_interaction_tracker_unittest.cc index 28eeaa7..d4fc947 100644 --- a/chrome/browser/safe_browsing/phishy_interaction_tracker_unittest.cc +++ b/chrome/browser/safe_browsing/phishy_interaction_tracker_unittest.cc
@@ -252,9 +252,7 @@ base::RunLoop run_loop; base::StatisticsRecorder::ScopedHistogramSampleObserver observer( - "SafeBrowsing.PhishySite.PasteEventCount", - base::IgnoreArgs<std::string_view, uint64_t, - base::HistogramBase::Sample32>(run_loop.QuitClosure())); + "SafeBrowsing.PhishySite.PasteEventCount", run_loop.QuitClosure()); run_loop.Run(); histogram_tester_.ExpectUniqueSample(
diff --git a/chrome/browser/safe_browsing/threat_details_unittest.cc b/chrome/browser/safe_browsing/threat_details_unittest.cc index fdc82105..136711b 100644 --- a/chrome/browser/safe_browsing/threat_details_unittest.cc +++ b/chrome/browser/safe_browsing/threat_details_unittest.cc
@@ -9,6 +9,7 @@ #include <algorithm> #include "base/functional/bind.h" +#include "base/hash/md5.h" #include "base/memory/raw_ptr.h" #include "base/pickle.h" #include "base/run_loop.h"
diff --git a/chrome/browser/safety_check/android/java/src/org/chromium/chrome/browser/safety_check/SafetyCheckCoordinator.java b/chrome/browser/safety_check/android/java/src/org/chromium/chrome/browser/safety_check/SafetyCheckCoordinator.java index a62cbb0..3549769 100644 --- a/chrome/browser/safety_check/android/java/src/org/chromium/chrome/browser/safety_check/SafetyCheckCoordinator.java +++ b/chrome/browser/safety_check/android/java/src/org/chromium/chrome/browser/safety_check/SafetyCheckCoordinator.java
@@ -114,7 +114,7 @@ .getViewLifecycleOwnerLiveData() .observe( mSettingsFragment, - new Observer<LifecycleOwner>() { + new Observer<>() { @Override public void onChanged(LifecycleOwner lifecycleOwner) { // Only interested in the event when the View becomes non-null,
diff --git a/chrome/browser/safety_hub/android/java/src/org/chromium/chrome/browser/safety_hub/SafetyHubFragment.java b/chrome/browser/safety_hub/android/java/src/org/chromium/chrome/browser/safety_hub/SafetyHubFragment.java index 0e237ddb..a66c5c9 100644 --- a/chrome/browser/safety_hub/android/java/src/org/chromium/chrome/browser/safety_hub/SafetyHubFragment.java +++ b/chrome/browser/safety_hub/android/java/src/org/chromium/chrome/browser/safety_hub/SafetyHubFragment.java
@@ -128,7 +128,7 @@ findPreference(PREF_SAFE_BROWSING), this, getProfile()); mModuleMediators = - new ArrayList<SafetyHubModuleMediator>( + new ArrayList<>( Arrays.asList( updateCheckModuleMediator, permissionsRevocationModuleMediator,
diff --git a/chrome/browser/segmentation_platform/android/javatests/src/org/chromium/chrome/browser/segmentation_platform/SegmentationPlatformServiceFactoryTest.java b/chrome/browser/segmentation_platform/android/javatests/src/org/chromium/chrome/browser/segmentation_platform/SegmentationPlatformServiceFactoryTest.java index 9d98f691..01933b3 100644 --- a/chrome/browser/segmentation_platform/android/javatests/src/org/chromium/chrome/browser/segmentation_platform/SegmentationPlatformServiceFactoryTest.java +++ b/chrome/browser/segmentation_platform/android/javatests/src/org/chromium/chrome/browser/segmentation_platform/SegmentationPlatformServiceFactoryTest.java
@@ -68,7 +68,7 @@ "intentional_user", options, null, - new Callback<ClassificationResult>() { + new Callback<>() { @Override public void onResult(ClassificationResult result) { Assert.assertEquals( @@ -120,7 +120,7 @@ "contextual_page_actions", options, inputContext, - new Callback<ClassificationResult>() { + new Callback<>() { @Override public void onResult(ClassificationResult result) { Assert.assertEquals(
diff --git a/chrome/browser/serial/android/java/src/org/chromium/chrome/browser/serial/SerialNotificationManager.java b/chrome/browser/serial/android/java/src/org/chromium/chrome/browser/serial/SerialNotificationManager.java index bace2929..4acf51e 100644 --- a/chrome/browser/serial/android/java/src/org/chromium/chrome/browser/serial/SerialNotificationManager.java +++ b/chrome/browser/serial/android/java/src/org/chromium/chrome/browser/serial/SerialNotificationManager.java
@@ -51,7 +51,7 @@ private final SerialNotificationManagerDelegate mDelegate; private final BaseNotificationManagerProxy mNotificationManager; private final SharedPreferencesManager mSharedPreferences; - private final List<Integer> mNotificationIds = new ArrayList<Integer>(); + private final List<Integer> mNotificationIds = new ArrayList<>(); public SerialNotificationManager( BaseNotificationManagerProxy notificationManager,
diff --git a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/ShareDelegateSupplier.java b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/ShareDelegateSupplier.java index f4c88df5..641410d 100644 --- a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/ShareDelegateSupplier.java +++ b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/ShareDelegateSupplier.java
@@ -19,7 +19,7 @@ @NullMarked public class ShareDelegateSupplier extends UnownedUserDataSupplier<ShareDelegate> { private static final UnownedUserDataKey<ShareDelegateSupplier> KEY = - new UnownedUserDataKey<ShareDelegateSupplier>(ShareDelegateSupplier.class); + new UnownedUserDataKey<>(ShareDelegateSupplier.class); private static @Nullable ShareDelegateSupplier sInstanceForTesting;
diff --git a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/link_to_text/LinkToTextHelper.java b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/link_to_text/LinkToTextHelper.java index e6cffc0..3b983946 100644 --- a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/link_to_text/LinkToTextHelper.java +++ b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/link_to_text/LinkToTextHelper.java
@@ -78,7 +78,7 @@ tab.getWebContents() .getMainFrame() .getCanonicalUrlForSharing( - new Callback<GURL>() { + new Callback<>() { @Override public void onResult(GURL result) { callback.onResult(result.getSpec()); @@ -153,7 +153,7 @@ List<RenderFrameHost> renderFrameHosts = tab.getWebContents().getMainFrame().getAllRenderFrameHosts(); getExistingSelectorsFromFrameAtIndex( - new ArrayList<String>(), renderFrameHosts, callback, /* index= */ 0); + new ArrayList<>(), renderFrameHosts, callback, /* index= */ 0); } /**
diff --git a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/long_screenshots/bitmap_generation/EntryManager.java b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/long_screenshots/bitmap_generation/EntryManager.java index 8376630b..d117cfc 100644 --- a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/long_screenshots/bitmap_generation/EntryManager.java +++ b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/long_screenshots/bitmap_generation/EntryManager.java
@@ -69,8 +69,8 @@ * @param inMemory Use memory buffers to store the capture rather than temporary files. */ public EntryManager(ScreenshotBoundsManager boundsManager, Tab tab, boolean inMemory) { - mEntries = new ArrayList<LongScreenshotsEntry>(); - mQueuedEntries = new ArrayList<LongScreenshotsEntry>(); + mEntries = new ArrayList<>(); + mQueuedEntries = new ArrayList<>(); mGeneratorObservers = new ObserverList<>(); mBoundsManager = boundsManager;
diff --git a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/qrcode/QrCodeDialog.java b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/qrcode/QrCodeDialog.java index 6c24116..9a3b0667 100644 --- a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/qrcode/QrCodeDialog.java +++ b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/qrcode/QrCodeDialog.java
@@ -112,7 +112,7 @@ assert tabLayout.getTabCount() == mTabs.size(); // Setup page adapter and tab layout. - ArrayList<View> pages = new ArrayList<View>(); + ArrayList<View> pages = new ArrayList<>(); for (int index = 0; index < mTabs.size(); index++) { QrCodeDialogTab tab = mTabs.get(index);
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 33e1bb9..8733fdc 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
@@ -22,7 +22,7 @@ * Callback to perform the specified operation. Argument to callback must be a NoArgOperation */ public static final WritableObjectPropertyKey<Callback<Integer>> NO_ARG_OPERATION_LISTENER = - new WritableObjectPropertyKey<Callback<Integer>>(); + new WritableObjectPropertyKey<>(); public static final WritableObjectPropertyKey<Bitmap> SCREENSHOT_BITMAP = new WritableObjectPropertyKey<>();
diff --git a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/send_tab_to_self/NotificationSharedPrefManager.java b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/send_tab_to_self/NotificationSharedPrefManager.java index 9c170302..e304b98 100644 --- a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/send_tab_to_self/NotificationSharedPrefManager.java +++ b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/send_tab_to_self/NotificationSharedPrefManager.java
@@ -116,9 +116,9 @@ SharedPreferencesManager prefs, String prefName) { Set<String> prefValue = prefs.readStringSet(prefName, null); if (prefValue == null) { - return new HashSet<String>(); + return new HashSet<>(); } - return new HashSet<String>(prefValue); + return new HashSet<>(prefValue); } /**
diff --git a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetUsageRankingHelper.java b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetUsageRankingHelper.java index 04fa26a..b869dedd 100644 --- a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetUsageRankingHelper.java +++ b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetUsageRankingHelper.java
@@ -125,8 +125,8 @@ availableResolveInfos.addAll( ShareHelper.getCompatibleAppsForSharingFiles(params.getFileContentType())); - List<String> availableActivities = new ArrayList<String>(); - Map<String, ResolveInfo> resolveInfos = new HashMap<String, ResolveInfo>(); + List<String> availableActivities = new ArrayList<>(); + Map<String, ResolveInfo> resolveInfos = new HashMap<>(); // The system can return ResolveInfos which refer to activities exported // by Chrome - especially the Print activity. We don't want to offer @@ -194,7 +194,7 @@ // package. private List<ResolveInfo> filterOutOwnResolveInfos(List<ResolveInfo> infos) { String currentPackageName = ContextUtils.getApplicationContext().getPackageName(); - List<ResolveInfo> remaining = new ArrayList<ResolveInfo>(); + List<ResolveInfo> remaining = new ArrayList<>(); for (ResolveInfo info : infos) { if (!info.activityInfo.packageName.equals(currentPackageName)) { remaining.add(info); @@ -206,7 +206,7 @@ // Returns a new list of ResolveInfos with blocklisted packages removed. @VisibleForTesting static List<ResolveInfo> filterOutBlocklistedResolveInfos(List<ResolveInfo> infos) { - List<ResolveInfo> remaining = new ArrayList<ResolveInfo>(); + List<ResolveInfo> remaining = new ArrayList<>(); for (ResolveInfo info : infos) { if (!PACKAGE_BLOCK_LIST.contains(info.activityInfo.packageName)) { remaining.add(info); @@ -251,7 +251,7 @@ List<String> targets) { // Build PropertyModels for all the ResolveInfos that correspond to // actual targets, in the order that we're going to show them. - List<PropertyModel> models = new ArrayList<PropertyModel>(); + List<PropertyModel> models = new ArrayList<>(); for (String target : targets) { if (target.equals(MORE_TARGET_NAME)) { models.add(createMorePropertyModel(activity, params, saveLastUsed));
diff --git a/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/long_screenshots/bitmap_generation/BitmapGeneratorTest.java b/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/long_screenshots/bitmap_generation/BitmapGeneratorTest.java index 1d2febdd..fdb0b156 100644 --- a/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/long_screenshots/bitmap_generation/BitmapGeneratorTest.java +++ b/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/long_screenshots/bitmap_generation/BitmapGeneratorTest.java
@@ -81,7 +81,7 @@ }; Callback<Bitmap> onBitmapGenerated = - new Callback<Bitmap>() { + new Callback<>() { @Override public void onResult(Bitmap result) { Assert.assertNotNull(result);
diff --git a/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/long_screenshots/bitmap_generation/LongScreenshotsCompositorTest.java b/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/long_screenshots/bitmap_generation/LongScreenshotsCompositorTest.java index d15752a..876ae5f4 100644 --- a/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/long_screenshots/bitmap_generation/LongScreenshotsCompositorTest.java +++ b/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/long_screenshots/bitmap_generation/LongScreenshotsCompositorTest.java
@@ -149,7 +149,7 @@ @Test public void testSuccessfulCompositing() { Callback<Bitmap> onBitmapResult = - new Callback<Bitmap>() { + new Callback<>() { @Override public void onResult(Bitmap result) { Assert.assertEquals(mTestBitmap, result); @@ -157,7 +157,7 @@ }; Callback<Integer> compositorCallback = - new Callback<Integer>() { + new Callback<>() { @Override public void onResult(Integer result) { Assert.assertEquals((Integer) CompositorStatus.OK, result); @@ -197,7 +197,7 @@ public void testRequestBitmapFailure() { mCompositorDelegate.setRequestBitmapError(); Callback<Bitmap> onBitmapResult = - new Callback<Bitmap>() { + new Callback<>() { @Override public void onResult(Bitmap result) { Assert.fail("Bitmap should not be returned"); @@ -205,7 +205,7 @@ }; Callback<Integer> compositorCallback = - new Callback<Integer>() { + new Callback<>() { @Override public void onResult(Integer result) { Assert.assertEquals((Integer) CompositorStatus.OK, result); @@ -242,7 +242,7 @@ @Test public void testCompositorError() { Callback<Integer> compositorCallback = - new Callback<Integer>() { + new Callback<>() { @Override public void onResult(Integer result) { Assert.assertEquals((Integer) CompositorStatus.INVALID_REQUEST, result);
diff --git a/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/long_screenshots/bitmap_generation/LongScreenshotsEntryTest.java b/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/long_screenshots/bitmap_generation/LongScreenshotsEntryTest.java index 35d76109..553e84d 100644 --- a/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/long_screenshots/bitmap_generation/LongScreenshotsEntryTest.java +++ b/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/long_screenshots/bitmap_generation/LongScreenshotsEntryTest.java
@@ -95,7 +95,7 @@ new LongScreenshotsEntry( testGenerator, new Rect(0, 1000, 0, 2000), - new Callback<Integer>() { + new Callback<>() { @Override public void onResult(Integer result) { assertEquals(2097152, (int) result); @@ -119,7 +119,7 @@ new LongScreenshotsEntry( testGenerator, new Rect(0, 1000, 0, 2000), - new Callback<Integer>() { + new Callback<>() { @Override public void onResult(Integer result) { fail("MemoryUsage should not be called");
diff --git a/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/screenshot/ScreenshotShareSheetViewTest.java b/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/screenshot/ScreenshotShareSheetViewTest.java index f45bb6e..97cd7460 100644 --- a/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/screenshot/ScreenshotShareSheetViewTest.java +++ b/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/screenshot/ScreenshotShareSheetViewTest.java
@@ -53,7 +53,7 @@ private final AtomicBoolean mSaveClicked = new AtomicBoolean(); private final Callback<Integer> mMockNoArgListener = - new Callback<Integer>() { + new Callback<>() { @Override public void onResult( @ScreenshotShareSheetViewProperties.NoArgOperation Integer operation) {
diff --git a/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetTest.java b/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetTest.java index 5842740..e927186 100644 --- a/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetTest.java +++ b/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetTest.java
@@ -271,7 +271,7 @@ * 'a', 'b', 'c', 'd', 'e' }. */ private List<String> defaultTestSystemApps() { - List<String> apps = new ArrayList<String>(); + List<String> apps = new ArrayList<>(); for (String s : Arrays.asList("a", "b", "c", "d", "e")) { apps.add(packageNameFromLabel(s)); }
diff --git a/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetUsageRankingHelperTest.java b/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetUsageRankingHelperTest.java index bdbd7c6..db3552f8 100644 --- a/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetUsageRankingHelperTest.java +++ b/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetUsageRankingHelperTest.java
@@ -106,7 +106,7 @@ @Test @SmallTest public void testCreateThirdPartyPropertyModelsFromUsageRanking() throws TimeoutException { - List<String> targets = new ArrayList<String>(); + List<String> targets = new ArrayList<>(); targets.add("$more"); targets.add("$more"); final AtomicReference<List<PropertyModel>> resultPropertyModels = new AtomicReference<>(); @@ -139,7 +139,7 @@ @Test @SmallTest public void testClickMoreRemovesCallback() throws TimeoutException { - List<String> targets = new ArrayList<String>(); + List<String> targets = new ArrayList<>(); targets.add("$more"); final AtomicReference<List<PropertyModel>> resultPropertyModels = new AtomicReference<>(); CallbackHelper helper = new CallbackHelper();
diff --git a/chrome/browser/ssl/https_upgrades_browsertest.cc b/chrome/browser/ssl/https_upgrades_browsertest.cc index 14f7c34..fbe8ddf 100644 --- a/chrome/browser/ssl/https_upgrades_browsertest.cc +++ b/chrome/browser/ssl/https_upgrades_browsertest.cc
@@ -64,8 +64,10 @@ #include "net/test/test_data_directory.h" #include "services/metrics/public/cpp/ukm_builders.h" #include "services/metrics/public/cpp/ukm_source.h" +#include "services/network/public/cpp/ip_address_space_overrides_test_utils.h" #include "services/network/public/cpp/network_switches.h" #include "services/network/public/cpp/url_loader_completion_status.h" +#include "services/network/public/mojom/ip_address_space.mojom.h" #include "services/network/public/mojom/network_context.mojom.h" #include "services/network/public/mojom/url_response_head.mojom.h" #include "ui/base/l10n/l10n_util.h" @@ -375,11 +377,10 @@ // // TODO(crbug.com/422956041): figure out why we need to do this, there may // be a bug where IP address spaces are not being set correctly. - command_line->AppendSwitchASCII( - network::switches::kIpAddressSpaceOverrides, - base::StringPrintf("%s=public,%s=public", - http_server_.host_port_pair().ToString().c_str(), - https_server_.host_port_pair().ToString().c_str())); + network::AddIpAddressSpaceOverridesToCommandLine( + {network::GenerateIpAddressSpaceOverride(http_server_), + network::GenerateIpAddressSpaceOverride(https_server_)}, + *command_line); } void SetUpInProcessBrowserTestFixture() override {
diff --git a/chrome/browser/sync/sync_service_factory_unittest.cc b/chrome/browser/sync/sync_service_factory_unittest.cc index 2706fa23..0ad27fff 100644 --- a/chrome/browser/sync/sync_service_factory_unittest.cc +++ b/chrome/browser/sync/sync_service_factory_unittest.cc
@@ -132,15 +132,7 @@ datatypes.Put(syncer::SEARCH_ENGINES); #endif // !BUILDFLAG(IS_ANDROID) -#if BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) || \ - BUILDFLAG(IS_WIN) datatypes.Put(syncer::SAVED_TAB_GROUP); -#elif BUILDFLAG(IS_ANDROID) - if (base::FeatureList::IsEnabled(tab_groups::kTabGroupSyncAndroid)) { - datatypes.Put(syncer::SAVED_TAB_GROUP); - } -#endif // BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) || - // BUILDFLAG(IS_WIN) #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN) datatypes.Put(syncer::DICTIONARY);
diff --git a/chrome/browser/tab_group_sync/android/java/src/org/chromium/chrome/browser/tab_group_sync/TabGroupSyncLocalObserverUnitTest.java b/chrome/browser/tab_group_sync/android/java/src/org/chromium/chrome/browser/tab_group_sync/TabGroupSyncLocalObserverUnitTest.java index 6697b8b..608f4e4 100644 --- a/chrome/browser/tab_group_sync/android/java/src/org/chromium/chrome/browser/tab_group_sync/TabGroupSyncLocalObserverUnitTest.java +++ b/chrome/browser/tab_group_sync/android/java/src/org/chromium/chrome/browser/tab_group_sync/TabGroupSyncLocalObserverUnitTest.java
@@ -297,7 +297,7 @@ public void testWillCloseMultipleTabs_GroupHiding() { List<Tab> tabs = new ArrayList<>(Arrays.asList(mTab1, mTab2)); when(mTabGroupModelFilter.getLazyAllTabGroupIds(any(), anyBoolean())) - .thenReturn(LazyOneshotSupplier.fromValue(new HashSet<Token>())); + .thenReturn(LazyOneshotSupplier.fromValue(new HashSet<>())); when(mTabGroupModelFilter.isTabGroupHiding(TOKEN_1)).thenReturn(true); mTabModelObserverCaptor.getValue().willCloseMultipleTabs(/* allowUndo= */ true, tabs);
diff --git a/chrome/browser/tab_group_sync/android/java/src/org/chromium/chrome/browser/tab_group_sync/TabGroupSyncLocalToRemoteTest.java b/chrome/browser/tab_group_sync/android/java/src/org/chromium/chrome/browser/tab_group_sync/TabGroupSyncLocalToRemoteTest.java index 849f529..391b51f 100644 --- a/chrome/browser/tab_group_sync/android/java/src/org/chromium/chrome/browser/tab_group_sync/TabGroupSyncLocalToRemoteTest.java +++ b/chrome/browser/tab_group_sync/android/java/src/org/chromium/chrome/browser/tab_group_sync/TabGroupSyncLocalToRemoteTest.java
@@ -19,9 +19,7 @@ import org.chromium.base.test.util.DisabledTest; import org.chromium.base.test.util.DoNotBatch; import org.chromium.base.test.util.Feature; -import org.chromium.base.test.util.Features.EnableFeatures; import org.chromium.base.test.util.Restriction; -import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.flags.ChromeSwitches; import org.chromium.chrome.browser.sync.SyncTestRule; import org.chromium.chrome.browser.tab.Tab; @@ -51,7 +49,6 @@ @RunWith(ChromeJUnit4ClassRunner.class) @DoNotBatch(reason = "TODO(b/40743432): SyncTestRule doesn't support batching.") @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE}) -@EnableFeatures({ChromeFeatureList.TAB_GROUP_SYNC_ANDROID}) @Restriction({DeviceFormFactor.PHONE, Restriction.RESTRICTION_TYPE_NON_LOW_END_DEVICE}) public class TabGroupSyncLocalToRemoteTest { public SyncTestRule mSyncTestRule = new SyncTestRule();
diff --git a/chrome/browser/tab_group_sync/android/java/src/org/chromium/chrome/browser/tab_group_sync/TabGroupSyncRemoteObserver.java b/chrome/browser/tab_group_sync/android/java/src/org/chromium/chrome/browser/tab_group_sync/TabGroupSyncRemoteObserver.java index 61fc727..51877da 100644 --- a/chrome/browser/tab_group_sync/android/java/src/org/chromium/chrome/browser/tab_group_sync/TabGroupSyncRemoteObserver.java +++ b/chrome/browser/tab_group_sync/android/java/src/org/chromium/chrome/browser/tab_group_sync/TabGroupSyncRemoteObserver.java
@@ -10,7 +10,6 @@ import org.chromium.base.supplier.Supplier; import org.chromium.build.annotations.NullMarked; import org.chromium.build.annotations.Nullable; -import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.preferences.Pref; import org.chromium.chrome.browser.tabmodel.TabGroupModelFilter; import org.chromium.components.prefs.PrefService; @@ -94,9 +93,7 @@ // Shared tab groups should always auto-open if supported. boolean isAutoOpenEnabled = - ChromeFeatureList.isEnabled(ChromeFeatureList.TAB_GROUP_SYNC_AUTO_OPEN_KILL_SWITCH) - && (mPrefService.getBoolean(Pref.AUTO_OPEN_SYNCED_TAB_GROUPS) - || isCollaboration); + mPrefService.getBoolean(Pref.AUTO_OPEN_SYNCED_TAB_GROUPS) || isCollaboration; if (!isAutoOpenEnabled) return; mEnableLocalObserverCallback.onResult(false);
diff --git a/chrome/browser/tab_group_sync/android/java/src/org/chromium/chrome/browser/tab_group_sync/TabGroupSyncRemoteObserverUnitTest.java b/chrome/browser/tab_group_sync/android/java/src/org/chromium/chrome/browser/tab_group_sync/TabGroupSyncRemoteObserverUnitTest.java index d544b277..991f601 100644 --- a/chrome/browser/tab_group_sync/android/java/src/org/chromium/chrome/browser/tab_group_sync/TabGroupSyncRemoteObserverUnitTest.java +++ b/chrome/browser/tab_group_sync/android/java/src/org/chromium/chrome/browser/tab_group_sync/TabGroupSyncRemoteObserverUnitTest.java
@@ -26,9 +26,6 @@ import org.chromium.base.Token; import org.chromium.base.supplier.Supplier; import org.chromium.base.test.BaseRobolectricTestRunner; -import org.chromium.base.test.util.Features.DisableFeatures; -import org.chromium.base.test.util.Features.EnableFeatures; -import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.preferences.Pref; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.tab.MockTab; @@ -52,7 +49,6 @@ /** Unit tests for the {@link TabGroupSyncRemoteObserver}. */ @RunWith(BaseRobolectricTestRunner.class) @Config(manifest = Config.NONE) -@EnableFeatures(ChromeFeatureList.TAB_GROUP_SYNC_AUTO_OPEN_KILL_SWITCH) public class TabGroupSyncRemoteObserverUnitTest { private static final Token TOKEN_1 = new Token(2, 3); private static final Token TOKEN_2 = new Token(4, 4); @@ -141,14 +137,6 @@ } @Test - @DisableFeatures(ChromeFeatureList.TAB_GROUP_SYNC_AUTO_OPEN_KILL_SWITCH) - public void testAutoOpenKillSwitch() { - SavedTabGroup savedTabGroup = TabGroupSyncTestUtils.createSavedTabGroup(); - mRemoteObserver.onTabGroupAdded(savedTabGroup, TriggerSource.REMOTE); - verify(mLocalMutationHelper, never()).createNewTabGroup(any(), anyInt()); - } - - @Test public void testTabGroupAdded_SkipsSharedTabGroupIfAlreadyOpen() { SavedTabGroup savedTabGroup = TabGroupSyncTestUtils.createSavedTabGroup(); savedTabGroup.localId = LOCAL_TAB_GROUP_ID_1;
diff --git a/chrome/browser/tab_group_sync/android/java/src/org/chromium/chrome/browser/tab_group_sync/TabGroupSyncRemoteToLocalTest.java b/chrome/browser/tab_group_sync/android/java/src/org/chromium/chrome/browser/tab_group_sync/TabGroupSyncRemoteToLocalTest.java index bb4797b1..ab4586b24 100644 --- a/chrome/browser/tab_group_sync/android/java/src/org/chromium/chrome/browser/tab_group_sync/TabGroupSyncRemoteToLocalTest.java +++ b/chrome/browser/tab_group_sync/android/java/src/org/chromium/chrome/browser/tab_group_sync/TabGroupSyncRemoteToLocalTest.java
@@ -25,9 +25,7 @@ import org.chromium.base.test.util.DisabledTest; import org.chromium.base.test.util.DoNotBatch; import org.chromium.base.test.util.Feature; -import org.chromium.base.test.util.Features.EnableFeatures; import org.chromium.base.test.util.Restriction; -import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.flags.ChromeSwitches; import org.chromium.chrome.browser.preferences.Pref; import org.chromium.chrome.browser.profiles.Profile; @@ -45,7 +43,6 @@ @RunWith(ChromeJUnit4ClassRunner.class) @DoNotBatch(reason = "TODO(b/40743432): SyncTestRule doesn't support batching.") @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE}) -@EnableFeatures({ChromeFeatureList.TAB_GROUP_SYNC_ANDROID}) @Restriction({DeviceFormFactor.PHONE, Restriction.RESTRICTION_TYPE_NON_LOW_END_DEVICE}) public class TabGroupSyncRemoteToLocalTest { private static final String TEST_URL1 = "/chrome/test/data/simple.html";
diff --git a/chrome/browser/tab_group_sync/android/java/src/org/chromium/chrome/browser/tab_group_sync/TabGroupSyncServiceFactory.java b/chrome/browser/tab_group_sync/android/java/src/org/chromium/chrome/browser/tab_group_sync/TabGroupSyncServiceFactory.java index 40b5dc09..148ba16 100644 --- a/chrome/browser/tab_group_sync/android/java/src/org/chromium/chrome/browser/tab_group_sync/TabGroupSyncServiceFactory.java +++ b/chrome/browser/tab_group_sync/android/java/src/org/chromium/chrome/browser/tab_group_sync/TabGroupSyncServiceFactory.java
@@ -10,7 +10,6 @@ import org.chromium.base.ResettersForTesting; import org.chromium.build.annotations.NullMarked; import org.chromium.build.annotations.Nullable; -import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.components.tab_group_sync.TabGroupSyncService; @@ -32,10 +31,6 @@ return sTabGroupSyncServiceForTesting; } - if (!ChromeFeatureList.isEnabled(ChromeFeatureList.TAB_GROUP_SYNC_ANDROID)) { - return null; - } - // Throw an exception if the native pointer is not initialized. This is useful to get a more // debuggable stacktrace than failing in native. profile.ensureNativeInitialized();
diff --git a/chrome/browser/tab_group_sync/android/java/src/org/chromium/chrome/browser/tab_group_sync/TabGroupSyncServiceFactoryTest.java b/chrome/browser/tab_group_sync/android/java/src/org/chromium/chrome/browser/tab_group_sync/TabGroupSyncServiceFactoryTest.java index 67b44a6..cb4a878 100644 --- a/chrome/browser/tab_group_sync/android/java/src/org/chromium/chrome/browser/tab_group_sync/TabGroupSyncServiceFactoryTest.java +++ b/chrome/browser/tab_group_sync/android/java/src/org/chromium/chrome/browser/tab_group_sync/TabGroupSyncServiceFactoryTest.java
@@ -18,8 +18,6 @@ import org.chromium.base.test.BaseJUnit4ClassRunner; import org.chromium.base.test.util.Batch; import org.chromium.base.test.util.CommandLineFlags; -import org.chromium.base.test.util.Features.EnableFeatures; -import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.flags.ChromeSwitches; import org.chromium.chrome.browser.profiles.ProfileManager; import org.chromium.chrome.test.ChromeTabbedActivityTestRule; @@ -58,7 +56,6 @@ @Test @MediumTest - @EnableFeatures(ChromeFeatureList.TAB_GROUP_SYNC_ANDROID) public void testServiceCreation_RealService() throws TimeoutException { LibraryLoader.getInstance().ensureInitialized(); mActivityTestRule.startMainActivityOnBlankPage();
diff --git a/chrome/browser/tab_group_sync/feature_utils.cc b/chrome/browser/tab_group_sync/feature_utils.cc index c3431e1..1991526 100644 --- a/chrome/browser/tab_group_sync/feature_utils.cc +++ b/chrome/browser/tab_group_sync/feature_utils.cc
@@ -35,7 +35,7 @@ // deprecate this after a milestone. pref_service->ClearPref(tab_groups::prefs::kSyncableTabGroups); - return base::FeatureList::IsEnabled(tab_groups::kTabGroupSyncAndroid); + return true; #else return IsTabGroupSyncServiceDesktopMigrationEnabled(); #endif // BUILDFLAG(IS_ANDROID)
diff --git a/chrome/browser/tab_group_sync/tab_group_sync_service_factory_unittest.cc b/chrome/browser/tab_group_sync/tab_group_sync_service_factory_unittest.cc index 333a550..a48adc7f 100644 --- a/chrome/browser/tab_group_sync/tab_group_sync_service_factory_unittest.cc +++ b/chrome/browser/tab_group_sync/tab_group_sync_service_factory_unittest.cc
@@ -27,10 +27,7 @@ profile_ = TestingProfile::Builder().Build(); base::flat_map<base::test::FeatureRef, bool> feature_states; -#if BUILDFLAG(IS_ANDROID) - feature_states.try_emplace(tab_groups::kTabGroupSyncAndroid, - enable_feature); -#else +#if !BUILDFLAG(IS_ANDROID) feature_states.try_emplace(tab_groups::kTabGroupSyncServiceDesktopMigration, enable_feature); #endif @@ -43,12 +40,14 @@ base::test::ScopedFeatureList scoped_feature_list_; }; +#if !BUILDFLAG(IS_ANDROID) TEST_F(TabGroupSyncServiceFactoryTest, FeatureDisabledReturnsNullService) { InitService(/*enable_feature=*/false); TabGroupSyncService* service = TabGroupSyncServiceFactory::GetForProfile(profile_.get()); EXPECT_FALSE(service); } +#endif TEST_F(TabGroupSyncServiceFactoryTest, ServiceCreatedInRegularProfile) { InitService(/*enable_feature=*/true);
diff --git a/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/IncognitoStateProvider.java b/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/IncognitoStateProvider.java index a0ba6818..876ab3f 100644 --- a/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/IncognitoStateProvider.java +++ b/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/IncognitoStateProvider.java
@@ -28,7 +28,7 @@ private @Nullable TabModelSelector mTabModelSelector; public IncognitoStateProvider() { - mIncognitoStateObservers = new ObserverList<IncognitoStateObserver>(); + mIncognitoStateObservers = new ObserverList<>(); mCurrentTabModelObserver = (tabModel) -> {
diff --git a/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/TabGroupModelFilterImpl.java b/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/TabGroupModelFilterImpl.java index 642a7cd51..9430dba 100644 --- a/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/TabGroupModelFilterImpl.java +++ b/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/TabGroupModelFilterImpl.java
@@ -61,7 +61,7 @@ @NullMarked public class TabGroupModelFilterImpl implements TabGroupModelFilterInternal, TabModelObserver { private static final List<Tab> sEmptyRelatedTabList = - Collections.unmodifiableList(new ArrayList<Tab>()); + Collections.unmodifiableList(new ArrayList<>()); /** * Class to hold metadata while fixRootIds still exists. Delete when rootId is removed.
diff --git a/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/TabGroupModelFilterImplUnitTest.java b/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/TabGroupModelFilterImplUnitTest.java index be4add3..50c5e21d 100644 --- a/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/TabGroupModelFilterImplUnitTest.java +++ b/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/TabGroupModelFilterImplUnitTest.java
@@ -61,7 +61,6 @@ import org.chromium.base.UserDataHost; import org.chromium.base.test.BaseRobolectricTestRunner; import org.chromium.base.test.util.Features.DisableFeatures; -import org.chromium.base.test.util.Features.EnableFeatures; import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.tab.Tab; @@ -2352,7 +2351,7 @@ tabGroupIds, mTabGroupModelFilter .getLazyAllTabGroupIds( - new ArrayList<Tab>(), /* includePendingClosures= */ true) + new ArrayList<>(), /* includePendingClosures= */ true) .get()); } @@ -2446,7 +2445,6 @@ } @Test - @EnableFeatures({ChromeFeatureList.TAB_GROUP_SYNC_ANDROID}) public void testCloseGroup_Hiding_Undone() { doReturn(true).when(mTabGroupSyncFeaturesJniMock).isTabGroupSyncEnabled(mProfile); @@ -2474,7 +2472,6 @@ } @Test - @EnableFeatures({ChromeFeatureList.TAB_GROUP_SYNC_ANDROID}) public void testCloseGroup_Hiding_Committed() { doReturn(true).when(mTabGroupSyncFeaturesJniMock).isTabGroupSyncEnabled(mProfile); @@ -2510,7 +2507,6 @@ } @Test - @EnableFeatures({ChromeFeatureList.TAB_GROUP_SYNC_ANDROID}) public void testCloseMultipleTabs_Hiding_GroupInParts() { doReturn(true).when(mTabGroupSyncFeaturesJniMock).isTabGroupSyncEnabled(mProfile); @@ -2553,7 +2549,6 @@ } @Test - @EnableFeatures({ChromeFeatureList.TAB_GROUP_SYNC_ANDROID}) public void testCloseGroup_Deleted_Committed() { assertFalse(mTabGroupModelFilter.isTabGroupHiding(TAB2_TAB_GROUP_ID)); @@ -2583,7 +2578,6 @@ } @Test - @EnableFeatures({ChromeFeatureList.TAB_GROUP_SYNC_ANDROID}) public void testCloseAllTabs_Hiding_Undone() { doReturn(true).when(mTabGroupSyncFeaturesJniMock).isTabGroupSyncEnabled(mProfile); @@ -2639,7 +2633,6 @@ * correct. */ @Test - @EnableFeatures({ChromeFeatureList.TAB_GROUP_SYNC_ANDROID}) public void testCloseAllTabs_Hiding_PartialCommit() { doReturn(true).when(mTabGroupSyncFeaturesJniMock).isTabGroupSyncEnabled(mProfile); @@ -2683,7 +2676,6 @@ } @Test - @EnableFeatures({ChromeFeatureList.TAB_GROUP_SYNC_ANDROID}) public void testCloseAllTabs_Deleted() { assertFalse(mTabGroupModelFilter.isTabGroupHiding(TAB2_TAB_GROUP_ID)); assertFalse(mTabGroupModelFilter.isTabGroupHiding(TAB5_TAB_GROUP_ID));
diff --git a/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorSupplier.java b/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorSupplier.java index 89134a0..97acead 100644 --- a/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorSupplier.java +++ b/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorSupplier.java
@@ -21,7 +21,7 @@ @NullMarked public class TabModelSelectorSupplier extends UnownedUserDataSupplier<TabModelSelector> { private static final UnownedUserDataKey<TabModelSelectorSupplier> KEY = - new UnownedUserDataKey<TabModelSelectorSupplier>(TabModelSelectorSupplier.class); + new UnownedUserDataKey<>(TabModelSelectorSupplier.class); private static @Nullable ObservableSupplierImpl<TabModelSelector> sInstanceForTesting; /** Return {@link TabModelSelector} supplier associated with the given {@link WindowAndroid}. */
diff --git a/chrome/browser/thumbnail/generator/android/java/src/org/chromium/chrome/browser/thumbnail/generator/ThumbnailDiskStorage.java b/chrome/browser/thumbnail/generator/android/java/src/org/chromium/chrome/browser/thumbnail/generator/ThumbnailDiskStorage.java index c723fed..d31f8b94 100644 --- a/chrome/browser/thumbnail/generator/android/java/src/org/chromium/chrome/browser/thumbnail/generator/ThumbnailDiskStorage.java +++ b/chrome/browser/thumbnail/generator/android/java/src/org/chromium/chrome/browser/thumbnail/generator/ThumbnailDiskStorage.java
@@ -64,14 +64,12 @@ // background thread. // It is static because cached thumbnails are shared across all instances of the class. @VisibleForTesting - static final LinkedHashSet<Pair<String, Integer>> sDiskLruCache = - new LinkedHashSet<Pair<String, Integer>>(); + static final LinkedHashSet<Pair<String, Integer>> sDiskLruCache = new LinkedHashSet<>(); // Maps content ID to a set of the requested sizes (maximum required dimension of the smaller // side) of the thumbnail with that ID. @VisibleForTesting - static final HashMap<String, HashSet<Integer>> sIconSizesMap = - new HashMap<String, HashSet<Integer>>(); + static final HashMap<String, HashSet<Integer>> sIconSizesMap = new HashMap<>(); @VisibleForTesting final ThumbnailGenerator mThumbnailGenerator; @@ -184,7 +182,7 @@ // Create a copy of the set of icon sizes because they can't be removed from the set // while iterating through the set - ArrayList<Integer> iconSizes = new ArrayList<Integer>(sIconSizesMap.get(mContentId)); + ArrayList<Integer> iconSizes = new ArrayList<>(sIconSizesMap.get(mContentId)); for (int iconSize : iconSizes) { removeFromDiskHelper(Pair.create(mContentId, iconSize)); } @@ -298,7 +296,7 @@ if (sIconSizesMap.containsKey(contentId)) { sIconSizesMap.get(contentId).add(iconSizePx); } else { - HashSet<Integer> iconSizes = new HashSet<Integer>(); + HashSet<Integer> iconSizes = new HashSet<>(); iconSizes.add(iconSizePx); sIconSizesMap.put(contentId, iconSizes); } @@ -356,7 +354,7 @@ if (sIconSizesMap.containsKey(contentId)) { sIconSizesMap.get(contentId).add(iconSizePx); } else { - HashSet<Integer> iconSizes = new HashSet<Integer>(); + HashSet<Integer> iconSizes = new HashSet<>(); iconSizes.add(iconSizePx); sIconSizesMap.put(contentId, iconSizes); }
diff --git a/chrome/browser/thumbnail/generator/android/java/src/org/chromium/chrome/browser/thumbnail/generator/ThumbnailDiskStorageTest.java b/chrome/browser/thumbnail/generator/android/java/src/org/chromium/chrome/browser/thumbnail/generator/ThumbnailDiskStorageTest.java index 4264c94..a604874 100644 --- a/chrome/browser/thumbnail/generator/android/java/src/org/chromium/chrome/browser/thumbnail/generator/ThumbnailDiskStorageTest.java +++ b/chrome/browser/thumbnail/generator/android/java/src/org/chromium/chrome/browser/thumbnail/generator/ThumbnailDiskStorageTest.java
@@ -104,8 +104,7 @@ public Pair<String, Integer> getMostRecentEntry() { if (getCacheCount() <= 0) return null; - ArrayList<Pair<String, Integer>> list = - new ArrayList<Pair<String, Integer>>(sDiskLruCache); + ArrayList<Pair<String, Integer>> list = new ArrayList<>(sDiskLruCache); return list.get(list.size() - 1); } }
diff --git a/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodMediator.java b/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodMediator.java index 0098e72..7d44c3c1 100644 --- a/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodMediator.java +++ b/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodMediator.java
@@ -67,6 +67,7 @@ import org.chromium.components.autofill.AutofillSuggestion; import org.chromium.components.autofill.IbanRecordType; import org.chromium.components.autofill.LoyaltyCard; +import org.chromium.components.autofill.PaymentsPayload; import org.chromium.components.autofill.SuggestionType; import org.chromium.components.browser_ui.bottomsheet.BottomSheetController; import org.chromium.components.browser_ui.bottomsheet.BottomSheetController.StateChangeReason; @@ -223,7 +224,9 @@ new FillableItemCollectionInfo(i + 1, mSuggestions.size()), cardImageFunction); sheetItems.add(new ListItem(CREDIT_CARD, model)); - cardBenefitsTermsAvailable |= suggestion.shouldDisplayTermsAvailable(); + // TODO(crbug.com/423849651): Add null checks. + PaymentsPayload paymentsPayload = (PaymentsPayload) suggestion.getPayload(); + cardBenefitsTermsAvailable |= paymentsPayload.shouldDisplayTermsAvailable(); } if (cardBenefitsTermsAvailable) { @@ -391,7 +394,9 @@ if (!mInputProtector.shouldInputBeProcessed()) return; boolean is_virtual_card = suggestion.getSuggestionType() == SuggestionType.VIRTUAL_CREDIT_CARD_ENTRY; - mDelegate.creditCardSuggestionSelected(suggestion.getGuid(), is_virtual_card); + // TODO(crbug.com/423849651): Add null checks. + PaymentsPayload payload = (PaymentsPayload) suggestion.getPayload(); + mDelegate.creditCardSuggestionSelected(payload.getGuid(), is_virtual_card); recordTouchToFillCreditCardOutcomeHistogram( is_virtual_card ? TouchToFillCreditCardOutcome.VIRTUAL_CARD @@ -433,15 +438,15 @@ == SuggestionType.VIRTUAL_CREDIT_CARD_ENTRY) ? suggestion.getCustomIconUrl() : new GURL(""); + // TODO(crbug.com/423849651): Add null checks. + PaymentsPayload payload = (PaymentsPayload) suggestion.getPayload(); TouchToFillPaymentMethodProperties.CardImageMetaData cardImageMetaData = new TouchToFillPaymentMethodProperties.CardImageMetaData(drawableId, artUrl); PropertyModel.Builder creditCardSuggestionModelBuilder = new PropertyModel.Builder(NON_TRANSFORMING_CREDIT_CARD_SUGGESTION_KEYS) .withTransformingKey(CARD_IMAGE, cardImageFunction, cardImageMetaData) .with(MAIN_TEXT, suggestion.getLabel()) - .with( - MAIN_TEXT_CONTENT_DESCRIPTION, - suggestion.getLabelContentDescription()) + .with(MAIN_TEXT_CONTENT_DESCRIPTION, payload.getLabelContentDescription()) .with(MINOR_TEXT, suggestion.getSecondaryLabel()) // For virtual cards, show the "Virtual card" label on the second // line, and for non-virtual cards, show the expiration date. @@ -580,7 +585,9 @@ private static boolean hasOnlyLocalCards(List<AutofillSuggestion> suggestions) { for (AutofillSuggestion suggestion : suggestions) { - if (!suggestion.isLocalPaymentsMethod()) return false; + // TODO(crbug.com/423849651): Add null checks. + PaymentsPayload payload = (PaymentsPayload) suggestion.getPayload(); + if (!payload.isLocalPaymentsMethod()) return false; } return true; }
diff --git a/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodViewTest.java b/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodViewTest.java index 3002289..6050d8a7 100644 --- a/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodViewTest.java +++ b/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodViewTest.java
@@ -101,6 +101,7 @@ import org.chromium.chrome.test.ChromeTabbedActivityTestRule; import org.chromium.components.autofill.AutofillSuggestion; import org.chromium.components.autofill.LoyaltyCard; +import org.chromium.components.autofill.PaymentsPayload; import org.chromium.components.autofill.SuggestionType; import org.chromium.components.browser_ui.bottomsheet.BottomSheetController; import org.chromium.components.browser_ui.bottomsheet.BottomSheetController.SheetState; @@ -1137,12 +1138,11 @@ AutofillSuggestion suggestion, FillableItemCollectionInfo collectionInfo, Runnable actionCallback) { + PaymentsPayload payload = (PaymentsPayload) suggestion.getPayload(); PropertyModel.Builder creditCardSuggestionModelBuilder = new PropertyModel.Builder(NON_TRANSFORMING_CREDIT_CARD_SUGGESTION_KEYS) .with(MAIN_TEXT, suggestion.getLabel()) - .with( - MAIN_TEXT_CONTENT_DESCRIPTION, - suggestion.getLabelContentDescription()) + .with(MAIN_TEXT_CONTENT_DESCRIPTION, payload.getLabelContentDescription()) .with(MINOR_TEXT, suggestion.getSecondaryLabel()) .with(FIRST_LINE_LABEL, suggestion.getSublabel()) .with(SECOND_LINE_LABEL, suggestion.getSecondarySublabel())
diff --git a/chrome/browser/touch_to_fill/autofill/android/touch_to_fill_payment_method_view_impl.cc b/chrome/browser/touch_to_fill/autofill/android/touch_to_fill_payment_method_view_impl.cc index e3cae08..7b60df7 100644 --- a/chrome/browser/touch_to_fill/autofill/android/touch_to_fill_payment_method_view_impl.cc +++ b/chrome/browser/touch_to_fill/autofill/android/touch_to_fill_payment_method_view_impl.cc
@@ -120,15 +120,12 @@ Java_TouchToFillPaymentMethodViewBridge_createAutofillSuggestion( env, suggestion.main_text.value, minor_text, suggestion.labels[0][0].value, secondarySubLabel, - payments_payload.main_text_content_description, base::to_underlying(suggestion.type), custom_icon_url ? url::GURLAndroid::FromNativeGURL( env, custom_icon_url->value()) : url::GURLAndroid::EmptyGURL(env), android_icon_id, suggestion.HasDeactivatedStyle(), - payments_payload.should_display_terms_available, - payments_payload.guid.value(), - payments_payload.is_local_payments_method)); + payments_payload.CreateJavaObject())); } Java_TouchToFillPaymentMethodViewBridge_showCreditCards( env, java_object_, std::move(suggestions_array),
diff --git a/chrome/browser/touch_to_fill/password_manager/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillMediator.java b/chrome/browser/touch_to_fill/password_manager/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillMediator.java index 88ff508..032ba2a 100644 --- a/chrome/browser/touch_to_fill/password_manager/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillMediator.java +++ b/chrome/browser/touch_to_fill/password_manager/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillMediator.java
@@ -444,7 +444,7 @@ List<Credential> credentials) { // TODO(http://crbug.com/1504098) : Add render test for a bottom sheet with shared passwords // after the UI is complete. - List<Credential> sharedCredentials = new ArrayList<Credential>(); + List<Credential> sharedCredentials = new ArrayList<>(); for (Credential credential : credentials) { if (credential.isShared() && !credential.isSharingNotificationDisplayed()) { sharedCredentials.add(credential);
diff --git a/chrome/browser/translate/android/java/src/org/chromium/chrome/browser/translate/AutoTranslateSnackbarControllerJavaTest.java b/chrome/browser/translate/android/java/src/org/chromium/chrome/browser/translate/AutoTranslateSnackbarControllerJavaTest.java index 87b6cdd71..e29ae58 100644 --- a/chrome/browser/translate/android/java/src/org/chromium/chrome/browser/translate/AutoTranslateSnackbarControllerJavaTest.java +++ b/chrome/browser/translate/android/java/src/org/chromium/chrome/browser/translate/AutoTranslateSnackbarControllerJavaTest.java
@@ -53,7 +53,7 @@ mActivityTestRule.startMainActivityOnBlankPage(); mSnackbarManager = mActivityTestRule.getActivity().getSnackbarManager(); WeakReference<Activity> weakReference = - new WeakReference<Activity>(mActivityTestRule.getActivity()); + new WeakReference<>(mActivityTestRule.getActivity()); mAutoTranslateSnackbarController = new AutoTranslateSnackbarController(
diff --git a/chrome/browser/translate/android/java/src/org/chromium/chrome/browser/translate/AutoTranslateSnackbarControllerTest.java b/chrome/browser/translate/android/java/src/org/chromium/chrome/browser/translate/AutoTranslateSnackbarControllerTest.java index 21ee206..30e6ea12 100644 --- a/chrome/browser/translate/android/java/src/org/chromium/chrome/browser/translate/AutoTranslateSnackbarControllerTest.java +++ b/chrome/browser/translate/android/java/src/org/chromium/chrome/browser/translate/AutoTranslateSnackbarControllerTest.java
@@ -60,7 +60,7 @@ public void testCreateWithNullSnackbarManager() { Activity activity = Mockito.mock(Activity.class); - Mockito.doReturn(new WeakReference<Activity>(activity)).when(mWindowAndroid).getActivity(); + Mockito.doReturn(new WeakReference<>(activity)).when(mWindowAndroid).getActivity(); Mockito.doReturn(mWindowAndroid).when(mWebContents).getTopLevelNativeWindow(); Mockito.doReturn(new UnownedUserDataHost()).when(mWindowAndroid).getUnownedUserDataHost(); Assert.assertNull(
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index bb93cc9..c7d115d 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -4119,6 +4119,8 @@ "views/location_bar/cookie_controls/cookie_controls_content_view.h", "views/location_bar/cookie_controls/cookie_controls_icon_view.cc", "views/location_bar/cookie_controls/cookie_controls_icon_view.h", + "views/location_bar/cookie_controls/cookie_controls_page_action_controller.cc", + "views/location_bar/cookie_controls/cookie_controls_page_action_controller.h", "views/location_bar/custom_tab_bar_view.cc", "views/location_bar/custom_tab_bar_view.h", "views/location_bar/find_bar_icon.cc", @@ -4496,6 +4498,8 @@ "views/permissions/permission_prompt_quiet_icon.cc", "views/permissions/permission_prompt_quiet_icon.h", "views/permissions/permission_prompt_style.h", + "views/picture_in_picture/picture_in_picture_tucker.cc", + "views/picture_in_picture/picture_in_picture_tucker.h", "views/profiles/avatar_toolbar_button.cc", "views/profiles/avatar_toolbar_button.h", "views/profiles/avatar_toolbar_button_delegate.cc",
diff --git a/chrome/browser/ui/actions/chrome_action_id.h b/chrome/browser/ui/actions/chrome_action_id.h index b79f667..7502e8b2 100644 --- a/chrome/browser/ui/actions/chrome_action_id.h +++ b/chrome/browser/ui/actions/chrome_action_id.h
@@ -89,6 +89,7 @@ E(kActionProfileMenuInAppMenu, IDC_PROFILE_MENU_IN_APP_MENU) \ E(kActionPasswordsAndAutofillMenu, IDC_PASSWORDS_AND_AUTOFILL_MENU) \ E(kActionShowMemorySaverChip) \ + E(kActionShowCookieControls) \ /* Page-manipulation commands that target a specified tab, which may not */ \ /* be the active one. */ \ E(kActionMuteTargetSite, IDC_MUTE_TARGET_SITE) \
diff --git a/chrome/browser/ui/android/edge_to_edge/internal/java/src/org/chromium/chrome/browser/ui/edge_to_edge/EdgeToEdgeControllerImpl.java b/chrome/browser/ui/android/edge_to_edge/internal/java/src/org/chromium/chrome/browser/ui/edge_to_edge/EdgeToEdgeControllerImpl.java index 0c21a6b5..f024fda8 100644 --- a/chrome/browser/ui/android/edge_to_edge/internal/java/src/org/chromium/chrome/browser/ui/edge_to_edge/EdgeToEdgeControllerImpl.java +++ b/chrome/browser/ui/android/edge_to_edge/internal/java/src/org/chromium/chrome/browser/ui/edge_to_edge/EdgeToEdgeControllerImpl.java
@@ -64,6 +64,8 @@ "Android.EdgeToEdge.DrawToEdgeInUnsupportedConfiguration"; private static final String SUPPORTED_CONFIGURATION_SWITCH_HISTOGRAM = "Android.EdgeToEdge.SupportedConfigurationSwitch2"; + private static final String CONFIGURATION_SWITCH_OUTCOME_HISTOGRAM = + "Android.EdgeToEdge.Debugging.ConfigurationSwitchOutcome"; // These values are persisted to logs. Entries should not be renumbered and // numeric values should never be reused. @@ -78,6 +80,33 @@ int NUM_ENTRIES = 2; } + /** When configuration changes from supported to unsupported, what's the outcome */ + // These values are persisted to logs. Entries should not be renumbered and + // numeric values should never be reused. + @IntDef({ + ConfigurationSwitchOutcome.ADD_PADDING_NEW_INSETS, + ConfigurationSwitchOutcome.ADD_PADDING_ORIGINAL_INSETS, + ConfigurationSwitchOutcome.ERROR_ADD_PADDING_BOTH_INSETS_EMPTY, + ConfigurationSwitchOutcome.NO_PADDING_BOTH_INSETS_EMPTY, + ConfigurationSwitchOutcome.NO_PADDING_NO_NEW_INSETS, + ConfigurationSwitchOutcome.ERROR_NO_PADDING_WITH_NEW_INSETS, + ConfigurationSwitchOutcome.NUM_ENTRIES + }) + public @interface ConfigurationSwitchOutcome { + + // Correct cases + int ADD_PADDING_ORIGINAL_INSETS = 0; + int ADD_PADDING_NEW_INSETS = 1; + // Error case / impossible case + int ERROR_ADD_PADDING_BOTH_INSETS_EMPTY = 2; + int NO_PADDING_BOTH_INSETS_EMPTY = 3; + int NO_PADDING_NO_NEW_INSETS = 4; + // Error case / impossible case + int ERROR_NO_PADDING_WITH_NEW_INSETS = 5; + + int NUM_ENTRIES = 6; + } + /** The outermost view in our view hierarchy that is identified with a resource ID. */ private static final int ROOT_UI_VIEW_ID = android.R.id.content; @@ -488,6 +517,8 @@ @VisibleForTesting WindowInsetsCompat handleWindowInsets(View rootView, WindowInsetsCompat windowInsets) { boolean changedWindowState = false; + @SupportedConfigurationSwitch + int configurationChanged = SupportedConfigurationSwitch.NUM_ENTRIES; if (mIsSupportedConfiguration != EdgeToEdgeControllerFactory.isSupportedConfiguration(mActivity)) { Log.v( @@ -496,11 +527,13 @@ (mIsSupportedConfiguration ? "supported to unsupported" : "unsupported to supported")); - RecordHistogram.recordEnumeratedHistogram( - SUPPORTED_CONFIGURATION_SWITCH_HISTOGRAM, + configurationChanged = mIsSupportedConfiguration ? SupportedConfigurationSwitch.FROM_SUPPORTED_TO_UNSUPPORTED - : SupportedConfigurationSwitch.FROM_UNSUPPORTED_TO_SUPPORTED, + : SupportedConfigurationSwitch.FROM_UNSUPPORTED_TO_SUPPORTED; + RecordHistogram.recordEnumeratedHistogram( + SUPPORTED_CONFIGURATION_SWITCH_HISTOGRAM, + configurationChanged, SupportedConfigurationSwitch.NUM_ENTRIES); mIsSupportedConfiguration = EdgeToEdgeControllerFactory.isSupportedConfiguration(mActivity); @@ -514,11 +547,12 @@ return windowInsets; } + Insets originalSystemInsets = mSystemInsets; Insets newInsets = getSystemInsets(windowInsets); Insets newKeyboardInsets = windowInsets.getInsets(WindowInsetsCompat.Type.ime()); if (updateVisibilityRects(rootView) - || !newInsets.equals(mSystemInsets) + || !newInsets.equals(originalSystemInsets) || !newKeyboardInsets.equals(mKeyboardInsets)) { mSystemInsets = newInsets; mKeyboardInsets = newKeyboardInsets; @@ -538,6 +572,12 @@ drawToEdge(mIsPageOptedIntoEdgeToEdge, /* changedWindowState= */ true); } + // Signal: When configuration is changed, did we pad the system correctly. + if (configurationChanged == SupportedConfigurationSwitch.FROM_SUPPORTED_TO_UNSUPPORTED) { + recordConfigurationSwitchScenario( + originalSystemInsets, newInsets, mAppliedContentViewPadding); + } + var builder = new WindowInsetsCompat.Builder(windowInsets); // Consume top insets only when in fullscreen, where we are forcing 0 as the top padding. @@ -698,6 +738,41 @@ mEdgeToEdgeStateProvider.releaseSetDecorFitsSystemWindowToken(mEdgeToEdgeToken); } + static void recordConfigurationSwitchScenario( + Insets originalInsets, Insets newInsets, Insets paddingApplied) { + // Do not record when configuration change is disabled. + if (!shouldMonitorConfigurationChanges()) return; + + // Do not record landscape mode. Assuming the configuration change will be triggered + // mostly with nav bar in portrait mode. + if (paddingApplied.left > 0 || paddingApplied.right > 0) return; + + @ConfigurationSwitchOutcome int outcome; + // Correct cases - fixed applied + if (paddingApplied.bottom > 0) { + if (originalInsets.bottom != 0) { + outcome = ConfigurationSwitchOutcome.ADD_PADDING_ORIGINAL_INSETS; + } else if (newInsets.bottom != 0) { + outcome = ConfigurationSwitchOutcome.ADD_PADDING_NEW_INSETS; + } else { + outcome = ConfigurationSwitchOutcome.ERROR_ADD_PADDING_BOTH_INSETS_EMPTY; + } + } else { // paddingApplied.bottom == 0 + if (originalInsets.bottom == 0 && newInsets.bottom == 0) { + outcome = ConfigurationSwitchOutcome.NO_PADDING_BOTH_INSETS_EMPTY; + } else if (originalInsets.bottom > 0) { + outcome = ConfigurationSwitchOutcome.NO_PADDING_NO_NEW_INSETS; + } else { + outcome = ConfigurationSwitchOutcome.ERROR_NO_PADDING_WITH_NEW_INSETS; + } + } + + RecordHistogram.recordEnumeratedHistogram( + CONFIGURATION_SWITCH_OUTCOME_HISTOGRAM, + outcome, + ConfigurationSwitchOutcome.NUM_ENTRIES); + } + @VisibleForTesting @Nullable WebContentsObserver getWebContentsObserver() { return mWebContentsObserver;
diff --git a/chrome/browser/ui/android/edge_to_edge/java/src/org/chromium/chrome/browser/ui/edge_to_edge/EdgeToEdgeUtils.java b/chrome/browser/ui/android/edge_to_edge/java/src/org/chromium/chrome/browser/ui/edge_to_edge/EdgeToEdgeUtils.java index 2b3064b..3e0259a 100644 --- a/chrome/browser/ui/android/edge_to_edge/java/src/org/chromium/chrome/browser/ui/edge_to_edge/EdgeToEdgeUtils.java +++ b/chrome/browser/ui/android/edge_to_edge/java/src/org/chromium/chrome/browser/ui/edge_to_edge/EdgeToEdgeUtils.java
@@ -394,6 +394,23 @@ ResettersForTesting.register(() -> sObservedTappableNavigationBar = false); } + /** Returns whether the insets indicate that the device is in gesture navigation mode. */ + public static boolean isInGestureNavigationMode(WindowInsetsCompat insets) { + Insets mandatorySystemGesturesInsets = + insets.getInsets(WindowInsetsCompat.Type.mandatorySystemGestures()); + Insets systemGesturesInsets = insets.getInsets(WindowInsetsCompat.Type.systemGestures()); + Insets nonMandatorySystemGestures = + Insets.subtract(systemGesturesInsets, mandatorySystemGesturesInsets); + + // In gesture navigation mode, the left and right sides have insets for swiping gestures, + // but these are not considered mandatory system gestures. These non-mandatory gesture + // insets do not appear in 3-button navigation mode. Note, though, that even in gesture + // navigation mode, one side may not show an inset when in landscape mode, as the side with + // the display cutout / camera will not show a gesture inset (the other side will still show + // an inset). + return nonMandatorySystemGestures.left > 0 || nonMandatorySystemGestures.right > 0; + } + /** * A class to store the debugging info for edge-to-edge error case, when EdgeToEdgeController is * presented in an unsupported configuration. @@ -439,34 +456,22 @@ + " \nmissingNavBarReason: " + missingNavbarReasonString; - String rootInsetsState = ""; - String rootInsetsIgnoringVisibilityState = ""; - String rootInsetsTappableState = ""; - if (window != null && window.getDecorView().getRootWindowInsets() != null) { - var rootWindowInsets = - WindowInsetsCompat.toWindowInsetsCompat( - window.getDecorView().getRootWindowInsets()); - var insetsString = - rootWindowInsets.getInsets(WindowInsetsCompat.Type.systemBars()).toString(); - rootInsetsState = " \nrootWindowInsets: " + insetsString; - var insetsIgnoringVisibilityString = - rootWindowInsets - .getInsetsIgnoringVisibility(WindowInsetsCompat.Type.systemBars()) - .toString(); - rootInsetsIgnoringVisibilityState = - " \nrootWindowInsetsIgnoringVisibility: " + insetsIgnoringVisibilityString; - var insetsTappableString = - rootWindowInsets - .getInsets(WindowInsetsCompat.Type.tappableElement()) - .toString(); - rootInsetsTappableState = " \nrootWindowInsetsTappable: " + insetsTappableString; - } - + String rawWindowInsetsIndicateGestureNav = ""; String rawWindowInsetsState = ""; String rawWindowInsetsIgnoringVisibilityState = ""; String rawWindowInsetsTappableState = ""; + String rawWindowInsetsStateSystemGestures = ""; if (windowAndroid != null && windowAndroid.getInsetObserver() != null) { var lastRawWindowInsets = windowAndroid.getInsetObserver().getLastRawWindowInsets(); + var gestureNavString = + lastRawWindowInsets == null + ? "null" + : Boolean.toString( + EdgeToEdgeUtils.isInGestureNavigationMode( + lastRawWindowInsets)); + rawWindowInsetsIndicateGestureNav = + "\nisGestureNav (from lastRawWindowInsets): " + gestureNavString; + var insetsString = lastRawWindowInsets == null ? "null" @@ -495,19 +500,40 @@ .toString(); rawWindowInsetsTappableState = " \nlastRawWindowInsets tappable: " + tappableInsetsString; + + var systemGesturesInsetsString = + lastRawWindowInsets == null + ? "null" + : lastRawWindowInsets + .getInsetsIgnoringVisibility( + WindowInsetsCompat.Type.systemGestures()) + .toString(); + rawWindowInsetsStateSystemGestures = + " \nlastRawWindowInsets systemGestures: " + systemGesturesInsetsString; } + String windowMetricsIndicateGestureNav = ""; String windowMetricsInsetsState = ""; String windowMetricsInsetsStateTappable = ""; String windowMetricsInsetsStateMandatoryGestures = ""; String windowMetricsInsetsStateSystemGestures = ""; - String windowMetricsInsetsStateSystemOverlays = ""; if (Build.VERSION.SDK_INT >= VERSION_CODES.R) { if (window != null && window.getWindowManager() != null && window.getWindowManager().getCurrentWindowMetrics() != null) { WindowInsets windowInsets = window.getWindowManager().getCurrentWindowMetrics().getWindowInsets(); + + var gestureNavString = + windowInsets == null + ? "null" + : Boolean.toString( + EdgeToEdgeUtils.isInGestureNavigationMode( + WindowInsetsCompat.toWindowInsetsCompat( + windowInsets))); + windowMetricsIndicateGestureNav = + "\nisGestureNav (from windowMetrics): " + gestureNavString; + var insetsString = windowInsets == null ? "null" @@ -545,15 +571,6 @@ .toString(); windowMetricsInsetsStateSystemGestures = " \nwindowMetricsInsetsSystemGestures: " + insetsStringSystemGestures; - - var insetsStringSystemOverlays = - windowInsets == null - ? "null" - : windowInsets - .getInsets(WindowInsetsCompat.Type.systemOverlays()) - .toString(); - windowMetricsInsetsStateSystemOverlays = - " \nwindowMetricsInsetsSystemOverlays: " + insetsStringSystemOverlays; } } @@ -561,17 +578,16 @@ mHasUploaded = true; reportUploadCallback.onResult( state - + rootInsetsState - + rootInsetsIgnoringVisibilityState - + rootInsetsTappableState + + rawWindowInsetsIndicateGestureNav + rawWindowInsetsState + rawWindowInsetsIgnoringVisibilityState + rawWindowInsetsTappableState + + rawWindowInsetsStateSystemGestures + + windowMetricsIndicateGestureNav + windowMetricsInsetsState + windowMetricsInsetsStateTappable + windowMetricsInsetsStateMandatoryGestures - + windowMetricsInsetsStateSystemGestures - + windowMetricsInsetsStateSystemOverlays); + + windowMetricsInsetsStateSystemGestures); } /** Returns whether the the instance has uploaded any report. */
diff --git a/chrome/browser/ui/android/night_mode/java/src/org/chromium/chrome/browser/night_mode/AutoDarkFeedbackSource.java b/chrome/browser/ui/android/night_mode/java/src/org/chromium/chrome/browser/night_mode/AutoDarkFeedbackSource.java index b501e3f..4731dde 100644 --- a/chrome/browser/ui/android/night_mode/java/src/org/chromium/chrome/browser/night_mode/AutoDarkFeedbackSource.java +++ b/chrome/browser/ui/android/night_mode/java/src/org/chromium/chrome/browser/night_mode/AutoDarkFeedbackSource.java
@@ -29,7 +29,7 @@ private final HashMap<String, String> mMap; public AutoDarkFeedbackSource(Profile profile, Context context, GURL url) { - mMap = new HashMap<String, String>(1); + mMap = new HashMap<>(1); // Ignore user settings in incognito, or not in auto dark feature is not enabled. if (profile.isOffTheRecord()) return;
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/LocationBarMediator.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/LocationBarMediator.java index fcb8c77..72f1aa1 100644 --- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/LocationBarMediator.java +++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/LocationBarMediator.java
@@ -44,7 +44,6 @@ import org.chromium.build.annotations.Nullable; import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider; import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider.ControlsPosition; -import org.chromium.chrome.browser.composeplate.ComposeplateUtils; import org.chromium.chrome.browser.device.DeviceClassManager; import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.flags.ChromeSwitches; @@ -749,9 +748,12 @@ || !mTabModelSelectorSupplier.hasValue()) return; Tab tab = mTabModelSelectorSupplier.get().getCurrentTab(); - if (tab == null || tab.isIncognito()) return; + if (tab == null || tab.isIncognito() || !mTemplateUrlServiceSupplier.hasValue()) return; - tab.loadUrl(new LoadUrlParams(ComposeplateUtils.getComposeplateURL())); + GURL url = mTemplateUrlServiceSupplier.get().getComposeplateUrl(); + if (url == null) return; + + tab.loadUrl(new LoadUrlParams(url)); } /** package */
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/LocationBarMediatorTest.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/LocationBarMediatorTest.java index 6e22e733..d3786ad 100644 --- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/LocationBarMediatorTest.java +++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/LocationBarMediatorTest.java
@@ -1631,15 +1631,15 @@ public void testComposeplateButtonClicked() { mMediator.onFinishNativeInitialization(); + GURL url = new GURL("https://foo.com"); + when(mTemplateUrlService.getComposeplateUrl()).thenReturn(url); when(mTabModelSelectorSupplier.hasValue()).thenReturn(true); when(mTabModelSelector.getCurrentTab()).thenReturn(mTab); when(mTab.isIncognito()).thenReturn(false); mMediator.composeplateButtonClicked(null); verify(mTab).loadUrl(mLoadUrlParamsCaptor.capture()); - assertEquals( - ChromeFeatureList.sAndroidComposeplateButtonUrl.getValue(), - mLoadUrlParamsCaptor.getValue().getUrl()); + assertEquals(url.getSpec(), mLoadUrlParamsCaptor.getValue().getUrl()); } private ArgumentMatcher<UrlBarData> matchesUrlBarDataForQuery(String query) {
diff --git a/chrome/browser/ui/android/tab_model/tab_model_jni_bridge.cc b/chrome/browser/ui/android/tab_model/tab_model_jni_bridge.cc index 2825fc0c2..71239f9 100644 --- a/chrome/browser/ui/android/tab_model/tab_model_jni_bridge.cc +++ b/chrome/browser/ui/android/tab_model/tab_model_jni_bridge.cc
@@ -7,6 +7,7 @@ #include <stdint.h> #include "base/android/jni_android.h" +#include "base/android/jni_array.h" #include "base/android/jni_string.h" #include "base/android/jni_weak_ref.h" #include "base/metrics/histogram_macros.h" @@ -29,6 +30,7 @@ using base::android::AttachCurrentThread; using base::android::ConvertUTF8ToJavaString; using base::android::JavaParamRef; +using base::android::SafeGetArrayLength; using base::android::ScopedJavaLocalRef; using chrome::android::ActivityType; using content::WebContents; @@ -273,9 +275,24 @@ } std::vector<tabs::TabInterface*> TabModelJniBridge::GetAllTabs() { - // TODO(crbug.com/415351293): Implement. - NOTIMPLEMENTED(); - return {}; + JNIEnv* env = AttachCurrentThread(); + ScopedJavaLocalRef<jobject> jobj = java_object_.get(env); + ScopedJavaLocalRef<jobjectArray> jtabs = + Java_TabModelJniBridge_getAllTabs(env, jobj); + + std::vector<tabs::TabInterface*> tabs; + if (jtabs) { + size_t numTabs = SafeGetArrayLength(env, jtabs); + tabs.reserve(numTabs); + + jobjectArray jarray = jtabs.obj(); + for (size_t i = 0; i < numTabs; i++) { + ScopedJavaLocalRef<jobject> jtab(env, + env->GetObjectArrayElement(jarray, i)); + tabs.push_back(TabAndroid::GetNativeTab(env, jtab)); + } + } + return tabs; } void TabModelJniBridge::PinTab(int index) {
diff --git a/chrome/browser/ui/android/theme/BUILD.gn b/chrome/browser/ui/android/theme/BUILD.gn index 5d6fb54..c257267 100644 --- a/chrome/browser/ui/android/theme/BUILD.gn +++ b/chrome/browser/ui/android/theme/BUILD.gn
@@ -76,7 +76,9 @@ "//components/browser_ui/styles/android:java", "//components/tab_groups:tab_groups_java", "//testing/android/junit:junit_test_support", + "//third_party/android_deps:material_design_java", "//third_party/androidx:androidx_annotation_annotation_java", + "//third_party/androidx:androidx_appcompat_appcompat_resources_java", "//third_party/androidx:androidx_core_core_java", "//third_party/hamcrest:hamcrest_core_java", "//third_party/hamcrest:hamcrest_library_java",
diff --git a/chrome/browser/ui/android/theme/java/res/values/colors.xml b/chrome/browser/ui/android/theme/java/res/values/colors.xml index e3f348c..2084af6 100644 --- a/chrome/browser/ui/android/theme/java/res/values/colors.xml +++ b/chrome/browser/ui/android/theme/java/res/values/colors.xml
@@ -21,4 +21,6 @@ <color name="pane_switcher_selected_tab_incognito_v2">@color/baseline_secondary_30</color> <color name="pane_switcher_selected_tab_icon_color_incognito">@color/baseline_neutral_90</color> + <color name="incognito_tab_action_button_color">@color/baseline_neutral_variant_80</color> + </resources>
diff --git a/chrome/browser/ui/android/theme/java/src/org/chromium/chrome/browser/theme/SurfaceColorUpdateUtils.java b/chrome/browser/ui/android/theme/java/src/org/chromium/chrome/browser/theme/SurfaceColorUpdateUtils.java index 0654f38f..113c48d 100644 --- a/chrome/browser/ui/android/theme/java/src/org/chromium/chrome/browser/theme/SurfaceColorUpdateUtils.java +++ b/chrome/browser/ui/android/theme/java/src/org/chromium/chrome/browser/theme/SurfaceColorUpdateUtils.java
@@ -5,10 +5,14 @@ package org.chromium.chrome.browser.theme; import android.content.Context; +import android.content.res.ColorStateList; import androidx.annotation.ColorInt; +import androidx.appcompat.content.res.AppCompatResources; import androidx.core.content.ContextCompat; +import com.google.android.material.color.MaterialColors; + import org.chromium.build.annotations.NullMarked; import org.chromium.build.annotations.Nullable; import org.chromium.chrome.browser.flags.ChromeFeatureList; @@ -21,6 +25,7 @@ /** Utility class that provides color values based on feature flags enabled. */ @NullMarked public class SurfaceColorUpdateUtils { + private static final String TAG = "SurfaceColorUpdateUtils"; /** Whether enable the containment on the tab group list pane. */ public static boolean isTabGroupListContainmentEnabled() { @@ -246,6 +251,29 @@ } /** + * Returns the text color used for the card view in grid tab switcher on the enabled flag and + * incognito. + * + * @param context {@link Context} used to retrieve colors. + * @param isIncognito Whether the color is used for incognito mode. + * @param colorId Color chosen by user for the TabGroup, null if not a tab group. + * @return The text color for the number used on the tab group cards. + */ + public static ColorStateList getCardViewActionButtonColor( + Context context, boolean isIncognito, @Nullable @TabGroupColorId Integer colorId) { + if (useNewGm3GtsTabGroupColors() && colorId != null) { + return ColorStateList.valueOf( + TabGroupColorPickerUtils.getTabGroupCardTextColor( + context, colorId, isIncognito)); + } + return isIncognito + ? AppCompatResources.getColorStateList( + context, R.color.incognito_tab_action_button_color) + : ColorStateList.valueOf( + MaterialColors.getColor(context, R.attr.colorOnSurfaceVariant, TAG)); + } + + /** * Returns the background color for the grid tab switcher message card based on the enabled flag * and incognito. *
diff --git a/chrome/browser/ui/android/theme/java/src/org/chromium/chrome/browser/theme/SurfaceColorUpdateUtilsUnitTest.java b/chrome/browser/ui/android/theme/java/src/org/chromium/chrome/browser/theme/SurfaceColorUpdateUtilsUnitTest.java index 092b0d23..9114d1f3 100644 --- a/chrome/browser/ui/android/theme/java/src/org/chromium/chrome/browser/theme/SurfaceColorUpdateUtilsUnitTest.java +++ b/chrome/browser/ui/android/theme/java/src/org/chromium/chrome/browser/theme/SurfaceColorUpdateUtilsUnitTest.java
@@ -7,11 +7,15 @@ import static org.junit.Assert.assertEquals; import android.content.Context; +import android.content.res.ColorStateList; import android.view.ContextThemeWrapper; import androidx.annotation.ColorInt; +import androidx.appcompat.content.res.AppCompatResources; import androidx.core.content.ContextCompat; +import com.google.android.material.color.MaterialColors; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -616,4 +620,111 @@ expectedNonIncognito, actualNonIncognitoNullId); } + + @Test + @EnableFeatures({ChromeFeatureList.ANDROID_TAB_GROUPS_COLOR_UPDATE_GM3}) + public void testGetCardViewActionButtonColor_gm3FlagEnabled_withColorId() { + @TabGroupColorId int testColorId = TabGroupColorId.RED; + + // Test non-incognito. + ColorStateList expectedNonIncognito = + ColorStateList.valueOf( + TabGroupColorPickerUtils.getTabGroupCardTextColor( + mContext, testColorId, /* isIncognito= */ false)); + ColorStateList actualNonIncognito = + SurfaceColorUpdateUtils.getCardViewActionButtonColor( + mContext, /* isIncognito= */ false, testColorId); + assertEquals( + "Action button color mismatch for non-incognito with GM3 flag and colorId.", + expectedNonIncognito, + actualNonIncognito); + + // Test incognito. + ColorStateList expectedIncognito = + ColorStateList.valueOf( + TabGroupColorPickerUtils.getTabGroupCardTextColor( + mContext, testColorId, /* isIncognito= */ true)); + ColorStateList actualIncognito = + SurfaceColorUpdateUtils.getCardViewActionButtonColor( + mContext, /* isIncognito= */ true, testColorId); + assertEquals( + "Action button color mismatch for incognito with GM3 flag and colorId.", + expectedIncognito, + actualIncognito); + } + + @Test + @EnableFeatures({ChromeFeatureList.ANDROID_TAB_GROUPS_COLOR_UPDATE_GM3}) + public void testGetCardViewActionButtonColor_gm3FlagEnabled_colorIdNull() { + // When the GM3 flag is enabled but the colorId is null, the function should + // execute its fallback logic. + + // Test non-incognito with a null colorId. + ColorStateList expectedNonIncognito = + ColorStateList.valueOf( + MaterialColors.getColor(mContext, R.attr.colorOnSurfaceVariant, "")); + ColorStateList actualNonIncognito = + SurfaceColorUpdateUtils.getCardViewActionButtonColor( + mContext, /* isIncognito= */ false, /* colorId= */ null); + assertEquals( + "Action button color should use fallback for non-incognito when colorId is null.", + expectedNonIncognito, + actualNonIncognito); + + // Test incognito with a null colorId. + ColorStateList expectedIncognito = + AppCompatResources.getColorStateList( + mContext, R.color.incognito_tab_action_button_color); + ColorStateList actualIncognito = + SurfaceColorUpdateUtils.getCardViewActionButtonColor( + mContext, /* isIncognito= */ true, /* colorId= */ null); + assertEquals( + "Action button color should use fallback for incognito when colorId is null.", + expectedIncognito, + actualIncognito); + } + + @Test + @DisableFeatures({ChromeFeatureList.ANDROID_TAB_GROUPS_COLOR_UPDATE_GM3}) + public void testGetCardViewActionButtonColor_gm3FlagDisabled() { + // If the GM3 flag is disabled, the colorId should be ignored and the fallback logic used. + @TabGroupColorId int testColorId = TabGroupColorId.GREEN; + + // Test non-incognito (fallback path). + ColorStateList expectedNonIncognito = + ColorStateList.valueOf( + MaterialColors.getColor(mContext, R.attr.colorOnSurfaceVariant, "")); + ColorStateList actualNonIncognito = + SurfaceColorUpdateUtils.getCardViewActionButtonColor( + mContext, /* isIncognito= */ false, testColorId); + assertEquals( + "Action button color mismatch for non-incognito with GM3 flag disabled (colorId" + + " ignored).", + expectedNonIncognito, + actualNonIncognito); + + // Test incognito (fallback path). + ColorStateList expectedIncognito = + AppCompatResources.getColorStateList( + mContext, R.color.incognito_tab_action_button_color); + ColorStateList actualIncognito = + SurfaceColorUpdateUtils.getCardViewActionButtonColor( + mContext, /* isIncognito= */ true, testColorId); + assertEquals( + "Action button color mismatch for incognito with GM3 flag disabled (colorId" + + " ignored).", + expectedIncognito, + actualIncognito); + + // Test with a null colorId to ensure it behaves the same as with a non-null colorId when + // the flag is off. + ColorStateList actualNonIncognitoNullId = + SurfaceColorUpdateUtils.getCardViewActionButtonColor( + mContext, /* isIncognito= */ false, /* colorId= */ null); + assertEquals( + "Action button color should be the same for null and non-null colorId when GM3 flag" + + " is disabled.", + expectedNonIncognito, + actualNonIncognitoNullId); + } }
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/ToolbarProgressBar.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/ToolbarProgressBar.java index e28be8f..7ce0b82 100644 --- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/ToolbarProgressBar.java +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/ToolbarProgressBar.java
@@ -388,6 +388,7 @@ setForegroundColor(SemanticColorUtils.getProgressBarForeground(getContext())); if (ChromeFeatureList.sAndroidProgressBarVisualUpdate.isEnabled()) { setBackgroundColor(SemanticColorUtils.getProgressBarTrackColor(getContext())); + setProgressGapBackgroundColor(color); } else { setBackgroundColor(getContext().getColor(R.color.progress_bar_bg_color_list)); } @@ -405,6 +406,9 @@ setBackgroundColor( ColorUtils.getColorWithOverlay( color, Color.WHITE, THEMED_BACKGROUND_WHITE_FRACTION)); + if (ChromeFeatureList.sAndroidProgressBarVisualUpdate.isEnabled()) { + setProgressGapBackgroundColor(color); + } } @Override
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/ToolbarProgressBarTest.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/ToolbarProgressBarTest.java index 2b58a83..de0f629 100644 --- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/ToolbarProgressBarTest.java +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/ToolbarProgressBarTest.java
@@ -14,6 +14,7 @@ import android.content.res.Resources; import android.graphics.Color; import android.graphics.drawable.ClipDrawable; +import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.LayerDrawable; import android.view.View; @@ -380,6 +381,10 @@ "Background color does not match expected color.", SemanticColorUtils.getProgressBarTrackColor(mActivity), mProgressBar.getBackgroundColor()); + + int gapBackgroundColor = ((ColorDrawable) mProgressBar.getBackground()).getColor(); + assertEquals("Gap color doesn't match the toolbar color.", mThemeColor, + gapBackgroundColor); } @Test
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/optional_button/OptionalButtonCoordinator.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/optional_button/OptionalButtonCoordinator.java index d984075b..4f8bd8a 100644 --- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/optional_button/OptionalButtonCoordinator.java +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/optional_button/OptionalButtonCoordinator.java
@@ -109,6 +109,16 @@ } /** + * Set the capability of optional button changing its own visibility. If set to {@code false}, + * optional button leaves the visibility control to some other entity. {@code true} by default. + * + * @param canChange Whether optional button can change its own visibility. + */ + public void setCanChangeVisibility(boolean canChange) { + mMediator.setCanChangeVisibility(canChange); + } + + /** * Sets the collapsed state width of the button, overriding the default value. * * @param width The new collapsed state width.
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/optional_button/OptionalButtonMediator.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/optional_button/OptionalButtonMediator.java index 7abe751..c1292a5 100644 --- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/optional_button/OptionalButtonMediator.java +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/optional_button/OptionalButtonMediator.java
@@ -48,6 +48,10 @@ mModel.set(OptionalButtonProperties.IS_INCOGNITO_BRANDED, isIncognitoBranded); } + void setCanChangeVisibility(boolean canChange) { + mModel.set(OptionalButtonProperties.CAN_CHANGE_VISIBILITY, canChange); + } + public void setOnBeforeHideTransitionCallback(Runnable onBeforeHideTransitionCallback) { mModel.set( OptionalButtonProperties.ON_BEFORE_HIDE_TRANSITION_CALLBACK,
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/optional_button/OptionalButtonProperties.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/optional_button/OptionalButtonProperties.java index 3c19db8..ffdb6e3 100644 --- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/optional_button/OptionalButtonProperties.java +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/optional_button/OptionalButtonProperties.java
@@ -25,6 +25,8 @@ public static final WritableObjectPropertyKey<ButtonData> BUTTON_DATA = new WritableObjectPropertyKey<>(/* skipEquality= */ true); public static final WritableBooleanPropertyKey IS_ENABLED = new WritableBooleanPropertyKey(); + public static final WritableBooleanPropertyKey CAN_CHANGE_VISIBILITY = + new WritableBooleanPropertyKey(); public static final WritableBooleanPropertyKey IS_INCOGNITO_BRANDED = new WritableBooleanPropertyKey(); public static final WritableObjectPropertyKey<Callback<Integer>> TRANSITION_STARTED_CALLBACK = @@ -49,6 +51,7 @@ public static final PropertyKey[] ALL_KEYS = { BUTTON_DATA, IS_ENABLED, + CAN_CHANGE_VISIBILITY, IS_INCOGNITO_BRANDED, TRANSITION_STARTED_CALLBACK, TRANSITION_FINISHED_CALLBACK,
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/optional_button/OptionalButtonView.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/optional_button/OptionalButtonView.java index ece5f28e5..b48d670f 100644 --- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/optional_button/OptionalButtonView.java +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/optional_button/OptionalButtonView.java
@@ -101,6 +101,10 @@ private @AdaptiveToolbarButtonVariant int mCurrentButtonVariant = AdaptiveToolbarButtonVariant.NONE; private boolean mCanCurrentButtonShow; + + // Indicates whether this optional button can change its own the visibility or leave the control + // to some other entity. {@code true} by default. + private boolean mCanChangeOwnVisibility = true; private @ButtonType int mCurrentButtonType; private @ButtonType int mNextButtonType; @@ -440,6 +444,10 @@ mActionChipLabel.setEnabled(enabled); } + void setCanChangeVisibility(boolean canChange) { + mCanChangeOwnVisibility = canChange; + } + /** * Gets a handler used to schedule the action chip collapse animation after the action chip * finishes expanding. Tests can set their own handler with {@code setHandlerForTesting}. @@ -512,7 +520,7 @@ mAnimationImage.setVisibility(GONE); if (mState == State.HIDDEN) { - this.setVisibility(GONE); + if (mCanChangeOwnVisibility) this.setVisibility(GONE); } else { mButton.setVisibility(VISIBLE); mButton.setImageDrawable(mIconDrawable); @@ -752,7 +760,7 @@ } if (getVisibility() == GONE) { - setVisibility(VISIBLE); + if (mCanChangeOwnVisibility) this.setVisibility(VISIBLE); setWidth(0); } @@ -884,7 +892,7 @@ } // Prepare views for the transition, these changes aren't animated. - this.setVisibility(VISIBLE); + if (mCanChangeOwnVisibility) this.setVisibility(VISIBLE); setWidth(0); mButton.setVisibility(GONE);
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/optional_button/OptionalButtonViewBinder.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/optional_button/OptionalButtonViewBinder.java index 269e7a8..ca4be4b 100644 --- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/optional_button/OptionalButtonViewBinder.java +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/optional_button/OptionalButtonViewBinder.java
@@ -15,6 +15,8 @@ view.updateButtonWithAnimation(model.get(OptionalButtonProperties.BUTTON_DATA)); } else if (OptionalButtonProperties.IS_ENABLED.equals(propertyKey)) { view.setEnabled(model.get(OptionalButtonProperties.IS_ENABLED)); + } else if (OptionalButtonProperties.CAN_CHANGE_VISIBILITY.equals(propertyKey)) { + view.setCanChangeVisibility(model.get(OptionalButtonProperties.CAN_CHANGE_VISIBILITY)); } else if (OptionalButtonProperties.TRANSITION_STARTED_CALLBACK.equals(propertyKey)) { view.setTransitionStartedCallback( model.get(OptionalButtonProperties.TRANSITION_STARTED_CALLBACK));
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/optional_button/OptionalButtonViewTest.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/optional_button/OptionalButtonViewTest.java index 00da1de..f095b482 100644 --- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/optional_button/OptionalButtonViewTest.java +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/optional_button/OptionalButtonViewTest.java
@@ -918,6 +918,17 @@ } @Test + public void testUpdateButton_canChangeOwnVisibility() { + ButtonDataImpl buttonData = getDataForReaderModeActionChip(); + mOptionalButtonView.setVisibility(View.GONE); + mOptionalButtonView.setCanChangeVisibility(false); + mOptionalButtonView.updateButtonWithAnimation(buttonData); + + // OptionalButtonView stays invisible after going through the animation. + assertEquals(View.GONE, mOptionalButtonView.getVisibility()); + } + + @Test public void testUpdateButton_shouldWaitUntilTransitionRootIsLaidOut() { ButtonDataImpl buttonData = getDataForReaderModeActionChip();
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarLayout.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarLayout.java index 4b77abad..80a010a 100644 --- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarLayout.java +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarLayout.java
@@ -133,6 +133,8 @@ * @param historyDelegate Delegate used to display navigation history. * @param userEducationHelper Helper for user education flows. * @param trackerSupplier Provides a {@link Tracker} when available. + * @param homeButtonDisplay The {@link HomeButtonDisplay} to manage the display and behavior of + * home button(s). Should be null on custom tabs. */ @CallSuper @Initializer @@ -147,7 +149,7 @@ ToolbarProgressBar progressBar, @Nullable ReloadButtonCoordinator reloadButtonCoordinator, @Nullable BackButtonCoordinator backButtonCoordinator, - HomeButtonDisplay homeButtonDisplay) { + @Nullable HomeButtonDisplay homeButtonDisplay) { mToolbarDataProvider = toolbarDataProvider; mToolbarTabController = tabController; mMenuButtonCoordinator = menuButtonCoordinator;
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 e1a04dd..f996fb3 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
@@ -363,7 +363,7 @@ ToolbarProgressBar progressBar, @Nullable ReloadButtonCoordinator reloadButtonCoordinator, @Nullable BackButtonCoordinator backButtonCoordinator, - HomeButtonDisplay homeButtonDisplay) { + @Nullable HomeButtonDisplay homeButtonDisplay) { super.initialize( toolbarDataProvider, tabController, @@ -378,7 +378,7 @@ homeButtonDisplay); mUserEducationHelper = userEducationHelper; mTrackerSupplier = trackerSupplier; - mHomeButtonDisplay = homeButtonDisplay; + mHomeButtonDisplay = assumeNonNull(homeButtonDisplay); getToolbarDataProvider().addToolbarDataProviderObserver(this);
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarTablet.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarTablet.java index bf309db..1f89a6e 100644 --- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarTablet.java +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarTablet.java
@@ -398,7 +398,7 @@ ToolbarProgressBar progressBar, @Nullable ReloadButtonCoordinator reloadButtonCoordinator, @Nullable BackButtonCoordinator backButtonCoordinator, - HomeButtonDisplay homeButtonDisplay) { + @Nullable HomeButtonDisplay homeButtonDisplay) { super.initialize( toolbarDataProvider, tabController,
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/TopToolbarCoordinator.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/TopToolbarCoordinator.java index b9cc771..da1b5dc 100644 --- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/TopToolbarCoordinator.java +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/TopToolbarCoordinator.java
@@ -151,7 +151,7 @@ * TabStripTransitionDelegate}. * @param onLongClickListener OnLongClickListener for the toolbar. * @param homeButtonDisplay The {@link HomeButtonDisplay} to manage the display and behavior of - * home button(s). + * home button(s). Should be null on custom tabs. */ public TopToolbarCoordinator( ToolbarControlContainer controlContainer, @@ -184,7 +184,7 @@ ObservableSupplier<@Nullable Tab> tabSupplier, ObservableSupplier<Boolean> toolbarNavControlsEnabledSupplier, @Nullable BackButtonCoordinator backButtonCoordinator, - HomeButtonDisplay homeButtonDisplay) { + @Nullable HomeButtonDisplay homeButtonDisplay) { mToolbarLayout = toolbarLayout; mMenuButtonCoordinator = browsingModeMenuButtonCoordinator; mControlContainer = controlContainer;
diff --git a/chrome/browser/ui/color/chrome_color_id.h b/chrome/browser/ui/color/chrome_color_id.h index 8e44a23..10e86f2 100644 --- a/chrome/browser/ui/color/chrome_color_id.h +++ b/chrome/browser/ui/color/chrome_color_id.h
@@ -260,6 +260,7 @@ E_CPONLY(kColorNewTabPageCartModuleDiscountChipForeground) \ E_CPONLY(kColorNewTabPageChipBackground) \ E_CPONLY(kColorNewTabPageChipForeground) \ + E_CPONLY(kColorNewTabPageComposeboxBackground) \ E_CPONLY(kColorNewTabPageControlBackgroundHovered) \ E_CPONLY(kColorNewTabPageControlBackgroundSelected) \ E_CPONLY(kColorNewTabPageDialogBackground) \
diff --git a/chrome/browser/ui/color/material_new_tab_page_color_mixer.cc b/chrome/browser/ui/color/material_new_tab_page_color_mixer.cc index c8a432af..9798f64 100644 --- a/chrome/browser/ui/color/material_new_tab_page_color_mixer.cc +++ b/chrome/browser/ui/color/material_new_tab_page_color_mixer.cc
@@ -38,6 +38,9 @@ mixer[kColorNewTabPageButtonBackgroundHovered] = { ui::kColorSysStateHoverOnSubtle}; mixer[kColorNewTabPageButtonForeground] = {ui::kColorSysOnTonalContainer}; + mixer[kColorNewTabPageComposeboxBackground] = { + dark_mode ? SkColorSetRGB(0x1D, 0x1E, 0x26) + : SkColorSetRGB(0xF0, 0xF2, 0xF5)}; mixer[kColorNewTabPageControlBackgroundHovered] = { ui::kColorSysStateHoverOnSubtle};
diff --git a/chrome/browser/ui/color/new_tab_page_color_mixer.cc b/chrome/browser/ui/color/new_tab_page_color_mixer.cc index fa44bdd8d..2a31a808 100644 --- a/chrome/browser/ui/color/new_tab_page_color_mixer.cc +++ b/chrome/browser/ui/color/new_tab_page_color_mixer.cc
@@ -313,6 +313,10 @@ ui::SelectBasedOnDarkInput(kColorNewTabPageAddShortcutBackground, SK_ColorWHITE, gfx::kGoogleGrey900); + mixer[kColorNewTabPageComposeboxBackground] = { + dark_mode ? SkColorSetRGB(0x1D, 0x1E, 0x26) + : SkColorSetRGB(0xF0, 0xF2, 0xF5)}; + mixer[kColorNewTabPageMostVisitedTileBackgroundUnthemed] = { gfx::kGoogleGrey100}; mixer[kColorNewTabPageSectionBorder] =
diff --git a/chrome/browser/ui/messages/android/java/src/org/chromium/chrome/browser/ui/messages/snackbar/SnackbarManager.java b/chrome/browser/ui/messages/android/java/src/org/chromium/chrome/browser/ui/messages/snackbar/SnackbarManager.java index 7715bf6db..9a0a9a5 100644 --- a/chrome/browser/ui/messages/android/java/src/org/chromium/chrome/browser/ui/messages/snackbar/SnackbarManager.java +++ b/chrome/browser/ui/messages/android/java/src/org/chromium/chrome/browser/ui/messages/snackbar/SnackbarManager.java
@@ -245,7 +245,7 @@ public int pushParentViewToOverrideStack(ViewGroup parentView) { assert parentView != null; int overrideToken = mTokenHolder.acquireToken(); - mParentViewOverrideStack.push(new Pair<Integer, ViewGroup>(overrideToken, parentView)); + mParentViewOverrideStack.push(new Pair<>(overrideToken, parentView)); overrideParent(parentView); return overrideToken; }
diff --git a/chrome/browser/ui/page_action/page_action_icon_type.cc b/chrome/browser/ui/page_action/page_action_icon_type.cc index f0a2560c..4a5a21f 100644 --- a/chrome/browser/ui/page_action/page_action_icon_type.cc +++ b/chrome/browser/ui/page_action/page_action_icon_type.cc
@@ -32,6 +32,8 @@ return &features::kPageActionsMigrationPriceInsights; case PageActionIconType::kManagePasswords: return &features::kPageActionsMigrationManagePasswords; + case PageActionIconType::kCookieControls: + return &features::kPageActionsMigrationCookieControls; default: return nullptr; }
diff --git a/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc b/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc index a8cc669..bb25d41 100644 --- a/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc +++ b/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc
@@ -31,6 +31,8 @@ #include "chrome/browser/password_manager/profile_password_store_factory.h" #include "chrome/browser/promos/promos_types.h" #include "chrome/browser/signin/signin_promo_util.h" +#include "chrome/browser/ui/actions/chrome_action_id.h" +#include "chrome/browser/ui/browser_actions.h" #include "chrome/browser/ui/browser_command_controller.h" #include "chrome/browser/ui/browser_commands.h" #include "chrome/browser/ui/browser_finder.h" @@ -1171,7 +1173,12 @@ CHECK(tab_features); auto* const controller = tab_features->manage_passwords_page_action_controller(); - controller->UpdateVisibility(GetState(), IsExplicitlyBlocklisted(), this); + actions::ActionItem* passwords_action_item = + actions::ActionManager::Get().FindAction( + kActionShowPasswordsBubbleOrPage, + browser->browser_actions()->root_action_item()); + controller->UpdateVisibility(GetState(), IsExplicitlyBlocklisted(), *this, + *passwords_action_item); } else { browser->window()->UpdatePageActionIcon( PageActionIconType::kManagePasswords);
diff --git a/chrome/browser/ui/tabs/tab_strip_model.cc b/chrome/browser/ui/tabs/tab_strip_model.cc index 6470e40..c2aa99fa 100644 --- a/chrome/browser/ui/tabs/tab_strip_model.cc +++ b/chrome/browser/ui/tabs/tab_strip_model.cc
@@ -2491,15 +2491,36 @@ case CommandAddToSplit: { CHECK(base::FeatureList::IsEnabled(features::kSideBySide)); std::vector<int> indices = GetIndicesForCommand(context_index); - if (indices.size() == 1) { - delegate_->NewSplitTab(context_index == active_index() - ? std::vector<int>() - : std::vector<int>({context_index})); - } else { - CHECK(indices.size() > 1); - std::erase(indices, active_index()); - delegate_->NewSplitTab(indices); + // There are three cases for adding to a split. + // 1. Selecting an inactive tab and making it a split with the active. + // 2. Selecting active and inactive tab and creating a split + // 3. Splitting the active tab with itself. + // Remove the active tab from the indices first since splitting is done + // with the active tab. Case 3 is a special zero split case that creates a + // new split tab and is inferred by the delegate. + std::erase_if(indices, [this](int tab_index) { + return tab_index == active_index(); + }); + + // This callback results in creating a split. It is either sent to the + // deletion dialog that owns it and is responsible for calling it or if no + // group is deleted it is simply called here. + base::OnceCallback<void()> callback = + base::BindOnce(&TabStripModelDelegate::NewSplitTab, + base::Unretained(delegate_), indices); + + // If we are splitting the active tab no group can be deleted. + if (!indices.empty()) { + std::vector<tab_groups::TabGroupId> groups_to_delete = + GetGroupsDestroyedFromRemovingIndices(indices); + if (!groups_to_delete.empty()) { + MarkTabGroupsForClosing(groups_to_delete); + return delegate_->OnRemovingAllTabsFromGroups(groups_to_delete, + std::move(callback)); + } } + + std::move(callback).Run(); break; }
diff --git a/chrome/browser/ui/tabs/tab_strip_model_browsertest.cc b/chrome/browser/ui/tabs/tab_strip_model_browsertest.cc index afe95b1..78e7afe9 100644 --- a/chrome/browser/ui/tabs/tab_strip_model_browsertest.cc +++ b/chrome/browser/ui/tabs/tab_strip_model_browsertest.cc
@@ -399,6 +399,35 @@ EXPECT_FALSE(tab_strip_model->GetTabAtIndex(4)->IsSplit()); } +IN_PROC_BROWSER_TEST_F(TabStripModelBrowserTest, + CommandAddToSplitWhenDeletesGroupShowsDeletionDialog) { + TabStripModel* const tab_strip_model = browser()->tab_strip_model(); + AddTabs(4); + EXPECT_EQ(tab_strip_model->count(), 5); + + // Add tab at index 4 to a group. + tab_groups::TabGroupId group_id = tab_strip_model->AddToNewGroup({4}); + + tab_strip_model->ActivateTabAt(3); + EXPECT_TRUE(tab_strip_model->IsContextMenuCommandEnabled( + 4, TabStripModel::CommandAddToSplit)); + + tab_strip_model->ExecuteContextMenuCommand(4, + TabStripModel::CommandAddToSplit); + + // Make sure the dialog is shown, and fake clicking the button. + tab_groups::DeletionDialogController* deletion_dialog_controller = + browser()->GetFeatures().tab_group_deletion_dialog_controller(); + EXPECT_TRUE(deletion_dialog_controller->IsShowingDialog()); + + // Pull the dialog state and call the OnDialogOk method. + deletion_dialog_controller->SimulateOkButtonForTesting(); + + EXPECT_FALSE(tab_strip_model->group_model()->ContainsTabGroup(group_id)); + EXPECT_TRUE(tab_strip_model->GetTabAtIndex(3)->GetSplit().has_value()); + EXPECT_TRUE(tab_strip_model->GetTabAtIndex(4)->GetSplit().has_value()); +} + IN_PROC_BROWSER_TEST_F(TabStripModelBrowserTest, CommandSwapWithActiveSplit) { TabStripModel* const tab_strip_model = browser()->tab_strip_model(); AddTabs(3);
diff --git a/chrome/browser/ui/ui_features.h b/chrome/browser/ui/ui_features.h index 71c4b8e..1d2c0bf 100644 --- a/chrome/browser/ui/ui_features.h +++ b/chrome/browser/ui/ui_features.h
@@ -368,6 +368,11 @@ "manage_passwords", false); +inline constexpr base::FeatureParam<bool> kPageActionsMigrationCookieControls( + &kPageActionsMigration, + "cookie_controls", + false); + // Determines whether the "save password" page action displays different UI if // the user has said to never save passwords for that site. BASE_DECLARE_FEATURE(kSavePasswordsContextualUi);
diff --git a/chrome/browser/ui/views/autofill/payments/payments_view_util.cc b/chrome/browser/ui/views/autofill/payments/payments_view_util.cc index a8113344..5a40f1e 100644 --- a/chrome/browser/ui/views/autofill/payments/payments_view_util.cc +++ b/chrome/browser/ui/views/autofill/payments/payments_view_util.cc
@@ -127,6 +127,36 @@ TextLinkInfo::~TextLinkInfo() = default; +LabeledTextfieldWithErrorMessage::LabeledTextfieldWithErrorMessage() = default; + +LabeledTextfieldWithErrorMessage::LabeledTextfieldWithErrorMessage( + LabeledTextfieldWithErrorMessage&& other) = default; +LabeledTextfieldWithErrorMessage& LabeledTextfieldWithErrorMessage::operator=( + LabeledTextfieldWithErrorMessage&& other) = default; + +LabeledTextfieldWithErrorMessage::~LabeledTextfieldWithErrorMessage() = default; + +views::Textfield& LabeledTextfieldWithErrorMessage::GetInputTextField() const { + CHECK(input); + return *input; +} + +void LabeledTextfieldWithErrorMessage::SetErrorState( + bool is_valid_input, + std::optional<std::u16string> error_message) { + CHECK(input); + input->SetInvalid(!is_valid_input); + if (error_label) { + if (error_message.has_value()) { + error_label->SetText(error_message.value()); + } + error_label->SetVisible(!is_valid_input); + } + if (error_label_placeholder) { + error_label_placeholder->SetVisible(is_valid_input); + } +} + ui::ImageModel GetProfileAvatar(const AccountInfo& account_info) { // Get the user avatar icon. gfx::Image account_avatar = account_info.account_image; @@ -346,25 +376,56 @@ } #endif // BUILDFLAG(GOOGLE_CHROME_BRANDING) -std::unique_ptr<views::View> CreateLabelAndTextfieldView( - const std::u16string& text) { - auto view_builder = +LabeledTextfieldWithErrorMessage CreateLabelAndTextfieldView( + const std::u16string& label_text, + std::optional<std::u16string> error_message) { + LabeledTextfieldWithErrorMessage result; + + result.container = views::Builder<views::BoxLayoutView>() .SetOrientation(views::BoxLayout::Orientation::kVertical) - .SetBetweenChildSpacing( - ChromeLayoutProvider::Get()->GetDistanceMetric( - DISTANCE_RELATED_CONTROL_VERTICAL_SMALL)); + .Build(); + result.container->AddChildView( + views::Builder<views::Label>() + .SetText(label_text) + .SetTextContext(views::style::CONTEXT_LABEL) + .SetTextStyle(views::style::STYLE_PRIMARY) + .SetHorizontalAlignment(gfx::ALIGN_TO_HEAD) + .Build()); + result.container->AddChildView( + views::Builder<views::View>() + .SetPreferredSize( + gfx::Size(0, ChromeLayoutProvider::Get()->GetDistanceMetric( + views::DISTANCE_RELATED_CONTROL_VERTICAL))) + .Build()); + result.input = result.container->AddChildView( + views::Builder<views::Textfield>().SetAccessibleName(label_text).Build()); - view_builder.AddChild(views::Builder<views::Label>() - .SetText(text) - .SetTextContext(views::style::CONTEXT_LABEL) - .SetTextStyle(views::style::STYLE_PRIMARY) - .SetHorizontalAlignment(gfx::ALIGN_TO_HEAD)); - - view_builder.AddChild( - views::Builder<views::Textfield>().SetAccessibleName(text)); - - return std::move(view_builder).Build(); + if (error_message.has_value()) { + result.error_label = result.container->AddChildView( + views::Builder<views::Label>() + .SetText(*error_message) + .SetTextContext(views::style::CONTEXT_TEXTFIELD_SUPPORTING_TEXT) + .SetTextStyle(STYLE_RED) + .SetHorizontalAlignment(gfx::HorizontalAlignment::ALIGN_LEFT) + .SetVisible(false) + .SetEnabled(false) + .SetMultiLine(true) + .Build()); + // Add a padding view which will be visible initially to reserve + // space for the error label. This helps maintain the height of the + // dialog regardless of whether the error message is visible or not, + // preventing the dialog from shifting and stretching. When the error + // message appears, this padding is hidden, and when the error message + // disappears, the padding reappears to fill the space. + result.error_label_placeholder = result.container->AddChildView( + views::Builder<views::View>() + .SetPreferredSize(result.error_label->GetPreferredSize( + views::SizeBounds(result.error_label->width(), {}))) + .SetVisible(true) + .Build()); + } + return result; } } // namespace autofill
diff --git a/chrome/browser/ui/views/autofill/payments/payments_view_util.h b/chrome/browser/ui/views/autofill/payments/payments_view_util.h index 4a27f86..8afaa92 100644 --- a/chrome/browser/ui/views/autofill/payments/payments_view_util.h +++ b/chrome/browser/ui/views/autofill/payments/payments_view_util.h
@@ -17,6 +17,8 @@ #include "ui/base/metadata/metadata_header_macros.h" #include "ui/base/models/image_model.h" #include "ui/gfx/range/range.h" +#include "ui/views/controls/label.h" +#include "ui/views/controls/textfield/textfield.h" #include "ui/views/layout/box_layout_view.h" class GURL; @@ -43,6 +45,30 @@ base::RepeatingCallback<void()> callback; }; +struct LabeledTextfieldWithErrorMessage { + LabeledTextfieldWithErrorMessage(); + + LabeledTextfieldWithErrorMessage( + const LabeledTextfieldWithErrorMessage& other); + LabeledTextfieldWithErrorMessage& operator=( + const LabeledTextfieldWithErrorMessage& other); + LabeledTextfieldWithErrorMessage(LabeledTextfieldWithErrorMessage&& other); + LabeledTextfieldWithErrorMessage& operator=( + LabeledTextfieldWithErrorMessage&& other); + + ~LabeledTextfieldWithErrorMessage(); + + std::unique_ptr<views::View> container = nullptr; + raw_ptr<views::Textfield> input = nullptr; + raw_ptr<views::Label> error_label = nullptr; + raw_ptr<views::View> error_label_placeholder = nullptr; + + views::Textfield& GetInputTextField() const; + + void SetErrorState(bool is_valid_input, + std::optional<std::u16string> error_message); +}; + // Gets the user avatar icon if available, or else a placeholder. ui::ImageModel GetProfileAvatar(const AccountInfo& account_info); @@ -110,10 +136,12 @@ const ui::ColorProvider* provider); #endif // BUILDFLAG(GOOGLE_CHROME_BRANDING) -// Creates a view containing a label and a textfield. The view is arranged -// vertically with the label positioned above the textfield. -std::unique_ptr<views::View> CreateLabelAndTextfieldView( - const std::u16string& text); +// Creates a view containing a label and a textfield with an optional error +// message. The view is arranged vertically with the label positioned above the +// textfield. +LabeledTextfieldWithErrorMessage CreateLabelAndTextfieldView( + const std::u16string& label_text, + std::optional<std::u16string> error_message); } // namespace autofill
diff --git a/chrome/browser/ui/views/autofill/payments/save_and_fill_dialog.cc b/chrome/browser/ui/views/autofill/payments/save_and_fill_dialog.cc index fa68ad89..04d520c 100644 --- a/chrome/browser/ui/views/autofill/payments/save_and_fill_dialog.cc +++ b/chrome/browser/ui/views/autofill/payments/save_and_fill_dialog.cc
@@ -6,6 +6,7 @@ #include "chrome/browser/ui/views/autofill/payments/payments_view_util.h" #include "chrome/browser/ui/views/chrome_layout_provider.h" +#include "chrome/browser/ui/views/chrome_typography.h" #include "components/autofill/core/browser/ui/payments/save_and_fill_dialog_controller.h" #include "ui/base/mojom/dialog_button.mojom.h" #include "ui/views/accessibility/view_accessibility.h" @@ -53,11 +54,20 @@ return controller_ ? controller_->GetWindowTitle() : std::u16string(); } +void SaveAndFillDialog::ContentsChanged(views::Textfield* sender, + const std::u16string& new_contents) { + if (sender == &card_number_data_.GetInputTextField()) { + card_number_data_.SetErrorState( + /*is_valid_input=*/controller_->IsValidCreditCardNumber(new_contents), + /*error_message=*/controller_->GetInvalidCardNumberErrorMessage()); + } +} + void SaveAndFillDialog::InitViews() { auto* layout = SetLayoutManager(std::make_unique<views::BoxLayout>( views::BoxLayout::Orientation::kVertical, gfx::Insets(), ChromeLayoutProvider::Get()->GetDistanceMetric( - views::DISTANCE_UNRELATED_CONTROL_VERTICAL))); + views::DISTANCE_RELATED_CONTROL_VERTICAL))); layout->set_main_axis_alignment(views::BoxLayout::MainAxisAlignment::kCenter); set_margins(ChromeLayoutProvider::Get()->GetDialogInsetsForContentType( views::DialogContentType::kControl, views::DialogContentType::kControl)); @@ -69,10 +79,21 @@ .SetMultiLine(true) .SetHorizontalAlignment(gfx::ALIGN_TO_HEAD) .Build()); - // Create a container for the card number label and textfield. - AddChildView(CreateLabelAndTextfieldView(controller_->GetCardNumberLabel())); - // Create a container for the cardholder name label and textfield. - AddChildView(CreateLabelAndTextfieldView(controller_->GetNameOnCardLabel())); + + card_number_data_ = CreateLabelAndTextfieldView( + /*label_text=*/controller_->GetCardNumberLabel(), + /*error_message=*/controller_->GetInvalidCardNumberErrorMessage()); + card_number_data_.GetInputTextField().SetTextInputType( + ui::TextInputType::TEXT_INPUT_TYPE_NUMBER); + card_number_data_.GetInputTextField().SetController(this); + AddChildView(std::move(card_number_data_.container)); + + // TODO(crbug.com/378163937): Implement validation rule for the `name on card` + // field. + AddChildView(std::move(CreateLabelAndTextfieldView( + /*label_text=*/controller_->GetNameOnCardLabel(), + /*error_message=*/std::u16string()) + .container)); } } // namespace autofill
diff --git a/chrome/browser/ui/views/autofill/payments/save_and_fill_dialog.h b/chrome/browser/ui/views/autofill/payments/save_and_fill_dialog.h index d6d3fc8..03cc9e3 100644 --- a/chrome/browser/ui/views/autofill/payments/save_and_fill_dialog.h +++ b/chrome/browser/ui/views/autofill/payments/save_and_fill_dialog.h
@@ -5,7 +5,9 @@ #ifndef CHROME_BROWSER_UI_VIEWS_AUTOFILL_PAYMENTS_SAVE_AND_FILL_DIALOG_H_ #define CHROME_BROWSER_UI_VIEWS_AUTOFILL_PAYMENTS_SAVE_AND_FILL_DIALOG_H_ +#include "chrome/browser/ui/views/autofill/payments/payments_view_util.h" #include "components/autofill/core/browser/ui/payments/save_and_fill_dialog_view.h" +#include "ui/views/controls/textfield/textfield_controller.h" #include "ui/views/window/dialog_delegate.h" namespace autofill { @@ -14,7 +16,8 @@ // The dialog delegate view implementation for the Save and Fill dialog view. // This is owned by the view hierarchy. -class SaveAndFillDialog : public views::DialogDelegateView { +class SaveAndFillDialog : public views::DialogDelegateView, + public views::TextfieldController { public: explicit SaveAndFillDialog( base::WeakPtr<SaveAndFillDialogController> controller); @@ -26,11 +29,17 @@ void AddedToWidget() override; std::u16string GetWindowTitle() const override; + // views::TextfieldController + void ContentsChanged(views::Textfield* sender, + const std::u16string& new_contents) override; + private: // Initialize the dialog's contents. void InitViews(); base::WeakPtr<SaveAndFillDialogController> controller_; + + LabeledTextfieldWithErrorMessage card_number_data_; }; } // namespace autofill
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_mac.mm b/chrome/browser/ui/views/frame/browser_non_client_frame_view_mac.mm index 09a8990..f69dd8c 100644 --- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_mac.mm +++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_mac.mm
@@ -377,8 +377,7 @@ AddChildView(std::make_unique<CaptionButtonPlaceholderContainer>()); UpdateCaptionButtonPlaceholderContainerBackground(); } else { - RemoveChildView(caption_button_placeholder_container_); - caption_button_placeholder_container_ = nullptr; + RemoveChildViewT(caption_button_placeholder_container_.ExtractAsDangling()); } } ///////////////////////////////////////////////////////////////////////////////
diff --git a/chrome/browser/ui/views/frame/picture_in_picture_browser_frame_view.cc b/chrome/browser/ui/views/frame/picture_in_picture_browser_frame_view.cc index 7f5daf3..aa79e8f 100644 --- a/chrome/browser/ui/views/frame/picture_in_picture_browser_frame_view.cc +++ b/chrome/browser/ui/views/frame/picture_in_picture_browser_frame_view.cc
@@ -20,6 +20,7 @@ #include "chrome/browser/ui/views/frame/top_container_view.h" #include "chrome/browser/ui/views/overlay/overlay_window_image_button.h" #include "chrome/browser/ui/views/page_info/page_info_bubble_view.h" +#include "chrome/browser/ui/views/picture_in_picture/picture_in_picture_tucker.h" #include "chrome/grit/generated_resources.h" #include "components/omnibox/browser/location_bar_model_impl.h" #include "components/vector_icons/vector_icons.h" @@ -610,6 +611,8 @@ PictureInPictureBrowserFrameView::~PictureInPictureBrowserFrameView() { base::UmaHistogramEnumeration("Media.DocumentPictureInPicture.CloseReason", close_reason_); + PictureInPictureWindowManager::GetInstance()->OnPictureInPictureWindowHidden( + this); } /////////////////////////////////////////////////////////////////////////////// @@ -874,6 +877,9 @@ tracker->OnPictureInPictureWidgetOpened(GetWidget()); } + PictureInPictureWindowManager::GetInstance()->OnPictureInPictureWindowShown( + this); + BrowserNonClientFrameView::AddedToWidget(); } @@ -887,6 +893,10 @@ auto_pip_setting_overlay_ = nullptr; } + PictureInPictureWindowManager::GetInstance()->OnPictureInPictureWindowHidden( + this); + tucker_.reset(); + BrowserNonClientFrameView::RemovedFromWidget(); } @@ -920,8 +930,15 @@ if (!base::FeatureList::IsEnabled( media::kDocumentPictureInPictureAnimateResize) || - !gfx::Animation::ShouldRenderRichAnimation()) { + !gfx::Animation::ShouldRenderRichAnimation() || is_tucking_forced_) { BrowserNonClientFrameView::SetFrameBounds(adjusted_bounds); + + // If we're forced to tuck, then re-tuck after the size adjustment. Note + // that we also always skip the bounds change animation when tucking is + // forced. + if (is_tucking_forced_) { + tucker_->Tuck(); + } return; } bounds_change_animation_ = @@ -1087,6 +1104,14 @@ child_dialog_observer_helper_.reset(); } +void PictureInPictureBrowserFrameView::OnWidgetVisibilityChanged( + views::Widget* widget, + bool visible) { + if (visible) { + EnforceTucking(); + } +} + void PictureInPictureBrowserFrameView::OnWidgetBoundsChanged( views::Widget* widget, const gfx::Rect& new_bounds) { @@ -1094,6 +1119,41 @@ } /////////////////////////////////////////////////////////////////////////////// +// PictureInPictureWindow implementations: + +void PictureInPictureBrowserFrameView::SetForcedTucking(bool tuck) { + if (!tucker_) { + CHECK(GetWidget()); + tucker_ = std::make_unique<PictureInPictureTucker>(*GetWidget()); + } + is_tucking_forced_ = tuck; + + // Attempting to tuck our Widget before it's been shown causes issues since + // it may be still adjusting its bounds. Once visible, tucking will be + // enforced. + if (GetWidget()->IsVisible()) { + EnforceTucking(); + } +} + +void PictureInPictureBrowserFrameView::EnforceTucking() { + // The `tucker_` will have been created if there's any tucking to be enforced. + if (!tucker_) { + return; + } + + if (is_tucking_forced_) { + // Stop any existing bounds change animations. + if (bounds_change_animation_) { + bounds_change_animation_->End(); + } + tucker_->Tuck(); + } else { + tucker_->Untuck(); + } +} + +/////////////////////////////////////////////////////////////////////////////// // gfx::AnimationDelegate implementations: void PictureInPictureBrowserFrameView::AnimationEnded(
diff --git a/chrome/browser/ui/views/frame/picture_in_picture_browser_frame_view.h b/chrome/browser/ui/views/frame/picture_in_picture_browser_frame_view.h index 2527151..4e630f5 100644 --- a/chrome/browser/ui/views/frame/picture_in_picture_browser_frame_view.h +++ b/chrome/browser/ui/views/frame/picture_in_picture_browser_frame_view.h
@@ -14,6 +14,7 @@ #include "base/scoped_observation.h" #include "base/timer/timer.h" #include "build/build_config.h" +#include "chrome/browser/picture_in_picture/picture_in_picture_window.h" #include "chrome/browser/ui/content_settings/content_setting_image_model_states.h" #include "chrome/browser/ui/toolbar/chrome_location_bar_model_delegate.h" #include "chrome/browser/ui/views/frame/browser_frame.h" @@ -33,6 +34,7 @@ #include "ui/views/widget/widget_observer.h" class BrowserFrameBoundsChangeAnimation; +class PictureInPictureTucker; namespace views { class Label; @@ -50,6 +52,7 @@ public IconLabelBubbleView::Delegate, public ContentSettingImageView::Delegate, public views::WidgetObserver, + public PictureInPictureWindow, public gfx::AnimationDelegate { METADATA_HEADER(PictureInPictureBrowserFrameView, BrowserNonClientFrameView) @@ -118,9 +121,13 @@ // views::WidgetObserver: void OnWidgetActivationChanged(views::Widget* widget, bool active) override; void OnWidgetDestroying(views::Widget* widget) override; + void OnWidgetVisibilityChanged(views::Widget* eidget, bool visible) override; void OnWidgetBoundsChanged(views::Widget* widget, const gfx::Rect& new_bounds) override; + // PictureInPictureWindow: + void SetForcedTucking(bool tuck) override; + // gfx::AnimationDelegate: void AnimationEnded(const gfx::Animation* animation) override; void AnimationProgressed(const gfx::Animation* animation) override; @@ -228,6 +235,8 @@ // Show `auto_pip_setting_overlay_` if we have it, and have a widget. void ShowOverlayIfNeeded(); + void EnforceTucking(); + CloseReason close_reason_ = CloseReason::kOther; // Observe child dialogs so that we can resize to ensure that they fit on @@ -380,6 +389,10 @@ // `resizeBy()` calls). std::unique_ptr<BrowserFrameBoundsChangeAnimation> bounds_change_animation_; + // Used to tuck/untuck this widget into the side of the screen. + std::unique_ptr<PictureInPictureTucker> tucker_; + bool is_tucking_forced_ = false; + base::WeakPtrFactory<PictureInPictureBrowserFrameView> weak_factory_{this}; };
diff --git a/chrome/browser/ui/views/location_bar/cookie_controls/cookie_controls_page_action_controller.cc b/chrome/browser/ui/views/location_bar/cookie_controls/cookie_controls_page_action_controller.cc new file mode 100644 index 0000000..ab5578a4 --- /dev/null +++ b/chrome/browser/ui/views/location_bar/cookie_controls/cookie_controls_page_action_controller.cc
@@ -0,0 +1,108 @@ +// Copyright 2025 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/location_bar/cookie_controls/cookie_controls_page_action_controller.h" + +#include "chrome/browser/ui/actions/chrome_action_id.h" +#include "chrome/browser/ui/page_action/page_action_icon_type.h" +#include "chrome/browser/ui/views/page_action/page_action_controller.h" +#include "chrome/browser/ui/views/page_action/page_action_observer.h" +#include "chrome/grit/generated_resources.h" +#include "components/content_settings/core/common/cookie_blocking_3pcd_status.h" +#include "components/feature_engagement/public/feature_constants.h" +#include "components/privacy_sandbox/privacy_sandbox_features.h" +#include "components/strings/grit/privacy_sandbox_strings.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/views/vector_icons.h" + +namespace { +int GetLabelForStatus(CookieControlsState controls_state, + CookieBlocking3pcdStatus blocking_status) { + switch (controls_state) { + case CookieControlsState::kActiveTp: + // TODO(crbug.com/376283777): Use + // IDS_TRACKING_PROTECTIONS_PAGE_ACTION_PROTECTIONS_RESUMED_LABEL when + // animating in. + return IDS_TRACKING_PROTECTIONS_PAGE_ACTION_PROTECTIONS_ENABLED_LABEL; + case CookieControlsState::kPausedTp: + return IDS_TRACKING_PROTECTIONS_PAGE_ACTION_PROTECTIONS_PAUSED_LABEL; + case CookieControlsState::kAllowed3pc: + return IDS_COOKIE_CONTROLS_PAGE_ACTION_COOKIES_ALLOWED_LABEL; + default: + return blocking_status == CookieBlocking3pcdStatus::kLimited + ? IDS_COOKIE_CONTROLS_PAGE_ACTION_COOKIES_LIMITED_LABEL + : IDS_COOKIE_CONTROLS_PAGE_ACTION_COOKIES_BLOCKED_LABEL; + } +} + +const gfx::VectorIcon& GetVectorIcon(CookieControlsState controls_state) { + return controls_state == CookieControlsState::kBlocked3pc || + controls_state == CookieControlsState::kActiveTp + ? views::kEyeCrossedRefreshIcon + : views::kEyeRefreshIcon; +} +} // namespace + +// TODO(crbug.com/376283777): This class needs further work to achieve full +// parity with the legacy page action, including: +// - Update icon visibility to always show if there's a bubble showing. +// - Support animations for specific cookie settings and for indication when a +// page is reloaded with new cookie settings. +// - Add IPH handling logic. +// - Implement the logic for executing the page action. +// - Add metrics reporting. +CookieControlsPageActionController::CookieControlsPageActionController( + page_actions::PageActionController& page_action_controller) + : page_action_controller_(page_action_controller) { + CHECK(IsPageActionMigrated(PageActionIconType::kCookieControls)); +} + +CookieControlsPageActionController::~CookieControlsPageActionController() = + default; + +void CookieControlsPageActionController::OnCookieControlsIconStatusChanged( + bool icon_visible, + CookieControlsState controls_state, + CookieBlocking3pcdStatus blocking_status, + bool should_highlight) { + UpdatePageActionIcon(CookieControlsIconStatus{ + .icon_visible = icon_visible, + .controls_state = controls_state, + .blocking_status = blocking_status, + .should_highlight = should_highlight, + }); +} + +void CookieControlsPageActionController::UpdatePageActionIcon( + const CookieControlsIconStatus& icon_status) { + if (!icon_status.icon_visible) { + page_action_controller_->HideSuggestionChip(kActionShowCookieControls); + page_action_controller_->Hide(kActionShowCookieControls); + return; + } + + const std::u16string& label = l10n_util::GetStringUTF16(GetLabelForStatus( + icon_status.controls_state, icon_status.blocking_status)); + page_action_controller_->OverrideImage( + kActionShowCookieControls, ui::ImageModel::FromVectorIcon(GetVectorIcon( + icon_status.controls_state))); + page_action_controller_->OverrideTooltip(kActionShowCookieControls, label); + page_action_controller_->OverrideText(kActionShowCookieControls, label); + page_action_controller_->Show(kActionShowCookieControls); + + if (icon_status.controls_state == CookieControlsState::kBlocked3pc && + icon_status.should_highlight) { + if (icon_status.blocking_status != CookieBlocking3pcdStatus::kNotIn3pcd) { + page_action_controller_->OverrideText( + kActionShowCookieControls, + l10n_util::GetStringUTF16( + IDS_TRACKING_PROTECTION_PAGE_ACTION_SITE_NOT_WORKING_LABEL)); + } + page_action_controller_->ShowSuggestionChip( + kActionShowCookieControls, page_actions::SuggestionChipConfig{ + .should_animate = true, + .should_announce_chip = true, + }); + } +}
diff --git a/chrome/browser/ui/views/location_bar/cookie_controls/cookie_controls_page_action_controller.h b/chrome/browser/ui/views/location_bar/cookie_controls/cookie_controls_page_action_controller.h new file mode 100644 index 0000000..4a60a7eb --- /dev/null +++ b/chrome/browser/ui/views/location_bar/cookie_controls/cookie_controls_page_action_controller.h
@@ -0,0 +1,53 @@ +// Copyright 2025 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_LOCATION_BAR_COOKIE_CONTROLS_COOKIE_CONTROLS_PAGE_ACTION_CONTROLLER_H_ +#define CHROME_BROWSER_UI_VIEWS_LOCATION_BAR_COOKIE_CONTROLS_COOKIE_CONTROLS_PAGE_ACTION_CONTROLLER_H_ + +#include "base/callback_list.h" +#include "base/memory/raw_ref.h" +#include "base/scoped_observation.h" +#include "components/content_settings/browser/ui/cookie_controls_view.h" +#include "components/content_settings/core/common/cookie_blocking_3pcd_status.h" + +namespace page_actions { +class PageActionController; +} // namespace page_actions + +// `CookieControlsPageActionController` is responsible for managing the cookie +// controls page action, including logic for showing/hiding and executing the +// page action. +class CookieControlsPageActionController + : public content_settings::CookieControlsObserver { + public: + explicit CookieControlsPageActionController( + page_actions::PageActionController& page_action_controller); + + CookieControlsPageActionController( + const CookieControlsPageActionController&) = delete; + CookieControlsPageActionController& operator=( + const CookieControlsPageActionController&) = delete; + ~CookieControlsPageActionController() override; + + // CookieControlsObserver: + void OnCookieControlsIconStatusChanged( + bool icon_visible, + CookieControlsState controls_state, + CookieBlocking3pcdStatus blocking_status, + bool should_highlight) override; + + private: + // Encapsulates values provided by `OnCookieControlsIconStatusChanged`. + struct CookieControlsIconStatus { + bool icon_visible; + CookieControlsState controls_state; + CookieBlocking3pcdStatus blocking_status; + bool should_highlight; + }; + + void UpdatePageActionIcon(const CookieControlsIconStatus& icon_status); + + const raw_ref<page_actions::PageActionController> page_action_controller_; +}; +#endif // CHROME_BROWSER_UI_VIEWS_LOCATION_BAR_COOKIE_CONTROLS_COOKIE_CONTROLS_PAGE_ACTION_CONTROLLER_H_
diff --git a/chrome/browser/ui/views/location_bar/cookie_controls/cookie_controls_page_action_controller_unittest.cc b/chrome/browser/ui/views/location_bar/cookie_controls/cookie_controls_page_action_controller_unittest.cc new file mode 100644 index 0000000..44e25d64 --- /dev/null +++ b/chrome/browser/ui/views/location_bar/cookie_controls/cookie_controls_page_action_controller_unittest.cc
@@ -0,0 +1,197 @@ +// Copyright 2025 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/location_bar/cookie_controls/cookie_controls_page_action_controller.h" + +#include <optional> + +#include "base/test/scoped_feature_list.h" +#include "chrome/browser/ui/actions/chrome_action_id.h" +#include "chrome/browser/ui/ui_features.h" +#include "chrome/browser/ui/views/page_action/page_action_controller.h" +#include "chrome/browser/ui/views/page_action/test_support/mock_page_action_controller.h" +#include "chrome/grit/generated_resources.h" +#include "components/content_settings/core/common/cookie_blocking_3pcd_status.h" +#include "components/content_settings/core/common/cookie_controls_state.h" +#include "components/strings/grit/privacy_sandbox_strings.h" +#include "content/public/test/browser_task_environment.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/actions/actions.h" +#include "ui/base/l10n/l10n_util.h" + +namespace { + +using testing::_; + +std::u16string AllowedLabel() { + return l10n_util::GetStringUTF16( + IDS_COOKIE_CONTROLS_PAGE_ACTION_COOKIES_ALLOWED_LABEL); +} + +std::u16string SiteNotWorkingLabel() { + return l10n_util::GetStringUTF16( + IDS_TRACKING_PROTECTION_PAGE_ACTION_SITE_NOT_WORKING_LABEL); +} + +class FakePageActionController : public page_actions::MockPageActionController { + public: + FakePageActionController() = default; + ~FakePageActionController() override = default; + + void OverrideText(actions::ActionId action_id, + const std::u16string& text) override { + page_actions::MockPageActionController::OverrideText(action_id, text); + last_text_ = text; + } + + void ClearOverrideText(actions::ActionId action_id) override { + page_actions::MockPageActionController::ClearOverrideText(action_id); + last_text_ = u""; + } + + const std::u16string& last_text() const { return last_text_; } + + private: + std::u16string last_text_; +}; + +class CookieControlsPageActionControllerTest + : public testing::Test, + public testing::WithParamInterface<CookieBlocking3pcdStatus> { + public: + CookieControlsPageActionControllerTest() { + scoped_feature_list_.InitAndEnableFeatureWithParameters( + features::kPageActionsMigration, + {{features::kPageActionsMigrationCookieControls.name, "true"}}); + + cookie_controls_page_action_controller_ = + std::make_unique<CookieControlsPageActionController>( + page_action_controller_); + } + + CookieControlsPageActionController& controller() { + return *cookie_controls_page_action_controller_; + } + + FakePageActionController& page_action_controller() { + return page_action_controller_; + } + + bool In3pcd() const { + return GetParam() != CookieBlocking3pcdStatus::kNotIn3pcd; + } + + std::u16string BlockedLabel() const { + return GetParam() == CookieBlocking3pcdStatus::kLimited + ? l10n_util::GetStringUTF16( + IDS_COOKIE_CONTROLS_PAGE_ACTION_COOKIES_LIMITED_LABEL) + : l10n_util::GetStringUTF16( + IDS_COOKIE_CONTROLS_PAGE_ACTION_COOKIES_BLOCKED_LABEL); + } + + private: + base::test::ScopedFeatureList scoped_feature_list_; + FakePageActionController page_action_controller_; + + std::unique_ptr<CookieControlsPageActionController> + cookie_controls_page_action_controller_; +}; + +INSTANTIATE_TEST_SUITE_P(All, + CookieControlsPageActionControllerTest, + testing::Values(CookieBlocking3pcdStatus::kNotIn3pcd, + CookieBlocking3pcdStatus::kLimited, + CookieBlocking3pcdStatus::kAll)); + +TEST_P(CookieControlsPageActionControllerTest, + IconAnimatesWhenShouldHighlightIsTrueAnd3pcsBlocked) { + EXPECT_CALL(page_action_controller(), Show(kActionShowCookieControls)) + .Times(1); + EXPECT_CALL(page_action_controller(), + ShowSuggestionChip(kActionShowCookieControls, _)) + .Times(1); + EXPECT_CALL(page_action_controller(), + OverrideTooltip(kActionShowCookieControls, BlockedLabel())) + .Times(1); + + controller().OnCookieControlsIconStatusChanged( + /*icon_visible=*/true, CookieControlsState::kBlocked3pc, GetParam(), + /*should_highlight=*/true); + + EXPECT_EQ(page_action_controller().last_text(), + In3pcd() ? SiteNotWorkingLabel() : BlockedLabel()); +} + +TEST_P(CookieControlsPageActionControllerTest, + IconAnimationTextDoesNotResetWhenStateDoesNotChange) { + EXPECT_CALL(page_action_controller(), Show(kActionShowCookieControls)) + .Times(1); + EXPECT_CALL(page_action_controller(), + ShowSuggestionChip(kActionShowCookieControls, _)) + .Times(1); + controller().OnCookieControlsIconStatusChanged( + /*icon_visible=*/true, CookieControlsState::kBlocked3pc, GetParam(), + /*should_highlight=*/true); + EXPECT_EQ(page_action_controller().last_text(), + In3pcd() ? SiteNotWorkingLabel() : BlockedLabel()); + + // Invoking again should not change anything. + EXPECT_CALL(page_action_controller(), Show(kActionShowCookieControls)) + .Times(1); + EXPECT_CALL(page_action_controller(), + ShowSuggestionChip(kActionShowCookieControls, _)) + .Times(1); + controller().OnCookieControlsIconStatusChanged( + /*icon_visible=*/true, CookieControlsState::kBlocked3pc, GetParam(), + /*should_highlight=*/true); + EXPECT_EQ(page_action_controller().last_text(), + In3pcd() ? SiteNotWorkingLabel() : BlockedLabel()); +} + +TEST_P(CookieControlsPageActionControllerTest, + IconAnimationTextUpdatesWhen3pcStateChanges) { + EXPECT_CALL(page_action_controller(), Show(kActionShowCookieControls)) + .Times(1); + EXPECT_CALL(page_action_controller(), + ShowSuggestionChip(kActionShowCookieControls, _)) + .Times(1); + controller().OnCookieControlsIconStatusChanged( + /*icon_visible=*/true, CookieControlsState::kBlocked3pc, GetParam(), + /*should_highlight=*/true); + EXPECT_EQ(page_action_controller().last_text(), + In3pcd() ? SiteNotWorkingLabel() : BlockedLabel()); + + // Invoking again with a new controls state should update the label. + EXPECT_CALL(page_action_controller(), Show(kActionShowCookieControls)) + .Times(1); + controller().OnCookieControlsIconStatusChanged( + /*icon_visible=*/true, CookieControlsState::kAllowed3pc, GetParam(), + /*should_highlight=*/true); + EXPECT_EQ(page_action_controller().last_text(), AllowedLabel()); +} + +TEST_P(CookieControlsPageActionControllerTest, + IconDoesNotAnimateWhenShouldHighlightIsFalse) { + EXPECT_CALL(page_action_controller(), Show(kActionShowCookieControls)) + .Times(1); + EXPECT_CALL(page_action_controller(), + ShowSuggestionChip(kActionShowCookieControls, _)) + .Times(0); + controller().OnCookieControlsIconStatusChanged( + /*icon_visible=*/true, CookieControlsState::kBlocked3pc, GetParam(), + /*should_highlight=*/false); +} + +TEST_P(CookieControlsPageActionControllerTest, + IconHiddenWhenIconVisibleIsFalse) { + EXPECT_CALL(page_action_controller(), Hide(kActionShowCookieControls)) + .Times(1); + EXPECT_CALL(page_action_controller(), Show(kActionShowCookieControls)) + .Times(0); + controller().OnCookieControlsIconStatusChanged( + /*icon_visible=*/false, CookieControlsState::kAllowed3pc, GetParam(), + /*should_highlight=*/false); +} + +} // namespace
diff --git a/chrome/browser/ui/views/overlay/video_overlay_window_views.cc b/chrome/browser/ui/views/overlay/video_overlay_window_views.cc index 64ac31d5..314cb1a 100644 --- a/chrome/browser/ui/views/overlay/video_overlay_window_views.cc +++ b/chrome/browser/ui/views/overlay/video_overlay_window_views.cc
@@ -37,6 +37,7 @@ #include "chrome/browser/ui/views/overlay/skip_ad_label_button.h" #include "chrome/browser/ui/views/overlay/toggle_camera_button.h" #include "chrome/browser/ui/views/overlay/toggle_microphone_button.h" +#include "chrome/browser/ui/views/picture_in_picture/picture_in_picture_tucker.h" #include "chrome/grit/generated_resources.h" #include "components/global_media_controls/public/format_duration.h" #include "components/vector_icons/vector_icons.h" @@ -57,7 +58,6 @@ #include "ui/gfx/canvas.h" #include "ui/gfx/favicon_size.h" #include "ui/gfx/geometry/resize_utils.h" -#include "ui/gfx/geometry/rounded_corners_f.h" #include "ui/gfx/geometry/skia_conversions.h" #include "ui/views/controls/image_view.h" #include "ui/views/controls/label.h" @@ -473,6 +473,8 @@ overlay_view_->RemoveObserver(this); } display::Screen::GetScreen()->RemoveObserver(this); + PictureInPictureWindowManager::GetInstance()->OnPictureInPictureWindowHidden( + this); } gfx::Size& VideoOverlayWindowViews::GetNaturalSize() { @@ -809,6 +811,18 @@ OnSizeConstraintsChanged(); } +void VideoOverlayWindowViews::SetForcedTucking(bool tuck) { + if (!tucker_) { + tucker_ = std::make_unique<PictureInPictureTucker>(*this); + } + is_tucking_forced_ = tuck; + if (tuck) { + tucker_->Tuck(); + } else { + tucker_->Untuck(); + } +} + void VideoOverlayWindowViews::OnAutoPipSettingOverlayViewHidden() { // If there is an existing overlay view, remove it now. RemoveOverlayViewIfExists(); @@ -1901,6 +1915,8 @@ void VideoOverlayWindowViews::Close() { views::Widget::Close(); MaybeUnregisterFrameSinkHierarchy(); + PictureInPictureWindowManager::GetInstance()->OnPictureInPictureWindowHidden( + this); } void VideoOverlayWindowViews::ShowInactive() { @@ -1934,6 +1950,15 @@ // If this is not the first time the window is shown, this will be a no-op. has_been_shown_ = true; + + // If we're still tucked from a previous session and it's no longer necessary, + // then untuck now. + if (is_tucking_forced_ && !PictureInPictureWindowManager::GetInstance() + ->IsPictureInPictureForceTucked()) { + SetForcedTucking(false); + } + PictureInPictureWindowManager::GetInstance()->OnPictureInPictureWindowShown( + this); } void VideoOverlayWindowViews::Hide() { @@ -1941,6 +1966,8 @@ RemoveOverlayViewIfExists(); views::Widget::Hide(); MaybeUnregisterFrameSinkHierarchy(); + PictureInPictureWindowManager::GetInstance()->OnPictureInPictureWindowHidden( + this); } bool VideoOverlayWindowViews::IsVisible() const { @@ -1965,6 +1992,9 @@ // Update the views::Widget bounds to adhere to sizing spec. This will also // update the layout of the controls. SetBounds(CalculateAndUpdateWindowBounds()); + if (is_tucking_forced_) { + tucker_->Tuck(); + } } void VideoOverlayWindowViews::SetPlaybackState(PlaybackState playback_state) {
diff --git a/chrome/browser/ui/views/overlay/video_overlay_window_views.h b/chrome/browser/ui/views/overlay/video_overlay_window_views.h index d5d5901..b1639f82 100644 --- a/chrome/browser/ui/views/overlay/video_overlay_window_views.h +++ b/chrome/browser/ui/views/overlay/video_overlay_window_views.h
@@ -11,6 +11,7 @@ #include "base/memory/weak_ptr.h" #include "base/timer/timer.h" #include "chrome/browser/picture_in_picture/auto_pip_setting_overlay_view.h" +#include "chrome/browser/picture_in_picture/picture_in_picture_window.h" #include "components/global_media_controls/public/views/media_progress_view.h" #include "content/public/browser/overlay_window.h" #include "content/public/browser/video_picture_in_picture_window_controller.h" @@ -39,6 +40,7 @@ class OverlayWindowBackToTabButton; class OverlayWindowLiveCaptionDialog; class OverlayWindowMinimizeButton; +class PictureInPictureTucker; class PlaybackImageButton; class ResizeHandleButton; class SimpleOverlayWindowImageButton; @@ -52,6 +54,7 @@ public views::Widget, public display::DisplayObserver, public views::ViewObserver, + public PictureInPictureWindow, public AutoPipSettingOverlayView::Delegate { public: using GetOverlayViewCb = @@ -120,6 +123,9 @@ void OnViewVisibilityChanged(views::View* observed_view, views::View* starting_view) override; + // PictureInPictureWindow: + void SetForcedTucking(bool tuck) override; + // AutoPipSettingOverlayView::Delegate: void OnAutoPipSettingOverlayViewHidden() override; @@ -459,6 +465,10 @@ // |video_view_| is registered as the child of the overlay window frame sink. bool has_registered_frame_sink_hierarchy_ = false; + // Used to tuck/untuck this widget into the side of the screen. + std::unique_ptr<PictureInPictureTucker> tucker_; + bool is_tucking_forced_ = false; + // Callback to get / create an overlay view. This is a callback to let tests // provide alternate implementations. GetOverlayViewCb get_overlay_view_cb_;
diff --git a/chrome/browser/ui/views/overlay/video_overlay_window_views_unittest.cc b/chrome/browser/ui/views/overlay/video_overlay_window_views_unittest.cc index 8b015e8..50e5fc34 100644 --- a/chrome/browser/ui/views/overlay/video_overlay_window_views_unittest.cc +++ b/chrome/browser/ui/views/overlay/video_overlay_window_views_unittest.cc
@@ -15,6 +15,7 @@ #include "chrome/browser/picture_in_picture/auto_pip_setting_overlay_view.h" #include "chrome/browser/picture_in_picture/picture_in_picture_occlusion_tracker.h" #include "chrome/browser/picture_in_picture/picture_in_picture_window_manager.h" +#include "chrome/browser/picture_in_picture/scoped_tuck_picture_in_picture.h" #include "chrome/browser/ui/views/chrome_layout_provider.h" #include "chrome/browser/ui/views/overlay/back_to_tab_button.h" #include "chrome/browser/ui/views/overlay/close_image_button.h" @@ -795,6 +796,45 @@ ASSERT_EQ(nullptr, live_status); } +TEST_F(VideoOverlayWindowViewsTest, CanBeTuckedToTheSideOfTheScreen) { + // Place the window on the left side of the screen. + SetDisplayWorkArea({0, 0, 2000, 2000}); + overlay_window().SetBounds({{400, 400}, {500, 500}}); + + // If we tell it to force tucking, it should tuck to the left side of the + // screen. + overlay_window().SetForcedTucking(true); + EXPECT_LT(overlay_window().GetWindowBoundsInScreen().x(), 0); + + // If we tell it to stop tucking, it should be put back in its original + // position. + overlay_window().SetForcedTucking(false); + EXPECT_EQ(overlay_window().GetWindowBoundsInScreen().x(), 400); +} + +TEST_F(VideoOverlayWindowViewsTest, UntucksWhenReshownIfNecessary) { + // Place the window on the left side of the screen. + SetDisplayWorkArea({0, 0, 2000, 2000}); + overlay_window().SetBounds({{400, 400}, {500, 500}}); + overlay_window().ShowInactive(); + + // Start tucking via a ScopedTuckPictureInPicture. + auto scoped_tuck = std::make_unique<ScopedTuckPictureInPicture>(); + EXPECT_LT(overlay_window().GetWindowBoundsInScreen().x(), 0); + + // Hide ourselves. This will mean if tucking ends then the + // PictureInPictureWindowManager won't actually notify us. + overlay_window().Hide(); + + // End tucking. + scoped_tuck.reset(); + + // Show ourselves. We should check with the PictureInPictureWindowManager and + // realize we should no longer tuck. + overlay_window().ShowInactive(); + EXPECT_EQ(overlay_window().GetWindowBoundsInScreen().x(), 400); +} + TEST_F(VideoOverlayWindowViewsTest, ReplayAndForward10SecondsNotDrawnWhen2024UIIsDisabled) { overlay_window().ForceControlsVisibleForTesting(true);
diff --git a/chrome/browser/ui/views/passwords/manage_passwords_icon_view_interactive_uitest.cc b/chrome/browser/ui/views/passwords/manage_passwords_icon_view_interactive_uitest.cc index 7786723..c8913c6 100644 --- a/chrome/browser/ui/views/passwords/manage_passwords_icon_view_interactive_uitest.cc +++ b/chrome/browser/ui/views/passwords/manage_passwords_icon_view_interactive_uitest.cc
@@ -4,11 +4,15 @@ #include "chrome/browser/ui/actions/chrome_action_id.h" #include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/browser_actions.h" +#include "chrome/browser/ui/browser_element_identifiers.h" #include "chrome/browser/ui/passwords/manage_passwords_test.h" #include "chrome/browser/ui/passwords/manage_passwords_ui_controller_mock.h" #include "chrome/browser/ui/toolbar/pinned_toolbar/pinned_toolbar_actions_model.h" +#include "chrome/browser/ui/ui_features.h" #include "chrome/browser/ui/views/frame/browser_view.h" #include "chrome/browser/ui/views/page_action/page_action_icon_view.h" +#include "chrome/browser/ui/views/page_action/page_action_view.h" #include "chrome/browser/ui/views/passwords/manage_passwords_icon_views.h" #include "chrome/browser/ui/views/passwords/password_bubble_view_base.h" #include "chrome/browser/ui/views/toolbar/pinned_toolbar_actions_container.h" @@ -22,14 +26,21 @@ #include "testing/gtest/include/gtest/gtest.h" #include "ui/base/l10n/l10n_util.h" #include "ui/events/event_utils.h" +#include "ui/views/bubble/bubble_dialog_delegate_view.h" #include "ui/views/interaction/interaction_test_util_views.h" #include "ui/views/layout/animating_layout_manager_test_util.h" #include "ui/views/test/widget_test.h" #include "ui/views/view_utils.h" -class ManagePasswordsIconViewTest : public ManagePasswordsTest { +class ManagePasswordsIconViewTest : public ManagePasswordsTest, + public ::testing::WithParamInterface<bool> { public: - ManagePasswordsIconViewTest() = default; + ManagePasswordsIconViewTest() { + scoped_feature_list_.InitAndEnableFeatureWithParameters( + features::kPageActionsMigration, + {{features::kPageActionsMigrationManagePasswords.name, + IsMigrationEnabled() ? "true" : "false"}}); + } ManagePasswordsIconViewTest(const ManagePasswordsIconViewTest&) = delete; ManagePasswordsIconViewTest& operator=(const ManagePasswordsIconViewTest&) = @@ -37,20 +48,38 @@ ~ManagePasswordsIconViewTest() override = default; - password_manager::ui::State ViewState() { return GetView()->state_; } - - ManagePasswordsIconViews* GetView() { - views::View* const view = - BrowserView::GetBrowserViewForBrowser(browser()) - ->toolbar_button_provider() - ->GetPageActionIconView(PageActionIconType::kManagePasswords); - DCHECK(views::IsViewClass<ManagePasswordsIconViews>(view)); - return static_cast<ManagePasswordsIconViews*>(view); + password_manager::ui::State ViewState() { + return GetController()->GetState(); } - std::u16string GetTooltipText() { - return GetView()->GetRenderedTooltipText(gfx::Point()); + IconLabelBubbleView* GetIcon() { + IconLabelBubbleView* view = nullptr; + if (IsMigrationEnabled()) { + view = static_cast<IconLabelBubbleView*>( + BrowserView::GetBrowserViewForBrowser(browser()) + ->toolbar_button_provider() + ->GetPageActionView(kActionShowPasswordsBubbleOrPage)); + DCHECK(views::IsViewClass<page_actions::PageActionView>(view)); + } else { + view = static_cast<IconLabelBubbleView*>( + BrowserView::GetBrowserViewForBrowser(browser()) + ->toolbar_button_provider() + ->GetPageActionIconView(PageActionIconType::kManagePasswords)); + DCHECK(views::IsViewClass<ManagePasswordsIconViews>(view)); + } + return view; } + + std::u16string GetTooltipText() { return GetIcon()->GetTooltipText(); } + + bool IsMigrationEnabled() const { return GetParam(); } + + static std::string GetTestSuffix(const testing::TestParamInfo<bool>& info) { + return info.param ? "MigrationOn" : "MigrationOff"; + } + + private: + base::test::ScopedFeatureList scoped_feature_list_; }; class ManagePasswordsIconViewTestToolbarPinningOnly @@ -67,45 +96,44 @@ } }; -IN_PROC_BROWSER_TEST_F(ManagePasswordsIconViewTest, DefaultStateIsInactive) { +IN_PROC_BROWSER_TEST_P(ManagePasswordsIconViewTest, DefaultStateIsInactive) { EXPECT_EQ(password_manager::ui::INACTIVE_STATE, ViewState()); - EXPECT_FALSE(GetView()->GetVisible()); + EXPECT_FALSE(GetIcon()->GetVisible()); } -IN_PROC_BROWSER_TEST_F(ManagePasswordsIconViewTest, PendingState) { +IN_PROC_BROWSER_TEST_P(ManagePasswordsIconViewTest, PendingState) { SetupPendingPassword(); EXPECT_EQ(password_manager::ui::PENDING_PASSWORD_STATE, ViewState()); - EXPECT_TRUE(GetView()->GetVisible()); + EXPECT_TRUE(GetIcon()->GetVisible()); // No tooltip because the bubble is showing. EXPECT_EQ(std::u16string(), GetTooltipText()); } -IN_PROC_BROWSER_TEST_F(ManagePasswordsIconViewTest, ManageState) { +IN_PROC_BROWSER_TEST_P(ManagePasswordsIconViewTest, ManageState) { SetupManagingPasswords(); EXPECT_EQ(password_manager::ui::MANAGE_STATE, ViewState()); - EXPECT_TRUE(GetView()->GetVisible()); + EXPECT_TRUE(GetIcon()->GetVisible()); EXPECT_EQ(l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_TOOLTIP_MANAGE), GetTooltipText()); } -IN_PROC_BROWSER_TEST_F(ManagePasswordsIconViewTest, CloseOnClick) { +IN_PROC_BROWSER_TEST_P(ManagePasswordsIconViewTest, CloseOnClick) { SetupPendingPassword(); - EXPECT_TRUE(GetView()->GetVisible()); - ui::MouseEvent mouse_down(ui::EventType::kMousePressed, gfx::Point(10, 10), - gfx::Point(900, 60), ui::EventTimeForNow(), - ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON); - GetView()->OnMousePressed(mouse_down); + EXPECT_TRUE(GetIcon()->GetVisible()); + views::test::InteractionTestUtilSimulatorViews::PressButton( + static_cast<views::Button*>(GetIcon()), + ui::test::InteractionTestUtil::InputType::kDontCare); // Wait for the command execution to close the bubble. content::RunAllPendingInMessageLoop(); } -IN_PROC_BROWSER_TEST_F(ManagePasswordsIconViewTest, PasswordChangeState) { +IN_PROC_BROWSER_TEST_P(ManagePasswordsIconViewTest, PasswordChangeState) { SetupPasswordChange(); EXPECT_EQ(password_manager::ui::PASSWORD_CHANGE_STATE, ViewState()); - EXPECT_FALSE(GetView()->GetVisible()); + EXPECT_FALSE(GetIcon()->GetVisible()); } -IN_PROC_BROWSER_TEST_F(ManagePasswordsIconViewTestToolbarPinningOnly, +IN_PROC_BROWSER_TEST_P(ManagePasswordsIconViewTestToolbarPinningOnly, ShowPasswordsBubbleOrPage) { const GURL passwords_url = GURL("chrome://password-manager/"); PinnedToolbarActionsModel::Get(browser()->profile()) @@ -134,3 +162,13 @@ button, ui::test::InteractionTestUtil::InputType::kDontCare); EXPECT_EQ(GetActiveWebContents()->GetVisibleURL(), passwords_url); } + +INSTANTIATE_TEST_SUITE_P(All, + ManagePasswordsIconViewTest, + ::testing::Bool(), + &ManagePasswordsIconViewTest::GetTestSuffix); + +INSTANTIATE_TEST_SUITE_P(All, + ManagePasswordsIconViewTestToolbarPinningOnly, + ::testing::Bool(), + &ManagePasswordsIconViewTest::GetTestSuffix);
diff --git a/chrome/browser/ui/views/passwords/manage_passwords_page_action_controller.cc b/chrome/browser/ui/views/passwords/manage_passwords_page_action_controller.cc index 620ea16..cc69a05 100644 --- a/chrome/browser/ui/views/passwords/manage_passwords_page_action_controller.cc +++ b/chrome/browser/ui/views/passwords/manage_passwords_page_action_controller.cc
@@ -8,7 +8,6 @@ #include "chrome/browser/ui/actions/chrome_action_id.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_actions.h" -#include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/passwords/manage_passwords_ui_controller.h" #include "chrome/browser/ui/tabs/public/tab_features.h" #include "chrome/browser/ui/ui_features.h" @@ -103,9 +102,10 @@ void ManagePasswordsPageActionController::UpdateVisibility( password_manager::ui::State state, bool is_blocklisted, - ManagePasswordsUIController* passwords_ui_controller) { - CHECK(passwords_ui_controller); - + ManagePasswordsUIController& passwords_ui_controller, + actions::ActionItem& passwords_action_item) { + // Determines if the password management feature is generally active for this + // page. bool should_be_visible = !(state == password_manager::ui::INACTIVE_STATE || state == password_manager::ui::PASSWORD_CHANGE_STATE); @@ -119,8 +119,7 @@ PasswordBubbleViewBase::manage_password_bubble() ->GetWidget() ->IsVisible()) || - (passwords_ui_controller && - passwords_ui_controller->IsAutomaticallyOpeningBubble()); + passwords_ui_controller.IsAutomaticallyOpeningBubble(); std::u16string tooltip = bubble_is_or_will_be_showing ? std::u16string() @@ -134,4 +133,7 @@ } else { page_action_controller_->Hide(kActionShowPasswordsBubbleOrPage); } + // Updates the underline indicator for the pinned toolbar button. + passwords_action_item.SetProperty(kActionItemUnderlineIndicatorKey, + should_be_visible); }
diff --git a/chrome/browser/ui/views/passwords/manage_passwords_page_action_controller.h b/chrome/browser/ui/views/passwords/manage_passwords_page_action_controller.h index 25db8ae..6095e92 100644 --- a/chrome/browser/ui/views/passwords/manage_passwords_page_action_controller.h +++ b/chrome/browser/ui/views/passwords/manage_passwords_page_action_controller.h
@@ -17,6 +17,10 @@ class ManagePasswordsUIController; +namespace actions { +class ActionItem; +} // namespace actions + // Controller for the manage passwords page action icon. This class observes // the state of ManagePasswordsUIController and updates the page action icon // visibility, icon, and tooltip accordingly. @@ -38,7 +42,8 @@ // saving. void UpdateVisibility(password_manager::ui::State state, bool is_blocklisted, - ManagePasswordsUIController* passwords_ui_controller); + ManagePasswordsUIController& passwords_ui_controller, + actions::ActionItem& passwords_action_item); // Returns the appropriate tooltip text for the manage passwords icon based // on the current state.
diff --git a/chrome/browser/ui/views/picture_in_picture/OWNERS b/chrome/browser/ui/views/picture_in_picture/OWNERS new file mode 100644 index 0000000..152582da --- /dev/null +++ b/chrome/browser/ui/views/picture_in_picture/OWNERS
@@ -0,0 +1,2 @@ +file://third_party/blink/renderer/modules/document_picture_in_picture/OWNERS +file://third_party/blink/renderer/modules/picture_in_picture/OWNERS \ No newline at end of file
diff --git a/chrome/browser/ui/views/picture_in_picture/README.md b/chrome/browser/ui/views/picture_in_picture/README.md new file mode 100644 index 0000000..4445e9c --- /dev/null +++ b/chrome/browser/ui/views/picture_in_picture/README.md
@@ -0,0 +1,5 @@ +# Picture-in-Picture Views + +This directory contains Views code that is used for both +[video picture-in-picture](/chrome/browser/ui/views/overlay/video_overlay/window_views) and +[document picture-in-picture](/chrome/browser/ui/views/frame/picture_in_picture_browser_frame_view.h) \ No newline at end of file
diff --git a/chrome/browser/ui/views/picture_in_picture/picture_in_picture_tucker.cc b/chrome/browser/ui/views/picture_in_picture/picture_in_picture_tucker.cc new file mode 100644 index 0000000..d87b0d4 --- /dev/null +++ b/chrome/browser/ui/views/picture_in_picture/picture_in_picture_tucker.cc
@@ -0,0 +1,87 @@ +// Copyright 2025 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/picture_in_picture/picture_in_picture_tucker.h" + +#include "ui/display/display.h" +#include "ui/display/screen.h" +#include "ui/views/widget/widget.h" + +namespace { + +constexpr int kTuckEdgeLength = 50; + +bool VerticallyIntersects(const gfx::Rect& r1, const gfx::Rect& r2) { + return std::max(r1.y(), r2.y()) < std::min(r1.bottom(), r2.bottom()); +} + +} // namespace + +PictureInPictureTucker::PictureInPictureTucker(views::Widget& pip_widget) + : pip_widget_(pip_widget) {} + +PictureInPictureTucker::~PictureInPictureTucker() = default; + +void PictureInPictureTucker::Tuck() { + gfx::Rect current_bounds = pip_widget_->GetWindowBoundsInScreen(); + + if (!tucking_) { + pretuck_location_ = current_bounds.origin(); + } + + tucking_ = true; + + // Get a list of all displays that we could move into if we only move + // horizontally. + std::vector<display::Display> possible_displays; + for (const auto& display : display::Screen::GetScreen()->GetAllDisplays()) { + if (VerticallyIntersects(display.work_area(), current_bounds)) { + possible_displays.push_back(display); + } + } + + // If somehow that list is empty (in most cases this shouldn't happen since + // the display we're on should count, but in certain test scenarios this could + // be the case), then just add the display we're currently on. + if (possible_displays.empty()) { + possible_displays.push_back( + display::Screen::GetScreen()->GetDisplayNearestWindow( + pip_widget_->GetNativeWindow())); + } + + gfx::Rect combined_work_area; + for (const auto& display : possible_displays) { + combined_work_area.Union(display.work_area()); + } + + gfx::Rect destination_bounds = current_bounds; + + // Tuck the picture-in-picture window to the closest left or right edge of the + // combined screen area of displays. + if (current_bounds.CenterPoint().x() < combined_work_area.CenterPoint().x()) { + destination_bounds.set_x(combined_work_area.x() + kTuckEdgeLength - + current_bounds.width()); + } else { + destination_bounds.set_x(combined_work_area.x() + + combined_work_area.width() - kTuckEdgeLength); + } + + pip_widget_->SetBounds(destination_bounds); + if (pip_widget_->IsActive()) { + pip_widget_->Deactivate(); + } +} + +void PictureInPictureTucker::Untuck() { + // It's possible to be told to untuck before tucking has actually occurred if + // tucking begins and ends before a `PictureInPictureBrowserFrameView` becomes + // visible. In that case, there's nothing to do. + if (!tucking_) { + return; + } + tucking_ = false; + gfx::Rect destination_bounds = pip_widget_->GetWindowBoundsInScreen(); + destination_bounds.set_origin(pretuck_location_); + pip_widget_->SetBounds(destination_bounds); +}
diff --git a/chrome/browser/ui/views/picture_in_picture/picture_in_picture_tucker.h b/chrome/browser/ui/views/picture_in_picture/picture_in_picture_tucker.h new file mode 100644 index 0000000..bd870c0a --- /dev/null +++ b/chrome/browser/ui/views/picture_in_picture/picture_in_picture_tucker.h
@@ -0,0 +1,42 @@ +// Copyright 2025 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_PICTURE_IN_PICTURE_PICTURE_IN_PICTURE_TUCKER_H_ +#define CHROME_BROWSER_UI_VIEWS_PICTURE_IN_PICTURE_PICTURE_IN_PICTURE_TUCKER_H_ + +#include "base/memory/raw_ref.h" +#include "ui/gfx/geometry/point.h" + +namespace views { +class Widget; +} // namespace views + +// The PictureInPictureTucker temporarily moves a picture-in-picture widget +// mostly offscreen ("tuck"ed away) so the user can get more screen real estate +// for another task. +class PictureInPictureTucker { + public: + // `pip_widget` is the picture-in-picture Widget to be tucked/untucked. + // `pip_widget` must outlive `this`. + explicit PictureInPictureTucker(views::Widget& pip_widget); + PictureInPictureTucker(const PictureInPictureTucker&) = delete; + PictureInPictureTucker& operator=(const PictureInPictureTucker&) = delete; + ~PictureInPictureTucker(); + + // Moves `pip_widget_` mostly offscreen. If `pip_widget_` is already tucked, + // then it is tucked again but the place it untucks to is not updated. This + // allows the caller to retuck for a size adjustment without losing the + // original location. + void Tuck(); + + // Moves `pip_widget_` back to where it was when `Tuck()` was called. + void Untuck(); + + private: + raw_ref<views::Widget> pip_widget_; + bool tucking_ = false; + gfx::Point pretuck_location_; +}; + +#endif // CHROME_BROWSER_UI_VIEWS_PICTURE_IN_PICTURE_PICTURE_IN_PICTURE_TUCKER_H_
diff --git a/chrome/browser/ui/views/picture_in_picture/picture_in_picture_tucker_unittest.cc b/chrome/browser/ui/views/picture_in_picture/picture_in_picture_tucker_unittest.cc new file mode 100644 index 0000000..372d502a --- /dev/null +++ b/chrome/browser/ui/views/picture_in_picture/picture_in_picture_tucker_unittest.cc
@@ -0,0 +1,144 @@ +// Copyright 2025 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/picture_in_picture/picture_in_picture_tucker.h" + +#include "ui/display/display.h" +#include "ui/display/screen.h" +#include "ui/display/test/test_screen.h" +#include "ui/views/test/views_test_base.h" +#include "ui/views/widget/widget.h" + +class PictureInPictureTuckerTest : public views::ViewsTestBase { + public: + void SetUp() override { + display::Screen::SetScreenInstance(&test_screen_); + views::ViewsTestBase::SetUp(); + + widget_ = CreateTestWidget(views::Widget::InitParams::CLIENT_OWNS_WIDGET); + tucker_ = std::make_unique<PictureInPictureTucker>(*widget_.get()); + } + + void TearDown() override { + tucker_.reset(); + widget_.reset(); + views::ViewsTestBase::TearDown(); + display::Screen::SetScreenInstance(nullptr); + } + + protected: + display::test::TestScreen& test_screen() { return test_screen_; } + views::Widget* widget() { return widget_.get(); } + PictureInPictureTucker* tucker() { return tucker_.get(); } + + private: + display::test::TestScreen test_screen_; + std::unique_ptr<views::Widget> widget_; + std::unique_ptr<PictureInPictureTucker> tucker_; +}; + +TEST_F(PictureInPictureTuckerTest, TucksTowardCloserEdge) { + const gfx::Rect work_area = + display::Screen::GetScreen() + ->GetDisplayNearestWindow(widget()->GetNativeWindow()) + .work_area(); + + // Place the widget on the left side of the screen. + const gfx::Rect initial_leftside_bounds({work_area.x() + 20, 50}, {200, 200}); + widget()->SetBounds(initial_leftside_bounds); + EXPECT_EQ(initial_leftside_bounds, widget()->GetWindowBoundsInScreen()); + + // Tuck the widget. This should tuck towards the left side. + tucker()->Tuck(); + EXPECT_LT(widget()->GetWindowBoundsInScreen().x(), + initial_leftside_bounds.x()); + + // Untucking should place the widget back where it started. + tucker()->Untuck(); + EXPECT_EQ(initial_leftside_bounds, widget()->GetWindowBoundsInScreen()); + + // Place the widget on the right side of the screen. + const gfx::Rect initial_rightside_bounds({work_area.right() - 220, 50}, + {200, 200}); + widget()->SetBounds(initial_rightside_bounds); + EXPECT_EQ(initial_rightside_bounds, widget()->GetWindowBoundsInScreen()); + + // Tuck the widget. This should tuck towards the right side. + tucker()->Tuck(); + EXPECT_GT(widget()->GetWindowBoundsInScreen().x(), + initial_rightside_bounds.x()); + + // Untucking should place the widget back where it started. + tucker()->Untuck(); + EXPECT_EQ(initial_rightside_bounds, widget()->GetWindowBoundsInScreen()); +} + +TEST_F(PictureInPictureTuckerTest, + RetuckingForResizeRemembersOriginalPosition) { + const gfx::Rect initial_bounds({20, 50}, {200, 200}); + widget()->SetBounds(initial_bounds); + EXPECT_EQ(initial_bounds, widget()->GetWindowBoundsInScreen()); + + // Tuck the widget. + tucker()->Tuck(); + ASSERT_NE(initial_bounds, widget()->GetWindowBoundsInScreen()); + + // Resize the widget and retuck it. + gfx::Size new_size = {300, 300}; + widget()->SetSize(new_size); + tucker()->Tuck(); + + // Untucking should place the widget back where it started. + tucker()->Untuck(); + const gfx::Rect expected_bounds(initial_bounds.origin(), new_size); + EXPECT_EQ(expected_bounds, widget()->GetWindowBoundsInScreen()); +} + +TEST_F(PictureInPictureTuckerTest, TucksTowardCloserEdge_Multiscreen) { + // Set up two screens side-by-side. + const gfx::Rect display1_bounds({0, 0}, {1000, 1000}); + const gfx::Rect display2_bounds({1000, 0}, {500, 500}); + display::Display display1 = test_screen().GetPrimaryDisplay(); + display1.set_work_area(display1_bounds); + test_screen().display_list().UpdateDisplay(display1); + display::Display display2(display1.id() + 1, display2_bounds); + test_screen().display_list().AddOrUpdateDisplay( + display2, display::DisplayList::Type::NOT_PRIMARY); + + // Place the widget on the left side of the left screen. This should tuck to + // left side of the left screen. + widget()->SetBounds({{20, 50}, {200, 200}}); + tucker()->Tuck(); + EXPECT_LT(widget()->GetWindowBoundsInScreen().x(), display1_bounds.x()); + tucker()->Untuck(); + + // Place the widget on the right half of the left screen, but still closer to + // the left edge of the left screen than the right edge of the right screen. + // This should tuck to the left side of the left screen. + widget()->SetBounds({{600, 50}, {200, 200}}); + tucker()->Tuck(); + EXPECT_LT(widget()->GetWindowBoundsInScreen().x(), display1_bounds.x()); + tucker()->Untuck(); + + // Place the widget on the right half of the left screen, and closer to the + // right side of the right screen than the left side of the left screen. This + // should tuck to the right side of the right screen. + widget()->SetBounds({{800, 50}, {200, 200}}); + tucker()->Tuck(); + EXPECT_GT(widget()->GetWindowBoundsInScreen().right(), + display2_bounds.right()); + tucker()->Untuck(); + + // Place the widget on the right half of the left screen, and closer to the + // right side of the right screen than the left side of the left screen, BUT + // close enough to the bottom of the left screen (which is taller) that moving + // to the right side of the right screen would be below the right screen. This + // should tuck to the right side of the left screen. + widget()->SetBounds({{800, 550}, {200, 200}}); + tucker()->Tuck(); + EXPECT_GT(widget()->GetWindowBoundsInScreen().right(), + display1_bounds.right()); + EXPECT_LT(widget()->GetWindowBoundsInScreen().x(), display1_bounds.right()); + tucker()->Untuck(); +}
diff --git a/chrome/browser/ui/views/tabs/glic_button.cc b/chrome/browser/ui/views/tabs/glic_button.cc index 1225954..eaf55c9 100644 --- a/chrome/browser/ui/views/tabs/glic_button.cc +++ b/chrome/browser/ui/views/tabs/glic_button.cc
@@ -74,6 +74,7 @@ UpdateColors(); SetVisible(true); + SetText(base::UTF8ToUTF16(std::string())); SetFocusBehavior(FocusBehavior::ALWAYS); @@ -92,6 +93,7 @@ AnnounceNudgeShown(); } else { SetCloseButtonFocusBehavior(FocusBehavior::NEVER); + SetText(base::UTF8ToUTF16(std::string())); } is_showing_nudge_ = is_showing; PreferredSizeChanged();
diff --git a/chrome/browser/ui/views/toolbar/pinned_action_toolbar_button.cc b/chrome/browser/ui/views/toolbar/pinned_action_toolbar_button.cc index 4c5fc9f..0020d9b 100644 --- a/chrome/browser/ui/views/toolbar/pinned_action_toolbar_button.cc +++ b/chrome/browser/ui/views/toolbar/pinned_action_toolbar_button.cc
@@ -41,6 +41,15 @@ #include "ui/views/view_class_properties.h" #include "ui/views/view_utils.h" +namespace { +// Width of the status indicator shown across the button. +constexpr int kStatusIndicatorWidth = 14; +// Height of the status indicator shown across the button. +constexpr int kStatusIndicatorHeight = 2; +// Spacing between the button's icon and the status indicator. +constexpr int kStatusIndicatorSpacing = 1; +} // namespace + DEFINE_UI_CLASS_PROPERTY_TYPE(PinnedToolbarActionFlexPriority) DEFINE_UI_CLASS_PROPERTY_KEY( std::underlying_type_t<PinnedToolbarActionFlexPriority>, @@ -91,6 +100,8 @@ status_indicator_ = PinnedToolbarButtonStatusIndicator::Install(image_container_view()); + status_indicator_->SetColorId(kColorToolbarActionItemEngaged, + kColorToolbarButtonIconInactive); // TODO(shibalik): Revisit since all pinned actions should not be toggle // buttons. @@ -183,14 +194,12 @@ void PinnedActionToolbarButton::Layout(PassKey) { LayoutSuperclass<ToolbarButton>(this); - gfx::Rect status_rect(14, 2); - status_indicator_->SetColorId(kColorToolbarActionItemEngaged, - kColorToolbarButtonIconInactive); - - gfx::Rect image_container_bounds = image_container_view()->GetLocalBounds(); - int new_x = image_container_bounds.x() + - (image_container_bounds.width() - status_rect.width()) / 2; - int new_y = image_container_bounds.bottom() + 1; + gfx::Rect status_rect(kStatusIndicatorWidth, kStatusIndicatorHeight); + const gfx::Rect image_container_bounds = + image_container_view()->GetLocalBounds(); + const int new_x = image_container_bounds.x() + + (image_container_bounds.width() - status_rect.width()) / 2; + const int new_y = image_container_bounds.bottom() + kStatusIndicatorSpacing; // Set the new origin for status_rect status_rect.set_origin(gfx::Point(new_x, new_y)); status_indicator_->SetBoundsRect(status_rect);
diff --git a/chrome/browser/ui/views/toolbar/split_tabs_button.cc b/chrome/browser/ui/views/toolbar/split_tabs_button.cc index 2863144..5ee5260 100644 --- a/chrome/browser/ui/views/toolbar/split_tabs_button.cc +++ b/chrome/browser/ui/views/toolbar/split_tabs_button.cc
@@ -8,7 +8,6 @@ #include "base/check_op.h" #include "base/containers/fixed_flat_map.h" -#include "base/scoped_observation.h" #include "chrome/app/vector_icons/vector_icons.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/actions/chrome_action_id.h" @@ -80,10 +79,6 @@ PinnedToolbarButtonStatusIndicator::Install(image_container); status_indicator_->SetColorId(kColorToolbarActionItemEngaged, kColorToolbarButtonIconInactive); - // Need to observe the image container view so that the status indicator can - // update its bounds when the image container bounds change. - image_container_observation_.Observe(image_container); - UpdateButtonVisibility(); split_tab_menu_ = std::make_unique<SplitTabMenuModel>(browser->tab_strip_model()); @@ -111,19 +106,17 @@ } } -void SplitTabsToolbarButton::OnViewBoundsChanged(View* observed_view) { - ToolbarButton::OnViewBoundsChanged(observed_view); - if (observed_view == image_container_view()) { - gfx::Rect status_rect(kStatusIndicatorWidth, kStatusIndicatorHeight); - const gfx::Rect image_container_bounds = - image_container_view()->GetLocalBounds(); - const int new_x = - image_container_bounds.x() + - (image_container_bounds.width() - kStatusIndicatorWidth) / 2; - const int new_y = image_container_bounds.bottom() + kStatusIndicatorSpacing; - status_rect.set_origin(gfx::Point(new_x, new_y)); - status_indicator_->SetBoundsRect(status_rect); - } +void SplitTabsToolbarButton::Layout(PassKey) { + LayoutSuperclass<ToolbarButton>(this); + gfx::Rect status_rect(kStatusIndicatorWidth, kStatusIndicatorHeight); + const gfx::Rect image_container_bounds = + image_container_view()->GetLocalBounds(); + const int new_x = + image_container_bounds.x() + + (image_container_bounds.width() - kStatusIndicatorWidth) / 2; + const int new_y = image_container_bounds.bottom() + kStatusIndicatorSpacing; + status_rect.set_origin(gfx::Point(new_x, new_y)); + status_indicator_->SetBoundsRect(status_rect); } void SplitTabsToolbarButton::UpdateIcon() {
diff --git a/chrome/browser/ui/views/toolbar/split_tabs_button.h b/chrome/browser/ui/views/toolbar/split_tabs_button.h index c033a7b..bedc7e38 100644 --- a/chrome/browser/ui/views/toolbar/split_tabs_button.h +++ b/chrome/browser/ui/views/toolbar/split_tabs_button.h
@@ -9,7 +9,6 @@ #include <optional> #include "base/memory/raw_ptr.h" -#include "base/scoped_observation.h" #include "chrome/browser/ui/tabs/tab_strip_model_observer.h" #include "chrome/browser/ui/views/toolbar/toolbar_button.h" #include "components/prefs/pref_member.h" @@ -24,8 +23,6 @@ namespace views { class MenuRunner; -class View; -class ViewObserver; } // namespace views // Pinnable toolbar button that allow users to create a split tab if the current @@ -49,10 +46,8 @@ const TabStripSelectionChange& selection) override; void OnSplitTabChanged(const SplitTabChange& change) override; - // views::ViewObserver override: - void OnViewBoundsChanged(View* observed_view) override; - // ToolbarButton override: + void Layout(PassKey) override; void UpdateIcon() override; const std::optional<ToolbarButton::VectorIcons>& GetIconsForTesting(); @@ -66,8 +61,6 @@ void UpdateAccessibilityRole(bool has_menu); BooleanPrefMember pin_state_; - base::ScopedObservation<views::View, views::ViewObserver> - image_container_observation_{this}; raw_ptr<Browser> browser_; raw_ptr<PinnedToolbarButtonStatusIndicator> status_indicator_; std::unique_ptr<ui::SimpleMenuModel> split_tab_menu_;
diff --git a/chrome/browser/ui/webui/ash/settings/pages/printing/cups_printers_handler_unittest.cc b/chrome/browser/ui/webui/ash/settings/pages/printing/cups_printers_handler_unittest.cc index 54e42f8..a67a9d5 100644 --- a/chrome/browser/ui/webui/ash/settings/pages/printing/cups_printers_handler_unittest.cc +++ b/chrome/browser/ui/webui/ash/settings/pages/printing/cups_printers_handler_unittest.cc
@@ -216,7 +216,7 @@ printers_handler_->SetWebUIForTest(&web_ui_); printers_handler_->RegisterMessages(); printers_handler_->AllowJavascriptForTesting(); - printing::PrintBackend::SetPrintBackendForTesting(print_backend_.get()); + ::printing::PrintBackend::SetPrintBackendForTesting(print_backend_.get()); PrintscanmgrClient::InitializeFake(); DownloadCoreServiceFactory::GetForBrowserContext(profile_.get()) @@ -232,7 +232,7 @@ void TearDown() override { PrintscanmgrClient::Shutdown(); - printing::PrintBackend::SetPrintBackendForTesting(nullptr); + ::printing::PrintBackend::SetPrintBackendForTesting(nullptr); } void CallRetrieveCupsPpd(const std::string& printer_id, @@ -274,8 +274,8 @@ FakeCupsPrintersManager printers_manager_; std::unique_ptr<CupsPrintersHandler> printers_handler_; base::RunLoop run_loop_; - scoped_refptr<printing::TestPrintBackend> print_backend_ = - base::MakeRefCounted<printing::TestPrintBackend>(); + scoped_refptr<::printing::TestPrintBackend> print_backend_ = + base::MakeRefCounted<::printing::TestPrintBackend>(); base::ScopedTempDir download_dir_; base::HistogramTester histogram_tester_; @@ -338,7 +338,7 @@ print_backend_->AddValidPrinter( printer.id(), - std::make_unique<printing::PrinterSemanticCapsAndDefaults>(), nullptr); + std::make_unique<::printing::PrinterSemanticCapsAndDefaults>(), nullptr); EXPECT_CALL(new_window_delegate(), OpenUrl(testing::Property(&GURL::ExtractFileName, @@ -366,7 +366,7 @@ print_backend_->AddValidPrinter( printer.id(), - std::make_unique<printing::PrinterSemanticCapsAndDefaults>(), nullptr); + std::make_unique<::printing::PrinterSemanticCapsAndDefaults>(), nullptr); EXPECT_CALL(new_window_delegate(), OpenUrl(testing::Property(&GURL::ExtractFileName, @@ -397,7 +397,7 @@ print_backend_->AddValidPrinter( printer.id(), - std::make_unique<printing::PrinterSemanticCapsAndDefaults>(), nullptr); + std::make_unique<::printing::PrinterSemanticCapsAndDefaults>(), nullptr); EXPECT_CALL(new_window_delegate(), OpenUrl(testing::Property(&GURL::ExtractFileName, @@ -426,7 +426,7 @@ print_backend_->AddValidPrinter( printer.id(), - std::make_unique<printing::PrinterSemanticCapsAndDefaults>(), nullptr); + std::make_unique<::printing::PrinterSemanticCapsAndDefaults>(), nullptr); EXPECT_CALL(new_window_delegate(), OpenUrl(testing::Property(&GURL::ExtractFileName, @@ -473,7 +473,7 @@ print_backend_->AddValidPrinter( printer.id(), - std::make_unique<printing::PrinterSemanticCapsAndDefaults>(), nullptr); + std::make_unique<::printing::PrinterSemanticCapsAndDefaults>(), nullptr); EXPECT_CALL(new_window_delegate(), OpenUrl(testing::Property(&GURL::ExtractFileName, @@ -500,7 +500,7 @@ print_backend_->AddValidPrinter( printer.id(), - std::make_unique<printing::PrinterSemanticCapsAndDefaults>(), nullptr); + std::make_unique<::printing::PrinterSemanticCapsAndDefaults>(), nullptr); EXPECT_CALL(new_window_delegate(), OpenUrl(testing::Property(&GURL::ExtractFileName,
diff --git a/chrome/browser/ui/webui/searchbox/searchbox_handler.cc b/chrome/browser/ui/webui/searchbox/searchbox_handler.cc index 611978c..25fef0d6 100644 --- a/chrome/browser/ui/webui/searchbox/searchbox_handler.cc +++ b/chrome/browser/ui/webui/searchbox/searchbox_handler.cc
@@ -300,7 +300,7 @@ mojom_match->icon_path = kGoogleAgentspaceIconResourceName; #endif } - mojom_match->icon_url = match.icon_url.spec(); + mojom_match->icon_url = match.icon_url; mojom_match->image_dominant_color = match.image_dominant_color; mojom_match->image_url = match.image_url.spec(); mojom_match->fill_into_edit = match.fill_into_edit; @@ -469,7 +469,8 @@ {"searchBoxHintMultimodal", IDS_GOOGLE_SEARCH_BOX_EMPTY_HINT_MULTIMODAL}, {"searchboxThumbnailLabel", IDS_GOOGLE_SEARCH_BOX_MULTIMODAL_IMAGE_THUMBNAIL}, - {"voiceSearchButtonLabel", IDS_TOOLTIP_MIC_SEARCH}}; + {"voiceSearchButtonLabel", IDS_TOOLTIP_MIC_SEARCH}, + {"searchboxComposeButtonText", IDS_NTP_COMPOSE_ENTRYPOINT}}; source->AddLocalizedStrings(kStrings); source->AddBoolean(
diff --git a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc index baf7ccef..d301acd 100644 --- a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc +++ b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
@@ -2045,8 +2045,12 @@ IDS_SETTINGS_PRELOAD_PAGES_EXTENDED_PRELOADING_THINGS_TO_CONSIDER_BULLET_TWO}, {"preloadingPageThingsToConsiderBulletOne", IDS_SETTINGS_PRELOAD_PAGES_THINGS_TO_CONSIDER_BULLET_ONE}, - {"securityV8LinkTitle", IDS_SETTINGS_SECURITY_V8_LINK_TITLE}, - {"securityV8LinkDescription", IDS_SETTINGS_SECURITY_V8_LINK_DESCRIPTION}, + {"securityJavascriptOptimizerLinkTitle", + IDS_SETTINGS_SECURITY_JAVASCRIPT_OPTIMIZATION_LINK_TITLE}, + {"securityJavascriptOptimizerLinkRowLabelEnabled", + IDS_SETTINGS_SECURITY_JAVASCRIPT_OPTIMIZATION_LINK_ROW_ENABLED}, + {"securityJavascriptOptimizerLinkRowLabelDisabled", + IDS_SETTINGS_SECURITY_JAVASCRIPT_OPTIMIZATION_LINK_ROW_DISABLED}, #if BUILDFLAG(IS_CHROMEOS) {"openChromeOSSecureDnsSettingsLabel", IDS_SETTINGS_SECURE_DNS_OPEN_CHROME_OS_SETTINGS_LABEL},
diff --git a/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_page_handler_unittest.cc b/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_page_handler_unittest.cc index 02801424..e3afa55 100644 --- a/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_page_handler_unittest.cc +++ b/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_page_handler_unittest.cc
@@ -206,6 +206,7 @@ : NtpBackgroundService(application_locale_storage, url_loader_factory) {} MOCK_CONST_METHOD0(collection_info, std::vector<CollectionInfo>&()); MOCK_CONST_METHOD0(collection_images, std::vector<CollectionImage>&()); + MOCK_METHOD(void, FetchCollectionInfo, (const std::string& filtering_label)); MOCK_METHOD(void, FetchCollectionInfo, ()); MOCK_METHOD(void, FetchCollectionImageInfo, (const std::string&)); MOCK_METHOD(void, @@ -587,7 +588,7 @@ CustomizeChromePageHandler::GetBackgroundCollectionsCallback> callback; EXPECT_CALL(callback, Run(_)).Times(1).WillOnce(MoveArg(&collections)); - EXPECT_CALL(mock_ntp_background_service(), FetchCollectionInfo).Times(1); + EXPECT_CALL(mock_ntp_background_service(), FetchCollectionInfo()).Times(1); handler().GetBackgroundCollections(callback.Get()); ntp_background_service_observer().OnCollectionInfoAvailable();
diff --git a/chrome/browser/uid/android/java/src/org/chromium/chrome/browser/uid/UniqueIdentificationGeneratorFactory.java b/chrome/browser/uid/android/java/src/org/chromium/chrome/browser/uid/UniqueIdentificationGeneratorFactory.java index 3a52c91..1aa5d00 100644 --- a/chrome/browser/uid/android/java/src/org/chromium/chrome/browser/uid/UniqueIdentificationGeneratorFactory.java +++ b/chrome/browser/uid/android/java/src/org/chromium/chrome/browser/uid/UniqueIdentificationGeneratorFactory.java
@@ -11,16 +11,15 @@ /** * Factory for setting and retrieving instances of {@link UniqueIdentificationGenerator}s. - * <p/> - * A generator must always be set for a generator type before it is asked for. A generator type + * + * <p>A generator must always be set for a generator type before it is asked for. A generator type * is any string you want to use for your generator. It is typically defined as a public static * field in the generator itself. */ @NullMarked public final class UniqueIdentificationGeneratorFactory { private static final Object LOCK = new Object(); - private static final Map<String, UniqueIdentificationGenerator> GENERATOR_MAP = - new HashMap<String, UniqueIdentificationGenerator>(); + private static final Map<String, UniqueIdentificationGenerator> GENERATOR_MAP = new HashMap<>(); private UniqueIdentificationGeneratorFactory() {}
diff --git a/chrome/browser/usb/android/java/src/org/chromium/chrome/browser/usb/UsbNotificationManager.java b/chrome/browser/usb/android/java/src/org/chromium/chrome/browser/usb/UsbNotificationManager.java index 5b60d396..5e909fa5 100644 --- a/chrome/browser/usb/android/java/src/org/chromium/chrome/browser/usb/UsbNotificationManager.java +++ b/chrome/browser/usb/android/java/src/org/chromium/chrome/browser/usb/UsbNotificationManager.java
@@ -51,7 +51,7 @@ private final UsbNotificationManagerDelegate mDelegate; private final BaseNotificationManagerProxy mNotificationManager; private final SharedPreferencesManager mSharedPreferences; - private final List<Integer> mNotificationIds = new ArrayList<Integer>(); + private final List<Integer> mNotificationIds = new ArrayList<>(); public UsbNotificationManager( BaseNotificationManagerProxy notificationManager,
diff --git a/chrome/browser/util/android/java/src/org/chromium/chrome/browser/util/DefaultBrowserInfo.java b/chrome/browser/util/android/java/src/org/chromium/chrome/browser/util/DefaultBrowserInfo.java index 2ce395f..d61f71b 100644 --- a/chrome/browser/util/android/java/src/org/chromium/chrome/browser/util/DefaultBrowserInfo.java +++ b/chrome/browser/util/android/java/src/org/chromium/chrome/browser/util/DefaultBrowserInfo.java
@@ -144,7 +144,7 @@ new ObserverList<>(); public static void setDefaultInfoForTests(DefaultInfo info) { - sTestInfo = new AtomicReference<DefaultInfo>(info); + sTestInfo = new AtomicReference<>(info); } public static void clearDefaultInfoForTests() {
diff --git a/chrome/browser/webid/android/java/src/org/chromium/chrome/browser/webid/DigitalCredentialsCreationDelegate.java b/chrome/browser/webid/android/java/src/org/chromium/chrome/browser/webid/DigitalCredentialsCreationDelegate.java index f966da7..476b4d6 100644 --- a/chrome/browser/webid/android/java/src/org/chromium/chrome/browser/webid/DigitalCredentialsCreationDelegate.java +++ b/chrome/browser/webid/android/java/src/org/chromium/chrome/browser/webid/DigitalCredentialsCreationDelegate.java
@@ -52,7 +52,7 @@ final IdentityCredentialClient client = IdentityCredentialManager.Companion.getClient(window); - final Promise<DigitalCredential> result = new Promise<DigitalCredential>(); + final Promise<DigitalCredential> result = new Promise<>(); ResultReceiver resultReceiver = new ResultReceiver(new Handler(Looper.getMainLooper())) {
diff --git a/chrome/browser/webid/android/java/src/org/chromium/chrome/browser/webid/DigitalCredentialsPresentationDelegate.java b/chrome/browser/webid/android/java/src/org/chromium/chrome/browser/webid/DigitalCredentialsPresentationDelegate.java index 0110ee9..3b7368c 100644 --- a/chrome/browser/webid/android/java/src/org/chromium/chrome/browser/webid/DigitalCredentialsPresentationDelegate.java +++ b/chrome/browser/webid/android/java/src/org/chromium/chrome/browser/webid/DigitalCredentialsPresentationDelegate.java
@@ -79,7 +79,7 @@ return Promise.rejected(); } - final Promise<DigitalCredential> result = new Promise<DigitalCredential>(); + final Promise<DigitalCredential> result = new Promise<>(); ResultReceiver resultReceiver = new ResultReceiver(new Handler(Looper.getMainLooper())) {
diff --git a/chrome/browser_exposed_mojom_targets.gni b/chrome/browser_exposed_mojom_targets.gni index 33ebc07..6f62efc7 100644 --- a/chrome/browser_exposed_mojom_targets.gni +++ b/chrome/browser_exposed_mojom_targets.gni
@@ -15,6 +15,7 @@ "//cc/mojom:layer_trees", "//cc/mojom:mojom", "//chrome/browser/glic:mojo_bindings", + "//chrome/browser/glic/fre:mojo_bindings", "//chrome/browser/lens/core/mojom:mojo_bindings", "//chrome/browser/media:mojo_bindings", "//chrome/browser/new_tab_page/modules/file_suggestion:mojo_bindings",
diff --git a/chrome/build/android-arm64.pgo.txt b/chrome/build/android-arm64.pgo.txt index 5b433846..44a0137 100644 --- a/chrome/build/android-arm64.pgo.txt +++ b/chrome/build/android-arm64.pgo.txt
@@ -1 +1 @@ -chrome-android64-main-1749562579-2c9f8fb967950c4cfecacb970035a3b3cc2837af-45ed15c2708470219dd3b306789ad81b3b0ab89b.profdata +chrome-android64-main-1749572381-b04961a75f457308686690ec38e20de7d9ddbcea-3cd894c433301ff72211122f66c51e0a8c38a7a3.profdata
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt index 33cf0c8f..3452f3b 100644 --- a/chrome/build/linux.pgo.txt +++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@ -chrome-linux-main-1749446856-b18f9994856ae25003a7215792a299a9c153d29d-3d8e1ae50db0f9b484ae626a8df2511f5a1b0df8.profdata +chrome-linux-main-1749556486-627e61906bd2b4d02d788f7220f5c429be049880-e41eb49291b473b1a10e176e3d85510cc531e40e.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt index 25b2787..f2f2f8a 100644 --- a/chrome/build/mac-arm.pgo.txt +++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@ -chrome-mac-arm-main-1749563762-e6812e868532072d82d7d4c704f7e4e07159f8f5-86ce19f89bdda48987d3e558e8cc559402552c49.profdata +chrome-mac-arm-main-1749578330-7b746bb61b9542ac02ee0ffcb8bf77fe58e5531b-5b2cd5e60c1cd23d11553899d9e63337c3cd1509.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt index 59eb9b6..6668f1d 100644 --- a/chrome/build/win32.pgo.txt +++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@ -chrome-win32-main-1749513533-0d7b46b2bd724431a91e5b05eab9295a856ab7a8-32b4f325b8cf8ca5ef802e2f446c4903776b0511.profdata +chrome-win32-main-1749556486-35ccacb7e7653b408a7a57027e8273adbb189015-e41eb49291b473b1a10e176e3d85510cc531e40e.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt index c1d2e24..1e5f7b1 100644 --- a/chrome/build/win64.pgo.txt +++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@ -chrome-win64-main-1749535081-478f02153148e1a28a5e3ce3a751d63fa04d9257-b1629ea692c8614cb272bd693571aa887de92c6c.profdata +chrome-win64-main-1749545897-8edb23968a45995495c12e240eb97d0e46a0c505-a001b35ca54499b32b3a0fd6d7045a6088974888.profdata
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 3a8fa55f..5e73a42 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -2725,6 +2725,7 @@ "//services/device/public/mojom", "//services/image_annotation/public/cpp", "//services/network/public/cpp", + "//services/network/public/cpp:ip_address_space_overrides_test_utils", "//services/network/public/mojom", "//services/network/public/proto:sct_audit_report_proto", "//services/preferences/public/cpp", @@ -7930,6 +7931,7 @@ "../browser/resource_coordinator/test_lifecycle_unit.h", "../browser/resources_integrity_unittest.cc", "../browser/safe_browsing/generated_safe_browsing_pref_unittest.cc", + "../browser/safe_browsing/generated_security_settings_bundle_pref_unittest.cc", "../browser/search/background/ntp_custom_background_service_unittest.cc", "../browser/search/background/wallpaper_search/wallpaper_search_background_manager_unittest.cc", "../browser/search/instant_service_unittest.cc", @@ -10313,6 +10315,7 @@ "../browser/ui/views/layout_provider_unittest.cc", "../browser/ui/views/location_bar/cookie_controls/cookie_controls_bubble_unittest.cc", "../browser/ui/views/location_bar/cookie_controls/cookie_controls_icon_view_unittest.cc", + "../browser/ui/views/location_bar/cookie_controls/cookie_controls_page_action_controller_unittest.cc", "../browser/ui/views/location_bar/icon_label_bubble_view_unittest.cc", "../browser/ui/views/location_bar/location_icon_view_unittest.cc", "../browser/ui/views/media_router/cast_dialog_access_code_cast_button_unittest.cc", @@ -10346,6 +10349,7 @@ "../browser/ui/views/permissions/permission_prompt_base_view_unittest.cc", "../browser/ui/views/permissions/permission_prompt_bubble_one_origin_view_unittest.cc", "../browser/ui/views/permissions/permission_prompt_bubble_two_origins_view_unittest.cc", + "../browser/ui/views/picture_in_picture/picture_in_picture_tucker_unittest.cc", "../browser/ui/views/qrcode_generator/qrcode_generator_bubble_unittest.cc", "../browser/ui/views/relaunch_notification/relaunch_notification_controller_unittest.cc", "../browser/ui/views/relaunch_notification/relaunch_required_timer_internal_unittest.cc",
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/browser/history/StubbedHistoryProvider.java b/chrome/test/android/javatests/src/org/chromium/chrome/browser/history/StubbedHistoryProvider.java index c9502c7b..4c2b4c8a 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/browser/history/StubbedHistoryProvider.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/browser/history/StubbedHistoryProvider.java
@@ -116,7 +116,7 @@ if (mItems.size() > 0) { Collections.sort( mItems, - new Comparator<HistoryItem>() { + new Comparator<>() { @Override public int compare(HistoryItem lhs, HistoryItem rhs) { long timeDelta = lhs.getTimestamp() - rhs.getTimestamp();
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeActivityTestRule.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeActivityTestRule.java index 57fbc21..40632dc7 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeActivityTestRule.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeActivityTestRule.java
@@ -378,7 +378,7 @@ */ public int tabsCount(boolean incognito) { return ThreadUtils.runOnUiThreadBlocking( - new Callable<Integer>() { + new Callable<>() { @Override public Integer call() { return getActivity().getTabModelSelector().getModel(incognito).getCount(); @@ -389,7 +389,7 @@ /** Returns the infobars being displayed by the current tab, or null if they don't exist. */ public List<InfoBar> getInfoBars() { return ThreadUtils.runOnUiThreadBlocking( - new Callable<List<InfoBar>>() { + new Callable<>() { @Override public List<InfoBar> call() { Tab currentTab = getActivity().getActivityTab();
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/TestContentProvider.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/TestContentProvider.java index 432e46c..8ff94ea 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/TestContentProvider.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/TestContentProvider.java
@@ -222,7 +222,7 @@ ? mResourceRequestCount.get(resource) : 0); } else if (RESET_RESOURCE_REQUEST_COUNTS.equals(action)) { - mResourceRequestCount = new HashMap<String, Integer>(); + mResourceRequestCount = new HashMap<>(); } else if (SET_DATA_PATH.equals(action)) { mDataFilePath = resource; }
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/invalidation/IntentSavingContext.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/invalidation/IntentSavingContext.java index c6b4d41aa..e44521a 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/invalidation/IntentSavingContext.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/invalidation/IntentSavingContext.java
@@ -16,7 +16,7 @@ /** Mock context that saves all intents given to {@code startService}. */ public class IntentSavingContext extends AdvancedMockContext { - private final List<Intent> mStartedIntents = new ArrayList<Intent>(); + private final List<Intent> mStartedIntents = new ArrayList<>(); public IntentSavingContext(Context targetContext) { super(targetContext);
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/utils/TestUtils.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/utils/TestUtils.java index 481b11f..9d6dcdc 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/utils/TestUtils.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/utils/TestUtils.java
@@ -68,7 +68,7 @@ * @return ArgumentMatcher that matches a BySelector for the given depth. */ public static ArgumentMatcher<BySelector> matchesByDepth(final int depth) { - return new ArgumentMatcher<BySelector>() { + return new ArgumentMatcher<>() { // Need to do logical matching since BySelector does not override equals(Object). @Override public boolean matches(BySelector argument) { @@ -93,7 +93,7 @@ * @return ArgumentMatcher that matches a BySelector for the field using pattern. */ public static ArgumentMatcher<BySelector> matchesByField(Pattern pattern, String fieldName) { - return new ArgumentMatcher<BySelector>() { + return new ArgumentMatcher<>() { // Need to do logical matching since BySelector does not override equals(Object). @Override public boolean matches(BySelector argument) {
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/hub/TabSwitcherCardFacility.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/hub/TabSwitcherCardFacility.java index 71d77dd..ef079e03 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/hub/TabSwitcherCardFacility.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/hub/TabSwitcherCardFacility.java
@@ -6,8 +6,8 @@ import static androidx.test.espresso.matcher.ViewMatchers.hasDescendant; import static androidx.test.espresso.matcher.ViewMatchers.isAssignableFrom; +import static androidx.test.espresso.matcher.ViewMatchers.isDescendantOfA; import static androidx.test.espresso.matcher.ViewMatchers.withId; -import static androidx.test.espresso.matcher.ViewMatchers.withParent; import static androidx.test.espresso.matcher.ViewMatchers.withText; import static org.hamcrest.CoreMatchers.allOf; @@ -44,7 +44,10 @@ @CallSuper public void declareExtraElements() { Matcher<View> cardTitleMatcher = - allOf(withText(mTitle), withId(R.id.tab_title), withParent(withId(R.id.card_view))); + allOf( + withText(mTitle), + withId(R.id.tab_title), + isDescendantOfA(withId(R.id.content_view))); titleElement = declareView(cardTitleMatcher); ViewSpec<View> cardSpec =
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/page/PageStation.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/page/PageStation.java index 04b57b1..f9c3e02 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/page/PageStation.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/page/PageStation.java
@@ -98,8 +98,7 @@ public PageAppMenuFacility<PageStation> openGenericAppMenu() { recheckActiveConditions(); - return enterFacilitySync( - new PageAppMenuFacility<PageStation>(), menuButtonElement.getClickTrigger()); + return enterFacilitySync(new PageAppMenuFacility<>(), menuButtonElement.getClickTrigger()); } /** Shortcut to open a new tab programmatically as if selecting "New Tab" from the app menu. */
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/testhtmls/PopupOnClickPageStation.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/testhtmls/PopupOnClickPageStation.java index e034964..6def06c4 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/testhtmls/PopupOnClickPageStation.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/testhtmls/PopupOnClickPageStation.java
@@ -45,7 +45,7 @@ /** Opens the same page as a pop-up (in Android, this means in a new tab). */ public PopupOnClickPageStation clickLinkToOpenPopup() { PopupOnClickPageStation newPage = - new Builder<PopupOnClickPageStation>(PopupOnClickPageStation::new) + new Builder<>(PopupOnClickPageStation::new) .initFrom(this) .withIsOpeningTabs(1) .withIsSelectingTabs(1) @@ -70,7 +70,6 @@ */ public PopupBlockedMessageFacility clickLinkAndExpectPopupBlockedMessage() { return enterFacilitySync( - new PopupBlockedMessageFacility<PopupOnClickPageStation>(1), - linkToPopup.getClickTrigger()); + new PopupBlockedMessageFacility<>(1), linkToPopup.getClickTrigger()); } }
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/testhtmls/PopupOnLoadPageStation.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/testhtmls/PopupOnLoadPageStation.java index 6f61789a..0dfa3d4 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/testhtmls/PopupOnLoadPageStation.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/testhtmls/PopupOnLoadPageStation.java
@@ -37,7 +37,7 @@ PopupOnLoadPageStation newPage = currentPageStation.loadPageProgrammatically( url, - new Builder<PopupOnLoadPageStation>(PopupOnLoadPageStation::new) + new Builder<>(PopupOnLoadPageStation::new) .withFacility(popupBlockedMessage)); return Pair.create(newPage, popupBlockedMessage);
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/testhtmls/TopBottomLinksPageStation.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/testhtmls/TopBottomLinksPageStation.java index 2624e51..bace28f 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/testhtmls/TopBottomLinksPageStation.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/testhtmls/TopBottomLinksPageStation.java
@@ -40,8 +40,7 @@ TopBottomLinksPageStation station = currentPageStation.loadPageProgrammatically( url, - new Builder<TopBottomLinksPageStation>(TopBottomLinksPageStation::new) - .withFacility(topFacility)); + new Builder<>(TopBottomLinksPageStation::new).withFacility(topFacility)); return Pair.create(station, topFacility); }
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ActivityTestUtils.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ActivityTestUtils.java index 86d855c..eeac9acc 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ActivityTestUtils.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ActivityTestUtils.java
@@ -87,7 +87,7 @@ public static <T> T waitForActivity( Instrumentation instrumentation, Class<T> activityType, Runnable activityTrigger) { Callable<Void> callableWrapper = - new Callable<Void>() { + new Callable<>() { @Override public Void call() { activityTrigger.run();
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ChromeTabUtils.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ChromeTabUtils.java index c2d514b1..3ca68745 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ChromeTabUtils.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ChromeTabUtils.java
@@ -590,7 +590,7 @@ /** Fetch the number of tabs open in the current model. */ public static int getNumOpenTabs(final ChromeActivity activity) { return ThreadUtils.runOnUiThreadBlocking( - new Callable<Integer>() { + new Callable<>() { @Override public Integer call() { return activity.getCurrentTabModel().getCount();
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/OmniboxTestUtils.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/OmniboxTestUtils.java index db53c3b..a0ad43a 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/OmniboxTestUtils.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/OmniboxTestUtils.java
@@ -367,7 +367,7 @@ T view = (T) dropdown.getDropdownItemViewForTest(i); if (filter.apply(info) && view != null) { result.set( - new SuggestionInfo<T>( + new SuggestionInfo<>( i, info.type, mAutocomplete.getSuggestionAt(i),
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/sync/SyncTestUtil.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/sync/SyncTestUtil.java index c19f990..3408926 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/sync/SyncTestUtil.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/sync/SyncTestUtil.java
@@ -345,7 +345,7 @@ } List<Pair<String, JSONObject>> localDataForDatatype = - new ArrayList<Pair<String, JSONObject>>(datatypeNodes.length()); + new ArrayList<>(datatypeNodes.length()); for (int i = 0; i < datatypeNodes.length(); i++) { JSONObject entity = datatypeNodes.getJSONObject(i); if (entity.has("UNIQUE_SERVER_TAG")
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/tabmodel/MockTabModel.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/tabmodel/MockTabModel.java index cfb7258a..e3f0f6f 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/tabmodel/MockTabModel.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/tabmodel/MockTabModel.java
@@ -74,7 +74,7 @@ private final ObservableSupplierImpl<Integer> mTabCountSupplier = new ObservableSupplierImpl<>(); private final ObserverList<TabModelObserver> mObservers = new ObserverList<>(); - private final ArrayList<Tab> mTabs = new ArrayList<Tab>(); + private final ArrayList<Tab> mTabs = new ArrayList<>(); private final ComprehensiveTabList mComprehensiveModel = new ComprehensiveTabList(); private final Profile mProfile; private final MockTabModelDelegate mDelegate;
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/webapps/WebApkIntentDataProviderBuilder.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/webapps/WebApkIntentDataProviderBuilder.java index c171bcc2..70bf6af 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/webapps/WebApkIntentDataProviderBuilder.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/webapps/WebApkIntentDataProviderBuilder.java
@@ -33,7 +33,7 @@ private String mName; private String mShortName; private WebappIcon mPrimaryIcon; - private Map<String, String> mIconUrlToMurmur2HashMap = new HashMap<String, String>(); + private Map<String, String> mIconUrlToMurmur2HashMap = new HashMap<>(); private long mToolbarColor; private int mShellApkVersion = 1;
diff --git a/chrome/test/data/webui/cr_components/searchbox/searchbox_lens_test.ts b/chrome/test/data/webui/cr_components/searchbox/searchbox_lens_test.ts index e8e6b0a7..e6bbf6a 100644 --- a/chrome/test/data/webui/cr_components/searchbox/searchbox_lens_test.ts +++ b/chrome/test/data/webui/cr_components/searchbox/searchbox_lens_test.ts
@@ -36,7 +36,7 @@ inlineAutocompletion: stringToMojoString16(''), fillIntoEdit: stringToMojoString16(''), iconPath: '', - iconUrl: '', + iconUrl: {url: ''}, imageDominantColor: '', imageUrl: '', removeButtonA11yLabel: stringToMojoString16(''),
diff --git a/chrome/test/data/webui/cr_components/searchbox/searchbox_test.ts b/chrome/test/data/webui/cr_components/searchbox/searchbox_test.ts index d0dda0c..30fb3ba 100644 --- a/chrome/test/data/webui/cr_components/searchbox/searchbox_test.ts +++ b/chrome/test/data/webui/cr_components/searchbox/searchbox_test.ts
@@ -2162,11 +2162,11 @@ const matches = [ createUrlMatch({ - iconUrl: 'https://helloworld.com/url.png', + iconUrl: {url: 'https://helloworld.com/url.png'}, iconPath: 'page.svg', }), createSearchMatch({ - iconUrl: 'https://helloworld.com/search.png', + iconUrl: {url: 'https://helloworld.com/search.png'}, iconPath: 'clock.svg', imageUrl: 'https://gstatic.com/', imageDominantColor: '#757575', @@ -2188,12 +2188,12 @@ assertIconState( matchEls[0], /*hasEntityImage=*/ false, /*expectUseIconImg=*/ false, `//image?staticEncode=true&encodeType=webp&url=${ - matches[0]!.iconUrl}`); + matches[0]!.iconUrl.url}`); // Test initial icon state for the second match: icon image not used. assertIconState( matchEls[1], /*hasEntityImage=*/ true, /*expectUseIconImg=*/ false, `//image?staticEncode=true&encodeType=webp&url=${ - matches[1]!.iconUrl}`); + matches[1]!.iconUrl.url}`); // Select the first match. let arrowDownEvent = arrowDown(realbox); @@ -2207,18 +2207,18 @@ assertIconState( realbox, /*hasEntityImage=*/ false, /*expectUseIconImg=*/ false, `//image?staticEncode=true&encodeType=webp&url=${ - matches[0]!.iconUrl}`); + matches[0]!.iconUrl.url}`); // Mock icon image finishing loading for the first match and the realbox // itself. The icon image should be used icon. assertAndLoadIcon( matchEls[0], /*hasEntityImage=*/ false, `//image?staticEncode=true&encodeType=webp&url=${ - matches[0]!.iconUrl}`); + matches[0]!.iconUrl.url}`); assertAndLoadIcon( realbox, /*hasEntityImage=*/ false, `//image?staticEncode=true&encodeType=webp&url=${ - matches[0]!.iconUrl}`); + matches[0]!.iconUrl.url}`); // Select the second match. arrowDownEvent = arrowDown(realbox); @@ -2232,17 +2232,17 @@ assertIconState( realbox, /*hasEntityImage=*/ false, /*expectUseIconImg=*/ false, `//image?staticEncode=true&encodeType=webp&url=${ - matches[1]!.iconUrl}`); + matches[1]!.iconUrl.url}`); // Mock icon image finishing loading for the second match and the // realbox itself. The icon image should be used. assertAndLoadIcon( matchEls[1], /*hasEntityImage=*/ true, `//image?staticEncode=true&encodeType=webp&url=${ - matches[1]!.iconUrl}`); + matches[1]!.iconUrl.url}`); assertAndLoadIcon( realbox, /*hasEntityImage=*/ false, `//image?staticEncode=true&encodeType=webp&url=${ - matches[1]!.iconUrl}`); + matches[1]!.iconUrl.url}`); // Select the first match by pressing 'Escape'. const escapeEvent = new KeyboardEvent('keydown', { @@ -2262,13 +2262,13 @@ assertIconState( realbox, /*hasEntityImage=*/ false, /*expectUseIconImg=*/ false, `//image?staticEncode=true&encodeType=webp&url=${ - matches[0]!.iconUrl}`); + matches[0]!.iconUrl.url}`); // Mock icon image finishing loading for the realbox (now showing the // first match's icon image again). assertAndLoadIcon( realbox, /*hasEntityImage=*/ false, `//image?staticEncode=true&encodeType=webp&url=${ - matches[0]!.iconUrl}`); + matches[0]!.iconUrl.url}`); }); @@ -2284,7 +2284,7 @@ isEnterpriseSearchAggregatorPeopleType: true, }), createUrlMatch({ - iconUrl: 'https://helloworld-2.com/url.png', + iconUrl: {url: 'https://helloworld-2.com/url.png'}, iconPath: fallbackIconPath, isEnterpriseSearchAggregatorPeopleType: true, contents: stringToMojoString16('helloworld-2.com'),
diff --git a/chrome/test/data/webui/cr_components/searchbox/searchbox_test_utils.ts b/chrome/test/data/webui/cr_components/searchbox/searchbox_test_utils.ts index f89ae76..ae08c04c 100644 --- a/chrome/test/data/webui/cr_components/searchbox/searchbox_test_utils.ts +++ b/chrome/test/data/webui/cr_components/searchbox/searchbox_test_utils.ts
@@ -23,7 +23,7 @@ inlineAutocompletion: {data: []}, fillIntoEdit: {data: []}, iconPath: '', - iconUrl: '', + iconUrl: {url: ''}, imageDominantColor: '', imageUrl: '', removeButtonA11yLabel: {data: []},
diff --git a/chrome/test/data/webui/new_tab_page/app_test.ts b/chrome/test/data/webui/new_tab_page/app_test.ts index b6658e2..50709dc 100644 --- a/chrome/test/data/webui/new_tab_page/app_test.ts +++ b/chrome/test/data/webui/new_tab_page/app_test.ts
@@ -990,6 +990,35 @@ }); }); + suite('Composebox', () => { + suiteSetup(() => { + loadTimeData.overrideValues({ + searchboxShowComposeButton: true, + }); + }); + test('toggle composebox visibility', async () => { + // Arrange. + callbackRouterRemote.setTheme(createTheme()); + await callbackRouterRemote.$.flushForTesting(); + + // Act. + $$(app, '#searchbox')!.dispatchEvent(new Event('open-composebox')); + await microtasksFinished(); + + // Assert. + const composebox = app.shadowRoot.querySelector('ntp-composebox'); + assertTrue(!!composebox); + assertStyle($$(app, '#searchbox')!, 'visibility', 'hidden'); + + // Act. + $$<HTMLElement>(app, '#composeboxScrim')!.click(); + await microtasksFinished(); + + // Assert. + assertStyle($$(app, '#searchbox')!, 'visibility', 'visible'); + }); + }); + suite('WallpaperSearch', () => { setup(async () => { // Set a theme with no background image and a baseline color to avoid
diff --git a/chrome/test/data/webui/new_tab_page/new_tab_page_browsertest.cc b/chrome/test/data/webui/new_tab_page/new_tab_page_browsertest.cc index 754e9f9..95e5fe61 100644 --- a/chrome/test/data/webui/new_tab_page/new_tab_page_browsertest.cc +++ b/chrome/test/data/webui/new_tab_page/new_tab_page_browsertest.cc
@@ -206,6 +206,11 @@ "runMochaSuite('NewTabPageAppTest LensUploadDialog')"); } +IN_PROC_BROWSER_TEST_F(NewTabPageAppTest, Composebox) { + RunTest("new_tab_page/app_test.js", + "runMochaSuite('NewTabPageAppTest Composebox')"); +} + IN_PROC_BROWSER_TEST_F(NewTabPageAppTest, WallpaperSearch) { RunTest("new_tab_page/app_test.js", "runMochaSuite('NewTabPageAppTest WallpaperSearch')");
diff --git a/chrome/test/data/webui/settings/BUILD.gn b/chrome/test/data/webui/settings/BUILD.gn index e7d7046..42fbd895 100644 --- a/chrome/test/data/webui/settings/BUILD.gn +++ b/chrome/test/data/webui/settings/BUILD.gn
@@ -115,6 +115,7 @@ "security_keys_subpage_test.ts", "security_keys_test_util.ts", "security_page_test.ts", + "security_page_v2_test.ts", "settings_animated_pages_test.ts", "settings_category_default_radio_group_test.ts", "settings_main_test.ts",
diff --git a/chrome/test/data/webui/settings/security_page_test.ts b/chrome/test/data/webui/settings/security_page_test.ts index dd0b737..17b2c6b 100644 --- a/chrome/test/data/webui/settings/security_page_test.ts +++ b/chrome/test/data/webui/settings/security_page_test.ts
@@ -6,8 +6,9 @@ import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import type {SettingsSecurityPageElement} from 'chrome://settings/lazy_load.js'; +import {ContentSetting, ContentSettingsTypes, DefaultSettingSource, SiteSettingsPrefsBrowserProxyImpl} from 'chrome://settings/lazy_load.js'; import {HttpsFirstModeSetting, SafeBrowsingSetting} from 'chrome://settings/lazy_load.js'; -import type {SettingsPrefsElement, SettingsToggleButtonElement} from 'chrome://settings/settings.js'; +import type {CrLinkRowElement, SettingsPrefsElement, SettingsToggleButtonElement} from 'chrome://settings/settings.js'; import {HatsBrowserProxyImpl, CrSettingsPrefs, MetricsBrowserProxyImpl, OpenWindowProxyImpl, PrivacyElementInteractions, PrivacyPageBrowserProxyImpl, resetRouterForTesting, Router, routes, SafeBrowsingInteractions, SecureDnsMode, SecurityPageInteraction} from 'chrome://settings/settings.js'; import {assertEquals, assertFalse, assertTrue, assertNotEquals} from 'chrome://webui-test/chai_assert.js'; import {isChildVisible, eventToPromise, microtasksFinished} from 'chrome://webui-test/test_util.js'; @@ -15,10 +16,12 @@ import {TestHatsBrowserProxy} from './test_hats_browser_proxy.js'; import {TestMetricsBrowserProxy} from './test_metrics_browser_proxy.js'; +import {createContentSettingTypeToValuePair, createDefaultContentSetting, createSiteSettingsPrefs} from './test_util.js'; import {TestOpenWindowProxy} from 'chrome://webui-test/test_open_window_proxy.js'; import {TestPrivacyPageBrowserProxy} from './test_privacy_page_browser_proxy.js'; +import {TestSiteSettingsPrefsBrowserProxy} from './test_site_settings_prefs_browser_proxy.js'; // clang-format on @@ -172,16 +175,6 @@ page.getPref('generated.https_first_mode_enabled').value); }); - // Test that clicking the V8 security row navigates to the setting page. - test('NavigateToV8Setting', function() { - const link = page.shadowRoot!.querySelector<HTMLElement>('#v8SettingLink'); - assertTrue(!!link); - link.click(); - assertEquals( - routes.SITE_SETTINGS_JAVASCRIPT_OPTIMIZER, - Router.getInstance().getCurrentRoute()); - }); - // Tests that the correct Advanced Protection sublabel is used when the // HTTPS-First Mode setting toggle has user control disabled. test('HttpsFirstModeSettingAdvancedProtectionSubLabel', function() { @@ -1131,6 +1124,79 @@ }); }); +suite('JavascriptOptimizer', function() { + let page: SettingsSecurityPageElement; + let siteSettingsBrowserProxy: TestSiteSettingsPrefsBrowserProxy; + + setup(function() { + document.body.innerHTML = window.trustedTypes!.emptyHTML; + siteSettingsBrowserProxy = new TestSiteSettingsPrefsBrowserProxy(); + SiteSettingsPrefsBrowserProxyImpl.setInstance(siteSettingsBrowserProxy); + }); + + teardown(function() { + Router.getInstance().navigateTo(routes.BASIC); + }); + + function createPage() { + document.body.innerHTML = window.trustedTypes!.emptyHTML; + + page = document.createElement('settings-security-page'); + page.prefs = pagePrefs(); + document.body.appendChild(page); + return flushTasks(); + } + + function setDefaultJavascriptOptimizerContentSetting(value: ContentSetting) { + const contentSettingPref = createSiteSettingsPrefs( + [ + createContentSettingTypeToValuePair( + ContentSettingsTypes.JAVASCRIPT_OPTIMIZER, + createDefaultContentSetting({ + setting: value, + source: DefaultSettingSource.DEFAULT, + })), + ], + []); + siteSettingsBrowserProxy.setPrefs(contentSettingPref); + } + + // Test that clicking the javascript-optimizer security row navigates to the + // setting page. + test('NavigateToJavascriptOptimizerSetting', async () => { + await createPage(); + const link = page.shadowRoot!.querySelector<HTMLElement>( + '#javascriptOptimizerSettingLink'); + assertTrue(!!link); + link.click(); + assertEquals( + routes.SITE_SETTINGS_JAVASCRIPT_OPTIMIZER, + Router.getInstance().getCurrentRoute()); + }); + + test('JavascriptOptimizerSubLabelAllow', async () => { + setDefaultJavascriptOptimizerContentSetting(ContentSetting.ALLOW); + await createPage(); + const link = page.shadowRoot!.querySelector<CrLinkRowElement>( + '#javascriptOptimizerSettingLink'); + assertTrue(!!link); + const expectedSubLabel = loadTimeData.getString( + 'securityJavascriptOptimizerLinkRowLabelEnabled'); + assertEquals(expectedSubLabel, link.subLabel); + }); + + test('JavascriptOptimizerSubLabelBlock', async () => { + setDefaultJavascriptOptimizerContentSetting(ContentSetting.BLOCK); + await createPage(); + const link = page.shadowRoot!.querySelector<CrLinkRowElement>( + '#javascriptOptimizerSettingLink'); + assertTrue(!!link); + const expectedSubLabel = loadTimeData.getString( + 'securityJavascriptOptimizerLinkRowLabelDisabled'); + assertEquals(expectedSubLabel, link.subLabel); + }); +}); + async function clickCancelOnDisableSafebrowsingDialog( page: SettingsSecurityPageElement) { const confirmationDialog =
diff --git a/chrome/test/data/webui/settings/security_page_v2_test.ts b/chrome/test/data/webui/settings/security_page_v2_test.ts new file mode 100644 index 0000000..b65842d --- /dev/null +++ b/chrome/test/data/webui/settings/security_page_v2_test.ts
@@ -0,0 +1,53 @@ +// Copyright 2025 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 {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import type {SettingsSecurityPageV2Element} from 'chrome://settings/lazy_load.js'; +import {SecuritySettingsBundleSetting} from 'chrome://settings/lazy_load.js'; +import type {SettingsPrefsElement} from 'chrome://settings/settings.js'; +import {CrSettingsPrefs} from 'chrome://settings/settings.js'; +import {assertEquals} from 'chrome://webui-test/chai_assert.js'; +import {microtasksFinished} from 'chrome://webui-test/test_util.js'; + +// clang-format on + +suite('Main', function() { + let settingsPrefs: SettingsPrefsElement; + let page: SettingsSecurityPageV2Element; + + suiteSetup(function() { + settingsPrefs = document.createElement('settings-prefs'); + return CrSettingsPrefs.initialized; + }); + + setup(function() { + document.body.innerHTML = window.trustedTypes!.emptyHTML; + + page = document.createElement('settings-security-page-v2'); + page.prefs = settingsPrefs.prefs; + document.body.appendChild(page); + flush(); + }); + + test('StandardBundleIsInitiallySelected', function() { + assertEquals( + SecuritySettingsBundleSetting.STANDARD, + page.prefs.generated.security_settings_bundle.value); + }); + + test('EnhanceBundleSelected', async function() { + // Standard bundle is initially selected. + assertEquals( + SecuritySettingsBundleSetting.STANDARD, + page.prefs.generated.security_settings_bundle.value); + + // Click on Enhanced bundle. + page.$.securitySettingsBundleEnhanced.click(); + await microtasksFinished(); + assertEquals( + SecuritySettingsBundleSetting.ENHANCED, + page.prefs.generated.security_settings_bundle.value); + }); +});
diff --git a/chrome/test/data/webui/settings/settings_browsertest.cc b/chrome/test/data/webui/settings/settings_browsertest.cc index ae73a1f..e091451 100644 --- a/chrome/test/data/webui/settings/settings_browsertest.cc +++ b/chrome/test/data/webui/settings/settings_browsertest.cc
@@ -688,7 +688,6 @@ } #endif - IN_PROC_BROWSER_TEST_F(SettingsTest, TabDiscardExceptionDialog) { RunTest("settings/tab_discard_exception_dialog_test.js", "mocha.run()"); } @@ -934,8 +933,7 @@ "runMochaSuite('MemorySaverAggressiveness')"); } -class SettingsPersonalizationOptionsTest : public SettingsBrowserTest { -}; +class SettingsPersonalizationOptionsTest : public SettingsBrowserTest {}; IN_PROC_BROWSER_TEST_F(SettingsPersonalizationOptionsTest, AllBuilds) { RunTest("settings/personalization_options_test.js", @@ -1469,6 +1467,11 @@ "runMochaSuite('SecurityPageHappinessTrackingSurveys')"); } +IN_PROC_BROWSER_TEST_F(SettingsSecurityPageTest, JavascriptOptimizer) { + RunTest("settings/security_page_test.js", + "runMochaSuite('JavascriptOptimizer')"); +} + // TODO(crbug/338155508): Enable this flaky test. This is flaky on Linux debug // build. // TODO(crbug.com/409069315): Re-enable this test on Mac. @@ -1481,6 +1484,12 @@ RunTest("settings/security_page_test.js", "runMochaSuite('SafeBrowsing')"); } +using SettingsSecurityPageV2Test = SettingsBrowserTest; + +IN_PROC_BROWSER_TEST_F(SettingsSecurityPageV2Test, Main) { + RunTest("settings/security_page_v2_test.js", "runMochaSuite('Main')"); +} + #if !BUILDFLAG(IS_CHROMEOS) using SettingsSpellCheckPageTest = SettingsBrowserTest;
diff --git a/chromecast/starboard/media/renderer/starboard_player_manager.cc b/chromecast/starboard/media/renderer/starboard_player_manager.cc index 7ac1564..bf4a50994 100644 --- a/chromecast/starboard/media/renderer/starboard_player_manager.cc +++ b/chromecast/starboard/media/renderer/starboard_player_manager.cc
@@ -38,10 +38,12 @@ std::optional<StarboardVideoSampleInfo> video_sample_info; chromecast::media::StarboardPlayerCreationParam creation_param = {}; - creation_param.drm_system = StarboardDrmWrapper::GetInstance().GetDrmSystem(); creation_param.output_mode = StarboardPlayerOutputMode::kStarboardPlayerOutputModePunchOut; + // This will be set below if audio or video is encrypted. + creation_param.drm_system = nullptr; + if (audio_stream) { audio_stream->EnableBitstreamConverter(); audio_config = audio_stream->audio_decoder_config(); @@ -55,6 +57,11 @@ LOG(INFO) << "Initial audio config: " << audio_config.AsHumanReadableString(); creation_param.audio_sample_info = *audio_sample_info; + + if (audio_config.is_encrypted()) { + creation_param.drm_system = + StarboardDrmWrapper::GetInstance().GetDrmSystem(); + } } if (video_stream) { @@ -79,6 +86,11 @@ // prioritize minimizing latency (render the frames as soon as possible). creation_param.video_sample_info.max_video_capabilities = "streaming=1"; } + + if (video_config.is_encrypted()) { + creation_param.drm_system = + StarboardDrmWrapper::GetInstance().GetDrmSystem(); + } } // base::WrapUnique is necessary because we're calling a private ctor.
diff --git a/chromecast/starboard/media/renderer/starboard_player_manager_test.cc b/chromecast/starboard/media/renderer/starboard_player_manager_test.cc index 9f287360..2e6fe4b 100644 --- a/chromecast/starboard/media/renderer/starboard_player_manager_test.cc +++ b/chromecast/starboard/media/renderer/starboard_player_manager_test.cc
@@ -49,23 +49,31 @@ // Returns a valid audio config with values arbitrarily set. The values will // match the values of GetStarboardAudioConfig. -::media::AudioDecoderConfig GetChromiumAudioConfig() { +// +// By default, content is unencrypted. An encryption scheme may be specified. +::media::AudioDecoderConfig GetChromiumAudioConfig( + ::media::EncryptionScheme encryption_scheme = + ::media::EncryptionScheme::kUnencrypted) { return ::media::AudioDecoderConfig( ::media::AudioCodec::kAC3, ::media::SampleFormat::kSampleFormatS32, ::media::ChannelLayout::CHANNEL_LAYOUT_5_1, 44100, /*extra_data=*/{}, - ::media::EncryptionScheme::kUnencrypted); + encryption_scheme); } // Returns a valid video config with values arbitrarily set. The values will // match the values of GetStarboardVideoConfig. -::media::VideoDecoderConfig GetChromiumVideoConfig() { +// +// By default, content is unencrypted. An encryption scheme may be specified. +::media::VideoDecoderConfig GetChromiumVideoConfig( + ::media::EncryptionScheme encryption_scheme = + ::media::EncryptionScheme::kUnencrypted) { ::media::VideoDecoderConfig video_config( ::media::VideoCodec::kHEVC, ::media::VideoCodecProfile::HEVCPROFILE_MAIN, ::media::VideoDecoderConfig::AlphaMode::kIsOpaque, ::media::VideoColorSpace(1, 1, 1, gfx::ColorSpace::RangeID::LIMITED), ::media::VideoTransformation(), gfx::Size(1920, 1080), gfx::Rect(0, 0, 1919, 1079), gfx::Size(1280, 720), /*extra_data=*/{}, - ::media::EncryptionScheme::kUnencrypted); + encryption_scheme); video_config.set_level(5); return video_config; } @@ -126,23 +134,13 @@ protected: StarboardPlayerManagerTest() : audio_stream_(DemuxerStream::Type::AUDIO), - video_stream_(DemuxerStream::Type::VIDEO) { - ON_CALL(starboard_for_drm_, CreateDrmSystem) - .WillByDefault(Return(&drm_system_)); - StarboardDrmWrapper::SetSingletonForTesting(&starboard_for_drm_); - } + video_stream_(DemuxerStream::Type::VIDEO) {} ~StarboardPlayerManagerTest() override = default; // This should be destructed last. base::test::TaskEnvironment task_environment_; NiceMock<MockStarboardApiWrapper> starboard_; - - // It is undefined behavior to set expectations on a mock after its mock - // functions have been called. Thus, to be safe we use a separate mock - // starboard for the StarboardDrmWrapper. All expectations are set before it - // is passed to the StarboardDrmWrapper (in this fixture's ctor). - NiceMock<MockStarboardApiWrapper> starboard_for_drm_; MockDemuxerStream audio_stream_; MockDemuxerStream video_stream_; MockRendererClient renderer_client_; @@ -150,8 +148,6 @@ // Since SbPlayer is used as an opaque void* by cast, we can use any type // here. All that matters is the address. int sb_player_ = 1; - // Same for SbDrmSystem. - int drm_system_ = 2; }; TEST_F(StarboardPlayerManagerTest, @@ -164,7 +160,7 @@ starboard_, CreatePlayer( Pointee(MatchesPlayerCreationParam(StarboardPlayerCreationParam{ - .drm_system = &drm_system_, + .drm_system = nullptr, .audio_sample_info = GetStarboardAudioConfig(), .video_sample_info = GetStarboardVideoConfig(), .output_mode = StarboardPlayerOutputMode:: @@ -190,7 +186,7 @@ starboard_, CreatePlayer( Pointee(MatchesPlayerCreationParam(StarboardPlayerCreationParam{ - .drm_system = &drm_system_, + .drm_system = nullptr, .audio_sample_info = GetStarboardAudioConfig(), .video_sample_info = GetStarboardVideoConfig(), .output_mode = StarboardPlayerOutputMode:: @@ -222,7 +218,7 @@ starboard_, CreatePlayer( Pointee(MatchesPlayerCreationParam(StarboardPlayerCreationParam{ - .drm_system = &drm_system_, + .drm_system = nullptr, .audio_sample_info = GetStarboardAudioConfig(), .video_sample_info = GetStarboardVideoConfig(), .output_mode = StarboardPlayerOutputMode:: @@ -274,7 +270,7 @@ starboard_, CreatePlayer( Pointee(MatchesPlayerCreationParam(StarboardPlayerCreationParam{ - .drm_system = &drm_system_, + .drm_system = nullptr, .audio_sample_info = GetStarboardAudioConfig(), .video_sample_info = GetStarboardVideoConfig(), .output_mode = StarboardPlayerOutputMode:: @@ -309,7 +305,7 @@ starboard_, CreatePlayer( Pointee(MatchesPlayerCreationParam(StarboardPlayerCreationParam{ - .drm_system = &drm_system_, + .drm_system = nullptr, .audio_sample_info = GetStarboardAudioConfig(), .video_sample_info = GetStarboardVideoConfig(), .output_mode = StarboardPlayerOutputMode:: @@ -341,7 +337,7 @@ starboard_, CreatePlayer( Pointee(MatchesPlayerCreationParam(StarboardPlayerCreationParam{ - .drm_system = &drm_system_, + .drm_system = nullptr, .audio_sample_info = GetStarboardAudioConfig(), .video_sample_info = GetStarboardVideoConfig(), .output_mode = StarboardPlayerOutputMode:: @@ -377,7 +373,7 @@ starboard_, CreatePlayer( Pointee(MatchesPlayerCreationParam(StarboardPlayerCreationParam{ - .drm_system = &drm_system_, + .drm_system = nullptr, .audio_sample_info = GetStarboardAudioConfig(), .video_sample_info = GetStarboardVideoConfig(), .output_mode = StarboardPlayerOutputMode:: @@ -410,7 +406,7 @@ starboard_, CreatePlayer( Pointee(MatchesPlayerCreationParam(StarboardPlayerCreationParam{ - .drm_system = &drm_system_, + .drm_system = nullptr, .audio_sample_info = GetStarboardAudioConfig(), .video_sample_info = sb_video_config, .output_mode = StarboardPlayerOutputMode:: @@ -451,7 +447,7 @@ starboard_, CreatePlayer( Pointee(MatchesPlayerCreationParam(StarboardPlayerCreationParam{ - .drm_system = &drm_system_, + .drm_system = nullptr, .audio_sample_info = sb_audio_config, .video_sample_info = sb_video_config, .output_mode = StarboardPlayerOutputMode:: @@ -556,7 +552,7 @@ starboard_, CreatePlayer( Pointee(MatchesPlayerCreationParam(StarboardPlayerCreationParam{ - .drm_system = &drm_system_, + .drm_system = nullptr, .audio_sample_info = {}, .video_sample_info = sb_video_config, .output_mode = StarboardPlayerOutputMode:: @@ -630,7 +626,7 @@ starboard_, CreatePlayer( Pointee(MatchesPlayerCreationParam(StarboardPlayerCreationParam{ - .drm_system = &drm_system_, + .drm_system = nullptr, .audio_sample_info = sb_audio_config, .video_sample_info = {}, .output_mode = StarboardPlayerOutputMode:: @@ -726,6 +722,102 @@ IsNull()); } +TEST_F(StarboardPlayerManagerTest, CreatesDrmSystemForEncryptedAudioAndVideo) { + // SbDrmSystem is an opaque blob to cast, so its actual value does not matter. + // All that matters is its address (treated as void*). + int drm_system = 3; + EXPECT_CALL(starboard_, CreateDrmSystem).WillOnce(Return(&drm_system)); + EXPECT_CALL( + starboard_, + CreatePlayer( + Pointee(MatchesPlayerCreationParam(StarboardPlayerCreationParam{ + .drm_system = &drm_system, + .audio_sample_info = GetStarboardAudioConfig(), + .video_sample_info = GetStarboardVideoConfig(), + .output_mode = StarboardPlayerOutputMode:: + kStarboardPlayerOutputModePunchOut})), + _)) + .WillOnce(Return(&sb_player_)); + StarboardDrmWrapper::SetSingletonForTesting(&starboard_); + + // Both audio and video streams are encrypted. + audio_stream_.set_audio_decoder_config( + GetChromiumAudioConfig(::media::EncryptionScheme::kCenc)); + video_stream_.set_video_decoder_config( + GetChromiumVideoConfig(::media::EncryptionScheme::kCenc)); + + std::unique_ptr<StarboardPlayerManager> player_manager = + StarboardPlayerManager::Create( + &starboard_, &audio_stream_, &video_stream_, &renderer_client_, + base::SequencedTaskRunner::GetCurrentDefault(), + /*enable_buffering=*/true); + EXPECT_THAT(player_manager, NotNull()); +} + +TEST_F(StarboardPlayerManagerTest, CreatesDrmSystemForEncryptedAudio) { + // SbDrmSystem is an opaque blob to cast, so its actual value does not matter. + // All that matters is its address (treated as void*). + int drm_system = 3; + EXPECT_CALL(starboard_, CreateDrmSystem).WillOnce(Return(&drm_system)); + EXPECT_CALL( + starboard_, + CreatePlayer( + Pointee(MatchesPlayerCreationParam(StarboardPlayerCreationParam{ + .drm_system = &drm_system, + .audio_sample_info = GetStarboardAudioConfig(), + .video_sample_info = GetStarboardVideoConfig(), + .output_mode = StarboardPlayerOutputMode:: + kStarboardPlayerOutputModePunchOut})), + _)) + .WillOnce(Return(&sb_player_)); + StarboardDrmWrapper::SetSingletonForTesting(&starboard_); + + // Only the audio stream is encrypted. + audio_stream_.set_audio_decoder_config( + GetChromiumAudioConfig(::media::EncryptionScheme::kCenc)); + video_stream_.set_video_decoder_config( + GetChromiumVideoConfig(::media::EncryptionScheme::kUnencrypted)); + + std::unique_ptr<StarboardPlayerManager> player_manager = + StarboardPlayerManager::Create( + &starboard_, &audio_stream_, &video_stream_, &renderer_client_, + base::SequencedTaskRunner::GetCurrentDefault(), + /*enable_buffering=*/true); + EXPECT_THAT(player_manager, NotNull()); +} + +TEST_F(StarboardPlayerManagerTest, CreatesDrmSystemForEncryptedVideo) { + // SbDrmSystem is an opaque blob to cast, so its actual value does not matter. + // All that matters is its address (treated as void*). + int drm_system = 3; + EXPECT_CALL(starboard_, CreateDrmSystem).WillOnce(Return(&drm_system)); + EXPECT_CALL( + starboard_, + CreatePlayer( + Pointee(MatchesPlayerCreationParam(StarboardPlayerCreationParam{ + .drm_system = &drm_system, + .audio_sample_info = GetStarboardAudioConfig(), + .video_sample_info = GetStarboardVideoConfig(), + .output_mode = StarboardPlayerOutputMode:: + kStarboardPlayerOutputModePunchOut})), + _)) + .WillOnce(Return(&sb_player_)); + StarboardDrmWrapper::SetSingletonForTesting(&starboard_); + + // Only the video stream is encrypted. + audio_stream_.set_audio_decoder_config( + GetChromiumAudioConfig(::media::EncryptionScheme::kUnencrypted)); + video_stream_.set_video_decoder_config( + GetChromiumVideoConfig(::media::EncryptionScheme::kCenc)); + + std::unique_ptr<StarboardPlayerManager> player_manager = + StarboardPlayerManager::Create( + &starboard_, &audio_stream_, &video_stream_, &renderer_client_, + base::SequencedTaskRunner::GetCurrentDefault(), + /*enable_buffering=*/true); + EXPECT_THAT(player_manager, NotNull()); +} + } // namespace } // namespace media } // namespace chromecast
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM index d05ef5b5..7e6db71 100644 --- a/chromeos/CHROMEOS_LKGM +++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@ -16314.0.0-1069484 \ No newline at end of file +16315.0.0-1069490 \ No newline at end of file
diff --git a/clank b/clank index 7a1ffc35..af5242e 160000 --- a/clank +++ b/clank
@@ -1 +1 @@ -Subproject commit 7a1ffc358fdcbfdc0be09cdf2b2462b7a5dc8cb2 +Subproject commit af5242eecbe2a033bcc8fcd7cbb89c09bf264dd8
diff --git a/components/autofill/android/BUILD.gn b/components/autofill/android/BUILD.gn index f1cc23c5..c4ee65e 100644 --- a/components/autofill/android/BUILD.gn +++ b/components/autofill/android/BUILD.gn
@@ -251,6 +251,7 @@ "java/src/org/chromium/components/autofill/AutofillSuggestion.java", "java/src/org/chromium/components/autofill/DropdownKeyValue.java", "java/src/org/chromium/components/autofill/LoyaltyCard.java", + "java/src/org/chromium/components/autofill/PaymentsPayload.java", "java/src/org/chromium/components/autofill/SubKeyRequester.java", ] srcjar_deps = [ @@ -269,6 +270,7 @@ "java/src/org/chromium/components/autofill/AutofillProfilePayload.java", "java/src/org/chromium/components/autofill/DropdownKeyValue.java", "java/src/org/chromium/components/autofill/LoyaltyCard.java", + "java/src/org/chromium/components/autofill/PaymentsPayload.java", "java/src/org/chromium/components/autofill/SubKeyRequester.java", ] }
diff --git a/components/autofill/android/java/src/org/chromium/components/autofill/AutofillSuggestion.java b/components/autofill/android/java/src/org/chromium/components/autofill/AutofillSuggestion.java index d41a2221..31ef394 100644 --- a/components/autofill/android/java/src/org/chromium/components/autofill/AutofillSuggestion.java +++ b/components/autofill/android/java/src/org/chromium/components/autofill/AutofillSuggestion.java
@@ -22,20 +22,16 @@ private final @Nullable String mSecondaryLabel; private final String mSublabel; private final @Nullable String mSecondarySublabel; - private final @Nullable String mLabelContentDescription; private final int mIconId; private final @SuggestionType int mSuggestionType; private final boolean mIsDeletable; private final boolean mApplyDeactivatedStyle; - private final boolean mShouldDisplayTermsAvailable; private final @Nullable String mFeatureForIph; private final @Nullable String mIphDescriptionText; private final @Nullable GURL mCustomIconUrl; - private final @Nullable String mGuid; - private final boolean mIsLocalPaymentsMethod; private final @Nullable Payload mPayload; - public static sealed interface Payload permits AutofillProfilePayload {} + public static sealed interface Payload permits AutofillProfilePayload, PaymentsPayload {} /** * Constructs a Autofill suggestion container. Use the {@link AutofillSuggestion.Builder} @@ -48,13 +44,9 @@ * @param popupItemId The type of suggestion. * @param isDeletable Whether the item can be deleted by the user. * @param applyDeactivatedStyle Whether to apply deactivated style to the suggestion. - * @param shouldDisplayTermsAvailable Whether the terms message is displayed. * @param featureForIph The IPH feature for the autofill suggestion. If present, it'll be * attempted to be shown in the keyboard accessory. * @param customIconUrl The {@link GURL} for the custom icon, if any. - * @param guid The payment method identifier associated with the suggestion. - * @param isLocalPaymentsMethod Whether the payments method associated with the suggestion is - * local. * @param payload Additional data passed with the suggestion. Currently only * AutofillProfilePayload may passed. New payloads can be added by implementing the {@link * AutofillSuggestion.Payload} interface. @@ -65,33 +57,25 @@ @Nullable String secondaryLabel, String sublabel, @Nullable String secondarySublabel, - @Nullable String labelContentDescription, int iconId, @SuggestionType int popupItemId, boolean isDeletable, boolean applyDeactivatedStyle, - boolean shouldDisplayTermsAvailable, @Nullable String featureForIph, @Nullable String iphDescriptionText, @Nullable GURL customIconUrl, - @Nullable String guid, - boolean isLocalPaymentsMethod, @Nullable Payload payload) { mLabel = label; mSecondaryLabel = secondaryLabel; mSublabel = sublabel; mSecondarySublabel = secondarySublabel; - mLabelContentDescription = labelContentDescription; mIconId = iconId; mSuggestionType = popupItemId; mIsDeletable = isDeletable; mApplyDeactivatedStyle = applyDeactivatedStyle; - mShouldDisplayTermsAvailable = shouldDisplayTermsAvailable; mFeatureForIph = featureForIph; mIphDescriptionText = iphDescriptionText; mCustomIconUrl = customIconUrl; - mGuid = guid; - mIsLocalPaymentsMethod = isLocalPaymentsMethod; mPayload = payload; } @@ -133,22 +117,10 @@ return mCustomIconUrl; } - public @Nullable String getLabelContentDescription() { - return mLabelContentDescription; - } - public @SuggestionType int getSuggestionType() { return mSuggestionType; } - public @Nullable String getGuid() { - return mGuid; - } - - public boolean isLocalPaymentsMethod() { - return mIsLocalPaymentsMethod; - } - public boolean isDeletable() { return mIsDeletable; } @@ -162,10 +134,6 @@ return mApplyDeactivatedStyle; } - public boolean shouldDisplayTermsAvailable() { - return mShouldDisplayTermsAvailable; - } - public @Nullable String getFeatureForIph() { return mFeatureForIph; } @@ -191,17 +159,13 @@ && Objects.equals(this.mSecondaryLabel, other.mSecondaryLabel) && this.mSublabel.equals(other.mSublabel) && Objects.equals(this.mSecondarySublabel, other.mSecondarySublabel) - && Objects.equals(this.mLabelContentDescription, other.mLabelContentDescription) && this.mIconId == other.mIconId && this.mSuggestionType == other.mSuggestionType && this.mIsDeletable == other.mIsDeletable && this.mApplyDeactivatedStyle == other.mApplyDeactivatedStyle - && this.mShouldDisplayTermsAvailable == other.mShouldDisplayTermsAvailable && Objects.equals(this.mFeatureForIph, other.mFeatureForIph) && Objects.equals(this.mIphDescriptionText, other.mIphDescriptionText) && Objects.equals(this.mCustomIconUrl, other.mCustomIconUrl) - && Objects.equals(this.mGuid, other.mGuid) - && this.mIsLocalPaymentsMethod == other.mIsLocalPaymentsMethod && Objects.equals(this.mPayload, other.mPayload); } @@ -211,17 +175,13 @@ private @Nullable GURL mCustomIconUrl; private boolean mIsDeletable; private boolean mApplyDeactivatedStyle; - private boolean mShouldDisplayTermsAvailable; private @Nullable String mFeatureForIph; private @Nullable String mIphDescriptionText; private @Nullable String mLabel; private @Nullable String mSecondaryLabel; private @Nullable String mSubLabel; private @Nullable String mSecondarySubLabel; - private @Nullable String mLabelContentDescription; private int mSuggestionType; - private @Nullable String mGuid; - private boolean mIsLocalPaymentsMethod; private @Nullable Payload mPayload; public Builder setIconId(int iconId) { @@ -244,11 +204,6 @@ return this; } - public Builder setShouldDisplayTermsAvailable(boolean shouldDisplayTermsAvailable) { - this.mShouldDisplayTermsAvailable = shouldDisplayTermsAvailable; - return this; - } - public Builder setFeatureForIph(String featureForIph) { this.mFeatureForIph = featureForIph; return this; @@ -279,26 +234,11 @@ return this; } - public Builder setLabelContentDescription(String labelContentDescription) { - this.mLabelContentDescription = labelContentDescription; - return this; - } - public Builder setSuggestionType(int popupItemId) { this.mSuggestionType = popupItemId; return this; } - public Builder setGuid(String guid) { - this.mGuid = guid; - return this; - } - - public Builder setIsLocalPaymentsMethod(boolean isLocalPaymentsMethod) { - this.mIsLocalPaymentsMethod = isLocalPaymentsMethod; - return this; - } - public Builder setPayload(Payload payload) { this.mPayload = payload; return this; @@ -314,17 +254,13 @@ mSecondaryLabel, mSubLabel, mSecondarySubLabel, - mLabelContentDescription, mIconId, mSuggestionType, mIsDeletable, mApplyDeactivatedStyle, - mShouldDisplayTermsAvailable, mFeatureForIph, mIphDescriptionText, mCustomIconUrl, - mGuid, - mIsLocalPaymentsMethod, mPayload); } }
diff --git a/components/autofill/android/java/src/org/chromium/components/autofill/PaymentsPayload.java b/components/autofill/android/java/src/org/chromium/components/autofill/PaymentsPayload.java new file mode 100644 index 0000000..e404302 --- /dev/null +++ b/components/autofill/android/java/src/org/chromium/components/autofill/PaymentsPayload.java
@@ -0,0 +1,60 @@ +// Copyright 2025 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.components.autofill; + +import org.jni_zero.CalledByNative; +import org.jni_zero.JNINamespace; +import org.jni_zero.JniType; + +import org.chromium.build.annotations.NullMarked; +import org.chromium.components.autofill.AutofillSuggestion.Payload; + +@JNINamespace("autofill") +@NullMarked +public final class PaymentsPayload implements Payload { + private final String mLabelContentDescription; + private final boolean mShouldDisplayTermsAvailable; + private final String mGuid; + private final boolean mIsLocalPaymentsMethod; + + /** + * Constructs a payload object for the TouchToFillPaymentMethod bottom sheet. + * + * @param labelContentDescription Accessibility content description for the main text in the + * bottom sheet. This description is used by accessibility services like screen readers to + * interpret the content for users. + * @param shouldDisplayTermsAvailable Whether the terms message is displayed. + * @param guid The payment method identifier associated with the suggestion. + * @param isLocalPaymentsMethod Whether the payments method associated with the suggestion is + * local. + */ + @CalledByNative + public PaymentsPayload( + @JniType("std::u16string") String labelContentDescription, + boolean shouldDisplayTermsAvailable, + @JniType("std::string") String guid, + boolean isLocalPaymentsMethod) { + mLabelContentDescription = labelContentDescription; + mShouldDisplayTermsAvailable = shouldDisplayTermsAvailable; + mGuid = guid; + mIsLocalPaymentsMethod = isLocalPaymentsMethod; + } + + public String getLabelContentDescription() { + return mLabelContentDescription; + } + + public boolean shouldDisplayTermsAvailable() { + return mShouldDisplayTermsAvailable; + } + + public String getGuid() { + return mGuid; + } + + public boolean isLocalPaymentsMethod() { + return mIsLocalPaymentsMethod; + } +}
diff --git a/components/autofill/core/browser/DEPS b/components/autofill/core/browser/DEPS index 6fc41405c..32a419bc 100644 --- a/components/autofill/core/browser/DEPS +++ b/components/autofill/core/browser/DEPS
@@ -33,9 +33,9 @@ "+components/version_info", "+components/webdata/common", "+components/webdata_services", + "+crypto/hash.h", "+crypto/hkdf.h", "+crypto/random.h", - "+crypto/sha2.h", "+google_apis/common", "+google_apis/gaia", "+google_apis/google_api_keys.h",
diff --git a/components/autofill/core/browser/studies/autofill_ablation_study.cc b/components/autofill/core/browser/studies/autofill_ablation_study.cc index 0de075e..661e7f54 100644 --- a/components/autofill/core/browser/studies/autofill_ablation_study.cc +++ b/components/autofill/core/browser/studies/autofill_ablation_study.cc
@@ -8,7 +8,6 @@ #include "base/check_op.h" #include "base/command_line.h" #include "base/containers/span.h" -#include "base/hash/md5.h" #include "base/memory/ptr_util.h" #include "base/metrics/field_trial.h" #include "base/no_destructor.h" @@ -24,6 +23,7 @@ #include "components/autofill/core/common/autofill_prefs.h" #include "components/optimization_guide/proto/hints.pb.h" #include "components/prefs/pref_service.h" +#include "crypto/hash.h" #include "third_party/icu/source/i18n/unicode/timezone.h" #include "url/gurl.h" #include "url/origin.h" @@ -50,14 +50,9 @@ namespace { -// Number of bytes that we use to randomly seed the MD5Sum. +// Number of bytes that we use to randomly seed the hash. constexpr size_t kSeedLengthInBytes = 8; -// Converts the 8-byte prefix of an MD5 hash into a uint64_t value. -inline uint64_t DigestToUInt64(const base::MD5Digest& digest) { - return base::U64FromBigEndian(base::span(digest.a).first<8u>()); -} - // Returns the ablation seed from prefs and creates one if that has not happened // before. std::string GetSeed(PrefService* pref_service) { @@ -107,14 +102,11 @@ uint64_t GetAblationHash(const std::string& seed, const GURL& url, base::Time now) { - // Derive a random number from |seed|, |url|'s security origin and today's - // date. - base::MD5Context ctx; - base::MD5Init(&ctx); + crypto::hash::Hasher hasher(crypto::hash::kSha256); // Incorporate |seed| into the MD5Sum. This ensures that on each browser // start the behavior is shuffled. - base::MD5Update(&ctx, seed); + hasher.Update(seed); // Incorporate |url|'s security origin into the MD5Sum. This ensures that // different sites can have different behavior but the behavior on a single @@ -125,18 +117,18 @@ // so that individual users don't experience an excessive amount of ablation // cases. url::Origin origin = url::Origin::Create(url); - base::MD5Update(&ctx, origin.Serialize()); + hasher.Update(origin.Serialize()); // Incorporate the date into MD5Sum. This ensures that the behavior stays the // same during a `kAblationWindowInDays` period but changes afterwards. int days_since_epoch = DaysSinceLocalWindowsEpoch(now); int day_window = days_since_epoch / kAblationWindowInDays; - base::MD5Update(&ctx, base::NumberToString(day_window)); + hasher.Update(base::NumberToString(day_window)); // Derive 64 bit hash. - base::MD5Digest digest; - base::MD5Final(&digest, &ctx); - return DigestToUInt64(digest); + std::array<uint8_t, crypto::hash::kSha256Size> hash; + hasher.Finish(hash); + return base::U64FromBigEndian(base::span(hash).first<sizeof(uint64_t)>()); } int GetDayInAblationWindow(base::Time now) {
diff --git a/components/autofill/core/browser/studies/autofill_experiments.cc b/components/autofill/core/browser/studies/autofill_experiments.cc index 5029de2a..56c1b22 100644 --- a/components/autofill/core/browser/studies/autofill_experiments.cc +++ b/components/autofill/core/browser/studies/autofill_experiments.cc
@@ -43,7 +43,7 @@ #include "components/sync/service/sync_service_utils.h" #include "components/sync/service/sync_user_settings.h" #include "components/variations/variations_associated_data.h" -#include "crypto/sha2.h" +#include "crypto/hash.h" #include "google_apis/gaia/gaia_auth_util.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/ui_base_features.h" @@ -299,7 +299,7 @@ // Get the hash of the account id. std::string account_hash = - base::Base64Encode(crypto::SHA256HashString(account_id.ToString())); + base::Base64Encode(crypto::hash::Sha256(account_id.ToString())); // Return whether the wallet opt-in bit is set. return GetSyncTransportOptInBitFieldForAccount(prefs, account_hash) & @@ -314,7 +314,7 @@ // obfuscation. The primary privacy guarantees are handled by clearing this // whenever cookies are cleared. std::string account_hash = - base::Base64Encode(crypto::SHA256HashString(account_id.ToString())); + base::Base64Encode(crypto::hash::Sha256(account_id.ToString())); ScopedDictPrefUpdate update(prefs, prefs::kAutofillSyncTransportOptIn); int value = GetSyncTransportOptInBitFieldForAccount(prefs, account_hash);
diff --git a/components/autofill/core/browser/suggestions/suggestion.cc b/components/autofill/core/browser/suggestions/suggestion.cc index 7e797cd6..d5ae5e13 100644 --- a/components/autofill/core/browser/suggestions/suggestion.cc +++ b/components/autofill/core/browser/suggestions/suggestion.cc
@@ -18,6 +18,7 @@ #include "base/android/jni_android.h" #include "base/android/jni_string.h" #include "components/autofill/android/main_autofill_jni_headers/AutofillProfilePayload_jni.h" +#include "components/autofill/android/main_autofill_jni_headers/PaymentsPayload_jni.h" #endif // BUILDFLAG(IS_ANDROID) namespace autofill { @@ -300,6 +301,16 @@ Suggestion::PaymentsPayload::~PaymentsPayload() = default; +#if BUILDFLAG(IS_ANDROID) +base::android::ScopedJavaLocalRef<jobject> +Suggestion::PaymentsPayload::CreateJavaObject() const { + JNIEnv* env = base::android::AttachCurrentThread(); + return Java_PaymentsPayload_Constructor( + env, main_text_content_description, should_display_terms_available, + guid.value(), is_local_payments_method); +} +#endif // BUILDFLAG(IS_ANDROID) + Suggestion::IPHMetadata::IPHMetadata() = default; Suggestion::IPHMetadata::IPHMetadata(const base::Feature* feature,
diff --git a/components/autofill/core/browser/suggestions/suggestion.h b/components/autofill/core/browser/suggestions/suggestion.h index 270b9e9..127a919 100644 --- a/components/autofill/core/browser/suggestions/suggestion.h +++ b/components/autofill/core/browser/suggestions/suggestion.h
@@ -115,6 +115,10 @@ PaymentsPayload& operator=(PaymentsPayload&&); ~PaymentsPayload(); +#if BUILDFLAG(IS_ANDROID) + base::android::ScopedJavaLocalRef<jobject> CreateJavaObject() const; +#endif // BUILDFLAG(IS_ANDROID) + friend bool operator==(const PaymentsPayload&, const PaymentsPayload&) = default;
diff --git a/components/autofill/core/browser/ui/payments/save_and_fill_dialog_controller.h b/components/autofill/core/browser/ui/payments/save_and_fill_dialog_controller.h index f0adaf7..9056c39 100644 --- a/components/autofill/core/browser/ui/payments/save_and_fill_dialog_controller.h +++ b/components/autofill/core/browser/ui/payments/save_and_fill_dialog_controller.h
@@ -20,7 +20,10 @@ virtual std::u16string GetCardNumberLabel() const = 0; virtual std::u16string GetNameOnCardLabel() const = 0; virtual std::u16string GetAcceptButtonText() const = 0; + virtual std::u16string GetInvalidCardNumberErrorMessage() const = 0; virtual bool IsUploadSaveAndFill() const = 0; + virtual bool IsValidCreditCardNumber( + std::u16string_view input_text) const = 0; virtual base::WeakPtr<SaveAndFillDialogController> GetWeakPtr() = 0; };
diff --git a/components/autofill/core/browser/ui/payments/save_and_fill_dialog_controller_impl.cc b/components/autofill/core/browser/ui/payments/save_and_fill_dialog_controller_impl.cc index ab3f7d6..79b2148d 100644 --- a/components/autofill/core/browser/ui/payments/save_and_fill_dialog_controller_impl.cc +++ b/components/autofill/core/browser/ui/payments/save_and_fill_dialog_controller_impl.cc
@@ -6,6 +6,7 @@ #include "base/memory/weak_ptr.h" #include "base/strings/utf_string_conversions.h" +#include "components/autofill/core/common/credit_card_number_validation.h" #include "components/strings/grit/components_strings.h" #include "ui/base/l10n/l10n_util.h" @@ -46,12 +47,23 @@ std::u16string SaveAndFillDialogControllerImpl::GetAcceptButtonText() const { return l10n_util::GetStringUTF16(IDS_AUTOFILL_SAVE_AND_FILL_DIALOG_ACCEPT); } + +std::u16string +SaveAndFillDialogControllerImpl::GetInvalidCardNumberErrorMessage() const { + return l10n_util::GetStringUTF16( + IDS_AUTOFILL_SAVE_AND_FILL_DIALOG_INVALID_CARD_NUMBER); +} #endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) bool SaveAndFillDialogControllerImpl::IsUploadSaveAndFill() const { return is_upload_save_and_fill_; } +bool SaveAndFillDialogControllerImpl::IsValidCreditCardNumber( + std::u16string_view input_text) const { + return autofill::IsValidCreditCardNumber(input_text); +} + base::WeakPtr<SaveAndFillDialogController> SaveAndFillDialogControllerImpl::GetWeakPtr() { return weak_ptr_factory_.GetWeakPtr();
diff --git a/components/autofill/core/browser/ui/payments/save_and_fill_dialog_controller_impl.h b/components/autofill/core/browser/ui/payments/save_and_fill_dialog_controller_impl.h index 74126e4..80c9301c 100644 --- a/components/autofill/core/browser/ui/payments/save_and_fill_dialog_controller_impl.h +++ b/components/autofill/core/browser/ui/payments/save_and_fill_dialog_controller_impl.h
@@ -33,8 +33,10 @@ std::u16string GetCardNumberLabel() const override; std::u16string GetNameOnCardLabel() const override; std::u16string GetAcceptButtonText() const override; + std::u16string GetInvalidCardNumberErrorMessage() const override; #endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) bool IsUploadSaveAndFill() const override; + bool IsValidCreditCardNumber(std::u16string_view input_text) const override; base::WeakPtr<SaveAndFillDialogController> GetWeakPtr() override;
diff --git a/components/autofill/core/browser/webdata/addresses/contact_info_sync_bridge.cc b/components/autofill/core/browser/webdata/addresses/contact_info_sync_bridge.cc index 16b39e8..3a55e33 100644 --- a/components/autofill/core/browser/webdata/addresses/contact_info_sync_bridge.cc +++ b/components/autofill/core/browser/webdata/addresses/contact_info_sync_bridge.cc
@@ -7,10 +7,13 @@ #include <algorithm> #include "base/check.h" +#include "base/metrics/histogram_functions.h" #include "base/uuid.h" #include "components/autofill/core/browser/data_model/addresses/autofill_profile.h" +#include "components/autofill/core/browser/data_quality/addresses/profile_requirement_utils.h" #include "components/autofill/core/browser/webdata/addresses/contact_info_sync_util.h" #include "components/autofill/core/browser/webdata/autofill_webdata_service.h" +#include "components/autofill/core/common/autofill_features.h" #include "components/autofill/core/common/dense_set.h" #include "components/sync/base/data_type.h" #include "components/sync/base/deletion_origin.h" @@ -34,6 +37,23 @@ AutofillProfile::RecordType::kAccountHome, AutofillProfile::RecordType::kAccountWork}; +// H/W addresses need to meet Autofill's completeness requirements since they +// are read from a source that doesn't enforce them. +// This is not checked as part of the bridge's IsEntityDataValid(), since H/W +// addresses that fail to meet the requirements after an update need to be +// removed from local storage. +bool IsIncompleteHomeAndWorkAddress(const AutofillProfile& profile) { + if (!profile.IsHomeAndWorkProfile() || + !base::FeatureList::IsEnabled( + features::kAutofillEnableSupportForHomeAndWork)) { + return false; + } + const bool is_incomplete = !IsMinimumAddress(profile); + base::UmaHistogramBoolean("Autofill.HomeWorkProfiles.ProfileFiltered", + is_incomplete); + return is_incomplete; +} + } // namespace ContactInfoSyncBridge::ContactInfoSyncBridge( @@ -117,6 +137,17 @@ DCHECK(change->data().specifics.has_contact_info()); AutofillProfile remote = CreateAutofillProfileFromContactInfoSpecifics( change->data().specifics.contact_info()); + if (IsIncompleteHomeAndWorkAddress(remote)) { + // In case H/W was updated and doesn't meet the completeness + // requirements anymore, remove it. + // This change doesn't need to be synced back, since H/W is read-only. + metadata_change_list->ClearMetadata(remote.guid()); + if (!GetAutofillTable()->RemoveAutofillProfile(remote.guid())) { + return syncer::ModelError(FROM_HERE, + "Failed to delete profile from table."); + } + continue; + } // Since the distinction between adds and updates is not always clear, // we check the existence of the profile manually and act accordingly. // TODO(crbug.com/40100455): Consider adding an AddOrUpdate() function
diff --git a/components/autofill/core/browser/webdata/addresses/contact_info_sync_bridge_unittest.cc b/components/autofill/core/browser/webdata/addresses/contact_info_sync_bridge_unittest.cc index 6058119..949d6d5 100644 --- a/components/autofill/core/browser/webdata/addresses/contact_info_sync_bridge_unittest.cc +++ b/components/autofill/core/browser/webdata/addresses/contact_info_sync_bridge_unittest.cc
@@ -10,15 +10,18 @@ #include "base/files/scoped_temp_dir.h" #include "base/run_loop.h" #include "base/test/bind.h" +#include "base/test/metrics/histogram_tester.h" #include "base/test/scoped_feature_list.h" #include "base/test/task_environment.h" #include "components/autofill/core/browser/data_model/addresses/autofill_profile.h" #include "components/autofill/core/browser/data_model/addresses/autofill_profile_test_api.h" +#include "components/autofill/core/browser/test_utils/autofill_test_utils.h" #include "components/autofill/core/browser/test_utils/test_autofill_clock.h" #include "components/autofill/core/browser/webdata/addresses/address_autofill_table.h" #include "components/autofill/core/browser/webdata/addresses/contact_info_sync_util.h" #include "components/autofill/core/browser/webdata/autofill_sync_metadata_table.h" #include "components/autofill/core/browser/webdata/mock_autofill_webdata_backend.h" +#include "components/autofill/core/common/autofill_features.h" #include "components/sync/base/features.h" #include "components/sync/model/data_batch.h" #include "components/sync/test/mock_data_type_local_change_processor.h" @@ -264,6 +267,37 @@ profile.usage_history().modification_date()); } +// Tests that incomplete Home and Work addresses are dropped and removed from +// local storage, if necessary. +TEST_F(ContactInfoSyncBridgeTest, + ApplyIncrementalSyncChanges_HomeAndWorkCompleteness) { + base::test::ScopedFeatureList feature( + features::kAutofillEnableSupportForHomeAndWork); + AutofillProfile remote = test::GetFullProfile(); + test_api(remote).set_record_type(AutofillProfile::RecordType::kAccountHome); + base::HistogramTester histogram_tester; + ASSERT_TRUE(StartSyncing({remote})); + + // Since `remote` is a complete H/W profile, expect it in local storage. + histogram_tester.ExpectUniqueSample( + "Autofill.HomeWorkProfiles.ProfileFiltered", false, 1); + EXPECT_THAT(GetAllDataFromTable(), ElementsAre(remote)); + + // Receive an update for remote that makes it incomplete. + remote.ClearFields({ADDRESS_HOME_CITY}); + syncer::EntityChangeList entity_change_list; + entity_change_list.push_back(syncer::EntityChange::CreateUpdate( + remote.guid(), ProfileToEntity(remote))); + EXPECT_FALSE(bridge().ApplyIncrementalSyncChanges( + bridge().CreateMetadataChangeList(), std::move(entity_change_list))); + + // Expect that the profile was removed locally. + EXPECT_THAT(histogram_tester.GetAllSamples( + "Autofill.HomeWorkProfiles.ProfileFiltered"), + BucketsAre(base::Bucket(false, 1), base::Bucket(true, 1))); + EXPECT_THAT(GetAllDataFromTable(), testing::IsEmpty()); +} + // Tests that `GetDataForCommit()` returns all local profiles of matching GUID. TEST_F(ContactInfoSyncBridgeTest, GetDataForCommit) { const AutofillProfile profile1 = TestProfile(kGUID1);
diff --git a/components/autofill/core/browser/webdata/addresses/contact_info_sync_util.cc b/components/autofill/core/browser/webdata/addresses/contact_info_sync_util.cc index 35f6ad41..f3812c6 100644 --- a/components/autofill/core/browser/webdata/addresses/contact_info_sync_util.cc +++ b/components/autofill/core/browser/webdata/addresses/contact_info_sync_util.cc
@@ -7,12 +7,10 @@ #include "base/feature_list.h" #include "base/hash/hash.h" #include "base/memory/raw_ref.h" -#include "base/metrics/histogram_functions.h" #include "base/strings/utf_string_conversions.h" #include "base/time/time.h" #include "base/uuid.h" #include "components/autofill/core/browser/country_type.h" -#include "components/autofill/core/browser/data_quality/addresses/profile_requirement_utils.h" #include "components/autofill/core/browser/data_quality/addresses/profile_token_quality.h" #include "components/autofill/core/browser/field_types.h" #include "components/autofill/core/browser/geo/country_names.h" @@ -437,26 +435,7 @@ bool AreContactInfoSpecificsValid( const sync_pb::ContactInfoSpecifics& specifics) { - if (!base::Uuid::ParseLowercase(specifics.guid()).is_valid()) { - return false; - } - - if (specifics.address_type() == sync_pb::ContactInfoSpecifics::REGULAR) { - return true; - } - - // H/W addresses need to meet Autofill's completeness requirements since they - // are read from a source that doesn't enforce them. - if (base::FeatureList::IsEnabled( - features::kAutofillEnableSupportForHomeAndWork)) { - const bool is_minimum_address = IsMinimumAddress( - CreateAutofillProfileFromContactInfoSpecifics(specifics)); - base::UmaHistogramBoolean("Autofill.HomeWorkProfiles.ProfileFiltered", - is_minimum_address); - return is_minimum_address; - } - - return false; + return base::Uuid::ParseLowercase(specifics.guid()).is_valid(); } sync_pb::ContactInfoSpecifics TrimContactInfoSpecificsDataForCaching(
diff --git a/components/autofill/core/browser/webdata/addresses/contact_info_sync_util_unittest.cc b/components/autofill/core/browser/webdata/addresses/contact_info_sync_util_unittest.cc index 8aff649d..efa59bf1 100644 --- a/components/autofill/core/browser/webdata/addresses/contact_info_sync_util_unittest.cc +++ b/components/autofill/core/browser/webdata/addresses/contact_info_sync_util_unittest.cc
@@ -7,7 +7,6 @@ #include "base/feature_list.h" #include "base/hash/hash.h" #include "base/strings/to_string.h" -#include "base/test/metrics/histogram_tester.h" #include "base/test/scoped_feature_list.h" #include "components/autofill/core/browser/country_type.h" #include "components/autofill/core/browser/data_model/addresses/autofill_profile_test_api.h" @@ -901,7 +900,7 @@ } // Tests that specifics without valid GUIDs are rejected. -TEST_F(ContactInfoSyncUtilTest, AreContactInfoSpecificsValid_GUID) { +TEST_F(ContactInfoSyncUtilTest, AreContactInfoSpecificsValid) { ContactInfoSpecifics specifics; specifics.set_guid(kInvalidGuid); EXPECT_FALSE(AreContactInfoSpecificsValid(specifics)); @@ -909,37 +908,6 @@ EXPECT_TRUE(AreContactInfoSpecificsValid(specifics)); } -// Tests that for H/W addresses, minimum address requirements need to be met. -TEST_F(ContactInfoSyncUtilTest, AreContactInfoSpecificsValid_Completeness) { - base::test::ScopedFeatureList feature( - features::kAutofillEnableSupportForHomeAndWork); - - base::HistogramTester histogram_tester; - - ContactInfoSpecifics specifics = ConstructBaseSpecifics(); - EXPECT_TRUE(AreContactInfoSpecificsValid(specifics)); - specifics.set_address_type(ContactInfoSpecifics::HOME); - EXPECT_TRUE(AreContactInfoSpecificsValid(specifics)); - specifics.set_address_type(ContactInfoSpecifics::WORK); - EXPECT_TRUE(AreContactInfoSpecificsValid(specifics)); - - EXPECT_THAT(histogram_tester.GetAllSamples( - "Autofill.HomeWorkProfiles.ProfileFiltered"), - BucketsAre(base::Bucket(false, 0), base::Bucket(true, 2))); - - specifics.clear_address_city(); - specifics.set_address_type(ContactInfoSpecifics::REGULAR); - EXPECT_TRUE(AreContactInfoSpecificsValid(specifics)); - specifics.set_address_type(ContactInfoSpecifics::HOME); - EXPECT_FALSE(AreContactInfoSpecificsValid(specifics)); - specifics.set_address_type(ContactInfoSpecifics::HOME); - EXPECT_FALSE(AreContactInfoSpecificsValid(specifics)); - - EXPECT_THAT(histogram_tester.GetAllSamples( - "Autofill.HomeWorkProfiles.ProfileFiltered"), - BucketsAre(base::Bucket(false, 2), base::Bucket(true, 2))); -} - // Tests that if a token's `value` changes by external means, its observations // are reset. TEST_F(ContactInfoSyncUtilTest, ObservationResetting) {
diff --git a/components/autofill/ios/common/features.h b/components/autofill/ios/common/features.h index 06e0a1b..589101cb 100644 --- a/components/autofill/ios/common/features.h +++ b/components/autofill/ios/common/features.h
@@ -41,6 +41,10 @@ // enabled. BASE_DECLARE_FEATURE(kAutofillFixXhrForXframe); +// Listen to form submission events in capture mode before the events are +// propagated. +BASE_DECLARE_FEATURE(kAutofillFormSubmissionEventsInCaptureMode); + // Controls whether to use the isolated content world instead of the page // content world for the Autofill JS feature scripts. // TODO(crbug.com/40747550) Remove once the isolated content world is launched
diff --git a/components/autofill/ios/common/features.mm b/components/autofill/ios/common/features.mm index aac05d8..41c5adee 100644 --- a/components/autofill/ios/common/features.mm +++ b/components/autofill/ios/common/features.mm
@@ -42,6 +42,10 @@ "AutofillFixXhrForXframe", base::FEATURE_DISABLED_BY_DEFAULT); +BASE_FEATURE(kAutofillFormSubmissionEventsInCaptureMode, + "AutofillFormSubmissionEventsInCaptureMode", + base::FEATURE_DISABLED_BY_DEFAULT); + // LINT.IfChange(autofill_isolated_content_world) BASE_FEATURE(kAutofillIsolatedWorldForJavascriptIos, "AutofillIsolatedWorldForJavascriptIos",
diff --git a/components/autofill/ios/form_util/form_handlers_java_script_feature.mm b/components/autofill/ios/form_util/form_handlers_java_script_feature.mm index b792d71..ddfa5087 100644 --- a/components/autofill/ios/form_util/form_handlers_java_script_feature.mm +++ b/components/autofill/ios/form_util/form_handlers_java_script_feature.mm
@@ -4,6 +4,7 @@ #import "components/autofill/ios/form_util/form_handlers_java_script_feature.h" +#import "base/feature_list.h" #import "base/no_destructor.h" #import "base/values.h" #import "components/autofill/core/common/autofill_features.h" @@ -14,6 +15,7 @@ #import "components/autofill/ios/form_util/form_activity_tab_helper.h" #import "components/autofill/ios/form_util/form_util_java_script_feature.h" #import "components/autofill/ios/form_util/remote_frame_registration_java_script_feature.h" +#import "ios/web/public/js_messaging/java_script_feature.h" #import "ios/web/public/js_messaging/java_script_feature_util.h" #import "ios/web/public/js_messaging/script_message.h" @@ -29,10 +31,23 @@ std::vector<web::JavaScriptFeature::FeatureScript> GetFeatureScripts() { std::vector<FeatureScript> feature_scripts; + auto placeholder_replacements_callback = base::BindRepeating( + []() -> web::JavaScriptFeature::FeatureScript::PlaceholderReplacements { + // Override the placeholder for setting the capture mode of the form + // submission listener. + bool use_capture = base::FeatureList::IsEnabled( + kAutofillFormSubmissionEventsInCaptureMode); + return @{ + @"{{PlaceholderFormSubmissionListenerCapture}}" : + use_capture ? @"true" : @"false" + }; + }); + feature_scripts.push_back(FeatureScript::CreateWithFilename( kFormHandlerScriptName, FeatureScript::InjectionTime::kDocumentStart, FeatureScript::TargetFrames::kAllFrames, - FeatureScript::ReinjectionBehavior::kReinjectOnDocumentRecreation)); + FeatureScript::ReinjectionBehavior::kReinjectOnDocumentRecreation, + placeholder_replacements_callback)); if (base::FeatureList::IsEnabled(kAutofillIsolatedWorldForJavascriptIos)) { feature_scripts.push_back(FeatureScript::CreateWithFilename(
diff --git a/components/autofill/ios/form_util/resources/form_handlers.ts b/components/autofill/ios/form_util/resources/form_handlers.ts index 7265f58e..d087a66 100644 --- a/components/autofill/ios/form_util/resources/form_handlers.ts +++ b/components/autofill/ios/form_util/resources/form_handlers.ts
@@ -61,6 +61,30 @@ */ let formMsgBatchMetadata: FormMsgBatchMetadata = {dropCount: 0}; +/** + * Parses a string to a boolean. + * @param boolStr The string to parse as a boolean. + * @returns The boolean value if parsing worked, null otherwise. + */ +function stringAsBool(boolStr: string): boolean | null { + switch (boolStr) { + case 'true': + return true; + case 'false': + return false; + default: + return null; + } +} + +/** + * Returns true if form submission events should be listened to in capture mode. + */ +function shouldListenToFormSubmissionEventsInCaptureMode(): boolean { + // Interpolate the placeholder and parse its string content to the desired + // boolean value. It is an error to not be able to parse the placeholder. + return stringAsBool('{{PlaceholderFormSubmissionListenerCapture}}')!; +} /** * Schedule `mesg` to be sent on next runloop. @@ -254,7 +278,9 @@ * practice and it is less obtrusive to page scripts than capture phase. */ document.addEventListener('keyup', formActivity, false); - document.addEventListener('submit', submitHandler, false); + document.addEventListener( + 'submit', submitHandler, + shouldListenToFormSubmissionEventsInCaptureMode()); /** * Receipt of cross-frame messages for Child Frame Registration don't use the @@ -291,7 +317,7 @@ attachListeners(); // Initial page loading can remove the listeners. Schedule a reattach after page -// build. +// build. This won't double attach listeners. setTimeout(attachListeners, 1000); /**
diff --git a/components/autofill_payments_strings.grdp b/components/autofill_payments_strings.grdp index f07cb97..39618d8 100644 --- a/components/autofill_payments_strings.grdp +++ b/components/autofill_payments_strings.grdp
@@ -274,6 +274,9 @@ <message name="IDS_AUTOFILL_SAVE_AND_FILL_DIALOG_ACCEPT" desc="Text to show for the Autofill Save and Fill dialog accept button."> Save and autofill </message> + <message name="IDS_AUTOFILL_SAVE_AND_FILL_DIALOG_INVALID_CARD_NUMBER" desc="Error message to show when a user has input an invalid card number."> + Card number is invalid + </message> </if> <!-- Autofill error dialog related strings -->
diff --git a/components/autofill_payments_strings_grdp/IDS_AUTOFILL_SAVE_AND_FILL_DIALOG_INVALID_CARD_NUMBER.png.sha1 b/components/autofill_payments_strings_grdp/IDS_AUTOFILL_SAVE_AND_FILL_DIALOG_INVALID_CARD_NUMBER.png.sha1 new file mode 100644 index 0000000..6c530df --- /dev/null +++ b/components/autofill_payments_strings_grdp/IDS_AUTOFILL_SAVE_AND_FILL_DIALOG_INVALID_CARD_NUMBER.png.sha1
@@ -0,0 +1 @@ +4abbbe172fbb2c5bff3fa7dc3911fc0655527fa0 \ No newline at end of file
diff --git a/components/browser_ui/contacts_picker/android/java/src/org/chromium/components/browser_ui/contacts_picker/ContactsFetcherWorkerTask.java b/components/browser_ui/contacts_picker/android/java/src/org/chromium/components/browser_ui/contacts_picker/ContactsFetcherWorkerTask.java index 5bfd52f..1bf358d1 100644 --- a/components/browser_ui/contacts_picker/android/java/src/org/chromium/components/browser_ui/contacts_picker/ContactsFetcherWorkerTask.java +++ b/components/browser_ui/contacts_picker/android/java/src/org/chromium/components/browser_ui/contacts_picker/ContactsFetcherWorkerTask.java
@@ -111,7 +111,7 @@ */ private Map<String, ArrayList<String>> getDetails( Uri source, String idColumn, String dataColumn, String sortOrder) { - Map<String, ArrayList<String>> map = new HashMap<String, ArrayList<String>>(); + Map<String, ArrayList<String>> map = new HashMap<>(); Cursor cursor = mContentResolver.query(source, null, null, null, sortOrder); ArrayList<String> list = new ArrayList<>();
diff --git a/components/browser_ui/media/android/java/src/org/chromium/components/browser_ui/media/MediaImageManagerTest.java b/components/browser_ui/media/android/java/src/org/chromium/components/browser_ui/media/MediaImageManagerTest.java index 0c87831..303a56c3 100644 --- a/components/browser_ui/media/android/java/src/org/chromium/components/browser_ui/media/MediaImageManagerTest.java +++ b/components/browser_ui/media/android/java/src/org/chromium/components/browser_ui/media/MediaImageManagerTest.java
@@ -287,7 +287,7 @@ public void testDownloadImageFails() { mMediaImageManager.downloadImage(mImages, mCallback); mMediaImageManager.onFinishDownloadImage( - REQUEST_ID_1, 404, IMAGE_URL_1, new ArrayList<>(), new ArrayList<Rect>()); + REQUEST_ID_1, 404, IMAGE_URL_1, new ArrayList<>(), new ArrayList<>()); verify(mCallback).onImageDownloaded((Bitmap) isNull()); verify(mCallback, times(0)).onImageDownloaded((Bitmap) isNotNull());
diff --git a/components/browser_ui/modaldialog/android/java/src/org/chromium/components/browser_ui/modaldialog/AppModalPresenterTest.java b/components/browser_ui/modaldialog/android/java/src/org/chromium/components/browser_ui/modaldialog/AppModalPresenterTest.java index d2a5c276..e48e4d3 100644 --- a/components/browser_ui/modaldialog/android/java/src/org/chromium/components/browser_ui/modaldialog/AppModalPresenterTest.java +++ b/components/browser_ui/modaldialog/android/java/src/org/chromium/components/browser_ui/modaldialog/AppModalPresenterTest.java
@@ -334,7 +334,7 @@ } private static Matcher<View> hasCurrentTextColor(int expected) { - return new BoundedMatcher<View, Button>(Button.class) { + return new BoundedMatcher<>(Button.class) { private int mColor; @Override
diff --git a/components/browser_ui/photo_picker/android/java/src/org/chromium/components/browser_ui/photo_picker/BitmapUtils.java b/components/browser_ui/photo_picker/android/java/src/org/chromium/components/browser_ui/photo_picker/BitmapUtils.java index d3f7719..ae6027a 100644 --- a/components/browser_ui/photo_picker/android/java/src/org/chromium/components/browser_ui/photo_picker/BitmapUtils.java +++ b/components/browser_ui/photo_picker/android/java/src/org/chromium/components/browser_ui/photo_picker/BitmapUtils.java
@@ -87,7 +87,7 @@ if (bitmap == null) return null; - return new Pair<Bitmap, Float>( + return new Pair<>( sizeBitmap(bitmap, size, fullWidth, descriptor), (float) bitmap.getHeight() / bitmap.getWidth()); } @@ -127,7 +127,7 @@ bitmaps.add(bitmap); } - return new Pair<List<Bitmap>, Float>(bitmaps, ratio); + return new Pair<>(bitmaps, ratio); } /**
diff --git a/components/browser_ui/photo_picker/android/java/src/org/chromium/components/browser_ui/photo_picker/PickerCategoryView.java b/components/browser_ui/photo_picker/android/java/src/org/chromium/components/browser_ui/photo_picker/PickerCategoryView.java index 98eff2b..5714a23 100644 --- a/components/browser_ui/photo_picker/android/java/src/org/chromium/components/browser_ui/photo_picker/PickerCategoryView.java +++ b/components/browser_ui/photo_picker/android/java/src/org/chromium/components/browser_ui/photo_picker/PickerCategoryView.java
@@ -519,7 +519,7 @@ if (mLowResThumbnails == null || mLowResThumbnails.get() == null) { mLowResThumbnails = GlobalDiscardableReferencePool.getReferencePool() - .put(new LruCache<String, Thumbnail>(mCacheSizeSmall)); + .put(new LruCache<>(mCacheSizeSmall)); } return assumeNonNull(mLowResThumbnails.get()); } @@ -528,7 +528,7 @@ if (mHighResThumbnails == null || mHighResThumbnails.get() == null) { mHighResThumbnails = GlobalDiscardableReferencePool.getReferencePool() - .put(new LruCache<String, Thumbnail>(mCacheSizeLarge)); + .put(new LruCache<>(mCacheSizeLarge)); } return assumeNonNull(mHighResThumbnails.get()); } @@ -537,7 +537,7 @@ if (mFullScreenBitmaps == null || mFullScreenBitmaps.get() == null) { mFullScreenBitmaps = GlobalDiscardableReferencePool.getReferencePool() - .put(new LruCache<String, Thumbnail>(mCacheSizeFullScreen)); + .put(new LruCache<>(mCacheSizeFullScreen)); } return assumeNonNull(mFullScreenBitmaps.get()); }
diff --git a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/WebsitePermissionsFetcher.java b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/WebsitePermissionsFetcher.java index 6e15b6b..09a216e 100644 --- a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/WebsitePermissionsFetcher.java +++ b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/WebsitePermissionsFetcher.java
@@ -650,7 +650,7 @@ public void runAsync(final TaskQueue queue) { mWebsitePreferenceBridge.fetchCookiesInfo( mBrowserContextHandle, - new Callback<Map<String, CookiesInfo>>() { + new Callback<>() { @Override public void onResult(Map<String, CookiesInfo> result) { for (Map.Entry<String, CookiesInfo> entry : result.entrySet()) {
diff --git a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/WebsitePreferenceBridge.java b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/WebsitePreferenceBridge.java index 7b78811b7..72a723a 100644 --- a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/WebsitePreferenceBridge.java +++ b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/WebsitePreferenceBridge.java
@@ -90,7 +90,7 @@ @CalledByNative private static Object createLocalStorageInfoMap() { - return new HashMap<String, LocalStorageInfo>(); + return new HashMap<>(); } @SuppressWarnings("unchecked") @@ -115,7 +115,7 @@ @CalledByNative private static Object createCookiesInfoMap() { - return new HashMap<String, CookiesInfo>(); + return new HashMap<>(); } @CalledByNative
diff --git a/components/browser_ui/styles/android/java/res/values-night/colors.xml b/components/browser_ui/styles/android/java/res/values-night/colors.xml index 89f70a9..65196ce 100644 --- a/components/browser_ui/styles/android/java/res/values-night/colors.xml +++ b/components/browser_ui/styles/android/java/res/values-night/colors.xml
@@ -18,7 +18,6 @@ <color name="empty_state_icon_bg_color">@color/material_primary_20</color> <color name="empty_state_icon_bg_background_color">@color/material_primary_10</color> <color name="empty_state_icon_bg_foreground_color">@color/material_primary_20</color> - <color name="empty_state_icon_tabswitcher_bg_color">@macro/default_bg_color_elev_0</color> <color name="empty_state_tab_group_border_color">@color/material_primary_80</color> <color name="empty_state_asset_bg_color">@color/material_primary_30</color> </resources>
diff --git a/components/browser_ui/styles/android/java/res/values/colors.xml b/components/browser_ui/styles/android/java/res/values/colors.xml index e38741d5..690fc7c 100644 --- a/components/browser_ui/styles/android/java/res/values/colors.xml +++ b/components/browser_ui/styles/android/java/res/values/colors.xml
@@ -51,7 +51,6 @@ <color name="empty_state_icon_bg_background_color">@color/material_primary_95</color> <color name="empty_state_icon_bg_foreground_color">@color/material_primary_90</color> <color name="empty_state_icon_color">@color/material_primary_40</color> - <color name="empty_state_icon_tabswitcher_bg_color">@color/material_primary_95</color> <color name="empty_state_tab_border_color">@color/material_primary_60</color> <color name="empty_state_tab_group_border_color">@color/material_primary_40</color> <color name="empty_state_asset_bg_color">@color/material_primary_90</color>
diff --git a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/ClipDrawableProgressBar.java b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/ClipDrawableProgressBar.java index 3a8874f..35527cd 100644 --- a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/ClipDrawableProgressBar.java +++ b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/ClipDrawableProgressBar.java
@@ -59,7 +59,7 @@ * Defines a small transparent gap between the foreground and background drawables when using * gradient drawables. The gap is a percentage of the max progress level 1.0f. */ - private static final float TRANSPARENT_GAP_SIZE = 0.01f; + private static final float GAP_SIZE = 0.01f; @Nullable private ColorDrawable mForegroundColorDrawable; @Nullable private GradientDrawable mForegroundGradientDrawable; @@ -73,7 +73,7 @@ /** * The width of the moving background drawable in pixels. * This is used when {@link #useGradientDrawable()} is true, where the background - * drawable scales with the inverse of the progress, leaving a small transparent + * drawable scales with the inverse of the progress, leaving a small * gap between the two drawables. */ private int mScaledBackgroundWidth; @@ -223,7 +223,7 @@ if (layerDrawable.getNumberOfLayers() >= 2) { ScaleDrawable backgroundScale = (ScaleDrawable) layerDrawable.getDrawable(1); if (progress > 0.0f) { - float backgroundProgressLevel = (1.0f - progress - TRANSPARENT_GAP_SIZE); + float backgroundProgressLevel = (1.0f - progress - GAP_SIZE); mScaledBackgroundWidth = (int) (getWidth() * backgroundProgressLevel); backgroundScale.setLevel(Math.round(backgroundProgressLevel * DRAWABLE_MAX_LEVEL)); } else { @@ -359,7 +359,6 @@ // moving background clip. mBackgroundGradientDrawable.setColor(color); mBackgroundColor = color; - super.setBackgroundColor(Color.TRANSPARENT); } } else if (color == Color.TRANSPARENT) { setBackground(null); @@ -386,6 +385,18 @@ mForegroundColor = color; } + /** + * Sets the background color of the Progress bar view. + * When {@link #useGradientDrawable()} is true, this color is used to fill the gap between the + * loaded and unloaded portion, preventing the background from being visible. + * Otherwise, this sets the general background of the progress bar. + * + * @param color The color to set for the background/gap. + */ + public void setProgressGapBackgroundColor(int color) { + super.setBackgroundColor(color); + } + @Override protected boolean onSetAlpha(int alpha) { updateInternalVisibility();
diff --git a/components/cronet/tracing.md b/components/cronet/tracing.md index 741bfdbf..20255f1 100644 --- a/components/cronet/tracing.md +++ b/components/cronet/tracing.md
@@ -160,6 +160,9 @@ data_sources { config { name: "android.statsd" + # Note: this data source only exists in Android 14+, see + # https://r.android.com/2132122. If you get a "no field named ..." error + # on the next line, you'll have to remove this data source. statsd_tracing_config { # Log Cronet telemetry atoms; see # org.chromium.net.telemetry.CronetStatsLog. @@ -181,6 +184,9 @@ # up under "System" > "Network" in the Perfetto UI, and as counters under # process tracks. name: "android.network_packets" + # Note: this data source only exists in Android 14+, see + # https://r.android.com/2310392. If you get a "no field named ..." error + # on the next line, you'll have to remove this data source. network_packet_trace_config { poll_ms: 250 }
diff --git a/components/exo/buffer_unittest.cc b/components/exo/buffer_unittest.cc index 2670aafd4..c73b7c9 100644 --- a/components/exo/buffer_unittest.cc +++ b/components/exo/buffer_unittest.cc
@@ -30,17 +30,11 @@ namespace exo { namespace { -class BufferTest - : public test::ExoTestBase, - public testing::WithParamInterface<test::FrameSubmissionType> { +class BufferTest : public test::ExoTestBase { public: BufferTest() : test::ExoTestBase(base::test::TaskEnvironment::TimeSource::MOCK_TIME) { - test::SetFrameSubmissionFeatureFlags(&feature_list_, GetParam()); } - - private: - base::test::ScopedFeatureList feature_list_; }; void VerifySyncTokensInCompositorFrame(viz::CompositorFrame* frame) { @@ -78,13 +72,7 @@ return frame; } -// Instantiate the values of frame submission types in the parameterized tests. -INSTANTIATE_TEST_SUITE_P(All, - BufferTest, - testing::Values(test::FrameSubmissionType::kNoReactive, - test::FrameSubmissionType::kReactive)); - -TEST_P(BufferTest, ReleaseCallback) { +TEST_F(BufferTest, ReleaseCallback) { gfx::Size buffer_size(256, 256); auto buffer = test::ExoTestHelper::CreateBuffer(buffer_size); auto surface_tree_host = std::make_unique<SurfaceTreeHost>("BufferTest"); @@ -132,7 +120,7 @@ ASSERT_EQ(release_call_count, 1); } -TEST_P(BufferTest, SolidColorReleaseCallback) { +TEST_F(BufferTest, SolidColorReleaseCallback) { gfx::Size buffer_size(256, 256); auto buffer = std::make_unique<SolidColorBuffer>(SkColors::kRed, buffer_size); auto surface_tree_host = std::make_unique<SurfaceTreeHost>("BufferTest"); @@ -181,7 +169,7 @@ EXPECT_EQ(release_call_count, 0); } -TEST_P(BufferTest, IsLost) { +TEST_F(BufferTest, IsLost) { gfx::Size buffer_size(256, 256); auto buffer = test::ExoTestHelper::CreateBuffer(buffer_size); auto surface_tree_host = std::make_unique<SurfaceTreeHost>("BufferTest"); @@ -240,7 +228,7 @@ // Buffer::Texture::OnLostResources is called when the gpu crashes. This test // verifies that the Texture is collected properly in such event. -TEST_P(BufferTest, OnLostResources) { +TEST_F(BufferTest, OnLostResources) { // Create a Buffer and use it to produce a Texture. constexpr gfx::Size buffer_size(256, 256); auto buffer = test::ExoTestHelper::CreateBuffer(buffer_size); @@ -265,7 +253,7 @@ ->SendOnContextLost(); } -TEST_P(BufferTest, SurfaceTreeHostDestruction) { +TEST_F(BufferTest, SurfaceTreeHostDestruction) { gfx::Size buffer_size(256, 256); // We need to setup shell surface and commit the surface, which properly @@ -324,7 +312,7 @@ ASSERT_EQ(release_resource_count, 1); } -TEST_P(BufferTest, SurfaceTreeHostLastFrame) { +TEST_F(BufferTest, SurfaceTreeHostLastFrame) { gfx::Size buffer_size(256, 256); // We need to setup shell surface and commit the surface, which properly @@ -398,20 +386,6 @@ ASSERT_EQ(release_resource_count, 1); } -// Tests that only apply if ExoReactiveFrameSubmission is enabled. -class ReactiveFrameSubmissionBufferTest - : public test::ExoTestBase, - public testing::WithParamInterface<test::FrameSubmissionType> { - public: - ReactiveFrameSubmissionBufferTest() - : test::ExoTestBase(base::test::TaskEnvironment::TimeSource::MOCK_TIME) { - test::SetFrameSubmissionFeatureFlags(&feature_list_, GetParam()); - } - - private: - base::test::ScopedFeatureList feature_list_; -}; - class TestLayerTreeFrameSinkHolder : public LayerTreeFrameSinkHolder { public: TestLayerTreeFrameSinkHolder( @@ -447,13 +421,7 @@ base::RepeatingClosure post_reclaim_callback_; }; -// Instantiate the values of frame submission types in the parameterized tests. -INSTANTIATE_TEST_SUITE_P(All, - ReactiveFrameSubmissionBufferTest, - testing::Values(test::FrameSubmissionType::kReactive)); - -TEST_P(ReactiveFrameSubmissionBufferTest, - SurfaceTreeHostNotReclaimCachedFrameResources) { +TEST_F(BufferTest, SurfaceTreeHostNotReclaimCachedFrameResources) { gfx::Size buffer_size(256, 256); auto shell_surface = @@ -552,8 +520,7 @@ ASSERT_EQ(release_resource_count, 1); } -TEST_P(ReactiveFrameSubmissionBufferTest, - SurfaceTreeHostDiscardFrameNotReclaimNewFrameResources) { +TEST_F(BufferTest, SurfaceTreeHostDiscardFrameNotReclaimNewFrameResources) { gfx::Size buffer_size(256, 256); auto shell_surface = @@ -626,8 +593,7 @@ ASSERT_EQ(release_resource_count, 1); } -TEST_P(ReactiveFrameSubmissionBufferTest, - SurfaceTreeHostDiscardFrameNotReclaimInUseResources) { +TEST_F(BufferTest, SurfaceTreeHostDiscardFrameNotReclaimInUseResources) { gfx::Size buffer_size(256, 256); auto shell_surface =
diff --git a/components/exo/client_controlled_shell_surface.cc b/components/exo/client_controlled_shell_surface.cc index 43cc14f9c..2804da82 100644 --- a/components/exo/client_controlled_shell_surface.cc +++ b/components/exo/client_controlled_shell_surface.cc
@@ -12,7 +12,6 @@ #include "ash/frame/wide_frame_view.h" #include "ash/public/cpp/arc_resize_lock_type.h" #include "ash/public/cpp/ash_constants.h" -#include "ash/public/cpp/rounded_corner_utils.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/public/cpp/window_backdrop.h" #include "ash/public/cpp/window_properties.h"
diff --git a/components/exo/client_controlled_shell_surface_unittest.cc b/components/exo/client_controlled_shell_surface_unittest.cc index 127c9463..e3d04df 100644 --- a/components/exo/client_controlled_shell_surface_unittest.cc +++ b/components/exo/client_controlled_shell_surface_unittest.cc
@@ -80,17 +80,7 @@ namespace exo { namespace { -class ClientControlledShellSurfaceTest - : public test::ExoTestBase, - public testing::WithParamInterface<test::FrameSubmissionType> { - public: - ClientControlledShellSurfaceTest() { - test::SetFrameSubmissionFeatureFlags(&feature_list_, GetParam()); - } - - private: - base::test::ScopedFeatureList feature_list_; -}; +using ClientControlledShellSurfaceTest = test::ExoTestBase; bool HasBackdrop() { ash::WorkspaceController* wc = ash::ShellTestApi().workspace_controller(); @@ -138,13 +128,7 @@ } // namespace -// Instantiate the values of frame submission types in the parameterized tests. -INSTANTIATE_TEST_SUITE_P(All, - ClientControlledShellSurfaceTest, - testing::Values(test::FrameSubmissionType::kNoReactive, - test::FrameSubmissionType::kReactive)); - -TEST_P(ClientControlledShellSurfaceTest, SetPinned) { +TEST_F(ClientControlledShellSurfaceTest, SetPinned) { auto shell_surface = exo::test::ShellSurfaceBuilder({256, 256}) .BuildClientControlledShellSurface(); @@ -169,7 +153,7 @@ EXPECT_FALSE(IsWidgetPinned(shell_surface->GetWidget())); } -TEST_P(ClientControlledShellSurfaceTest, SetSystemUiVisibility) { +TEST_F(ClientControlledShellSurfaceTest, SetSystemUiVisibility) { auto shell_surface = exo::test::ShellSurfaceBuilder({256, 256}) .BuildClientControlledShellSurface(); @@ -184,7 +168,7 @@ ->autohide_shelf_when_maximized_or_fullscreen()); } -TEST_P(ClientControlledShellSurfaceTest, SetTopInset) { +TEST_F(ClientControlledShellSurfaceTest, SetTopInset) { auto shell_surface = exo::test::ShellSurfaceBuilder({64, 64}) .BuildClientControlledShellSurface(); auto* surface = shell_surface->root_surface(); @@ -198,7 +182,7 @@ EXPECT_EQ(kTopInsetHeight, window->GetProperty(aura::client::kTopViewInset)); } -TEST_P(ClientControlledShellSurfaceTest, UpdateModalWindow) { +TEST_F(ClientControlledShellSurfaceTest, UpdateModalWindow) { auto shell_surface = exo::test::ShellSurfaceBuilder({640, 480}) .SetUseSystemModalContainer() .SetInputRegion(cc::Region()) @@ -258,7 +242,7 @@ EXPECT_TRUE(shell_surface->GetWidget()->IsActive()); } -TEST_P(ClientControlledShellSurfaceTest, +TEST_F(ClientControlledShellSurfaceTest, ModalWindowSetSystemModalBeforeCommit) { auto shell_surface = exo::test::ShellSurfaceBuilder({640, 480}) .SetUseSystemModalContainer() @@ -284,7 +268,7 @@ EXPECT_FALSE(ash::Shell::IsSystemModalWindowOpen()); } -TEST_P(ClientControlledShellSurfaceTest, +TEST_F(ClientControlledShellSurfaceTest, NonSystemModalContainerCantChangeModality) { auto shell_surface = exo::test::ShellSurfaceBuilder({640, 480}) .SetInputRegion(cc::Region()) @@ -295,7 +279,7 @@ EXPECT_FALSE(ash::Shell::IsSystemModalWindowOpen()); } -TEST_P(ClientControlledShellSurfaceTest, SurfaceShadow) { +TEST_F(ClientControlledShellSurfaceTest, SurfaceShadow) { auto shell_surface = exo::test::ShellSurfaceBuilder({128, 128}) .BuildClientControlledShellSurface(); auto* surface = shell_surface->root_surface(); @@ -354,7 +338,7 @@ EXPECT_TRUE(shadow->layer()->visible()); } -TEST_P(ClientControlledShellSurfaceTest, ShadowWithStateChange) { +TEST_F(ClientControlledShellSurfaceTest, ShadowWithStateChange) { constexpr gfx::Size kContentSize(100, 100); // Position the widget at 10,10 so that we get non zero offset. auto shell_surface = exo::test::ShellSurfaceBuilder(kContentSize) @@ -401,7 +385,7 @@ EXPECT_EQ(kShadowBounds, shadow->content_bounds()); } -TEST_P(ClientControlledShellSurfaceTest, ShadowWithTransform) { +TEST_F(ClientControlledShellSurfaceTest, ShadowWithTransform) { constexpr gfx::Size kContentSize(100, 100); // Position the widget at 10,10 so that we get non zero offset. auto shell_surface = exo::test::ShellSurfaceBuilder(kContentSize) @@ -425,7 +409,7 @@ EXPECT_EQ(gfx::Rect(-10, -10, 100, 100), shadow->content_bounds()); } -TEST_P(ClientControlledShellSurfaceTest, ShadowStartMaximized) { +TEST_F(ClientControlledShellSurfaceTest, ShadowStartMaximized) { auto shell_surface = exo::test::ShellSurfaceBuilder({256, 256}) .SetWindowState(chromeos::WindowStateType::kMaximized) @@ -452,7 +436,7 @@ EXPECT_EQ(gfx::Rect(10, 10, 100, 100), shadow->content_bounds()); } -TEST_P(ClientControlledShellSurfaceTest, Frame) { +TEST_F(ClientControlledShellSurfaceTest, Frame) { UpdateDisplay("800x600"); constexpr gfx::Rect kClientBounds(20, 50, 300, 200); @@ -602,7 +586,7 @@ frame_view->GetClientBoundsForWindowBounds(kNormalWindowBounds)); } -TEST_P(ClientControlledShellSurfaceTest, +TEST_F(ClientControlledShellSurfaceTest, ShadowRoundedCornersWithPipTransition) { constexpr gfx::Point kOrigin(20, 20); @@ -665,7 +649,7 @@ } // namespace -TEST_P(ClientControlledShellSurfaceTest, NoSynthesizedEventOnFrameChange) { +TEST_F(ClientControlledShellSurfaceTest, NoSynthesizedEventOnFrameChange) { UpdateDisplay("800x600"); auto shell_surface = exo::test::ShellSurfaceBuilder({256, 256}) @@ -698,7 +682,7 @@ // Shell surfaces should not emit extra events on commit even if using pixel // coordinates and a cursor is hovering over the window. // https://crbug.com/1296315. -TEST_P(ClientControlledShellSurfaceTest, +TEST_F(ClientControlledShellSurfaceTest, NoSynthesizedEventsForPixelCoordinates) { TestEventHandler event_handler; @@ -736,7 +720,7 @@ shell_surface->host_window()->RemovePreTargetHandler(&event_handler); } -TEST_P(ClientControlledShellSurfaceTest, CompositorLockInRotation) { +TEST_F(ClientControlledShellSurfaceTest, CompositorLockInRotation) { UpdateDisplay("800x600"); EnableTabletMode(true); @@ -773,7 +757,7 @@ // If system tray is shown by click. It should be activated if user presses tab // key while shell surface is active. -TEST_P(ClientControlledShellSurfaceTest, +TEST_F(ClientControlledShellSurfaceTest, KeyboardNavigationWithUnifiedSystemTray) { auto shell_surface = exo::test::ShellSurfaceBuilder({800, 600}) .BuildClientControlledShellSurface(); @@ -797,7 +781,7 @@ EXPECT_TRUE(system_tray->IsBubbleActive()); } -TEST_P(ClientControlledShellSurfaceTest, Maximize) { +TEST_F(ClientControlledShellSurfaceTest, Maximize) { auto shell_surface = exo::test::ShellSurfaceBuilder({256, 256}) .BuildClientControlledShellSurface(); auto* surface = shell_surface->root_surface(); @@ -835,7 +819,7 @@ EXPECT_TRUE(HasBackdrop()); } -TEST_P(ClientControlledShellSurfaceTest, Restore) { +TEST_F(ClientControlledShellSurfaceTest, Restore) { auto shell_surface = exo::test::ShellSurfaceBuilder({256, 256}) .BuildClientControlledShellSurface(); auto* surface = shell_surface->root_surface(); @@ -852,7 +836,7 @@ EXPECT_FALSE(HasBackdrop()); } -TEST_P(ClientControlledShellSurfaceTest, SetFullscreen) { +TEST_F(ClientControlledShellSurfaceTest, SetFullscreen) { auto shell_surface = exo::test::ShellSurfaceBuilder({256, 256}) .SetWindowState(chromeos::WindowStateType::kFullscreen) @@ -881,7 +865,7 @@ shell_surface->GetWidget()->GetWindowBoundsInScreen().ToString()); } -TEST_P(ClientControlledShellSurfaceTest, ToggleFullscreen) { +TEST_F(ClientControlledShellSurfaceTest, ToggleFullscreen) { auto shell_surface = exo::test::ShellSurfaceBuilder({256, 256}) .BuildClientControlledShellSurface(); auto* surface = shell_surface->root_surface(); @@ -903,7 +887,7 @@ EXPECT_TRUE(HasBackdrop()); } -TEST_P(ClientControlledShellSurfaceTest, +TEST_F(ClientControlledShellSurfaceTest, DefaultDeviceScaleFactorFromDisplayManager) { int64_t display_id = display::Screen::GetScreen()->GetPrimaryDisplay().id(); display::SetInternalDisplayIds({display_id}); @@ -941,7 +925,7 @@ shell_surface->root_surface()->window()->transform().ToString()); } -TEST_P(ClientControlledShellSurfaceTest, MouseAndTouchTarget) { +TEST_F(ClientControlledShellSurfaceTest, MouseAndTouchTarget) { auto shell_surface = exo::test::ShellSurfaceBuilder({256, 256}) .SetGeometry({0, 0, 256, 256}) .BuildClientControlledShellSurface(); @@ -984,7 +968,7 @@ } // The shell surface in SystemModal container should be unresizable. -TEST_P(ClientControlledShellSurfaceTest, +TEST_F(ClientControlledShellSurfaceTest, ShellSurfaceInSystemModalIsUnresizable) { auto shell_surface = exo::test::ShellSurfaceBuilder({256, 256}) .SetUseSystemModalContainer() @@ -995,7 +979,7 @@ // The shell surface in SystemModal container should be a target // at the edge. -TEST_P(ClientControlledShellSurfaceTest, ShellSurfaceInSystemModalHitTest) { +TEST_F(ClientControlledShellSurfaceTest, ShellSurfaceInSystemModalHitTest) { display::Display display = display::Screen::GetScreen()->GetPrimaryDisplay(); auto shell_surface = exo::test::ShellSurfaceBuilder({640, 480}) .SetUseSystemModalContainer() @@ -1015,7 +999,7 @@ } // Test the snap functionalities in splitscreen in tablet mode. -TEST_P(ClientControlledShellSurfaceTest, SnapWindowInSplitViewModeTest) { +TEST_F(ClientControlledShellSurfaceTest, SnapWindowInSplitViewModeTest) { UpdateDisplay("807x607"); EnableTabletMode(true); @@ -1068,7 +1052,7 @@ // The shell surface in SystemModal container should not become target // at the edge. -TEST_P(ClientControlledShellSurfaceTest, ClientIniatedResize) { +TEST_F(ClientControlledShellSurfaceTest, ClientIniatedResize) { display::Display display = display::Screen::GetScreen()->GetPrimaryDisplay(); auto shell_surface = exo::test::ShellSurfaceBuilder({100, 100}) .SetGeometry(gfx::Rect({0, 0, 100, 100})) @@ -1097,7 +1081,7 @@ ASSERT_FALSE(window_state->is_dragged()); } -TEST_P(ClientControlledShellSurfaceTest, ResizabilityAndSizeConstraints) { +TEST_F(ClientControlledShellSurfaceTest, ResizabilityAndSizeConstraints) { auto shell_surface = exo::test::ShellSurfaceBuilder() .SetMinimumSize(gfx::Size(0, 0)) .SetMaximumSize(gfx::Size(0, 0)) @@ -1163,7 +1147,7 @@ // Test that when a shell surface is destroyed during its dragging, its window // delegate should be reset properly. -TEST_P(ClientControlledShellSurfaceTest, CloseWindowWhenDraggingTest) { +TEST_F(ClientControlledShellSurfaceTest, CloseWindowWhenDraggingTest) { auto shell_surface = exo::test::ShellSurfaceBuilder({256, 256}) .SetGeometry({0, 0, 256, 256}) .BuildClientControlledShellSurface(); @@ -1439,7 +1423,7 @@ EXPECT_EQ(0, delegate->pending_task_count()); } -TEST_P(ClientControlledShellSurfaceTest, CaptionButtonModel) { +TEST_F(ClientControlledShellSurfaceTest, CaptionButtonModel) { auto shell_surface = exo::test::ShellSurfaceBuilder({64, 64}) .SetGeometry(gfx::Rect(0, 0, 64, 64)) .BuildClientControlledShellSurface(); @@ -1506,7 +1490,7 @@ // set, there should be no text in the window frame, but the window's name // should still be set (for overview mode, accessibility, etc.). When the debug // text is set, the window frame should paint it. -TEST_P(ClientControlledShellSurfaceTest, SetExtraTitle) { +TEST_F(ClientControlledShellSurfaceTest, SetExtraTitle) { auto shell_surface = exo::test::ShellSurfaceBuilder({640, 64}) .BuildClientControlledShellSurface(); auto* surface = shell_surface->root_surface(); @@ -1552,7 +1536,7 @@ shell_surface->GetWidget()->widget_delegate()->ShouldShowWindowTitle()); } -TEST_P(ClientControlledShellSurfaceTest, WideFrame) { +TEST_F(ClientControlledShellSurfaceTest, WideFrame) { auto shell_surface = exo::test::ShellSurfaceBuilder({64, 64}) .SetWindowState(chromeos::WindowStateType::kMaximized) @@ -1701,7 +1685,7 @@ } // Tests that a WideFrameView is created for an unparented ARC task and that the -TEST_P(ClientControlledShellSurfaceTest, NoFrameOnModalContainer) { +TEST_F(ClientControlledShellSurfaceTest, NoFrameOnModalContainer) { auto shell_surface = exo::test::ShellSurfaceBuilder({64, 64}) .SetUseSystemModalContainer() .SetGeometry(gfx::Rect(100, 0, 64, 64)) @@ -1714,7 +1698,7 @@ EXPECT_FALSE(shell_surface->frame_enabled()); } -TEST_P(ClientControlledShellSurfaceTest, +TEST_F(ClientControlledShellSurfaceTest, SetGeometryReparentsToDisplayOnFirstCommit) { UpdateDisplay("100x200,100x200"); const auto* screen = display::Screen::GetScreen(); @@ -1748,7 +1732,7 @@ } } -TEST_P(ClientControlledShellSurfaceTest, SetBoundsReparentsToDisplay) { +TEST_F(ClientControlledShellSurfaceTest, SetBoundsReparentsToDisplay) { UpdateDisplay("100x200,100x200"); const auto* screen = display::Screen::GetScreen(); @@ -1806,7 +1790,7 @@ // Test if the surface bounds is correctly set when default scale cancellation // is enabled or disabled. -TEST_P(ClientControlledShellSurfaceTest, +TEST_F(ClientControlledShellSurfaceTest, SetBoundsWithAndWithoutDefaultScaleCancellation) { UpdateDisplay("800x600*2,800x600*2"); @@ -1878,7 +1862,7 @@ } // Set orientation lock to a window. -TEST_P(ClientControlledShellSurfaceTest, SetOrientationLock) { +TEST_F(ClientControlledShellSurfaceTest, SetOrientationLock) { display::test::DisplayManagerTestApi(ash::Shell::Get()->display_manager()) .SetFirstDisplayAsInternalDisplay(); @@ -1905,7 +1889,7 @@ } // Tests adjust bounds locally should also request remote client bounds update. -TEST_P(ClientControlledShellSurfaceTest, AdjustBoundsLocally) { +TEST_F(ClientControlledShellSurfaceTest, AdjustBoundsLocally) { UpdateDisplay("800x600"); constexpr gfx::Rect kClientBounds(900, 0, 200, 300); auto shell_surface = exo::test::ShellSurfaceBuilder({64, 64}) @@ -1929,7 +1913,7 @@ EXPECT_EQ(0, delegate->bounds_change_count()); } -TEST_P(ClientControlledShellSurfaceTest, SnappedInTabletMode) { +TEST_F(ClientControlledShellSurfaceTest, SnappedInTabletMode) { constexpr gfx::Rect kClientBounds(256, 256); auto shell_surface = exo::test::ShellSurfaceBuilder(kClientBounds.size()) .SetGeometry(kClientBounds) @@ -1954,7 +1938,7 @@ EXPECT_TRUE(frame_view->GetHeaderView()->in_immersive_mode()); } -TEST_P(ClientControlledShellSurfaceTest, PipWindowCannotBeActivated) { +TEST_F(ClientControlledShellSurfaceTest, PipWindowCannotBeActivated) { auto shell_surface = exo::test::ShellSurfaceBuilder({256, 256}) .BuildClientControlledShellSurface(); auto* surface = shell_surface->root_surface(); @@ -2043,7 +2027,7 @@ EXPECT_EQ(gfx::Rect(0, 0, 100, 100), delegate->requested_bounds().back()); } -TEST_P(ClientControlledShellSurfaceTest, SetPipWindowBoundsAnimates) { +TEST_F(ClientControlledShellSurfaceTest, SetPipWindowBoundsAnimates) { constexpr gfx::Rect kClientBounds(256, 256); auto shell_surface = exo::test::ShellSurfaceBuilder(kClientBounds.size()) .SetWindowState(chromeos::WindowStateType::kPip) @@ -2066,7 +2050,7 @@ EXPECT_EQ(gfx::Rect(8, 8, 256, 256), window->layer()->bounds()); } -TEST_P(ClientControlledShellSurfaceTest, PipWindowDragDoesNotAnimate) { +TEST_F(ClientControlledShellSurfaceTest, PipWindowDragDoesNotAnimate) { constexpr gfx::Rect kClientBounds(256, 256); auto shell_surface = exo::test::ShellSurfaceBuilder(kClientBounds.size()) .SetWindowState(chromeos::WindowStateType::kPip) @@ -2111,7 +2095,7 @@ } } -TEST_P(ClientControlledShellSurfaceTest, +TEST_F(ClientControlledShellSurfaceTest, PipWindowDragDoesNotAnimateWithExtraCommit) { constexpr gfx::Rect kClientBounds(256, 256); auto shell_surface = exo::test::ShellSurfaceBuilder({kClientBounds.size()}) @@ -2142,7 +2126,7 @@ resizer->CompleteDrag(); } -TEST_P(ClientControlledShellSurfaceTest, +TEST_F(ClientControlledShellSurfaceTest, ExpandingPipInTabletModeEndsSplitView) { EnableTabletMode(true); @@ -2170,7 +2154,7 @@ EXPECT_FALSE(split_view_controller->InSplitViewMode()); } -TEST_P(ClientControlledShellSurfaceTest, +TEST_F(ClientControlledShellSurfaceTest, DismissingPipInTabletModeDoesNotEndSplitView) { EnableTabletMode(true); @@ -2225,7 +2209,7 @@ } }; -TEST_P(ClientControlledShellSurfaceTest, DoNotReplayWindowStateRequest) { +TEST_F(ClientControlledShellSurfaceTest, DoNotReplayWindowStateRequest) { auto shell_surface = exo::test::ShellSurfaceBuilder({64, 64}) .SetWindowState(chromeos::WindowStateType::kMinimized) @@ -2237,7 +2221,7 @@ surface->Commit(); } -TEST_P(ClientControlledShellSurfaceTest, UnPinTriggersStateChangeRequest) { +TEST_F(ClientControlledShellSurfaceTest, UnPinTriggersStateChangeRequest) { // Only test in tablet mode. Because after restore from pin state, in tablet // mode the window will still be fullscreen. EnableTabletMode(true); @@ -2277,7 +2261,7 @@ ASSERT_EQ(1, delegate->bounds_change_count()); } -TEST_P(ClientControlledShellSurfaceTest, +TEST_F(ClientControlledShellSurfaceTest, DoNotSavePipBoundsAcrossMultiplePipTransition) { // Create a PIP window: constexpr gfx::Size kBufferSize(100, 100); @@ -2314,7 +2298,7 @@ EXPECT_EQ(gfx::Rect(8, 20, 100, 100), window->bounds()); } -TEST_P(ClientControlledShellSurfaceTest, +TEST_F(ClientControlledShellSurfaceTest, DoNotApplyCollisionDetectionWhileDraggedOrTucked) { constexpr gfx::Size kBufferSize(256, 256); constexpr gfx::Rect kOriginalBounds({8, 50}, kBufferSize); @@ -2349,7 +2333,7 @@ EXPECT_EQ(gfx::Rect(-20, 50, 256, 256), window->bounds()); } -TEST_P(ClientControlledShellSurfaceTest, EnteringPipSavesPipSnapFraction) { +TEST_F(ClientControlledShellSurfaceTest, EnteringPipSavesPipSnapFraction) { constexpr gfx::Size kBufferSize(100, 100); constexpr gfx::Rect kOriginalBounds({8, 50}, kBufferSize); auto shell_surface = exo::test::ShellSurfaceBuilder(kBufferSize) @@ -2366,7 +2350,7 @@ window->bounds()); } -TEST_P(ClientControlledShellSurfaceTest, +TEST_F(ClientControlledShellSurfaceTest, ShadowBoundsChangedIsResetAfterCommit) { auto shell_surface = exo::test::ShellSurfaceBuilder().BuildClientControlledShellSurface(); @@ -2453,7 +2437,7 @@ EXPECT_EQ(0, delegate->bounds_change_count()); } -TEST_P(ClientControlledShellSurfaceTest, SnappedClientBounds) { +TEST_F(ClientControlledShellSurfaceTest, SnappedClientBounds) { UpdateDisplay("800x600"); auto shell_surface = exo::test::ShellSurfaceBuilder({256, 256}) @@ -2516,7 +2500,7 @@ } // The shell surface with resize lock on should be unresizable. -TEST_P(ClientControlledShellSurfaceTest, +TEST_F(ClientControlledShellSurfaceTest, ShellSurfaceWithResizeLockOnIsUnresizable) { auto shell_surface = exo::test::ShellSurfaceBuilder({256, 256}) .BuildClientControlledShellSurface(); @@ -2535,7 +2519,7 @@ EXPECT_TRUE(shell_surface->CanResize()); } -TEST_P(ClientControlledShellSurfaceTest, OverlayShadowBounds) { +TEST_F(ClientControlledShellSurfaceTest, OverlayShadowBounds) { constexpr gfx::Rect kInitialBounds(150, 10, 200, 200); auto shell_surface = exo::test::ShellSurfaceBuilder({1, 1}) .BuildClientControlledShellSurface(); @@ -2564,7 +2548,7 @@ // WideFrameView should be safely deleted even when the window is // deleted directly. -TEST_P(ClientControlledShellSurfaceTest, DeleteWindowWithWideframe) { +TEST_F(ClientControlledShellSurfaceTest, DeleteWindowWithWideframe) { auto shell_surface = exo::test::ShellSurfaceBuilder({64, 64}) .SetWindowState(chromeos::WindowStateType::kMaximized) @@ -2579,7 +2563,7 @@ // WideFrameView follows its respective surface when it is eventually parented. // See crbug.com/1223135. -TEST_P(ClientControlledShellSurfaceTest, WideframeForUnparentedTasks) { +TEST_F(ClientControlledShellSurfaceTest, WideframeForUnparentedTasks) { auto shell_surface = exo::test::ShellSurfaceBuilder({64, 64}) .SetGeometry(gfx::Rect(100, 0, 64, 64)) .SetInputRegion(gfx::Rect(0, 0, 64, 64)) @@ -2619,7 +2603,7 @@ wide_frame->GetWidget()->GetNativeWindow()->parent()); } -TEST_P(ClientControlledShellSurfaceTest, +TEST_F(ClientControlledShellSurfaceTest, InitializeWindowStateGrantsPermissionToActivate) { auto shell_surface = exo::test::ShellSurfaceBuilder().BuildClientControlledShellSurface(); @@ -2630,7 +2614,7 @@ EXPECT_TRUE(permission->Check(Permission::Capability::kActivate)); } -TEST_P(ClientControlledShellSurfaceTest, SupportsFloatedState) { +TEST_F(ClientControlledShellSurfaceTest, SupportsFloatedState) { // Test disabling support. { auto shell_surface = exo::test::ShellSurfaceBuilder() @@ -2650,7 +2634,7 @@ // Test if the surface bounds is correctly set when the scale factor is not // explicitly set. -TEST_P(ClientControlledShellSurfaceTest, +TEST_F(ClientControlledShellSurfaceTest, SetBoundsWithoutExplicitScaleFactorSet) { UpdateDisplay("800x600*2"); aura::Window::Windows root_windows = ash::Shell::GetAllRootWindows(); @@ -2696,7 +2680,7 @@ } } -TEST_P(ClientControlledShellSurfaceTest, FrameOverlap) { +TEST_F(ClientControlledShellSurfaceTest, FrameOverlap) { constexpr gfx::Rect kWindowBounds(20, 50, 300, 200); // The bounds for views::ClientView, should be kWindowBounds excluding // caption. @@ -2744,7 +2728,7 @@ EXPECT_TRUE(shell_surface->GetWidget()->IsMinimized()); } -TEST_P(ClientControlledShellSurfaceTest, ShowMinimizedNoActivation) { +TEST_F(ClientControlledShellSurfaceTest, ShowMinimizedNoActivation) { class TestObserver : public SeatObserver { public: // SeatObserver:
diff --git a/components/exo/layer_tree_frame_sink_holder.cc b/components/exo/layer_tree_frame_sink_holder.cc index d17d9a3..465f22a 100644 --- a/components/exo/layer_tree_frame_sink_holder.cc +++ b/components/exo/layer_tree_frame_sink_holder.cc
@@ -25,10 +25,6 @@ } // namespace -BASE_FEATURE(kExoReactiveFrameSubmission, - "ExoReactiveFrameSubmission", - base::FEATURE_ENABLED_BY_DEFAULT); - //////////////////////////////////////////////////////////////////////////////// // LayerTreeFrameSinkHolder, public: @@ -36,13 +32,8 @@ SurfaceTreeHost* surface_tree_host, std::unique_ptr<cc::mojo_embedder::AsyncLayerTreeFrameSink> frame_sink) : surface_tree_host_(surface_tree_host), - frame_sink_(std::move(frame_sink)), - reactive_frame_submission_( - base::FeatureList::IsEnabled(kExoReactiveFrameSubmission)) { - if (reactive_frame_submission_) { - frame_timing_history_.emplace(); - } - + frame_sink_(std::move(frame_sink)) { + frame_timing_history_.emplace(); frame_sink_->BindToClient(this); } @@ -109,11 +100,6 @@ void LayerTreeFrameSinkHolder::SubmitCompositorFrame(viz::CompositorFrame frame, bool submit_now) { - if (!reactive_frame_submission_) { - SubmitCompositorFrameToRemote(&frame); - return; - } - DiscardCachedFrame(&frame); ObserveBeginFrameSource(true); @@ -147,10 +133,6 @@ void LayerTreeFrameSinkHolder::SetBeginFrameSource( viz::BeginFrameSource* source) { - if (!reactive_frame_submission_) { - return; - } - ObserveBeginFrameSource(false); begin_frame_source_ = source; @@ -208,10 +190,6 @@ if (surface_tree_host_) surface_tree_host_->DidReceiveCompositorFrameAck(); - if (!reactive_frame_submission_) { - return; - } - if (pending_submit_frames_ == 0) { while (!pending_discarded_frame_notifications_.empty()) { SendDiscardedFrameNotifications( @@ -295,8 +273,6 @@ bool LayerTreeFrameSinkHolder::OnBeginFrameDerivedImpl( const viz::BeginFrameArgs& args) { - DCHECK(reactive_frame_submission_); - base::TimeDelta timing_estimate = base::Milliseconds(0); if (frame_timing_history_) { timing_estimate = frame_timing_history_->GetFrameTransferDurationEstimate(); @@ -359,8 +335,6 @@ return; } - DCHECK(reactive_frame_submission_); - for (const auto& resource : cached_frame_->resource_list) { // Skip if the resource is still in use by the remote side. if (in_use_resources_.contains(resource.id)) { @@ -425,7 +399,7 @@ } void LayerTreeFrameSinkHolder::OnSendDeadlineExpired(bool update_timer) { - DCHECK(!is_lost_ && reactive_frame_submission_); + CHECK(!is_lost_); if (pending_begin_frames_.empty()) { return; @@ -521,8 +495,6 @@ } bool LayerTreeFrameSinkHolder::ShouldSubmitFrameNow() const { - DCHECK(reactive_frame_submission_); - return (!pending_begin_frames_.empty() || UnsolicitedFrameAllowed()) && pending_submit_frames_ == 0; } @@ -548,8 +520,6 @@ } bool LayerTreeFrameSinkHolder::UnsolicitedFrameAllowed() const { - DCHECK(reactive_frame_submission_); - // `frame_sink_->needs_begin_frames()` being false means the remote side is // currently not configured to send us BeginFrames. In this case, an // unsolicited frame should be allowed.
diff --git a/components/exo/layer_tree_frame_sink_holder.h b/components/exo/layer_tree_frame_sink_holder.h index 3a319b8f..eb6ab783 100644 --- a/components/exo/layer_tree_frame_sink_holder.h +++ b/components/exo/layer_tree_frame_sink_holder.h
@@ -9,7 +9,6 @@ #include <optional> #include "base/containers/queue.h" -#include "base/feature_list.h" #include "base/memory/raw_ptr.h" #include "base/timer/timer.h" #include "cc/trees/layer_tree_frame_sink_client.h" @@ -31,14 +30,6 @@ class SurfaceTreeHost; -// When this feature is disabled (by default at the moment), frames are -// submitted to the remote side as soon as they arrive, disregarding BeginFrame -// requests. -// -// TODO(yzshen): Remove this flag and always submit according to BeginFrame -// requests. crbug.com/1408614 -BASE_DECLARE_FEATURE(kExoReactiveFrameSubmission); - // This class talks to CompositorFrameSink and keeps track of references to // the contents of Buffers. class LayerTreeFrameSinkHolder : public cc::LayerTreeFrameSinkClient, @@ -174,9 +165,6 @@ base::DeadlineTimer submit_frame_timer_; - const bool reactive_frame_submission_ = false; - - // Set if `reactive_frame_submission_` is enabled. std::optional<FrameTimingHistory> frame_timing_history_; };
diff --git a/components/exo/pointer_unittest.cc b/components/exo/pointer_unittest.cc index e2ab38f..6edb15a 100644 --- a/components/exo/pointer_unittest.cc +++ b/components/exo/pointer_unittest.cc
@@ -175,13 +175,9 @@ MOCK_METHOD(void, OnPointerTilt, (base::TimeTicks, const gfx::Vector2dF&)); }; -class PointerTest - : public test::ExoTestBase, - public testing::WithParamInterface<test::FrameSubmissionType> { +class PointerTest : public test::ExoTestBase { public: - PointerTest() { - test::SetFrameSubmissionFeatureFlags(&feature_list_, GetParam()); - } + PointerTest() = default; PointerTest(const PointerTest&) = delete; PointerTest& operator=(const PointerTest&) = delete; @@ -271,17 +267,7 @@ raw_ptr<aura::client::FocusClient, DanglingUntriaged> focus_client_; }; -// Instantiate the values of frame submission types in the parameterized tests. -INSTANTIATE_TEST_SUITE_P(All, - PointerTest, - testing::Values(test::FrameSubmissionType::kNoReactive, - test::FrameSubmissionType::kReactive)); -INSTANTIATE_TEST_SUITE_P(All, - PointerConstraintTest, - testing::Values(test::FrameSubmissionType::kNoReactive, - test::FrameSubmissionType::kReactive)); - -TEST_P(PointerTest, SetCursor) { +TEST_F(PointerTest, SetCursor) { auto shell_surface = test::ShellSurfaceBuilder({10, 10}).BuildShellSurface(); auto* surface = shell_surface->surface_for_testing(); @@ -342,7 +328,7 @@ pointer.reset(); } -TEST_P(PointerTest, SetCursorNull) { +TEST_F(PointerTest, SetCursorNull) { auto shell_surface = test::ShellSurfaceBuilder({10, 10}).BuildShellSurface(); auto* surface = shell_surface->surface_for_testing(); @@ -367,7 +353,7 @@ pointer.reset(); } -TEST_P(PointerTest, SetCursorType) { +TEST_F(PointerTest, SetCursorType) { auto shell_surface = test::ShellSurfaceBuilder({10, 10}).BuildShellSurface(); auto* surface = shell_surface->surface_for_testing(); @@ -420,7 +406,7 @@ pointer.reset(); } -TEST_P(PointerTest, SetCursorTypeOutsideOfSurface) { +TEST_F(PointerTest, SetCursorTypeOutsideOfSurface) { auto shell_surface = test::ShellSurfaceBuilder({10, 10}).BuildShellSurface(); auto* surface = shell_surface->surface_for_testing(); @@ -446,7 +432,7 @@ pointer.reset(); } -TEST_P(PointerTest, SetCursorAndSetCursorType) { +TEST_F(PointerTest, SetCursorAndSetCursorType) { auto shell_surface = test::ShellSurfaceBuilder({10, 10}).BuildShellSurface(); auto* surface = shell_surface->surface_for_testing(); @@ -508,7 +494,7 @@ pointer.reset(); } -TEST_P(PointerTest, SetCursorNullAndSetCursorType) { +TEST_F(PointerTest, SetCursorNullAndSetCursorType) { auto shell_surface = test::ShellSurfaceBuilder({10, 10}).BuildShellSurface(); auto* surface = shell_surface->surface_for_testing(); @@ -544,7 +530,7 @@ pointer.reset(); } -TEST_P(PointerTest, OnPointerEnter) { +TEST_F(PointerTest, OnPointerEnter) { auto shell_surface = test::ShellSurfaceBuilder({10, 10}).BuildShellSurface(); auto* surface = shell_surface->surface_for_testing(); @@ -562,7 +548,7 @@ pointer.reset(); } -TEST_P(PointerTest, OnPointerLeave) { +TEST_F(PointerTest, OnPointerLeave) { auto shell_surface = test::ShellSurfaceBuilder({10, 10}).BuildShellSurface(); auto* surface = shell_surface->surface_for_testing(); @@ -589,7 +575,7 @@ pointer.reset(); } -TEST_P(PointerTest, OnPointerMotion) { +TEST_F(PointerTest, OnPointerMotion) { auto shell_surface = test::ShellSurfaceBuilder({10, 10}).BuildShellSurface(); auto* surface = shell_surface->surface_for_testing(); @@ -654,7 +640,7 @@ pointer.reset(); } -TEST_P(PointerTest, OnPointerButton) { +TEST_F(PointerTest, OnPointerButton) { auto shell_surface = test::ShellSurfaceBuilder({10, 10}).BuildShellSurface(); auto* surface = shell_surface->surface_for_testing(); @@ -679,7 +665,7 @@ pointer.reset(); } -TEST_P(PointerTest, OnPointerButtonWithAttemptToStartDrag) { +TEST_F(PointerTest, OnPointerButtonWithAttemptToStartDrag) { auto shell_surface = test::ShellSurfaceBuilder({10, 10}).BuildShellSurface(); auto* surface = shell_surface->surface_for_testing(); @@ -707,7 +693,7 @@ pointer.reset(); } -TEST_P(PointerTest, OnPointerScroll) { +TEST_F(PointerTest, OnPointerScroll) { auto shell_surface = test::ShellSurfaceBuilder({10, 10}).BuildShellSurface(); auto* surface = shell_surface->surface_for_testing(); @@ -737,7 +723,7 @@ pointer.reset(); } -TEST_P(PointerTest, OnPointerScrollWithThreeFinger) { +TEST_F(PointerTest, OnPointerScrollWithThreeFinger) { auto shell_surface = test::ShellSurfaceBuilder({10, 10}).BuildShellSurface(); auto* surface = shell_surface->surface_for_testing(); @@ -767,7 +753,7 @@ pointer.reset(); } -TEST_P(PointerTest, OnPointerScrollDiscrete) { +TEST_F(PointerTest, OnPointerScrollDiscrete) { auto shell_surface = test::ShellSurfaceBuilder({10, 10}).BuildShellSurface(); auto* surface = shell_surface->surface_for_testing(); @@ -790,7 +776,7 @@ pointer.reset(); } -TEST_P(PointerTest, RegisterPointerEventsOnModal) { +TEST_F(PointerTest, RegisterPointerEventsOnModal) { // Create modal surface. auto shell_surface = test::ShellSurfaceBuilder({5, 5}) .SetCentered() @@ -838,7 +824,7 @@ pointer.reset(); } -TEST_P(PointerTest, IgnorePointerEventsOnNonModalWhenModalIsOpen) { +TEST_F(PointerTest, IgnorePointerEventsOnNonModalWhenModalIsOpen) { // Create surface for non-modal window. auto shell_surface = test::ShellSurfaceBuilder({10, 10}).BuildShellSurface(); auto* surface = shell_surface->surface_for_testing(); @@ -900,7 +886,7 @@ pointer.reset(); } -TEST_P(PointerTest, IgnorePointerLeaveOnModal) { +TEST_F(PointerTest, IgnorePointerLeaveOnModal) { // Create modal surface. auto shell_surface = test::ShellSurfaceBuilder({5, 5}) .SetCentered() @@ -940,7 +926,7 @@ pointer.reset(); } -TEST_P(PointerTest, RegisterPointerEventsOnNonModal) { +TEST_F(PointerTest, RegisterPointerEventsOnNonModal) { // Create surface for non-modal window. auto shell_surface = test::ShellSurfaceBuilder({10, 10}).BuildShellSurface(); auto* surface = shell_surface->surface_for_testing(); @@ -999,7 +985,7 @@ pointer.reset(); } -TEST_P(PointerTest, DragDropAbortBeforeStart) { +TEST_F(PointerTest, DragDropAbortBeforeStart) { MockPointerDelegate delegate; auto pointer = std::make_unique<Pointer>(&delegate, seat_.get()); TestDataSourceDelegate data_source_delegate; @@ -1031,7 +1017,7 @@ pointer.reset(); } -TEST_P(PointerTest, DragDropAndPointerEnterLeaveEvents) { +TEST_F(PointerTest, DragDropAndPointerEnterLeaveEvents) { MockPointerDelegate delegate; std::unique_ptr<Pointer> pointer(new Pointer(&delegate, seat_.get())); TestDataSourceDelegate data_source_delegate; @@ -1106,7 +1092,7 @@ pointer.reset(); } -TEST_P(PointerTest, DragDropAndPointerEnterLeaveEvents_NoOpOnTouchDrag) { +TEST_F(PointerTest, DragDropAndPointerEnterLeaveEvents_NoOpOnTouchDrag) { MockPointerDelegate delegate; std::unique_ptr<Pointer> pointer(new Pointer(&delegate, seat_.get())); TestDataSourceDelegate data_source_delegate; @@ -1151,7 +1137,7 @@ pointer.reset(); } -TEST_P(PointerTest, IgnoresHandledEvents) { +TEST_F(PointerTest, IgnoresHandledEvents) { // A very dumb handler that simply marks all events as handled. This is needed // allows us to mark a mouse event as handled as it gets processed by the // event processor. @@ -1188,7 +1174,7 @@ ash::Shell::Get()->RemovePreTargetHandler(&handler); } -TEST_P(PointerTest, IgnoresCursorHideEvents) { +TEST_F(PointerTest, IgnoresCursorHideEvents) { testing::NiceMock<MockPointerDelegate> delegate; auto pointer = std::make_unique<Pointer>(&delegate, seat_.get()); @@ -1281,7 +1267,7 @@ // Test for crbug.com/1307143: It ensures no "pointer enter" event is // processed in case the target surface is destroyed during the drop action. -TEST_P(PointerTest, +TEST_F(PointerTest, DragDropAndPointerEnterLeaveEvents_NoEnterOnSurfaceDestroy) { MockPointerDelegate delegate; std::unique_ptr<Pointer> pointer(new Pointer(&delegate, seat_.get())); @@ -1343,7 +1329,7 @@ // Test for crbug.com/1307143: It ensures no "pointer enter" event is // processed in case the target surface parent is destroyed during the drop // action. -TEST_P(PointerTest, +TEST_F(PointerTest, DragDropAndPointerEnterLeaveEvents_NoEnterOnParentSurfaceDestroy) { MockPointerDelegate delegate; std::unique_ptr<Pointer> pointer(new Pointer(&delegate, seat_.get())); @@ -1399,7 +1385,7 @@ pointer.reset(); } -TEST_P(PointerTest, OnPointerRelativeMotion) { +TEST_F(PointerTest, OnPointerRelativeMotion) { auto shell_surface = test::ShellSurfaceBuilder({10, 10}).BuildShellSurface(); auto* surface = shell_surface->surface_for_testing(); @@ -1508,11 +1494,7 @@ base::test::ScopedFeatureList scoped_feature_list_; }; -INSTANTIATE_TEST_SUITE_P(All, - PointerOrdinalMotionTest, - testing::Values(false, true)); - -TEST_P(PointerOrdinalMotionTest, OrdinalMotionOverridesRelativeMotion) { +TEST_F(PointerOrdinalMotionTest, OrdinalMotionOverridesRelativeMotion) { auto shell_surface = test::ShellSurfaceBuilder({10, 10}).BuildShellSurface(); auto* surface = shell_surface->surface_for_testing(); @@ -1551,7 +1533,7 @@ pointer->UnregisterRelativePointerDelegate(&relative_delegate); } -TEST_P(PointerConstraintTest, ConstrainPointer) { +TEST_F(PointerConstraintTest, ConstrainPointer) { EXPECT_TRUE(pointer_->ConstrainPointer(&constraint_delegate_)); EXPECT_CALL(delegate_, OnPointerEnter(surface_.get(), gfx::PointF(), 0)); @@ -1588,7 +1570,7 @@ pointer_.reset(); } -TEST_P(PointerConstraintTest, CanOnlyConstrainPermittedWindows) { +TEST_F(PointerConstraintTest, CanOnlyConstrainPermittedWindows) { std::unique_ptr<ShellSurface> shell_surface = test::ShellSurfaceBuilder({10, 10}).BuildShellSurface(); EXPECT_CALL(constraint_delegate_, GetConstrainedSurface()) @@ -1604,7 +1586,7 @@ pointer_.reset(); } -TEST_P(PointerConstraintTest, OneConstraintPerSurface) { +TEST_F(PointerConstraintTest, OneConstraintPerSurface) { ON_CALL(constraint_delegate_, IsPersistent()) .WillByDefault(testing::Return(false)); EXPECT_TRUE(pointer_->ConstrainPointer(&constraint_delegate_)); @@ -1628,7 +1610,7 @@ pointer_.reset(); } -TEST_P(PointerConstraintTest, OneShotConstraintActivatedOnFirstFocus) { +TEST_F(PointerConstraintTest, OneShotConstraintActivatedOnFirstFocus) { auto second_shell_surface = BuildShellSurfaceWhichPermitsPointerLock(); Surface* second_surface = second_shell_surface->surface_for_testing(); @@ -1655,7 +1637,7 @@ pointer_.reset(); } -TEST_P(PointerConstraintTest, UnconstrainPointerWhenSurfaceIsDestroyed) { +TEST_F(PointerConstraintTest, UnconstrainPointerWhenSurfaceIsDestroyed) { EXPECT_TRUE(pointer_->ConstrainPointer(&constraint_delegate_)); EXPECT_CALL(delegate_, OnPointerEnter(surface_.get(), gfx::PointF(), 0)); @@ -1672,7 +1654,7 @@ pointer_.reset(); } -TEST_P(PointerConstraintTest, UnconstrainPointerWhenWindowLosesFocus) { +TEST_F(PointerConstraintTest, UnconstrainPointerWhenWindowLosesFocus) { ON_CALL(constraint_delegate_, IsPersistent()) .WillByDefault(testing::Return(false)); EXPECT_TRUE(pointer_->ConstrainPointer(&constraint_delegate_)); @@ -1691,7 +1673,7 @@ pointer_.reset(); } -TEST_P(PointerConstraintTest, PersistentConstraintActivatedOnRefocus) { +TEST_F(PointerConstraintTest, PersistentConstraintActivatedOnRefocus) { ON_CALL(constraint_delegate_, IsPersistent()) .WillByDefault(testing::Return(true)); EXPECT_TRUE(pointer_->ConstrainPointer(&constraint_delegate_)); @@ -1710,7 +1692,7 @@ pointer_.reset(); } -TEST_P(PointerConstraintTest, MultipleSurfacesCanBeConstrained) { +TEST_F(PointerConstraintTest, MultipleSurfacesCanBeConstrained) { // Arrange: First surface + persistent constraint ON_CALL(constraint_delegate_, IsPersistent()) .WillByDefault(testing::Return(true)); @@ -1756,7 +1738,7 @@ pointer_.reset(); } -TEST_P(PointerConstraintTest, UserActionPreventsConstraint) { +TEST_F(PointerConstraintTest, UserActionPreventsConstraint) { ON_CALL(constraint_delegate_, IsPersistent()) .WillByDefault(testing::Return(false)); EXPECT_TRUE(pointer_->ConstrainPointer(&constraint_delegate_)); @@ -1797,7 +1779,7 @@ pointer_.reset(); } -TEST_P(PointerConstraintTest, UserCanBreakAndActivatePersistentConstraint) { +TEST_F(PointerConstraintTest, UserCanBreakAndActivatePersistentConstraint) { ON_CALL(constraint_delegate_, IsPersistent()) .WillByDefault(testing::Return(true)); EXPECT_TRUE(pointer_->ConstrainPointer(&constraint_delegate_)); @@ -1822,7 +1804,7 @@ pointer_.reset(); } -TEST_P(PointerConstraintTest, NoPointerMotionEventWhenUnconstrainingPointer) { +TEST_F(PointerConstraintTest, NoPointerMotionEventWhenUnconstrainingPointer) { testing::MockFunction<void(std::string check_point_name)> check; { testing::InSequence s; @@ -1851,7 +1833,7 @@ pointer_.reset(); } -TEST_P(PointerConstraintTest, ConstrainPointerWithUncommittedShellSurface) { +TEST_F(PointerConstraintTest, ConstrainPointerWithUncommittedShellSurface) { std::unique_ptr<ShellSurface> uncommitted_shell_surface = test::ShellSurfaceBuilder({10, 10}).SetNoCommit().BuildShellSurface(); @@ -1880,7 +1862,7 @@ // This test verifies that if pointer lock is activated during a desk switch // swipe animation, that the animation is able to complete and pointer lock is // correctly set. Regression test for b/324146178. -TEST_P(PointerConstraintTest, DeskSwitchSwipeGesture) { +TEST_F(PointerConstraintTest, DeskSwitchSwipeGesture) { ui::ScopedAnimationDurationScaleMode animation_scale( ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION); @@ -1989,7 +1971,7 @@ pointer_.reset(); } -TEST_P(PointerTest, PointerStylus) { +TEST_F(PointerTest, PointerStylus) { auto shell_surface = test::ShellSurfaceBuilder({10, 10}).BuildShellSurface(); auto* surface = shell_surface->surface_for_testing(); @@ -2019,7 +2001,7 @@ pointer.reset(); } -TEST_P(PointerTest, PointerStylus2) { +TEST_F(PointerTest, PointerStylus2) { auto shell_surface = test::ShellSurfaceBuilder({10, 10}).BuildShellSurface(); auto* surface = shell_surface->surface_for_testing(); @@ -2056,7 +2038,7 @@ pointer.reset(); } -TEST_P(PointerTest, DontSendMouseEventDuringMove) { +TEST_F(PointerTest, DontSendMouseEventDuringMove) { testing::NiceMock<MockPointerDelegate> delegate; auto pointer = std::make_unique<Pointer>(&delegate, seat_.get()); @@ -2090,7 +2072,7 @@ ::testing::Mock::VerifyAndClearExpectations(&delegate); } -TEST_P(PointerTest, SetCursorWithSurfaceChange) { +TEST_F(PointerTest, SetCursorWithSurfaceChange) { auto shell_surface = test::ShellSurfaceBuilder({20, 20}).BuildShellSurface(); auto* surface = shell_surface->surface_for_testing(); @@ -2154,7 +2136,7 @@ pointer.reset(); } -TEST_P(PointerTest, SetCursorBitmapFromBuffer) { +TEST_F(PointerTest, SetCursorBitmapFromBuffer) { auto shell_surface = test::ShellSurfaceBuilder({10, 10}).BuildShellSurface(); auto* surface = shell_surface->surface_for_testing(); @@ -2221,7 +2203,7 @@ pointer.reset(); } -TEST_P(PointerConstraintTest, ConstraintPointerLockPointer) { +TEST_F(PointerConstraintTest, ConstraintPointerLockPointer) { auto* cursor_client = WMHelper::GetInstance()->GetCursorClient(); auto original_cursor = cursor_client->GetCursor(); EXPECT_TRUE(pointer_->ConstrainPointer(&constraint_delegate_));
diff --git a/components/exo/shell_surface_base.cc b/components/exo/shell_surface_base.cc index 63c65bc2..eef43ab 100644 --- a/components/exo/shell_surface_base.cc +++ b/components/exo/shell_surface_base.cc
@@ -11,7 +11,6 @@ #include "ash/display/screen_orientation_controller.h" #include "ash/frame/non_client_frame_view_ash.h" #include "ash/metrics/login_unlock_throughput_recorder.h" -#include "ash/public/cpp/rounded_corner_utils.h" #include "ash/public/cpp/window_properties.h" #include "ash/shell.h" #include "ash/wm/desks/desks_controller.h"
diff --git a/components/exo/surface_tree_host.cc b/components/exo/surface_tree_host.cc index 5180c8ce..d44e338 100644 --- a/components/exo/surface_tree_host.cc +++ b/components/exo/surface_tree_host.cc
@@ -553,9 +553,8 @@ cc::mojo_embedder::AsyncLayerTreeFrameSink::InitParams params; params.pipes.compositor_frame_sink_remote = std::move(sink_remote); params.pipes.client_receiver = std::move(client_receiver); + params.auto_needs_begin_frame = true; - params.auto_needs_begin_frame = - base::FeatureList::IsEnabled(kExoReactiveFrameSubmission); auto frame_sink = std::make_unique<cc::mojo_embedder::AsyncLayerTreeFrameSink>( nullptr /* context_provider */, nullptr /* worker_context_provider */,
diff --git a/components/exo/surface_unittest.cc b/components/exo/surface_unittest.cc index 3e6f31f..ce1cd646 100644 --- a/components/exo/surface_unittest.cc +++ b/components/exo/surface_unittest.cc
@@ -100,13 +100,9 @@ } class SurfaceTest : public test::ExoTestBase, - public ::testing::WithParamInterface< - std::tuple<test::FrameSubmissionType, float>> { + public ::testing::WithParamInterface<float> { public: - SurfaceTest() { - test::SetFrameSubmissionFeatureFlags(&feature_list_, - GetFrameSubmissionType()); - } + SurfaceTest() = default; SurfaceTest(const SurfaceTest&) = delete; SurfaceTest& operator=(const SurfaceTest&) = delete; @@ -126,10 +122,7 @@ display::Display::ResetForceDeviceScaleFactorForTesting(); } - test::FrameSubmissionType GetFrameSubmissionType() const { - return std::get<0>(GetParam()); - } - float device_scale_factor() const { return std::get<1>(GetParam()); } + float device_scale_factor() const { return GetParam(); } gfx::Rect ToPixel(const gfx::Rect rect) { return gfx::ToEnclosingRect( @@ -181,14 +174,8 @@ base::test::ScopedFeatureList feature_list_; }; -// Instantiate the values of frame submission types and device scale factor in -// the parameterized tests. -INSTANTIATE_TEST_SUITE_P( - All, - SurfaceTest, - testing::Combine(testing::Values(test::FrameSubmissionType::kNoReactive, - test::FrameSubmissionType::kReactive), - testing::Values(1.0f, 1.25f, 2.0f))); +// Instantiate the values of device scale factor in the parameterized tests. +INSTANTIATE_TEST_SUITE_P(All, SurfaceTest, testing::Values(1.0f, 1.25f, 2.0f)); TEST_P(SurfaceTest, AttachOffset) { gfx::Size buffer_size(256, 256); @@ -1814,30 +1801,7 @@ } } -// Tests that only apply if ExoReactiveFrameSubmission is enabled. -class ReactiveFrameSubmissionSurfaceTest : public SurfaceTest { - public: - ReactiveFrameSubmissionSurfaceTest() { - DCHECK_EQ(GetFrameSubmissionType(), test::FrameSubmissionType::kReactive); - } - - ReactiveFrameSubmissionSurfaceTest( - const ReactiveFrameSubmissionSurfaceTest&) = delete; - ReactiveFrameSubmissionSurfaceTest& operator=( - const ReactiveFrameSubmissionSurfaceTest&) = delete; - - ~ReactiveFrameSubmissionSurfaceTest() override = default; -}; - -// Instantiate the values of frame submission types and device scale factor in -// the parameterized tests. -INSTANTIATE_TEST_SUITE_P( - All, - ReactiveFrameSubmissionSurfaceTest, - testing::Combine(testing::Values(test::FrameSubmissionType::kReactive), - testing::Values(1.0f, 1.25f, 2.0f))); - -TEST_P(ReactiveFrameSubmissionSurfaceTest, FullDamageAfterDiscardingFrame) { +TEST_P(SurfaceTest, FullDamageAfterDiscardingFrame) { gfx::Size buffer_size(256, 256); auto buffer = test::ExoTestHelper::CreateBuffer(buffer_size); std::unique_ptr<Surface> surface(new Surface);
diff --git a/components/exo/test/surface_tree_host_test_util.cc b/components/exo/test/surface_tree_host_test_util.cc index 96a3adf..fa65ff74 100644 --- a/components/exo/test/surface_tree_host_test_util.cc +++ b/components/exo/test/surface_tree_host_test_util.cc
@@ -10,24 +10,6 @@ namespace exo::test { -void SetFrameSubmissionFeatureFlags(base::test::ScopedFeatureList* feature_list, - FrameSubmissionType frame_submission) { - switch (frame_submission) { - case FrameSubmissionType::kNoReactive: { - feature_list->InitWithFeatures( - /*enabled_features=*/{}, - /*disabled_features=*/{kExoReactiveFrameSubmission}); - break; - } - case FrameSubmissionType::kReactive: { - feature_list->InitWithFeatures( - /*enabled_features=*/{kExoReactiveFrameSubmission}, - /*disabled_features=*/{}); - break; - } - } -} - void WaitForLastFrameAck(SurfaceTreeHost* surface_tree_host) { CHECK(!surface_tree_host->GetFrameCallbacksForTesting().empty());
diff --git a/components/exo/test/surface_tree_host_test_util.h b/components/exo/test/surface_tree_host_test_util.h index fa90c197..e82492d 100644 --- a/components/exo/test/surface_tree_host_test_util.h +++ b/components/exo/test/surface_tree_host_test_util.h
@@ -12,11 +12,6 @@ namespace exo::test { -enum class FrameSubmissionType { kNoReactive = 0, kReactive = 1 }; - -void SetFrameSubmissionFeatureFlags(base::test::ScopedFeatureList* feature_list, - FrameSubmissionType frame_submission); - // Waits for the last compositor frame submitted by `surface_tree_host` to be // acked. void WaitForLastFrameAck(SurfaceTreeHost* surface_tree_host);
diff --git a/components/infobars/android/java/src/org/chromium/components/infobars/InfoBarControlLayout.java b/components/infobars/android/java/src/org/chromium/components/infobars/InfoBarControlLayout.java index ce7bb94..4a1405c 100644 --- a/components/infobars/android/java/src/org/chromium/components/infobars/InfoBarControlLayout.java +++ b/components/infobars/android/java/src/org/chromium/components/infobars/InfoBarControlLayout.java
@@ -453,7 +453,7 @@ Bitmap iconBitmap, int iconColorId, CharSequence primaryMessage, - CharSequence secondaryMessage, + @Nullable CharSequence secondaryMessage, int resourceId) { LinearLayout layout = (LinearLayout)
diff --git a/components/media_router/browser/android/java/src/org/chromium/components/media_router/BrowserMediaRouter.java b/components/media_router/browser/android/java/src/org/chromium/components/media_router/BrowserMediaRouter.java index cded6fe..eaa9d610 100644 --- a/components/media_router/browser/android/java/src/org/chromium/components/media_router/BrowserMediaRouter.java +++ b/components/media_router/browser/android/java/src/org/chromium/components/media_router/BrowserMediaRouter.java
@@ -69,13 +69,11 @@ // The pointer to the native object. Can be null during tests, or when the // native object has been destroyed. private long mNativeMediaRouterAndroidBridge; - private final List<MediaRouteProvider> mRouteProviders = new ArrayList<MediaRouteProvider>(); - private final Map<String, MediaRouteProvider> mRouteIdsToProviders = - new HashMap<String, MediaRouteProvider>(); + private final List<MediaRouteProvider> mRouteProviders = new ArrayList<>(); + private final Map<String, MediaRouteProvider> mRouteIdsToProviders = new HashMap<>(); private final Map<String, Map<MediaRouteProvider, List<MediaSink>>> mSinksPerSourcePerProvider = - new HashMap<String, Map<MediaRouteProvider, List<MediaSink>>>(); - private final Map<String, List<MediaSink>> mSinksPerSource = - new HashMap<String, List<MediaSink>>(); + new HashMap<>(); + private final Map<String, List<MediaSink>> mSinksPerSource = new HashMap<>(); public static void setRouteProviderFactoryForTest(MediaRouteProvider.Factory factory) { var oldValue = sRouteProviderFactory; @@ -118,8 +116,7 @@ public void onSinksReceived( String sourceId, MediaRouteProvider provider, List<MediaSink> sinks) { if (!mSinksPerSourcePerProvider.containsKey(sourceId)) { - mSinksPerSourcePerProvider.put( - sourceId, new HashMap<MediaRouteProvider, List<MediaSink>>()); + mSinksPerSourcePerProvider.put(sourceId, new HashMap<>()); } // Replace the sinks found by this provider with the new list. @@ -127,7 +124,7 @@ mSinksPerSourcePerProvider.get(sourceId); sinksPerProvider.put(provider, sinks); - List<MediaSink> allSinksPerSource = new ArrayList<MediaSink>(); + List<MediaSink> allSinksPerSource = new ArrayList<>(); for (List<MediaSink> s : sinksPerProvider.values()) allSinksPerSource.addAll(s); mSinksPerSource.put(sourceId, allSinksPerSource);
diff --git a/components/media_router/browser/android/java/src/org/chromium/components/media_router/ClientRecord.java b/components/media_router/browser/android/java/src/org/chromium/components/media_router/ClientRecord.java index d5c2790..5f104cd 100644 --- a/components/media_router/browser/android/java/src/org/chromium/components/media_router/ClientRecord.java +++ b/components/media_router/browser/android/java/src/org/chromium/components/media_router/ClientRecord.java
@@ -34,7 +34,7 @@ public boolean isConnected; /** The pending messages for the client. */ - public List<String> pendingMessages = new ArrayList<String>(); + public List<String> pendingMessages = new ArrayList<>(); public ClientRecord( String routeId,
diff --git a/components/media_router/browser/android/java/src/org/chromium/components/media_router/DiscoveryCallback.java b/components/media_router/browser/android/java/src/org/chromium/components/media_router/DiscoveryCallback.java index 4938a7b..b1503b9c 100644 --- a/components/media_router/browser/android/java/src/org/chromium/components/media_router/DiscoveryCallback.java +++ b/components/media_router/browser/android/java/src/org/chromium/components/media_router/DiscoveryCallback.java
@@ -23,8 +23,8 @@ public class DiscoveryCallback extends MediaRouter.Callback { private final DiscoveryDelegate mDiscoveryDelegate; private final MediaRouteSelector mRouteSelector; - private final Set<String> mSourceUrns = new HashSet<String>(); - private List<MediaSink> mSinks = new ArrayList<MediaSink>(); + private final Set<String> mSourceUrns = new HashSet<>(); + private List<MediaSink> mSinks = new ArrayList<>(); public DiscoveryCallback( String sourceUrn, DiscoveryDelegate delegate, MediaRouteSelector selector) { @@ -47,7 +47,7 @@ public void addSourceUrn(String sourceUrn) { if (mSourceUrns.add(sourceUrn)) { - mDiscoveryDelegate.onSinksReceived(sourceUrn, new ArrayList<MediaSink>(mSinks)); + mDiscoveryDelegate.onSinksReceived(sourceUrn, new ArrayList<>(mSinks)); } } @@ -101,7 +101,7 @@ private void updateBrowserMediaRouter() { for (String sourceUrn : mSourceUrns) { - mDiscoveryDelegate.onSinksReceived(sourceUrn, new ArrayList<MediaSink>(mSinks)); + mDiscoveryDelegate.onSinksReceived(sourceUrn, new ArrayList<>(mSinks)); } } }
diff --git a/components/media_router/browser/android/java/src/org/chromium/components/media_router/caf/CafBaseMediaRouteProvider.java b/components/media_router/browser/android/java/src/org/chromium/components/media_router/caf/CafBaseMediaRouteProvider.java index 0afe7798..a0d6770b 100644 --- a/components/media_router/browser/android/java/src/org/chromium/components/media_router/caf/CafBaseMediaRouteProvider.java +++ b/components/media_router/browser/android/java/src/org/chromium/components/media_router/caf/CafBaseMediaRouteProvider.java
@@ -45,9 +45,8 @@ protected static final List<MediaSink> NO_SINKS = Collections.emptyList(); private final MediaRouter mAndroidMediaRouter; protected final MediaRouteManager mManager; - protected final Map<String, DiscoveryCallback> mDiscoveryCallbacks = - new HashMap<String, DiscoveryCallback>(); - protected final Map<String, MediaRoute> mRoutes = new HashMap<String, MediaRoute>(); + protected final Map<String, DiscoveryCallback> mDiscoveryCallbacks = new HashMap<>(); + protected final Map<String, MediaRoute> mRoutes = new HashMap<>(); protected Handler mHandler = new Handler(); private @Nullable CreateRouteRequestInfo mPendingCreateRouteRequestInfo; @@ -354,7 +353,7 @@ } private List<MediaSink> getKnownSinksFromAndroidMediaRouter(MediaRouteSelector routeSelector) { - List<MediaSink> knownSinks = new ArrayList<MediaSink>(); + List<MediaSink> knownSinks = new ArrayList<>(); for (RouteInfo route : mAndroidMediaRouter.getRoutes()) { if (route.matchesSelector(routeSelector)) { knownSinks.add(MediaSink.fromRoute(route));
diff --git a/components/media_router/browser/android/java/src/org/chromium/components/media_router/caf/CafMediaRouteProvider.java b/components/media_router/browser/android/java/src/org/chromium/components/media_router/caf/CafMediaRouteProvider.java index 8eea472..028cf78 100644 --- a/components/media_router/browser/android/java/src/org/chromium/components/media_router/caf/CafMediaRouteProvider.java +++ b/components/media_router/browser/android/java/src/org/chromium/components/media_router/caf/CafMediaRouteProvider.java
@@ -38,8 +38,7 @@ @VisibleForTesting @Nullable ClientRecord mLastRemovedRouteRecord; // The records for clients, which must match mRoutes. This is used for the saving last record // for autojoin. - private final Map<String, ClientRecord> mClientIdToRecords = - new HashMap<String, ClientRecord>(); + private final Map<String, ClientRecord> mClientIdToRecords = new HashMap<>(); @VisibleForTesting CafMessageHandler mMessageHandler; // The session controller which is always attached to the current CastSession. private final CastSessionController mSessionController;
diff --git a/components/media_router/browser/android/java/src/org/chromium/components/media_router/caf/CafMessageHandler.java b/components/media_router/browser/android/java/src/org/chromium/components/media_router/caf/CafMessageHandler.java index c74a9999..0d73b415 100644 --- a/components/media_router/browser/android/java/src/org/chromium/components/media_router/caf/CafMessageHandler.java +++ b/components/media_router/browser/android/java/src/org/chromium/components/media_router/caf/CafMessageHandler.java
@@ -52,7 +52,7 @@ static final int VOID_SEQUENCE_NUMBER = -1; static final int TIMEOUT_IMMEDIATE = 0; - private static final String MEDIA_MESSAGE_TYPES[] = { + private static final String[] MEDIA_MESSAGE_TYPES = { "PLAY", "LOAD", "PAUSE", @@ -68,7 +68,7 @@ "QUEUE_REORDER", }; - private static final String MEDIA_SUPPORTED_COMMANDS[] = { + private static final String[] MEDIA_SUPPORTED_COMMANDS = { "pause", "seek", "stream_volume", "stream_mute", }; @@ -106,16 +106,17 @@ /** * Initializes a new {@link CafMessageHandler} instance. - * @param session The {@link CastSession} for communicating with the Cast SDK. + * + * @param session The {@link CastSession} for communicating with the Cast SDK. * @param provider The {@link CafMediaRouteProvider} for communicating with the page. */ public CafMessageHandler( CafMediaRouteProvider provider, CastSessionController sessionController) { mRouteProvider = provider; - mRequests = new SparseArray<RequestRecord>(); - mStopRequests = new ArrayMap<String, Queue<Integer>>(); + mRequests = new SparseArray<>(); + mStopRequests = new ArrayMap<>(); mSessionController = sessionController; - mVolumeRequests = new ArrayDeque<RequestRecord>(); + mVolumeRequests = new ArrayDeque<>(); mHandler = new Handler(); } @@ -386,7 +387,7 @@ void handleStopMessage(String clientId, int sequenceNumber) { Queue<Integer> sequenceNumbersForClient = mStopRequests.get(clientId); if (sequenceNumbersForClient == null) { - sequenceNumbersForClient = new ArrayDeque<Integer>(); + sequenceNumbersForClient = new ArrayDeque<>(); mStopRequests.put(clientId, sequenceNumbersForClient); } sequenceNumbersForClient.add(sequenceNumber);
diff --git a/components/media_router/browser/android/java/src/org/chromium/components/media_router/caf/CastSessionController.java b/components/media_router/browser/android/java/src/org/chromium/components/media_router/caf/CastSessionController.java index 58e6087..c6786df 100644 --- a/components/media_router/browser/android/java/src/org/chromium/components/media_router/caf/CastSessionController.java +++ b/components/media_router/browser/android/java/src/org/chromium/components/media_router/caf/CastSessionController.java
@@ -27,7 +27,7 @@ public class CastSessionController extends BaseSessionController { private static final String TAG = "CafSessionCtrl"; - private final List<String> mNamespaces = new ArrayList<String>(); + private final List<String> mNamespaces = new ArrayList<>(); private CastListener mCastListener; private final CafNotificationController mNotificationController; @@ -115,7 +115,7 @@ Set<String> namespacesToAdd = new HashSet<>(getSession().getApplicationMetadata().getSupportedNamespaces()); - Set<String> namespacesToRemove = new HashSet<String>(mNamespaces); + Set<String> namespacesToRemove = new HashSet<>(mNamespaces); namespacesToRemove.removeAll(namespacesToAdd); namespacesToAdd.removeAll(mNamespaces);
diff --git a/components/media_router/browser/android/javatests/src/org/chromium/components/media_router/MockMediaRouteProvider.java b/components/media_router/browser/android/javatests/src/org/chromium/components/media_router/MockMediaRouteProvider.java index 0551e57..e424593 100644 --- a/components/media_router/browser/android/javatests/src/org/chromium/components/media_router/MockMediaRouteProvider.java +++ b/components/media_router/browser/android/javatests/src/org/chromium/components/media_router/MockMediaRouteProvider.java
@@ -25,9 +25,8 @@ private MediaRouteManager mManager; - private final Map<String, MediaRoute> mRoutes = new HashMap<String, MediaRoute>(); - private final Map<String, MediaRoute> mPresentationIdToRoute = - new HashMap<String, MediaRoute>(); + private final Map<String, MediaRoute> mRoutes = new HashMap<>(); + private final Map<String, MediaRoute> mPresentationIdToRoute = new HashMap<>(); private int mSinksObservedDelayMillis; private int mCreateRouteDelayMillis; @@ -82,7 +81,7 @@ @Override public void startObservingMediaSinks(final String sourceId) { - final ArrayList<MediaSink> sinks = new ArrayList<MediaSink>(); + final ArrayList<MediaSink> sinks = new ArrayList<>(); sinks.add(new MediaSink(SINK_ID1, SINK_NAME1, null)); sinks.add(new MediaSink(SINK_ID2, SINK_NAME2, null)); PostTask.postDelayedTask( @@ -162,7 +161,7 @@ return; } mRoutes.remove(routeId); - Map<String, MediaRoute> newPresentationIdToRoute = new HashMap<String, MediaRoute>(); + Map<String, MediaRoute> newPresentationIdToRoute = new HashMap<>(); for (Map.Entry<String, MediaRoute> entry : mPresentationIdToRoute.entrySet()) { if (!entry.getValue().id.equals(routeId)) { newPresentationIdToRoute.put(entry.getKey(), entry.getValue());
diff --git a/components/media_router/browser/android/javatests/src/org/chromium/components/media_router/RouterTestUtils.java b/components/media_router/browser/android/javatests/src/org/chromium/components/media_router/RouterTestUtils.java index 3a12c2f..0206d4d 100644 --- a/components/media_router/browser/android/javatests/src/org/chromium/components/media_router/RouterTestUtils.java +++ b/components/media_router/browser/android/javatests/src/org/chromium/components/media_router/RouterTestUtils.java
@@ -30,7 +30,7 @@ public static View waitForRouteButton( final FragmentManager fragmentManager, final String chromecastName) { return waitForView( - new Callable<View>() { + new Callable<>() { @Override public View call() { Dialog mediaRouteListDialog = getDialog(fragmentManager); @@ -44,7 +44,7 @@ Log.w(TAG, "Cannot find device list"); return null; } - ArrayList<View> routesWanted = new ArrayList<View>(); + ArrayList<View> routesWanted = new ArrayList<>(); mediaRouteList.findViewsWithText( routesWanted, chromecastName, View.FIND_VIEWS_WITH_TEXT); if (routesWanted.size() == 0) {
diff --git a/components/media_router/browser/android/junit/src/org/chromium/components/media_router/BrowserMediaRouterSinkObservationTest.java b/components/media_router/browser/android/junit/src/org/chromium/components/media_router/BrowserMediaRouterSinkObservationTest.java index 94e55aaa..3baf7db 100644 --- a/components/media_router/browser/android/junit/src/org/chromium/components/media_router/BrowserMediaRouterSinkObservationTest.java +++ b/components/media_router/browser/android/junit/src/org/chromium/components/media_router/BrowserMediaRouterSinkObservationTest.java
@@ -27,7 +27,7 @@ @Test @Feature({"MediaRouter"}) public void testRouterOnSinksReceived() { - mBrowserMediaRouter.onSinksReceived(SOURCE_ID1, mRouteProvider, new ArrayList<MediaSink>()); + mBrowserMediaRouter.onSinksReceived(SOURCE_ID1, mRouteProvider, new ArrayList<>()); assertEquals(1, mBrowserMediaRouter.getSinksPerSourcePerProviderForTest().size()); assertEquals( @@ -47,9 +47,9 @@ @Test @Feature({"MediaRouter"}) public void testRouterOnSinksReceivedTwiceForOneSource() { - mBrowserMediaRouter.onSinksReceived(SOURCE_ID1, mRouteProvider, new ArrayList<MediaSink>()); + mBrowserMediaRouter.onSinksReceived(SOURCE_ID1, mRouteProvider, new ArrayList<>()); - List<MediaSink> sinkList = new ArrayList<MediaSink>(); + List<MediaSink> sinkList = new ArrayList<>(); MediaSink sink = new MediaSink(SINK_ID1, SINK_NAME1, null); sinkList.add(sink); mBrowserMediaRouter.onSinksReceived(SOURCE_ID1, mRouteProvider, sinkList); @@ -80,9 +80,9 @@ @Test @Feature({"MediaRouter"}) public void testRouterOnSinksReceivedForTwoSources() { - mBrowserMediaRouter.onSinksReceived(SOURCE_ID1, mRouteProvider, new ArrayList<MediaSink>()); + mBrowserMediaRouter.onSinksReceived(SOURCE_ID1, mRouteProvider, new ArrayList<>()); - List<MediaSink> sinkList = new ArrayList<MediaSink>(); + List<MediaSink> sinkList = new ArrayList<>(); MediaSink sink = new MediaSink(SINK_ID1, SINK_NAME1, null); sinkList.add(sink); mBrowserMediaRouter.onSinksReceived(SOURCE_ID2, mRouteProvider, sinkList);
diff --git a/components/media_router/browser/android/junit/src/org/chromium/components/media_router/DiscoveryCallbackTest.java b/components/media_router/browser/android/junit/src/org/chromium/components/media_router/DiscoveryCallbackTest.java index 68a9b8e..66c344ac 100644 --- a/components/media_router/browser/android/junit/src/org/chromium/components/media_router/DiscoveryCallbackTest.java +++ b/components/media_router/browser/android/junit/src/org/chromium/components/media_router/DiscoveryCallbackTest.java
@@ -47,9 +47,8 @@ @Test @Feature({"MediaRouter"}) public void testInitCallbackWithEmptyKnownSinks() { - List<MediaSink> knownSinks = new ArrayList<MediaSink>(); - DiscoveryCallback callback = - new DiscoveryCallback(SOURCE_ID1, knownSinks, mDiscoveryDelegate, null); + List<MediaSink> knownSinks = new ArrayList<>(); + new DiscoveryCallback(SOURCE_ID1, knownSinks, mDiscoveryDelegate, null); verify(mDiscoveryDelegate).onSinksReceived(eq(SOURCE_ID1), eq(knownSinks)); } @@ -57,10 +56,9 @@ @Test @Feature({"MediaRouter"}) public void testInitCallbackWithNonemptyKnownSinks() { - List<MediaSink> knownSinks = new ArrayList<MediaSink>(); - MediaSink sink = new MediaSink(SINK_ID1, SINK_NAME1, null); - DiscoveryCallback callback = - new DiscoveryCallback(SOURCE_ID1, knownSinks, mDiscoveryDelegate, null); + List<MediaSink> knownSinks = new ArrayList<>(); + new MediaSink(SINK_ID1, SINK_NAME1, null); + new DiscoveryCallback(SOURCE_ID1, knownSinks, mDiscoveryDelegate, null); verify(mDiscoveryDelegate).onSinksReceived(eq(SOURCE_ID1), eq(knownSinks)); } @@ -68,12 +66,12 @@ @Test @Feature({"MediaRouter"}) public void testCallbackAddOneSink() { - List<MediaSink> knownSinks = new ArrayList<MediaSink>(); + List<MediaSink> knownSinks = new ArrayList<>(); DiscoveryCallback callback = new DiscoveryCallback(SOURCE_ID1, knownSinks, mDiscoveryDelegate, null); callback.onRouteAdded(null, createMockRouteInfo(SINK_ID1, SINK_NAME1)); - List<MediaSink> expectedSinks = new ArrayList<MediaSink>(); + List<MediaSink> expectedSinks = new ArrayList<>(); expectedSinks.add(new MediaSink(SINK_ID1, SINK_NAME1, null)); verify(mDiscoveryDelegate).onSinksReceived(eq(SOURCE_ID1), eq(expectedSinks)); } @@ -81,13 +79,13 @@ @Test @Feature({"MediaRouter"}) public void testCallbackAddTwoSinks() { - List<MediaSink> knownSinks = new ArrayList<MediaSink>(); + List<MediaSink> knownSinks = new ArrayList<>(); DiscoveryCallback callback = new DiscoveryCallback(SOURCE_ID1, knownSinks, mDiscoveryDelegate, null); callback.onRouteAdded(null, createMockRouteInfo(SINK_ID1, SINK_NAME1)); callback.onRouteAdded(null, createMockRouteInfo(SINK_ID2, SINK_NAME2)); - List<MediaSink> expectedSinks = new ArrayList<MediaSink>(); + List<MediaSink> expectedSinks = new ArrayList<>(); expectedSinks.add(new MediaSink(SINK_ID1, SINK_NAME1, null)); expectedSinks.add(new MediaSink(SINK_ID2, SINK_NAME2, null)); verify(mDiscoveryDelegate).onSinksReceived(eq(SOURCE_ID1), eq(expectedSinks)); @@ -96,13 +94,13 @@ @Test @Feature({"MediaRouter"}) public void testCallbackAddDuplicateSink() { - List<MediaSink> knownSinks = new ArrayList<MediaSink>(); + List<MediaSink> knownSinks = new ArrayList<>(); DiscoveryCallback callback = new DiscoveryCallback(SOURCE_ID1, knownSinks, mDiscoveryDelegate, null); callback.onRouteAdded(null, createMockRouteInfo(SINK_ID1, SINK_NAME1)); callback.onRouteAdded(null, createMockRouteInfo(SINK_ID1, SINK_NAME1)); - List<MediaSink> expectedSinks = new ArrayList<MediaSink>(); + List<MediaSink> expectedSinks = new ArrayList<>(); expectedSinks.add(new MediaSink(SINK_ID1, SINK_NAME1, null)); // Only expect one time. The duplicate add will not be notified. verify(mDiscoveryDelegate).onSinksReceived(eq(SOURCE_ID1), eq(expectedSinks)); @@ -111,14 +109,14 @@ @Test @Feature({"MediaRouter"}) public void testCallbackRemoveSink() { - List<MediaSink> knownSinks = new ArrayList<MediaSink>(); + List<MediaSink> knownSinks = new ArrayList<>(); DiscoveryCallback callback = new DiscoveryCallback(SOURCE_ID1, knownSinks, mDiscoveryDelegate, null); callback.onRouteAdded(null, createMockRouteInfo(SINK_ID1, SINK_NAME1)); callback.onRouteRemoved(null, createMockRouteInfo(SINK_ID1, SINK_NAME1)); - List<MediaSink> expectedSinks = new ArrayList<MediaSink>(); + List<MediaSink> expectedSinks = new ArrayList<>(); // One time for init, one time for remove. verify(mDiscoveryDelegate, times(2)).onSinksReceived(eq(SOURCE_ID1), eq(expectedSinks)); } @@ -126,14 +124,14 @@ @Test @Feature({"MediaRouter"}) public void testCallbackRemoveNonexistingSink() { - List<MediaSink> knownSinks = new ArrayList<MediaSink>(); + List<MediaSink> knownSinks = new ArrayList<>(); DiscoveryCallback callback = new DiscoveryCallback(SOURCE_ID1, knownSinks, mDiscoveryDelegate, null); callback.onRouteAdded(null, createMockRouteInfo(SINK_ID1, SINK_NAME1)); callback.onRouteRemoved(null, createMockRouteInfo(SINK_ID2, SINK_NAME2)); - List<MediaSink> expectedSinks = new ArrayList<MediaSink>(); + List<MediaSink> expectedSinks = new ArrayList<>(); // Only one time for init. verify(mDiscoveryDelegate, times(1)).onSinksReceived(eq(SOURCE_ID1), eq(expectedSinks)); } @@ -141,12 +139,12 @@ @Test @Feature({"MediaRouter"}) public void testCallbackChangeRouteAddsOneSink() { - List<MediaSink> knownSinks = new ArrayList<MediaSink>(); + List<MediaSink> knownSinks = new ArrayList<>(); DiscoveryCallback callback = new DiscoveryCallback(SOURCE_ID1, knownSinks, mDiscoveryDelegate, null); callback.onRouteChanged(null, createMockRouteInfo(SINK_ID1, SINK_NAME1)); - List<MediaSink> expectedSinks = new ArrayList<MediaSink>(); + List<MediaSink> expectedSinks = new ArrayList<>(); expectedSinks.add(new MediaSink(SINK_ID1, SINK_NAME1, null)); verify(mDiscoveryDelegate).onSinksReceived(eq(SOURCE_ID1), eq(expectedSinks)); } @@ -154,7 +152,7 @@ @Test @Feature({"MediaRouter"}) public void testCallbackRemoveSinkAfterRouteChanged() { - List<MediaSink> knownSinks = new ArrayList<MediaSink>(); + List<MediaSink> knownSinks = new ArrayList<>(); DiscoveryCallback callback = new DiscoveryCallback(SOURCE_ID1, knownSinks, mDiscoveryDelegate, null); @@ -164,7 +162,7 @@ doReturn(false).when(info).matchesSelector((MediaRouteSelector) isNull()); callback.onRouteChanged(null, info); - List<MediaSink> expectedSinks = new ArrayList<MediaSink>(); + List<MediaSink> expectedSinks = new ArrayList<>(); // One time for init, one time for remove. verify(mDiscoveryDelegate, times(2)).onSinksReceived(eq(SOURCE_ID1), eq(expectedSinks)); } @@ -172,14 +170,14 @@ @Test @Feature({"MediaRouter"}) public void testCallbackAddSourceUrn() { - List<MediaSink> knownSinks = new ArrayList<MediaSink>(); + List<MediaSink> knownSinks = new ArrayList<>(); DiscoveryCallback callback = new DiscoveryCallback(SOURCE_ID1, knownSinks, mDiscoveryDelegate, null); callback.onRouteAdded(null, createMockRouteInfo(SINK_ID1, SINK_NAME1)); callback.addSourceUrn(SOURCE_ID2); - List<MediaSink> expectedSinks = new ArrayList<MediaSink>(); + List<MediaSink> expectedSinks = new ArrayList<>(); expectedSinks.add(new MediaSink(SINK_ID1, SINK_NAME1, null)); verify(mDiscoveryDelegate).onSinksReceived(eq(SOURCE_ID2), eq(expectedSinks)); } @@ -187,14 +185,14 @@ @Test @Feature({"MediaRouter"}) public void testCallbackAddDuplicateSourceUrn() { - List<MediaSink> knownSinks = new ArrayList<MediaSink>(); + List<MediaSink> knownSinks = new ArrayList<>(); DiscoveryCallback callback = new DiscoveryCallback(SOURCE_ID1, knownSinks, mDiscoveryDelegate, null); callback.onRouteAdded(null, createMockRouteInfo(SINK_ID1, SINK_NAME1)); callback.addSourceUrn(SOURCE_ID1); - List<MediaSink> expectedSinks = new ArrayList<MediaSink>(); + List<MediaSink> expectedSinks = new ArrayList<>(); expectedSinks.add(new MediaSink(SINK_ID1, SINK_NAME1, null)); // Only the one time after onRouteAdded(). verify(mDiscoveryDelegate).onSinksReceived(eq(SOURCE_ID1), eq(expectedSinks)); @@ -203,7 +201,7 @@ @Test @Feature({"MediaRouter"}) public void testCallbackRemoveSourceUrn() { - List<MediaSink> knownSinks = new ArrayList<MediaSink>(); + List<MediaSink> knownSinks = new ArrayList<>(); DiscoveryCallback callback = new DiscoveryCallback(SOURCE_ID1, knownSinks, mDiscoveryDelegate, null); @@ -212,7 +210,7 @@ callback.removeSourceUrn(SOURCE_ID1); assertFalse(callback.containsSourceUrn(SOURCE_ID1)); - List<MediaSink> expectedSinks = new ArrayList<MediaSink>(); + List<MediaSink> expectedSinks = new ArrayList<>(); // Only the one time for init. verify(mDiscoveryDelegate).onSinksReceived(eq(SOURCE_ID1), eq(expectedSinks)); } @@ -220,14 +218,14 @@ @Test @Feature({"MediaRouter"}) public void testCallbackRemoveNonexistingSourceUrn() { - List<MediaSink> knownSinks = new ArrayList<MediaSink>(); + List<MediaSink> knownSinks = new ArrayList<>(); DiscoveryCallback callback = new DiscoveryCallback(SOURCE_ID1, knownSinks, mDiscoveryDelegate, null); callback.onRouteAdded(null, createMockRouteInfo(SINK_ID1, SINK_NAME1)); callback.removeSourceUrn(SOURCE_ID2); - List<MediaSink> expectedSinks = new ArrayList<MediaSink>(); + List<MediaSink> expectedSinks = new ArrayList<>(); // Only the one time for init. verify(mDiscoveryDelegate, never()).onSinksReceived(eq(SOURCE_ID2), eq(expectedSinks)); }
diff --git a/components/media_router/browser/android/junit/src/org/chromium/components/media_router/caf/CafMediaRouteProviderTest.java b/components/media_router/browser/android/junit/src/org/chromium/components/media_router/caf/CafMediaRouteProviderTest.java index 7398114..ea32f7e 100644 --- a/components/media_router/browser/android/junit/src/org/chromium/components/media_router/caf/CafMediaRouteProviderTest.java +++ b/components/media_router/browser/android/junit/src/org/chromium/components/media_router/caf/CafMediaRouteProviderTest.java
@@ -267,7 +267,7 @@ doReturn(mCastSession).when(mSessionManager).getCurrentCastSession(); doReturn(null).when(mSessionController).getSession(); doAnswer( - new Answer<Void>() { + new Answer<>() { @Override public Void answer(InvocationOnMock invocation) { doReturn(invocation.getArguments()[0])
diff --git a/components/media_router/browser/android/junit/src/org/chromium/components/media_router/caf/CafMessageHandlerTest.java b/components/media_router/browser/android/junit/src/org/chromium/components/media_router/caf/CafMessageHandlerTest.java index 9a2a9a16..371de49 100644 --- a/components/media_router/browser/android/junit/src/org/chromium/components/media_router/caf/CafMessageHandlerTest.java +++ b/components/media_router/browser/android/junit/src/org/chromium/components/media_router/caf/CafMessageHandlerTest.java
@@ -110,7 +110,7 @@ } void setUpForAppMessageTest() throws JSONException { - List<String> namespaces = new ArrayList<String>(); + List<String> namespaces = new ArrayList<>(); namespaces.add(NAMESPACE1); doReturn(namespaces).when(mSessionController).getNamespaces(); doReturn(true) @@ -900,7 +900,7 @@ .when(mMessageHandler) .sendEnclosedMessageToClient(anyString(), anyString(), anyString(), anyInt()); assertEquals(0, mMessageHandler.getStopRequestsForTest().size()); - mMessageHandler.getStopRequestsForTest().put(CLIENT_ID1, new ArrayDeque<Integer>()); + mMessageHandler.getStopRequestsForTest().put(CLIENT_ID1, new ArrayDeque<>()); mMessageHandler.getStopRequestsForTest().get(CLIENT_ID1).add(SEQUENCE_NUMBER1); mMessageHandler.getStopRequestsForTest().get(CLIENT_ID1).add(SEQUENCE_NUMBER2); assertEquals(1, mMessageHandler.getStopRequestsForTest().size());
diff --git a/components/media_router/browser/android/junit/src/org/chromium/components/media_router/caf/CastSessionControllerTest.java b/components/media_router/browser/android/junit/src/org/chromium/components/media_router/caf/CastSessionControllerTest.java index ddfe350..d33dca4 100644 --- a/components/media_router/browser/android/junit/src/org/chromium/components/media_router/caf/CastSessionControllerTest.java +++ b/components/media_router/browser/android/junit/src/org/chromium/components/media_router/caf/CastSessionControllerTest.java
@@ -17,8 +17,6 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; -import android.content.Context; - import com.google.android.gms.cast.ApplicationMetadata; import com.google.android.gms.cast.Cast; import com.google.android.gms.cast.CastDevice; @@ -35,14 +33,11 @@ import org.mockito.MockitoAnnotations; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; -import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import org.chromium.base.test.BaseRobolectricTestRunner; import org.chromium.components.media_router.CastSessionUtil; import org.chromium.components.media_router.MediaRouterClient; -import org.chromium.components.media_router.MediaSink; -import org.chromium.components.media_router.MediaSource; import org.chromium.components.media_router.TestMediaRouterClient; import java.util.ArrayList; @@ -54,16 +49,11 @@ public class CastSessionControllerTest { @Mock private CastDevice mCastDevice; @Mock private CafMediaRouteProvider mProvider; - @Mock private MediaSource mSource; - @Mock private MediaSink mSink; @Mock private CastSession mCastSession; @Mock private RemoteMediaClient mRemoteMediaClient; @Mock private CafMessageHandler mMessageHandler; @Mock private ApplicationMetadata mApplicationMetadata; private CastSessionController mController; - private CreateRouteRequestInfo mRequestInfo; - private MediaRouterTestHelper mMediaRouterHelper; - private Context mContext; @Before public void setUp() { @@ -71,8 +61,6 @@ MediaRouterClient.setInstance(new TestMediaRouterClient()); - mContext = RuntimeEnvironment.application; - mMediaRouterHelper = new MediaRouterTestHelper(); mController = spy(new CastSessionController(mProvider)); mController.initNestedFieldsForTesting(); @@ -144,7 +132,6 @@ @Test public void testUpdateNamespaces() throws Exception { org.robolectric.shadows.ShadowLog.stream = System.out; - InOrder inOrder = inOrder(mCastSession); mController.attachToCastSession(mCastSession); @@ -152,7 +139,7 @@ List<String> observedNamespaces = new ArrayList<>(); doReturn(namespaces).when(mApplicationMetadata).getSupportedNamespaces(); doAnswer( - new Answer<Void>() { + new Answer<>() { @Override public Void answer(InvocationOnMock invocation) { observedNamespaces.add((String) invocation.getArguments()[0]); @@ -163,7 +150,7 @@ .setMessageReceivedCallbacks( any(String.class), any(Cast.MessageReceivedCallback.class)); doAnswer( - new Answer<Void>() { + new Answer<>() { @Override public Void answer(InvocationOnMock invocation) { observedNamespaces.remove((String) invocation.getArguments()[0]);
diff --git a/components/media_router/browser/android/junit/src/org/chromium/components/media_router/caf/MediaRouterTestHelper.java b/components/media_router/browser/android/junit/src/org/chromium/components/media_router/caf/MediaRouterTestHelper.java index 7aa8bf6..24d75d5 100644 --- a/components/media_router/browser/android/junit/src/org/chromium/components/media_router/caf/MediaRouterTestHelper.java +++ b/components/media_router/browser/android/junit/src/org/chromium/components/media_router/caf/MediaRouterTestHelper.java
@@ -30,7 +30,7 @@ setUpRoutes(); ShadowMediaRouter.setImplementation(mShadowMediaRouter); doAnswer( - new Answer<Void>() { + new Answer<>() { @Override public Void answer(InvocationOnMock invocation) { selectRoute(getDefaultRoute()); @@ -84,7 +84,7 @@ private void setUpRouteStubs(MediaRouter.RouteInfo routeInfo) { doAnswer( - new Answer<Void>() { + new Answer<>() { @Override public Void answer(InvocationOnMock invocation) { selectRoute(routeInfo);
diff --git a/components/media_router/test/android/cast_emulator/src/org/chromium/components/media_router/cast_emulator/TestMediaRouteProvider.java b/components/media_router/test/android/cast_emulator/src/org/chromium/components/media_router/cast_emulator/TestMediaRouteProvider.java index 13d724d..9dbcae3 100644 --- a/components/media_router/test/android/cast_emulator/src/org/chromium/components/media_router/cast_emulator/TestMediaRouteProvider.java +++ b/components/media_router/test/android/cast_emulator/src/org/chromium/components/media_router/cast_emulator/TestMediaRouteProvider.java
@@ -26,7 +26,7 @@ final class TestMediaRouteProvider extends MediaRouteProvider { private static final String TAG = "TestMRP"; - private final List<RoutePublisher> mRoutePublishers = new ArrayList<RoutePublisher>(); + private final List<RoutePublisher> mRoutePublishers = new ArrayList<>(); public TestMediaRouteProvider(Context context) { super(context);
diff --git a/components/media_router/test/android/cast_emulator/src/org/chromium/components/media_router/cast_emulator/remote/RemotePlaybackRoutePublisher.java b/components/media_router/test/android/cast_emulator/src/org/chromium/components/media_router/cast_emulator/remote/RemotePlaybackRoutePublisher.java index 92627e9d..0ad7ef32 100644 --- a/components/media_router/test/android/cast_emulator/src/org/chromium/components/media_router/cast_emulator/remote/RemotePlaybackRoutePublisher.java +++ b/components/media_router/test/android/cast_emulator/src/org/chromium/components/media_router/cast_emulator/remote/RemotePlaybackRoutePublisher.java
@@ -49,7 +49,7 @@ private int mVolume = 5; private final MediaRouteProvider mProvider; - private final List<String> mControlCategories = new ArrayList<String>(); + private final List<String> mControlCategories = new ArrayList<>(); public RemotePlaybackRoutePublisher(MediaRouteProvider provider) { mProvider = provider; @@ -100,7 +100,7 @@ f2.addAction(MediaControlIntent.ACTION_END_SESSION); f2.addAction(CastMediaControlIntent.ACTION_SYNC_STATUS); - ArrayList<IntentFilter> controlFilters = new ArrayList<IntentFilter>(); + ArrayList<IntentFilter> controlFilters = new ArrayList<>(); controlFilters.add(f1); controlFilters.add(f2);
diff --git a/components/media_router/test/android/cast_emulator/src/org/chromium/components/media_router/cast_emulator/router/DummyRoutePublisher.java b/components/media_router/test/android/cast_emulator/src/org/chromium/components/media_router/cast_emulator/router/DummyRoutePublisher.java index a3b9aff8..03bc6ee 100644 --- a/components/media_router/test/android/cast_emulator/src/org/chromium/components/media_router/cast_emulator/router/DummyRoutePublisher.java +++ b/components/media_router/test/android/cast_emulator/src/org/chromium/components/media_router/cast_emulator/router/DummyRoutePublisher.java
@@ -52,7 +52,7 @@ filter.addDataScheme("https"); filter.addDataScheme("file"); - ArrayList<IntentFilter> controlFilters = new ArrayList<IntentFilter>(); + ArrayList<IntentFilter> controlFilters = new ArrayList<>(); controlFilters.add(filter); MediaRouteDescriptor testRouteDescriptor1 =
diff --git a/components/omnibox/browser/omnibox_edit_model.cc b/components/omnibox/browser/omnibox_edit_model.cc index dbbee84..3707706 100644 --- a/components/omnibox/browser/omnibox_edit_model.cc +++ b/components/omnibox/browser/omnibox_edit_model.cc
@@ -63,6 +63,7 @@ #include "components/omnibox/browser/verbatim_match.h" #include "components/omnibox/common/omnibox_feature_configs.h" #include "components/omnibox/common/omnibox_features.h" +#include "components/omnibox/common/omnibox_focus_state.h" #include "components/prefs/pref_service.h" #include "components/search_engines/search_engine_type.h" #include "components/search_engines/template_url.h" @@ -273,8 +274,9 @@ // Restore the autocomplete controller's input, or clear it if this is a new // tab. input_ = state ? state->autocomplete_input : AutocompleteInput(); - if (!state) + if (!state) { return; + } // The tab-management system saves the last-focused control for each tab and // restores it. That operation also updates this edit model's focus_state_ @@ -286,9 +288,20 @@ // However, in some circumstances (if the last-focused control was destroyed), // the Omnibox will be focused by default, and the edit model's saved state // may be invalid. We make a check to guard against that. - bool saved_focus_state_invalid = focus_state_ == OMNIBOX_FOCUS_VISIBLE && - state->focus_state == OMNIBOX_FOCUS_NONE; - if (!saved_focus_state_invalid) { + // + // The experiment with `features::kOmniboxRestoreInvisibleFocusOnly` explores + // only restoring focus when needed due to one of the states being the + // "invisible focus" state. + const bool saved_focus_state_invalid = + focus_state_ == OMNIBOX_FOCUS_VISIBLE && + state->focus_state == OMNIBOX_FOCUS_NONE; + const bool invisible_focus_changed = + focus_state_ == OMNIBOX_FOCUS_INVISIBLE || + state->focus_state == OMNIBOX_FOCUS_INVISIBLE; + + if (base::FeatureList::IsEnabled(omnibox::kOmniboxRestoreInvisibleFocusOnly) + ? invisible_focus_changed + : !saved_focus_state_invalid) { SetFocusState(state->focus_state, OMNIBOX_FOCUS_CHANGE_TAB_SWITCH); }
diff --git a/components/omnibox/browser/omnibox_edit_model_unittest.cc b/components/omnibox/browser/omnibox_edit_model_unittest.cc index 7c625e2..8c06ebd8b 100644 --- a/components/omnibox/browser/omnibox_edit_model_unittest.cc +++ b/components/omnibox/browser/omnibox_edit_model_unittest.cc
@@ -35,6 +35,7 @@ #include "components/omnibox/browser/test_scheme_classifier.h" #include "components/omnibox/browser/unscoped_extension_provider.h" #include "components/omnibox/common/omnibox_features.h" +#include "components/omnibox/common/omnibox_focus_state.h" #include "components/prefs/testing_pref_service.h" #include "components/url_formatter/url_fixer.h" #include "extensions/buildflags/buildflags.h" @@ -344,6 +345,10 @@ // The tab-switching system sometimes focuses the Omnibox even if it was not // previously focused. In those cases, ignore the saved focus state. TEST_F(OmniboxEditModelTest, IgnoreInvalidSavedFocusStates) { + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitWithFeatures( + {}, {omnibox::kOmniboxRestoreInvisibleFocusOnly}); + // The Omnibox starts out unfocused. Save that state. ASSERT_FALSE(model()->has_focus()); OmniboxEditModel::State state = model()->GetStateForTabSwitch(); @@ -358,6 +363,47 @@ EXPECT_TRUE(model()->is_caret_visible()); } +TEST_F(OmniboxEditModelTest, RestoreInvisibleFocusOnlyForVisibleState) { + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitWithFeatures( + {omnibox::kOmniboxRestoreInvisibleFocusOnly}, {}); + + // The Omnibox starts out focused. Save that state. + model()->OnSetFocus(false); + ASSERT_TRUE(model()->has_focus()); + OmniboxEditModel::State state = model()->GetStateForTabSwitch(); + ASSERT_EQ(OMNIBOX_FOCUS_VISIBLE, state.focus_state); + + // Remove focus from the Omnibox and confirm it no longer has focus. + model()->OnKillFocus(); + ASSERT_FALSE(model()->has_focus()); + + // Restoring the old saved state should not clobber the model's focus state. + model()->RestoreState(&state); + EXPECT_FALSE(model()->has_focus()); +} + +TEST_F(OmniboxEditModelTest, RestoreInvisibleFocusOnlyForInvisibleState) { + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitWithFeatures( + {omnibox::kOmniboxRestoreInvisibleFocusOnly}, {}); + + // The Omnibox starts out invisibly focused. Save that state. + model()->OnSetFocus(false); + model()->SetCaretVisibility(false); + ASSERT_TRUE(model()->has_focus()); + OmniboxEditModel::State state = model()->GetStateForTabSwitch(); + ASSERT_EQ(OMNIBOX_FOCUS_INVISIBLE, state.focus_state); + + // Remove focus from the Omnibox and confirm it no longer has focus. + model()->OnKillFocus(); + ASSERT_FALSE(model()->has_focus()); + + // Restoring the old saved state should clobber the model's focus state. + model()->RestoreState(&state); + EXPECT_TRUE(model()->has_focus()); +} + // Tests ConsumeCtrlKey() consumes ctrl key when down, but does not affect ctrl // state otherwise. TEST_F(OmniboxEditModelTest, ConsumeCtrlKey) {
diff --git a/components/omnibox/common/omnibox_features.cc b/components/omnibox/common/omnibox_features.cc index 85ac2a36..a884b3b4 100644 --- a/components/omnibox/common/omnibox_features.cc +++ b/components/omnibox/common/omnibox_features.cc
@@ -452,4 +452,10 @@ "PreconnectNonSearchOmniboxSuggestions", DISABLED); +// Enables restricting omnibox focus restoration to only situations that involve +// "invisible focus". +BASE_FEATURE(kOmniboxRestoreInvisibleFocusOnly, + "OmniboxRestoreInvisibleFocusOnly", + DISABLED); + } // namespace omnibox
diff --git a/components/omnibox/common/omnibox_features.h b/components/omnibox/common/omnibox_features.h index bc168c29..5a2441b 100644 --- a/components/omnibox/common/omnibox_features.h +++ b/components/omnibox/common/omnibox_features.h
@@ -158,6 +158,9 @@ // Preconnect/prerender behavior for suggestions BASE_DECLARE_FEATURE(kPreconnectNonSearchOmniboxSuggestions); +// Only restore focus when invisible. +BASE_DECLARE_FEATURE(kOmniboxRestoreInvisibleFocusOnly); + } // namespace omnibox #endif // COMPONENTS_OMNIBOX_COMMON_OMNIBOX_FEATURES_H_
diff --git a/components/optimization_guide/content/browser/page_content_proto_provider_browsertest.cc b/components/optimization_guide/content/browser/page_content_proto_provider_browsertest.cc index 76db9c4..1a7bf11 100644 --- a/components/optimization_guide/content/browser/page_content_proto_provider_browsertest.cc +++ b/components/optimization_guide/content/browser/page_content_proto_provider_browsertest.cc
@@ -365,6 +365,30 @@ } IN_PROC_BROWSER_TEST_F(PageContentProtoProviderBrowserTest, + ClickabilityReason) { + LoadPage(https_server()->GetURL("/clickability_reason.html"), + ActionableAIPageContentOptions()); + EXPECT_EQ(page_content().version(), + optimization_guide::proto:: + ANNOTATED_PAGE_CONTENT_VERSION_ONLY_ACTIONABLE_ELEMENTS_1_0); + + const auto& button_node = ActionableContentRootNode().children_nodes()[0]; + ASSERT_TRUE(button_node.content_attributes().has_interaction_info()); + EXPECT_THAT( + button_node.content_attributes() + .interaction_info() + .debug_clickability_reasons(), + testing::UnorderedElementsAre( + optimization_guide::proto::CLICKABILITY_REASON_CLICKABLE_CONTROL, + optimization_guide::proto::CLICKABILITY_REASON_CLICK_HANDLER, + optimization_guide::proto::CLICKABILITY_REASON_MOUSE_EVENTS, + optimization_guide::proto::CLICKABILITY_REASON_KEY_EVENTS, + optimization_guide::proto::CLICKABILITY_REASON_EDITABLE, + optimization_guide::proto::CLICKABILITY_REASON_CURSOR_POINTER, + optimization_guide::proto::CLICKABILITY_REASON_ARIA_ROLE)); +} + +IN_PROC_BROWSER_TEST_F(PageContentProtoProviderBrowserTest, LabelNotActionable) { LoadPage(https_server()->GetURL("/label_not_actionable.html"), ActionableAIPageContentOptions());
diff --git a/components/optimization_guide/content/browser/page_content_proto_util.cc b/components/optimization_guide/content/browser/page_content_proto_util.cc index ad416b1..4aec3518 100644 --- a/components/optimization_guide/content/browser/page_content_proto_util.cc +++ b/components/optimization_guide/content/browser/page_content_proto_util.cc
@@ -37,6 +37,27 @@ namespace { +optimization_guide::proto::ClickabilityReason ConvertClickabilityReason( + blink::mojom::AIPageContentClickabilityReason reason) { + switch (reason) { + case blink::mojom::AIPageContentClickabilityReason::kClickableControl: + return optimization_guide::proto::CLICKABILITY_REASON_CLICKABLE_CONTROL; + case blink::mojom::AIPageContentClickabilityReason::kClickEvents: + return optimization_guide::proto::CLICKABILITY_REASON_CLICK_HANDLER; + case blink::mojom::AIPageContentClickabilityReason::kMouseEvents: + return optimization_guide::proto::CLICKABILITY_REASON_MOUSE_EVENTS; + case blink::mojom::AIPageContentClickabilityReason::kKeyEvents: + return optimization_guide::proto::CLICKABILITY_REASON_KEY_EVENTS; + case blink::mojom::AIPageContentClickabilityReason::kEditable: + return optimization_guide::proto::CLICKABILITY_REASON_EDITABLE; + case blink::mojom::AIPageContentClickabilityReason::kCursorPointer: + return optimization_guide::proto::CLICKABILITY_REASON_CURSOR_POINTER; + case blink::mojom::AIPageContentClickabilityReason::kAriaRole: + return optimization_guide::proto::CLICKABILITY_REASON_ARIA_ROLE; + } + NOTREACHED(); +} + optimization_guide::proto::ContentAttributeType ConvertAttributeType( blink::mojom::AIPageContentAttributeType type) { switch (type) { @@ -180,6 +201,12 @@ proto_interaction_info->set_document_scoped_z_order( *mojom_node_interaction_info.document_scoped_z_order); } + + for (const auto& reason : + mojom_node_interaction_info.debug_clickability_reasons) { + proto_interaction_info->add_debug_clickability_reasons( + ConvertClickabilityReason(reason)); + } } void ConvertPoint(const gfx::Point& mojom_point,
diff --git a/components/optimization_guide/core/optimization_guide_features.cc b/components/optimization_guide/core/optimization_guide_features.cc index 6909cd5..46bf32b 100644 --- a/components/optimization_guide/core/optimization_guide_features.cc +++ b/components/optimization_guide/core/optimization_guide_features.cc
@@ -191,7 +191,7 @@ BASE_FEATURE(kAiSettingsPageEnterpriseDisabledUi, "AiSettingsPageEnterpriseDisabledUi", - base::FEATURE_DISABLED_BY_DEFAULT); + base::FEATURE_ENABLED_BY_DEFAULT); BASE_FEATURE(kOnDeviceModelPerformanceParams, "OnDeviceModelPerformanceParams",
diff --git a/components/payments/content/android/payment_feature_map.cc b/components/payments/content/android/payment_feature_map.cc index 0c6dd5e2..8041511 100644 --- a/components/payments/content/android/payment_feature_map.cc +++ b/components/payments/content/android/payment_feature_map.cc
@@ -59,7 +59,7 @@ // Android only features. BASE_FEATURE(kAndroidPaymentIntentsOmitDeprecatedParameters, "AndroidPaymentIntentsOmitDeprecatedParameters", - base::FEATURE_ENABLED_BY_DEFAULT); + base::FEATURE_DISABLED_BY_DEFAULT); BASE_FEATURE(kGooglePayViaAndroidIntents, "GooglePayViaAndroidIntents", base::FEATURE_DISABLED_BY_DEFAULT);
diff --git a/components/permissions/android/BUILD.gn b/components/permissions/android/BUILD.gn index 0069f22..377c690 100644 --- a/components/permissions/android/BUILD.gn +++ b/components/permissions/android/BUILD.gn
@@ -203,6 +203,7 @@ android_library("core_java") { srcjar_deps = [ ":core_jni" ] sources = [ + "java/src/org/chromium/components/permissions/ApproximateGeolocationPromptArm.java", "java/src/org/chromium/components/permissions/PermissionUtil.java", "java/src/org/chromium/components/permissions/PermissionsAndroidFeatureList.java", "java/src/org/chromium/components/permissions/PermissionsAndroidFeatureMap.java", @@ -215,6 +216,7 @@ "//components/location/android:location_java", "//components/webxr/android:features_java", "//device/vr/public:java", + "//third_party/androidx:androidx_annotation_annotation_java", "//third_party/androidx:androidx_core_core_java", "//third_party/jni_zero:jni_zero_java", "//ui/android:ui_no_recycler_view_java",
diff --git a/components/permissions/android/java/src/org/chromium/components/permissions/ApproximateGeolocationPromptArm.java b/components/permissions/android/java/src/org/chromium/components/permissions/ApproximateGeolocationPromptArm.java new file mode 100644 index 0000000..502efdfb --- /dev/null +++ b/components/permissions/android/java/src/org/chromium/components/permissions/ApproximateGeolocationPromptArm.java
@@ -0,0 +1,33 @@ +// Copyright 2025 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.components.permissions; + +import androidx.annotation.IntDef; + +import org.chromium.build.annotations.NullMarked; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@NullMarked +@IntDef({ + ApproximateGeolocationPromptArm.NO_ARM_SELECTED, + ApproximateGeolocationPromptArm.ARM_1, + ApproximateGeolocationPromptArm.ARM_2, + ApproximateGeolocationPromptArm.ARM_3, + ApproximateGeolocationPromptArm.ARM_4, + ApproximateGeolocationPromptArm.ARM_5, + ApproximateGeolocationPromptArm.ARM_6 +}) +@Retention(RetentionPolicy.SOURCE) +public @interface ApproximateGeolocationPromptArm { + int NO_ARM_SELECTED = 0; + int ARM_1 = 1; + int ARM_2 = 2; + int ARM_3 = 3; + int ARM_4 = 4; + int ARM_5 = 5; + int ARM_6 = 6; +}
diff --git a/components/permissions/android/java/src/org/chromium/components/permissions/PermissionsAndroidFeatureList.java b/components/permissions/android/java/src/org/chromium/components/permissions/PermissionsAndroidFeatureList.java index ba32263..5b158d8 100644 --- a/components/permissions/android/java/src/org/chromium/components/permissions/PermissionsAndroidFeatureList.java +++ b/components/permissions/android/java/src/org/chromium/components/permissions/PermissionsAndroidFeatureList.java
@@ -6,6 +6,7 @@ import org.chromium.build.annotations.NullMarked; import org.chromium.components.cached_flags.BooleanCachedFeatureParam; +import org.chromium.components.cached_flags.IntCachedFeatureParam; /** * Lists base::Features that can be accessed through {@link PermissionsAndroidFeatureMap}. @@ -32,4 +33,10 @@ public static final BooleanCachedFeatureParam APPROXIMATE_GEOLOCATION_SAMPLE_DATA = PermissionsAndroidFeatureMap.newBooleanCachedFeatureParam( APPROXIMATE_GEOLOCATION_PERMISSION, "sample_data", false); + + public static final IntCachedFeatureParam APPROXIMATE_GEOLOCATION_PROMPT_ARM = + PermissionsAndroidFeatureMap.newIntCachedFeatureParam( + APPROXIMATE_GEOLOCATION_PERMISSION, + "prompt_arm", + ApproximateGeolocationPromptArm.NO_ARM_SELECTED); }
diff --git a/components/permissions/android/java/src/org/chromium/components/permissions/PermissionsAndroidFeatureMap.java b/components/permissions/android/java/src/org/chromium/components/permissions/PermissionsAndroidFeatureMap.java index 41fe5756..2138b5c9 100644 --- a/components/permissions/android/java/src/org/chromium/components/permissions/PermissionsAndroidFeatureMap.java +++ b/components/permissions/android/java/src/org/chromium/components/permissions/PermissionsAndroidFeatureMap.java
@@ -10,6 +10,7 @@ import org.chromium.base.FeatureMap; import org.chromium.build.annotations.NullMarked; import org.chromium.components.cached_flags.BooleanCachedFeatureParam; +import org.chromium.components.cached_flags.IntCachedFeatureParam; /** Java accessor for base::Features listed in {@link PermissionsAndroidFeatureList} */ @JNINamespace("permissions") @@ -37,6 +38,11 @@ getInstance(), featureName, variationName, defaultValue); } + public static IntCachedFeatureParam newIntCachedFeatureParam( + String featureName, String variationName, int defaultValue) { + return new IntCachedFeatureParam(getInstance(), featureName, variationName, defaultValue); + } + @Override protected long getNativeMap() { return PermissionsAndroidFeatureMapJni.get().getNativeMap();
diff --git a/components/permissions/features.cc b/components/permissions/features.cc index 009f003..e0769bb9 100644 --- a/components/permissions/features.cc +++ b/components/permissions/features.cc
@@ -91,6 +91,11 @@ "sample_data", false); +const base::FeatureParam<int> kApproximateGeolocationPermissionPromptArm( + &features::kApproximateGeolocationPermission, + "prompt_arm", + 0); + #else // When enabled, chooser permissions grants will have a last visited timestamp
diff --git a/components/permissions/features.h b/components/permissions/features.h index cfecc44c..933e45a 100644 --- a/components/permissions/features.h +++ b/components/permissions/features.h
@@ -60,6 +60,9 @@ extern const base::FeatureParam<bool> kApproximateGeolocationPermissionSampleData; +COMPONENT_EXPORT(PERMISSIONS_COMMON) +extern const base::FeatureParam<int> kApproximateGeolocationPermissionPromptArm; + #else COMPONENT_EXPORT(PERMISSIONS_COMMON)
diff --git a/components/permissions/permission_uma_util.cc b/components/permissions/permission_uma_util.cc index 0cc62e14..4d91c06 100644 --- a/components/permissions/permission_uma_util.cc +++ b/components/permissions/permission_uma_util.cc
@@ -2010,9 +2010,19 @@ // static void PermissionUmaUtil::RecordPermissionRequestRelevance( - PermissionRequestRelevance permission_request_relevance) { - base::UmaHistogramEnumeration("Permissions.AIv1.PermissionRequestRelevance", - permission_request_relevance); + permissions::RequestType permission_request_type, + PermissionRequestRelevance permission_request_relevance, + std::string model_version) { + std::string permission_request_type_string = + permission_request_type == permissions::RequestType::kNotifications + ? "Notifications" + : "Geolocation"; + + base::UmaHistogramEnumeration( + base::StrCat({"Permissions.", model_version, ".", + permission_request_type_string, + ".PermissionRequestRelevance"}), + permission_request_relevance); } // static
diff --git a/components/permissions/permission_uma_util.h b/components/permissions/permission_uma_util.h index 677811df..1d0d4e3 100644 --- a/components/permissions/permission_uma_util.h +++ b/components/permissions/permission_uma_util.h
@@ -891,7 +891,9 @@ base::TimeDelta time_delta); static void RecordPermissionRequestRelevance( - PermissionRequestRelevance permission_request_relevance); + permissions::RequestType permission_request_type, + PermissionRequestRelevance permission_request_relevance, + std::string model_version); // Records if the browser was always active while the prompt was // displaying.
diff --git a/components/persistent_cache/backend.h b/components/persistent_cache/backend.h index 2a61a4c1..94f4c182 100644 --- a/components/persistent_cache/backend.h +++ b/components/persistent_cache/backend.h
@@ -52,6 +52,11 @@ base::span<const uint8_t> content, EntryMetadata metadata) = 0; + // Used to get type of instance. Intended for things like metrics recording. + // Externally behavior of all backend types should be equivalent and control + // flow should not be tailored to the type. + virtual BackendType GetType() const = 0; + protected: Backend(); };
diff --git a/components/persistent_cache/mock/mock_backend_impl.cc b/components/persistent_cache/mock/mock_backend_impl.cc index 27262ab..89519b3 100644 --- a/components/persistent_cache/mock/mock_backend_impl.cc +++ b/components/persistent_cache/mock/mock_backend_impl.cc
@@ -4,9 +4,15 @@ #include "components/persistent_cache/mock/mock_backend_impl.h" +#include "components/persistent_cache/backend_params.h" + namespace persistent_cache { MockBackendImpl::MockBackendImpl(const BackendParams& backend_params) {} MockBackendImpl::~MockBackendImpl() = default; +BackendType MockBackendImpl::GetType() const { + return BackendType::kMock; +} + } // namespace persistent_cache
diff --git a/components/persistent_cache/mock/mock_backend_impl.h b/components/persistent_cache/mock/mock_backend_impl.h index 57dad6e..30018e6 100644 --- a/components/persistent_cache/mock/mock_backend_impl.h +++ b/components/persistent_cache/mock/mock_backend_impl.h
@@ -8,6 +8,7 @@ #include <memory> #include "components/persistent_cache/backend.h" +#include "components/persistent_cache/backend_params.h" #include "components/persistent_cache/entry.h" #include "components/persistent_cache/entry_metadata.h" #include "testing/gmock/include/gmock/gmock.h" @@ -18,6 +19,7 @@ public: explicit MockBackendImpl(const BackendParams& backend_params); ~MockBackendImpl() override; + BackendType GetType() const override; MockBackendImpl(const MockBackendImpl&) = delete; MockBackendImpl(MockBackendImpl&&) = delete;
diff --git a/components/persistent_cache/persistent_cache.cc b/components/persistent_cache/persistent_cache.cc index a146d7d..04b86fc 100644 --- a/components/persistent_cache/persistent_cache.cc +++ b/components/persistent_cache/persistent_cache.cc
@@ -6,13 +6,26 @@ #include <memory> +#include "base/metrics/histogram_functions.h" #include "base/notreached.h" +#include "base/strings/strcat.h" +#include "base/timer/elapsed_timer.h" #include "components/persistent_cache/backend.h" +#include "components/persistent_cache/backend_params.h" #include "components/persistent_cache/entry.h" #include "components/persistent_cache/sqlite/sqlite_backend_impl.h" namespace persistent_cache { +const char* GetBackendTypeName(BackendType backend_type) { + switch (backend_type) { + case BackendType::kSqlite: + return "SQLite"; + case BackendType::kMock: + return "Mock"; + } +} + // static std::unique_ptr<PersistentCache> PersistentCache::Open( BackendParams backend_params) { @@ -32,8 +45,15 @@ PersistentCache::PersistentCache(std::unique_ptr<Backend> backend) { CHECK(backend); + base::ElapsedTimer timer; + BackendType backend_type = backend->GetType(); if (backend->Initialize()) { backend_ = std::move(backend); + // TODO (https://crbug.com/377475540): Implement read-only mode. + std::string histogram_name = + base::StrCat({"PersistentCache.BackendInitialize.", + GetBackendTypeName(backend_type), ".ReadWrite"}); + base::UmaHistogramMicrosecondsTimes(histogram_name, timer.Elapsed()); } }
diff --git a/components/persistent_cache/sqlite/sqlite_backend_impl.cc b/components/persistent_cache/sqlite/sqlite_backend_impl.cc index fd4e659e..4a870b7 100644 --- a/components/persistent_cache/sqlite/sqlite_backend_impl.cc +++ b/components/persistent_cache/sqlite/sqlite_backend_impl.cc
@@ -11,6 +11,7 @@ #include "base/containers/span.h" #include "base/strings/string_view_util.h" #include "base/trace_event/trace_event.h" +#include "components/persistent_cache/backend_params.h" #include "components/persistent_cache/sqlite/sqlite_entry_impl.h" #include "components/persistent_cache/sqlite/vfs/sandboxed_file.h" #include "components/persistent_cache/sqlite/vfs/sqlite_sandboxed_vfs.h" @@ -145,4 +146,8 @@ } } +BackendType SqliteBackendImpl::GetType() const { + return BackendType::kSqlite; +} + } // namespace persistent_cache
diff --git a/components/persistent_cache/sqlite/sqlite_backend_impl.h b/components/persistent_cache/sqlite/sqlite_backend_impl.h index e10ce4e..ff40ff3 100644 --- a/components/persistent_cache/sqlite/sqlite_backend_impl.h +++ b/components/persistent_cache/sqlite/sqlite_backend_impl.h
@@ -12,6 +12,7 @@ #include "base/files/file_path.h" #include "base/types/pass_key.h" #include "components/persistent_cache/backend.h" +#include "components/persistent_cache/backend_params.h" #include "components/persistent_cache/entry.h" #include "components/persistent_cache/sqlite/vfs/sqlite_database_vfs_file_set.h" #include "components/persistent_cache/sqlite/vfs/sqlite_sandboxed_vfs.h" @@ -37,6 +38,7 @@ void Insert(std::string_view key, base::span<const uint8_t> content, EntryMetadata metadata) override; + BackendType GetType() const override; private: static SqliteVfsFileSet GetVfsFileSetFromParams(BackendParams backend_params);
diff --git a/components/privacy_sandbox_chrome_strings.grdp b/components/privacy_sandbox_chrome_strings.grdp index 1deef416..afb50ebe 100644 --- a/components/privacy_sandbox_chrome_strings.grdp +++ b/components/privacy_sandbox_chrome_strings.grdp
@@ -225,7 +225,7 @@ <message name="IDS_SETTINGS_TOPICS_PAGE_FOOTER_CANONICAL" desc="This footer helps the user understand that this setting is just one signal among others that affect whether this user sees personalized ads on a site. We define 'personalize' as 'when Google provides recommendations and other content for users based on their data'. At a high level, there are 4 things that affect whether an ad is personalized in this context: * 'this setting' refers to the 'Ad topics' setting. The user is on this page. * 'Site-suggested ads': this is a link to the other new ad setting Chrome is launching and that sites can use to personalize ads a user sees. * 'cookie settings': this is a link to the cookies control section in Chrome settings. The Privacy Sandbox project deprecates third-party cookies, but it's a process, and we're launching new functionality that will replace important functionality of cookies. Until third-party cookies are deprecated, the two systems remain active in Chrome. * 'site you're viewing personalizes ads': When a user engages with a site, Chrome has no control over whether that site shows the user personalized ads. Imagine you visit www.interesting-site.com and they know a lot about you already based on previous visits. They can personalize content and ads to you if they like. They can use an ad-serving product, like Facebook or Google Ads to deliver personalized ads. They can also use the new Privacy Sandbox APIs (if they so choose) in order to get more information about the user that could be helpful to them in order to personalize ads. Those 2 APIs (settings, from the user's perspective), are 'Ad topics' and 'Site-suggested ads'."> As you browse, whether an ad you see is personalized depends on this setting, Site-suggested ads, your cookie settings, and if the site you’re viewing personalizes ads </message> - <message name="IDS_SETTINGS_TOPICS_PAGE_FIRST_LEVEL_TOPIC_DESCRIPTOR" desc="Description of a couple of popular topics. Used in the Manage Topics page." translateable="false"> + <message name="IDS_SETTINGS_TOPICS_PAGE_FIRST_LEVEL_TOPIC_DESCRIPTOR" desc="Description of a couple of popular topics. Used in the Manage Topics page."> <ph name="TOPIC_1">$1<ex>American football</ex></ph>, <ph name="TOPIC_2">$2<ex>Tennis</ex></ph> and more </message>
diff --git a/components/privacy_sandbox_chrome_strings_grdp/IDS_SETTINGS_TOPICS_PAGE_FIRST_LEVEL_TOPIC_DESCRIPTOR.png.sha1 b/components/privacy_sandbox_chrome_strings_grdp/IDS_SETTINGS_TOPICS_PAGE_FIRST_LEVEL_TOPIC_DESCRIPTOR.png.sha1 new file mode 100644 index 0000000..f23cc03 --- /dev/null +++ b/components/privacy_sandbox_chrome_strings_grdp/IDS_SETTINGS_TOPICS_PAGE_FIRST_LEVEL_TOPIC_DESCRIPTOR.png.sha1
@@ -0,0 +1 @@ +add969fa8e09ea840139cb594f21a20de15ebdbb \ No newline at end of file
diff --git a/components/safe_browsing/core/browser/db/hit_report.h b/components/safe_browsing/core/browser/db/hit_report.h index 0b523d49..4e7d4c7 100644 --- a/components/safe_browsing/core/browser/db/hit_report.h +++ b/components/safe_browsing/core/browser/db/hit_report.h
@@ -7,7 +7,9 @@ #ifndef COMPONENTS_SAFE_BROWSING_CORE_BROWSER_DB_HIT_REPORT_H_ #define COMPONENTS_SAFE_BROWSING_CORE_BROWSER_DB_HIT_REPORT_H_ -#include "components/safe_browsing/core/browser/db/util.h" +#include <string> + +#include "components/safe_browsing/core/browser/db/v4_protocol_manager_util.h" #include "components/safe_browsing/core/common/safe_browsing_prefs.h" #include "url/gurl.h"
diff --git a/components/safe_browsing/core/browser/ping_manager_unittest.cc b/components/safe_browsing/core/browser/ping_manager_unittest.cc index 3860ec1e..4667b699 100644 --- a/components/safe_browsing/core/browser/ping_manager_unittest.cc +++ b/components/safe_browsing/core/browser/ping_manager_unittest.cc
@@ -9,6 +9,7 @@ #include "base/files/file_enumerator.h" #include "base/functional/callback.h" #include "base/functional/callback_helpers.h" +#include "base/metrics/statistics_recorder.h" #include "base/run_loop.h" #include "base/strings/escape.h" #include "base/strings/stringprintf.h" @@ -143,6 +144,12 @@ } std::string PingManagerTest::CallPersistThreatDetails(const std::string& url) { + base::RunLoop run_loop; + auto histogram_waiter = + std::make_unique<base::StatisticsRecorder::ScopedHistogramSampleObserver>( + "SafeBrowsing.ClientSafeBrowsingReport.PersisterWriteResult", + run_loop.QuitClosure()); + std::unique_ptr<ClientSafeBrowsingReportRequest> report = std::make_unique<ClientSafeBrowsingReportRequest>(); report->set_type( @@ -156,7 +163,7 @@ std::move(report)); EXPECT_EQ(result, PingManager::PersistThreatDetailsResult::kPersistTaskPosted); - task_environment_.RunUntilIdle(); + run_loop.Run(); return serialized_report; }
diff --git a/components/safe_browsing/core/common/safe_browsing_prefs.cc b/components/safe_browsing/core/common/safe_browsing_prefs.cc index 90ec1b91..cbda8e4 100644 --- a/components/safe_browsing/core/common/safe_browsing_prefs.cc +++ b/components/safe_browsing/core/common/safe_browsing_prefs.cc
@@ -205,6 +205,10 @@ } void RegisterProfilePrefs(PrefRegistrySimple* registry) { + // TODO(crbug.com/422747384): Implement correct logic to set bundle level + // based on user's safe browsing status. + registry->RegisterIntegerPref(prefs::kSecuritySettingsBundle, + SecuritySettingsBundleLevel::STANDARD); registry->RegisterListPref(prefs::kSafeBrowsingCsdPingTimestamps); registry->RegisterBooleanPref(prefs::kSafeBrowsingScoutReportingEnabled, false);
diff --git a/components/safe_browsing/core/common/safe_browsing_prefs.h b/components/safe_browsing/core/common/safe_browsing_prefs.h index ec1c0314..41a3b53 100644 --- a/components/safe_browsing/core/common/safe_browsing_prefs.h +++ b/components/safe_browsing/core/common/safe_browsing_prefs.h
@@ -263,10 +263,23 @@ inline constexpr char kExternalAppRedirectTimestamps[] = "safe_browsing.external_app_redirect_timestamps"; +// Integer that maps to SecuritySettingsBundleLevel. Indicates what bundle +// the user is in. +inline constexpr char kSecuritySettingsBundle[] = "safebrowsing.bundle"; + } // namespace prefs namespace safe_browsing { +// Enumerates the possible bundle options for bundled security settings found +// chrome://settings/security. +enum SecuritySettingsBundleLevel { + // Standard bundle with default settings. + STANDARD = 0, + // Enhanced bundle with most secure settings selected. + ENHANCED = 1, +}; + // Enumerates the level of Safe Browsing Extended Reporting that is currently // available. enum class ExtendedReportingLevel {
diff --git a/components/saved_tab_groups/public/features.cc b/components/saved_tab_groups/public/features.cc index b3ab8eb3..32b35ac6 100644 --- a/components/saved_tab_groups/public/features.cc +++ b/components/saved_tab_groups/public/features.cc
@@ -18,14 +18,6 @@ constexpr char kGroupCleanUpTimeIntervalInSecondsFinchKey[] = "group_clean_up_time_internal_seconds"; -// Core feature flag for tab group sync on Android. -// Controls registration with the sync service and tab model hookup UI layer. -// TabGroupSyncService is eanbled when either this flag or kTabGroupPaneAndroid -// is enabled. -BASE_FEATURE(kTabGroupSyncAndroid, - "TabGroupSyncAndroid", - base::FEATURE_ENABLED_BY_DEFAULT); - // Feature flag used to determine whether the network layer is disabled for // tab group sync. BASE_FEATURE(kTabGroupSyncDisableNetworkLayer, @@ -45,14 +37,6 @@ "TabGroupSyncDelegateAndroid", base::FEATURE_ENABLED_BY_DEFAULT); -// Feature flag to disable auto-open of saved tab groups. Note that the -// settings page for auto open will still be visible, and when user is allowed -// to change. However the written pref from the user selection will not be -// honored. This feature flag should be used only in case of an emergency. -BASE_FEATURE(kTabGroupSyncAutoOpenKillSwitch, - "TabGroupSyncAutoOpenKillSwitch", - base::FEATURE_ENABLED_BY_DEFAULT); - // Feature flag to restrict download on synced tabs if the navigation is // triggered without attention.. BASE_FEATURE(kRestrictDownloadOnSyncedTabs,
diff --git a/components/saved_tab_groups/public/features.h b/components/saved_tab_groups/public/features.h index 53e4b843..4730454 100644 --- a/components/saved_tab_groups/public/features.h +++ b/components/saved_tab_groups/public/features.h
@@ -10,8 +10,6 @@ namespace tab_groups { -BASE_DECLARE_FEATURE(kTabGroupSyncAndroid); - BASE_DECLARE_FEATURE(kTabGroupSyncDisableNetworkLayer); BASE_DECLARE_FEATURE(kTabGroupsSaveV2); @@ -20,8 +18,6 @@ BASE_DECLARE_FEATURE(kTabGroupSyncDelegateAndroid); -BASE_DECLARE_FEATURE(kTabGroupSyncAutoOpenKillSwitch); - BASE_DECLARE_FEATURE(kRestrictDownloadOnSyncedTabs); BASE_DECLARE_FEATURE(kUseAlternateHistorySyncIllustration);
diff --git a/components/saved_tab_groups/public/pref_names.cc b/components/saved_tab_groups/public/pref_names.cc index 842f980..18e4f17 100644 --- a/components/saved_tab_groups/public/pref_names.cc +++ b/components/saved_tab_groups/public/pref_names.cc
@@ -19,12 +19,7 @@ // this value is never read. registry->RegisterBooleanPref(prefs::kSyncableTabGroups, false); #if BUILDFLAG(IS_ANDROID) - if (base::FeatureList::IsEnabled(tab_groups::kTabGroupSyncAndroid)) { - registry->RegisterBooleanPref(prefs::kAutoOpenSyncedTabGroups, - base::GetFieldTrialParamByFeatureAsBool( - tab_groups::kTabGroupSyncAndroid, - "auto_open_synced_tab_groups", false)); - } + registry->RegisterBooleanPref(prefs::kAutoOpenSyncedTabGroups, false); // Always register stop showing prefs. They're conditionally used by a cached // feature in Java, which is hard to synchronize. registry->RegisterBooleanPref(prefs::kStopShowingTabGroupConfirmationOnClose,
diff --git a/components/search_engines/android/java/src/org/chromium/components/search_engines/TemplateUrlService.java b/components/search_engines/android/java/src/org/chromium/components/search_engines/TemplateUrlService.java index c739fafd..f732cbb 100644 --- a/components/search_engines/android/java/src/org/chromium/components/search_engines/TemplateUrlService.java +++ b/components/search_engines/android/java/src/org/chromium/components/search_engines/TemplateUrlService.java
@@ -306,12 +306,21 @@ } /** - * Finds the default search engine for the default provider and returns the url query - * {@link String} for {@code query} with voice input source param set. + * Returns the URL for the composeplate button, null if the default search engine isn't Google. + */ + public @Nullable GURL getComposeplateUrl() { + return TemplateUrlServiceJni.get() + .getComposeplateUrl(mNativeTemplateUrlServiceAndroid, this); + } + + /** + * Finds the default search engine for the default provider and returns the url query {@link + * String} for {@code query} with voice input source param set. + * * @param query The {@link String} that represents the text query the search url should - * represent. - * @return A {@link String} that contains the url of the default search engine with - * {@code query} inserted as the search parameter and voice input source param set. + * represent. + * @return A {@link String} that contains the url of the default search engine with {@code + * query} inserted as the search parameter and voice input source param set. */ public GURL getUrlForVoiceSearchQuery(String query) { return TemplateUrlServiceJni.get() @@ -476,6 +485,8 @@ GURL getUrlForVoiceSearchQuery( long nativeTemplateUrlServiceAndroid, TemplateUrlService caller, String query); + GURL getComposeplateUrl(long nativeTemplateUrlServiceAndroid, TemplateUrlService caller); + GURL getUrlForContextualSearchQuery( long nativeTemplateUrlServiceAndroid, TemplateUrlService caller,
diff --git a/components/search_engines/android/template_url_service_android.cc b/components/search_engines/android/template_url_service_android.cc index dc1bcf0..b005398 100644 --- a/components/search_engines/android/template_url_service_android.cc +++ b/components/search_engines/android/template_url_service_android.cc
@@ -42,6 +42,8 @@ using base::android::ScopedJavaLocalRef; namespace { +const char kAdditionalParam[] = "udm=50"; + TemplateURLData CreatePlayAPITemplateURLData( JNIEnv* env, const base::android::JavaParamRef<jobject>& obj, @@ -320,6 +322,24 @@ } base::android::ScopedJavaLocalRef<jobject> +TemplateUrlServiceAndroid::GetComposeplateUrl( + JNIEnv* env, + const JavaParamRef<jobject>& obj) { + if (!IsDefaultSearchEngineGoogle()) { + return nullptr; + } + + const TemplateURLRef& url_ref = + template_url_service_->GetDefaultSearchProvider()->url_ref(); + TemplateURLRef::SearchTermsArgs search_term_args = + TemplateURLRef::SearchTermsArgs(std::u16string()); + search_term_args.additional_query_params = kAdditionalParam; + GURL gurl = GURL(url_ref.ReplaceSearchTerms( + search_term_args, template_url_service_->search_terms_data())); + return url::GURLAndroid::FromNativeGURL(env, gurl); +} + +base::android::ScopedJavaLocalRef<jobject> TemplateUrlServiceAndroid::GetUrlForContextualSearchQuery( JNIEnv* env, const JavaParamRef<jobject>& obj,
diff --git a/components/search_engines/android/template_url_service_android.h b/components/search_engines/android/template_url_service_android.h index 52563f5..010829a6 100644 --- a/components/search_engines/android/template_url_service_android.h +++ b/components/search_engines/android/template_url_service_android.h
@@ -62,6 +62,9 @@ JNIEnv* env, const base::android::JavaParamRef<jobject>& obj, const base::android::JavaParamRef<jstring>& jquery); + base::android::ScopedJavaLocalRef<jobject> GetComposeplateUrl( + JNIEnv* env, + const base::android::JavaParamRef<jobject>& obj); base::android::ScopedJavaLocalRef<jobject> GetUrlForContextualSearchQuery( JNIEnv* env, const base::android::JavaParamRef<jobject>& obj,
diff --git a/components/search_engines/template_url.cc b/components/search_engines/template_url.cc index 6df3cf6..d9ce75c 100644 --- a/components/search_engines/template_url.cc +++ b/components/search_engines/template_url.cc
@@ -34,7 +34,6 @@ #include "base/strings/strcat.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_split.h" -#include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "base/trace_event/memory_usage_estimator.h" @@ -743,9 +742,8 @@ length--; } - const auto parameter = - base::MakeStringPiece(original_url.begin() + start + 1, - original_url.begin() + start + 1 + length); + const std::string_view parameter = + std::string_view(original_url).substr(start + 1, length); // Remove the parameter from the string. For parameters who replacement is // constant and already known, just replace them directly. For other cases, // like parameters whose values may change over time, use |replacements|.
diff --git a/components/security_interstitials/core/unsafe_resource.h b/components/security_interstitials/core/unsafe_resource.h index 4a917dd..b952c6d4 100644 --- a/components/security_interstitials/core/unsafe_resource.h +++ b/components/security_interstitials/core/unsafe_resource.h
@@ -13,6 +13,7 @@ #include "base/task/sequenced_task_runner.h" #include "base/unguessable_token.h" #include "components/safe_browsing/core/browser/db/hit_report.h" +#include "components/safe_browsing/core/browser/db/util.h" #include "components/safe_browsing/core/common/proto/realtimeapi.pb.h" #include "components/security_interstitials/core/unsafe_resource_locator.h" #include "services/network/public/mojom/fetch_api.mojom.h"
diff --git a/components/tab_groups/android/java/res/values-night/colors.xml b/components/tab_groups/android/java/res/values-night/colors.xml index 210081a..221716da 100644 --- a/components/tab_groups/android/java/res/values-night/colors.xml +++ b/components/tab_groups/android/java/res/values-night/colors.xml
@@ -6,6 +6,7 @@ --> <resources xmlns:tools="http://schemas.android.com/tools"> + <!-- Colors used by the tab group color picker UI and for the small color dot indicator on the card. --> <color name="tab_group_color_picker_blue">@color/tab_group_color_picker_blue_light</color> <color name="tab_group_color_picker_cyan">@color/tab_group_color_picker_cyan_light</color> <color name="tab_group_color_picker_green">@color/tab_group_color_picker_green_light</color> @@ -15,4 +16,34 @@ <color name="tab_group_color_picker_purple">@color/tab_group_color_picker_purple_light</color> <color name="tab_group_color_picker_red">@color/tab_group_color_picker_red_light</color> <color name="tab_group_color_picker_yellow">@color/tab_group_color_picker_yellow_light</color> + <!-- Colors that define the main background tint for the entire tab group card. --> + <color name="tab_group_card_color_grey">@color/tab_group_card_primary_color_grey_dark_gm3</color> + <color name="tab_group_card_color_blue">@color/tab_group_card_primary_color_blue_dark_gm3</color> + <color name="tab_group_card_color_cyan">@color/tab_group_card_primary_color_cyan_dark_gm3</color> + <color name="tab_group_card_color_green">@color/tab_group_card_primary_color_green_dark_gm3</color> + <color name="tab_group_card_color_orange">@color/tab_group_card_primary_color_orange_dark_gm3</color> + <color name="tab_group_card_color_pink">@color/tab_group_card_primary_color_pink_dark_gm3</color> + <color name="tab_group_card_color_purple">@color/tab_group_card_primary_color_purple_dark_gm3</color> + <color name="tab_group_card_color_red">@color/tab_group_card_primary_color_red_dark_gm3</color> + <color name="tab_group_card_color_yellow">@color/tab_group_card_primary_color_yellow_dark_gm3</color> + <!-- Colors for foreground elements, used for the title, tab counter, and action button on a tab group card. --> + <color name="tab_group_card_text_color_grey">@color/tab_group_card_secondary_color_grey_light_gm3</color> + <color name="tab_group_card_text_color_blue">@color/tab_group_card_secondary_color_blue_light_gm3</color> + <color name="tab_group_card_text_color_cyan">@color/tab_group_card_secondary_color_cyan_light_gm3</color> + <color name="tab_group_card_text_color_green">@color/tab_group_card_secondary_color_green_light_gm3</color> + <color name="tab_group_card_text_color_orange">@color/tab_group_card_secondary_color_orange_light_gm3</color> + <color name="tab_group_card_text_color_pink">@color/tab_group_card_secondary_color_pink_light_gm3</color> + <color name="tab_group_card_text_color_purple">@color/tab_group_card_secondary_color_purple_light_gm3</color> + <color name="tab_group_card_text_color_red">@color/tab_group_card_secondary_color_red_light_gm3</color> + <color name="tab_group_card_text_color_yellow">@color/tab_group_card_secondary_color_yellow_light_gm3</color> + <!-- Colors for the background of empty mini-thumbnail slots within a tab group card. --> + <color name="tab_group_card_placeholder_color_grey">@color/tab_group_card_secondary_color_grey_dark_gm3</color> + <color name="tab_group_card_placeholder_color_blue">@color/tab_group_card_secondary_color_blue_dark_gm3</color> + <color name="tab_group_card_placeholder_color_cyan">@color/tab_group_card_secondary_color_cyan_dark_gm3</color> + <color name="tab_group_card_placeholder_color_green">@color/tab_group_card_secondary_color_green_dark_gm3</color> + <color name="tab_group_card_placeholder_color_orange">@color/tab_group_card_secondary_color_orange_dark_gm3</color> + <color name="tab_group_card_placeholder_color_pink">@color/tab_group_card_secondary_color_pink_dark_gm3</color> + <color name="tab_group_card_placeholder_color_purple">@color/tab_group_card_secondary_color_purple_dark_gm3</color> + <color name="tab_group_card_placeholder_color_red">@color/tab_group_card_secondary_color_red_dark_gm3</color> + <color name="tab_group_card_placeholder_color_yellow">@color/tab_group_card_secondary_color_yellow_dark_gm3</color> </resources>
diff --git a/components/tab_groups/android/java/res/values/colors.xml b/components/tab_groups/android/java/res/values/colors.xml index 2509ec5..42197e8 100644 --- a/components/tab_groups/android/java/res/values/colors.xml +++ b/components/tab_groups/android/java/res/values/colors.xml
@@ -6,7 +6,7 @@ --> <resources> - <!-- Tab group color picker related colors. --> + <!-- Colors used by the tab group color picker UI and for the small color dot indicator on the card. --> <color name="tab_group_color_picker_blue">@color/tab_group_color_picker_blue_dark</color> <color name="tab_group_color_picker_blue_incognito">@color/tab_group_color_picker_blue_light</color> <color name="tab_group_color_picker_cyan">@color/tab_group_color_picker_cyan_dark</color> @@ -26,38 +26,62 @@ <color name="tab_group_color_picker_yellow">@color/tab_group_color_picker_yellow_dark</color> <color name="tab_group_color_picker_yellow_incognito">@color/tab_group_color_picker_yellow_light</color> <color name="tab_group_tab_strip_title_text_color_incognito">@color/baseline_neutral_20</color> - - <!-- Tab group card related colors. --> - <color name="tab_group_card_color_grey">@color/tab_group_card_color_grey_gm3</color> - <color name="tab_group_card_color_blue">@color/tab_group_card_color_blue_gm3</color> - <color name="tab_group_card_color_cyan">@color/tab_group_card_color_cyan_gm3</color> - <color name="tab_group_card_color_green">@color/tab_group_card_color_green_gm3</color> - <color name="tab_group_card_color_orange">@color/tab_group_card_color_orange_gm3</color> - <color name="tab_group_card_color_pink">@color/tab_group_card_color_pink_gm3</color> - <color name="tab_group_card_color_purple">@color/tab_group_card_color_purple_gm3</color> - <color name="tab_group_card_color_red">@color/tab_group_card_color_red_gm3</color> - <color name="tab_group_card_color_yellow">@color/tab_group_card_color_yellow_gm3</color> - - <!-- Tab group card text related colors. --> - <color name="tab_group_card_text_color_grey">@color/tab_group_card_text_color_grey_gm3</color> - <color name="tab_group_card_text_color_blue">@color/tab_group_card_text_color_blue_gm3</color> - <color name="tab_group_card_text_color_cyan">@color/tab_group_card_text_color_cyan_gm3</color> - <color name="tab_group_card_text_color_green">@color/tab_group_card_text_color_green_gm3</color> - <color name="tab_group_card_text_color_orange">@color/tab_group_card_text_color_orange_gm3</color> - <color name="tab_group_card_text_color_pink">@color/tab_group_card_text_color_pink_gm3</color> - <color name="tab_group_card_text_color_purple">@color/tab_group_card_text_color_purple_gm3</color> - <color name="tab_group_card_text_color_red">@color/tab_group_card_text_color_red_gm3</color> - <color name="tab_group_card_text_color_yellow">@color/tab_group_card_text_color_yellow_gm3</color> - - <!-- Tab group card placeholder related colors. --> - <color name="tab_group_card_placeholder_color_grey">@color/baseline_neutral_90</color> - <color name="tab_group_card_placeholder_color_blue">@color/tab_group_card_placeholder_color_blue_gm3</color> - <color name="tab_group_card_placeholder_color_cyan">@color/tab_group_card_placeholder_color_cyan_gm3</color> - <color name="tab_group_card_placeholder_color_green">@color/tab_group_card_placeholder_color_green_gm3</color> - <color name="tab_group_card_placeholder_color_orange">@color/tab_group_card_placeholder_color_orange_gm3</color> - <color name="tab_group_card_placeholder_color_pink">@color/tab_group_card_placeholder_color_pink_gm3</color> - <color name="tab_group_card_placeholder_color_purple">@color/tab_group_card_placeholder_color_purple_gm3</color> - <color name="tab_group_card_placeholder_color_red">@color/tab_group_card_placeholder_color_red_gm3</color> - <color name="tab_group_card_placeholder_color_yellow">@color/tab_group_card_placeholder_color_yellow_gm3</color> + <!-- Colors that define the main background tint for the entire tab group card. --> + <color name="tab_group_card_color_grey">@color/tab_group_card_primary_color_grey_light_gm3</color> + <color name="tab_group_card_color_grey_incognito">@color/tab_group_card_primary_color_grey_dark_gm3</color> + <color name="tab_group_card_color_blue">@color/tab_group_card_primary_color_blue_light_gm3</color> + <color name="tab_group_card_color_blue_incognito">@color/tab_group_card_primary_color_blue_dark_gm3</color> + <color name="tab_group_card_color_cyan">@color/tab_group_card_primary_color_cyan_light_gm3</color> + <color name="tab_group_card_color_cyan_incognito">@color/tab_group_card_primary_color_cyan_dark_gm3</color> + <color name="tab_group_card_color_green">@color/tab_group_card_primary_color_green_light_gm3</color> + <color name="tab_group_card_color_green_incognito">@color/tab_group_card_primary_color_green_dark_gm3</color> + <color name="tab_group_card_color_orange">@color/tab_group_card_primary_color_orange_light_gm3</color> + <color name="tab_group_card_color_orange_incognito">@color/tab_group_card_primary_color_orange_dark_gm3</color> + <color name="tab_group_card_color_pink">@color/tab_group_card_primary_color_pink_light_gm3</color> + <color name="tab_group_card_color_pink_incognito">@color/tab_group_card_primary_color_pink_dark_gm3</color> + <color name="tab_group_card_color_purple">@color/tab_group_card_primary_color_purple_light_gm3</color> + <color name="tab_group_card_color_purple_incognito">@color/tab_group_card_primary_color_purple_dark_gm3</color> + <color name="tab_group_card_color_red">@color/tab_group_card_primary_color_red_light_gm3</color> + <color name="tab_group_card_color_red_incognito">@color/tab_group_card_primary_color_red_dark_gm3</color> + <color name="tab_group_card_color_yellow">@color/tab_group_card_primary_color_yellow_light_gm3</color> + <color name="tab_group_card_color_yellow_incognito">@color/tab_group_card_primary_color_yellow_dark_gm3</color> + <!-- Colors for foreground elements, used for the title, tab counter, and action button on a tab group card. --> + <color name="tab_group_card_text_color_grey">@color/tab_group_card_secondary_color_grey_dark_gm3</color> + <color name="tab_group_card_text_color_grey_incognito">@color/tab_group_card_secondary_color_grey_light_gm3</color> + <color name="tab_group_card_text_color_blue">@color/tab_group_card_secondary_color_blue_dark_gm3</color> + <color name="tab_group_card_text_color_blue_incognito">@color/tab_group_card_secondary_color_blue_light_gm3</color> + <color name="tab_group_card_text_color_cyan">@color/tab_group_card_secondary_color_cyan_dark_gm3</color> + <color name="tab_group_card_text_color_cyan_incognito">@color/tab_group_card_secondary_color_cyan_light_gm3</color> + <color name="tab_group_card_text_color_green">@color/tab_group_card_secondary_color_green_dark_gm3</color> + <color name="tab_group_card_text_color_green_incognito">@color/tab_group_card_secondary_color_green_light_gm3</color> + <color name="tab_group_card_text_color_orange">@color/tab_group_card_secondary_color_orange_dark_gm3</color> + <color name="tab_group_card_text_color_orange_incognito">@color/tab_group_card_secondary_color_orange_light_gm3</color> + <color name="tab_group_card_text_color_pink">@color/tab_group_card_secondary_color_pink_dark_gm3</color> + <color name="tab_group_card_text_color_pink_incognito">@color/tab_group_card_secondary_color_pink_light_gm3</color> + <color name="tab_group_card_text_color_purple">@color/tab_group_card_secondary_color_purple_dark_gm3</color> + <color name="tab_group_card_text_color_purple_incognito">@color/tab_group_card_secondary_color_purple_light_gm3</color> + <color name="tab_group_card_text_color_red">@color/tab_group_card_secondary_color_red_dark_gm3</color> + <color name="tab_group_card_text_color_red_incognito">@color/tab_group_card_secondary_color_red_light_gm3</color> + <color name="tab_group_card_text_color_yellow">@color/tab_group_card_secondary_color_yellow_dark_gm3</color> + <color name="tab_group_card_text_color_yellow_incognito">@color/tab_group_card_secondary_color_yellow_light_gm3</color> + <!-- Colors for the background of empty mini-thumbnail slots within a tab group card. --> + <color name="tab_group_card_placeholder_color_grey">@color/tab_group_card_secondary_color_grey_light_gm3</color> + <color name="tab_group_card_placeholder_color_grey_incognito">@color/tab_group_card_secondary_color_grey_dark_gm3</color> + <color name="tab_group_card_placeholder_color_blue">@color/tab_group_card_secondary_color_blue_light_gm3</color> + <color name="tab_group_card_placeholder_color_blue_incognito">@color/tab_group_card_secondary_color_blue_dark_gm3</color> + <color name="tab_group_card_placeholder_color_cyan">@color/tab_group_card_secondary_color_cyan_light_gm3</color> + <color name="tab_group_card_placeholder_color_cyan_incognito">@color/tab_group_card_secondary_color_cyan_dark_gm3</color> + <color name="tab_group_card_placeholder_color_green">@color/tab_group_card_secondary_color_green_light_gm3</color> + <color name="tab_group_card_placeholder_color_green_incognito">@color/tab_group_card_secondary_color_green_dark_gm3</color> + <color name="tab_group_card_placeholder_color_orange">@color/tab_group_card_secondary_color_orange_light_gm3</color> + <color name="tab_group_card_placeholder_color_orange_incognito">@color/tab_group_card_secondary_color_orange_dark_gm3</color> + <color name="tab_group_card_placeholder_color_pink">@color/tab_group_card_secondary_color_pink_light_gm3</color> + <color name="tab_group_card_placeholder_color_pink_incognito">@color/tab_group_card_secondary_color_pink_dark_gm3</color> + <color name="tab_group_card_placeholder_color_purple">@color/tab_group_card_secondary_color_purple_light_gm3</color> + <color name="tab_group_card_placeholder_color_purple_incognito">@color/tab_group_card_secondary_color_purple_dark_gm3</color> + <color name="tab_group_card_placeholder_color_red">@color/tab_group_card_secondary_color_red_light_gm3</color> + <color name="tab_group_card_placeholder_color_red_incognito">@color/tab_group_card_secondary_color_red_dark_gm3</color> + <color name="tab_group_card_placeholder_color_yellow">@color/tab_group_card_secondary_color_yellow_light_gm3</color> + <color name="tab_group_card_placeholder_color_yellow_incognito">@color/tab_group_card_secondary_color_yellow_dark_gm3</color> </resources> \ No newline at end of file
diff --git a/components/tab_groups/android/java/src/org/chromium/components/tab_groups/TabGroupColorPickerUtils.java b/components/tab_groups/android/java/src/org/chromium/components/tab_groups/TabGroupColorPickerUtils.java index 6e6f06a..ef94e15 100644 --- a/components/tab_groups/android/java/src/org/chromium/components/tab_groups/TabGroupColorPickerUtils.java +++ b/components/tab_groups/android/java/src/org/chromium/components/tab_groups/TabGroupColorPickerUtils.java
@@ -123,7 +123,7 @@ */ public static @ColorInt int getTabGroupCardColor( Context context, @TabGroupColorId int colorId, boolean isIncognito) { - @ColorRes int colorRes = getTabGroupCardColorResource(colorId); + @ColorRes int colorRes = getTabGroupCardColorResource(colorId, isIncognito); return resolveGroupRelatedColor(context, colorRes, isIncognito); } @@ -133,17 +133,36 @@ * * @param colorId The color id corresponding to the color of the Tab Group. */ - public static @ColorRes int getTabGroupCardColorResource(@TabGroupColorId int colorId) { + public static @ColorRes int getTabGroupCardColorResource( + @TabGroupColorId int colorId, boolean isIncognito) { return switch (colorId) { - case TabGroupColorId.GREY -> R.color.tab_group_card_color_grey; - case TabGroupColorId.BLUE -> R.color.tab_group_card_color_blue; - case TabGroupColorId.RED -> R.color.tab_group_card_color_red; - case TabGroupColorId.YELLOW -> R.color.tab_group_card_color_yellow; - case TabGroupColorId.GREEN -> R.color.tab_group_card_color_green; - case TabGroupColorId.PINK -> R.color.tab_group_card_color_pink; - case TabGroupColorId.PURPLE -> R.color.tab_group_card_color_purple; - case TabGroupColorId.CYAN -> R.color.tab_group_card_color_cyan; - case TabGroupColorId.ORANGE -> R.color.tab_group_card_color_orange; + case TabGroupColorId.GREY -> isIncognito + ? R.color.tab_group_card_color_grey_incognito + : R.color.tab_group_card_color_grey; + case TabGroupColorId.BLUE -> isIncognito + ? R.color.tab_group_card_color_blue_incognito + : R.color.tab_group_card_color_blue; + case TabGroupColorId.RED -> isIncognito + ? R.color.tab_group_card_color_red_incognito + : R.color.tab_group_card_color_red; + case TabGroupColorId.YELLOW -> isIncognito + ? R.color.tab_group_card_color_yellow_incognito + : R.color.tab_group_card_color_yellow; + case TabGroupColorId.GREEN -> isIncognito + ? R.color.tab_group_card_color_green_incognito + : R.color.tab_group_card_color_green; + case TabGroupColorId.PINK -> isIncognito + ? R.color.tab_group_card_color_pink_incognito + : R.color.tab_group_card_color_pink; + case TabGroupColorId.PURPLE -> isIncognito + ? R.color.tab_group_card_color_purple_incognito + : R.color.tab_group_card_color_purple; + case TabGroupColorId.CYAN -> isIncognito + ? R.color.tab_group_card_color_cyan_incognito + : R.color.tab_group_card_color_cyan; + case TabGroupColorId.ORANGE -> isIncognito + ? R.color.tab_group_card_color_orange_incognito + : R.color.tab_group_card_color_orange; default -> { assert false : "Invalid tab group color id " + colorId; yield Resources.ID_NULL; @@ -162,7 +181,7 @@ */ public static @ColorInt int getTabGroupCardTextColor( Context context, @TabGroupColorId int colorId, boolean isIncognito) { - @ColorRes int colorRes = getTabGroupCardTextColorResource(colorId); + @ColorRes int colorRes = getTabGroupCardTextColorResource(colorId, isIncognito); return resolveGroupRelatedColor(context, colorRes, isIncognito); } @@ -172,17 +191,36 @@ * * @param colorId The color id corresponding to the color of the Tab Group. */ - public static @ColorRes int getTabGroupCardTextColorResource(@TabGroupColorId int colorId) { + public static @ColorRes int getTabGroupCardTextColorResource( + @TabGroupColorId int colorId, boolean isIncognito) { return switch (colorId) { - case TabGroupColorId.GREY -> R.color.tab_group_card_text_color_grey; - case TabGroupColorId.BLUE -> R.color.tab_group_card_text_color_blue; - case TabGroupColorId.RED -> R.color.tab_group_card_text_color_red; - case TabGroupColorId.YELLOW -> R.color.tab_group_card_text_color_yellow; - case TabGroupColorId.GREEN -> R.color.tab_group_card_text_color_green; - case TabGroupColorId.PINK -> R.color.tab_group_card_text_color_pink; - case TabGroupColorId.PURPLE -> R.color.tab_group_card_text_color_purple; - case TabGroupColorId.CYAN -> R.color.tab_group_card_text_color_cyan; - case TabGroupColorId.ORANGE -> R.color.tab_group_card_text_color_orange; + case TabGroupColorId.GREY -> isIncognito + ? R.color.tab_group_card_text_color_grey_incognito + : R.color.tab_group_card_text_color_grey; + case TabGroupColorId.BLUE -> isIncognito + ? R.color.tab_group_card_text_color_blue_incognito + : R.color.tab_group_card_text_color_blue; + case TabGroupColorId.RED -> isIncognito + ? R.color.tab_group_card_text_color_red_incognito + : R.color.tab_group_card_text_color_red; + case TabGroupColorId.YELLOW -> isIncognito + ? R.color.tab_group_card_text_color_yellow_incognito + : R.color.tab_group_card_text_color_yellow; + case TabGroupColorId.GREEN -> isIncognito + ? R.color.tab_group_card_text_color_green_incognito + : R.color.tab_group_card_text_color_green; + case TabGroupColorId.PINK -> isIncognito + ? R.color.tab_group_card_text_color_pink_incognito + : R.color.tab_group_card_text_color_pink; + case TabGroupColorId.PURPLE -> isIncognito + ? R.color.tab_group_card_text_color_purple_incognito + : R.color.tab_group_card_text_color_purple; + case TabGroupColorId.CYAN -> isIncognito + ? R.color.tab_group_card_text_color_cyan_incognito + : R.color.tab_group_card_text_color_cyan; + case TabGroupColorId.ORANGE -> isIncognito + ? R.color.tab_group_card_text_color_orange_incognito + : R.color.tab_group_card_text_color_orange; default -> { assert false : "Invalid tab group text color id " + colorId; yield Resources.ID_NULL; @@ -201,7 +239,8 @@ */ public static @ColorInt int getTabGroupCardMiniThumbnailPlaceholderColor( Context context, @TabGroupColorId int colorId, boolean isIncognito) { - @ColorRes int colorRes = getTabGroupCardMiniThumbnailPlaceholderColorResource(colorId); + @ColorRes + int colorRes = getTabGroupCardMiniThumbnailPlaceholderColorResource(colorId, isIncognito); return resolveGroupRelatedColor(context, colorRes, isIncognito); } @@ -212,30 +251,40 @@ * @param colorId The color id corresponding to the color of the Tab Group. */ public static @ColorRes int getTabGroupCardMiniThumbnailPlaceholderColorResource( - @TabGroupColorId int colorId) { - switch (colorId) { - case TabGroupColorId.GREY: - return R.color.tab_group_card_placeholder_color_grey; - case TabGroupColorId.BLUE: - return R.color.tab_group_card_placeholder_color_blue; - case TabGroupColorId.RED: - return R.color.tab_group_card_placeholder_color_red; - case TabGroupColorId.YELLOW: - return R.color.tab_group_card_placeholder_color_yellow; - case TabGroupColorId.GREEN: - return R.color.tab_group_card_placeholder_color_green; - case TabGroupColorId.PINK: - return R.color.tab_group_card_placeholder_color_pink; - case TabGroupColorId.PURPLE: - return R.color.tab_group_card_placeholder_color_purple; - case TabGroupColorId.CYAN: - return R.color.tab_group_card_placeholder_color_cyan; - case TabGroupColorId.ORANGE: - return R.color.tab_group_card_placeholder_color_orange; - default: + @TabGroupColorId int colorId, boolean isIncognito) { + return switch (colorId) { + case TabGroupColorId.GREY -> isIncognito + ? R.color.tab_group_card_placeholder_color_grey_incognito + : R.color.tab_group_card_placeholder_color_grey; + case TabGroupColorId.BLUE -> isIncognito + ? R.color.tab_group_card_placeholder_color_blue_incognito + : R.color.tab_group_card_placeholder_color_blue; + case TabGroupColorId.RED -> isIncognito + ? R.color.tab_group_card_placeholder_color_red_incognito + : R.color.tab_group_card_placeholder_color_red; + case TabGroupColorId.YELLOW -> isIncognito + ? R.color.tab_group_card_placeholder_color_yellow_incognito + : R.color.tab_group_card_placeholder_color_yellow; + case TabGroupColorId.GREEN -> isIncognito + ? R.color.tab_group_card_placeholder_color_green_incognito + : R.color.tab_group_card_placeholder_color_green; + case TabGroupColorId.PINK -> isIncognito + ? R.color.tab_group_card_placeholder_color_pink_incognito + : R.color.tab_group_card_placeholder_color_pink; + case TabGroupColorId.PURPLE -> isIncognito + ? R.color.tab_group_card_placeholder_color_purple_incognito + : R.color.tab_group_card_placeholder_color_purple; + case TabGroupColorId.CYAN -> isIncognito + ? R.color.tab_group_card_placeholder_color_cyan_incognito + : R.color.tab_group_card_placeholder_color_cyan; + case TabGroupColorId.ORANGE -> isIncognito + ? R.color.tab_group_card_placeholder_color_orange_incognito + : R.color.tab_group_card_placeholder_color_orange; + default -> { assert false : "Invalid tab group text color id " + colorId; - return Resources.ID_NULL; - } + yield Resources.ID_NULL; + } + }; } private static @ColorInt int resolveGroupRelatedColor(
diff --git a/components/test/data/optimization_guide/clickability_reason.html b/components/test/data/optimization_guide/clickability_reason.html new file mode 100644 index 0000000..a71ddf6 --- /dev/null +++ b/components/test/data/optimization_guide/clickability_reason.html
@@ -0,0 +1,12 @@ +<body> + <button id='multiReasonBtn' contenteditable='true' style='cursor: + pointer;' role='menuitem'> + Multi-Reason Button + </button> + <script> + const btn = document.getElementById('multiReasonBtn'); + btn.onclick = function(){}; + btn.onmouseover = function(){}; + btn.onkeydown = function(){}; + </script> +</body>
diff --git a/components/themes/ntp_background_service.cc b/components/themes/ntp_background_service.cc index 84faa192..7b663688 100644 --- a/components/themes/ntp_background_service.cc +++ b/components/themes/ntp_background_service.cc
@@ -87,7 +87,8 @@ DCHECK(observers_.empty()); } -void NtpBackgroundService::FetchCollectionInfo() { +void NtpBackgroundService::FetchCollectionInfo( + const std::string& filtering_label) { // If a request is currently in progress, drop the new request. if (collections_loader_ != nullptr) { return; @@ -136,18 +137,18 @@ ntp::background::GetCollectionsRequest request; // The language field may include the country code (e.g. "en-US"). request.set_language(application_locale_storage_->Get()); - request.add_filtering_label(GetFilteringLabel()); + request.add_filtering_label(filtering_label); // Add some extra filtering information in case we need to target a specific // milestone post release. request.add_filtering_label(base::StrCat( - {GetFilteringLabel(), ".M", version_info::GetMajorVersionNumber()})); + {filtering_label, ".M", version_info::GetMajorVersionNumber()})); // Add filtering for Panorama feature. - request.add_filtering_label(base::StrCat({GetFilteringLabel(), ".panorama"})); - request.add_filtering_label(base::StrCat({GetFilteringLabel(), ".gm3"})); + request.add_filtering_label(base::StrCat({filtering_label, ".panorama"})); + request.add_filtering_label(base::StrCat({filtering_label, ".gm3"})); if (base::FeatureList::IsEnabled( ntp_features::kNtpBackgroundImageErrorDetection)) { request.add_filtering_label( - base::StrCat({GetFilteringLabel(), ".error_detection"})); + base::StrCat({filtering_label, ".error_detection"})); } std::string serialized_proto; @@ -168,6 +169,11 @@ 1024 * 1024); } +void NtpBackgroundService::FetchCollectionInfo() { + // Calls `FetchCollectionInfo` method using the default filter. + FetchCollectionInfo(GetFilteringLabel()); +} + void NtpBackgroundService::OnCollectionInfoFetchComplete( std::unique_ptr<std::string> response_body) { collection_info_.clear();
diff --git a/components/themes/ntp_background_service.h b/components/themes/ntp_background_service.h index b06a2b7b..6e931453 100644 --- a/components/themes/ntp_background_service.h +++ b/components/themes/ntp_background_service.h
@@ -61,7 +61,13 @@ // Requests an asynchronous fetch from the network. After the update // completes, OnCollectionInfoAvailable will be called on the observers. // Requests that are made while an asynchronous fetch is in progress will be - // dropped until the currently active loader completes. + // dropped until the currently active loader completes. `filtering_label` is + // provided to guide the fetch. + virtual void FetchCollectionInfo(const std::string& filtering_label); + + // Requests an asynchronous fetch from network by calling + // `FetchCollectionInfo(const std::string& filtering_label)` with + // filtering_label set to the default label. virtual void FetchCollectionInfo(); // Callback type for fetching collection images, invoked with a vector of
diff --git a/components/themes/ntp_background_service_unittest.cc b/components/themes/ntp_background_service_unittest.cc index c3506e4..69462c9 100644 --- a/components/themes/ntp_background_service_unittest.cc +++ b/components/themes/ntp_background_service_unittest.cc
@@ -135,6 +135,35 @@ collection_request.filtering_label(3)); } +TEST_F(NtpBackgroundServiceTest, CollectionRequestWithFilteringLabel) { + application_locale_storage_->Set("foo"); + + service()->FetchCollectionInfo("test"); + EXPECT_TRUE(base::test::RunUntil([&]() { + return test_url_loader_factory()->pending_requests()->size() == 1u; + })); + + std::string request_body(test_url_loader_factory() + ->pending_requests() + ->at(0) + .request.request_body->elements() + ->at(0) + .As<network::DataElementBytes>() + .AsStringPiece()); + ntp::background::GetCollectionsRequest collection_request; + EXPECT_TRUE(collection_request.ParseFromString(request_body)); + EXPECT_EQ("foo", collection_request.language()); + EXPECT_EQ(4, collection_request.filtering_label_size()); + EXPECT_EQ("test", collection_request.filtering_label(0)); + EXPECT_EQ( + base::StrCat({"test", ".M"}) + version_info::GetMajorVersionNumber(), + collection_request.filtering_label(1)); + EXPECT_EQ(base::StrCat({"test", ".panorama"}), + collection_request.filtering_label(2)); + EXPECT_EQ(base::StrCat({"test", ".gm3"}), + collection_request.filtering_label(3)); +} + TEST_F(NtpBackgroundServiceTest, CollectionRequestWithImageErrorDetectionEnabled) { base::test::ScopedFeatureList scoped_feature_list;
diff --git a/components/update_client/protocol_parser.h b/components/update_client/protocol_parser.h index ac3dcc118c..9084979 100644 --- a/components/update_client/protocol_parser.h +++ b/components/update_client/protocol_parser.h
@@ -126,7 +126,7 @@ void ParseError(const char* details, ...); private: - virtual bool DoParse(const std::string& response, Results* results) = 0; + virtual bool DoParse(std::string_view response, Results* results) = 0; Results results_; std::string errors_;
diff --git a/components/update_client/protocol_parser_json.cc b/components/update_client/protocol_parser_json.cc index 232f9722..2541617 100644 --- a/components/update_client/protocol_parser_json.cc +++ b/components/update_client/protocol_parser_json.cc
@@ -8,6 +8,7 @@ #include <cstdint> #include <optional> #include <string> +#include <string_view> #include <utility> #include "base/check.h" @@ -258,7 +259,7 @@ } // namespace -bool ProtocolParserJSON::DoParse(const std::string& response_json, +bool ProtocolParserJSON::DoParse(std::string_view response_json, Results* results) { CHECK(results); @@ -268,15 +269,14 @@ } // The JSON response contains a prefix to prevent XSSI. - static constexpr char kJSONPrefix[] = ")]}'"; + static constexpr std::string_view kJSONPrefix = ")]}'"; if (!base::StartsWith(response_json, kJSONPrefix, base::CompareCase::SENSITIVE)) { ParseError("Missing secure JSON prefix."); return false; } - const auto doc = base::JSONReader::ReadDict(base::MakeStringPiece( - response_json.begin() + std::char_traits<char>::length(kJSONPrefix), - response_json.end())); + const auto doc = + base::JSONReader::ReadDict(response_json.substr(kJSONPrefix.size())); if (!doc) { ParseError("JSON read error."); return false;
diff --git a/components/update_client/protocol_parser_json.h b/components/update_client/protocol_parser_json.h index 6cef633..311476b 100644 --- a/components/update_client/protocol_parser_json.h +++ b/components/update_client/protocol_parser_json.h
@@ -26,7 +26,7 @@ private: // Overrides for ProtocolParser. - bool DoParse(const std::string& response_json, Results* results) override; + bool DoParse(std::string_view response_json, Results* results) override; }; } // namespace update_client
diff --git a/components/viz/service/display/skia_renderer.cc b/components/viz/service/display/skia_renderer.cc index 8563b06e..772ab57 100644 --- a/components/viz/service/display/skia_renderer.cc +++ b/components/viz/service/display/skia_renderer.cc
@@ -1089,8 +1089,8 @@ use_partial_swap_ ? gfx::RectF(swap_buffer_rect_) : gfx::RectF(surface_plane.resource_size); #if BUILDFLAG(IS_WIN) - surface_candidate.layer_id = gfx::OverlayLayerId::MakeVizInternal( - gfx::OverlayLayerId::VizInternalId::kPrimaryPlane); + surface_candidate.layer_id = gfx::OverlayLayerId::MakeVizInternalRenderPass( + current_frame()->root_render_pass->id); #endif #if BUILDFLAG(IS_OZONE) // Ozone DRM needs the primary plane as the first overlay when overlay
diff --git a/components/viz/service/layers/layer_context_impl.cc b/components/viz/service/layers/layer_context_impl.cc index 816f934..c4d3a14 100644 --- a/components/viz/service/layers/layer_context_impl.cc +++ b/components/viz/service/layers/layer_context_impl.cc
@@ -85,7 +85,10 @@ break; case cc::mojom::LayerType::kNinePatchThumbScrollbar: { - RETURN_IF_FALSE(wire.layer_extra, "Invalid layer_extra"); + RETURN_IF_FALSE( + wire.layer_extra && + wire.layer_extra->is_nine_patch_thumb_scrollbar_layer_extra(), + "Invalid layer_extra type for NinePatchThumbScrollbarLayerImpl"); auto& extra = wire.layer_extra->get_nine_patch_thumb_scrollbar_layer_extra(); cc::ScrollbarOrientation orientation = @@ -99,7 +102,9 @@ } case cc::mojom::LayerType::kPaintedScrollbar: { - RETURN_IF_FALSE(wire.layer_extra, "Invalid layer_extra"); + RETURN_IF_FALSE(wire.layer_extra && + wire.layer_extra->is_painted_scrollbar_layer_extra(), + "Invalid layer_extra type for PaintedScrollbarLayerImpl"); auto& extra = wire.layer_extra->get_painted_scrollbar_layer_extra(); cc::ScrollbarOrientation orientation = extra->scrollbar_base_extra->is_horizontal_orientation @@ -117,7 +122,10 @@ break; case cc::mojom::LayerType::kSolidColorScrollbar: { - RETURN_IF_FALSE(wire.layer_extra, "Invalid layer_extra"); + RETURN_IF_FALSE( + wire.layer_extra && + wire.layer_extra->is_solid_color_scrollbar_layer_extra(), + "Invalid layer_extra type for SolidColorScrollbarLayerImpl"); auto& extra = wire.layer_extra->get_solid_color_scrollbar_layer_extra(); cc::ScrollbarOrientation orientation = extra->scrollbar_base_extra->is_horizontal_orientation @@ -140,7 +148,10 @@ break; case cc::mojom::LayerType::kViewTransitionContent: { - RETURN_IF_FALSE(wire.layer_extra, "Invalid layer_extra"); + RETURN_IF_FALSE( + wire.layer_extra && + wire.layer_extra->is_view_transition_content_layer_extra(), + "Invalid layer_extra type for ViewTransitionContentLayerImpl"); auto& extra = wire.layer_extra->get_view_transition_content_layer_extra(); layer = cc::ViewTransitionContentLayerImpl::Create( &tree, id, extra->resource_id, extra->is_live_content_layer, @@ -599,6 +610,12 @@ layer.SetMaxExtentsRect(extra->max_extents_rect); } +void UpdateTileDisplayLayerExtra(const mojom::TileDisplayLayerExtraPtr& extra, + cc::TileDisplayLayerImpl& layer) { + layer.SetSolidColor(extra->solid_color); + layer.SetIsBackdropFilterMask(extra->is_backdrop_filter_mask); +} + base::expected<void, std::string> UpdateLayer(const mojom::Layer& wire, cc::LayerImpl& layer) { if (wire.contents_opaque && !wire.contents_opaque_for_text) { @@ -635,12 +652,6 @@ layer.SetCaptureBounds(wire.rare_properties->capture_bounds); } - if (layer.GetLayerType() == cc::mojom::LayerType::kTileDisplay) { - auto& tile_display_layer = static_cast<cc::TileDisplayLayerImpl&>(layer); - tile_display_layer.SetSolidColor(wire.solid_color); - tile_display_layer.SetIsBackdropFilterMask(wire.is_backdrop_filter_mask); - } - const cc::PropertyTrees& property_trees = *layer.layer_tree_impl()->property_trees(); if (!IsPropertyTreeIndexValid(property_trees.transform_tree(), @@ -678,40 +689,65 @@ switch (wire.type) { case cc::mojom::LayerType::kMirror: - RETURN_IF_FALSE(wire.layer_extra, "Invalid layer_extra"); + RETURN_IF_FALSE( + wire.layer_extra && wire.layer_extra->is_mirror_layer_extra(), + "Invalid layer_extra type for MirrorLayerImpl"); UpdateMirrorLayerExtra(wire.layer_extra->get_mirror_layer_extra(), static_cast<cc::MirrorLayerImpl&>(layer)); break; case cc::mojom::LayerType::kNinePatchThumbScrollbar: - RETURN_IF_FALSE(wire.layer_extra, "Invalid layer_extra"); + RETURN_IF_FALSE( + wire.layer_extra && + wire.layer_extra->is_nine_patch_thumb_scrollbar_layer_extra(), + "Invalid layer_extra type for NinePatchThumbScrollbarLayerImpl"); UpdateNinePatchThumbScrollbarLayerExtra( wire.layer_extra->get_nine_patch_thumb_scrollbar_layer_extra(), static_cast<cc::NinePatchThumbScrollbarLayerImpl&>(layer)); break; case cc::mojom::LayerType::kPaintedScrollbar: - RETURN_IF_FALSE(wire.layer_extra, "Invalid layer_extra"); + RETURN_IF_FALSE(wire.layer_extra && + wire.layer_extra->is_painted_scrollbar_layer_extra(), + "Invalid layer_extra type for PaintedScrollbarLayerImpl"); UpdatePaintedScrollbarLayerExtra( wire.layer_extra->get_painted_scrollbar_layer_extra(), static_cast<cc::PaintedScrollbarLayerImpl&>(layer)); break; case cc::mojom::LayerType::kSolidColorScrollbar: - RETURN_IF_FALSE(wire.layer_extra, "Invalid layer_extra"); + RETURN_IF_FALSE( + wire.layer_extra && + wire.layer_extra->is_solid_color_scrollbar_layer_extra(), + "Invalid layer_extra type for SolidColorScrollbarLayerImpl"); UpdateSolidColorScrollbarLayerExtra( wire.layer_extra->get_solid_color_scrollbar_layer_extra(), static_cast<cc::SolidColorScrollbarLayerImpl&>(layer)); break; case cc::mojom::LayerType::kSurface: - RETURN_IF_FALSE(wire.layer_extra, "Invalid layer_extra"); + RETURN_IF_FALSE( + wire.layer_extra && wire.layer_extra->is_surface_layer_extra(), + "Invalid layer_extra type for SurfaceLayerImpl"); UpdateSurfaceLayerExtra(wire.layer_extra->get_surface_layer_extra(), static_cast<cc::SurfaceLayerImpl&>(layer)); break; case cc::mojom::LayerType::kTexture: - RETURN_IF_FALSE(wire.layer_extra, "Invalid layer_extra"); + RETURN_IF_FALSE( + wire.layer_extra && wire.layer_extra->is_texture_layer_extra(), + "Invalid layer_extra type for TextureLayerImpl"); UpdateTextureLayerExtra(wire.layer_extra->get_texture_layer_extra(), static_cast<cc::TextureLayerImpl&>(layer)); break; + case cc::mojom::LayerType::kTileDisplay: + RETURN_IF_FALSE( + wire.layer_extra && wire.layer_extra->is_tile_display_layer_extra(), + "Invalid layer_extra type for TileDisplayLayerImpl"); + UpdateTileDisplayLayerExtra( + wire.layer_extra->get_tile_display_layer_extra(), + static_cast<cc::TileDisplayLayerImpl&>(layer)); + break; case cc::mojom::LayerType::kViewTransitionContent: - RETURN_IF_FALSE(wire.layer_extra, "Invalid layer_extra"); + RETURN_IF_FALSE( + wire.layer_extra && + wire.layer_extra->is_view_transition_content_layer_extra(), + "Invalid layer_extra type for ViewTransitionContentLayerImpl"); UpdateViewTransitionContentLayerExtra( wire.layer_extra->get_view_transition_content_layer_extra(), static_cast<cc::ViewTransitionContentLayerImpl&>(layer));
diff --git a/components/viz/service/layers/layer_context_impl_unittest.cc b/components/viz/service/layers/layer_context_impl_unittest.cc index 513eee3..f846cb67 100644 --- a/components/viz/service/layers/layer_context_impl_unittest.cc +++ b/components/viz/service/layers/layer_context_impl_unittest.cc
@@ -129,6 +129,10 @@ const bool kDefaultViewTransitionContentLayerIsLiveContentLayer = false; const gfx::RectF kDefaultViewTransitionContentLayerMaxExtentsRect; +// Default TileDisplayLayer property values +const std::optional<SkColor4f> kDefaultTileDisplaySolidColor = std::nullopt; +const bool kDefaultTileDisplayIsBackdropFilterMask = false; + class LayerContextImplTest : public testing::Test { public: LayerContextImplTest() @@ -396,6 +400,13 @@ return mojom::LayerExtra::NewViewTransitionContentLayerExtra( std::move(extra)); } + case cc::mojom::LayerType::kTileDisplay: { + auto extra = mojom::TileDisplayLayerExtra::New(); + extra->solid_color = kDefaultTileDisplaySolidColor; + extra->is_backdrop_filter_mask = + kDefaultTileDisplayIsBackdropFilterMask; + return mojom::LayerExtra::NewTileDisplayLayerExtra(std::move(extra)); + } default: // TODO(vmiura): Add each layer type's initialization. @@ -1785,6 +1796,32 @@ } class LayerContextImplLayerLifecycleTest : public LayerContextImplTest { + public: + static std::string GetLayerImplName(cc::mojom::LayerType type) { + switch (type) { + case cc::mojom::LayerType::kLayer: + return "LayerImpl"; + case cc::mojom::LayerType::kMirror: + return "MirrorLayerImpl"; + case cc::mojom::LayerType::kNinePatchThumbScrollbar: + return "NinePatchThumbScrollbarLayerImpl"; + case cc::mojom::LayerType::kPaintedScrollbar: + return "PaintedScrollbarLayerImpl"; + case cc::mojom::LayerType::kSolidColorScrollbar: + return "SolidColorScrollbarLayerImpl"; + case cc::mojom::LayerType::kSurface: + return "SurfaceLayerImpl"; + case cc::mojom::LayerType::kTexture: + return "TextureLayerImpl"; + case cc::mojom::LayerType::kTileDisplay: + return "TileDisplayLayerImpl"; + case cc::mojom::LayerType::kViewTransitionContent: + return "ViewTransitionContentLayerImpl"; + default: + return "UnknownLayerType"; + } + } + protected: cc::LayerImpl* GetLayerFromActiveTree(int layer_id) { return layer_context_impl_->host_impl()->active_tree()->LayerById(layer_id); @@ -2427,7 +2464,7 @@ for (cc::mojom::LayerType type : types_requiring_extra) { SCOPED_TRACE(testing::Message() - << "Testing LayerType: " << static_cast<int>(type)); + << "Testing LayerType: " << GetLayerImplName(type)); ResetTestState(); // Create a valid root layer first. auto initial_update = CreateDefaultUpdate(); @@ -2449,10 +2486,93 @@ auto result = layer_context_impl_->DoUpdateDisplayTree( std::move(update_missing_extra)); ASSERT_FALSE(result.has_value()); - EXPECT_EQ(result.error(), "Invalid layer_extra"); + EXPECT_EQ(result.error(), + "Invalid layer_extra type for " + GetLayerImplName(type)); } } +class LayerContextImplLayerExtraTypeValidationTest + : public LayerContextImplLayerLifecycleTest, + public testing::WithParamInterface<cc::mojom::LayerType> {}; + +const cc::mojom::LayerType kLayerTypesWithSpecificExtras[] = { + cc::mojom::LayerType::kMirror, + cc::mojom::LayerType::kNinePatchThumbScrollbar, + cc::mojom::LayerType::kPaintedScrollbar, + cc::mojom::LayerType::kSolidColorScrollbar, + cc::mojom::LayerType::kSurface, + cc::mojom::LayerType::kTexture, + cc::mojom::LayerType::kTileDisplay, + cc::mojom::LayerType::kViewTransitionContent, +}; + +TEST_P(LayerContextImplLayerExtraTypeValidationTest, MismatchedLayerExtra) { + constexpr int kLayerId = 2; + cc::mojom::LayerType layer_type_under_test = GetParam(); + + for (cc::mojom::LayerType mismatching_extra_provider_type : + kLayerTypesWithSpecificExtras) { + if (layer_type_under_test == mismatching_extra_provider_type) { + continue; + } + + SCOPED_TRACE(testing::Message() + << "LayerTypeUnderTest: " + << GetLayerImplName(layer_type_under_test) + << ", MismatchingExtraProviderType: " + << GetLayerImplName(mismatching_extra_provider_type)); + + // Test Creation with mismatched extra + ResetTestState(); + auto update_create = CreateDefaultUpdate(); + auto layer_props_create = + CreateManualLayer(kLayerId, layer_type_under_test); + layer_props_create->layer_extra = + CreateDefaultLayerExtra(mismatching_extra_provider_type); + update_create->layers.push_back(std::move(layer_props_create)); + update_create->layer_order = {1, kLayerId}; // Root layer (1) + test layer + + auto result_create = + layer_context_impl_->DoUpdateDisplayTree(std::move(update_create)); + ASSERT_FALSE(result_create.has_value()); + EXPECT_THAT(result_create.error(), + testing::StartsWith("Invalid layer_extra type for " + + GetLayerImplName(layer_type_under_test))); + + // Test Update with mismatched extra + ResetTestState(); + auto initial_update = CreateDefaultUpdate(); + AddDefaultLayerToUpdate(initial_update.get(), layer_type_under_test, + kLayerId); + EXPECT_TRUE( + layer_context_impl_->DoUpdateDisplayTree(std::move(initial_update)) + .has_value()); + + auto update_props = CreateDefaultUpdate(); + auto layer_props_update = + CreateManualLayer(kLayerId, layer_type_under_test); + layer_props_update->layer_extra = + CreateDefaultLayerExtra(mismatching_extra_provider_type); + update_props->layers.push_back(std::move(layer_props_update)); + + auto result_update = + layer_context_impl_->DoUpdateDisplayTree(std::move(update_props)); + ASSERT_FALSE(result_update.has_value()); + EXPECT_THAT(result_update.error(), + testing::StartsWith("Invalid layer_extra type for " + + GetLayerImplName(layer_type_under_test))); + } +} + +INSTANTIATE_TEST_SUITE_P( + AllLayerTypesRequiringExtra, + LayerContextImplLayerExtraTypeValidationTest, + testing::ValuesIn(kLayerTypesWithSpecificExtras), + [](const testing::TestParamInfo< + LayerContextImplLayerExtraTypeValidationTest::ParamType>& info) { + return LayerContextImplLayerLifecycleTest::GetLayerImplName(info.param); + }); + TEST_F(LayerContextImplLayerLifecycleTest, UpdateExistingLayerWithInvalidPropertyTreeIndicesFails) { constexpr int kLayerId = 2; @@ -2495,7 +2615,7 @@ ASSERT_FALSE(result_clip.has_value()); EXPECT_THAT(result_clip.error(), testing::StartsWith("Invalid clip tree ID")); - // Test Case 3: Update with invalid effect_tree_index (similar for scroll). + // Test Case 3: Update with invalid effect_tree_index. auto update_invalid_effect = CreateDefaultUpdate(); update_invalid_effect->layers.push_back(CreateManualLayer( kLayerId, cc::mojom::LayerType::kLayer, kDefaultLayerBounds, kValidIndex, @@ -2506,6 +2626,17 @@ EXPECT_THAT(result_effect.error(), testing::StartsWith("Invalid effect tree ID")); + // Test Case 4: Update with invalid scroll_tree_index. + auto update_invalid_scroll = CreateDefaultUpdate(); + update_invalid_scroll->layers.push_back(CreateManualLayer( + kLayerId, cc::mojom::LayerType::kLayer, kDefaultLayerBounds, kValidIndex, + kValidIndex, kValidIndex, kInvalidIndex)); + auto result_scroll = layer_context_impl_->DoUpdateDisplayTree( + std::move(update_invalid_scroll)); + ASSERT_FALSE(result_scroll.has_value()); + EXPECT_THAT(result_scroll.error(), + testing::StartsWith("Invalid scroll tree ID")); + // Verify layer properties remain from the last successful update. cc::LayerImpl* layer_impl_after_invalid = GetLayerFromActiveTree(kLayerId); ASSERT_NE(nullptr, layer_impl_after_invalid); @@ -2802,6 +2933,366 @@ EXPECT_EQ(layer_impl->should_check_backface_visibility(), kDefaultValue); } +// Test fixture for TileDisplayLayerImpl specific property updates. +class LayerContextImplUpdateDisplayTreeTileDisplayLayerPropertiesTest + : public LayerContextImplLayerLifecycleTest {}; + +TEST_F(LayerContextImplUpdateDisplayTreeTileDisplayLayerPropertiesTest, + UpdateTileDisplayLayerProperties) { + constexpr int kLayerId = 2; + const SkColor4f kSolidColor = SkColors::kMagenta; + + // Initial update: Create TileDisplayLayer with default properties. + auto update1 = CreateDefaultUpdate(); + AddDefaultLayerToUpdate(update1.get(), cc::mojom::LayerType::kTileDisplay, + kLayerId); + EXPECT_TRUE( + layer_context_impl_->DoUpdateDisplayTree(std::move(update1)).has_value()); + + cc::LayerImpl* layer_impl_base = GetLayerFromActiveTree(kLayerId); + ASSERT_NE(nullptr, layer_impl_base); + ASSERT_EQ(layer_impl_base->GetLayerType(), + cc::mojom::LayerType::kTileDisplay); + auto* tile_display_layer_impl = + static_cast<cc::TileDisplayLayerImpl*>(layer_impl_base); + + EXPECT_FALSE(tile_display_layer_impl->solid_color_for_testing().has_value()); + EXPECT_FALSE(tile_display_layer_impl->is_backdrop_filter_mask_for_testing()); + + // Second update: Set solid_color and is_backdrop_filter_mask. + auto update2 = CreateDefaultUpdate(); + auto layer_props2 = + CreateManualLayer(kLayerId, cc::mojom::LayerType::kTileDisplay); + auto tile_extra2 = mojom::TileDisplayLayerExtra::New(); + tile_extra2->solid_color = kSolidColor; + tile_extra2->is_backdrop_filter_mask = true; + layer_props2->layer_extra = + mojom::LayerExtra::NewTileDisplayLayerExtra(std::move(tile_extra2)); + update2->layers.push_back(std::move(layer_props2)); + + EXPECT_TRUE( + layer_context_impl_->DoUpdateDisplayTree(std::move(update2)).has_value()); + + EXPECT_TRUE(tile_display_layer_impl->solid_color_for_testing().has_value()); + EXPECT_EQ(tile_display_layer_impl->solid_color_for_testing().value(), + kSolidColor); + EXPECT_TRUE(tile_display_layer_impl->is_backdrop_filter_mask_for_testing()); + + // Third update: Clear solid_color and set is_backdrop_filter_mask to false. + auto update3 = CreateDefaultUpdate(); + auto layer_props3 = + CreateManualLayer(kLayerId, cc::mojom::LayerType::kTileDisplay); + auto tile_extra3 = mojom::TileDisplayLayerExtra::New(); + tile_extra3->solid_color = std::nullopt; + tile_extra3->is_backdrop_filter_mask = false; + layer_props3->layer_extra = + mojom::LayerExtra::NewTileDisplayLayerExtra(std::move(tile_extra3)); + update3->layers.push_back(std::move(layer_props3)); + + EXPECT_TRUE( + layer_context_impl_->DoUpdateDisplayTree(std::move(update3)).has_value()); + + EXPECT_FALSE(tile_display_layer_impl->solid_color_for_testing().has_value()); + EXPECT_FALSE(tile_display_layer_impl->is_backdrop_filter_mask_for_testing()); +} + +TEST_F(LayerContextImplUpdateDisplayTreeTilingTest, TilingAndTileLifecycle) { + constexpr int kLayerId = 2; + constexpr float kScaleKey1 = 1.0f; + constexpr float kScaleKey2 = 2.0f; + const gfx::Size kTileSize1(64, 64); + const gfx::Size kTileSize2(128, 128); + const gfx::Rect kTilingRect1(0, 0, 200, 200); + const gfx::Rect kTilingRect2(0, 0, 400, 400); + const cc::TileIndex kTileIndex1(0, 0); + const cc::TileIndex kTileIndex2(1, 1); + const ResourceId kResourceId1(23); + const ResourceId kResourceId2(45); + + // Initial update: Create TileDisplayLayer. + auto update1 = CreateDefaultUpdate(); + AddDefaultLayerToUpdate(update1.get(), cc::mojom::LayerType::kTileDisplay, + kLayerId); + EXPECT_TRUE( + layer_context_impl_->DoUpdateDisplayTree(std::move(update1)).has_value()); + + cc::LayerTreeImpl* active_tree = + layer_context_impl_->host_impl()->active_tree(); + ASSERT_TRUE(active_tree); + cc::LayerImpl* layer_impl_base = active_tree->LayerById(kLayerId); + ASSERT_NE(nullptr, layer_impl_base); + ASSERT_EQ(layer_impl_base->GetLayerType(), + cc::mojom::LayerType::kTileDisplay); + auto* tile_display_layer_impl = + static_cast<cc::TileDisplayLayerImpl*>(layer_impl_base); + + // Test Case 1: Create a new Tiling with a SolidColor Tile. + auto update_create_tiling = CreateDefaultUpdate(); + auto tiling1 = mojom::Tiling::New(); + tiling1->layer_id = kLayerId; + tiling1->scale_key = kScaleKey1; + tiling1->raster_scale = gfx::Vector2dF(kScaleKey1, kScaleKey1); + tiling1->tile_size = kTileSize1; + tiling1->tiling_rect = kTilingRect1; + auto tile1_solid = mojom::Tile::New(); + tile1_solid->column_index = kTileIndex1.i; + tile1_solid->row_index = kTileIndex1.j; + tile1_solid->contents = + mojom::TileContents::NewSolidColor(SkColors::kMagenta); + tiling1->tiles.push_back(std::move(tile1_solid)); + update_create_tiling->tilings.push_back(std::move(tiling1)); + + EXPECT_TRUE( + layer_context_impl_->DoUpdateDisplayTree(std::move(update_create_tiling)) + .has_value()); + const cc::TileDisplayLayerImpl::Tiling* tiling_impl1 = + tile_display_layer_impl->GetTilingForTesting(kScaleKey1); + ASSERT_NE(nullptr, tiling_impl1); + EXPECT_EQ(tiling_impl1->tile_size(), kTileSize1); + EXPECT_EQ(tiling_impl1->tiling_rect(), kTilingRect1); + ASSERT_NE(nullptr, tiling_impl1->TileAt(kTileIndex1)); + EXPECT_TRUE(tiling_impl1->TileAt(kTileIndex1)->solid_color().has_value()); + EXPECT_EQ(tiling_impl1->TileAt(kTileIndex1)->solid_color().value(), + SkColors::kMagenta); + + // Test Case 2: Update existing Tiling (tile_size) and add a Resource Tile. + auto update_update_tiling = CreateDefaultUpdate(); + auto tiling1_updated = mojom::Tiling::New(); + tiling1_updated->layer_id = kLayerId; + tiling1_updated->scale_key = kScaleKey1; // Same key to update + tiling1_updated->raster_scale = gfx::Vector2dF(kScaleKey1, kScaleKey1); + tiling1_updated->tile_size = kTileSize2; // New tile size + tiling1_updated->tiling_rect = kTilingRect1; + // Add a new resource tile + auto tile2_resource = mojom::Tile::New(); + tile2_resource->column_index = kTileIndex2.i; + tile2_resource->row_index = kTileIndex2.j; + auto resource_contents = mojom::TileResource::New(); + resource_contents->resource = TransferableResource::MakeGpu( + gpu::Mailbox::Generate(), GL_TEXTURE_2D, gpu::SyncToken(), kTileSize2, + SinglePlaneFormat::kRGBA_8888, false); + resource_contents->resource.id = kResourceId1; + resource_contents->is_checkered = false; + tile2_resource->contents = + mojom::TileContents::NewResource(std::move(resource_contents)); + tiling1_updated->tiles.push_back(std::move(tile2_resource)); + update_update_tiling->tilings.push_back(std::move(tiling1_updated)); + + auto result = + layer_context_impl_->DoUpdateDisplayTree(std::move(update_update_tiling)); + EXPECT_TRUE(result.has_value()) << result.error(); + ASSERT_NE(nullptr, tiling_impl1); // Should still be the same tiling object + EXPECT_EQ(tiling_impl1->tile_size(), kTileSize2); // Updated + // Previous tile should be gone due to tile_size change + EXPECT_EQ(nullptr, tiling_impl1->TileAt(kTileIndex1)); + ASSERT_NE(nullptr, tiling_impl1->TileAt(kTileIndex2)); + EXPECT_TRUE(tiling_impl1->TileAt(kTileIndex2)->resource().has_value()); + + // Test Case 3: Add a second Tiling with a MissingReason Tile. + auto update_add_tiling2 = CreateDefaultUpdate(); + auto tiling2 = mojom::Tiling::New(); + tiling2->layer_id = kLayerId; + tiling2->scale_key = kScaleKey2; + tiling2->raster_scale = gfx::Vector2dF(kScaleKey2, kScaleKey2); + tiling2->tile_size = kTileSize1; + tiling2->tiling_rect = kTilingRect2; + auto tile3_missing = mojom::Tile::New(); + tile3_missing->column_index = kTileIndex1.i; + tile3_missing->row_index = kTileIndex1.j; + tile3_missing->contents = mojom::TileContents::NewMissingReason( + cc::mojom::MissingTileReason::kResourceNotReady); + tiling2->tiles.push_back(std::move(tile3_missing)); + update_add_tiling2->tilings.push_back(std::move(tiling2)); + + EXPECT_TRUE( + layer_context_impl_->DoUpdateDisplayTree(std::move(update_add_tiling2)) + .has_value()); + const cc::TileDisplayLayerImpl::Tiling* tiling_impl2 = + tile_display_layer_impl->GetTilingForTesting(kScaleKey2); + ASSERT_NE(nullptr, tiling_impl2); + EXPECT_EQ(tiling_impl2->tile_size(), kTileSize1); + ASSERT_NE(nullptr, tiling_impl2->TileAt(kTileIndex1)); + EXPECT_TRUE(std::holds_alternative<cc::TileDisplayLayerImpl::NoContents>( + tiling_impl2->TileAt(kTileIndex1)->contents())); + EXPECT_EQ(std::get<cc::TileDisplayLayerImpl::NoContents>( + tiling_impl2->TileAt(kTileIndex1)->contents()) + .reason, + cc::mojom::MissingTileReason::kResourceNotReady); + + // Test Case 4: Explicitly delete a Tiling (tiling_impl1). + auto update_delete_tiling1 = CreateDefaultUpdate(); + auto tiling1_deleted_marker = mojom::Tiling::New(); + tiling1_deleted_marker->layer_id = kLayerId; + tiling1_deleted_marker->scale_key = kScaleKey1; + tiling1_deleted_marker->is_deleted = true; + update_delete_tiling1->tilings.push_back(std::move(tiling1_deleted_marker)); + + EXPECT_TRUE( + layer_context_impl_->DoUpdateDisplayTree(std::move(update_delete_tiling1)) + .has_value()); + EXPECT_EQ(nullptr, tile_display_layer_impl->GetTilingForTesting(kScaleKey1)); + EXPECT_NE(nullptr, tile_display_layer_impl->GetTilingForTesting(kScaleKey2)); + + // Test Case 5: Implicitly delete a Tiling by removing all its tiles. + // (tiling_impl2 currently has one kMissingReason tile). + // Send an update for tiling_impl2 that marks its only tile as deleted. + auto update_empty_tiling2 = CreateDefaultUpdate(); + auto tiling2_empty_update = mojom::Tiling::New(); + tiling2_empty_update->layer_id = kLayerId; + tiling2_empty_update->scale_key = kScaleKey2; + tiling2_empty_update->raster_scale = gfx::Vector2dF(kScaleKey2, kScaleKey2); + tiling2_empty_update->tile_size = kTileSize1; // Keep same tile size + tiling2_empty_update->tiling_rect = kTilingRect2; + auto tile_deleted_marker = mojom::Tile::New(); + tile_deleted_marker->column_index = kTileIndex1.i; + tile_deleted_marker->row_index = kTileIndex1.j; + tile_deleted_marker->contents = mojom::TileContents::NewMissingReason( + cc::mojom::MissingTileReason::kTileDeleted); // Mark for deletion + tiling2_empty_update->tiles.push_back(std::move(tile_deleted_marker)); + update_empty_tiling2->tilings.push_back(std::move(tiling2_empty_update)); + + EXPECT_TRUE( + layer_context_impl_->DoUpdateDisplayTree(std::move(update_empty_tiling2)) + .has_value()); + EXPECT_EQ(nullptr, tile_display_layer_impl->GetTilingForTesting(kScaleKey2)); + + // Test Case 6: Update a tile within a tiling (change its content type). + // First, re-add tiling1 with a solid color tile. + auto update_recreate_tiling1 = CreateDefaultUpdate(); + auto tiling1_recreate = mojom::Tiling::New(); + tiling1_recreate->layer_id = kLayerId; + tiling1_recreate->scale_key = kScaleKey1; + tiling1_recreate->raster_scale = gfx::Vector2dF(kScaleKey1, kScaleKey1); + tiling1_recreate->tile_size = kTileSize1; + tiling1_recreate->tiling_rect = kTilingRect1; + auto tile_initial_solid = mojom::Tile::New(); + tile_initial_solid->column_index = kTileIndex1.i; + tile_initial_solid->row_index = kTileIndex1.j; + tile_initial_solid->contents = + mojom::TileContents::NewSolidColor(SkColors::kBlue); + tiling1_recreate->tiles.push_back(std::move(tile_initial_solid)); + update_recreate_tiling1->tilings.push_back(std::move(tiling1_recreate)); + EXPECT_TRUE(layer_context_impl_ + ->DoUpdateDisplayTree(std::move(update_recreate_tiling1)) + .has_value()); + tiling_impl1 = tile_display_layer_impl->GetTilingForTesting(kScaleKey1); + ASSERT_NE(nullptr, tiling_impl1); + ASSERT_NE(nullptr, tiling_impl1->TileAt(kTileIndex1)); + EXPECT_TRUE(tiling_impl1->TileAt(kTileIndex1)->solid_color().has_value()); + + // Now, update that tile to be a resource tile. + auto update_change_tile_type = CreateDefaultUpdate(); + auto tiling1_tile_update = mojom::Tiling::New(); + tiling1_tile_update->layer_id = kLayerId; + tiling1_tile_update->scale_key = kScaleKey1; + tiling1_tile_update->raster_scale = gfx::Vector2dF(kScaleKey1, kScaleKey1); + tiling1_tile_update->tile_size = kTileSize1; // Keep same tile size + tiling1_tile_update->tiling_rect = kTilingRect1; + auto tile_updated_to_resource = mojom::Tile::New(); + tile_updated_to_resource->column_index = kTileIndex1.i; + tile_updated_to_resource->row_index = kTileIndex1.j; + auto resource_contents_updated = mojom::TileResource::New(); + resource_contents_updated->resource = TransferableResource::MakeGpu( + gpu::Mailbox::Generate(), GL_TEXTURE_2D, gpu::SyncToken(), kTileSize1, + SinglePlaneFormat::kRGBA_8888, false); + resource_contents_updated->resource.id = kResourceId2; + resource_contents_updated->is_checkered = true; + tile_updated_to_resource->contents = + mojom::TileContents::NewResource(std::move(resource_contents_updated)); + tiling1_tile_update->tiles.push_back(std::move(tile_updated_to_resource)); + update_change_tile_type->tilings.push_back(std::move(tiling1_tile_update)); + + EXPECT_TRUE(layer_context_impl_ + ->DoUpdateDisplayTree(std::move(update_change_tile_type)) + .has_value()); + ASSERT_NE(nullptr, tiling_impl1->TileAt(kTileIndex1)); + EXPECT_FALSE(tiling_impl1->TileAt(kTileIndex1)->solid_color().has_value()); + EXPECT_TRUE(tiling_impl1->TileAt(kTileIndex1)->resource().has_value()); + EXPECT_TRUE(tiling_impl1->TileAt(kTileIndex1)->resource()->is_checkered); + + // Test Case 7: Attempt to add a tile with an invalid resource ID. + auto update_invalid_resource_tile = CreateDefaultUpdate(); + auto tiling1_invalid_resource_update = mojom::Tiling::New(); + tiling1_invalid_resource_update->layer_id = kLayerId; + tiling1_invalid_resource_update->scale_key = kScaleKey1; + tiling1_invalid_resource_update->raster_scale = + gfx::Vector2dF(kScaleKey1, kScaleKey1); + tiling1_invalid_resource_update->tile_size = kTileSize1; + tiling1_invalid_resource_update->tiling_rect = kTilingRect1; + auto tile_invalid_resource = mojom::Tile::New(); + tile_invalid_resource->column_index = kTileIndex1.i; // Use existing index + tile_invalid_resource->row_index = kTileIndex1.j; + auto invalid_resource_contents = mojom::TileResource::New(); + invalid_resource_contents->resource.id = kInvalidResourceId; // Invalid ID + invalid_resource_contents->resource.size = kTileSize1; + tile_invalid_resource->contents = + mojom::TileContents::NewResource(std::move(invalid_resource_contents)); + tiling1_invalid_resource_update->tiles.push_back( + std::move(tile_invalid_resource)); + update_invalid_resource_tile->tilings.push_back( + std::move(tiling1_invalid_resource_update)); + auto update_invalid_resource_tile_result = + layer_context_impl_->DoUpdateDisplayTree( + std::move(update_invalid_resource_tile)); + ASSERT_FALSE(update_invalid_resource_tile_result.has_value()); + EXPECT_EQ(update_invalid_resource_tile_result.error(), + "Invalid tile resource"); +} + +TEST_F(LayerContextImplUpdateDisplayTreeTilingTest, + TilingForNonTileDisplayLayerFails) { + constexpr int kNonTileDisplayLayerId = 2; + + // Initial update: Create a regular Layer (not TileDisplayLayer). + auto update1 = CreateDefaultUpdate(); + AddDefaultLayerToUpdate(update1.get(), cc::mojom::LayerType::kLayer, + kNonTileDisplayLayerId); + EXPECT_TRUE( + layer_context_impl_->DoUpdateDisplayTree(std::move(update1)).has_value()); + + // Attempt to send tiling data for this non-TileDisplayLayer. + auto update_tiling = CreateDefaultUpdate(); + auto tiling = mojom::Tiling::New(); + tiling->layer_id = kNonTileDisplayLayerId; // ID of a non-TileDisplayLayer + tiling->scale_key = 1.0f; + tiling->raster_scale = gfx::Vector2dF(1.0f, 1.0f); + tiling->tile_size = gfx::Size(64, 64); + tiling->tiling_rect = gfx::Rect(100, 100); + auto tile = mojom::Tile::New(); + tile->column_index = 0; + tile->row_index = 0; + tile->contents = mojom::TileContents::NewSolidColor(SkColors::kRed); + tiling->tiles.push_back(std::move(tile)); + update_tiling->tilings.push_back(std::move(tiling)); + + auto result = + layer_context_impl_->DoUpdateDisplayTree(std::move(update_tiling)); + ASSERT_FALSE(result.has_value()); + EXPECT_EQ(result.error(), "Invalid tile update"); +} + +TEST_F(LayerContextImplUpdateDisplayTreeTilingTest, + TilingWithInvalidLayerIdFails) { + constexpr int kInvalidLayerId = 999; // An ID that doesn't exist. + + auto update_tiling = CreateDefaultUpdate(); + auto tiling = mojom::Tiling::New(); + tiling->layer_id = kInvalidLayerId; + tiling->scale_key = 1.0f; + // Other tiling properties are set to valid defaults for this test. + tiling->raster_scale = gfx::Vector2dF(1.0f, 1.0f); + tiling->tile_size = gfx::Size(64, 64); + tiling->tiling_rect = gfx::Rect(100, 100); + update_tiling->tilings.push_back(std::move(tiling)); + + // No specific error message for invalid layer ID in tiling, it's handled by + // layer_impl being null. The update should still pass, but no tiling occurs. + EXPECT_TRUE(layer_context_impl_->DoUpdateDisplayTree(std::move(update_tiling)) + .has_value()); + // We can't directly verify that no tiling happened for the invalid ID without + // more complex state inspection, but the update itself shouldn't crash. +} + class LayerContextImplUpdateDisplayTreeTextureLayerTest : public LayerContextImplLayerLifecycleTest { protected:
diff --git a/content/browser/browser_context.cc b/content/browser/browser_context.cc index 0e35bf3..80919b9 100644 --- a/content/browser/browser_context.cc +++ b/content/browser/browser_context.cc
@@ -201,7 +201,8 @@ const net::HttpRequestHeaders& additional_headers, std::unique_ptr<PrefetchRequestStatusListener> request_status_listener, base::TimeDelta ttl, - bool should_append_variations_header) { + bool should_append_variations_header, + bool should_disable_block_until_head_timeout) { DCHECK_CURRENTLY_ON(BrowserThread::UI); TRACE_EVENT0("loading", "BrowserContext::StartBrowserPrefetchRequest"); @@ -221,7 +222,8 @@ blink::mojom::Referrer(), javascript_enabled, /*referring_origin=*/std::nullopt, std::move(no_vary_search_hint), /*attempt=*/nullptr, additional_headers, - std::move(request_status_listener), ttl, should_append_variations_header); + std::move(request_status_listener), ttl, should_append_variations_header, + should_disable_block_until_head_timeout); return prefetch_service->AddPrefetchContainerWithHandle(std::move(container)); }
diff --git a/content/browser/fenced_frame/SANDBOX_FLAGS.md b/content/browser/fenced_frame/SANDBOX_FLAGS.md new file mode 100644 index 0000000..7ea6470c --- /dev/null +++ b/content/browser/fenced_frame/SANDBOX_FLAGS.md
@@ -0,0 +1,249 @@ +# Fenced frame: Sandbox Flags + +## How to use this document + +A fenced frame is an embedded context that enforces strict boundaries between +itself and its embedder. Fenced frames are not allowed to communicate +information to and from their embedders (i.e. using something like +`window.postMessage()`), nor are they allowed to learn information about their +context that can help them form a fingerprint of where they're embedded. + +This document serves as an audit for every sandbox flag to determine whether +it's safe to enable inside of a fenced frame. To determine that, we need to +answer the following questions: + +1. Will unsandboxing this flag allow an embedder to send information into a + fenced frame? For example, can the embedder modify some global state that a + fenced frame can later observe? We refer to this in the audit as an + "infiltration risk". +1. Will unsandboxing this flag allow a fenced frame to send information back to + its embedder? We refer to this as an "exfiltration risk". +1. Will unsandboxing this flag allow a fenced frame to learn about the context + it's embedded in and create a fingerprint? We refer to this as a + "fingerprinting risk". When referring to fingerprinting in this document, we + are referring to [active + fingerprinting](https://www.w3.org/TR/fingerprinting-guidance/#active-0) + specifically, as all of these require the use of JavaScript to read the + relevant properties the APIs expose. + +**If you're adding a new sandbox flag, please do the following:** + +1. Answer the 3 questions above to determine the infiltration, exfiltration, and + fingerprinting risks for your flag, if any exist. +1. Add a new entry in this document with your sandbox flag, what risks they + carry, and a brief justification either outlining the risks or explaining why + the API carries no risk. + +Please feel free to reach out to +`third_party/blink/renderer/core/html/fenced_frame/OWNERS` with any questions +you have. + +## Sandbox flags for fenced frames created with Protected Audience + +Protected Audience-created fenced frames have the privacy guarantee that no +information can flow from the embedder into the fenced frame. If we allowed +arbitrary sandboxing flag sets to be applied, an embedder can enable and disable +a specific combination of flags, which the fenced frame can then test for to +create a fingerprint of the context it's in, allowing up to 1 bit per flag (up +to 15 bits, as of January 2025) to be infiltrated into the fenced frame. + +To mitigate this risk, we require a specific set of sandbox flags to be +unsandboxed in the context the fenced frame loads in. If any of those flags are +sandboxed (i.e. restricted), the fenced frame will not load. The rest of the +flags are forced to be sandboxed once the fenced frame loads, even if the fenced +frame attempts to enable the flag. + +See: `kFencedFrameForcedSandboxFlags` and +`kFencedFrameMandatoryUnsandboxedFlags` in +`third_party/blink/public/common/frame/fenced_frame_sandbox_flags.h`. The forced +sandboxed and mandatory unsandboxed flags are the current behavior for all +fenced frames variants. + +## Sandbox flags for fenced frames created with selectURL() + +selectURL-created fenced frames can contain information from the embedder by +having the embedder add arbitrary data to the URLs that the frame is navigated +to. Because of this, it is acceptable to have information flow in from the +embedder to the fenced frame via the combination of sandboxing flags in place. + +However, stopping data outflow from the fenced frame to the embedder is still +part of the privacy story. If unsandboxing a flag results in access to an API +that can exfiltrate data across a fenced frame boundary, that flag must always +be forced to be sandboxed. + +## Sandbox flags for fenced frames with unpartitioned data access + +When fenced frames get access to unpartitioned data, they also lose network +access. This is done to prevent the unpartitioned data from being exfiltrated +and joined with other cross-site signals. After this point, the unpartitioned +data must not be able to be sent out of the fenced frame. Otherwise, a frame +that still has network access can act as a proxy to send the data to an external +server. Note that these fenced frames can be created with the +`FencedFrameConfig(url)` constructor, which allows arbitrary data to flow in via +the URL. + +## Sandbox flags audit + +Below is an audit of all sandbox flags (as of January 2025) and whether enabling +them for fenced frames (that can allow embedder information to be transferred to +the FF, i.e. `FencedFrameConfig(url)` and `selectURL()`-created frames), if +needed in the future, is safe or will pose a risk: + +Legend: + +* ✅: No risk/issues +* 🔻: Infiltration risk +* 🔺: Exfiltration risk +* 🖐️: Fingerprinting risk +* ❌: Usability issues +* 🤬: UX concerns + +Note that since Protected Audience-created fenced frames are used specifically +for ads, much of the UX concerns listed in this document are from an ads +perspective. + +### 🤬 Downloads: UX concerns +*Sandbox flag: allow-downloads* + +All downloads are explicitly disabled in fenced frames regardless of sandbox +flags. An ad that automatically starts a download is something we want to avoid, +since that can be used for abuse vectors. Allowing this flag will have no effect +inside of a fenced frame. + +### ✅ Forms: no risk +*Sandbox flag: allow-forms* + +Forms allow data to be POSTed to external servers. However, the embedding +context has no knowledge of this happening. Since forms are entirely +self-contained within the fenced frame, no new information can be infiltrated +into the fenced frame, and the form can't be used to learn about the embedding +context. + +### 🤬 Modals: UX concerns +*Sandbox flag: allow-modals* + +Modals (such as `alert()`, `confirm()`, and `print()`) are explicitly disallowed +in fenced frames. Allowing an ad to open an alert box will be extremely +irritating to the user, regardless of whether the user gave the frame user +activation. This flag will and should have no effect inside of a fenced frame. + +### 🤬 Orientation Lock: UX concerns +*Sandbox flag: allow-orientation-lock* + +Orientation lock is +[deprecated](https://developer.mozilla.org/en-US/docs/Web/API/Screen/lockOrientation) +because allowing subframes to lock the orientation of an entire device's screen +rotation can easily be confusing and frustrating for users. The replacement, +`orientation.lock()`, is also explicitly disallowed in fenced frames for that +same reason. This flag will and should have no effect inside of a fenced frame. + +### 🤬 Pointer Lock: UX concerns +*Sandbox flag: allow-pointer-lock* + +An ad locking the user's pointer is very bad UX, so pointer lock is always +disabled in fenced frames regardless of the sandbox flag. + +### ✅ Pop-ups: no risk +*Sandbox flag: allow-popups* + +Data is sent to external servers in order to open a pop-up window. However, the +embedding context has no knowledge of this happening, and servers can only be +provided information that already exists in the fenced frame. Once a pop-up is +created, it will follow a no-opener relationship with the fenced frame and not +be able to send any data back to it. Any potential risks with unpartition data +access are mitigated simply by the network revocation mechanism preventing any +network requests from going out after the fenced frame gets access. + +### ✅ Pop-ups escape sandbox: no risk +*Sandbox flag: allow-popups-to-escape-sandbox* + +This is currently forced to be unsandboxed. If we allow this to be sandboxed, +then a pop-up could inherit the sandboxing flag set of the fenced frame, using +that to build a fingerprint of the context that opened it. However, the same +amount of information can be conveyed simply by passing in query parameters to +the URL. For that reason, there is no additional risk allowing this restriction +introduces. + +### 🔻🔺 Presentations: infiltration/exfiltration risk +*Sandbox flag: allow-presentation* + +Information about [display availability for +presentations](https://developer.mozilla.org/en-US/docs/Web/API/PresentationAvailability) +is available across contexts. If one context enters presentation mode, that can +be observed by another context. Therefore, this must not be allowed inside of +fenced frames. + +### ✅ Same-origin: no risk +*Sandbox flag: allow-same-origin* + +This flag is currently forced to be unsandboxed. The fenced frame getting +information about its origin does not pose any risk since fenced frames cannot +access origin scoped storage. Their storage, cookies, and network access is +further guaranteed to be ephemeral via a nonce in the corresponding storage, +cookie, and network isolation keys as described in [this +explainer](https://github.com/WICG/fenced-frame/blob/master/explainer/storage_cookies_network_state.md). + +### ✅ Scripts: no risk +*Sandbox flag: allow-scripts* + +While there exist APIs that are called via JavaScript that are able to leak +information across fenced frame boundaries, disabling all scripts for all fenced +frames would be too drastic of a move and would render fenced frames useless. +Instead, our approach is to tackle the offending APIs directly, disallowing them +within fenced frames rather than all script calls, problematic or otherwise. + +### 🔻🔺🖐️ Storage Access With User Activation: infiltration/exfiltration/fingerprinting risk +*Sandbox flag: allow-storage-access-by-user-activation* + +The [Storage Access +API](https://developer.mozilla.org/en-US/docs/Web/API/Storage_Access_API) allows +subframes to get access to unpartitioned third party cookies, an explicit +non-goal of fenced frames. Allowing this will open an unrestricted communication +channel across fenced frame boundaries. + +### ✅ Top-level Navigation With User Activation: minimal risk +*Sandbox flag: allow-top-navigation-by-user-activation* + +For most use cases, no information can be exfiltrated that can't already be +exfiltrated via a `fetch()` request. + +Fenced frames created with +[`selectURL()`](https://github.com/WICG/shared-storage?tab=readme-ov-file#select-url) +can have up to 3 bits of cross-site data per navigation (since `selectURL()` +takes up to 8 URLs as input) which can be leaked as part of a top-level +navigation. However, there are mitigations in place in the Shared Storage API to +minimize this risk and make this acceptable to enable in fenced frames. + +See: https://github.com/WICG/shared-storage/blob/main/select-url.md#privacy + +### 🖐️🤬 Top-level Navigation Without User Activation: fingerprinting risk, UX concerns +*Sandbox flag: allow-top-navigation* + +This has the same risks as `allow-top-navigation-by-user-activation`, but now +there does not need to be a user gesture to send the information out. Because +this can now happen automatically, this is more of a risk for +`selectURL()`-generated fenced frames. + +Allowing fenced frames to open pop-ups without ever getting any user interaction +can result in a bad user experience. This should not be allowed. even in cases +where no information can be leaked. + +### ✅ Top-level Navigation to Custom Protocols: no risk +*Sandbox flag: allow-top-navigation-to-custom-protocols* + +A fenced frame making a request to an http:// or https:// endpoint is no +different from a privacy standpoint than a request to an ftp:// or a mailto:// +endpoint. Information can be encoded in each protocol's request, and none of +them give the fenced frame access to any new information about its context or +vice versa. + +### ❌ SameSite=None Cookies: usability issues +*Sandbox flag: allow-same-site-none-cookies* + +Fenced frames [only allow access to partitioned +cookies](https://github.com/WICG/fenced-frame/blob/master/explainer/storage_cookies_network_state.md#cookies). +Allowing `SameSite=None` cookies allows cookies to be shared between sites and +cross-site requests, but that is only useful in contexts where this kind of +unpartitioned cookie access is allowed to begin with. Since fenced frames force +all cookies to be partitioned regardless, enabling this flag inside a fenced +frame will be a no-op.
diff --git a/content/browser/preloading/prefetch/prefetch_container.cc b/content/browser/preloading/prefetch/prefetch_container.cc index 7443662..fcf8bed 100644 --- a/content/browser/preloading/prefetch/prefetch_container.cc +++ b/content/browser/preloading/prefetch/prefetch_container.cc
@@ -355,7 +355,8 @@ ->GetOrCreateWebPreferences() .javascript_enabled, PrefetchContainerDefaultTtlInPrefetchService(), - /*should_append_variations_header=*/true) { + /*should_append_variations_header=*/true, + /*should_disable_block_until_head_timeout=*/false) { CHECK(prefetch_type_.IsRendererInitiated()); } @@ -395,7 +396,8 @@ referring_web_contents.GetOrCreateWebPreferences().javascript_enabled, ttl.has_value() ? ttl.value() : PrefetchContainerDefaultTtlInPrefetchService(), - /*should_append_variations_header=*/true) { + /*should_append_variations_header=*/true, + /*should_disable_block_until_head_timeout=*/false) { CHECK(!prefetch_type_.IsRendererInitiated()); CHECK(PrefetchBrowserInitiatedTriggersEnabled()); CHECK(!embedder_histogram_suffix_.value().empty()); @@ -414,7 +416,8 @@ const net::HttpRequestHeaders& additional_headers, std::unique_ptr<PrefetchRequestStatusListener> request_status_listener, base::TimeDelta ttl, - bool should_append_variations_header) + bool should_append_variations_header, + bool should_disable_block_until_head_timeout) : PrefetchContainer( GlobalRenderFrameHostId(), referring_origin, @@ -439,7 +442,8 @@ std::move(request_status_listener), javascript_enabled, ttl, - should_append_variations_header) { + should_append_variations_header, + should_disable_block_until_head_timeout) { CHECK(!prefetch_type_.IsRendererInitiated()); CHECK(PrefetchBrowserInitiatedTriggersEnabled()); CHECK(!embedder_histogram_suffix_.value().empty()); @@ -466,7 +470,8 @@ std::unique_ptr<PrefetchRequestStatusListener> request_status_listener, bool is_javascript_enabled, base::TimeDelta ttl, - bool should_append_variations_header) + bool should_append_variations_header, + bool should_disable_block_until_head_timeout) : referring_render_frame_host_id_(referring_render_frame_host_id), referring_origin_(referring_origin), referring_url_hash_(referring_url_hash), @@ -490,7 +495,9 @@ request_status_listener_(std::move(request_status_listener)), is_javascript_enabled_(is_javascript_enabled), ttl_(ttl), - should_append_variations_header_(should_append_variations_header) { + should_append_variations_header_(should_append_variations_header), + should_disable_block_until_head_timeout_( + should_disable_block_until_head_timeout) { is_likely_ahead_of_prerender_ = CalculateIsLikelyAheadOfPrerender(*preload_pipeline_info_);
diff --git a/content/browser/preloading/prefetch/prefetch_container.h b/content/browser/preloading/prefetch/prefetch_container.h index 82bea9f..7b2bd87 100644 --- a/content/browser/preloading/prefetch/prefetch_container.h +++ b/content/browser/preloading/prefetch/prefetch_container.h
@@ -150,7 +150,8 @@ std::unique_ptr<PrefetchRequestStatusListener> request_status_listener = nullptr, base::TimeDelta ttl = PrefetchContainerDefaultTtlInPrefetchService(), - bool should_append_variations_header = true); + bool should_append_variations_header = true, + bool should_disable_block_until_head_timeout = false); ~PrefetchContainer(); @@ -797,6 +798,10 @@ return service_worker_state_; } + bool ShouldDisableBlockUntilHeadTimeout() const { + return should_disable_block_until_head_timeout_; + } + protected: friend class PrefetchContainerTestBase; @@ -828,7 +833,8 @@ std::unique_ptr<PrefetchRequestStatusListener> request_status_listener, bool is_javascript_enabled, base::TimeDelta ttl, - bool should_append_variations_header); + bool should_append_variations_header, + bool should_disable_block_until_head_timeout); // Update |prefetch_status_| and report prefetch status to // DevTools without updating TriggeringOutcome. @@ -1103,6 +1109,11 @@ // content. const bool should_append_variations_header_ = true; + // Whether the caller of prefetches requests to disable + // `BlockUntilHeadTimeout`, which is currently calculated by + // `PrefetchBlockUntilHeadTimeout()` as a `prefetch_params`. + const bool should_disable_block_until_head_timeout_ = false; + // Timing information for metrics // // Constraint: That earlier one is null implies that later one is null.
diff --git a/content/browser/preloading/prefetch/prefetch_match_resolver.cc b/content/browser/preloading/prefetch/prefetch_match_resolver.cc index 9a1e626..97eec695 100644 --- a/content/browser/preloading/prefetch/prefetch_match_resolver.cc +++ b/content/browser/preloading/prefetch/prefetch_match_resolver.cc
@@ -221,7 +221,9 @@ // https://chromium-review.googlesource.com/c/chromium/src/+/5668924 and // write tests. base::TimeDelta timeout = PrefetchBlockUntilHeadTimeout( - prefetch_container.GetPrefetchType(), is_nav_prerender_); + prefetch_container.GetPrefetchType(), + prefetch_container.ShouldDisableBlockUntilHeadTimeout(), + is_nav_prerender_); if (timeout.is_positive()) { candidate_data->timeout_timer = std::make_unique<base::OneShotTimer>(); candidate_data->timeout_timer->Start(
diff --git a/content/browser/preloading/prefetch/prefetch_params.cc b/content/browser/preloading/prefetch/prefetch_params.cc index 6e94e6a3..616298c7 100644 --- a/content/browser/preloading/prefetch/prefetch_params.cc +++ b/content/browser/preloading/prefetch/prefetch_params.cc
@@ -189,8 +189,15 @@ features::kPrefetchUseContentRefactor, "canary_check_retries", 1); } -base::TimeDelta PrefetchBlockUntilHeadTimeout(const PrefetchType& prefetch_type, - bool is_nav_prerender) { +base::TimeDelta PrefetchBlockUntilHeadTimeout( + const PrefetchType& prefetch_type, + bool should_disable_block_until_head_timeout, + bool is_nav_prerender) { + // If the caller of prefetches requests to disable the timeout, follow that. + if (should_disable_block_until_head_timeout) { + return base::Seconds(0); + } + // Don't set a timeout for prerender because // // - The intention of prefetch ahead of prerender is not sending additional
diff --git a/content/browser/preloading/prefetch/prefetch_params.h b/content/browser/preloading/prefetch/prefetch_params.h index 22b82921..b3c9b96 100644 --- a/content/browser/preloading/prefetch/prefetch_params.h +++ b/content/browser/preloading/prefetch/prefetch_params.h
@@ -101,6 +101,7 @@ // If the value is zero or less, then a navigation can be blocked indefinitely. CONTENT_EXPORT base::TimeDelta PrefetchBlockUntilHeadTimeout( const PrefetchType& prefetch_type, + bool should_disable_block_until_head_timeout, bool is_nav_prerender); // Gets the histogram suffix for the given `prefetch_type` and
diff --git a/content/browser/preloading/prefetch/prefetch_service_unittest.cc b/content/browser/preloading/prefetch/prefetch_service_unittest.cc index 25aef95..bba066b 100644 --- a/content/browser/preloading/prefetch/prefetch_service_unittest.cc +++ b/content/browser/preloading/prefetch/prefetch_service_unittest.cc
@@ -550,12 +550,14 @@ std::optional<net::HttpNoVarySearchData> no_vary_search_data, const net::HttpRequestHeaders& additional_headers, std::unique_ptr<PrefetchRequestStatusListener> request_status_listener, - base::TimeDelta ttl = base::Seconds(/* 10 minutes */ 60 * 10)) { + base::TimeDelta ttl = base::Seconds(/* 10 minutes */ 60 * 10), + bool should_disable_block_until_head_timeout = false) { return browser_context()->StartBrowserPrefetchRequest( url, test::kPreloadingEmbedderHistgramSuffixForTesting, true, no_vary_search_data, additional_headers, std::move(request_status_listener), ttl, - /*should_append_variations_header=*/true); + /*should_append_variations_header=*/true, + should_disable_block_until_head_timeout); } int RequestCount() { return test_url_loader_factory_.NumPending(); } @@ -4626,8 +4628,9 @@ std::string histogram_suffix = GetMetricsSuffixTriggerTypeAndEagerness(prefetch_type, std::nullopt); - base::TimeDelta block_until_head_timeout = - PrefetchBlockUntilHeadTimeout(prefetch_type, /*is_nav_prerender=*/false); + base::TimeDelta block_until_head_timeout = PrefetchBlockUntilHeadTimeout( + prefetch_type, /*should_disable_block_until_head_timeout=*/false, + /*is_nav_prerender=*/false); histogram_tester.ExpectTotalCount( base::StringPrintf( "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.Served.%s", @@ -5434,6 +5437,156 @@ true, 2); } +class PrefetchServiceDisableBlockUntilHeadTimeoutTest + : public PrefetchServiceTestBase, + public WithPrefetchServiceRearchParam, + public ::testing::WithParamInterface<PrefetchServiceRearchParam::Arg> { + public: + PrefetchServiceDisableBlockUntilHeadTimeoutTest() + : WithPrefetchServiceRearchParam(GetParam()) {} + + static constexpr int kBlockUntilHeadTimeout = 1000; + + void InitScopedFeatureList() override { + InitBaseParams(); + InitRearchFeatures(); + // Override `kPrefetchUseContentRefactor`. + scoped_feature_list_.InitWithFeaturesAndParameters( + {{features::kPrefetchUseContentRefactor, + { + {"ineligible_decoy_request_probability", "0"}, + {"prefetch_container_lifetime_s", "-1"}, + {"prefetch_timeout_ms", "10000"}, + // Initialize > 0ms timeouts for testing purposes. + {"block_until_head_timeout_embedder_prefetch", + base::NumberToString(kBlockUntilHeadTimeout)}, + }}}, + {}); + } + + private: + base::test::ScopedFeatureList scoped_feature_list_; +}; + +INSTANTIATE_TEST_SUITE_P( + ParametrizedTests, + PrefetchServiceDisableBlockUntilHeadTimeoutTest, + testing::ValuesIn(PrefetchServiceRearchParam::Params())); + +// Tests that the default `BlockUntilHeadTimeout` is used if +// `should_disable_block_until_head_timeout` is false. +TEST_P(PrefetchServiceDisableBlockUntilHeadTimeoutTest, + DISABLED_CHROMEOS(DisableBlockUntilHeadTimeoutFalse)) { + base::HistogramTester histogram_tester; + MakePrefetchService( + std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>( + /*num_on_prefetch_likely_calls=*/std::nullopt)); + + // Set `should_disable_block_until_head_timeout` to false. + std::unique_ptr<content::PrefetchHandle> handle = + MakePrefetchFromBrowserContext( + GURL("https://example.com"), + /*no_vary_search_data=*/std::nullopt, /*additional_headers=*/{}, + /*request_status_listener=*/nullptr, + base::Seconds(/* 10 minutes */ 60 * 10), + /*should_disable_block_until_head_timeout=*/false); + task_environment()->RunUntilIdle(); + + VerifyCommonRequestStateForEmbedders(GURL("https://example.com"), + {.use_prefetch_proxy = false}); + + // Simulate a navigation. The prefetch should not be served after a timeout. + std::unique_ptr<NavigationResult> navigation_result = + SimulatePartOfNavigation(GURL("https://example.com"), + /*is_renderer_initiated=*/false, + /*is_nav_prerender=*/false); + task_environment()->RunUntilIdle(); + ASSERT_FALSE(navigation_result->reader_future.IsReady()); + task_environment()->FastForwardBy(base::Milliseconds(kBlockUntilHeadTimeout)); + EXPECT_TRUE(navigation_result->reader_future.IsReady()); + EXPECT_FALSE(navigation_result->reader_future.Take()); + + auto metrics_suffix = GetMetricsSuffixTriggerTypeAndEagerness( + PrefetchType(PreloadingTriggerType::kEmbedder, + /*use_prefetch_proxy=*/false), + test::kPreloadingEmbedderHistgramSuffixForTesting); + histogram_tester.ExpectUniqueSample( + base::StringPrintf( + "Prefetch.PrefetchMatchingBlockedNavigation.PerMatchingCandidate.%s", + metrics_suffix), + true, 1); + histogram_tester.ExpectUniqueTimeSample( + base::StringPrintf( + "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.NotServed.%s", + metrics_suffix), + base::Milliseconds(kBlockUntilHeadTimeout), 1); + histogram_tester.ExpectTotalCount( + base::StringPrintf( + "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.Served.%s", + metrics_suffix), + 0); +} + +// Tests that the default `BlockUntilHeadTimeout` is ignored if +// `should_disable_block_until_head_timeout` is true. +TEST_P(PrefetchServiceDisableBlockUntilHeadTimeoutTest, + DISABLED_CHROMEOS(DisableBlockUntilHeadTimeoutTrue)) { + base::HistogramTester histogram_tester; + MakePrefetchService( + std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>( + /*num_on_prefetch_likely_calls=*/std::nullopt)); + + // Set `should_disable_block_until_head_timeout` to true. + std::unique_ptr<content::PrefetchHandle> handle = + MakePrefetchFromBrowserContext( + GURL("https://example.com"), + /*no_vary_search_data=*/std::nullopt, /*additional_headers=*/{}, + /*request_status_listener=*/nullptr, + base::Seconds(/* 10 minutes */ 60 * 10), + /*should_disable_block_until_head_timeout=*/true); + task_environment()->RunUntilIdle(); + + VerifyCommonRequestStateForEmbedders(GURL("https://example.com"), + {.use_prefetch_proxy = false}); + + // Simulate a navigation. The prefetch still blocks the navigation, after the + // default timeout/ + std::unique_ptr<NavigationResult> navigation_result = + SimulatePartOfNavigation(GURL("https://example.com"), + /*is_renderer_initiated=*/false, + /*is_nav_prerender=*/false); + ASSERT_FALSE(navigation_result->reader_future.IsReady()); + task_environment()->FastForwardBy(base::Milliseconds(kBlockUntilHeadTimeout)); + EXPECT_FALSE(navigation_result->reader_future.IsReady()); + + // It is eventually served after creating a response head. + MakeResponseAndWait(net::HTTP_OK, net::OK, kHTMLMimeType, + /*use_prefetch_proxy=*/true, + {{"X-Testing", "Hello World"}}, kHTMLBody); + EXPECT_TRUE(navigation_result->reader_future.IsReady()); + EXPECT_TRUE(navigation_result->reader_future.Take()); + + auto metrics_suffix = GetMetricsSuffixTriggerTypeAndEagerness( + PrefetchType(PreloadingTriggerType::kEmbedder, + /*use_prefetch_proxy=*/false), + test::kPreloadingEmbedderHistgramSuffixForTesting); + histogram_tester.ExpectUniqueSample( + base::StringPrintf( + "Prefetch.PrefetchMatchingBlockedNavigation.PerMatchingCandidate.%s", + metrics_suffix), + true, 1); + histogram_tester.ExpectUniqueTimeSample( + base::StringPrintf( + "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.Served.%s", + metrics_suffix), + base::Milliseconds(kBlockUntilHeadTimeout), 1); + histogram_tester.ExpectTotalCount( + base::StringPrintf( + "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.NotServed.%s", + metrics_suffix), + 0); +} + // Tests that the prefetch eviction for eligible but not started triggers (i.e. // `PreloadingAttempt`'s `PreloadingHoldbackStatus` is `kUnspecified`) causes no // crash. This is a regression test of crbug.com/404703517.
diff --git a/content/public/browser/browser_context.h b/content/public/browser/browser_context.h index e4b6b78..d9d30c0 100644 --- a/content/public/browser/browser_context.h +++ b/content/public/browser/browser_context.h
@@ -204,8 +204,11 @@ // `embedder_histogram_suffix` is used for generating internal histogram names // recorded per trigger. `ttl` (Time-To-Live) specifies how long // prefetched data remains valid in the cache. After this period, the data is - // reset. Returns `PrefetchHandle` to control prefetch resources. This can be - // null when it can't add `PrefetchContainer` to `PrefetchService`. + // reset. `should_disable_block_until_head_timeout` specifies whether we + // should have a timeout when this prefetch blocks the navigation until its + // head is determined. Returns `PrefetchHandle` to control prefetch resources. + // This can be null when it can't add `PrefetchContainer` to + // `PrefetchService`. std::unique_ptr<content::PrefetchHandle> StartBrowserPrefetchRequest( const GURL& url, const std::string& embedder_histogram_suffix, @@ -214,7 +217,8 @@ const net::HttpRequestHeaders& additional_headers, std::unique_ptr<PrefetchRequestStatusListener> request_status_listener, base::TimeDelta ttl, - bool should_append_variations_header); + bool should_append_variations_header, + bool should_disable_block_until_head_timeout); // Updates the "Accept Language" header that the prefetch service delegate // will use.
diff --git a/content/public/browser/web_contents_observer.h b/content/public/browser/web_contents_observer.h index 7e0dd46..575856f 100644 --- a/content/public/browser/web_contents_observer.h +++ b/content/public/browser/web_contents_observer.h
@@ -25,7 +25,6 @@ #include "ipc/ipc_message.h" #include "mojo/public/cpp/system/message_pipe.h" #include "services/network/public/mojom/fetch_api.mojom-forward.h" -#include "services/service_manager/public/cpp/bind_source_info.h" #include "third_party/blink/public/common/input/web_input_event.h" #include "third_party/blink/public/common/user_agent/user_agent_metadata.h" #include "third_party/blink/public/mojom/css/preferred_color_scheme.mojom.h"
diff --git a/crypto/features.cc b/crypto/features.cc index 110cbf8..5ed1518 100644 --- a/crypto/features.cc +++ b/crypto/features.cc
@@ -14,6 +14,6 @@ BASE_FEATURE(kIsHardwareBackedFixEnabled, "IsHardwareBackedFixEnabled", - base::FEATURE_DISABLED_BY_DEFAULT); + base::FEATURE_ENABLED_BY_DEFAULT); } // namespace crypto::features
diff --git a/crypto/features.h b/crypto/features.h index e029c62..05e3557 100644 --- a/crypto/features.h +++ b/crypto/features.h
@@ -15,8 +15,7 @@ // Enables the fix for `UnexportableSigningKey::IsHardwareBacked` when // dealing with Windows software keys. -// Currently disabled until a workaround is landed for existing enclave -// keys. +// Enabled by default on M139. Remove in or after M142. CRYPTO_EXPORT BASE_DECLARE_FEATURE(kIsHardwareBackedFixEnabled); } // namespace crypto::features
diff --git a/crypto/obsolete/md5.h b/crypto/obsolete/md5.h index 2e263b27..872d9e42 100644 --- a/crypto/obsolete/md5.h +++ b/crypto/obsolete/md5.h
@@ -31,6 +31,10 @@ crypto::obsolete::Md5 MakeMd5HasherForImageWriter(); } +namespace net { +crypto::obsolete::Md5 MakeMd5HasherForHttpVaryData(); +} + namespace policy { crypto::obsolete::Md5 MakeMd5HasherForPolicyEventId(); } @@ -81,6 +85,9 @@ friend Md5 ash::printing::MakeMd5HasherForZeroconf(); friend std::string ash::printing::ServerPrinterId(const std::string& url); + // TODO(https://crbug.com/419853200): get rid of this. + friend Md5 net::MakeMd5HasherForHttpVaryData(); + // TODO(https://crbug.com/416304903): get rid of this. friend Md5 web_app::internals::MakeMd5HasherForWebAppShortcutIcon();
diff --git a/device/bluetooth/bluez/bluetooth_adapter_bluez.cc b/device/bluetooth/bluez/bluetooth_adapter_bluez.cc index 726a2cb..155811a2 100644 --- a/device/bluetooth/bluez/bluetooth_adapter_bluez.cc +++ b/device/bluetooth/bluez/bluetooth_adapter_bluez.cc
@@ -19,10 +19,8 @@ #include "base/location.h" #include "base/logging.h" #include "base/memory/ptr_util.h" -#include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" #include "base/observer_list.h" -#include "base/strings/string_util.h" #include "base/task/single_thread_task_runner.h" #include "base/time/time.h" #include "build/build_config.h" @@ -1428,10 +1426,6 @@ if (!scan_record) return; - base::UmaHistogramBoolean( - "Bluetooth.LocalNameIsUtf8", - base::IsStringUTF8(scan_record->advertisement_name)); - auto service_data_map = ConvertServiceDataMap(scan_record->service_data_map); auto manufacturer_data_map = ConvertManufacturerDataMap(scan_record->manufacturer_data_map);
diff --git a/docs/mojo_ipc_conversion.md b/docs/mojo_ipc_conversion.md index 9b10a4f..28a8438 100644 --- a/docs/mojo_ipc_conversion.md +++ b/docs/mojo_ipc_conversion.md
@@ -108,19 +108,13 @@ solution for establishing a mutual FIFO between multiple logical Mojo interfaces by having them share a single message pipe. -In Chrome, the `IPC::Channel` which carries all legacy IPC messages between -two processes is itself a Mojo message pipe. We provide a mechanism for +In Chrome, the `IPC::Channel` which carries all legacy IPC messages between two +processes is itself a Mojo message pipe (implicitly). We provide a mechanism for associating arbitrary Mojo interfaces with this pipe, which means messages can be converted to Mojo while preserving strict FIFO with respect to other legacy IPC messages. Such interfaces are designated in Chrome parlance as **Channel-associated interfaces**. -*** aside -**NOTE:** Channel-associated interface acquisition is not constrained by the -Service Manager in any way, so security reviewers need to be careful to inspect -new additions and uses of such interfaces. -*** - Usage of Channel-associated interfaces should be rare but is considered a reasonable intermediate solution for incremental IPC conversions where it would be too risky or noisy to convert a large IPC surface all at once, but it would @@ -132,14 +126,14 @@ a renderer process, as this is the most complex IPC surface with the most implicit ordering dependencies. A few simple APIs exist to support this. -`RenderProcessHostImpl` owns an `IPC::Channel` to its corresponding -`RenderThreadImpl` in the render process. This object has a +`RenderProcessHostImpl` owns an `IPC::Channel` (through `IPC::ChannelProxy`) +to its corresponding `RenderFrameImpl` in the render process. This object has a `GetRemoteAssociatedInterfaces` method which can be used to pass arbitrary associated interface requests: ``` cpp mojo::PendingAssociatedRemote<magic::mojom::GoatTeleporter> teleporter; -channel_->GetRemoteAssociatedInterfaces()->GetInterface(teleporter.BindNewEndpointAndPassReceiver()); +render_frame->GetRemoteAssociatedInterfaces()->GetInterface(&teleporter); // These messages are all guaranteed to arrive in the same order they were sent. channel_->Send(new FooMsg_SomeLegacyIPC); @@ -147,18 +141,12 @@ channel_->Send(new FooMsg_AnotherLegacyIPC); ``` -Likewise, `ChildThreadImpl` has an `IPC::Channel` that can be used in the same -way to send such messages back to the browser. +Likewise, `RenderFrameHostImpl` defines a `GetRemoteAssociatedInterfaces` +method. To receive and bind incoming Channel-associated interface requests, the above objects also implement `IPC::Listener::OnAssociatedInterfaceRequest`. -For supplementation of routed messages, both `RenderFrameHostImpl` and -`RenderFrameImpl` define a `GetRemoteAssociatedInterfaces` method which works -like the one on `IPC::Channel`, and both objects also implement -`IPC::Listener::OnAssociatedInterfaceRequest` for processing incoming associated -interface requests specific to their own frame. - There are some example conversion CLs which use Channel-associated interfaces [here](https://codereview.chromium.org/2381493003) and [here](https://codereview.chromium.org/2400313002).
diff --git a/extensions/browser/extension_host.cc b/extensions/browser/extension_host.cc index a513075..087c7e15 100644 --- a/extensions/browser/extension_host.cc +++ b/extensions/browser/extension_host.cc
@@ -30,6 +30,7 @@ #include "extensions/browser/extension_host_observer.h" #include "extensions/browser/extension_host_queue.h" #include "extensions/browser/extension_host_registry.h" +#include "extensions/browser/extension_registrar.h" #include "extensions/browser/extension_registry.h" #include "extensions/browser/extension_web_contents_observer.h" #include "extensions/browser/extensions_browser_client.h" @@ -244,7 +245,8 @@ if (IsBackgroundPage()) { DCHECK(IsRendererLive()); // Connect orphaned dev-tools instances. - delegate_->OnMainFrameCreatedForBackgroundPage(this); + ExtensionRegistrar::Get(browser_context()) + ->DidCreateMainFrameForBackgroundPage(this); } }
diff --git a/extensions/browser/extension_host_delegate.h b/extensions/browser/extension_host_delegate.h index 3a1dd20..33f5581 100644 --- a/extensions/browser/extension_host_delegate.h +++ b/extensions/browser/extension_host_delegate.h
@@ -37,9 +37,6 @@ // implementation may wish to add preference observers to `web_contents`. virtual void OnExtensionHostCreated(content::WebContents* web_contents) = 0; - // Called after `host` creates the renderer main frame for an extension. - virtual void OnMainFrameCreatedForBackgroundPage(ExtensionHost* host) = 0; - // Creates a new tab or popup window with `web_contents`. The embedder may // choose to do nothing if tabs and popups are not supported. virtual void CreateTab(std::unique_ptr<content::WebContents> web_contents,
diff --git a/extensions/common/extension_features.cc b/extensions/common/extension_features.cc index c703c0a..aec52be 100644 --- a/extensions/common/extension_features.cc +++ b/extensions/common/extension_features.cc
@@ -222,4 +222,8 @@ "ExtensionBrowserNamespaceAlternative", base::FEATURE_DISABLED_BY_DEFAULT); +BASE_FEATURE(kRuntimeOnMessagePromiseReturnSupport, + "RuntimeOnMessagePromiseReturnSupport", + base::FEATURE_DISABLED_BY_DEFAULT); + } // namespace extensions_features
diff --git a/extensions/common/extension_features.h b/extensions/common/extension_features.h index 0380548e..410bfae6 100644 --- a/extensions/common/extension_features.h +++ b/extensions/common/extension_features.h
@@ -263,6 +263,11 @@ // `loadTimes` , `csi`, etc. or deprecated APIs (e.g. `app`). BASE_DECLARE_FEATURE(kExtensionBrowserNamespaceAlternative); +// Supports chrome.runtime.onMessage() returning a JS Promise to reply to sender +// response callbacks. Promise resolve or rejection value will be sent to the +// sender response callbacks. +BASE_DECLARE_FEATURE(kRuntimeOnMessagePromiseReturnSupport); + } // namespace extensions_features #endif // EXTENSIONS_COMMON_EXTENSION_FEATURES_H_
diff --git a/extensions/renderer/api/messaging/gin_port.cc b/extensions/renderer/api/messaging/gin_port.cc index c24a7b0..aef640f8 100644 --- a/extensions/renderer/api/messaging/gin_port.cc +++ b/extensions/renderer/api/messaging/gin_port.cc
@@ -249,8 +249,8 @@ EventEmitter* emitter = nullptr; gin::Converter<EventEmitter*>::FromV8(isolate, on_message, &emitter); CHECK(emitter); - - emitter->Fire(context, args, nullptr, JSRunner::ResultCallback()); + emitter->Fire(context, args, /*filter=*/nullptr, + /*callback=*/v8::Local<v8::Function>()); } void GinPort::OnContextInvalidated() {
diff --git a/extensions/renderer/api/messaging/native_renderer_messaging_service.cc b/extensions/renderer/api/messaging/native_renderer_messaging_service.cc index c94c007..f518fb1 100644 --- a/extensions/renderer/api/messaging/native_renderer_messaging_service.cc +++ b/extensions/renderer/api/messaging/native_renderer_messaging_service.cc
@@ -662,7 +662,8 @@ port->SetSender(v8_context, sender); v8::LocalVector<v8::Value> args(isolate, {port.ToV8()}); bindings_system_->api_system()->event_handler()->FireEventInContext( - event_name, v8_context, &args, nullptr, JSRunner::ResultCallback()); + event_name, v8_context, &args, /*filter=*/nullptr, + /*callback=*/v8::Local<v8::Function>()); } // Note: Arbitrary JS may have run; the context may now be deleted.
diff --git a/extensions/renderer/api/messaging/one_time_message_handler.cc b/extensions/renderer/api/messaging/one_time_message_handler.cc index 4ef7e14e..bb26bafd 100644 --- a/extensions/renderer/api/messaging/one_time_message_handler.cc +++ b/extensions/renderer/api/messaging/one_time_message_handler.cc
@@ -15,6 +15,7 @@ #include "content/public/renderer/render_frame.h" #include "extensions/common/api/messaging/message.h" #include "extensions/common/api/messaging/port_id.h" +#include "extensions/common/extension_features.h" #include "extensions/common/mojom/event_dispatcher.mojom.h" #include "extensions/common/mojom/message_port.mojom-shared.h" #include "extensions/renderer/api/messaging/message_target.h" @@ -61,6 +62,7 @@ struct OneTimeReceiver { std::string event_name; v8::Global<v8::Object> sender; + v8::Global<v8::Function> response_function; }; using OneTimeMessageCallback = @@ -103,24 +105,70 @@ std::move(*callback).Run(&arguments); } -// Called with the results of dispatching an onMessage event to listeners. -// Returns true if any of the listeners responded with `true`, indicating they -// will respond to the call asynchronously. -bool WillListenerReplyAsync(std::optional<base::Value> result) { - // `result` can be `nullopt` if the context was destroyed before the - // listeners were ran (or while they were running). - if (!result) +// Returns true if any of the listeners responded with `true` or a Promise, +// indicating they will respond to the call asynchronously. If a Promise is +// returned, `promise_settled_function` is attached to its resolution. +bool CheckAndHandleAsyncListenerReply( + v8::Isolate* isolate, + v8::Local<v8::Context> context, + v8::Local<v8::Value> result, + v8::Local<v8::Function> promise_settled_function) { + // `result` can be undefined if the context was destroyed before the + // listeners were run (or while they were running). + if (result->IsUndefined()) { return false; + } - if (const base::Value::Dict* dict = result->GetIfDict()) { - // We expect results in the form of an object with an array of results as - // a `results` property. - if (const base::Value::List* list = dict->FindList("results")) { - // Check if any of the results is `true`. - for (const base::Value& value : *list) { - if (value.is_bool() && value.GetBool()) - return true; - } + // We expect results as a value with an array of results as a `results` + // property, however, since this comes from untrusted JS let's confirm this + // first. + if (!result->IsObject()) { + return false; + } + v8::Local<v8::Object> result_object = result.As<v8::Object>(); + v8::Local<v8::Value> results_value; + if (!result_object->Get(context, gin::StringToSymbol(isolate, "results")) + .ToLocal(&results_value)) { + return false; + } + if (!results_value->IsArray()) { + return false; + } + + v8::Local<v8::Array> results_array = results_value.As<v8::Array>(); + uint32_t results_count = results_array->Length(); + + bool promise_return_support_enabled = base::FeatureList::IsEnabled( + extensions_features::kRuntimeOnMessagePromiseReturnSupport); + for (uint32_t i = 0; i < results_count; ++i) { + v8::MaybeLocal<v8::Value> maybe_result = results_array->Get(context, i); + v8::Local<v8::Value> listener_return; + // Assume the result could throw due to changes at runtime by the + // extension's JS code. + if (!maybe_result.ToLocal(&listener_return)) { + continue; + } + + // Check if any of the results is indicating it will reply async by + // returning `true`. + if (listener_return->IsBoolean()) { + return listener_return.As<v8::Boolean>()->Value(); + } + + // Check if any of the returns are a promise -- indicating the listener + // will reply async. If they do, we call the equivalent of + // sendResponse() with the promise's settled value. + if (listener_return->IsPromise() && promise_return_support_enabled) { + // TODO(crbug.com/40753031): Support promise rejects as per the polyfill: + // https://github.com/mozilla/webextension-polyfill/tree/master. If + // rejected value is object with a ".message" property then return an + // error with that message, otherwise a generic message ("An unexpected + // error occurred"). + std::ignore = listener_return.As<v8::Promise>()->Then( + context, promise_settled_function); + // TODO(crbug.com/40753031): Consider setting lastError in JS + // when promise is rejected. + return true; } } @@ -323,8 +371,8 @@ // callback through which the port can respond. The port stays open until we // receive a response. // TODO(devlin): With chrome.runtime.sendMessage, we actually require that a - // listener return `true` if they intend to respond asynchronously; otherwise - // we close the port. + // listener indicate if they intend to respond asynchronously; otherwise we + // close the port. auto callback = std::make_unique<OneTimeMessageCallback>( base::BindOnce(&OneTimeMessageHandler::OnOneTimeMessageResponse, @@ -344,6 +392,8 @@ reinterpret_cast<CallbackID>(callback.get())), base::OnceClosure()); + port.response_function = v8::Global<v8::Function>(isolate, response_function); + v8::HandleScope handle_scope(isolate); // The current port is a receiver. The parsing should be fail-safe if this is @@ -360,18 +410,30 @@ v8::LocalVector<v8::Value> args(isolate, {v8_message, v8_sender, response_function}); - JSRunner::ResultCallback dispatch_callback; - // For runtime.onMessage, we require that the listener return `true` if they + v8::Local<v8::Function> dispatch_callback_function; + // For runtime.onMessage, we require that the listener indicate if they // intend to respond asynchronously. Check the results of the listeners. if (port.event_name == messaging_util::kOnMessageEvent) { - dispatch_callback = + auto dispatch_callback = std::make_unique<OneTimeMessageCallback>( base::BindOnce(&OneTimeMessageHandler::OnEventFired, - weak_factory_.GetWeakPtr(), target_port_id); + weak_factory_.GetWeakPtr(), target_port_id)); + v8::Local<v8::External> dispatch_external = + v8::External::New(isolate, dispatch_callback.get()); + + // TODO(crbug.com/40753031): Pull out the functionality of + // OneTimeMessageResponseHelper wrapping the callback into a helper class + // so it's clearer to understand this mechanism. + if (!v8::Function::New(context, &OneTimeMessageResponseHelper, + dispatch_external) + .ToLocal(&dispatch_callback_function)) { + NOTREACHED(); + } + data->pending_callbacks.push_back(std::move(dispatch_callback)); } data->pending_callbacks.push_back(std::move(callback)); bindings_system_->api_system()->event_handler()->FireEventInContext( - port.event_name, context, &args, nullptr, std::move(dispatch_callback)); + port.event_name, context, &args, nullptr, dispatch_callback_function); } else { console::AddMessage(script_context, blink::mojom::ConsoleMessageLevel::kError, error); @@ -522,8 +584,8 @@ // The listener may try replying after the context or the channel has been // closed. Fail gracefully. // TODO(devlin): At least in the case of the channel being closed (e.g. - // because the listener did not return `true`), it might be good to surface an - // error. + // because the listener did not indicate it would reply asynchronously), it + // might be good to surface an error. OneTimeMessageContextData* data = GetPerContextData<OneTimeMessageContextData>(context, kDontCreateIfMissing); @@ -604,8 +666,17 @@ } void OneTimeMessageHandler::OnEventFired(const PortId& port_id, - v8::Local<v8::Context> context, - std::optional<base::Value> result) { + gin::Arguments* arguments) { + v8::Isolate* isolate = arguments->isolate(); + v8::Local<v8::Context> context = isolate->GetCurrentContext(); + + v8::Local<v8::Value> result; + if (arguments->Length() > 0) { + CHECK(arguments->GetNext(&result)); + } else { + result = v8::Undefined(isolate); + } + // The context could be tearing down by the time the event is fully // dispatched. OneTimeMessageContextData* data = @@ -618,10 +689,15 @@ if (iter == data->receivers.end()) return; + OneTimeReceiver& port = iter->second; + NativeRendererMessagingService* messaging_service = bindings_system_->messaging_service(); - if (WillListenerReplyAsync(std::move(result))) { + if (CheckAndHandleAsyncListenerReply(isolate, context, result, + port.response_function.Get(isolate))) { + // Ensure the global function doesn't outlive port closing. + port.response_function.SetWeak(); // Inform the browser that one of the listeners said they would be replying // later and leave the channel open. ScriptContext* script_context = GetScriptContextFromV8Context(context); @@ -634,9 +710,9 @@ data->receivers.erase(iter); - // The listener did not reply and did not return `true` from any of its - // listeners. Close the message port. Don't close the channel because another - // listener (in a separate context) may reply. + // The listener did not reply and did not indicate it would reply later from + // any of its listeners. Close the message port. Don't close the channel + // because another listener (in a separate context) may reply. ScriptContext* script_context = GetScriptContextFromV8Context(context); messaging_service->CloseMessagePort(script_context, port_id, /*close_channel=*/false);
diff --git a/extensions/renderer/api/messaging/one_time_message_handler.h b/extensions/renderer/api/messaging/one_time_message_handler.h index 7cf5417..05b6e233 100644 --- a/extensions/renderer/api/messaging/one_time_message_handler.h +++ b/extensions/renderer/api/messaging/one_time_message_handler.h
@@ -17,10 +17,6 @@ #include "extensions/renderer/bindings/api_binding_types.h" #include "v8/include/v8-forward.h" -namespace base { -class Value; -} - namespace gin { class Arguments; } @@ -167,9 +163,7 @@ // Called when the messaging event has been dispatched with the result of the // listeners. - void OnEventFired(const PortId& port_id, - v8::Local<v8::Context> context, - std::optional<base::Value> result); + void OnEventFired(const PortId& port_id, gin::Arguments* arguments); // The associated bindings system. Outlives this object. const raw_ptr<NativeExtensionBindingsSystem> bindings_system_;
diff --git a/extensions/renderer/bindings/api_event_handler.cc b/extensions/renderer/bindings/api_event_handler.cc index 7ef1fd5..5770003 100644 --- a/extensions/renderer/bindings/api_event_handler.cc +++ b/extensions/renderer/bindings/api_event_handler.cc
@@ -269,14 +269,14 @@ } FireEventInContext(event_name, context, &v8_args, std::move(filter), - JSRunner::ResultCallback()); + /*callback=*/v8::Local<v8::Function>()); } void APIEventHandler::FireEventInContext(const std::string& event_name, v8::Local<v8::Context> context, v8::LocalVector<v8::Value>* arguments, mojom::EventFilteringInfoPtr filter, - JSRunner::ResultCallback callback) { + v8::Local<v8::Function> callback) { APIEventPerContextData* data = APIEventPerContextData::GetFrom(context, kDontCreateIfMissing); if (!data) { @@ -305,9 +305,10 @@ api_response_validator_->ValidateEvent(context, event_name, *arguments); } - emitter->Fire(context, arguments, std::move(filter), std::move(callback)); + emitter->Fire(context, arguments, std::move(filter), callback); } else { - DCHECK(!callback) << "Can't use an event callback with argument massagers."; + DCHECK(callback.IsEmpty()) + << "Can't use an event callback with argument massagers."; v8::Isolate* isolate = context->GetIsolate(); v8::HandleScope handle_scope(isolate);
diff --git a/extensions/renderer/bindings/api_event_handler.h b/extensions/renderer/bindings/api_event_handler.h index 63f1118..5ee26e4 100644 --- a/extensions/renderer/bindings/api_event_handler.h +++ b/extensions/renderer/bindings/api_event_handler.h
@@ -78,7 +78,7 @@ v8::Local<v8::Context> context, v8::LocalVector<v8::Value>* arguments, mojom::EventFilteringInfoPtr filter, - JSRunner::ResultCallback callback); + v8::Local<v8::Function> callback); // Registers a `function` to serve as an "argument massager" for the given // `event_name`, mutating the original arguments.
diff --git a/extensions/renderer/bindings/event_emitter.cc b/extensions/renderer/bindings/event_emitter.cc index 880c2d0..ab25fd02 100644 --- a/extensions/renderer/bindings/event_emitter.cc +++ b/extensions/renderer/bindings/event_emitter.cc
@@ -22,6 +22,7 @@ constexpr const char kEmitterKey[] = "emitter"; constexpr const char kArgumentsKey[] = "arguments"; constexpr const char kFilterKey[] = "filter"; +constexpr const char kCallbackFunctionKey[] = "callback"; constexpr const char kEventEmitterTypeName[] = "Event"; } // namespace @@ -58,8 +59,8 @@ void EventEmitter::Fire(v8::Local<v8::Context> context, v8::LocalVector<v8::Value>* args, mojom::EventFilteringInfoPtr filter, - JSRunner::ResultCallback callback) { - DispatchAsync(context, args, std::move(filter), std::move(callback)); + v8::Local<v8::Function> callback) { + DispatchAsync(context, args, std::move(filter), callback); } v8::Local<v8::Value> EventEmitter::FireSync( @@ -271,7 +272,7 @@ void EventEmitter::DispatchAsync(v8::Local<v8::Context> context, v8::LocalVector<v8::Value>* args, mojom::EventFilteringInfoPtr filter, - JSRunner::ResultCallback callback) { + v8::Local<v8::Function> callback) { v8::Isolate* isolate = context->GetIsolate(); v8::HandleScope handle_scope(isolate); v8::Context::Scope context_scope(context); @@ -283,11 +284,19 @@ CHECK(args_array->CreateDataProperty(context, i, args->at(i)).ToChecked()); } + v8::Local<v8::Value> callback_value; + if (callback.IsEmpty()) { + callback_value = v8::Undefined(isolate); + } else { + callback_value = callback; + } + v8::Local<v8::Object> data = gin::DataObjectBuilder(isolate) .Set(kEmitterKey, GetWrapper(isolate).ToLocalChecked()) .Set(kArgumentsKey, args_array.As<v8::Value>()) .Set(kFilterKey, gin::ConvertToV8(isolate, filter_id)) + .Set(kCallbackFunctionKey, callback_value) .Build(); v8::Local<v8::Function> function; // TODO(devlin): Function construction can fail in some weird cases (looking @@ -297,8 +306,11 @@ CHECK(v8::Function::New(context, &DispatchAsyncHelper, data) .ToLocal(&function)); - JSRunner::Get(context)->RunJSFunction(function, context, {}, - std::move(callback)); + JSRunner::Get(context)->RunJSFunction( + function, context, {}, + // We handle the callback via `callback_value` instead so we can pass + // it v8 objects. + JSRunner::ResultCallback()); } // static @@ -339,8 +351,37 @@ // We know that dispatching synchronously should be safe because this function // was triggered by JS execution. - info.GetReturnValue().Set( - emitter->DispatchSync(context, &arguments, std::move(filter))); + v8::Local<v8::Value> dispatch_sync_result = + emitter->DispatchSync(context, &arguments, std::move(filter)); + + // Script context could be destroyed as a result of the above dispatch. + if (!binding::IsContextValid(context)) { + return; + } + + v8::Local<v8::Value> callback_value; + bool callback_set = + data->Get(context, gin::StringToSymbol(isolate, kCallbackFunctionKey)) + .ToLocal(&callback_value); + + // No callback provided. + if (!callback_set || callback_value->IsUndefined()) { + return; + } + + v8::Local<v8::Function> callback_function; + if (callback_value->IsFunction()) { + callback_function = callback_value.As<v8::Function>(); + } + + if (callback_function.IsEmpty()) { + return; + } + + v8::LocalVector<v8::Value> callback_argument(isolate); + callback_argument.push_back(dispatch_sync_result); + JSRunner::Get(context)->RunJSFunctionSync(callback_function, context, + callback_argument); } } // namespace extensions
diff --git a/extensions/renderer/bindings/event_emitter.h b/extensions/renderer/bindings/event_emitter.h index f257335..baa1d41 100644 --- a/extensions/renderer/bindings/event_emitter.h +++ b/extensions/renderer/bindings/event_emitter.h
@@ -48,7 +48,7 @@ void Fire(v8::Local<v8::Context> context, v8::LocalVector<v8::Value>* args, mojom::EventFilteringInfoPtr filter, - JSRunner::ResultCallback callback); + v8::Local<v8::Function> callback); // Fires the event to any listeners synchronously, and returns the result. // This should only be used if the caller is certain that JS is already @@ -95,7 +95,7 @@ void DispatchAsync(v8::Local<v8::Context> context, v8::LocalVector<v8::Value>* args, mojom::EventFilteringInfoPtr filter, - JSRunner::ResultCallback callback); + v8::Local<v8::Function> callback); static void DispatchAsyncHelper( const v8::FunctionCallbackInfo<v8::Value>& info);
diff --git a/extensions/renderer/bindings/event_emitter_unittest.cc b/extensions/renderer/bindings/event_emitter_unittest.cc index ba0cc5e..22e4e65e 100644 --- a/extensions/renderer/bindings/event_emitter_unittest.cc +++ b/extensions/renderer/bindings/event_emitter_unittest.cc
@@ -189,7 +189,8 @@ EXPECT_EQ(kNumListeners, event->GetNumListeners()); v8::LocalVector<v8::Value> args(isolate()); - event->Fire(context, &args, nullptr, JSRunner::ResultCallback()); + event->Fire(context, &args, /*filter=*/nullptr, + /*callback=*/v8::Local<v8::Function>()); EXPECT_TRUE(closure_data.did_invalidate_context); }
diff --git a/extensions/shell/browser/shell_extension_host_delegate.cc b/extensions/shell/browser/shell_extension_host_delegate.cc index b09e698d..a153627 100644 --- a/extensions/shell/browser/shell_extension_host_delegate.cc +++ b/extensions/shell/browser/shell_extension_host_delegate.cc
@@ -20,9 +20,6 @@ ShellExtensionWebContentsObserver::CreateForWebContents(web_contents); } -void ShellExtensionHostDelegate::OnMainFrameCreatedForBackgroundPage( - ExtensionHost* host) {} - void ShellExtensionHostDelegate::CreateTab( std::unique_ptr<content::WebContents> web_contents, const ExtensionId& extension_id,
diff --git a/extensions/shell/browser/shell_extension_host_delegate.h b/extensions/shell/browser/shell_extension_host_delegate.h index 0830c0a..ab083d4 100644 --- a/extensions/shell/browser/shell_extension_host_delegate.h +++ b/extensions/shell/browser/shell_extension_host_delegate.h
@@ -23,7 +23,6 @@ // ExtensionHostDelegate implementation. void OnExtensionHostCreated(content::WebContents* web_contents) override; - void OnMainFrameCreatedForBackgroundPage(ExtensionHost* host) override; void CreateTab(std::unique_ptr<content::WebContents> web_contents, const ExtensionId& extension_id, WindowOpenDisposition disposition,
diff --git a/extensions/test/data/api_test/messaging/on_message_promise/background.js b/extensions/test/data/api_test/messaging/on_message_promise/background.js new file mode 100644 index 0000000..9c486ae --- /dev/null +++ b/extensions/test/data/api_test/messaging/on_message_promise/background.js
@@ -0,0 +1,46 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +async function onMessageListenerReturnsPromiseAsAsyncFunction() { + return 'async function promise return'; +} + +function doSomeAsyncThing() { + return new Promise( + resolve => setTimeout(resolve, 1, 'async function promise return')); +} + +async function OnMessageListenerCallsSendResponseAsyncAfterPromise( + unused_message, unused_sender, sendResponse) { + doSomeAsyncThing().then((result) => { + sendResponse(result); + }); + return 'outer promise return'; +} + +function onMessageListener(message, sender, sendResponse) { + switch (message) { + case 'return promise resolve value': + return new Promise((resolve) => { + resolve('promise resolved'); + }); + case 'return promise as an async function': + return onMessageListenerReturnsPromiseAsAsyncFunction( + message, sender, sendResponse); + case 'call sendResponse asynchronously after returned promise resolves': + return OnMessageListenerCallsSendResponseAsyncAfterPromise( + message, sender, sendResponse); + case 'call sendResponse synchronously': + sendResponse('synchronous response return'); + return; + case 'return promise after synchronous sendResponse() is called': + sendResponse('synchronous response return'); + return new Promise(resolve => resolve('promise resolved')); + case 'synchronously throw an error': + throw new Error('synchronous error thrown'); + default: + chrome.test.fail('Unexpected test message: ' + message); + } +} +chrome.runtime.onMessage.addListener(onMessageListener);
diff --git a/extensions/test/data/api_test/messaging/on_message_promise/content_script.js b/extensions/test/data/api_test/messaging/on_message_promise/content_script.js new file mode 100644 index 0000000..0caf57ec --- /dev/null +++ b/extensions/test/data/api_test/messaging/on_message_promise/content_script.js
@@ -0,0 +1,65 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +chrome.test.runTests([ + // Tests that a runtime.onMessage() listener can return a promise that will + // keep the message port alive until the promise has a chance to resolve. + async function onMessagePromiseResolve() { + const response = + await chrome.runtime.sendMessage('return promise resolve value'); + chrome.test.assertEq('promise resolved', response); + chrome.test.succeed(); + }, + + // Tests that a runtime.onMessage() listener can return an async function + // (e.g. a promise) that will keep the message port alive until the promise + // has a chance to settle. + async function onMessageAsyncFunction() { + const response = + await chrome.runtime.sendMessage('return promise as an async function'); + chrome.test.assertEq('async function promise return', response); + chrome.test.succeed(); + }, + + // Tests that a runtime.onMessage() listener that returns a promise that + // contains an asynchronous call to sendResponse() will return the result of + // the promise, not the value passed to sendResponse() to the the sender's + // response callback. + async function onMessagePromiseAsyncReply() { + const response = await chrome.runtime.sendMessage( + 'call sendResponse asynchronously after returned promise resolves'); + chrome.test.assertEq('outer promise return', response); + chrome.test.succeed(); + }, + + // Tests that a runtime.onMessage() listener that synchronously calls + // sendResponse() causes the the sender's response callback to be provided the + // synchronous response call's value. + async function onMessageSyncReply() { + const response = + await chrome.runtime.sendMessage('call sendResponse synchronously'); + chrome.test.assertEq('synchronous response return', response); + chrome.test.succeed(); + }, + + // Tests that a runtime.onMessage() listener that synchronously responds, but + // then returns a promise will provide the synchronous response to the caller, + // and the promise settled value is ignored. + async function onMessageSyncReplyAndReturnsPromise() { + const response = await chrome.runtime.sendMessage( + 'return promise after synchronous sendResponse() is called'); + chrome.test.assertEq('synchronous response return', response); + chrome.test.succeed(); + }, + + // Tests that a runtime.onMessage() listener that throws an error + // synchronously returns an `undefined` response. + async function onMessageSyncThrowsError() { + const response = + await chrome.runtime.sendMessage('synchronously throw an error'); + chrome.test.assertEq(undefined, response); + chrome.test.succeed(); + }, + +]);
diff --git a/extensions/test/data/api_test/messaging/on_message_promise/manifest.json b/extensions/test/data/api_test/messaging/on_message_promise/manifest.json new file mode 100644 index 0000000..2e65df5 --- /dev/null +++ b/extensions/test/data/api_test/messaging/on_message_promise/manifest.json
@@ -0,0 +1,13 @@ +{ + "version": "1.0", + "manifest_version": 3, + "name": "Test extension for onMessage() handler promise return", + "background": { + "service_worker": "background.js" + }, + "content_scripts": [{ + "matches": ["<all_urls>"], + "js": ["content_script.js"], + "run_at": "document_start" + }] +}
diff --git a/gpu/command_buffer/service/shared_image/d3d_image_backing_factory.cc b/gpu/command_buffer/service/shared_image/d3d_image_backing_factory.cc index 643ac1fa..88bd9181 100644 --- a/gpu/command_buffer/service/shared_image/d3d_image_backing_factory.cc +++ b/gpu/command_buffer/service/shared_image/d3d_image_backing_factory.cc
@@ -197,6 +197,15 @@ bool has_required_format_support = (format_support & kRequiredUsage) == kRequiredUsage; d3d11_supports_nv12_ = SUCCEEDED(hr) && has_required_format_support; + + D3D_FEATURE_LEVEL feature_level = d3d11_device_->GetFeatureLevel(); + if (feature_level < D3D_FEATURE_LEVEL_9_3) { + max_nv12_dim_supported_ = 2048; + } else if (feature_level < D3D_FEATURE_LEVEL_11_0) { + max_nv12_dim_supported_ = 4096; + } else { + max_nv12_dim_supported_ = 16384; + } } D3DImageBackingFactory::~D3DImageBackingFactory() = default; @@ -825,35 +834,30 @@ D3D11_FORMAT_SUPPORT_RENDER_TARGET; bool has_required_format_support = (format_support & kRequiredUsage) == kRequiredUsage; - if (!SUCCEEDED(hr) || !has_required_format_support) { - return false; - } - - D3D11_TEXTURE2D_DESC desc; - desc.Width = size.width(); - desc.Height = size.height(); - desc.MipLevels = 1; - desc.ArraySize = 1; - desc.Format = dxgi_format; - desc.SampleDesc.Count = 1; - desc.SampleDesc.Quality = 0; - desc.Usage = D3D11_USAGE_DEFAULT; - desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET; - desc.CPUAccessFlags = 0; - desc.MiscFlags = 0; - - Microsoft::WRL::ComPtr<ID3D11Texture2D> d3d11_texture; - hr = d3d11_device_->CreateTexture2D(&desc, nullptr, &d3d11_texture); if (!SUCCEEDED(hr)) { - LOG(ERROR) << "CanCreateNV12Texture failed with size " << size.ToString() - << " error " << std::hex << hr; - - min_nv12_size_unsupported_ = - std::min(size.GetArea(), min_nv12_size_unsupported_); + LOG(ERROR) << "D3D device does not support NV12 texture creation with " + "format usage=" + << format_support; + return false; + } + if (!has_required_format_support) { + LOG(ERROR) << "D3D device does not support NV12 texture with format usage=" + << format_support; return false; } - max_nv12_size_supported_ = std::max(size.GetArea(), max_nv12_size_supported_); + // We know current size width and height must be within + // `max_nv12_dim_supported_` as nv12 creation is supported for + // `max_nv12_dim_supported_`. + if (size.width() > max_nv12_dim_supported_ || + size.height() > max_nv12_dim_supported_) { + LOG(ERROR) + << "Provided size=" << size.ToString() + << "is not supported by d3d device, with max supported dimensions=" + << max_nv12_dim_supported_; + return false; + } + return true; } @@ -902,16 +906,6 @@ if (!d3d11_supports_nv12_) { return false; } - // We know current size is within `max_nv12_size_supported_` and nv12 - // creation is supported for `max_nv12_size_supported_`. - if (size.GetArea() <= max_nv12_size_supported_) { - return true; - } - // We know current size is larger than `min_nv12_size_unsupported_` and nv12 - // creation is unsupported for `min_nv12_size_unsupported_`. - if (size.GetArea() >= min_nv12_size_unsupported_) { - return false; - } if (!CanCreateNV12Texture(size)) { return false; }
diff --git a/gpu/command_buffer/service/shared_image/d3d_image_backing_factory.h b/gpu/command_buffer/service/shared_image/d3d_image_backing_factory.h index f183d96..9ed6fb8 100644 --- a/gpu/command_buffer/service/shared_image/d3d_image_backing_factory.h +++ b/gpu/command_buffer/service/shared_image/d3d_image_backing_factory.h
@@ -161,12 +161,8 @@ // using Graphite. Microsoft::WRL::ComPtr<ID3D11Device> angle_d3d11_device_; - // Stores the minimum size area unsupported by an nv12 texture. - // Default initialized to max size. - int min_nv12_size_unsupported_ = std::numeric_limits<int>::max(); - - // Stores the maximum size area supported by an nv12 texture. - int max_nv12_size_supported_ = 0; + // Stores the maximum size dimension supported by an nv12 texture. + int max_nv12_dim_supported_ = 0; // Stores whether NV12 format is supported by the D3D device. bool d3d11_supports_nv12_;
diff --git a/gpu/command_buffer/service/shared_image/shared_image_factory.cc b/gpu/command_buffer/service/shared_image/shared_image_factory.cc index 8e316b3..7092b9e 100644 --- a/gpu/command_buffer/service/shared_image/shared_image_factory.cc +++ b/gpu/command_buffer/service/shared_image/shared_image_factory.cc
@@ -342,7 +342,7 @@ auto* factory = GetFactoryByUsage(usage, format, size, /*pixel_data=*/{}, gfx::EMPTY_BUFFER); if (!factory) { - LogGetFactoryFailed(usage, format, gfx::EMPTY_BUFFER, debug_label); + LogGetFactoryFailed(usage, format, gfx::EMPTY_BUFFER, size, debug_label); return false; } @@ -408,7 +408,8 @@ auto* factory = GetFactoryByUsage(usage, format, size, /*pixel_data=*/{}, GetNativeBufferType()); if (!factory) { - LogGetFactoryFailed(usage, format, GetNativeBufferType(), debug_label); + LogGetFactoryFailed(usage, format, GetNativeBufferType(), size, + debug_label); return false; } @@ -454,7 +455,7 @@ } if (!factory) { - LogGetFactoryFailed(usage, format, gfx::SHARED_MEMORY_BUFFER, + LogGetFactoryFailed(usage, format, gfx::SHARED_MEMORY_BUFFER, size, debug_label); return false; } @@ -499,7 +500,7 @@ SharedImageBackingFactory* const factory = GetFactoryByUsage(usage, format, size, data, gfx::EMPTY_BUFFER); if (!factory) { - LogGetFactoryFailed(usage, format, gfx::EMPTY_BUFFER, debug_label); + LogGetFactoryFailed(usage, format, gfx::EMPTY_BUFFER, size, debug_label); return false; } @@ -547,7 +548,7 @@ } if (!factory) { - LogGetFactoryFailed(usage, format, gmb_type, debug_label); + LogGetFactoryFailed(usage, format, gmb_type, size, debug_label); return false; } @@ -887,11 +888,13 @@ void SharedImageFactory::LogGetFactoryFailed(gpu::SharedImageUsageSet usage, viz::SharedImageFormat format, gfx::GpuMemoryBufferType gmb_type, + const gfx::Size& size, const std::string& debug_label) { SCOPED_CRASH_KEY_STRING32("SIFactory", "DebugLabel", debug_label); SCOPED_CRASH_KEY_STRING64("SIFactory", "Format", format.ToString()); SCOPED_CRASH_KEY_NUMBER("SIFactory", "Usage", usage); SCOPED_CRASH_KEY_STRING64("SIFactory", "GMBType", GmbTypeToString(gmb_type)); + SCOPED_CRASH_KEY_STRING64("SIFactory", "Size", size.ToString()); SCOPED_CRASH_KEY_BOOL("SIFactory", "SharedBwThreads", IsSharedBetweenThreads(usage)); LOG(ERROR) << "Could not find SharedImageBackingFactory with params: usage: " @@ -899,6 +902,7 @@ << ", format: " << format.ToString() << ", share_between_threads: " << IsSharedBetweenThreads(usage) << ", gmb_type: " << GmbTypeToString(gmb_type) + << ", size: " << size.ToString() << ", debug_label: " << debug_label; // DumpWithoutCrashing to get crash reports for failure to find a shared image // backing factory.
diff --git a/gpu/command_buffer/service/shared_image/shared_image_factory.h b/gpu/command_buffer/service/shared_image/shared_image_factory.h index f3e8e17..a5b8b03 100644 --- a/gpu/command_buffer/service/shared_image/shared_image_factory.h +++ b/gpu/command_buffer/service/shared_image/shared_image_factory.h
@@ -171,6 +171,7 @@ void LogGetFactoryFailed(gpu::SharedImageUsageSet usage, viz::SharedImageFormat format, gfx::GpuMemoryBufferType gmb_type, + const gfx::Size& size, const std::string& debug_label); bool IsNativeBufferSupported(gfx::BufferFormat format, gfx::BufferUsage usage);
diff --git a/infra/config/generated/builders/ci/Linux ASan LSan Builder/targets/chromium.memory.json b/infra/config/generated/builders/ci/Linux ASan LSan Builder/targets/chromium.memory.json index 2009213..d8eb42f0 100644 --- a/infra/config/generated/builders/ci/Linux ASan LSan Builder/targets/chromium.memory.json +++ b/infra/config/generated/builders/ci/Linux ASan LSan Builder/targets/chromium.memory.json
@@ -227,7 +227,7 @@ "os": "Ubuntu-22.04" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 50 + "shards": 55 }, "test": "browser_tests", "test_id_prefix": "ninja://chrome/test:browser_tests/"
diff --git "a/infra/config/generated/builders/ci/Linux ASan LSan Tests \0501\051/targets/chromium.memory.json" "b/infra/config/generated/builders/ci/Linux ASan LSan Tests \0501\051/targets/chromium.memory.json" index 2009213..d8eb42f0 100644 --- "a/infra/config/generated/builders/ci/Linux ASan LSan Tests \0501\051/targets/chromium.memory.json" +++ "b/infra/config/generated/builders/ci/Linux ASan LSan Tests \0501\051/targets/chromium.memory.json"
@@ -227,7 +227,7 @@ "os": "Ubuntu-22.04" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 50 + "shards": 55 }, "test": "browser_tests", "test_id_prefix": "ninja://chrome/test:browser_tests/"
diff --git a/infra/config/generated/builders/ci/Linux MSan Builder/targets/chromium.memory.json b/infra/config/generated/builders/ci/Linux MSan Builder/targets/chromium.memory.json index 9c2820be..35263a9 100644 --- a/infra/config/generated/builders/ci/Linux MSan Builder/targets/chromium.memory.json +++ b/infra/config/generated/builders/ci/Linux MSan Builder/targets/chromium.memory.json
@@ -238,7 +238,7 @@ "os": "Ubuntu-22.04" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 35 + "shards": 40 }, "test": "browser_tests", "test_id_prefix": "ninja://chrome/test:browser_tests/"
diff --git a/infra/config/generated/builders/ci/Linux MSan Tests/targets/chromium.memory.json b/infra/config/generated/builders/ci/Linux MSan Tests/targets/chromium.memory.json index 9c2820be..35263a9 100644 --- a/infra/config/generated/builders/ci/Linux MSan Tests/targets/chromium.memory.json +++ b/infra/config/generated/builders/ci/Linux MSan Tests/targets/chromium.memory.json
@@ -238,7 +238,7 @@ "os": "Ubuntu-22.04" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 35 + "shards": 40 }, "test": "browser_tests", "test_id_prefix": "ninja://chrome/test:browser_tests/"
diff --git a/infra/config/generated/builders/try/linux_chromium_asan_rel_ng/targets/chromium.memory.json b/infra/config/generated/builders/try/linux_chromium_asan_rel_ng/targets/chromium.memory.json index 2009213..d8eb42f0 100644 --- a/infra/config/generated/builders/try/linux_chromium_asan_rel_ng/targets/chromium.memory.json +++ b/infra/config/generated/builders/try/linux_chromium_asan_rel_ng/targets/chromium.memory.json
@@ -227,7 +227,7 @@ "os": "Ubuntu-22.04" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 50 + "shards": 55 }, "test": "browser_tests", "test_id_prefix": "ninja://chrome/test:browser_tests/"
diff --git a/infra/config/generated/builders/try/linux_chromium_msan_rel_ng/targets/chromium.memory.json b/infra/config/generated/builders/try/linux_chromium_msan_rel_ng/targets/chromium.memory.json index 9c2820be..35263a9 100644 --- a/infra/config/generated/builders/try/linux_chromium_msan_rel_ng/targets/chromium.memory.json +++ b/infra/config/generated/builders/try/linux_chromium_msan_rel_ng/targets/chromium.memory.json
@@ -238,7 +238,7 @@ "os": "Ubuntu-22.04" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 35 + "shards": 40 }, "test": "browser_tests", "test_id_prefix": "ninja://chrome/test:browser_tests/"
diff --git a/infra/config/subprojects/chromium/ci/chromium.memory.star b/infra/config/subprojects/chromium/ci/chromium.memory.star index b06adf7..ec56c0e 100644 --- a/infra/config/subprojects/chromium/ci/chromium.memory.star +++ b/infra/config/subprojects/chromium/ci/chromium.memory.star
@@ -154,7 +154,7 @@ # These are very slow on the ASAN trybot for some reason. # crbug.com/1257927 swarming = targets.swarming( - shards = 50, + shards = 55, ), ), "components_unittests": targets.mixin( @@ -691,7 +691,7 @@ per_test_modifications = { "browser_tests": targets.mixin( swarming = targets.swarming( - shards = 35, + shards = 40, ), ), "content_browsertests": targets.mixin(
diff --git a/internal b/internal index 7964be3..ce8575a 160000 --- a/internal +++ b/internal
@@ -1 +1 @@ -Subproject commit 7964be3418696ef3ab1788b335ba0f6caf5917c5 +Subproject commit ce8575ab9f020c7b9f39a089d8d6c10f0ab34b59
diff --git a/ios/chrome/app/BUILD.gn b/ios/chrome/app/BUILD.gn index 82f9b04..e34a822d 100644 --- a/ios/chrome/app/BUILD.gn +++ b/ios/chrome/app/BUILD.gn
@@ -463,6 +463,7 @@ "//ios/chrome/browser/crash_report/model:model_internal", "//ios/chrome/browser/crash_report/model/breadcrumbs", "//ios/chrome/browser/credential_provider/model:buildflags", + "//ios/chrome/browser/default_browser/model:features", "//ios/chrome/browser/default_browser/model:utils", "//ios/chrome/browser/device_orientation/ui_bundled", "//ios/chrome/browser/discover_feed/model:discover_feed_app_agent",
diff --git a/ios/chrome/app/main_controller.mm b/ios/chrome/app/main_controller.mm index 209022f..bd8efc0 100644 --- a/ios/chrome/app/main_controller.mm +++ b/ios/chrome/app/main_controller.mm
@@ -82,6 +82,7 @@ #import "ios/chrome/browser/crash_report/model/crash_loop_detection_util.h" #import "ios/chrome/browser/crash_report/model/crash_report_helper.h" #import "ios/chrome/browser/credential_provider/model/credential_provider_buildflags.h" +#import "ios/chrome/browser/default_browser/model/features.h" #import "ios/chrome/browser/default_browser/model/utils.h" #import "ios/chrome/browser/device_orientation/ui_bundled/scoped_force_portrait_orientation.h" #import "ios/chrome/browser/discover_feed/model/discover_feed_app_agent.h" @@ -1405,6 +1406,10 @@ [capabilities setObject:supportsShowDefaultBrowserPromo forKey:app_group::kChromeShowDefaultBrowserPromoCapability]; + [capabilities + setObject:@(IsShareDefaultBrowserStatusEnabled()) + forKey:app_group::kChromeSupportShareDefaultBrowserStatusCapability]; + if (base::FeatureList::IsEnabled(kYoutubeIncognito) && base::FeatureList::IsEnabled(kChromeStartupParametersAsync)) { [capabilities
diff --git a/ios/chrome/browser/autofill/ui_bundled/save_profile_egtest.mm b/ios/chrome/browser/autofill/ui_bundled/save_profile_egtest.mm index cd8db1dd..7e380a4 100644 --- a/ios/chrome/browser/autofill/ui_bundled/save_profile_egtest.mm +++ b/ios/chrome/browser/autofill/ui_bundled/save_profile_egtest.mm
@@ -63,8 +63,11 @@ // True if the submission should be default prevented. bool default_prevented = false; // True if there should be redirection done after submitting with - // `default_prevented` enabled in the parameters. + // a parameter that can stop the submit event from being handled by Autofill. bool redirect = false; + // True if the submission should be prevented from propagating to any other + // listener regardless of their positioning. + bool stop_immediate_propagation = false; }; // Matcher for the banner button. @@ -250,6 +253,17 @@ config.features_enabled.push_back(kAutofillAllowDefaultPreventedSubmission); } + if ([self isRunningTest:@selector(testSubmissionDetection_inCaptureMode)]) { + config.features_enabled.push_back( + kAutofillFormSubmissionEventsInCaptureMode); + } + + if ([self + isRunningTest:@selector(testSubmissionDetection_notInCaptureMode)]) { + config.features_disabled.push_back( + kAutofillFormSubmissionEventsInCaptureMode); + } + return config; } @@ -330,7 +344,10 @@ queryParameters.push_back("preventDefault"); } if (params.redirect) { - queryParameters.push_back("redirectWhenDefaultPrevented"); + queryParameters.push_back("redirectWhenSubmissionPrevented"); + } + if (params.stop_immediate_propagation) { + queryParameters.push_back("stopImmediatePropagation"); } return base::JoinString(queryParameters, "&"); }; @@ -930,4 +947,58 @@ forHistogram:@"Autofill.iOS.FormSubmission.Outcome"]); } +// Tests that submission is detected hence the infobar is displayed when the +// "form" event behind the submission has its propagation entirely stopped via +// stopImmediatePropagation() while the form submit event listener for Autofill +// is set in capture mode. +- (void)testSubmissionDetection_inCaptureMode { + // Sign-in so the profile can be saved into the account. + [SigninEarlGrey signinWithFakeIdentity:[FakeSystemIdentity fakeIdentity1]]; + + // Submit the form with `defaultPrevented` not considered. + FullAddressFormPageParams params{.redirect = true, + .stop_immediate_propagation = true}; + [self loadAndSubmitFullAddressFormWithParams:params]; + + // Wait on the infobar to be displayed after submission. + [InfobarEarlGreyUI waitUntilInfobarBannerVisibleOrTimeout:YES]; + + // Accept the banner to save the profile. + [[EarlGrey selectElementWithMatcher:BannerButtonMatcher()] + performAction:grey_tap()]; + + // Wait for the save profile dialog to appear. + [ChromeEarlGrey waitForMatcher:ModalButtonMatcher()]; + + // Save the profile. + [[EarlGrey selectElementWithMatcher:ModalButtonMatcher()] + performAction:grey_tap()]; + + // Ensure profile is saved. + GREYAssertEqual(1U, [AutofillAppInterface profilesCount], + @"Profile should have been saved."); + + [SigninEarlGrey signOut]; +} + +// Tests that submission isn't detected hence the infobar not displayed when the +// "form" event behind the submission has its propagation entirely stopped via +// stopImmediatePropagation() while the form submit event listener for Autofill +// isn't set in capture mode. +- (void)testSubmissionDetection_notInCaptureMode { + // Sign-in so the profile can be saved into the account. + [SigninEarlGrey signinWithFakeIdentity:[FakeSystemIdentity fakeIdentity1]]; + + // Submit the form with the submit event propagation stopped via + // stopImmediatePropagation(). + FullAddressFormPageParams params{.redirect = true, + .stop_immediate_propagation = true}; + [self loadAndSubmitFullAddressFormWithParams:params]; + + // Make sure the infobar isn't displayed. + [InfobarEarlGreyUI waitUntilInfobarBannerVisibleOrTimeout:NO]; + + [SigninEarlGrey signOut]; +} + @end
diff --git a/ios/chrome/browser/browser_view/ui_bundled/BUILD.gn b/ios/chrome/browser/browser_view/ui_bundled/BUILD.gn index b5ecea35..951b393 100644 --- a/ios/chrome/browser/browser_view/ui_bundled/BUILD.gn +++ b/ios/chrome/browser/browser_view/ui_bundled/BUILD.gn
@@ -410,7 +410,6 @@ "//ios/chrome/browser/sync/model:sync_error_browser_agent", "//ios/chrome/browser/tab_insertion/model", "//ios/chrome/browser/tab_switcher/ui_bundled/tab_strip/coordinator", - "//ios/chrome/browser/tabs/model", "//ios/chrome/browser/tabs/ui_bundled", "//ios/chrome/browser/tips_manager/model:factory", "//ios/chrome/browser/toolbar/ui_bundled:coordinator",
diff --git a/ios/chrome/browser/browser_view/ui_bundled/key_commands_provider_unittest.mm b/ios/chrome/browser/browser_view/ui_bundled/key_commands_provider_unittest.mm index 691172f..24f1d02 100644 --- a/ios/chrome/browser/browser_view/ui_bundled/key_commands_provider_unittest.mm +++ b/ios/chrome/browser/browser_view/ui_bundled/key_commands_provider_unittest.mm
@@ -24,6 +24,7 @@ #import "ios/chrome/browser/ntp/model/new_tab_page_tab_helper_delegate.h" #import "ios/chrome/browser/policy/model/policy_util.h" #import "ios/chrome/browser/sessions/model/fake_tab_restore_service.h" +#import "ios/chrome/browser/sessions/model/ios_chrome_tab_restore_browser_agent.h" #import "ios/chrome/browser/sessions/model/ios_chrome_tab_restore_service_factory.h" #import "ios/chrome/browser/shared/model/browser/test/test_browser.h" #import "ios/chrome/browser/shared/model/profile/test/test_profile_ios.h" @@ -41,7 +42,6 @@ #import "ios/chrome/browser/shared/public/commands/reading_list_add_command.h" #import "ios/chrome/browser/shared/public/commands/settings_commands.h" #import "ios/chrome/browser/shared/ui/util/url_with_title.h" -#import "ios/chrome/browser/tabs/model/closing_web_state_observer_browser_agent.h" #import "ios/chrome/browser/web/model/web_navigation_browser_agent.h" #import "ios/chrome/browser/web/model/web_navigation_util.h" #import "ios/chrome/grit/ios_strings.h" @@ -474,7 +474,7 @@ // Checks whether KeyCommandsProvider can perform the actions that are only // available when there are at least one closed tab. TEST_F(KeyCommandsProviderTest, CanPerform_ReopenLastClosedTab) { - ClosingWebStateObserverBrowserAgent::CreateForBrowser(browser_.get()); + IOSChromeTabRestoreBrowserAgent::CreateForBrowser(browser_.get()); // No tabs. ASSERT_EQ(web_state_list_->count(), 0); EXPECT_FALSE(CanPerform(@"keyCommand_reopenLastClosedTab"));
diff --git a/ios/chrome/browser/home_customization/model/home_background_image_service.h b/ios/chrome/browser/home_customization/model/home_background_image_service.h index c092dba..0c45f89f 100644 --- a/ios/chrome/browser/home_customization/model/home_background_image_service.h +++ b/ios/chrome/browser/home_customization/model/home_background_image_service.h
@@ -40,13 +40,16 @@ // vector of tuples of collection name and collection images. using CollectionsImagesCallback = base::OnceCallback<void(const CollectionImageMap&)>; - // Requests an asynchronous fetch of all collections and their images. This - // calls the `NtpBackgroundService` to fetch the collections images and then - // returns the data via the `CollectionsImagesCallback`. Requests that are - // made while an asynchronous fetch is in progress will be dropped until the - // currently active loader completes. + // Requests an asynchronous fetch of all ios ntp background collections and + // their images. This method calls `FetchCollectionsImagesInternal` under the + // hood. void FetchCollectionsImages(CollectionsImagesCallback callback); + // Requests an asynchronous fetch of the default ios ntp background + // collection and its images. This method calls + // `FetchCollectionsImagesInternal` under the hood. + void FetchDefaultCollectionImages(CollectionsImagesCallback callback); + private: // Callback for when collection images info is received. void OnCollectionImageInfoReceived( @@ -57,6 +60,15 @@ // Callback for when all collections and their images have been received. void OnAllCollectionImagesReceived(); + // Requests an asynchronous fetch of all collections and their images. This + // calls the `NtpBackgroundService` to fetch the collections images and then + // returns the data via the `CollectionsImagesCallback`. Requests that are + // made while an asynchronous fetch is in progress will be dropped until the + // currently active loader completes. Optionally, a `filtering_label` can be + // provided to guide the fetch. + void FetchCollectionsImagesInternal(CollectionsImagesCallback callback, + const std::string& filtering_label = ""); + CollectionsImagesCallback collections_images_callback_; CollectionImageMap collections_images_; raw_ptr<NtpBackgroundService> ntp_background_service_;
diff --git a/ios/chrome/browser/home_customization/model/home_background_image_service.mm b/ios/chrome/browser/home_customization/model/home_background_image_service.mm index cbcedf6..b6ce1f38 100644 --- a/ios/chrome/browser/home_customization/model/home_background_image_service.mm +++ b/ios/chrome/browser/home_customization/model/home_background_image_service.mm
@@ -9,6 +9,11 @@ #import "components/themes/ntp_background_service.h" #import "ios/chrome/browser/shared/model/application_context/application_context.h" +namespace { +// The filtering label to use for the default collection images. +const std::string kDefaultFilteringLabel = "default_chrome_ios_ntp"; +} // namespace + HomeBackgroundImageService::HomeBackgroundImageService( NtpBackgroundService* ntp_background_service) : ntp_background_service_(ntp_background_service) { @@ -20,8 +25,19 @@ ntp_background_service_ = nullptr; } +void HomeBackgroundImageService::FetchDefaultCollectionImages( + CollectionsImagesCallback callback) { + FetchCollectionsImagesInternal(std::move(callback), kDefaultFilteringLabel); +} + void HomeBackgroundImageService::FetchCollectionsImages( CollectionsImagesCallback callback) { + FetchCollectionsImagesInternal(std::move(callback)); +} + +void HomeBackgroundImageService::FetchCollectionsImagesInternal( + CollectionsImagesCallback callback, + const std::string& filtering_label) { // If a request is already in progress, drop the new request. if (collections_images_callback_) { return; @@ -29,20 +45,19 @@ collections_images_callback_ = std::move(callback); - // If the images are already loaded, return them, and make network request for - // the next fetch. - if (collections_images_.size() > 0 && collections_images_callback_) { - std::move(collections_images_callback_).Run(collections_images_); - } - - // If a request is currently in progress, to update the cache, drop the new - // request. + // If a request is currently in progress, drop the new request. if (all_images_received_barrier_) { return; } // Clear the collections images to start fresh. collections_images_.clear(); + + // If a filtering label is provided, use it to fetch the collection info. + if (!filtering_label.empty()) { + ntp_background_service_->FetchCollectionInfo(filtering_label); + return; + } ntp_background_service_->FetchCollectionInfo(); }
diff --git a/ios/chrome/browser/home_customization/model/home_background_image_service_unittest.mm b/ios/chrome/browser/home_customization/model/home_background_image_service_unittest.mm index 5955ad4..05293a6 100644 --- a/ios/chrome/browser/home_customization/model/home_background_image_service_unittest.mm +++ b/ios/chrome/browser/home_customization/model/home_background_image_service_unittest.mm
@@ -128,6 +128,61 @@ } TEST_F(HomeBackgroundImageServiceTest, + SuccessFetchDefaultCollectionsImagesResponse) { + // Add a collection + ntp::background::Collection collection; + collection.set_collection_id("shapes"); + collection.set_collection_name("Shapes Title"); + collection.add_preview()->set_image_url(kTestImageUrl); + ntp::background::GetCollectionsResponse response; + *response.add_collections() = collection; + std::string response_string; + response.SerializeToString(&response_string); + SetUpResponseWithData(service_.get()->GetCollectionsLoadURLForTesting(), + response_string); + + // Add an image to the collection + ntp::background::Image image; + image.set_asset_id(12345); + image.set_image_url(kTestImageUrl); + image.add_attribution()->set_text("attribution text"); + image.set_action_url(kTestActionUrl); + ntp::background::GetImagesInCollectionResponse image_response; + *image_response.add_images() = image; + std::string image_response_string; + image_response.SerializeToString(&image_response_string); + SetUpResponseWithData(service_.get()->GetImagesURLForTesting(), + image_response_string); + + HomeBackgroundImageService::CollectionImageMap collections_images; + base::MockCallback<HomeBackgroundImageService::CollectionsImagesCallback> + mock_callback; + EXPECT_CALL(mock_callback, Run(_)) + .WillOnce(DoAll(SaveArg<0>(&collections_images))); + + base::RunLoop run_loop; + model_.get()->FetchDefaultCollectionImages( + mock_callback.Get().Then(run_loop.QuitClosure())); + run_loop.Run(); + + EXPECT_EQ(collections_images.size(), 1u); + std::string collection_name = std::get<0>(collections_images[0]); + std::vector<CollectionImage> images = std::get<1>(collections_images[0]); + std::string expected_image_url = + std::string(kTestImageUrl) + GetImageOptions(); + std::string expected_thumbnail_image_url = + std::string(kTestImageUrl) + GetThumbnailImageOptions(); + EXPECT_EQ(collection_name, "Shapes Title"); + EXPECT_EQ(images.size(), 1u); + EXPECT_EQ(images[0].collection_id, "shapes"); + EXPECT_EQ(images[0].asset_id, 12345u); + EXPECT_EQ(images[0].image_url, GURL(expected_image_url)); + EXPECT_EQ(images[0].thumbnail_image_url, GURL(expected_thumbnail_image_url)); + EXPECT_EQ(images[0].attribution[0], "attribution text"); + EXPECT_EQ(images[0].attribution_action_url, GURL(kTestActionUrl)); +} + +TEST_F(HomeBackgroundImageServiceTest, SuccessMultipleFetchCollectionsImagesResponse) { // Add a collection ntp::background::Collection collection; @@ -193,6 +248,90 @@ EXPECT_EQ(second_image[0].collection_id, "nature"); } +TEST_F(HomeBackgroundImageServiceTest, + SuccessFetchDefaultCollectionsThenFetchImagesResponse) { + // Add a collection + ntp::background::Collection collection; + collection.set_collection_id("shapes"); + collection.set_collection_name("Shapes Title"); + collection.add_preview()->set_image_url(kTestImageUrl); + + ntp::background::GetCollectionsResponse response; + *response.add_collections() = collection; + std::string response_string; + response.SerializeToString(&response_string); + + SetUpResponseWithData(service_.get()->GetCollectionsLoadURLForTesting(), + response_string); + + // Add an image to the collection + ntp::background::Image image; + image.set_asset_id(12345); + image.set_image_url(kTestImageUrl); + image.add_attribution()->set_text("attribution text"); + image.set_action_url(kTestActionUrl); + ntp::background::GetImagesInCollectionResponse image_response; + *image_response.add_images() = image; + std::string image_response_string; + image_response.SerializeToString(&image_response_string); + + SetUpResponseWithData(service_.get()->GetImagesURLForTesting(), + image_response_string); + + HomeBackgroundImageService::CollectionImageMap collections_images; + base::MockCallback<HomeBackgroundImageService::CollectionsImagesCallback> + mock_callback; + EXPECT_CALL(mock_callback, Run(_)) + .WillOnce(DoAll(SaveArg<0>(&collections_images))); + + base::RunLoop run_loop; + model_.get()->FetchDefaultCollectionImages( + mock_callback.Get().Then(run_loop.QuitClosure())); + run_loop.Run(); + + EXPECT_EQ(collections_images.size(), 1u); + std::string collection_name = std::get<0>(collections_images[0]); + std::vector<CollectionImage> images = std::get<1>(collections_images[0]); + std::string expected_image_url = + std::string(kTestImageUrl) + GetImageOptions(); + std::string expected_thumbnail_image_url = + std::string(kTestImageUrl) + GetThumbnailImageOptions(); + EXPECT_EQ(collection_name, "Shapes Title"); + EXPECT_EQ(images.size(), 1u); + EXPECT_EQ(images[0].collection_id, "shapes"); + + ntp::background::Collection second_collection; + second_collection.set_collection_id("nature"); + second_collection.set_collection_name("Nature Title"); + second_collection.add_preview()->set_image_url(kTestImageUrl2); + + ntp::background::GetCollectionsResponse second_response; + *second_response.add_collections() = second_collection; + std::string second_response_string; + second_response.SerializeToString(&second_response_string); + + SetUpResponseWithData(service_.get()->GetCollectionsLoadURLForTesting(), + second_response_string); + + EXPECT_CALL(mock_callback, Run(_)) + .WillOnce(DoAll(SaveArg<0>(&collections_images))); + + base::RunLoop run_loop_2; + model_.get()->FetchCollectionsImages( + mock_callback.Get().Then(run_loop_2.QuitClosure())); + run_loop_2.Run(); + + EXPECT_EQ(collections_images.size(), 1u); + collection_name = std::get<0>(collections_images[0]); + images = std::get<1>(collections_images[0]); + expected_image_url = std::string(kTestImageUrl2) + GetImageOptions(); + expected_thumbnail_image_url = + std::string(kTestImageUrl2) + GetThumbnailImageOptions(); + EXPECT_EQ(collection_name, "Nature Title"); + EXPECT_EQ(images.size(), 1u); + EXPECT_EQ(images[0].collection_id, "nature"); +} + TEST_F(HomeBackgroundImageServiceTest, BadCollectionResponse) { SetUpResponseWithData(service_.get()->GetCollectionsLoadURLForTesting(), "bad serialized GetCollectionsResponse");
diff --git a/ios/chrome/browser/keyboard/ui_bundled/menu_builder_unittest.mm b/ios/chrome/browser/keyboard/ui_bundled/menu_builder_unittest.mm index 4c064de..a7c1b5e 100644 --- a/ios/chrome/browser/keyboard/ui_bundled/menu_builder_unittest.mm +++ b/ios/chrome/browser/keyboard/ui_bundled/menu_builder_unittest.mm
@@ -39,6 +39,74 @@ _wasMutated = YES; } +- (void)replaceMenuForIdentifier:(UIMenuIdentifier)replacedIdentifier + withElements:(NSArray<UIMenuElement*>*)replacementElements { + _wasMutated = YES; +} + +- (void)replaceActionForIdentifier:(UIActionIdentifier)replacedIdentifier + withElements: + (NSArray<UIMenuElement*>*)replacementElements { + _wasMutated = YES; +} + +- (void)replaceCommandForAction:(SEL)replacedAction + propertyList:(nullable id)replacedPropertyList + withElements:(NSArray<UIMenuElement*>*)replacementElements { + _wasMutated = YES; +} + +- (void)insertElements:(NSArray<UIMenuElement*>*)insertedElements + beforeMenuForIdentifier:(UIMenuIdentifier)siblingIdentifier { + _wasMutated = YES; +} + +- (void)insertElements:(NSArray<UIMenuElement*>*)insertedElements + afterMenuForIdentifier:(UIMenuIdentifier)siblingIdentifier { + _wasMutated = YES; +} + +- (void)insertElements:(NSArray<UIMenuElement*>*)insertedElements + beforeActionForIdentifier:(UIActionIdentifier)siblingIdentifier { + _wasMutated = YES; +} + +- (void)insertElements:(NSArray<UIMenuElement*>*)insertedElements + afterActionForIdentifier:(UIActionIdentifier)siblingIdentifier { + _wasMutated = YES; +} + +- (void)insertElements:(NSArray<UIMenuElement*>*)insertedElements + beforeCommandForAction:(SEL)siblingAction + propertyList:(nullable id)siblingPropertyList { + _wasMutated = YES; +} + +- (void)insertElements:(NSArray<UIMenuElement*>*)insertedElements + afterCommandForAction:(SEL)siblingAction + propertyList:(nullable id)siblingPropertyList { + _wasMutated = YES; +} + +- (void)insertElements:(NSArray<UIMenuElement*>*)childElements + atStartOfMenuForIdentifier:(UIMenuIdentifier)parentIdentifier { + _wasMutated = YES; +} + +- (void)insertElements:(NSArray<UIMenuElement*>*)childElements + atEndOfMenuForIdentifier:(UIMenuIdentifier)parentIdentifier { + _wasMutated = YES; +} + +- (void)removeActionForIdentifier:(UIActionIdentifier)removedIdentifier { + _wasMutated = YES; +} + +- (void)removeCommandForAction:(SEL)removedAction + propertyList:(nullable id)removedPropertyList { + _wasMutated = YES; +} + - (void)replaceChildrenOfMenuForIdentifier:(UIMenuIdentifier)parentIdentifier fromChildrenBlock: (NSArray<UIMenuElement*>*(NS_NOESCAPE ^)(
diff --git a/ios/chrome/browser/lens_overlay/ui/lens_overlay_container_view_controller.mm b/ios/chrome/browser/lens_overlay/ui/lens_overlay_container_view_controller.mm index 91d8ea2c..1382949 100644 --- a/ios/chrome/browser/lens_overlay/ui/lens_overlay_container_view_controller.mm +++ b/ios/chrome/browser/lens_overlay/ui/lens_overlay_container_view_controller.mm
@@ -203,6 +203,8 @@ - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; + UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, + self.selectionViewController); [self.delegate lensOverlayContainerDidAppear:self animated:animated]; }
diff --git a/ios/chrome/browser/main/model/browser_agent_util.mm b/ios/chrome/browser/main/model/browser_agent_util.mm index 40ff0cc..ed8027d 100644 --- a/ios/chrome/browser/main/model/browser_agent_util.mm +++ b/ios/chrome/browser/main/model/browser_agent_util.mm
@@ -27,6 +27,7 @@ #import "ios/chrome/browser/reader_mode/model/reader_mode_browser_agent.h" #import "ios/chrome/browser/reading_list/model/reading_list_browser_agent.h" #import "ios/chrome/browser/send_tab_to_self/model/send_tab_to_self_browser_agent.h" +#import "ios/chrome/browser/sessions/model/ios_chrome_tab_restore_browser_agent.h" #import "ios/chrome/browser/sessions/model/live_tab_context_browser_agent.h" #import "ios/chrome/browser/shared/model/application_context/application_context.h" #import "ios/chrome/browser/shared/model/profile/profile_ios.h" @@ -82,6 +83,7 @@ if (!browser_is_off_record) { ClosingWebStateObserverBrowserAgent::CreateForBrowser(browser); + IOSChromeTabRestoreBrowserAgent::CreateForBrowser(browser); } SnapshotBrowserAgent::CreateForBrowser(browser);
diff --git a/ios/chrome/browser/omnibox/coordinator/popup/omnibox_popup_coordinator.mm b/ios/chrome/browser/omnibox/coordinator/popup/omnibox_popup_coordinator.mm index 5ea0296..6ba4345 100644 --- a/ios/chrome/browser/omnibox/coordinator/popup/omnibox_popup_coordinator.mm +++ b/ios/chrome/browser/omnibox/coordinator/popup/omnibox_popup_coordinator.mm
@@ -237,6 +237,7 @@ PopupDebugInfoViewController* viewController = [[PopupDebugInfoViewController alloc] init]; _omniboxDebuggerMediator.consumer = viewController; + viewController.mutator = _omniboxDebuggerMediator; UINavigationController* navController = [[UINavigationController alloc] initWithRootViewController:viewController];
diff --git a/ios/chrome/browser/omnibox/debugger/BUILD.gn b/ios/chrome/browser/omnibox/debugger/BUILD.gn index 77de71c5..7dbb779 100644 --- a/ios/chrome/browser/omnibox/debugger/BUILD.gn +++ b/ios/chrome/browser/omnibox/debugger/BUILD.gn
@@ -11,9 +11,12 @@ "omnibox_debugger_consumer.h", "omnibox_debugger_mediator.h", "omnibox_debugger_mediator.mm", + "omnibox_debugger_mutator.h", "omnibox_event.h", "omnibox_remote_suggestion_event.h", "omnibox_remote_suggestion_event.mm", + "remote_suggestions_service_delegate_bridge.h", + "remote_suggestions_service_delegate_bridge.mm", "remote_suggestions_service_observer_bridge.h", "remote_suggestions_service_observer_bridge.mm", ]
diff --git a/ios/chrome/browser/omnibox/debugger/omnibox_debugger_mediator.h b/ios/chrome/browser/omnibox/debugger/omnibox_debugger_mediator.h index 200803e1..8d6829f 100644 --- a/ios/chrome/browser/omnibox/debugger/omnibox_debugger_mediator.h +++ b/ios/chrome/browser/omnibox/debugger/omnibox_debugger_mediator.h
@@ -7,6 +7,7 @@ #import <UIKit/UIKit.h> +#import "ios/chrome/browser/omnibox/debugger/omnibox_debugger_mutator.h" #import "ios/chrome/browser/omnibox/debugger/remote_suggestions_service_observer_bridge.h" #import "ios/chrome/browser/omnibox/model/autocomplete_controller_observer_bridge.h" #import "ios/chrome/browser/omnibox/model/omnibox_autocomplete_controller_debugger_delegate.h" @@ -20,6 +21,7 @@ // The omnibox debugger mediator. @interface OmniboxDebuggerMediator : NSObject <OmniboxAutocompleteControllerDebuggerDelegate, + OmniboxDebuggerMutator, RemoteSuggestionsServiceObserver, AutocompleteControllerObserver>
diff --git a/ios/chrome/browser/omnibox/debugger/omnibox_debugger_mediator.mm b/ios/chrome/browser/omnibox/debugger/omnibox_debugger_mediator.mm index aed7c8d..0033d0bf 100644 --- a/ios/chrome/browser/omnibox/debugger/omnibox_debugger_mediator.mm +++ b/ios/chrome/browser/omnibox/debugger/omnibox_debugger_mediator.mm
@@ -10,12 +10,17 @@ #import "ios/chrome/browser/omnibox/debugger/omnibox_autocomplete_event.h" #import "ios/chrome/browser/omnibox/debugger/omnibox_debugger_consumer.h" #import "ios/chrome/browser/omnibox/debugger/omnibox_remote_suggestion_event.h" +#import "ios/chrome/browser/omnibox/debugger/remote_suggestions_service_delegate_bridge.h" #import "ios/chrome/browser/omnibox/debugger/remote_suggestions_service_observer_bridge.h" #import "ios/chrome/browser/omnibox/model/autocomplete_controller_observer_bridge.h" #import "ios/chrome/browser/shared/public/features/system_flags.h" #import "ios/chrome/common/NSString+Chromium.h" #import "services/network/public/cpp/resource_request.h" +@interface OmniboxDebuggerMediator () <RemoteSuggestionsServiceDelegate> + +@end + @implementation OmniboxDebuggerMediator { // Autocomolete controller. raw_ptr<AutocompleteController> _autocompleteController; @@ -27,6 +32,11 @@ // Remote suggestions service observer bridge. std::unique_ptr<RemoteSuggestionsServiceObserverBridge> _remoteSuggestionsServiceObserverBridge; + // Remote suggestions service observer bridge. + std::unique_ptr<RemoteSuggestionsServiceDelegateBridge> + _remoteSuggestionsServiceDelegateBridge; + // Hardcoded suggest response. + std::string _hardcodedSuggestResponse; } - (instancetype)initWithAutocompleteController: @@ -50,6 +60,11 @@ _remoteSuggestionsServiceObserverBridge.reset(); } + if (_remoteSuggestionsServiceDelegateBridge) { + _remoteSuggestionsService->SetDelegate(nullptr); + _remoteSuggestionsServiceDelegateBridge.reset(); + } + if (_autocompleteObserverBridge) { _autocompleteController->RemoveObserver(_autocompleteObserverBridge.get()); _autocompleteObserverBridge.reset(); @@ -78,6 +93,49 @@ _consumer = consumer; } +#pragma mark - OmniboxDebuggerMutator + +- (void)hardcodeSuggestResponse:(NSString*)response { + _hardcodedSuggestResponse = response.cr_UTF8String; + + if (!_remoteSuggestionsServiceDelegateBridge && _remoteSuggestionsService) { + _remoteSuggestionsServiceDelegateBridge = + std::make_unique<RemoteSuggestionsServiceDelegateBridge>( + self, _remoteSuggestionsService); + _remoteSuggestionsService->SetDelegate( + _remoteSuggestionsServiceDelegateBridge->AsWeakPtr()); + } +} + +#pragma mark - RemoteSuggestionsServiceDelegate + +- (void)onRequestCompleted:(const network::SimpleURLLoader*)source + responseCode:(int)responseCode + responseBody:(std::unique_ptr<std::string>)responseBody + completion: + (RemoteSuggestionsService::CompletionCallback)completion { + if (responseCode == 200 && !_hardcodedSuggestResponse.empty()) { + *responseBody = _hardcodedSuggestResponse; + } + + std::move(completion).Run(source, responseCode, std::move(responseBody)); +} + +- (void)onIndexedRequestCompleted:(int)requestIndex + urlLoader:(const network::SimpleURLLoader*)source + responseCode:(int)responseCode + responseBody:(std::unique_ptr<std::string>)responseBody + completion: + (RemoteSuggestionsService::IndexedCompletionCallback) + completion { + if (responseCode == 200 && !_hardcodedSuggestResponse.empty()) { + *responseBody = _hardcodedSuggestResponse; + } + + std::move(completion) + .Run(requestIndex, source, responseCode, std::move(responseBody)); +} + #pragma mark - RemoteSuggestionsServiceObserver - (void)remoteSuggestionsService:(RemoteSuggestionsService*)service
diff --git a/ios/chrome/browser/omnibox/debugger/omnibox_debugger_mutator.h b/ios/chrome/browser/omnibox/debugger/omnibox_debugger_mutator.h new file mode 100644 index 0000000..11c9aee --- /dev/null +++ b/ios/chrome/browser/omnibox/debugger/omnibox_debugger_mutator.h
@@ -0,0 +1,17 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_BROWSER_OMNIBOX_DEBUGGER_OMNIBOX_DEBUGGER_MUTATOR_H_ +#define IOS_CHROME_BROWSER_OMNIBOX_DEBUGGER_OMNIBOX_DEBUGGER_MUTATOR_H_ + +#import <UIKit/UIKit.h> + +@protocol OmniboxDebuggerMutator <NSObject> + +/// Hardcode suggest response with `response`. +- (void)hardcodeSuggestResponse:(NSString*)response; + +@end + +#endif // IOS_CHROME_BROWSER_OMNIBOX_DEBUGGER_OMNIBOX_DEBUGGER_MUTATOR_H_
diff --git a/ios/chrome/browser/omnibox/debugger/omnibox_debugger_view_controller.h b/ios/chrome/browser/omnibox/debugger/omnibox_debugger_view_controller.h index aee43c0..039ec83 100644 --- a/ios/chrome/browser/omnibox/debugger/omnibox_debugger_view_controller.h +++ b/ios/chrome/browser/omnibox/debugger/omnibox_debugger_view_controller.h
@@ -9,10 +9,15 @@ #import "ios/chrome/browser/omnibox/debugger/omnibox_debugger_consumer.h" +@protocol OmniboxDebuggerMutator; + /// View controller used to display omnibox and popup related debug info. @interface PopupDebugInfoViewController : UIViewController <OmniboxDebuggerConsumer> +/// Mutator of the omnibox debugger. +@property(nonatomic, weak) id<OmniboxDebuggerMutator> mutator; + - (instancetype)init NS_DESIGNATED_INITIALIZER; - (instancetype)initWithCoder:(NSCoder*)aDecoder NS_UNAVAILABLE;
diff --git a/ios/chrome/browser/omnibox/debugger/omnibox_debugger_view_controller.mm b/ios/chrome/browser/omnibox/debugger/omnibox_debugger_view_controller.mm index 07591e8..0f54fb9 100644 --- a/ios/chrome/browser/omnibox/debugger/omnibox_debugger_view_controller.mm +++ b/ios/chrome/browser/omnibox/debugger/omnibox_debugger_view_controller.mm
@@ -11,6 +11,7 @@ #import "components/variations/variations_switches.h" #import "ios/chrome/browser/omnibox/debugger/omnibox_autocomplete_event.h" #import "ios/chrome/browser/omnibox/debugger/omnibox_autocomplete_event_view_controller.h" +#import "ios/chrome/browser/omnibox/debugger/omnibox_debugger_mutator.h" #import "ios/chrome/browser/omnibox/debugger/omnibox_event.h" #import "ios/chrome/browser/omnibox/debugger/omnibox_remote_suggestion_event.h" #import "ios/chrome/browser/omnibox/debugger/omnibox_remote_suggestion_event_view_controller.h" @@ -116,7 +117,8 @@ @interface PopupDebugInfoViewController () <UITextFieldDelegate, UITableViewDelegate, - UITableViewDataSource> + UITableViewDataSource, + UITextViewDelegate> @property(nonatomic, strong) UITextView* activeVariationIDTextView; @property(nonatomic, strong) UITextField* variationIDTextField; @@ -135,6 +137,11 @@ @implementation PopupDebugInfoViewController { // In reverse chronological order: index 0 is most recent. NSMutableArray<id<OmniboxEvent>>* _events; + + /// Label for hardcoded suggest response. + UILabel* _hardcodedTextLabel; + /// Text view for hardcoded suggest response. + UITextView* _hardcodedTextView; } - (instancetype)init { @@ -165,6 +172,18 @@ - (void)viewDidLoad { [super viewDidLoad]; + _hardcodedTextLabel = [[UILabel alloc] init]; + _hardcodedTextLabel.translatesAutoresizingMaskIntoConstraints = NO; + _hardcodedTextLabel.numberOfLines = 0; + _hardcodedTextLabel.textColor = UIColor.blackColor; + _hardcodedTextLabel.text = @"Hardcoded suggest response:"; + + _hardcodedTextView = [[UITextView alloc] init]; + _hardcodedTextView.translatesAutoresizingMaskIntoConstraints = NO; + _hardcodedTextView.delegate = self; + _hardcodedTextView.backgroundColor = UIColor.lightGrayColor; + [_hardcodedTextView.heightAnchor constraintEqualToConstant:50].active = YES; + UIScrollView* scrollView = [[UIScrollView alloc] init]; scrollView.translatesAutoresizingMaskIntoConstraints = NO; scrollView.backgroundColor = UIColor.systemBackgroundColor; @@ -188,12 +207,14 @@ [stackView addArrangedSubview:self.variationInstructionLabel]; [stackView addArrangedSubview:self.enableVariationIDTextView]; [stackView addArrangedSubview:self.disableVariationIDsTextView]; + [stackView addArrangedSubview:_hardcodedTextLabel]; + [stackView addArrangedSubview:_hardcodedTextView]; [stackView addArrangedSubview:_tableView]; [NSLayoutConstraint activateConstraints:@[ [_tableView.widthAnchor constraintEqualToAnchor:stackView.widthAnchor], [_tableView.topAnchor - constraintEqualToAnchor:self.disableVariationIDsTextView.bottomAnchor + constraintEqualToAnchor:_hardcodedTextView.bottomAnchor constant:16], [_tableView.bottomAnchor constraintEqualToAnchor:stackView.bottomAnchor constant:-16] @@ -237,6 +258,12 @@ [self updateForceVariationTextViews]; } +#pragma mark - UITextViewDelegate + +- (void)textViewDidChange:(UITextView*)textView { + [self.mutator hardcodeSuggestResponse:textView.text]; +} + #pragma mark - OmniboxDebuggerConsumer - (void)setVariationIDString:(NSString*)string {
diff --git a/ios/chrome/browser/omnibox/debugger/remote_suggestions_service_delegate_bridge.h b/ios/chrome/browser/omnibox/debugger/remote_suggestions_service_delegate_bridge.h new file mode 100644 index 0000000..09da2a9 --- /dev/null +++ b/ios/chrome/browser/omnibox/debugger/remote_suggestions_service_delegate_bridge.h
@@ -0,0 +1,72 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_BROWSER_OMNIBOX_DEBUGGER_REMOTE_SUGGESTIONS_SERVICE_DELEGATE_BRIDGE_H_ +#define IOS_CHROME_BROWSER_OMNIBOX_DEBUGGER_REMOTE_SUGGESTIONS_SERVICE_DELEGATE_BRIDGE_H_ + +#import <memory> +#import <string> + +#import "base/functional/callback_forward.h" +#import "base/memory/raw_ptr.h" +#import "base/strings/sys_string_conversions.h" +#import "base/strings/utf_string_conversions.h" +#import "components/omnibox/browser/remote_suggestions_service.h" + +@protocol RemoteSuggestionsServiceDelegate <NSObject> + +- (void)onRequestCompleted:(const network::SimpleURLLoader*)source + responseCode:(int)responseCode + responseBody:(std::unique_ptr<std::string>)responseBody + completion: + (RemoteSuggestionsService::CompletionCallback)completion; + +- (void)onIndexedRequestCompleted:(int)requestIndex + urlLoader:(const network::SimpleURLLoader*)source + responseCode:(int)responseCode + responseBody:(std::unique_ptr<std::string>)responseBody + completion: + (RemoteSuggestionsService::IndexedCompletionCallback) + completion; + +@end + +class RemoteSuggestionsServiceDelegateBridge + : public RemoteSuggestionsService::Delegate { + public: + RemoteSuggestionsServiceDelegateBridge( + id<RemoteSuggestionsServiceDelegate> delegate, + RemoteSuggestionsService* remote_suggestions_service); + + ~RemoteSuggestionsServiceDelegateBridge() override; + + RemoteSuggestionsServiceDelegateBridge( + const RemoteSuggestionsServiceDelegateBridge&) = delete; + RemoteSuggestionsServiceDelegateBridge& operator=( + const RemoteSuggestionsServiceDelegateBridge&) = delete; + + base::WeakPtr<RemoteSuggestionsServiceDelegateBridge> AsWeakPtr(); + + void OnRequestCompleted(const network::SimpleURLLoader* source, + const int response_code, + std::unique_ptr<std::string> response_body, + RemoteSuggestionsService::CompletionCallback + completion_callback) override; + + void OnIndexedRequestCompleted( + const int request_index, + const network::SimpleURLLoader* source, + const int response_code, + std::unique_ptr<std::string> response_body, + RemoteSuggestionsService::IndexedCompletionCallback completion_callback) + override; + + private: + __weak id<RemoteSuggestionsServiceDelegate> delegate_; + raw_ptr<RemoteSuggestionsService> remote_suggestions_service_; + base::WeakPtrFactory<RemoteSuggestionsServiceDelegateBridge> + weak_ptr_factory_{this}; +}; + +#endif // IOS_CHROME_BROWSER_OMNIBOX_DEBUGGER_REMOTE_SUGGESTIONS_SERVICE_DELEGATE_BRIDGE_H_
diff --git a/ios/chrome/browser/omnibox/debugger/remote_suggestions_service_delegate_bridge.mm b/ios/chrome/browser/omnibox/debugger/remote_suggestions_service_delegate_bridge.mm new file mode 100644 index 0000000..7ed61ab --- /dev/null +++ b/ios/chrome/browser/omnibox/debugger/remote_suggestions_service_delegate_bridge.mm
@@ -0,0 +1,46 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/chrome/browser/omnibox/debugger/remote_suggestions_service_delegate_bridge.h" + +RemoteSuggestionsServiceDelegateBridge::RemoteSuggestionsServiceDelegateBridge( + id<RemoteSuggestionsServiceDelegate> delegate, + RemoteSuggestionsService* remote_suggestions_service) + : delegate_(delegate), + remote_suggestions_service_(remote_suggestions_service) {} + +RemoteSuggestionsServiceDelegateBridge:: + ~RemoteSuggestionsServiceDelegateBridge() { + remote_suggestions_service_ = nullptr; + delegate_ = nil; +} + +base::WeakPtr<RemoteSuggestionsServiceDelegateBridge> +RemoteSuggestionsServiceDelegateBridge::AsWeakPtr() { + return this->weak_ptr_factory_.GetWeakPtr(); +} + +void RemoteSuggestionsServiceDelegateBridge::OnRequestCompleted( + const network::SimpleURLLoader* source, + const int response_code, + std::unique_ptr<std::string> response_body, + RemoteSuggestionsService::CompletionCallback completion_callback) { + [delegate_ onRequestCompleted:source + responseCode:response_code + responseBody:std::move(response_body) + completion:std::move(completion_callback)]; +} + +void RemoteSuggestionsServiceDelegateBridge::OnIndexedRequestCompleted( + const int request_index, + const network::SimpleURLLoader* source, + const int response_code, + std::unique_ptr<std::string> response_body, + RemoteSuggestionsService::IndexedCompletionCallback completion_callback) { + [delegate_ onIndexedRequestCompleted:request_index + urlLoader:source + responseCode:response_code + responseBody:std::move(response_body) + completion:std::move(completion_callback)]; +}
diff --git a/ios/chrome/browser/passwords/ui_bundled/bottom_sheet/BUILD.gn b/ios/chrome/browser/passwords/ui_bundled/bottom_sheet/BUILD.gn index 78e1890c..8c1fbd7 100644 --- a/ios/chrome/browser/passwords/ui_bundled/bottom_sheet/BUILD.gn +++ b/ios/chrome/browser/passwords/ui_bundled/bottom_sheet/BUILD.gn
@@ -120,6 +120,7 @@ "//ios/chrome/browser/settings/ui_bundled/password:eg_test_support+eg2", "//ios/chrome/browser/settings/ui_bundled/password:password_constants", "//ios/chrome/browser/settings/ui_bundled/password/password_details:password_details_table_view_constants", + "//ios/chrome/browser/shared/ui/symbols", "//ios/chrome/browser/signin/model:fake_system_identity", "//ios/chrome/common/ui/confirmation_alert:constants", "//ios/chrome/test:eg_test_support+eg2",
diff --git a/ios/chrome/browser/passwords/ui_bundled/bottom_sheet/password_suggestion_bottom_sheet_egtest.mm b/ios/chrome/browser/passwords/ui_bundled/bottom_sheet/password_suggestion_bottom_sheet_egtest.mm index 0098e0b..63655e49 100644 --- a/ios/chrome/browser/passwords/ui_bundled/bottom_sheet/password_suggestion_bottom_sheet_egtest.mm +++ b/ios/chrome/browser/passwords/ui_bundled/bottom_sheet/password_suggestion_bottom_sheet_egtest.mm
@@ -23,6 +23,7 @@ #import "ios/chrome/browser/settings/ui_bundled/password/password_manager_egtest_utils.h" #import "ios/chrome/browser/settings/ui_bundled/password/password_settings_app_interface.h" #import "ios/chrome/browser/settings/ui_bundled/password/passwords_table_view_constants.h" +#import "ios/chrome/browser/shared/ui/symbols/symbols.h" #import "ios/chrome/browser/signin/model/fake_system_identity.h" #import "ios/chrome/common/ui/confirmation_alert/constants.h" #import "ios/chrome/grit/ios_strings.h" @@ -38,13 +39,14 @@ #import "net/test/embedded_test_server/default_handlers.h" #import "ui/base/l10n/l10n_util.h" +using chrome_test_util::WebViewMatcher; +using password_manager_test_utils::DeleteCredential; + static constexpr char kFormUsername[] = "un"; static constexpr char kFormPassword[] = "pw"; namespace { -using password_manager_test_utils::DeleteCredential; - id<GREYMatcher> ButtonWithAccessibilityID(NSString* id) { return grey_allOf(grey_accessibilityID(id), grey_accessibilityTrait(UIAccessibilityTraitButton), nil); @@ -244,6 +246,13 @@ password_manager::features::kIOSStatelessFillDataFlow); } + if ([self isRunningTest:@selector(testDisplayRecoveryPassword)] || + [self isRunningTest:@selector + (testAvailableContextMenuItemsForRecoveryPassword)]) { + config.features_enabled.push_back( + password_manager::features::kIOSFillRecoveryPassword); + } + return config; } @@ -269,6 +278,7 @@ // Loads simple page. It is on localhost so it is considered a secure context. [ChromeEarlGrey loadURL:[self loginPageURL]]; [ChromeEarlGrey waitForWebStateContainingText:"Login form."]; + [ChromeEarlGrey waitForUIElementToAppearWithMatcher:WebViewMatcher()]; } - (void)loadLoginAutofocusPage { @@ -328,7 +338,7 @@ URL:net::NSURLWithGURL(URL)]; [self loadLoginPage]; - [[EarlGrey selectElementWithMatcher:chrome_test_util::WebViewMatcher()] + [[EarlGrey selectElementWithMatcher:WebViewMatcher()] performAction:chrome_test_util::TapWebElementWithId(kFormPassword)]; [ChromeEarlGrey @@ -365,7 +375,7 @@ // moment doesn't always work. base::test::ios::SpinRunLoopWithMinDelay(base::Seconds(1)); - [[EarlGrey selectElementWithMatcher:chrome_test_util::WebViewMatcher()] + [[EarlGrey selectElementWithMatcher:WebViewMatcher()] performAction:chrome_test_util::TapWebElementWithId(kFormPassword)]; [ChromeEarlGrey @@ -429,7 +439,7 @@ [self loadLoginPasskeyPage]; - [[EarlGrey selectElementWithMatcher:chrome_test_util::WebViewMatcher()] + [[EarlGrey selectElementWithMatcher:WebViewMatcher()] performAction:chrome_test_util::TapWebElementWithId(kFormPassword)]; [ChromeEarlGrey waitForKeyboardToAppear]; @@ -446,7 +456,7 @@ [ChromeEarlGrey openNewIncognitoTab]; [self loadLoginPage]; - [[EarlGrey selectElementWithMatcher:chrome_test_util::WebViewMatcher()] + [[EarlGrey selectElementWithMatcher:WebViewMatcher()] performAction:chrome_test_util::TapWebElementWithId(kFormPassword)]; [ChromeEarlGrey @@ -466,7 +476,7 @@ [self saveGenericPasswordAndLoadLoginPage]; - [[EarlGrey selectElementWithMatcher:chrome_test_util::WebViewMatcher()] + [[EarlGrey selectElementWithMatcher:WebViewMatcher()] performAction:chrome_test_util::TapWebElementWithId(kFormPassword)]; [ChromeEarlGrey @@ -487,7 +497,7 @@ [self saveGenericPasswordAndLoadLoginPage]; - [[EarlGrey selectElementWithMatcher:chrome_test_util::WebViewMatcher()] + [[EarlGrey selectElementWithMatcher:WebViewMatcher()] performAction:chrome_test_util::TapWebElementWithId(kFormPassword)]; [ChromeEarlGrey @@ -511,7 +521,7 @@ [self loadLoginPage]; - [[EarlGrey selectElementWithMatcher:chrome_test_util::WebViewMatcher()] + [[EarlGrey selectElementWithMatcher:WebViewMatcher()] performAction:chrome_test_util::TapWebElementWithId(kFormPassword)]; TapElementOnceVisible(grey_accessibilityID(@"user")); @@ -555,7 +565,7 @@ [self loadLoginPage]; - [[EarlGrey selectElementWithMatcher:chrome_test_util::WebViewMatcher()] + [[EarlGrey selectElementWithMatcher:WebViewMatcher()] performAction:chrome_test_util::TapWebElementWithId(kFormPassword)]; TapElementOnceVisible(grey_accessibilityID(@"user")); @@ -631,7 +641,7 @@ [self loadLoginPage]; - [[EarlGrey selectElementWithMatcher:chrome_test_util::WebViewMatcher()] + [[EarlGrey selectElementWithMatcher:WebViewMatcher()] performAction:chrome_test_util::TapWebElementWithId(kFormPassword)]; TapElementOnceVisible(grey_accessibilityID(@"user")); @@ -692,7 +702,7 @@ [self loadLoginPage]; - [[EarlGrey selectElementWithMatcher:chrome_test_util::WebViewMatcher()] + [[EarlGrey selectElementWithMatcher:WebViewMatcher()] performAction:chrome_test_util::TapWebElementWithId(kFormPassword)]; TapElementOnceVisible(grey_accessibilityID(@"user")); @@ -723,7 +733,7 @@ [ChromeEarlGreyUI waitForAppToIdle]; // Verify that user2 is not available anymore. - [[EarlGrey selectElementWithMatcher:chrome_test_util::WebViewMatcher()] + [[EarlGrey selectElementWithMatcher:WebViewMatcher()] performAction:chrome_test_util::TapWebElementWithId(kFormPassword)]; TapElementOnceVisible(grey_accessibilityID(@"user")); @@ -741,7 +751,7 @@ [self loadLoginPage]; - [[EarlGrey selectElementWithMatcher:chrome_test_util::WebViewMatcher()] + [[EarlGrey selectElementWithMatcher:WebViewMatcher()] performAction:chrome_test_util::TapWebElementWithId(kFormPassword)]; // Tapping the single item doesn't change anything. @@ -762,7 +772,7 @@ // Reload the page, now with 2 credentials. [self loadLoginPage]; - [[EarlGrey selectElementWithMatcher:chrome_test_util::WebViewMatcher()] + [[EarlGrey selectElementWithMatcher:WebViewMatcher()] performAction:chrome_test_util::TapWebElementWithId(kFormPassword)]; // Select the first item. @@ -805,7 +815,7 @@ [self loadLoginPage]; - [[EarlGrey selectElementWithMatcher:chrome_test_util::WebViewMatcher()] + [[EarlGrey selectElementWithMatcher:WebViewMatcher()] performAction:chrome_test_util::TapWebElementWithId(kFormPassword)]; // Tap to expand. @@ -834,7 +844,7 @@ // Dismiss #1. [self saveGenericPasswordAndLoadLoginPage]; - [[EarlGrey selectElementWithMatcher:chrome_test_util::WebViewMatcher()] + [[EarlGrey selectElementWithMatcher:WebViewMatcher()] performAction:chrome_test_util::TapWebElementWithId(kFormPassword)]; [ChromeEarlGrey @@ -848,7 +858,7 @@ // Dismiss #2. [self loadLoginPage]; - [[EarlGrey selectElementWithMatcher:chrome_test_util::WebViewMatcher()] + [[EarlGrey selectElementWithMatcher:WebViewMatcher()] performAction:chrome_test_util::TapWebElementWithId(kFormPassword)]; [ChromeEarlGrey @@ -862,7 +872,7 @@ // Dismiss #3. [self loadLoginPage]; - [[EarlGrey selectElementWithMatcher:chrome_test_util::WebViewMatcher()] + [[EarlGrey selectElementWithMatcher:WebViewMatcher()] performAction:chrome_test_util::TapWebElementWithId(kFormPassword)]; [ChromeEarlGrey @@ -875,7 +885,7 @@ // Verify that keyboard is shown. [self loadLoginPage]; - [[EarlGrey selectElementWithMatcher:chrome_test_util::WebViewMatcher()] + [[EarlGrey selectElementWithMatcher:WebViewMatcher()] performAction:chrome_test_util::TapWebElementWithId(kFormPassword)]; [ChromeEarlGrey waitForKeyboardToAppear]; } @@ -888,7 +898,7 @@ URL:net::NSURLWithGURL([self loginPageURL])]; [self loadLoginPage]; - [[EarlGrey selectElementWithMatcher:chrome_test_util::WebViewMatcher()] + [[EarlGrey selectElementWithMatcher:WebViewMatcher()] performAction:chrome_test_util::TapWebElementWithId(kFormPassword)]; [ChromeEarlGrey waitForUIElementToAppearWithMatcher: @@ -905,7 +915,7 @@ // Verify that selecting credentials with no username disables the bottom // sheet. - [[EarlGrey selectElementWithMatcher:chrome_test_util::WebViewMatcher()] + [[EarlGrey selectElementWithMatcher:WebViewMatcher()] performAction:chrome_test_util::TapWebElementWithId(kFormPassword)]; [ChromeEarlGrey waitForKeyboardToAppear]; @@ -918,7 +928,7 @@ if (@available(iOS 17.0, *)) { [self saveGenericPasswordAndLoadLoginPage]; - [[EarlGrey selectElementWithMatcher:chrome_test_util::WebViewMatcher()] + [[EarlGrey selectElementWithMatcher:WebViewMatcher()] performAction:chrome_test_util::TapWebElementWithId(kFormPassword)]; [ChromeEarlGrey @@ -967,7 +977,7 @@ [self loadLoginPage]; - [[EarlGrey selectElementWithMatcher:chrome_test_util::WebViewMatcher()] + [[EarlGrey selectElementWithMatcher:WebViewMatcher()] performAction:chrome_test_util::TapWebElementWithId(kFormPassword)]; [ChromeEarlGrey waitForUIElementToAppearWithMatcher:grey_accessibilityID(@"user1")]; @@ -994,7 +1004,7 @@ // Verify that after using the shared password regular bottom sheet is // displayed. [self loadLoginPage]; - [[EarlGrey selectElementWithMatcher:chrome_test_util::WebViewMatcher()] + [[EarlGrey selectElementWithMatcher:WebViewMatcher()] performAction:chrome_test_util::TapWebElementWithId(kFormPassword)]; [ChromeEarlGrey @@ -1022,7 +1032,7 @@ shared:YES]; [self loadLoginPage]; - [[EarlGrey selectElementWithMatcher:chrome_test_util::WebViewMatcher()] + [[EarlGrey selectElementWithMatcher:WebViewMatcher()] performAction:chrome_test_util::TapWebElementWithId(kFormPassword)]; [ChromeEarlGrey @@ -1058,7 +1068,7 @@ [self loadLoginPage]; - [[EarlGrey selectElementWithMatcher:chrome_test_util::WebViewMatcher()] + [[EarlGrey selectElementWithMatcher:WebViewMatcher()] performAction:chrome_test_util::TapWebElementWithId(kFormPassword)]; [ChromeEarlGrey @@ -1080,7 +1090,7 @@ // bottom sheet is displayed. [self loadLoginPage]; - [[EarlGrey selectElementWithMatcher:chrome_test_util::WebViewMatcher()] + [[EarlGrey selectElementWithMatcher:WebViewMatcher()] performAction:chrome_test_util::TapWebElementWithId(kFormPassword)]; [ChromeEarlGrey @@ -1124,4 +1134,37 @@ assertWithMatcher:grey_nil()]; } +// Tests that recovery passwords appear as expected in the bottom sheet. +- (void)testDisplayRecoveryPassword { + // TODO(crbug.com/422206607): Add a PasswordForm with a recovery password. + [self saveGenericPasswordAndLoadLoginPage]; + + // Tap on a field to trigger the bottom sheet. + [[EarlGrey selectElementWithMatcher:WebViewMatcher()] + performAction:chrome_test_util::TapWebElementWithId(kFormPassword)]; + [ChromeEarlGrey + waitForUIElementToAppearWithMatcher:grey_accessibilityID(@"user")]; + + // TODO(crbug.com/422206607): Switch the `grey_nil()` matcher for + // `grey_sufficientlyVisible` once a recovery password will have been added. + [[EarlGrey selectElementWithMatcher:grey_accessibilityID(kHistorySymbol)] + assertWithMatcher:grey_nil()]; +} + +// Tests that only the expected options are available in the context menu when +// opened from a recovery password suggestion. +- (void)testAvailableContextMenuItemsForRecoveryPassword { + // TODO(crbug.com/422206607): Add a PasswordForm with a recovery password. + [self saveGenericPasswordAndLoadLoginPage]; + + // Tap on a field to trigger the bottom sheet. + [[EarlGrey selectElementWithMatcher:WebViewMatcher()] + performAction:chrome_test_util::TapWebElementWithId(kFormPassword)]; + + // TODO(crbug.com/422206607): Once a recovery password will have been added, + // make sure to long press the recovery password suggestion and verify that + // only the "Password Manager" context menu item is available. + LongPressElementOnceVisible(grey_accessibilityID(@"user")); +} + @end
diff --git a/ios/chrome/browser/passwords/ui_bundled/bottom_sheet/password_suggestion_bottom_sheet_view_controller.mm b/ios/chrome/browser/passwords/ui_bundled/bottom_sheet/password_suggestion_bottom_sheet_view_controller.mm index ff987ff..55374d0 100644 --- a/ios/chrome/browser/passwords/ui_bundled/bottom_sheet/password_suggestion_bottom_sheet_view_controller.mm +++ b/ios/chrome/browser/passwords/ui_bundled/bottom_sheet/password_suggestion_bottom_sheet_view_controller.mm
@@ -160,6 +160,12 @@ [self.handler viewDidDisappear]; } +#pragma mark - Getters + +- (NSArray<FormSuggestion*>*)suggestions { + return _suggestions; +} + #pragma mark - PasswordSuggestionBottomSheetConsumer - (void)setSuggestions:(NSArray<FormSuggestion*>*)suggestions @@ -203,16 +209,22 @@ children:@[ [strongSelf openPasswordManagerAction] ]]]; - [menuElements - addObject:[UIMenu - menuWithTitle:@"" - image:nil - identifier:nil - options:UIMenuOptionsDisplayInline - children:@[ - [strongSelf - openPasswordDetailsForIndexPath:indexPath] - ]]]; + + // The option to open password details shouldn't be available for recovery + // passwords as they are not displayed in the Password Manager for now. + FormSuggestion* formSuggestion = + [strongSelf.suggestions objectAtIndex:indexPath.row]; + if (!formSuggestion.metadata.is_recovery_password) { + [menuElements + addObject:[UIMenu + menuWithTitle:@"" + image:nil + identifier:nil + options:UIMenuOptionsDisplayInline + children:@[ [strongSelf + openPasswordDetailsForSuggestion: + formSuggestion] ]]]; + } } return [UIMenu menuWithTitle:@"" children:menuElements]; @@ -339,7 +351,7 @@ base::apple::ObjCCastStrict<TableViewURLCell>(cell); if (suggestion.metadata.is_recovery_password) { - // TODO(crbug.com/417943553): Replace favicon with kHistorySymbol. + [URLCell replaceFaviconWithSymbol:kHistorySymbol]; } else { auto faviconLoadedBlock = ^(FaviconAttributes* attributes) { DCHECK(attributes); @@ -369,11 +381,10 @@ handler:passwordManagerButtonTapHandler]; } -// Creates the UI action used to open the password details for form suggestion -// at index path. -- (UIAction*)openPasswordDetailsForIndexPath:(NSIndexPath*)indexPath { +// Creates the UI action used to open the password details for the given +// `formSuggestion`. +- (UIAction*)openPasswordDetailsForSuggestion:(FormSuggestion*)formSuggestion { __weak __typeof(self) weakSelf = self; - FormSuggestion* formSuggestion = [_suggestions objectAtIndex:indexPath.row]; void (^showDetailsButtonTapHandler)(UIAction*) = ^(UIAction* action) { // Open Password Details. weakSelf.disableBottomSheetOnExit = NO;
diff --git a/ios/chrome/browser/sessions/model/BUILD.gn b/ios/chrome/browser/sessions/model/BUILD.gn index 5d82542..d449cba 100644 --- a/ios/chrome/browser/sessions/model/BUILD.gn +++ b/ios/chrome/browser/sessions/model/BUILD.gn
@@ -6,6 +6,8 @@ sources = [ "ios_chrome_session_tab_helper.h", "ios_chrome_session_tab_helper.mm", + "ios_chrome_tab_restore_browser_agent.h", + "ios_chrome_tab_restore_browser_agent.mm", "ios_chrome_tab_restore_service_client.h", "ios_chrome_tab_restore_service_client.mm", "ios_chrome_tab_restore_service_factory.cc", @@ -19,6 +21,8 @@ ] deps = [ ":serialisation", + ":session_restoration_service", + ":session_restoration_service_factory", ":session_util", "//base", "//components/tab_groups",
diff --git a/ios/chrome/browser/sessions/model/ios_chrome_tab_restore_browser_agent.h b/ios/chrome/browser/sessions/model/ios_chrome_tab_restore_browser_agent.h new file mode 100644 index 0000000..b29f18ac --- /dev/null +++ b/ios/chrome/browser/sessions/model/ios_chrome_tab_restore_browser_agent.h
@@ -0,0 +1,53 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_BROWSER_SESSIONS_MODEL_IOS_CHROME_TAB_RESTORE_BROWSER_AGENT_H_ +#define IOS_CHROME_BROWSER_SESSIONS_MODEL_IOS_CHROME_TAB_RESTORE_BROWSER_AGENT_H_ + +#import "base/memory/weak_ptr.h" +#import "base/scoped_observation.h" +#import "ios/chrome/browser/shared/model/browser/browser_user_data.h" +#import "ios/chrome/browser/shared/model/web_state_list/web_state_list.h" +#import "ios/chrome/browser/shared/model/web_state_list/web_state_list_observer.h" + +namespace web::proto { +class WebStateStorage; +} // namespace web::proto + +// A browser agent that is responsible for observing tab closures and +// informing the IOSChromeTabRestoreService about those events. +class IOSChromeTabRestoreBrowserAgent + : public BrowserUserData<IOSChromeTabRestoreBrowserAgent>, + public WebStateListObserver { + public: + ~IOSChromeTabRestoreBrowserAgent() override; + + private: + friend class BrowserUserData<IOSChromeTabRestoreBrowserAgent>; + + explicit IOSChromeTabRestoreBrowserAgent(Browser* browser); + + // Records history for a given non-incognito WebState and does not record + // history if the tab has no navigation or has only presented the NTP or the + // bookmark UI. + void RecordHistoryForWebState(int index, web::WebState* web_state); + + // Records history for a given unrealized WebState after loading its state + // from storage. + void RecordHistoryFromStorage(int index, web::proto::WebStateStorage storage); + + // WebStateListObserver implementation. + void WebStateListWillChange(WebStateList* web_state_list, + const WebStateListChangeDetach& detach_change, + const WebStateListStatus& status) override; + + // Observation of the Browser's WebStateList. + base::ScopedObservation<WebStateList, WebStateListObserver> + web_state_list_observation_{this}; + + // Weak pointer factory. + base::WeakPtrFactory<IOSChromeTabRestoreBrowserAgent> weak_ptr_factory_{this}; +}; + +#endif // IOS_CHROME_BROWSER_SESSIONS_MODEL_IOS_CHROME_TAB_RESTORE_BROWSER_AGENT_H_
diff --git a/ios/chrome/browser/sessions/model/ios_chrome_tab_restore_browser_agent.mm b/ios/chrome/browser/sessions/model/ios_chrome_tab_restore_browser_agent.mm new file mode 100644 index 0000000..f8679394ac --- /dev/null +++ b/ios/chrome/browser/sessions/model/ios_chrome_tab_restore_browser_agent.mm
@@ -0,0 +1,88 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/chrome/browser/sessions/model/ios_chrome_tab_restore_browser_agent.h" + +#import "base/check.h" +#import "base/functional/bind.h" +#import "components/sessions/core/tab_restore_service.h" +#import "components/sessions/ios/ios_restore_live_tab.h" +#import "components/sessions/ios/ios_webstate_live_tab.h" +#import "ios/chrome/browser/sessions/model/ios_chrome_tab_restore_service_factory.h" +#import "ios/chrome/browser/sessions/model/session_restoration_service.h" +#import "ios/chrome/browser/sessions/model/session_restoration_service_factory.h" +#import "ios/chrome/browser/shared/model/browser/browser.h" +#import "ios/chrome/browser/shared/model/profile/profile_ios.h" +#import "ios/chrome/browser/shared/model/url/chrome_url_constants.h" +#import "ios/web/public/session/proto/navigation.pb.h" +#import "ios/web/public/session/proto/storage.pb.h" +#import "ios/web/public/web_state.h" +#import "url/gurl.h" + +IOSChromeTabRestoreBrowserAgent::~IOSChromeTabRestoreBrowserAgent() = default; + +IOSChromeTabRestoreBrowserAgent::IOSChromeTabRestoreBrowserAgent( + Browser* browser) + : BrowserUserData(browser) { + CHECK(!browser_->GetProfile()->IsOffTheRecord()); + web_state_list_observation_.Observe(browser_->GetWebStateList()); +} + +void IOSChromeTabRestoreBrowserAgent::RecordHistoryForWebState( + int index, + web::WebState* web_state) { + // No need to record history if the tab has no navigation or has only + // presented the NTP. + if (web_state->GetNavigationItemCount() <= 1) { + const GURL& url = web_state->GetLastCommittedURL(); + if (!url.is_valid() || url.host_piece() == kChromeUINewTabHost) { + return; + } + } + + ProfileIOS* profile = browser_->GetProfile(); + CHECK(profile); + + // If the WebState is still unrealized, ask the SessionRestorationService + // to load the data from storage (it should exists otherwise the WebState + // would have no navigation history). + if (!web_state->IsRealized()) { + SessionRestorationServiceFactory::GetForProfile(profile) + ->LoadWebStateStorage( + browser_, web_state, + base::BindOnce( + &IOSChromeTabRestoreBrowserAgent::RecordHistoryFromStorage, + weak_ptr_factory_.GetWeakPtr(), index)); + return; + } + + IOSChromeTabRestoreServiceFactory::GetForProfile(profile) + ->CreateHistoricalTab( + sessions::IOSWebStateLiveTab::GetForWebState(web_state), index); +} + +void IOSChromeTabRestoreBrowserAgent::RecordHistoryFromStorage( + int index, + web::proto::WebStateStorage storage) { + ProfileIOS* profile = browser_->GetProfile(); + CHECK(profile); + + sessions::RestoreIOSLiveTab live_tab(storage.navigation()); + IOSChromeTabRestoreServiceFactory::GetForProfile(profile) + ->CreateHistoricalTab(&live_tab, index); +} + +void IOSChromeTabRestoreBrowserAgent::WebStateListWillChange( + WebStateList* web_state_list, + const WebStateListChangeDetach& detach_change, + const WebStateListStatus& status) { + // Do not record history if the tabs is simply detached (i.e. moved + // from between Browser) or if it is closed due to tabs cleanup. + if (!detach_change.is_closing() || detach_change.is_tabs_cleanup()) { + return; + } + + RecordHistoryForWebState(detach_change.detached_from_index(), + detach_change.detached_web_state()); +}
diff --git a/ios/chrome/browser/shared/ui/table_view/cells/table_view_url_item.h b/ios/chrome/browser/shared/ui/table_view/cells/table_view_url_item.h index 202c9b5..dfdc727 100644 --- a/ios/chrome/browser/shared/ui/table_view/cells/table_view_url_item.h +++ b/ios/chrome/browser/shared/ui/table_view/cells/table_view_url_item.h
@@ -96,6 +96,10 @@ // Sets the background color for the favicon container view. - (void)setFaviconContainerBackgroundColor:(UIColor*)backgroundColor; +// Replaces the favicon with a custom symbol associated with the given +// `symbolName`. `symbolName` needs to be a valid name for an existing resource. +- (void)replaceFaviconWithSymbol:(NSString*)symbolName; + @end #endif // IOS_CHROME_BROWSER_SHARED_UI_TABLE_VIEW_CELLS_TABLE_VIEW_URL_ITEM_H_
diff --git a/ios/chrome/browser/shared/ui/table_view/cells/table_view_url_item.mm b/ios/chrome/browser/shared/ui/table_view/cells/table_view_url_item.mm index 8b83494..0e8fc6a 100644 --- a/ios/chrome/browser/shared/ui/table_view/cells/table_view_url_item.mm +++ b/ios/chrome/browser/shared/ui/table_view/cells/table_view_url_item.mm
@@ -9,6 +9,7 @@ #import "components/url_formatter/elide_url.h" #import "ios/chrome/browser/net/model/crurl.h" #import "ios/chrome/browser/shared/public/features/features.h" +#import "ios/chrome/browser/shared/ui/symbols/symbols.h" #import "ios/chrome/browser/shared/ui/table_view/legacy_chrome_table_view_styler.h" #import "ios/chrome/browser/shared/ui/util/uikit_ui_util.h" #import "ios/chrome/common/ui/colors/semantic_color_names.h" @@ -19,11 +20,17 @@ #import "ios/chrome/common/ui/util/constraints_ui_util.h" namespace { + // Default delimiter to use between the hostname and the supplemental URL text // if text is specified but not the delimiter. const char kDefaultSupplementalURLTextDelimiter[] = "•"; + // The max number of lines for the cell title label. const int kMaxNumberOfLinesForCellTitleLabel = 2; + +// Point size for the symbol that's replacing the cell favicon. +constexpr CGFloat kFaviconReplacementSymbolPointSize = 18; + } // namespace #pragma mark - TableViewURLItem @@ -150,6 +157,9 @@ // Constraint defining the distance between the metadata label and the // metadata image views. NSLayoutConstraint* _metadataViewsSpacingConstraint; + // UIImageView for the symbol replacing the favicon. Stays nil if no + // replacement symbol is ever set. + UIImageView* _faviconReplacementSymbolImageView; } - (instancetype)initWithStyle:(UITableViewCellStyle)style @@ -344,6 +354,8 @@ self.metadataImage.image = nil; self.URLLabel.hidden = YES; self.thirdRowLabel.hidden = YES; + [_faviconReplacementSymbolImageView removeFromSuperview]; + _faviconReplacementSymbolImageView = nil; } - (void)setAccessibilityLabel:(NSString*)accessibilityLabel { @@ -418,4 +430,33 @@ self.activityIndicatorView = nil; } +- (void)replaceFaviconWithSymbol:(NSString*)symbolName { + if (!symbolName) { + return; + } + + // Make sure the activity indicator isn't running. + [self stopAnimatingActivityIndicator]; + + UIImage* symbol = + SymbolWithPalette(DefaultSymbolWithPointSize( + symbolName, kFaviconReplacementSymbolPointSize), + @[ [UIColor colorNamed:kTextPrimaryColor] ]); + symbol.accessibilityIdentifier = symbolName; + UIImageView* symbolImageView = [[UIImageView alloc] initWithImage:symbol]; + symbolImageView.translatesAutoresizingMaskIntoConstraints = NO; + symbolImageView.backgroundColor = self.backgroundColor; + + [self setFaviconContainerBackgroundColor:self.backgroundColor]; + [self.faviconContainerView addSubview:symbolImageView]; + [NSLayoutConstraint activateConstraints:@[ + [symbolImageView.centerXAnchor + constraintEqualToAnchor:self.faviconContainerView.centerXAnchor], + [symbolImageView.centerYAnchor + constraintEqualToAnchor:self.faviconContainerView.centerYAnchor], + ]]; + + _faviconReplacementSymbolImageView = symbolImageView; +} + @end
diff --git a/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/grid/BUILD.gn b/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/grid/BUILD.gn index 8cfce8a..5e0429a0 100644 --- a/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/grid/BUILD.gn +++ b/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/grid/BUILD.gn
@@ -445,7 +445,6 @@ "//ios/chrome/browser/tab_insertion/model", "//ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/toolbars/test:fakes", "//ios/chrome/browser/tab_switcher/ui_bundled/test:fakes", - "//ios/chrome/browser/tabs/model", "//ios/chrome/browser/tips_manager/model:factory", "//ios/chrome/browser/url_loading/model", "//ios/chrome/browser/url_loading/model:test_support",
diff --git a/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/grid/grid_mediator_test.mm b/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/grid/grid_mediator_test.mm index 7bbf3f8..bfe2cd8d 100644 --- a/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/grid/grid_mediator_test.mm +++ b/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/grid/grid_mediator_test.mm
@@ -40,7 +40,6 @@ #import "ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/grid/base_grid_mediator.h" #import "ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/toolbars/test/fake_tab_grid_toolbars_mediator.h" #import "ios/chrome/browser/tab_switcher/ui_bundled/test/fake_tab_collection_consumer.h" -#import "ios/chrome/browser/tabs/model/closing_web_state_observer_browser_agent.h" #import "ios/chrome/browser/tips_manager/model/tips_manager_ios_factory.h" #import "ios/chrome/browser/url_loading/model/fake_url_loading_delegate.h" #import "ios/chrome/browser/url_loading/model/scene_url_loading_service.h" @@ -151,7 +150,6 @@ url_loading_delegate_ = [[FakeURLLoadingDelegate alloc] init]; WebUsageEnablerBrowserAgent::CreateForBrowser(browser_.get()); - ClosingWebStateObserverBrowserAgent::CreateForBrowser(browser_.get()); SnapshotBrowserAgent::CreateForBrowser(browser_.get()); SnapshotBrowserAgent::FromBrowser(browser_.get())->SetSessionID(kIdentifier);
diff --git a/ios/chrome/browser/tabs/model/closing_web_state_observer_browser_agent.h b/ios/chrome/browser/tabs/model/closing_web_state_observer_browser_agent.h index 7353a4ae..b8e5556 100644 --- a/ios/chrome/browser/tabs/model/closing_web_state_observer_browser_agent.h +++ b/ios/chrome/browser/tabs/model/closing_web_state_observer_browser_agent.h
@@ -5,26 +5,15 @@ #ifndef IOS_CHROME_BROWSER_TABS_MODEL_CLOSING_WEB_STATE_OBSERVER_BROWSER_AGENT_H_ #define IOS_CHROME_BROWSER_TABS_MODEL_CLOSING_WEB_STATE_OBSERVER_BROWSER_AGENT_H_ -#import "base/memory/raw_ptr.h" -#import "base/memory/weak_ptr.h" -#import "ios/chrome/browser/shared/model/browser/browser_observer.h" +#import "base/scoped_observation.h" #import "ios/chrome/browser/shared/model/browser/browser_user_data.h" #import "ios/chrome/browser/shared/model/web_state_list/web_state_list_observer_bridge.h" -namespace web::proto { -class WebStateStorage; -} - -// A browser agent that is responsible for handling WebStateList -// events about closing WebState, like requesting deletion of the current page -// snapshot from disk and memory. This class also records of history for -// non-incognito Browser's WebStates. +// A browser agent that record the IOS.ClosedTabIsAboutBlank histogram. class ClosingWebStateObserverBrowserAgent - : public BrowserObserver, - public BrowserUserData<ClosingWebStateObserverBrowserAgent>, + : public BrowserUserData<ClosingWebStateObserverBrowserAgent>, public WebStateListObserver { public: - ClosingWebStateObserverBrowserAgent(); ~ClosingWebStateObserverBrowserAgent() override; private: @@ -32,27 +21,14 @@ explicit ClosingWebStateObserverBrowserAgent(Browser* browser); - // Records history for a given non-incognito WebState and does not record - // history if the tab has no navigation or has only presented the NTP or the - // bookmark UI. - void RecordHistoryForWebStateAtIndex(web::WebState* web_state, int index); - - // Records history for a given unrealized WebState after loading its state - // from storage. - void RecordHistoryFromStorage(int index, web::proto::WebStateStorage storage); - - // BrowserObserver methods. - void BrowserDestroyed(Browser* browser) override; - // WebStateListObserver implementation. - void WebStateListWillChange(WebStateList* web_state_list, - const WebStateListChangeDetach& detach_change, - const WebStateListStatus& status) override; void WebStateListDidChange(WebStateList* web_state_list, const WebStateListChange& change, const WebStateListStatus& status) override; - base::WeakPtrFactory<ClosingWebStateObserverBrowserAgent> weak_ptr_factory_{ - this}; + // Observation of the Browser's WebStateList. + base::ScopedObservation<WebStateList, WebStateListObserver> + web_state_list_observation_{this}; }; + #endif // IOS_CHROME_BROWSER_TABS_MODEL_CLOSING_WEB_STATE_OBSERVER_BROWSER_AGENT_H_
diff --git a/ios/chrome/browser/tabs/model/closing_web_state_observer_browser_agent.mm b/ios/chrome/browser/tabs/model/closing_web_state_observer_browser_agent.mm index 4a56c743..b8d7f6b5 100644 --- a/ios/chrome/browser/tabs/model/closing_web_state_observer_browser_agent.mm +++ b/ios/chrome/browser/tabs/model/closing_web_state_observer_browser_agent.mm
@@ -5,100 +5,19 @@ #import "ios/chrome/browser/tabs/model/closing_web_state_observer_browser_agent.h" #import "base/metrics/histogram_macros.h" -#import "components/sessions/core/tab_restore_service.h" -#import "components/sessions/ios/ios_restore_live_tab.h" -#import "components/sessions/ios/ios_webstate_live_tab.h" -#import "ios/chrome/browser/sessions/model/ios_chrome_tab_restore_service_factory.h" -#import "ios/chrome/browser/sessions/model/session_restoration_service.h" -#import "ios/chrome/browser/sessions/model/session_restoration_service_factory.h" #import "ios/chrome/browser/shared/model/profile/profile_ios.h" -#import "ios/chrome/browser/shared/model/url/chrome_url_constants.h" #import "ios/chrome/browser/shared/model/web_state_list/web_state_list.h" -#import "ios/web/public/navigation/navigation_item.h" -#import "ios/web/public/navigation/navigation_manager.h" -#import "ios/web/public/session/proto/navigation.pb.h" -#import "ios/web/public/session/proto/storage.pb.h" #import "ios/web/public/web_state.h" #import "url/gurl.h" +ClosingWebStateObserverBrowserAgent::~ClosingWebStateObserverBrowserAgent() = + default; + ClosingWebStateObserverBrowserAgent::ClosingWebStateObserverBrowserAgent( Browser* browser) : BrowserUserData(browser) { DCHECK(!browser_->GetProfile()->IsOffTheRecord()); - browser_->AddObserver(this); - browser_->GetWebStateList()->AddObserver(this); -} - -ClosingWebStateObserverBrowserAgent::~ClosingWebStateObserverBrowserAgent() {} - -#pragma mark - Private methods - -void ClosingWebStateObserverBrowserAgent::RecordHistoryForWebStateAtIndex( - web::WebState* web_state, - int index) { - // No need to record history if the tab has no navigation or has only - // presented the NTP or the bookmark UI. - if (web_state->GetNavigationItemCount() <= 1) { - const GURL& last_committed_url = web_state->GetLastCommittedURL(); - if (!last_committed_url.is_valid() || - (last_committed_url.host_piece() == kChromeUINewTabHost)) { - return; - } - } - - // If the WebState is unrealized, ask the SessionRestorationService to load - // the data from storage (it should exists otherwise the WebState could not - // transition to the realized state). - if (!web_state->IsRealized()) { - ProfileIOS* profile = browser_->GetProfile(); - SessionRestorationServiceFactory::GetForProfile(profile) - ->LoadWebStateStorage( - browser_, web_state, - base::BindOnce( - &ClosingWebStateObserverBrowserAgent::RecordHistoryFromStorage, - weak_ptr_factory_.GetWeakPtr(), index)); - return; - } - - IOSChromeTabRestoreServiceFactory::GetForProfile(browser_->GetProfile()) - ->CreateHistoricalTab( - sessions::IOSWebStateLiveTab::GetForWebState(web_state), index); -} - -void ClosingWebStateObserverBrowserAgent::RecordHistoryFromStorage( - int index, - web::proto::WebStateStorage storage) { - sessions::RestoreIOSLiveTab live_tab(storage.navigation()); - IOSChromeTabRestoreServiceFactory::GetForProfile(browser_->GetProfile()) - ->CreateHistoricalTab(&live_tab, index); -} - -#pragma mark - BrowserObserver - -void ClosingWebStateObserverBrowserAgent::BrowserDestroyed(Browser* browser) { - DCHECK_EQ(browser, browser_.get()); - // Prevent any posted callbacks to be invoked. - weak_ptr_factory_.InvalidateWeakPtrs(); - - browser_->RemoveObserver(this); - browser_->GetWebStateList()->RemoveObserver(this); -} - -#pragma mark - WebStateListObserving - -void ClosingWebStateObserverBrowserAgent::WebStateListWillChange( - WebStateList* web_state_list, - const WebStateListChangeDetach& detach_change, - const WebStateListStatus& status) { - if (!detach_change.is_closing()) { - return; - } - - web::WebState* detached_web_state = detach_change.detached_web_state(); - if (!detach_change.is_tabs_cleanup()) { - RecordHistoryForWebStateAtIndex(detached_web_state, - detach_change.detached_from_index()); - } + web_state_list_observation_.Observe(browser_->GetWebStateList()); } void ClosingWebStateObserverBrowserAgent::WebStateListDidChange( @@ -113,7 +32,7 @@ const WebStateListChangeDetach& detach_change = change.As<WebStateListChangeDetach>(); web::WebState* detached_web_state = detach_change.detached_web_state(); - GURL url = detached_web_state->GetLastCommittedURL(); + const GURL& url = detached_web_state->GetLastCommittedURL(); UMA_HISTOGRAM_BOOLEAN("IOS.ClosedTabIsAboutBlank", url.IsAboutBlank()); break; }
diff --git a/ios/chrome/browser/tabs_search/model/BUILD.gn b/ios/chrome/browser/tabs_search/model/BUILD.gn index 37544be..cb8e021 100644 --- a/ios/chrome/browser/tabs_search/model/BUILD.gn +++ b/ios/chrome/browser/tabs_search/model/BUILD.gn
@@ -57,7 +57,6 @@ "//ios/chrome/browser/shared/model/browser/test:test_support", "//ios/chrome/browser/shared/model/profile/test", "//ios/chrome/browser/shared/model/web_state_list", - "//ios/chrome/browser/tabs/model", "//ios/chrome/test:test_support", "//ios/web/public/test", "//ios/web/public/test/fakes",
diff --git a/ios/chrome/browser/tabs_search/model/tabs_search_service_unittest.mm b/ios/chrome/browser/tabs_search/model/tabs_search_service_unittest.mm index c10d7c6..1a8b283 100644 --- a/ios/chrome/browser/tabs_search/model/tabs_search_service_unittest.mm +++ b/ios/chrome/browser/tabs_search/model/tabs_search_service_unittest.mm
@@ -12,6 +12,7 @@ #import "base/strings/utf_string_conversions.h" #import "components/sessions/core/tab_restore_service_impl.h" #import "ios/chrome/browser/history/model/history_service_factory.h" +#import "ios/chrome/browser/sessions/model/ios_chrome_tab_restore_browser_agent.h" #import "ios/chrome/browser/sessions/model/ios_chrome_tab_restore_service_factory.h" #import "ios/chrome/browser/shared/model/browser/browser_list.h" #import "ios/chrome/browser/shared/model/browser/browser_list_factory.h" @@ -20,7 +21,6 @@ #import "ios/chrome/browser/shared/model/profile/test/test_profile_manager_ios.h" #import "ios/chrome/browser/shared/model/web_state_list/web_state_list.h" #import "ios/chrome/browser/shared/model/web_state_list/web_state_opener.h" -#import "ios/chrome/browser/tabs/model/closing_web_state_observer_browser_agent.h" #import "ios/chrome/browser/tabs_search/model/tabs_search_service_factory.h" #import "ios/chrome/test/ios_chrome_scoped_testing_local_state.h" #import "ios/web/public/test/fakes/fake_navigation_manager.h" @@ -68,7 +68,7 @@ browser_list_ = BrowserListFactory::GetForProfile(profile_.get()); browser_ = std::make_unique<TestBrowser>(profile_.get()); - ClosingWebStateObserverBrowserAgent::CreateForBrowser(browser_.get()); + IOSChromeTabRestoreBrowserAgent::CreateForBrowser(browser_.get()); browser_list_->AddBrowser(browser_.get());
diff --git a/ios/chrome/common/app_group/app_group_constants.h b/ios/chrome/common/app_group/app_group_constants.h index bf1a689..768f459 100644 --- a/ios/chrome/common/app_group/app_group_constants.h +++ b/ios/chrome/common/app_group/app_group_constants.h
@@ -58,6 +58,9 @@ // links in chrome. extern NSString* const kChromeSupportOpenLinksParametersFromCapability; +// Share default browser promo status capability. +extern NSString* const kChromeSupportShareDefaultBrowserStatusCapability; + // The x-callback-url indicating that an application in the group requires a // command. extern const char kChromeAppGroupXCallbackCommand[];
diff --git a/ios/chrome/common/app_group/app_group_constants.mm b/ios/chrome/common/app_group/app_group_constants.mm index bd518be..2ab3d012 100644 --- a/ios/chrome/common/app_group/app_group_constants.mm +++ b/ios/chrome/common/app_group/app_group_constants.mm
@@ -19,6 +19,8 @@ @"ShowDefaultBrowserPromo"; extern NSString* const kChromeSupportOpenLinksParametersFromCapability = @"SupportOpenLinksParametersFrom"; +extern NSString* const kChromeSupportShareDefaultBrowserStatusCapability = + @"SupportShareDefaultBrowserStatus"; const char kChromeAppGroupXCallbackCommand[] = "app-group-command";
diff --git a/ios/testing/data/http_server_files/full_address_form.html b/ios/testing/data/http_server_files/full_address_form.html index bfedfb1..74e76a1 100644 --- a/ios/testing/data/http_server_files/full_address_form.html +++ b/ios/testing/data/http_server_files/full_address_form.html
@@ -11,8 +11,10 @@ parameters: * preventDefault: When set, will use the form submission variant that prevents default for form submission. You only need to put the key, no value needed. - * redirectWhenDefaultPrevented: When set, will redirect to another page when - the form submission is preventDefault()ed. + * redirectWhenSubmissionPrevented: When set, will redirect to another page when + the form submission is prevented via the available methods. + * stopImmediatePropagation: When set, will stop the propagation of the form + submit event in any direction. --> <!DOCTYPE html> @@ -48,17 +50,29 @@ const queryParams = Object.fromEntries( new URLSearchParams(window.location.search)); + const preventDefault = queryParams.hasOwnProperty('preventDefault'); + const stopImmediatePropagation = queryParams.hasOwnProperty('stopImmediatePropagation'); + const redirectWhenSubmissionPrevented = queryParams.hasOwnProperty('redirectWhenSubmissionPrevented') + // Use the variant that prevents default submission if specified in the // URL query. - if (queryParams.hasOwnProperty('preventDefault')) { - // Add a "submit" event listener that takes over submission and prevents - // the browser from handling submission through the regular flow. + if (preventDefault || stopImmediatePropagation) { + // Add a "submit" event listener that takes over submission and could + // prevent the browser from handling submission through the regular flow. const form = document.forms[0]; form.addEventListener('submit', (e) => { - // Prevent default for other listeners so the the Autofill listener will - // read the event with the defaultPrevented bit set to true. - e.preventDefault(); - if (queryParams.hasOwnProperty('redirectWhenDefaultPrevented')) { + if (preventDefault) { + // Prevent default for other listeners so the the Autofill listener + // will read the event with the defaultPrevented bit set to true. + e.preventDefault(); + } + if (stopImmediatePropagation) { + // Stop propagation for any other listener that follows up this one, + // regardless of how they are situated in the DOM which defacto + // includes the Autofill listener if it is not set in capture mode. + e.stopImmediatePropagation(); + } + if (redirectWhenSubmissionPrevented) { // Emulate a post-submit navigation that happens slightly after // propagating the "submit" event, when enabled. setTimeout(() => window.location = '/destination.html', 10);
diff --git a/ios/web/download/download_task_impl.mm b/ios/web/download/download_task_impl.mm index 9b686833..69ab158 100644 --- a/ios/web/download/download_task_impl.mm +++ b/ios/web/download/download_task_impl.mm
@@ -275,7 +275,7 @@ return net::GenerateFileName(original_url_, content_disposition_, /*referrer_charset=*/std::string(), /*suggested_name=*/GetSuggestedName(), - /*mime_type=*/std::string(), + /*mime_type=*/mime_type_, /*default_name=*/"document"); }
diff --git a/ios/web/download/download_task_impl_unittest.mm b/ios/web/download/download_task_impl_unittest.mm index 4e03f7da49..c8f15a35 100644 --- a/ios/web/download/download_task_impl_unittest.mm +++ b/ios/web/download/download_task_impl_unittest.mm
@@ -29,6 +29,10 @@ const char kContentDisposition[] = "attachment; filename=file.test"; const char kMimeType[] = "application/pdf"; const base::FilePath::CharType kTestFileName[] = FILE_PATH_LITERAL("file.test"); +const base::FilePath::CharType kNoExtensionFileName[] = + FILE_PATH_LITERAL("file"); +const base::FilePath::CharType kWithExtensionFileName[] = + FILE_PATH_LITERAL("file.pdf"); NSString* const kHttpMethod = @"POST"; } // namespace @@ -123,4 +127,18 @@ EXPECT_EQ(kUrlRedirected, task_->GetRedirectedUrl()); } +// Tests DownloadTaskImpl GenerateFileName with no extension and no content +// disposition. +TEST_F(DownloadTaskImplTest, GenerateFileNameTest) { + task_ = std::make_unique<FakeDownloadTaskImpl>( + &web_state_, GURL(std::string(kUrl) + kNoExtensionFileName), + kOrigninatingHost, kHttpMethod, "", + /*total_bytes=*/-1, kMimeType, [[NSUUID UUID] UUIDString], + base::ThreadPool::CreateSequencedTaskRunner( + {base::MayBlock(), base::TaskPriority::USER_BLOCKING})); + EXPECT_EQ(kMimeType, task_->GetMimeType()); + EXPECT_EQ(kMimeType, task_->GetOriginalMimeType()); + EXPECT_EQ(base::FilePath(kWithExtensionFileName), task_->GenerateFileName()); +} + } // namespace web
diff --git a/ios_internal b/ios_internal index dda9885..a1191d4 160000 --- a/ios_internal +++ b/ios_internal
@@ -1 +1 @@ -Subproject commit dda9885a588fbcec1566158cdb2b401a374a989b +Subproject commit a1191d44f93cda2981ea440a89ff41690d354fe6
diff --git a/ipc/ipc_channel.h b/ipc/ipc_channel.h index 838f0d8..4addd6c 100644 --- a/ipc/ipc_channel.h +++ b/ipc/ipc_channel.h
@@ -41,8 +41,8 @@ // http://www.chromium.org/developers/design-documents/inter-process-communication // for overview of IPC in Chromium. -// Channels are implemented using mojo message pipes on all platforms other -// than NaCl. +// Channels are implemented using mojo message pipes (via IPC::ChannelMojo) on +// all platforms other than NaCl. class COMPONENT_EXPORT(IPC) Channel : public Sender { // Security tests need access to the pipe handle.
diff --git a/ipc/ipc_channel_mojo.h b/ipc/ipc_channel_mojo.h index 00a873ff..34505e1f 100644 --- a/ipc/ipc_channel_mojo.h +++ b/ipc/ipc_channel_mojo.h
@@ -35,10 +35,6 @@ // ChannelMojo builds a Mojo MessagePipe using the provided message pipe // |handle| and builds an associated interface for each direction on the // channel. -// -// TODO(morrita): Add APIs to create extra MessagePipes to let -// Mojo-based objects talk over this Channel. -// class COMPONENT_EXPORT(IPC) ChannelMojo : public Channel, public Channel::AssociatedInterfaceSupport,
diff --git a/media/base/media_switches.cc b/media/base/media_switches.cc index 115bbdb..1c96b4b 100644 --- a/media/base/media_switches.cc +++ b/media/base/media_switches.cc
@@ -653,6 +653,15 @@ BASE_FEATURE(kFileDialogsBlockPictureInPicture, "FileDialogsBlockPictureInPicture", base::FEATURE_DISABLED_BY_DEFAULT); + +// Tucks picture-in-picture windows while file dialogs are open. +BASE_FEATURE(kFileDialogsTuckPictureInPicture, + "FileDialogsTuckPictureInPicture", +#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) + base::FEATURE_ENABLED_BY_DEFAULT); +#else + base::FEATURE_DISABLED_BY_DEFAULT); +#endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) #endif // !BUILDFLAG(IS_ANDROID) // Show toolbar button that opens dialog for controlling media sessions.
diff --git a/media/base/media_switches.h b/media/base/media_switches.h index 45222f1..bfa1dbe 100644 --- a/media/base/media_switches.h +++ b/media/base/media_switches.h
@@ -258,6 +258,7 @@ MEDIA_EXPORT BASE_DECLARE_FEATURE(kFeatureManagementLiveTranslateCrOS); #if !BUILDFLAG(IS_ANDROID) MEDIA_EXPORT BASE_DECLARE_FEATURE(kFileDialogsBlockPictureInPicture); +MEDIA_EXPORT BASE_DECLARE_FEATURE(kFileDialogsTuckPictureInPicture); #endif // !BUILDFLAG(IS_ANDROID) MEDIA_EXPORT BASE_DECLARE_FEATURE(kGetDisplayMediaConfersActivation); MEDIA_EXPORT BASE_DECLARE_FEATURE(kGlobalMediaControls);
diff --git a/media/mojo/services/media_foundation_service.cc b/media/mojo/services/media_foundation_service.cc index ab5fdd0..f7dde8c 100644 --- a/media/mojo/services/media_foundation_service.cc +++ b/media/mojo/services/media_foundation_service.cc
@@ -245,19 +245,6 @@ /*offsets=*/nullptr); } -// This function checks if clear lead is supported for the codec. -bool IsClearLeadSupported(VideoCodec video_codec, - IsTypeSupportedCallback is_type_supported_cb) { - const FeatureMap extra_features = { - {kEncryptionSchemeQueryName, kClearLeadEncryptionScheme}, - {kEncryptionIvQueryName, - base::NumberToString(GetIvSize(EncryptionScheme::kCenc))}}; - - std::string content_type = - GetTypeString(video_codec, /*audio_codec=*/std::nullopt, extra_features); - return is_type_supported_cb.Run(/*is_hw_secure=*/true, content_type); -} - base::flat_set<EncryptionScheme> GetSupportedEncryptionSchemes( bool is_hw_secure, VideoCodec video_codec, @@ -371,7 +358,6 @@ FeatureMap extra_features = {}; if (!is_os_cdm) { - // TODO(hmchen): make this generic for more key systems. robustness = is_hw_secure ? kHwSecureRobustness : kSwSecureRobustness; // encryption-robustness is not a supported for PlayReady key systems. @@ -380,6 +366,29 @@ CdmCapability capability; + // Check for clear lead support for hardware security and OS CDMs, as we + // only support codecs that support clear lead for OS CDMs in HW security. + // Software security always supports clear lead, and non OS CDMs for + // hardware security always does NOT support clear lead. + // For Audio Codecs: + // The contract of the API is such that the encryption scheme is applied + // to both audio and video. In terms of the current implementation, the + // encryption type is essentially ignored for audio, but that's because + // all encryption types should be supported for audio. + // `cenc-clearlead` and `cenc` are equivalent for audio in all cases. + // Software vs Hardware Clearlead Codec Enforcement: + // SWDRM and HWDRM are enforced the same for cenc-clearlead checking, + // which can cause issues since clear lead should always be supported + // for SWDRM. So for the OS_CDM, if the CDM is software secure, do not + // pass in the cenc-clearlead because the codec checking might result in + // an unsupported value, which is an oversight in the current PR impl. + if (is_hw_secure && is_os_cdm) { + extra_features.insert( + {{kEncryptionSchemeQueryName, kClearLeadEncryptionScheme}, + {kEncryptionIvQueryName, + base::NumberToString(GetIvSize(EncryptionScheme::kCenc))}}); + } + // Query video codecs. for (const auto video_codec : kAllVideoCodecs) { #if BUILDFLAG(ENABLE_PLATFORM_HEVC) @@ -417,18 +426,12 @@ // assume all relevant profiles are supported. VideoCodecInfo video_codec_info; - // Only check for clear lead support for hardware security and OS CDMs. - // Software security always supports clear lead, and non OS CDMs for - // hardware security always does NOT support clear lead. - // When IsClearLeadSupported returns false, this can either happen - // because: 1. The OS doesn't support the check of cenc-clearlead - // yet or 2. Clear Lead fix for `video_codec` is not available. - video_codec_info.supports_clear_lead = - is_hw_secure - ? (is_os_cdm - ? IsClearLeadSupported(video_codec, is_type_supported_cb) - : false) - : true; + // Software security always supports clear lead. + // Non-OS CDMs for hardware security always do NOT support clear lead. + // For hardware secure OS CDMs, we query for clear lead support as part + // of the video codec querying, so if is_type_supported cb returns true, + // we support clear lead. + video_codec_info.supports_clear_lead = !is_hw_secure || is_os_cdm; #if BUILDFLAG(ENABLE_PLATFORM_DOLBY_VISION) // Dolby Vision on Windows only support profile 4/5/8 now. But profile 4
diff --git a/net/base/data_url.cc b/net/base/data_url.cc index eb63815..e43507e 100644 --- a/net/base/data_url.cc +++ b/net/base/data_url.cc
@@ -60,12 +60,14 @@ // Avoid copying the URL content which can be expensive for large URLs. std::string_view content = url.GetContentPiece(); - std::string_view::const_iterator comma = std::ranges::find(content, ','); - if (comma == content.end()) + std::optional<std::pair<std::string_view, std::string_view>> + media_type_and_body = base::SplitStringOnce(content, ','); + if (!media_type_and_body) { return false; + } std::vector<std::string_view> meta_data = - base::SplitStringPiece(base::MakeStringPiece(content.begin(), comma), ";", + base::SplitStringPiece(media_type_and_body->first, ";", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); // These are moved to |mime_type| and |charset| on success. @@ -126,7 +128,7 @@ // spaces itself, anyways. Should we just trim leading spaces instead? // Allowing random intermediary spaces seems unnecessary. - auto raw_body = base::MakeStringPiece(comma + 1, content.end()); + std::string_view raw_body = media_type_and_body->second; // For base64, we may have url-escaped whitespace which is not part // of the data, and should be stripped. Otherwise, the escaped whitespace
diff --git a/net/base/mime_util.cc b/net/base/mime_util.cc index d9e9d73..3e198e6 100644 --- a/net/base/mime_util.cc +++ b/net/base/mime_util.cc
@@ -547,8 +547,8 @@ if (offset == std::string::npos || type_str[offset] == ';') continue; - auto param_name = base::MakeStringPiece(type_str.begin() + param_name_start, - type_str.begin() + offset); + auto param_name = + type_str.substr(param_name_start, offset - param_name_start); // Now parse the value. DCHECK_EQ('=', type_str[offset]);
diff --git a/net/base/scheme_host_port_matcher_rule.cc b/net/base/scheme_host_port_matcher_rule.cc index 4c6a94b..0f7762e 100644 --- a/net/base/scheme_host_port_matcher_rule.cc +++ b/net/base/scheme_host_port_matcher_rule.cc
@@ -78,9 +78,8 @@ std::string::size_type pos_colon = raw.rfind(':'); port = -1; if (pos_colon != std::string::npos) { - if (!ParseInt32( - base::MakeStringPiece(raw.begin() + pos_colon + 1, raw.end()), - ParseIntFormat::NON_NEGATIVE, &port) || + if (!ParseInt32(raw.substr(pos_colon + 1), ParseIntFormat::NON_NEGATIVE, + &port) || port > 0xFFFF) { return nullptr; // Port was invalid. }
diff --git a/net/cookies/cookie_monster_unittest.cc b/net/cookies/cookie_monster_unittest.cc index 0ec825a1..3ff21bb3b 100644 --- a/net/cookies/cookie_monster_unittest.cc +++ b/net/cookies/cookie_monster_unittest.cc
@@ -549,7 +549,7 @@ int rep = 1; if (!token.empty()) { bool result = base::StringToInt( - base::MakeStringPiece(token.begin(), token.end() - 2), &rep); + std::string_view(token.begin(), token.end() - 2), &rep); DCHECK(result); } for (; rep > 0; --rep, ++next_cookie_id) { @@ -598,7 +598,7 @@ // Assuming *it is "a#=b", so extract and parse "#" portion. int id = -1; bool result = base::StringToInt( - base::MakeStringPiece(token.begin() + 1, token.end() - 2), &id); + std::string_view(token.begin() + 1, token.end() - 2), &id); DCHECK(result); DCHECK_GE(id, 0); DCHECK_LT(id, num_cookies);
diff --git a/net/cookies/cookie_util.cc b/net/cookies/cookie_util.cc index cd4d90ae..b52294e 100644 --- a/net/cookies/cookie_util.cc +++ b/net/cookies/cookie_util.cc
@@ -827,7 +827,7 @@ // Find cookie name. std::string::const_iterator cookie_name_beginning = i; while (i != header_value.end() && *i != '=') ++i; - auto cookie_name = base::MakeStringPiece(cookie_name_beginning, i); + auto cookie_name = std::string_view(cookie_name_beginning, i); // Find cookie value. std::string_view cookie_value; @@ -840,11 +840,11 @@ while (i != header_value.end() && *i != '"') ++i; if (i == header_value.end()) return; ++i; // Skip '"'. - cookie_value = base::MakeStringPiece(cookie_value_beginning, i); + cookie_value = std::string_view(cookie_value_beginning, i); // i points to character after '"', potentially a ';'. } else { while (i != header_value.end() && *i != ';') ++i; - cookie_value = base::MakeStringPiece(cookie_value_beginning, i); + cookie_value = std::string_view(cookie_value_beginning, i); // i points to ';' or end of string. } }
diff --git a/net/disk_cache/simple/simple_index_file.cc b/net/disk_cache/simple/simple_index_file.cc index b136b5d2..a44da1e 100644 --- a/net/disk_cache/simple/simple_index_file.cc +++ b/net/disk_cache/simple/simple_index_file.cc
@@ -5,6 +5,7 @@ #include "net/disk_cache/simple/simple_index_file.h" +#include <string_view> #include <utility> #include <vector> @@ -15,7 +16,6 @@ #include "base/logging.h" #include "base/numerics/safe_conversions.h" #include "base/pickle.h" -#include "base/strings/string_util.h" #include "base/task/sequenced_task_runner.h" #include "base/task/thread_pool.h" #include "base/threading/thread_restrictions.h" @@ -151,8 +151,8 @@ if (file_name.size() != kEntryFilesLength) return; - const auto hash_string = base::MakeStringPiece( - file_name.begin(), file_name.begin() + kEntryFilesHashLength); + const auto hash_string = + std::string_view(file_name).substr(0, kEntryFilesHashLength); uint64_t hash_key = 0; if (!simple_util::GetEntryHashKeyFromHexString(hash_string, &hash_key)) { LOG(WARNING) << "Invalid entry hash key filename while restoring index from"
diff --git a/net/http/http_auth_challenge_tokenizer.cc b/net/http/http_auth_challenge_tokenizer.cc index 1f7c22f..49ea7d9 100644 --- a/net/http/http_auth_challenge_tokenizer.cc +++ b/net/http/http_auth_challenge_tokenizer.cc
@@ -48,8 +48,7 @@ } // Save the scheme's position. - lower_case_scheme_ = base::ToLowerASCII( - base::MakeStringPiece(tok.token_begin(), tok.token_end())); + lower_case_scheme_ = base::ToLowerASCII(tok.token_piece()); params_ = HttpUtil::TrimLWS(std::string_view(tok.token_end(), challenge.end()));
diff --git a/net/http/http_response_headers.cc b/net/http/http_response_headers.cc index bd1782b..da4b7eb 100644 --- a/net/http/http_response_headers.cc +++ b/net/http/http_response_headers.cc
@@ -166,7 +166,7 @@ int response_code = -1; // For backwards compatibility, overlarge response codes are permitted. // base::StringToInt will clamp the value to INT_MAX. - base::StringToInt(base::MakeStringPiece(status.begin(), first_non_digit), + base::StringToInt(std::string_view(status.begin(), first_non_digit), &response_code); CHECK_GE(response_code, 0);
diff --git a/net/http/http_vary_data.cc b/net/http/http_vary_data.cc index 8d06c9c..50722b8a 100644 --- a/net/http/http_vary_data.cc +++ b/net/http/http_vary_data.cc
@@ -16,12 +16,15 @@ namespace net { +crypto::obsolete::Md5 MakeMd5HasherForHttpVaryData() { + return {}; +} + HttpVaryData::HttpVaryData() = default; bool HttpVaryData::Init(const HttpRequestInfo& request_info, const HttpResponseHeaders& response_headers) { - base::MD5Context ctx; - base::MD5Init(&ctx); + auto ctx = MakeMd5HasherForHttpVaryData(); is_valid_ = false; bool processed_header = false; @@ -41,17 +44,17 @@ if (*request_header == "*") { // What's in request_digest_ will never be looked at, but make it // deterministic so we don't serialize out uninitialized memory content. - request_digest_.a.fill(0u); + request_digest_.fill(0u); return is_valid_ = true; } - AddField(request_info, *request_header, &ctx); + AddField(request_info, *request_header, ctx); processed_header = true; } if (!processed_header) return false; - base::MD5Final(&request_digest_, &ctx); + ctx.Finish(request_digest_); return is_valid_ = true; } @@ -60,7 +63,7 @@ std::optional<base::span<const uint8_t>> bytes = iter->ReadBytes(sizeof(request_digest_)); if (bytes) { - base::span(request_digest_.a).copy_from(*bytes); + base::span(request_digest_).copy_from(*bytes); return is_valid_ = true; } return false; @@ -68,7 +71,7 @@ void HttpVaryData::Persist(base::Pickle* pickle) const { DCHECK(is_valid()); - pickle->WriteBytes(request_digest_.a); + pickle->WriteBytes(request_digest_); } bool HttpVaryData::MatchesRequest( @@ -84,13 +87,13 @@ // by a build before crbug.com/469675 was fixed. return false; } - return new_vary_data.request_digest_.a == request_digest_.a; + return new_vary_data.request_digest_ == request_digest_; } // static void HttpVaryData::AddField(const HttpRequestInfo& request_info, std::string_view request_header, - base::MD5Context* ctx) { + crypto::obsolete::Md5& context) { std::string request_value = request_info.extra_headers.GetHeader(request_header) .value_or(std::string()); @@ -101,7 +104,7 @@ // For example, "foo: 12\nbar: 3" looks like "foo: 1\nbar: 23" otherwise. request_value.append(1, '\n'); - base::MD5Update(ctx, request_value); + context.Update(request_value); } } // namespace net
diff --git a/net/http/http_vary_data.h b/net/http/http_vary_data.h index b8d3ce8..b8e57f8 100644 --- a/net/http/http_vary_data.h +++ b/net/http/http_vary_data.h
@@ -7,7 +7,7 @@ #include <string_view> -#include "base/hash/md5.h" +#include "crypto/obsolete/md5.h" #include "net/base/net_export.h" namespace base { @@ -71,10 +71,10 @@ // Append to the MD5 context for the given request header. static void AddField(const HttpRequestInfo& request_info, std::string_view request_header, - base::MD5Context* context); + crypto::obsolete::Md5& context); // A digested version of the request headers corresponding to the Vary header. - base::MD5Digest request_digest_; + std::array<uint8_t, crypto::obsolete::Md5::kSize> request_digest_; // True when request_digest_ contains meaningful data. bool is_valid_ = false;
diff --git a/net/http/transport_security_state_static.pins b/net/http/transport_security_state_static.pins index 8e14d4c..2419378 100644 --- a/net/http/transport_security_state_static.pins +++ b/net/http/transport_security_state_static.pins
@@ -43,9 +43,9 @@ # hash function for preloaded entries again (we have already done so once). # -# Last updated: 2025-06-09 12:56 UTC +# Last updated: 2025-06-10 12:53 UTC PinsListTimestamp -1749473796 +1749560028 TestSPKI sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
diff --git a/net/http/transport_security_state_static_pins.json b/net/http/transport_security_state_static_pins.json index 8b715f0f..b218e3b 100644 --- a/net/http/transport_security_state_static_pins.json +++ b/net/http/transport_security_state_static_pins.json
@@ -31,7 +31,7 @@ // the 'static_spki_hashes' and 'bad_static_spki_hashes' fields in 'pinsets' // refer to, and the timestamp at which the pins list was last updated. // -// Last updated: 2025-06-09 12:56 UTC +// Last updated: 2025-06-10 12:53 UTC // { "pinsets": [
diff --git a/services/data_decoder/BUILD.gn b/services/data_decoder/BUILD.gn index f0dd371..6e94769 100644 --- a/services/data_decoder/BUILD.gn +++ b/services/data_decoder/BUILD.gn
@@ -55,6 +55,7 @@ "ble_scan_parser_impl.cc", "ble_scan_parser_impl.h", ] + deps += [ "//services/data_decoder/ble_scan_parser:parser" ] } if (use_blink) {
diff --git a/services/data_decoder/ble_scan_parser_impl.cc b/services/data_decoder/ble_scan_parser_impl.cc index b8698a0..b3c1021 100644 --- a/services/data_decoder/ble_scan_parser_impl.cc +++ b/services/data_decoder/ble_scan_parser_impl.cc
@@ -9,11 +9,17 @@ #include <vector> #include "base/containers/flat_map.h" +#include "base/feature_list.h" +#include "base/metrics/histogram_functions.h" #include "base/strings/strcat.h" #include "base/strings/string_number_conversions.h" +#include "base/strings/string_util.h" +#include "services/data_decoder/ble_scan_parser/parser.h" namespace data_decoder { +namespace { + // Definitions of the data type flags: // https://www.bluetooth.com/specifications/assigned-numbers/generic-access-profile/ constexpr uint8_t kDataTypeFlags = 0x01; @@ -32,13 +38,29 @@ constexpr char kUuidPrefix[] = "0000"; constexpr char kUuidSuffix[] = "-0000-1000-8000-00805F9B34FB"; +BASE_FEATURE(kUseRustBleScanParser, + "UseRustBleScanParser", + base::FEATURE_DISABLED_BY_DEFAULT); + +} // namespace + BleScanParserImpl::BleScanParserImpl() = default; BleScanParserImpl::~BleScanParserImpl() = default; void BleScanParserImpl::Parse(const std::vector<uint8_t>& advertisement_data, ParseCallback callback) { - std::move(callback).Run(ParseBleScan(advertisement_data)); + mojom::ScanRecordPtr result; + if (base::FeatureList::IsEnabled(kUseRustBleScanParser)) { + result = ble_scan_parser::Parse(advertisement_data); + } else { + result = ParseBleScan(advertisement_data); + } + if (result) { + base::UmaHistogramBoolean("Bluetooth.LocalNameIsUtf8", + base::IsStringUTF8(result->advertisement_name)); + } + std::move(callback).Run(std::move(result)); } mojom::ScanRecordPtr BleScanParserImpl::ParseBleScan(
diff --git a/services/network/public/cpp/BUILD.gn b/services/network/public/cpp/BUILD.gn index 5b66798..053631dd 100644 --- a/services/network/public/cpp/BUILD.gn +++ b/services/network/public/cpp/BUILD.gn
@@ -454,6 +454,29 @@ defines = [ "IS_NETWORK_CPP_DOCUMENT_ISOLATION_IMPL" ] } +source_set("ip_address_space_overrides_test_utils") { + testonly = true + + sources = [ + "ip_address_space_overrides_test_utils.cc", + "ip_address_space_overrides_test_utils.h", + ] + + public_deps = [ + "//base", + "//services/network/public/mojom:mojom_ip_address_shared", + ] + + deps = [ + ":cpp", + ":flags_and_switches", + "//base", + "//net:test_support", + ] + + configs += [ "//build/config/compiler:wexit_time_destructors" ] +} + component("shared_storage_support") { sources = [ "shared_storage_mojom_traits.cc",
diff --git a/services/network/public/cpp/ip_address_space_overrides_test_utils.cc b/services/network/public/cpp/ip_address_space_overrides_test_utils.cc new file mode 100644 index 0000000..da14353 --- /dev/null +++ b/services/network/public/cpp/ip_address_space_overrides_test_utils.cc
@@ -0,0 +1,42 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "services/network/public/cpp/ip_address_space_overrides_test_utils.h" + +#include "base/check.h" +#include "base/command_line.h" +#include "base/strings/strcat.h" +#include "base/strings/string_util.h" +#include "net/test/embedded_test_server/embedded_test_server.h" +#include "services/network/public/cpp/ip_address_space_util.h" +#include "services/network/public/cpp/network_switches.h" +#include "services/network/public/mojom/ip_address_space.mojom.h" + +namespace network { + +void AddPublicIpAddressSpaceOverrideToCommandLine( + const net::test_server::EmbeddedTestServer& server, + base::CommandLine& command_line) { + CHECK(server.Started()); + AddIpAddressSpaceOverridesToCommandLine( + {GenerateIpAddressSpaceOverride(server, mojom::IPAddressSpace::kPublic)}, + command_line); +} + +void AddIpAddressSpaceOverridesToCommandLine( + base::span<const std::string> parts, + base::CommandLine& command_line) { + command_line.AppendSwitchASCII(network::switches::kIpAddressSpaceOverrides, + base::JoinString(parts, ",")); +} + +std::string GenerateIpAddressSpaceOverride( + const net::test_server::EmbeddedTestServer& server, + mojom::IPAddressSpace space) { + CHECK(server.Started()); + return base::StrCat({server.host_port_pair().ToString(), "=", + IPAddressSpaceToStringPiece(space)}); +} + +} // namespace network
diff --git a/services/network/public/cpp/ip_address_space_overrides_test_utils.h b/services/network/public/cpp/ip_address_space_overrides_test_utils.h new file mode 100644 index 0000000..7c46e970 --- /dev/null +++ b/services/network/public/cpp/ip_address_space_overrides_test_utils.h
@@ -0,0 +1,84 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef SERVICES_NETWORK_PUBLIC_CPP_IP_ADDRESS_SPACE_OVERRIDES_TEST_UTILS_H_ +#define SERVICES_NETWORK_PUBLIC_CPP_IP_ADDRESS_SPACE_OVERRIDES_TEST_UTILS_H_ + +#include <string> + +#include "base/containers/span.h" +#include "services/network/public/mojom/ip_address_space.mojom.h" + +namespace base { +class CommandLine; +} + +namespace net::test_server { +class EmbeddedTestServer; +} + +namespace network { + +// These functions are all helper functions to make addition of IP Address Space +// overrides for net::test_server::EmbeddedTestServers easier. +// +// IP Address Space overrides are needed for EmbeddedTestServers that are the +// targets of web requests that are considered Local Network Access (LNA). LNA +// requests are those where the requesting page is more public than the resource +// that is being requested. Since most EmbeddedTestServers are run on 127.0.0.1, +// this can catch many browser tests. For more background, see the comment for +// kIpAddressSpaceOverrides in services/network/public/cpp/network_switches.cc. +// +// Most calls will look something this: +// +// network::AddPublicIpAddressSpaceOverrideToCommandLine( +// embedded_test_server, command_line); +// +// which will mark all requests to embedded_test_server in the kPublic address +// space. +// +// If you have multiple servers, this might look like the following: +// +// network::AddIpAddressSpaceOverridesToCommandLine( +// {network::GenerateIpAddressSpaceOverride(embedded_server_1), +// network::GenerateIpAddressSpaceOverride( +// embedded_server_2, network::mojom::IPAddressSpace::kLocal)}, +// command_line); +// +// All net::test_server::EmbeddedTestServers passed in must have their ports +// assigned. This can be done by calling either +// EmbeddedTestServer::InitializeAndListen() or EmbeddedTestServer::Start() +// before calling the below functions. + +// Ensures resources hosted by the server are treated as in the public IP +// Address Space by LNA, using the network::switches::kIpAddressSpaceOverrides +// command line switch. +// +// This appends to command_line, and will overwrite any previous overrides added +// to the command_line. +void AddPublicIpAddressSpaceOverrideToCommandLine( + const net::test_server::EmbeddedTestServer& server, + base::CommandLine& command_line); + +// Appends IP Address Space overrides to the command line using the +// the network::switches::kIpAddressSpaceOverrides command line switch. Will +// overwrite any other IP Address Space overrides already applied. +// +// This is commonly used in conjunction with GenerateIpAddressSpaceOverride(). +void AddIpAddressSpaceOverridesToCommandLine( + base::span<const std::string> parts, + base::CommandLine& command_line); + +// Generates an IP Address space override part indicating that resources hosted +// by the server are in the specified IP Address Space. +// +// This is commonly used in conjunction with +// AddIpAddressSpaceOverridesToCommandLine(). +std::string GenerateIpAddressSpaceOverride( + const net::test_server::EmbeddedTestServer& server, + mojom::IPAddressSpace space = mojom::IPAddressSpace::kPublic); + +} // namespace network + +#endif // SERVICES_NETWORK_PUBLIC_CPP_IP_ADDRESS_SPACE_OVERRIDES_TEST_UTILS_H_
diff --git a/services/viz/public/mojom/compositing/layer.mojom b/services/viz/public/mojom/compositing/layer.mojom index a1186f7..537c6964 100644 --- a/services/viz/public/mojom/compositing/layer.mojom +++ b/services/viz/public/mojom/compositing/layer.mojom
@@ -94,6 +94,17 @@ TransferableResource? transferable_resource; }; +// Extra fields in a cc::TileDisplayLayerImpl that has been added to a tree or +// modified in some interesting way since a prior tree update. +struct TileDisplayLayerExtra { + // Optional field that will be set if this Layer is a PictureLayer that is + // actually a solid color. + skia.mojom.SkColor4f? solid_color; + + // Will be set to true for PictureLayers that are backdrop filter masks. + bool is_backdrop_filter_mask; +}; + // Extra fields in a cc::ScrollbarLayerImplBase that has been added // to a tree or modified in some interesting way since a prior tree update. struct ScrollbarLayerBaseExtra { @@ -188,6 +199,8 @@ SurfaceLayerExtra surface_layer_extra; // Extra properties that are specific to TextureLayerImpl. TextureLayerExtra texture_layer_extra; + // Extra properties that are specific to TileDisplayLayerImpl. + TileDisplayLayerExtra tile_display_layer_extra; // Extra properties that are specific to ViewTransitionContentLayerImpl. ViewTransitionContentLayerExtra view_transition_content_layer_extra; }; @@ -231,13 +244,6 @@ skia.mojom.SkColor4f background_color; skia.mojom.SkColor4f safe_opaque_background_color; - // Optional field that will be set if this Layer is a PictureLayer that is - // actually a solid color. - skia.mojom.SkColor4f? solid_color; - - // Will be set to true for PictureLayers that are backdrop filter masks. - bool is_backdrop_filter_mask; - // Optional stable identifier that may be referenced in property trees and // animations. Identifies a client-side object which can be represented by // multiple layers over time but only by a single layer at once.
diff --git a/testing/scripts/run_variations_smoke_tests.py b/testing/scripts/run_variations_smoke_tests.py index f0fead4..1ed5644 100755 --- a/testing/scripts/run_variations_smoke_tests.py +++ b/testing/scripts/run_variations_smoke_tests.py
@@ -26,6 +26,8 @@ # //third_party/webdriver/pylib imports. from selenium import webdriver from selenium.webdriver import ChromeOptions +from selenium.webdriver.chrome.service import Service +from selenium.webdriver.common.by import By from selenium.common.exceptions import NoSuchElementException from selenium.common.exceptions import WebDriverException @@ -141,7 +143,9 @@ wait_timeout_in_sec = _WAIT_TIMEOUT_IN_SEC while attempt < _MAX_ATTEMPTS: # Starts Chrome to allow it to download a seed or a seed delta. - driver = webdriver.Chrome(path_chromedriver, chrome_options=chrome_options) + chromedriver_service = Service(executable_path=path_chromedriver) + driver = webdriver.Chrome(service=chromedriver_service, + options=chrome_options) time.sleep(5) # Exits Chrome so that Local State could be serialized to disk. driver.quit() @@ -246,21 +250,23 @@ driver = None try: - chrome_verison = _check_chrome_version() + chrome_version = _check_chrome_version() # If --variations-test-seed-path flag was not implemented in this version - if chrome_verison <= _FLAG_RELEASE_VERSION: + if chrome_version <= _FLAG_RELEASE_VERSION: if _inject_seed(user_data_dir, path_chromedriver, chrome_options) == 1: return 1 # Starts Chrome with the test seed injected. - driver = webdriver.Chrome(path_chromedriver, chrome_options=chrome_options) + chromedriver_service = Service(executable_path=path_chromedriver) + driver = webdriver.Chrome(service=chromedriver_service, + options=chrome_options) # Run test cases: visit urls and verify certain web elements are rendered # correctly. for t in _TEST_CASES: driver.get(t['url']) driver.set_window_size(1280, 1024) - element = driver.find_element_by_id(t['expected_id']) + element = driver.find_element(By.ID, t['expected_id']) if not element.is_displayed() or t['expected_text'] != element.text: logging.error( 'Test failed because element: "%s" is not visibly found after ' @@ -269,7 +275,7 @@ if 'skia_gold_image' in t: image_name = t['skia_gold_image'] sc_file = os.path.join(work_dir, image_name + '.png') - driver.find_element_by_id('body').screenshot(sc_file) + driver.find_element(By.ID, 'body').screenshot(sc_file) force_dryrun = False if skia_util.IsTryjobRun and skia_util.IsRetryWithoutPatch: force_dryrun = True
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index 931aac78..55e6e17 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -422,24 +422,6 @@ ] } ], - "AiSettingsPageEnterpriseDisabledUi": [ - { - "platforms": [ - "chromeos", - "linux", - "mac", - "windows" - ], - "experiments": [ - { - "name": "Enabled", - "enable_features": [ - "AiSettingsPageEnterpriseDisabledUi" - ] - } - ] - } - ], "AlignWakeUps": [ { "platforms": [ @@ -748,6 +730,21 @@ ] } ], + "AndroidProgressBarVisualUpdate": [ + { + "platforms": [ + "android" + ], + "experiments": [ + { + "name": "Enabled", + "enable_features": [ + "AndroidProgressBarVisualUpdate" + ] + } + ] + } + ], "AndroidReaderModeImprovements": [ { "platforms": [ @@ -3796,6 +3793,21 @@ ] } ], + "CCTFixWarmup": [ + { + "platforms": [ + "android" + ], + "experiments": [ + { + "name": "Enabled", + "enable_features": [ + "CCTFixWarmup" + ] + } + ] + } + ], "CCTGoogleBottomBar": [ { "platforms": [ @@ -10397,7 +10409,8 @@ { "platforms": [ "mac", - "windows" + "windows", + "linux" ], "experiments": [ { @@ -10413,7 +10426,8 @@ { "platforms": [ "mac", - "windows" + "windows", + "linux" ], "experiments": [ { @@ -10444,7 +10458,8 @@ { "platforms": [ "mac", - "windows" + "windows", + "linux" ], "experiments": [ { @@ -10479,14 +10494,14 @@ { "platforms": [ "mac", - "windows" + "windows", + "linux" ], "experiments": [ { "name": "Enabled", "params": { "glic-allowed-origins-override": "https://www.google.com", - "glic-client-responsiveness-check-interval-ms": "5000", "glic-fre-url": "https://www.google.com/?", "glic-guest-url": "https://www.google.com/", "glic-shortcuts-launcher-toggle-learn-more-url": "https://support.google.com/", @@ -10497,7 +10512,6 @@ "enable_features": [ "GlicAppMenuNewBadge", "GlicCSPConfig", - "GlicClientResponsivenessCheck", "GlicFreURLConfig", "GlicKeyboardShortcutNewBadge", "GlicPageContextEligibility", @@ -10512,7 +10526,8 @@ { "platforms": [ "mac", - "windows" + "windows", + "linux" ], "experiments": [ { @@ -10528,7 +10543,8 @@ { "platforms": [ "mac", - "windows" + "windows", + "linux" ], "experiments": [ { @@ -10549,7 +10565,8 @@ { "platforms": [ "mac", - "windows" + "windows", + "linux" ], "experiments": [ { @@ -13260,6 +13277,25 @@ ] } ], + "KeepDefaultSearchEngineAlive": [ + { + "platforms": [ + "chromeos", + "linux", + "mac", + "windows" + ], + "experiments": [ + { + "name": "EnabledDSEKeepAlive", + "enable_features": [ + "KeepDefaultSearchEngineRendererAlive", + "TrackEmptyRendererProcessesForReuse" + ] + } + ] + } + ], "KeyboardAccessoryAddressIPH": [ { "platforms": [ @@ -15626,6 +15662,24 @@ ] } ], + "OmniboxAiModeZpsIOS": [ + { + "platforms": [ + "ios" + ], + "experiments": [ + { + "name": "Enabled_5_PSuggest_4_AIM_Without_Backfill", + "params": { + "SuppressPsuggestBackfillWithMIA": "true" + }, + "enable_features": [ + "OmniboxMiaZPS" + ] + } + ] + } + ], "OmniboxAnswerActions": [ { "platforms": [ @@ -17727,21 +17781,6 @@ ] } ], - "PowerSavingModeBroadcastReceiverInBackground": [ - { - "platforms": [ - "android" - ], - "experiments": [ - { - "name": "Enabled", - "enable_features": [ - "PowerSavingModeBroadcastReceiverInBackground" - ] - } - ] - } - ], "PreconnectCreateNewTab": [ { "platforms": [ @@ -25707,6 +25746,29 @@ ] } ], + "WasmTtsComponentUpdaterV3Enabled": [ + { + "platforms": [ + "linux", + "mac", + "windows" + ], + "experiments": [ + { + "name": "Enabled", + "enable_features": [ + "WasmTtsComponentUpdaterV3Enabled" + ] + }, + { + "name": "Disabled", + "disable_features": [ + "WasmTtsComponentUpdaterV3Enabled" + ] + } + ] + } + ], "WebApkBackupAndRestore": [ { "platforms": [
diff --git a/third_party/android_build_tools/jetifier/3pp/3pp.pb b/third_party/android_build_tools/jetifier/3pp/3pp.pb deleted file mode 100644 index 39ba0229..0000000 --- a/third_party/android_build_tools/jetifier/3pp/3pp.pb +++ /dev/null
@@ -1,16 +0,0 @@ -create { - source { - url { - download_url: "https://dl.google.com/dl/android/studio/jetifier-zips/1.0.0-beta10/jetifier-standalone.zip" - version: "1.0.0-beta10" - extension: '.zip' - } - patch_version: 'cr0' - unpack_archive: true - } -} - -upload { - universal: true - pkg_prefix: "chromium/third_party/android_build_tools" -}
diff --git a/third_party/android_build_tools/jetifier/LICENSE b/third_party/android_build_tools/jetifier/LICENSE deleted file mode 100644 index 261eeb9..0000000 --- a/third_party/android_build_tools/jetifier/LICENSE +++ /dev/null
@@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License.
diff --git a/third_party/android_build_tools/jetifier/OWNERS b/third_party/android_build_tools/jetifier/OWNERS deleted file mode 100644 index 39f58e9..0000000 --- a/third_party/android_build_tools/jetifier/OWNERS +++ /dev/null
@@ -1 +0,0 @@ -agrieve@chromium.org
diff --git a/third_party/android_build_tools/jetifier/README.chromium b/third_party/android_build_tools/jetifier/README.chromium deleted file mode 100644 index 01aeb8e6..0000000 --- a/third_party/android_build_tools/jetifier/README.chromium +++ /dev/null
@@ -1,13 +0,0 @@ -Name: Androidx Jetifier -Short Name: jetifier -URL: https://dl.google.com/dl/android/studio/jetifier-zips/1.0.0-beta10/jetifier-standalone.zip -Version: 1.0.0-beta10 -License: Apache-2.0 -License File: LICENSE -Security Critical: no -Shipped: no -License Android Compatible: yes - -Description: -The standalone Jetifier tool migrates support-library-dependent libraries to -instead rely on the equivalent AndroidX packages.
diff --git a/third_party/angle b/third_party/angle index 8c512f3..ef85f28 160000 --- a/third_party/angle +++ b/third_party/angle
@@ -1 +1 @@ -Subproject commit 8c512f3e03d0d2fd21b4d55a7fc1becff9604a8e +Subproject commit ef85f283434e5b26b672c39f050a0e2c8c655aef
diff --git a/third_party/blink/public/mojom/manifest/manifest.mojom b/third_party/blink/public/mojom/manifest/manifest.mojom index da8d929..35e9eb5 100644 --- a/third_party/blink/public/mojom/manifest/manifest.mojom +++ b/third_party/blink/public/mojom/manifest/manifest.mojom
@@ -152,11 +152,6 @@ // TODO(crbug.com/1444407): This field is non-standard and part of an // experiment. See: https://github.com/WICG/isolated-web-apps mojo_base.mojom.String16? version; - - // Represent a string value which when provided will be used to trigger a - // manifest update. - // TODO(crbug.com/403252969): Add explainer here once complete. - mojo_base.mojom.String16? update_token; }; // Structure representing a Shortcut Item per the Manifest specification, see:
diff --git a/third_party/blink/public/mojom/use_counter/metrics/webdx_feature.mojom b/third_party/blink/public/mojom/use_counter/metrics/webdx_feature.mojom index 7696b369..2ecd384c 100644 --- a/third_party/blink/public/mojom/use_counter/metrics/webdx_feature.mojom +++ b/third_party/blink/public/mojom/use_counter/metrics/webdx_feature.mojom
@@ -371,7 +371,7 @@ kAppLaunchHandler = 309, kFunction = 310, kIf = 311, - kWebAppManifestUpdateToken = 312, + kDRAFT_WebAppManifestUpdate = 312, kReadingFlow = 313, kComposedRanges = 314, kCompressionDictionaryTransport = 315,
diff --git a/third_party/blink/renderer/bindings/generated_in_core.gni b/third_party/blink/renderer/bindings/generated_in_core.gni index e5ce1d3..57d6b5d 100644 --- a/third_party/blink/renderer/bindings/generated_in_core.gni +++ b/third_party/blink/renderer/bindings/generated_in_core.gni
@@ -386,6 +386,8 @@ "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_queuing_strategy_init.h", "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_quota_exceeded_error_options.cc", "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_quota_exceeded_error_options.h", + "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_readable_stream_byob_reader_read_options.cc", + "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_readable_stream_byob_reader_read_options.h", "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_readable_stream_get_reader_options.cc", "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_readable_stream_get_reader_options.h", "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_readable_stream_iterator_options.cc",
diff --git a/third_party/blink/renderer/bindings/idl_in_core.gni b/third_party/blink/renderer/bindings/idl_in_core.gni index 7b410a3..6033505 100644 --- a/third_party/blink/renderer/bindings/idl_in_core.gni +++ b/third_party/blink/renderer/bindings/idl_in_core.gni
@@ -585,6 +585,7 @@ "//third_party/blink/renderer/core/streams/readable_byte_stream_controller.idl", "//third_party/blink/renderer/core/streams/readable_stream.idl", "//third_party/blink/renderer/core/streams/readable_stream_byob_reader.idl", + "//third_party/blink/renderer/core/streams/readable_stream_byob_reader_read_options.idl", "//third_party/blink/renderer/core/streams/readable_stream_byob_request.idl", "//third_party/blink/renderer/core/streams/readable_stream_default_controller.idl", "//third_party/blink/renderer/core/streams/readable_stream_default_reader.idl",
diff --git a/third_party/blink/renderer/core/frame/local_frame_view.h b/third_party/blink/renderer/core/frame/local_frame_view.h index 034743f..02dc185f 100644 --- a/third_party/blink/renderer/core/frame/local_frame_view.h +++ b/third_party/blink/renderer/core/frame/local_frame_view.h
@@ -415,7 +415,7 @@ // disallows layout invalidation within the containing scope. If layout // invalidation takes place while the scoper is active a DCHECK will be // triggered. - class InvalidationDisallowedScope { + class CORE_EXPORT InvalidationDisallowedScope { STACK_ALLOCATED(); public:
diff --git a/third_party/blink/renderer/core/html/media/html_media_element.cc b/third_party/blink/renderer/core/html/media/html_media_element.cc index 279fa8c..92a2262 100644 --- a/third_party/blink/renderer/core/html/media/html_media_element.cc +++ b/third_party/blink/renderer/core/html/media/html_media_element.cc
@@ -3347,6 +3347,7 @@ return; } } + web_media_player_->EnabledAudioTracksChanged(std::nullopt); } VideoTrackList& HTMLMediaElement::videoTracks() {
diff --git a/third_party/blink/renderer/core/html/media/html_video_element_test.cc b/third_party/blink/renderer/core/html/media/html_video_element_test.cc index 82e2c8f..1290d3f 100644 --- a/third_party/blink/renderer/core/html/media/html_video_element_test.cc +++ b/third_party/blink/renderer/core/html/media/html_video_element_test.cc
@@ -13,6 +13,8 @@ #include "third_party/blink/renderer/core/frame/settings.h" #include "third_party/blink/renderer/core/html/media/html_media_test_helper.h" #include "third_party/blink/renderer/core/html/media/media_video_visibility_tracker.h" +#include "third_party/blink/renderer/core/html/track/audio_track_list.h" +#include "third_party/blink/renderer/core/html/track/video_track_list.h" #include "third_party/blink/renderer/core/html_names.h" #include "third_party/blink/renderer/core/layout/geometry/physical_rect.h" #include "third_party/blink/renderer/core/layout/layout_box_model_object.h" @@ -26,6 +28,7 @@ #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h" using testing::_; +using testing::Eq; using testing::Return; namespace blink { @@ -42,6 +45,8 @@ RecordVideoOcclusionState, (std::string_view occlusion_state)); MOCK_METHOD(gfx::Size, NaturalSize, (), (const)); + MOCK_METHOD(void, EnabledAudioTracksChanged, (std::optional<TrackId>)); + MOCK_METHOD(void, SelectedVideoTrackChanged, (std::optional<TrackId>)); }; } // namespace @@ -102,6 +107,76 @@ }; INSTANTIATE_PAINT_TEST_SUITE_P(HTMLVideoElementTest); +TEST_P(HTMLVideoElementTest, TrackChangeEventPropagationTest) { + scoped_refptr<cc::Layer> layer = cc::Layer::Create(); + SetFakeCcLayer(layer.get()); + + video()->SetBooleanAttribute(html_names::kControlsAttr, true); + video()->SetSrc(AtomicString("http://example.com/foo.mp4")); + test::RunPendingTasks(); + + video()->AddMediaTrackForTesting(media::MediaTrack::CreateAudioTrack( + "a0", media::MediaTrack::AudioKind::kMain, "zero", "EN", true, 0, true)); + video()->AddMediaTrackForTesting(media::MediaTrack::CreateAudioTrack( + "a1", media::MediaTrack::AudioKind::kMain, "one", "EN", false, 1, true)); + ASSERT_EQ(video()->audioTracks().length(), 2); + ASSERT_EQ(video()->audioTracks().AnonymousIndexedGetter(0)->id(), "a0"); + ASSERT_TRUE(video()->audioTracks().AnonymousIndexedGetter(0)->enabled()); + ASSERT_EQ(video()->audioTracks().AnonymousIndexedGetter(1)->id(), "a1"); + ASSERT_FALSE(video()->audioTracks().AnonymousIndexedGetter(1)->enabled()); + + video()->AddMediaTrackForTesting(media::MediaTrack::CreateVideoTrack( + "v0", media::MediaTrack::VideoKind::kMain, "zero", "EN", true, 0)); + video()->AddMediaTrackForTesting(media::MediaTrack::CreateVideoTrack( + "v1", media::MediaTrack::VideoKind::kMain, "one", "EN", false, 1)); + ASSERT_EQ(video()->videoTracks().length(), 2); + ASSERT_EQ(video()->videoTracks().AnonymousIndexedGetter(0)->id(), "v0"); + ASSERT_TRUE(video()->videoTracks().AnonymousIndexedGetter(0)->selected()); + ASSERT_EQ(video()->videoTracks().AnonymousIndexedGetter(1)->id(), "v1"); + ASSERT_FALSE(video()->videoTracks().AnonymousIndexedGetter(1)->selected()); + + // Enabling the enabled audio track does nothing. + EXPECT_CALL(*MockMediaPlayer(), EnabledAudioTracksChanged(_)).Times(0); + video()->audioTracks().AnonymousIndexedGetter(0)->setEnabled(true); + test::RunPendingTasks(); + testing::Mock::VerifyAndClearExpectations(MockMediaPlayer()); + + // Enabling the disabled audio track triggers a track change for it. + EXPECT_CALL(*MockWebMediaPlayer(), + EnabledAudioTracksChanged( + testing::Optional(EmptyWebMediaPlayer::TrackId("a1")))); + video()->audioTracks().AnonymousIndexedGetter(1)->setEnabled(true); + test::RunPendingTasks(); + testing::Mock::VerifyAndClearExpectations(MockMediaPlayer()); + + // Disabling the enabled audio track triggers a track disable for the media + // player. + EXPECT_CALL(*MockWebMediaPlayer(), + EnabledAudioTracksChanged(Eq(std::nullopt))); + video()->audioTracks().AnonymousIndexedGetter(1)->setEnabled(false); + test::RunPendingTasks(); + testing::Mock::VerifyAndClearExpectations(MockMediaPlayer()); + + // Now do the same things for video tracks. + EXPECT_CALL(*MockMediaPlayer(), SelectedVideoTrackChanged(_)).Times(0); + video()->videoTracks().AnonymousIndexedGetter(0)->setSelected(true); + test::RunPendingTasks(); + testing::Mock::VerifyAndClearExpectations(MockMediaPlayer()); + + EXPECT_CALL(*MockWebMediaPlayer(), + SelectedVideoTrackChanged( + testing::Optional(EmptyWebMediaPlayer::TrackId("v1")))); + video()->videoTracks().AnonymousIndexedGetter(1)->setSelected(true); + test::RunPendingTasks(); + testing::Mock::VerifyAndClearExpectations(MockMediaPlayer()); + + EXPECT_CALL(*MockWebMediaPlayer(), + SelectedVideoTrackChanged(Eq(std::nullopt))); + video()->videoTracks().AnonymousIndexedGetter(1)->setSelected(false); + test::RunPendingTasks(); + testing::Mock::VerifyAndClearExpectations(MockMediaPlayer()); +} + TEST_P(HTMLVideoElementTest, PictureInPictureInterstitialAndTextContainer) { scoped_refptr<cc::Layer> layer = cc::Layer::Create(); SetFakeCcLayer(layer.get());
diff --git a/third_party/blink/renderer/core/layout/forms/layout_text_control.cc b/third_party/blink/renderer/core/layout/forms/layout_text_control.cc index bc08a325..631b5e7b 100644 --- a/third_party/blink/renderer/core/layout/forms/layout_text_control.cc +++ b/third_party/blink/renderer/core/layout/forms/layout_text_control.cc
@@ -30,6 +30,7 @@ #include "third_party/blink/renderer/core/layout/text_utils.h" #include "third_party/blink/renderer/core/page/chrome_client.h" #include "third_party/blink/renderer/core/page/page.h" +#include "third_party/blink/renderer/core/scroll/scrollbar_theme.h" namespace blink {
diff --git a/third_party/blink/renderer/core/layout/grid/layout_grid.cc b/third_party/blink/renderer/core/layout/grid/layout_grid.cc index 3b6cd5bf..6db513d 100644 --- a/third_party/blink/renderer/core/layout/grid/layout_grid.cc +++ b/third_party/blink/renderer/core/layout/grid/layout_grid.cc
@@ -27,20 +27,17 @@ NOT_DESTROYED(); LayoutBlock::AddChild(new_child, before_child); - // Out-of-flow grid items don't impact placement. - if (!new_child->IsOutOfFlowPositioned()) { - MarkGridDirty(); - } + // Counter-intuitively, adding/removing a "position:absolute" child or + // similar *can* make the placement dirty as the OOF may cause an anonymous + // child to be split (or merged). + MarkGridDirty(); } void LayoutGrid::RemoveChild(LayoutObject* child) { NOT_DESTROYED(); LayoutBlock::RemoveChild(child); - // Out-of-flow grid items don't impact placement. - if (!child->IsOutOfFlowPositioned()) { - MarkGridDirty(); - } + MarkGridDirty(); } namespace {
diff --git a/third_party/blink/renderer/core/layout/layout_block.cc b/third_party/blink/renderer/core/layout/layout_block.cc index c9e95049..1fc09af 100644 --- a/third_party/blink/renderer/core/layout/layout_block.cc +++ b/third_party/blink/renderer/core/layout/layout_block.cc
@@ -202,6 +202,45 @@ void LayoutBlock::AddChildBeforeDescendant(LayoutObject* new_child, LayoutObject* before_descendant) { NOT_DESTROYED(); + DCHECK(RuntimeEnabledFeatures::LayoutAddChildBeforeDescendantFixEnabled()); + DCHECK(!IsLayoutBlockFlow()); + DCHECK_NE(before_descendant->Parent(), this); + LayoutObject* before_descendant_container = before_descendant->Parent(); + while (before_descendant_container->Parent() != this) { + before_descendant_container = before_descendant_container->Parent(); + } + DCHECK(before_descendant_container); + + // We really can't go on if what we have found isn't anonymous. We're not + // supposed to use some random non-anonymous object and put the child there. + // That's a recipe for security issues. + CHECK(before_descendant_container->IsAnonymous()); + + // Insert the child into the anonymous block box instead of here. + if (new_child->IsInline() && + before_descendant_container->IsAnonymousBlockFlow()) { + before_descendant_container->AddChild(new_child, before_descendant); + return; + } + + // Insert into the anonymous table. + if (new_child->IsTablePart()) { + before_descendant_container->AddChild(new_child, before_descendant); + return; + } + + LayoutObject* before_child = + SplitAnonymousBoxesAroundChild(before_descendant); + + DCHECK_EQ(before_child->Parent(), this); + AddChild(new_child, before_child); +} + +void LayoutBlock::AddChildBeforeDescendantDeprecated( + LayoutObject* new_child, + LayoutObject* before_descendant) { + NOT_DESTROYED(); + DCHECK(!RuntimeEnabledFeatures::LayoutAddChildBeforeDescendantFixEnabled()); DCHECK_NE(before_descendant->Parent(), this); LayoutObject* before_descendant_container = before_descendant->Parent(); while (before_descendant_container->Parent() != this) @@ -254,7 +293,11 @@ LayoutObject* before_child) { NOT_DESTROYED(); if (before_child && before_child->Parent() != this) { - AddChildBeforeDescendant(new_child, before_child); + if (RuntimeEnabledFeatures::LayoutAddChildBeforeDescendantFixEnabled()) { + AddChildBeforeDescendant(new_child, before_child); + } else { + AddChildBeforeDescendantDeprecated(new_child, before_child); + } return; }
diff --git a/third_party/blink/renderer/core/layout/layout_block.h b/third_party/blink/renderer/core/layout/layout_block.h index d6700f38..468e83f 100644 --- a/third_party/blink/renderer/core/layout/layout_block.h +++ b/third_party/blink/renderer/core/layout/layout_block.h
@@ -142,6 +142,10 @@ // child of |this| and |before_descendant| has been reparented into that one. // Such things are invisible to the DOM, and addChild() is typically called // with the DOM tree (and not the layout tree) in mind. + void AddChildBeforeDescendantDeprecated(LayoutObject* new_child, + LayoutObject* before_descendant); + + private: void AddChildBeforeDescendant(LayoutObject* new_child, LayoutObject* before_descendant);
diff --git a/third_party/blink/renderer/core/layout/layout_block_flow.cc b/third_party/blink/renderer/core/layout/layout_block_flow.cc index 49fdb948..b4a4957c 100644 --- a/third_party/blink/renderer/core/layout/layout_block_flow.cc +++ b/third_party/blink/renderer/core/layout/layout_block_flow.cc
@@ -149,6 +149,60 @@ LayoutBlock::WillBeDestroyed(); } +void LayoutBlockFlow::AddChildBeforeDescendant( + LayoutObject* new_child, + LayoutObject* before_descendant) { + NOT_DESTROYED(); + DCHECK(RuntimeEnabledFeatures::LayoutAddChildBeforeDescendantFixEnabled()); + DCHECK_NE(before_descendant->Parent(), this); + LayoutObject* before_descendant_container = before_descendant->Parent(); + while (before_descendant_container->Parent() != this) { + before_descendant_container = before_descendant_container->Parent(); + } + DCHECK(before_descendant_container); + + // We really can't go on if what we have found isn't anonymous. We're not + // supposed to use some random non-anonymous object and put the child there. + // That's a recipe for security issues. + CHECK(before_descendant_container->IsAnonymous()); + + // If the requested insertion point is not one of our children, then this is + // because there is an anonymous container within this object that contains + // the beforeDescendant. + if (before_descendant_container->IsAnonymousBlockFlow()) { + // Insert the child into the anonymous block box instead of here. Note that + // a LayoutOutsideListMarker is out-of-flow for tree building purposes, and + // that is not inline level, although IsInline() is true. + if ((new_child->IsInline() && !new_child->IsLayoutOutsideListMarker()) || + new_child->IsFloatingOrOutOfFlowPositioned() || + before_descendant->PreviousSibling()) { + before_descendant_container->AddChild(new_child, before_descendant); + } else { + AddChild(new_child, before_descendant->Parent()); + } + return; + } + + DCHECK(before_descendant_container->IsTable()); + if (new_child->IsTablePart()) { + // Insert into the anonymous table. + before_descendant_container->AddChild(new_child, before_descendant); + return; + } + + LayoutObject* before_child = + SplitAnonymousBoxesAroundChild(before_descendant); + + DCHECK_EQ(before_child->Parent(), this); + if (before_child->Parent() != this) { + // We should never reach here. If we do, we need to use the + // safe fallback to use the topmost beforeChild container. + before_child = before_descendant_container; + } + + AddChild(new_child, before_child); +} + void LayoutBlockFlow::AddChild(LayoutObject* new_child, LayoutObject* before_child) { NOT_DESTROYED(); @@ -162,7 +216,11 @@ } if (before_child && before_child->Parent() != this) { - AddChildBeforeDescendant(new_child, before_child); + if (RuntimeEnabledFeatures::LayoutAddChildBeforeDescendantFixEnabled()) { + AddChildBeforeDescendant(new_child, before_child); + } else { + AddChildBeforeDescendantDeprecated(new_child, before_child); + } return; }
diff --git a/third_party/blink/renderer/core/layout/layout_block_flow.h b/third_party/blink/renderer/core/layout/layout_block_flow.h index 704b37f..ed4dd81 100644 --- a/third_party/blink/renderer/core/layout/layout_block_flow.h +++ b/third_party/blink/renderer/core/layout/layout_block_flow.h
@@ -171,6 +171,9 @@ private: void UpdateForMulticol(const ComputedStyle* old_style); + void AddChildBeforeDescendant(LayoutObject* new_child, + LayoutObject* before_descendant); + // Merge children of |sibling_that_may_be_deleted| into this object if // possible, and delete |sibling_that_may_be_deleted|. Returns true if we // were able to merge. In that case, |sibling_that_may_be_deleted| will be
diff --git a/third_party/blink/renderer/core/layout/layout_box.cc b/third_party/blink/renderer/core/layout/layout_box.cc index 0ec939e9..3d9e5d5 100644 --- a/third_party/blink/renderer/core/layout/layout_box.cc +++ b/third_party/blink/renderer/core/layout/layout_box.cc
@@ -111,6 +111,7 @@ #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h" #include "third_party/blink/renderer/core/resize_observer/resize_observer_size.h" #include "third_party/blink/renderer/core/scroll/scroll_into_view_util.h" +#include "third_party/blink/renderer/core/scroll/scrollbar_theme.h" #include "third_party/blink/renderer/core/style/computed_style_base_constants.h" #include "third_party/blink/renderer/core/style/shadow_list.h" #include "third_party/blink/renderer/core/style/style_overflow_clip_margin.h"
diff --git a/third_party/blink/renderer/core/layout/layout_box.h b/third_party/blink/renderer/core/layout/layout_box.h index 9d8edb6..8e6c0fb 100644 --- a/third_party/blink/renderer/core/layout/layout_box.h +++ b/third_party/blink/renderer/core/layout/layout_box.h
@@ -38,7 +38,6 @@ #include "third_party/blink/renderer/core/layout/min_max_sizes_cache.h" #include "third_party/blink/renderer/core/layout/overflow_model.h" #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h" -#include "third_party/blink/renderer/core/scroll/scrollbar_theme.h" #include "third_party/blink/renderer/core/style/style_overflow_clip_margin.h" #include "third_party/blink/renderer/platform/graphics/overlay_scrollbar_clip_behavior.h" #include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h"
diff --git a/third_party/blink/renderer/core/paint/box_fragment_painter.h b/third_party/blink/renderer/core/paint/box_fragment_painter.h index 23ee026e..f2fe29e 100644 --- a/third_party/blink/renderer/core/paint/box_fragment_painter.h +++ b/third_party/blink/renderer/core/paint/box_fragment_painter.h
@@ -14,6 +14,7 @@ #include "third_party/blink/renderer/core/layout/physical_box_fragment.h" #include "third_party/blink/renderer/core/paint/box_painter_base.h" #include "third_party/blink/renderer/core/paint/inline_paint_context.h" +#include "third_party/blink/renderer/platform/graphics/paint/display_item.h" #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" namespace blink {
diff --git a/third_party/blink/renderer/core/streams/byte_stream_tee_engine.cc b/third_party/blink/renderer/core/streams/byte_stream_tee_engine.cc index 06da60b..97e299d9 100644 --- a/third_party/blink/renderer/core/streams/byte_stream_tee_engine.cc +++ b/third_party/blink/renderer/core/streams/byte_stream_tee_engine.cc
@@ -585,12 +585,12 @@ // d. Let readIntoRequest be a read-into request with the following items: auto* read_into_request = MakeGarbageCollected<ByteTeeReadIntoRequest>( this, byob_branch, other_branch, for_branch_2); - // e. Perform ! ReadableStreamBYOBReaderRead(reader, view, + // e. Perform ! ReadableStreamBYOBReaderRead(reader, view, 1, // readIntoRequest). ReadableStreamGenericReader* reader = reader_; - ReadableStreamBYOBReader::Read(script_state, - To<ReadableStreamBYOBReader>(reader), view, - read_into_request, exception_state); + ReadableStreamBYOBReader::Read( + script_state, To<ReadableStreamBYOBReader>(reader), view, + /*min_read_length=*/1, read_into_request, exception_state); DCHECK(!exception_state.HadException()); }
diff --git a/third_party/blink/renderer/core/streams/readable_byte_stream_controller.cc b/third_party/blink/renderer/core/streams/readable_byte_stream_controller.cc index f53cf0f9..a8dd063 100644 --- a/third_party/blink/renderer/core/streams/readable_byte_stream_controller.cc +++ b/third_party/blink/renderer/core/streams/readable_byte_stream_controller.cc
@@ -54,6 +54,7 @@ size_t byte_offset, size_t byte_length, size_t bytes_filled, + uint64_t minimum_fill, size_t element_size, ViewConstructorType view_constructor, ReaderType reader_type) @@ -62,6 +63,7 @@ byte_offset(byte_offset), byte_length(byte_length), bytes_filled(bytes_filled), + minimum_fill(minimum_fill), element_size(element_size), view_constructor(view_constructor), reader_type(reader_type) {} @@ -230,11 +232,22 @@ // 4. If controller.[[pendingPullIntos]] is not empty, if (!controller->pending_pull_intos_.empty()) { - // a. Let firstPendingPullInto be controller.[[pendingPullIntos]][0]. + // a. Let firstPendingPullInto be controller.[[pendingPullIntos]][0]. const PullIntoDescriptor* first_pending_pull_into = controller->pending_pull_intos_[0]; - // b. If firstPendingPullInto’s bytes filled > 0, - if (first_pending_pull_into->bytes_filled > 0) { + // b. If the remainder after dividing firstPendingPullInto’s bytes filled + // by firstPendingPullInto's element size is not 0, + // + // The "min" option sets the minimum number of bytes a read should wait for + // before resolving. Normally, reads only complete when at least `min` bytes + // are available. However, if the stream closes before `min` bytes arrive, + // it is allowed to resolve early with any data that forms complete elements + // (no partial elements), even if fewer than `min`. This prevents the reader + // from waiting indefinitely when the stream ends early, while still + // ensuring data integrity by disallowing partial elements. + if (first_pending_pull_into->bytes_filled % + first_pending_pull_into->element_size != + 0) { // i. Let e be a new TypeError exception. v8::Local<v8::Value> e = V8ThrowException::CreateTypeError( script_state->GetIsolate(), "Cannot close while responding"); @@ -697,8 +710,11 @@ bool done = false; // 4. If stream.[[state]] is "closed", if (stream->state_ == ReadableStream::kClosed) { - // a. Assert: pullIntoDescriptor’s bytes filled is 0. - DCHECK_EQ(pull_into_descriptor->bytes_filled, 0u); + // a. Assert: the remainder after dividing pullIntoDescriptor’s + // bytes filled by pullIntoDescriptor’s element size is 0. + CHECK_EQ( + pull_into_descriptor->bytes_filled % pull_into_descriptor->element_size, + 0u); // b. Set done to true. done = true; } @@ -991,116 +1007,132 @@ return false; } // https://streams.spec.whatwg.org/#readable-byte-stream-controller-fill-pull-into-descriptor-from-queue - // 1. Let elementSize be pullIntoDescriptor.[[elementSize]]. - const size_t element_size = pull_into_descriptor->element_size; - // 2. Let currentAlignedBytes be pullIntoDescriptor's bytes filled − - // (pullIntoDescriptor's bytes filled mod elementSize). - const size_t current_aligned_bytes = - pull_into_descriptor->bytes_filled - - (pull_into_descriptor->bytes_filled % element_size); - // 3. Let maxBytesToCopy be min(controller.[[queueTotalSize]], + // 1. Let maxBytesToCopy be min(controller.[[queueTotalSize]], // pullIntoDescriptor’s byte length − pullIntoDescriptor’s bytes filled). // The subtraction will not underflow because bytes length will always be more // than or equal to bytes filled. const size_t max_bytes_to_copy = std::min( static_cast<size_t>(controller->queue_total_size_), pull_into_descriptor->byte_length - pull_into_descriptor->bytes_filled); - // 4. Let maxBytesFilled be pullIntoDescriptor’s bytes filled + + // 2. Let maxBytesFilled be pullIntoDescriptor’s bytes filled + // maxBytesToCopy. // This addition will not overflow because maxBytesToCopy can be at most // queue_total_size_. Both bytes_filled and queue_total_size_ refer to // actually allocated memory, so together they cannot exceed size_t. const size_t max_bytes_filled = pull_into_descriptor->bytes_filled + max_bytes_to_copy; - // 5. Let maxAlignedBytes be maxBytesFilled − (maxBytesFilled mod - // elementSize). + // 3. Let totalBytesToCopyRemaining be maxBytesToCopy. + size_t total_bytes_to_copy_remaining = max_bytes_to_copy; + // 4. Let ready be false; + bool ready = false; + // 5. Assert: ! IsDetachedBuffer(pullIntoDescriptor’s buffer) is false. + CHECK(!pull_into_descriptor->buffer->IsDetached()); + // 6. Assert: pullIntoDescriptor’s bytes filled < pullIntoDescriptor’s + // minimum fill. + CHECK_LT(pull_into_descriptor->bytes_filled, + pull_into_descriptor->minimum_fill); + // 7. Let remainderBytes be the remainder after dividing maxBytesFilled by + // pullIntoDescriptor’s element size. + const size_t remainder_bytes = + max_bytes_filled % pull_into_descriptor->element_size; + // 8. Let maxAlignedBytes be maxBytesFilled − remainderBytes. // This subtraction will not underflow because the modulus operator is // guaranteed to return a value less than or equal to the first argument. - const size_t max_aligned_bytes = - max_bytes_filled - (max_bytes_filled % element_size); - // 6. Let totalBytesToCopyRemaining be maxBytesToCopy. - size_t total_bytes_to_copy_remaining = max_bytes_to_copy; - // 7. Let ready be false; - bool ready = false; - // 8. If maxAlignedBytes > currentAlignedBytes, - if (max_aligned_bytes > current_aligned_bytes) { - // a. Set totalBytesToCopyRemaining to maxAlignedBytes − + const size_t max_aligned_bytes = max_bytes_filled - remainder_bytes; + // 9. If maxAlignedBytes >= pullIntoDescriptor’s minimum fill, + if (max_aligned_bytes >= pull_into_descriptor->minimum_fill) { + // 1. Set totalBytesToCopyRemaining to maxAlignedBytes − // pullIntoDescriptor’s bytes filled. total_bytes_to_copy_remaining = base::CheckSub(max_aligned_bytes, pull_into_descriptor->bytes_filled) .ValueOrDie(); - // b. Set ready to true. + // 2. Set ready to true. ready = true; } - // 9. Let queue be controller.[[queue]]. + // 10. Let queue be controller.[[queue]]. HeapDeque<Member<QueueEntry>>& queue = controller->queue_; - // 10. While totalBytesToCopyRemaining > 0, + // 11. While totalBytesToCopyRemaining > 0, while (total_bytes_to_copy_remaining > 0) { - // a. Let headOfQueue be queue[0]. + // 1. Let headOfQueue be queue[0]. QueueEntry* head_of_queue = queue[0]; - // b. Let bytesToCopy be min(totalBytesToCopyRemaining, + // 2. Let bytesToCopy be min(totalBytesToCopyRemaining, // headOfQueue’s byte length). size_t bytes_to_copy = std::min(total_bytes_to_copy_remaining, head_of_queue->byte_length); - // c. Let destStart be pullIntoDescriptor’s byte offset + + // 3. Let destStart be pullIntoDescriptor’s byte offset + // pullIntoDescriptor’s bytes filled. // This addition will not overflow because byte offset and bytes filled // refer to actually allocated memory, so together they cannot exceed // size_t. size_t dest_start = pull_into_descriptor->byte_offset + pull_into_descriptor->bytes_filled; - // d. Perform ! CopyDataBlockBytes(pullIntoDescriptor’s + // 4. Let descriptorBuffer = pullIntoDescriptor.buffer + DOMArrayBuffer* descriptor_buffer = pull_into_descriptor->buffer; + // 5. Let queueBuffer be headOfQueue’s buffer. + DOMArrayBuffer* queue_buffer = head_of_queue->buffer; + // 6: Let queueByteOffset be headOfQueue’s byte offset. + size_t queue_byte_offset = head_of_queue->byte_offset; + // 7.Assert: ! CanCopyDataBlockBytes(descriptorBuffer, destStart, + // queueBuffer, queueByteOffset, bytesToCopy) is true. + // Warning: If this assertion were to fail (due to a bug in this + // specification or its implementation), then the next step may read from or + // write to potentially invalid memory. The user agent should always check + // this assertion, and stop in an implementation-defined manner if it fails + // (e.g. by crashing the process, or by erroring the stream). + CHECK_LE(dest_start + bytes_to_copy, descriptor_buffer->ByteLength()); + CHECK_LE(queue_byte_offset + bytes_to_copy, queue_buffer->ByteLength()); + // 8. Perform ! CopyDataBlockBytes(pullIntoDescriptor’s // buffer.[[ArrayBufferData]], destStart, headOfQueue’s // buffer.[[ArrayBufferData]], headOfQueue’s byte offset, bytesToCopy). - auto copy_destination = pull_into_descriptor->buffer->ByteSpan().subspan( - dest_start, bytes_to_copy); - auto copy_source = head_of_queue->buffer->ByteSpan().subspan( - head_of_queue->byte_offset, bytes_to_copy); + auto copy_destination = + descriptor_buffer->ByteSpan().subspan(dest_start, bytes_to_copy); + auto copy_source = + queue_buffer->ByteSpan().subspan(queue_byte_offset, bytes_to_copy); copy_destination.copy_from(copy_source); - // e. If headOfQueue’s byte length is bytesToCopy, + // 9. If headOfQueue’s byte length is bytesToCopy, if (head_of_queue->byte_length == bytes_to_copy) { - // i. Remove queue[0]. + // 1. Remove queue[0]. queue.pop_front(); } else { - // f. Otherwise, - // i. Set headOfQueue’s byte offset to headOfQueue’s byte offset + + // 10. Otherwise, + // 1. Set headOfQueue’s byte offset to headOfQueue’s byte offset + // bytesToCopy. head_of_queue->byte_offset = base::CheckAdd(head_of_queue->byte_offset, bytes_to_copy) .ValueOrDie(); - // ii. Set headOfQueue’s byte length to headOfQueue’s byte + // 2. Set headOfQueue’s byte length to headOfQueue’s byte // length − bytesToCopy. head_of_queue->byte_length = base::CheckSub(head_of_queue->byte_length, bytes_to_copy) .ValueOrDie(); } - // g. Set controller.[[queueTotalSize]] to controller.[[queueTotalSize]] − + // 11. Set controller.[[queueTotalSize]] to controller.[[queueTotalSize]] − // bytesToCopy. controller->queue_total_size_ = base::CheckSub(controller->queue_total_size_, bytes_to_copy) .ValueOrDie(); - // h. Perform ! + // 12. Perform ! // ReadableByteStreamControllerFillHeadPullIntoDescriptor(controller, // bytesToCopy, pullIntoDescriptor). FillHeadPullIntoDescriptor(controller, bytes_to_copy, pull_into_descriptor); - // i. Set totalBytesToCopyRemaining to totalBytesToCopyRemaining − + // 13. Set totalBytesToCopyRemaining to totalBytesToCopyRemaining − // bytesToCopy. // This subtraction will not underflow because bytes_to_copy will always be // greater than or equal to total_bytes_to_copy_remaining. total_bytes_to_copy_remaining -= bytes_to_copy; } - // 11. If ready is false, + // 12. If ready is false, if (!ready) { - // a. Assert: controller.[[queueTotalSize]] is 0. + // 1. Assert: controller.[[queueTotalSize]] is 0. DCHECK_EQ(controller->queue_total_size_, 0u); - // b. Assert: pullIntoDescriptor’s bytes filled > 0. + // 2. Assert: pullIntoDescriptor’s bytes filled > 0. DCHECK_GT(pull_into_descriptor->bytes_filled, 0.0); - // c. Assert: pullIntoDescriptor’s bytes filled < pullIntoDescriptor’s - // element size. + // 3. Assert: pullIntoDescriptor’s bytes filled < pullIntoDescriptor’s + // minimum fill. DCHECK_LT(pull_into_descriptor->bytes_filled, - pull_into_descriptor->element_size); + pull_into_descriptor->minimum_fill); } - // 12. Return ready. + // 13. Return ready. return ready; } @@ -1135,6 +1167,7 @@ ScriptState* script_state, ReadableByteStreamController* controller, NotShared<DOMArrayBufferView> view, + uint64_t min, ReadIntoRequest* read_into_request, ExceptionState& exception_state) { // https://streams.spec.whatwg.org/#readable-byte-stream-controller-pull-into @@ -1193,37 +1226,45 @@ NOTREACHED(); } } - // 5. Let byteOffset be view.[[ByteOffset]]. + // 5. Let minimumFill be min * elementSize. + const uint64_t minimum_fill = base::CheckMul(min, element_size).ValueOrDie(); + // 6. Assert: minimumFill >= 0 and minimumFill <= view.[[ByteLength]]. + CHECK_GE(minimum_fill, 0u); + CHECK_LE(minimum_fill, view->byteLength()); + // 7. Assert: the remainder after dividing minimumFill by elementSize is 0. + CHECK_EQ(minimum_fill % element_size, 0u); + // 8. Let byteOffset be view.[[ByteOffset]]. const size_t byte_offset = view->byteOffset(); - // 6. Let byteLength be view.[[ByteLength]]. + // 9. Let byteLength be view.[[ByteLength]]. const size_t byte_length = view->byteLength(); - // 7. Let bufferResult be TransferArrayBuffer(view.[[ViewedArrayBuffer]]). + // 10. Let bufferResult be TransferArrayBuffer(view.[[ViewedArrayBuffer]]). DOMArrayBuffer* buffer = nullptr; { v8::TryCatch try_catch(script_state->GetIsolate()); buffer = TransferArrayBuffer(script_state, view->buffer(), PassThroughException(script_state->GetIsolate())); - // 8. If bufferResult is an abrupt completion, + // 11. If bufferResult is an abrupt completion, if (try_catch.HasCaught()) { // a. Perform readIntoRequest's error steps, given - // bufferResult.[[Value]]. + // bufferResult.[[Value]]. read_into_request->ErrorSteps(script_state, try_catch.Exception()); // b. Return. return; } } - // 9. Let buffer be bufferResult.[[Value]]. + // 12. Let buffer be bufferResult.[[Value]]. - // 10. Let pullIntoDescriptor be a new pull-into descriptor with buffer + // 13. Let pullIntoDescriptor be a new pull-into descriptor with buffer // buffer, buffer byte length buffer.[[ArrayBufferByteLength]], byte offset - // byteOffset, byte length byteLength, bytes filled 0, element size - // elementSize, view constructor ctor, and reader type "byob". + // byteOffset, byte length byteLength, bytes filled 0, minimum fill + // minimumFill, element size elementSize, view constructor ctor, and + // reader type "byob". PullIntoDescriptor* pull_into_descriptor = MakeGarbageCollected<PullIntoDescriptor>( buffer, buffer->ByteLength(), byte_offset, byte_length, 0, - element_size, ctor, ReaderType::kBYOB); - // 11. If controller.[[pendingPullIntos]] is not empty, + minimum_fill, element_size, ctor, ReaderType::kBYOB); + // 14. If controller.[[pendingPullIntos]] is not empty, if (!controller->pending_pull_intos_.empty()) { // a. Append pullIntoDescriptor to controller.[[pendingPullIntos]]. controller->pending_pull_intos_.push_back(pull_into_descriptor); @@ -1232,7 +1273,7 @@ // c. Return. return; } - // 12. If stream.[[state]] is "closed", + // 15. If stream.[[state]] is "closed", if (stream->state_ == ReadableStream::kClosed) { // a. Let emptyView be ! Construct(ctor, « pullIntoDescriptor’s buffer, // pullIntoDescriptor’s byte offset, 0 »). @@ -1243,7 +1284,7 @@ // c. Return. return; } - // 13. If controller.[[queueTotalSize]] > 0, + // 16. If controller.[[queueTotalSize]] > 0, if (controller->queue_total_size_ > 0) { // a. If ! // ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(controller, @@ -1287,11 +1328,11 @@ return; } } - // 14. Append pullIntoDescriptor to controller.[[pendingPullIntos]]. + // 17. Append pullIntoDescriptor to controller.[[pendingPullIntos]]. controller->pending_pull_intos_.push_back(pull_into_descriptor); - // 15. Perform ! ReadableStreamAddReadIntoRequest(stream, readIntoRequest). + // 18. Perform ! ReadableStreamAddReadIntoRequest(stream, readIntoRequest). ReadableStream::AddReadIntoRequest(script_state, stream, read_into_request); - // 16. Perform ! ReadableByteStreamControllerCallPullIfNeeded(controller). + // 19. Perform ! ReadableByteStreamControllerCallPullIfNeeded(controller). CallPullIfNeeded(script_state, controller); } @@ -1380,8 +1421,9 @@ PullIntoDescriptor* first_descriptor, ExceptionState& exception_state) { // https://streams.spec.whatwg.org/#readable-byte-stream-controller-respond-in-closed-state - // 1. Assert: firstDescriptor’s bytes filled is 0. - DCHECK_EQ(first_descriptor->bytes_filled, 0u); + // 1. Assert: the remainder after dividing firstDescriptor’s bytes filled by + // firstDescriptor’s element size is 0. + CHECK_EQ(first_descriptor->bytes_filled % first_descriptor->element_size, 0u); // 2. If firstDescriptor’s reader type is "none", perform ! // ReadableByteStreamControllerShiftPendingPullInto(controller). if (first_descriptor->reader_type == ReaderType::kNone) { @@ -1434,9 +1476,12 @@ // c. Return. return; } - // 4. If pullIntoDescriptor’s bytes filled < pullIntoDescriptor’s element - // size, return. - if (pull_into_descriptor->bytes_filled < pull_into_descriptor->element_size) { + // 4. If pullIntoDescriptor’s bytes filled < pullIntoDescriptor’s + // minimum fill, return. + if (pull_into_descriptor->bytes_filled < pull_into_descriptor->minimum_fill) { + // A descriptor for a read() request that is not yet filled up to its + // minimum length will stay at the head of the queue, so the underlying + // source can keep filling it. return; } // 5. Perform ! ReadableByteStreamControllerShiftPendingPullInto(controller). @@ -1644,11 +1689,7 @@ void ReadableByteStreamController::PullSteps(ScriptState* script_state, ReadRequest* read_request, ExceptionState& exception_state) { - // https://whatpr.org/streams/1029.html#rbs-controller-private-pull - // TODO: This function follows an old version of the spec referenced above, so - // it needs to be updated to the new version on - // https://streams.spec.whatwg.org when the ReadableStreamDefaultReader - // implementation is updated. + // https://streams.spec.whatwg.org/#rbs-controller-private-pull // 1. Let stream be this.[[stream]]. ReadableStream* const stream = controlled_readable_stream_; // 2. Assert: ! ReadableStreamHasDefaultReader(stream) is true. @@ -1675,15 +1716,22 @@ // This is not needed as DOMArrayBuffer::Create() is designed to // crash if it cannot allocate the memory. - // c. Let pullIntoDescriptor be Record {[[buffer]]: buffer.[[Value]], - // [[bufferByteLength]]: autoAllocateChunkSize, [[byteOffset]]: 0, - // [[byteLength]]: autoAllocateChunkSize, [[bytesFilled]]: 0, - // [[elementSize]]: 1, [[ctor]]: %Uint8Array%, [[readerType]]: "default"}. + // c. Let pullIntoDescriptor be a new pull-into descriptor with: + // buffer buffer.[[Value]], + // buffer byte length autoAllocateChunkSize, + // byte offset 0, + // byte length autoAllocateChunkSize, + // bytes filled 0, + // minimum fill 1, + // element size 1, + // view constructor %Uint8Array%, + // reader type "default". auto* ctor = &CreateAsArrayBufferView<DOMUint8Array>; PullIntoDescriptor* pull_into_descriptor = MakeGarbageCollected<PullIntoDescriptor>( - buffer, auto_allocate_chunk_size, 0, auto_allocate_chunk_size, 0, 1, - ctor, ReaderType::kDefault); + buffer, auto_allocate_chunk_size, /*byte_offset=*/0, + auto_allocate_chunk_size, /*bytes_filled=*/0, /*minimum_fill=*/1, + /*element_size=*/1, ctor, ReaderType::kDefault); // d. Append pullIntoDescriptor as the last element of // this.[[pendingPullIntos]]. pending_pull_intos_.push_back(pull_into_descriptor);
diff --git a/third_party/blink/renderer/core/streams/readable_byte_stream_controller.h b/third_party/blink/renderer/core/streams/readable_byte_stream_controller.h index 5042b68b..41fe6c7 100644 --- a/third_party/blink/renderer/core/streams/readable_byte_stream_controller.h +++ b/third_party/blink/renderer/core/streams/readable_byte_stream_controller.h
@@ -105,6 +105,7 @@ size_t byte_offset, size_t byte_length, size_t bytes_filled, + uint64_t minimum_fill, size_t element_size, ViewConstructorType view_constructor, ReaderType reader_type); @@ -114,6 +115,7 @@ size_t byte_offset; const size_t byte_length; size_t bytes_filled; + const uint64_t minimum_fill; const size_t element_size; const ViewConstructorType view_constructor; ReaderType reader_type; @@ -231,6 +233,7 @@ static void PullInto(ScriptState*, ReadableByteStreamController*, NotShared<DOMArrayBufferView> view, + uint64_t min, ReadIntoRequest*, ExceptionState&);
diff --git a/third_party/blink/renderer/core/streams/readable_stream_byob_reader.cc b/third_party/blink/renderer/core/streams/readable_stream_byob_reader.cc index 41735cbb..91e72a0 100644 --- a/third_party/blink/renderer/core/streams/readable_stream_byob_reader.cc +++ b/third_party/blink/renderer/core/streams/readable_stream_byob_reader.cc
@@ -6,6 +6,7 @@ #include "third_party/blink/renderer/bindings/core/v8/script_promise.h" #include "third_party/blink/renderer/bindings/core/v8/to_v8_traits.h" +#include "third_party/blink/renderer/bindings/core/v8/v8_readable_stream_byob_reader_read_options.h" #include "third_party/blink/renderer/bindings/core/v8/v8_readable_stream_read_result.h" #include "third_party/blink/renderer/core/streams/read_into_request.h" #include "third_party/blink/renderer/core/streams/readable_byte_stream_controller.h" @@ -16,6 +17,7 @@ #include "third_party/blink/renderer/platform/bindings/script_state.h" #include "third_party/blink/renderer/platform/bindings/v8_binding.h" #include "third_party/blink/renderer/platform/bindings/v8_throw_exception.h" +#include "third_party/blink/renderer/platform/runtime_enabled_features.h" namespace blink { @@ -86,6 +88,7 @@ ScriptPromise<ReadableStreamReadResult> ReadableStreamBYOBReader::read( ScriptState* script_state, NotShared<DOMArrayBufferView> view, + const ReadableStreamBYOBReaderReadOptions* options, ExceptionState& exception_state) { // https://streams.spec.whatwg.org/#byob-reader-read // 1. If view.[[ByteLength]] is 0, return a promise rejected with a TypeError @@ -115,7 +118,40 @@ return EmptyPromise(); } - // 4. If this.[[stream]] is undefined, return a promise rejected with a + uint64_t min = 1; + + if (RuntimeEnabledFeatures::ReadableStreamBYOBReaderReadMinOptionEnabled()) { + // 4. If options["min"] is 0, return a promise rejected with a TypeError + // exception. + if (options->min() == 0) { + exception_state.ThrowTypeError("min cannot be 0"); + return EmptyPromise(); + } + + if (view->GetType() != DOMArrayBufferView::kTypeDataView) { + // 5. If view has a [[TypedArrayName]] internal slot, + // 1. If options["min"] > view.[[ArrayLength]], return a promise + // rejected with a RangeError exception. + size_t array_length = view->byteLength() / view->TypeSize(); + if (options->min() > array_length) { + exception_state.ThrowRangeError( + "min cannot be larger than view's length"); + return EmptyPromise(); + } + } else { + // 6. Otherwise (i.e., it is a DataView), + // 1. If options["min"] > view.[[ByteLength]], return a promise + // rejected with a RangeError exception. + if (options->min() > view->byteLength()) { + exception_state.ThrowRangeError( + "min cannot be larger than view's byteLength"); + return EmptyPromise(); + } + } + min = options->min(); + } + + // 7. If this.[[stream]] is undefined, return a promise rejected with a // TypeError exception. if (!owner_readable_stream_) { exception_state.ThrowTypeError( @@ -124,7 +160,7 @@ return EmptyPromise(); } - // 5. Let promise be a new promise. + // 8. Let promise be a new promise. auto* resolver = MakeGarbageCollected<ScriptPromiseResolver<ReadableStreamReadResult>>( script_state, exception_state.GetContext()); @@ -133,7 +169,7 @@ // are released. resolver->SuppressDetachCheck(); - // 6. Let readIntoRequest be a new read-into request with the following items: + // 9. Let readIntoRequest be a new read-into request with the following items: // chunk steps, given chunk // 1. Resolve promise with «[ "value" → chunk, "done" → false ]». // close steps, given chunk @@ -143,15 +179,18 @@ auto* read_into_request = MakeGarbageCollected<BYOBReaderReadIntoRequest>(resolver); - // 7. Perform ! ReadableStreamBYOBReaderRead(this, view, readIntoRequest). - Read(script_state, this, view, read_into_request, exception_state); - // 8. Return promise. + // 10. Perform ! ReadableStreamBYOBReaderRead(this, view, min, + // readIntoRequest). + Read(script_state, this, view, min, read_into_request, exception_state); + + // 11. Return promise. return resolver->Promise(); } void ReadableStreamBYOBReader::Read(ScriptState* script_state, ReadableStreamBYOBReader* reader, NotShared<DOMArrayBufferView> view, + const uint64_t min, ReadIntoRequest* read_into_request, ExceptionState& exception_state) { // https://streams.spec.whatwg.org/#readable-stream-byob-reader-read @@ -171,11 +210,11 @@ script_state, stream->GetStoredError(script_state->GetIsolate())); } else { // 5. Otherwise, perform ! - // ReadableByteStreamControllerPullInto(stream.[[controller]], view, + // ReadableByteStreamControllerPullInto(stream.[[controller]], view, min, // readIntoRequest). ReadableStreamController* controller = stream->readable_stream_controller_; ReadableByteStreamController::PullInto( - script_state, To<ReadableByteStreamController>(controller), view, + script_state, To<ReadableByteStreamController>(controller), view, min, read_into_request, exception_state); } }
diff --git a/third_party/blink/renderer/core/streams/readable_stream_byob_reader.h b/third_party/blink/renderer/core/streams/readable_stream_byob_reader.h index 90a3cf5..0cd5983 100644 --- a/third_party/blink/renderer/core/streams/readable_stream_byob_reader.h +++ b/third_party/blink/renderer/core/streams/readable_stream_byob_reader.h
@@ -20,6 +20,7 @@ class ExceptionState; class ScriptState; class ReadableStream; +class ReadableStreamBYOBReaderReadOptions; class ReadableStreamReadResult; class ReadIntoRequest; class DOMArrayBufferView; @@ -43,10 +44,11 @@ bool IsBYOBReader() const override { return true; } // https://streams.spec.whatwg.org/#byob-reader-read - - ScriptPromise<ReadableStreamReadResult> read(ScriptState*, - NotShared<DOMArrayBufferView>, - ExceptionState&); + ScriptPromise<ReadableStreamReadResult> read( + ScriptState*, + NotShared<DOMArrayBufferView> view, + const ReadableStreamBYOBReaderReadOptions* options, + ExceptionState&); // https://streams.spec.whatwg.org/#byob-reader-release-lock void releaseLock(ScriptState*, ExceptionState&); @@ -75,6 +77,7 @@ static void Read(ScriptState*, ReadableStreamBYOBReader*, NotShared<DOMArrayBufferView> view, + const uint64_t min, ReadIntoRequest*, ExceptionState&);
diff --git a/third_party/blink/renderer/core/streams/readable_stream_byob_reader.idl b/third_party/blink/renderer/core/streams/readable_stream_byob_reader.idl index fee1494d..6af0c21 100644 --- a/third_party/blink/renderer/core/streams/readable_stream_byob_reader.idl +++ b/third_party/blink/renderer/core/streams/readable_stream_byob_reader.idl
@@ -8,7 +8,8 @@ ] interface ReadableStreamBYOBReader { [CallWith=ScriptState, RaisesException] constructor(ReadableStream stream); - [CallWith=ScriptState, RaisesException] Promise<ReadableStreamReadResult> read(ArrayBufferView view); + [CallWith=ScriptState, RaisesException] Promise<ReadableStreamReadResult> read(ArrayBufferView view, optional ReadableStreamBYOBReaderReadOptions options = {}); + [CallWith=ScriptState, RaisesException] void releaseLock(); };
diff --git a/third_party/blink/renderer/core/streams/readable_stream_byob_reader_read_options.idl b/third_party/blink/renderer/core/streams/readable_stream_byob_reader_read_options.idl new file mode 100644 index 0000000..33043399 --- /dev/null +++ b/third_party/blink/renderer/core/streams/readable_stream_byob_reader_read_options.idl
@@ -0,0 +1,9 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// https://streams.spec.whatwg.org/#dictdef-readablestreambyobreaderreadoptions + +dictionary ReadableStreamBYOBReaderReadOptions { + [EnforceRange] unsigned long long min = 1; +};
diff --git a/third_party/blink/renderer/core/streams/readable_stream_test.cc b/third_party/blink/renderer/core/streams/readable_stream_test.cc index 76fc726..0ff1f00 100644 --- a/third_party/blink/renderer/core/streams/readable_stream_test.cc +++ b/third_party/blink/renderer/core/streams/readable_stream_test.cc
@@ -6,8 +6,10 @@ #include <optional> +#include "base/containers/span.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/public/platform/platform.h" #include "third_party/blink/renderer/bindings/core/v8/script_function.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h" @@ -17,6 +19,7 @@ #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h" #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h" #include "third_party/blink/renderer/bindings/core/v8/v8_readable_stream.h" +#include "third_party/blink/renderer/bindings/core/v8/v8_readable_stream_byob_reader_read_options.h" #include "third_party/blink/renderer/bindings/core/v8/v8_readable_stream_get_reader_options.h" #include "third_party/blink/renderer/bindings/core/v8/v8_readable_stream_read_result.h" #include "third_party/blink/renderer/bindings/core/v8/v8_union_readablestreambyobreader_readablestreamdefaultreader.h" @@ -33,6 +36,7 @@ #include "third_party/blink/renderer/platform/bindings/script_state.h" #include "third_party/blink/renderer/platform/bindings/string_resource.h" #include "third_party/blink/renderer/platform/heap/garbage_collected.h" +#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h" #include "third_party/blink/renderer/platform/testing/task_environment.h" #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h" #include "v8/include/v8.h" @@ -109,6 +113,52 @@ NOTREACHED(); } test::TaskEnvironment task_environment_; + + static void ExpectBYOBReadByteLengthAndContents( + ScriptState* script_state, + v8::Isolate* isolate, + ReadableStreamBYOBReader* reader, + NotShared<DOMArrayBufferView> original_view, + ReadableStreamBYOBReaderReadOptions* options, + const std::vector<uint8_t>& expected_bytes) { + ScriptPromiseTester tester( + script_state, reader->read(script_state, original_view, options, + ASSERT_NO_EXCEPTION)); + tester.WaitUntilSettled(); + EXPECT_TRUE(tester.IsFulfilled()); + + v8::Local<v8::Object> result; + ASSERT_TRUE(tester.Value() + .V8Value() + ->ToObject(script_state->GetContext()) + .ToLocal(&result)); + + // Extract the "value" property (a Uint8Array). + v8::Local<v8::Value> value_prop; + ASSERT_TRUE( + result->Get(script_state->GetContext(), V8String(isolate, "value")) + .ToLocal(&value_prop)); + + v8::Local<v8::Object> value_obj; + ASSERT_TRUE( + value_prop->ToObject(script_state->GetContext()).ToLocal(&value_obj)); + + // Get the DOMUint8Array from the JS object. + auto* array_view = ToScriptWrappable<DOMUint8Array>(isolate, value_obj); + ASSERT_TRUE(array_view); + + // Validate length. + const size_t expected_length = expected_bytes.size(); + EXPECT_EQ(array_view->byteLength(), expected_length); + + base::span<const uint8_t> actual_bytes = array_view->AsSpan(); + ASSERT_EQ(actual_bytes.size(), expected_length); + + // Validate contents + for (size_t i = 0; i < expected_length; ++i) { + EXPECT_EQ(actual_bytes, base::span(expected_bytes)); + } + } }; // This breaks expectations for general ReadableStreamTransferringOptimizer @@ -259,11 +309,112 @@ NotShared<DOMArrayBufferView> view = NotShared<DOMUint8Array>(DOMUint8Array::Create(1)); - reader->read(script_state, view, ASSERT_NO_EXCEPTION); + + auto* read_options = ReadableStreamBYOBReaderReadOptions::Create(); + reader->read(script_state, view, read_options, ASSERT_NO_EXCEPTION); EXPECT_TRUE(stream->IsDisturbed()); } +// Tests that `ReadableStreamBYOBReader.read()` correctly fulfills a read +// request when a minimum number of bytes (`min`) is specified. +TEST_F(ReadableStreamTest, BYOBReaderWithMinOption) { + V8TestingScope scope; + ScriptState* script_state = scope.GetScriptState(); + v8::Isolate* isolate = scope.GetIsolate(); + + ScriptValue byte_stream = EvalWithPrintingError(&scope, + R"( + new ReadableStream({ + type: 'bytes', + pull(controller) { + controller.enqueue(new Uint8Array([1,2,3,4,5,6,7])); + } + }) + )"); + ReadableStream* stream = + V8ReadableStream::ToWrappable(isolate, byte_stream.V8Value()); + ASSERT_TRUE(stream); + + auto* options = ReadableStreamGetReaderOptions::Create(); + options->setMode("byob"); + + ReadableStreamBYOBReader* reader = nullptr; + if (const auto* result = + stream->getReader(script_state, options, ASSERT_NO_EXCEPTION)) { + reader = result->GetAsReadableStreamBYOBReader(); + } + ASSERT_TRUE(reader); + + NotShared<DOMArrayBufferView> view_1 = + NotShared<DOMUint8Array>(DOMUint8Array::Create(4)); + + // Set a min value smaller than or equal to `view.byteLength`. + constexpr uint64_t min = 4; + auto* read_options = + MakeGarbageCollected<ReadableStreamBYOBReaderReadOptions>(); + read_options->setMin(min); + ExpectBYOBReadByteLengthAndContents(script_state, isolate, reader, view_1, + read_options, {1, 2, 3, 4}); + + // Request another read of 4 bytes from the stream. Since only 3 bytes remain + // and `min` is set to 4, the read should fulfill with at least the minimum + // number of bytes. + NotShared<DOMArrayBufferView> view_2 = + NotShared<DOMUint8Array>(DOMUint8Array::Create(4)); + ExpectBYOBReadByteLengthAndContents(script_state, isolate, reader, view_2, + read_options, {5, 6, 7, 1}); +} + +// Verifies that `ReadableStreamBYOBReader.read()` ignores the `min` option when +// the feature is disabled. +TEST_F(ReadableStreamTest, BYOBReadMinOptionIgnoredWhenFeatureDisabled) { + ScopedReadableStreamBYOBReaderReadMinOptionForTest byob_min_option(false); + + V8TestingScope scope; + ScriptState* script_state = scope.GetScriptState(); + v8::Isolate* isolate = scope.GetIsolate(); + + // Stream with 5 bytes. + ScriptValue stream_val = EvalWithPrintingError(&scope, + R"( + new ReadableStream({ + type: 'bytes', + pull(controller) { + controller.enqueue(new Uint8Array([1,2,3,4,5])); + } + }) + )"); + ReadableStream* stream = + V8ReadableStream::ToWrappable(isolate, stream_val.V8Value()); + ASSERT_TRUE(stream); + + auto* options = ReadableStreamGetReaderOptions::Create(); + options->setMode("byob"); + + ReadableStreamBYOBReader* reader = nullptr; + if (const auto* result = + stream->getReader(script_state, options, ASSERT_NO_EXCEPTION)) { + reader = result->GetAsReadableStreamBYOBReader(); + } + ASSERT_TRUE(reader); + + // First read with `view` of 3, `min` should be ignored. + NotShared<DOMArrayBufferView> view_1 = + NotShared<DOMUint8Array>(DOMUint8Array::Create(3)); + auto* read_options = + MakeGarbageCollected<ReadableStreamBYOBReaderReadOptions>(); + read_options->setMin(3); + ExpectBYOBReadByteLengthAndContents(script_state, isolate, reader, view_1, + read_options, {1, 2, 3}); + + // Second read to get the last remaining 2 bytes. + NotShared<DOMArrayBufferView> view_2 = + NotShared<DOMUint8Array>(DOMUint8Array::Create(3)); + ExpectBYOBReadByteLengthAndContents(script_state, isolate, reader, view_2, + read_options, {4, 5}); +} + TEST_F(ReadableStreamTest, Cancel) { V8TestingScope scope; ScriptState* script_state = scope.GetScriptState(); @@ -767,8 +918,10 @@ Stream()->GetBYOBReaderForTesting(script_state, ASSERT_NO_EXCEPTION); NotShared<DOMArrayBufferView> view = NotShared<DOMUint8Array>(DOMUint8Array::Create(1)); + auto* options = ReadableStreamBYOBReaderReadOptions::Create(); ScriptPromiseTester read_tester( - script_state, reader->read(script_state, view, ASSERT_NO_EXCEPTION)); + script_state, + reader->read(script_state, view, options, ASSERT_NO_EXCEPTION)); read_tester.WaitUntilSettled(); EXPECT_TRUE(read_tester.IsRejected()); EXPECT_TRUE(IsTypeError(script_state, read_tester.Value(), kMessage)); @@ -813,8 +966,10 @@ Stream()->GetBYOBReaderForTesting(script_state, ASSERT_NO_EXCEPTION); NotShared<DOMArrayBufferView> view = NotShared<DOMUint8Array>(DOMUint8Array::Create(1)); + auto* options = ReadableStreamBYOBReaderReadOptions::Create(); ScriptPromiseTester read_tester( - script_state, reader->read(script_state, view, ASSERT_NO_EXCEPTION)); + script_state, + reader->read(script_state, view, options, ASSERT_NO_EXCEPTION)); // Close a byte stream with pending pull intos should fulfill read requests // with bytes filled is 0 and done is true. Stream()->CloseStream(scope.GetScriptState(), ASSERT_NO_EXCEPTION);
diff --git a/third_party/blink/renderer/core/svg/svg_animation_element.cc b/third_party/blink/renderer/core/svg/svg_animation_element.cc index 8982c382..dadeb1a 100644 --- a/third_party/blink/renderer/core/svg/svg_animation_element.cc +++ b/third_party/blink/renderer/core/svg/svg_animation_element.cc
@@ -372,9 +372,8 @@ DCHECK_EQ(GetCalcMode(), kCalcModePaced); DCHECK_EQ(GetAnimationMode(), kValuesAnimation); - unsigned values_count = values_.size(); - DCHECK_GE(values_count, 1u); - if (values_count == 1) { + const unsigned values_count = values_.size(); + if (values_count <= 1) { // Don't swap lists. use_paced_key_times_ = false; return;
diff --git a/third_party/blink/renderer/core/timing/performance.cc b/third_party/blink/renderer/core/timing/performance.cc index fc0827c..ee864f3 100644 --- a/third_party/blink/renderer/core/timing/performance.cc +++ b/third_party/blink/renderer/core/timing/performance.cc
@@ -1432,12 +1432,4 @@ time_origin_ = time_origin; } -// TODO(https://crbug.com/1457049): remove this once visited links are -// partitioned. -bool Performance::softNavPaintMetricsSupported() const { - CHECK( - RuntimeEnabledFeatures::SoftNavigationHeuristicsExposeFPAndFCPEnabled()); - return true; -} - } // namespace blink
diff --git a/third_party/blink/renderer/core/timing/performance.h b/third_party/blink/renderer/core/timing/performance.h index dcd1fc5c..178f977 100644 --- a/third_party/blink/renderer/core/timing/performance.h +++ b/third_party/blink/renderer/core/timing/performance.h
@@ -328,10 +328,6 @@ return cross_origin_isolated_capability_; } - // TODO(https://crbug.com/1457049): remove this once visited links are - // partitioned. - bool softNavPaintMetricsSupported() const; - base::SingleThreadTaskRunner& GetTaskRunner() { return *task_runner_; } private:
diff --git a/third_party/blink/renderer/core/timing/performance.idl b/third_party/blink/renderer/core/timing/performance.idl index 082305b5..11c4cec 100644 --- a/third_party/blink/renderer/core/timing/performance.idl +++ b/third_party/blink/renderer/core/timing/performance.idl
@@ -74,9 +74,6 @@ [Exposed=Window, SameObject, SaveSameObject] readonly attribute EventCounts eventCounts; [Exposed=Window, RuntimeEnabled=EventTimingInteractionCount] readonly attribute unsigned long long interactionCount; - // TODO(https://crbug.com/1457049): remove this once visited links are partitioned. - [RuntimeEnabled=SoftNavigationHeuristicsExposeFPAndFCP] readonly attribute boolean softNavPaintMetricsSupported; - [Exposed=Window, RuntimeEnabled=UserDefinedEntryPointTiming] Function bind(Function innerFunction, optional any thisArg, any... args); [CallWith=ScriptState, ImplementedAs=toJSONForBinding] object toJSON();
diff --git a/third_party/blink/renderer/core/timing/soft_navigation_heuristics.cc b/third_party/blink/renderer/core/timing/soft_navigation_heuristics.cc index 45feac8..64aa1ad9 100644 --- a/third_party/blink/renderer/core/timing/soft_navigation_heuristics.cc +++ b/third_party/blink/renderer/core/timing/soft_navigation_heuristics.cc
@@ -445,12 +445,6 @@ LocalFrameView* local_frame_view = frame->View(); CHECK(local_frame_view); if (RuntimeEnabledFeatures::SoftNavigationHeuristicsEnabled(window_)) { - if (Document* document = window_->document(); - document && - RuntimeEnabledFeatures::SoftNavigationHeuristicsExposeFPAndFCPEnabled( - window_.Get())) { - PaintTiming::From(*document).ResetFirstPaintAndFCP(); - } local_frame_view->GetPaintTimingDetector().RestartRecordingLCP(); } @@ -469,10 +463,6 @@ local_frame_view->GetPaintTimingDetector().SoftNavigationDetected( window_.Get()); - if (RuntimeEnabledFeatures::SoftNavigationHeuristicsExposeFPAndFCPEnabled( - window_.Get())) { - PaintTiming::From(*window_->document()).SoftNavigationDetected(); - } } void SoftNavigationHeuristics::Trace(Visitor* visitor) const {
diff --git a/third_party/blink/renderer/modules/content_extraction/ai_page_content_agent.cc b/third_party/blink/renderer/modules/content_extraction/ai_page_content_agent.cc index 2d8750a..154670a 100644 --- a/third_party/blink/renderer/modules/content_extraction/ai_page_content_agent.cc +++ b/third_party/blink/renderer/modules/content_extraction/ai_page_content_agent.cc
@@ -682,6 +682,10 @@ // activation reason of FindInPage. std::vector<DisplayLockDocumentState::ScopedForceActivatableDisplayLocks> forced_activatable_locks; + + // If we're doing this extraction as a part of the document lifecycle, we + // can't invalidate style/layout. + if (!document.InvalidationDisallowed()) { forced_activatable_locks.emplace_back( document.GetDisplayLockDocumentState() .GetScopedForceActivatableLocks()); @@ -697,6 +701,7 @@ ->GetDisplayLockDocumentState() .GetScopedForceActivatableLocks()); }); + } // Running lifecycle beyond layout is expensive and the information is only // needed to compute geometry. Limit the update to layout if we don't need
diff --git a/third_party/blink/renderer/modules/content_extraction/ai_page_content_agent_unittest.cc b/third_party/blink/renderer/modules/content_extraction/ai_page_content_agent_unittest.cc index e087fb9..6f785281 100644 --- a/third_party/blink/renderer/modules/content_extraction/ai_page_content_agent_unittest.cc +++ b/third_party/blink/renderer/modules/content_extraction/ai_page_content_agent_unittest.cc
@@ -1493,6 +1493,40 @@ CheckTextNode(visible_text_node, "visible text"); } +TEST_F(AIPageContentAgentTest, HiddenUntilFoundNoInvalidationAllowed) { + frame_test_helpers::LoadHTMLString( + helper_.LocalMainFrame(), + R"HTML( + <body> + <style> + body { + margin: 0; font-size: 100px; + } + </style> + <header hidden=until-found>hidden text</header><div>visible text</div> + </body> + )HTML", + url_test_helpers::ToKURL("http://foobar.com")); + + LocalFrameView::InvalidationDisallowedScope disallow( + *helper_.LocalMainFrame()->GetFrame()->View()); + GetAIPageContent(); + + const auto& root = ContentRootNode(); + EXPECT_EQ(root.children_nodes.size(), 2u); + + const auto& hidden_container = *root.children_nodes[0]; + CheckContainerNode(hidden_container); + CheckAnnotatedRoles( + hidden_container, + {mojom::blink::AIPageContentAnnotatedRole::kHeader, + mojom::blink::AIPageContentAnnotatedRole::kContentHidden}); + EXPECT_TRUE(hidden_container.children_nodes.empty()); + + const auto& visible_text_node = *root.children_nodes[1]; + CheckTextNode(visible_text_node, "visible text"); +} + TEST_F(AIPageContentAgentTest, HiddenUntilFoundGeometry) { frame_test_helpers::LoadHTMLString( helper_.LocalMainFrame(),
diff --git a/third_party/blink/renderer/modules/credentialmanagement/authentication_credentials_container.cc b/third_party/blink/renderer/modules/credentialmanagement/authentication_credentials_container.cc index debff546..2534d49 100644 --- a/third_party/blink/renderer/modules/credentialmanagement/authentication_credentials_container.cc +++ b/third_party/blink/renderer/modules/credentialmanagement/authentication_credentials_container.cc
@@ -100,7 +100,6 @@ using mojom::blink::CredentialInfoPtr; using mojom::blink::CredentialManagerError; using mojom::blink::CredentialMediationRequirement; -using mojom::blink::PaymentCredentialInstrument; using mojom::blink::WebAuthnDOMExceptionDetailsPtr; using MojoPublicKeyCredentialCreationOptions = mojom::blink::PublicKeyCredentialCreationOptions;
diff --git a/third_party/blink/renderer/modules/manifest/manifest_parser.cc b/third_party/blink/renderer/modules/manifest/manifest_parser.cc index fdf9a7a1..bfab22e3 100644 --- a/third_party/blink/renderer/modules/manifest/manifest_parser.cc +++ b/third_party/blink/renderer/modules/manifest/manifest_parser.cc
@@ -327,14 +327,6 @@ ParseId(root_object.get(), manifest_->start_url); manifest_->id = id; manifest_->has_custom_id = id_parse_result == ParseIdResultType::kSucceed; - - manifest_->update_token = - ParseUpdateToken(root_object.get(), manifest_->has_custom_id); - if (!manifest_->update_token.IsNull()) { - UseCounter::CountWebDXFeature(execution_context_, - WebDXFeature::kWebAppManifestUpdateToken); - } - manifest_->scope = ParseScope(root_object.get(), manifest_->start_url); manifest_->display = ParseDisplay(root_object.get()); if (manifest_->display != mojom::blink::DisplayMode::kUndefined) { @@ -2535,13 +2527,6 @@ return ParseString(object, "version", Trim(false)).value_or(String()); } -String ManifestParser::ParseUpdateToken(const JSONObject* object, - bool has_id_in_manifest) { - return has_id_in_manifest ? ParseString(object, "update_token", Trim(false)) - .value_or(String()) - : String(); -} - void ManifestParser::AddErrorInfo(const String& error_msg, bool critical, int error_line,
diff --git a/third_party/blink/renderer/modules/manifest/manifest_parser.h b/third_party/blink/renderer/modules/manifest/manifest_parser.h index 9e7af22..6155833 100644 --- a/third_party/blink/renderer/modules/manifest/manifest_parser.h +++ b/third_party/blink/renderer/modules/manifest/manifest_parser.h
@@ -564,10 +564,6 @@ String ParseVersion(const JSONObject* object); - // Parses the `update_token` field in the manifest iff the `id` is defined in - // the manifest. Returns `String()` which is null otherwise. - String ParseUpdateToken(const JSONObject* object, bool has_custom_id); - void AddErrorInfo(const String& error_msg, bool critical = false, int error_line = 0,
diff --git a/third_party/blink/renderer/modules/manifest/manifest_parser_unittest.cc b/third_party/blink/renderer/modules/manifest/manifest_parser_unittest.cc index 232e06c..fa76fc5 100644 --- a/third_party/blink/renderer/modules/manifest/manifest_parser_unittest.cc +++ b/third_party/blink/renderer/modules/manifest/manifest_parser_unittest.cc
@@ -6619,98 +6619,4 @@ } } -TEST_F(ManifestParserTest, UpdateTokenParseRules) { - // update_token is not parsed when manifest id is not specified - { - auto& manifest = ParseManifest(R"({"update_token": "foo" })"); - EXPECT_TRUE(manifest->update_token.IsNull()); - EXPECT_NE(manifest->update_token, "foo"); - EXPECT_FALSE(GetDocument().IsWebDXFeatureCounted( - WebDXFeature::kWebAppManifestUpdateToken)); - EXPECT_EQ(0u, GetErrorCount()); - } - - // update_token is not parsed when manifest id is not specified by the - // developer and uses the default value. - { - auto& manifest = ParseManifest(R"({ "id": "", "update_token": "foo" })"); - EXPECT_TRUE(manifest->update_token.IsNull()); - EXPECT_NE(manifest->update_token, "foo"); - EXPECT_FALSE(GetDocument().IsWebDXFeatureCounted( - WebDXFeature::kWebAppManifestUpdateToken)); - EXPECT_EQ(0u, GetErrorCount()); - } - - // update_token is valid but not parsed since the manifest id is invalid. - { - auto& manifest = ParseManifest(R"({ "id": 42, "update_token": "foo" })"); - EXPECT_TRUE(manifest->update_token.IsNull()); - EXPECT_NE(manifest->update_token, "foo"); - EXPECT_FALSE(GetDocument().IsWebDXFeatureCounted( - WebDXFeature::kWebAppManifestUpdateToken)); - // 1 error since `id` will be ignored as this is not a string. - EXPECT_EQ(1u, GetErrorCount()); - } - - // update_token is valid but not parsed since the manifest id is a json - // (malformed input). - { - auto& manifest = ParseManifest(R"({ "id": {}, "update_token": "foo" })"); - EXPECT_TRUE(manifest->update_token.IsNull()); - EXPECT_NE(manifest->update_token, "foo"); - EXPECT_FALSE(GetDocument().IsWebDXFeatureCounted( - WebDXFeature::kWebAppManifestUpdateToken)); - // 1 error since `id` will be ignored as this is not a string. - EXPECT_EQ(1u, GetErrorCount()); - } - - // update_token not specified in the manifest so it is not parsed. - { - auto& manifest = ParseManifest(R"({"id": "foo", "version": "1.2.3" })"); - EXPECT_TRUE(manifest->update_token.IsNull()); - EXPECT_FALSE(GetDocument().IsWebDXFeatureCounted( - WebDXFeature::kWebAppManifestUpdateToken)); - EXPECT_EQ(0u, GetErrorCount()); - } - - // update_token as an empty string is parsed and counted since it is not null. - { - auto& manifest = ParseManifest(R"({"id": "foo", "update_token": "" })"); - EXPECT_FALSE(manifest->update_token.IsNull()); - EXPECT_TRUE(manifest->update_token.empty()); - EXPECT_EQ(0u, GetErrorCount()); - EXPECT_TRUE(GetDocument().IsWebDXFeatureCounted( - WebDXFeature::kWebAppManifestUpdateToken)); - } - - // update_token specified in the manifest are parsed and increments use - // counter - { - auto& manifest = ParseManifest(R"({ "id": "foo", "update_token": "foo" })"); - EXPECT_FALSE(manifest->update_token.IsNull()); - EXPECT_EQ(manifest->update_token, "foo"); - EXPECT_TRUE(GetDocument().IsWebDXFeatureCounted( - WebDXFeature::kWebAppManifestUpdateToken)); - EXPECT_EQ(0u, GetErrorCount()); - } - - // Don't parse if update_token is not a string (invalid data type). - { - auto& manifest = ParseManifest(R"({"id": "foo", "update_token": 42 })"); - EXPECT_TRUE(manifest->update_token.IsNull()); - ASSERT_EQ(1u, GetErrorCount()); - EXPECT_EQ("property 'update_token' ignored, type string expected.", - errors()[0]); - } - - // Don't parse if update_token is a json (malformed input). - { - auto& manifest = ParseManifest(R"({"id": "foo", "update_token": {} })"); - EXPECT_TRUE(manifest->update_token.IsNull()); - ASSERT_EQ(1u, GetErrorCount()); - EXPECT_EQ("property 'update_token' ignored, type string expected.", - errors()[0]); - } -} - } // namespace blink
diff --git a/third_party/blink/renderer/modules/speech/speech_grammar.idl b/third_party/blink/renderer/modules/speech/speech_grammar.idl index 0b86587..62f0c04 100644 --- a/third_party/blink/renderer/modules/speech/speech_grammar.idl +++ b/third_party/blink/renderer/modules/speech/speech_grammar.idl
@@ -29,7 +29,7 @@ LegacyWindowAlias=webkitSpeechGrammar, LegacyWindowAlias_Measure, LegacyWindowAlias_RuntimeEnabled=ScriptedSpeechRecognition, - LegacyNoInterfaceObject + Exposed=Window, RuntimeEnabled=UnprefixedSpeechRecognition ] interface SpeechGrammar { [Measure] constructor(); [URL,CallWith=ScriptState] attribute DOMString src;
diff --git a/third_party/blink/renderer/modules/speech/speech_grammar_list.idl b/third_party/blink/renderer/modules/speech/speech_grammar_list.idl index 41acd6c..af54d02 100644 --- a/third_party/blink/renderer/modules/speech/speech_grammar_list.idl +++ b/third_party/blink/renderer/modules/speech/speech_grammar_list.idl
@@ -29,7 +29,7 @@ LegacyWindowAlias=webkitSpeechGrammarList, LegacyWindowAlias_Measure, LegacyWindowAlias_RuntimeEnabled=ScriptedSpeechRecognition, - LegacyNoInterfaceObject + Exposed=Window, RuntimeEnabled=UnprefixedSpeechRecognition ] interface SpeechGrammarList { [Measure] constructor(); readonly attribute unsigned long length;
diff --git a/third_party/blink/renderer/modules/speech/speech_recognition.idl b/third_party/blink/renderer/modules/speech/speech_recognition.idl index ac8ffbf..7f3d0402 100644 --- a/third_party/blink/renderer/modules/speech/speech_recognition.idl +++ b/third_party/blink/renderer/modules/speech/speech_recognition.idl
@@ -49,7 +49,7 @@ LegacyWindowAlias=webkitSpeechRecognition, LegacyWindowAlias_Measure, LegacyWindowAlias_RuntimeEnabled=ScriptedSpeechRecognition, - LegacyNoInterfaceObject + Exposed=Window, RuntimeEnabled=UnprefixedSpeechRecognition ] interface SpeechRecognition : EventTarget { [CallWith=ExecutionContext, Measure] constructor(); // recognition parameters
diff --git a/third_party/blink/renderer/modules/speech/speech_recognition_error_event.idl b/third_party/blink/renderer/modules/speech/speech_recognition_error_event.idl index b75869f..c12f7c2 100644 --- a/third_party/blink/renderer/modules/speech/speech_recognition_error_event.idl +++ b/third_party/blink/renderer/modules/speech/speech_recognition_error_event.idl
@@ -29,7 +29,7 @@ LegacyWindowAlias=webkitSpeechRecognitionError, LegacyWindowAlias_Measure, LegacyWindowAlias_RuntimeEnabled=ScriptedSpeechRecognition, - LegacyNoInterfaceObject + Exposed=Window, RuntimeEnabled=UnprefixedSpeechRecognition ] interface SpeechRecognitionErrorEvent : Event { constructor(DOMString type, optional SpeechRecognitionErrorEventInit eventInitDict = {}); readonly attribute DOMString error;
diff --git a/third_party/blink/renderer/modules/speech/speech_recognition_event.idl b/third_party/blink/renderer/modules/speech/speech_recognition_event.idl index c06bb2e..1d85c6ff 100644 --- a/third_party/blink/renderer/modules/speech/speech_recognition_event.idl +++ b/third_party/blink/renderer/modules/speech/speech_recognition_event.idl
@@ -29,7 +29,7 @@ LegacyWindowAlias=webkitSpeechRecognitionEvent, LegacyWindowAlias_Measure, LegacyWindowAlias_RuntimeEnabled=ScriptedSpeechRecognition, - LegacyNoInterfaceObject + Exposed=Window, RuntimeEnabled=UnprefixedSpeechRecognition ] interface SpeechRecognitionEvent : Event { constructor(DOMString type, optional SpeechRecognitionEventInit initDict = {}); readonly attribute unsigned long resultIndex;
diff --git a/third_party/blink/renderer/modules/webtransport/incoming_stream_test.cc b/third_party/blink/renderer/modules/webtransport/incoming_stream_test.cc index cdabcd5..6d6ea8c 100644 --- a/third_party/blink/renderer/modules/webtransport/incoming_stream_test.cc +++ b/third_party/blink/renderer/modules/webtransport/incoming_stream_test.cc
@@ -16,6 +16,7 @@ #include "third_party/blink/renderer/bindings/core/v8/to_v8_traits.h" #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h" #include "third_party/blink/renderer/bindings/core/v8/v8_dom_exception.h" +#include "third_party/blink/renderer/bindings/core/v8/v8_readable_stream_byob_reader_read_options.h" #include "third_party/blink/renderer/bindings/core/v8/v8_readable_stream_read_result.h" #include "third_party/blink/renderer/core/dom/dom_exception.h" #include "third_party/blink/renderer/core/streams/readable_stream.h" @@ -105,7 +106,10 @@ ReadableStreamBYOBReader* reader, NotShared<DOMArrayBufferView> view) { auto* script_state = scope.GetScriptState(); - auto read_promise = reader->read(script_state, view, ASSERT_NO_EXCEPTION); + auto* read_options = + MakeGarbageCollected<ReadableStreamBYOBReaderReadOptions>(); + auto read_promise = + reader->read(script_state, view, read_options, ASSERT_NO_EXCEPTION); ScriptPromiseTester tester(script_state, read_promise); tester.WaitUntilSettled(); EXPECT_TRUE(tester.IsFulfilled()); @@ -132,6 +136,26 @@ return ret; } + static Iterator IteratorFromReadResultAllowingValueOnDone( + V8TestingScope& scope, + v8::Local<v8::Value> result) { + CHECK(result->IsObject()); + Iterator ret; + v8::Local<v8::Value> v8value; + if (!V8UnpackIterationResult(scope.GetScriptState(), + result.As<v8::Object>(), &v8value, + &ret.done)) { + ADD_FAILURE() << "Couldn't unpack iterator"; + return {}; + } + + if (!v8value->IsUndefined()) { + ret.value = ToVector(scope, v8value); + } + + return ret; + } + base::MockOnceCallback<void(std::optional<uint8_t>)> mock_on_abort_; test::TaskEnvironment task_environment_; mojo::ScopedDataPipeProducerHandle data_pipe_producer_; @@ -168,7 +192,10 @@ script_state, ASSERT_NO_EXCEPTION); NotShared<DOMArrayBufferView> view = NotShared<DOMUint8Array>(DOMUint8Array::Create(1)); - auto read_promise = reader->read(script_state, view, ASSERT_NO_EXCEPTION); + auto* read_options = + MakeGarbageCollected<ReadableStreamBYOBReaderReadOptions>(); + auto read_promise = + reader->read(script_state, view, read_options, ASSERT_NO_EXCEPTION); ScriptPromiseTester tester(script_state, read_promise); EXPECT_FALSE(tester.IsFulfilled()); @@ -186,6 +213,131 @@ EXPECT_THAT(result.value, ElementsAre('B', 'C')); } +// Ensure that when `min` is less than buffer size, the BYOB reader +// does not resolve until `min` bytes are available. +TEST_F(IncomingStreamTest, + ReadArrayBufferWithBYOBReaderAndMinOptionLessThanBufferSize) { + V8TestingScope scope; + + auto* incoming_stream = CreateIncomingStream(scope); + auto* script_state = scope.GetScriptState(); + auto* reader = incoming_stream->Readable()->GetBYOBReaderForTesting( + script_state, ASSERT_NO_EXCEPTION); + + // Create a view of 5 bytes. + NotShared<DOMArrayBufferView> view = + NotShared<DOMUint8Array>(DOMUint8Array::Create(5)); + + // Set `min` = 3. + auto* read_options = + MakeGarbageCollected<ReadableStreamBYOBReaderReadOptions>(); + read_options->setMin(3); + + // Start the read before writing any data. + auto read_promise = + reader->read(script_state, view, read_options, ASSERT_NO_EXCEPTION); + ScriptPromiseTester tester(script_state, read_promise); + + // Write only 2 bytes: should not fulfill yet since `min` = 3. + WriteToPipe({'A', 'B'}); + test::RunPendingTasks(); + EXPECT_FALSE(tester.IsFulfilled()); + + // Write one more byte (total now = 3): should fulfill. + WriteToPipe({'C'}); + tester.WaitUntilSettled(); + EXPECT_TRUE(tester.IsFulfilled()); + + Iterator result = IteratorFromReadResult(scope, tester.Value().V8Value()); + EXPECT_FALSE(result.done); + EXPECT_EQ(result.value.size(), 3u); + EXPECT_THAT(result.value, ElementsAre('A', 'B', 'C')); +} + +// Ensure read with `min` equal to buffer size only resolves when the full +// buffer can be filled. +TEST_F(IncomingStreamTest, ReadArrayBufferWithBYOBReaderMinEqualToBufferSize) { + V8TestingScope scope; + + auto* incoming_stream = CreateIncomingStream(scope); + auto* script_state = scope.GetScriptState(); + auto* reader = incoming_stream->Readable()->GetBYOBReaderForTesting( + script_state, ASSERT_NO_EXCEPTION); + + // Create a view of 4 bytes. + NotShared<DOMArrayBufferView> view = + NotShared<DOMUint8Array>(DOMUint8Array::Create(4)); + + // Set `min` = 4 (equal to view size). + auto* read_options = + MakeGarbageCollected<ReadableStreamBYOBReaderReadOptions>(); + read_options->setMin(4); + + // Start the read before writing any data. + auto read_promise = + reader->read(script_state, view, read_options, ASSERT_NO_EXCEPTION); + ScriptPromiseTester tester(script_state, read_promise); + + // Write only 3 bytes, which is not enough to fulfill. + WriteToPipe({'A', 'B', 'C'}); + test::RunPendingTasks(); + EXPECT_FALSE(tester.IsFulfilled()); + + // Write 1 more byte (total = 4), now it should fulfill. + WriteToPipe({'D'}); + tester.WaitUntilSettled(); + EXPECT_TRUE(tester.IsFulfilled()); + + Iterator result = IteratorFromReadResult(scope, tester.Value().V8Value()); + EXPECT_FALSE(result.done); + EXPECT_EQ(result.value.size(), 4u); + EXPECT_THAT(result.value, ElementsAre('A', 'B', 'C', 'D')); +} + +// This test verifies that a BYOB read with a `min` requirement resolves with +// available data when the stream is closed remotely before `min` bytes are +// received. Even though `min` was not satisfied, the read must resolve with the +// partial data instead of hanging or throwing, as per the spec behavior for +// stream closure. +TEST_F(IncomingStreamTest, ReadWithMinAndStreamClosure) { + V8TestingScope scope; + + auto* incoming_stream = CreateIncomingStream(scope); + auto* script_state = scope.GetScriptState(); + auto* reader = incoming_stream->Readable()->GetBYOBReaderForTesting( + script_state, ASSERT_NO_EXCEPTION); + + NotShared<DOMArrayBufferView> view = + NotShared<DOMUint8Array>(DOMUint8Array::Create(4)); + + auto* read_options = + MakeGarbageCollected<ReadableStreamBYOBReaderReadOptions>(); + read_options->setMin(4); + + auto read_promise = + reader->read(script_state, view, read_options, ASSERT_NO_EXCEPTION); + ScriptPromiseTester tester(script_state, read_promise); + + // Write only 3 bytes. + WriteToPipe({'A', 'B', 'C'}); + test::RunPendingTasks(); + EXPECT_FALSE(tester.IsFulfilled()); + + incoming_stream->OnIncomingStreamClosed(true); + ClosePipe(); + + test::RunPendingTasks(); + tester.WaitUntilSettled(); + EXPECT_TRUE(tester.IsFulfilled()); + + // Validate that 3 bytes were returned. + Iterator result = IteratorFromReadResultAllowingValueOnDone( + scope, tester.Value().V8Value()); + EXPECT_TRUE(result.done); + EXPECT_EQ(result.value.size(), 3u); + EXPECT_THAT(result.value, ElementsAre('A', 'B', 'C')); +} + // Reading data followed by a remote close should not lose data. TEST_F(IncomingStreamTest, ReadThenClosedWithFin) { V8TestingScope scope;
diff --git a/third_party/blink/renderer/modules/webtransport/web_transport_test.cc b/third_party/blink/renderer/modules/webtransport/web_transport_test.cc index 6be7e69..cf3a569 100644 --- a/third_party/blink/renderer/modules/webtransport/web_transport_test.cc +++ b/third_party/blink/renderer/modules/webtransport/web_transport_test.cc
@@ -28,6 +28,7 @@ #include "third_party/blink/renderer/bindings/core/v8/v8_dom_exception.h" #include "third_party/blink/renderer/bindings/core/v8/v8_gc_controller.h" #include "third_party/blink/renderer/bindings/core/v8/v8_readable_stream.h" +#include "third_party/blink/renderer/bindings/core/v8/v8_readable_stream_byob_reader_read_options.h" #include "third_party/blink/renderer/bindings/core/v8/v8_readable_stream_read_result.h" #include "third_party/blink/renderer/bindings/core/v8/v8_union_arraybuffer_arraybufferview.h" #include "third_party/blink/renderer/bindings/core/v8/v8_writable_stream.h" @@ -1010,7 +1011,11 @@ NotShared<DOMArrayBufferView> view = NotShared<DOMUint8Array>(DOMUint8Array::Create(1)); - auto result = reader->read(script_state, view, ASSERT_NO_EXCEPTION); + auto* read_options = + MakeGarbageCollected<ReadableStreamBYOBReaderReadOptions>(); + + auto result = + reader->read(script_state, view, read_options, ASSERT_NO_EXCEPTION); ScriptPromiseTester tester(script_state, result); const std::array<uint8_t, 1> chunk = {'A'}; @@ -1023,6 +1028,45 @@ EXPECT_THAT(GetValueAsVector(script_state, tester.Value()), ElementsAre('A')); } +TEST_F(WebTransportTest, ReceiveDatagramWithBYOBReaderMinOption) { + V8TestingScope scope; + auto* script_state = scope.GetScriptState(); + auto* web_transport = + CreateAndConnectSuccessfully(scope, "https://example.com"); + + auto* readable = web_transport->datagrams()->readable(); + auto* reader = + readable->GetBYOBReaderForTesting(script_state, ASSERT_NO_EXCEPTION); + + // Create a buffer of 4 bytes. + NotShared<DOMArrayBufferView> view = + NotShared<DOMUint8Array>(DOMUint8Array::Create(4)); + + auto* read_options = + MakeGarbageCollected<ReadableStreamBYOBReaderReadOptions>(); + read_options->setMin(2); + + // Request to read at least 2 bytes. + ScriptPromiseTester tester( + script_state, + reader->read(script_state, view, read_options, ASSERT_NO_EXCEPTION)); + + // Send only 1 byte first. This should not fulfill the read. + client_remote_->OnDatagramReceived({'A'}); + test::RunPendingTasks(); + // Promise should still be pending. + EXPECT_FALSE(tester.IsFulfilled()); + EXPECT_FALSE(tester.IsRejected()); + // Send another byte. + client_remote_->OnDatagramReceived({'B'}); + test::RunPendingTasks(); + tester.WaitUntilSettled(); + + EXPECT_TRUE(tester.IsFulfilled()); + EXPECT_THAT(GetValueAsVector(script_state, tester.Value()), + ElementsAre('A', 'B')); +} + bool IsRangeError(ScriptState* script_state, ScriptValue value, const String& message) { @@ -1059,7 +1103,12 @@ NotShared<DOMArrayBufferView> view = NotShared<DOMUint8Array>(DOMUint8Array::Create(1)); - auto result = reader->read(script_state, view, ASSERT_NO_EXCEPTION); + auto* read_options = + MakeGarbageCollected<ReadableStreamBYOBReaderReadOptions>(); + read_options->setMin(1); + + auto result = + reader->read(script_state, view, read_options, ASSERT_NO_EXCEPTION); ScriptPromiseTester tester(script_state, result); const std::array<uint8_t, 3> chunk = {'A', 'B', 'C'};
diff --git a/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc b/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc index 1b0acf3..a4de956b 100644 --- a/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc +++ b/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc
@@ -217,7 +217,7 @@ is_rendering_ = false; frame_trackers_.StopSequence(cc::FrameSequenceTrackerType::kVideo); - frame_sorter_.Reset(); + frame_sorter_.Reset(/*reset_fcp=*/false); UpdateSubmissionState(); }
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5 index f7d16aca..35ffab4f 100644 --- a/third_party/blink/renderer/platform/runtime_enabled_features.json5 +++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -2879,6 +2879,10 @@ public: true, }, { + name: "LayoutAddChildBeforeDescendantFix", + status: "stable", + }, + { // LayoutBox::PhysicalLocation() to return a truly visual offset - the // offset of its first fragment relatively to the first fragment of its // containing block, also when block-fragmented (used to be in the @@ -3887,6 +3891,14 @@ name: "ReadableStreamAsyncIterable", status: "stable", }, + { + // Enables support for a 'min' option in ReadableStream BYOBReader.read(), + // allowing callers to specify the minimum number of bytes to be read into + // the buffer before resolving the read request. + // https://chromestatus.com/feature/6396991665602560 + name: "ReadableStreamBYOBReaderReadMinOption", + status: "experimental", + }, // If enabled, both Accept-Language HTTP header and JavaScript getter will // be reduced. { @@ -4640,9 +4652,6 @@ origin_trial_feature_name: "SoftNavigationHeuristics", }, { - name: "SoftNavigationHeuristicsExposeFPAndFCP", - }, - { // Whether spatial navigation should use cursor inheritance to exclude // nodes where cursor is inherited. Kill-switch that can be remove once // the change goes through a stable release. @@ -5034,9 +5043,9 @@ { name: "TranslationAPI", status: { - "Win": "experimental", - "Mac": "experimental", - "Linux": "experimental", + "Win": "stable", + "Mac": "stable", + "Linux": "stable", "default": "", }, origin_trial_feature_name: "TranslationAPI", @@ -5089,6 +5098,11 @@ { name: "UnexposedTaskIds", }, + // This is a kill switch for the unprefixed Web Speech API. + { + name: "UnprefixedSpeechRecognition", + status: "stable", + }, { name: "UnrestrictedMeasureUserAgentSpecificMemory", }, @@ -5636,6 +5650,7 @@ }, { name: "WebSpeechRecognitionContext", + status: "experimental", }, { name: "WebTransportCustomCertificates",
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index 51d13c87..4e3f06c9 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -1028,7 +1028,6 @@ # [css-flexbox] -crbug.com/807497 external/wpt/css/css-flexbox/anonymous-flex-item-005.html [ Failure ] crbug.com/1311206 external/wpt/css/css-sizing/aspect-ratio/flex-aspect-ratio-038.html [ Failure ] # Needs "new" flex container intrinsic size algorithm to work in the block direction. @@ -3073,6 +3072,7 @@ crbug.com/386128935 [ Mac12 ] external/wpt/css/css-position/position-fixed-scroll-nested-fixed.html [ Failure ] crbug.com/386128935 [ Mac13 ] external/wpt/css/css-position/position-fixed-scroll-nested-fixed.html [ Failure ] crbug.com/386128935 [ Mac14 ] external/wpt/css/css-position/position-fixed-scroll-nested-fixed.html [ Failure ] +crbug.com/386128935 [ Mac15 ] external/wpt/css/css-position/position-fixed-scroll-nested-fixed.html [ Failure ] crbug.com/385918134 [ Linux ] external/wpt/wasm/core/address.wast.js.html [ Crash ] crbug.com/385918134 [ Linux ] external/wpt/wasm/core/align.wast.js.html [ Crash ] crbug.com/385918134 [ Linux ] external/wpt/wasm/core/imports.wast.js.html [ Crash ]
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 90f7298..bc16f2a6 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
@@ -413529,7 +413529,7 @@ [] ], "dom.idl": [ - "253e7bf913eba90db9dc6c2e7e7412dda6f2d493", + "d2129285383a34e28ea3b04989273b7e76f6d0dd", [] ], "edit-context.idl": [ @@ -413649,7 +413649,7 @@ [] ], "html.idl": [ - "3a7dce9693ef3ecaaf1ea274029663b8068c4222", + "a7a03c97ad07a65cb672ba280864882d1de0fb99", [] ], "idle-detection.idl": [ @@ -413888,6 +413888,10 @@ "516fb59d8d41489b405264289a4a0fd814f79fa8", [] ], + "pointer-animations.idl": [ + "e1b03197514cf0fffd78c3de17ec84ef94eace21", + [] + ], "pointerevents.idl": [ "0356e845058a5c97d27f96c5bc41e8ea74bd9cbc", [] @@ -414009,7 +414013,7 @@ [] ], "secure-payment-confirmation.idl": [ - "0a2207684ec71074ffea786bf459b6073799e8d3", + "c0cbc41e99cf5b053a742495cda7474e66299779", [] ], "selection-api.idl": [
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/anonymous-grid-items-002-ref.html b/third_party/blink/web_tests/external/wpt/css/css-grid/anonymous-grid-items-002-ref.html new file mode 100644 index 0000000..0a14a1f9 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-grid/anonymous-grid-items-002-ref.html
@@ -0,0 +1,6 @@ +<!DOCTYPE html> +<p>Test passes if there are two lines below:</p> +<hr> +<div style="display: grid; grid-auto-flow: row;"> + line one <span style="position: absolute;"></span> line two +</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/anonymous-grid-items-002.html b/third_party/blink/web_tests/external/wpt/css/css-grid/anonymous-grid-items-002.html new file mode 100644 index 0000000..5463b725 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-grid/anonymous-grid-items-002.html
@@ -0,0 +1,12 @@ +<!DOCTYPE html> +<link rel="help" href="https://drafts.csswg.org/css-grid-1/#grid-items"> +<link rel="match" href="anonymous-grid-items-002-ref.html"> +<p>Test passes if there are two lines below:</p> +<hr> +<div style="display: grid; grid-auto-flow: row;"> + line one <span id="target" style="position: absolute; display: none;"></span> line two +</div> +<script> +document.body.offsetTop; +document.getElementById('target').style.display = 'inline'; +</script>
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/dom.idl b/third_party/blink/web_tests/external/wpt/interfaces/dom.idl index 253e7bf..d21292853 100644 --- a/third_party/blink/web_tests/external/wpt/interfaces/dom.idl +++ b/third_party/blink/web_tests/external/wpt/interfaces/dom.idl
@@ -324,7 +324,7 @@ [Exposed=Window] interface DOMImplementation { - [NewObject] DocumentType createDocumentType(DOMString qualifiedName, DOMString publicId, DOMString systemId); + [NewObject] DocumentType createDocumentType(DOMString name, DOMString publicId, DOMString systemId); [NewObject] XMLDocument createDocument(DOMString? namespace, [LegacyNullToEmptyString] DOMString qualifiedName, optional DocumentType? doctype = null); [NewObject] Document createHTMLDocument(optional DOMString title);
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/html.idl b/third_party/blink/web_tests/external/wpt/interfaces/html.idl index 3a7dce96..a7a03c9 100644 --- a/third_party/blink/web_tests/external/wpt/interfaces/html.idl +++ b/third_party/blink/web_tests/external/wpt/interfaces/html.idl
@@ -1695,7 +1695,7 @@ constructor(DOMString type, optional ToggleEventInit eventInitDict = {}); readonly attribute DOMString oldState; readonly attribute DOMString newState; - readonly attribute Element source; + readonly attribute Element? source; }; dictionary ToggleEventInit : EventInit {
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/pointer-animations.idl b/third_party/blink/web_tests/external/wpt/interfaces/pointer-animations.idl new file mode 100644 index 0000000..e1b0319 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/interfaces/pointer-animations.idl
@@ -0,0 +1,23 @@ +// GENERATED CONTENT - DO NOT EDIT +// Content was automatically extracted by Reffy into webref +// (https://github.com/w3c/webref) +// Source: Pointer-driven Animations (https://drafts.csswg.org/pointer-animations-1/) + +enum PointerAxis { + "block", + "inline", + "x", + "y" +}; + +dictionary PointerTimelineOptions { + Element? source; + PointerAxis axis = "block"; +}; + +[Exposed=Window] +interface PointerTimeline : AnimationTimeline { + constructor(optional PointerTimelineOptions options = {}); + readonly attribute Element? source; + readonly attribute PointerAxis axis; +};
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/secure-payment-confirmation.idl b/third_party/blink/web_tests/external/wpt/interfaces/secure-payment-confirmation.idl index 0a22076..c0cbc41 100644 --- a/third_party/blink/web_tests/external/wpt/interfaces/secure-payment-confirmation.idl +++ b/third_party/blink/web_tests/external/wpt/interfaces/secure-payment-confirmation.idl
@@ -13,6 +13,7 @@ USVString payeeOrigin; sequence<PaymentEntityLogo> paymentEntitiesLogos; AuthenticationExtensionsClientInputs extensions; + sequence<PublicKeyCredentialParameters> browserBoundPubKeyCredParams; sequence<USVString> locale; boolean showOptOut; }; @@ -35,6 +36,7 @@ dictionary AuthenticationExtensionsPaymentInputs { boolean isPayment; + sequence<PublicKeyCredentialParameters> browserBoundPubKeyCredParams; // Only used for authentication. USVString rpId; @@ -46,8 +48,20 @@ PaymentCredentialInstrument instrument; }; +partial dictionary AuthenticationExtensionsClientOutputs { + AuthenticationExtensionsPaymentOutputs payment; +}; + +dictionary AuthenticationExtensionsPaymentOutputs { + BrowserBoundSignature browserBoundSignature; +}; + +dictionary BrowserBoundSignature { + required ArrayBuffer signature; +}; + dictionary CollectedClientPaymentData : CollectedClientData { - required CollectedClientAdditionalPaymentData payment; + required (CollectedClientAdditionalPaymentData or CollectedClientAdditionalPaymentRegistrationData) payment; }; dictionary CollectedClientAdditionalPaymentData { @@ -58,6 +72,11 @@ sequence<PaymentEntityLogo> paymentEntitiesLogos; required PaymentCurrencyAmount total; required PaymentCredentialInstrument instrument; + USVString browserBoundPublicKey; +}; + +dictionary CollectedClientAdditionalPaymentRegistrationData { + USVString browserBoundPublicKey; }; dictionary PaymentCredentialInstrument {
diff --git a/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/image-lcp-followed-by-two-image-softnavs-lcp.tentative.html b/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/image-lcp-followed-by-two-image-softnavs-lcp.tentative.html index 66a9e51..4a39464 100644 --- a/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/image-lcp-followed-by-two-image-softnavs-lcp.tentative.html +++ b/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/image-lcp-followed-by-two-image-softnavs-lcp.tentative.html
@@ -19,8 +19,6 @@ const link = document.getElementById("link"); promise_test(async t => { - validatePaintEntries('first-contentful-paint', 1); - validatePaintEntries('first-paint', 1); const preClickLcp = await getLcpEntries(); setEvent(t, link, /*pushState=*/url=>history.pushState({}, '', url), /*addContent=*/async () => await addImageToMain(), /*pushUrl=*/true,
diff --git a/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/resources/soft-navigation-helper.js b/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/resources/soft-navigation-helper.js index 4bc16b4..9ee79d3 100644 --- a/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/resources/soft-navigation-helper.js +++ b/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/resources/soft-navigation-helper.js
@@ -2,8 +2,6 @@ var interacted; var timestamps = []; const MAX_CLICKS = 50; -// Entries for one hard navigation + 50 soft navigations. -const MAX_PAINT_ENTRIES = 51; const URL = 'foobar.html'; const readValue = (value, defaultValue) => { return value !== undefined ? value : defaultValue; @@ -116,10 +114,6 @@ const runEntryValidations = async ( preClickLcp, first_navigation_id, entries_expected_number = 2, validate = null) => { - await validatePaintEntries( - 'first-contentful-paint', entries_expected_number, first_navigation_id); - await validatePaintEntries( - 'first-paint', entries_expected_number, first_navigation_id); const postClickLcp = await getLcpEntries(); const postClickLcpWithoutSoftNavs = await getLcpEntriesWithoutSoftNavs(); assert_greater_than( @@ -236,50 +230,6 @@ await extraValidations(entries, options); }; -const validatePaintEntries = - async (type, entries_number, first_navigation_id) => { - if (!performance.softNavPaintMetricsSupported) { - return; - } - const expected_entries_number = Math.min(entries_number, MAX_PAINT_ENTRIES); - const entries = await new Promise(resolve => { - const entries = []; - new PerformanceObserver(list => { - entries.push(...list.getEntriesByName(type)); - if (entries.length >= expected_entries_number) { - resolve(entries); - } - }).observe({ - type: 'paint', - buffered: true, - includeSoftNavigationObservations: true - }); - }); - const entries_without_softnavs = await new Promise(resolve => { - new PerformanceObserver(list => { - resolve(list.getEntriesByName(type)); - }).observe({type: 'paint', buffered: true}); - }); - assert_equals( - entries.length, expected_entries_number, - `There are ${entries_number} entries for ${type}`); - assert_equals( - entries_without_softnavs.length, 1, - `There is one non-softnav entry for ${type}`); - if (entries_number > 1) { - assert_not_equals( - entries[0].startTime, entries[1].startTime, - 'Entries have different timestamps for ' + type); - } - if (expected_entries_number > entries_without_softnavs.length) { - assert_equals( - entries[entries_without_softnavs.length].navigationId, - first_navigation_id, - 'First paint entry should have the same navigation ID as the last soft ' + - 'navigation entry'); - } -}; - const waitInitialLCP = () => { return new Promise(resolve => {
diff --git a/third_party/blink/web_tests/external/wpt/speech-api/SpeechRecognition-concurrentMediaStreamTrack-manual.https.html b/third_party/blink/web_tests/external/wpt/speech-api/SpeechRecognition-concurrentMediaStreamTrack-manual.https.html index 9da5cc6..c3bdd70 100644 --- a/third_party/blink/web_tests/external/wpt/speech-api/SpeechRecognition-concurrentMediaStreamTrack-manual.https.html +++ b/third_party/blink/web_tests/external/wpt/speech-api/SpeechRecognition-concurrentMediaStreamTrack-manual.https.html
@@ -27,10 +27,10 @@ // Create two SpeechRecognition instances const speechRecognition1 = new SpeechRecognition(); - speechRecognition1.mode = 'cloud-only'; + speechRecognition1.processLocally = false; speechRecognition1.lang = lang; const speechRecognition2 = new SpeechRecognition(); - speechRecognition2.mode = 'cloud-only'; + speechRecognition2.processLocally = false; speechRecognition2.lang = lang; const audioTrack1 = await getAudioTrackFromFile("/media/speech.wav");
diff --git a/third_party/blink/web_tests/external/wpt/speech-api/SpeechRecognition-mediaStreamTrack-manual.https.html b/third_party/blink/web_tests/external/wpt/speech-api/SpeechRecognition-mediaStreamTrack-manual.https.html index 01a5cd0..212ccb7 100644 --- a/third_party/blink/web_tests/external/wpt/speech-api/SpeechRecognition-mediaStreamTrack-manual.https.html +++ b/third_party/blink/web_tests/external/wpt/speech-api/SpeechRecognition-mediaStreamTrack-manual.https.html
@@ -25,7 +25,7 @@ const lang = "en-US"; window.SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition; const speechRecognition = new SpeechRecognition(); - speechRecognition.mode = 'cloud-only'; + speechRecognition.processLocally = false; speechRecognition.lang = lang; const audioTrack = await getAudioTrackFromFile("/media/speech.wav");
diff --git a/third_party/blink/web_tests/external/wpt/speech-api/historical-expected.txt b/third_party/blink/web_tests/external/wpt/speech-api/historical-expected.txt index 3310f71..dd91c36 100644 --- a/third_party/blink/web_tests/external/wpt/speech-api/historical-expected.txt +++ b/third_party/blink/web_tests/external/wpt/speech-api/historical-expected.txt
@@ -9,11 +9,4 @@ assert_false: expected false got true [FAIL] webkitSpeechRecognitionEvent interface should not exist assert_false: expected false got true -[FAIL] SpeechRecognition's serviceURI attribute should not exist - assert_implements: SpeechRecognition exposed undefined -[FAIL] SpeechRecognitionEvent's interpretation attribute should not exist - assert_implements: SpeechRecognitionEvent exposed undefined -[FAIL] SpeechRecognitionEvent's emma attribute should not exist - assert_implements: SpeechRecognitionEvent exposed undefined Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/external/wpt/speech-api/idlharness.window-expected.txt b/third_party/blink/web_tests/external/wpt/speech-api/idlharness.window-expected.txt index 18443119..49886379 100644 --- a/third_party/blink/web_tests/external/wpt/speech-api/idlharness.window-expected.txt +++ b/third_party/blink/web_tests/external/wpt/speech-api/idlharness.window-expected.txt
@@ -1,135 +1,7 @@ This is a testharness.js-based test. -Found 123 FAIL, 0 TIMEOUT, 0 NOTRUN. -[FAIL] SpeechRecognition interface: existence and properties of interface object - assert_own_property: self does not have own property "SpeechRecognition" expected property "SpeechRecognition" missing -[FAIL] SpeechRecognition interface object length - assert_own_property: self does not have own property "SpeechRecognition" expected property "SpeechRecognition" missing -[FAIL] SpeechRecognition interface object name - assert_own_property: self does not have own property "SpeechRecognition" expected property "SpeechRecognition" missing -[FAIL] SpeechRecognition interface: existence and properties of interface prototype object - assert_own_property: self does not have own property "SpeechRecognition" expected property "SpeechRecognition" missing -[FAIL] SpeechRecognition interface: existence and properties of interface prototype object's "constructor" property - assert_own_property: self does not have own property "SpeechRecognition" expected property "SpeechRecognition" missing -[FAIL] SpeechRecognition interface: existence and properties of interface prototype object's @@unscopables property - assert_own_property: self does not have own property "SpeechRecognition" expected property "SpeechRecognition" missing -[FAIL] SpeechRecognition interface: attribute lang - assert_own_property: self does not have own property "SpeechRecognition" expected property "SpeechRecognition" missing -[FAIL] SpeechRecognition interface: attribute continuous - assert_own_property: self does not have own property "SpeechRecognition" expected property "SpeechRecognition" missing -[FAIL] SpeechRecognition interface: attribute interimResults - assert_own_property: self does not have own property "SpeechRecognition" expected property "SpeechRecognition" missing -[FAIL] SpeechRecognition interface: attribute maxAlternatives - assert_own_property: self does not have own property "SpeechRecognition" expected property "SpeechRecognition" missing -[FAIL] SpeechRecognition interface: attribute processLocally - assert_own_property: self does not have own property "SpeechRecognition" expected property "SpeechRecognition" missing -[FAIL] SpeechRecognition interface: attribute phrases - assert_own_property: self does not have own property "SpeechRecognition" expected property "SpeechRecognition" missing -[FAIL] SpeechRecognition interface: operation start() - assert_own_property: self does not have own property "SpeechRecognition" expected property "SpeechRecognition" missing -[FAIL] SpeechRecognition interface: operation start(MediaStreamTrack) - assert_own_property: self does not have own property "SpeechRecognition" expected property "SpeechRecognition" missing -[FAIL] SpeechRecognition interface: operation stop() - assert_own_property: self does not have own property "SpeechRecognition" expected property "SpeechRecognition" missing -[FAIL] SpeechRecognition interface: operation abort() - assert_own_property: self does not have own property "SpeechRecognition" expected property "SpeechRecognition" missing -[FAIL] SpeechRecognition interface: operation available(SpeechRecognitionOptions) - assert_own_property: self does not have own property "SpeechRecognition" expected property "SpeechRecognition" missing -[FAIL] SpeechRecognition interface: operation install(SpeechRecognitionOptions) - assert_own_property: self does not have own property "SpeechRecognition" expected property "SpeechRecognition" missing -[FAIL] SpeechRecognition interface: attribute onaudiostart - assert_own_property: self does not have own property "SpeechRecognition" expected property "SpeechRecognition" missing -[FAIL] SpeechRecognition interface: attribute onsoundstart - assert_own_property: self does not have own property "SpeechRecognition" expected property "SpeechRecognition" missing -[FAIL] SpeechRecognition interface: attribute onspeechstart - assert_own_property: self does not have own property "SpeechRecognition" expected property "SpeechRecognition" missing -[FAIL] SpeechRecognition interface: attribute onspeechend - assert_own_property: self does not have own property "SpeechRecognition" expected property "SpeechRecognition" missing -[FAIL] SpeechRecognition interface: attribute onsoundend - assert_own_property: self does not have own property "SpeechRecognition" expected property "SpeechRecognition" missing -[FAIL] SpeechRecognition interface: attribute onaudioend - assert_own_property: self does not have own property "SpeechRecognition" expected property "SpeechRecognition" missing -[FAIL] SpeechRecognition interface: attribute onresult - assert_own_property: self does not have own property "SpeechRecognition" expected property "SpeechRecognition" missing -[FAIL] SpeechRecognition interface: attribute onnomatch - assert_own_property: self does not have own property "SpeechRecognition" expected property "SpeechRecognition" missing -[FAIL] SpeechRecognition interface: attribute onerror - assert_own_property: self does not have own property "SpeechRecognition" expected property "SpeechRecognition" missing -[FAIL] SpeechRecognition interface: attribute onstart - assert_own_property: self does not have own property "SpeechRecognition" expected property "SpeechRecognition" missing -[FAIL] SpeechRecognition interface: attribute onend - assert_own_property: self does not have own property "SpeechRecognition" expected property "SpeechRecognition" missing -[FAIL] SpeechRecognition must be primary interface of new SpeechRecognition() - assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: SpeechRecognition is not defined" -[FAIL] Stringification of new SpeechRecognition() - assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: SpeechRecognition is not defined" -[FAIL] SpeechRecognition interface: new SpeechRecognition() must inherit property "lang" with the proper type - assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: SpeechRecognition is not defined" -[FAIL] SpeechRecognition interface: new SpeechRecognition() must inherit property "continuous" with the proper type - assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: SpeechRecognition is not defined" -[FAIL] SpeechRecognition interface: new SpeechRecognition() must inherit property "interimResults" with the proper type - assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: SpeechRecognition is not defined" -[FAIL] SpeechRecognition interface: new SpeechRecognition() must inherit property "maxAlternatives" with the proper type - assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: SpeechRecognition is not defined" -[FAIL] SpeechRecognition interface: new SpeechRecognition() must inherit property "processLocally" with the proper type - assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: SpeechRecognition is not defined" -[FAIL] SpeechRecognition interface: new SpeechRecognition() must inherit property "phrases" with the proper type - assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: SpeechRecognition is not defined" -[FAIL] SpeechRecognition interface: new SpeechRecognition() must inherit property "start()" with the proper type - assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: SpeechRecognition is not defined" -[FAIL] SpeechRecognition interface: new SpeechRecognition() must inherit property "start(MediaStreamTrack)" with the proper type - assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: SpeechRecognition is not defined" -[FAIL] SpeechRecognition interface: calling start(MediaStreamTrack) on new SpeechRecognition() with too few arguments must throw TypeError - assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: SpeechRecognition is not defined" -[FAIL] SpeechRecognition interface: new SpeechRecognition() must inherit property "stop()" with the proper type - assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: SpeechRecognition is not defined" -[FAIL] SpeechRecognition interface: new SpeechRecognition() must inherit property "abort()" with the proper type - assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: SpeechRecognition is not defined" -[FAIL] SpeechRecognition interface: new SpeechRecognition() must inherit property "available(SpeechRecognitionOptions)" with the proper type - assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: SpeechRecognition is not defined" -[FAIL] SpeechRecognition interface: calling available(SpeechRecognitionOptions) on new SpeechRecognition() with too few arguments must throw TypeError - assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: SpeechRecognition is not defined" -[FAIL] SpeechRecognition interface: new SpeechRecognition() must inherit property "install(SpeechRecognitionOptions)" with the proper type - assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: SpeechRecognition is not defined" -[FAIL] SpeechRecognition interface: calling install(SpeechRecognitionOptions) on new SpeechRecognition() with too few arguments must throw TypeError - assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: SpeechRecognition is not defined" -[FAIL] SpeechRecognition interface: new SpeechRecognition() must inherit property "onaudiostart" with the proper type - assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: SpeechRecognition is not defined" -[FAIL] SpeechRecognition interface: new SpeechRecognition() must inherit property "onsoundstart" with the proper type - assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: SpeechRecognition is not defined" -[FAIL] SpeechRecognition interface: new SpeechRecognition() must inherit property "onspeechstart" with the proper type - assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: SpeechRecognition is not defined" -[FAIL] SpeechRecognition interface: new SpeechRecognition() must inherit property "onspeechend" with the proper type - assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: SpeechRecognition is not defined" -[FAIL] SpeechRecognition interface: new SpeechRecognition() must inherit property "onsoundend" with the proper type - assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: SpeechRecognition is not defined" -[FAIL] SpeechRecognition interface: new SpeechRecognition() must inherit property "onaudioend" with the proper type - assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: SpeechRecognition is not defined" -[FAIL] SpeechRecognition interface: new SpeechRecognition() must inherit property "onresult" with the proper type - assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: SpeechRecognition is not defined" -[FAIL] SpeechRecognition interface: new SpeechRecognition() must inherit property "onnomatch" with the proper type - assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: SpeechRecognition is not defined" -[FAIL] SpeechRecognition interface: new SpeechRecognition() must inherit property "onerror" with the proper type - assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: SpeechRecognition is not defined" -[FAIL] SpeechRecognition interface: new SpeechRecognition() must inherit property "onstart" with the proper type - assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: SpeechRecognition is not defined" -[FAIL] SpeechRecognition interface: new SpeechRecognition() must inherit property "onend" with the proper type - assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: SpeechRecognition is not defined" -[FAIL] SpeechRecognitionErrorEvent interface: existence and properties of interface object - assert_own_property: self does not have own property "SpeechRecognitionErrorEvent" expected property "SpeechRecognitionErrorEvent" missing +Found 52 FAIL, 0 TIMEOUT, 0 NOTRUN. [FAIL] SpeechRecognitionErrorEvent interface object length - assert_own_property: self does not have own property "SpeechRecognitionErrorEvent" expected property "SpeechRecognitionErrorEvent" missing -[FAIL] SpeechRecognitionErrorEvent interface object name - assert_own_property: self does not have own property "SpeechRecognitionErrorEvent" expected property "SpeechRecognitionErrorEvent" missing -[FAIL] SpeechRecognitionErrorEvent interface: existence and properties of interface prototype object - assert_own_property: self does not have own property "SpeechRecognitionErrorEvent" expected property "SpeechRecognitionErrorEvent" missing -[FAIL] SpeechRecognitionErrorEvent interface: existence and properties of interface prototype object's "constructor" property - assert_own_property: self does not have own property "SpeechRecognitionErrorEvent" expected property "SpeechRecognitionErrorEvent" missing -[FAIL] SpeechRecognitionErrorEvent interface: existence and properties of interface prototype object's @@unscopables property - assert_own_property: self does not have own property "SpeechRecognitionErrorEvent" expected property "SpeechRecognitionErrorEvent" missing -[FAIL] SpeechRecognitionErrorEvent interface: attribute error - assert_own_property: self does not have own property "SpeechRecognitionErrorEvent" expected property "SpeechRecognitionErrorEvent" missing -[FAIL] SpeechRecognitionErrorEvent interface: attribute message - assert_own_property: self does not have own property "SpeechRecognitionErrorEvent" expected property "SpeechRecognitionErrorEvent" missing + assert_equals: wrong value for SpeechRecognitionErrorEvent.length expected 2 but got 1 [FAIL] SpeechRecognitionAlternative interface: existence and properties of interface object assert_own_property: self does not have own property "SpeechRecognitionAlternative" expected property "SpeechRecognitionAlternative" missing [FAIL] SpeechRecognitionAlternative interface object length @@ -180,22 +52,8 @@ assert_own_property: self does not have own property "SpeechRecognitionResultList" expected property "SpeechRecognitionResultList" missing [FAIL] SpeechRecognitionResultList interface: operation item(unsigned long) assert_own_property: self does not have own property "SpeechRecognitionResultList" expected property "SpeechRecognitionResultList" missing -[FAIL] SpeechRecognitionEvent interface: existence and properties of interface object - assert_own_property: self does not have own property "SpeechRecognitionEvent" expected property "SpeechRecognitionEvent" missing [FAIL] SpeechRecognitionEvent interface object length - assert_own_property: self does not have own property "SpeechRecognitionEvent" expected property "SpeechRecognitionEvent" missing -[FAIL] SpeechRecognitionEvent interface object name - assert_own_property: self does not have own property "SpeechRecognitionEvent" expected property "SpeechRecognitionEvent" missing -[FAIL] SpeechRecognitionEvent interface: existence and properties of interface prototype object - assert_own_property: self does not have own property "SpeechRecognitionEvent" expected property "SpeechRecognitionEvent" missing -[FAIL] SpeechRecognitionEvent interface: existence and properties of interface prototype object's "constructor" property - assert_own_property: self does not have own property "SpeechRecognitionEvent" expected property "SpeechRecognitionEvent" missing -[FAIL] SpeechRecognitionEvent interface: existence and properties of interface prototype object's @@unscopables property - assert_own_property: self does not have own property "SpeechRecognitionEvent" expected property "SpeechRecognitionEvent" missing -[FAIL] SpeechRecognitionEvent interface: attribute resultIndex - assert_own_property: self does not have own property "SpeechRecognitionEvent" expected property "SpeechRecognitionEvent" missing -[FAIL] SpeechRecognitionEvent interface: attribute results - assert_own_property: self does not have own property "SpeechRecognitionEvent" expected property "SpeechRecognitionEvent" missing + assert_equals: wrong value for SpeechRecognitionEvent.length expected 2 but got 1 [FAIL] SpeechRecognitionPhrase interface: existence and properties of interface object assert_own_property: self does not have own property "SpeechRecognitionPhrase" expected property "SpeechRecognitionPhrase" missing [FAIL] SpeechRecognitionPhrase interface object length
diff --git a/third_party/blink/web_tests/external/wpt/streams/readable-byte-streams/read-min.any-expected.txt b/third_party/blink/web_tests/external/wpt/streams/readable-byte-streams/read-min.any-expected.txt deleted file mode 100644 index 31bec614..0000000 --- a/third_party/blink/web_tests/external/wpt/streams/readable-byte-streams/read-min.any-expected.txt +++ /dev/null
@@ -1,37 +0,0 @@ -This is a testharness.js-based test. -[FAIL] ReadableStream with byte source: read({ min }) rejects if min is 0 - assert_unreached: pull() should not be called Reached unreachable code -[FAIL] ReadableStream with byte source: read({ min }) rejects if min is negative - assert_unreached: pull() should not be called Reached unreachable code -[FAIL] ReadableStream with byte source: read({ min }) rejects if min is larger than view's length (Uint8Array) - assert_unreached: pull() should not be called Reached unreachable code -[FAIL] ReadableStream with byte source: read({ min }) rejects if min is larger than view's length (Uint16Array) - assert_unreached: pull() should not be called Reached unreachable code -[FAIL] ReadableStream with byte source: read({ min }) rejects if min is larger than view's length (DataView) - assert_unreached: pull() should not be called Reached unreachable code -[FAIL] ReadableStream with byte source: read({ min }), then read() - assert_equals: first result value byteLength expected 3 but got 2 -[FAIL] ReadableStream with byte source: read({ min }) with a DataView - assert_equals: result.value.byteLength expected 3 but got 2 -[FAIL] ReadableStream with byte source: enqueue(), then read({ min }) - assert_equals: first result value byteLength expected 3 but got 1 -[FAIL] ReadableStream with byte source: read({ min: 3 }) on a 3-byte Uint8Array, then multiple enqueue() up to 3 bytes - assert_equals: first result value byteLength expected 3 but got 2 -[FAIL] ReadableStream with byte source: read({ min: 3 }) on a 5-byte Uint8Array, then multiple enqueue() up to 3 bytes - assert_equals: first result value byteLength expected 3 but got 2 -[FAIL] ReadableStream with byte source: read({ min: 3 }) on a 5-byte Uint8Array, then multiple enqueue() up to 4 bytes - assert_equals: first result value byteLength expected 4 but got 2 -[FAIL] ReadableStream with byte source: read({ min }) when closed before view is filled - assert_true: result.done expected true got false -[FAIL] ReadableStream with byte source: read({ min }) when closed immediately after view is filled - assert_equals: result.value byteLength expected 3 but got 2 -[FAIL] ReadableStream with byte source: cancel() with partially filled pending read({ min }) request - Cannot read properties of null (reading 'view') -[FAIL] ReadableStream with byte source: 3 byte enqueue(), then close(), then read({ min }) with 2-element Uint16Array must fail - assert_unreached: Should have rejected: read() must fail Reached unreachable code -[FAIL] ReadableStream with byte source: read({ min }) with 2-element Uint16Array, then 3 byte enqueue(), then close() must fail - assert_throws_js: controller.close() must throw function "() => controller.close()" did not throw -[FAIL] ReadableStream with byte source: tee() with read({ min }) from branch1 and read() from branch2 - assert_equals: pull() must have been called 2 times expected 2 but got 1 -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/external/wpt/streams/readable-byte-streams/read-min.any.serviceworker-expected.txt b/third_party/blink/web_tests/external/wpt/streams/readable-byte-streams/read-min.any.serviceworker-expected.txt deleted file mode 100644 index 31bec614..0000000 --- a/third_party/blink/web_tests/external/wpt/streams/readable-byte-streams/read-min.any.serviceworker-expected.txt +++ /dev/null
@@ -1,37 +0,0 @@ -This is a testharness.js-based test. -[FAIL] ReadableStream with byte source: read({ min }) rejects if min is 0 - assert_unreached: pull() should not be called Reached unreachable code -[FAIL] ReadableStream with byte source: read({ min }) rejects if min is negative - assert_unreached: pull() should not be called Reached unreachable code -[FAIL] ReadableStream with byte source: read({ min }) rejects if min is larger than view's length (Uint8Array) - assert_unreached: pull() should not be called Reached unreachable code -[FAIL] ReadableStream with byte source: read({ min }) rejects if min is larger than view's length (Uint16Array) - assert_unreached: pull() should not be called Reached unreachable code -[FAIL] ReadableStream with byte source: read({ min }) rejects if min is larger than view's length (DataView) - assert_unreached: pull() should not be called Reached unreachable code -[FAIL] ReadableStream with byte source: read({ min }), then read() - assert_equals: first result value byteLength expected 3 but got 2 -[FAIL] ReadableStream with byte source: read({ min }) with a DataView - assert_equals: result.value.byteLength expected 3 but got 2 -[FAIL] ReadableStream with byte source: enqueue(), then read({ min }) - assert_equals: first result value byteLength expected 3 but got 1 -[FAIL] ReadableStream with byte source: read({ min: 3 }) on a 3-byte Uint8Array, then multiple enqueue() up to 3 bytes - assert_equals: first result value byteLength expected 3 but got 2 -[FAIL] ReadableStream with byte source: read({ min: 3 }) on a 5-byte Uint8Array, then multiple enqueue() up to 3 bytes - assert_equals: first result value byteLength expected 3 but got 2 -[FAIL] ReadableStream with byte source: read({ min: 3 }) on a 5-byte Uint8Array, then multiple enqueue() up to 4 bytes - assert_equals: first result value byteLength expected 4 but got 2 -[FAIL] ReadableStream with byte source: read({ min }) when closed before view is filled - assert_true: result.done expected true got false -[FAIL] ReadableStream with byte source: read({ min }) when closed immediately after view is filled - assert_equals: result.value byteLength expected 3 but got 2 -[FAIL] ReadableStream with byte source: cancel() with partially filled pending read({ min }) request - Cannot read properties of null (reading 'view') -[FAIL] ReadableStream with byte source: 3 byte enqueue(), then close(), then read({ min }) with 2-element Uint16Array must fail - assert_unreached: Should have rejected: read() must fail Reached unreachable code -[FAIL] ReadableStream with byte source: read({ min }) with 2-element Uint16Array, then 3 byte enqueue(), then close() must fail - assert_throws_js: controller.close() must throw function "() => controller.close()" did not throw -[FAIL] ReadableStream with byte source: tee() with read({ min }) from branch1 and read() from branch2 - assert_equals: pull() must have been called 2 times expected 2 but got 1 -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/external/wpt/streams/readable-byte-streams/read-min.any.sharedworker-expected.txt b/third_party/blink/web_tests/external/wpt/streams/readable-byte-streams/read-min.any.sharedworker-expected.txt deleted file mode 100644 index 31bec614..0000000 --- a/third_party/blink/web_tests/external/wpt/streams/readable-byte-streams/read-min.any.sharedworker-expected.txt +++ /dev/null
@@ -1,37 +0,0 @@ -This is a testharness.js-based test. -[FAIL] ReadableStream with byte source: read({ min }) rejects if min is 0 - assert_unreached: pull() should not be called Reached unreachable code -[FAIL] ReadableStream with byte source: read({ min }) rejects if min is negative - assert_unreached: pull() should not be called Reached unreachable code -[FAIL] ReadableStream with byte source: read({ min }) rejects if min is larger than view's length (Uint8Array) - assert_unreached: pull() should not be called Reached unreachable code -[FAIL] ReadableStream with byte source: read({ min }) rejects if min is larger than view's length (Uint16Array) - assert_unreached: pull() should not be called Reached unreachable code -[FAIL] ReadableStream with byte source: read({ min }) rejects if min is larger than view's length (DataView) - assert_unreached: pull() should not be called Reached unreachable code -[FAIL] ReadableStream with byte source: read({ min }), then read() - assert_equals: first result value byteLength expected 3 but got 2 -[FAIL] ReadableStream with byte source: read({ min }) with a DataView - assert_equals: result.value.byteLength expected 3 but got 2 -[FAIL] ReadableStream with byte source: enqueue(), then read({ min }) - assert_equals: first result value byteLength expected 3 but got 1 -[FAIL] ReadableStream with byte source: read({ min: 3 }) on a 3-byte Uint8Array, then multiple enqueue() up to 3 bytes - assert_equals: first result value byteLength expected 3 but got 2 -[FAIL] ReadableStream with byte source: read({ min: 3 }) on a 5-byte Uint8Array, then multiple enqueue() up to 3 bytes - assert_equals: first result value byteLength expected 3 but got 2 -[FAIL] ReadableStream with byte source: read({ min: 3 }) on a 5-byte Uint8Array, then multiple enqueue() up to 4 bytes - assert_equals: first result value byteLength expected 4 but got 2 -[FAIL] ReadableStream with byte source: read({ min }) when closed before view is filled - assert_true: result.done expected true got false -[FAIL] ReadableStream with byte source: read({ min }) when closed immediately after view is filled - assert_equals: result.value byteLength expected 3 but got 2 -[FAIL] ReadableStream with byte source: cancel() with partially filled pending read({ min }) request - Cannot read properties of null (reading 'view') -[FAIL] ReadableStream with byte source: 3 byte enqueue(), then close(), then read({ min }) with 2-element Uint16Array must fail - assert_unreached: Should have rejected: read() must fail Reached unreachable code -[FAIL] ReadableStream with byte source: read({ min }) with 2-element Uint16Array, then 3 byte enqueue(), then close() must fail - assert_throws_js: controller.close() must throw function "() => controller.close()" did not throw -[FAIL] ReadableStream with byte source: tee() with read({ min }) from branch1 and read() from branch2 - assert_equals: pull() must have been called 2 times expected 2 but got 1 -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/external/wpt/streams/readable-byte-streams/read-min.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/streams/readable-byte-streams/read-min.any.worker-expected.txt deleted file mode 100644 index 31bec614..0000000 --- a/third_party/blink/web_tests/external/wpt/streams/readable-byte-streams/read-min.any.worker-expected.txt +++ /dev/null
@@ -1,37 +0,0 @@ -This is a testharness.js-based test. -[FAIL] ReadableStream with byte source: read({ min }) rejects if min is 0 - assert_unreached: pull() should not be called Reached unreachable code -[FAIL] ReadableStream with byte source: read({ min }) rejects if min is negative - assert_unreached: pull() should not be called Reached unreachable code -[FAIL] ReadableStream with byte source: read({ min }) rejects if min is larger than view's length (Uint8Array) - assert_unreached: pull() should not be called Reached unreachable code -[FAIL] ReadableStream with byte source: read({ min }) rejects if min is larger than view's length (Uint16Array) - assert_unreached: pull() should not be called Reached unreachable code -[FAIL] ReadableStream with byte source: read({ min }) rejects if min is larger than view's length (DataView) - assert_unreached: pull() should not be called Reached unreachable code -[FAIL] ReadableStream with byte source: read({ min }), then read() - assert_equals: first result value byteLength expected 3 but got 2 -[FAIL] ReadableStream with byte source: read({ min }) with a DataView - assert_equals: result.value.byteLength expected 3 but got 2 -[FAIL] ReadableStream with byte source: enqueue(), then read({ min }) - assert_equals: first result value byteLength expected 3 but got 1 -[FAIL] ReadableStream with byte source: read({ min: 3 }) on a 3-byte Uint8Array, then multiple enqueue() up to 3 bytes - assert_equals: first result value byteLength expected 3 but got 2 -[FAIL] ReadableStream with byte source: read({ min: 3 }) on a 5-byte Uint8Array, then multiple enqueue() up to 3 bytes - assert_equals: first result value byteLength expected 3 but got 2 -[FAIL] ReadableStream with byte source: read({ min: 3 }) on a 5-byte Uint8Array, then multiple enqueue() up to 4 bytes - assert_equals: first result value byteLength expected 4 but got 2 -[FAIL] ReadableStream with byte source: read({ min }) when closed before view is filled - assert_true: result.done expected true got false -[FAIL] ReadableStream with byte source: read({ min }) when closed immediately after view is filled - assert_equals: result.value byteLength expected 3 but got 2 -[FAIL] ReadableStream with byte source: cancel() with partially filled pending read({ min }) request - Cannot read properties of null (reading 'view') -[FAIL] ReadableStream with byte source: 3 byte enqueue(), then close(), then read({ min }) with 2-element Uint16Array must fail - assert_unreached: Should have rejected: read() must fail Reached unreachable code -[FAIL] ReadableStream with byte source: read({ min }) with 2-element Uint16Array, then 3 byte enqueue(), then close() must fail - assert_throws_js: controller.close() must throw function "() => controller.close()" did not throw -[FAIL] ReadableStream with byte source: tee() with read({ min }) from branch1 and read() from branch2 - assert_equals: pull() must have been called 2 times expected 2 but got 1 -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/external/wpt/svg/animations/crashtests/empty-values-list-paced-animation.html b/third_party/blink/web_tests/external/wpt/svg/animations/crashtests/empty-values-list-paced-animation.html new file mode 100644 index 0000000..16d450e --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/svg/animations/crashtests/empty-values-list-paced-animation.html
@@ -0,0 +1,6 @@ +<!doctype html> +<svg> + <rect width="100" height="100" fill="green"> + <animateMotion values=""/> + </rect> +</svg>
diff --git a/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt index 52068d0..7d02a4cd 100644 --- a/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt +++ b/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -9004,6 +9004,69 @@ method constructor setter onaddsourcebuffer setter onremovesourcebuffer +interface SpeechGrammar + attribute @@toStringTag + getter src + getter weight + method constructor + setter src + setter weight +interface SpeechGrammarList + attribute @@toStringTag + getter length + method @@iterator + method addFromString + method addFromUri + method constructor + method item +interface SpeechRecognition : EventTarget + attribute @@toStringTag + getter continuous + getter grammars + getter interimResults + getter lang + getter maxAlternatives + getter onaudioend + getter onaudiostart + getter onend + getter onerror + getter onnomatch + getter onresult + getter onsoundend + getter onsoundstart + getter onspeechend + getter onspeechstart + getter onstart + method abort + method constructor + method start + method stop + setter continuous + setter grammars + setter interimResults + setter lang + setter maxAlternatives + setter onaudioend + setter onaudiostart + setter onend + setter onerror + setter onnomatch + setter onresult + setter onsoundend + setter onsoundstart + setter onspeechend + setter onspeechstart + setter onstart +interface SpeechRecognitionErrorEvent : Event + attribute @@toStringTag + getter error + getter message + method constructor +interface SpeechRecognitionEvent : Event + attribute @@toStringTag + getter resultIndex + getter results + method constructor interface SpeechSynthesis : EventTarget attribute @@toStringTag getter onvoiceschanged @@ -9412,6 +9475,18 @@ getter propertyName getter pseudoElement method constructor +interface Translator + static method availability + static method create + attribute @@toStringTag + getter inputQuota + getter sourceLanguage + getter targetLanguage + method constructor + method destroy + method measureInputUsage + method translate + method translateStreaming interface TreeWalker attribute @@toStringTag getter currentNode @@ -11785,6 +11860,7 @@ attribute @@toStringTag getter src getter weight + method constructor setter src setter weight interface webkitSpeechGrammarList @@ -11793,6 +11869,7 @@ method @@iterator method addFromString method addFromUri + method constructor method item interface webkitSpeechRecognition : EventTarget attribute @@toStringTag @@ -11813,6 +11890,7 @@ getter onspeechstart getter onstart method abort + method constructor method start method stop setter continuous @@ -11835,10 +11913,12 @@ attribute @@toStringTag getter error getter message + method constructor interface webkitSpeechRecognitionEvent : Event attribute @@toStringTag getter resultIndex getter results + method constructor interface webkitURL static method canParse static method createObjectURL
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt index bd4ad5e5..67d240b 100644 --- a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt +++ b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
@@ -9747,6 +9747,92 @@ method constructor setter onaddsourcebuffer setter onremovesourcebuffer +interface SpeechGrammar + attribute @@toStringTag + getter src + getter weight + method constructor + setter src + setter weight +interface SpeechGrammarList + attribute @@toStringTag + getter length + method @@iterator + method addFromString + method addFromUri + method constructor + method item +interface SpeechRecognition : EventTarget + static method available + static method install + attribute @@toStringTag + getter continuous + getter grammars + getter interimResults + getter lang + getter maxAlternatives + getter onaudioend + getter onaudiostart + getter onend + getter onerror + getter onnomatch + getter onresult + getter onsoundend + getter onsoundstart + getter onspeechend + getter onspeechstart + getter onstart + getter phrases + getter processLocally + method abort + method constructor + method start + method stop + setter continuous + setter grammars + setter interimResults + setter lang + setter maxAlternatives + setter onaudioend + setter onaudiostart + setter onend + setter onerror + setter onnomatch + setter onresult + setter onsoundend + setter onsoundstart + setter onspeechend + setter onspeechstart + setter onstart + setter phrases + setter processLocally +interface SpeechRecognitionContext + attribute @@toStringTag + getter phrases + method constructor + setter phrases +interface SpeechRecognitionErrorEvent : Event + attribute @@toStringTag + getter error + getter message + method constructor +interface SpeechRecognitionEvent : Event + attribute @@toStringTag + getter resultIndex + getter results + method constructor +interface SpeechRecognitionPhrase + attribute @@toStringTag + getter boost + getter phrase + method constructor +interface SpeechRecognitionPhraseList + attribute @@toStringTag + getter length + method addItem + method constructor + method item + method removeItem interface SpeechSynthesis : EventTarget attribute @@toStringTag getter onvoiceschanged @@ -12773,6 +12859,7 @@ attribute @@toStringTag getter src getter weight + method constructor setter src setter weight interface webkitSpeechGrammarList @@ -12781,6 +12868,7 @@ method @@iterator method addFromString method addFromUri + method constructor method item interface webkitSpeechRecognition : EventTarget static method available @@ -12802,8 +12890,10 @@ getter onspeechend getter onspeechstart getter onstart + getter phrases getter processLocally method abort + method constructor method start method stop setter continuous @@ -12822,15 +12912,18 @@ setter onspeechend setter onspeechstart setter onstart + setter phrases setter processLocally interface webkitSpeechRecognitionError : Event attribute @@toStringTag getter error getter message + method constructor interface webkitSpeechRecognitionEvent : Event attribute @@toStringTag getter resultIndex getter results + method constructor interface webkitURL static method canParse static method createObjectURL
diff --git a/third_party/chromite b/third_party/chromite index dd06165..0f33b29 160000 --- a/third_party/chromite +++ b/third_party/chromite
@@ -1 +1 @@ -Subproject commit dd0616580a90055b4b8aee7f82da48f7d8407906 +Subproject commit 0f33b29b972dfeba968b18e4ee9c34f5c80e7fa3
diff --git a/third_party/crossbench b/third_party/crossbench index c9c52cc..1009ebd 160000 --- a/third_party/crossbench +++ b/third_party/crossbench
@@ -1 +1 @@ -Subproject commit c9c52cc6dead7d399b602b116d124cfe53339d55 +Subproject commit 1009ebd5d406ddcaf346e48c10aea62d10326bda
diff --git a/third_party/devtools-frontend/src b/third_party/devtools-frontend/src index 9e5dddf..af5c090 160000 --- a/third_party/devtools-frontend/src +++ b/third_party/devtools-frontend/src
@@ -1 +1 @@ -Subproject commit 9e5dddf1ba1a8f1dbad8f55edb1b71970fc3832b +Subproject commit af5c09099862f7e4a4cd0ed131b2bd0369f5c5d1
diff --git a/third_party/ink_stroke_modeler/README.chromium b/third_party/ink_stroke_modeler/README.chromium index 9080f54..24ba69b 100644 --- a/third_party/ink_stroke_modeler/README.chromium +++ b/third_party/ink_stroke_modeler/README.chromium
@@ -1,7 +1,7 @@ Name: Ink Stroke Modeler URL: https://github.com/google/ink-stroke-modeler Version: N/A -Revision: 03db1ed37b8b10b47d62ed0fa142d198a3861689 +Revision: fe79520c9ad7d2d445d26d3c59fda6fc54eb4d5c License: Apache-2.0 License File: LICENSE Shipped: yes
diff --git a/third_party/ink_stroke_modeler/src b/third_party/ink_stroke_modeler/src index 03db1ed..fe79520 160000 --- a/third_party/ink_stroke_modeler/src +++ b/third_party/ink_stroke_modeler/src
@@ -1 +1 @@ -Subproject commit 03db1ed37b8b10b47d62ed0fa142d198a3861689 +Subproject commit fe79520c9ad7d2d445d26d3c59fda6fc54eb4d5c
diff --git a/third_party/libtess2/README.chromium b/third_party/libtess2/README.chromium index 4c039d0..dfc7957 100644 --- a/third_party/libtess2/README.chromium +++ b/third_party/libtess2/README.chromium
@@ -1,7 +1,7 @@ Name: Libtess2 URL: https://github.com/memononen/libtess2 Version: 1.0.3 -Revision: 6e05801a57ca06bfd2908ceb9a73b6df5b0aae71 +Revision: 9a450cc9e5b4b79c36b89648f8b92fe65b6dd407 License: SGI-B-2.0 License File: LICENSE Shipped: yes
diff --git a/third_party/libtess2/src/Include/tesselator.h b/third_party/libtess2/src/Include/tesselator.h index 3d431559..667da41 100644 --- a/third_party/libtess2/src/Include/tesselator.h +++ b/third_party/libtess2/src/Include/tesselator.h
@@ -138,6 +138,14 @@ #define TESS_NOTUSED(v) do { (void)(1 ? (void)0 : ( (void)(v) ) ); } while(0) +// These two constants define the valid input coordinate range the library is +// able to operate on. Tesselation will fail if any of the coordinates are not +// within this range. Clients are responsible for dealing with inputs outside of +// this range (e.g. clamping or filtering invalid points, scaling down the +// coordinate space). +#define TESS_MAX_VALID_INPUT_VALUE ((TESSreal) (1<<23)) +#define TESS_MIN_VALID_INPUT_VALUE (-TESS_MAX_VALID_INPUT_VALUE) + // Custom memory allocator interface. // The internal memory allocator allocates mesh edges, vertices and faces // as well as dictionary nodes and active regions in buckets and uses simple @@ -214,7 +222,8 @@ // vertexSize - defines the number of coordinates in tesselation result vertex, must be 2 or 3. // normal - defines the normal of the input contours, of null the normal is calculated automatically. // Returns: -// 1 if succeed, 0 if failed. +// 1 if succeed, 0 if failed (tessGetStatus can be used after to get a more +// specific failure status) int tessTesselate( TESStesselator *tess, int windingRule, int elementType, int polySize, int vertexSize, const TESSreal* normal ); // tessGetVertexCount() - Returns number of vertices in the tesselated output. @@ -235,6 +244,18 @@ // tessGetElements() - Returns pointer to the first element. const TESSindex* tessGetElements( TESStesselator *tess ); +typedef enum TESSstatus { + TESS_STATUS_OK, + TESS_STATUS_OUT_OF_MEMORY, + TESS_STATUS_INVALID_INPUT +} TESSstatus; + +// Return the success or failure status. If tessTesselate fails (or will fail, +// e.g. after invalid data is passed to tessAddContour), this can indicate +// more specifically why. It can also be checked after tessAddContour to +// see whether to bail out early. +TESSstatus tessGetStatus( TESStesselator *tess ); + #ifdef __cplusplus }; #endif
diff --git a/third_party/libtess2/src/Source/geom.h b/third_party/libtess2/src/Source/geom.h index 1b93fd6..017e6c24 100644 --- a/third_party/libtess2/src/Source/geom.h +++ b/third_party/libtess2/src/Source/geom.h
@@ -48,7 +48,12 @@ #endif #define EdgeEval(u,v,w) tesedgeEval(u,v,w) -#define EdgeSign(u,v,w) tesedgeSign(u,v,w) + +/* EdgeSign used to call tesedgeSign(), which is a cheaper version of tesedgeEval(), but should return the same sign. +* This does not seem to be the case if the x coordinates are almost 0. Always using tesedgeEval() fixes this discrepancy. +* See https://github.com/memononen/libtess2/issues/22 for example data that triggers the issue. +*/ +#define EdgeSign(u,v,w) tesedgeEval(u,v,w) /* Versions of VertLeq, EdgeSign, EdgeEval with s and t transposed. */
diff --git a/third_party/libtess2/src/Source/sweep.c b/third_party/libtess2/src/Source/sweep.c index abeb6e4c..164d705 100644 --- a/third_party/libtess2/src/Source/sweep.c +++ b/third_party/libtess2/src/Source/sweep.c
@@ -493,7 +493,7 @@ SpliceMergeVertices( tess, eLo->Oprev, eUp ); } } else { - if( EdgeSign( eUp->Dst, eLo->Org, eUp->Org ) <= 0 ) return FALSE; + if( EdgeSign( eUp->Dst, eLo->Org, eUp->Org ) < 0 ) return FALSE; /* eLo->Org appears to be above eUp, so splice eLo->Org into eUp */ regUp->dirty = TRUE;
diff --git a/third_party/libtess2/src/Source/tess.c b/third_party/libtess2/src/Source/tess.c index 1f638885..21b015d 100644 --- a/third_party/libtess2/src/Source/tess.c +++ b/third_party/libtess2/src/Source/tess.c
@@ -34,6 +34,7 @@ #include <setjmp.h> #include "bucketalloc.h" #include "tess.h" +#include "tesselator.h" #include "mesh.h" #include "sweep.h" #include "geom.h" @@ -649,7 +650,7 @@ // Initialize to begin polygon. tess->mesh = NULL; - tess->outOfMemory = 0; + tess->status = TESS_STATUS_OK; tess->vertexIndexCounter = 0; tess->vertices = 0; @@ -715,7 +716,7 @@ { if (!tessMeshMergeConvexFaces( mesh, polySize )) { - tess->outOfMemory = 1; + tess->status = TESS_STATUS_OUT_OF_MEMORY; return; } } @@ -758,7 +759,7 @@ sizeof(TESSindex) * maxFaceCount * polySize ); if (!tess->elements) { - tess->outOfMemory = 1; + tess->status = TESS_STATUS_OUT_OF_MEMORY; return; } @@ -767,7 +768,7 @@ sizeof(TESSreal) * tess->vertexCount * vertexSize ); if (!tess->vertices) { - tess->outOfMemory = 1; + tess->status = TESS_STATUS_OUT_OF_MEMORY; return; } @@ -775,7 +776,7 @@ sizeof(TESSindex) * tess->vertexCount ); if (!tess->vertexIndices) { - tess->outOfMemory = 1; + tess->status = TESS_STATUS_OUT_OF_MEMORY; return; } @@ -866,7 +867,7 @@ sizeof(TESSindex) * tess->elementCount * 2 ); if (!tess->elements) { - tess->outOfMemory = 1; + tess->status = TESS_STATUS_OUT_OF_MEMORY; return; } @@ -874,7 +875,7 @@ sizeof(TESSreal) * tess->vertexCount * vertexSize ); if (!tess->vertices) { - tess->outOfMemory = 1; + tess->status = TESS_STATUS_OUT_OF_MEMORY; return; } @@ -882,7 +883,7 @@ sizeof(TESSindex) * tess->vertexCount ); if (!tess->vertexIndices) { - tess->outOfMemory = 1; + tess->status = TESS_STATUS_OUT_OF_MEMORY; return; } @@ -918,6 +919,11 @@ } } +int IsValidCoord(TESSreal coord) { + return coord <= TESS_MAX_VALID_INPUT_VALUE && + coord >= TESS_MIN_VALID_INPUT_VALUE; +} + void tessAddContour( TESStesselator *tess, int size, const void* vertices, int stride, int numVertices ) { @@ -928,7 +934,7 @@ if ( tess->mesh == NULL ) tess->mesh = tessMeshNewMesh( &tess->alloc ); if ( tess->mesh == NULL ) { - tess->outOfMemory = 1; + tess->status = TESS_STATUS_OUT_OF_MEMORY; return; } @@ -942,20 +948,21 @@ { const TESSreal* coords = (const TESSreal*)src; src += stride; - if (isnan(coords[0]) || isnan(coords[1]) || (size > 2 && isnan(coords[2]))) { - // "Out of memory" isn't quite right, but give up and bail out - tess->outOfMemory = 1; + if (!IsValidCoord(coords[0]) || + !IsValidCoord(coords[1]) || + (size > 2 && !IsValidCoord(coords[2]))) { + tess->status = TESS_STATUS_INVALID_INPUT; return; } if( e == NULL ) { /* Make a self-loop (one vertex, one edge). */ e = tessMeshMakeEdge( tess->mesh ); if ( e == NULL ) { - tess->outOfMemory = 1; + tess->status = TESS_STATUS_OUT_OF_MEMORY; return; } if ( !tessMeshSplice( tess->mesh, e, e->Sym ) ) { - tess->outOfMemory = 1; + tess->status = TESS_STATUS_OUT_OF_MEMORY; return; } } else { @@ -963,7 +970,7 @@ * in the ordering around the left face. */ if ( tessMeshSplitEdge( tess->mesh, e ) == NULL ) { - tess->outOfMemory = 1; + tess->status = TESS_STATUS_OUT_OF_MEMORY; return; } e = e->Lnext; @@ -1043,7 +1050,7 @@ return 0; } - if (tess->outOfMemory || !tess->mesh) + if (tess->status != TESS_STATUS_OK || !tess->mesh) { return 0; } @@ -1091,9 +1098,7 @@ tessMeshDeleteMesh( &tess->alloc, mesh ); tess->mesh = NULL; - if (tess->outOfMemory) - return 0; - return 1; + return tess->status == TESS_STATUS_OK; } int tessGetVertexCount( TESStesselator *tess ) @@ -1120,3 +1125,9 @@ { return tess->elements; } + +TESSstatus tessGetStatus( TESStesselator *tess ) +{ + return tess->status; +} +
diff --git a/third_party/libtess2/src/Source/tess.h b/third_party/libtess2/src/Source/tess.h index 30fda27..c754af0f6 100644 --- a/third_party/libtess2/src/Source/tess.h +++ b/third_party/libtess2/src/Source/tess.h
@@ -43,14 +43,12 @@ extern "C" { #endif -//typedef struct TESStesselator TESStesselator; - struct TESStesselator { /*** state needed for collecting the input data ***/ TESSmesh *mesh; /* stores the input contours, and eventually the tessellation itself */ - int outOfMemory; + TESSstatus status; /*** state needed for projecting onto the sweep plane ***/
diff --git a/third_party/llvm-libc/src b/third_party/llvm-libc/src index c7b224d..2be4a57 160000 --- a/third_party/llvm-libc/src +++ b/third_party/llvm-libc/src
@@ -1 +1 @@ -Subproject commit c7b224d8e8261aa4ba880280349bca74c1a9a2e7 +Subproject commit 2be4a578cb2136558bc0070ffd38e0b1bafb34e9
diff --git a/third_party/mediapipe/src/mediapipe/framework/scheduler.h b/third_party/mediapipe/src/mediapipe/framework/scheduler.h index 1c391e94..549695ee 100644 --- a/third_party/mediapipe/src/mediapipe/framework/scheduler.h +++ b/third_party/mediapipe/src/mediapipe/framework/scheduler.h
@@ -16,7 +16,6 @@ #define MEDIAPIPE_FRAMEWORK_SCHEDULER_H_ #include <atomic> -#include <deque> #include <functional> #include <map> #include <memory>
diff --git a/third_party/mediapipe/src/mediapipe/framework/scheduler_shared.h b/third_party/mediapipe/src/mediapipe/framework/scheduler_shared.h index f8b5d86..3e5c7217 100644 --- a/third_party/mediapipe/src/mediapipe/framework/scheduler_shared.h +++ b/third_party/mediapipe/src/mediapipe/framework/scheduler_shared.h
@@ -19,6 +19,7 @@ #include <cstdint> #include <functional> #include <memory> +#include <queue> #include <utility> #include "absl/base/macros.h"
diff --git a/third_party/mediapipe/src/mediapipe/util/tracking/region_flow_visualization.h b/third_party/mediapipe/src/mediapipe/util/tracking/region_flow_visualization.h index 9954411..b28ce9c 100644 --- a/third_party/mediapipe/src/mediapipe/util/tracking/region_flow_visualization.h +++ b/third_party/mediapipe/src/mediapipe/util/tracking/region_flow_visualization.h
@@ -18,6 +18,7 @@ #include <algorithm> #include <cmath> +#include <deque> #include <unordered_map> #include <unordered_set> #include <utility>
diff --git a/third_party/mediapipe/src/third_party/com_google_audio_tools/audio/dsp/number_util.cc b/third_party/mediapipe/src/third_party/com_google_audio_tools/audio/dsp/number_util.cc index 38369459..2a5a93336 100644 --- a/third_party/mediapipe/src/third_party/com_google_audio_tools/audio/dsp/number_util.cc +++ b/third_party/mediapipe/src/third_party/com_google_audio_tools/audio/dsp/number_util.cc
@@ -16,6 +16,7 @@ #include "audio/dsp/number_util.h" +#include <algorithm> #include <cmath> #include <iomanip> #include <limits>
diff --git a/third_party/mediapipe/src/third_party/com_google_audio_tools/audio/dsp/porting.cc b/third_party/mediapipe/src/third_party/com_google_audio_tools/audio/dsp/porting.cc index e906d2d0..753c286 100644 --- a/third_party/mediapipe/src/third_party/com_google_audio_tools/audio/dsp/porting.cc +++ b/third_party/mediapipe/src/third_party/com_google_audio_tools/audio/dsp/porting.cc
@@ -16,6 +16,7 @@ #include "audio/dsp/porting.h" +#include <algorithm> #include <cfloat> #include <cstdarg>
diff --git a/third_party/mediapipe/src/third_party/com_google_audio_tools/audio/dsp/porting.h b/third_party/mediapipe/src/third_party/com_google_audio_tools/audio/dsp/porting.h index 87231c5..fab40f9 100644 --- a/third_party/mediapipe/src/third_party/com_google_audio_tools/audio/dsp/porting.h +++ b/third_party/mediapipe/src/third_party/com_google_audio_tools/audio/dsp/porting.h
@@ -17,6 +17,7 @@ #ifndef AUDIO_DSP_OPEN_SOURCE_PORTING_H_ #define AUDIO_DSP_OPEN_SOURCE_PORTING_H_ +#include <cstdint> #include <iostream> #include <cmath> #include <limits>
diff --git a/third_party/mediapipe/src/third_party/com_google_audio_tools/third_party/eigen3/BUILD b/third_party/mediapipe/src/third_party/com_google_audio_tools/third_party/eigen3/BUILD index 497c1f0..de1c7f4 100644 --- a/third_party/mediapipe/src/third_party/com_google_audio_tools/third_party/eigen3/BUILD +++ b/third_party/mediapipe/src/third_party/com_google_audio_tools/third_party/eigen3/BUILD
@@ -23,6 +23,6 @@ ], visibility = ["//visibility:public"], deps = [ - "@eigen_archive//:eigen", + "@eigen_archive//:eigen3", ], )
diff --git a/third_party/perfetto b/third_party/perfetto index 393c152..717bd45 160000 --- a/third_party/perfetto +++ b/third_party/perfetto
@@ -1 +1 @@ -Subproject commit 393c1529c36f43332b3d89f32aa5ee1e2493c2c1 +Subproject commit 717bd456079cad23a0d1d52f3f9e7628af0b17ac
diff --git a/third_party/skia b/third_party/skia index 2e03299..3393a17 160000 --- a/third_party/skia +++ b/third_party/skia
@@ -1 +1 @@ -Subproject commit 2e032998eb66b3dc42647871b0a2639f33abd196 +Subproject commit 3393a17d5fdcc6cf47862ec516b0ff3592850bea
diff --git a/third_party/swiftshader b/third_party/swiftshader index 5fdf5e4..155f095 160000 --- a/third_party/swiftshader +++ b/third_party/swiftshader
@@ -1 +1 @@ -Subproject commit 5fdf5e4c58918bd8ce3d8b9bd3b33755ebc26ab0 +Subproject commit 155f095a8c6354d25c7bd062094cdff98ca9d6ae
diff --git a/third_party/vulkan-deps b/third_party/vulkan-deps index e72c7b6..ae1d44f 160000 --- a/third_party/vulkan-deps +++ b/third_party/vulkan-deps
@@ -1 +1 @@ -Subproject commit e72c7b63fe81f659c6cf653fbf83bf4cc6d9e3a2 +Subproject commit ae1d44f55e826515a19a789f1ecbefe2099ed4f2
diff --git a/third_party/vulkan-validation-layers/src b/third_party/vulkan-validation-layers/src index f06294f..3fd33817 160000 --- a/third_party/vulkan-validation-layers/src +++ b/third_party/vulkan-validation-layers/src
@@ -1 +1 @@ -Subproject commit f06294f4aaa84cbe64dcddebe3ad478692798707 +Subproject commit 3fd3381758c8f721bb3d395ecbf08b4d71d6ce6e
diff --git a/third_party/webrtc b/third_party/webrtc index 8305f8c..0292d38 160000 --- a/third_party/webrtc +++ b/third_party/webrtc
@@ -1 +1 @@ -Subproject commit 8305f8c14afeff1e81478a574f3fa76efafc43d5 +Subproject commit 0292d38b7f56a83c0838e63bde92fb7a47be0927
diff --git a/tools/bedrock/OWNERS b/tools/bedrock/OWNERS new file mode 100644 index 0000000..ea16f2f --- /dev/null +++ b/tools/bedrock/OWNERS
@@ -0,0 +1,2 @@ +tluk@chromium.org +erikchen@chromium.org
diff --git a/tools/bedrock/README.md b/tools/bedrock/README.md new file mode 100644 index 0000000..4b1494b --- /dev/null +++ b/tools/bedrock/README.md
@@ -0,0 +1,23 @@ +# Bedrock Tools and Utilities + +## Overview + +This directory contains helper scripts and utilities for Project Bedrock +(Browser modularization). For example these may be utilities for generating +project metrics, or tools to assist prompt-driven test refactors. + +## bedrock_metrics.py + +`bedrock_metrics.py` is a script that generates a JSON file with metrics +specific to the Bedrock project. + +### Usage +```sh +usage: Generates project metrics from the src and build directories. + + $ tools/bedrock/bedrock_metrics.py [src_dir] [build_dir] [output_filepath] +``` + +### Tests +The `./bedrock_metrics_tests.py` runs a simple test suite leveraging python's +built-in unittest framework.
diff --git a/tools/bedrock/bedrock_metrics.py b/tools/bedrock/bedrock_metrics.py new file mode 100755 index 0000000..fc954e4e --- /dev/null +++ b/tools/bedrock/bedrock_metrics.py
@@ -0,0 +1,259 @@ +#!/usr/bin/env python3 +# Copyright 2025 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import argparse +import datetime +import json +import os +import subprocess +import sys + + +def count_matching_files(abs_directory, + include_file_content_strings=None, + content_match_strings=None, + include_filename_strings=None, + exclude_filename_strings=None): + """ + Returns the number of files under `abs_directory` that match the include and + exclude criteria. It will also return a sum of the content matches these + files have with the `content_match_strings` list. + + Args: + abs_directory (str): The absolute directory to search in. + include_file_content_strings (list, optional): List of strings. A file + must contain at least one + of these (if defined) in + order to be included in + the count. + content_match_strings (list, optional): List of strings. Files that pass + the match criteria will also + have their content checked for + matches in this list. Any + matches will contribute to the + sum of content string matches + returned. + include_filename_strings (list, optional): List of strings. All must be + present in the filename. + exclude_filename_strings (list, optional): List of strings. If any are + present in the filename, the + file is excluded. + + Returns: + tuple: The count of files passing the include / exclude criteria, and + the number of times `content_match_strings` are found within + these files. + """ + + if not os.path.isdir(abs_directory): + print(f"Error: Directory '{abs_directory}' not found.") + return 0, 0 + + items_to_scan = [] + for dirpath, _, filenames in os.walk(abs_directory): + for filename in filenames: + items_to_scan.append(os.path.join(dirpath, filename)) + + matched_file_count = 0 + string_matches_count = 0 + for filepath in items_to_scan: + filename_only = os.path.basename(filepath) + + # 1. Filename include filter. + if include_filename_strings: + if not all(inc_str in filename_only + for inc_str in include_filename_strings): + continue # Skip if not all include_filename_strings are present. + + # 2. Extension include filter. + if not any(inc_str in filename_only for inc_str in [".h", ".cc", ".mm"]): + continue # Skip if not a valid source file. + + # 3. Filename exclude filter. + if exclude_filename_strings: + if any(exc_str in filename_only for exc_str in exclude_filename_strings): + continue # Skip if any exclude_filename_strings are present. + + # Open the matching file for steps 4 and 5. + with open(filepath, 'r', encoding='utf-8', errors='ignore') as f: + content = f.read() + + # 4. File content filter. + if include_file_content_strings: + if not any(s_str in content for s_str in include_file_content_strings): + continue # Skip if no include strings to match. + matched_file_count += 1 + + # 5. Content string counts. + if content_match_strings: + file_string_matches_count = 0 + for s_str in content_match_strings: + if s_str: # Avoid issues with empty search strings. + file_string_matches_count += content.count(s_str) + string_matches_count += file_string_matches_count + + return matched_file_count, string_matches_count + + +def count_lines(filenames): + """ + Counts number of lines in the list of `filenames`. + + Args: + filenames (list): A list of absolute paths to the files. + + Returns: + int: The total line count for all `filenames`. + """ + total_count = 0 + for filename in filenames: + with open(filename, 'r') as file: + lines = file.readlines() + total_count += len(lines) + return total_count + + +def get_shell_metrics(command_str): + """ + Runs a shell command and returns the output as an int. + + Args: + command_str (str): The shell command to run. + + Returns: + int: The output cast to an int. + """ + result = subprocess.run(command_str, + shell=True, + capture_output=True, + text=True, + check=True) + + # Get the standard output and strip any leading/trailing whitespace (like + # newlines). + output_str = result.stdout.strip() + + # Convert the cleaned string to an integer. + number = int(output_str) + + return number + + +def main(): + parser = argparse.ArgumentParser( + description="Produces project Bedrock metrics.") + parser.add_argument("src_directory", type=str, help="Input directory path.") + parser.add_argument("build_directory", + type=str, + help="Build directory relative to src.") + parser.add_argument("output_file", + type=str, + help="Path to the output JSON file.") + args = parser.parse_args() + + # Store the chrome/browser directory as an absolute path. + abs_cb_directory = os.path.abspath( + os.path.join(args.src_directory, "./chrome/browser")) + + # Record the git commit hash and datetime. + commit_hash = subprocess.run("git rev-parse HEAD", + shell=True, + capture_output=True, + text=True, + check=True).stdout.strip() + git_timestamp = subprocess.run("git show -s --format=%cI", + shell=True, + capture_output=True, + text=True, + check=True).stdout.strip() + timestamp = datetime.datetime.fromisoformat(git_timestamp).strftime( + "%Y-%m-%d %H:%M:%S") + + # Calculate the use of Browser fixtures and utilities in unit tests. + unittest_ref_files, unittest_ref_matches = count_matching_files( + abs_cb_directory, [ + "TestBrowserWindow", "BrowserWithTestWindowTest", + "TestWithBrowserView", "CreateBrowserWithTestWindowForParams" + ], [ + "TestBrowserWindow", "BrowserWithTestWindowTest", + "TestWithBrowserView", "CreateBrowserWithTestWindowForParams", + "Browser*", "raw_ptr<Browser>", "BrowserView*", + "raw_ptr<BrowserView>", "browser_view()", "GetBrowserView(" + ], ["unittest"], None) + unittest_total, _ = count_matching_files(abs_cb_directory, None, None, + ["unittest"], None) + + # Calculate the use of Browser and BrowserView in production code. + production_ref_files, production_ref_matches = count_matching_files( + abs_cb_directory, [ + "Browser*", "raw_ptr<Browser>", "BrowserView*", + "raw_ptr<BrowserView>", "browser_view()", "GetBrowserView(" + ], [ + "Browser*", "raw_ptr<Browser>", "BrowserView*", + "raw_ptr<BrowserView>", "browser_view()", "GetBrowserView(" + ], None, ["test"]) + production_total, _ = count_matching_files(abs_cb_directory, None, None, None, + ["test"]) + + # Calculate total LOC for both Browser and BrowserView. + browser_lc = count_lines([ + os.path.join(abs_cb_directory, "./ui/browser.h"), + os.path.join(abs_cb_directory, "./ui/browser.cc") + ]) + browser_view_lc = count_lines([ + os.path.join(abs_cb_directory, "./ui/views/frame/browser_view.h"), + os.path.join(abs_cb_directory, "./ui/views/frame/browser_view.cc") + ]) + + # Calculate number of sources for both :browser and :ui targets. + browser_sources = get_shell_metrics( + f"gn desc {args.build_directory} chrome/browser:browser sources | wc -l") + browser_ui_sources = get_shell_metrics( + f"gn desc {args.build_directory} chrome/browser/ui:ui sources | wc -l") + + # Calculate number of circular references for both :browser and :ui targets. + browser_sources_circular = get_shell_metrics( + f"gn desc {args.build_directory} chrome/browser:browser " + "allow_circular_includes_from | xargs -I{} gn desc out/Default {} " + "sources | wc -l") + browser_ui_sources_circular = get_shell_metrics( + f"gn desc {args.build_directory} chrome/browser/ui:ui " + "allow_circular_includes_from | xargs -I{} gn desc out/Default {} " + "sources | wc -l") + + # Define the JSON data. + data_to_write = { + "commit_hash": commit_hash, + "timestamp": timestamp, + "unittest_ref_files": unittest_ref_files, + "unittest_ref_matches": unittest_ref_matches, + "unittest_total": unittest_total, + "production_ref_files": production_ref_files, + "production_ref_matches": production_ref_matches, + "production_total": production_total, + "browser_lc": browser_lc, + "browser_view_lc": browser_view_lc, + "browser_sources": browser_sources, + "browser_ui_sources": browser_ui_sources, + "browser_sources_circular": browser_sources_circular, + "browser_ui_sources_circular": browser_ui_sources_circular, + } + + # Write the JSON data to the output file. + try: + with open(args.output_file, 'w') as f: + json.dump(data_to_write, f) + print(f"Successfully wrote JSON to '{args.output_file}'") + except IOError as e: + print(f"Error: Could not write to file '{args.output_file}': {e}", + file=sys.stderr) + sys.exit(1) + except Exception as e: + print(f"An unexpected error occurred: {e}", file=sys.stderr) + sys.exit(1) + + +if __name__ == "__main__": + main()
diff --git a/tools/bedrock/bedrock_metrics_test.py b/tools/bedrock/bedrock_metrics_test.py new file mode 100755 index 0000000..7d9b3a0e --- /dev/null +++ b/tools/bedrock/bedrock_metrics_test.py
@@ -0,0 +1,273 @@ +#!/usr/bin/env python3 +# Copyright 2025 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import unittest +import os +import tempfile +import shutil + +import bedrock_metrics + + +class TestBedrockMetrics(unittest.TestCase): + + def setUp(self): + # Create a temporary directory for test files. + self.test_dir = tempfile.mkdtemp(prefix="bedrock_test_") + self.sub_dir = os.path.join(self.test_dir, "sub") + os.makedirs(self.sub_dir) + + # --- Files for count_matching_files --- + # Structure: + # self.test_dir/ + # - file_alpha.h (Content: "apple banana\ncount_me_once") + # - file_beta.cc (Content: "banana cherry\ncount_me_once\ncount_me_once") + # - file_gamma.mm (Content: "apple cherry\nno_count_string") + # - sub/ + # - file_delta.h (Content: "apple\ncount_me_once") + # - file_exclude_me.cc (Content: "apple banana\ncontent for exclude") + # - other_extension.txt (Content: "apple banana\ntext file content") + # - empty_file.h (Content: "") + files_to_create_for_matching = [ + ("file_alpha.h", "apple banana\ncount_me_once"), + ("file_beta.cc", "banana cherry\ncount_me_once\ncount_me_once"), + ("file_gamma.mm", "apple cherry\nno_count_string"), + (os.path.join("sub", "file_delta.h"), "apple\ncount_me_once"), + ("file_exclude_me.cc", "apple banana\ncontent for exclude"), + ("other_extension.txt", + "apple banana\ntext file content"), # Invalid extension + ("empty_file.h", "") + ] + + for rel_path, content in files_to_create_for_matching: + full_path = os.path.join(self.test_dir, rel_path) + os.makedirs(os.path.dirname(full_path), exist_ok=True) + with open(full_path, 'w', encoding='utf-8') as f: + f.write(content) + + # --- Files for count_lines --- + self.lines_file1_path = os.path.join(self.test_dir, "lines_file1.data") + with open(self.lines_file1_path, 'w', encoding='utf-8') as f: + f.write("line1\nline2\nline3") # 3 lines + + self.lines_file2_path = os.path.join(self.test_dir, "lines_file2.data") + with open(self.lines_file2_path, 'w', encoding='utf-8') as f: + f.write("single line") # 1 line + + self.lines_empty_file_path = os.path.join(self.test_dir, "lines_empty.data") + with open(self.lines_empty_file_path, 'w', encoding='utf-8') as f: + f.write("") # 0 lines + + def tearDown(self): + # Remove the temporary directory and its contents after tests. + shutil.rmtree(self.test_dir) + + # --- Tests for count_matching_files --- + + def test_cmf_no_filters_counts_valid_extensions(self): + # Expected: file_alpha.h, file_beta.cc, file_gamma.mm, sub/file_delta.h, + # file_exclude_me.cc, empty_file.h (6 files with .h, .cc, .mm) + # other_extension.txt is ignored due to extension. + # No content_match_strings, so string_matches_count is 0. + count, str_count = bedrock_metrics.count_matching_files(self.test_dir) + self.assertEqual(count, 6, "File count mismatch with no filters") + self.assertEqual(str_count, 0, + "String count should be 0 with no content search strings") + + def test_cmf_include_filename_single(self): + # include_filename_strings=["alpha"] -> matches file_alpha.h + count, str_count = bedrock_metrics.count_matching_files( + self.test_dir, include_filename_strings=["alpha"]) + self.assertEqual(count, 1) + self.assertEqual(str_count, 0) + + def test_cmf_include_filename_multiple_all_match(self): + # include_filename_strings=["file", "alpha"] -> matches file_alpha.h + count, str_count = bedrock_metrics.count_matching_files( + self.test_dir, include_filename_strings=["file", "alpha"]) + self.assertEqual(count, 1) + self.assertEqual(str_count, 0) + + def test_cmf_include_filename_multiple_one_no_match(self): + # include_filename_strings=["alpha", "beta"] -> No file has BOTH "alpha" + # AND"beta". + count, str_count = bedrock_metrics.count_matching_files( + self.test_dir, include_filename_strings=["alpha", "nomatch"]) + self.assertEqual(count, 0) + self.assertEqual(str_count, 0) + + def test_cmf_exclude_filename_single(self): + # exclude_filename_strings=["exclude"] -> Excludes file_exclude_me.cc + # Original 6 valid files - 1 = 5 files. + count, str_count = bedrock_metrics.count_matching_files( + self.test_dir, exclude_filename_strings=["exclude"]) + self.assertEqual(count, 5) + self.assertEqual(str_count, 0) + + # These tests verify the current code behavior (ANY). + def test_cmf_include_file_content_strings_any_behavior_one_present(self): + # include_file_content_strings=["apple"] + # Matches: file_alpha.h, file_gamma.mm, sub/file_delta.h, file_exclude_me.cc + # (4 files) + # file_beta.cc (banana cherry) does not contain "apple". empty_file.h is + # empty. + count, str_count = bedrock_metrics.count_matching_files( + self.test_dir, include_file_content_strings=["apple"]) + self.assertEqual(count, 4) + self.assertEqual(str_count, 0) + + def test_cmf_include_file_content_strings_any_behavior_multiple_options(self): + # include_file_content_strings=["apple", "cherry"] (any of these in content) + # file_alpha.h ("apple") - Yes + # file_beta.cc ("cherry") - Yes + # file_gamma.mm ("apple", "cherry") - Yes + # sub/file_delta.h ("apple") - Yes + # file_exclude_me.cc ("apple") - Yes + # empty_file.h - No + # Expected: 5 files + count, str_count = bedrock_metrics.count_matching_files( + self.test_dir, include_file_content_strings=["apple", "cherry"]) + self.assertEqual(count, 5) + self.assertEqual(str_count, 0) + + def test_cmf_include_file_content_strings_none_present_in_content(self): + # include_file_content_strings=["nonexistent_string_pattern"] + count, str_count = bedrock_metrics.count_matching_files( + self.test_dir, + include_file_content_strings=["nonexistent_string_pattern"]) + self.assertEqual(count, 0) + self.assertEqual(str_count, 0) + + def test_cmf_content_match_strings_single_term_count(self): + # content_match_strings=["count_me_once"] + # All 6 valid files are checked for content counts. + # file_alpha.h: 1 | file_beta.cc: 2 | file_gamma.mm: 0 + # sub/file_delta.h: 1 | file_exclude_me.cc: 0 | empty_file.h: 0 + # Total string matches: 1 + 2 + 0 + 1 + 0 + 0 = 4 + count, str_count = bedrock_metrics.count_matching_files( + self.test_dir, content_match_strings=["count_me_once"]) + self.assertEqual( + count, 6, + "File count should include all valid files for content counting") + self.assertEqual(str_count, 4, "String match count error") + + def test_cmf_content_match_strings_multiple_terms_count(self): + # content_match_strings=["apple", "banana"] + # All 6 valid files are checked. + # file_alpha.h ("apple banana"): apple(1)+banana(1)=2 + # file_beta.cc ("banana cherry"): apple(0)+banana(1)=1 + # file_gamma.mm ("apple cherry"): apple(1)+banana(0)=1 + # sub/file_delta.h ("apple"): apple(1)+banana(0)=1 + # file_exclude_me.cc ("apple banana"): apple(1)+banana(1)=2 + # empty_file.h: apple(0)+banana(0)=0 + # Total string matches: 2+1+1+1+2+0 = 7 + count, str_count = bedrock_metrics.count_matching_files( + self.test_dir, content_match_strings=["apple", "banana"]) + self.assertEqual(count, 6) + self.assertEqual(str_count, 7) + + def test_cmf_all_filters_combined(self): + # include_filename_strings=["file"], exclude_filename_strings=["exclude"] + # include_file_content_strings=["apple"] (content filter, using 'any' logic + # of code) + # content_match_strings=["count_me_once"] + + # 1. Include "file": file_alpha.h, file_beta.cc, file_gamma.mm, + # file_exclude_me.cc, empty_file.h + # 2. Exclude "exclude": Removes file_exclude_me.cc. + # Remaining: file_alpha.h, file_beta.cc, file_gamma.mm, empty_file.h + # 3. include_file_content_strings=["apple"]: (file must contain "apple") + # file_alpha.h (has "apple") - Keep + # file_beta.cc (no "apple") - Remove + # file_gamma.mm (has "apple") - Keep + # sub/file_delta.h (has "apple"): - Keep + # empty_file.h (no "apple") - Remove + # Matched files: file_alpha.h, file_gamma.mm. So, count = 2. + # 4. content_match_strings=["count_me_once"] on these 2 files: + # file_alpha.h: 1 occurrence + # file_gamma.mm: 0 occurrences + # sub/file_delta.h (has "apple"): 1 occurrences + # Total str_count = 1. + count, str_count = bedrock_metrics.count_matching_files( + self.test_dir, + include_file_content_strings=["apple"], + content_match_strings=["count_me_once"], + include_filename_strings=["file"], + exclude_filename_strings=["exclude"]) + self.assertEqual(count, 3) + self.assertEqual(str_count, 2) + + def test_cmf_empty_directory(self): + empty_subdir_path = os.path.join(self.test_dir, "empty_subdir_for_test") + os.makedirs(empty_subdir_path) + count, str_count = bedrock_metrics.count_matching_files(empty_subdir_path) + self.assertEqual(count, 0) + self.assertEqual(str_count, 0) + + def test_cmf_no_matching_extension_files_present(self): + # Directory with only a .txt file, which is not in [.h, .cc, .mm] + other_ext_dir = os.path.join(self.test_dir, "other_ext_dir") + os.makedirs(other_ext_dir) + with open(os.path.join(other_ext_dir, "somefile.txt"), 'w') as f: + f.write("content") + count, str_count = bedrock_metrics.count_matching_files(other_ext_dir) + self.assertEqual(count, 0) + self.assertEqual(str_count, 0) + + def test_cmf_include_file_content_strings_is_empty_list(self): + # An empty list for include_file_content_strings means the content filter + # (Step 4) is skipped. + # Same as include_file_content_strings=None. + count, str_count = bedrock_metrics.count_matching_files( + self.test_dir, include_file_content_strings=[]) + self.assertEqual(count, 6) # All 6 valid extension files + self.assertEqual(str_count, 0) + + def test_cmf_content_match_strings_is_empty_list(self): + # No strings to count, so str_count should be 0. + # File count reflects all files matching other criteria. + count, str_count = bedrock_metrics.count_matching_files( + self.test_dir, content_match_strings=[]) + self.assertEqual(count, 6) # All 6 valid extension files + self.assertEqual(str_count, 0) + + def test_cmf_content_match_strings_includes_empty_string(self): + # The code `if s_str:` skips empty strings in content_match_strings. + # So, ["count_me_once", ""] should behave like ["count_me_once"]. + count, str_count = bedrock_metrics.count_matching_files( + self.test_dir, content_match_strings=["count_me_once", ""]) + self.assertEqual(count, 6) + self.assertEqual(str_count, 4) # Same as just ["count_me_once"] + + # --- Tests for count_lines --- + + def test_cl_single_file_multiple_lines(self): + self.assertEqual(bedrock_metrics.count_lines([self.lines_file1_path]), 3) + + def test_cl_single_file_one_line_no_trailing_newline(self): + self.assertEqual(bedrock_metrics.count_lines([self.lines_file2_path]), 1) + + def test_cl_multiple_files(self): + total_lines = bedrock_metrics.count_lines( + [self.lines_file1_path, self.lines_file2_path]) + self.assertEqual(total_lines, 3 + 1) # 4 + + def test_cl_empty_file(self): + # An empty file has 0 lines according to file.readlines(). + self.assertEqual(bedrock_metrics.count_lines([self.lines_empty_file_path]), + 0) + + def test_cl_mixed_files_including_empty(self): + total_lines = bedrock_metrics.count_lines([ + self.lines_file1_path, self.lines_empty_file_path, self.lines_file2_path + ]) + self.assertEqual(total_lines, 3 + 0 + 1) # 4 + + def test_cl_empty_file_list(self): + self.assertEqual(bedrock_metrics.count_lines([]), 0) + + +if __name__ == '__main__': + unittest.main(verbosity=2)
diff --git a/tools/metrics/histograms/histograms_xml_files.gni b/tools/metrics/histograms/histograms_xml_files.gni index e6f96d3..00a834c 100644 --- a/tools/metrics/histograms/histograms_xml_files.gni +++ b/tools/metrics/histograms/histograms_xml_files.gni
@@ -194,6 +194,7 @@ "//tools/metrics/histograms/metadata/performance_manager/histograms.xml", "//tools/metrics/histograms/metadata/permissions/enums.xml", "//tools/metrics/histograms/metadata/permissions/histograms.xml", + "//tools/metrics/histograms/metadata/persistent_cache/histograms.xml", "//tools/metrics/histograms/metadata/phonehub/enums.xml", "//tools/metrics/histograms/metadata/phonehub/histograms.xml", "//tools/metrics/histograms/metadata/platform/enums.xml",
diff --git a/tools/metrics/histograms/metadata/android/enums.xml b/tools/metrics/histograms/metadata/android/enums.xml index 3f68d33..cb71bce 100644 --- a/tools/metrics/histograms/metadata/android/enums.xml +++ b/tools/metrics/histograms/metadata/android/enums.xml
@@ -1025,6 +1025,18 @@ <int value="4" label="UNKNOWN_TO_NEW_INSTANCE"/> </enum> +<enum name="EdgeToEdgeConfigurationSwitchOutcome"> + <summary> + When edge to edge changed into unsupported configuration, what's the outcome + </summary> + <int value="0" label="ADD_PADDING_NEW_INSETS"/> + <int value="1" label="ADD_PADDING_ORIGINAL_INSETS"/> + <int value="2" label="ERROR_ADD_PADDING_BOTH_INSETS_EMPTY"/> + <int value="3" label="NO_PADDING_BOTH_INSETS_EMPTY"/> + <int value="4" label="NO_PADDING_NO_NEW_INSETS"/> + <int value="5" label="ERROR_NO_PADDING_WITH_NEW_INSETS"/> +</enum> + <enum name="ExifOrientation"> <int value="0" label="Normal"/> <int value="1" label="Rotate 90"/>
diff --git a/tools/metrics/histograms/metadata/android/histograms.xml b/tools/metrics/histograms/metadata/android/histograms.xml index 1bb3ea30..14e0e44 100644 --- a/tools/metrics/histograms/metadata/android/histograms.xml +++ b/tools/metrics/histograms/metadata/android/histograms.xml
@@ -1942,6 +1942,19 @@ </summary> </histogram> +<histogram name="Android.EdgeToEdge.Debugging.ConfigurationSwitchOutcome" + enum="EdgeToEdgeConfigurationSwitchOutcome" expires_after="2025-11-23"> + <owner>clhager@google.com</owner> + <owner>wenyufu@chromium.org</owner> + <owner>edge-to-edge@chromium.org</owner> + <summary> + Records when the EdgeToEdgeControllerImpl notices a change when edge-to-edge + is changed from a supported configuration into unsupported. Record the + outcome combination of the original window insets, new window insets, and + paddings applied to the content view. + </summary> +</histogram> + <histogram name="Android.EdgeToEdge.DrawToEdgeInUnsupportedConfiguration" enum="Boolean" expires_after="2025-11-23"> <owner>clhager@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/blink/enums.xml b/tools/metrics/histograms/metadata/blink/enums.xml index 44419155..1de929a9 100644 --- a/tools/metrics/histograms/metadata/blink/enums.xml +++ b/tools/metrics/histograms/metadata/blink/enums.xml
@@ -8244,7 +8244,7 @@ <int value="309" label="AppLaunchHandler"/> <int value="310" label="Function"/> <int value="311" label="If"/> - <int value="312" label="WebAppManifestUpdateToken"/> + <int value="312" label="DRAFT_WebAppManifestUpdate"/> <int value="313" label="ReadingFlow"/> <int value="314" label="ComposedRanges"/> <int value="315" label="CompressionDictionaryTransport"/>
diff --git a/tools/metrics/histograms/metadata/compositing/histograms.xml b/tools/metrics/histograms/metadata/compositing/histograms.xml index 9bf6476..2bade1f 100644 --- a/tools/metrics/histograms/metadata/compositing/histograms.xml +++ b/tools/metrics/histograms/metadata/compositing/histograms.xml
@@ -1147,6 +1147,7 @@ <owner>jonross@chromium.org</owner> <owner>mjzhang@chromium.org</owner> <owner>chrome-gpu-metric-alerts@chromium.org</owner> + <improvement direction="LOWER_IS_BETTER"/> <summary> Tracks the percent of janks for a sequence by aggregating all its animations and interactions, where a sequence is a series of frames produced which @@ -1170,6 +1171,7 @@ <owner>jonross@chromium.org</owner> <owner>mjzhang@chromium.org</owner> <owner>chrome-gpu-metric-alerts@chromium.org</owner> + <improvement direction="LOWER_IS_BETTER"/> <summary> Tracks the percent of janks for a sequence by aggregating all {Sequence}, where a sequence is a series of frames produced which contain at least one @@ -1192,6 +1194,7 @@ <owner>jonross@chromium.org</owner> <owner>mjzhang@chromium.org</owner> <owner>chrome-gpu-metric-alerts@chromium.org</owner> + <improvement direction="LOWER_IS_BETTER"/> <summary> Tracks the percent of janks for a sequence by aggregating all {Sequence}, where a sequence is a series of frames produced which contain at least one @@ -1214,6 +1217,7 @@ units="%" expires_after="2025-09-21"> <owner>jonross@chromium.org</owner> <owner>chrome-gpu-metric-alerts@chromium.org</owner> + <improvement direction="LOWER_IS_BETTER"/> <summary> Tracks the percent of dropped frames for in a 1 second sliding window. @@ -1231,6 +1235,7 @@ <owner>jonross@chromium.org</owner> <owner>chrome-gpu-metric-alerts@chromium.org</owner> <owner>chrome-analysis-team@google.com</owner> + <improvement direction="LOWER_IS_BETTER"/> <summary> Tracks the percent of dropped frames for a sequence by aggregating all its animations and interactions, where a sequence is a series of frames produced @@ -1262,6 +1267,7 @@ units="%" expires_after="2025-12-07"> <owner>jonross@chromium.org</owner> <owner>chrome-gpu-metric-alerts@chromium.org</owner> + <improvement direction="LOWER_IS_BETTER"/> <summary> Tracks the percent of dropped frames for a sequence by aggregating all {Sequence}, where a sequence is a series of frames produced which contain at @@ -1288,6 +1294,7 @@ units="%" expires_after="2025-10-12"> <owner>kawasin@google.com</owner> <owner>baseos-perf@google.com</owner> + <improvement direction="LOWER_IS_BETTER"/> <summary> Tracks the percent of dropped frames for a sequence by aggregating all {Sequence}, where a sequence is a series of frames produced which contain at @@ -1314,6 +1321,7 @@ units="%" expires_after="2025-12-07"> <owner>jonross@chromium.org</owner> <owner>chrome-gpu-metric-alerts@chromium.org</owner> + <improvement direction="LOWER_IS_BETTER"/> <summary> Tracks the percent of dropped frames for a sequence by aggregating all {Sequence}, where a sequence is a series of frames produced which contain at @@ -1341,6 +1349,7 @@ <owner>jonross@chromium.org</owner> <owner>gaiko@chromium.org</owner> <owner>chrome-gpu-metric-alerts@chromium.org</owner> + <improvement direction="LOWER_IS_BETTER"/> <summary> Tracks the percent of dropped frames for a sequence by aggregating all its animations and interactions, where a sequence is a series of frames produced @@ -1376,6 +1385,7 @@ <owner>jonross@chromium.org</owner> <owner>gaiko@chromium.org</owner> <owner>chrome-gpu-metric-alerts@chromium.org</owner> + <improvement direction="LOWER_IS_BETTER"/> <summary> Tracks the percent of dropped frames for a sequence by aggregating all {Sequence}, where a sequence is a series of frames produced which contain at @@ -1405,6 +1415,7 @@ <owner>jonross@chromium.org</owner> <owner>gaiko@chromium.org</owner> <owner>chrome-gpu-metric-alerts@chromium.org</owner> + <improvement direction="LOWER_IS_BETTER"/> <summary> Tracks the percent of dropped frames for a sequence by aggregating all {Sequence}, where a sequence is a series of frames produced which contain at
diff --git a/tools/metrics/histograms/metadata/dev/enums.xml b/tools/metrics/histograms/metadata/dev/enums.xml index 0be1be5..a2a7516 100644 --- a/tools/metrics/histograms/metadata/dev/enums.xml +++ b/tools/metrics/histograms/metadata/dev/enums.xml
@@ -847,14 +847,6 @@ <int value="3" label="Other"/> </enum> -<enum name="DevToolsAnimationPointDragged"> - <int value="0" label="Animation is dragged as a whole"/> - <int value="1" label="Keyframe is moved"/> - <int value="2" label="Animation start point is moved"/> - <int value="3" label="Animation finish point is moved"/> - <int value="4" label="Other"/> -</enum> - <enum name="DevToolsCSSHintShown"> <int value="0" label="Other"/> <int value="1" label="AlignContent"/>
diff --git a/tools/metrics/histograms/metadata/dev/histograms.xml b/tools/metrics/histograms/metadata/dev/histograms.xml index 3d1604e..5a5a3bfc 100644 --- a/tools/metrics/histograms/metadata/dev/histograms.xml +++ b/tools/metrics/histograms/metadata/dev/histograms.xml
@@ -48,17 +48,6 @@ <summary>Playback rate is changed in Animations panel in DevTools.</summary> </histogram> -<histogram name="DevTools.AnimationPointDragged" - enum="DevToolsAnimationPointDragged" expires_after="2024-10-13"> - <owner>yangguo@google.com</owner> - <owner>changhaohan@google.com</owner> - <owner>ergunsh@google.com</owner> - <summary> - An animation's duration or delay updated visually by dragging the animation - point in Animations panel in DevTools. - </summary> -</histogram> - <histogram name="DevTools.CDPCommandFrom{ClientType}" enum="CDPCommands" expires_after="2025-11-16"> <owner>wolfi@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/event/histograms.xml b/tools/metrics/histograms/metadata/event/histograms.xml index 721a3c8b..c30f812 100644 --- a/tools/metrics/histograms/metadata/event/histograms.xml +++ b/tools/metrics/histograms/metadata/event/histograms.xml
@@ -201,6 +201,7 @@ expires_after="2025-10-12"> <owner>jonross@chromium.org</owner> <owner>woa-performance@google.com</owner> + <improvement direction="LOWER_IS_BETTER"/> <summary> A frame is deemed janky if an irregular jump in screen displacement occured in consecutive frames, this metric is the percentage of those janky frames @@ -222,6 +223,7 @@ units="ratio * 100" expires_after="2025-11-23"> <owner>jonross@chromium.org</owner> <owner>woa-performance@google.com</owner> + <improvement direction="LOWER_IS_BETTER"/> <summary> This metric is the ratio between a larger screen displacement divided by a following small screen displacement {ScrollSpeed}. If the larger screen @@ -492,6 +494,7 @@ <owner>jonross@chromium.org</owner> <owner>woa-performance-team@google.com</owner> <owner>chrome-analysis-team@google.com</owner> + <improvement direction="LOWER_IS_BETTER"/> <summary> The percentage of frames not presented during a scroll or a fling[1], meaning frame production took longer than expected and the frame was @@ -526,6 +529,7 @@ <owner>kartarsingh@google.com</owner> <owner>jonross@chromium.org</owner> <owner>woa-performance-team@google.com</owner> + <improvement direction="LOWER_IS_BETTER"/> <summary> NOTE: This metric is a new experimental version of Event.ScrollJank.DelayedFramesPercentage.FixedWindow. This new metric aims @@ -563,6 +567,7 @@ <owner>kartarsingh@google.com</owner> <owner>jonross@chromium.org</owner> <owner>woa-performance-team@google.com</owner> + <improvement direction="LOWER_IS_BETTER"/> <summary> NOTE: This metric is a new experimental version of Event.ScrollJank.DelayedFramesPercentage.PerScroll. This new metric aims to @@ -590,6 +595,7 @@ <owner>kartarsingh@google.com</owner> <owner>jonross@chromium.org</owner> <owner>woa-performance-team@google.com</owner> + <improvement direction="LOWER_IS_BETTER"/> <summary> A frame is deemed janky during a scroll if there was no presented frame in the previous vsync, and the current frame contains input that was not @@ -611,6 +617,7 @@ <owner>kartarsingh@google.com</owner> <owner>jonross@chromium.org</owner> <owner>woa-performance-team@google.com</owner> + <improvement direction="LOWER_IS_BETTER"/> <summary> A frame is deemed janky during a scroll if there was no presented frame in the previous vsync, and the current frame contains input that was not @@ -634,6 +641,7 @@ expires_after="2025-12-07"> <owner>jonross@chromium.org</owner> <owner>woa-performance-team@google.com</owner> + <improvement direction="LOWER_IS_BETTER"/> <summary> NOTE: This metric is experimental, for performance analysis, please use Event.ScrollJank.DelayedFramesPercentage.FixedWindow. @@ -657,6 +665,7 @@ <owner>petrcermak@chromium.org</owner> <owner>jonross@chromium.org</owner> <owner>woa-performance-team@google.com</owner> + <improvement direction="LOWER_IS_BETTER"/> <summary> NOTE: This metric is a new experimental version of Event.ScrollJank.MissedVsyncsPercentage.FixedWindow. This new metric aims to @@ -685,6 +694,7 @@ <owner>kartarsingh@google.com</owner> <owner>jonross@chromium.org</owner> <owner>woa-performance-team@google.com</owner> + <improvement direction="LOWER_IS_BETTER"/> <summary> NOTE: This metric is a new experimental version of Event.ScrollJank.MissedVsyncsPercentage.PerScroll. This new metric aims to @@ -713,6 +723,7 @@ <owner>kartarsingh@google.com</owner> <owner>jonross@chromium.org</owner> <owner>woa-performance-team@google.com</owner> + <improvement direction="LOWER_IS_BETTER"/> <summary> A vsync is deemed janky during a scroll if there was no presented frame in the vsync and the next frame contained late input that was not presented @@ -739,6 +750,7 @@ <owner>kartarsingh@google.com</owner> <owner>jonross@chromium.org</owner> <owner>woa-performance-team@google.com</owner> + <improvement direction="LOWER_IS_BETTER"/> <summary> NOTE: This metric is a new experimental version of Event.ScrollJank.MissedVsyncsSum.FixedWindow. This new metric aims to @@ -767,6 +779,7 @@ <owner>kartarsingh@google.com</owner> <owner>jonross@chromium.org</owner> <owner>woa-performance-team@google.com</owner> + <improvement direction="LOWER_IS_BETTER"/> <summary> NOTE: This metric is a new experimental version of Event.ScrollJank.MissedVsyncsSum.PerScroll. This new metric aims to address @@ -794,6 +807,7 @@ <owner>kartarsingh@google.com</owner> <owner>jonross@chromium.org</owner> <owner>woa-performance-team@google.com</owner> + <improvement direction="LOWER_IS_BETTER"/> <summary> A frame is deemed janky during a scroll if there was no presented frame in the previous vsync, and the current frame contains input that was not @@ -818,6 +832,7 @@ units="counts" expires_after="2025-10-19"> <owner>jonross@chromium.org</owner> <owner>woa-performance-team@google.com</owner> + <improvement direction="LOWER_IS_BETTER"/> <summary> NOTE: This metric is experimental, for performance analysis, please use Event.ScrollJank.MissedVsyncs{Operator}.FixedWindow. @@ -843,6 +858,7 @@ <owner>kartarsingh@google.com</owner> <owner>jonross@chromium.org</owner> <owner>woa-performance-team@google.com</owner> + <improvement direction="LOWER_IS_BETTER"/> <summary> A frame is deemed janky during a scroll if there was no presented frame in the previous vsync, and the current frame contains input that was not
diff --git a/tools/metrics/histograms/metadata/installer/enums.xml b/tools/metrics/histograms/metadata/installer/enums.xml index 30897b969..ce428f10 100644 --- a/tools/metrics/histograms/metadata/installer/enums.xml +++ b/tools/metrics/histograms/metadata/installer/enums.xml
@@ -35,8 +35,8 @@ </enum> <enum name="ChromeOSEfiManagementEvent"> - <int value="0" label="RequiredEntryManagementFailed"/> - <int value="1" label="OptionalEntryManagementFailed"/> + <int value="1" label="RequiredEntryManagementFailed"/> + <int value="2" label="OptionalEntryManagementFailed"/> </enum> <enum name="ChromeOSRecoveryReason">
diff --git a/tools/metrics/histograms/metadata/media/enums.xml b/tools/metrics/histograms/metadata/media/enums.xml index 32bb904e..d9699c9 100644 --- a/tools/metrics/histograms/metadata/media/enums.xml +++ b/tools/metrics/histograms/metadata/media/enums.xml
@@ -1780,6 +1780,15 @@ <!-- LINT.ThenChange(//chrome/browser/picture_in_picture/picture_in_picture_window_manager.h:PictureInPictureDisallowedType) --> +<!-- LINT.IfChange(PictureInPictureTuckedTypeEnum) --> + +<enum name="PictureInPictureTuckedType"> + <int value="0" label="Existing picture-in-picture window was tucked"/> + <int value="1" label="New picture-in-picture window was tucked"/> +</enum> + +<!-- LINT.ThenChange(//chrome/browser/picture_in_picture/picture_in_picture_window_manager.h:PictureInPictureTuckedType) --> + <enum name="PlaylistSegmentType"> <int value="0" label="kTS"/> <int value="1" label="kMP4"/>
diff --git a/tools/metrics/histograms/metadata/media/histograms.xml b/tools/metrics/histograms/metadata/media/histograms.xml index 52cf5fc..fd50111d 100644 --- a/tools/metrics/histograms/metadata/media/histograms.xml +++ b/tools/metrics/histograms/metadata/media/histograms.xml
@@ -5154,6 +5154,18 @@ </summary> </histogram> +<histogram name="Media.PictureInPicture.Tucked" + enum="PictureInPictureTuckedType" expires_after="2026-04-22"> + <owner>steimel@chromium.org</owner> + <owner>liberato@chromium.org</owner> + <summary> + Recorded when a picture-in-picture window is tucked due to a + ScopedTuckPictureInPicture object. Records whether the tucked + picture-in-picture window was just opened or already existed when the + ScopedTuckPictureInPicture was created. + </summary> +</histogram> + <histogram name="Media.PictureInPicture.Window.TotalTime" units="ms" expires_after="2025-11-02"> <owner>bkeen@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/permissions/histograms.xml b/tools/metrics/histograms/metadata/permissions/histograms.xml index 5a688c4..c0bb5de 100644 --- a/tools/metrics/histograms/metadata/permissions/histograms.xml +++ b/tools/metrics/histograms/metadata/permissions/histograms.xml
@@ -1871,6 +1871,25 @@ </token> </histogram> +<histogram + name="Permissions.{Version}.{PermissionType}.PermissionRequestRelevance" + enum="PermissionRequestRelevance" expires_after="2026-03-07"> + <owner>elklm@chromium.org</owner> + <owner>src/components/permissions/PERMISSIONS_OWNERS</owner> + <summary> + Records the generated relevance signal after a successful execution of the + available model. + </summary> + <token key="Version"> + <variant name="AIv1"/> + <variant name="AIv3"/> + </token> + <token key="PermissionType"> + <variant name="Geolocation"/> + <variant name="Notifications"/> + </token> +</histogram> + <histogram name="SiteEngagementService.EngagementScore" units="units" expires_after="2025-11-16"> <owner>calamity@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/persistent_cache/OWNERS b/tools/metrics/histograms/metadata/persistent_cache/OWNERS new file mode 100644 index 0000000..55680ad1 --- /dev/null +++ b/tools/metrics/histograms/metadata/persistent_cache/OWNERS
@@ -0,0 +1,5 @@ +per-file OWNERS=file://tools/metrics/histograms/metadata/METRIC_REVIEWER_OWNERS + +# Prefer sending CLs to the owners listed below. +# Use chromium-metrics-reviews@google.com as a backup. +olivierli@chromium.org
diff --git a/tools/metrics/histograms/metadata/persistent_cache/histograms.xml b/tools/metrics/histograms/metadata/persistent_cache/histograms.xml new file mode 100644 index 0000000..49d65682 --- /dev/null +++ b/tools/metrics/histograms/metadata/persistent_cache/histograms.xml
@@ -0,0 +1,49 @@ +<!-- +Copyright 2025 The Chromium Authors +Use of this source code is governed by a BSD-style license that can be +found in the LICENSE file. +--> + +<!-- +This file is used to generate a comprehensive list of HangWatcher histograms +along with a detailed description for each histogram. + +For best practices on writing histogram descriptions, see +https://chromium.googlesource.com/chromium/src.git/+/HEAD/tools/metrics/histograms/README.md + +Please follow the instructions in the OWNERS file in this directory to find a +reviewer. If no OWNERS file exists, please consider signing up at +go/reviewing-metrics (Googlers only), as all subdirectories are expected to +have an OWNERS file. As a last resort you can send the CL to +chromium-metrics-reviews@google.com. +--> + +<histogram-configuration> + +<histograms> + +<variants name="BackendType"> + <variant name="SQLite" summary="SQLite"/> +</variants> + +<variants name="Mode"> + <variant name="ReadOnly" summary="read only"/> + <variant name="ReadWrite" summary="read/write"/> +</variants> + +<histogram name="PersistentCache.BackendInitialize.{BackendType}.{Mode}" + units="microseconds" expires_after="2026-06-09"> + <owner>olivierli@chromium.org</owner> + <owner>catan-team@chromium.org</owner> + <summary> + Time it took to initialize a {BackendType} backend in {Mode} mode. Recorded + every time a backend is successfully initialized. + + Note: This metric is dropped for clients without high-precision clocks. + </summary> + <token key="Mode" variants="Mode"/> +</histogram> + +</histograms> + +</histogram-configuration>
diff --git a/tools/metrics/histograms/metadata/safe_browsing/histograms.xml b/tools/metrics/histograms/metadata/safe_browsing/histograms.xml index 5d8b46a..4d3b2ba 100644 --- a/tools/metrics/histograms/metadata/safe_browsing/histograms.xml +++ b/tools/metrics/histograms/metadata/safe_browsing/histograms.xml
@@ -873,7 +873,7 @@ </histogram> <histogram name="SafeBrowsing.EsbDownloadRowPromo.Outcome" - enum="SafeBrowsingEsbDownloadRowPromoOutcome" expires_after="2025-06-22"> + enum="SafeBrowsingEsbDownloadRowPromoOutcome" expires_after="2026-06-22"> <owner>awado@google.com</owner> <owner>chrome-safebrowsing-alerts@google.com</owner> <summary>
diff --git a/tools/perf/benchmark.csv b/tools/perf/benchmark.csv index 8d6f0341..73fe53a3 100644 --- a/tools/perf/benchmark.csv +++ b/tools/perf/benchmark.csv
@@ -46,6 +46,7 @@ dummy_benchmark.stable_benchmark_1,"johnchen@chromium.org, wenbinzhang@google.com",Test>Telemetry,, jetstream2,"vahl@chromium.org, cbruni@chromium.org",Blink>JavaScript,https://browserbench.org/JetStream2.0/in-depth.html,all jetstream2-minorms,omerkatz@chromium.org,Blink>JavaScript>GarbageCollection,https://browserbench.org/JetStream2.0/in-depth.html,all +jetstream2-no-field-trials,"vahl@chromium.org, cbruni@chromium.org",Blink>JavaScript,https://browserbench.org/JetStream2.0/in-depth.html,all load_library_perf_tests,"xhwang@chromium.org, jrummell@chromium.org",Internals>Media>Encrypted,, media.desktop,dalecurtis@chromium.org,Internals>Media,https://chromium.googlesource.com/chromium/src/+/main/docs/speed/benchmark/harnesses/media.md,"aac,audio_only,audio_video,av1,background,beginning_to_end,busyjs,cns,h264,is_2min,is_4k,is_50fps,mp3,mse,opus,seek,src,video_only,vorbis,vp8,vp9" media.mobile,dalecurtis@chromium.org,Internals>Media,https://chromium.googlesource.com/chromium/src/+/main/docs/speed/benchmark/harnesses/media.md,"aac,audio_only,audio_video,background,beginning_to_end,busyjs,cns,h264,is_2min,mp3,mse,opus,seek,src,video_only,vorbis,vp9" @@ -70,9 +71,10 @@ speedometer3,"cbruni@chromium.org, vahl@chromium.org",Blink>JavaScript,https://github.com/WebKit/Speedometer,all speedometer3-future,"cbruni@chromium.org, vahl@chromium.org",Blink>JavaScript,https://github.com/WebKit/Speedometer,all speedometer3-minorms,omerkatz@chromium.org,Blink>JavaScript>GarbageCollection,https://github.com/WebKit/Speedometer,all -speedometer3-predictable,"rasikan@google.com, wnwen@google.com",Blink>JavaScript,https://browserbench.org/Speedometer3.0,all -speedometer3.0,"cbruni@chromium.org, vahl@chromium.org",Blink>JavaScript,https://browserbench.org/Speedometer3.0,all -speedometer3.1,"cbruni@chromium.org, vahl@chromium.org",Blink>JavaScript,https://browserbench.org/Speedometer3.1,all +speedometer3-no-field-trials,"cbruni@chromium.org, vahl@chromium.org",Blink>JavaScript,https://github.com/WebKit/Speedometer,all +speedometer3-predictable,"rasikan@google.com, wnwen@google.com",Blink>JavaScript,https://github.com/WebKit/Speedometer,all +speedometer3.0,"cbruni@chromium.org, vahl@chromium.org",Blink>JavaScript,https://github.com/WebKit/Speedometer,all +speedometer3.1,"cbruni@chromium.org, vahl@chromium.org",Blink>JavaScript,https://github.com/WebKit/Speedometer,all startup.mobile,"pasko@chromium.org, lizeb@chromium.org",Speed>Metrics>SystemHealthRegressions,, system_health.common_desktop,kouhei@chromium.org,Speed>Metrics>SystemHealthRegressions,https://bit.ly/system-health-benchmarks,"2016,2018,2019,2020,2021,2025,accessibility,emerging_market,health_check,images,infinite_scroll,international,javascript_heavy,keyboard_input,scroll,wasm,webgl" system_health.common_mobile,kouhei@chromium.org,Speed>Metrics>SystemHealthRegressions,https://bit.ly/system-health-benchmarks,"2016,2018,2019,2020,2021,2023,emerging_market,health_check,images,infinite_scroll,international,javascript_heavy"
diff --git a/tools/perf/benchmarks/jetstream2.py b/tools/perf/benchmarks/jetstream2.py index 982a105..e6918fac 100644 --- a/tools/perf/benchmarks/jetstream2.py +++ b/tools/perf/benchmarks/jetstream2.py
@@ -30,7 +30,7 @@ class _JetStream2Base(press._PressBenchmark): # pylint:disable=protected-access """JetStream2, a combination of JavaScript and Web Assembly benchmarks. - Run all the JetStream 2 benchmarks by default. + Run all the JetStream 2.x benchmarks by default. """ @classmethod def AddBenchmarkCommandLineArgs(cls, parser): @@ -86,7 +86,7 @@ component='Blink>JavaScript', documentation_url='https://browserbench.org/JetStream2.0/in-depth.html') class JetStream2(_JetStream2Base): - """Latest JetStream 2 """ + """Latest JetStream 2.x """ @classmethod def Name(cls): return 'jetstream2' @@ -100,7 +100,7 @@ component='Blink>JavaScript>GarbageCollection', documentation_url='https://browserbench.org/JetStream2.0/in-depth.html') class JetStream2MinorMS(JetStream2): - """Latest JetStream2 with the MinorMS flag. + """Latest JetStream 2.x with the MinorMS flag. Shows the performance with MinorMS young generation GC in V8. """ @@ -110,3 +110,21 @@ def SetExtraBrowserOptions(self, options): options.AppendExtraBrowserArgs('--js-flags=--minor-ms') + + +@benchmark.Info( + emails=['vahl@chromium.org', 'cbruni@chromium.org'], + component='Blink>JavaScript', + documentation_url='https://browserbench.org/JetStream2.0/in-depth.html') +class JetStream2NoFieldTrial(JetStream2): + """Latest JetStream 2.x without field-trials + """ + + SCHEDULED = False + + @classmethod + def Name(cls): + return 'jetstream2-no-field-trials' + + def SetExtraBrowserOptions(self, options): + options.AppendExtraBrowserArgs('--disable-field-trial-config')
diff --git a/tools/perf/benchmarks/speedometer3.py b/tools/perf/benchmarks/speedometer3.py index 2c5e076..5a4a7b2 100644 --- a/tools/perf/benchmarks/speedometer3.py +++ b/tools/perf/benchmarks/speedometer3.py
@@ -23,9 +23,9 @@ class _Speedometer3(press._PressBenchmark): # pylint: disable=protected-access - """Abstract base Speedometer3 Benchmark class. + """Abstract base Speedometer 3.x Benchmark class. - Runs all the speedometer 2 suites by default. Add --suite=<regex> to filter + Runs all the speedometer 3 suites by default. Add --suite=<regex> to filter out suites, and only run suites whose names are matched by the regular expression provided. """ @@ -70,11 +70,10 @@ if self.take_memory_measurement: cat_filter.AddDisabledByDefault('disabled-by-default-memory-infra') - # "blink.console" is used for marking ranges in - # cache_temperature.MarkTelemetryInternal. + # Used for marking ranges in cache_temperature.MarkTelemetryInternal. cat_filter.AddIncludedCategory('blink.console') - # "toplevel" category is used to capture TaskQueueManager events. + # Used to capture TaskQueueManager events. cat_filter.AddIncludedCategory('toplevel') if self.extra_chrome_categories: @@ -139,9 +138,9 @@ @benchmark.Info(emails=['cbruni@chromium.org', 'vahl@chromium.org'], component='Blink>JavaScript', - documentation_url='https://browserbench.org/Speedometer3.0') + documentation_url='https://github.com/WebKit/Speedometer') class Speedometer30(_Speedometer3): - """Speedometer3.0 benchmark. + """Speedometer 3.0 benchmark. Explicitly named version.""" SCHEDULED = False @@ -158,9 +157,9 @@ @benchmark.Info(emails=['cbruni@chromium.org', 'vahl@chromium.org'], component='Blink>JavaScript', - documentation_url='https://browserbench.org/Speedometer3.1') + documentation_url='https://github.com/WebKit/Speedometer') class Speedometer31(_Speedometer3): - """Speedometer3.1 benchmark. + """Speedometer 3.1 benchmark. Explicitly named version.""" SCHEDULED = False @@ -179,7 +178,7 @@ component='Blink>JavaScript', documentation_url='https://github.com/WebKit/Speedometer') class Speedometer3(Speedometer31): - """The latest version of the Speedometer3 benchmark.""" + """The latest version of the Speedometer 3.x benchmark.""" SCHEDULED = True @classmethod @@ -194,8 +193,8 @@ @benchmark.Info(emails=['cbruni@chromium.org', 'vahl@chromium.org'], component='Blink>JavaScript', documentation_url='https://github.com/WebKit/Speedometer') -class V8Speedometer3Future(Speedometer3): - """The latest Speedometer3 benchmark with the V8 flag --future. +class Speedometer3Future(Speedometer3): + """The latest Speedometer 3.x benchmark with the V8 flag --future. Shows the performance of upcoming V8 VM features. """ @@ -211,7 +210,7 @@ component='Blink>JavaScript>GarbageCollection', documentation_url='https://github.com/WebKit/Speedometer') class Speedometer3MinorMS(Speedometer3): - """The latest Speedometer3 benchmark without the MinorMS flag. + """The latest Speedometer 3.x benchmark without the MinorMS flag. Shows the performance of Scavenger young generation GC in V8. """ @@ -225,9 +224,9 @@ @benchmark.Info(emails=['rasikan@google.com', 'wnwen@google.com'], component='Blink>JavaScript', - documentation_url='https://browserbench.org/Speedometer3.0') + documentation_url='https://github.com/WebKit/Speedometer') class Speedometer3Predictable(Speedometer3): - """The latest Speedometer3 benchmark with V8's `predictable` mode. + """The latest Speedometer 3.x benchmark with V8's `predictable` mode. This should (hopefully) help reduce variance in the score. """ @@ -238,3 +237,20 @@ def SetExtraBrowserOptions(self, options): options.AppendExtraBrowserArgs('--js-flags=--predictable') + + +@benchmark.Info(emails=['cbruni@chromium.org', 'vahl@chromium.org'], + component='Blink>JavaScript', + documentation_url='https://github.com/WebKit/Speedometer') +class Speedometer3NoFieldTrials(Speedometer3): + """The latest Speedometer 3.x benchmark without field-trials. + """ + + SCHEDULED = False + + @classmethod + def Name(cls): + return 'speedometer3-no-field-trials' + + def SetExtraBrowserOptions(self, options): + options.AppendExtraBrowserArgs('--disable-field-trial-config')
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json index 68f839b..0a00ec0 100644 --- a/tools/perf/core/perfetto_binary_roller/binary_deps.json +++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -5,8 +5,8 @@ "full_remote_path": "perfetto-luci-artifacts/v50.1/linux-arm64/trace_processor_shell" }, "win": { - "hash": "5bdf766679afb45ebcd3f927334ea60c428135f4", - "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/705a7f1d4eaea57364c6e74c71fe1073f359f3bc/trace_processor_shell.exe" + "hash": "15dead6b0790a4427797f7d73d704ad9f7f5add2", + "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/393c1529c36f43332b3d89f32aa5ee1e2493c2c1/trace_processor_shell.exe" }, "linux_arm": { "hash": "99f971ca131f6d11c73f4b918099d434bdd8093c", @@ -21,8 +21,8 @@ "full_remote_path": "perfetto-luci-artifacts/v50.1/mac-arm64/trace_processor_shell" }, "linux": { - "hash": "56a72d8a46e4fdba13ed6d93acfaf5718dedc0d6", - "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/393c1529c36f43332b3d89f32aa5ee1e2493c2c1/trace_processor_shell" + "hash": "82fbcb49e8dba8ad33e51215439fbaa1600519df", + "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/717bd456079cad23a0d1d52f3f9e7628af0b17ac/trace_processor_shell" } }, "power_profile.sql": {
diff --git a/tools/translation/TRANSLATION_OWNERS b/tools/translation/TRANSLATION_OWNERS index f4afbee..9533993 100644 --- a/tools/translation/TRANSLATION_OWNERS +++ b/tools/translation/TRANSLATION_OWNERS
@@ -1,3 +1,4 @@ govind@chromium.org mmoss@chromium.org benmason@chromium.org +mdb.chrome-release-translation-dump@google.com \ No newline at end of file
diff --git a/ui/android/BUILD.gn b/ui/android/BUILD.gn index e2b5fbc7..8731a58 100644 --- a/ui/android/BUILD.gn +++ b/ui/android/BUILD.gn
@@ -344,6 +344,7 @@ "java/src/org/chromium/ui/UiSwitches.java", "java/src/org/chromium/ui/ViewProvider.java", "java/src/org/chromium/ui/animation/AnimationHandler.java", + "java/src/org/chromium/ui/animation/AnimationListeners.java", "java/src/org/chromium/ui/animation/AnimationPerformanceTracker.java", "java/src/org/chromium/ui/animation/DrawableFadeInAnimatorFactory.java", "java/src/org/chromium/ui/animation/DrawableTranslationAnimatorFactory.java",
diff --git a/ui/android/java/res/values/one_off_colors.xml b/ui/android/java/res/values/one_off_colors.xml index 3041b65..dcf31045 100644 --- a/ui/android/java/res/values/one_off_colors.xml +++ b/ui/android/java/res/values/one_off_colors.xml
@@ -31,7 +31,6 @@ <color name="find_result_bar_active" tools:ignore="UnusedResources">#FF9632</color> <color name="find_result_bar_active_border" tools:ignore="UnusedResources">#C37E3B</color> - <!-- Tab group color picker related colors. These should not be used elsewhere. --> <color name="tab_group_color_picker_blue_dark">#1A73E8</color> <color name="tab_group_color_picker_blue_light">#8AB4F8</color> <color name="tab_group_color_picker_cyan_dark">#007B83</color> @@ -51,38 +50,53 @@ <color name="tab_group_color_picker_yellow_dark">#F9AB00</color> <color name="tab_group_color_picker_yellow_light">#FDD663</color> - <!-- Tab group card related colors. These should not be used elsewhere. --> - <color name="tab_group_card_color_grey_gm3">#E3E3E3</color> - <color name="tab_group_card_color_blue_gm3">#76ACFF</color> - <color name="tab_group_card_color_cyan_gm3">#60D5F3</color> - <color name="tab_group_card_color_green_gm3">#44C265</color> - <color name="tab_group_card_color_orange_gm3">#FF8D41</color> - <color name="tab_group_card_color_pink_gm3">#FF7DD2</color> - <color name="tab_group_card_color_purple_gm3">#C597FF</color> - <color name="tab_group_card_color_red_gm3">#FF8983</color> - <color name="tab_group_card_color_yellow_gm3">#FCBD00</color> + <!-- + Primary colors used for the main background of the entire tab group card. + These are defined for each color name with variants for light and dark themes. + --> + <color name="tab_group_card_primary_color_grey_light_gm3">#E3E3E3</color> + <color name="tab_group_card_primary_color_grey_dark_gm3">#303030</color> + <color name="tab_group_card_primary_color_blue_light_gm3">#D0E4FF</color> + <color name="tab_group_card_primary_color_blue_dark_gm3">#012C6F</color> + <color name="tab_group_card_primary_color_cyan_light_gm3">#ACEDFF</color> + <color name="tab_group_card_primary_color_cyan_dark_gm3">#003641</color> + <color name="tab_group_card_primary_color_green_light_gm3">#BEEFBB</color> + <color name="tab_group_card_primary_color_green_dark_gm3">#00381F</color> + <color name="tab_group_card_primary_color_orange_light_gm3">#FFDCC3</color> + <color name="tab_group_card_primary_color_orange_dark_gm3">#522302</color> + <color name="tab_group_card_primary_color_pink_light_gm3">#FFD8EF</color> + <color name="tab_group_card_primary_color_pink_dark_gm3">#620438</color> + <color name="tab_group_card_primary_color_purple_light_gm3">#EEDCFE</color> + <color name="tab_group_card_primary_color_purple_dark_gm3">#400B84</color> + <color name="tab_group_card_primary_color_red_light_gm3">#FFDADC</color> + <color name="tab_group_card_primary_color_red_dark_gm3">#60150F</color> + <color name="tab_group_card_primary_color_yellow_light_gm3">#FFE07C</color> + <color name="tab_group_card_primary_color_yellow_dark_gm3">#4D2600</color> - <!-- Tab group card text related colors. These should not be used elsewhere. --> - <color name="tab_group_card_text_color_grey_gm3">#1B1B1C</color> - <color name="tab_group_card_text_color_blue_gm3">#001944</color> - <color name="tab_group_card_text_color_cyan_gm3">#001F26</color> - <color name="tab_group_card_text_color_green_gm3">#002110</color> - <color name="tab_group_card_text_color_orange_gm3">#321200</color> - <color name="tab_group_card_text_color_pink_gm3">#3D0023</color> - <color name="tab_group_card_text_color_purple_gm3">#280255</color> - <color name="tab_group_card_text_color_red_gm3">#3A0907</color> - <color name="tab_group_card_text_color_yellow_gm3">#2F1400</color> - - <!-- Tab Group Card Placeholder related colors. These should not be used elsewhere. --> - <!-- The color for grey exists in color pallet --> - <color name="tab_group_card_placeholder_color_blue_gm3">#D0E4FF</color> - <color name="tab_group_card_placeholder_color_cyan_gm3">#ACEDFF</color> - <color name="tab_group_card_placeholder_color_green_gm3">#BEEFBB</color> - <color name="tab_group_card_placeholder_color_orange_gm3">#FFDCC3</color> - <color name="tab_group_card_placeholder_color_pink_gm3">#FFD8EF</color> - <color name="tab_group_card_placeholder_color_purple_gm3">#EEDCFE</color> - <color name="tab_group_card_placeholder_color_red_gm3">#FFDADC</color> - <color name="tab_group_card_placeholder_color_yellow_gm3">#FFE07C</color> + <!-- + Secondary colors used by subparts within the tab group card. + This palette provides colors for elements such as text, action buttons, + empty thumbnail placeholders, and the tab counter, + designed to be placed on top of the primary colors. + --> + <color name="tab_group_card_secondary_color_grey_light_gm3">#F2F2F2</color> + <color name="tab_group_card_secondary_color_grey_dark_gm3">#1B1B1C</color> + <color name="tab_group_card_secondary_color_blue_light_gm3">#E7F2FF</color> + <color name="tab_group_card_secondary_color_blue_dark_gm3">#001944</color> + <color name="tab_group_card_secondary_color_cyan_light_gm3">#D8F6FF</color> + <color name="tab_group_card_secondary_color_cyan_dark_gm3">#001F26</color> + <color name="tab_group_card_secondary_color_green_light_gm3">#DDF8D8</color> + <color name="tab_group_card_secondary_color_green_dark_gm3">#002110</color> + <color name="tab_group_card_secondary_color_orange_light_gm3">#FFEDE1</color> + <color name="tab_group_card_secondary_color_orange_dark_gm3">#321200</color> + <color name="tab_group_card_secondary_color_pink_light_gm3">#FFECF6</color> + <color name="tab_group_card_secondary_color_pink_dark_gm3">#3D0023</color> + <color name="tab_group_card_secondary_color_purple_light_gm3">#F7ECFE</color> + <color name="tab_group_card_secondary_color_purple_dark_gm3">#280255</color> + <color name="tab_group_card_secondary_color_red_light_gm3">#FFECEE</color> + <color name="tab_group_card_secondary_color_red_dark_gm3">#3A0907</color> + <color name="tab_group_card_secondary_color_yellow_light_gm3">#FFF2B4</color> + <color name="tab_group_card_secondary_color_yellow_dark_gm3">#2F1400</color> <!-- Colors used in Google Pay icon --> <color name="google_pay_icon_grey_dark">#3C4043</color>
diff --git a/ui/android/java/src/org/chromium/ui/animation/AnimationListeners.java b/ui/android/java/src/org/chromium/ui/animation/AnimationListeners.java new file mode 100644 index 0000000..078335b --- /dev/null +++ b/ui/android/java/src/org/chromium/ui/animation/AnimationListeners.java
@@ -0,0 +1,68 @@ +// Copyright 2025 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.ui.animation; + +import android.animation.Animator; +import android.animation.Animator.AnimatorListener; +import android.animation.AnimatorListenerAdapter; + +import org.chromium.base.Callback; +import org.chromium.build.annotations.NullMarked; + +/** + * A utility class for creating {@link AnimatorListener} instances from callbacks. This helps avoid + * the boilerplate of creating an anonymous {@link AnimatorListenerAdapter} when you only care about + * a single animation event. + */ +@NullMarked +public class AnimationListeners { + /** + * Creates a listener that executes a callback when an animation starts. + * + * @param callback Invoked when the animation starts. The animator that started is passed as an + * argument. + * @return An {@link AnimatorListener} that listens for the start event. + */ + public static AnimatorListener onAnimationStart(Callback<Animator> callback) { + return new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animation) { + callback.onResult(animation); + } + }; + } + + /** + * Creates a listener that executes a callback when an animation ends. + * + * @param callback Invoked when the animation ends. The animator that ended is passed as an + * argument. + * @return An {@link AnimatorListener} that listens for the end event. + */ + public static AnimatorListener onAnimationEnd(Callback<Animator> callback) { + return new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + callback.onResult(animation); + } + }; + } + + /** + * Creates a listener that executes a callback when an animation is canceled. + * + * @param callback Invoked when the animation is canceled. The animator that was canceled is + * passed as an argument. + * @return An {@link AnimatorListener} that listens for the cancel event. + */ + public static AnimatorListener onAnimationCancel(Callback<Animator> callback) { + return new AnimatorListenerAdapter() { + @Override + public void onAnimationCancel(Animator animation) { + callback.onResult(animation); + } + }; + } +}
diff --git a/ui/display/util/display_util.h b/ui/display/util/display_util.h index 74237ea..6cc85c48 100644 --- a/ui/display/util/display_util.h +++ b/ui/display/util/display_util.h
@@ -12,6 +12,7 @@ #include "ui/gfx/color_space.h" #include "ui/gfx/display_color_spaces.h" #include "ui/gfx/geometry/size.h" +#include "ui/gfx/hdr_static_metadata.h" namespace display {
diff --git a/ui/gfx/display_color_spaces.h b/ui/gfx/display_color_spaces.h index 626db13c2..0592fa49 100644 --- a/ui/gfx/display_color_spaces.h +++ b/ui/gfx/display_color_spaces.h
@@ -14,7 +14,6 @@ #include "ui/gfx/buffer_types.h" #include "ui/gfx/color_space.h" #include "ui/gfx/color_space_export.h" -#include "ui/gfx/hdr_static_metadata.h" namespace mojo { template <class T, class U>
diff --git a/ui/gfx/overlay_layer_id.cc b/ui/gfx/overlay_layer_id.cc index a718872..9ad68aac 100644 --- a/ui/gfx/overlay_layer_id.cc +++ b/ui/gfx/overlay_layer_id.cc
@@ -4,25 +4,43 @@ #include "ui/gfx/overlay_layer_id.h" +#include <sstream> +#include <variant> + #include "base/check_op.h" -#include "base/strings/stringprintf.h" +#include "base/numerics/byte_conversions.h" namespace gfx { -OverlayLayerId::OverlayLayerId() = default; +OverlayLayerId::OverlayLayerId() : impl_(VizInternalId::kOsCompositorRoot) {} + OverlayLayerId::OverlayLayerId(const NamespaceId& layer_namespace_id, - uint32_t layer_id) - : layer_namespace_id_(layer_namespace_id), layer_id_(layer_id) { + uint32_t layer_id, + uint32_t sqs_z_order) + : impl_(RendererLayer{ + .layer_namespace_id = layer_namespace_id, + .layer_id = layer_id, + .sqs_z_order = sqs_z_order, + }) { // See: `viz::FrameSinkId::is_valid()`. - CHECK(layer_namespace_id_.first != 0 || layer_namespace_id_.second != 0); + CHECK(layer_namespace_id.first != 0 || layer_namespace_id.second != 0); } + OverlayLayerId::~OverlayLayerId() = default; // static OverlayLayerId OverlayLayerId::MakeVizInternal(VizInternalId layer_id) { - CHECK_NE(VizInternalId::kInvalid, layer_id); OverlayLayerId overlay_layer_id; - overlay_layer_id.layer_id_ = static_cast<uint32_t>(layer_id); + overlay_layer_id.impl_ = {layer_id}; + return overlay_layer_id; +} + +// static +OverlayLayerId OverlayLayerId::MakeVizInternalRenderPass( + RenderPassId render_pass_id) { + OverlayLayerId overlay_layer_id; + overlay_layer_id.impl_ = std::array<uint8_t, sizeof(RenderPassId)>( + base::U64ToNativeEndian(render_pass_id.value())); return overlay_layer_id; } @@ -31,9 +49,61 @@ return OverlayLayerId({1, 1}, layer_id); } +OverlayLayerId OverlayLayerId::MakeForChildOfSharedQuadStateLayer( + uint32_t non_zero_z_order) const { + CHECK_NE(0u, non_zero_z_order); + CHECK_EQ(0u, this->z_order_); + OverlayLayerId child_id = *this; + child_id.z_order_ = non_zero_z_order; + return child_id; +} + +std::optional<OverlayLayerId::SharedQuadStateLayerId> +OverlayLayerId::shared_quad_state_layer_id() const { + if (const auto* renderer_layer = std::get_if<RendererLayer>(&impl_)) { + return std::make_optional<OverlayLayerId::SharedQuadStateLayerId>( + renderer_layer->layer_namespace_id, renderer_layer->layer_id, + renderer_layer->sqs_z_order); + } + return std::nullopt; +} + std::string OverlayLayerId::ToString() const { - return base::StringPrintf("%d:%d:%d", layer_namespace_id_.first, - layer_namespace_id_.second, layer_id_); + std::stringstream out; + + std::visit( + [&](auto&& arg) { + using T = std::decay_t<decltype(arg)>; + + if constexpr (std::is_same_v<T, VizInternalId>) { + switch (arg) { + case VizInternalId::kOsCompositorRoot: + out << "OsCompositorRoot"; + break; + case VizInternalId::kDelegatedInkTrail: + out << "DelegatedInkTrail"; + break; + } + } + + if constexpr (std::is_same_v< + T, std::array<uint8_t, sizeof(RenderPassId)>>) { + out << "RenderPass(" << base::U64FromNativeEndian(arg) << ")"; + } + + if constexpr (std::is_same_v<T, RendererLayer>) { + out << arg.layer_namespace_id.first << ":" + << arg.layer_namespace_id.second << ":" << arg.layer_id << "." + << arg.sqs_z_order; + } + }, + impl_); + + if (z_order_) { + out << "(" << z_order_ << ")"; + } + + return out.str(); } } // namespace gfx
diff --git a/ui/gfx/overlay_layer_id.h b/ui/gfx/overlay_layer_id.h index 4157c43..dcb27fc 100644 --- a/ui/gfx/overlay_layer_id.h +++ b/ui/gfx/overlay_layer_id.h
@@ -8,57 +8,97 @@ #include <stdint.h> #include <compare> +#include <optional> #include <string> #include <utility> +#include <variant> #include "base/component_export.h" +#include "base/types/id_type.h" + +namespace viz { +class AggregatedRenderPass; +} namespace gfx { -// A layer ID packing that includes the namespace. Should be stable across -// frames if OS compositor subtree reuse is desired. -// See |SharedQuadState::layer_id| and |SharedQuadState::layer_namespace_id|. +// An identifier for an overlay layer that is unique within a frame. Should be +// stable across frames if OS compositor subtree reuse is desired. class COMPONENT_EXPORT(GFX) OverlayLayerId { public: using NamespaceId = std::pair<uint32_t, uint32_t>; + // Copy of AggregatedRenderPassId, since we cannot depend on viz from here. + using RenderPassId = base::IdTypeU64<viz::AggregatedRenderPass>; + // The default constructed instance represents the implicit root node of the + // OS compositor tree. OverlayLayerId(); // `layer_namespace_id` must be non-zero. - OverlayLayerId(const NamespaceId& layer_namespace_id, uint32_t layer_id); + OverlayLayerId(const NamespaceId& layer_namespace_id, + uint32_t layer_id, + uint32_t sqs_z_order = 0); ~OverlayLayerId(); // The set of named layers that Viz make create that do not (or cannot) map // back to anything in any compositor frames. enum class VizInternalId : uint32_t { - kInvalid = 0, - kPrimaryPlane, + kOsCompositorRoot, kDelegatedInkTrail, }; - // Create an `OverlayLayerId` with a zero `layer_namespace_id`, which is - // reserved for internal viz use. - // `layer_id` must be non-zero. + // Create a named `OverlayLayerId` that is namespaced for internal viz use. static OverlayLayerId MakeVizInternal(VizInternalId layer_id); + // Create an `OverlayLayerId` that is namespaced for internal viz use and + // identifies a render pass ID. + static OverlayLayerId MakeVizInternalRenderPass(RenderPassId render_pass_id); + // Create an `OverlayLayerId` with a `layer_namespace_id` of {1,1}. static OverlayLayerId MakeForTesting(uint32_t layer_id); + // We are currently using the `SharedQuadState` layer ID, which is unique if a + // layer only contains one quad. In the case a layer contains more than one + // quad, use this function to derive unique IDs for the children. + OverlayLayerId MakeForChildOfSharedQuadStateLayer( + uint32_t non_zero_z_order) const; + auto operator<=>(const OverlayLayerId&) const = default; std::string ToString() const; // TODO(crbug.com/324460866): remove when we remove partial delegation. - using SharedQuadStateLayerId = std::pair<NamespaceId, uint32_t>; - SharedQuadStateLayerId shared_quad_state_layer_id() const { - return {layer_namespace_id_, layer_id_}; - } + using SharedQuadStateLayerId = std::tuple<NamespaceId, uint32_t, uint32_t>; + std::optional<SharedQuadStateLayerId> shared_quad_state_layer_id() const; private: - // See `viz::SharedQuadState::layer_namespace_id`. - // A value of 0 is reserved for Viz use. - NamespaceId layer_namespace_id_; - // See `viz::SharedQuadState::layer_id`. - uint32_t layer_id_ = 0; + // Represents a layer ID that is constructed from a `cc::Layer` and the frame + // sink it came from. + struct RendererLayer { + // See `viz::SharedQuadState::layer_namespace_id`. + // A value of 0 is reserved for Viz use. + NamespaceId layer_namespace_id; + // See `viz::SharedQuadState::layer_id`. + uint32_t layer_id = 0; + + // An identifier to disambiguate multiple `SharedQuadState` produced by the + // same `cc::Layer`. + uint32_t sqs_z_order = 0; + + auto operator<=>(const RendererLayer&) const = default; + }; + + // Note we store the `RenderPassId` as a byte array to not force `impl_` (and + // its discriminant) to be aligned to 8 bytes. + std::variant<VizInternalId, + std::array<uint8_t, sizeof(RenderPassId)>, + RendererLayer> + impl_; + + // This is a hack while we need to derive a stable layer ID statelessly in + // viz. This is non-zero and used for child layers when a cc layer has more + // than one quad under it. When this is zero this ID refers to the container + // node that represents the cc layer itself. + uint32_t z_order_ = 0; }; } // namespace gfx
diff --git a/ui/gl/dc_layer_tree.cc b/ui/gl/dc_layer_tree.cc index fbc86d8..a221177 100644 --- a/ui/gl/dc_layer_tree.cc +++ b/ui/gl/dc_layer_tree.cc
@@ -908,12 +908,12 @@ IDCompositionVisual2* left_sibling_visual = nullptr; - base::flat_set<gfx::OverlayLayerId::SharedQuadStateLayerId> + base::flat_set<std::optional<gfx::OverlayLayerId::SharedQuadStateLayerId>> layers_with_multiple_overlays; for (size_t i = 1; i < overlays.size(); i++) { - const gfx::OverlayLayerId::SharedQuadStateLayerId sqs_layer_id = + const decltype(layers_with_multiple_overlays)::key_type sqs_layer_id = overlays[i].layer_id.shared_quad_state_layer_id(); - if (sqs_layer_id == gfx::OverlayLayerId::SharedQuadStateLayerId()) { + if (sqs_layer_id == decltype(layers_with_multiple_overlays)::key_type()) { // A default layer ID implies no explicit layer, which should be treated // as different from every other layer ID, including itself. continue;
diff --git a/ui/gl/dcomp_presenter_unittest.cc b/ui/gl/dcomp_presenter_unittest.cc index 45dc877..25fa0fc 100644 --- a/ui/gl/dcomp_presenter_unittest.cc +++ b/ui/gl/dcomp_presenter_unittest.cc
@@ -324,6 +324,14 @@ std::ranges::move(overlays, std::back_inserter(pending_overlays_)); } + static gfx::OverlayLayerId GetRootSurfaceId() { + // Use an arbitrary render pass ID. The render passes themselves have been + // forgotten by the time we reach DCompPresenter, so we just need any unique + // identifier to represent the root surface. + return gfx::OverlayLayerId::MakeVizInternalRenderPass( + gfx::OverlayLayerId::RenderPassId(1)); + } + // DCompPresenter is surfaceless--it's root surface is achieved via an // overlay the size of the window. // We can also present a manual initialized root surface with specific size @@ -336,8 +344,7 @@ params.z_order = 0; params.quad_rect = gfx::Rect(window_size); params.overlay_image = CreateDCompSurface(window_size, initial_color); - params.layer_id = gfx::OverlayLayerId::MakeVizInternal( - gfx::OverlayLayerId::VizInternalId::kPrimaryPlane); + params.layer_id = GetRootSurfaceId(); ScheduleOverlay(std::move(params)); } @@ -865,9 +872,7 @@ EXPECT_EQ(2u, dcLayerTree->GetDcompLayerCountForTesting()); Microsoft::WRL::ComPtr<IDCompositionVisual2> visual0 = - dcLayerTree->GetContentVisualForTesting( - gfx::OverlayLayerId::MakeVizInternal( - gfx::OverlayLayerId::VizInternalId::kPrimaryPlane)); + dcLayerTree->GetContentVisualForTesting(GetRootSurfaceId()); Microsoft::WRL::ComPtr<IDCompositionVisual2> visual1 = dcLayerTree->GetContentVisualForTesting( gfx::OverlayLayerId::MakeForTesting(0)); @@ -893,9 +898,7 @@ // Verify that the visuals are reused from the previous frame but attached // to the root visual in a reversed order. EXPECT_EQ(visual0.Get(), - dcLayerTree->GetContentVisualForTesting( - gfx::OverlayLayerId::MakeVizInternal( - gfx::OverlayLayerId::VizInternalId::kPrimaryPlane))); + dcLayerTree->GetContentVisualForTesting(GetRootSurfaceId())); EXPECT_EQ(visual1.Get(), dcLayerTree->GetContentVisualForTesting( gfx::OverlayLayerId::MakeForTesting(0))); #if DCHECK_IS_ON() @@ -1013,9 +1016,7 @@ EXPECT_EQ(7u, dc_layer_tree->GetDcompLayerCountForTesting()); Microsoft::WRL::ComPtr<IDCompositionVisual2> visualRS = - dc_layer_tree->GetContentVisualForTesting( - gfx::OverlayLayerId::MakeVizInternal( - gfx::OverlayLayerId::VizInternalId::kPrimaryPlane)); + dc_layer_tree->GetContentVisualForTesting(GetRootSurfaceId()); EXPECT_NE(visualRS, nullptr); Microsoft::WRL::ComPtr<IDCompositionVisual2> visualA = dc_layer_tree->GetContentVisualForTesting( @@ -1061,10 +1062,8 @@ // D is matched to D and kept attached to the root. // C is matched to C and reattached to the root. // M is reused from E and kept attached to the root. - EXPECT_EQ(visualRS.Get(), - dc_layer_tree->GetContentVisualForTesting( - gfx::OverlayLayerId::MakeVizInternal( - gfx::OverlayLayerId::VizInternalId::kPrimaryPlane)) /*RS*/); + EXPECT_EQ(visualRS.Get(), dc_layer_tree->GetContentVisualForTesting( + GetRootSurfaceId()) /*RS*/); EXPECT_EQ(visualA.Get(), dc_layer_tree->GetContentVisualForTesting( gfx::OverlayLayerId::MakeForTesting(1)) /*A*/); EXPECT_EQ(visualB.Get(), dc_layer_tree->GetContentVisualForTesting( @@ -1317,8 +1316,7 @@ {{root_surface_hole, kRootSurfaceHiddenColor}})); root_surface.quad_rect = gfx::Rect(window_size); root_surface.z_order = 0; - root_surface.layer_id = gfx::OverlayLayerId::MakeVizInternal( - gfx::OverlayLayerId::VizInternalId::kPrimaryPlane); + root_surface.layer_id = GetRootSurfaceId(); ScheduleOverlay(std::move(root_surface)); ScheduleOverlay(std::move(fit_in_hole_overlay)); @@ -3046,8 +3044,7 @@ CreateParamsFromImage(DCLayerOverlayImage(swap_chain_size, swap_chain)); dc_layer_params.quad_rect = gfx::Rect(monitor_size); dc_layer_params.z_order = 0; - dc_layer_params.layer_id = gfx::OverlayLayerId::MakeVizInternal( - gfx::OverlayLayerId::VizInternalId::kPrimaryPlane); + dc_layer_params.layer_id = GetRootSurfaceId(); ScheduleOverlay(std::move(dc_layer_params)); ASSERT_HRESULT_SUCCEEDED(ClearRenderTargetViewAndPresent( @@ -3062,8 +3059,7 @@ dc_layer_params = CreateParamsFromImage(DCLayerOverlayImage(swap_chain_size, swap_chain)); dc_layer_params.quad_rect = gfx::Rect(monitor_size); - dc_layer_params.layer_id = gfx::OverlayLayerId::MakeVizInternal( - gfx::OverlayLayerId::VizInternalId::kPrimaryPlane); + dc_layer_params.layer_id = GetRootSurfaceId(); ScheduleOverlay(std::move(dc_layer_params)); PresentAndCheckScreenshot("cleared-swapchain"); } @@ -3099,8 +3095,7 @@ CreateParamsFromImage(CreateDCompSurface(window_size, SkColors::kWhite)); overlay.quad_rect = gfx::Rect(200, 200); overlay.z_order = 0; - overlay.layer_id = gfx::OverlayLayerId::MakeVizInternal( - gfx::OverlayLayerId::VizInternalId::kPrimaryPlane); + overlay.layer_id = GetRootSurfaceId(); ScheduleOverlay(std::move(overlay)); PresentAndCheckScreenshot("no-ink-trail"); }
diff --git a/ui/views/accessibility/tree/widget_ax_manager.cc b/ui/views/accessibility/tree/widget_ax_manager.cc index 1879f75..efe748b0 100644 --- a/ui/views/accessibility/tree/widget_ax_manager.cc +++ b/ui/views/accessibility/tree/widget_ax_manager.cc
@@ -5,6 +5,7 @@ #include "ui/views/accessibility/tree/widget_ax_manager.h" #include "ui/accessibility/accessibility_features.h" +#include "ui/accessibility/platform/ax_platform.h" namespace views { @@ -12,16 +13,26 @@ CHECK(::features::IsAccessibilityTreeForViewsEnabled()) << "WidgetAXManager should only be created when the " "accessibility tree feature is enabled."; + + ui::AXPlatform::GetInstance().AddModeObserver(this); + + if (ui::AXPlatform::GetInstance().GetMode() == ui::AXMode::kNativeAPIs) { + Enable(); + } } -WidgetAXManager::~WidgetAXManager() = default; +WidgetAXManager::~WidgetAXManager() { + ui::AXPlatform::GetInstance().RemoveModeObserver(this); +} void WidgetAXManager::Enable() { is_enabled_ = true; } -void WidgetAXManager::Disable() { - is_enabled_ = false; +void WidgetAXManager::OnAXModeAdded(ui::AXMode mode) { + if (mode.has_mode(ui::AXMode::kNativeAPIs)) { + Enable(); + } } } // namespace views
diff --git a/ui/views/accessibility/tree/widget_ax_manager.h b/ui/views/accessibility/tree/widget_ax_manager.h index bf02532..7e89928 100644 --- a/ui/views/accessibility/tree/widget_ax_manager.h +++ b/ui/views/accessibility/tree/widget_ax_manager.h
@@ -6,6 +6,7 @@ #define UI_VIEWS_ACCESSIBILITY_TREE_WIDGET_AX_MANAGER_H_ #include "base/memory/raw_ptr.h" +#include "ui/accessibility/platform/ax_mode_observer.h" #include "ui/views/views_export.h" namespace views { @@ -15,18 +16,20 @@ // This class owns and manages the accessibility tree for a Widget. It is owned // by the `widget_` and must never outlive its owner. This is currently under // construction. -class VIEWS_EXPORT WidgetAXManager { +class VIEWS_EXPORT WidgetAXManager : public ui::AXModeObserver { public: explicit WidgetAXManager(Widget* widget); WidgetAXManager(const WidgetAXManager&) = delete; WidgetAXManager& operator=(const WidgetAXManager&) = delete; - ~WidgetAXManager(); + ~WidgetAXManager() override; void Enable(); - void Disable(); bool is_enabled() const { return is_enabled_; } + // ui::AXModeObserver: + void OnAXModeAdded(ui::AXMode mode) override; + private: // The widget this manager is owned by. raw_ptr<Widget> widget_;
diff --git a/ui/views/accessibility/tree/widget_ax_manager_unittest.cc b/ui/views/accessibility/tree/widget_ax_manager_unittest.cc index 12f7a1f..79ee1626 100644 --- a/ui/views/accessibility/tree/widget_ax_manager_unittest.cc +++ b/ui/views/accessibility/tree/widget_ax_manager_unittest.cc
@@ -10,29 +10,24 @@ #include "base/test/scoped_feature_list.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/accessibility/accessibility_features.h" -#include "ui/views/test/views_test_base.h" +#include "ui/views/test/widget_test.h" #include "ui/views/widget/widget.h" -namespace views { +namespace views::test { -class WidgetAXManagerTest : public ViewsTestBase { +class WidgetAXManagerTest : public test::WidgetTest { protected: WidgetAXManagerTest() = default; ~WidgetAXManagerTest() override = default; void SetUp() override { - ViewsTestBase::SetUp(); - widget_.reset(new Widget()); - Widget::InitParams params = - CreateParams(Widget::InitParams::CLIENT_OWNS_WIDGET, - Widget::InitParams::TYPE_WINDOW); - params.bounds = gfx::Rect(0, 0, 500, 500); - widget_->Init(std::move(params)); + WidgetTest::SetUp(); + widget_.reset(CreateTopLevelPlatformWidget()); } void TearDown() override { widget_.reset(); - ViewsTestBase::TearDown(); + WidgetTest::TearDown(); } Widget* widget() { return widget_.get(); } @@ -54,10 +49,13 @@ EXPECT_TRUE(manager()->is_enabled()); } -TEST_F(WidgetAXManagerTest, DisableSetsDisabled) { - manager()->Enable(); - manager()->Disable(); - EXPECT_FALSE(manager()->is_enabled()); +TEST_F(WidgetAXManagerTest, IsEnabledAfterAXModeAdded) { + // Initially, the manager should not be enabled. + ASSERT_FALSE(manager()->is_enabled()); + + // Simulate that AXMode with kNativeAPIs was added. + ui::AXPlatform::GetInstance().NotifyModeAdded(ui::AXMode::kNativeAPIs); + EXPECT_TRUE(manager()->is_enabled()); } class WidgetAXManagerOffTest : public ViewsTestBase { @@ -88,4 +86,4 @@ widget.reset(); } -} // namespace views +} // namespace views::test
diff --git a/ui/views/test/configurable_test_frame_view.cc b/ui/views/test/configurable_test_frame_view.cc index 181337c..3be09a2 100644 --- a/ui/views/test/configurable_test_frame_view.cc +++ b/ui/views/test/configurable_test_frame_view.cc
@@ -24,6 +24,36 @@ return NativeFrameView::GetMinimumSize(); } +gfx::Rect ConfigurableTestFrameView::GetBoundsForClientView() const { + gfx::Rect client_view_bounds = NativeFrameView::GetBoundsForClientView(); + + if (client_view_margin_) { + client_view_bounds.set_width(client_view_bounds.width() - + client_view_margin_->width()); + client_view_bounds.set_height(client_view_bounds.height() - + client_view_margin_->height()); + } + + return client_view_bounds; +} + +gfx::Rect ConfigurableTestFrameView::GetWindowBoundsForClientBounds( + const gfx::Rect& client_bounds) const { + if (client_view_margin_) { + // If a margin is set, adjust the window bounds to account for the custom + // margin. We do this to answer the question: + // "How large is the window for a client with size `client_bounds?`" + gfx::Rect window_bounds = client_bounds; + window_bounds.set_width(window_bounds.width() + + client_view_margin_->width()); + window_bounds.set_height(window_bounds.height() + + client_view_margin_->height()); + return window_bounds; + } + + return NativeFrameView::GetWindowBoundsForClientBounds(client_bounds); +} + int ConfigurableTestFrameView::NonClientHitTest(const gfx::Point& point) { if (hit_test_result_) { return hit_test_result_.value();
diff --git a/ui/views/test/configurable_test_frame_view.h b/ui/views/test/configurable_test_frame_view.h index 8c3fc4c..5993b34 100644 --- a/ui/views/test/configurable_test_frame_view.h +++ b/ui/views/test/configurable_test_frame_view.h
@@ -9,6 +9,7 @@ #include "ui/base/metadata/metadata_header_macros.h" #include "ui/gfx/geometry/point.h" +#include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" #include "ui/views/window/native_frame_view.h" @@ -32,14 +33,20 @@ ConfigurableTestFrameView& operator=(const ConfigurableTestFrameView&) = delete; - void SetMinimumSize(const gfx::Size& size) { minimum_size_ = size; } - void SetHitTestResult(int result) { hit_test_result_ = result; } + void set_minimum_size(const gfx::Size& size) { minimum_size_ = size; } + void set_hit_test_result(int result) { hit_test_result_ = result; } bool fullscreen_layout_called() { return fullscreen_layout_caled_; } + void set_client_view_margin(const gfx::Size& margin) { + client_view_margin_ = margin; + } // Views gfx::Size GetMinimumSize() const override; // NativeFrameView + gfx::Rect GetBoundsForClientView() const override; + gfx::Rect GetWindowBoundsForClientBounds( + const gfx::Rect& client_bounds) const override; int NonClientHitTest(const gfx::Point& point) override; void Layout(PassKey) override; @@ -47,6 +54,7 @@ std::optional<gfx::Size> minimum_size_; std::optional<int> hit_test_result_; bool fullscreen_layout_caled_ = false; + std::optional<gfx::Size> client_view_margin_; }; } // namespace test
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform_impl_interactive_uitest.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform_impl_interactive_uitest.cc index 98294a2..26a8899d 100644 --- a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform_impl_interactive_uitest.cc +++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform_impl_interactive_uitest.cc
@@ -350,7 +350,7 @@ // Set the desired hit test result value, which will be returned, when // WindowEventFilter starts to perform hit testing. - frame_view->SetHitTestResult(hittest); + frame_view->set_hit_test_result(hittest); gfx::Rect bounds = window->GetBoundsInScreen(); @@ -432,7 +432,7 @@ auto* frame_view = delegate_->frame_view(); // Set the desired hit test result value, which will be returned, when // WindowEventFilter starts to perform hit testing. - frame_view->SetHitTestResult(HTCAPTION); + frame_view->set_hit_test_result(HTCAPTION); host_->ResetCalledMaximize(); @@ -474,20 +474,20 @@ auto* frame_view = delegate_->frame_view(); if (use_touch_event()) { - frame_view->SetHitTestResult(HTCLIENT); + frame_view->set_hit_test_result(HTCLIENT); ui::GestureEventDetails details(ui::EventType::kGestureTap); details.set_tap_count(1); DispatchEvent(GenerateGestureEvent(gfx::Point(), details)); - frame_view->SetHitTestResult(HTCLIENT); + frame_view->set_hit_test_result(HTCLIENT); details.set_tap_count(2); DispatchEvent(GenerateGestureEvent(gfx::Point(), details)); } else { - frame_view->SetHitTestResult(HTCLIENT); + frame_view->set_hit_test_result(HTCLIENT); int flags = ui::EF_LEFT_MOUSE_BUTTON; GenerateAndDispatchClickMouseEvent(gfx::Point(), flags); - frame_view->SetHitTestResult(HTCLIENT); + frame_view->set_hit_test_result(HTCLIENT); flags |= ui::EF_IS_DOUBLE_CLICK; GenerateAndDispatchClickMouseEvent(gfx::Point(), flags); } @@ -515,11 +515,11 @@ auto* frame_view = delegate_->frame_view(); - frame_view->SetHitTestResult(HTCLIENT); + frame_view->set_hit_test_result(HTCLIENT); int flags_left_button = ui::EF_LEFT_MOUSE_BUTTON; GenerateAndDispatchClickMouseEvent(gfx::Point(), flags_left_button); - frame_view->SetHitTestResult(HTCAPTION); + frame_view->set_hit_test_result(HTCAPTION); GenerateAndDispatchClickMouseEvent(gfx::Point(), ui::EF_RIGHT_MOUSE_BUTTON); EXPECT_FALSE(host_->called_maximize());
diff --git a/ui/views/widget/widget_unittest.cc b/ui/views/widget/widget_unittest.cc index 6a1489c..9774f03 100644 --- a/ui/views/widget/widget_unittest.cc +++ b/ui/views/widget/widget_unittest.cc
@@ -141,7 +141,7 @@ std::unique_ptr<NativeFrameView> CreateMinimumSizeFrameView(Widget* frame) { auto frame_view = std::make_unique<ConfigurableTestFrameView>(frame); - frame_view->SetMinimumSize(gfx::Size(300, 400)); + frame_view->set_minimum_size(gfx::Size(300, 400)); return std::move(frame_view); } @@ -5807,7 +5807,10 @@ Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW); native_widget_ = std::make_unique<MockNativeWidget>(widget()); ON_CALL(*native_widget(), CreateNonClientFrameView).WillByDefault([this]() { - return std::make_unique<NonClientFrameViewWithFixedMargin>(margin()); + auto frame_view_with_fixed_margin = + std::make_unique<test::ConfigurableTestFrameView>(widget_.get()); + frame_view_with_fixed_margin->set_client_view_margin(margin()); + return frame_view_with_fixed_margin; }); params.native_widget = native_widget(); widget()->Init(std::move(params)); @@ -5836,24 +5839,6 @@ const gfx::Size margin_; std::unique_ptr<Widget> widget_; std::unique_ptr<MockNativeWidget> native_widget_; - - // `NonClientFrameView` that pads the client view with a fixed-size margin, - // to leave room for drawing that's not included in the aspect ratio. - class NonClientFrameViewWithFixedMargin : public NonClientFrameView { - public: - // `margin` is the margin that we'll provide to our client view. - explicit NonClientFrameViewWithFixedMargin(const gfx::Size& margin) - : margin_(margin) {} - - // NonClientFrameView - gfx::Rect GetBoundsForClientView() const override { - gfx::Rect r = bounds(); - return gfx::Rect(r.x(), r.y(), r.width() - margin_.width(), - r.height() - margin_.height()); - } - - const gfx::Size margin_; - }; }; TEST_P(WidgetSetAspectRatioTest, SetAspectRatioIncludesMargin) {
diff --git a/ui/webui/resources/cr_components/searchbox/searchbox.html b/ui/webui/resources/cr_components/searchbox/searchbox.html index 538ec9cb..4f6dbc0 100644 --- a/ui/webui/resources/cr_components/searchbox/searchbox.html +++ b/ui/webui/resources/cr_components/searchbox/searchbox.html
@@ -8,7 +8,7 @@ --cr-searchbox-voice-icon-offset: 16px; --cr-searchbox-voice-search-button-width: 0px; --cr-searchbox-match-padding-inline-start: 12px; - --cr-compose-button-width: 104px; + --cr-compose-button-width: 110px; --cr-searchbox-icon-spacing: 11px; border-radius: var(--cr-searchbox-border-radius); box-shadow: var(--cr-searchbox-shadow); @@ -257,7 +257,6 @@ font-weight: 400; border: none; position: absolute; - padding: 8px 20px; } :host([searchbox-chrome-refresh-theming]:not([color-source-is-baseline])) #voiceSearchButton, @@ -372,6 +371,11 @@ top: 50%; transform: translateY(-50%); z-index: 100; + } + +.compose-icon { + filter:invert(1); + vertical-align: text-bottom; } </style> @@ -435,9 +439,10 @@ </button> </template> <template is="dom-if" if="[[composeButtonEnabled]]"> - <cr-button on-click="onComposeButtonClick_" id="composeButton" class="compose-container"> - Compose - </cr-button> + <cr-button on-click="onComposeButtonClick_" id="composeButton" class="compose-container" title="[[i18n('searchboxComposeButtonText')]]"> + <img slot="prefix-icon" src="[[composeIcon]]" class="compose-icon"></img> + $i18n{searchboxComposeButtonText} + </cr-button> </template> </template> <cr-searchbox-dropdown id="matches" part="searchbox-dropdown"
diff --git a/ui/webui/resources/cr_components/searchbox/searchbox.mojom b/ui/webui/resources/cr_components/searchbox/searchbox.mojom index 0da0795..a48a95b 100644 --- a/ui/webui/resources/cr_components/searchbox/searchbox.mojom +++ b/ui/webui/resources/cr_components/searchbox/searchbox.mojom
@@ -51,8 +51,7 @@ string icon_path; // The url for the suggestion icon. |icon_url| is an external url or // a data URI. - //TODO(crbug.com/422559532): Use url.mojom.Url instead. - string icon_url; + url.mojom.Url icon_url; // Used to paint a placeholder while fetching |image_url|. These two fields // are valid for entity suggestions only. Entity suggestions have a |type| of // 'search-suggest-entity'.
diff --git a/ui/webui/resources/cr_components/searchbox/searchbox.ts b/ui/webui/resources/cr_components/searchbox/searchbox.ts index 83131c7..9fdf86e 100644 --- a/ui/webui/resources/cr_components/searchbox/searchbox.ts +++ b/ui/webui/resources/cr_components/searchbox/searchbox.ts
@@ -147,6 +147,13 @@ reflectToAttribute: true, }, + composeIcon: { + type: String, + value: () => + '//resources/cr_components/searchbox/icons/search_spark.svg', + reflectToAttribute: true, + }, + //======================================================================== // Private properties //======================================================================== @@ -292,6 +299,7 @@ declare searchboxChromeRefreshTheming: boolean; declare searchboxSteadyStateShadow: boolean; declare composeButtonEnabled: boolean; + declare composeIcon: string; declare showThumbnail: boolean; declare private inputAriaLive_: string; declare private isLensSearchbox_: boolean;
diff --git a/ui/webui/resources/cr_components/searchbox/searchbox_icon.ts b/ui/webui/resources/cr_components/searchbox/searchbox_icon.ts index f89212c7d..d6e1b5c 100644 --- a/ui/webui/resources/cr_components/searchbox/searchbox_icon.ts +++ b/ui/webui/resources/cr_components/searchbox/searchbox_icon.ts
@@ -129,7 +129,7 @@ iconSrc_: { type: String, - computed: `computeIconSrc_(match.iconUrl, match)`, + computed: `computeIconSrc_(match.iconUrl.url, match)`, observer: 'onIconSrcChanged_', }, @@ -148,7 +148,7 @@ */ showIconImg_: { type: Boolean, - computed: `computeShowIconImg_(isLensSearchbox_, match.iconUrl, + computed: `computeShowIconImg_(isLensSearchbox_, match.iconUrl.url, match, iconLoading_)`, }, @@ -238,7 +238,7 @@ private computeShowIconImg_(): boolean { // Lens searchbox should not use icon URL. - return !this.isLensSearchbox_ && this.match && !!this.match.iconUrl && + return !this.isLensSearchbox_ && this.match && !!this.match.iconUrl.url && !this.iconLoading_; } @@ -316,7 +316,7 @@ } private computeIconSrc_(): string { - return this.computeSrc_(this.match?.iconUrl); + return this.computeSrc_(this.match?.iconUrl?.url); } private computeImageSrc_(): string {
diff --git a/v8 b/v8 index 9503e87..369e42e 160000 --- a/v8 +++ b/v8
@@ -1 +1 @@ -Subproject commit 9503e87cce58a06ea4bed24ea073f1f12c34b959 +Subproject commit 369e42eddbcbbdd259da17182c67fbe33c5170e6