diff --git a/DEPS b/DEPS index 984e9c71..4c61d50 100644 --- a/DEPS +++ b/DEPS
@@ -305,19 +305,19 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. - 'src_internal_revision': '9044ebbb524768005838a1dc2a8b0e7114e575eb', + 'src_internal_revision': '86a4a8afd51091e4227435859e44c9be53d99e77', # 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': 'b54e1064ccae404b7a7bff410585fef1c5381241', + 'skia_revision': '2b871d6b99caae5e3990351b91606e9a957f196f', # 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': '4cfbba3684e7d04a5d46c9f9a2117f84e02ef5ca', + 'v8_revision': 'ca4e6e3b342f30687ca4d36fda90be00be782331', # 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': '1f40285c90cd45ae6238c57f30d0ec8c8d6e2e4b', + 'angle_revision': '5e51d8e71c08a84ad81080036c6b25cc36b53b1b', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. @@ -397,7 +397,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': '2d6e3ee0f3197f192fe4d759e8eb6934dea46069', + 'devtools_frontend_revision': '0ef5b0631522c714639536c36dabf98a1802bf1f', # 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. @@ -1190,7 +1190,7 @@ 'packages': [ { 'package': 'chromium/chrome/android/orderfiles/arm', - 'version': 'T2mzadHQPsuVG1HhjRt3-c58amiQisG8Fp-qPRoY_FgC', + 'version': 'uz_stHaQNtsXhHznyeslC8HUgqFiaJ3qxmcGsJTArqQC', }, ], 'condition': 'checkout_android', @@ -1201,7 +1201,7 @@ 'packages': [ { 'package': 'chromium/chrome/android/orderfiles/arm64', - 'version': '0afF61bx4wGehx0eczze3V2EfbcEDoo1G_6b1afMm5cC', + 'version': 'oA9esWVQ9jlXhVe0_wczPWxQMQFzZH52279s63QufugC', }, ], 'condition': 'checkout_android', @@ -1212,7 +1212,7 @@ 'packages': [ { 'package': 'chromium/android_webview/tools/orderfiles/arm64', - 'version': 'd7DpavunvU4AgJmf14dK0lOQJPu7lzAykqvsHXqXfvMC', + 'version': 'm7Cc-GTz68mEl6sQSSDI2yEKOzzoJZoNkzrR_YYn1dkC', }, ], 'condition': 'checkout_android', @@ -1384,7 +1384,7 @@ 'packages': [ { 'package': 'chromium/third_party/updater/chromium_linux64', - 'version': 'version:2@1515005', + 'version': 'version:2@1516003', }, ], }, @@ -1439,7 +1439,7 @@ 'packages': [ { 'package': 'chromium/third_party/updater/chromium_win_x86_64', - 'version': 'version:2@1515009', + 'version': 'version:2@1516030', }, ], }, @@ -1517,7 +1517,7 @@ 'packages': [ { 'package': 'chromium/third_party/enterprise_companion/chromium_linux64', - 'version': 'pbnDd5wNxdibEG5vIXB4bluuqXvFWB_UyHpiVSW4HjQC', + 'version': 'tmcsHXibYG2BNsfWFLEnyI60NwRtLCo43oTy_6_ns00C', }, ], }, @@ -1528,7 +1528,7 @@ 'packages': [ { 'package': 'chromium/third_party/enterprise_companion/chromium_mac_amd64', - 'version': 'j1I0YjRznWAyAoJqyoAHAOSQr9gM-jJ-Waa1oArGyKYC', + 'version': 'J134yskB9yHRr9omSDGqeGm6CkfCwm8bbSf0R1CwricC', }, ], }, @@ -1561,7 +1561,7 @@ 'packages': [ { 'package': 'chromium/third_party/enterprise_companion/chromium_win_x86_64', - 'version': 'KwN21d5HdHtmiYmwVBT-QyKBMjiOdATbd3OGUNa1AvkC', + 'version': 'jY8nhCbLbm_u1NrABE_YXAcDzu1tHRns_wev2f9rlsYC', }, ], }, @@ -1708,7 +1708,7 @@ 'packages': [ { 'package': 'chromium/third_party/androidx', - 'version': 'XJzoXfyWG0qIm_nytRL9cXq3o5XVhOVLLhKUqyhiAMgC', + 'version': 'NXMMjktEtvspOzqqwtr0vBTB2fC-K4RjyzljCw8bD_gC', }, ], 'condition': 'checkout_android and non_git_source', @@ -2589,7 +2589,7 @@ Var('pdfium_git') + '/pdfium.git' + '@' + Var('pdfium_revision'), 'src/third_party/perfetto': - Var('chromium_git') + '/external/github.com/google/perfetto.git' + '@' + '95317c91aadc41a24abc2a671b211baec3d6d749', + Var('chromium_git') + '/external/github.com/google/perfetto.git' + '@' + 'c65beb1b174079f116a0d31729c43e6cbfacfc85', 'src/base/tracing/test/data': { 'bucket': 'perfetto', @@ -2908,7 +2908,7 @@ 'dep_type': 'cipd', }, - 'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@2458bba6f0d087f6ad588af68bcb4075c1d0701b', + 'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@5bc0a41ae522a65e91c77b043bce45637a1a2fde', 'src/third_party/glslang/src': '{chromium_git}/external/github.com/KhronosGroup/glslang@a57276bf558f5cf94d3a9854ebdf5a2236849a5a', '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@01e0577914a75a2569c846778c2f93aa8e6feddd', @@ -2917,7 +2917,7 @@ 'src/third_party/vulkan-loader/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Loader@6ec5a0d91c253c6374701e142a95a0d3215bf5a7', 'src/third_party/vulkan-tools/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Tools@e3ecc39da57a5ed15ec8de67f136273ee54b78be', 'src/third_party/vulkan-utility-libraries/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Utility-Libraries@23081f01cdee214226bfed5aedd37f092fa55dd9', - 'src/third_party/vulkan-validation-layers/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-ValidationLayers@102c30690b1e84e58ad659a249dbb819dcc7f926', + 'src/third_party/vulkan-validation-layers/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-ValidationLayers@c352f86877474dbc7294125d31523e8c74918c76', 'src/third_party/vulkan_memory_allocator': Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git' + '@' + 'cb0597213b0fcb999caa9ed08c2f88dc45eb7d50', @@ -2960,7 +2960,7 @@ Var('chromium_git') + '/webpagereplay.git' + '@' + Var('webpagereplay_revision'), 'src/third_party/webrtc': - Var('webrtc_git') + '/src.git' + '@' + '96075773302f4a4b7265052c37a793486355aef9', + Var('webrtc_git') + '/src.git' + '@' + 'ba391e6893da350a48a7895a0bff8f033369a729', # 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. @@ -3093,7 +3093,7 @@ 'packages': [ { 'package': 'chromeos_internal/apps/boca_app/app', - 'version': 'ZV9oYBlrFysUJa8weZCtyL-JNzGnYtCjdOaWvYXZ3ZwC', + 'version': 'Mz5dXx73Yd3-srzT2ipOxc7qC9_ynsB0a5OcvaIQdQUC', }, ], 'condition': 'checkout_chromeos and checkout_src_internal', @@ -3148,7 +3148,7 @@ 'packages': [ { 'package': 'chromeos_internal/apps/projector_app/app', - 'version': 'NjPtn9txqM5h1NzimFeMsKVu2Hqp5KOW5RO7ZELtfPsC', + 'version': '1_DjXQ2Rs1l_YNHCq7MI4n5qXa1YgJbjpp_hpQcQhcMC', }, ], 'condition': 'checkout_chromeos and checkout_src_internal', @@ -3741,7 +3741,7 @@ 'src/ios_internal': { 'url': Var('chrome_git') + '/chrome/ios_internal.git' + '@' + - 'c3935b3d5c33aad75608bd4ce39545d47b8d5b24', + '695ab1904c1b36f5a5e9864c0304ac499a0007ff', 'condition': 'checkout_ios and checkout_src_internal', },
diff --git a/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java b/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java index d7ee961..ecbfcd1 100644 --- a/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java +++ b/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java
@@ -1154,7 +1154,10 @@ Flag.baseFeature( BaseFeatures.USE_IS_UNBOUND_CHECK, "Use ChildServiceConnectionController.isUnbound() instead of isConnected() to check" - + " the connection state in ChildProcessConnection."), + + " the connection state in ChildProcessConnection."), + Flag.baseFeature( + "ProbeStylusWritingInBackground", + "Offload probing of stylus writing support to a background thread."), // Add new commandline switches and features above. The final entry should have a // trailing comma for cleaner diffs. };
diff --git a/android_webview/support_library/java/src/org/chromium/support_lib_glue/SupportLibWebViewChromiumFactory.java b/android_webview/support_library/java/src/org/chromium/support_lib_glue/SupportLibWebViewChromiumFactory.java index bf15aa8d..244e71da 100644 --- a/android_webview/support_library/java/src/org/chromium/support_lib_glue/SupportLibWebViewChromiumFactory.java +++ b/android_webview/support_library/java/src/org/chromium/support_lib_glue/SupportLibWebViewChromiumFactory.java
@@ -122,7 +122,7 @@ Features.HYPERLINK_CONTEXT_MENU_ITEMS + Features.DEV_SUFFIX, Features.ASYNC_WEBVIEW_STARTUP_ASYNC_STARTUP_LOCATIONS + Features.DEV_SUFFIX, Features.PAGE_IS_PRERENDERING, - Features.CUSTOM_REQUEST_HEADERS + Features.DEV_SUFFIX, + Features.CUSTOM_REQUEST_HEADERS, // Add new features above. New features must include `+ Features.DEV_SUFFIX` // when they're initially added (this can be removed in a future CL). The final // feature should have a trailing comma for cleaner diffs.
diff --git a/ash/app_list/app_list_presenter_unittest.cc b/ash/app_list/app_list_presenter_unittest.cc index b282225..910fadd3 100644 --- a/ash/app_list/app_list_presenter_unittest.cc +++ b/ash/app_list/app_list_presenter_unittest.cc
@@ -3126,7 +3126,7 @@ aura::Window* applist_container = Shell::GetContainer( Shell::GetPrimaryRootWindow(), kShellWindowId_AppListContainer); std::unique_ptr<aura::Window> window = aura::test::CreateTestWindow( - {.parent = applist_container, .window_id = 0}); + {.parent = applist_container, .bounds = {100, 100}, .window_id = 0}); wm::ActivateWindow(window.get()); GetAppListTestHelper()->WaitUntilIdle();
diff --git a/ash/constants/ash_pref_names.h b/ash/constants/ash_pref_names.h index 260a72b..d2ae3af 100644 --- a/ash/constants/ash_pref_names.h +++ b/ash/constants/ash_pref_names.h
@@ -1744,6 +1744,10 @@ // Whether the user is allowed to disconnect and configure VPN connections. inline constexpr char kVpnConfigAllowed[] = "vpn_config_allowed"; +// A boolean pref that indicates whether silent printing is enabled. +inline constexpr char kSilentPrintingEnabled[] = + "ash.printing.silent_printing_enabled"; + // A boolean pref that indicates whether power peak shift is enabled. // Ignored unless powerd is configured to honor charging-related prefs. inline constexpr char kPowerPeakShiftEnabled[] = "ash.power.peak_shift_enabled";
diff --git a/base/allocator/partition_alloc_features.cc b/base/allocator/partition_alloc_features.cc index 67240d6..acb0af3 100644 --- a/base/allocator/partition_alloc_features.cc +++ b/base/allocator/partition_alloc_features.cc
@@ -140,14 +140,6 @@ BASE_FEATURE(kPartitionAllocEventuallyZeroFreedMemory, FEATURE_DISABLED_BY_DEFAULT); -// Evaluated and positive stability and peformance-wise on Linux-based systems, -// disabled elsewhere (for now). Does not apply to Windows. -BASE_FEATURE(kPartitionAllocFewerMemoryRegions, -#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS) - FEATURE_ENABLED_BY_DEFAULT); -#else - FEATURE_DISABLED_BY_DEFAULT); -#endif #endif // PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) BASE_FEATURE(kPartitionAllocBackupRefPtr, @@ -216,7 +208,7 @@ {MemtagMode::kSync, "sync"}, {MemtagMode::kAsync, "async"}}; -// Note: Do not use the prepared macro as of no need for a local cache. +// Note: Do not use the prepared muacro as of no need for a local cache. constinit const FeatureParam<MemtagMode> kMemtagModeParam{ &kPartitionAllocMemoryTagging, "memtag-mode", #if PA_BUILDFLAG(USE_FULL_MTE)
diff --git a/base/allocator/partition_alloc_features.h b/base/allocator/partition_alloc_features.h index 8b4827d..fab50d9 100644 --- a/base/allocator/partition_alloc_features.h +++ b/base/allocator/partition_alloc_features.h
@@ -106,10 +106,6 @@ // fragmented super pages. BASE_EXPORT BASE_DECLARE_FEATURE(kPartitionAllocEventuallyZeroFreedMemory); -// Whether to make PartitionAlloc use fewer memory regions. This matters on -// Linux-based systems, where there is a per-process limit that we hit in some -// cases. See the comment in PartitionBucket::SlotSpanCOmmitedSize() for detail. -BASE_EXPORT BASE_DECLARE_FEATURE(kPartitionAllocFewerMemoryRegions); #endif // PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) using BackupRefPtrEnabledProcesses = internal::PAFeatureEnabledProcesses;
diff --git a/base/allocator/partition_alloc_support.cc b/base/allocator/partition_alloc_support.cc index b82382e7..7c89a9be 100644 --- a/base/allocator/partition_alloc_support.cc +++ b/base/allocator/partition_alloc_support.cc
@@ -1097,8 +1097,6 @@ const bool eventually_zero_freed_memory = base::FeatureList::IsEnabled( base::features::kPartitionAllocEventuallyZeroFreedMemory); - const bool fewer_memory_regions = base::FeatureList::IsEnabled( - base::features::kPartitionAllocFewerMemoryRegions); bool enable_memory_tagging = false; partition_alloc::TagViolationReportingMode memory_tagging_reporting_mode = @@ -1196,8 +1194,7 @@ scheduler_loop_quarantine_global_config, scheduler_loop_quarantine_thread_local_config, scheduler_loop_quarantine_for_advanced_memory_safety_checks_config, - allocator_shim::EventuallyZeroFreedMemory(eventually_zero_freed_memory), - allocator_shim::FewerMemoryRegions(fewer_memory_regions)); + allocator_shim::EventuallyZeroFreedMemory(eventually_zero_freed_memory)); const uint32_t extras_size = allocator_shim::GetMainPartitionRootExtrasSize(); // As per description, extras are optional and are expected not to
diff --git a/base/allocator/partition_allocator/src/partition_alloc/partition_alloc_config.h b/base/allocator/partition_allocator/src/partition_alloc/partition_alloc_config.h index 0756517..823ab415 100644 --- a/base/allocator/partition_allocator/src/partition_alloc/partition_alloc_config.h +++ b/base/allocator/partition_allocator/src/partition_alloc/partition_alloc_config.h
@@ -165,6 +165,18 @@ constexpr bool kUseLazyCommit = false; #endif +// See the comment in PartitionBucket::SlotSpanCommittedSize(). This should not +// be enabled on Windows (because it increases committed memory, which is a +// limited system-wide resource on this platform). It has been evaluated on +// macOS, where it yielded no beenefit (nor any real downside). +constexpr bool kUseFewerMemoryRegions = +#if PA_BUILDFLAG(IS_LINUX) || PA_BUILDFLAG(IS_ANDROID) || \ + PA_BUILDFLAG(IS_CHROMEOS) + true; +#else + false; +#endif + // On these platforms, lock all the partitions before fork(), and unlock after. // This may be required on more platforms in the future. #define PA_CONFIG_HAS_ATFORK_HANDLER() \
diff --git a/base/allocator/partition_allocator/src/partition_alloc/partition_alloc_unittest.cc b/base/allocator/partition_allocator/src/partition_alloc/partition_alloc_unittest.cc index 4306a28d..f6a2f70 100644 --- a/base/allocator/partition_allocator/src/partition_alloc/partition_alloc_unittest.cc +++ b/base/allocator/partition_allocator/src/partition_alloc/partition_alloc_unittest.cc
@@ -390,7 +390,6 @@ PartitionOptions GetCommonPartitionOptions() { PartitionOptions opts; opts.eventually_zero_freed_memory = PartitionOptions::kEnabled; - opts.fewer_memory_regions = PartitionOptions::kDisabled; opts.scheduler_loop_quarantine_global_config = { .branch_capacity_in_bytes = std::numeric_limits<size_t>::max(), .leak_on_destruction = true, @@ -3933,9 +3932,13 @@ PA_BUILDFLAG(IS_CHROMEOS) TEST_P(PartitionAllocTest, InaccessibleRegionAfterSlotSpans) { - auto* root = allocator.root(); - ASSERT_FALSE(root->settings.fewer_memory_regions); + // There is inaccessible space only when this setting is not enabled, + // otherwise we extend the region to use fewer memory regions. + if (kUseFewerMemoryRegions) { + GTEST_SKIP(); + } + auto* root = allocator.root(); // Look for an allocation size that matches a bucket which doesn't fill its // last PartitionPage. Scan through allocation sizes rather than buckets, as // depending on the bucket distribution, some buckets may not be active. @@ -3987,9 +3990,8 @@ } TEST_P(PartitionAllocTest, FewerMemoryRegions) { + static_assert(kUseFewerMemoryRegions); auto* root = allocator.root(); - ASSERT_FALSE(root->settings.fewer_memory_regions); - root->settings.fewer_memory_regions = true; // Look for an allocation size that matches a bucket which doesn't fill its // last PartitionPage. Scan through allocation sizes rather than buckets, as
diff --git a/base/allocator/partition_allocator/src/partition_alloc/partition_bucket.cc b/base/allocator/partition_allocator/src/partition_alloc/partition_bucket.cc index 31702ead..7905183 100644 --- a/base/allocator/partition_allocator/src/partition_alloc/partition_bucket.cc +++ b/base/allocator/partition_allocator/src/partition_alloc/partition_bucket.cc
@@ -1449,7 +1449,7 @@ size_t PartitionBucket::SlotSpanCommittedSize(PartitionRoot* root) const { // With lazy commit, we certainly don't want to commit more than // necessary. This is not reached, but keep the CHECK() as documentation. - PA_CHECK(!kUseLazyCommit); + static_assert(!(kUseLazyCommit && kUseFewerMemoryRegions)); // Memory is reserved in units of PartitionPage, but a given slot span may be // smaller than the reserved area. For instance (assuming 4k pages), for a @@ -1473,7 +1473,9 @@ // less than 2^16, and Chromium sometimes hits the limit (see // /proc/sys/vm/max_map_count for the current limit), largely because of // PartitionAlloc contributing thousands of regions. Locally, on a Linux - // system, this reduces the number of PartitionAlloc regions by up to ~4x. + // system, this reduces the number of PartitionAlloc regions by up to + // ~4x. This has been shown to meaningfully reduce crash rate on Linux-based + // platforms. // // Why is it safe? // The extra memory is not used by anything, so committing it doesn't make a @@ -1488,19 +1490,13 @@ // the size of the VMA red-black tree in the kernel), it might increase // slightly the cases where we bump into the sandbox memory limit. // - // Is it safe to do while running? - // Since this is decided through root settings, the value changes at runtime, - // so we may decommit memory that was never committed. This is safe onLinux, - // since decommitting is just changing permissions back to PROT_NONE, which - // the tail end would already have. - // // Can we do better? // For simplicity, we do not "fix" the regions that were committed before the // settings are changed (after feature list initialization). This means that // we end up with more regions that we could. The intent is to run a field // experiment, then change the default value, at which point we get the full // impact, so this is only temporary. - return root->settings.fewer_memory_regions + return kUseFewerMemoryRegions ? (get_pages_per_slot_span() << PartitionPageShift()) : get_bytes_per_span(); }
diff --git a/base/allocator/partition_allocator/src/partition_alloc/partition_root.cc b/base/allocator/partition_allocator/src/partition_alloc/partition_root.cc index 9834d60d..e82d9cb 100644 --- a/base/allocator/partition_allocator/src/partition_alloc/partition_root.cc +++ b/base/allocator/partition_allocator/src/partition_alloc/partition_root.cc
@@ -1042,8 +1042,6 @@ #endif // PA_BUILDFLAG(HAS_64_BIT_POINTERS) settings.eventually_zero_freed_memory = opts.eventually_zero_freed_memory == PartitionOptions::kEnabled; - settings.fewer_memory_regions = - opts.fewer_memory_regions == PartitionOptions::kEnabled; scheduler_loop_quarantine.Configure( scheduler_loop_quarantine_root,
diff --git a/base/allocator/partition_allocator/src/partition_alloc/partition_root.h b/base/allocator/partition_allocator/src/partition_alloc/partition_root.h index 8345065..b6459123 100644 --- a/base/allocator/partition_allocator/src/partition_alloc/partition_root.h +++ b/base/allocator/partition_allocator/src/partition_alloc/partition_root.h
@@ -196,17 +196,6 @@ // compression ratio of freed memory inside partially allocated pages (due to // fragmentation). EnableToggle eventually_zero_freed_memory = kDisabled; - // Linux-based systems have a limited per-process VMA limit, be more - // conservative there. This matches the feature setting in - // partition_alloc_features.cc, but not all clients use Chromium's feature - // system to configure PartitionAlloc. - EnableToggle fewer_memory_regions = -#if PA_BUILDFLAG(IS_LINUX) || PA_BUILDFLAG(IS_ANDROID) || \ - PA_BUILDFLAG(IS_CHROMEOS) - kEnabled; -#else - kDisabled; -#endif struct { EnableToggle enabled = kDisabled; @@ -279,7 +268,6 @@ bool eventually_zero_freed_memory = false; internal::SchedulerLoopQuarantineConfig scheduler_loop_quarantine_thread_local_config; - bool fewer_memory_regions = false; #if PA_BUILDFLAG(HAS_MEMORY_TAGGING) bool memory_tagging_enabled_ = false; bool use_random_memory_tagging_ = false;
diff --git a/base/allocator/partition_allocator/src/partition_alloc/shim/allocator_shim.h b/base/allocator/partition_allocator/src/partition_alloc/shim/allocator_shim.h index a35afc8..05f9e40c 100644 --- a/base/allocator/partition_allocator/src/partition_alloc/shim/allocator_shim.h +++ b/base/allocator/partition_allocator/src/partition_alloc/shim/allocator_shim.h
@@ -156,9 +156,6 @@ enum class BucketDistribution : uint8_t { kNeutral, kDenser }; using EventuallyZeroFreedMemory = partition_alloc::internal::base:: StrongAlias<class EventuallyZeroFreedMemoryTag, bool>; -using FewerMemoryRegions = - partition_alloc::internal::base::StrongAlias<class FewerMemoryRegionsTag, - bool>; // If |thread_cache_on_non_quarantinable_partition| is specified, the // thread-cache will be enabled on the non-quarantinable partition. The // thread-cache on the main (malloc) partition will be disabled. @@ -175,8 +172,7 @@ scheduler_loop_quarantine_thread_local_config, partition_alloc::internal::SchedulerLoopQuarantineConfig scheduler_loop_quarantine_for_advanced_memory_safety_checks_config, - EventuallyZeroFreedMemory eventually_zero_freed_memory, - FewerMemoryRegions fewer_memory_regions); + EventuallyZeroFreedMemory eventually_zero_freed_memory); PA_COMPONENT_EXPORT(ALLOCATOR_SHIM) uint32_t GetMainPartitionRootExtrasSize();
diff --git a/base/allocator/partition_allocator/src/partition_alloc/shim/allocator_shim_default_dispatch_to_partition_alloc.cc b/base/allocator/partition_allocator/src/partition_alloc/shim/allocator_shim_default_dispatch_to_partition_alloc.cc index 804ca665..db241ee 100644 --- a/base/allocator/partition_allocator/src/partition_alloc/shim/allocator_shim_default_dispatch_to_partition_alloc.cc +++ b/base/allocator/partition_allocator/src/partition_alloc/shim/allocator_shim_default_dispatch_to_partition_alloc.cc
@@ -659,8 +659,7 @@ scheduler_loop_quarantine_thread_local_config, partition_alloc::internal::SchedulerLoopQuarantineConfig scheduler_loop_quarantine_for_advanced_memory_safety_checks_config, - EventuallyZeroFreedMemory eventually_zero_freed_memory, - FewerMemoryRegions fewer_memory_regions) { + EventuallyZeroFreedMemory eventually_zero_freed_memory) { // Calling Get() is actually important, even if the return value isn't // used, because it has a side effect of initializing the variable, if it // wasn't already. @@ -688,9 +687,6 @@ eventually_zero_freed_memory ? partition_alloc::PartitionOptions::kEnabled : partition_alloc::PartitionOptions::kDisabled; - opts.fewer_memory_regions = - fewer_memory_regions ? partition_alloc::PartitionOptions::kEnabled - : partition_alloc::PartitionOptions::kDisabled; opts.scheduler_loop_quarantine_global_config = scheduler_loop_quarantine_global_config; opts.scheduler_loop_quarantine_thread_local_config =
diff --git a/base/allocator/partition_allocator/src/partition_alloc/shim/allocator_shim_default_dispatch_to_partition_alloc.h b/base/allocator/partition_allocator/src/partition_alloc/shim/allocator_shim_default_dispatch_to_partition_alloc.h index da97f12b..1bce541 100644 --- a/base/allocator/partition_allocator/src/partition_alloc/shim/allocator_shim_default_dispatch_to_partition_alloc.h +++ b/base/allocator/partition_allocator/src/partition_alloc/shim/allocator_shim_default_dispatch_to_partition_alloc.h
@@ -198,7 +198,6 @@ partition_alloc::internal::SchedulerLoopQuarantineConfig(); auto eventually_zero_freed_memory = EventuallyZeroFreedMemory(false); - auto fewer_memory_regions = FewerMemoryRegions(false); ConfigurePartitions( enable_brp, brp_extra_extras_size, enable_memory_tagging, @@ -206,7 +205,7 @@ scheduler_loop_quarantine_global_config, scheduler_loop_quarantine_thread_local_config, scheduler_loop_quarantine_for_advanced_memory_safety_checks_config, - eventually_zero_freed_memory, fewer_memory_regions); + eventually_zero_freed_memory); } #endif // PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
diff --git a/base/trace_event/malloc_dump_provider.cc b/base/trace_event/malloc_dump_provider.cc index b63b0cb..4da14ed 100644 --- a/base/trace_event/malloc_dump_provider.cc +++ b/base/trace_event/malloc_dump_provider.cc
@@ -608,10 +608,10 @@ auto total_active_bytes = memory_stats->total_active_bytes; size_t wasted = 0; // This should always be true, but only if our accounting of committed bytes - // is consistent, which it isn't. Indeed, with - // PartitionAllocFewerMemoryRegions, we may allocate a slot span before the - // feature state is known, in which case we commit less, then decommit it - // after, in which case we subtract the new commit unit, which is larger. + // is consistent, which it isn't. Indeed, with kUseFewerMemoryRegions, we may + // allocate a slot span before the feature state is known, in which case we + // commit less, then decommit it after, in which case we subtract the new + // commit unit, which is larger. // // Properly handling this would require remembering how much was committed, // which complicates bookkeeping, especially as metadata space is
diff --git a/build_overrides/partition_alloc.gni b/build_overrides/partition_alloc.gni index 2c92eeb..8d824e1 100644 --- a/build_overrides/partition_alloc.gni +++ b/build_overrides/partition_alloc.gni
@@ -99,6 +99,12 @@ use_allocator_shim_default = false } +# When Cronet builds within Android this is not supported. See +# https://crrev.com/c/6179216. +if (is_cronet_for_aosp_build) { + use_allocator_shim_default = false +} + shim_supports_sized_dealloc_default = use_sized_deallocation use_partition_alloc_as_malloc_default =
diff --git a/cc/tiles/gpu_image_decode_cache.cc b/cc/tiles/gpu_image_decode_cache.cc index 9f59da2..c94cead5 100644 --- a/cc/tiles/gpu_image_decode_cache.cc +++ b/cc/tiles/gpu_image_decode_cache.cc
@@ -47,8 +47,6 @@ #include "gpu/config/gpu_finch_features.h" #include "gpu/config/gpu_info.h" #include "third_party/skia/include/core/SkBitmap.h" -#include "third_party/skia/include/core/SkCanvas.h" -#include "third_party/skia/include/core/SkColorFilter.h" #include "third_party/skia/include/core/SkColorSpace.h" #include "third_party/skia/include/core/SkData.h" #include "third_party/skia/include/core/SkImage.h" @@ -57,15 +55,7 @@ #include "third_party/skia/include/core/SkRect.h" #include "third_party/skia/include/core/SkSamplingOptions.h" #include "third_party/skia/include/core/SkSize.h" -#include "third_party/skia/include/core/SkSurface.h" #include "third_party/skia/include/core/SkYUVAPixmaps.h" -#include "third_party/skia/include/gpu/GpuTypes.h" -#include "third_party/skia/include/gpu/ganesh/GrBackendSurface.h" -#include "third_party/skia/include/gpu/ganesh/GrDirectContext.h" -#include "third_party/skia/include/gpu/ganesh/GrYUVABackendTextures.h" -#include "third_party/skia/include/gpu/ganesh/SkImageGanesh.h" -#include "third_party/skia/include/gpu/ganesh/gl/GrGLBackendSurface.h" -#include "third_party/skia/include/gpu/ganesh/gl/GrGLTypes.h" #include "ui/gfx/color_space.h" #include "ui/gfx/geometry/size.h" #include "ui/gfx/geometry/skia_conversions.h" @@ -891,31 +881,19 @@ // GpuImageDecodeCache::UploadedImageData GpuImageDecodeCache::UploadedImageData::UploadedImageData() = default; -GpuImageDecodeCache::UploadedImageData::~UploadedImageData() { - DCHECK(!image()); - DCHECK(!image_yuv_planes_); - DCHECK(!gl_plane_ids_); -} +GpuImageDecodeCache::UploadedImageData::~UploadedImageData() = default; void GpuImageDecodeCache::UploadedImageData::SetTransferCacheId(uint32_t id) { - DCHECK(mode_ == Mode::kNone); - DCHECK(!image_); DCHECK(!transfer_cache_id_); - mode_ = Mode::kTransferCache; transfer_cache_id_ = id; OnSetLockedData(false /* out_of_raster */); } void GpuImageDecodeCache::UploadedImageData::Reset() { - if (mode_ != Mode::kNone) + if (transfer_cache_id_) { ReportUsageStats(); - mode_ = Mode::kNone; - image_ = nullptr; - image_yuv_planes_.reset(); - gl_plane_ids_.reset(); - gl_id_ = 0; - is_alpha_ = false; + } transfer_cache_id_.reset(); OnResetData(); } @@ -1595,66 +1573,6 @@ return max_working_set_bytes_; } -void GpuImageDecodeCache::AddTextureDump( - base::trace_event::ProcessMemoryDump* pmd, - const std::string& texture_dump_name, - const size_t bytes, - const GrGLuint gl_id, - const size_t locked_size) const { - using base::trace_event::MemoryAllocatorDump; - using base::trace_event::MemoryAllocatorDumpGuid; - - MemoryAllocatorDump* dump = pmd->CreateAllocatorDump(texture_dump_name); - dump->AddScalar(MemoryAllocatorDump::kNameSize, - MemoryAllocatorDump::kUnitsBytes, bytes); - - // Dump the "locked_size" as an additional column. - dump->AddScalar("locked_size", MemoryAllocatorDump::kUnitsBytes, locked_size); - - MemoryAllocatorDumpGuid guid; - guid = gl::GetGLTextureClientGUIDForTracing( - context_->ContextSupport()->ShareGroupTracingGUID(), gl_id); - pmd->CreateSharedGlobalAllocatorDump(guid); - // Importance of 3 gives this dump priority over the dump made by Skia - // (importance 2), attributing memory here. - const int kImportance = 3; - pmd->AddOwnershipEdge(dump->guid(), guid, kImportance); -} - -void GpuImageDecodeCache::MemoryDumpYUVImage( - base::trace_event::ProcessMemoryDump* pmd, - const ImageData* image_data, - const std::string& dump_base_name, - size_t locked_size) const { - using base::trace_event::MemoryAllocatorDump; - DCHECK(image_data->info.yuva.has_value()); - DCHECK(image_data->upload.has_yuv_planes()); - - struct PlaneMemoryDumpInfo { - size_t byte_size; - GrGLuint gl_id; - }; - std::vector<PlaneMemoryDumpInfo> plane_dump_infos; - // TODO(crbug.com/40604431): Also include alpha plane if applicable. - plane_dump_infos.push_back({image_data->upload.y_image()->textureSize(), - image_data->upload.gl_y_id()}); - plane_dump_infos.push_back({image_data->upload.u_image()->textureSize(), - image_data->upload.gl_u_id()}); - plane_dump_infos.push_back({image_data->upload.v_image()->textureSize(), - image_data->upload.gl_v_id()}); - - for (size_t i = 0u; i < plane_dump_infos.size(); ++i) { - auto plane_dump_info = plane_dump_infos.at(i); - // If the image is currently locked, we dump the locked size per plane. - AddTextureDump( - pmd, - dump_base_name + - base::StringPrintf("/plane_%0u", base::checked_cast<uint32_t>(i)), - plane_dump_info.byte_size, plane_dump_info.gl_id, - locked_size ? plane_dump_info.byte_size : 0u); - } -} - bool GpuImageDecodeCache::OnMemoryDump( const base::trace_event::MemoryDumpArgs& args, base::trace_event::ProcessMemoryDump* pmd) { @@ -2912,30 +2830,6 @@ return image_data->decode.ImageForTesting(); } -// Used for in-process-raster YUV decoding tests, where we often need the -// SkImages for each underlying plane because asserting or requesting fields for -// the YUV SkImage may flatten it to RGB or not be possible to request. -sk_sp<SkImage> GpuImageDecodeCache::GetUploadedPlaneForTesting( - const DrawImage& draw_image, - YUVIndex index) { - base::AutoLock lock(lock_); - ImageData* image_data = GetImageDataForDrawImage( - draw_image, InUseCacheKeyFromDrawImage(draw_image)); - if (!image_data->info.yuva.has_value()) { - return nullptr; - } - switch (index) { - case YUVIndex::kY: - return image_data->upload.y_image(); - case YUVIndex::kU: - return image_data->upload.u_image(); - case YUVIndex::kV: - return image_data->upload.v_image(); - default: - return nullptr; - } -} - size_t GpuImageDecodeCache::GetDarkModeImageCacheSizeForTesting( const DrawImage& draw_image) { base::AutoLock lock(lock_);
diff --git a/cc/tiles/gpu_image_decode_cache.h b/cc/tiles/gpu_image_decode_cache.h index 6446c7f..0ff2115c 100644 --- a/cc/tiles/gpu_image_decode_cache.h +++ b/cc/tiles/gpu_image_decode_cache.h
@@ -30,10 +30,6 @@ #include "cc/cc_export.h" #include "cc/paint/image_transfer_cache_entry.h" #include "cc/tiles/image_decode_cache.h" -#include "third_party/skia/include/core/SkImage.h" -#include "third_party/skia/include/core/SkRefCnt.h" -#include "third_party/skia/include/core/SkYUVAInfo.h" -#include "third_party/skia/include/gpu/ganesh/gl/GrGLTypes.h" namespace viz { class RasterContextProvider; @@ -226,8 +222,6 @@ bool IsInInUseCacheForTesting(const DrawImage& image) const; bool IsInPersistentCacheForTesting(const DrawImage& image) const; sk_sp<SkImage> GetSWImageDecodeForTesting(const DrawImage& image); - sk_sp<SkImage> GetUploadedPlaneForTesting(const DrawImage& draw_image, - YUVIndex index); size_t GetDarkModeImageCacheSizeForTesting(const DrawImage& draw_image); size_t paint_image_entries_count_for_testing() const { base::AutoLock locker(lock_); @@ -423,94 +417,13 @@ void SetTransferCacheId(uint32_t id); void Reset(); - // If in image mode. - const sk_sp<SkImage>& image() const { - DCHECK(mode_ == Mode::kSkImage || mode_ == Mode::kNone); - return image_; - } - const sk_sp<SkImage>& y_image() const { - return plane_image_internal(YUVIndex::kY); - } - const sk_sp<SkImage>& u_image() const { - return plane_image_internal(YUVIndex::kU); - } - const sk_sp<SkImage>& v_image() const { - return plane_image_internal(YUVIndex::kV); - } - GrGLuint gl_id() const { - DCHECK(mode_ == Mode::kSkImage || mode_ == Mode::kNone); - return gl_id_; - } - - GrGLuint gl_y_id() const { return gl_plane_id_internal(YUVIndex::kY); } - GrGLuint gl_u_id() const { return gl_plane_id_internal(YUVIndex::kU); } - GrGLuint gl_v_id() const { return gl_plane_id_internal(YUVIndex::kV); } - - // We consider an image to be valid YUV if all planes are non-null. - bool has_yuv_planes() const { - if (!image_yuv_planes_) { - return false; - } - auto yuv_planes_rstart = image_yuv_planes_->crbegin() + !is_alpha_; - auto yuv_planes_rend = image_yuv_planes_->crend(); - // Iterates from end to beginning, skipping alpha plane (verified to be - // last) if the image is not alpha. - bool has_existing_planes = std::any_of(yuv_planes_rstart, yuv_planes_rend, - [](auto& it) { return it; }); - bool has_null_planes = std::any_of(yuv_planes_rstart, yuv_planes_rend, - [](auto& it) { return !it; }); - if (has_existing_planes && has_null_planes) { - DLOG(ERROR) << "Image has a mix of null and decoded planes"; - } - return has_existing_planes && !has_null_planes; - } - - // If in transfer cache mode. std::optional<uint32_t> transfer_cache_id() const { - DCHECK(mode_ == Mode::kTransferCache || mode_ == Mode::kNone); return transfer_cache_id_; } private: - // Used for internal DCHECKs only. - enum class Mode { - kNone, - kSkImage, - kTransferCache, - }; - void ReportUsageStats() const; - const sk_sp<SkImage>& plane_image_internal(const YUVIndex yuv_index) const { - DCHECK(mode_ == Mode::kSkImage || mode_ == Mode::kNone); - DCHECK(image_yuv_planes_); - const size_t index = static_cast<size_t>(yuv_index); - DCHECK_GT(image_yuv_planes_->size(), index) - << "Requested reference to a plane_id that is not set"; - return image_yuv_planes_->at(index); - } - - GrGLuint gl_plane_id_internal(const YUVIndex yuv_index) const { - DCHECK(mode_ == Mode::kSkImage || mode_ == Mode::kNone); - DCHECK(gl_plane_ids_); - const size_t index = static_cast<size_t>(yuv_index); - DCHECK_GT(gl_plane_ids_->size(), index) - << "Requested GL id for a plane texture that is not uploaded"; - return gl_plane_ids_->at(index); - } - - Mode mode_ = Mode::kNone; - - // Used if |mode_| == kSkImage. - // May be null if image not yet uploaded / prepared. - sk_sp<SkImage> image_; - std::optional<YUVSkImages> image_yuv_planes_; - // TODO(crbug.com/40604431): Change after alpha support. - bool is_alpha_ = false; - GrGLuint gl_id_ = 0; - std::optional<std::array<GrGLuint, kNumYUVPlanes>> gl_plane_ids_; - - // Used if |mode_| == kTransferCache. std::optional<uint32_t> transfer_cache_id_; }; @@ -782,28 +695,6 @@ sk_sp<SkColorSpace> ColorSpaceForImageDecode(const DrawImage& image) const; - // Helper function to add a memory dump to |pmd| for a single texture - // identified by |gl_id| with size |bytes| and |locked_size| equal to either - // |bytes| or 0 depending on whether the texture is currently locked. - void AddTextureDump(base::trace_event::ProcessMemoryDump* pmd, - const std::string& texture_dump_name, - const size_t bytes, - const GrGLuint gl_id, - const size_t locked_size) const - EXCLUSIVE_LOCKS_REQUIRED(lock_); - - // Alias each texture of the YUV image entry to its Skia texture counterpart, - // taking ownership of the memory and preventing double counting. - // - // Given |dump_base_name| as the location where single RGB image textures are - // dumped, this method creates dumps under |pmd| for the planar textures - // backing |image_data| as subcategories plane_0, plane_1, etc. - void MemoryDumpYUVImage(base::trace_event::ProcessMemoryDump* pmd, - const ImageData* image_data, - const std::string& dump_base_name, - size_t locked_size) const - EXCLUSIVE_LOCKS_REQUIRED(lock_); - // |persistent_cache_| represents the long-lived cache, keeping a certain // budget of ImageDatas alive even when their ref count reaches zero. using PersistentCache = base::HashingLRUCache<PaintImage::FrameKey,
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn index 87c40042..8321c32 100644 --- a/chrome/android/BUILD.gn +++ b/chrome/android/BUILD.gn
@@ -1184,6 +1184,7 @@ "//chrome/browser/ui/messages/android:junit", "//chrome/browser/ui/plus_addresses/android:junit", "//chrome/browser/uid/android:junit", + "//chrome/browser/url_constants/android:junit", "//chrome/browser/usb/android:junit", "//chrome/browser/user_education:junit", "//chrome/browser/util:junit_tests",
diff --git a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryChipViewRenderTest.java b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryChipViewRenderTest.java index ba8867c..776e299 100644 --- a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryChipViewRenderTest.java +++ b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryChipViewRenderTest.java
@@ -97,7 +97,7 @@ public final RenderTestRule mRenderTestRule = RenderTestRule.Builder.withPublicCorpus() .setBugComponent(Component.UI_BROWSER_AUTOFILL) - .setRevision(2) + .setRevision(4) .build(); @Mock private KeyboardAccessoryView mKeyboardAccessoryView;
diff --git a/chrome/android/java/res/layout/sync_enter_passphrase.xml b/chrome/android/java/res/layout/sync_enter_passphrase.xml index 433fc1e..734eda7e 100644 --- a/chrome/android/java/res/layout/sync_enter_passphrase.xml +++ b/chrome/android/java/res/layout/sync_enter_passphrase.xml
@@ -25,7 +25,8 @@ android:hint="@string/sync_enter_custom_passphrase_hint" android:inputType="textPassword" android:singleLine="true" - android:imeOptions="actionNext" /> + android:imeOptions="actionNext" + android:textAlignment="viewStart" /> <!-- Sets this TextView as a polite accessibility live region. Changes to its text, such as "Verifying..." or "Incorrect passphrase", will be
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 14ea79e..c4c8311 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
@@ -577,6 +577,15 @@ @JniType("base::Token") Token tabGroupId, Activity activity, int newIndex); @Override + public int getPinnedTabsCount() { + // The index of the first non-pinned tab is equivalent to the number of pinned tabs. + // For example, if there are 3 pinned tabs at indices 0, 1, and 2, the first non-pinned + // tab will be at index 3. If all tabs are pinned, this will return getCount(). If no + // tabs are pinned, this will return 0. + return findFirstNonPinnedTabIndex(); + } + + @Override public void setMuteSetting(List<Tab> tabs, boolean mute) { TabModelJniBridgeJni.get().setMuteSetting(mNativeTabModelJniBridge, tabs, mute); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabPersistentStore.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabPersistentStore.java index 091ec43..db44fe3 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabPersistentStore.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabPersistentStore.java
@@ -1598,6 +1598,7 @@ recordLegacyTabCountMetrics(); recordTabCountMetrics(); + recordPinnedTabCountMetrics(); recordRestoreDuration(); recordUniqueTabUrlMetrics(); cleanUpPersistentData(); @@ -1651,6 +1652,15 @@ mTabModelSelector.getModel(true).getCount()); } + private void recordPinnedTabCountMetrics() { + RecordHistogram.recordCount1MHistogram( + "Tabs.Startup.PinnedTabCount." + mClientTag + ".Regular", + mTabModelSelector.getModel(false).getPinnedTabsCount()); + RecordHistogram.recordCount1MHistogram( + "Tabs.Startup.PinnedTabCount." + mClientTag + ".Incognito", + mTabModelSelector.getModel(true).getPinnedTabsCount()); + } + private void recordRestoreDuration() { if (mTabRestoreStartTime == INVALID_TIME) return;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinatorTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinatorTest.java index 580baa4..5b228022 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinatorTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinatorTest.java
@@ -34,6 +34,7 @@ import org.chromium.base.test.util.Batch; import org.chromium.base.test.util.CommandLineFlags; 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.Restriction; @@ -144,6 +145,8 @@ @UiThreadTest @EnableFeatures(ChromeFeatureList.ANDROID_BOOKMARK_BAR) @Restriction({DeviceFormFactor.PHONE}) + @DisabledTest + // TODO(crbug.com/447525636): Re-enable tests. public void testTopControlsHeightWithBookmarkBarWhenFlagIsEnabledOnPhone() { testTopControlsHeightWithBookmarkBar(/* expectBookmarkBar= */ false); }
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 2ba74254..5eaebf9 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
@@ -1735,6 +1735,35 @@ }); } + @Test + @SmallTest + @EnableFeatures(ChromeFeatureList.ANDROID_PINNED_TABS) + public void testGetPinnedTabsCount() { + createTabs(3); + + ThreadUtils.runOnUiThreadBlocking( + () -> { + TabModel tabModel = + mActivityTestRule.getActivity().getTabModelSelector().getModel(false); + Tab tab1 = tabModel.getTabAt(1); + Tab tab2 = tabModel.getTabAt(2); + + assertEquals(0, tabModel.getPinnedTabsCount()); + + tabModel.pinTab(tab1.getId()); + assertEquals(1, tabModel.getPinnedTabsCount()); + + tabModel.pinTab(tab2.getId()); + assertEquals(2, tabModel.getPinnedTabsCount()); + + tabModel.unpinTab(tab1.getId()); + assertEquals(1, tabModel.getPinnedTabsCount()); + + // Cleanup. + tabModel.unpinTab(tab2.getId()); + }); + } + private void assertMoveTabToIndex( int oldIndex, int newIndex, int expectedIndex, boolean movingInsideGroup) { Tab oldIndexTab = mTabModelJni.getTabAt(oldIndex);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/ToolbarTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/ToolbarTest.java index 4b1e43f..7545384 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/ToolbarTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/ToolbarTest.java
@@ -181,6 +181,8 @@ @UiThreadTest @EnableFeatures(ChromeFeatureList.ANDROID_BOOKMARK_BAR) @Restriction({DeviceFormFactor.PHONE}) + @DisabledTest + // TODO(crbug.com/447525636): Re-enable tests. public void testControlContainerTopMarginWhenBookmarkBarIsEnabledOnPhone() { testControlContainerTopMargin(/* expectBookmarkBar= */ false); }
diff --git a/chrome/android/junit/BUILD.gn b/chrome/android/junit/BUILD.gn index 6d03fadb..cb9916c 100644 --- a/chrome/android/junit/BUILD.gn +++ b/chrome/android/junit/BUILD.gn
@@ -215,6 +215,7 @@ "//chrome/browser/ui/android/toolbar:java", "//chrome/browser/ui/messages/android:java", "//chrome/browser/uid/android:java", + "//chrome/browser/url_constants/android:java", "//chrome/browser/user_education:java", "//chrome/browser/util:java", "//chrome/browser/version:java",
diff --git a/chrome/browser/ash/app_list/app_sync_ui_state.cc b/chrome/browser/ash/app_list/app_sync_ui_state.cc index 41c2a97d..41a352e7 100644 --- a/chrome/browser/ash/app_list/app_sync_ui_state.cc +++ b/chrome/browser/ash/app_list/app_sync_ui_state.cc
@@ -149,6 +149,11 @@ CheckAppSync(); } +void AppSyncUIState::OnSyncShutdown(syncer::SyncService* sync) { + // Unreachable, since this service is Shutdown() before the SyncService. + NOTREACHED(); +} + void AppSyncUIState::OnExtensionLoaded(content::BrowserContext* browser_context, const extensions::Extension* extension) { CheckAppSync();
diff --git a/chrome/browser/ash/app_list/app_sync_ui_state.h b/chrome/browser/ash/app_list/app_sync_ui_state.h index e5ee1260..30b6fd8 100644 --- a/chrome/browser/ash/app_list/app_sync_ui_state.h +++ b/chrome/browser/ash/app_list/app_sync_ui_state.h
@@ -76,6 +76,7 @@ // syncer::SyncServiceObserver overrides: void OnStateChanged(syncer::SyncService* sync) override; + void OnSyncShutdown(syncer::SyncService* sync) override; // extensions::ExtensionRegistryObserver overrides: void OnExtensionLoaded(content::BrowserContext* browser_context,
diff --git a/chrome/browser/ash/crostini/crostini_features.cc b/chrome/browser/ash/crostini/crostini_features.cc index 722dae4..bb7f214 100644 --- a/chrome/browser/ash/crostini/crostini_features.cc +++ b/chrome/browser/ash/crostini/crostini_features.cc
@@ -180,7 +180,8 @@ CrostiniFeatures::~CrostiniFeatures() = default; -bool CrostiniFeatures::CouldBeAllowed(Profile* profile, std::string* reason) { +bool CrostiniFeatures::CouldBeAllowed(Profile* profile, + std::string* reason) const { if (!base::FeatureList::IsEnabled(features::kCrostini)) { VLOG(1) << "Crostini is not enabled in feature list."; // Prior to M105, the /dev/kvm check used the same reason string. @@ -217,12 +218,13 @@ return true; } -bool CrostiniFeatures::CouldBeAllowed(Profile* profile) { +bool CrostiniFeatures::CouldBeAllowed(Profile* profile) const { std::string reason; return CouldBeAllowed(profile, &reason); } -bool CrostiniFeatures::IsAllowedNow(Profile* profile, std::string* reason) { +bool CrostiniFeatures::IsAllowedNow(Profile* profile, + std::string* reason) const { if (!CouldBeAllowed(profile, reason)) { return false; } @@ -259,23 +261,23 @@ return true; } -bool CrostiniFeatures::IsAllowedNow(Profile* profile) { +bool CrostiniFeatures::IsAllowedNow(Profile* profile) const { std::string reason; return IsAllowedNow(profile, &reason); } -bool CrostiniFeatures::IsEnabled(Profile* profile) { +bool CrostiniFeatures::IsEnabled(Profile* profile) const { return g_crostini_features->IsAllowedNow(profile) && profile->GetPrefs()->GetBoolean(crostini::prefs::kCrostiniEnabled); } -bool CrostiniFeatures::IsExportImportUIAllowed(Profile* profile) { +bool CrostiniFeatures::IsExportImportUIAllowed(Profile* profile) const { return g_crostini_features->IsAllowedNow(profile) && profile->GetPrefs()->GetBoolean( crostini::prefs::kUserCrostiniExportImportUIAllowedByPolicy); } -bool CrostiniFeatures::IsRootAccessAllowed(Profile* profile) { +bool CrostiniFeatures::IsRootAccessAllowed(Profile* profile) const { if (base::FeatureList::IsEnabled(features::kCrostiniAdvancedAccessControls)) { return profile->GetPrefs()->GetBoolean( crostini::prefs::kUserCrostiniRootAccessAllowedByPolicy); @@ -283,13 +285,13 @@ return true; } -bool CrostiniFeatures::IsContainerUpgradeUIAllowed(Profile* profile) { +bool CrostiniFeatures::IsContainerUpgradeUIAllowed(Profile* profile) const { return g_crostini_features->IsAllowedNow(profile); } void CrostiniFeatures::CanChangeAdbSideloading( Profile* profile, - CanChangeAdbSideloadingCallback callback) { + CanChangeAdbSideloadingCallback callback) const { // First rule out a child account as it is a special case - a child can be an // owner, but ADB sideloading is currently not supported for this case if (profile->IsChild()) { @@ -331,7 +333,7 @@ std::move(callback).Run(true); } -bool CrostiniFeatures::IsPortForwardingAllowed(Profile* profile) { +bool CrostiniFeatures::IsPortForwardingAllowed(Profile* profile) const { if (!profile->GetPrefs()->GetBoolean( crostini::prefs::kCrostiniPortForwardingAllowedByPolicy)) { VLOG(1) << "kCrostiniPortForwardingAllowedByPolicy preference is false."; @@ -358,7 +360,7 @@ return is_baguette; } -bool CrostiniFeatures::IsMultiContainerAllowed(Profile* profile) { +bool CrostiniFeatures::IsMultiContainerAllowed(Profile* profile) const { return g_crostini_features->IsAllowedNow(profile) && base::FeatureList::IsEnabled(ash::features::kCrostiniMultiContainer); }
diff --git a/chrome/browser/ash/crostini/crostini_features.h b/chrome/browser/ash/crostini/crostini_features.h index 55afb18..3ae68ac 100644 --- a/chrome/browser/ash/crostini/crostini_features.h +++ b/chrome/browser/ash/crostini/crostini_features.h
@@ -29,38 +29,38 @@ // lifetime of the process. Also provides the |reason| if crostini is // disallowed. The |reason| string is to only be used in crosh/vmc error // messages. - virtual bool CouldBeAllowed(Profile* profile, std::string* reason); + virtual bool CouldBeAllowed(Profile* profile, std::string* reason) const; // Returns false if this |profile| will never be allowed to run crostini for // the lifetime of this process, otherwise returns true. The return value of // this method is guaranteed not to change for a given |profile| within the // lifetime of the process. - virtual bool CouldBeAllowed(Profile* profile); + virtual bool CouldBeAllowed(Profile* profile) const; // Returns true if |profile| is allowed to run crostini at this moment. This // method will never return true if CouldBeAllowed returns false for the same // profile, but otherwise may change return value at any time. Also provides // the reason if crostini is disallowed. - virtual bool IsAllowedNow(Profile* profile, std::string* reason); + virtual bool IsAllowedNow(Profile* profile, std::string* reason) const; // Returns true if |profile| is allowed to run crostini at this moment. This // method will never return true if CouldBeAllowed returns false for the same // profile, but otherwise may change return value at any time. - virtual bool IsAllowedNow(Profile* profile); + virtual bool IsAllowedNow(Profile* profile) const; // Returns whether if Crostini has been enabled, i.e. the user has launched it // at least once and not deleted it. - virtual bool IsEnabled(Profile* profile); + virtual bool IsEnabled(Profile* profile) const; // Returns true if policy allows export import UI. - virtual bool IsExportImportUIAllowed(Profile*); + virtual bool IsExportImportUIAllowed(Profile*) const; // Returns whether user is allowed root access to Crostini. Always returns // true when advanced access controls feature flag is disabled. - virtual bool IsRootAccessAllowed(Profile*); + virtual bool IsRootAccessAllowed(Profile*) const; // Returns true if container upgrade ui is allowed by flag. - virtual bool IsContainerUpgradeUIAllowed(Profile*); + virtual bool IsContainerUpgradeUIAllowed(Profile*) const; using CanChangeAdbSideloadingCallback = base::OnceCallback<void(bool can_change_adb_sideloading)>; @@ -72,19 +72,19 @@ // whether changes to ADB sideloading are allowed. virtual void CanChangeAdbSideloading( Profile* profile, - CanChangeAdbSideloadingCallback callback); + CanChangeAdbSideloadingCallback callback) const; // Returns whether the user is allowed to configure port forwarding into // Crostini. If the user is not managed or if the policy is unset or true, // then this returns true, else if the policy is set to false, this returns // false. - virtual bool IsPortForwardingAllowed(Profile* profile); + virtual bool IsPortForwardingAllowed(Profile* profile) const; // Returns whether we are running a baguette (containerless) crostini. virtual bool IsBaguette(Profile* profile) const; // Returns true if user is allowed to use multiple (non-default) containers. - virtual bool IsMultiContainerAllowed(Profile*); + virtual bool IsMultiContainerAllowed(Profile*) const; // TODO(crbug.com/40647881): Move other functions from crostini_util to here.
diff --git a/chrome/browser/ash/crostini/fake_crostini_features.cc b/chrome/browser/ash/crostini/fake_crostini_features.cc index 1ff02dd..904cf6f1 100644 --- a/chrome/browser/ash/crostini/fake_crostini_features.cc +++ b/chrome/browser/ash/crostini/fake_crostini_features.cc
@@ -40,7 +40,7 @@ } bool FakeCrostiniFeatures::CouldBeAllowed(Profile* profile, - std::string* reason) { + std::string* reason) const { if (could_be_allowed_.has_value()) { *reason = "some reason"; return *could_be_allowed_; @@ -48,7 +48,8 @@ return original_features_->CouldBeAllowed(profile, reason); } -bool FakeCrostiniFeatures::IsAllowedNow(Profile* profile, std::string* reason) { +bool FakeCrostiniFeatures::IsAllowedNow(Profile* profile, + std::string* reason) const { if (could_be_allowed_.has_value() && !could_be_allowed_) { *reason = "some reason"; return false; @@ -60,28 +61,28 @@ return original_features_->IsAllowedNow(profile, reason); } -bool FakeCrostiniFeatures::IsEnabled(Profile* profile) { +bool FakeCrostiniFeatures::IsEnabled(Profile* profile) const { if (enabled_.has_value()) { return *enabled_; } return original_features_->IsEnabled(profile); } -bool FakeCrostiniFeatures::IsExportImportUIAllowed(Profile* profile) { +bool FakeCrostiniFeatures::IsExportImportUIAllowed(Profile* profile) const { if (export_import_ui_allowed_.has_value()) { return *export_import_ui_allowed_; } return original_features_->IsExportImportUIAllowed(profile); } -bool FakeCrostiniFeatures::IsRootAccessAllowed(Profile* profile) { +bool FakeCrostiniFeatures::IsRootAccessAllowed(Profile* profile) const { if (root_access_allowed_.has_value()) { return *root_access_allowed_; } return original_features_->IsRootAccessAllowed(profile); } -bool FakeCrostiniFeatures::IsContainerUpgradeUIAllowed(Profile* profile) { +bool FakeCrostiniFeatures::IsContainerUpgradeUIAllowed(Profile* profile) const { if (container_upgrade_ui_allowed_.has_value()) { return *container_upgrade_ui_allowed_; } @@ -90,7 +91,7 @@ void FakeCrostiniFeatures::CanChangeAdbSideloading( Profile* profile, - CanChangeAdbSideloadingCallback callback) { + CanChangeAdbSideloadingCallback callback) const { if (can_change_adb_sideloading_.has_value()) { std::move(callback).Run(*can_change_adb_sideloading_); return; @@ -98,14 +99,14 @@ original_features_->CanChangeAdbSideloading(profile, std::move(callback)); } -bool FakeCrostiniFeatures::IsPortForwardingAllowed(Profile* profile) { +bool FakeCrostiniFeatures::IsPortForwardingAllowed(Profile* profile) const { if (port_forwarding_allowed_.has_value()) { return *port_forwarding_allowed_; } return original_features_->IsPortForwardingAllowed(profile); } -bool FakeCrostiniFeatures::IsMultiContainerAllowed(Profile* profile) { +bool FakeCrostiniFeatures::IsMultiContainerAllowed(Profile* profile) const { return multi_container_allowed_.value_or( original_features_->IsMultiContainerAllowed(profile)); }
diff --git a/chrome/browser/ash/crostini/fake_crostini_features.h b/chrome/browser/ash/crostini/fake_crostini_features.h index 99c88cb..2df655c4 100644 --- a/chrome/browser/ash/crostini/fake_crostini_features.h +++ b/chrome/browser/ash/crostini/fake_crostini_features.h
@@ -24,17 +24,17 @@ ~FakeCrostiniFeatures() override; // CrostiniFeatures: - bool CouldBeAllowed(Profile* profile, std::string* reason) override; - bool IsAllowedNow(Profile* profile, std::string* reason) override; - bool IsEnabled(Profile* profile) override; - bool IsExportImportUIAllowed(Profile* profile) override; - bool IsRootAccessAllowed(Profile* profile) override; - bool IsContainerUpgradeUIAllowed(Profile* profile) override; + bool CouldBeAllowed(Profile* profile, std::string* reason) const override; + bool IsAllowedNow(Profile* profile, std::string* reason) const override; + bool IsEnabled(Profile* profile) const override; + bool IsExportImportUIAllowed(Profile* profile) const override; + bool IsRootAccessAllowed(Profile* profile) const override; + bool IsContainerUpgradeUIAllowed(Profile* profile) const override; void CanChangeAdbSideloading( Profile* profile, - CanChangeAdbSideloadingCallback callback) override; - bool IsPortForwardingAllowed(Profile* profile) override; - bool IsMultiContainerAllowed(Profile* profile) override; + CanChangeAdbSideloadingCallback callback) const override; + bool IsPortForwardingAllowed(Profile* profile) const override; + bool IsMultiContainerAllowed(Profile* profile) const override; void SetAll(bool flag); void ClearAll();
diff --git a/chrome/browser/ash/login/signin/auth_error_observer.cc b/chrome/browser/ash/login/signin/auth_error_observer.cc index 13627077..51c9a07 100644 --- a/chrome/browser/ash/login/signin/auth_error_observer.cc +++ b/chrome/browser/ash/login/signin/auth_error_observer.cc
@@ -63,6 +63,11 @@ HandleAuthError(sync->GetAuthError()); } +void AuthErrorObserver::OnSyncShutdown(syncer::SyncService* sync) { + // Unreachable, since this service is Shutdown() before the SyncService. + NOTREACHED(); +} + void AuthErrorObserver::OnErrorChanged() { // This notification could have come for any account but we are only // interested in errors for the Primary Account.
diff --git a/chrome/browser/ash/login/signin/auth_error_observer.h b/chrome/browser/ash/login/signin/auth_error_observer.h index 9bd6783..5c34dd1 100644 --- a/chrome/browser/ash/login/signin/auth_error_observer.h +++ b/chrome/browser/ash/login/signin/auth_error_observer.h
@@ -43,6 +43,7 @@ // syncer::SyncServiceObserver implementation. void OnStateChanged(syncer::SyncService* sync) override; + void OnSyncShutdown(syncer::SyncService* sync) override; // SigninErrorController::Observer implementation. void OnErrorChanged() override;
diff --git a/chrome/browser/ash/preferences/preferences.cc b/chrome/browser/ash/preferences/preferences.cc index 88751aa..84fc340 100644 --- a/chrome/browser/ash/preferences/preferences.cc +++ b/chrome/browser/ash/preferences/preferences.cc
@@ -170,6 +170,7 @@ base::Value::List()); registry->RegisterListPref(prefs::kDnsOverHttpsIncludedDomains, base::Value::List()); + registry->RegisterBooleanPref(prefs::kSilentPrintingEnabled, false); RegisterLocalStatePrefs(registry); }
diff --git a/chrome/browser/auxiliary_search/javatests/src/org/chromium/chrome/browser/auxiliary_search/AuxiliarySearchDonorTest.java b/chrome/browser/auxiliary_search/javatests/src/org/chromium/chrome/browser/auxiliary_search/AuxiliarySearchDonorTest.java index 496b956..1e612fb6 100644 --- a/chrome/browser/auxiliary_search/javatests/src/org/chromium/chrome/browser/auxiliary_search/AuxiliarySearchDonorTest.java +++ b/chrome/browser/auxiliary_search/javatests/src/org/chromium/chrome/browser/auxiliary_search/AuxiliarySearchDonorTest.java
@@ -93,16 +93,6 @@ testDonateTabsImpl(); } - @Test - @MediumTest - @EnableFeatures({ - "AndroidAppIntegrationMultiDataSource:multi_data_source_skip_schema_check/true" - }) - @DisableIf.Build(sdk_is_less_than = VERSION_CODES.S, message = "The donation API is for S+.") - public void testDonateTabs_MultiDataSource() { - testDonateTabsImpl(); - } - private void testDonateTabsImpl() { ThreadUtils.runOnUiThreadBlocking(() -> mAuxiliarySearchDonor.createSessionAndInit()); CriteriaHelper.pollUiThread(() -> mAuxiliarySearchDonor.getIsSchemaSetForTesting());
diff --git a/chrome/browser/enterprise/reporting/extension_request/extension_request_notification_unittest.cc b/chrome/browser/enterprise/reporting/extension_request/extension_request_notification_browsertest.cc similarity index 80% rename from chrome/browser/enterprise/reporting/extension_request/extension_request_notification_unittest.cc rename to chrome/browser/enterprise/reporting/extension_request/extension_request_notification_browsertest.cc index aa8fbfc3f..8757b88 100644 --- a/chrome/browser/enterprise/reporting/extension_request/extension_request_notification_unittest.cc +++ b/chrome/browser/enterprise/reporting/extension_request/extension_request_notification_browsertest.cc
@@ -10,11 +10,13 @@ #include "base/strings/utf_string_conversions.h" #include "chrome/browser/notifications/notification_display_service_tester.h" #include "chrome/browser/notifications/notification_handler.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/grit/generated_resources.h" -#include "chrome/test/base/browser_with_test_window_test.h" -#include "chrome/test/base/testing_browser_process.h" -#include "chrome/test/base/testing_profile_manager.h" -#include "content/public/test/browser_task_environment.h" +#include "chrome/test/base/in_process_browser_test.h" +#include "content/public/browser/web_contents.h" +#include "content/public/test/browser_test.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -49,17 +51,22 @@ } class ExtensionRequestNotificationTest - : public BrowserWithTestWindowTest, + : public InProcessBrowserTest, public testing::WithParamInterface< ExtensionRequestNotification::NotifyType> { public: ExtensionRequestNotificationTest() = default; ~ExtensionRequestNotificationTest() override = default; - void SetUp() override { - BrowserWithTestWindowTest::SetUp(); + void SetUpOnMainThread() override { + InProcessBrowserTest::SetUpOnMainThread(); display_service_tester_ = - std::make_unique<NotificationDisplayServiceTester>(profile()); + std::make_unique<NotificationDisplayServiceTester>(GetProfile()); + } + + void TearDownOnMainThread() override { + display_service_tester_.reset(); + InProcessBrowserTest::TearDownOnMainThread(); } ExtensionRequestNotification::NotifyType GetNotifyType() { @@ -81,9 +88,10 @@ ExtensionRequestNotification::kRejected, ExtensionRequestNotification::kForceInstalled)); -TEST_P(ExtensionRequestNotificationTest, HasExtensionAndClickedByUser) { +IN_PROC_BROWSER_TEST_P(ExtensionRequestNotificationTest, + HasExtensionAndClickedByUser) { ExtensionRequestNotification request_notification( - profile(), GetNotifyType(), + GetProfile(), GetNotifyType(), ExtensionRequestNotification::ExtensionIds({kFakeExtensionId})); base::RunLoop show_run_loop; display_service_tester_->SetNotificationAddedClosure( @@ -110,13 +118,15 @@ EXPECT_FALSE(GetNotification().has_value()); std::string expected_url = std::string(kChromeWebstoreUrl) + std::string(kFakeExtensionId); - EXPECT_EQ(GURL(expected_url), - browser()->tab_strip_model()->GetWebContentsAt(0)->GetVisibleURL()); + EXPECT_EQ( + GURL(expected_url), + browser()->tab_strip_model()->GetActiveWebContents()->GetVisibleURL()); } -TEST_P(ExtensionRequestNotificationTest, HasExtensionAndClosedByBrowser) { +IN_PROC_BROWSER_TEST_P(ExtensionRequestNotificationTest, + HasExtensionAndClosedByBrowser) { ExtensionRequestNotification request_notification( - profile(), GetNotifyType(), + GetProfile(), GetNotifyType(), ExtensionRequestNotification::ExtensionIds({kFakeExtensionId})); base::RunLoop show_run_loop; display_service_tester_->SetNotificationAddedClosure(
diff --git a/chrome/browser/extensions/api/autofill_private/autofill_ai_util.cc b/chrome/browser/extensions/api/autofill_private/autofill_ai_util.cc index 595adb7..6253b7c3 100644 --- a/chrome/browser/extensions/api/autofill_private/autofill_ai_util.cc +++ b/chrome/browser/extensions/api/autofill_private/autofill_ai_util.cc
@@ -17,6 +17,7 @@ #include "base/types/cxx23_to_underlying.h" #include "base/values.h" #include "chrome/common/extensions/api/autofill_private.h" +#include "components/autofill/core/browser/autofill_field.h" #include "components/autofill/core/browser/data_model/addresses/autofill_structured_address_component.h" #include "components/autofill/core/browser/data_model/autofill_ai/entity_instance.h" #include "components/autofill/core/browser/data_model/autofill_ai/entity_type.h" @@ -35,6 +36,7 @@ using autofill::AttributeInstance; using autofill::AttributeType; using autofill::AttributeTypeName; +using autofill::AutofillFormatString; using autofill::EntityInstance; using autofill::EntityType; using autofill::EntityTypeName; @@ -210,16 +212,21 @@ return std::nullopt; } - attribute_instance.SetInfo(attribute_instance.type().field_type(), - base::UTF8ToUTF16(date->month), app_locale, - u"M", - autofill::VerificationStatus::kUserVerified); - attribute_instance.SetInfo(attribute_instance.type().field_type(), - base::UTF8ToUTF16(date->day), app_locale, u"D", - autofill::VerificationStatus::kUserVerified); + attribute_instance.SetInfo( + attribute_instance.type().field_type(), + base::UTF8ToUTF16(date->month), app_locale, + AutofillFormatString(u"M", autofill::FormatString_Type_DATE), + autofill::VerificationStatus::kUserVerified); + attribute_instance.SetInfo( + attribute_instance.type().field_type(), base::UTF8ToUTF16(date->day), + app_locale, + AutofillFormatString(u"D", autofill::FormatString_Type_DATE), + autofill::VerificationStatus::kUserVerified); attribute_instance.SetInfo( attribute_instance.type().field_type(), base::UTF8ToUTF16(date->year), - app_locale, u"YYYY", autofill::VerificationStatus::kUserVerified); + app_locale, + AutofillFormatString(u"YYYY", autofill::FormatString_Type_DATE), + autofill::VerificationStatus::kUserVerified); } else { if (!private_api_attribute_instance.value.as_string.has_value()) { return std::nullopt; @@ -273,14 +280,20 @@ autofill::FieldType field_type = attribute_instance.type().field_type(); base::DictValue date_value; date_value.SetByDottedPath( - "month", base::UTF16ToUTF8(attribute_instance.GetInfo( - field_type, app_locale, std::u16string(u"M")))); + "month", + base::UTF16ToUTF8(attribute_instance.GetInfo( + field_type, app_locale, + AutofillFormatString(u"M", autofill::FormatString_Type_DATE)))); date_value.SetByDottedPath( - "day", base::UTF16ToUTF8(attribute_instance.GetInfo( - field_type, app_locale, std::u16string(u"D")))); + "day", + base::UTF16ToUTF8(attribute_instance.GetInfo( + field_type, app_locale, + AutofillFormatString(u"D", autofill::FormatString_Type_DATE)))); date_value.SetByDottedPath( "year", base::UTF16ToUTF8(attribute_instance.GetInfo( - field_type, app_locale, std::u16string(u"YYYY")))); + field_type, app_locale, + AutofillFormatString(u"YYYY", + autofill::FormatString_Type_DATE)))); autofill_private::AttributeInstance::Value::Populate( base::Value(std::move(date_value)), private_api_attribute_instances.back().value);
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index 75bd7be4..a16b009 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -6490,6 +6490,11 @@ "expiry_milestone": 140 }, { + "name": "lens-overlay-custom-bottom-sheet", + "owners": ["radunitescu@google.com"], + "expiry_milestone": 152 + }, + { "name": "lens-overlay-disable-iph-pan-gesture", "owners": [ "stkhapugin@chromium.org", "christianxu@chromium.org", "lens-chrome@google.com" ], "expiry_milestone": 140
diff --git a/chrome/browser/keyboard_accessory/android/internal/java/res/values/dimens.xml b/chrome/browser/keyboard_accessory/android/internal/java/res/values/dimens.xml index 68402398..64af1ebc 100644 --- a/chrome/browser/keyboard_accessory/android/internal/java/res/values/dimens.xml +++ b/chrome/browser/keyboard_accessory/android/internal/java/res/values/dimens.xml
@@ -12,7 +12,7 @@ <dimen name="keyboard_accessory_height">48dp</dimen> <dimen name="keyboard_accessory_height_redesign">64dp</dimen> <dimen name="keyboard_accessory_chip_min_height_redesign">64dp</dimen> - <dimen name="keyboard_accessory_chip_corner_radius_redesign">16dp</dimen> + <dimen name="keyboard_accessory_chip_corner_radius_redesign">8dp</dimen> <dimen name="keyboard_accessory_chip_home_and_work_start_padding">12dp</dimen> <dimen name="keyboard_accessory_top_inset_overlap">4dp</dimen> <dimen name="keyboard_accessory_dismiss_button_end_padding">10dp</dimen> @@ -26,6 +26,9 @@ <dimen name="keyboard_accessory_sheet_top_margin">16dp</dimen> <dimen name="keyboard_accessory_sheet_bottom_margin">8dp</dimen> <dimen name="keyboard_accessory_suggestion_padding">16dp</dimen> + <dimen name="keyboard_accessory_chip_start_padding_redesign">6dp</dimen> + <dimen name="keyboard_accessory_chip_end_padding_redesign">12dp</dimen> + <dimen name="keyboard_accessory_text_start_padding_redesign">6dp</dimen> <dimen name="keyboard_accessory_suggestion_offset">12dp</dimen> <dimen name="keyboard_accessory_suggestion_height">48dp</dimen> <dimen name="keyboard_accessory_scroll_shadow_width">80dp</dimen>
diff --git a/chrome/browser/keyboard_accessory/android/internal/java/res/values/styles.xml b/chrome/browser/keyboard_accessory/android/internal/java/res/values/styles.xml index 6fede38..5f27131 100644 --- a/chrome/browser/keyboard_accessory/android/internal/java/res/values/styles.xml +++ b/chrome/browser/keyboard_accessory/android/internal/java/res/values/styles.xml
@@ -47,11 +47,13 @@ <item name="cornerRadius"> @dimen/keyboard_accessory_chip_corner_radius_redesign </item> - <item name="solidColorChip">true</item> + <item name="chipStartPadding">@dimen/keyboard_accessory_chip_start_padding_redesign</item> + <item name="chipEndPadding">@dimen/keyboard_accessory_chip_end_padding_redesign</item> <item name="textArrangement">vertical</item> <item name="textAlignStart">true</item> <item name="primaryTextAppearance">@style/TextAppearance.TextAccentMediumThick.Primary</item> - <item name="secondaryTextAppearance">@style/TextAppearance.TextSmall.Secondary</item> + <item name="primaryTextStartPadding">@dimen/keyboard_accessory_text_start_padding_redesign</item> + <item name="secondaryTextAppearance">@style/TextAppearance.TextSmall.Primary</item> <item name="iconWidth"> @dimen/keyboard_accessory_bar_item_icon_width </item> @@ -62,22 +64,18 @@ <style name="KeyboardAccessoryLoyaltyCardTwoLineChip" parent="KeyboardAccessoryTwoLineChip"> <item name="iconWidth">@dimen/keyboard_accessory_suggestion_icon_size</item> <item name="iconHeight">@dimen/keyboard_accessory_suggestion_icon_size</item> - <item name="useRoundedIcon">true</item> </style> <style name="KeyboardAccessoryLoyaltyCardLargeTwoLineChip" parent="KeyboardAccessoryLargeTwoLineChip"> <item name="iconWidth">@dimen/keyboard_accessory_suggestion_icon_size</item> <item name="iconHeight">@dimen/keyboard_accessory_suggestion_icon_size</item> - <item name="useRoundedIcon">true</item> </style> - <!-- TODO: crbug.com/444403583 - Figure out correcr padding for Home&Word suggestions. --> + <!-- TODO: crbug.com/444403583 - Figure out correct padding for Home&Word suggestions. --> <style name="KeyboardAccessoryHomeAndWorkTwoLineChip" parent="KeyboardAccessoryTwoLineChip"> <item name="iconWidth">@dimen/keyboard_accessory_suggestion_icon_size</item> <item name="iconHeight">@dimen/keyboard_accessory_suggestion_icon_size</item> - <item name="chipStartPadding">@dimen/keyboard_accessory_chip_home_and_work_start_padding</item> </style> <style name="KeyboardAccessoryHomeAndWorkLargeTwoLineChip" parent="KeyboardAccessoryLargeTwoLineChip"> <item name="iconWidth">@dimen/keyboard_accessory_suggestion_icon_size</item> <item name="iconHeight">@dimen/keyboard_accessory_suggestion_icon_size</item> - <item name="chipStartPadding">@dimen/keyboard_accessory_chip_home_and_work_start_padding</item> </style> </resources>
diff --git a/chrome/browser/password_manager/actor_login/internal/actor_login_delegate_impl.cc b/chrome/browser/password_manager/actor_login/internal/actor_login_delegate_impl.cc index 38e616b5..2a8c24d 100644 --- a/chrome/browser/password_manager/actor_login/internal/actor_login_delegate_impl.cc +++ b/chrome/browser/password_manager/actor_login/internal/actor_login_delegate_impl.cc
@@ -164,5 +164,4 @@ std::move(pending_attempt_login_callback_).Run(std::move(result)); } - } // namespace actor_login
diff --git a/chrome/browser/password_manager/android/password_manager_settings_service_android_impl.cc b/chrome/browser/password_manager/android/password_manager_settings_service_android_impl.cc index c6a2791..4ec5899 100644 --- a/chrome/browser/password_manager/android/password_manager_settings_service_android_impl.cc +++ b/chrome/browser/password_manager/android/password_manager_settings_service_android_impl.cc
@@ -163,6 +163,13 @@ account, PasswordManagerSetting::kAutoSignIn, false); } +void PasswordManagerSettingsServiceAndroidImpl::Shutdown() { + if (sync_service_) { + sync_service_->RemoveObserver(this); + sync_service_ = nullptr; + } +} + void PasswordManagerSettingsServiceAndroidImpl::Init() { bridge_helper_->SetConsumer(weak_ptr_factory_.GetWeakPtr()); lifecycle_helper_->RegisterObserver(base::BindRepeating( @@ -245,3 +252,9 @@ // Chrome's cache. RequestSettingsFromBackend(); } + +void PasswordManagerSettingsServiceAndroidImpl::OnSyncShutdown( + syncer::SyncService* sync) { + // Unreachable, since this service is Shutdown() before the SyncService. + NOTREACHED(); +}
diff --git a/chrome/browser/password_manager/android/password_manager_settings_service_android_impl.h b/chrome/browser/password_manager/android/password_manager_settings_service_android_impl.h index 12537d4..e86fc2ff1 100644 --- a/chrome/browser/password_manager/android/password_manager_settings_service_android_impl.h +++ b/chrome/browser/password_manager/android/password_manager_settings_service_android_impl.h
@@ -57,6 +57,9 @@ void RequestSettingsFromBackend() override; void TurnOffAutoSignIn() override; + // KeyedService implementation + void Shutdown() override; + private: // Does actions that need to be done on startup (e.g. attaches services // observers and migrates and requests settings if needed). @@ -84,6 +87,7 @@ // syncer::SyncServiceObserver implementation void OnStateChanged(syncer::SyncService* sync) override; + void OnSyncShutdown(syncer::SyncService* sync) override; // Pref service used to read and write password manager user prefs. raw_ptr<PrefService> pref_service_ = nullptr;
diff --git a/chrome/browser/policy/cloud/user_policy_signin_service_browsertest.cc b/chrome/browser/policy/cloud/user_policy_signin_service_browsertest.cc index 85b3ae0b..0a089c1 100644 --- a/chrome/browser/policy/cloud/user_policy_signin_service_browsertest.cc +++ b/chrome/browser/policy/cloud/user_policy_signin_service_browsertest.cc
@@ -39,6 +39,7 @@ #include "components/signin/public/identity_manager/identity_test_utils.h" #include "components/signin/public/identity_manager/primary_account_mutator.h" #include "components/sync/base/command_line_switches.h" +#include "components/sync/base/features.h" #include "content/public/test/browser_test.h" #include "google_apis/gaia/fake_gaia.h" #include "google_apis/gaia/gaia_switches.h" @@ -422,41 +423,6 @@ EXPECT_TRUE(enterprise_util::ProfileCanBeManaged(profile())); } -// Regression test for https://crbug.com/1061459 -// Start a new signing flow while the existing one is hanging on a policy -// request. -IN_PROC_BROWSER_TEST_F(UserPolicySigninServiceTest, ConcurrentSignin) { - EXPECT_FALSE(profile()->GetPrefs()->GetBoolean(prefs::kShowHomeButton)); - - set_policy_hanging(true); - CreateTurnSyncOnHelper(); - WaitForPolicyHanging(); - - // Policy hanging, policy is not applied. - EXPECT_FALSE(profile()->GetPrefs()->GetBoolean(prefs::kShowHomeButton)); - EXPECT_TRUE(signin_client()->IsClearPrimaryAccountAllowed()); - - // Restart a new signin flow and allow it to complete. - CreateTurnSyncOnHelper(); - set_policy_hanging(false); - WaitForSyncConfirmation(); - - // Policies are applied right before the sync confirmation is shown. - EXPECT_EQ(signin::ConsentLevel::kSignin, - signin::GetPrimaryAccountConsentLevel(identity_manager())); - EXPECT_TRUE(profile()->GetPrefs()->GetBoolean(prefs::kShowHomeButton)); - EXPECT_FALSE(signin_client()->IsClearPrimaryAccountAllowed()); - - // Confirm the signin. - ConfirmSync(LoginUIService::SYNC_WITH_DEFAULT_SETTINGS); - // Policy is still applied. - EXPECT_TRUE(profile()->GetPrefs()->GetBoolean(prefs::kShowHomeButton)); - EXPECT_EQ(signin::ConsentLevel::kSync, - signin::GetPrimaryAccountConsentLevel(identity_manager())); - EXPECT_FALSE(signin_client()->IsClearPrimaryAccountAllowed()); - EXPECT_TRUE(signin_client()->IsRevokeSyncConsentAllowed()); -} - // Disabled for Win11 arm64 flakes: https://crbug.com/340623286 IN_PROC_BROWSER_TEST_F(UserPolicySigninServiceTest, DISABLED_AcceptManagementDeclineSync) { @@ -493,3 +459,52 @@ EXPECT_TRUE(enterprise_util::ProfileCanBeManaged(profile())); TurnSyncOnHelper::SetShowSyncEnabledUiForTesting(false); } + +class UserPolicySigninServiceTestWithReplaceSyncPromosWithSignInPromosDisabled + : public UserPolicySigninServiceTest { + public: + UserPolicySigninServiceTestWithReplaceSyncPromosWithSignInPromosDisabled() { + scoped_feature_list_.InitAndDisableFeature( + syncer::kReplaceSyncPromosWithSignInPromos); + } + + private: + base::test::ScopedFeatureList scoped_feature_list_; +}; + +// Regression test for https://crbug.com/1061459 +// Start a new signing flow while the existing one is hanging on a policy +// request. +IN_PROC_BROWSER_TEST_F( + UserPolicySigninServiceTestWithReplaceSyncPromosWithSignInPromosDisabled, + ConcurrentSignin) { + EXPECT_FALSE(profile()->GetPrefs()->GetBoolean(prefs::kShowHomeButton)); + + set_policy_hanging(true); + CreateTurnSyncOnHelper(); + WaitForPolicyHanging(); + + // Policy hanging, policy is not applied. + EXPECT_FALSE(profile()->GetPrefs()->GetBoolean(prefs::kShowHomeButton)); + EXPECT_TRUE(signin_client()->IsClearPrimaryAccountAllowed()); + + // Restart a new signin flow and allow it to complete. + CreateTurnSyncOnHelper(); + set_policy_hanging(false); + WaitForSyncConfirmation(); + + // Policies are applied right before the sync confirmation is shown. + EXPECT_EQ(signin::ConsentLevel::kSignin, + signin::GetPrimaryAccountConsentLevel(identity_manager())); + EXPECT_TRUE(profile()->GetPrefs()->GetBoolean(prefs::kShowHomeButton)); + EXPECT_FALSE(signin_client()->IsClearPrimaryAccountAllowed()); + + // Confirm the signin. + ConfirmSync(LoginUIService::SYNC_WITH_DEFAULT_SETTINGS); + // Policy is still applied. + EXPECT_TRUE(profile()->GetPrefs()->GetBoolean(prefs::kShowHomeButton)); + EXPECT_EQ(signin::ConsentLevel::kSync, + signin::GetPrimaryAccountConsentLevel(identity_manager())); + EXPECT_FALSE(signin_client()->IsClearPrimaryAccountAllowed()); + EXPECT_TRUE(signin_client()->IsRevokeSyncConsentAllowed()); +}
diff --git a/chrome/browser/policy/cloud/user_policy_signin_service_mobile.cc b/chrome/browser/policy/cloud/user_policy_signin_service_mobile.cc index c1070d87..28275b8 100644 --- a/chrome/browser/policy/cloud/user_policy_signin_service_mobile.cc +++ b/chrome/browser/policy/cloud/user_policy_signin_service_mobile.cc
@@ -16,6 +16,7 @@ #include "base/time/time.h" #include "build/build_config.h" #include "chrome/browser/browser_process.h" +#include "chrome/browser/enterprise/client_certificates/certificate_provisioning_service_factory.h" #include "chrome/browser/enterprise/remote_commands/user_remote_commands_service.h" #include "chrome/browser/enterprise/remote_commands/user_remote_commands_service_factory.h" #include "chrome/browser/enterprise/util/managed_browser_utils.h" @@ -27,6 +28,7 @@ #include "chrome/browser/signin/account_id_from_account_info.h" #include "chrome/common/chrome_content_client.h" #include "chrome/common/pref_names.h" +#include "components/enterprise/client_certificates/core/certificate_provisioning_service.h" #include "components/policy/core/browser/cloud/user_policy_signin_service_util.h" #include "components/policy/core/common/cloud/cloud_policy_client_registration_helper.h" #include "components/policy/core/common/cloud/user_cloud_policy_manager.h" @@ -97,6 +99,21 @@ // `ProfileManager` may be null in tests. UpdateProfileAttributesWhenSignout(profile_, profile_manager); } + + client_certificates::CertificateProvisioningService* provisioning_service = + client_certificates::CertificateProvisioningServiceFactory::GetForProfile( + profile_); + + if (provisioning_service) { + // Delete the managed identities (permanent and temporary). + provisioning_service->DeleteManagedIdentities( + base::BindOnce([](bool success) { + if (!success) { + LOG(ERROR) << "Failed to delete managed identities on sign-out."; + } + })); + } + ShutdownCloudPolicyManager(); }
diff --git a/chrome/browser/policy/configuration_policy_handler_list_factory.cc b/chrome/browser/policy/configuration_policy_handler_list_factory.cc index 9ff3f8d..cbeea4c2 100644 --- a/chrome/browser/policy/configuration_policy_handler_list_factory.cc +++ b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
@@ -1850,6 +1850,9 @@ { key::kGenAIInlineImageSettings, ash::prefs::kLobsterEnterprisePolicySettings, base::Value::Type::INTEGER}, + { key::kSilentPrintingEnabled, + ash::prefs::kSilentPrintingEnabled, + base::Value::Type::BOOLEAN }, #endif // BUILDFLAG(IS_CHROMEOS) #if BUILDFLAG(IS_LINUX)
diff --git a/chrome/browser/resources/settings/clear_browsing_data_dialog/other_google_data_dialog.ts b/chrome/browser/resources/settings/clear_browsing_data_dialog/other_google_data_dialog.ts index 3813eb98..cacb868 100644 --- a/chrome/browser/resources/settings/clear_browsing_data_dialog/other_google_data_dialog.ts +++ b/chrome/browser/resources/settings/clear_browsing_data_dialog/other_google_data_dialog.ts
@@ -142,6 +142,9 @@ private onGeminiAppsActivityClick_() { OpenWindowProxyImpl.getInstance().openUrl( loadTimeData.getString('myActivityGeminiAppsUrl')); + + this.metricsBrowserProxy_.recordAction( + 'Settings.DeleteBrowsingData.GeminiAppsActivityLinkClick'); } private onGeminiPersonalContextClick_() {
diff --git a/chrome/browser/search_engine_choice/search_engine_choice_service_factory.cc b/chrome/browser/search_engine_choice/search_engine_choice_service_factory.cc index d1cc344b..56c9a6b 100644 --- a/chrome/browser/search_engine_choice/search_engine_choice_service_factory.cc +++ b/chrome/browser/search_engine_choice/search_engine_choice_service_factory.cc
@@ -33,7 +33,7 @@ CHECK_DEREF( TemplateURLPrepopulateData::ResolverFactory::GetForProfile(&profile)), CHECK_DEREF(IdentityManagerFactory::GetForProfile(&profile)), - CHECK_DEREF(policy::ManagementServiceFactory::GetForProfile(&profile))); + CHECK_DEREF(policy::ManagementServiceFactory::GetForPlatform())); service->Init(); return service; }
diff --git a/chrome/browser/signin/dice_browsertest.cc b/chrome/browser/signin/dice_browsertest.cc index ee3734f..02b2aebb 100644 --- a/chrome/browser/signin/dice_browsertest.cc +++ b/chrome/browser/signin/dice_browsertest.cc
@@ -1018,203 +1018,6 @@ WaitForReconcilorUnblockedCount(0); } -// Tests that Sync is enabled if the ENABLE_SYNC response is received after the -// refresh token. -IN_PROC_BROWSER_TEST_F(DiceBrowserTest, EnableSyncAfterToken) { - base::HistogramTester histogram_tester; - EXPECT_EQ(0, reconcilor_started_count_); - - // Signin using the Chrome Sync endpoint. - signin_metrics::AccessPoint access_point = - signin_metrics::AccessPoint::kSettings; - browser()->GetFeatures().signin_view_controller()->ShowDiceEnableSyncTab( - access_point, - signin_metrics::PromoAction::PROMO_ACTION_NEW_ACCOUNT_NO_EXISTING_ACCOUNT, - /*email_hint=*/std::string()); - - // Receive token. - EXPECT_FALSE( - GetIdentityManager()->HasAccountWithRefreshToken(GetMainAccountID())); - SendRefreshTokenResponse(); - EXPECT_TRUE( - GetIdentityManager()->HasAccountWithRefreshToken(GetMainAccountID())); - - // Receive ENABLE_SYNC. - SendEnableSyncResponse(); - - // Check that the Dice request header was sent, with signout confirmation. - std::string client_id = GaiaUrls::GetInstance()->oauth2_chrome_client_id(); - EXPECT_EQ(base::StringPrintf("version=%s,client_id=%s,device_id=%s," - "signin_mode=all_accounts," - "signout_mode=show_confirmation", - signin::kDiceProtocolVersion, client_id.c_str(), - GetDeviceId().c_str()), - dice_request_header_); - - content::WebContents* tab_contents = - browser()->tab_strip_model()->GetActiveWebContents(); - base::RunLoop ntp_run_loop; - content::DidFinishNavigationObserver ntp_url_observer( - tab_contents, - base::BindLambdaForTesting( - [&ntp_run_loop](content::NavigationHandle* navigation_handle) { - const GURL& url = navigation_handle->GetURL(); - // Some test flags (e.g. ForceWebRequestProxyForTest) can change - // whether the reported NTP URL is chrome://newtab or - // chrome://new-tab-page. - if (url == GURL(chrome::kChromeUINewTabPageURL) || - url == GURL(chrome::kChromeUINewTabURL)) { - ntp_run_loop.Quit(); - } - })); - - WaitForSigninSucceeded(); - EXPECT_EQ(GetMainAccountID(), GetIdentityManager()->GetPrimaryAccountId( - signin::ConsentLevel::kSignin)); - histogram_tester.ExpectUniqueSample("Signin.SignIn.Completed", access_point, - 1); - - EXPECT_EQ(1, reconcilor_blocked_count_); - WaitForReconcilorUnblockedCount(1); - EXPECT_EQ(1, reconcilor_started_count_); - - // Check that the tab was navigated to the NTP. - ntp_run_loop.Run(); - - // Dismiss the Sync confirmation UI. - EXPECT_TRUE(login_ui_test_utils::ConfirmSyncConfirmationDialog(browser())); - - // Expect that metrics related to the browser signin stage are recorded. - histogram_tester.ExpectBucketCount( - "Signin.SigninManager.SetPrimaryAccountSigninInStage", - PrimaryAccountSettingGaiaIntegrationState::kOnTokenExchangeSuccess, - /*expected_count=*/1); - histogram_tester.ExpectBucketCount( - "Signin.SigninManager.SetPrimaryAccountSigninInStage", - PrimaryAccountSettingGaiaIntegrationState::kOnSyncHeaderReceived, - /*expected_count=*/ - base::FeatureList::IsEnabled( - switches::kBrowserSigninInSyncHeaderOnGaiaIntegration) - ? 1 - : 0); - // The interception bubble should not have been shown. - histogram_tester.ExpectBucketCount( - "Signin.Intercept.HeuristicOutcome", - SigninInterceptionHeuristicOutcome::kInterceptChromeSignin, 0); - // A Sync header on time event has been recorded. - histogram_tester.ExpectUniqueSample("Signin.SigninManager.SyncHeaderTimeout", - false, 1); - - // Both LST and Sync Header are received so their time difference must be - // recorded. - histogram_tester.ExpectTotalCount( - "Signin.SigninManager.SyncHeaderArrivalTimeWindowAfterLst", 1); -} - -// Tests that the account is signed in if the ENABLE_SYNC response is received -// before the refresh token, and the Sync opt-in is offered. -// https://crbug.com/1082858 -IN_PROC_BROWSER_TEST_F(DiceBrowserTest, EnableSyncBeforeToken) { - base::HistogramTester histogram_tester; - EXPECT_EQ(0, reconcilor_started_count_); - - ui_test_utils::UrlLoadObserver enable_sync_url_observer( - https_server_.GetURL(kEnableSyncURL)); - - // Signin using the Chrome Sync endpoint. - browser()->GetFeatures().signin_view_controller()->ShowSignin( - signin_metrics::AccessPoint::kSettings); - - // Receive ENABLE_SYNC. - SendEnableSyncResponse(); - // Wait for the page to be fully loaded. - enable_sync_url_observer.Wait(); - - // Receive token. - EXPECT_FALSE( - GetIdentityManager()->HasPrimaryAccount(signin::ConsentLevel::kSignin)); - EXPECT_FALSE( - GetIdentityManager()->HasAccountWithRefreshToken(GetMainAccountID())); - SendRefreshTokenResponse(); - - ui_test_utils::UrlLoadObserver ntp_url_observer( - (GURL(chrome::kChromeUINewTabURL))); - - EXPECT_EQ(1, reconcilor_blocked_count_); - WaitForReconcilorUnblockedCount(1); - EXPECT_EQ(1, reconcilor_started_count_); - - // Check that the tab was navigated to the NTP. - ntp_url_observer.Wait(); - - EXPECT_TRUE( - GetIdentityManager()->HasAccountWithRefreshToken(GetMainAccountID())); - EXPECT_EQ(GetMainAccountID(), GetIdentityManager()->GetPrimaryAccountId( - signin::ConsentLevel::kSignin)); - - AddCanShowHistorySyncOptInsWithoutMinorModeCapability(GetIdentityManager()); - - // Check that the Dice request header was sent, with signout confirmation. - std::string client_id = GaiaUrls::GetInstance()->oauth2_chrome_client_id(); - EXPECT_EQ(base::StringPrintf("version=%s,client_id=%s,device_id=%s," - "signin_mode=all_accounts," - "signout_mode=show_confirmation", - signin::kDiceProtocolVersion, client_id.c_str(), - GetDeviceId().c_str()), - dice_request_header_); - - // Wait for the Sync confirmation UI and click through. - EXPECT_TRUE(login_ui_test_utils::ConfirmSyncConfirmationDialog(browser())); - - EXPECT_EQ(signin::ConsentLevel::kSync, - signin::GetPrimaryAccountConsentLevel(GetIdentityManager())); - - // The interception bubble should not have been shown. - histogram_tester.ExpectBucketCount( - "Signin.Intercept.HeuristicOutcome", - SigninInterceptionHeuristicOutcome::kInterceptChromeSignin, 0); - // A Sync header on time event has been recorded. - histogram_tester.ExpectUniqueSample("Signin.SigninManager.SyncHeaderTimeout", - false, 1); - // Both LST and Sync Header are received so their time difference must be - // recorded. - histogram_tester.ExpectTotalCount( - "Signin.SigninManager.SyncHeaderArrivalTimeWindowAfterLst", 1); -} - -// Verifies that Chrome doesn't crash on browser window close when the sync -// confirmation dialog is waiting for its size. -// Regression test for https://crbug.com/1304055. -IN_PROC_BROWSER_TEST_F(DiceBrowserTest, - CloseBrowserWhileInitializingSyncConfirmation) { - content::TestNavigationObserver sync_confirmation_url_observer( - GURL("chrome://sync-confirmation?style=0&is_sync_promo=true")); - sync_confirmation_url_observer.StartWatchingNewWebContents(); - - // Signin using the Chrome Sync endpoint. - browser()->GetFeatures().signin_view_controller()->ShowDiceEnableSyncTab( - signin_metrics::AccessPoint::kAvatarBubbleSignInWithSyncPromo, - signin_metrics::PromoAction::PROMO_ACTION_NEW_ACCOUNT_NO_EXISTING_ACCOUNT, - /*email_hint=*/std::string()); - - // Receive token. - SendRefreshTokenResponse(); - // Receive ENABLE_SYNC. - SendEnableSyncResponse(); - - WaitForSigninSucceeded(); - EXPECT_EQ(GetMainAccountID(), GetIdentityManager()->GetPrimaryAccountId( - signin::ConsentLevel::kSignin)); - - // Wait until the sync confirmation webUI is created but not fully loaded - // yet. The native dialog is not displayed yet since it waits until the webUI - // passes the dialog height back to native. - sync_confirmation_url_observer.WaitForNavigationFinished(); - - // This should not crash. - CloseBrowser(); -} - // Tests that turning off Dice via preferences works when singed out. IN_PROC_BROWSER_TEST_F(DiceBrowserTest, PRE_TurnOffDice_SignedOut) { ASSERT_FALSE( @@ -1342,6 +1145,229 @@ incognito_browser->profile())); } +// Tests that Sync is enabled if the ENABLE_SYNC response is received after the +// refresh token. +IN_PROC_BROWSER_TEST_F(DiceBrowserTest, EnableSyncAfterToken) { + base::HistogramTester histogram_tester; + EXPECT_EQ(0, reconcilor_started_count_); + + // Signin using the Chrome Sync endpoint. + signin_metrics::AccessPoint access_point = + signin_metrics::AccessPoint::kSettings; + browser()->GetFeatures().signin_view_controller()->ShowDiceEnableSyncTab( + access_point, + signin_metrics::PromoAction::PROMO_ACTION_NEW_ACCOUNT_NO_EXISTING_ACCOUNT, + /*email_hint=*/std::string()); + + // Receive token. + EXPECT_FALSE( + GetIdentityManager()->HasAccountWithRefreshToken(GetMainAccountID())); + SendRefreshTokenResponse(); + EXPECT_TRUE( + GetIdentityManager()->HasAccountWithRefreshToken(GetMainAccountID())); + + // Receive ENABLE_SYNC. + SendEnableSyncResponse(); + + // Check that the Dice request header was sent, with signout confirmation. + std::string client_id = GaiaUrls::GetInstance()->oauth2_chrome_client_id(); + EXPECT_EQ(base::StringPrintf("version=%s,client_id=%s,device_id=%s," + "signin_mode=all_accounts," + "signout_mode=show_confirmation", + signin::kDiceProtocolVersion, client_id.c_str(), + GetDeviceId().c_str()), + dice_request_header_); + + content::WebContents* tab_contents = + browser()->tab_strip_model()->GetActiveWebContents(); + base::RunLoop ntp_run_loop; + content::DidFinishNavigationObserver ntp_url_observer( + tab_contents, + base::BindLambdaForTesting( + [&ntp_run_loop](content::NavigationHandle* navigation_handle) { + const GURL& url = navigation_handle->GetURL(); + // Some test flags (e.g. ForceWebRequestProxyForTest) can change + // whether the reported NTP URL is chrome://newtab or + // chrome://new-tab-page. + if (url == GURL(chrome::kChromeUINewTabPageURL) || + url == GURL(chrome::kChromeUINewTabURL)) { + ntp_run_loop.Quit(); + } + })); + + WaitForSigninSucceeded(); + EXPECT_EQ(GetMainAccountID(), GetIdentityManager()->GetPrimaryAccountId( + signin::ConsentLevel::kSignin)); + histogram_tester.ExpectUniqueSample("Signin.SignIn.Completed", access_point, + 1); + + EXPECT_EQ(1, reconcilor_blocked_count_); + WaitForReconcilorUnblockedCount(1); + EXPECT_EQ(1, reconcilor_started_count_); + + // Check that the tab was navigated to the NTP. + ntp_run_loop.Run(); + + // Wait for the Sync confirmation UI and click through. This is only needed + // when `syncer::kReplaceSyncPromosWithSignInPromos` is disabled, because + // otherwise it is a sign-in flow without involving the Sync confirmation + // dialog. + if (!base::FeatureList::IsEnabled( + syncer::kReplaceSyncPromosWithSignInPromos)) { + EXPECT_TRUE(login_ui_test_utils::ConfirmSyncConfirmationDialog(browser())); + } + + // Expect that metrics related to the browser signin stage are recorded. + histogram_tester.ExpectBucketCount( + "Signin.SigninManager.SetPrimaryAccountSigninInStage", + PrimaryAccountSettingGaiaIntegrationState::kOnTokenExchangeSuccess, + /*expected_count=*/1); + histogram_tester.ExpectBucketCount( + "Signin.SigninManager.SetPrimaryAccountSigninInStage", + PrimaryAccountSettingGaiaIntegrationState::kOnSyncHeaderReceived, + /*expected_count=*/ + base::FeatureList::IsEnabled( + switches::kBrowserSigninInSyncHeaderOnGaiaIntegration) + ? 1 + : 0); + // The interception bubble should not have been shown. + histogram_tester.ExpectBucketCount( + "Signin.Intercept.HeuristicOutcome", + SigninInterceptionHeuristicOutcome::kInterceptChromeSignin, 0); + // A Sync header on time event has been recorded. + histogram_tester.ExpectUniqueSample("Signin.SigninManager.SyncHeaderTimeout", + false, 1); + + // Both LST and Sync Header are received so their time difference must be + // recorded. + histogram_tester.ExpectTotalCount( + "Signin.SigninManager.SyncHeaderArrivalTimeWindowAfterLst", 1); +} + +// Tests that the account is signed in if the ENABLE_SYNC response is received +// before the refresh token, and the Sync opt-in is offered. +// https://crbug.com/1082858 +IN_PROC_BROWSER_TEST_F(DiceBrowserTest, EnableSyncBeforeToken) { + base::HistogramTester histogram_tester; + EXPECT_EQ(0, reconcilor_started_count_); + + ui_test_utils::UrlLoadObserver enable_sync_url_observer( + https_server_.GetURL(kEnableSyncURL)); + + // Signin using the Chrome Sync endpoint. + browser()->GetFeatures().signin_view_controller()->ShowSignin( + signin_metrics::AccessPoint::kSettings); + + // Receive ENABLE_SYNC. + SendEnableSyncResponse(); + // Wait for the page to be fully loaded. + enable_sync_url_observer.Wait(); + + // Receive token. + EXPECT_FALSE( + GetIdentityManager()->HasPrimaryAccount(signin::ConsentLevel::kSignin)); + EXPECT_FALSE( + GetIdentityManager()->HasAccountWithRefreshToken(GetMainAccountID())); + SendRefreshTokenResponse(); + + ui_test_utils::UrlLoadObserver ntp_url_observer( + (GURL(chrome::kChromeUINewTabURL))); + + EXPECT_EQ(1, reconcilor_blocked_count_); + WaitForReconcilorUnblockedCount(1); + EXPECT_EQ(1, reconcilor_started_count_); + + // Check that the tab was navigated to the NTP. + ntp_url_observer.Wait(); + + EXPECT_TRUE( + GetIdentityManager()->HasAccountWithRefreshToken(GetMainAccountID())); + EXPECT_EQ(GetMainAccountID(), GetIdentityManager()->GetPrimaryAccountId( + signin::ConsentLevel::kSignin)); + + AddCanShowHistorySyncOptInsWithoutMinorModeCapability(GetIdentityManager()); + + // Check that the Dice request header was sent, with signout confirmation. + std::string client_id = GaiaUrls::GetInstance()->oauth2_chrome_client_id(); + EXPECT_EQ(base::StringPrintf("version=%s,client_id=%s,device_id=%s," + "signin_mode=all_accounts," + "signout_mode=show_confirmation", + signin::kDiceProtocolVersion, client_id.c_str(), + GetDeviceId().c_str()), + dice_request_header_); + + // Wait for the Sync confirmation UI and click through. This is only needed + // when `syncer::kReplaceSyncPromosWithSignInPromos` is disabled, because + // otherwise it is a sign-in flow without involving the Sync confirmation + // dialog. + if (base::FeatureList::IsEnabled( + syncer::kReplaceSyncPromosWithSignInPromos)) { + EXPECT_EQ(signin::ConsentLevel::kSignin, + signin::GetPrimaryAccountConsentLevel(GetIdentityManager())); + } else { + EXPECT_TRUE(login_ui_test_utils::ConfirmSyncConfirmationDialog(browser())); + EXPECT_EQ(signin::ConsentLevel::kSync, + signin::GetPrimaryAccountConsentLevel(GetIdentityManager())); + } + + // The interception bubble should not have been shown. + histogram_tester.ExpectBucketCount( + "Signin.Intercept.HeuristicOutcome", + SigninInterceptionHeuristicOutcome::kInterceptChromeSignin, 0); + // A Sync header on time event has been recorded. + histogram_tester.ExpectUniqueSample("Signin.SigninManager.SyncHeaderTimeout", + false, 1); + // Both LST and Sync Header are received so their time difference must be + // recorded. + histogram_tester.ExpectTotalCount( + "Signin.SigninManager.SyncHeaderArrivalTimeWindowAfterLst", 1); +} + +class DiceBrowserTestWithoutReplaceSyncPromosWithSignInPromos + : public DiceBrowserTest { + public: + DiceBrowserTestWithoutReplaceSyncPromosWithSignInPromos() { + feature_list_.InitAndDisableFeature( + syncer::kReplaceSyncPromosWithSignInPromos); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + +// Verifies that Chrome doesn't crash on browser window close when the sync +// confirmation dialog is waiting for its size. +// Regression test for https://crbug.com/1304055. +IN_PROC_BROWSER_TEST_F(DiceBrowserTestWithoutReplaceSyncPromosWithSignInPromos, + CloseBrowserWhileInitializingSyncConfirmation) { + content::TestNavigationObserver sync_confirmation_url_observer( + GURL("chrome://sync-confirmation?style=0&is_sync_promo=true")); + sync_confirmation_url_observer.StartWatchingNewWebContents(); + + // Signin using the Chrome Sync endpoint. + browser()->GetFeatures().signin_view_controller()->ShowDiceEnableSyncTab( + signin_metrics::AccessPoint::kAvatarBubbleSignInWithSyncPromo, + signin_metrics::PromoAction::PROMO_ACTION_NEW_ACCOUNT_NO_EXISTING_ACCOUNT, + /*email_hint=*/std::string()); + + // Receive token. + SendRefreshTokenResponse(); + // Receive ENABLE_SYNC. + SendEnableSyncResponse(); + + WaitForSigninSucceeded(); + EXPECT_EQ(GetMainAccountID(), GetIdentityManager()->GetPrimaryAccountId( + signin::ConsentLevel::kSignin)); + + // Wait until the sync confirmation webUI is created but not fully loaded + // yet. The native dialog is not displayed yet since it waits until the webUI + // passes the dialog height back to native. + sync_confirmation_url_observer.WaitForNavigationFinished(); + + // This should not crash. + CloseBrowser(); +} + class DiceBrowserSiginInInterceptionInteractiveTest : public InteractiveBrowserTestT<DiceBrowserTest> { public: @@ -1580,65 +1606,6 @@ base::test::ScopedFeatureList feature_list_; }; -IN_PROC_BROWSER_TEST_F(DiceExplicitSigninBrowserTest, PRE_Migration) { - signin::AccountAvailabilityOptionsBuilder builder; - signin::MakeAccountAvailable( - GetIdentityManager(), - builder - .AsPrimary(signin::ConsentLevel::kSignin) - // `kWebSignin` is not explicit before the migration. - .WithAccessPoint(signin_metrics::AccessPoint::kWebSignin) - .Build(kMainGmailEmail)); - ASSERT_EQ(signin::GetPrimaryAccountConsentLevel(GetIdentityManager()), - signin::ConsentLevel::kSignin); - - ASSERT_FALSE(browser()->profile()->GetPrefs()->GetBoolean( - prefs::kExplicitBrowserSignin)); - - AccountStorageStatus account_storage_status = GetAccountStorageStatus(); - EXPECT_FALSE(account_storage_status.autofill_sync_toggle_available); - EXPECT_FALSE(account_storage_status.user_selectable_type_set.HasAny( - {syncer::UserSelectableType::kAutofill, - syncer::UserSelectableType::kPasswords})); -} - -// Checks that a user who signed in with Dice before UNO was enabled does not -// get the account storage enabled silently. Account storage is enabled after -// the user signs out and signs in again through an explicit flow. -IN_PROC_BROWSER_TEST_F(DiceExplicitSigninBrowserTest, Migration) { - Profile* profile = browser()->profile(); - // The user is still signed in implicitly. - ASSERT_EQ(signin::GetPrimaryAccountConsentLevel(GetIdentityManager()), - signin::ConsentLevel::kSignin); - ASSERT_TRUE(gaia::AreEmailsSame( - GetIdentityManager() - ->GetPrimaryAccountInfo(signin::ConsentLevel::kSignin) - .email, - kMainGmailEmail)); - ASSERT_FALSE(profile->GetPrefs()->GetBoolean(prefs::kExplicitBrowserSignin)); - // Account storage was not enabled yet. - AccountStorageStatus account_storage_status = GetAccountStorageStatus(); - EXPECT_FALSE(account_storage_status.user_selectable_type_set.HasAny( - {syncer::UserSelectableType::kAutofill, - syncer::UserSelectableType::kPasswords})); - - // Signout, and then signin again explicitly. - signin::ClearPrimaryAccount(GetIdentityManager()); - AccountInfo primary_account_info = signin::MakePrimaryAccountAvailable( - GetIdentityManager(), kMainGmailEmail, signin::ConsentLevel::kSignin); - EXPECT_TRUE(profile->GetPrefs()->GetBoolean(prefs::kExplicitBrowserSignin)); - - // Account storage is now enabled. - account_storage_status = GetAccountStorageStatus(); - EXPECT_TRUE(account_storage_status.user_selectable_type_set.HasAll( - {syncer::UserSelectableType::kAutofill, - syncer::UserSelectableType::kPasswords})); - - // Cookie migration is done. - EXPECT_TRUE(profile->GetPrefs()->GetBoolean( - prefs::kCookieClearOnExitMigrationNoticeComplete)); -} - // Checks that migration handles Cookie clear on exit and sync toggles. IN_PROC_BROWSER_TEST_F(DiceExplicitSigninBrowserTest, PRE_MigrationWithSettings) { @@ -1697,9 +1664,84 @@ prefs::kCookieClearOnExitMigrationNoticeComplete)); } +class DiceExplicitSigninBrowserTestWithForcedDiceMigrationDisabled + : public DiceExplicitSigninBrowserTest { + public: + DiceExplicitSigninBrowserTestWithForcedDiceMigrationDisabled() { + scoped_feature_list_.InitAndDisableFeature(switches::kForcedDiceMigration); + } + + private: + base::test::ScopedFeatureList scoped_feature_list_; +}; + +IN_PROC_BROWSER_TEST_F( + DiceExplicitSigninBrowserTestWithForcedDiceMigrationDisabled, + PRE_Migration) { + signin::AccountAvailabilityOptionsBuilder builder; + signin::MakeAccountAvailable( + GetIdentityManager(), + builder + .AsPrimary(signin::ConsentLevel::kSignin) + // `kWebSignin` is not explicit before the migration. + .WithAccessPoint(signin_metrics::AccessPoint::kWebSignin) + .Build(kMainGmailEmail)); + ASSERT_EQ(signin::GetPrimaryAccountConsentLevel(GetIdentityManager()), + signin::ConsentLevel::kSignin); + + ASSERT_FALSE(browser()->profile()->GetPrefs()->GetBoolean( + prefs::kExplicitBrowserSignin)); + + AccountStorageStatus account_storage_status = GetAccountStorageStatus(); + EXPECT_FALSE(account_storage_status.autofill_sync_toggle_available); + EXPECT_FALSE(account_storage_status.user_selectable_type_set.HasAny( + {syncer::UserSelectableType::kAutofill, + syncer::UserSelectableType::kPasswords})); +} + +// Checks that a user who signed in with Dice before UNO was enabled does not +// get the account storage enabled silently. Account storage is enabled after +// the user signs out and signs in again through an explicit flow. +IN_PROC_BROWSER_TEST_F( + DiceExplicitSigninBrowserTestWithForcedDiceMigrationDisabled, + Migration) { + Profile* profile = browser()->profile(); + // The user is still signed in implicitly. + ASSERT_EQ(signin::GetPrimaryAccountConsentLevel(GetIdentityManager()), + signin::ConsentLevel::kSignin); + ASSERT_TRUE(gaia::AreEmailsSame( + GetIdentityManager() + ->GetPrimaryAccountInfo(signin::ConsentLevel::kSignin) + .email, + kMainGmailEmail)); + ASSERT_FALSE(profile->GetPrefs()->GetBoolean(prefs::kExplicitBrowserSignin)); + // Account storage was not enabled yet. + AccountStorageStatus account_storage_status = GetAccountStorageStatus(); + EXPECT_FALSE(account_storage_status.user_selectable_type_set.HasAny( + {syncer::UserSelectableType::kAutofill, + syncer::UserSelectableType::kPasswords})); + + // Signout, and then signin again explicitly. + signin::ClearPrimaryAccount(GetIdentityManager()); + AccountInfo primary_account_info = signin::MakePrimaryAccountAvailable( + GetIdentityManager(), kMainGmailEmail, signin::ConsentLevel::kSignin); + EXPECT_TRUE(profile->GetPrefs()->GetBoolean(prefs::kExplicitBrowserSignin)); + + // Account storage is now enabled. + account_storage_status = GetAccountStorageStatus(); + EXPECT_TRUE(account_storage_status.user_selectable_type_set.HasAll( + {syncer::UserSelectableType::kAutofill, + syncer::UserSelectableType::kPasswords})); + + // Cookie migration is done. + EXPECT_TRUE(profile->GetPrefs()->GetBoolean( + prefs::kCookieClearOnExitMigrationNoticeComplete)); +} + // Signin implicitlty, Dice Signin. -IN_PROC_BROWSER_TEST_F(DiceExplicitSigninBrowserTest, - PRE_DiceUserMigratedClearsCookie) { +IN_PROC_BROWSER_TEST_F( + DiceExplicitSigninBrowserTestWithForcedDiceMigrationDisabled, + PRE_DiceUserMigratedClearsCookie) { signin::MakeAccountAvailable( GetIdentityManager(), signin::AccountAvailabilityOptionsBuilder() @@ -1720,8 +1762,9 @@ } // Dice Signin with UNO enabled. -IN_PROC_BROWSER_TEST_F(DiceExplicitSigninBrowserTest, - DiceUserMigratedClearsCookie) { +IN_PROC_BROWSER_TEST_F( + DiceExplicitSigninBrowserTestWithForcedDiceMigrationDisabled, + DiceUserMigratedClearsCookie) { Profile* profile = browser()->profile(); // The user is still signed in implicitly. ASSERT_TRUE(
diff --git a/chrome/browser/signin/dice_web_signin_interceptor_browsertest.cc b/chrome/browser/signin/dice_web_signin_interceptor_browsertest.cc index 3b40876..1694af7 100644 --- a/chrome/browser/signin/dice_web_signin_interceptor_browsertest.cc +++ b/chrome/browser/signin/dice_web_signin_interceptor_browsertest.cc
@@ -1673,10 +1673,15 @@ class DiceWebSigninInterceptorWithUnoEnabledAndPREDisabledBrowserTest : public DiceWebSigninInterceptorWithChromeSigninHelpersBrowserTest { public: - DiceWebSigninInterceptorWithUnoEnabledAndPREDisabledBrowserTest() = default; + DiceWebSigninInterceptorWithUnoEnabledAndPREDisabledBrowserTest() { + // With kForcedDiceMigration enabled, am implicit signed-in user is signed + // out leaving the test a no-op. + feature_list_.InitAndDisableFeature(switches::kForcedDiceMigration); + } protected: const std::string email_ = "alice@example.com"; + base::test::ScopedFeatureList feature_list_; }; // Signing in to Chrome while explicit signin is disabled, to simulate a signed
diff --git a/chrome/browser/sync/test/integration/password_manager_sync_test.cc b/chrome/browser/sync/test/integration/password_manager_sync_test.cc index ee1e9e5d..d8982a92 100644 --- a/chrome/browser/sync/test/integration/password_manager_sync_test.cc +++ b/chrome/browser/sync/test/integration/password_manager_sync_test.cc
@@ -941,69 +941,6 @@ GetSyncService(0))); } -// TODO(b/327118794): Delete this test once implicit signin no longer exists. -IN_PROC_BROWSER_TEST_F(PasswordManagerSyncTest, - PRE_ClearAccountStoreOnStartup) { - ASSERT_TRUE(SetupClients()); - - // Add a credential to the server. - AddCredentialToFakeServer( - CreateTestPasswordForm("accountuser", "accountpass")); - - SetupSyncTransportWithPasswordAccountStorage(/*explicit_signin=*/false); - - // Also add a credential to the profile store. - AddLocalCredential("localuser", "localpass"); - - ASSERT_THAT(GetAllLoginsFromProfilePasswordStore(), - ElementsAre(MatchesLogin("localuser", "localpass"))); - ASSERT_THAT(GetAllLoginsFromAccountPasswordStore(), - ElementsAre(MatchesLogin("accountuser", "accountpass"))); -} - -// TODO(b/327118794): Delete this test once implicit signin no longer exists. -IN_PROC_BROWSER_TEST_F(PasswordManagerSyncTest, ClearAccountStoreOnStartup) { - // Before setting up the client (aka profile), manually set account storage to - // off in the profile's prefs file. This simulates the case where the user - // disabled account storage, but the account store was not cleared correctly, - // e.g. due to a poorly-timed crash. - base::FilePath user_data_dir; - base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir); - base::FilePath profile_path = user_data_dir.Append(GetProfileBaseName(0)); - base::FilePath json_path = profile_path.Append(chrome::kPreferencesFilename); - { - base::ScopedAllowBlockingForTesting allow_blocking; - std::string json; - ASSERT_TRUE(base::ReadFileToString(json_path, &json)); - std::optional<base::Value> prefs = base::JSONReader::Read(json); - ASSERT_TRUE(prefs.has_value()); - ASSERT_TRUE(prefs->is_dict()); - ASSERT_TRUE(prefs->GetDict().RemoveByDottedPath( - syncer::prefs::internal::kSelectedTypesPerAccount)); - std::optional<std::string> new_json = base::WriteJson(prefs.value()); - ASSERT_TRUE(new_json.has_value()); - ASSERT_TRUE(base::WriteFile(json_path, new_json.value())); - } - - ASSERT_TRUE(SetupClients()); - - ASSERT_TRUE(GetClient(0)->AwaitSyncTransportActive()); - - // Since we mangled the prefs file, account storage should be disabled. - ASSERT_FALSE(password_manager::features_util::IsAccountStorageEnabled( - GetSyncService(0))); - ASSERT_FALSE(GetSyncService(0)->GetActiveDataTypes().Has(syncer::PASSWORDS)); - - // The account-scoped store should have been cleared during startup, and the - // credential added by the PRE_ test should be gone. - EXPECT_THAT(GetAllLoginsFromAccountPasswordStore(), IsEmpty()); - - // Just as a sanity check: The credential in the profile-scoped store should - // still be there. - ASSERT_THAT(GetAllLoginsFromProfilePasswordStore(), - ElementsAre(MatchesLogin("localuser", "localpass"))); -} - #endif // !BUILDFLAG(IS_CHROMEOS) IN_PROC_BROWSER_TEST_F(PasswordManagerSyncTest, SyncUtilApis) { @@ -1111,6 +1048,82 @@ waiter.Wait(); } } + +class PasswordManagerSyncTestWithForcedDiceMigrationDisabled + : public PasswordManagerSyncTest { + public: + PasswordManagerSyncTestWithForcedDiceMigrationDisabled() { + feature_list_.InitAndDisableFeature(switches::kForcedDiceMigration); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + +// TODO(b/327118794): Delete this test once implicit signin no longer exists. +IN_PROC_BROWSER_TEST_F(PasswordManagerSyncTestWithForcedDiceMigrationDisabled, + PRE_ClearAccountStoreOnStartup) { + ASSERT_TRUE(SetupClients()); + + // Add a credential to the server. + AddCredentialToFakeServer( + CreateTestPasswordForm("accountuser", "accountpass")); + + SetupSyncTransportWithPasswordAccountStorage(/*explicit_signin=*/false); + + // Also add a credential to the profile store. + AddLocalCredential("localuser", "localpass"); + + ASSERT_THAT(GetAllLoginsFromProfilePasswordStore(), + ElementsAre(MatchesLogin("localuser", "localpass"))); + ASSERT_THAT(GetAllLoginsFromAccountPasswordStore(), + ElementsAre(MatchesLogin("accountuser", "accountpass"))); +} + +// TODO(b/327118794): Delete this test once implicit signin no longer exists. +IN_PROC_BROWSER_TEST_F(PasswordManagerSyncTestWithForcedDiceMigrationDisabled, + ClearAccountStoreOnStartup) { + // Before setting up the client (aka profile), manually set account storage to + // off in the profile's prefs file. This simulates the case where the user + // disabled account storage, but the account store was not cleared correctly, + // e.g. due to a poorly-timed crash. + base::FilePath user_data_dir; + base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir); + base::FilePath profile_path = user_data_dir.Append(GetProfileBaseName(0)); + base::FilePath json_path = profile_path.Append(chrome::kPreferencesFilename); + { + base::ScopedAllowBlockingForTesting allow_blocking; + std::string json; + ASSERT_TRUE(base::ReadFileToString(json_path, &json)); + std::optional<base::Value> prefs = base::JSONReader::Read(json); + ASSERT_TRUE(prefs.has_value()); + ASSERT_TRUE(prefs->is_dict()); + ASSERT_TRUE(prefs->GetDict().RemoveByDottedPath( + syncer::prefs::internal::kSelectedTypesPerAccount)); + std::optional<std::string> new_json = base::WriteJson(prefs.value()); + ASSERT_TRUE(new_json.has_value()); + ASSERT_TRUE(base::WriteFile(json_path, new_json.value())); + } + + ASSERT_TRUE(SetupClients()); + + ASSERT_TRUE(GetClient(0)->AwaitSyncTransportActive()); + + // Since we mangled the prefs file, account storage should be disabled. + ASSERT_FALSE(password_manager::features_util::IsAccountStorageEnabled( + GetSyncService(0))); + ASSERT_FALSE(GetSyncService(0)->GetActiveDataTypes().Has(syncer::PASSWORDS)); + + // The account-scoped store should have been cleared during startup, and the + // credential added by the PRE_ test should be gone. + EXPECT_THAT(GetAllLoginsFromAccountPasswordStore(), IsEmpty()); + + // Just as a sanity check: The credential in the profile-scoped store should + // still be there. + ASSERT_THAT(GetAllLoginsFromProfilePasswordStore(), + ElementsAre(MatchesLogin("localuser", "localpass"))); +} + #endif // !BUILDFLAG(IS_CHROMEOS) } // namespace
diff --git a/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc b/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc index f5ba559b..b679af01 100644 --- a/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc +++ b/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc
@@ -31,6 +31,7 @@ #include "components/autofill/core/browser/webdata/payments/payments_sync_bridge_util.h" #include "components/autofill/core/common/autofill_switches.h" #include "components/prefs/pref_service.h" +#include "components/signin/public/base/signin_switches.h" #include "components/signin/public/identity_manager/identity_test_utils.h" #include "components/sync/base/data_type.h" #include "components/sync/base/features.h" @@ -254,81 +255,6 @@ EXPECT_EQ(0U, GetServerCards(account_data).size()); } -// PRE_ test used to ensure the user is signed in at the time the browser starts -// up, which is more realistic for the implicit signed-in state. -IN_PROC_BROWSER_TEST_F(SingleClientWalletSyncTest, - PRE_DownloadAccountStorageWithImplicitSignIn_Card) { - ASSERT_TRUE(SetupClients()); - - secondary_account_helper::ImplicitSignInUnconsentedAccount( - GetProfile(0), &test_url_loader_factory_, "user@email.com"); - ASSERT_TRUE(GetClient(0)->AwaitSyncTransportActive()); - ASSERT_TRUE(AwaitQuiescence()); - ASSERT_EQ(syncer::SyncService::TransportState::ACTIVE, - GetSyncService(0)->GetTransportState()); - ASSERT_TRUE(GetSyncService(0)->GetActiveDataTypes().Has( - syncer::AUTOFILL_WALLET_DATA)); -} - -IN_PROC_BROWSER_TEST_F(SingleClientWalletSyncTest, - DownloadAccountStorageWithImplicitSignIn_Card) { - ASSERT_TRUE(SetupClients()); - GetFakeServer()->SetWalletData( - {CreateDefaultSyncWalletCard(), CreateDefaultSyncPaymentsCustomerData()}); - - ASSERT_TRUE(GetClient(0)->AwaitSyncTransportActive()); - ASSERT_TRUE(AwaitQuiescence()); - ASSERT_EQ(syncer::SyncService::TransportState::ACTIVE, - GetSyncService(0)->GetTransportState()); - ASSERT_TRUE(GetSyncService(0)->GetActiveDataTypes().Has( - syncer::AUTOFILL_WALLET_DATA)); - - scoped_refptr<autofill::AutofillWebDataService> profile_data = - GetProfileWebDataService(0); - ASSERT_NE(nullptr, profile_data); - scoped_refptr<autofill::AutofillWebDataService> account_data = - GetAccountWebDataService(0); - ASSERT_NE(nullptr, account_data); - - // Check that no data is stored in the profile storage. - EXPECT_EQ(0U, GetServerCards(profile_data).size()); - - // Check that one card is stored in the account storage. - EXPECT_EQ(1U, GetServerCards(account_data).size()); - - // Check whether cards are stored in-memory (which is always the case for - // implicit sign-ins). The corresponding metric is recorded twice as an - // artifact of the test setup: SyncTest creates a new profile for - // single-client tests, disregarding the existing profile that browser tests - // already have. - EXPECT_TRUE(GetAccountWebDataService(0)->UsesInMemoryDatabaseForTesting()); - histogram_tester_.ExpectBucketCount( - "WebDatabase.AutofillAccountStorage", - /*sample=*/1, // kInMemory_SignedInImplicitly. - /*expected_bucket_count=*/1); - - PaymentsDataManager* paydm = GetPaymentsDataManager(0); - ASSERT_NE(nullptr, paydm); - std::vector<const CreditCard*> cards = paydm->GetCreditCards(); - ASSERT_EQ(1uL, cards.size()); - - ExpectDefaultCreditCardValues(*cards[0]); - - GetClient(0)->SignOutPrimaryAccount(); - - // Verify that sync is stopped. - ASSERT_EQ(syncer::SyncService::TransportState::DISABLED, - GetSyncService(0)->GetTransportState()); - ASSERT_FALSE(GetSyncService(0)->GetActiveDataTypes().Has( - syncer::AUTOFILL_WALLET_DATA)); - - // Wait for paydm to receive the data change with no cards. - WaitForNumberOfCards(0, paydm); - - // Check directly in the DB that the account storage is now cleared. - EXPECT_EQ(0U, GetServerCards(account_data).size()); -} - // Wallet data should get cleared from the database when the user signs out and // different data should get downstreamed when the user signs in with a // different account. @@ -1122,4 +1048,93 @@ EXPECT_EQ(0U, GetCreditCardCloudTokenData(account_data).size()); EXPECT_EQ(1U, GetCreditCardCloudTokenData(profile_data).size()); } + +class SingleClientWalletSyncTestWithForcedDiceMigrationDisabled + : public SingleClientWalletSyncTest { + public: + SingleClientWalletSyncTestWithForcedDiceMigrationDisabled() { + feature_list_.InitAndDisableFeature(switches::kForcedDiceMigration); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + +// PRE_ test used to ensure the user is signed in at the time the browser starts +// up, which is more realistic for the implicit signed-in state. +IN_PROC_BROWSER_TEST_F( + SingleClientWalletSyncTestWithForcedDiceMigrationDisabled, + PRE_DownloadAccountStorageWithImplicitSignIn_Card) { + ASSERT_TRUE(SetupClients()); + + secondary_account_helper::ImplicitSignInUnconsentedAccount( + GetProfile(0), &test_url_loader_factory_, "user@email.com"); + ASSERT_TRUE(GetClient(0)->AwaitSyncTransportActive()); + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_EQ(syncer::SyncService::TransportState::ACTIVE, + GetSyncService(0)->GetTransportState()); + ASSERT_TRUE(GetSyncService(0)->GetActiveDataTypes().Has( + syncer::AUTOFILL_WALLET_DATA)); +} + +IN_PROC_BROWSER_TEST_F( + SingleClientWalletSyncTestWithForcedDiceMigrationDisabled, + DownloadAccountStorageWithImplicitSignIn_Card) { + ASSERT_TRUE(SetupClients()); + GetFakeServer()->SetWalletData( + {CreateDefaultSyncWalletCard(), CreateDefaultSyncPaymentsCustomerData()}); + + ASSERT_TRUE(GetClient(0)->AwaitSyncTransportActive()); + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_EQ(syncer::SyncService::TransportState::ACTIVE, + GetSyncService(0)->GetTransportState()); + ASSERT_TRUE(GetSyncService(0)->GetActiveDataTypes().Has( + syncer::AUTOFILL_WALLET_DATA)); + + scoped_refptr<autofill::AutofillWebDataService> profile_data = + GetProfileWebDataService(0); + ASSERT_NE(nullptr, profile_data); + scoped_refptr<autofill::AutofillWebDataService> account_data = + GetAccountWebDataService(0); + ASSERT_NE(nullptr, account_data); + + // Check that no data is stored in the profile storage. + EXPECT_EQ(0U, GetServerCards(profile_data).size()); + + // Check that one card is stored in the account storage. + EXPECT_EQ(1U, GetServerCards(account_data).size()); + + // Check whether cards are stored in-memory (which is always the case for + // implicit sign-ins). The corresponding metric is recorded twice as an + // artifact of the test setup: SyncTest creates a new profile for + // single-client tests, disregarding the existing profile that browser tests + // already have. + EXPECT_TRUE(GetAccountWebDataService(0)->UsesInMemoryDatabaseForTesting()); + histogram_tester_.ExpectBucketCount( + "WebDatabase.AutofillAccountStorage", + /*sample=*/1, // kInMemory_SignedInImplicitly. + /*expected_bucket_count=*/1); + + PaymentsDataManager* paydm = GetPaymentsDataManager(0); + ASSERT_NE(nullptr, paydm); + std::vector<const CreditCard*> cards = paydm->GetCreditCards(); + ASSERT_EQ(1uL, cards.size()); + + ExpectDefaultCreditCardValues(*cards[0]); + + GetClient(0)->SignOutPrimaryAccount(); + + // Verify that sync is stopped. + ASSERT_EQ(syncer::SyncService::TransportState::DISABLED, + GetSyncService(0)->GetTransportState()); + ASSERT_FALSE(GetSyncService(0)->GetActiveDataTypes().Has( + syncer::AUTOFILL_WALLET_DATA)); + + // Wait for paydm to receive the data change with no cards. + WaitForNumberOfCards(0, paydm); + + // Check directly in the DB that the account storage is now cleared. + EXPECT_EQ(0U, GetServerCards(account_data).size()); +} + #endif // !BUILDFLAG(IS_CHROMEOS)
diff --git a/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/EmptyTabModel.java b/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/EmptyTabModel.java index c08b9a8..7444a8ab1 100644 --- a/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/EmptyTabModel.java +++ b/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/EmptyTabModel.java
@@ -258,6 +258,11 @@ } @Override + public int getPinnedTabsCount() { + return 0; + } + + @Override public OptionalInt getNativeSessionIdForTesting() { return OptionalInt.empty(); }
diff --git a/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/IncognitoTabModelImpl.java b/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/IncognitoTabModelImpl.java index cbd8381..7011d96f 100644 --- a/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/IncognitoTabModelImpl.java +++ b/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/IncognitoTabModelImpl.java
@@ -421,6 +421,11 @@ } @Override + public int getPinnedTabsCount() { + return mDelegateModel.getPinnedTabsCount(); + } + + @Override public OptionalInt getNativeSessionIdForTesting() { return mDelegateModel.getNativeSessionIdForTesting(); }
diff --git a/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/TabModel.java b/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/TabModel.java index d80727d6..128219b 100644 --- a/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/TabModel.java +++ b/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/TabModel.java
@@ -206,6 +206,11 @@ */ int findFirstNonPinnedTabIndex(); + /** + * @return The number of pinned tabs in this model. + */ + int getPinnedTabsCount(); + /** Returns the native {@code SessionID} as returned by {@code tab_model.h:GetSessionId()}. */ OptionalInt getNativeSessionIdForTesting();
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index 6241fb89..5a753e3 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -1918,6 +1918,10 @@ "views/relaunch_notification/relaunch_notification_controller_platform_impl_chromeos.cc", "views/relaunch_notification/relaunch_notification_controller_platform_impl_chromeos.h", "views/web_apps/isolated_web_apps/pref_observer_ash.cc", + "views/web_apps/protocol_handler_picker_coordinator.cc", + "views/web_apps/protocol_handler_picker_coordinator.h", + "views/web_apps/protocol_handler_picker_dialog.cc", + "views/web_apps/protocol_handler_picker_dialog.h", "webui/ash/dlp_internals/dlp_internals_page_handler.cc", "webui/ash/dlp_internals/dlp_internals_page_handler.h", "webui/ash/dlp_internals/dlp_internals_ui.cc",
diff --git a/chrome/browser/ui/autofill/bubble_manager.h b/chrome/browser/ui/autofill/bubble_manager.h index 7a39983d..c74ebc8aa 100644 --- a/chrome/browser/ui/autofill/bubble_manager.h +++ b/chrome/browser/ui/autofill/bubble_manager.h
@@ -38,21 +38,19 @@ // - Show B immediately. // // 2. If a bubble (A) is already showing: -// - The manager determines if the new bubble's controller (B) -// should preempt the active bubble (A). If the request is to force -// show, the active bubble is preempted irrespective of the priorities of -// the bubbles and hovering state. The default preemption policy is based -// on priority (i.e., priority(B) > priority(A)), but custom rules can be -// defined in ShouldAlwaysPreemptSameType(e.g., to always preempt another -// bubble of the same type). -// - HOWEVER, preemption is blocked if the user is currently hovering their -// mouse over bubble A. +// - Preemption of an active bubble (A) by a new bubble (B) is determined by +// the following rules, in order: +// - Force Show: If `force_show` is true, B always preempts A. +// - Mouse Hover: If the user is hovering over A, B never preempts A. +// - Same Type: If B and A have the same type, B preempts A only if that +// type has a "preempt same type" policy. +// - Priority: Otherwise, B preempts A if priority(B) > priority(A). // // - If B preempts A: // - Hide A and add it to the pending queue. // - Show B. // -// - If B does not preempt A (due to its policy or A being hovered): +// - If B does not preempt A: // - Add B to the pending queue. A remains visible. // // === Queue and Hiding Logic === @@ -79,7 +77,9 @@ static std::unique_ptr<BubbleManager> Create(tabs::TabInterface* tab); static BubbleManager* GetForWebContents(content::WebContents* web_contents); - // Called by the bubbles once they are ready to be shown. + // Requests the bubble for `controller_to_show` to be displayed. + // If `force_show` is true, this bubble will preempt any active bubble, + // regardless of priority or hover state. virtual void RequestShowController(BubbleControllerBase& controller_to_show, bool force_show) = 0; @@ -90,9 +90,11 @@ BubbleControllerBase& controller_to_hide, bool show_next_bubble) = 0; - // Returns true if there is a pending bubble that has not timed out, of the - // specified `bubble_type` in the queue. Always returns false for the bubble - // types that preempt themselves (eg. Password manager bubbles). + // Returns true if a bubble of the specified `bubble_type` is already + // pending in the queue and has not timed out. + // Note: This will always return false for bubble types that preempt + // themselves (e.g., password bubbles), as they replace existing requests + // instead of waiting in the queue. [[nodiscard]] virtual bool HasPendingBubbleOfSameType( const BubbleType bubble_type) const = 0; };
diff --git a/chrome/browser/ui/autofill/bubble_manager_impl.cc b/chrome/browser/ui/autofill/bubble_manager_impl.cc index 45d241c..c821702 100644 --- a/chrome/browser/ui/autofill/bubble_manager_impl.cc +++ b/chrome/browser/ui/autofill/bubble_manager_impl.cc
@@ -344,8 +344,7 @@ void BubbleManagerImpl::TabWillEnterBackground( tabs::TabInterface* tab_interface) { - if (active_bubble_controller_ && - active_bubble_controller_->IsShowingBubble()) { + if (active_bubble_controller_) { AddToPendingQueue(active_bubble_controller_); active_bubble_controller_->HideBubble(/*show_next_bubble=*/false); active_bubble_controller_ = nullptr; @@ -354,7 +353,12 @@ void BubbleManagerImpl::TabDidEnterForeground( tabs::TabInterface* tab_interface) { - ProcessPendingBubbles(); + if (!active_bubble_controller_) { + ProcessPendingBubbles(); + } else if (!active_bubble_controller_->IsShowingBubble()) { + // This can happen if a tab created in background becomes visible. + active_bubble_controller_->ShowBubble(); + } } } // namespace autofill
diff --git a/chrome/browser/ui/autofill/bubble_manager_impl_unittest.cc b/chrome/browser/ui/autofill/bubble_manager_impl_unittest.cc index eb95023..56ac068 100644 --- a/chrome/browser/ui/autofill/bubble_manager_impl_unittest.cc +++ b/chrome/browser/ui/autofill/bubble_manager_impl_unittest.cc
@@ -651,4 +651,102 @@ tab_interface()->Deactivate(); } +// Test that `force_show` preempts an active bubble regardless of priority or +// hover state. +TEST_F(BubbleManagerImplTest, + RequestShow_ForceShow_PreemptsRegardlessOfPriority) { + std::unique_ptr<MockBubbleController> card_controller = + CreateController(BubbleType::kSaveUpdateCard); + std::unique_ptr<MockBubbleController> address_controller = + CreateController(BubbleType::kSaveUpdateAddress); + + // Show the higher-priority card bubble. + EXPECT_CALL(*card_controller, ShowBubble()); + bubble_manager().RequestShowController(*card_controller, + /*force_show=*/false); + ASSERT_TRUE(card_controller->IsShowingBubble()); + + // Simulate hovering to ensure `force_show` bypasses it. + ON_CALL(*card_controller, IsMouseHovered).WillByDefault(Return(true)); + { + InSequence sequence; + EXPECT_CALL(*card_controller, HideBubble(/*show_next_bubble=*/false)); + EXPECT_CALL(*address_controller, ShowBubble()); + } + + // Force show the lower-priority address bubble. + bubble_manager().RequestShowController(*address_controller, + /*force_show=*/true); + EXPECT_FALSE(card_controller->IsShowingBubble()); + EXPECT_TRUE(address_controller->IsShowingBubble()); +} + +// Test that the active bubble is hidden and queued when the tab is deactivated. +TEST_F(BubbleManagerImplTest, TabDeactivated_ActiveBubbleIsQueuedAndHidden) { + std::unique_ptr<MockBubbleController> address_controller = + CreateController(BubbleType::kSaveUpdateAddress); + EXPECT_CALL(*address_controller, ShowBubble()); + bubble_manager().RequestShowController(*address_controller, + /*force_show=*/false); + ASSERT_TRUE(address_controller->IsShowingBubble()); + + // Deactivating the tab should hide the bubble. + EXPECT_CALL(*address_controller, HideBubble(/*show_next_bubble=*/false)); + tab_interface()->Deactivate(); + EXPECT_FALSE(address_controller->IsShowingBubble()); + + // When the tab is reactivated, the bubble should be shown again from the + // queue. + EXPECT_CALL(*address_controller, ShowBubble()); + tab_interface()->Activate(); + EXPECT_TRUE(address_controller->IsShowingBubble()); +} + +// Test that `ProcessPendingBubbles` cleans up stale pointers from the queue. +TEST_F(BubbleManagerImplTest, ProcessPendingBubbles_CleansUpStaleControllers) { + auto card_controller = CreateController(BubbleType::kSaveUpdateCard); + auto address_controller = CreateController(BubbleType::kSaveUpdateAddress); + + EXPECT_CALL(*card_controller, ShowBubble()); + bubble_manager().RequestShowController(*card_controller, + /*force_show=*/false); + + // Queue the address bubble. + bubble_manager().RequestShowController(*address_controller, + /*force_show=*/false); + EXPECT_TRUE(card_controller->IsShowingBubble()); + EXPECT_FALSE(address_controller->IsShowingBubble()); + + // Destroy the address controller, invalidating its weak pointer. + address_controller.reset(); + bubble_manager().OnBubbleHiddenByController(*card_controller, + /*show_next_bubble=*/true); +} + +// Test that the time a bubble spends in the queue is logged correctly. +TEST_F(BubbleManagerImplTest, HideActiveBubble_LogsTimeInQueue) { + std::unique_ptr<MockBubbleController> address_controller = + CreateController(BubbleType::kSaveUpdateAddress); + std::unique_ptr<MockBubbleController> card_controller = + CreateController(BubbleType::kSaveUpdateCard); + + // Show card bubble, then queue address bubble. + EXPECT_CALL(*card_controller, ShowBubble()); + bubble_manager().RequestShowController(*card_controller, + /*force_show=*/false); + bubble_manager().RequestShowController(*address_controller, + /*force_show=*/false); + + // Advance time by 5 seconds. + FastForwardBy(base::Seconds(5)); + + // Hide the active bubble, which should trigger the queued bubble to show. + EXPECT_CALL(*address_controller, ShowBubble()); + bubble_manager().OnBubbleHiddenByController(*card_controller, + /*show_next_bubble=*/true); + histogram_tester_.ExpectUniqueTimeSample( + "Autofill.Bubble.Queue.TimeInQueue.SaveUpdateAddress", base::Seconds(5), + 1); +} + } // namespace autofill
diff --git a/chrome/browser/ui/browser_browsertest.cc b/chrome/browser/ui/browser_browsertest.cc index 3bd8225..61155b3 100644 --- a/chrome/browser/ui/browser_browsertest.cc +++ b/chrome/browser/ui/browser_browsertest.cc
@@ -990,6 +990,7 @@ // Accept the navigation so we end up on a page without a beforeunload hook. alert->view()->AcceptAppModalDialog(); + EXPECT_TRUE(content::WaitForLoadStop(contents)); } IN_PROC_BROWSER_TEST_F(BrowserTest, NotifiesBrowserDidClose) {
diff --git a/chrome/browser/ui/profiles/signin_intercept_first_run_experience_dialog_browsertest.cc b/chrome/browser/ui/profiles/signin_intercept_first_run_experience_dialog_browsertest.cc index e0a1257ad..dfdc9d8 100644 --- a/chrome/browser/ui/profiles/signin_intercept_first_run_experience_dialog_browsertest.cc +++ b/chrome/browser/ui/profiles/signin_intercept_first_run_experience_dialog_browsertest.cc
@@ -39,6 +39,7 @@ #include "components/policy/policy_constants.h" #include "components/signin/public/base/signin_metrics.h" #include "components/signin/public/base/signin_switches.h" +#include "components/sync/base/features.h" #include "components/sync/test/test_sync_service.h" #include "components/user_education/common/feature_promo/feature_promo_controller.h" #include "content/public/browser/web_contents.h" @@ -120,7 +121,12 @@ /*use_main_profile=*/true), scoped_iph_delay_( AvatarToolbarButton::SetScopedIPHMinDelayAfterCreationForTesting( - base::Seconds(0))) {} + base::Seconds(0))) { + // TODO(crbug.com/447155093): Fix the tests to work with + // `kReplaceSyncPromosWithSignInPromos` enabled. + scoped_feature_list_.InitAndDisableFeature( + syncer::kReplaceSyncPromosWithSignInPromos); + } ~SigninInterceptFirstRunExperienceDialogBrowserTest() override = default; @@ -249,6 +255,7 @@ const GURL kSyncSettingsUrl = GURL("chrome://settings/syncSetup"); private: + base::test::ScopedFeatureList scoped_feature_list_; testing::NiceMock<policy::MockConfigurationPolicyProvider> policy_provider_; // Needed for profile switch IPH testing. base::AutoReset<base::TimeDelta> scoped_iph_delay_;
diff --git a/chrome/browser/ui/signin/dice_migration_service_browsertest.cc b/chrome/browser/ui/signin/dice_migration_service_browsertest.cc index fbab126..5ed3d133 100644 --- a/chrome/browser/ui/signin/dice_migration_service_browsertest.cc +++ b/chrome/browser/ui/signin/dice_migration_service_browsertest.cc
@@ -84,6 +84,14 @@ class DiceMigrationServiceBrowserTest : public InProcessBrowserTest { public: + DiceMigrationServiceBrowserTest() { + scoped_feature_list_.InitWithFeatures( + /*enabled_features=*/{switches::kOfferMigrationToDiceUsers}, + // DICe migration dialog is not shown when forced migration flag is + // enabled. + /*disabled_features=*/{switches::kForcedDiceMigration}); + } + void SetUpOnMainThread() override { InProcessBrowserTest::SetUpOnMainThread(); disclaimer_service_resetter_ = @@ -147,8 +155,7 @@ } protected: - base::test::ScopedFeatureList scoped_feature_list_{ - switches::kOfferMigrationToDiceUsers}; + base::test::ScopedFeatureList scoped_feature_list_; base::ScopedClosureRunner disclaimer_service_resetter_; base::HistogramTester histogram_tester_; }; @@ -841,7 +848,11 @@ class DiceMigrationServiceSyncTest : public SyncTest { public: - DiceMigrationServiceSyncTest() : SyncTest(SINGLE_CLIENT) {} + DiceMigrationServiceSyncTest() : SyncTest(SINGLE_CLIENT) { + scoped_feature_list_.InitWithFeatures( + /*enabled_features=*/{switches::kOfferMigrationToDiceUsers}, + /*disabled_features=*/{switches::kForcedDiceMigration}); + } signin::IdentityManager* GetIdentityManager() { return IdentityManagerFactory::GetForProfile(GetProfile(0)); @@ -873,8 +884,7 @@ } private: - base::test::ScopedFeatureList scoped_feature_list_{ - switches::kOfferMigrationToDiceUsers}; + base::test::ScopedFeatureList scoped_feature_list_; }; IN_PROC_BROWSER_TEST_F(DiceMigrationServiceSyncTest, PRE_MigrateUser) {
diff --git a/chrome/browser/ui/signin/dice_migration_service_interactive_uitest.cc b/chrome/browser/ui/signin/dice_migration_service_interactive_uitest.cc index b5828d24..79de456 100644 --- a/chrome/browser/ui/signin/dice_migration_service_interactive_uitest.cc +++ b/chrome/browser/ui/signin/dice_migration_service_interactive_uitest.cc
@@ -55,6 +55,12 @@ class DiceMigrationServiceInteractiveUiTest : public InteractiveBrowserTest { public: + DiceMigrationServiceInteractiveUiTest() { + scoped_feature_list_.InitWithFeatures( + /*enabled_features=*/{switches::kOfferMigrationToDiceUsers}, + /*disabled_features=*/{switches::kForcedDiceMigration}); + } + Profile* GetProfile() { return browser()->profile(); } DiceMigrationService* GetDiceMigrationService() { @@ -106,8 +112,7 @@ } protected: - const base::test::ScopedFeatureList scoped_feature_list_{ - switches::kOfferMigrationToDiceUsers}; + base::test::ScopedFeatureList scoped_feature_list_; base::HistogramTester histogram_tester_; base::UserActionTester user_action_tester_; };
diff --git a/chrome/browser/ui/signin/dice_migration_service_pixel_browsertest.cc b/chrome/browser/ui/signin/dice_migration_service_pixel_browsertest.cc index 04df3f4..dd17e4d 100644 --- a/chrome/browser/ui/signin/dice_migration_service_pixel_browsertest.cc +++ b/chrome/browser/ui/signin/dice_migration_service_pixel_browsertest.cc
@@ -34,6 +34,12 @@ class DiceMigrationServicePixelBrowserTest : public InteractiveBrowserTest { public: + DiceMigrationServicePixelBrowserTest() { + scoped_feature_list_.InitWithFeatures( + /*enabled_features=*/{switches::kOfferMigrationToDiceUsers}, + /*disabled_features=*/{switches::kForcedDiceMigration}); + } + DiceMigrationService* GetDiceMigrationService() { return DiceMigrationServiceFactory::GetForProfile(GetProfile()); } @@ -58,8 +64,7 @@ } private: - base::test::ScopedFeatureList scoped_feature_list_{ - switches::kOfferMigrationToDiceUsers}; + base::test::ScopedFeatureList scoped_feature_list_; }; // This dialog is shown during all but the final time the migration is offered.
diff --git a/chrome/browser/ui/views/autofill/payments/offer_notification_bubble_views_interactive_uitest.cc b/chrome/browser/ui/views/autofill/payments/offer_notification_bubble_views_interactive_uitest.cc index 24cfa86..1d90165b 100644 --- a/chrome/browser/ui/views/autofill/payments/offer_notification_bubble_views_interactive_uitest.cc +++ b/chrome/browser/ui/views/autofill/payments/offer_notification_bubble_views_interactive_uitest.cc
@@ -3,6 +3,7 @@ // found in the LICENSE file. #include <string_view> +#include <vector> #include "base/strings/utf_string_conversions.h" #include "base/test/metrics/histogram_tester.h" @@ -28,6 +29,7 @@ #include "components/autofill/core/browser/payments/offer_notification_handler.h" #include "components/autofill/core/browser/test_utils/test_autofill_clock.h" #include "components/autofill/core/common/autofill_clock.h" +#include "components/autofill/core/common/autofill_features.h" #include "components/autofill/core/common/autofill_payments_features.h" #include "components/search/ntp_features.h" #include "components/strings/grit/components_strings.h" @@ -59,22 +61,46 @@ std::string GetTestName( const ::testing::TestParamInfo< - OfferNotificationBubbleViewsInteractiveUiTestData>& info) { - return info.param.name; + std::tuple<OfferNotificationBubbleViewsInteractiveUiTestData, bool>>& + info) { + const auto& params = std::get<0>(info.param); + bool bubble_manager_enabled = std::get<1>(info.param); + return params.name + (bubble_manager_enabled ? "WithBubbleManagerEnabled" + : "WithBubbleManagerDisabled"); } class OfferNotificationBubbleViewsInteractiveUiTest : public OfferNotificationBubbleViewsTestBase, public testing::WithParamInterface< - OfferNotificationBubbleViewsInteractiveUiTestData> { + std::tuple<OfferNotificationBubbleViewsInteractiveUiTestData, bool>> { public: OfferNotificationBubbleViewsInteractiveUiTest() - : test_offer_type_(GetParam().offer_type) { - if (GetParam().is_page_actions_migration_enabled) { - feature_list_.InitAndEnableFeatureWithParameters( - ::features::kPageActionsMigration, - {{::features::kPageActionsMigrationOfferNotification.name, "true"}}); + : test_offer_type_(std::get<0>(GetParam()).offer_type) { + const auto& params = std::get<0>(GetParam()); + bool bubble_manager_enabled = std::get<1>(GetParam()); + + std::vector<base::test::FeatureRefAndParams> enabled_features; + std::vector<base::test::FeatureRef> disabled_features; + + if (bubble_manager_enabled) { + enabled_features.push_back( + {features::kAutofillShowBubblesBasedOnPriorities, {}}); + } else { + disabled_features.push_back( + features::kAutofillShowBubblesBasedOnPriorities); } + + if (params.is_page_actions_migration_enabled) { + enabled_features.push_back( + {::features::kPageActionsMigration, + {{::features::kPageActionsMigrationOfferNotification.name, + "true"}}}); + } else { + disabled_features.push_back(::features::kPageActionsMigration); + } + + feature_list_.InitWithFeaturesAndParameters(enabled_features, + disabled_features); } ~OfferNotificationBubbleViewsInteractiveUiTest() override = default; @@ -178,10 +204,13 @@ INSTANTIATE_TEST_SUITE_P( MAYBE_GPayCardLinked, OfferNotificationBubbleViewsInteractiveUiTest, - testing::Values(OfferNotificationBubbleViewsInteractiveUiTestData{ - "GPayCardLinked", - AutofillOfferData::OfferType::GPAY_CARD_LINKED_OFFER, - })); + testing::Combine( + testing::Values(OfferNotificationBubbleViewsInteractiveUiTestData{ + "GPayCardLinked", + AutofillOfferData::OfferType::GPAY_CARD_LINKED_OFFER, + }), + testing::Bool()), + &GetTestName); // TODO(crbug.com/416010106): Flaky failures. #if BUILDFLAG(IS_MAC) @@ -193,11 +222,14 @@ INSTANTIATE_TEST_SUITE_P( MAYBE_GPayCardLinkedWithNewPageAction, OfferNotificationBubbleViewsInteractiveUiTest, - testing::Values(OfferNotificationBubbleViewsInteractiveUiTestData{ - "GPayCardLinked", - AutofillOfferData::OfferType::GPAY_CARD_LINKED_OFFER, - /*is_page_actions_migration_enabled=*/true, - })); + testing::Combine( + testing::Values(OfferNotificationBubbleViewsInteractiveUiTestData{ + "GPayCardLinkedWithNewPageAction", + AutofillOfferData::OfferType::GPAY_CARD_LINKED_OFFER, + /*is_page_actions_migration_enabled=*/true, + }), + testing::Bool()), + &GetTestName); // TODO(crbug.com/416010106): Flaky failures. #if BUILDFLAG(IS_MAC) @@ -208,8 +240,12 @@ INSTANTIATE_TEST_SUITE_P( MAYBE_GPayPromoCode, OfferNotificationBubbleViewsInteractiveUiTest, - testing::Values(OfferNotificationBubbleViewsInteractiveUiTestData{ - "GPayPromoCode", AutofillOfferData::OfferType::GPAY_PROMO_CODE_OFFER})); + testing::Combine( + testing::Values(OfferNotificationBubbleViewsInteractiveUiTestData{ + "GPayPromoCode", + AutofillOfferData::OfferType::GPAY_PROMO_CODE_OFFER}), + testing::Bool()), + &GetTestName); // TODO(crbug.com/416010106): Flaky failures. #if BUILDFLAG(IS_MAC) @@ -221,9 +257,13 @@ INSTANTIATE_TEST_SUITE_P( MAYBE_GPayPromoCodeWithNewPageAction, OfferNotificationBubbleViewsInteractiveUiTest, - testing::Values(OfferNotificationBubbleViewsInteractiveUiTestData{ - "GPayPromoCode", AutofillOfferData::OfferType::GPAY_PROMO_CODE_OFFER, - /*is_page_actions_migration_enabled=*/true})); + testing::Combine( + testing::Values(OfferNotificationBubbleViewsInteractiveUiTestData{ + "GPayPromoCodeWithNewPageAction", + AutofillOfferData::OfferType::GPAY_PROMO_CODE_OFFER, + /*is_page_actions_migration_enabled=*/true}), + testing::Bool()), + &GetTestName); // TODO(crbug.com/40285326): This fails with the field trial testing config. class OfferNotificationBubbleViewsInteractiveUiTestNoTestingConfig @@ -245,8 +285,12 @@ INSTANTIATE_TEST_SUITE_P( MAYBE_GPayPromoCode, OfferNotificationBubbleViewsInteractiveUiTestNoTestingConfig, - testing::Values(OfferNotificationBubbleViewsInteractiveUiTestData{ - "GPayPromoCode", AutofillOfferData::OfferType::GPAY_PROMO_CODE_OFFER})); + testing::Combine( + testing::Values(OfferNotificationBubbleViewsInteractiveUiTestData{ + "GPayPromoCode", + AutofillOfferData::OfferType::GPAY_PROMO_CODE_OFFER}), + testing::Bool()), + &GetTestName); // TODO(crbug.com/416010106): Flaky failures. #if BUILDFLAG(IS_MAC) @@ -258,9 +302,13 @@ INSTANTIATE_TEST_SUITE_P( MAYBE_GPayPromoCodeWithNewPageAction, OfferNotificationBubbleViewsInteractiveUiTestNoTestingConfig, - testing::Values(OfferNotificationBubbleViewsInteractiveUiTestData{ - "GPayPromoCode", AutofillOfferData::OfferType::GPAY_PROMO_CODE_OFFER, - /*is_page_actions_migration_enabled=*/true})); + testing::Combine( + testing::Values(OfferNotificationBubbleViewsInteractiveUiTestData{ + "GPayPromoCodeWithNewPageAction", + AutofillOfferData::OfferType::GPAY_PROMO_CODE_OFFER, + /*is_page_actions_migration_enabled=*/true}), + testing::Bool()), + &GetTestName); // TODO(crbug.com/40817360): Flaky failures. #if BUILDFLAG(IS_LINUX)
diff --git a/chrome/browser/ui/views/external_protocol_handler_ash.cc b/chrome/browser/ui/views/external_protocol_handler_ash.cc index 04be034..68b12e6b 100644 --- a/chrome/browser/ui/views/external_protocol_handler_ash.cc +++ b/chrome/browser/ui/views/external_protocol_handler_ash.cc
@@ -9,14 +9,13 @@ #include "base/memory/raw_ptr.h" #include "base/strings/utf_string_conversions.h" #include "base/time/time.h" -#include "chrome/browser/apps/app_service/app_service_proxy.h" -#include "chrome/browser/apps/app_service/app_service_proxy_factory.h" #include "chrome/browser/ash/arc/intent_helper/arc_intent_helper_mojo_ash.h" #include "chrome/browser/ash/guest_os/guest_os_external_protocol_handler.h" #include "chrome/browser/chromeos/arc/arc_external_protocol_dialog.h" #include "chrome/browser/external_protocol/external_protocol_handler.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/views/external_protocol_dialog.h" +#include "chrome/browser/ui/views/web_apps/protocol_handler_picker_coordinator.h" #include "chrome/browser/web_applications/app_service/publisher_helper.h" #include "chrome/grit/branded_strings.h" #include "chrome/grit/generated_resources.h" @@ -125,49 +124,6 @@ } } -std::string GetAppName(apps::AppServiceProxy* proxy, - const std::string& app_id) { - std::optional<std::string> app_name; - proxy->AppRegistryCache().ForOneApp( - app_id, - [&](const apps::AppUpdate& update) { app_name = update.ShortName(); }); - CHECK(app_name); - return *app_name; -} - -void HandleWebAppManifestProtocolHandler( - Profile* profile, - WebContents* web_contents, - const GURL& url, - const std::vector<std::string>& app_ids, - const std::optional<url::Origin>& initiating_origin, - content::WeakDocumentPtr initiator_document) { - CHECK(!app_ids.empty()); - CHECK(apps::AppServiceProxyFactory::IsAppServiceAvailableForProfile(profile)); - auto* proxy = apps::AppServiceProxyFactory::GetForProfile(profile); - if (app_ids.size() > 1) { - // TODO(crbug.com/422422887): Figure out how to disambiguate conflicting - // protocol handlers; for now, pick the first one in the list. - static constexpr std::string_view kConfictingProtocolHandlersWarning = - "There's more than one web application handling %s links : [%s]; " - "ChromeOS currently doesn't support disambiguating multiple handlers."; - if (content::RenderFrameHost* rfh = - initiator_document.AsRenderFrameHostIfValid()) { - std::vector<std::string> app_names = base::ToVector( - app_ids, - [&](const auto& app_id) { return GetAppName(proxy, app_id); }); - rfh->AddMessageToConsole( - blink::mojom::ConsoleMessageLevel::kWarning, - base::StringPrintf(kConfictingProtocolHandlersWarning, url.scheme(), - base::JoinString(app_names, ","))); - } - } - - new ExternalProtocolDialog(web_contents, url, - base::UTF8ToUTF16(GetAppName(proxy, app_ids[0])), - initiating_origin, std::move(initiator_document)); -} - } // namespace /////////////////////////////////////////////////////////////////////////////// @@ -194,8 +150,8 @@ if (std::vector<std::string> app_ids = web_app::GetWebAppIdsForProtocolUrl(profile, url); !app_ids.empty()) { - HandleWebAppManifestProtocolHandler(profile, web_contents, url, app_ids, - initiating_origin, initiator_document); + web_app::LaunchProtocolUrlInPreferredApp(web_contents, url, app_ids, + initiating_origin); return; }
diff --git a/chrome/browser/ui/views/profiles/avatar_toolbar_button_browsertest.cc b/chrome/browser/ui/views/profiles/avatar_toolbar_button_browsertest.cc index 21b72b3d..7cefb79 100644 --- a/chrome/browser/ui/views/profiles/avatar_toolbar_button_browsertest.cc +++ b/chrome/browser/ui/views/profiles/avatar_toolbar_button_browsertest.cc
@@ -394,7 +394,6 @@ delay_resets_.push_back( signin_ui_util:: CreateZeroOverrideDelayForCrossWindowAnimationReplayForTesting()); - ClearSyncOptinPromoIfEnabled(avatar); return account_info; } @@ -934,20 +933,6 @@ EXPECT_EQ(avatar_button->GetText(), std::u16string()); } -IN_PROC_BROWSER_TEST_F(AvatarToolbarButtonBrowserTest, SigninWithSyncError) { - AvatarToolbarButton* avatar_button = GetAvatarToolbarButton(browser()); - // Normal state. - ASSERT_TRUE(avatar_button->GetText().empty()); - - SigninWithImageAndClearGreetingAndSyncPromo(avatar_button, u"test@gmail.com"); - SimulateSyncError(); - EXPECT_EQ(avatar_button->GetText(), - l10n_util::GetStringUTF16(IDS_AVATAR_BUTTON_SIGNIN_PAUSED)); - - ClearSyncError(); - EXPECT_EQ(avatar_button->GetText(), std::u16string()); -} - IN_PROC_BROWSER_TEST_F(AvatarToolbarButtonWithSyncBrowserTest, SyncPausedThenExplicitText) { AvatarToolbarButton* avatar_button = GetAvatarToolbarButton(browser()); @@ -970,32 +955,6 @@ ExpectSyncPaused(avatar_button); } -#if !BUILDFLAG(IS_CHROMEOS) -IN_PROC_BROWSER_TEST_F(AvatarToolbarButtonBrowserTest, - SigninPendingThenExplicitText) { - AvatarToolbarButton* avatar_button = GetAvatarToolbarButton(browser()); - // Normal state. - ASSERT_TRUE(avatar_button->GetText().empty()); - - SigninWithImageAndClearGreetingAndSyncPromo(avatar_button, u"test@gmail.com"); - SimulateSigninPending(/*web_sign_out=*/false); - ASSERT_EQ(avatar_button->GetText(), - l10n_util::GetStringUTF16(IDS_AVATAR_BUTTON_SIGNIN_PAUSED)); - - const std::u16string profile_switch_text(u"Profile Switch?"); - base::ScopedClosureRunner hide_callback = - avatar_button->SetExplicitButtonState( - profile_switch_text, /*accessibility_label=*/std::nullopt, - /*explicit_action=*/std::nullopt); - ASSERT_EQ(avatar_button->GetText(), profile_switch_text); - - // Clearing explicit text should go back to Signin Pending. - hide_callback.RunAndReset(); - EXPECT_EQ(avatar_button->GetText(), - l10n_util::GetStringUTF16(IDS_AVATAR_BUTTON_SIGNIN_PAUSED)); -} -#endif - // Explicit text over sync paused/error. IN_PROC_BROWSER_TEST_F(AvatarToolbarButtonWithSyncBrowserTest, ExplicitTextThenSyncPaused) { @@ -1020,33 +979,6 @@ ExpectSyncPaused(avatar_button); } -#if !BUILDFLAG(IS_CHROMEOS) -// Explicit text over signin pending. -IN_PROC_BROWSER_TEST_F(AvatarToolbarButtonBrowserTest, - ExplicitTextThenSigninPending) { - AvatarToolbarButton* avatar_button = GetAvatarToolbarButton(browser()); - // Normal state. - ASSERT_TRUE(avatar_button->GetText().empty()); - - SigninWithImageAndClearGreetingAndSyncPromo(avatar_button, u"test@gmail.com"); - const std::u16string profile_switch_text(u"Profile Switch?"); - base::ScopedClosureRunner hide_callback = - avatar_button->SetExplicitButtonState( - profile_switch_text, /*accessibility_label=*/std::nullopt, - /*explicit_action=*/std::nullopt); - ASSERT_EQ(avatar_button->GetText(), profile_switch_text); - - SimulateSigninPending(/*web_sign_out=*/false); - // Explicit text should still be shown even if Signin Pending. - ASSERT_EQ(avatar_button->GetText(), profile_switch_text); - - // Clearing explicit text should go back to Signin Pending. - hide_callback.RunAndReset(); - EXPECT_EQ(avatar_button->GetText(), - l10n_util::GetStringUTF16(IDS_AVATAR_BUTTON_SIGNIN_PAUSED)); -} -#endif - IN_PROC_BROWSER_TEST_F(AvatarToolbarButtonBrowserTest, ShowExplicitTextAndHide) { AvatarToolbarButton* avatar = GetAvatarToolbarButton(browser()); @@ -1202,6 +1134,151 @@ #endif +class AvatarToolbarButtonBrowserTestWithoutReplaceSyncWithSigninPromos + : public AvatarToolbarButtonBrowserTest { + public: + AvatarToolbarButtonBrowserTestWithoutReplaceSyncWithSigninPromos() { + // TODO(crbug.com/444617947): Fix the tests to work with the feature enabled + // and move them back to AvatarToolbarButtonBrowserTest. + feature_list_.InitAndDisableFeature( + syncer::kReplaceSyncPromosWithSignInPromos); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + +IN_PROC_BROWSER_TEST_F( + AvatarToolbarButtonBrowserTestWithoutReplaceSyncWithSigninPromos, + SigninWithSyncError) { + AvatarToolbarButton* avatar_button = GetAvatarToolbarButton(browser()); + // Normal state. + ASSERT_TRUE(avatar_button->GetText().empty()); + + SigninWithImageAndClearGreetingAndSyncPromo(avatar_button, u"test@gmail.com"); + SimulateSyncError(); + EXPECT_EQ(avatar_button->GetText(), + l10n_util::GetStringUTF16(IDS_AVATAR_BUTTON_SIGNIN_PAUSED)); + + ClearSyncError(); + EXPECT_EQ(avatar_button->GetText(), std::u16string()); +} + +#if !BUILDFLAG(IS_CHROMEOS) +IN_PROC_BROWSER_TEST_F( + AvatarToolbarButtonBrowserTestWithoutReplaceSyncWithSigninPromos, + SigninPendingThenExplicitText) { + AvatarToolbarButton* avatar_button = GetAvatarToolbarButton(browser()); + // Normal state. + ASSERT_TRUE(avatar_button->GetText().empty()); + + SigninWithImageAndClearGreetingAndSyncPromo(avatar_button, u"test@gmail.com"); + SimulateSigninPending(/*web_sign_out=*/false); + ASSERT_EQ(avatar_button->GetText(), + l10n_util::GetStringUTF16(IDS_AVATAR_BUTTON_SIGNIN_PAUSED)); + + const std::u16string profile_switch_text(u"Profile Switch?"); + base::ScopedClosureRunner hide_callback = + avatar_button->SetExplicitButtonState( + profile_switch_text, /*accessibility_label=*/std::nullopt, + /*explicit_action=*/std::nullopt); + ASSERT_EQ(avatar_button->GetText(), profile_switch_text); + + // Clearing explicit text should go back to Signin Pending. + hide_callback.RunAndReset(); + EXPECT_EQ(avatar_button->GetText(), + l10n_util::GetStringUTF16(IDS_AVATAR_BUTTON_SIGNIN_PAUSED)); +} +#endif + +#if !BUILDFLAG(IS_CHROMEOS) +// Explicit text over signin pending. +IN_PROC_BROWSER_TEST_F( + AvatarToolbarButtonBrowserTestWithoutReplaceSyncWithSigninPromos, + ExplicitTextThenSigninPending) { + AvatarToolbarButton* avatar_button = GetAvatarToolbarButton(browser()); + // Normal state. + ASSERT_TRUE(avatar_button->GetText().empty()); + + SigninWithImageAndClearGreetingAndSyncPromo(avatar_button, u"test@gmail.com"); + const std::u16string profile_switch_text(u"Profile Switch?"); + base::ScopedClosureRunner hide_callback = + avatar_button->SetExplicitButtonState( + profile_switch_text, /*accessibility_label=*/std::nullopt, + /*explicit_action=*/std::nullopt); + ASSERT_EQ(avatar_button->GetText(), profile_switch_text); + + SimulateSigninPending(/*web_sign_out=*/false); + // Explicit text should still be shown even if Signin Pending. + ASSERT_EQ(avatar_button->GetText(), profile_switch_text); + + // Clearing explicit text should go back to Signin Pending. + hide_callback.RunAndReset(); + EXPECT_EQ(avatar_button->GetText(), + l10n_util::GetStringUTF16(IDS_AVATAR_BUTTON_SIGNIN_PAUSED)); +} +#endif + +#if BUILDFLAG(ENABLE_DICE_SUPPORT) + +IN_PROC_BROWSER_TEST_F( + AvatarToolbarButtonBrowserTestWithoutReplaceSyncWithSigninPromos, + PRE_SigninPendingFromWebSignoutThenRestartChrome) { + AvatarToolbarButton* avatar = GetAvatarToolbarButton(browser()); + SigninWithImageAndClearGreetingAndSyncPromo(avatar, test_email(), + test_given_name()); + + SimulateSigninPending(/*web_sign_out=*/true); + ASSERT_EQ(avatar->GetText(), std::u16string()); +} + +IN_PROC_BROWSER_TEST_F( + AvatarToolbarButtonBrowserTestWithoutReplaceSyncWithSigninPromos, + SigninPendingFromWebSignoutThenRestartChrome) { + AvatarToolbarButton* avatar = GetAvatarToolbarButton(browser()); + // The greetings are shown after the restart. + EXPECT_EQ(avatar->GetText(), + l10n_util::GetStringFUTF16(IDS_AVATAR_BUTTON_GREETING, + test_given_name())); + + avatar->ClearActiveStateForTesting(); + // The error text is expected to be shown even if the error delay has not + // reached yet. + EXPECT_EQ(avatar->GetText(), + l10n_util::GetStringUTF16(IDS_AVATAR_BUTTON_SIGNIN_PAUSED)); +} + +// Regression test for https://crbug.com/348587566 +IN_PROC_BROWSER_TEST_F( + AvatarToolbarButtonBrowserTestWithoutReplaceSyncWithSigninPromos, + SigninPendingDelayEndedNoBrowser) { + ASSERT_EQ(1u, chrome::GetTotalBrowserCount()); + AvatarToolbarButton* avatar = GetAvatarToolbarButton(browser()); + + SigninWithImageAndClearGreetingAndSyncPromo(avatar, u"test@gmail.com", + u"TestName"); + SimulateSigninPending(/*web_sign_out=*/true); + ASSERT_TRUE(avatar->GetText().empty()); + Profile* profile = browser()->profile(); + + // Close the browser before the delay ends, but keep the profile and Chrome + // alive by opening an incognito browser. + CreateIncognitoBrowser(profile); + CloseBrowserSynchronously(browser()); + + // This simulates the delay expiry for the next browser. Instead of advancing + // time, we set the expected delay to 0, making the elapsed time greater than + // the delay for sure - simulating the delay expiry. + SetZeroAvatarDelayForSigninPendingText(); + + // Open a new browser, this should not crash. + Browser* new_browser = CreateBrowser(profile); + EXPECT_EQ(GetAvatarToolbarButton(new_browser)->GetText(), + l10n_util::GetStringUTF16(IDS_AVATAR_BUTTON_SIGNIN_PAUSED)); +} + +#endif // BUILDFLAG(ENABLE_DICE_SUPPORT) + class AvatarToolbarButtonWithInteractiveFeaturePromoBrowserTest : public InteractiveFeaturePromoTest, public AvatarToolbarButtonBaseBrowserTest { @@ -2897,59 +2974,6 @@ EXPECT_EQ(new_browser_avatar_button->GetText(), std::u16string()); } -IN_PROC_BROWSER_TEST_F(AvatarToolbarButtonBrowserTest, - PRE_SigninPendingFromWebSignoutThenRestartChrome) { - AvatarToolbarButton* avatar = GetAvatarToolbarButton(browser()); - SigninWithImageAndClearGreetingAndSyncPromo(avatar, test_email(), - test_given_name()); - - SimulateSigninPending(/*web_sign_out=*/true); - ASSERT_EQ(avatar->GetText(), std::u16string()); -} - -IN_PROC_BROWSER_TEST_F(AvatarToolbarButtonBrowserTest, - SigninPendingFromWebSignoutThenRestartChrome) { - AvatarToolbarButton* avatar = GetAvatarToolbarButton(browser()); - // The greetings are shown after the restart. - EXPECT_EQ(avatar->GetText(), - l10n_util::GetStringFUTF16(IDS_AVATAR_BUTTON_GREETING, - test_given_name())); - - avatar->ClearActiveStateForTesting(); - // The error text is expected to be shown even if the error delay has not - // reached yet. - EXPECT_EQ(avatar->GetText(), - l10n_util::GetStringUTF16(IDS_AVATAR_BUTTON_SIGNIN_PAUSED)); -} - -// Regression test for https://crbug.com/348587566 -IN_PROC_BROWSER_TEST_F(AvatarToolbarButtonBrowserTest, - SigninPendingDelayEndedNoBrowser) { - ASSERT_EQ(1u, chrome::GetTotalBrowserCount()); - AvatarToolbarButton* avatar = GetAvatarToolbarButton(browser()); - - SigninWithImageAndClearGreetingAndSyncPromo(avatar, u"test@gmail.com", - u"TestName"); - SimulateSigninPending(/*web_sign_out=*/true); - ASSERT_TRUE(avatar->GetText().empty()); - Profile* profile = browser()->profile(); - - // Close the browser before the delay ends, but keep the profile and Chrome - // alive by opening an incognito browser. - CreateIncognitoBrowser(profile); - CloseBrowserSynchronously(browser()); - - // This simulates the delay expiry for the next browser. Instead of advancing - // time, we set the expected delay to 0, making the elapsed time greater than - // the delay for sure - simulating the delay expiry. - SetZeroAvatarDelayForSigninPendingText(); - - // Open a new browser, this should not crash. - Browser* new_browser = CreateBrowser(profile); - EXPECT_EQ(GetAvatarToolbarButton(new_browser)->GetText(), - l10n_util::GetStringUTF16(IDS_AVATAR_BUTTON_SIGNIN_PAUSED)); -} - // TODO(b/331746545): Check flaky test issue on windows. #if BUILDFLAG(IS_WIN) #define MAYBE_SigninPendingThenSignout DISABLED_SigninPendingThenSignout
diff --git a/chrome/browser/ui/views/profiles/first_run_interactive_uitest.cc b/chrome/browser/ui/views/profiles/first_run_interactive_uitest.cc index 5549a3b..680a088 100644 --- a/chrome/browser/ui/views/profiles/first_run_interactive_uitest.cc +++ b/chrome/browser/ui/views/profiles/first_run_interactive_uitest.cc
@@ -52,6 +52,7 @@ #include "components/signin/public/identity_manager/account_info.h" #include "components/signin/public/identity_manager/identity_manager.h" #include "components/signin/public/identity_manager/identity_test_utils.h" +#include "components/sync/base/features.h" #include "components/user_education/views/help_bubble_view.h" #include "content/public/test/browser_test.h" #include "content/public/test/browser_test_utils.h" @@ -209,7 +210,12 @@ : InteractiveFeaturePromoTestT<FirstRunServiceBrowserTestBase>( UseDefaultTrackerAllowingPromos( {feature_engagement::kIPHSupervisedUserProfileSigninFeature})), - params_(params) {} + params_(params) { + // TODO(crbug.com/447151253): Fix the tests to work with the feature + // enabled. + scoped_feature_list_.InitAndDisableFeature( + syncer::kReplaceSyncPromosWithSignInPromos); + } ~FirstRunInteractiveUiTest() override = default; protected: @@ -433,6 +439,7 @@ private: TestParam params_; + base::test::ScopedFeatureList scoped_feature_list_; ChromeSigninClientWithURLLoaderHelper url_loader_factory_helper_; base::HistogramTester histogram_tester_;
diff --git a/chrome/browser/ui/views/profiles/profile_picker_view_browsertest.cc b/chrome/browser/ui/views/profiles/profile_picker_view_browsertest.cc index be6eede2..0e362ad 100644 --- a/chrome/browser/ui/views/profiles/profile_picker_view_browsertest.cc +++ b/chrome/browser/ui/views/profiles/profile_picker_view_browsertest.cc
@@ -2969,7 +2969,12 @@ public testing::WithParamInterface< LoginUIService::SyncConfirmationUIClosedResult> { public: - SupervisedUserProfileIPHTest() = default; + SupervisedUserProfileIPHTest() { + // TODO(crbug.com/447099373): Fix the tests to work with the feature + // enabled. + scoped_feature_list_.InitAndDisableFeature( + syncer::kReplaceSyncPromosWithSignInPromos); + } protected: LoginUIService::SyncConfirmationUIClosedResult GetSyncConfirmationResult() { @@ -2981,6 +2986,8 @@ return HasPromoBeenShown( browser, feature_engagement::kIPHSupervisedUserProfileSigninFeature); } + + base::test::ScopedFeatureList scoped_feature_list_; }; std::string SyncConfirmationResultToString( @@ -3750,8 +3757,11 @@ SyncConfirmationExitChromeTest) { // Simulate a successful sign-in and wait for the sign-in to propagate to the // flow, resulting in sync confirmation screen getting displayed. - SignInForNewProfile(GetSyncConfirmationURL(), "joe.consumer@gmail.com", - "Joe"); + GURL target_url = + base::FeatureList::IsEnabled(syncer::kReplaceSyncPromosWithSignInPromos) + ? GetHistorySyncOptinURL() + : GetSyncConfirmationURL(); + SignInForNewProfile(target_url, "joe.consumer@gmail.com", "Joe"); EXPECT_TRUE(ProfilePicker::IsOpen()); // Exit the sync confirmation view (Cmd-Q).
diff --git a/chrome/browser/ui/views/web_apps/OWNERS b/chrome/browser/ui/views/web_apps/OWNERS index 1255a2c..bc96c62 100644 --- a/chrome/browser/ui/views/web_apps/OWNERS +++ b/chrome/browser/ui/views/web_apps/OWNERS
@@ -1 +1,3 @@ file://chrome/browser/web_applications/OWNERS + +per-file protocol_handler_picker*=greengrape@google.com
diff --git a/chrome/browser/ui/views/web_apps/protocol_handler_picker_coordinator.cc b/chrome/browser/ui/views/web_apps/protocol_handler_picker_coordinator.cc new file mode 100644 index 0000000..d1f4d46 --- /dev/null +++ b/chrome/browser/ui/views/web_apps/protocol_handler_picker_coordinator.cc
@@ -0,0 +1,169 @@ +// 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/web_apps/protocol_handler_picker_coordinator.h" + +#include <string> +#include <vector> + +#include "base/barrier_callback.h" +#include "base/containers/contains.h" +#include "base/functional/callback.h" +#include "base/memory/weak_ptr.h" +#include "chrome/browser/apps/app_service/app_launch_params.h" +#include "chrome/browser/apps/app_service/app_service_proxy.h" +#include "chrome/browser/apps/app_service/app_service_proxy_factory.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/browser_window/public/browser_window_interface.h" +#include "chrome/browser/ui/tabs/tab_strip_model.h" +#include "chrome/browser/ui/views/web_apps/protocol_handler_picker_dialog.h" +#include "components/services/app_service/public/cpp/app_update.h" +#include "components/services/app_service/public/cpp/icon_types.h" +#include "content/public/browser/browser_task_traits.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/navigation_controller.h" +#include "content/public/browser/web_contents.h" +#include "ui/base/models/image_model.h" +#include "url/gurl.h" + +namespace { + +constexpr int kIconSizeInDip = 32; + +void LaunchApp(apps::AppServiceProxy* proxy, + const std::string& app_id, + const GURL& protocol_url) { + apps::AppLaunchParams params(app_id, + apps::LaunchContainer::kLaunchContainerWindow, + WindowOpenDisposition::NEW_FOREGROUND_TAB, + apps::LaunchSource::kFromProtocolHandler); + params.protocol_handler_launch_url = protocol_url; + proxy->LaunchAppWithParams(std::move(params)); +} + +void MaybeCloseWebContentsAsync(content::WebContents* web_contents) { + tabs::TabInterface* tab = + tabs::TabInterface::MaybeGetFromContents(web_contents); + if (!tab) { + return; + } + TabStripModel* tab_strip_model = + tab->GetBrowserWindowInterface()->GetTabStripModel(); + // If there's more than one tab in the browser corresponding to the current + // tab and the current tab still in the initial navigation state, it's + // expected to be closed. + if (tab_strip_model->GetIndexOfTab(tab) != TabStripModel::kNoTab && + tab_strip_model->count() > 1 && + web_contents->GetController().IsInitialNavigation()) { + content::GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindOnce(&content::WebContents::Close, + web_contents->GetWeakPtr())); + } +} + +} // namespace + +namespace web_app { + +void ProtocolHandlerPickerCoordinator::ShowPicker( + const GURL& protocol_url, + const std::vector<std::string>& app_ids, + const std::optional<url::Origin>& initiator_origin) { + GatherAppData(protocol_url, app_ids, initiator_origin); +} + +ProtocolHandlerPickerCoordinator::ProtocolHandlerPickerCoordinator( + content::WebContents* web_contents) + : content::WebContentsUserData<ProtocolHandlerPickerCoordinator>( + *web_contents), + proxy_(apps::AppServiceProxyFactory::GetForProfile( + Profile::FromBrowserContext(web_contents->GetBrowserContext()))) { + CHECK(proxy_) << " AppServiceProxy must exist for this instance of " + "WebContents; the caller is responsible for ensuring this."; +} + +ProtocolHandlerPickerCoordinator::~ProtocolHandlerPickerCoordinator() = default; + +void ProtocolHandlerPickerCoordinator::GatherAppData( + const GURL& protocol_url, + const std::vector<std::string>& app_ids, + const std::optional<url::Origin>& initiator_origin) { + CHECK(!app_ids.empty()); + auto all_apps_collected_callback = + base::BarrierCallback<ProtocolHandlerPickerDialogEntry>( + app_ids.size(), + base::BindOnce( + &ProtocolHandlerPickerCoordinator::ShowPickerWithEntries, + weak_factory_.GetWeakPtr(), protocol_url, initiator_origin)); + + for (const std::string& app_id : app_ids) { + std::u16string app_name; + proxy_->AppRegistryCache().ForOneApp( + app_id, [&app_name](const apps::AppUpdate& update) { + app_name = base::UTF8ToUTF16(update.Name()); + }); + + proxy_->LoadIcon( + app_id, apps::IconType::kStandard, kIconSizeInDip, + /*allow_placeholder_icon=*/false, + base::BindOnce( + [](const std::string& app_id, const std::u16string& app_name, + apps::IconValuePtr icon_value) + -> ProtocolHandlerPickerDialogEntry { + return {app_id, app_name, + ui::ImageModel::FromImageSkia(icon_value->uncompressed)}; + }, + app_id, app_name) + .Then(all_apps_collected_callback)); + } +} + +void ProtocolHandlerPickerCoordinator::ShowPickerWithEntries( + const GURL& protocol_url, + const std::optional<url::Origin>& initiator_origin, + ProtocolHandlerPickerDialogEntries app_entries) { + auto dialog_model = CreateProtocolHandlerPickerDialog( + protocol_url, app_entries, initiator_origin, + base::BindOnce(&ProtocolHandlerPickerCoordinator::OnPickerClosed, + weak_factory_.GetWeakPtr(), protocol_url)); + // TODO(cbug.com/422422887): Attach `dialog_model` to `tab_dialog_manager()`. +} + +void ProtocolHandlerPickerCoordinator::OnPickerClosed( + const GURL& protocol_url, + std::optional<ProtocolHandlerPickerDialogResult> result) { + if (result) { + const auto& app_id = result->selected_app_id; + if (result->remember_choice) { + // TODO(cbug.com/422422887): Store the user pref in PreferredAppsList. + } + LaunchApp(proxy_, app_id, protocol_url); + } + + MaybeCloseWebContentsAsync(&GetWebContents()); +} + +WEB_CONTENTS_USER_DATA_KEY_IMPL(ProtocolHandlerPickerCoordinator); + +void LaunchProtocolUrlInPreferredApp( + content::WebContents* web_contents, + const GURL& protocol_url, + const std::vector<std::string>& app_ids, + const std::optional<url::Origin>& initiator_origin) { + auto* proxy = apps::AppServiceProxyFactory::GetForProfile( + Profile::FromBrowserContext(web_contents->GetBrowserContext())); + if (std::optional<std::string> app_id = + proxy->PreferredAppsList().FindPreferredAppForUrl(protocol_url)) { + if (base::Contains(app_ids, *app_id)) { + LaunchApp(proxy, *app_id, protocol_url); + MaybeCloseWebContentsAsync(web_contents); + return; + } + } + + ProtocolHandlerPickerCoordinator::GetOrCreateForWebContents(web_contents) + ->ShowPicker(protocol_url, app_ids, initiator_origin); +} + +} // namespace web_app
diff --git a/chrome/browser/ui/views/web_apps/protocol_handler_picker_coordinator.h b/chrome/browser/ui/views/web_apps/protocol_handler_picker_coordinator.h new file mode 100644 index 0000000..91499c36 --- /dev/null +++ b/chrome/browser/ui/views/web_apps/protocol_handler_picker_coordinator.h
@@ -0,0 +1,71 @@ +// 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_WEB_APPS_PROTOCOL_HANDLER_PICKER_COORDINATOR_H_ +#define CHROME_BROWSER_UI_VIEWS_WEB_APPS_PROTOCOL_HANDLER_PICKER_COORDINATOR_H_ + +#include <optional> +#include <string> +#include <vector> + +#include "base/memory/raw_ptr.h" +#include "base/memory/weak_ptr.h" +#include "chrome/browser/apps/app_service/app_service_proxy_forward.h" +#include "chrome/browser/ui/views/web_apps/protocol_handler_picker_dialog.h" +#include "content/public/browser/web_contents_user_data.h" +#include "ui/views/widget/widget.h" +#include "url/gurl.h" +#include "url/origin.h" + +namespace web_app { + +// This class manages the UI flow for picking a web app to handle a protocol +// request. Its lifetime is tied to the WebContents it's attached to. +class ProtocolHandlerPickerCoordinator + : public content::WebContentsUserData<ProtocolHandlerPickerCoordinator> { + public: + ~ProtocolHandlerPickerCoordinator() override; + + void ShowPicker(const GURL& protocol_url, + const std::vector<std::string>& app_ids, + const std::optional<url::Origin>& initiating_origin); + + private: + friend class content::WebContentsUserData<ProtocolHandlerPickerCoordinator>; + + explicit ProtocolHandlerPickerCoordinator(content::WebContents* web_contents); + + void GatherAppData(const GURL& protocol_url, + const std::vector<std::string>& app_ids, + const std::optional<url::Origin>& initiating_origin); + void ShowPickerWithEntries( + const GURL& protocol_url, + const std::optional<url::Origin>& initiating_origin, + ProtocolHandlerPickerDialogEntries app_entries); + void OnPickerClosed(const GURL& protocol_url, + std::optional<ProtocolHandlerPickerDialogResult> result); + bool HasOpenDialogWidget() const; + + const raw_ptr<apps::AppServiceProxy> proxy_; + + // Owns the currently opened dialog for this tab. + std::unique_ptr<views::Widget> dialog_; + + base::WeakPtrFactory<ProtocolHandlerPickerCoordinator> weak_factory_{this}; + + WEB_CONTENTS_USER_DATA_KEY_DECL(); +}; + +// If there's a preferred app among `app_ids` for handling `protocol_url`, +// launches this app directly; otherwise shows the protocol handler picker +// dialog. +void LaunchProtocolUrlInPreferredApp( + content::WebContents* web_contents, + const GURL& protocol_url, + const std::vector<std::string>& app_ids, + const std::optional<url::Origin>& initiator_origin); + +} // namespace web_app + +#endif // CHROME_BROWSER_UI_VIEWS_WEB_APPS_PROTOCOL_HANDLER_PICKER_COORDINATOR_H_
diff --git a/chrome/browser/ui/views/web_apps/protocol_handler_picker_dialog.cc b/chrome/browser/ui/views/web_apps/protocol_handler_picker_dialog.cc new file mode 100644 index 0000000..b17be8b --- /dev/null +++ b/chrome/browser/ui/views/web_apps/protocol_handler_picker_dialog.cc
@@ -0,0 +1,21 @@ +// 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/web_apps/protocol_handler_picker_dialog.h" + +#include <optional> + +namespace web_app { + +std::unique_ptr<ui::DialogModel> CreateProtocolHandlerPickerDialog( + const GURL& protocol_url, + const ProtocolHandlerPickerDialogEntries& apps, + const std::optional<url::Origin>& initiator_origin, + OnPickerClosedCallback callback) { + // TODO(crbug.com/422422887): Implement the dialog. + std::move(callback).Run({{.selected_app_id = apps[0].app_id}}); + return nullptr; +} + +} // namespace web_app
diff --git a/chrome/browser/ui/views/web_apps/protocol_handler_picker_dialog.h b/chrome/browser/ui/views/web_apps/protocol_handler_picker_dialog.h new file mode 100644 index 0000000..a1d62d9 --- /dev/null +++ b/chrome/browser/ui/views/web_apps/protocol_handler_picker_dialog.h
@@ -0,0 +1,50 @@ +// 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_WEB_APPS_PROTOCOL_HANDLER_PICKER_DIALOG_H_ +#define CHROME_BROWSER_UI_VIEWS_WEB_APPS_PROTOCOL_HANDLER_PICKER_DIALOG_H_ + +#include <memory> +#include <optional> +#include <string> +#include <vector> + +#include "base/functional/callback_forward.h" +#include "content/public/browser/web_contents.h" +#include "ui/base/models/dialog_model.h" +#include "ui/base/models/image_model.h" +#include "url/gurl.h" +#include "url/origin.h" + +namespace web_app { + +struct ProtocolHandlerPickerDialogEntry { + std::string app_id; + std::u16string app_name; + ui::ImageModel icon; +}; + +using ProtocolHandlerPickerDialogEntries = + std::vector<ProtocolHandlerPickerDialogEntry>; + +struct ProtocolHandlerPickerDialogResult { + std::string selected_app_id; + bool remember_choice; +}; + +// The callback to be run when the dialog is closed for any reason. +// The optional will be empty (std::nullopt) if the user canceled or the dialog +// was destroyed for some reason. +using OnPickerClosedCallback = + base::OnceCallback<void(std::optional<ProtocolHandlerPickerDialogResult>)>; + +std::unique_ptr<ui::DialogModel> CreateProtocolHandlerPickerDialog( + const GURL& protocol_url, + const ProtocolHandlerPickerDialogEntries& apps, + const std::optional<url::Origin>& initiator_origin, + OnPickerClosedCallback callback); + +} // namespace web_app + +#endif // CHROME_BROWSER_UI_VIEWS_WEB_APPS_PROTOCOL_HANDLER_PICKER_DIALOG_H_
diff --git a/chrome/browser/url_constants/android/BUILD.gn b/chrome/browser/url_constants/android/BUILD.gn index a24ac20..7ae0af8 100644 --- a/chrome/browser/url_constants/android/BUILD.gn +++ b/chrome/browser/url_constants/android/BUILD.gn
@@ -18,6 +18,26 @@ "//chrome/browser/preferences:java", "//chrome/browser/profiles/android:java", "//components/embedder_support/android:util_java", + "//third_party/androidx:androidx_annotation_annotation_java", "//url:gurl_java", ] } + +robolectric_library("junit") { + sources = [ + "java/src/org/chromium/chrome/browser/url_constants/UrlConstantResolverFactoryUnitTest.java", + "java/src/org/chromium/chrome/browser/url_constants/UrlConstantResolverUnitTest.java", + ] + deps = [ + ":java", + "//base:base_java", + "//base:base_java_test_support", + "//base:base_junit_test_support", + "//chrome/browser/flags:java", + "//chrome/browser/preferences:java", + "//chrome/browser/profiles/android:java", + "//components/embedder_support/android:util_java", + "//third_party/junit", + "//third_party/mockito:mockito_java", + ] +}
diff --git a/chrome/browser/url_constants/android/java/src/org/chromium/chrome/browser/url_constants/UrlConstantResolverFactory.java b/chrome/browser/url_constants/android/java/src/org/chromium/chrome/browser/url_constants/UrlConstantResolverFactory.java index 8035bb6..5d122442 100644 --- a/chrome/browser/url_constants/android/java/src/org/chromium/chrome/browser/url_constants/UrlConstantResolverFactory.java +++ b/chrome/browser/url_constants/android/java/src/org/chromium/chrome/browser/url_constants/UrlConstantResolverFactory.java
@@ -4,6 +4,8 @@ package org.chromium.chrome.browser.url_constants; +import androidx.annotation.VisibleForTesting; + import org.chromium.base.ResettersForTesting; import org.chromium.build.annotations.NullMarked; import org.chromium.build.annotations.Nullable; @@ -24,7 +26,7 @@ // Prevent instantiation. private UrlConstantResolverFactory() {} - public UrlConstantResolver getForProfile(@Nullable Profile profile) { + public static UrlConstantResolver getForProfile(@Nullable Profile profile) { if (sResolverForTesting != null) { return sResolverForTesting; } @@ -98,4 +100,10 @@ sResolverForTesting = resolver; ResettersForTesting.register(() -> sResolverForTesting = null); } + + @VisibleForTesting + public static void resetResolvers() { + sOriginalResolver = null; + sIncognitoResolver = null; + } }
diff --git a/chrome/browser/url_constants/android/java/src/org/chromium/chrome/browser/url_constants/UrlConstantResolverFactoryUnitTest.java b/chrome/browser/url_constants/android/java/src/org/chromium/chrome/browser/url_constants/UrlConstantResolverFactoryUnitTest.java new file mode 100644 index 0000000..84cec14 --- /dev/null +++ b/chrome/browser/url_constants/android/java/src/org/chromium/chrome/browser/url_constants/UrlConstantResolverFactoryUnitTest.java
@@ -0,0 +1,164 @@ +// 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.url_constants; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; +import static org.mockito.Mockito.when; + +import org.junit.After; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +import org.chromium.base.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.components.embedder_support.util.UrlConstants; + +/** Unit tests for {@link UrlConstantResolverFactory}. */ +@RunWith(BaseRobolectricTestRunner.class) +@EnableFeatures({ChromeFeatureList.CHROME_NATIVE_URL_OVERRIDING}) +public class UrlConstantResolverFactoryUnitTest { + @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule(); + + @Mock private Profile mProfile; + + @After + public void tearDown() throws Exception { + ExtensionsUrlOverrideRegistry.setNtpOverrideEnabled(false); + ExtensionsUrlOverrideRegistry.setIncognitoNtpOverrideEnabled(false); + ExtensionsUrlOverrideRegistry.setHistoryPageOverrideEnabled(false); + ExtensionsUrlOverrideRegistry.setBookmarksPageOverrideEnabled(false); + ExtensionsUrlOverrideRegistry.setIncognitoBookmarksPageOverrideEnabled(false); + UrlConstantResolverFactory.resetResolvers(); + } + + @Test + public void testGetForProfile_NullProfile() { + UrlConstantResolver resolver = UrlConstantResolverFactory.getForProfile(null); + assertNotNull(resolver); + } + + @Test + public void testGetForProfile_RegularProfile() { + UrlConstantResolver originalResolver = UrlConstantResolverFactory.getForProfile(null); + UrlConstantResolver profileResolver = UrlConstantResolverFactory.getForProfile(mProfile); + assertEquals(originalResolver, profileResolver); + } + + @Test + public void testGetForProfile_IncognitoProfile() { + UrlConstantResolver originalResolver = UrlConstantResolverFactory.getForProfile(mProfile); + + when(mProfile.isIncognitoBranded()).thenReturn(true); + UrlConstantResolver incognitoResolver = UrlConstantResolverFactory.getForProfile(mProfile); + + assertNotEquals(originalResolver, incognitoResolver); + } + + @Test + public void testSetForTesting() { + UrlConstantResolver testResolver = new UrlConstantResolver(); + UrlConstantResolverFactory.setForTesting(testResolver); + + assertEquals(testResolver, UrlConstantResolverFactory.getForProfile(null)); + assertEquals(testResolver, UrlConstantResolverFactory.getForProfile(mProfile)); + + when(mProfile.isIncognitoBranded()).thenReturn(true); + assertEquals(testResolver, UrlConstantResolverFactory.getForProfile(mProfile)); + } + + @Test + @DisableFeatures({ChromeFeatureList.CHROME_NATIVE_URL_OVERRIDING}) + public void testOriginalResolver_FeatureDisabled() { + UrlConstantResolver resolver = UrlConstantResolverFactory.getForProfile(mProfile); + assertEquals(UrlConstants.NTP_URL, resolver.getNtpUrl()); + assertEquals(UrlConstants.BOOKMARKS_NATIVE_URL, resolver.getBookmarksNativeUrl()); + assertEquals(UrlConstants.NATIVE_HISTORY_URL, resolver.getNativeHistoryUrl()); + } + + @Test + public void testOriginalResolver_NtpOverride() { + UrlConstantResolver resolver = UrlConstantResolverFactory.getForProfile(mProfile); + + ExtensionsUrlOverrideRegistry.setNtpOverrideEnabled(true); + assertEquals(UrlConstants.NTP_NON_NATIVE_URL, resolver.getNtpUrl()); + + ExtensionsUrlOverrideRegistry.setNtpOverrideEnabled(false); + assertEquals(UrlConstants.NTP_URL, resolver.getNtpUrl()); + } + + @Test + public void testOriginalResolver_BookmarksOverride() { + UrlConstantResolver resolver = UrlConstantResolverFactory.getForProfile(mProfile); + + ExtensionsUrlOverrideRegistry.setBookmarksPageOverrideEnabled(true); + assertEquals(UrlConstants.BOOKMARKS_URL, resolver.getBookmarksNativeUrl()); + + ExtensionsUrlOverrideRegistry.setBookmarksPageOverrideEnabled(false); + assertEquals(UrlConstants.BOOKMARKS_NATIVE_URL, resolver.getBookmarksNativeUrl()); + } + + @Test + public void testOriginalResolver_HistoryOverride() { + UrlConstantResolver resolver = UrlConstantResolverFactory.getForProfile(mProfile); + + ExtensionsUrlOverrideRegistry.setHistoryPageOverrideEnabled(true); + assertEquals(UrlConstants.HISTORY_URL, resolver.getNativeHistoryUrl()); + + ExtensionsUrlOverrideRegistry.setHistoryPageOverrideEnabled(false); + assertEquals(UrlConstants.NATIVE_HISTORY_URL, resolver.getNativeHistoryUrl()); + } + + @Test + @DisableFeatures({ChromeFeatureList.CHROME_NATIVE_URL_OVERRIDING}) + public void testIncognitoResolver_FeatureDisabled() { + when(mProfile.isIncognitoBranded()).thenReturn(true); + UrlConstantResolver resolver = UrlConstantResolverFactory.getForProfile(mProfile); + assertEquals(UrlConstants.NTP_URL, resolver.getNtpUrl()); + assertEquals(UrlConstants.BOOKMARKS_NATIVE_URL, resolver.getBookmarksNativeUrl()); + assertEquals(UrlConstants.NATIVE_HISTORY_URL, resolver.getNativeHistoryUrl()); + } + + @Test + public void testIncognitoResolver_NtpOverride() { + when(mProfile.isIncognitoBranded()).thenReturn(true); + UrlConstantResolver resolver = UrlConstantResolverFactory.getForProfile(mProfile); + + ExtensionsUrlOverrideRegistry.setIncognitoNtpOverrideEnabled(true); + assertEquals(UrlConstants.NTP_NON_NATIVE_URL, resolver.getNtpUrl()); + + ExtensionsUrlOverrideRegistry.setIncognitoNtpOverrideEnabled(false); + assertEquals(UrlConstants.NTP_URL, resolver.getNtpUrl()); + } + + @Test + public void testIncognitoResolver_BookmarksOverride() { + when(mProfile.isIncognitoBranded()).thenReturn(true); + UrlConstantResolver resolver = UrlConstantResolverFactory.getForProfile(mProfile); + + ExtensionsUrlOverrideRegistry.setIncognitoBookmarksPageOverrideEnabled(true); + assertEquals(UrlConstants.BOOKMARKS_URL, resolver.getBookmarksNativeUrl()); + + ExtensionsUrlOverrideRegistry.setIncognitoBookmarksPageOverrideEnabled(false); + assertEquals(UrlConstants.BOOKMARKS_NATIVE_URL, resolver.getBookmarksNativeUrl()); + } + + @Test + public void testIncognitoResolver_NoHistoryOverride() { + when(mProfile.isIncognitoBranded()).thenReturn(true); + UrlConstantResolver resolver = UrlConstantResolverFactory.getForProfile(mProfile); + + ExtensionsUrlOverrideRegistry.setHistoryPageOverrideEnabled(true); + assertEquals(UrlConstants.NATIVE_HISTORY_URL, resolver.getNativeHistoryUrl()); + } +}
diff --git a/chrome/browser/url_constants/android/java/src/org/chromium/chrome/browser/url_constants/UrlConstantResolverUnitTest.java b/chrome/browser/url_constants/android/java/src/org/chromium/chrome/browser/url_constants/UrlConstantResolverUnitTest.java new file mode 100644 index 0000000..4c98fd8 --- /dev/null +++ b/chrome/browser/url_constants/android/java/src/org/chromium/chrome/browser/url_constants/UrlConstantResolverUnitTest.java
@@ -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. + +package org.chromium.chrome.browser.url_constants; + +import static org.junit.Assert.assertEquals; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.chromium.base.test.BaseRobolectricTestRunner; +import org.chromium.components.embedder_support.util.UrlConstants; + +/** Unit tests for {@link UrlConstantResolver}. */ +@RunWith(BaseRobolectricTestRunner.class) +public class UrlConstantResolverUnitTest { + private static final String OVERRIDE_URL = "OVERRIDE"; + private UrlConstantResolver mResolver; + + @Before + public void setUp() { + mResolver = new UrlConstantResolver(); + } + + @Test + public void testGetNtpUrl_NoOverride() { + assertEquals(UrlConstants.NTP_URL, mResolver.getNtpUrl()); + } + + @Test + public void testGetBookmarksNativeUrl_NoOverride() { + assertEquals(UrlConstants.BOOKMARKS_NATIVE_URL, mResolver.getBookmarksNativeUrl()); + } + + @Test + public void testGetNativeHistoryUrl_NoOverride() { + assertEquals(UrlConstants.NATIVE_HISTORY_URL, mResolver.getNativeHistoryUrl()); + } + + @Test + public void testGetNtpUrl_WithOverrideEnabled() { + mResolver.registerOverride(UrlConstants.NTP_URL, () -> OVERRIDE_URL); + assertEquals(OVERRIDE_URL, mResolver.getNtpUrl()); + } + + @Test + public void testGetNtpUrl_WithOverrideDisabled() { + mResolver.registerOverride(UrlConstants.NTP_URL, () -> null); + assertEquals(UrlConstants.NTP_URL, mResolver.getNtpUrl()); + } + + @Test + public void testGetBookmarksNativeUrl_WithOverrideEnabled() { + mResolver.registerOverride(UrlConstants.BOOKMARKS_NATIVE_URL, () -> OVERRIDE_URL); + assertEquals(OVERRIDE_URL, mResolver.getBookmarksNativeUrl()); + } + + @Test + public void testGetBookmarksNativeUrl_WithOverrideDisabled() { + mResolver.registerOverride(UrlConstants.BOOKMARKS_NATIVE_URL, () -> null); + assertEquals(UrlConstants.BOOKMARKS_NATIVE_URL, mResolver.getBookmarksNativeUrl()); + } + + @Test + public void testGetNativeHistoryUrl_WithOverrideEnabled() { + mResolver.registerOverride(UrlConstants.NATIVE_HISTORY_URL, () -> OVERRIDE_URL); + assertEquals(OVERRIDE_URL, mResolver.getNativeHistoryUrl()); + } + + @Test + public void testGetNativeHistoryUrl_WithOverrideDisabled() { + mResolver.registerOverride(UrlConstants.NATIVE_HISTORY_URL, () -> null); + assertEquals(UrlConstants.NATIVE_HISTORY_URL, mResolver.getNativeHistoryUrl()); + } +}
diff --git a/chrome/browser/web_applications/isolated_web_apps/browser_navigator_iwa_browsertest.cc b/chrome/browser/web_applications/isolated_web_apps/browser_navigator_iwa_browsertest.cc index 80af07ba..ecde73d 100644 --- a/chrome/browser/web_applications/isolated_web_apps/browser_navigator_iwa_browsertest.cc +++ b/chrome/browser/web_applications/isolated_web_apps/browser_navigator_iwa_browsertest.cc
@@ -225,9 +225,6 @@ { // Eliminate all prompts/guards along the way. ExternalProtocolHandler::PermitLaunchUrl(); - ExternalProtocolHandler::SetBlockState("meow", url_info2_->origin(), - ExternalProtocolHandler::DONT_BLOCK, - profile()); base::test::TestFuture<void> future; web_app::WebAppProvider::GetForWebApps(profile()) ->scheduler()
diff --git a/chrome/build/android-arm32.pgo.txt b/chrome/build/android-arm32.pgo.txt index 19df498..fb5d62e8 100644 --- a/chrome/build/android-arm32.pgo.txt +++ b/chrome/build/android-arm32.pgo.txt
@@ -1 +1 @@ -chrome-android32-main-1758866082-8a235d1b8b489bc36d6266e9b9e820074eac66d6-f6e9c60194c98e19bf0d98a25f997e346965b892.profdata +chrome-android32-main-1758887821-8eff871eb517cf601ff9146ee154e4c494fe9ee7-8f33ed4a83774b89e76819368c55ce9c1830b42f.profdata
diff --git a/chrome/build/android-arm64.pgo.txt b/chrome/build/android-arm64.pgo.txt index 4718ccd8..2b8c4a1f 100644 --- a/chrome/build/android-arm64.pgo.txt +++ b/chrome/build/android-arm64.pgo.txt
@@ -1 +1 @@ -chrome-android64-main-1758849749-5e944251df227dd9fd2a9f28e4b7849ac21ff72a-40536ec79d7b29117543aac3a29c3919a54660bc.profdata +chrome-android64-main-1758878852-4a739e060ae2052cc127c24dfcbbe625ccf6d3d4-4cb457723ca1adc9e010a69e18f3142cd85f3ec8.profdata
diff --git a/chrome/build/android-desktop-x64.pgo.txt b/chrome/build/android-desktop-x64.pgo.txt index 88e656c..936a164 100644 --- a/chrome/build/android-desktop-x64.pgo.txt +++ b/chrome/build/android-desktop-x64.pgo.txt
@@ -1 +1 @@ -chrome-android-desktop-x64-main-1758866082-16e3d2d42334928e6d7f22ff9d9bd3f8842ece15-f6e9c60194c98e19bf0d98a25f997e346965b892.profdata +chrome-android-desktop-x64-main-1758887821-febfc698c9d7c2f08f00a5346944f9a307ecd5b0-8f33ed4a83774b89e76819368c55ce9c1830b42f.profdata
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt index f81c925..4ee2012 100644 --- a/chrome/build/linux.pgo.txt +++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@ -chrome-linux-main-1758823188-05d75ff3bbf3ae7154dd2521ff9cef50fe4046d7-4390848015957f42af7b44583fb3546d877dd0fe.profdata +chrome-linux-main-1758887821-86d46083f409d45f51fb0e3a1f4e5ff85b211d2d-8f33ed4a83774b89e76819368c55ce9c1830b42f.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt index 1332894..ad961c53 100644 --- a/chrome/build/mac-arm.pgo.txt +++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@ -chrome-mac-arm-main-1758866082-cd64dd224d20a46943591037dbc0ffbd76f8790e-f6e9c60194c98e19bf0d98a25f997e346965b892.profdata +chrome-mac-arm-main-1758887821-62ae5e470342e33475155b7843d41e05a8d9a411-8f33ed4a83774b89e76819368c55ce9c1830b42f.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt index 1cfcd9f8..f68a875a 100644 --- a/chrome/build/mac.pgo.txt +++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@ -chrome-mac-main-1758844681-67386715ca4f45612a51d15eca7f405057965522-cb37e57bbc308979e611a16e766617becb7d88ee.profdata +chrome-mac-main-1758866082-6a501898643195544ae9f5e867c8287fe7ae0a0f-f6e9c60194c98e19bf0d98a25f997e346965b892.profdata
diff --git a/chrome/build/win-arm64.pgo.txt b/chrome/build/win-arm64.pgo.txt index 2c5315a..8917a862 100644 --- a/chrome/build/win-arm64.pgo.txt +++ b/chrome/build/win-arm64.pgo.txt
@@ -1 +1 @@ -chrome-win-arm64-main-1758844681-0022566591801490467fae70fc26dafecc01d7c8-cb37e57bbc308979e611a16e766617becb7d88ee.profdata +chrome-win-arm64-main-1758887821-20c09da6739ec79a43fb97f1cf557715eb35244b-8f33ed4a83774b89e76819368c55ce9c1830b42f.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt index 2d4663f..e7393460 100644 --- a/chrome/build/win32.pgo.txt +++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@ -chrome-win32-main-1758855354-6ac655027b571e5cad18939a1c7ffd16babdfa02-ec56c443b711d9d2ece93b672095b6607c54fec5.profdata +chrome-win32-main-1758866082-30f8627a468a722377fd2e8965656d47ee1cbf0a-f6e9c60194c98e19bf0d98a25f997e346965b892.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt index 5ab926b..42ce2ee 100644 --- a/chrome/build/win64.pgo.txt +++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@ -chrome-win64-main-1758833983-68b3e696cecebcdcb767539b3830aec861198962-7499615ba103a5665f1df5180f134e252f987363.profdata +chrome-win64-main-1758866082-c76bdda257d628a8121f0b7a289b8a11ef7b1aa1-f6e9c60194c98e19bf0d98a25f997e346965b892.profdata
diff --git a/chrome/renderer/accessibility/phrase_segmentation/dependency_parser_op_resolver.cc b/chrome/renderer/accessibility/phrase_segmentation/dependency_parser_op_resolver.cc index 623dd12..89ce23d7 100644 --- a/chrome/renderer/accessibility/phrase_segmentation/dependency_parser_op_resolver.cc +++ b/chrome/renderer/accessibility/phrase_segmentation/dependency_parser_op_resolver.cc
@@ -43,12 +43,10 @@ seq_flow_lite::ops::custom::Register_SEQUENCE_STRING_PROJECTION_V2()); #if BUILDFLAG(BUILD_TFLITE_WITH_XNNPACK) - if (optimization_guide::features::TFLiteXNNPACKDelegateEnabled()) { - delegate_creators_.push_back([](TfLiteContext* context) { - return tflite::MaybeCreateXNNPACKDelegate( - context, tflite::XNNPackQS8Options::default_value); - }); - } + delegate_creators_.push_back([](TfLiteContext* context) { + return tflite::MaybeCreateXNNPACKDelegate( + context, tflite::XNNPackQS8Options::default_value); + }); #endif } DependencyParserOpResolver::~DependencyParserOpResolver() = default;
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 33fe0a10..cc0564bf 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -3274,6 +3274,7 @@ "../browser/engagement/site_engagement_helper_browsertest.cc", "../browser/enterprise/browser_management/management_service_browsertest.cc", "../browser/enterprise/incognito/incognito_navigation_throttle_browsertest.cc", + "../browser/enterprise/reporting/extension_request/extension_request_notification_browsertest.cc", "../browser/enterprise/signals/profile_signals_collector_browsertest.cc", "../browser/enterprise/util/managed_browser_utils_browsertest.cc", "../browser/enterprise/watermark/watermark_browsertest.cc", @@ -8058,7 +8059,6 @@ "../browser/download/download_ui_enterprise_util_unittest.cc", "../browser/download/download_warning_desktop_hats_utils_unittest.cc", "../browser/enterprise/reporting/extension_info_unittest.cc", - "../browser/enterprise/reporting/extension_request/extension_request_notification_unittest.cc", "../browser/enterprise/reporting/extension_request/extension_request_observer_factory_unittest.cc", "../browser/enterprise/reporting/extension_request/extension_request_observer_unittest.cc", "../browser/enterprise/reporting/extension_request/extension_request_report_generator_unittest.cc",
diff --git a/chrome/test/data/webui/history/history_ui_browsertest.cc b/chrome/test/data/webui/history/history_ui_browsertest.cc index 627a5408..c37b858 100644 --- a/chrome/test/data/webui/history/history_ui_browsertest.cc +++ b/chrome/test/data/webui/history/history_ui_browsertest.cc
@@ -7,6 +7,7 @@ #include "chrome/test/base/web_ui_mocha_browser_test.h" #include "components/history_clusters/core/features.h" #include "components/history_embeddings/history_embeddings_features.h" +#include "components/sync/base/features.h" #include "content/public/test/browser_test.h" #if BUILDFLAG(IS_CHROMEOS) @@ -50,10 +51,6 @@ RunTest("history/history_routing_with_query_param_test.js", "mocha.run()"); } -IN_PROC_BROWSER_TEST_F(HistoryTest, SyncedTabs) { - RunTest("history/history_synced_tabs_test.js", "mocha.run()"); -} - IN_PROC_BROWSER_TEST_F(HistoryTest, Toolbar) { RunTest("history/history_toolbar_test.js", "mocha.run()"); } @@ -70,6 +67,24 @@ RunTest("history/history_side_bar_footer_test.js", "mocha.run()"); } +// TODO(crbug.com/444617758): Fix the test to work with the feature enabled and +// move it back to HistoryTest. +class HistoryTestWithoutReplaceSyncPromosWithSignInPromos : public HistoryTest { + public: + HistoryTestWithoutReplaceSyncPromosWithSignInPromos() { + scoped_feature_list_.InitAndDisableFeature( + syncer::kReplaceSyncPromosWithSignInPromos); + } + + private: + base::test::ScopedFeatureList scoped_feature_list_; +}; + +IN_PROC_BROWSER_TEST_F(HistoryTestWithoutReplaceSyncPromosWithSignInPromos, + SyncedTabs) { + RunTest("history/history_synced_tabs_test.js", "mocha.run()"); +} + class HistoryListTest : public HistoryUIBrowserTest { protected: void RunTestCase(const std::string& testCase) {
diff --git a/chrome/test/data/webui/settings/other_google_data_dialog_test.ts b/chrome/test/data/webui/settings/other_google_data_dialog_test.ts index 81d07b8..891dcfdb 100644 --- a/chrome/test/data/webui/settings/other_google_data_dialog_test.ts +++ b/chrome/test/data/webui/settings/other_google_data_dialog_test.ts
@@ -233,6 +233,10 @@ const url = await testOpenWindowProxy.whenCalled('openUrl'); assertEquals(loadTimeData.getString('myActivityGeminiAppsUrl'), url); + + assertEquals( + 'Settings.DeleteBrowsingData.GeminiAppsActivityLinkClick', + await testMetricsBrowserProxy.whenCalled('recordAction')); }); test('GeminiAppsActivityVisibility', async function() {
diff --git a/chromeos/ash/components/sync_wifi/wifi_configuration_bridge.cc b/chromeos/ash/components/sync_wifi/wifi_configuration_bridge.cc index aeffddd..a4f3677c9 100644 --- a/chromeos/ash/components/sync_wifi/wifi_configuration_bridge.cc +++ b/chromeos/ash/components/sync_wifi/wifi_configuration_bridge.cc
@@ -297,6 +297,26 @@ .SerializeToString(); } +bool WifiConfigurationBridge::IsEntityDataValid( + const syncer::EntityData& entity_data) const { + const sync_pb::WifiConfigurationSpecifics& specifics = + entity_data.specifics.wifi_configuration(); + if (specifics.hex_ssid().empty()) { + return false; + } + // Only security types PSK and WEP are supported, see + // sync_wifi::SecurityTypeStringFromProto(). + switch (specifics.security_type()) { + case sync_pb::WifiConfigurationSpecifics::SECURITY_TYPE_UNSPECIFIED: + case sync_pb::WifiConfigurationSpecifics::SECURITY_TYPE_NONE: + return false; + case sync_pb::WifiConfigurationSpecifics::SECURITY_TYPE_PSK: + case sync_pb::WifiConfigurationSpecifics::SECURITY_TYPE_WEP: + return true; + } + NOTREACHED(); +} + void WifiConfigurationBridge::ApplyDisableSyncChanges( std::unique_ptr<syncer::MetadataChangeList> delete_metadata_change_list) { // Since bridge and DataTypeStore state represents the synced networks state,
diff --git a/chromeos/ash/components/sync_wifi/wifi_configuration_bridge.h b/chromeos/ash/components/sync_wifi/wifi_configuration_bridge.h index d47e1b9..eba3885 100644 --- a/chromeos/ash/components/sync_wifi/wifi_configuration_bridge.h +++ b/chromeos/ash/components/sync_wifi/wifi_configuration_bridge.h
@@ -85,6 +85,7 @@ const syncer::EntityData& entity_data) const override; std::string GetStorageKey( const syncer::EntityData& entity_data) const override; + bool IsEntityDataValid(const syncer::EntityData& entity_data) const override; void ApplyDisableSyncChanges(std::unique_ptr<syncer::MetadataChangeList> delete_metadata_change_list) override;
diff --git a/components/BUILD.gn b/components/BUILD.gn index fda67ed..16f2d6f5 100644 --- a/components/BUILD.gn +++ b/components/BUILD.gn
@@ -733,7 +733,6 @@ deps += [ "//components/keep_alive_registry:unit_tests", "//components/manta:unit_tests", - "//components/password_manager/core/browser/actor_login/internal:unit_tests", "//components/trusted_vault:unit_tests", ] } @@ -745,6 +744,7 @@ "//components/headless/console_message_logger:unit_tests", "//components/headless/screen_info:unit_tests", "//components/live_caption:unit_tests", + "//components/password_manager/core/browser/actor_login/internal:unit_tests", "//components/soda:unit_tests", "//components/storage_monitor:unit_tests", "//components/web_modal:unit_tests",
diff --git a/components/autofill/core/browser/BUILD.gn b/components/autofill/core/browser/BUILD.gn index a7eca848..e188eba 100644 --- a/components/autofill/core/browser/BUILD.gn +++ b/components/autofill/core/browser/BUILD.gn
@@ -679,6 +679,8 @@ "suggestions/passkeys/hybrid_passkey_availability.h", "suggestions/passkeys/passkey_autofill_suggestion_generator.cc", "suggestions/passkeys/passkey_autofill_suggestion_generator.h", + "suggestions/payments/credit_card_suggestion_generator.cc", + "suggestions/payments/credit_card_suggestion_generator.h", "suggestions/payments/iban_suggestion_generator.cc", "suggestions/payments/iban_suggestion_generator.h", "suggestions/payments/merchant_promo_code_suggestion_generator.cc",
diff --git a/components/autofill/core/browser/autofill_field.cc b/components/autofill/core/browser/autofill_field.cc index 64490a8..a108c098 100644 --- a/components/autofill/core/browser/autofill_field.cc +++ b/components/autofill/core/browser/autofill_field.cc
@@ -21,6 +21,7 @@ #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "base/types/cxx23_to_underlying.h" +#include "components/autofill/core/browser/data_model/data_model_utils.h" #include "components/autofill/core/browser/field_type_utils.h" #include "components/autofill/core/browser/field_types.h" #include "components/autofill/core/browser/heuristic_source.h" @@ -415,6 +416,27 @@ return os << section.ToString(); } +AutofillFormatString::AutofillFormatString() = default; + +AutofillFormatString::AutofillFormatString(std::u16string v, + FormatString_Type type) + : value(std::move(v)), type(type) { + // TODO(crbug.com/446883719): Add a DCHECK that the format is valid. +} + +AutofillFormatString::AutofillFormatString(const AutofillFormatString&) = + default; + +AutofillFormatString& AutofillFormatString::operator=( + const AutofillFormatString&) = default; + +AutofillFormatString::AutofillFormatString(AutofillFormatString&&) = default; + +AutofillFormatString& AutofillFormatString::operator=(AutofillFormatString&&) = + default; + +AutofillFormatString::~AutofillFormatString() = default; + AutofillField::AutofillField() { local_type_predictions_.fill(NO_SERVER_DATA); } @@ -771,16 +793,19 @@ password_requirements_ = std::move(spec); } -base::optional_ref<const std::u16string> AutofillField::format_string() const { +base::optional_ref<const AutofillFormatString> AutofillField::format_string() + const { if (form_control_type() == FormControlType::kInputDate) { - static const base::NoDestructor<std::u16string> kFormat(u"YYYY-MM-DD"); + static const base::NoDestructor<AutofillFormatString> kFormat( + AutofillFormatString(u"YYYY-MM-DD", FormatString_Type_DATE)); return *kFormat; } if (form_control_type() == FormControlType::kInputMonth) { - static const base::NoDestructor<std::u16string> kFormat(u"YYYY-MM"); + static const base::NoDestructor<AutofillFormatString> kFormat( + AutofillFormatString(u"YYYY-MM", FormatString_Type_DATE)); return *kFormat; } - if (format_string_source_ == FormatStringSource::kUnset) { + if (format_string_source_ == AutofillFormatStringSource::kUnset) { return std::nullopt; } return format_string_;
diff --git a/components/autofill/core/browser/autofill_field.h b/components/autofill/core/browser/autofill_field.h index 8b7b3e1..5f480d6 100644 --- a/components/autofill/core/browser/autofill_field.h +++ b/components/autofill/core/browser/autofill_field.h
@@ -121,6 +121,35 @@ LogBuffer& operator<<(LogBuffer& buffer, const Section& section); std::ostream& operator<<(std::ostream& os, const Section& section); +// Describes formatting information for a field. Currently used only for +// filling Autofill AI data. +struct AutofillFormatString final { + AutofillFormatString(); + AutofillFormatString(std::u16string value, FormatString_Type type); + + AutofillFormatString(const AutofillFormatString&); + AutofillFormatString& operator=(const AutofillFormatString&); + AutofillFormatString(AutofillFormatString&&); + AutofillFormatString& operator=(AutofillFormatString&&); + ~AutofillFormatString(); + + // The actual format string. + std::u16string value; + + // Format strings can have different types: They can specify a date + // format, an affix format, etc. See `FormatString_Type` for allowed values. + FormatString_Type type{}; +}; + +// The ordering matters: higher values overrule lower values (e.g., kServer +// overrules kHeuristics). +enum class AutofillFormatStringSource { + kUnset = 0, // No format string set. + kHeuristics = 1, // Set by local heuristics. + kModelResult = 2, // Set by a direct model response + kServer = 3, // Set by an (Autofill) server response. +}; + class AutofillField : public FormFieldData { public: using FieldLogEventType = std::variant<std::monostate, @@ -328,30 +357,23 @@ return password_requirements_; } - // The ordering ordering matters: higher values overrule lower values (e.g., - // kServer overrules kHeuristics). - enum class FormatStringSource { - kUnset = 0, // No format string set. - kHeuristics = 1, // Set by local heuristics. - kModelResult = 2, // Set by a direct model response - kServer = 3, // Set by an (Autofill) server response. - }; - // The format of the value expected by the web document. Currently, the // following kinds of format stings are supported: // - Affix format strings (see data_util::IsValidAffixFormat()). // - Date format strings (data_util::IsValidDateFormat()). + // - Flight number format strings (data_util::IsValidFlightNumberFormat()). // // Only one format string is stored at a time: the one with the - // highest-ranking `FormatStringSource`. - base::optional_ref<const std::u16string> format_string() const LIFETIME_BOUND; + // highest-ranking `AutofillFormatString::Source`. + base::optional_ref<const AutofillFormatString> format_string() const + LIFETIME_BOUND; - FormatStringSource format_string_source() const { + AutofillFormatStringSource format_string_source() const { return format_string_source_; } - void set_format_string_unless_overruled(std::u16string format_string, - FormatStringSource source) { + void set_format_string_unless_overruled(AutofillFormatString format_string, + AutofillFormatStringSource source) { if (format_string_source_ <= source) { format_string_ = std::move(format_string); format_string_source_ = source; @@ -491,8 +513,9 @@ // Corresponds to the requirements determined by the Autofill server. std::optional<PasswordRequirementsSpec> password_requirements_; - std::u16string format_string_; - FormatStringSource format_string_source_ = FormatStringSource::kUnset; + AutofillFormatString format_string_; + AutofillFormatStringSource format_string_source_ = + AutofillFormatStringSource::kUnset; // Predictions which where calculated on the client. This is initialized to // `NO_SERVER_DATA`, which means "NO_DATA", i.e. no classification was
diff --git a/components/autofill/core/browser/crowdsourcing/autofill_crowdsourcing_encoding.cc b/components/autofill/core/browser/crowdsourcing/autofill_crowdsourcing_encoding.cc index e13b806e..1f6b3af93 100644 --- a/components/autofill/core/browser/crowdsourcing/autofill_crowdsourcing_encoding.cc +++ b/components/autofill/core/browser/crowdsourcing/autofill_crowdsourcing_encoding.cc
@@ -1058,9 +1058,11 @@ case FormatString_Type_DATE: case FormatString_Type_FLIGHT_NUMBER: field->set_format_string_unless_overruled( - base::UTF8ToUTF16( - field_suggestion->format_string().format_string()), - AutofillField::FormatStringSource::kServer); + AutofillFormatString( + base::UTF8ToUTF16( + field_suggestion->format_string().format_string()), + field_suggestion->format_string().type()), + AutofillFormatStringSource::kServer); break; } }
diff --git a/components/autofill/core/browser/crowdsourcing/determine_possible_field_types.cc b/components/autofill/core/browser/crowdsourcing/determine_possible_field_types.cc index c86a6d6..1211d5f 100644 --- a/components/autofill/core/browser/crowdsourcing/determine_possible_field_types.cc +++ b/components/autofill/core/browser/crowdsourcing/determine_possible_field_types.cc
@@ -13,6 +13,7 @@ #include "base/containers/flat_set.h" #include "base/containers/span.h" #include "base/containers/to_vector.h" +#include "base/feature_list.h" #include "base/metrics/histogram_functions.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_split.h" @@ -280,7 +281,8 @@ for (const AttributeInstance& attribute : entity.attributes()) { for (const FieldType field_type : attribute.type().field_subtypes()) { const std::u16string& value_on_file = - attribute.GetInfo(field_type, app_locale, std::nullopt); + normalization::NormalizeForComparison( + attribute.GetInfo(field_type, app_locale, std::nullopt)); // Test if `value_in_field` and `value_on_file` match. bool full_match = @@ -292,6 +294,11 @@ features::kAutofillAiVoteForFormatStringsForAffixes)) { pt.formats.emplace(FormatString_Type_AFFIX, u"0"); } + if (field_type == FLIGHT_RESERVATION_FLIGHT_NUMBER && + base::FeatureList::IsEnabled( + features::kAutofillAiVoteForFormatStringsForFlightNumbers)) { + pt.formats.emplace(FormatString_Type_FLIGHT_NUMBER, u"F"); + } } // Test if `value_in_field` is an affix of `value_on_file`. @@ -316,6 +323,20 @@ -1 * static_cast<int>(value_in_field.size()))); } } + + if (field_type == FLIGHT_RESERVATION_FLIGHT_NUMBER && + base::FeatureList::IsEnabled( + features::kAutofillAiVoteForFormatStringsForFlightNumbers)) { + if (value_in_field.size() == 2 && + value_on_file.starts_with(value_in_field)) { + pt.types.insert(field_type); + pt.formats.emplace(FormatString_Type_FLIGHT_NUMBER, u"A"); + } else if (value_on_file.size() > 3 && + value_on_file.substr(2) == value_in_field) { + pt.types.insert(field_type); + pt.formats.emplace(FormatString_Type_FLIGHT_NUMBER, u"N"); + } + } } } }
diff --git a/components/autofill/core/browser/crowdsourcing/determine_possible_field_types_unittest.cc b/components/autofill/core/browser/crowdsourcing/determine_possible_field_types_unittest.cc index 402a17f..4b3275f 100644 --- a/components/autofill/core/browser/crowdsourcing/determine_possible_field_types_unittest.cc +++ b/components/autofill/core/browser/crowdsourcing/determine_possible_field_types_unittest.cc
@@ -23,6 +23,7 @@ #include "components/autofill/core/common/autofill_features.h" #include "components/autofill/core/common/autofill_test_utils.h" #include "components/autofill/core/common/form_data_test_api.h" +#include "components/autofill/core/common/form_field_data.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -89,21 +90,26 @@ // Matcher for `PossibleTypes::formats`. template <typename... Ts> requires(std::convertible_to<Ts, const char*> && ...) -Matcher<const PossibleTypes&> HasAffixFormats(Ts&&... formats) { +Matcher<const PossibleTypes&> HasFormats(FormatString_Type type, + Ts&&... formats) { return Field("PossibleTypes::formats", &PossibleTypes::formats, - UnorderedElementsAre( - Pair(FormatString_Type_AFFIX, - base::UTF8ToUTF16(std::string_view(formats)))...)); + UnorderedElementsAre(Pair( + type, base::UTF8ToUTF16(std::string_view(formats)))...)); } -// Matcher for `PossibleTypes::formats`. template <typename... Ts> - requires(std::convertible_to<Ts, const char*> && ...) +Matcher<const PossibleTypes&> HasAffixFormats(Ts&&... formats) { + return HasFormats(FormatString_Type_AFFIX, formats...); +} + +template <typename... Ts> Matcher<const PossibleTypes&> HasDateFormats(Ts&&... formats) { - return Field("PossibleTypes::formats", &PossibleTypes::formats, - UnorderedElementsAre( - Pair(FormatString_Type_DATE, - base::UTF8ToUTF16(std::string_view(formats)))...)); + return HasFormats(FormatString_Type_DATE, formats...); +} + +template <typename... Ts> +Matcher<const PossibleTypes&> HasFlightNumberFormats(Ts&&... formats) { + return HasFormats(FormatString_Type_FLIGHT_NUMBER, formats...); } // Fakes that a `form` has been seen (without its field value) and parsed and @@ -414,6 +420,7 @@ scoped_feature_list_.InitWithFeatures( {features::kAutofillAiWithDataSchema, features::kAutofillAiVoteForFormatStringsForAffixes, + features::kAutofillAiVoteForFormatStringsForFlightNumbers, features::kAutofillEnableLoyaltyCardsFilling}, {}); } @@ -807,6 +814,13 @@ FormControlType::kInputText), CreateTestFormField("issue", "issue-year", "2010", FormControlType::kInputText), + // Flight number. + CreateTestFormField("airline", "airline", "LH", + FormControlType::kInputText), + CreateTestFormField("number", "number", "93", + FormControlType::kInputText), + CreateTestFormField("flight number", "flight number", "LH93", + FormControlType::kInputText), // No format string. CreateTestFormField("wrong-country", "wrong-country", "Finland", FormControlType::kInputText), @@ -814,7 +828,7 @@ std::unique_ptr<FormStructure> form_structure = ConstructFormStructureFromFormData(form); - EntityInstance entity = test::GetPassportEntityInstance({ + const EntityInstance passport_entity = test::GetPassportEntityInstance({ .name = u"Pippi Longstocking", .number = u"0123456789", .country = u"Sweden", @@ -822,10 +836,13 @@ .issue_date = u"2010-09-01", }); + const EntityInstance flight_entity = + test::GetFlightReservationEntityInstance({.flight_number = u"LH93"}); + EXPECT_THAT( DeterminePossibleFieldTypesForUpload( std::vector<AutofillProfile>(), std::vector<CreditCard>(), - base::span_from_ref(entity), std::vector<LoyaltyCard>(), + {passport_entity, flight_entity}, std::vector<LoyaltyCard>(), /*fields_that_match_state=*/{}, /*last_unlocked_credit_card_cvc=*/u"", "en-US", form_structure->fields()), @@ -843,6 +860,12 @@ AllOf(HasTypes(PASSPORT_ISSUE_DATE), HasDateFormats("DD", "MM")), AllOf(HasTypes(PASSPORT_ISSUE_DATE), HasDateFormats("DD", "MM")), AllOf(HasTypes(PASSPORT_ISSUE_DATE), HasDateFormats("YYYY")), + AllOf(HasTypes(FLIGHT_RESERVATION_FLIGHT_NUMBER), + HasFlightNumberFormats("A")), + AllOf(HasTypes(FLIGHT_RESERVATION_FLIGHT_NUMBER), + HasFlightNumberFormats("N")), + AllOf(HasTypes(FLIGHT_RESERVATION_FLIGHT_NUMBER), + HasFlightNumberFormats("F")), AllOf(HasTypes(UNKNOWN_TYPE), HasNoFormats()))); }
diff --git a/components/autofill/core/browser/data_manager/addresses/account_name_email_store.cc b/components/autofill/core/browser/data_manager/addresses/account_name_email_store.cc index 022a5fbb..5a2ece26 100644 --- a/components/autofill/core/browser/data_manager/addresses/account_name_email_store.cc +++ b/components/autofill/core/browser/data_manager/addresses/account_name_email_store.cc
@@ -14,7 +14,9 @@ #include "components/signin/public/base/consent_level.h" #include "components/signin/public/identity_manager/account_info.h" #include "components/signin/public/identity_manager/identity_manager.h" +#include "components/sync/base/user_selectable_type.h" #include "components/sync/service/sync_service.h" +#include "components/sync/service/sync_user_settings.h" namespace autofill { @@ -55,7 +57,7 @@ (!primary_info->IsEmpty() && info.gaia != primary_info->gaia)) { return; } - UpdateOrCreateAccountNameEmail(info); + MaybeUpdateOrCreateAccountNameEmail(); } void AccountNameEmailStore::OnSyncShutdown(syncer::SyncService*) { @@ -64,6 +66,48 @@ NOTREACHED(); } +void AccountNameEmailStore::OnStateChanged(syncer::SyncService* sync_service) { + // Only autofill syncing users are eligible for the kAccountNameEmail + // profile. Having all relevant data loaded is crucial for correct execution. + // If the user doesn't have the autofill sync toggle enabled, try to remove + // the kAccountNameEmail profile. + std::optional<ProfileUpdateBlockReason> reason = + GetBlockAccountNameEmailUpdateReason(); + if (!reason.has_value()) { + MaybeUpdateOrCreateAccountNameEmail(); + return; + } + switch (reason.value()) { + case ProfileUpdateBlockReason::kSyncOff: + RemoveAccountNameEmail(); + return; + case ProfileUpdateBlockReason::kDataNotLoaded: + // Defer call. When data is loaded, `OnStateChanged` will be called again, + // reattempting to create the profile. + return; + } +} + +void AccountNameEmailStore::MaybeUpdateOrCreateAccountNameEmail() { + if (GetBlockAccountNameEmailUpdateReason().has_value()) { + return; + } + + const std::optional<CoreAccountInfo>& core_info = + identity_manager_->GetPrimaryAccountInfo(signin::ConsentLevel::kSignin); + if (!core_info.has_value()) { + return; + } + + const std::optional<AccountInfo>& extended_info = + identity_manager_->FindExtendedAccountInfo(core_info.value()); + if (!extended_info.has_value()) { + return; + } + + UpdateOrCreateAccountNameEmail(extended_info.value()); +} + void AccountNameEmailStore::OnAddressDataChanged() { if (pref_service_->GetInteger( prefs::kAutofillNameAndEmailProfileNotSelectedCounter) > @@ -89,11 +133,23 @@ } } +void AccountNameEmailStore::RemoveAccountNameEmail() { + const std::vector<const AutofillProfile*> account_name_email_profiles = + address_data_manager_->GetProfilesByRecordType( + AutofillProfile::RecordType::kAccountNameEmail); + if (account_name_email_profiles.empty()) { + return; + } + CHECK_EQ(1u, account_name_email_profiles.size()); + + address_data_manager_->RemoveProfile(account_name_email_profiles[0]->guid()); +} + void AccountNameEmailStore::UpdateOrCreateAccountNameEmail( const AccountInfo& info) { // During signin the `OnExtendedAccountInfoUpdated` method might call this // method with an empty `info.full_name` since not all data arrives all at - // once and `AccountiInfo` is updated multiple times. The `kAccountNameEmail` + // once and `AccountInfo` is updated multiple times. The `kAccountNameEmail` // profile and hash signature require non-empty `full_name` value. if (info.IsEmpty() || info.full_name.empty()) { return; @@ -132,22 +188,33 @@ prefs::kAutofillNameAndEmailProfileNotSelectedCounter, 0); } -void AccountNameEmailStore::RemoveAccountNameEmail() { - const std::vector<const AutofillProfile*> account_name_email_profiles = - address_data_manager_->GetProfilesByRecordType( - AutofillProfile::RecordType::kAccountNameEmail); - if (account_name_email_profiles.empty()) { - return; - } - CHECK_EQ(1u, account_name_email_profiles.size()); - - address_data_manager_->RemoveProfile(account_name_email_profiles[0]->guid()); -} - std::string AccountNameEmailStore::HashAccountInfo( const AccountInfo& info) const { return base::NumberToString(base::PersistentHash( base::StrCat({info.full_name, kSeparator, info.email}))); } +std::optional<AccountNameEmailStore::ProfileUpdateBlockReason> +AccountNameEmailStore::GetBlockAccountNameEmailUpdateReason() { + if (!sync_service_->GetUserSettings()->GetSelectedTypes().Has( + syncer::UserSelectableType::kAutofill)) { + return ProfileUpdateBlockReason::kSyncOff; + } + + if (address_data_manager_->IsAwaitingPendingAddressChanges()) { + return ProfileUpdateBlockReason::kDataNotLoaded; + } + + switch (sync_service_->GetDownloadStatusFor( + syncer::DataType::PRIORITY_PREFERENCES)) { + case syncer::SyncService::DataTypeDownloadStatus::kWaitingForUpdates: + return ProfileUpdateBlockReason::kDataNotLoaded; + case syncer::SyncService::DataTypeDownloadStatus::kUpToDate: + // If the download status is kError, it will likely not become + // available anytime soon. + case syncer::SyncService::DataTypeDownloadStatus::kError: + return std::nullopt; + } +} + } // namespace autofill
diff --git a/components/autofill/core/browser/data_manager/addresses/account_name_email_store.h b/components/autofill/core/browser/data_manager/addresses/account_name_email_store.h index 5b22518..1a0c4c29 100644 --- a/components/autofill/core/browser/data_manager/addresses/account_name_email_store.h +++ b/components/autofill/core/browser/data_manager/addresses/account_name_email_store.h
@@ -17,19 +17,22 @@ namespace autofill { // The kAccountNameEmail autofill profile is an un-syncable, locally stored, -// profile generated automatically for every signed in user, unless they deleted -// it or didn't use it. This profile is composed of 2 pieces of data: +// profile generated automatically for the every signed in user with the +// Autofill sync toggle enabled, unless they have deleted it or have not used +// it. +// +// This profile is composed of 2 pieces of data: // - full name // - email +// `kLegacyHierarchyCountryCode` is used to not reveal the country of this +// profile. +// // Keeping kAccountNameEmail profile's state up to date between the devices is -// handled through syncable prefs. `AccountNameEmailStore` is a class +// handled through priority prefs. `AccountNameEmailStore` is a class // responsible for accessing and modifying those prefs, as well as managing // (create, update, remove) kAccountNameEmail profile. In code // `AccountNameEmailStore` is owned by and has the same lifetime as // `AddressDataManager`. -// TODO(441657422): `AccountNameEmailStrikeManager` should notify this class if -// a suggestion with kAccountNameEmail profile was showed and whether it was -// accepted. class AccountNameEmailStore : public signin::IdentityManager::Observer, public AddressDataManager::Observer, public syncer::SyncServiceObserver { @@ -49,6 +52,12 @@ // syncer::SyncServiceObserver: void OnSyncShutdown(syncer::SyncService* sync) override; + void OnStateChanged(syncer::SyncService* sync_service) override; + + // Checks that the necessary data is available and that the user has enabled + // autofill sync before updating/creating the kAccountNameEmail profile. + // This prevents premature update/create without all of the relevant data. + void MaybeUpdateOrCreateAccountNameEmail(); // AddressDataManager::Observer: // Called when the address data of the `AddressDataManager` changes. If @@ -57,20 +66,32 @@ // `kAutofillNameAndEmailProfileNotSelectedThreshold` + 1. void OnAddressDataChanged() override; - // Updates the `kAccountNameEmail` autofill profile with the newest signed-in - // account `info`. If the `kAccountNameEmail` profile doesn't exist, it is - // created. - void UpdateOrCreateAccountNameEmail(const AccountInfo& info); - // Removes the `kAccountNameEmail` autofill profile if it exists. void RemoveAccountNameEmail(); private: friend class AccountNameEmailStoreTestApi; + enum class ProfileUpdateBlockReason { + kSyncOff = 0, + kDataNotLoaded = 1, + }; + + // Updates the kAccountNameEmail autofill profile with the account `info`. If + // the kAccountNameEmail profile doesn't exist, it is created. + void UpdateOrCreateAccountNameEmail(const AccountInfo& info); + // Hashes concatenated full_name and email_address delimited by |. std::string HashAccountInfo(const AccountInfo& info) const; + // Determines if the conditions for creating or updating the kAccountNameEmail + // profile are not met. The operation should be blocked if sync is disabled + // for Autofill or if sync is enabled but the necessary data has not yet been + // downloaded. + // Returns a blocking reason or nullopt if the operation shouldn't be blocked. + std::optional<ProfileUpdateBlockReason> + GetBlockAccountNameEmailUpdateReason(); + const raw_ref<AddressDataManager> address_data_manager_; const raw_ref<signin::IdentityManager> identity_manager_; const raw_ref<syncer::SyncService> sync_service_;
diff --git a/components/autofill/core/browser/data_manager/addresses/account_name_email_store_unittest.cc b/components/autofill/core/browser/data_manager/addresses/account_name_email_store_unittest.cc index b1bc134a..5a1be1b 100644 --- a/components/autofill/core/browser/data_manager/addresses/account_name_email_store_unittest.cc +++ b/components/autofill/core/browser/data_manager/addresses/account_name_email_store_unittest.cc
@@ -85,6 +85,7 @@ signin::IdentityTestEnvironment& identity_test_env() { return identity_test_env_; } + syncer::TestSyncService& sync_service() { return sync_service_; } private: base::test::ScopedFeatureList feature_{ @@ -109,51 +110,80 @@ } // Tests that a new `kAccountNameEmail` profile isn't created when an empty -// `AccountInfo` is passed into the `UpdateOrCreateAccountNameEmail` method. +// `AccountInfo` is passed into the `MaybeUpdateOrCreateAccountNameEmail` +// method. TEST_F(AccountNameEmailStoreTest, EmptyAccountInfoCreation) { - account_name_email_store().UpdateOrCreateAccountNameEmail({}); + account_name_email_store().MaybeUpdateOrCreateAccountNameEmail(); EXPECT_THAT(address_data_manager().GetProfiles(), IsEmpty()); } -// Tests that a new `kAccountNameEmail` profile isn't created when the -// `full_name` field of passed in `AccountInfo` is empty. +// Tests that a new kAccountNameEmail profile isn't created when the account +// info misses the full_name. TEST_F(AccountNameEmailStoreTest, EmptyAccountNameCreation) { - AccountInfo info; - info.email = kTestEmailAddress1; - account_name_email_store().UpdateOrCreateAccountNameEmail(info); + CreatePrimaryAccount(std::string(), kTestEmailAddress1); EXPECT_THAT(address_data_manager().GetProfiles(), IsEmpty()); } -// Tests that the `UpdateOrCreateAccountNameEmail` method creates / updates -// `kAccountNameEmail` with the correct info. +// Tests that a new kAccountNameEmail profile isn't created when autofill is not +// synced. +TEST_F(AccountNameEmailStoreTest, AutofillNotSynced) { + sync_service().SetSignedOut(); + CreatePrimaryAccount(kTestName1, kTestEmailAddress1); + EXPECT_THAT(address_data_manager().GetProfiles(), IsEmpty()); +} + +// Tests that a new kAccountNameEmail profile is removed if user disabled +// autofill sync toggle. +TEST_F(AccountNameEmailStoreTest, ProfileRemovedAfterSyncOff) { + CreatePrimaryAccount(kTestName1, kTestEmailAddress1); + + ASSERT_THAT(address_data_manager().GetProfiles(), + ElementsAre(IsCorrectAccountNameEmail( + base::UTF8ToUTF16(kTestName1), + base::UTF8ToUTF16(kTestEmailAddress1)))); + + syncer::UserSelectableTypeSet selected_sync_types = + sync_service().GetUserSettings()->GetSelectedTypes(); + selected_sync_types.Remove(syncer::UserSelectableType::kAutofill); + sync_service().GetUserSettings()->SetSelectedTypes( + /*sync_everything=*/false, selected_sync_types); + sync_service().FireStateChanged(); + + EXPECT_THAT(address_data_manager().GetProfiles(), IsEmpty()); +} + +TEST_F(AccountNameEmailStoreTest, ProfileNotCreatedBeforeDataLoaded) { + sync_service().SetDownloadStatusFor( + {syncer::DataType::PRIORITY_PREFERENCES}, + syncer::SyncService::DataTypeDownloadStatus::kWaitingForUpdates); + + CreatePrimaryAccount(kTestName1, kTestEmailAddress1); + EXPECT_THAT(address_data_manager().GetProfiles(), IsEmpty()); +} + +// Tests that the created profile holds the correct data. TEST_F(AccountNameEmailStoreTest, SpecificInfoCreationUpdate) { - AccountInfo info; - info.full_name = kTestName1; - info.email = kTestEmailAddress1; - - account_name_email_store().UpdateOrCreateAccountNameEmail(info); - + CreatePrimaryAccount(kTestName1, kTestEmailAddress1); EXPECT_THAT(address_data_manager().GetProfiles(), ElementsAre(IsCorrectAccountNameEmail( base::UTF8ToUTF16(kTestName1), base::UTF8ToUTF16(kTestEmailAddress1)))); } -// Tests that the `UpdateOrCreateAccountNameEmail` correctly updates the +// Tests that the creating the profile correctly updates the // `kAutofillNameAndEmailProfileSignature` pref. TEST_F(AccountNameEmailStoreTest, HashPrefSaving) { - AccountInfo info; - info.full_name = kTestName1; - info.email = kTestEmailAddress1; - account_name_email_store().UpdateOrCreateAccountNameEmail(info); + CreatePrimaryAccount(kTestName1, kTestEmailAddress1); EXPECT_EQ( pref_service().GetString(prefs::kAutofillNameAndEmailProfileSignature), - test_api(&account_name_email_store()).HashAccountInfo(info)); + test_api(&account_name_email_store()) + .HashAccountInfo(identity_manager().FindExtendedAccountInfo( + identity_manager().GetPrimaryAccountInfo( + signin::ConsentLevel::kSignin)))); } -// Tests that the `UpdateOrCreateAccountNameEmail` returns early (does nothing) -// when account info with the same hash as the stored one in pref was passed in. +// Tests that no new profile is created if hashes match. TEST_F(AccountNameEmailStoreTest, EarlyReturnWhenHashesAreEqual) { AccountInfo info; info.full_name = kTestName1; @@ -163,31 +193,23 @@ test_api(&account_name_email_store()).HashAccountInfo(info); pref_service().SetString(prefs::kAutofillNameAndEmailProfileSignature, hash); - account_name_email_store().UpdateOrCreateAccountNameEmail(info); + // Start profile creation after the hash is already set to the right value. + CreatePrimaryAccount(kTestName1, kTestEmailAddress1); EXPECT_EQ(hash, pref_service().GetString( prefs::kAutofillNameAndEmailProfileSignature)); + EXPECT_THAT(address_data_manager().GetProfiles(), IsEmpty()); } -// Tests that the `UpdateOrCreateAccountNameEmail` removes the Account Name -// Email profile when updating. +// Tests that old profile is removed when new primary account is used. TEST_F(AccountNameEmailStoreTest, RemovingProfile) { - AccountInfo info1; - info1.full_name = kTestName1; - info1.email = kTestEmailAddress1; + CreatePrimaryAccount(kTestName1, kTestEmailAddress1); + CreatePrimaryAccount(kTestName2, kTestEmailAddress2); - AccountInfo info2; - info2.full_name = kTestName2; - info2.email = kTestEmailAddress2; - - account_name_email_store().UpdateOrCreateAccountNameEmail(info1); - account_name_email_store().UpdateOrCreateAccountNameEmail(info2); - - EXPECT_THAT( - address_data_manager().GetProfiles(), - Contains(IsCorrectAccountNameEmail(base::UTF8ToUTF16(kTestName1), - base::UTF8ToUTF16(kTestEmailAddress1))) - .Times(0)); + EXPECT_THAT(address_data_manager().GetProfiles(), + ElementsAre(IsCorrectAccountNameEmail( + base::UTF8ToUTF16(kTestName2), + base::UTF8ToUTF16(kTestEmailAddress2)))); } // Tests that the `OnExtendedAccountInfoUpdated` method will create the
diff --git a/components/autofill/core/browser/data_manager/addresses/account_name_email_strike_manager.cc b/components/autofill/core/browser/data_manager/addresses/account_name_email_strike_manager.cc index 61adadc..5910ddd4 100644 --- a/components/autofill/core/browser/data_manager/addresses/account_name_email_strike_manager.cc +++ b/components/autofill/core/browser/data_manager/addresses/account_name_email_strike_manager.cc
@@ -6,10 +6,13 @@ #include <algorithm> +#include "base/feature_list.h" #include "components/autofill/core/browser/data_manager/personal_data_manager.h" #include "components/autofill/core/browser/data_model/addresses/autofill_profile.h" #include "components/autofill/core/browser/suggestions/addresses/address_suggestion_generator.h" #include "components/autofill/core/browser/suggestions/suggestion.h" +#include "components/autofill/core/common/autofill_prefs.h" +#include "components/prefs/pref_service.h" namespace autofill { @@ -20,8 +23,26 @@ } AccountNameEmailStrikeManager::~AccountNameEmailStrikeManager() { - // TODO(crbug.com/356845298): Use the recorded members to set prefs correctly - // in `AccountNameEmailStore`. + PrefService* pref_service = client_->GetPrefs(); + if (!pref_service || !was_name_email_profile_suggestion_shown_) { + return; + } + if (pref_service->GetBoolean(prefs::kAutofillWasNameAndEmailProfileUsed)) { + return; + } + + if (was_name_email_profile_filled_) { + pref_service->SetBoolean(prefs::kAutofillWasNameAndEmailProfileUsed, true); + return; + } + + // TODO(crbug.com/356845298): React to the pref changes in + // `AccountNameEmailStore` and possibly delete the profile. + pref_service->SetInteger( + prefs::kAutofillNameAndEmailProfileNotSelectedCounter, + pref_service->GetInteger( + prefs::kAutofillNameAndEmailProfileNotSelectedCounter) + + 1); } void AccountNameEmailStrikeManager::OnSuggestionsShown(
diff --git a/components/autofill/core/browser/data_manager/addresses/account_name_email_strike_manager.h b/components/autofill/core/browser/data_manager/addresses/account_name_email_strike_manager.h index a991374..a6333fa 100644 --- a/components/autofill/core/browser/data_manager/addresses/account_name_email_strike_manager.h +++ b/components/autofill/core/browser/data_manager/addresses/account_name_email_strike_manager.h
@@ -12,9 +12,10 @@ // This class is responsible for reacting to suggestions that are offered and // filled with `kAccountNameEmail` profiles. On destruction (i.e. navigation) -// it may notify the `AccountNameEmailStore`, if the suggestion with -// kAccountNameEmail profile was showed and whether it was filled. -// Owned by the `BrowserAutofillManger`, destroyed and recreated on navigation. +// it will record prefs related to the ussage of those suggestions (if the +// suggestion with kAccountNameEmail profile was showed and whether it was +// filled). Owned by the `BrowserAutofillManger`, destroyed and recreated on +// navigation. class AccountNameEmailStrikeManager : AutofillManager::Observer { public: explicit AccountNameEmailStrikeManager(AutofillManager& autofill_manager); @@ -37,7 +38,7 @@ private: friend class AccountNameEmailStrikeManagerTestApi; - base::raw_ref<const AutofillClient> client_; + base::raw_ref<AutofillClient> client_; bool was_name_email_profile_suggestion_shown_ = false; bool was_name_email_profile_filled_ = false;
diff --git a/components/autofill/core/browser/data_manager/addresses/account_name_email_strike_manager_unittests.cc b/components/autofill/core/browser/data_manager/addresses/account_name_email_strike_manager_unittests.cc index 911ba52..3ba0992d 100644 --- a/components/autofill/core/browser/data_manager/addresses/account_name_email_strike_manager_unittests.cc +++ b/components/autofill/core/browser/data_manager/addresses/account_name_email_strike_manager_unittests.cc
@@ -78,6 +78,15 @@ FormData(), FieldGlobalId(), base::DoNothing()); EXPECT_FALSE(test_api(GetAccountNameEmailStrikeManager()) .was_name_email_profile_suggestion_shown()); + EXPECT_FALSE(test_api(GetAccountNameEmailStrikeManager()) + .was_name_email_profile_filled()); + + autofill_manager().Reset(); + EXPECT_EQ(autofill_client().GetPrefs()->GetInteger( + prefs::kAutofillNameAndEmailProfileNotSelectedCounter), + 0); + EXPECT_FALSE(autofill_client().GetPrefs()->GetBoolean( + prefs::kAutofillWasNameAndEmailProfileUsed)); } TEST_F(AccountNameEmailStrikeManagerTest, @@ -90,6 +99,13 @@ .was_name_email_profile_suggestion_shown()); EXPECT_FALSE(test_api(GetAccountNameEmailStrikeManager()) .was_name_email_profile_filled()); + + autofill_manager().Reset(); + EXPECT_EQ(autofill_client().GetPrefs()->GetInteger( + prefs::kAutofillNameAndEmailProfileNotSelectedCounter), + 1); + EXPECT_FALSE(autofill_client().GetPrefs()->GetBoolean( + prefs::kAutofillWasNameAndEmailProfileUsed)); } TEST_F(AccountNameEmailStrikeManagerTest, @@ -108,6 +124,13 @@ .was_name_email_profile_suggestion_shown()); EXPECT_FALSE(test_api(GetAccountNameEmailStrikeManager()) .was_name_email_profile_filled()); + + autofill_manager().Reset(); + EXPECT_EQ(autofill_client().GetPrefs()->GetInteger( + prefs::kAutofillNameAndEmailProfileNotSelectedCounter), + 1); + EXPECT_FALSE(autofill_client().GetPrefs()->GetBoolean( + prefs::kAutofillWasNameAndEmailProfileUsed)); } TEST_F(AccountNameEmailStrikeManagerTest, @@ -126,6 +149,13 @@ .was_name_email_profile_suggestion_shown()); EXPECT_TRUE(test_api(GetAccountNameEmailStrikeManager()) .was_name_email_profile_filled()); + + autofill_manager().Reset(); + EXPECT_EQ(autofill_client().GetPrefs()->GetInteger( + prefs::kAutofillNameAndEmailProfileNotSelectedCounter), + 0); + EXPECT_TRUE(autofill_client().GetPrefs()->GetBoolean( + prefs::kAutofillWasNameAndEmailProfileUsed)); } TEST_F(AccountNameEmailStrikeManagerTest, @@ -148,6 +178,13 @@ .was_name_email_profile_suggestion_shown()); EXPECT_FALSE(test_api(GetAccountNameEmailStrikeManager()) .was_name_email_profile_filled()); + + autofill_manager().Reset(); + EXPECT_EQ(autofill_client().GetPrefs()->GetInteger( + prefs::kAutofillNameAndEmailProfileNotSelectedCounter), + 1); + EXPECT_FALSE(autofill_client().GetPrefs()->GetBoolean( + prefs::kAutofillWasNameAndEmailProfileUsed)); } } // namespace
diff --git a/components/autofill/core/browser/data_manager/addresses/address_data_manager.cc b/components/autofill/core/browser/data_manager/addresses/address_data_manager.cc index c2e38f5..4eea3d33 100644 --- a/components/autofill/core/browser/data_manager/addresses/address_data_manager.cc +++ b/components/autofill/core/browser/data_manager/addresses/address_data_manager.cc
@@ -9,6 +9,7 @@ #include <memory> #include "base/check_deref.h" +#include "base/check_is_test.h" #include "base/check_op.h" #include "base/containers/contains.h" #include "base/containers/to_vector.h" @@ -178,21 +179,17 @@ if (!has_initial_load_finished_) { has_initial_load_finished_ = true; - // `UpdateOrCreateAccountNameEmail()` is responsible for creating or - // updating the `kAccountNameEmail` profile. This requires profiles from the - // database to be loaded, so any old `kAccountNameEmail` profile can be - // accessed. Updates to the account info are generally caught by an identity - // observer. But if the account info becomes available before the initial - // load has finished, the additional call here is necessary to apply these - // updates. + // `AccountNameEmailStore::MaybeUpdateOrCreateAccountNameEmail()` is + // responsible for creating or updating the `kAccountNameEmail` profile. + // This requires profiles from the database to be loaded, so any old + // `kAccountNameEmail` profile can be accessed. Updates to the account info + // are generally caught by an identity observer. But if the account info + // becomes available before the initial load has finished, the additional + // call here is necessary to apply these updates. // TODO(crbug.com/356845298): Clean up after launch. if (base::FeatureList::IsEnabled( features::kAutofillEnableSupportForNameAndEmail)) { - const std::optional<CoreAccountInfo>& core_info = GetPrimaryAccountInfo(); - if (core_info.has_value()) { - account_name_email_store_->UpdateOrCreateAccountNameEmail( - identity_manager_->FindExtendedAccountInfo(core_info.value())); - } + account_name_email_store_->MaybeUpdateOrCreateAccountNameEmail(); } else { // In case the feature got disabled the profile should be cleaned up. if (!GetProfilesByRecordType( @@ -237,7 +234,47 @@ if (!IsAutofillProfileEnabled()) { return {}; } - return GetProfiles(ProfileOrder::kHighestFrecencyDesc); + + std::vector<const AutofillProfile*> profiles = + GetProfiles(ProfileOrder::kHighestFrecencyDesc); + + // If the `pref_service_` doesn't exits the special logic which depends on + // prefs shouldn't run. + if (!pref_service_) { + CHECK_IS_TEST(); + return profiles; + } + + if (!base::FeatureList::IsEnabled( + features::kAutofillEnableSupportForNameAndEmail)) { + return profiles; + } + + // `prefs::kAutofillNameAndEmailProfileNotSelectedCounter` counts how many + // times the suggestion for kAccountNameEmail profile was shown and wasn't + // accepted. + // TODO(crbug.com/441657423): If the profile was accepted, the counter will + // remain 0, yet the profile should be moved to the end. This will be fixed + // once a pref indicating the acceptance is added. + const bool name_email_profile_suggestion_was_shown_before = + pref_service_->GetInteger( + prefs::kAutofillNameAndEmailProfileNotSelectedCounter) == 0; + // Move the kAccountNameEmail profile to the front (or back) depending on + // the `name_email_profile_suggestion_was_shown_before`. + std::ranges::stable_partition( + profiles, [name_email_profile_suggestion_was_shown_before]( + const AutofillProfile* p) { + bool is_name_email_profile = + p->record_type() == AutofillProfile::RecordType::kAccountNameEmail; + // stable_partition() moves all elements where the predicate returns + // true to the front. The name/email profile should be in front when + // it hasn't been used before and in the back otherwise. + return name_email_profile_suggestion_was_shown_before + ? is_name_email_profile + : !is_name_email_profile; + }); + + return profiles; } std::vector<const AutofillProfile*> AddressDataManager::GetProfilesForSettings()
diff --git a/components/autofill/core/browser/data_manager/addresses/address_data_manager.h b/components/autofill/core/browser/data_manager/addresses/address_data_manager.h index db97455..0679cdf 100644 --- a/components/autofill/core/browser/data_manager/addresses/address_data_manager.h +++ b/components/autofill/core/browser/data_manager/addresses/address_data_manager.h
@@ -131,6 +131,8 @@ // Returns the profiles to suggest to the user for filling, ordered by // frecency. + // If kAccountNameEmail is present in `profiles_`, it is always moved to the + // end of the vector unless this is the first time it is suggested. std::vector<const AutofillProfile*> GetProfilesToSuggest() const; // Returns all `GetProfiles()` in the order that the should be shown in the
diff --git a/components/autofill/core/browser/data_manager/addresses/address_data_manager_unittest.cc b/components/autofill/core/browser/data_manager/addresses/address_data_manager_unittest.cc index 8537bf6..3cfae880 100644 --- a/components/autofill/core/browser/data_manager/addresses/address_data_manager_unittest.cc +++ b/components/autofill/core/browser/data_manager/addresses/address_data_manager_unittest.cc
@@ -14,6 +14,7 @@ #include "base/test/gmock_callback_support.h" #include "base/test/scoped_feature_list.h" #include "base/test/task_environment.h" +#include "base/time/time.h" #include "base/uuid.h" #include "build/buildflag.h" #include "components/autofill/core/browser/data_manager/personal_data_manager_test_utils.h" @@ -21,6 +22,7 @@ #include "components/autofill/core/browser/data_model/addresses/autofill_profile_test_api.h" #include "components/autofill/core/browser/data_quality/addresses/profile_token_quality_test_api.h" #include "components/autofill/core/browser/test_utils/autofill_test_utils.h" +#include "components/autofill/core/browser/test_utils/test_profiles.h" #include "components/autofill/core/browser/webdata/addresses/address_autofill_table.h" #include "components/autofill/core/browser/webdata/autofill_change.h" #include "components/autofill/core/common/autofill_clock.h" @@ -303,6 +305,49 @@ Pointee(profile3))); } +TEST_F(AddressDataManagerTest, GetProfilesToSuggest_NameEmailOrder) { + base::test::ScopedFeatureList scoped_feature_list{ + features::kAutofillEnableSupportForNameAndEmail}; + base::Time now = base::Time::Now(); + AutofillProfile profile1 = test::GetFullProfile(); + profile1.usage_history().set_use_date(now - base::Hours(2)); + profile1.usage_history().set_use_count(1); + AutofillProfile profile2 = test::GetFullProfile2(); + profile2.usage_history().set_use_date(now); + profile2.usage_history().set_use_count(1234); + AutofillProfile profile_name_email = test::AccountNameEmailProfile(); + profile_name_email.usage_history().set_use_date(now - base::Hours(1)); + profile_name_email.usage_history().set_use_count(1); + + AddProfileToAddressDataManager(profile1); + AddProfileToAddressDataManager(profile2); + AddProfileToAddressDataManager(profile_name_email); + + // Based solely on the default suggestion order, the `profile_name_email` + // should be placed in the middle. + ASSERT_THAT( + address_data_manager().GetProfiles( + AddressDataManager::ProfileOrder::kHighestFrecencyDesc), + testing::ElementsAre(Pointee(profile2), Pointee(profile_name_email), + Pointee(profile1))); + ASSERT_EQ( + prefs_->GetInteger(prefs::kAutofillNameAndEmailProfileNotSelectedCounter), + 0); + // Verify that calling the GetProfilesToSuggest() checks the counter, which + // will make the `profile_name_email` to be suggested first, because + // `prefs::kAutofillNameAndEmailProfileNotSelectedCounter` is 0. + EXPECT_THAT(address_data_manager().GetProfilesToSuggest(), + testing::ElementsAre(Pointee(profile_name_email), + Pointee(profile2), Pointee(profile1))); + + prefs_->SetInteger(prefs::kAutofillNameAndEmailProfileNotSelectedCounter, 1); + // After the pref changes to a non zero value the kAccountNameEmail should be + // last. + EXPECT_THAT(address_data_manager().GetProfilesToSuggest(), + testing::ElementsAre(Pointee(profile2), Pointee(profile1), + Pointee(profile_name_email))); +} + // Test that profiles are not shown if |kAutofillProfileEnabled| is set to // |false|. TEST_F(AddressDataManagerTest, GetProfilesToSuggest_ProfileAutofillDisabled) {
diff --git a/components/autofill/core/browser/data_model/addresses/autofill_structured_address.cc b/components/autofill/core/browser/data_model/addresses/autofill_structured_address.cc index fb9a682..d2b26dc 100644 --- a/components/autofill/core/browser/data_model/addresses/autofill_structured_address.cc +++ b/components/autofill/core/browser/data_model/addresses/autofill_structured_address.cc
@@ -15,6 +15,7 @@ #include "base/strings/utf_string_conversions.h" #include "components/autofill/core/browser/autofill_type.h" #include "components/autofill/core/browser/data_model/addresses/autofill_i18n_api.h" +#include "components/autofill/core/browser/data_model/addresses/autofill_normalization_utils.h" #include "components/autofill/core/browser/data_model/addresses/autofill_structured_address_component.h" #include "components/autofill/core/browser/data_model/addresses/autofill_structured_address_regex_provider.h" #include "components/autofill/core/browser/data_model/addresses/autofill_structured_address_utils.h" @@ -47,6 +48,18 @@ HouseNumberNode::~HouseNumberNode() = default; +std::u16string HouseNumberNode::GetValueForComparison( + const std::u16string& value, + const AddressCountryCode& common_country_code) const { + if (base::FeatureList::IsEnabled( + features::kAutofillAddressDiscardWhitespaceInHouseNumber)) { + return normalization::NormalizeForComparison( + value, normalization::WhitespaceSpec::kDiscard, common_country_code); + } else { + return AddressComponent::GetValueForComparison(value, common_country_code); + } +} + FloorNode::FloorNode(SubcomponentsList children) : AddressComponent(ADDRESS_HOME_FLOOR, std::move(children),
diff --git a/components/autofill/core/browser/data_model/addresses/autofill_structured_address.h b/components/autofill/core/browser/data_model/addresses/autofill_structured_address.h index 7065e14..b30f893 100644 --- a/components/autofill/core/browser/data_model/addresses/autofill_structured_address.h +++ b/components/autofill/core/browser/data_model/addresses/autofill_structured_address.h
@@ -27,6 +27,10 @@ public: explicit HouseNumberNode(SubcomponentsList children); ~HouseNumberNode() override; + + std::u16string GetValueForComparison( + const std::u16string& value, + const AddressCountryCode& common_country_code) const override; }; // Contains the specific location in the street (e.g. street name and house
diff --git a/components/autofill/core/browser/data_model/addresses/autofill_structured_address_unittest.cc b/components/autofill/core/browser/data_model/addresses/autofill_structured_address_unittest.cc index 3286424e..8a4988e 100644 --- a/components/autofill/core/browser/data_model/addresses/autofill_structured_address_unittest.cc +++ b/components/autofill/core/browser/data_model/addresses/autofill_structured_address_unittest.cc
@@ -3128,6 +3128,56 @@ } } +struct HouseNumberTestCase { + std::u16string input; + std::u16string expected; +}; + +class AutofillStructuredAddressHouseNumberTest + : public AutofillStructuredAddress, + public testing::WithParamInterface<HouseNumberTestCase> { + private: + base::test::ScopedFeatureList features_{ + features::kAutofillAddressDiscardWhitespaceInHouseNumber}; +}; + +TEST_P(AutofillStructuredAddressHouseNumberTest, + DiscardWhitespaceWhenNormalizingHouseNumber) { + const HouseNumberTestCase& test_case = GetParam(); + + AddressComponentsStore address = + i18n_model_definition::CreateAddressComponentModel(); + AddressComponent* house_number_node = + test_api(*address.Root()).GetNodeForType(ADDRESS_HOME_HOUSE_NUMBER); + + ASSERT_TRUE(house_number_node->SetValueForType( + ADDRESS_HOME_HOUSE_NUMBER, test_case.input, + VerificationStatus::kObserved)); + ASSERT_EQ(house_number_node->GetValue(), test_case.input); + EXPECT_EQ(house_number_node->GetValueForComparisonForType( + ADDRESS_HOME_HOUSE_NUMBER, house_number_node->GetCountryCode()), + test_case.expected); +} + +INSTANTIATE_TEST_SUITE_P( + , + AutofillStructuredAddressHouseNumberTest, + ::testing::ValuesIn<HouseNumberTestCase>( + {{u" 123 ", u"123"}, + {u"123 A", u"123a"}, + {u"123 a", u"123a"}, + {u" 45 B ", u"45b"}, + {u"123", u"123"}, + {u" ", u""}, + {u"apt. 123", u"apt123"}, + // Test cases below are considered equal because normalization removes + // character such as "/", "-" and whitespaces. The risks of merging + // profiles with "12/3" and "123" are considered acceptable as it + // requires other profile fields to match as well. Such cases are + // expected to be rare compared to the "123 A" and "123a". + {u"12/3", u"123"}, + {u"12-3", u"123"}})); + } // namespace } // namespace autofill
diff --git a/components/autofill/core/browser/data_model/autofill_ai/entity_instance.cc b/components/autofill/core/browser/data_model/autofill_ai/entity_instance.cc index 2f3f2de8..b2db283 100644 --- a/components/autofill/core/browser/data_model/autofill_ai/entity_instance.cc +++ b/components/autofill/core/browser/data_model/autofill_ai/entity_instance.cc
@@ -11,6 +11,7 @@ #include "base/numerics/safe_conversions.h" #include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" +#include "components/autofill/core/browser/autofill_field.h" #include "components/autofill/core/browser/data_model/addresses/autofill_i18n_api.h" #include "components/autofill/core/browser/data_model/addresses/autofill_normalization_utils.h" #include "components/autofill/core/browser/data_model/addresses/autofill_structured_address_component.h" @@ -33,18 +34,14 @@ attribute.GetRawInfo(attribute.type().field_type())); } -std::u16string Format(std::u16string s, - base::optional_ref<const std::u16string> format_string) { - if (!format_string) { - return s; - } - +// Returns `s` in the demanded `format`. See `data_util::IsValidDateFormat` for +// the valid `format` values. +std::u16string FormatAffix(std::u16string s, std::u16string_view format) { // We parse the leading minus here rather than using `base::StringToInt()` to // avoid mixing signed and unsigned integers as this easily leads to // undefined behavior. - std::u16string_view format = *format_string; bool suffix = false; - if (format_string->starts_with(u"-")) { + if (format.starts_with(u"-")) { format = format.substr(1); suffix = true; } @@ -62,6 +59,44 @@ return s; } +// Returns `s` in the demanded `format`. See +// `data_util::IsValidFlightNumberFormat` for the valid `format` values. +std::u16string FormatFlightNumber(std::u16string s, + std::u16string_view format) { + // Invalid flight number - do not attempt to format. + if (s.size() < 3) { + return s; + } + + // The airline designator corresponds to the first two characters. + if (format == u"A") { + return s.substr(0, 2); + } + // The number is the remainder of the string. + if (format == u"N") { + return s.substr(2); + } + return s; +} + +std::u16string Format( + std::u16string s, + base::optional_ref<const AutofillFormatString> format_string) { + if (!format_string) { + return s; + } + + switch (format_string->type) { + case FormatString_Type_AFFIX: + return FormatAffix(std::move(s), format_string->value); + case FormatString_Type_FLIGHT_NUMBER: + return FormatFlightNumber(std::move(s), format_string->value); + case FormatString_Type_DATE: + break; + } + return s; +} + } // namespace AttributeInstance::AttributeInstance(AttributeType type) @@ -90,7 +125,7 @@ std::u16string AttributeInstance::GetInfo( FieldType field_type, const std::string& app_locale, - base::optional_ref<const std::u16string> format_string) const { + base::optional_ref<const AutofillFormatString> format_string) const { field_type = GetNormalizedFieldType(field_type); return std::visit( absl::Overload{[&](const CountryInfo& country) { @@ -100,7 +135,7 @@ // TODO(crbug.com/396325496): Consider falling back // to a locale-specific format by relying on // `app_locale`. - return date.GetDate(format_string ? *format_string + return date.GetDate(format_string ? format_string->value : u"YYYY-MM-DD"); }, [&](const NameInfo&) { return GetRawInfo(field_type); }, @@ -148,11 +183,12 @@ info_); } -void AttributeInstance::SetInfo(FieldType field_type, - const std::u16string& value, - const std::string& app_locale, - std::u16string_view format_string, - VerificationStatus status) { +void AttributeInstance::SetInfo( + FieldType field_type, + const std::u16string& value, + const std::string& app_locale, + base::optional_ref<const AutofillFormatString> format_string, + VerificationStatus status) { field_type = GetNormalizedFieldType(field_type); std::visit( absl::Overload{ @@ -167,7 +203,12 @@ country = CountryInfo(); } }, - [&](DateInfo& date) { date.SetDate(value, format_string); }, + [&](DateInfo& date) { + date.SetDate(value, format_string && format_string->type == + FormatString_Type_DATE + ? format_string->value + : u""); + }, [&](NameInfo& name) { if (!name.GetSupportedTypes().contains(field_type)) { return;
diff --git a/components/autofill/core/browser/data_model/autofill_ai/entity_instance.h b/components/autofill/core/browser/data_model/autofill_ai/entity_instance.h index b883224..6b3ce93e 100644 --- a/components/autofill/core/browser/data_model/autofill_ai/entity_instance.h +++ b/components/autofill/core/browser/data_model/autofill_ai/entity_instance.h
@@ -39,6 +39,7 @@ // Entity instances are loaded from a webdata table and exposed through // EntityDataManager. class AttributeInstance; +struct AutofillFormatString; class EntityInstance; class EntityTable; @@ -94,7 +95,7 @@ std::u16string GetInfo( FieldType field_type, const std::string& app_locale, - base::optional_ref<const std::u16string> format_string) const; + base::optional_ref<const AutofillFormatString> format_string) const; // Same as `GetInfo` but returns the value as stored with no formatting // whatsoever. @@ -114,15 +115,19 @@ // See GetInfo() for the meaning of `field_type`. // // Currently, the `format_string` only matters for dates. Dates are updated - // incrementally, e.g., SetInfo(..., u"16", ..., u"DD", ...) only changes the - // day and does not reset the month or year. If `value` doesn't fully match - // the `format_string`, the function is a no-op, e.g., - // SetInfo(..., u"16/12/2022", ..., u"DD", ...) is a no-op. + // incrementally, e.g., + // SetInfo(..., u"16", ..., + // AutofillFormatString::FromDateFormat(u"DD"), ...); + // only changes the day and does not reset the month or year. If `value` + // doesn't fully match the `format_string`, e.g. + // SetInfo(..., u"16/12/2022", ..., + // AutofillFormatString::FromDateFormat(u"DD"), ...); + // the function is a no-op. // See AutofillField::format_string() for the grammar of format strings. void SetInfo(FieldType field_type, const std::u16string& value, const std::string& app_locale, - std::u16string_view format_string, + base::optional_ref<const AutofillFormatString> format_string, VerificationStatus status); // Similar to SetInfo() but without canonicalization: It does not accept
diff --git a/components/autofill/core/browser/data_model/autofill_ai/entity_instance_unittest.cc b/components/autofill/core/browser/data_model/autofill_ai/entity_instance_unittest.cc index 88ed5b7..97ac60d 100644 --- a/components/autofill/core/browser/data_model/autofill_ai/entity_instance_unittest.cc +++ b/components/autofill/core/browser/data_model/autofill_ai/entity_instance_unittest.cc
@@ -8,6 +8,8 @@ #include "base/time/time.h" #include "base/types/optional_ref.h" #include "base/uuid.h" +#include "components/autofill/core/browser/autofill_field.h" +#include "components/autofill/core/browser/data_model/addresses/autofill_structured_address_component.h" #include "components/autofill/core/browser/data_model/autofill_ai/entity_type.h" #include "components/autofill/core/browser/field_types.h" #include "components/autofill/core/browser/test_utils/autofill_test_utils.h" @@ -24,16 +26,13 @@ struct GetInfoParams { std::string app_locale = ""; - const char16_t* format_string = nullptr; + std::optional<AutofillFormatString> format_string; }; std::u16string GetInfo(const AttributeInstance& a, FieldType field_type, GetInfoParams params = {}) { - return a.GetInfo(field_type, params.app_locale, - params.format_string - ? std::optional(std::u16string(params.format_string)) - : std::nullopt); + return a.GetInfo(field_type, params.app_locale, params.format_string); } TEST(AutofillEntityInstanceTest, Attributes) { @@ -58,13 +57,13 @@ TEST(AutofillEntityInstanceTest, Attributes_NormalizedType) { AttributeInstance passport_name((AttributeType(kPassportName))); passport_name.SetInfo(NAME_FULL, u"John Doe", - /*app_locale=*/"", /*format_string=*/u"", + /*app_locale=*/"", /*format_string=*/std::nullopt, VerificationStatus::kObserved); passport_name.FinalizeInfo(); AttributeInstance passport_number((AttributeType(kPassportNumber))); passport_number.SetInfo(PASSPORT_NUMBER, u"LR0123456", - /*app_locale=*/"", /*format_string=*/u"", + /*app_locale=*/"", /*format_string=*/std::nullopt, VerificationStatus::kObserved); EXPECT_EQ(GetInfo(passport_name, NAME_FULL), u"John Doe"); @@ -82,7 +81,7 @@ TEST(AutofillEntityInstanceTest, Attributes_CountryLocalization) { AttributeInstance passport_country((AttributeType(kPassportCountry))); passport_country.SetInfo(PASSPORT_ISSUING_COUNTRY, u"SE", - /*app_locale=*/"", /*format_string=*/u"", + /*app_locale=*/"", /*format_string=*/std::nullopt, VerificationStatus::kObserved); EXPECT_EQ(GetInfo(passport_country, PASSPORT_ISSUING_COUNTRY, @@ -109,7 +108,7 @@ TEST(AutofillEntityInstanceTest, Attributes_StructuredName) { AttributeInstance passport_name((AttributeType(kPassportName))); passport_name.SetInfo(NAME_FULL, u"Some Name", - /*app_locale=*/"", /*format_string=*/u"", + /*app_locale=*/"", /*format_string=*/std::nullopt, VerificationStatus::kObserved); passport_name.FinalizeInfo(); @@ -121,37 +120,98 @@ // Tests that AttributeInstance honors the affix formats. TEST(AutofillEntityInstanceTest, Attributes_IdentificationNumbers) { + auto from_affix = [](std::u16string fs) { + return AutofillFormatString(std::move(fs), FormatString_Type_AFFIX); + }; + AttributeInstance passport_number((AttributeType(kPassportNumber))); passport_number.SetInfo(PASSPORT_NUMBER, u"LR0123456", - /*app_locale=*/"", /*format_string=*/u"", + /*app_locale=*/"", /*format_string=*/std::nullopt, VerificationStatus::kObserved); EXPECT_EQ(GetInfo(passport_number, PASSPORT_NUMBER), u"LR0123456"); - EXPECT_EQ(GetInfo(passport_number, PASSPORT_NUMBER, {.format_string = u"0"}), + EXPECT_EQ(GetInfo(passport_number, PASSPORT_NUMBER, + {.format_string = from_affix(u"0")}), u"LR0123456"); - EXPECT_EQ(GetInfo(passport_number, PASSPORT_NUMBER, {.format_string = u"4"}), + EXPECT_EQ(GetInfo(passport_number, PASSPORT_NUMBER, + {.format_string = from_affix(u"4")}), u"LR01"); - EXPECT_EQ(GetInfo(passport_number, PASSPORT_NUMBER, {.format_string = u"-4"}), + EXPECT_EQ(GetInfo(passport_number, PASSPORT_NUMBER, + {.format_string = from_affix(u"-4")}), u"3456"); EXPECT_EQ(GetInfo(passport_number, PASSPORT_NUMBER, - {.format_string = - base::NumberToString16(std::numeric_limits<int>::min()) - .c_str()}), + {.format_string = from_affix(base::NumberToString16( + std::numeric_limits<int>::min()))}), u"LR0123456"); } // Tests that AttributeInstance appropriately manages dates. TEST(AutofillEntityInstanceTest, Attributes_Date) { + auto from_date = [](std::u16string fs) { + return AutofillFormatString(std::move(fs), FormatString_Type_DATE); + }; + AttributeInstance passport_name((AttributeType(kPassportIssueDate))); passport_name.SetInfo(PASSPORT_ISSUE_DATE, u"2001-02-03", - /*app_locale=*/"", /*format_string=*/u"YYYY-MM-DD", + /*app_locale=*/"", from_date(u"YYYY-MM-DD"), VerificationStatus::kNoStatus); EXPECT_EQ(GetInfo(passport_name, PASSPORT_ISSUE_DATE), u"2001-02-03"); EXPECT_EQ(GetInfo(passport_name, PASSPORT_ISSUE_DATE, - {.format_string = u"DD/MM/YYYY"}), + {.format_string = from_date(u"DD/MM/YYYY")}), u"03/02/2001"); } +// Tests that formatting flight numbers works correctly. +TEST(AutofillEntityInstanceTest, AttributesFlightFormat) { + auto from_flight_number = [](std::u16string fs) { + return AutofillFormatString(std::move(fs), FormatString_Type_FLIGHT_NUMBER); + }; + + { + AttributeInstance flight_number( + (AttributeType(kFlightReservationFlightNumber))); + flight_number.SetInfo( + FLIGHT_RESERVATION_FLIGHT_NUMBER, u"LH89", /*app_locale*/ "", + /*format_string=*/std::nullopt, VerificationStatus::kNoStatus); + EXPECT_EQ(GetInfo(flight_number, FLIGHT_RESERVATION_FLIGHT_NUMBER), + u"LH89"); + EXPECT_EQ(GetInfo(flight_number, FLIGHT_RESERVATION_FLIGHT_NUMBER, + {.format_string = from_flight_number(u"A")}), + u"LH"); + EXPECT_EQ(GetInfo(flight_number, FLIGHT_RESERVATION_FLIGHT_NUMBER, + {.format_string = from_flight_number(u"N")}), + u"89"); + EXPECT_EQ(GetInfo(flight_number, FLIGHT_RESERVATION_FLIGHT_NUMBER, + {.format_string = from_flight_number(u"F")}), + u"LH89"); + EXPECT_EQ(GetInfo(flight_number, FLIGHT_RESERVATION_FLIGHT_NUMBER, + {.format_string = from_flight_number(u"")}), + u"LH89"); + } + + { + // A mal-formed flight number. + AttributeInstance flight_number( + (AttributeType(kFlightReservationFlightNumber))); + flight_number.SetInfo( + FLIGHT_RESERVATION_FLIGHT_NUMBER, u"AA", /*app_locale*/ "", + /*format_string=*/std::nullopt, VerificationStatus::kNoStatus); + EXPECT_EQ(GetInfo(flight_number, FLIGHT_RESERVATION_FLIGHT_NUMBER), u"AA"); + EXPECT_EQ(GetInfo(flight_number, FLIGHT_RESERVATION_FLIGHT_NUMBER, + {.format_string = from_flight_number(u"A")}), + u"AA"); + EXPECT_EQ(GetInfo(flight_number, FLIGHT_RESERVATION_FLIGHT_NUMBER, + {.format_string = from_flight_number(u"N")}), + u"AA"); + EXPECT_EQ(GetInfo(flight_number, FLIGHT_RESERVATION_FLIGHT_NUMBER, + {.format_string = from_flight_number(u"F")}), + u"AA"); + EXPECT_EQ(GetInfo(flight_number, FLIGHT_RESERVATION_FLIGHT_NUMBER, + {.format_string = from_flight_number(u"F")}), + u"AA"); + } +} + TEST(AutofillEntityInstanceTest, GetEntityMergeability_IdentiticalEntities_NoMergeableAttribute_IsASubset) { EntityInstance::EntityMergeability result =
diff --git a/components/autofill/core/browser/filling/autofill_ai/field_filling_entity_util.cc b/components/autofill/core/browser/filling/autofill_ai/field_filling_entity_util.cc index 62c0d4c..955aeed 100644 --- a/components/autofill/core/browser/filling/autofill_ai/field_filling_entity_util.cc +++ b/components/autofill/core/browser/filling/autofill_ai/field_filling_entity_util.cc
@@ -90,10 +90,12 @@ return std::nullopt; } - auto get_part = [&](const std::u16string& format_string, uint32_t min = 0, + auto get_part = [&](std::u16string format_string, uint32_t min = 0, uint32_t max = std::numeric_limits<uint32_t>::max()) -> uint32_t { - std::u16string s = attribute.GetInfo(type, app_locale, format_string); + std::u16string s = attribute.GetInfo( + type, app_locale, + AutofillFormatString(std::move(format_string), FormatString_Type_DATE)); unsigned int i = 0; return base::StringToUint(s, &i) && min <= i && i <= max ? i
diff --git a/components/autofill/core/browser/filling/autofill_ai/field_filling_entity_util_unittest.cc b/components/autofill/core/browser/filling/autofill_ai/field_filling_entity_util_unittest.cc index 4206450..d3cddb7 100644 --- a/components/autofill/core/browser/filling/autofill_ai/field_filling_entity_util_unittest.cc +++ b/components/autofill/core/browser/filling/autofill_ai/field_filling_entity_util_unittest.cc
@@ -565,7 +565,8 @@ TEST_F(GetFillValueForEntityTest_Date, FillingDateValueIntoTextInput) { auto field = CreateInput(FormControlType::kInputText); field->set_format_string_unless_overruled( - u"DD/MM/YYYY", AutofillField::FormatStringSource::kServer); + AutofillFormatString(u"DD/MM/YYYY", FormatString_Type_DATE), + AutofillFormatStringSource::kServer); EXPECT_EQ( GetFillValueForEntity(passport(), field, mojom::ActionPersistence::kFill, /*app_locale=*/"",
diff --git a/components/autofill/core/browser/filling/form_filler_unittest.cc b/components/autofill/core/browser/filling/form_filler_unittest.cc index 864412d..120ee272 100644 --- a/components/autofill/core/browser/filling/form_filler_unittest.cc +++ b/components/autofill/core/browser/filling/form_filler_unittest.cc
@@ -1588,8 +1588,9 @@ auto set_format_string = [&](size_t field_index, std::string_view format_string) { form_structure->fields()[field_index]->set_format_string_unless_overruled( - base::UTF8ToUTF16(format_string), - AutofillField::FormatStringSource::kServer); + AutofillFormatString(base::UTF8ToUTF16(format_string), + FormatString_Type_DATE), + AutofillFormatStringSource::kServer); }; set_server_type(0, PASSPORT_NUMBER); set_server_type(1, NAME_FIRST);
diff --git a/components/autofill/core/browser/form_structure.cc b/components/autofill/core/browser/form_structure.cc index 5526467..eacb567 100644 --- a/components/autofill/core/browser/form_structure.cc +++ b/components/autofill/core/browser/form_structure.cc
@@ -268,9 +268,9 @@ it != field_to_attribute_types.end()) { annotated_field.attribute_types = AttributeTypesToString(it->second); } - if (base::optional_ref<const std::u16string> format_string = + if (base::optional_ref<const AutofillFormatString> format_string = field->format_string()) { - annotated_field.format_string = base::UTF16ToUTF8(*format_string); + annotated_field.format_string = base::UTF16ToUTF8(format_string->value); } annotated_field.html_type = FieldTypeToStringView(field->html_type()); annotated_field.overall_type = [&] { @@ -436,7 +436,7 @@ field->set_previously_autofilled(cached_field->previously_autofilled()); field->set_did_trigger_suggestions(cached_field->did_trigger_suggestions()); field->set_was_focused(cached_field->was_focused()); - if (base::optional_ref<const std::u16string> format_string = + if (base::optional_ref<const AutofillFormatString> format_string = cached_field->format_string()) { field->set_format_string_unless_overruled( *format_string, cached_field->format_string_source()); @@ -829,25 +829,25 @@ buffer << Tr{} << "Autofill AI AttributeTypes:" << AttributeTypesToString(it->second); } - if (base::optional_ref<const std::u16string> format_string = + if (base::optional_ref<const AutofillFormatString> format_string = field->format_string()) { std::string_view source; switch (field->format_string_source()) { - case AutofillField::FormatStringSource::kUnset: + case AutofillFormatStringSource::kUnset: source = "unset"; break; - case AutofillField::FormatStringSource::kHeuristics: + case AutofillFormatStringSource::kHeuristics: source = "heuristic"; break; - case AutofillField::FormatStringSource::kModelResult: + case AutofillFormatStringSource::kModelResult: source = "model"; break; - case AutofillField::FormatStringSource::kServer: + case AutofillFormatStringSource::kServer: source = "server"; break; } buffer << Tr{} << "Format string:" - << base::StrCat({"\"", base::UTF16ToUTF8(*format_string), + << base::StrCat({"\"", base::UTF16ToUTF8(format_string->value), "\" from ", source}); } buffer << Tr{} << "Section:" << field->section();
diff --git a/components/autofill/core/browser/form_structure_rationalizer.cc b/components/autofill/core/browser/form_structure_rationalizer.cc index b58e0e74..36a42191 100644 --- a/components/autofill/core/browser/form_structure_rationalizer.cc +++ b/components/autofill/core/browser/form_structure_rationalizer.cc
@@ -710,8 +710,9 @@ << "Set format string of " << field.global_id() << " to " << format_string; field.set_format_string_unless_overruled( - std::move(format_string), - AutofillField::FormatStringSource::kHeuristics); + AutofillFormatString(std::move(format_string), + FormatString_Type::FormatString_Type_DATE), + AutofillFormatStringSource::kHeuristics); }; auto get_autofill_ai_date_types = [](const AutofillField& field) { @@ -732,11 +733,11 @@ continue; } switch (field.format_string_source()) { - case AutofillField::FormatStringSource::kUnset: - case AutofillField::FormatStringSource::kHeuristics: + case AutofillFormatStringSource::kUnset: + case AutofillFormatStringSource::kHeuristics: break; // Breaks the switch, not the loop. - case AutofillField::FormatStringSource::kModelResult: - case AutofillField::FormatStringSource::kServer: + case AutofillFormatStringSource::kModelResult: + case AutofillFormatStringSource::kServer: continue; }
diff --git a/components/autofill/core/browser/form_structure_rationalizer_unittest.cc b/components/autofill/core/browser/form_structure_rationalizer_unittest.cc index 6dbb05e..c1afd6b 100644 --- a/components/autofill/core/browser/form_structure_rationalizer_unittest.cc +++ b/components/autofill/core/browser/form_structure_rationalizer_unittest.cc
@@ -167,14 +167,15 @@ return ElementsAre(FieldTypeSet{types}...); } -std::vector<std::optional<std::string>> GetFormatStrings( +std::vector<std::optional<std::string>> GetDateFormatStrings( const FormStructure& form_structure) { std::vector<std::optional<std::string>> format_strings; format_strings.reserve(form_structure.field_count()); for (size_t i = 0; i < form_structure.field_count(); ++i) { - if (std::optional<std::u16string> format_string = - form_structure.field(i)->format_string().CopyAsOptional()) { - format_strings.emplace_back(base::UTF16ToUTF8(*format_string)); + if (std::optional<AutofillFormatString> format_string = + form_structure.field(i)->format_string().CopyAsOptional(); + format_string && format_string->type == FormatString_Type_DATE) { + format_strings.emplace_back(base::UTF16ToUTF8(format_string->value)); } else { format_strings.push_back(std::nullopt); } @@ -1236,8 +1237,9 @@ {.field_type = PASSPORT_EXPIRATION_DATE, .placeholder = "DD/MM/YYYY"}}, /*run_heuristics=*/false); form_structure->fields()[1]->set_format_string_unless_overruled( - u"YYYY-MM-DD", AutofillField::FormatStringSource::kServer); - EXPECT_THAT(GetFormatStrings(*form_structure), + AutofillFormatString(u"YYYY-MM-DD", FormatString_Type_DATE), + AutofillFormatStringSource::kServer); + EXPECT_THAT(GetDateFormatStrings(*form_structure), ElementsAre(std::nullopt, "YYYY-MM-DD", "DD/MM/YYYY")); } @@ -1247,9 +1249,10 @@ {{.field_type = PASSPORT_EXPIRATION_DATE, .placeholder = "DD/MM/YYYY"}, {.field_type = PASSPORT_EXPIRATION_DATE, .placeholder = "DD/MM/YYYY"}}, /*run_heuristics=*/false); - form_structure->fields().back()->set_format_string_unless_overruled( - u"YYYY-MM-DD", AutofillField::FormatStringSource::kServer); - EXPECT_THAT(GetFormatStrings(*form_structure), + form_structure->fields()[1]->set_format_string_unless_overruled( + AutofillFormatString(u"YYYY-MM-DD", FormatString_Type_DATE), + AutofillFormatStringSource::kServer); + EXPECT_THAT(GetDateFormatStrings(*form_structure), ElementsAre("DD/MM/YYYY", "YYYY-MM-DD")); } @@ -1266,7 +1269,7 @@ .value = "YYYY-MM-DD"}}, /*run_heuristics=*/false); EXPECT_THAT( - GetFormatStrings(*form_structure), + GetDateFormatStrings(*form_structure), ElementsAre("YYYY-MM-DD", "DD", "YYYY-MM", "DD/MM/YY", "DD/MM/YY")); } @@ -1287,7 +1290,7 @@ .value = "YYYY-MM-DD"}}, /*run_heuristics=*/false); EXPECT_THAT( - GetFormatStrings(*form_structure), + GetDateFormatStrings(*form_structure), ElementsAre("YYYY-MM-DD", "DD", "YYYY-MM", "DD/MM/YY", "DD/MM/YY")); } @@ -1300,7 +1303,7 @@ {.label = "Until which D/M/YY is the thing valid?", .field_type = PASSPORT_EXPIRATION_DATE}}, /*run_heuristics=*/false); - EXPECT_THAT(GetFormatStrings(*form_structure), + EXPECT_THAT(GetDateFormatStrings(*form_structure), ElementsAre("YYYY-MM-DD", "D/M/YY")); } @@ -1317,7 +1320,7 @@ {.label = "Until which D/M/YY is the thing valid?", .field_type = PASSPORT_EXPIRATION_DATE}}, /*run_heuristics=*/false); - EXPECT_THAT(GetFormatStrings(*form_structure), + EXPECT_THAT(GetDateFormatStrings(*form_structure), ElementsAre("YYYY", "MM", "DD", "D/M/YY")); } @@ -1332,7 +1335,7 @@ {.label = "Until which D/M/YY is the thing valid?", .field_type = PASSPORT_ISSUE_DATE}}, /*run_heuristics=*/false); - EXPECT_THAT(GetFormatStrings(*form_structure), + EXPECT_THAT(GetDateFormatStrings(*form_structure), ElementsAre("DD", "MM", "YYYY", "D/M/YY")); } @@ -1347,7 +1350,7 @@ {.label = "Until which D/M/YY is the thing valid?", .field_type = PASSPORT_EXPIRATION_DATE}}, /*run_heuristics=*/false); - EXPECT_THAT(GetFormatStrings(*form_structure), + EXPECT_THAT(GetDateFormatStrings(*form_structure), ElementsAre("YYYY", "MM", "D/M/YY")); } @@ -1360,7 +1363,7 @@ {.label = "When did you pick it up? YYYY-MM-DD", .field_type = PASSPORT_ISSUE_DATE}}, /*run_heuristics=*/false); - EXPECT_THAT(GetFormatStrings(*form_structure), + EXPECT_THAT(GetDateFormatStrings(*form_structure), ElementsAre("YYYY-MM-DD", "YYYY-MM-DD")); } @@ -1378,7 +1381,7 @@ .field_type = PASSPORT_ISSUE_DATE}}, /*run_heuristics=*/false); // There is no particular motivation for this assignment. - EXPECT_THAT(GetFormatStrings(*form_structure), + EXPECT_THAT(GetDateFormatStrings(*form_structure), ElementsAre("YYYY", "MM", "DD", "YYYY-MM-DD")); }
diff --git a/components/autofill/core/browser/foundations/browser_autofill_manager.cc b/components/autofill/core/browser/foundations/browser_autofill_manager.cc index d63c62e2..4dd940c 100644 --- a/components/autofill/core/browser/foundations/browser_autofill_manager.cc +++ b/components/autofill/core/browser/foundations/browser_autofill_manager.cc
@@ -726,9 +726,12 @@ field->MaybeAddServerPrediction(std::move(server_prediction)); } if (!prediction.format_string.empty()) { + // TODO(crbug.com/389625753): Either implement format strings properly + // in the model or remove this here. field->set_format_string_unless_overruled( - prediction.format_string, - AutofillField::FormatStringSource::kModelResult); + AutofillFormatString(std::move(prediction.format_string), + FormatString_Type_DATE), + AutofillFormatStringSource::kModelResult); } } } @@ -1354,6 +1357,8 @@ // autofill. The warning is shown even if there are no autofill suggestions // available. if (IsFormMixedContent(client(), form) && + client().GetPrefs()->FindPreference( + ::prefs::kMixedFormsWarningsEnabled) && client().GetPrefs()->GetBoolean(::prefs::kMixedFormsWarningsEnabled)) { LOG_AF(log_manager()) << LoggingScope::kFilling << LogMessage::kSuggestionSuppressed
diff --git a/components/autofill/core/browser/foundations/browser_autofill_manager_unittest.cc b/components/autofill/core/browser/foundations/browser_autofill_manager_unittest.cc index 8ca356e1..8ac5314 100644 --- a/components/autofill/core/browser/foundations/browser_autofill_manager_unittest.cc +++ b/components/autofill/core/browser/foundations/browser_autofill_manager_unittest.cc
@@ -7873,9 +7873,9 @@ EXPECT_THAT(fs->field(3)->Type().GetAutofillAiTypes(), ElementsAre(PASSPORT_ISSUE_DATE)); ASSERT_TRUE(fs->field(3)->format_string().has_value()); - EXPECT_EQ(fs->field(3)->format_string().value(), u"D.M.YYYY"); + EXPECT_EQ(fs->field(3)->format_string()->value, u"D.M.YYYY"); EXPECT_EQ(fs->field(3)->format_string_source(), - AutofillField::FormatStringSource::kModelResult); + AutofillFormatStringSource::kModelResult); } // Tests that if the form has at least one existing AutofillAI prediction, then
diff --git a/components/autofill/core/browser/integrators/autofill_ai/autofill_ai_import_utils.cc b/components/autofill/core/browser/integrators/autofill_ai/autofill_ai_import_utils.cc index 6b318a9..fc866ca 100644 --- a/components/autofill/core/browser/integrators/autofill_ai/autofill_ai_import_utils.cc +++ b/components/autofill/core/browser/integrators/autofill_ai/autofill_ai_import_utils.cc
@@ -48,7 +48,7 @@ struct ValueAndFormatString { std::u16string value; - std::u16string format_string; + AutofillFormatString format_string; }; // Returns the value and format string of `field` for import by Autofill AI. @@ -58,9 +58,9 @@ !field.IsSelectElement()) { std::u16string value = field.value_for_import(); base::TrimWhitespace(value, base::TRIM_ALL, &value); - return { - .value = std::move(value), - .format_string = field.format_string() ? *field.format_string() : u""}; + return {.value = std::move(value), + .format_string = field.format_string() ? *field.format_string() + : AutofillFormatString()}; } auto get_value = [&](DatePartRange range) { @@ -77,13 +77,19 @@ } return std::u16string(); }; + + auto make_date_format = [](std::u16string fs) { + return AutofillFormatString(std::move(fs), FormatString_Type_DATE); + }; + std::u16string value; if (!(value = get_value(GetYearRange(field.options()))).empty()) { - return {.value = std::move(value), .format_string = u"YYYY"}; + return {.value = std::move(value), + .format_string = make_date_format(u"YYYY")}; } else if (!(value = get_value(GetMonthRange(field.options()))).empty()) { - return {.value = std::move(value), .format_string = u"M"}; + return {.value = std::move(value), .format_string = make_date_format(u"M")}; } else if (!(value = get_value(GetDayRange(field.options()))).empty()) { - return {.value = std::move(value), .format_string = u"D"}; + return {.value = std::move(value), .format_string = make_date_format(u"D")}; } return {}; } @@ -139,7 +145,8 @@ // Do not import entities that have an attribute whose value is a proper // prefix or suffix. if (IsAffixFormatStringEnabledForType(field_type) && - data_util::IsValidAffixFormat(value.format_string, + value.format_string.type == FormatString_Type_AFFIX && + data_util::IsValidAffixFormat(value.format_string.value, /*exclude_full_value=*/true)) { if (auto it = section_to_entity_types_attributes.find(section); it != section_to_entity_types_attributes.end()) { @@ -207,7 +214,10 @@ int part = 0; // The app_locale is irrelevant for dates. bool success = base::StringToInt( - attribute.GetInfo(field_type, /*app_locale=*/"", format), &part); + attribute.GetInfo( + field_type, /*app_locale=*/"", + AutofillFormatString(std::move(format), FormatString_Type_DATE)), + &part); return success ? part : 0; }; base::Time time;
diff --git a/components/autofill/core/browser/integrators/autofill_ai/autofill_ai_import_utils_unittest.cc b/components/autofill/core/browser/integrators/autofill_ai/autofill_ai_import_utils_unittest.cc index bac6e9dff..85b702f7 100644 --- a/components/autofill/core/browser/integrators/autofill_ai/autofill_ai_import_utils_unittest.cc +++ b/components/autofill/core/browser/integrators/autofill_ai/autofill_ai_import_utils_unittest.cc
@@ -84,7 +84,7 @@ FormControlType form_control_type, const std::vector<FieldType>& field_types, std::string_view value, - std::string_view format_string = "", + std::optional<AutofillFormatString> format_string = std::nullopt, std::string_view initial_value = "") { auto field = std::make_unique<AutofillField>(test::CreateTestFormField( /*label=*/"", @@ -93,10 +93,9 @@ // Explicitly set the value here to ensure that it differs from the initial // value. field->set_value(base::UTF8ToUTF16(value)); - if (!format_string.empty()) { + if (format_string) { field->set_format_string_unless_overruled( - base::UTF8ToUTF16(format_string), - AutofillField::FormatStringSource::kServer); + std::move(*format_string), AutofillFormatStringSource::kServer); } AddPrediction(*field, field_types); return field; @@ -106,10 +105,10 @@ FormControlType form_control_type, FieldType field_type, std::string_view value, - std::string_view format_string = "", + std::optional<AutofillFormatString> format_string = std::nullopt, std::string_view initial_value = "") { return CreateInput(form_control_type, std::vector<FieldType>{field_type}, - value, format_string, initial_value); + value, std::move(format_string), initial_value); } std::unique_ptr<AutofillField> CreateSelect( @@ -160,13 +159,16 @@ // are ignored during import. fields.push_back(CreateInput(FormControlType::kInputText, FieldType::PASSPORT_ISSUING_COUNTRY, "Sweden", - /*format_string=*/"", "Sweden")); - fields.push_back(CreateInput(FormControlType::kInputText, - FieldType::PASSPORT_ISSUE_DATE, "24", "DD")); - fields.push_back(CreateInput(FormControlType::kInputText, - FieldType::PASSPORT_ISSUE_DATE, "12", "MM")); - fields.push_back(CreateInput(FormControlType::kInputText, - FieldType::PASSPORT_ISSUE_DATE, "2025", "YYYY")); + /*format_string=*/std::nullopt, "Sweden")); + fields.push_back( + CreateInput(FormControlType::kInputText, FieldType::PASSPORT_ISSUE_DATE, + "24", AutofillFormatString(u"DD", FormatString_Type_DATE))); + fields.push_back( + CreateInput(FormControlType::kInputText, FieldType::PASSPORT_ISSUE_DATE, + "12", AutofillFormatString(u"MM", FormatString_Type_DATE))); + fields.push_back(CreateInput( + FormControlType::kInputText, FieldType::PASSPORT_ISSUE_DATE, "2025", + AutofillFormatString(u"YYYY", FormatString_Type_DATE))); EXPECT_THAT(GetPossibleEntitiesFromSubmittedForm(fields, "en-US", GeoIpCountryCode("US")), @@ -253,10 +255,13 @@ CreateAttribute(kDriversLicenseName, "Karlsson on the Roof"))))); + auto from_affix = [](std::u16string fs) { + return AutofillFormatString(std::move(fs), FormatString_Type_AFFIX); + }; fields[1]->set_format_string_unless_overruled( - u"3", AutofillField::FormatStringSource::kServer); + from_affix(u"3"), AutofillFormatStringSource::kServer); fields[2]->set_format_string_unless_overruled( - u"0", AutofillField::FormatStringSource::kServer); + from_affix(u"0"), AutofillFormatStringSource::kServer); EXPECT_THAT( GetPossibleEntitiesFromSubmittedForm(fields, "en-US", GeoIpCountryCode("US")),
diff --git a/components/autofill/core/browser/integrators/autofill_ai/autofill_ai_manager_unittest.cc b/components/autofill/core/browser/integrators/autofill_ai/autofill_ai_manager_unittest.cc index 0779bd53..f8f0f444 100644 --- a/components/autofill/core/browser/integrators/autofill_ai/autofill_ai_manager_unittest.cc +++ b/components/autofill/core/browser/integrators/autofill_ai/autofill_ai_manager_unittest.cc
@@ -14,6 +14,7 @@ #include "base/test/task_environment.h" #include "base/test/test_future.h" #include "base/time/time.h" +#include "components/autofill/core/browser/autofill_field.h" #include "components/autofill/core/browser/data_manager/autofill_ai/entity_data_manager.h" #include "components/autofill/core/browser/data_model/addresses/autofill_structured_address_component.h" #include "components/autofill/core/browser/data_model/autofill_ai/entity_instance.h" @@ -864,7 +865,8 @@ existing_entity_without_expiry_dates, AttributeType(kPassportNumber))); form->field(1)->set_value(u"01/02/20"); form->field(1)->set_format_string_unless_overruled( - u"DD/MM/YY", AutofillField::FormatStringSource::kServer); + AutofillFormatString(u"DD/MM/YY", FormatString_Type_DATE), + AutofillFormatStringSource::kServer); std::optional<EntityInstance> new_entity; std::optional<EntityInstance> old_entity; @@ -911,7 +913,8 @@ // Set a new expiry date value, different from the one currently stored. form->field(1)->set_value(u"01/02/20"); form->field(1)->set_format_string_unless_overruled( - u"DD/MM/YY", AutofillField::FormatStringSource::kServer); + AutofillFormatString(u"DD/MM/YY", FormatString_Type_DATE), + AutofillFormatStringSource::kServer); std::optional<EntityInstance> new_entity; std::optional<EntityInstance> old_entity; @@ -969,7 +972,8 @@ // Issue date. form->field(2)->set_value(u"01/02/16"); form->field(2)->set_format_string_unless_overruled( - u"DD/MM/YY", AutofillField::FormatStringSource::kServer); + AutofillFormatString(u"DD/MM/YY", FormatString_Type_DATE), + AutofillFormatStringSource::kServer); // Since the current entity instance is read only, no prompt should be shown. EXPECT_CALL(autofill_client(), ShowEntitySaveOrUpdateBubble).Times(0);
diff --git a/components/autofill/core/browser/integrators/autofill_ai/metrics/autofill_ai_logger_unittest.cc b/components/autofill/core/browser/integrators/autofill_ai/metrics/autofill_ai_logger_unittest.cc index 4b434f1..7cc2c6a 100644 --- a/components/autofill/core/browser/integrators/autofill_ai/metrics/autofill_ai_logger_unittest.cc +++ b/components/autofill/core/browser/integrators/autofill_ai/metrics/autofill_ai_logger_unittest.cc
@@ -54,6 +54,7 @@ using ::testing::NiceMock; using ::testing::Return; using ::testing::ReturnRef; +using ::testing::UnorderedElementsAreArray; constexpr auto kVehicle = EntityType(EntityTypeName::kVehicle); constexpr auto kDriversLicense = EntityType(EntityTypeName::kDriversLicense); @@ -810,6 +811,10 @@ : UNKNOWN_TYPE; }())) << event; + EXPECT_THAT(mqls_field_event.field_types(), + UnorderedElementsAreArray(field.Type().GetTypes())); + EXPECT_THAT(mqls_field_event.ai_field_types(), + UnorderedElementsAreArray(field.Type().GetAutofillAiTypes())); EXPECT_EQ(base::to_underlying(mqls_field_event.format_string_source()), base::to_underlying(field.format_string_source())) << event;
diff --git a/components/autofill/core/browser/integrators/autofill_ai/metrics/autofill_ai_ukm_logger.cc b/components/autofill/core/browser/integrators/autofill_ai/metrics/autofill_ai_ukm_logger.cc index 87779210..4eb25f7 100644 --- a/components/autofill/core/browser/integrators/autofill_ai/metrics/autofill_ai_ukm_logger.cc +++ b/components/autofill/core/browser/integrators/autofill_ai/metrics/autofill_ai_ukm_logger.cc
@@ -55,15 +55,15 @@ } optimization_guide::proto::FormatStringSource GetFormatStringSource( - AutofillField::FormatStringSource format_string_source) { + AutofillFormatStringSource format_string_source) { switch (format_string_source) { - case AutofillField::FormatStringSource::kUnset: + case AutofillFormatStringSource::kUnset: return optimization_guide::proto::FORMAT_STRING_SOURCE_UNSET; - case AutofillField::FormatStringSource::kHeuristics: + case AutofillFormatStringSource::kHeuristics: return optimization_guide::proto::FORMAT_STRING_SOURCE_HEURISTICS; - case AutofillField::FormatStringSource::kModelResult: + case AutofillFormatStringSource::kModelResult: return optimization_guide::proto::FORMAT_STRING_SOURCE_ML_MODEL; - case AutofillField::FormatStringSource::kServer: + case AutofillFormatStringSource::kServer: return optimization_guide::proto::FORMAT_STRING_SOURCE_SERVER; } NOTREACHED(); @@ -316,13 +316,6 @@ const FieldTypeSet field_types = field.Type().GetTypes(); const FieldTypeSet ai_field_types = field.Type().GetAutofillAiTypes(); - // TODO(crbug.com/432645177): Emit multiple `field_types` and - // `ai_field_types`. - const auto field_type = base::to_underlying( - !field_types.empty() ? *field_types.begin() : UNKNOWN_TYPE); - const auto ai_field_type = base::to_underlying( - !ai_field_types.empty() ? *ai_field_types.begin() : UNKNOWN_TYPE); - if (optimization_guide::ModelQualityLogsUploaderService* uploader_ = client_->GetMqlsUploadService(); uploader_ && @@ -352,8 +345,16 @@ mqls_field_event->set_field_rank(field.rank()); mqls_field_event->set_field_rank_in_signature_group( field.rank_in_signature_group()); - mqls_field_event->set_field_type(field_type); - mqls_field_event->set_ai_field_type(ai_field_type); + mqls_field_event->set_field_type(base::to_underlying( + !field_types.empty() ? *field_types.begin() : UNKNOWN_TYPE)); + mqls_field_event->set_ai_field_type(base::to_underlying( + !ai_field_types.empty() ? *ai_field_types.begin() : UNKNOWN_TYPE)); + for (FieldType field_type : field_types) { + mqls_field_event->add_field_types(field_type); + } + for (FieldType ai_field_type : ai_field_types) { + mqls_field_event->add_ai_field_types(ai_field_type); + } mqls_field_event->set_format_string_source( GetFormatStringSource(field.format_string_source())); mqls_field_event->set_form_control_type(
diff --git a/components/autofill/core/browser/payments/autofill_wallet_data_type_controller.cc b/components/autofill/core/browser/payments/autofill_wallet_data_type_controller.cc index ba95605..e1f2b9f 100644 --- a/components/autofill/core/browser/payments/autofill_wallet_data_type_controller.cc +++ b/components/autofill/core/browser/payments/autofill_wallet_data_type_controller.cc
@@ -79,4 +79,9 @@ sync_service_->DataTypePreconditionChanged(type()); } +void AutofillWalletDataTypeController::OnSyncShutdown( + syncer::SyncService* sync) { + // Nothing to be done, `this` will be destructed imminently. +} + } // namespace browser_sync
diff --git a/components/autofill/core/browser/payments/autofill_wallet_data_type_controller.h b/components/autofill/core/browser/payments/autofill_wallet_data_type_controller.h index c12ddfb..66380d5d 100644 --- a/components/autofill/core/browser/payments/autofill_wallet_data_type_controller.h +++ b/components/autofill/core/browser/payments/autofill_wallet_data_type_controller.h
@@ -47,6 +47,7 @@ // syncer::SyncServiceObserver implementation. void OnStateChanged(syncer::SyncService* sync) override; + void OnSyncShutdown(syncer::SyncService* sync) override; private: // Callback for changes to the autofill pref.
diff --git a/components/autofill/core/browser/suggestions/payments/credit_card_suggestion_generator.cc b/components/autofill/core/browser/suggestions/payments/credit_card_suggestion_generator.cc new file mode 100644 index 0000000..4f0f14d --- /dev/null +++ b/components/autofill/core/browser/suggestions/payments/credit_card_suggestion_generator.cc
@@ -0,0 +1,94 @@ +// 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 "components/autofill/core/browser/suggestions/payments/credit_card_suggestion_generator.h" + +#include <string> +#include <utility> +#include <vector> + +#include "base/functional/callback.h" +#include "base/functional/function_ref.h" +#include "components/autofill/core/browser/autofill_field.h" +#include "components/autofill/core/browser/data_manager/payments/payments_data_manager.h" +#include "components/autofill/core/browser/data_manager/personal_data_manager.h" +#include "components/autofill/core/browser/form_structure.h" +#include "components/autofill/core/browser/foundations/autofill_client.h" +#include "components/autofill/core/browser/suggestions/suggestion.h" +#include "components/autofill/core/browser/suggestions/suggestion_generator.h" +#include "components/autofill/core/common/form_data.h" + +namespace autofill { + +using SuggestionDataSource = SuggestionGenerator::SuggestionDataSource; + +CreditCardSuggestionGenerator::CreditCardSuggestionGenerator( + AutofillClient* client, + const std::vector<std::string>& four_digit_combinations_in_dom) + : client_(client), + four_digit_combinations_in_dom_(four_digit_combinations_in_dom) {} + +CreditCardSuggestionGenerator::~CreditCardSuggestionGenerator() = default; + +void CreditCardSuggestionGenerator::FetchSuggestionData( + const FormData& form_data, + const FormFieldData& field_data, + const FormStructure* form, + const AutofillField* field, + const AutofillClient& client, + base::OnceCallback< + void(std::pair<SuggestionDataSource, + std::vector<SuggestionGenerator::SuggestionData>>)> + callback) { + FetchSuggestionData( + form_data, field_data, form, field, client, + [&callback](std::pair<SuggestionDataSource, + std::vector<SuggestionGenerator::SuggestionData>> + suggestion_data) { + std::move(callback).Run(std::move(suggestion_data)); + }); +} + +void CreditCardSuggestionGenerator::GenerateSuggestions( + const FormData& form_data, + const FormFieldData& field_data, + const FormStructure* form, + const AutofillField* field, + const std::vector< + std::pair<SuggestionDataSource, std::vector<SuggestionData>>>& + all_suggestion_data, + base::OnceCallback<void(ReturnedSuggestions)> callback) { + GenerateSuggestions( + form_data, field_data, form, field, all_suggestion_data, + [&callback](ReturnedSuggestions returned_suggestions) { + std::move(callback).Run(std::move(returned_suggestions)); + }); +} + +void CreditCardSuggestionGenerator::FetchSuggestionData( + const FormData& form_data, + const FormFieldData& field_data, + const FormStructure* form, + const AutofillField* field, + const AutofillClient& client, + base::FunctionRef< + void(std::pair<SuggestionDataSource, + std::vector<SuggestionGenerator::SuggestionData>>)> + callback) { + // TODO(crbug.com/409962888): will appear in the next CL chain links. +} + +void CreditCardSuggestionGenerator::GenerateSuggestions( + const FormData& form_data, + const FormFieldData& field_data, + const FormStructure* form, + const AutofillField* field, + const std::vector< + std::pair<SuggestionDataSource, std::vector<SuggestionData>>>& + all_suggestion_data, + base::FunctionRef<void(ReturnedSuggestions)> callback) { + // TODO(crbug.com/409962888): will appear in the next CL chain links. +} + +} // namespace autofill
diff --git a/components/autofill/core/browser/suggestions/payments/credit_card_suggestion_generator.h b/components/autofill/core/browser/suggestions/payments/credit_card_suggestion_generator.h new file mode 100644 index 0000000..fcfcdae6 --- /dev/null +++ b/components/autofill/core/browser/suggestions/payments/credit_card_suggestion_generator.h
@@ -0,0 +1,137 @@ +// 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 COMPONENTS_AUTOFILL_CORE_BROWSER_SUGGESTIONS_PAYMENTS_CREDIT_CARD_SUGGESTION_GENERATOR_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_SUGGESTIONS_PAYMENTS_CREDIT_CARD_SUGGESTION_GENERATOR_H_ + +#include "base/functional/function_ref.h" +#include "components/autofill/core/browser/data_manager/payments/payments_data_manager.h" +#include "components/autofill/core/browser/data_manager/personal_data_manager.h" +#include "components/autofill/core/browser/data_model/payments/autofill_wallet_usage_data.h" +#include "components/autofill/core/browser/data_model/payments/credit_card.h" +#include "components/autofill/core/browser/field_types.h" +#include "components/autofill/core/browser/form_structure.h" +#include "components/autofill/core/browser/foundations/autofill_client.h" +#include "components/autofill/core/browser/logging/log_manager.h" +#include "components/autofill/core/browser/metrics/payments/card_metadata_metrics.h" +#include "components/autofill/core/browser/metrics/suggestions_list_metrics.h" +#include "components/autofill/core/browser/payments/payments_autofill_client.h" +#include "components/autofill/core/browser/payments/save_and_fill_manager.h" +#include "components/autofill/core/browser/suggestions/suggestion.h" +#include "components/autofill/core/browser/suggestions/suggestion_generator.h" +#include "components/autofill/core/common/form_data.h" +#include "components/prefs/pref_service.h" +#include "components/sync/service/sync_service.h" +#include "ui/base/l10n/l10n_util.h" + +namespace autofill { + +class AutofillClient; +class PaymentsDataManager; +class FormFieldData; + +// A `SuggestionGenerator` for `FillingProduct::kCreditCard`. +// +// This class encapsulates logic used exclusively for generating credit card +// suggestions. Free functions, that are also used in TouchToFill feature, +// are still shared in payments_suggestion_generator.h file. +class CreditCardSuggestionGenerator : public SuggestionGenerator { + public: + explicit CreditCardSuggestionGenerator( + AutofillClient* client, + const std::vector<std::string>& four_digit_combinations_in_dom); + ~CreditCardSuggestionGenerator() override; + + void FetchSuggestionData( + const FormData& form_data, + const FormFieldData& field_data, + const FormStructure* form, + const AutofillField* field, + const AutofillClient& client, + base::OnceCallback< + void(std::pair<SuggestionDataSource, + std::vector<SuggestionGenerator::SuggestionData>>)> + callback) override; + + void GenerateSuggestions( + const FormData& form_data, + const FormFieldData& field_data, + const FormStructure* form, + const AutofillField* field, + const std::vector< + std::pair<SuggestionDataSource, std::vector<SuggestionData>>>& + all_suggestion_data, + base::OnceCallback<void(ReturnedSuggestions)> callback) override; + + // Like SuggestionGenerator override, but takes a base::FunctionRef instead of + // a base::OnceCallback. Calls that callback exactly once. + // TODO(crbug.com/409962888): Clean up after launch. + void FetchSuggestionData( + const FormData& form_data, + const FormFieldData& field_data, + const FormStructure* form, + const AutofillField* field, + const AutofillClient& client, + base::FunctionRef<void(std::pair<SuggestionDataSource, + std::vector<SuggestionData>>)> callback); + + // Like SuggestionGenerator override, but takes a base::FunctionRef instead of + // a base::OnceCallback. Calls that callback exactly once. + // TODO(crbug.com/409962888): Clean up after launch. + void GenerateSuggestions( + const FormData& form_data, + const FormFieldData& field_data, + const FormStructure* form, + const AutofillField* field, + const std::vector< + std::pair<SuggestionDataSource, std::vector<SuggestionData>>>& + all_suggestion_data, + base::FunctionRef<void(ReturnedSuggestions)> callback); + + void SetCreditCardUploadStatusForTest(bool value) { + credit_card_upload_enabled_for_test_ = value; + } + + void SetConsiderFromAsSecureForTest(bool value) { + consider_form_as_secure_for_testing_ = value; + } + + private: + PaymentsDataManager* payments_data_manager() const { + return &client_->GetPersonalDataManager().payments_data_manager(); + } + + payments::SaveAndFillManager* save_and_fill_manager() const { + return client_->GetPaymentsAutofillClient()->GetSaveAndFillManager(); + } + + PrefService* pref_service() const { return client_->GetPrefs(); } + + syncer::SyncService* sync_service() const { + return client_->GetSyncService(); + } + + LogManager* log_manager() const { return client_->GetCurrentLogManager(); } + + payments::PaymentsAutofillClient* payments_autofill_client() const { + return client_->GetPaymentsAutofillClient(); + } + + raw_ptr<AutofillClient> client_; + + const std::vector<std::string> four_digit_combinations_in_dom_; + + // TODO(crbug.com/409962888): Make naming consistent after moving all logic. + std::optional<bool> credit_card_upload_enabled_for_test_; + std::optional<bool> consider_form_as_secure_for_testing_; + + base::flat_map<std::string, VirtualCardUsageData::VirtualCardLastFour> + virtual_card_guid_to_last_four_map_; + + base::WeakPtrFactory<CreditCardSuggestionGenerator> weak_ptr_factory_{this}; +}; + +} // namespace autofill + +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_SUGGESTIONS_PAYMENTS_CREDIT_CARD_SUGGESTION_GENERATOR_H_
diff --git a/components/autofill/core/browser/test_utils/autofill_test_utils.cc b/components/autofill/core/browser/test_utils/autofill_test_utils.cc index 18259f0c..858080e 100644 --- a/components/autofill/core/browser/test_utils/autofill_test_utils.cc +++ b/components/autofill/core/browser/test_utils/autofill_test_utils.cc
@@ -913,35 +913,37 @@ attributes.emplace_back(AttributeType(kPassportNumber)); attributes.back().SetInfo( PASSPORT_NUMBER, options.number, std::string(options.app_locale), - /*format_string=*/u"", VerificationStatus::kNoStatus); + /*format_string=*/std::nullopt, VerificationStatus::kNoStatus); } if (options.name) { attributes.emplace_back(AttributeType(kPassportName)); attributes.back().SetInfo( NAME_FULL, options.name, std::string(options.app_locale), - /*format_string=*/u"", VerificationStatus::kNoStatus); + /*format_string=*/std::nullopt, VerificationStatus::kNoStatus); attributes.back().FinalizeInfo(); } if (options.country) { attributes.emplace_back(AttributeType(kPassportCountry)); attributes.back().SetInfo(PASSPORT_ISSUING_COUNTRY, options.country, std::string(options.app_locale), - /*format_string=*/u"", + /*format_string=*/std::nullopt, VerificationStatus::kNoStatus); } if (options.expiry_date) { attributes.emplace_back(AttributeType(kPassportExpirationDate)); - attributes.back().SetInfo(PASSPORT_EXPIRATION_DATE, options.expiry_date, - std::string(options.app_locale), - /*format_string=*/u"YYYY-MM-DD", - VerificationStatus::kNoStatus); + attributes.back().SetInfo( + PASSPORT_EXPIRATION_DATE, options.expiry_date, + std::string(options.app_locale), + AutofillFormatString(u"YYYY-MM-DD", FormatString_Type_DATE), + VerificationStatus::kNoStatus); } if (options.issue_date) { attributes.emplace_back(AttributeType(kPassportIssueDate)); - attributes.back().SetInfo(PASSPORT_ISSUE_DATE, options.issue_date, - std::string(options.app_locale), - /*format_string=*/u"YYYY-MM-DD", - VerificationStatus::kNoStatus); + attributes.back().SetInfo( + PASSPORT_ISSUE_DATE, options.issue_date, + std::string(options.app_locale), + AutofillFormatString(u"YYYY-MM-DD", FormatString_Type_DATE), + VerificationStatus::kNoStatus); } return EntityInstance( EntityType(EntityTypeName::kPassport), std::move(attributes), @@ -966,34 +968,36 @@ attributes.emplace_back(AttributeType(kDriversLicenseName)); attributes.back().SetInfo( NAME_FULL, options.name, std::string(options.app_locale), - /*format_string=*/u"", VerificationStatus::kNoStatus); + /*format_string=*/std::nullopt, VerificationStatus::kNoStatus); attributes.back().FinalizeInfo(); } if (options.region) { attributes.emplace_back(AttributeType(kDriversLicenseState)); attributes.back().SetInfo( DRIVERS_LICENSE_REGION, options.region, std::string(options.app_locale), - /*format_string=*/u"", VerificationStatus::kNoStatus); + /*format_string=*/std::nullopt, VerificationStatus::kNoStatus); } if (options.number) { attributes.emplace_back(AttributeType(kDriversLicenseNumber)); attributes.back().SetInfo( DRIVERS_LICENSE_NUMBER, options.number, std::string(options.app_locale), - /*format_string=*/u"", VerificationStatus::kNoStatus); + /*format_string=*/std::nullopt, VerificationStatus::kNoStatus); } if (options.expiration_date) { attributes.emplace_back(AttributeType(kDriversLicenseExpirationDate)); attributes.back().SetInfo( DRIVERS_LICENSE_EXPIRATION_DATE, options.expiration_date, - std::string(options.app_locale), /*format_string=*/u"YYYY-MM-DD", + std::string(options.app_locale), + AutofillFormatString(u"YYYY-MM-DD", FormatString_Type_DATE), VerificationStatus::kNoStatus); } if (options.issue_date) { attributes.emplace_back(AttributeType(kDriversLicenseIssueDate)); - attributes.back().SetInfo(DRIVERS_LICENSE_ISSUE_DATE, options.issue_date, - std::string(options.app_locale), - /*format_string=*/u"YYYY-MM-DD", - VerificationStatus::kNoStatus); + attributes.back().SetInfo( + DRIVERS_LICENSE_ISSUE_DATE, options.issue_date, + std::string(options.app_locale), + AutofillFormatString(u"YYYY-MM-DD", FormatString_Type_DATE), + VerificationStatus::kNoStatus); } return EntityInstance( EntityType(EntityTypeName::kDriversLicense), std::move(attributes), @@ -1019,13 +1023,14 @@ attributes.emplace_back(AttributeType(kKnownTravelerNumberNumber)); attributes.back().SetInfo( KNOWN_TRAVELER_NUMBER, options.number, std::string(options.app_locale), - /*format_string=*/u"", VerificationStatus::kNoStatus); + /*format_string=*/std::nullopt, VerificationStatus::kNoStatus); } if (options.expiration_date) { attributes.emplace_back(AttributeType(kKnownTravelerNumberNumber)); attributes.back().SetInfo( DRIVERS_LICENSE_EXPIRATION_DATE, options.expiration_date, - std::string(options.app_locale), /*format_string=*/u"YYYY-MM-DD", + std::string(options.app_locale), + AutofillFormatString(u"YYYY-MM-DD", FormatString_Type_DATE), VerificationStatus::kNoStatus); } return EntityInstance( @@ -1044,7 +1049,7 @@ attributes.emplace_back(AttributeType(kRedressNumberNumber)); attributes.back().SetInfo( REDRESS_NUMBER, options.number, std::string(options.app_locale), - /*format_string=*/u"", VerificationStatus::kNoStatus); + /*format_string=*/std::nullopt, VerificationStatus::kNoStatus); } return EntityInstance( @@ -1063,44 +1068,44 @@ attributes.emplace_back(AttributeType(kVehicleOwner)); attributes.back().SetInfo( NAME_FULL, options.name, std::string(options.app_locale), - /*format_string=*/u"", VerificationStatus::kNoStatus); + /*format_string=*/std::nullopt, VerificationStatus::kNoStatus); attributes.back().FinalizeInfo(); } if (options.plate) { attributes.emplace_back(AttributeType(kVehiclePlateNumber)); attributes.back().SetInfo( VEHICLE_LICENSE_PLATE, options.plate, std::string(options.app_locale), - /*format_string=*/u"", VerificationStatus::kNoStatus); + /*format_string=*/std::nullopt, VerificationStatus::kNoStatus); } if (options.number) { attributes.emplace_back(AttributeType(kVehicleVin)); attributes.back().SetInfo( VEHICLE_VIN, options.number, std::string(options.app_locale), - /*format_string=*/u"", VerificationStatus::kNoStatus); + /*format_string=*/std::nullopt, VerificationStatus::kNoStatus); } if (options.make) { attributes.emplace_back(AttributeType(kVehicleMake)); attributes.back().SetInfo( VEHICLE_MAKE, options.make, std::string(options.app_locale), - /*format_string=*/u"", VerificationStatus::kNoStatus); + /*format_string=*/std::nullopt, VerificationStatus::kNoStatus); } if (options.model) { attributes.emplace_back(AttributeType(kVehicleModel)); attributes.back().SetInfo( VEHICLE_MODEL, options.model, std::string(options.app_locale), - /*format_string=*/u"", VerificationStatus::kNoStatus); + /*format_string=*/std::nullopt, VerificationStatus::kNoStatus); } if (options.year) { attributes.emplace_back(AttributeType(kVehicleYear)); attributes.back().SetInfo( VEHICLE_YEAR, options.year, std::string(options.app_locale), - /*format_string=*/u"", VerificationStatus::kNoStatus); + /*format_string=*/std::nullopt, VerificationStatus::kNoStatus); } if (options.state) { attributes.emplace_back(AttributeType(kVehiclePlateState)); attributes.back().SetInfo( VEHICLE_PLATE_STATE, options.state, std::string(options.app_locale), - /*format_string=*/u"", VerificationStatus::kNoStatus); + /*format_string=*/std::nullopt, VerificationStatus::kNoStatus); } return EntityInstance( EntityType(EntityTypeName::kVehicle), std::move(attributes), @@ -1124,21 +1129,21 @@ attributes.emplace_back(AttributeType(kNationalIdCardNumber)); attributes.back().SetInfo(NATIONAL_ID_CARD_NUMBER, options.number, std::string(options.app_locale), - /*format_string=*/u"", + /*format_string=*/std::nullopt, VerificationStatus::kNoStatus); } if (options.country) { attributes.emplace_back(AttributeType(kNationalIdCardCountry)); attributes.back().SetInfo(NATIONAL_ID_CARD_ISSUING_COUNTRY, options.country, std::string(options.app_locale), - /*format_string=*/u"", + /*format_string=*/std::nullopt, VerificationStatus::kNoStatus); } if (options.issue_date) { attributes.emplace_back(AttributeType(kNationalIdCardIssueDate)); attributes.back().SetInfo(NATIONAL_ID_CARD_ISSUE_DATE, options.issue_date, std::string(options.app_locale), - /*format_string=*/u"", + /*format_string=*/std::nullopt, VerificationStatus::kNoStatus); } if (options.expiry_date) { @@ -1146,7 +1151,7 @@ attributes.back().SetInfo( NATIONAL_ID_CARD_EXPIRATION_DATE, options.expiry_date, std::string(options.app_locale), - /*format_string=*/u"", VerificationStatus::kNoStatus); + /*format_string=*/std::nullopt, VerificationStatus::kNoStatus); } return EntityInstance( EntityType(EntityTypeName::kNationalIdCard), std::move(attributes), @@ -1165,7 +1170,7 @@ attributes.emplace_back(AttributeType(kFlightReservationPassengerName)); attributes.back().SetInfo( NAME_FULL, options.name, std::string(options.app_locale), - /*format_string=*/u"", VerificationStatus::kNoStatus); + /*format_string=*/std::nullopt, VerificationStatus::kNoStatus); attributes.back().FinalizeInfo(); } if (options.flight_number) { @@ -1173,35 +1178,35 @@ attributes.back().SetInfo( FLIGHT_RESERVATION_FLIGHT_NUMBER, options.flight_number, std::string(options.app_locale), - /*format_string=*/u"", VerificationStatus::kNoStatus); + /*format_string=*/std::nullopt, VerificationStatus::kNoStatus); } if (options.ticket_number) { attributes.emplace_back(AttributeType(kFlightReservationTicketNumber)); attributes.back().SetInfo( FLIGHT_RESERVATION_TICKET_NUMBER, options.ticket_number, std::string(options.app_locale), - /*format_string=*/u"", VerificationStatus::kNoStatus); + /*format_string=*/std::nullopt, VerificationStatus::kNoStatus); } if (options.confirmation_code) { attributes.emplace_back(AttributeType(kFlightReservationConfirmationCode)); attributes.back().SetInfo( FLIGHT_RESERVATION_CONFIRMATION_CODE, options.confirmation_code, std::string(options.app_locale), - /*format_string=*/u"", VerificationStatus::kNoStatus); + /*format_string=*/std::nullopt, VerificationStatus::kNoStatus); } if (options.departure_airport) { attributes.emplace_back(AttributeType(kFlightReservationDepartureAirport)); attributes.back().SetInfo( FLIGHT_RESERVATION_DEPARTURE_AIRPORT, options.departure_airport, std::string(options.app_locale), - /*format_string=*/u"", VerificationStatus::kNoStatus); + /*format_string=*/std::nullopt, VerificationStatus::kNoStatus); } if (options.arrival_airport) { attributes.emplace_back(AttributeType(kFlightReservationArrivalAirport)); attributes.back().SetInfo( FLIGHT_RESERVATION_ARRIVAL_AIRPORT, options.arrival_airport, std::string(options.app_locale), - /*format_string=*/u"", VerificationStatus::kNoStatus); + /*format_string=*/std::nullopt, VerificationStatus::kNoStatus); } return EntityInstance(
diff --git a/components/autofill/core/browser/test_utils/autofill_test_utils.h b/components/autofill/core/browser/test_utils/autofill_test_utils.h index fc0313d..b7c5d7a 100644 --- a/components/autofill/core/browser/test_utils/autofill_test_utils.h +++ b/components/autofill/core/browser/test_utils/autofill_test_utils.h
@@ -466,9 +466,9 @@ template <typename = void> struct FlightReservationOptionsT { - const char16_t* flight_number = u"987654321"; + const char16_t* flight_number = u"AA123"; const char16_t* ticket_number = u"123123456"; - const char16_t* confirmation_code = u"0123"; + const char16_t* confirmation_code = u"AB4KW5"; const char16_t* name = u"John Doe"; const char16_t* departure_airport = u"MUC"; const char16_t* arrival_airport = u"BEY";
diff --git a/components/autofill/core/browser/webdata/autofill_ai/entity_table.cc b/components/autofill/core/browser/webdata/autofill_ai/entity_table.cc index 0b3b274..d82eab4 100644 --- a/components/autofill/core/browser/webdata/autofill_ai/entity_table.cc +++ b/components/autofill/core/browser/webdata/autofill_ai/entity_table.cc
@@ -96,10 +96,13 @@ std::u16string value) -> AttributeInstance { auto type = AttributeType(type_name); auto instance = AttributeInstance(AttributeType(type)); - instance.SetInfo(instance.type().field_type(), value, /*app_locale=*/"", - /*format_string=*/ - IsDateFieldType(type.field_type()) ? u"YYYY-MM-DD" : u"", - VerificationStatus::kNoStatus); + instance.SetInfo( + instance.type().field_type(), value, /*app_locale=*/"", + /*format_string=*/ + IsDateFieldType(type.field_type()) + ? AutofillFormatString(u"YYYY-MM-DD", FormatString_Type_DATE) + : base::optional_ref<const AutofillFormatString>(), + VerificationStatus::kNoStatus); return instance; };
diff --git a/components/autofill/core/common/autofill_features.cc b/components/autofill/core/common/autofill_features.cc index dad161a..a6d8101 100644 --- a/components/autofill/core/common/autofill_features.cc +++ b/components/autofill/core/common/autofill_features.cc
@@ -33,6 +33,12 @@ BASE_FEATURE(kAutofillAcrossIframesIosTriggerFormExtraction, base::FEATURE_DISABLED_BY_DEFAULT); +// If enabled, whitespace is discarded during normalization of a house +// number field. +// TODO(crbug.com/447111009): Remove when launched. +BASE_FEATURE(kAutofillAddressDiscardWhitespaceInHouseNumber, + base::FEATURE_DISABLED_BY_DEFAULT); + // Feature flag to control displaying of Autofill suggestions on // unclassified fields based on prefix matching. These suggestions are displayed // after the user typed a certain number of characters that match some data @@ -198,6 +204,12 @@ BASE_FEATURE(kAutofillAiVoteForFormatStringsForAffixes, base::FEATURE_DISABLED_BY_DEFAULT); +// If enabled, votes for the format of flight number fields are uploaded. For +// example, if there is a flight number "LH89" on file, a submitted value of +// "89" on a field with type `FLIGHT_RESERVATION_FLIGHT_NUMBER` uploads "N". +BASE_FEATURE(kAutofillAiVoteForFormatStringsForFlightNumbers, + base::FEATURE_DISABLED_BY_DEFAULT); + // Enables the second iteration AutofillAI. BASE_FEATURE(kAutofillAiWithDataSchema, IS_AUTOFILL_AI_PLATFORM ? base::FEATURE_ENABLED_BY_DEFAULT
diff --git a/components/autofill/core/common/autofill_features.h b/components/autofill/core/common/autofill_features.h index 3ddc252..6aa1803a 100644 --- a/components/autofill/core/common/autofill_features.h +++ b/components/autofill/core/common/autofill_features.h
@@ -20,6 +20,8 @@ COMPONENT_EXPORT(AUTOFILL) BASE_DECLARE_FEATURE(kAutofillAcrossIframesIosTriggerFormExtraction); COMPONENT_EXPORT(AUTOFILL) +BASE_DECLARE_FEATURE(kAutofillAddressDiscardWhitespaceInHouseNumber); +COMPONENT_EXPORT(AUTOFILL) BASE_DECLARE_FEATURE(kAutofillAddressSuggestionsOnTyping); COMPONENT_EXPORT(AUTOFILL) BASE_DECLARE_FEATURE(kAutofillAddressUserDeclinedSaveSurvey); @@ -75,6 +77,8 @@ COMPONENT_EXPORT(AUTOFILL) BASE_DECLARE_FEATURE(kAutofillAiVoteForFormatStringsForAffixes); COMPONENT_EXPORT(AUTOFILL) +BASE_DECLARE_FEATURE(kAutofillAiVoteForFormatStringsForFlightNumbers); +COMPONENT_EXPORT(AUTOFILL) BASE_DECLARE_FEATURE(kAutofillAiWithDataSchema); COMPONENT_EXPORT(AUTOFILL) extern const base::FeatureParam<int>
diff --git a/components/autofill/core/common/autofill_prefs.cc b/components/autofill/core/common/autofill_prefs.cc index dfb51ae..f7b33941 100644 --- a/components/autofill/core/common/autofill_prefs.cc +++ b/components/autofill/core/common/autofill_prefs.cc
@@ -58,6 +58,9 @@ registry->RegisterIntegerPref( kAutofillNameAndEmailProfileNotSelectedCounter, 0, user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF); + registry->RegisterBooleanPref( + kAutofillWasNameAndEmailProfileUsed, false, + user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF); // Non-synced prefs. Used for per-device choices, e.g., signin promo. registry->RegisterDictionaryPref(kAutofillAiOptInStatus);
diff --git a/components/autofill/core/common/autofill_prefs.h b/components/autofill/core/common/autofill_prefs.h index 87ac3fc..6118d4f 100644 --- a/components/autofill/core/common/autofill_prefs.h +++ b/components/autofill/core/common/autofill_prefs.h
@@ -118,6 +118,12 @@ // accept `kAccountNameEmail` profile suggestion. inline constexpr char kAutofillNameAndEmailProfileNotSelectedCounter[] = "autofill.name_and_email_profile_not_selected_counter"; +// Boolean responsible for storing if kAccountNameEmail profile suggestion was +// filled and submitted. The use_count (and other types of `AutofillProfile` +// metadata) are not synced for kAccountNameEmail profile, thus making the +// tracking of the usage pref based. +inline constexpr char kAutofillWasNameAndEmailProfileUsed[] = + "autofill.was_name_and_email_profile_used"; // Integer that is set to the last major version where the Autocomplete // retention policy was run. inline constexpr char kAutocompleteLastVersionRetentionPolicy[] =
diff --git a/components/autofill/core/common/save_password_progress_logger.cc b/components/autofill/core/common/save_password_progress_logger.cc index 09d66ae1..6b215ea 100644 --- a/components/autofill/core/common/save_password_progress_logger.cc +++ b/components/autofill/core/common/save_password_progress_logger.cc
@@ -588,7 +588,7 @@ return "Actor login: the form to fill went away"; case STRING_ACTOR_LOGIN_NO_USERNAME_FIELD: return "Actor login: no username field"; - case STRING_ACTOR_LOGIN_NO_PASWORD_FIELD: + case STRING_ACTOR_LOGIN_NO_PASSWORD_FIELD: return "Actor login: no password field"; case STRING_ACTOR_LOGIN_FILLING_FIELD_WITH_ID: return "Actor login: filling field with id";
diff --git a/components/autofill/core/common/save_password_progress_logger.h b/components/autofill/core/common/save_password_progress_logger.h index f58a3ac..c1923f5 100644 --- a/components/autofill/core/common/save_password_progress_logger.h +++ b/components/autofill/core/common/save_password_progress_logger.h
@@ -223,7 +223,7 @@ STRING_ACTOR_LOGIN_FRAME_CHANGED, STRING_ACTOR_LOGIN_FORM_WENT_AWAY, STRING_ACTOR_LOGIN_NO_USERNAME_FIELD, - STRING_ACTOR_LOGIN_NO_PASWORD_FIELD, + STRING_ACTOR_LOGIN_NO_PASSWORD_FIELD, STRING_ACTOR_LOGIN_FILLING_FIELD_WITH_ID, STRING_ACTOR_LOGIN_USERNAME_FILL_SUCCESS, STRING_ACTOR_LOGIN_PASSWORD_FILL_SUCCESS,
diff --git a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/chips/ChipView.java b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/chips/ChipView.java index b92e671..2e5c2b9f 100644 --- a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/chips/ChipView.java +++ b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/chips/ChipView.java
@@ -70,6 +70,7 @@ private final ChromeImageView mStartIcon; private final boolean mUseRoundedStartIcon; private final LoadingView mLoadingView; + private final @Px int mTextStartPadding; private final @StyleRes int mSecondaryTextAppearanceId; private final boolean mTextAlignStart; private final int mEndIconWidth; @@ -191,8 +192,7 @@ .getDimensionPixelSize( R.dimen.chip_text_multiline_vertical_padding)); mTextAlignStart = a.getBoolean(R.styleable.ChipView_textAlignStart, false); - @Px - int textStartPadding = + mTextStartPadding = a.getDimensionPixelSize( R.styleable.ChipView_primaryTextStartPadding, getResources() @@ -234,6 +234,8 @@ new AppCompatTextView(new ContextThemeWrapper(getContext(), R.style.ChipTextView)); mPrimaryText.setId(R.id.chip_view_primary_text); mPrimaryText.setTextAppearance(primaryTextAppearance); + // Reduce font padding if the text is aligned vertically. + mPrimaryText.setIncludeFontPadding(!alignTextVertically); // If false fall back to single line defined in XML styles. if (allowMultipleLines) { @@ -251,7 +253,7 @@ mPrimaryText.setTextAlignment(View.TEXT_ALIGNMENT_VIEW_START); } mPrimaryText.setPaddingRelative( - textStartPadding, + mTextStartPadding, mPrimaryText.getPaddingTop(), mPrimaryText.getPaddingEnd(), mPrimaryText.getPaddingBottom()); @@ -456,6 +458,8 @@ new ContextThemeWrapper(getContext(), R.style.ChipTextView)); mSecondaryText.setId(R.id.chip_view_secondary_text); mSecondaryText.setTextAppearance(mSecondaryTextAppearanceId); + // Reduce font padding if the text is aligned vertically. + mSecondaryText.setIncludeFontPadding(isSingleLineChip()); // Ensure that basic state changes are aligned with the ChipView. They update // automatically once the view is part of the hierarchy. mSecondaryText.setSelected(isSelected()); @@ -464,6 +468,13 @@ if (mTextAlignStart) { mSecondaryText.setTextAlignment(View.TEXT_ALIGNMENT_VIEW_START); } + // Align secondary text view with the primary text view if they are stacked + // vertically. + mSecondaryText.setPaddingRelative( + mTextStartPadding, + mSecondaryText.getPaddingTop(), + mSecondaryText.getPaddingEnd(), + mSecondaryText.getPaddingBottom()); mTextViewsWrapper.addView(mSecondaryText); } else { addView(mSecondaryText);
diff --git a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/chips/ChipViewRenderTest.java b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/chips/ChipViewRenderTest.java index 8bbb9f4..c621c0c 100644 --- a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/chips/ChipViewRenderTest.java +++ b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/chips/ChipViewRenderTest.java
@@ -64,6 +64,7 @@ public final RenderTestRule mRenderTestRule = RenderTestRule.Builder.withPublicCorpus() .setBugComponent(Component.UI_BROWSER_MOBILE) + .setRevision(2) .build(); private ViewGroup mContentView;
diff --git a/components/cronet/android/BUILD.gn b/components/cronet/android/BUILD.gn index 1442a3c..9b811380 100644 --- a/components/cronet/android/BUILD.gn +++ b/components/cronet/android/BUILD.gn
@@ -28,9 +28,12 @@ _gn_path = "//buildtools/linux64/gn" _ninja_path = "//third_party/ninja/ninja" -assert(!is_component_build) assert(is_cronet_build) +assert(!is_component_build) +assert(use_platform_icu_alternatives, + "Cronet only supports being built with ICU alternatives") + generate_jni("cronet_jni_headers") { sources = [ "java/src/org/chromium/net/impl/CompletionOnceCallback.java", @@ -198,7 +201,6 @@ "//net", "//third_party/zlib", "//url", - "//url:buildflags", ] if (!is_cronet_for_aosp_build) { deps += [ "//components/cronet/native:cronet_native_impl" ] @@ -240,10 +242,6 @@ "log", ] - if (!use_platform_icu_alternatives) { - deps += [ "//base:i18n" ] - } - # TODO(crbug.com/40031409): Fix code that adds exit-time destructors and # enable the diagnostic by removing this line. configs += [ "//build/config/compiler:no_exit_time_destructors" ] @@ -1190,7 +1188,6 @@ ":cronet_test_apk_jni", ":cronet_tests_jni_headers", "//base", - "//base:i18n", "//base/test:test_support", "//components/cronet:cronet_common", "//components/cronet:cronet_version_header", @@ -2146,11 +2143,9 @@ group("cronet_non_test_package") { # Target containing all of cronet's non-test targets. - # Enforce building with ICU alternatives, crbug.com/611621. # Enforce that arm_use_neon==false when building for ARMv7 by # not including any deps in cronet_package target otherwise. - if (use_platform_icu_alternatives && - (!(target_cpu == "arm" && arm_version == 7) || !arm_use_neon)) { + if (!(target_cpu == "arm" && arm_version == 7) || !arm_use_neon) { deps = [ ":cronet_package_copy", ":cronet_package_copy_native_headers",
diff --git a/components/cronet/android/cronet_library_loader.cc b/components/cronet/android/cronet_library_loader.cc index aff9e209..881d77c 100644 --- a/components/cronet/android/cronet_library_loader.cc +++ b/components/cronet/android/cronet_library_loader.cc
@@ -51,11 +51,6 @@ #include "net/proxy_resolution/proxy_config_service_android.h" #include "third_party/perfetto/include/perfetto/tracing/tracing.h" #include "third_party/zlib/zlib.h" -#include "url/buildflags.h" - -#if !BUILDFLAG(USE_PLATFORM_ICU_ALTERNATIVES) -#include "base/i18n/icu_util.h" // nogncheck -#endif // Must come after all headers that specialize FromJniType() / ToJniType(). #include "components/cronet/android/cronet_jni_headers/CronetLibraryLoader_jni.h" @@ -166,10 +161,6 @@ jboolean initializePerfetto) { logging::InitLogging(logging::LoggingSettings()); -#if !BUILDFLAG(USE_PLATFORM_ICU_ALTERNATIVES) - base::i18n::InitializeICU(); -#endif - if (!base::ThreadPoolInstance::Get()) { base::ThreadPoolInstance::CreateAndStartWithDefaultParams("Cronet"); }
diff --git a/components/cronet/tools/utils.py b/components/cronet/tools/utils.py index 708a35f..90d326d2 100755 --- a/components/cronet/tools/utils.py +++ b/components/cronet/tools/utils.py
@@ -22,11 +22,11 @@ _MB_PATH = os.path.join(REPOSITORY_ROOT, 'tools/mb/mb.py') GN_PATH = os.path.join(REPOSITORY_ROOT, 'buildtools/linux64/gn') NINJA_PATH = os.path.join(REPOSITORY_ROOT, 'third_party/ninja/ninja') +# Cronet in Android is distributed via Mainline +# (https://source.android.com/docs/core/ota/modular-system) to devices back to +# Android R (API 30). MIN_SDK_VERSION_FOR_AOSP = 30 ARCHS = ['x86', 'x64', 'arm', 'arm64', 'riscv64'] -AOSP_EXTRA_ARGS = ('is_cronet_for_aosp_build=true', 'use_nss_certs=false', - 'use_allocator_shim=false', - f'default_min_sdk_version={MIN_SDK_VERSION_FOR_AOSP}') _GN_ARG_MATCHER = re.compile("^.*=.*$") @@ -157,13 +157,34 @@ all_deps.remove('') return all_deps - def get_gn_args_for_aosp(arch: str) -> List[str]: - default_args = filter_gn_args(get_android_gn_args(True, arch), - ["use_remoteexec", "default_min_sdk_version"]) - default_args.extend(AOSP_EXTRA_ARGS) - return default_args - + # This is the source of truth for GN args for Cronet in Android. + # Note: for readability and discoverability, prefer to make the default value + # of the GN arg depend on `is_cronet_for_aosp_build` GN arg whenever possible, + # instead of setting the value here. + return ( + # TODO: https://crbug.com/446652679 - It might be possible to drop this. + 'dcheck_always_on = false', + # TODO: https://crbug.com/446652679 - It might be possible to drop this. + 'debuggable_apks = false', + # Override here, instead of modifying `default_min_sdk_version`'s + # declaration to avoid hardcoding this value twice (there is no easy way + # to share a constant between GN and python files). + f'default_min_sdk_version={MIN_SDK_VERSION_FOR_AOSP}', + # TODO: https://crbug.com/446652679 - It might be possible to drop this. + 'is_debug = false', + 'is_cronet_for_aosp_build=true', + # TODO: https://crbug.com/446652679 - It might be possible to drop this. + 'is_component_build = false', + # TODO: https://crbug.com/446652193 - It might be possible to drop this. + 'is_official_build = true', + # TODO: https://crbug.com/446652679 - It might be possible to drop this. + 'strip_debug_info = true', + # TODO: https://crbug.com/446652679 - It might be possible to drop this. + 'symbol_level = 1', + f'target_cpu = "{arch}"', + 'target_os = "android"', + ) def android_gn_gen(is_release, target_cpu, out_dir): """Runs `gn gen` using Cronet's android gn_args.
diff --git a/components/enterprise/client_certificates/core/certificate_provisioning_service.cc b/components/enterprise/client_certificates/core/certificate_provisioning_service.cc index 95ddcab7..4357f918 100644 --- a/components/enterprise/client_certificates/core/certificate_provisioning_service.cc +++ b/components/enterprise/client_certificates/core/certificate_provisioning_service.cc
@@ -9,6 +9,7 @@ #include <vector> #include "base/check.h" +#include "base/containers/contains.h" #include "base/functional/bind.h" #include "base/functional/callback.h" #include "base/memory/raw_ptr.h" @@ -64,6 +65,8 @@ // CertificateProvisioningService: void GetManagedIdentity(GetManagedIdentityCallback callback) override; + void DeleteManagedIdentities( + base::OnceCallback<void(bool)> callback) override; Status GetCurrentStatus() const override; private: @@ -92,6 +95,10 @@ scoped_refptr<net::X509Certificate> certificate, std::optional<StoreError> commit_error); + void OnIdentitiesDeleted(const std::vector<std::string>& identity_names, + base::OnceCallback<void(bool)> callback, + std::optional<StoreError> error); + void OnProvisioningError( ProvisioningError error, std::optional<StoreError> store_error = std::nullopt); @@ -191,6 +198,21 @@ } } +void CertificateProvisioningServiceImpl::DeleteManagedIdentities( + base::OnceCallback<void(bool)> callback) { + if (IsProvisioning()) { + std::move(callback).Run(false); + return; + } + std::vector<std::string> identity_names = {identity_name(), + temporary_identity_name()}; + certificate_store_->DeleteIdentities( + identity_names, + base::BindOnce(&CertificateProvisioningServiceImpl::OnIdentitiesDeleted, + weak_factory_.GetWeakPtr(), identity_names, + std::move(callback))); +} + CertificateProvisioningService::Status CertificateProvisioningServiceImpl::GetCurrentStatus() const { Status status(IsProvisioning()); @@ -461,6 +483,33 @@ OnFinishedProvisioning(/*success=*/true); } +void CertificateProvisioningServiceImpl::OnIdentitiesDeleted( + const std::vector<std::string>& identity_names, + base::OnceCallback<void(bool)> callback, + std::optional<StoreError> error) { + if (error.has_value()) { + LOG_POLICY(ERROR, DEVICE_TRUST) + << "Failed to delete identities from store: " + << StoreErrorToString(error.value()); + std::move(callback).Run(false); + return; + } + + LOG_POLICY(INFO, DEVICE_TRUST) + << "Identities successfully deleted from store."; + + if (cached_identity_ && + base::Contains(identity_names, cached_identity_->name)) { + if (cached_identity_->certificate) { + context_delegate_->OnClientCertificateDeleted( + cached_identity_->certificate); + } + cached_identity_ = std::nullopt; + } + + std::move(callback).Run(true); +} + void CertificateProvisioningServiceImpl::OnProvisioningError( ProvisioningError provisioning_error, std::optional<StoreError> store_error) {
diff --git a/components/enterprise/client_certificates/core/certificate_provisioning_service.h b/components/enterprise/client_certificates/core/certificate_provisioning_service.h index e99217703..fd5f789 100644 --- a/components/enterprise/client_certificates/core/certificate_provisioning_service.h +++ b/components/enterprise/client_certificates/core/certificate_provisioning_service.h
@@ -65,6 +65,14 @@ // some reason, subsequent calls will retry loading it. virtual void GetManagedIdentity(GetManagedIdentityCallback callback) = 0; + // Deletes the managed identities (permanent and temporary). `callback` will + // be invoked with true if the identities were deleted successfully, and false + // otherwise. In case of an unexpected failure, the identities might still + // exist in the store but not be usable anymore currently we just log an + // error. + virtual void DeleteManagedIdentities( + base::OnceCallback<void(bool)> callback) = 0; + // Returns metadata about the current status of the service, mainly for // debugging purposes. virtual Status GetCurrentStatus() const = 0;
diff --git a/components/enterprise/client_certificates/core/certificate_provisioning_service_unittest.cc b/components/enterprise/client_certificates/core/certificate_provisioning_service_unittest.cc index 5ecd809..5d5c592 100644 --- a/components/enterprise/client_certificates/core/certificate_provisioning_service_unittest.cc +++ b/components/enterprise/client_certificates/core/certificate_provisioning_service_unittest.cc
@@ -840,4 +840,81 @@ VerifyIdleWithCache(mocked_private_key, fake_cert, kSuccessUploadCode); } +TEST_F(CertificateProvisioningServiceTest, DeleteManagedIdentities_Success) { + SetPolicyPref(true); + + auto mocked_private_key = base::MakeRefCounted<StrictMock<MockPrivateKey>>(); + auto test_cert = LoadTestCert(); + ClientIdentity existing_identity(kIdentityName, mocked_private_key, + test_cert); + + auto mock_context_delegate = CreateContextDelegate(); + auto* mock_context_delegate_ptr = mock_context_delegate.get(); + + // This will be called on service creation since policy is enabled. + EXPECT_CALL(mock_store_, GetIdentity(kIdentityName, _)) + .WillOnce(RunOnceCallback<1>(existing_identity)); + + CreateProvisioningService( + std::move(mock_context_delegate), + std::make_unique<StrictMock<MockKeyUploadClient>>()); + ASSERT_TRUE(service_); + + // Let the service initialize. + task_environment_.RunUntilIdle(); + + // Verify that the identity is cached. + auto status_before_delete = service_->GetCurrentStatus(); + ASSERT_TRUE(status_before_delete.identity.has_value()); + EXPECT_TRUE(test_cert->EqualsIncludingChain( + status_before_delete.identity->certificate.get())); + + // Set up expectations for deletion. + EXPECT_CALL(mock_store_, + DeleteIdentities( + testing::ElementsAre(kIdentityName, kTempIdentityName), _)) + .WillOnce(RunOnceCallback<1>(std::nullopt)); + EXPECT_CALL(*mock_context_delegate_ptr, + OnClientCertificateDeleted(test_cert)); + + base::test::TestFuture<bool> delete_future; + service_->DeleteManagedIdentities(delete_future.GetCallback()); + EXPECT_TRUE(delete_future.Get()); + + // Verify the cache is cleared. + auto status_after_delete = service_->GetCurrentStatus(); + EXPECT_FALSE(status_after_delete.identity.has_value()); +} + +TEST_F(CertificateProvisioningServiceTest, DeleteManagedIdentities_NoIdentity) { + CreateProvisioningService( + CreateContextDelegate(), + std::make_unique<StrictMock<MockKeyUploadClient>>()); + + EXPECT_CALL(mock_store_, + DeleteIdentities( + testing::ElementsAre(kIdentityName, kTempIdentityName), _)) + .WillOnce(RunOnceCallback<1>(std::nullopt)); + + base::test::TestFuture<bool> delete_future; + service_->DeleteManagedIdentities(delete_future.GetCallback()); + EXPECT_TRUE(delete_future.Get()); +} + +TEST_F(CertificateProvisioningServiceTest, + DeleteManagedIdentities_StoreDeleteFailure) { + CreateProvisioningService( + CreateContextDelegate(), + std::make_unique<StrictMock<MockKeyUploadClient>>()); + + EXPECT_CALL(mock_store_, + DeleteIdentities( + testing::ElementsAre(kIdentityName, kTempIdentityName), _)) + .WillOnce(RunOnceCallback<1>(StoreError::kDeleteIdentityFailed)); + + base::test::TestFuture<bool> delete_future; + service_->DeleteManagedIdentities(delete_future.GetCallback()); + EXPECT_FALSE(delete_future.Get()); +} + } // namespace client_certificates
diff --git a/components/enterprise/client_certificates/core/certificate_store.h b/components/enterprise/client_certificates/core/certificate_store.h index c901af7..e5d37f8d 100644 --- a/components/enterprise/client_certificates/core/certificate_store.h +++ b/components/enterprise/client_certificates/core/certificate_store.h
@@ -8,6 +8,7 @@ #include <memory> #include <optional> #include <string> +#include <vector> #include "base/functional/callback_forward.h" #include "base/memory/scoped_refptr.h" @@ -72,6 +73,13 @@ const std::string& identity_name, base::OnceCallback<void(StoreErrorOr<std::optional<ClientIdentity>>)> callback) = 0; + + // Will delete the identities with the given `identity_names`. Will invoke + // `callback` with std::nullopt on success, or with an error if something + // went wrong. + virtual void DeleteIdentities( + const std::vector<std::string>& identity_names, + base::OnceCallback<void(std::optional<StoreError>)> callback) = 0; }; } // namespace client_certificates
diff --git a/components/enterprise/client_certificates/core/leveldb_certificate_store.cc b/components/enterprise/client_certificates/core/leveldb_certificate_store.cc index 2370731..0faf0dba 100644 --- a/components/enterprise/client_certificates/core/leveldb_certificate_store.cc +++ b/components/enterprise/client_certificates/core/leveldb_certificate_store.cc
@@ -246,6 +246,42 @@ base::BindOnce(OnIdentityFetched, std::move(callback))); } +void LevelDbCertificateStore::DeleteIdentities( + const std::vector<std::string>& identity_names, + base::OnceCallback<void(std::optional<StoreError>)> callback) { + for (const auto& identity_name : identity_names) { + if (identity_name.empty()) { + std::move(callback).Run(StoreError::kInvalidIdentityName); + return; + } + } + + if (database_state_ != DatabaseState::kInitialized) { + pending_operations_.push_back(base::BindOnce( + &LevelDbCertificateStore::DeleteIdentities, weak_factory_.GetWeakPtr(), + identity_names, std::move(callback))); + InitializeDatabase(); + return; + } + + auto mod_keys = std::make_unique<std::vector<std::string>>(identity_names); + + database_->UpdateEntries( + std::make_unique<leveldb_proto::ProtoDatabase< + client_certificates_pb::ClientIdentity>::KeyEntryVector>(), + std::move(mod_keys), + base::BindOnce( + [](base::OnceCallback<void(std::optional<StoreError>)> callback, + bool success) { + if (!success) { + std::move(callback).Run(StoreError::kDeleteIdentityFailed); + return; + } + std::move(callback).Run(std::nullopt); + }, + std::move(callback))); +} + void LevelDbCertificateStore::CreatePrivateKeyInner( const std::string& identity_name, base::OnceCallback<void(StoreErrorOr<scoped_refptr<PrivateKey>>)> callback,
diff --git a/components/enterprise/client_certificates/core/leveldb_certificate_store.h b/components/enterprise/client_certificates/core/leveldb_certificate_store.h index 0b2a2e1b..7b66c09 100644 --- a/components/enterprise/client_certificates/core/leveldb_certificate_store.h +++ b/components/enterprise/client_certificates/core/leveldb_certificate_store.h
@@ -79,6 +79,9 @@ const std::string& identity_name, base::OnceCallback<void(StoreErrorOr<std::optional<ClientIdentity>>)> callback) override; + void DeleteIdentities( + const std::vector<std::string>& identity_names, + base::OnceCallback<void(std::optional<StoreError>)> callback) override; private: enum class DatabaseState {
diff --git a/components/enterprise/client_certificates/core/leveldb_certificate_store_unittest.cc b/components/enterprise/client_certificates/core/leveldb_certificate_store_unittest.cc index 279da2cd..5fba9a97 100644 --- a/components/enterprise/client_certificates/core/leveldb_certificate_store_unittest.cc +++ b/components/enterprise/client_certificates/core/leveldb_certificate_store_unittest.cc
@@ -748,4 +748,39 @@ EXPECT_THAT(test_future.Get(), ErrorIs(StoreError::kLoadKeyFailed)); } +TEST_F(LevelDbCertificateStoreTest, DeleteIdentities_Success) { + client_certificates_pb::ClientIdentity proto_identity; + *proto_identity.mutable_private_key() = CreateFakeProtoKey(); + AddDatabaseEntry(kTestIdentityName, proto_identity); + AddDatabaseEntry(kOtherTestIdentityName, proto_identity); + + base::test::TestFuture<std::optional<StoreError>> test_future; + store_->DeleteIdentities({kTestIdentityName, kOtherTestIdentityName}, + test_future.GetCallback()); + + fake_db_->InitStatusCallback(InitStatus::kOK); + fake_db_->UpdateCallback(/*success=*/true); + + EXPECT_EQ(test_future.Get(), std::nullopt); + ExpectNoDatabaseEntry(kTestIdentityName); + ExpectNoDatabaseEntry(kOtherTestIdentityName); +} + +TEST_F(LevelDbCertificateStoreTest, DeleteIdentities_NotFound) { + base::test::TestFuture<std::optional<StoreError>> test_future; + store_->DeleteIdentities({kTestIdentityName}, test_future.GetCallback()); + + fake_db_->InitStatusCallback(InitStatus::kOK); + fake_db_->UpdateCallback(/*success=*/true); + + EXPECT_EQ(test_future.Get(), std::nullopt); +} + +TEST_F(LevelDbCertificateStoreTest, DeleteIdentities_InvalidName) { + base::test::TestFuture<std::optional<StoreError>> test_future; + store_->DeleteIdentities({kTestIdentityName, ""}, test_future.GetCallback()); + + EXPECT_EQ(test_future.Get(), StoreError::kInvalidIdentityName); +} + } // namespace client_certificates
diff --git a/components/enterprise/client_certificates/core/mock_certificate_provisioning_service.h b/components/enterprise/client_certificates/core/mock_certificate_provisioning_service.h index 8ee2f30d..e2f9619 100644 --- a/components/enterprise/client_certificates/core/mock_certificate_provisioning_service.h +++ b/components/enterprise/client_certificates/core/mock_certificate_provisioning_service.h
@@ -5,6 +5,8 @@ #ifndef COMPONENTS_ENTERPRISE_CLIENT_CERTIFICATES_CORE_MOCK_CERTIFICATE_PROVISIONING_SERVICE_H_ #define COMPONENTS_ENTERPRISE_CLIENT_CERTIFICATES_CORE_MOCK_CERTIFICATE_PROVISIONING_SERVICE_H_ +#include <memory> + #include "base/functional/callback.h" #include "components/enterprise/client_certificates/core/certificate_provisioning_service.h" #include "components/enterprise/client_certificates/core/certificate_store.h" @@ -23,7 +25,12 @@ GetManagedIdentity, (GetManagedIdentityCallback), (override)); + MOCK_METHOD(void, + DeleteManagedIdentities, + (base::OnceCallback<void(bool)> callback), + (override)); MOCK_METHOD(Status, GetCurrentStatus, (), (const, override)); + }; } // namespace client_certificates
diff --git a/components/enterprise/client_certificates/core/mock_certificate_store.h b/components/enterprise/client_certificates/core/mock_certificate_store.h index 515de6a..d66b7209 100644 --- a/components/enterprise/client_certificates/core/mock_certificate_store.h +++ b/components/enterprise/client_certificates/core/mock_certificate_store.h
@@ -47,6 +47,11 @@ (const std::string&, base::OnceCallback<void(StoreErrorOr<std::optional<ClientIdentity>>)>), (override)); + MOCK_METHOD(void, + DeleteIdentities, + (const std::vector<std::string>&, + base::OnceCallback<void(std::optional<StoreError>)>), + (override)); }; } // namespace client_certificates
diff --git a/components/enterprise/client_certificates/core/prefs_certificate_store.cc b/components/enterprise/client_certificates/core/prefs_certificate_store.cc index 8286121..05f75b1 100644 --- a/components/enterprise/client_certificates/core/prefs_certificate_store.cc +++ b/components/enterprise/client_certificates/core/prefs_certificate_store.cc
@@ -203,4 +203,23 @@ std::move(callback).Run(private_key); } +void PrefsCertificateStore::DeleteIdentities( + const std::vector<std::string>& identity_names, + base::OnceCallback<void(std::optional<StoreError>)> callback) { + // Check that all identity names are non-empty. + for (const auto& identity_name : identity_names) { + if (identity_name.empty()) { + std::move(callback).Run(StoreError::kInvalidIdentityName); + return; + } + } + + // Clear all identities from the prefs. + for (const auto& identity_name : identity_names) { + pref_service_->ClearPref(identity_name); + } + + std::move(callback).Run(std::nullopt); +} + } // namespace client_certificates
diff --git a/components/enterprise/client_certificates/core/prefs_certificate_store.h b/components/enterprise/client_certificates/core/prefs_certificate_store.h index 9a16cab..78e05d08 100644 --- a/components/enterprise/client_certificates/core/prefs_certificate_store.h +++ b/components/enterprise/client_certificates/core/prefs_certificate_store.h
@@ -57,6 +57,9 @@ const std::string& identity_name, base::OnceCallback<void(StoreErrorOr<std::optional<ClientIdentity>>)> callback) override; + void DeleteIdentities( + const std::vector<std::string>& identity_names, + base::OnceCallback<void(std::optional<StoreError>)> callback) override; private: // Called when a private key was created from `CreatePrivateKeyInner`.
diff --git a/components/enterprise/client_certificates/core/prefs_certificate_store_unittest.cc b/components/enterprise/client_certificates/core/prefs_certificate_store_unittest.cc index 418e729..523118f 100644 --- a/components/enterprise/client_certificates/core/prefs_certificate_store_unittest.cc +++ b/components/enterprise/client_certificates/core/prefs_certificate_store_unittest.cc
@@ -375,4 +375,38 @@ EXPECT_THAT(test_future.Get(), ErrorIs(StoreError::kLoadKeyFailed)); } +TEST_F(PrefsCertificateStoreTest, DeleteIdentities_Success) { + base::Value::Dict identity; + identity.Set(kCertificate, "some_cert"); + prefs_.SetDict(kTestIdentityName, identity.Clone()); + prefs_.SetDict(kOtherTestIdentityName, identity.Clone()); + ASSERT_TRUE(prefs_.HasPrefPath(kTestIdentityName)); + ASSERT_TRUE(prefs_.HasPrefPath(kOtherTestIdentityName)); + + base::test::TestFuture<std::optional<StoreError>> test_future; + store_->DeleteIdentities({kTestIdentityName, kOtherTestIdentityName}, + test_future.GetCallback()); + + EXPECT_EQ(test_future.Get(), std::nullopt); + EXPECT_FALSE(prefs_.HasPrefPath(kTestIdentityName)); + EXPECT_FALSE(prefs_.HasPrefPath(kOtherTestIdentityName)); +} + +TEST_F(PrefsCertificateStoreTest, DeleteIdentities_NotFound) { + ASSERT_FALSE(prefs_.HasPrefPath(kTestIdentityName)); + + base::test::TestFuture<std::optional<StoreError>> test_future; + store_->DeleteIdentities({kTestIdentityName}, test_future.GetCallback()); + + EXPECT_EQ(test_future.Get(), std::nullopt); + EXPECT_FALSE(prefs_.HasPrefPath(kTestIdentityName)); +} + +TEST_F(PrefsCertificateStoreTest, DeleteIdentities_InvalidName) { + base::test::TestFuture<std::optional<StoreError>> test_future; + store_->DeleteIdentities({kTestIdentityName, ""}, test_future.GetCallback()); + + EXPECT_EQ(test_future.Get(), StoreError::kInvalidIdentityName); +} + } // namespace client_certificates
diff --git a/components/enterprise/client_certificates/core/store_error.cc b/components/enterprise/client_certificates/core/store_error.cc index 2d5d4e59..3f96256 100644 --- a/components/enterprise/client_certificates/core/store_error.cc +++ b/components/enterprise/client_certificates/core/store_error.cc
@@ -32,6 +32,8 @@ return "InvalidFinalIdentityName"; case StoreError::kIdentityNotFound: return "IdentityNotFound"; + case StoreError::kDeleteIdentityFailed: + return "DeleteIdentityFailed"; } }
diff --git a/components/enterprise/client_certificates/core/store_error.h b/components/enterprise/client_certificates/core/store_error.h index 9004984..805ad9bf 100644 --- a/components/enterprise/client_certificates/core/store_error.h +++ b/components/enterprise/client_certificates/core/store_error.h
@@ -27,7 +27,8 @@ kLoadKeyFailed = 9, kInvalidFinalIdentityName = 10, kIdentityNotFound = 11, - kMaxValue = kIdentityNotFound + kDeleteIdentityFailed = 12, + kMaxValue = kDeleteIdentityFailed }; template <class T>
diff --git a/components/gcm_driver/crypto/message_payload_parser_unittest.cc b/components/gcm_driver/crypto/message_payload_parser_unittest.cc index eebb733..a096946 100644 --- a/components/gcm_driver/crypto/message_payload_parser_unittest.cc +++ b/components/gcm_driver/crypto/message_payload_parser_unittest.cc
@@ -10,6 +10,7 @@ #include "base/compiler_specific.h" #include "base/containers/span.h" #include "base/numerics/byte_conversions.h" +#include "base/strings/string_view_util.h" #include "components/gcm_driver/crypto/gcm_decryption_result.h" #include "testing/gtest/include/gtest/gtest.h" @@ -47,13 +48,11 @@ // Creates an std::string for the |kValidMessage| constant. std::string CreateMessageString() { - std::string result(kValidMessage.size(), 0x0); - base::as_writable_byte_span(result).copy_from_nonoverlapping(kValidMessage); - return result; + return std::string(base::as_string_view(kValidMessage)); } TEST(MessagePayloadParserTest, ValidMessage) { - MessagePayloadParser parser(CreateMessageString()); + MessagePayloadParser parser(base::as_string_view(kValidMessage)); ASSERT_TRUE(parser.IsValid()); base::span<const uint8_t> salt = base::span(kValidMessage).first(kSaltSize); @@ -82,10 +81,8 @@ } TEST(MessagePayloadParserTest, MinimumMessageSize) { - std::string message = CreateMessageString(); - message.resize(std::size(kValidMessage) / 2); - - MessagePayloadParser parser(message); + MessagePayloadParser parser( + base::as_string_view(kValidMessage).substr(0u, kValidMessage.size() / 2)); EXPECT_FALSE(parser.IsValid()); EXPECT_EQ(parser.GetFailureReason(), GCMDecryptionResult::INVALID_BINARY_HEADER_PAYLOAD_LENGTH);
diff --git a/components/history/core/browser/sync/history_data_type_controller.cc b/components/history/core/browser/sync/history_data_type_controller.cc index a04027e..a7e11dad 100644 --- a/components/history/core/browser/sync/history_data_type_controller.cc +++ b/components/history/core/browser/sync/history_data_type_controller.cc
@@ -164,6 +164,10 @@ helper_.sync_service()->DataTypePreconditionChanged(type()); } +void HistoryDataTypeController::OnSyncShutdown(syncer::SyncService* sync) { + // Nothing to be done, `this` will be destructed imminently. +} + void HistoryDataTypeController::AccountTypeDetermined() { helper_.sync_service()->DataTypePreconditionChanged(type()); }
diff --git a/components/history/core/browser/sync/history_data_type_controller.h b/components/history/core/browser/sync/history_data_type_controller.h index db3118d8..3bcdfba4 100644 --- a/components/history/core/browser/sync/history_data_type_controller.h +++ b/components/history/core/browser/sync/history_data_type_controller.h
@@ -43,6 +43,7 @@ // syncer::SyncServiceObserver implementation. void OnStateChanged(syncer::SyncService* sync) override; + void OnSyncShutdown(syncer::SyncService* sync) override; private: void AccountTypeDetermined();
diff --git a/components/history/core/browser/sync/history_delete_directives_data_type_controller.cc b/components/history/core/browser/sync/history_delete_directives_data_type_controller.cc index 2084944..a345a83 100644 --- a/components/history/core/browser/sync/history_delete_directives_data_type_controller.cc +++ b/components/history/core/browser/sync/history_delete_directives_data_type_controller.cc
@@ -96,4 +96,9 @@ helper_.sync_service()->DataTypePreconditionChanged(type()); } +void HistoryDeleteDirectivesDataTypeController::OnSyncShutdown( + syncer::SyncService* sync) { + // Nothing to be done, `this` will be destructed imminently. +} + } // namespace history
diff --git a/components/history/core/browser/sync/history_delete_directives_data_type_controller.h b/components/history/core/browser/sync/history_delete_directives_data_type_controller.h index b5db1ed2..b8c433cb 100644 --- a/components/history/core/browser/sync/history_delete_directives_data_type_controller.h +++ b/components/history/core/browser/sync/history_delete_directives_data_type_controller.h
@@ -51,6 +51,7 @@ // syncer::SyncServiceObserver implementation. void OnStateChanged(syncer::SyncService* sync) override; + void OnSyncShutdown(syncer::SyncService* sync) override; private: history::HistoryDataTypeControllerHelper helper_;
diff --git a/components/ip_protection/common/ip_protection_data_types.h b/components/ip_protection/common/ip_protection_data_types.h index 04cd63294..0a27fd2 100644 --- a/components/ip_protection/common/ip_protection_data_types.h +++ b/components/ip_protection/common/ip_protection_data_types.h
@@ -183,7 +183,7 @@ kInvalidEpochIdSize = 15, kMaxValue = kInvalidEpochIdSize, }; -// LINT.ThenChange(//tools/metrics/histograms/metadata/network/enums.xml:ProbabilisticRevealTokensResult) +// LINT.ThenChange(//tools/metrics/histograms/metadata/ip_protection/enums.xml:ProbabilisticRevealTokensResult) // Stores return status of TryGetProbabilisticRevealTokens() together with // NetError() returned by url loader.
diff --git a/components/ip_protection/common/ip_protection_telemetry.h b/components/ip_protection/common/ip_protection_telemetry.h index 27ac307..bb68641 100644 --- a/components/ip_protection/common/ip_protection_telemetry.h +++ b/components/ip_protection/common/ip_protection_telemetry.h
@@ -81,7 +81,7 @@ kAvailableForOtherCachedGeo = 3, kMaxValue = kAvailableForOtherCachedGeo, }; -// LINT.ThenChange(//tools/metrics/histograms/metadata/network/enums.xml:IpProtectionGetAuthTokenResultForGeo) +// LINT.ThenChange(//tools/metrics/histograms/metadata/ip_protection/enums.xml:IpProtectionGetAuthTokenResultForGeo) // An enumeration of events affecting the token count. These values are // persisted to logs. Entries should not be renumbered and numeric values should @@ -103,7 +103,7 @@ kAuthAndSign, kUnblindTokens, }; -// LINT.ThenChange(//tools/metrics/histograms/metadata/network/histograms.xml:BlindSignAuthPhase) +// LINT.ThenChange(//tools/metrics/histograms/metadata/ip_protection/histograms.xml:BlindSignAuthPhase) // An abstract interface for all of the telemetry associated with IP Protection. //
diff --git a/components/one_time_tokens/OWNERS b/components/one_time_tokens/OWNERS index 50580fd0..7df1e838 100644 --- a/components/one_time_tokens/OWNERS +++ b/components/one_time_tokens/OWNERS
@@ -1,2 +1,3 @@ battre@chromium.org koerber@google.com +luchenpeng@google.com
diff --git a/components/optimization_guide/core/optimization_guide_features.cc b/components/optimization_guide/core/optimization_guide_features.cc index a10593d9..0cc913c 100644 --- a/components/optimization_guide/core/optimization_guide_features.cc +++ b/components/optimization_guide/core/optimization_guide_features.cc
@@ -75,9 +75,6 @@ BASE_FEATURE(kOverrideNumThreadsForModelExecution, base::FEATURE_DISABLED_BY_DEFAULT); -BASE_FEATURE(kOptGuideEnableXNNPACKDelegateWithTFLite, - base::FEATURE_ENABLED_BY_DEFAULT); - // Killswitch for fetching on search results from a remote Optimization Guide // Service. BASE_FEATURE(kOptimizationGuideFetchingForSRP, @@ -395,10 +392,6 @@ return std::min(num_threads, base::SysInfo::NumberOfProcessors()); } -bool TFLiteXNNPACKDelegateEnabled() { - return base::FeatureList::IsEnabled(kOptGuideEnableXNNPACKDelegateWithTFLite); -} - std::map<proto::OptimizationTarget, std::set<int64_t>> GetPredictionModelVersionsInKillSwitch() { if (!base::FeatureList::IsEnabled(
diff --git a/components/optimization_guide/core/optimization_guide_features.h b/components/optimization_guide/core/optimization_guide_features.h index f56f69e..dfe69db8 100644 --- a/components/optimization_guide/core/optimization_guide_features.h +++ b/components/optimization_guide/core/optimization_guide_features.h
@@ -49,8 +49,6 @@ COMPONENT_EXPORT(OPTIMIZATION_GUIDE_FEATURES) BASE_DECLARE_FEATURE(kOverrideNumThreadsForModelExecution); COMPONENT_EXPORT(OPTIMIZATION_GUIDE_FEATURES) -BASE_DECLARE_FEATURE(kOptGuideEnableXNNPACKDelegateWithTFLite); -COMPONENT_EXPORT(OPTIMIZATION_GUIDE_FEATURES) BASE_DECLARE_FEATURE(kOptimizationGuidePersonalizedFetching); COMPONENT_EXPORT(OPTIMIZATION_GUIDE_FEATURES) BASE_DECLARE_FEATURE(kOptimizationGuidePredictionModelKillswitch); @@ -245,11 +243,6 @@ std::optional<int> OverrideNumThreadsForOptTarget( proto::OptimizationTarget opt_target); -// Whether XNNPACK should be used with TFLite, on platforms where it is -// supported. This is a no-op on unsupported platforms. -COMPONENT_EXPORT(OPTIMIZATION_GUIDE_FEATURES) -bool TFLiteXNNPACKDelegateEnabled(); - // Whether logging of model quality is enabled. COMPONENT_EXPORT(OPTIMIZATION_GUIDE_FEATURES) bool IsModelQualityLoggingEnabled();
diff --git a/components/optimization_guide/core/tflite_op_resolver.cc b/components/optimization_guide/core/tflite_op_resolver.cc index 3f7de3e5..f46c802b 100644 --- a/components/optimization_guide/core/tflite_op_resolver.cc +++ b/components/optimization_guide/core/tflite_op_resolver.cc
@@ -387,12 +387,10 @@ tflite::ops::builtin::Register_RANDOM_UNIFORM()); #if BUILDFLAG(BUILD_TFLITE_WITH_XNNPACK) - if (features::TFLiteXNNPACKDelegateEnabled()) { - delegate_creators_.push_back([](TfLiteContext* context) { - return tflite::MaybeCreateXNNPACKDelegate( - context, tflite::XNNPackQS8Options::default_value); - }); - } + delegate_creators_.push_back([](TfLiteContext* context) { + return tflite::MaybeCreateXNNPACKDelegate( + context, tflite::XNNPackQS8Options::default_value); + }); #endif }
diff --git a/components/page_load_metrics/renderer/features.cc b/components/page_load_metrics/renderer/features.cc index b892bff..5ba3282 100644 --- a/components/page_load_metrics/renderer/features.cc +++ b/components/page_load_metrics/renderer/features.cc
@@ -7,15 +7,7 @@ #include "base/feature_list.h" namespace page_load_metrics::features { - -// Reduce the number of `DidObserveNewFeatureUsage` calls. crbug.com/404425954 -// for more details. -BASE_FEATURE(kDidObserveNewFeatureUsageImprovement, +// Reduce the number of observer calls. crbug.com/40442595 for more details. +BASE_FEATURE(kMetricsRenderFrameObserverImprovement, base::FEATURE_DISABLED_BY_DEFAULT); - -// Reduce the number of `DidObserveSubresourceLoad` calls. crbug.com/404425954 -// for more details. -BASE_FEATURE(kDidObserveSubresourceLoadImprovement, - base::FEATURE_DISABLED_BY_DEFAULT); - } // namespace page_load_metrics::features
diff --git a/components/page_load_metrics/renderer/features.h b/components/page_load_metrics/renderer/features.h index 4d761f1e..c8808eb3 100644 --- a/components/page_load_metrics/renderer/features.h +++ b/components/page_load_metrics/renderer/features.h
@@ -8,7 +8,6 @@ #include "base/feature_list.h" namespace page_load_metrics::features { -BASE_DECLARE_FEATURE(kDidObserveNewFeatureUsageImprovement); -BASE_DECLARE_FEATURE(kDidObserveSubresourceLoadImprovement); +BASE_DECLARE_FEATURE(kMetricsRenderFrameObserverImprovement); } #endif // COMPONENTS_PAGE_LOAD_METRICS_RENDERER_FEATURES_H_
diff --git a/components/page_load_metrics/renderer/metrics_render_frame_observer.cc b/components/page_load_metrics/renderer/metrics_render_frame_observer.cc index 5d0e144..e0b085d 100644 --- a/components/page_load_metrics/renderer/metrics_render_frame_observer.cc +++ b/components/page_load_metrics/renderer/metrics_render_frame_observer.cc
@@ -109,21 +109,23 @@ blink::WebLocalFrameObserver(render_frame ? render_frame->GetWebFrame() : nullptr) { if (base::FeatureList::IsEnabled( - features::kDidObserveNewFeatureUsageImprovement) && + features::kMetricsRenderFrameObserverImprovement) && render_frame) { // If the optimization is enabled, `DidObserveNewFeatureUsage()` will be // called as a callback instead of the observer interface. render_frame->SetNewFeatureUsageCallback(base::BindRepeating( &MetricsRenderFrameObserver::DidObserveNewFeatureUsage, weak_factory_.GetWeakPtr())); - } - if (base::FeatureList::IsEnabled( - features::kDidObserveSubresourceLoadImprovement)) { // If the optimization is enabled, `DidObserveSubresourceLoad()` will be // called as a callback instead of the observer interface. render_frame->SetSubresourceLoadCallback(base::BindRepeating( &MetricsRenderFrameObserver::DidObserveSubresourceLoad, weak_factory_.GetWeakPtr())); + // If the optimization is enabled, `DidLoadResourceFromMemoryCache()` will + // be called as a callback instead of the observer interface. + render_frame->SetLoadFromMemoryCacheCallback(base::BindRepeating( + &MetricsRenderFrameObserver::DidLoadResourceFromMemoryCache, + weak_factory_.GetWeakPtr())); } }
diff --git a/components/password_manager/core/browser/actor_login/BUILD.gn b/components/password_manager/core/browser/actor_login/BUILD.gn index 47b8fbf..d5ac785 100644 --- a/components/password_manager/core/browser/actor_login/BUILD.gn +++ b/components/password_manager/core/browser/actor_login/BUILD.gn
@@ -4,7 +4,10 @@ import("//build/config/features.gni") -assert(!is_android) +# The code can theoretically be used on mobile too, it's just currently +# not needed. Remove the asserts if using it on mobile and remember +# to also modify components/BUILD.gn to start building the tests. +assert(!is_android && !is_ios) # All actor_login code should be able to depend on this. source_set("common") {
diff --git a/components/password_manager/core/browser/actor_login/internal/BUILD.gn b/components/password_manager/core/browser/actor_login/internal/BUILD.gn index f5f68d3c..697027d 100644 --- a/components/password_manager/core/browser/actor_login/internal/BUILD.gn +++ b/components/password_manager/core/browser/actor_login/internal/BUILD.gn
@@ -4,7 +4,10 @@ import("//build/config/features.gni") -assert(!is_android) +# The code can theoretically be used on mobile too, it's just currently +# not needed. Remove the asserts if using it on mobile and remember +# to also modify components/BUILD.gn to start building the tests. +assert(!is_android && !is_ios) source_set("delegate") { sources = [ @@ -32,6 +35,7 @@ "//components/password_manager/core/browser", "//components/password_manager/core/browser:password_form", "//components/password_manager/core/browser/actor_login:common", + "//components/password_manager/core/browser/features:password_features", "//components/strings:components_strings", "//url", ] @@ -51,6 +55,7 @@ "//components/password_manager/core/browser:test_support", "//components/password_manager/core/browser/actor_login:common", "//components/password_manager/core/browser/actor_login/test:test_support", + "//components/password_manager/core/browser/features:password_features", "//testing/gmock", "//testing/gtest", "//url",
diff --git a/components/password_manager/core/browser/actor_login/internal/actor_login_credential_filler.cc b/components/password_manager/core/browser/actor_login/internal/actor_login_credential_filler.cc index 301afc2..54a4914 100644 --- a/components/password_manager/core/browser/actor_login/internal/actor_login_credential_filler.cc +++ b/components/password_manager/core/browser/actor_login/internal/actor_login_credential_filler.cc
@@ -7,7 +7,6 @@ #include <ranges> #include <utility> -#include "base/functional/callback.h" #include "base/functional/callback_forward.h" #include "base/functional/concurrent_closures.h" #include "base/strings/to_string.h" @@ -19,6 +18,7 @@ #include "components/password_manager/core/browser/actor_login/actor_login_types.h" #include "components/password_manager/core/browser/actor_login/internal/actor_login_util.h" #include "components/password_manager/core/browser/browser_save_password_progress_logger.h" +#include "components/password_manager/core/browser/features/password_features.h" #include "components/password_manager/core/browser/password_form.h" #include "components/password_manager/core/browser/password_form_cache.h" #include "components/password_manager/core/browser/password_form_manager.h" @@ -148,16 +148,25 @@ autofill::FormRendererId form_renderer_id = signin_form_manager->GetParsedObservedForm()->form_data.renderer_id(); - auto fill_form_cb = base::BindOnce( - &ActorLoginCredentialFiller::FillForm, weak_ptr_factory_.GetWeakPtr(), - driver, form_renderer_id, stored_credential->username_value, - stored_credential->password_value); + base::OnceClosure fill_cb = base::DoNothing(); + if (base::FeatureList::IsEnabled( + password_manager::features::kActorLoginFillingHeuristics)) { + fill_cb = base::BindOnce(&ActorLoginCredentialFiller::FillAllEligibleFields, + weak_ptr_factory_.GetWeakPtr(), + stored_credential->username_value, + stored_credential->password_value); + } else { + fill_cb = base::BindOnce( + &ActorLoginCredentialFiller::FillForm, weak_ptr_factory_.GetWeakPtr(), + driver, form_renderer_id, stored_credential->username_value, + stored_credential->password_value); + } if (client_->IsReauthBeforeFillingRequired(device_authenticator_.get())) { LogStatus(logger.get(), Logger::STRING_ACTOR_LOGIN_WAITING_FOR_REAUTH); - ReauthenticateAndFill(std::move(fill_form_cb)); + ReauthenticateAndFill(std::move(fill_cb)); } else { - std::move(fill_form_cb).Run(); + std::move(fill_cb).Run(); } } @@ -244,6 +253,40 @@ weak_ptr_factory_.GetWeakPtr())); } +void ActorLoginCredentialFiller::FillAllEligibleFields( + std::u16string username, + std::u16string password) { + PasswordManagerInterface* password_manager = client_->GetPasswordManager(); + PasswordFormCache* form_cache = password_manager->GetPasswordFormCache(); + + base::ConcurrentClosures concurrent_filling; + for (const auto& manager : form_cache->GetFormManagers()) { + if (!manager->GetDriver()) { + continue; + } + if (!manager->GetDriver()->GetLastCommittedOrigin().IsSameOriginWith( + origin_)) { + continue; + } + + const password_manager::PasswordForm* parsed_form = + manager->GetParsedObservedForm(); + if (!parsed_form || !IsLoginForm(*parsed_form)) { + continue; + } + FillField(manager->GetDriver().get(), + parsed_form->username_element_renderer_id, username, + FieldType::kUsername, concurrent_filling.CreateClosure()); + FillField(manager->GetDriver().get(), + parsed_form->password_element_renderer_id, password, + FieldType::kPassword, concurrent_filling.CreateClosure()); + } + + std::move(concurrent_filling) + .Done(base::BindOnce(&ActorLoginCredentialFiller::OnFillingDone, + weak_ptr_factory_.GetWeakPtr())); +} + void ActorLoginCredentialFiller::FillField(PasswordManagerDriver* driver, FieldRendererId field_renderer_id, const std::u16string& value, @@ -290,4 +333,5 @@ std::move(callback_).Run( GetEndFillingResult(username_filled_, password_filled_)); } + } // namespace actor_login
diff --git a/components/password_manager/core/browser/actor_login/internal/actor_login_credential_filler.h b/components/password_manager/core/browser/actor_login/internal/actor_login_credential_filler.h index 6bad2691..8718063 100644 --- a/components/password_manager/core/browser/actor_login/internal/actor_login_credential_filler.h +++ b/components/password_manager/core/browser/actor_login/internal/actor_login_credential_filler.h
@@ -63,6 +63,9 @@ std::u16string username, std::u16string password); + // Fills all eligible fields with `username` and `password`. + void FillAllEligibleFields(std::u16string username, std::u16string password); + // Fills the field of `type` identified by `field_renderer_id` within the // `driver`'s frame with `value`. `closure` will be called to signal // completion at the very end of the flow.
diff --git a/components/password_manager/core/browser/actor_login/internal/actor_login_credential_filler_unittest.cc b/components/password_manager/core/browser/actor_login/internal/actor_login_credential_filler_unittest.cc index fea5c61..a9171bec 100644 --- a/components/password_manager/core/browser/actor_login/internal/actor_login_credential_filler_unittest.cc +++ b/components/password_manager/core/browser/actor_login/internal/actor_login_credential_filler_unittest.cc
@@ -5,6 +5,7 @@ #include "base/test/gmock_callback_support.h" #include "base/test/mock_callback.h" +#include "base/test/scoped_feature_list.h" #include "base/test/task_environment.h" #include "base/test/test_future.h" #include "base/types/expected.h" @@ -19,6 +20,7 @@ #include "components/password_manager/core/browser/actor_login/actor_login_types.h" #include "components/password_manager/core/browser/actor_login/test/actor_login_test_util.h" #include "components/password_manager/core/browser/fake_form_fetcher.h" +#include "components/password_manager/core/browser/features/password_features.h" #include "components/password_manager/core/browser/mock_password_form_cache.h" #include "components/password_manager/core/browser/mock_password_manager.h" #include "components/password_manager/core/browser/password_form.h" @@ -80,6 +82,10 @@ class MockPasswordManagerClient : public password_manager::StubPasswordManagerClient { public: + MOCK_METHOD(const PasswordManagerInterface*, + GetPasswordManager, + (), + (const, override)); MOCK_METHOD(bool, IsFillingEnabled, (const GURL&), (const, override)); MOCK_METHOD(bool, IsReauthBeforeFillingRequired, @@ -137,6 +143,8 @@ // Used by `PasswordFormManager`. OSCryptMocker::SetUp(); + ON_CALL(mock_client_, GetPasswordManager) + .WillByDefault(Return(&mock_password_manager_)); ON_CALL(mock_password_manager_, GetPasswordFormCache()) .WillByDefault(Return(&mock_form_cache_)); ON_CALL(mock_driver_, IsInPrimaryMainFrame).WillByDefault(Return(true)); @@ -170,9 +178,9 @@ base::test::SingleThreadTaskEnvironment task_environment_; autofill::test::AutofillUnitTestEnvironment autofill_test_environment_{ {.disable_server_communication = true}}; - MockPasswordManager mock_password_manager_; - MockPasswordFormCache mock_form_cache_; - MockPasswordManagerClient mock_client_; + testing::NiceMock<MockPasswordManager> mock_password_manager_; + testing::NiceMock<MockPasswordFormCache> mock_form_cache_; + testing::NiceMock<MockPasswordManagerClient> mock_client_; MockStubPasswordManagerDriver mock_driver_; FakeFormFetcher form_fetcher_; }; @@ -334,6 +342,9 @@ // Tests filling the username and password in a single chosen form. TEST_F(ActorLoginCredentialFillerTest, FillUsernameAndPasswordSingleForm) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndDisableFeature( + password_manager::features::kActorLoginFillingHeuristics); const url::Origin origin = url::Origin::Create(GURL(kLoginUrl)); const Credential credential = CreateTestCredential(kTestUsername, origin.GetURL()); @@ -381,6 +392,9 @@ // Tests filling the username in a single chosen form. TEST_F(ActorLoginCredentialFillerTest, FillOnlyUsernameFieldSingleForm) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndDisableFeature( + password_manager::features::kActorLoginFillingHeuristics); const url::Origin origin = url::Origin::Create(GURL(kLoginUrl)); const Credential credential = CreateTestCredential(kTestUsername, origin.GetURL()); @@ -429,6 +443,9 @@ // Tests filling the password in a single chosen form. TEST_F(ActorLoginCredentialFillerTest, FillOnlyPasswordFieldSingleForm) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndDisableFeature( + password_manager::features::kActorLoginFillingHeuristics); const url::Origin origin = url::Origin::Create(GURL(kLoginUrl)); const Credential credential = CreateTestCredential(kTestUsername, origin.GetURL()); @@ -477,6 +494,9 @@ // Tests filling the username in a single chosen form. TEST_F(ActorLoginCredentialFillerTest, FillUsernameFailsSingleForm) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndDisableFeature( + password_manager::features::kActorLoginFillingHeuristics); const url::Origin origin = url::Origin::Create(GURL(kLoginUrl)); const Credential credential = CreateTestCredential(kTestUsername, origin.GetURL()); @@ -521,6 +541,9 @@ // Tests filling the password in a single chosen form. TEST_F(ActorLoginCredentialFillerTest, FillPasswordFailsSingleForm) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndDisableFeature( + password_manager::features::kActorLoginFillingHeuristics); const url::Origin origin = url::Origin::Create(GURL(kLoginUrl)); const Credential credential = CreateTestCredential(kTestUsername, origin.GetURL()); @@ -564,6 +587,9 @@ // Tests that filling both fields fails in a single chosen form. TEST_F(ActorLoginCredentialFillerTest, FillBothFailsSingleForm) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndDisableFeature( + password_manager::features::kActorLoginFillingHeuristics); const url::Origin origin = url::Origin::Create(GURL(kLoginUrl)); const Credential credential = CreateTestCredential(kTestUsername, origin.GetURL()); @@ -606,6 +632,287 @@ EXPECT_EQ(result.value(), LoginStatusResult::kErrorNoFillableFields); } +// Tests filling username and password succeeds if filling all eligible fields. +TEST_F(ActorLoginCredentialFillerTest, + FillUsernameAndPasswordInAllEligibleFields) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature( + password_manager::features::kActorLoginFillingHeuristics); + const url::Origin origin = url::Origin::Create(GURL(kLoginUrl)); + const Credential credential = + CreateTestCredential(kTestUsername, origin.GetURL()); + const FormData form_data = CreateSigninFormData(origin.GetURL()); + const FormData username_only_form_data = + CreateUsernameOnlyFormData(origin.GetURL()); + const FormData password_only_form_data = + CreatePasswordOnlyFormData(origin.GetURL()); + + // Make sure a saved credential with a matching username exists. + SetSavedCredential(&form_fetcher_, origin.GetURL(), kTestUsername, + kTestPassword); + + // Simulate signin forms existing on the page. + std::vector<std::unique_ptr<PasswordFormManager>> form_managers; + form_managers.push_back(CreateFormManagerWithParsedForm(origin, form_data)); + form_managers.push_back( + CreateFormManagerWithParsedForm(origin, username_only_form_data)); + form_managers.push_back( + CreateFormManagerWithParsedForm(origin, password_only_form_data)); + + const PasswordForm* parsed_form = form_managers[0]->GetParsedObservedForm(); + const PasswordForm* username_only_parsed_form = + form_managers[1]->GetParsedObservedForm(); + const PasswordForm* password_only_parsed_form = + form_managers[2]->GetParsedObservedForm(); + + base::test::TestFuture<LoginStatusResultOrError> future; + ActorLoginCredentialFiller filler(origin, credential, &mock_client_, + future.GetCallback()); + + ON_CALL(mock_form_cache_, GetFormManagers) + .WillByDefault(Return(base::span(form_managers))); + + // There are 4 fields to fill, so there should be 4 calls to the driver, + // one for each field. Make the first 2 fail and the last 2 succeed. + EXPECT_CALL( + mock_driver_, + FillField(parsed_form->username_element_renderer_id, Eq(kTestUsername), + autofill::FieldPropertiesFlags::kAutofilledActorLogin, _)) + .WillOnce(RunOnceCallback<3>(false)); + EXPECT_CALL( + mock_driver_, + FillField(parsed_form->password_element_renderer_id, Eq(kTestPassword), + autofill::FieldPropertiesFlags::kAutofilledActorLogin, _)) + .WillOnce(RunOnceCallback<3>(false)); + EXPECT_CALL( + mock_driver_, + FillField(username_only_parsed_form->username_element_renderer_id, + Eq(kTestUsername), + autofill::FieldPropertiesFlags::kAutofilledActorLogin, _)) + .WillOnce(RunOnceCallback<3>(true)); + EXPECT_CALL( + mock_driver_, + FillField(password_only_parsed_form->password_element_renderer_id, + Eq(kTestPassword), + autofill::FieldPropertiesFlags::kAutofilledActorLogin, _)) + .WillOnce(RunOnceCallback<3>(true)); + + filler.AttemptLogin(&mock_password_manager_); + const LoginStatusResultOrError& result = future.Get(); + ASSERT_TRUE(result.has_value()); + EXPECT_EQ(result.value(), + LoginStatusResult::kSuccessUsernameAndPasswordFilled); +} + +TEST_F(ActorLoginCredentialFillerTest, FillOnlyUsernameInAllEligibleFields) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature( + password_manager::features::kActorLoginFillingHeuristics); + const url::Origin origin = url::Origin::Create(GURL(kLoginUrl)); + const Credential credential = + CreateTestCredential(kTestUsername, origin.GetURL()); + const FormData form_data = CreateSigninFormData(origin.GetURL()); + const FormData username_only_form_data = + CreateUsernameOnlyFormData(origin.GetURL()); + const FormData password_only_form_data = + CreatePasswordOnlyFormData(origin.GetURL()); + + // Make sure a saved credential with a matching username exists. + SetSavedCredential(&form_fetcher_, origin.GetURL(), kTestUsername, + kTestPassword); + + // Simulate signin forms existing on the page. + std::vector<std::unique_ptr<PasswordFormManager>> form_managers; + form_managers.push_back(CreateFormManagerWithParsedForm(origin, form_data)); + form_managers.push_back( + CreateFormManagerWithParsedForm(origin, username_only_form_data)); + form_managers.push_back( + CreateFormManagerWithParsedForm(origin, password_only_form_data)); + + const PasswordForm* parsed_form = form_managers[0]->GetParsedObservedForm(); + const PasswordForm* username_only_parsed_form = + form_managers[1]->GetParsedObservedForm(); + const PasswordForm* password_only_parsed_form = + form_managers[2]->GetParsedObservedForm(); + + base::test::TestFuture<LoginStatusResultOrError> future; + ActorLoginCredentialFiller filler(origin, credential, &mock_client_, + future.GetCallback()); + + ON_CALL(mock_form_cache_, GetFormManagers) + .WillByDefault(Return(base::span(form_managers))); + + // There are 4 fields to fill, so there should be 4 calls to the driver, + // one for each field. Make all password fields filling fail and one + // username filling succeed. + EXPECT_CALL( + mock_driver_, + FillField(parsed_form->username_element_renderer_id, Eq(kTestUsername), + autofill::FieldPropertiesFlags::kAutofilledActorLogin, _)) + .WillOnce(RunOnceCallback<3>(false)); + EXPECT_CALL( + mock_driver_, + FillField(parsed_form->password_element_renderer_id, Eq(kTestPassword), + autofill::FieldPropertiesFlags::kAutofilledActorLogin, _)) + .WillOnce(RunOnceCallback<3>(false)); + EXPECT_CALL( + mock_driver_, + FillField(username_only_parsed_form->username_element_renderer_id, + Eq(kTestUsername), + autofill::FieldPropertiesFlags::kAutofilledActorLogin, _)) + .WillOnce(RunOnceCallback<3>(true)); + EXPECT_CALL( + mock_driver_, + FillField(password_only_parsed_form->password_element_renderer_id, + Eq(kTestPassword), + autofill::FieldPropertiesFlags::kAutofilledActorLogin, _)) + .WillOnce(RunOnceCallback<3>(false)); + + filler.AttemptLogin(&mock_password_manager_); + const LoginStatusResultOrError& result = future.Get(); + ASSERT_TRUE(result.has_value()); + EXPECT_EQ(result.value(), LoginStatusResult::kSuccessUsernameFilled); +} + +TEST_F(ActorLoginCredentialFillerTest, FillOnlyPasswordInAllEligibleFields) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature( + password_manager::features::kActorLoginFillingHeuristics); + const url::Origin origin = url::Origin::Create(GURL(kLoginUrl)); + const Credential credential = + CreateTestCredential(kTestUsername, origin.GetURL()); + const FormData form_data = CreateSigninFormData(origin.GetURL()); + const FormData username_only_form_data = + CreateUsernameOnlyFormData(origin.GetURL()); + const FormData password_only_form_data = + CreatePasswordOnlyFormData(origin.GetURL()); + + // Make sure a saved credential with a matching username exists. + SetSavedCredential(&form_fetcher_, origin.GetURL(), kTestUsername, + kTestPassword); + + // Simulate signin forms existing on the page. + std::vector<std::unique_ptr<PasswordFormManager>> form_managers; + form_managers.push_back(CreateFormManagerWithParsedForm(origin, form_data)); + form_managers.push_back( + CreateFormManagerWithParsedForm(origin, username_only_form_data)); + form_managers.push_back( + CreateFormManagerWithParsedForm(origin, password_only_form_data)); + + const PasswordForm* parsed_form = form_managers[0]->GetParsedObservedForm(); + const PasswordForm* username_only_parsed_form = + form_managers[1]->GetParsedObservedForm(); + const PasswordForm* password_only_parsed_form = + form_managers[2]->GetParsedObservedForm(); + + base::test::TestFuture<LoginStatusResultOrError> future; + ActorLoginCredentialFiller filler(origin, credential, &mock_client_, + future.GetCallback()); + + ON_CALL(mock_form_cache_, GetFormManagers) + .WillByDefault(Return(base::span(form_managers))); + + // There are 4 fields to fill, so there should be 4 calls to the driver, + // one for each field. Make all username fields filling fail and one + // password filling succeed. + EXPECT_CALL( + mock_driver_, + FillField(parsed_form->username_element_renderer_id, Eq(kTestUsername), + autofill::FieldPropertiesFlags::kAutofilledActorLogin, _)) + .WillOnce(RunOnceCallback<3>(false)); + EXPECT_CALL( + mock_driver_, + FillField(parsed_form->password_element_renderer_id, Eq(kTestPassword), + autofill::FieldPropertiesFlags::kAutofilledActorLogin, _)) + .WillOnce(RunOnceCallback<3>(true)); + EXPECT_CALL( + mock_driver_, + FillField(username_only_parsed_form->username_element_renderer_id, + Eq(kTestUsername), + autofill::FieldPropertiesFlags::kAutofilledActorLogin, _)) + .WillOnce(RunOnceCallback<3>(false)); + EXPECT_CALL( + mock_driver_, + FillField(password_only_parsed_form->password_element_renderer_id, + Eq(kTestPassword), + autofill::FieldPropertiesFlags::kAutofilledActorLogin, _)) + .WillOnce(RunOnceCallback<3>(false)); + + filler.AttemptLogin(&mock_password_manager_); + const LoginStatusResultOrError& result = future.Get(); + ASSERT_TRUE(result.has_value()); + EXPECT_EQ(result.value(), LoginStatusResult::kSuccessPasswordFilled); +} + +TEST_F(ActorLoginCredentialFillerTest, FillingFailsInAllEligibleFields) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature( + password_manager::features::kActorLoginFillingHeuristics); + const url::Origin origin = url::Origin::Create(GURL(kLoginUrl)); + const Credential credential = + CreateTestCredential(kTestUsername, origin.GetURL()); + const FormData form_data = CreateSigninFormData(origin.GetURL()); + const FormData username_only_form_data = + CreateUsernameOnlyFormData(origin.GetURL()); + const FormData password_only_form_data = + CreatePasswordOnlyFormData(origin.GetURL()); + + // Make sure a saved credential with a matching username exists. + SetSavedCredential(&form_fetcher_, origin.GetURL(), kTestUsername, + kTestPassword); + + // Simulate signin forms existing on the page. + std::vector<std::unique_ptr<PasswordFormManager>> form_managers; + form_managers.push_back(CreateFormManagerWithParsedForm(origin, form_data)); + form_managers.push_back( + CreateFormManagerWithParsedForm(origin, username_only_form_data)); + form_managers.push_back( + CreateFormManagerWithParsedForm(origin, password_only_form_data)); + + const PasswordForm* parsed_form = form_managers[0]->GetParsedObservedForm(); + const PasswordForm* username_only_parsed_form = + form_managers[1]->GetParsedObservedForm(); + const PasswordForm* password_only_parsed_form = + form_managers[2]->GetParsedObservedForm(); + + base::test::TestFuture<LoginStatusResultOrError> future; + ActorLoginCredentialFiller filler(origin, credential, &mock_client_, + future.GetCallback()); + + ON_CALL(mock_form_cache_, GetFormManagers) + .WillByDefault(Return(base::span(form_managers))); + + // There are 4 fields to fill, so there should be 4 calls to the driver, + // one for each field. Make all filling attempts fail. + EXPECT_CALL( + mock_driver_, + FillField(parsed_form->username_element_renderer_id, Eq(kTestUsername), + autofill::FieldPropertiesFlags::kAutofilledActorLogin, _)) + .WillOnce(RunOnceCallback<3>(false)); + EXPECT_CALL( + mock_driver_, + FillField(parsed_form->password_element_renderer_id, Eq(kTestPassword), + autofill::FieldPropertiesFlags::kAutofilledActorLogin, _)) + .WillOnce(RunOnceCallback<3>(false)); + EXPECT_CALL( + mock_driver_, + FillField(username_only_parsed_form->username_element_renderer_id, + Eq(kTestUsername), + autofill::FieldPropertiesFlags::kAutofilledActorLogin, _)) + .WillOnce(RunOnceCallback<3>(false)); + EXPECT_CALL( + mock_driver_, + FillField(password_only_parsed_form->password_element_renderer_id, + Eq(kTestPassword), + autofill::FieldPropertiesFlags::kAutofilledActorLogin, _)) + .WillOnce(RunOnceCallback<3>(false)); + + filler.AttemptLogin(&mock_password_manager_); + const LoginStatusResultOrError& result = future.Get(); + ASSERT_TRUE(result.has_value()); + EXPECT_EQ(result.value(), LoginStatusResult::kErrorNoFillableFields); +} + TEST_F(ActorLoginCredentialFillerTest, FillingIsDisabled) { const url::Origin origin = url::Origin::Create(GURL("https://example.com/login")); @@ -668,6 +975,7 @@ FillField(parsed_form->password_element_renderer_id, Eq(kTestPassword), autofill::FieldPropertiesFlags::kAutofilledActorLogin, _)) .WillOnce(RunOnceCallback<3>(true)); + filler.AttemptLogin(&mock_password_manager_); const LoginStatusResultOrError& result = future.Get(); ASSERT_TRUE(result.has_value());
diff --git a/components/password_manager/core/browser/actor_login/internal/actor_login_util.cc b/components/password_manager/core/browser/actor_login/internal/actor_login_util.cc index a2b2c7f..a678863 100644 --- a/components/password_manager/core/browser/actor_login/internal/actor_login_util.cc +++ b/components/password_manager/core/browser/actor_login/internal/actor_login_util.cc
@@ -17,8 +17,6 @@ namespace actor_login { -namespace { - bool IsElementFocusable(autofill::FieldRendererId renderer_id, const autofill::FormData& form_data) { auto field = std::ranges::find(form_data.fields(), renderer_id, @@ -41,9 +39,6 @@ return (has_focusable_username || has_focusable_password) && !has_focusable_new_password; } - -} // namespace - std::u16string GetSourceSiteOrAppFromUrl(const GURL& url) { return base::UTF8ToUTF16(url.GetWithEmptyPath().spec()); }
diff --git a/components/password_manager/core/browser/actor_login/internal/actor_login_util.h b/components/password_manager/core/browser/actor_login/internal/actor_login_util.h index 7280a9b6..066ed7f2 100644 --- a/components/password_manager/core/browser/actor_login/internal/actor_login_util.h +++ b/components/password_manager/core/browser/actor_login/internal/actor_login_util.h
@@ -10,6 +10,7 @@ #include "url/gurl.h" namespace password_manager { +struct PasswordForm; class PasswordFormCache; class PasswordFormManager; } // namespace password_manager @@ -20,6 +21,9 @@ namespace actor_login { +// Checks whether `form` is a login form. +bool IsLoginForm(const password_manager::PasswordForm& form); + // Transforms `url` into `Credential.source_site_or_app` std::u16string GetSourceSiteOrAppFromUrl(const GURL& url);
diff --git a/components/password_manager/core/browser/features/password_features.cc b/components/password_manager/core/browser/features/password_features.cc index b1862f9..d760750e 100644 --- a/components/password_manager/core/browser/features/password_features.cc +++ b/components/password_manager/core/browser/features/password_features.cc
@@ -11,6 +11,7 @@ namespace password_manager::features { #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) // Desktop BASE_FEATURE(kActorLogin, base::FEATURE_ENABLED_BY_DEFAULT); +BASE_FEATURE(kActorLoginFillingHeuristics, base::FEATURE_DISABLED_BY_DEFAULT); #endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) #if BUILDFLAG(IS_ANDROID)
diff --git a/components/password_manager/core/browser/features/password_features.h b/components/password_manager/core/browser/features/password_features.h index 2dd1085..d7276b5 100644 --- a/components/password_manager/core/browser/features/password_features.h +++ b/components/password_manager/core/browser/features/password_features.h
@@ -18,6 +18,7 @@ #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) BASE_DECLARE_FEATURE(kActorLogin); +BASE_DECLARE_FEATURE(kActorLoginFillingHeuristics); #endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) #if BUILDFLAG(IS_ANDROID)
diff --git a/components/password_manager/core/browser/password_session_durations_metrics_recorder.cc b/components/password_manager/core/browser/password_session_durations_metrics_recorder.cc index 1e286ada..9edb71e 100644 --- a/components/password_manager/core/browser/password_session_durations_metrics_recorder.cc +++ b/components/password_manager/core/browser/password_session_durations_metrics_recorder.cc
@@ -82,6 +82,13 @@ CheckForUserStateChange(); } +void PasswordSessionDurationsMetricsRecorder::OnSyncShutdown( + syncer::SyncService* sync) { + // Unreachable, since the service owning this instance is Shutdown() before + // the SyncService. + NOTREACHED(); +} + void PasswordSessionDurationsMetricsRecorder::CheckForUserStateChange() { features_util::PasswordAccountStorageUserState new_user_state = features_util::ComputePasswordAccountStorageUserState(sync_service_);
diff --git a/components/password_manager/core/browser/password_session_durations_metrics_recorder.h b/components/password_manager/core/browser/password_session_durations_metrics_recorder.h index 2767f13..52c1342 100644 --- a/components/password_manager/core/browser/password_session_durations_metrics_recorder.h +++ b/components/password_manager/core/browser/password_session_durations_metrics_recorder.h
@@ -40,6 +40,7 @@ // syncer::SyncServiceObserver: void OnStateChanged(syncer::SyncService* sync) override; + void OnSyncShutdown(syncer::SyncService* sync) override; private: void CheckForUserStateChange();
diff --git a/components/password_manager/core/browser/sharing/incoming_password_sharing_invitation_data_type_controller.cc b/components/password_manager/core/browser/sharing/incoming_password_sharing_invitation_data_type_controller.cc index 6986544..b538511 100644 --- a/components/password_manager/core/browser/sharing/incoming_password_sharing_invitation_data_type_controller.cc +++ b/components/password_manager/core/browser/sharing/incoming_password_sharing_invitation_data_type_controller.cc
@@ -79,6 +79,11 @@ sync_service_->DataTypePreconditionChanged(type()); } +void IncomingPasswordSharingInvitationDataTypeController::OnSyncShutdown( + syncer::SyncService* sync) { + // Nothing to be done, `this` will be destructed imminently. +} + void IncomingPasswordSharingInvitationDataTypeController:: OnPasswordSharingEnabledPolicyChanged() { DCHECK(CalledOnValidThread());
diff --git a/components/password_manager/core/browser/sharing/incoming_password_sharing_invitation_data_type_controller.h b/components/password_manager/core/browser/sharing/incoming_password_sharing_invitation_data_type_controller.h index 18833e5..1ac43f5 100644 --- a/components/password_manager/core/browser/sharing/incoming_password_sharing_invitation_data_type_controller.h +++ b/components/password_manager/core/browser/sharing/incoming_password_sharing_invitation_data_type_controller.h
@@ -36,6 +36,7 @@ // syncer::SyncServiceObserver implementation. void OnStateChanged(syncer::SyncService* sync) override; + void OnSyncShutdown(syncer::SyncService* sync) override; private: void OnPasswordSharingEnabledPolicyChanged();
diff --git a/components/password_manager_strings.grdp b/components/password_manager_strings.grdp index fdd05b2..21b8298 100644 --- a/components/password_manager_strings.grdp +++ b/components/password_manager_strings.grdp
@@ -311,7 +311,16 @@ <message name="IDS_PASSWORD_MANAGER_UI_PROACTIVE_RECOVERY_FOOTER_NON_BRANDED" desc="Footer text of an autofill suggestion drop-down that explains why we are suggesting to try a recovery password."> You recently changed a password found in a public data breach. In case of trouble, Password Manager can help you sign in. </message> - <message name="IDS_PASSWORD_MANAGER_UI_BACKUP_PASSWORD_TAG" desc="Text shown next to the backup credential in the autofill drop-down. In this case the backup suggestion will be shown right after the usual password suggestion that it corresponds to."> - Recovery - </message> + <if expr="is_android"> + <then> + <message name="IDS_PASSWORD_MANAGER_UI_BACKUP_PASSWORD_TAG" desc="Text shown next to the backup credential in keyboard accessory bar. In this case the backup suggestion will be shown right after the usual password suggestion that it corresponds to."> + Recovery password + </message> + </then> + <else> + <message name="IDS_PASSWORD_MANAGER_UI_BACKUP_PASSWORD_TAG" desc="Text shown next to the backup credential in the autofill drop-down. In this case the backup suggestion will be shown right after the usual password suggestion that it corresponds to."> + Recovery + </message> + </else> + </if> </grit-part>
diff --git a/components/plus_addresses/core/browser/sync_utils/plus_address_data_type_controller.cc b/components/plus_addresses/core/browser/sync_utils/plus_address_data_type_controller.cc index 50935a5..58afa7d 100644 --- a/components/plus_addresses/core/browser/sync_utils/plus_address_data_type_controller.cc +++ b/components/plus_addresses/core/browser/sync_utils/plus_address_data_type_controller.cc
@@ -85,6 +85,10 @@ } } +void PlusAddressDataTypeController::OnSyncShutdown(syncer::SyncService*) { + // Nothing to be done, `this` will be destructed imminently. +} + void PlusAddressDataTypeController::RecreateManagedStatusFinder() { managed_status_finder_ = std::make_unique<signin::AccountManagedStatusFinder>( identity_manager_, sync_service_->GetAccountInfo(),
diff --git a/components/plus_addresses/core/browser/sync_utils/plus_address_data_type_controller.h b/components/plus_addresses/core/browser/sync_utils/plus_address_data_type_controller.h index 44b10ff..f1d0c78 100644 --- a/components/plus_addresses/core/browser/sync_utils/plus_address_data_type_controller.h +++ b/components/plus_addresses/core/browser/sync_utils/plus_address_data_type_controller.h
@@ -50,6 +50,7 @@ // SyncServiceObserver: void OnStateChanged(syncer::SyncService*) override; + void OnSyncShutdown(syncer::SyncService*) override; private: void RecreateManagedStatusFinder();
diff --git a/components/policy/resources/templates/policies.yaml b/components/policy/resources/templates/policies.yaml index 1688723..69e18b12 100644 --- a/components/policy/resources/templates/policies.yaml +++ b/components/policy/resources/templates/policies.yaml
@@ -1395,6 +1395,7 @@ 1394: PreferSlowKexAlgorithms 1395: ExtensionForceInstallWithNonMalwareViolationsEnabled 1396: CacheEncryptionEnabled + 1397: SilentPrintingEnabled atomic_groups: 1: Homepage 2: RemoteAccess
diff --git a/components/policy/resources/templates/policy_definitions/Miscellaneous/SilentPrintingEnabled.yaml b/components/policy/resources/templates/policy_definitions/Miscellaneous/SilentPrintingEnabled.yaml new file mode 100644 index 0000000..d6b4ea56 --- /dev/null +++ b/components/policy/resources/templates/policy_definitions/Miscellaneous/SilentPrintingEnabled.yaml
@@ -0,0 +1,30 @@ +caption: Enable Silent Printing +desc: |- + Setting this policy to true enables silent printing, which immediately closes + print preview window when opened and prints to the default printer with + default options. If the default printer is 'Save as PDF', the file will be + saved to the Downloads folder. + + Not setting this policy or setting this policy to false disables silent + printing, which doesn't automatically close print preview window and requires + the user to make a selection as usual. +features: + dynamic_refresh: true + per_profile: false +items: +- caption: Enable Silent Printing + value: true +- caption: Disable Silent Printing + value: false +default: false +example_value: false +owners: +- file://components/policy/OWNERS +- poromov@chromium.org +- orko@igalia.com +schema: + type: boolean +future_on: +- chrome_os +tags: [] +type: main
diff --git a/components/policy/test/data/pref_mapping/SilentPrintingEnabled.json b/components/policy/test/data/pref_mapping/SilentPrintingEnabled.json new file mode 100644 index 0000000..83fafe731 --- /dev/null +++ b/components/policy/test/data/pref_mapping/SilentPrintingEnabled.json
@@ -0,0 +1,5 @@ +[ + { + "reason_for_missing_test": "Mapping not yet implemented." + } +]
diff --git a/components/search_engines/search_engine_choice/search_engine_choice_service.cc b/components/search_engines/search_engine_choice/search_engine_choice_service.cc index 4a67038..b4425890 100644 --- a/components/search_engines/search_engine_choice/search_engine_choice_service.cc +++ b/components/search_engines/search_engine_choice/search_engine_choice_service.cc
@@ -329,7 +329,7 @@ bool ManagementStatusEligibleForChoiceScreen( const regional_capabilities::ChoiceScreenEligibilityConfig& config, - policy::ManagementService& management_service) { + policy::ManagementService& platform_management_service) { if (!base::FeatureList::IsEnabled( switches::kChoiceScreenEligibilityCheckManagementStatus)) { return true; @@ -339,15 +339,7 @@ return true; } - switch (management_service.GetManagementAuthorityTrustworthiness()) { - case policy::ManagementAuthorityTrustworthiness::NONE: - return true; - case policy::ManagementAuthorityTrustworthiness::LOW: - case policy::ManagementAuthorityTrustworthiness::TRUSTED: - case policy::ManagementAuthorityTrustworthiness::FULLY_TRUSTED: - return false; - } - NOTREACHED(); + return !platform_management_service.IsManaged(); } // Checks account properties against the eligibility config to determine if the @@ -413,14 +405,14 @@ regional_capabilities::RegionalCapabilitiesService& regional_capabilities, TemplateURLPrepopulateData::Resolver& prepopulate_data_resolver, signin::IdentityManager& identity_manager, - policy::ManagementService& management_service) + policy::ManagementService& platform_management_service) : client_(std::move(client)), profile_prefs_(profile_prefs), local_state_(local_state), regional_capabilities_service_(regional_capabilities), prepopulate_data_resolver_(prepopulate_data_resolver), identity_manager_(identity_manager), - management_service_(management_service) {} + platform_management_service_(platform_management_service) {} SearchEngineChoiceService::~SearchEngineChoiceService() = default; @@ -935,7 +927,7 @@ // 3.1: Check eligibility based on management status. if (!ManagementStatusEligibleForChoiceScreen(eligibility_config, - *management_service_)) { + *platform_management_service_)) { return ChoiceStatus::kManaged; }
diff --git a/components/search_engines/search_engine_choice/search_engine_choice_service.h b/components/search_engines/search_engine_choice/search_engine_choice_service.h index 87fb32c..5f1c4c7 100644 --- a/components/search_engines/search_engine_choice/search_engine_choice_service.h +++ b/components/search_engines/search_engine_choice/search_engine_choice_service.h
@@ -99,7 +99,7 @@ regional_capabilities::RegionalCapabilitiesService& regional_capabilities, TemplateURLPrepopulateData::Resolver& prepopulate_data_resolver, signin::IdentityManager& identity_manager, - policy::ManagementService& management_service); + policy::ManagementService& platform_management_service); ~SearchEngineChoiceService() override; // Runs the initialisation step for this service, checking consistency in the @@ -278,7 +278,7 @@ const raw_ref<TemplateURLPrepopulateData::Resolver> prepopulate_data_resolver_; const raw_ref<signin::IdentityManager> identity_manager_; - const raw_ref<policy::ManagementService> management_service_; + const raw_ref<policy::ManagementService> platform_management_service_; base::ObserverList<Observer> observers_; // Used to track whether `MaybeRecordChoiceScreenDisplayState()` has already
diff --git a/components/signin/public/android/BUILD.gn b/components/signin/public/android/BUILD.gn index 6583f33..b7731a2d 100644 --- a/components/signin/public/android/BUILD.gn +++ b/components/signin/public/android/BUILD.gn
@@ -171,6 +171,7 @@ "//base:base_java", "//base:base_java_test_support", "//chrome/test/android:chrome_java_test_support_common", + "//components/cached_flags:java", "//content/public/test/android:content_java_test_support", "//google_apis/gaia/android:java", "//third_party/androidx:androidx_annotation_annotation_java",
diff --git a/components/signin/public/android/java/src/org/chromium/components/signin/AccountManagerFacade.java b/components/signin/public/android/java/src/org/chromium/components/signin/AccountManagerFacade.java index f2d88895..53aa29e 100644 --- a/components/signin/public/android/java/src/org/chromium/components/signin/AccountManagerFacade.java +++ b/components/signin/public/android/java/src/org/chromium/components/signin/AccountManagerFacade.java
@@ -84,11 +84,10 @@ /** * Asynchronously gets OAuth2 access token for the given account and scope. May return a cached - * version, use {@link #invalidateAccessToken} to invalidate a token in the cache. Please note - * that this method expects a scope with 'oauth2:' prefix. + * version, use {@link #invalidateAccessToken} to invalidate a token in the cache. * * @param account the account to get the access token for. - * @param scope The scope to get an auth token for (with Android-style 'oauth2:' prefix). + * @param scope The scope to get an auth token for. * @param callback called on successful and unsuccessful fetching of auth token. */ @MainThread
diff --git a/components/signin/public/android/java/src/org/chromium/components/signin/AccountManagerFacadeImpl.java b/components/signin/public/android/java/src/org/chromium/components/signin/AccountManagerFacadeImpl.java index acf6c55f..a30a68d5 100644 --- a/components/signin/public/android/java/src/org/chromium/components/signin/AccountManagerFacadeImpl.java +++ b/components/signin/public/android/java/src/org/chromium/components/signin/AccountManagerFacadeImpl.java
@@ -66,6 +66,8 @@ // Time, in milliseconds, between two attempts to fetch the accounts. private static final long GET_ACCOUNTS_BACKOFF_DELAY = 1000L; + private static final String OAUTH2_SCOPE_PREFIX = "oauth2:"; + private static final String TAG = "AccountManager"; private final AccountManagerDelegate mDelegate; @@ -157,12 +159,56 @@ } pendingRequestStarted(); + + if (!SigninFeatureMap.sMigrateAccountManagerDelegate.isEnabled()) { + String oauth2Scope = OAUTH2_SCOPE_PREFIX + scope; + ConnectionRetry.runAuthTask( + new AuthTask() { + @Override + public AccessTokenData run() throws AuthException { + return mDelegate.getAccessToken( + CoreAccountInfo.getAndroidAccountFrom(coreAccountInfo), + oauth2Scope); + } + + @Override + public void onSuccess(@Nullable AccessTokenData token) { + assert token != null : "AccessTokenData must not be null on success."; + callback.onGetTokenSuccess(token); + pendingRequestFinished(); + } + + @Override + public void onFailure(GoogleServiceAuthError authError) { + callback.onGetTokenFailure(authError); + pendingRequestFinished(); + } + }); + return; + } + + getAccounts() + .then( + unused -> { + getAccessTokenHelper(coreAccountInfo, scope, callback); + }); + } + + private void getAccessTokenHelper( + CoreAccountInfo coreAccountInfo, String scope, GetAccessTokenCallback callback) { + PlatformAccount platformAccount = getPlatformAccount(coreAccountInfo.getGaiaId()); + if (platformAccount == null) { + callback.onGetTokenFailure( + new GoogleServiceAuthError(GoogleServiceAuthErrorState.USER_NOT_SIGNED_UP)); + pendingRequestFinished(); + return; + } + ConnectionRetry.runAuthTask( new AuthTask() { @Override public AccessTokenData run() throws AuthException { - return mDelegate.getAccessToken( - CoreAccountInfo.getAndroidAccountFrom(coreAccountInfo), scope); + return mDelegate.getAccessTokenForPlatformAccount(platformAccount, scope); } @Override @@ -210,6 +256,11 @@ new AuthTask() { @Override public @Nullable AccessTokenData run() throws AuthException { + if (SigninFeatureMap.sMigrateAccountManagerDelegate.isEnabled()) { + mDelegate.invalidateAccessTokenForPlatformAccount(accessToken); + return null; + } + mDelegate.invalidateAccessToken(accessToken); return null; }
diff --git a/components/signin/public/android/java/src/org/chromium/components/signin/PlatformAccount.java b/components/signin/public/android/java/src/org/chromium/components/signin/PlatformAccount.java index 569add4..131ce7bb 100644 --- a/components/signin/public/android/java/src/org/chromium/components/signin/PlatformAccount.java +++ b/components/signin/public/android/java/src/org/chromium/components/signin/PlatformAccount.java
@@ -3,6 +3,7 @@ // found in the LICENSE file. package org.chromium.components.signin; +import androidx.annotation.AnyThread; import androidx.annotation.MainThread; import androidx.annotation.WorkerThread; @@ -14,7 +15,7 @@ @NullMarked public interface PlatformAccount { /** Returns gaiaId of the PlatformAccount. */ - @MainThread + @AnyThread GaiaId getId(); /** Returns email of the PlatformAccount. */
diff --git a/components/signin/public/android/java/src/org/chromium/components/signin/identitymanager/ProfileOAuth2TokenServiceDelegate.java b/components/signin/public/android/java/src/org/chromium/components/signin/identitymanager/ProfileOAuth2TokenServiceDelegate.java index 50c0f10..2b3bd6f 100644 --- a/components/signin/public/android/java/src/org/chromium/components/signin/identitymanager/ProfileOAuth2TokenServiceDelegate.java +++ b/components/signin/public/android/java/src/org/chromium/components/signin/identitymanager/ProfileOAuth2TokenServiceDelegate.java
@@ -33,8 +33,6 @@ */ @NullMarked final class ProfileOAuth2TokenServiceDelegate { - private static final String OAUTH2_SCOPE_PREFIX = "oauth2:"; - private final long mNativePtr; private final AccountManagerFacade mAccountManagerFacade; @@ -51,7 +49,7 @@ * Called by native method AndroidAccessTokenFetcher::Start() to retrieve OAuth2 tokens. * * @param coreAccountInfo The account info. - * @param scope The scope to get an auth token for (without Android-style 'oauth2:' prefix). + * @param scope The scope to get an auth token for. * @param nativeCallback The pointer to the native callback that should be run upon completion. */ @MainThread @@ -73,10 +71,9 @@ }); return; } - String oauth2Scope = OAUTH2_SCOPE_PREFIX + scope; mAccountManagerFacade.getAccessToken( coreAccountInfo, - oauth2Scope, + scope, new AccountManagerFacade.GetAccessTokenCallback() { @Override public void onGetTokenSuccess(AccessTokenData token) {
diff --git a/components/signin/public/android/java/src/org/chromium/components/signin/test/util/FakeAccountManagerDelegate.java b/components/signin/public/android/java/src/org/chromium/components/signin/test/util/FakeAccountManagerDelegate.java index f94c235a..d054e7a6 100644 --- a/components/signin/public/android/java/src/org/chromium/components/signin/test/util/FakeAccountManagerDelegate.java +++ b/components/signin/public/android/java/src/org/chromium/components/signin/test/util/FakeAccountManagerDelegate.java
@@ -84,7 +84,7 @@ /** Adds an AccountHolder. */ public PlatformAccount addAccount(AccountInfo accountInfo) { boolean added = false; - PlatformAccount account = new FakePlatformAccount(accountInfo); + FakePlatformAccount account = new FakePlatformAccount(accountInfo); if (SigninFeatureMap.sMigrateAccountManagerDelegate.isEnabled()) { added = mPlatformAccounts.add(account); } else { @@ -137,6 +137,14 @@ } @Override + public AccessTokenData getAccessTokenForPlatformAccount( + PlatformAccount account, String authTokenScopes) throws AuthException { + FakePlatformAccount platformAccount = (FakePlatformAccount) account; + assert platformAccount != null; + return platformAccount.getAccessTokenOrGenerateNew(authTokenScopes); + } + + @Override public void invalidateAccessToken(String authToken) { if (authToken == null) { throw new IllegalArgumentException("AuthToken can not be null"); @@ -150,6 +158,20 @@ } } + @Override + public void invalidateAccessTokenForPlatformAccount(String authToken) throws AuthException { + if (authToken == null) { + throw new IllegalArgumentException("AuthToken can not be null"); + } + synchronized (mPlatformAccounts) { + for (PlatformAccount account : mPlatformAccounts) { + FakePlatformAccount fakePlatformAccount = (FakePlatformAccount) account; + if (fakePlatformAccount.removeAccessToken(authToken)) { + break; + } + } + } + } @Override public @CapabilityResponse int hasCapability(Account account, String capability) {
diff --git a/components/signin/public/android/java/src/org/chromium/components/signin/test/util/FakeAccountManagerFacade.java b/components/signin/public/android/java/src/org/chromium/components/signin/test/util/FakeAccountManagerFacade.java index b37a211..475642a 100644 --- a/components/signin/public/android/java/src/org/chromium/components/signin/test/util/FakeAccountManagerFacade.java +++ b/components/signin/public/android/java/src/org/chromium/components/signin/test/util/FakeAccountManagerFacade.java
@@ -25,6 +25,8 @@ import org.chromium.components.signin.AccountManagerFacadeProvider; import org.chromium.components.signin.AccountsChangeObserver; import org.chromium.components.signin.AuthException; +import org.chromium.components.signin.PlatformAccount; +import org.chromium.components.signin.SigninFeatureMap; import org.chromium.components.signin.Tribool; import org.chromium.components.signin.base.AccountCapabilities; import org.chromium.components.signin.base.AccountInfo; @@ -39,6 +41,7 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; import java.util.stream.Collectors; @@ -107,9 +110,14 @@ // `mAccountHolders` can be read from non-UI threads (this is used by `getAccessToken`), but // should only be changed from the UI thread to guarantee the consistency of the observed state. + // TODO(crbug.com/429143376): Deprecate AccountHolder after sMigrateAccountManagerDelegate is + // enabled by default. private final Set<AccountHolder> mAccountHolders = Collections.synchronizedSet(new LinkedHashSet<>()); + private final Set<PlatformAccount> mPlatformAccounts = + Collections.synchronizedSet(new LinkedHashSet<>()); + /** Can be used to cause {@link #getAccessToken} method to fail. */ private final Map<CoreAccountId, GoogleServiceAuthError> mGetAccessTokenError = new HashMap<>(); @@ -155,6 +163,30 @@ @Override public void getAccessToken( CoreAccountInfo coreAccountInfo, String scope, GetAccessTokenCallback callback) { + if (SigninFeatureMap.sMigrateAccountManagerDelegate.isEnabled()) { + @Nullable FakePlatformAccount account = getPlatformAccount(coreAccountInfo.getGaiaId()); + if (account == null) { + Log.w(TAG, "Cannot find account:" + coreAccountInfo.toString()); + ThreadUtils.postOnUiThread( + () -> + callback.onGetTokenFailure( + new GoogleServiceAuthError( + GoogleServiceAuthErrorState.USER_NOT_SIGNED_UP))); + return; + } + + GoogleServiceAuthError authError = mGetAccessTokenError.get(coreAccountInfo.getId()); + if (authError != null) { + ThreadUtils.postOnUiThread(() -> callback.onGetTokenFailure(authError)); + } else { + ThreadUtils.postOnUiThread( + () -> + callback.onGetTokenSuccess( + account.getAccessTokenOrGenerateNew(scope))); + } + return; + } + @Nullable AccountHolder accountHolder = getAccountHolder(coreAccountInfo.getId()); if (accountHolder == null) { Log.w(TAG, "Cannot find account:" + coreAccountInfo.toString()); @@ -255,6 +287,17 @@ /** Adds an account represented by {@link AccountInfo}. */ public void addAccount(AccountInfo accountInfo) { + if (SigninFeatureMap.sMigrateAccountManagerDelegate.isEnabled()) { + ThreadUtils.runOnUiThreadBlocking( + () -> { + mPlatformAccounts.add(new FakePlatformAccount(accountInfo)); + if (mBlockedGetAccountsPromise == null) { + fireOnAccountsChangedNotification(); + } + }); + return; + } + ThreadUtils.runOnUiThreadBlocking( () -> { mAccountHolders.add(new AccountHolder(accountInfo)); @@ -269,11 +312,38 @@ * equality to search for the account to update. Throws if the account can't be found. */ public void updateAccount(AccountInfo accountInfo) { + if (SigninFeatureMap.sMigrateAccountManagerDelegate.isEnabled()) { + ThreadUtils.runOnUiThreadBlocking( + () -> { + synchronized (mPlatformAccounts) { + @Nullable FakePlatformAccount platformAccount = + (FakePlatformAccount) + mPlatformAccounts.stream() + .filter( + (account) -> + Objects.equals( + account.getId(), + accountInfo + .getGaiaId())) + .findFirst() + .orElse(null); + if (platformAccount == null) { + throw new IllegalArgumentException( + "Account " + accountInfo.getEmail() + " can't be found!"); + } + mPlatformAccounts.remove(platformAccount); + mPlatformAccounts.add(new FakePlatformAccount(accountInfo)); + } + if (mBlockedGetAccountsPromise == null) { + fireOnAccountsChangedNotification(); + } + }); + return; + } ThreadUtils.runOnUiThreadBlocking( () -> { synchronized (mAccountHolders) { - @Nullable - AccountHolder accountHolder = + @Nullable AccountHolder accountHolder = mAccountHolders.stream() .filter( (ah) -> @@ -445,6 +515,19 @@ } } + @AnyThread + private @Nullable FakePlatformAccount getPlatformAccount(GaiaId gaiaId) { + synchronized (mPlatformAccounts) { + return (FakePlatformAccount) + mPlatformAccounts.stream() + .filter( + platformAccount -> + Objects.equals(gaiaId, platformAccount.getId())) + .findFirst() + .orElse(null); + } + } + @MainThread private void fireOnAccountsChangedNotification() { ThreadUtils.checkUiThread();
diff --git a/components/signin/public/android/java/src/org/chromium/components/signin/test/util/FakePlatformAccount.java b/components/signin/public/android/java/src/org/chromium/components/signin/test/util/FakePlatformAccount.java index 33b15c4f..a9a6e71 100644 --- a/components/signin/public/android/java/src/org/chromium/components/signin/test/util/FakePlatformAccount.java +++ b/components/signin/public/android/java/src/org/chromium/components/signin/test/util/FakePlatformAccount.java
@@ -3,17 +3,26 @@ // found in the LICENSE file. package org.chromium.components.signin.test.util; +import org.chromium.build.annotations.Nullable; +import org.chromium.components.signin.AccessTokenData; import org.chromium.components.signin.AccountManagerDelegate; import org.chromium.components.signin.PlatformAccount; import org.chromium.components.signin.base.AccountInfo; import org.chromium.google_apis.gaia.GaiaId; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + /** * A test implementation of {@link PlatformAccount} for testing components that depend on {@link * AccountManagerDelegate}. */ public class FakePlatformAccount implements PlatformAccount { private final AccountInfo mAccount; + private final Map<String, AccessTokenData> mAccessTokens = + Collections.synchronizedMap(new HashMap<>()); public FakePlatformAccount(AccountInfo accountInfo) { mAccount = accountInfo; @@ -46,4 +55,26 @@ // specified capability or not. return AccountManagerDelegate.CapabilityResponse.EXCEPTION; } + + /** + * Gets the access token for the given scope. If a token has not been previously generated for + * this scope, a new one will be created. + */ + @Nullable + public AccessTokenData getAccessTokenOrGenerateNew(String scope) { + return mAccessTokens.computeIfAbsent( + scope, (ignored) -> new AccessTokenData(UUID.randomUUID().toString())); + } + + /** + * Removes an auth token from the auth token map. + * + * @param authToken the auth token to remove. + * @return true if the auth token was found. + */ + public boolean removeAccessToken(String accessToken) { + return mAccessTokens + .values() + .removeIf(tokenData -> accessToken.equals(tokenData.getToken())); + } }
diff --git a/components/signin/public/android/javatests/src/org/chromium/components/signin/AccountManagerFacadeTest.java b/components/signin/public/android/javatests/src/org/chromium/components/signin/AccountManagerFacadeTest.java index 21a4a5e4..db6ebc2 100644 --- a/components/signin/public/android/javatests/src/org/chromium/components/signin/AccountManagerFacadeTest.java +++ b/components/signin/public/android/javatests/src/org/chromium/components/signin/AccountManagerFacadeTest.java
@@ -33,6 +33,7 @@ import org.chromium.base.test.util.CallbackHelper; import org.chromium.base.test.util.CriteriaHelper; import org.chromium.base.test.util.DoNotBatch; +import org.chromium.components.signin.base.AccountInfo; import org.chromium.components.signin.base.CoreAccountInfo; import org.chromium.components.signin.test.util.FakeAccountManagerDelegate; import org.chromium.components.signin.test.util.TestAccounts; @@ -81,6 +82,13 @@ return super.getAccessToken(account, scope); } + @Override + public AccessTokenData getAccessTokenForPlatformAccount( + PlatformAccount platformAccount, String authTokenScopes) throws AuthException { + maybeBlockOnLatch(mGetAuthTokenLatch); + return super.getAccessTokenForPlatformAccount(platformAccount, authTokenScopes); + } + void blockGetAuthToken() { assertThat(mGetAuthTokenLatch).isNull(); mGetAuthTokenLatch = new CountDownLatch(1); @@ -141,7 +149,8 @@ } } - private static final String TOKEN_SCOPE = "oauth2:http://example.com/scope"; + private static final String TOKEN_SCOPE = "http://example.com/scope"; + private static final String OAUTH2_SCOPE_PREFIX = "oauth2:"; public static class AccountManagerFacadeTestParams implements ParameterProvider { private static final List<ParameterSet> sAccountManagerFacadeTestParams = @@ -254,15 +263,26 @@ @Test @SmallTest - public void testGetOAuth2AccessTokenOnSuccess() throws AuthException { + @ParameterAnnotations.UseMethodParameter(AccountManagerFacadeTestParams.class) + public void testGetOAuth2AccessTokenOnSuccess(boolean isMigrationEnabled) throws AuthException { FakeAccountManagerDelegate delegate = new FakeAccountManagerDelegate(); AccountManagerFacade facade = ThreadUtils.runOnUiThreadBlocking(() -> new AccountManagerFacadeImpl(delegate)); + PlatformAccount platformAccount = delegate.addAccount(TestAccounts.ACCOUNT1); + waitForAccountToBeAdded(facade, TestAccounts.ACCOUNT1); - delegate.addAccount(TestAccounts.ACCOUNT1); - AccessTokenData expectedToken = - delegate.getAccessToken( - CoreAccountInfo.getAndroidAccountFrom(TestAccounts.ACCOUNT1), TOKEN_SCOPE); + final AccessTokenData expectedToken; + if (isMigrationEnabled) { + assert SigninFeatureMap.sMigrateAccountManagerDelegate.isEnabled(); + expectedToken = delegate.getAccessTokenForPlatformAccount(platformAccount, TOKEN_SCOPE); + assertNotNull(expectedToken); + } else { + expectedToken = + delegate.getAccessToken( + CoreAccountInfo.getAndroidAccountFrom(TestAccounts.ACCOUNT1), + OAUTH2_SCOPE_PREFIX + TOKEN_SCOPE); + assertNotNull(expectedToken); + } CustomGetAccessTokenCallback callback = new CustomGetAccessTokenCallback(); ThreadUtils.runOnUiThread( @@ -288,12 +308,13 @@ @Test @SmallTest - public void testGetAndInvalidateAccessToken() throws Exception { + @ParameterAnnotations.UseMethodParameter(AccountManagerFacadeTestParams.class) + public void testGetAndInvalidateAccessToken(boolean isMigrationEnabled) throws Exception { FakeAccountManagerDelegate delegate = new FakeAccountManagerDelegate(); AccountManagerFacade facade = ThreadUtils.runOnUiThreadBlocking(() -> new AccountManagerFacadeImpl(delegate)); - delegate.addAccount(TestAccounts.ACCOUNT1); + waitForAccountToBeAdded(facade, TestAccounts.ACCOUNT1); CustomGetAccessTokenCallback callback1 = new CustomGetAccessTokenCallback(); ThreadUtils.runOnUiThread( @@ -327,9 +348,7 @@ @Test @SmallTest - @ParameterAnnotations.UseMethodParameter(AccountManagerFacadeTestParams.class) - public void testWaitForPendingTokenRequestsToComplete(boolean isMigrationEnabled) - throws Exception { + public void testWaitForPendingTokenRequestsToComplete() throws Exception { BlockingAccountManagerDelegate blockingDelegate = new BlockingAccountManagerDelegate(); blockingDelegate.addAccount(TestAccounts.ACCOUNT1); blockingDelegate.blockGetAuthToken(); @@ -356,4 +375,30 @@ pendingRequestsCompleteCallback.waitForOnly(); assertTrue(tokenCallback.isReady()); } + + @Test + @SmallTest + public void testFetchAccessTokenIfNoAccountsAreLoaded() throws Exception { + FeatureOverrides.overrideFlag(SigninFeatures.MIGRATE_ACCOUNT_MANAGER_DELEGATE, true); + + FakeAccountManagerDelegate delegate = new FakeAccountManagerDelegate(); + AccountManagerFacade facade = + ThreadUtils.runOnUiThreadBlocking(() -> new AccountManagerFacadeImpl(delegate)); + assert SigninFeatureMap.sMigrateAccountManagerDelegate.isEnabled(); + CustomGetAccessTokenCallback callback = new CustomGetAccessTokenCallback(); + + // Fetching account with a test + ThreadUtils.runOnUiThread( + () -> facade.getAccessToken(TestAccounts.ACCOUNT1, TOKEN_SCOPE, callback)); + + assertNull(callback.getToken()); + } + + private static void waitForAccountToBeAdded(AccountManagerFacade facade, AccountInfo account) { + CriteriaHelper.pollUiThread( + () -> { + return facade.getAccounts().isFulfilled() + && facade.getAccounts().getResult().contains(account); + }); + } }
diff --git a/components/stylus_handwriting/android/BUILD.gn b/components/stylus_handwriting/android/BUILD.gn index 8f69e1b..8f5d63d 100644 --- a/components/stylus_handwriting/android/BUILD.gn +++ b/components/stylus_handwriting/android/BUILD.gn
@@ -45,6 +45,7 @@ "//base:base_java", "//content/public/android:content_full_java", "//mojo/public/mojom/base:base_java", + "//third_party/android_deps:com_google_code_findbugs_jsr305_java", "//third_party/androidx:androidx_annotation_annotation_experimental_java", "//third_party/androidx:androidx_annotation_annotation_java", "//third_party/androidx:androidx_core_core_java",
diff --git a/components/stylus_handwriting/android/java/src/org/chromium/components/stylus_handwriting/StylusHandwritingFeatureMap.java b/components/stylus_handwriting/android/java/src/org/chromium/components/stylus_handwriting/StylusHandwritingFeatureMap.java index 9bf375d3..57b6905 100644 --- a/components/stylus_handwriting/android/java/src/org/chromium/components/stylus_handwriting/StylusHandwritingFeatureMap.java +++ b/components/stylus_handwriting/android/java/src/org/chromium/components/stylus_handwriting/StylusHandwritingFeatureMap.java
@@ -18,6 +18,8 @@ public static final String CACHE_STYLUS_SETTINGS = "CacheStylusSettings"; public static final String USE_HANDWRITING_INITIATOR = "UseHandwritingInitiator"; + public static final String PROBE_STYLUS_WRITING_IN_BACKGROUND = + "ProbeStylusWritingInBackground"; private static final StylusHandwritingFeatureMap sInstance = new StylusHandwritingFeatureMap(); // Do not instantiate this class.
diff --git a/components/stylus_handwriting/android/java/src/org/chromium/components/stylus_handwriting/StylusWritingController.java b/components/stylus_handwriting/android/java/src/org/chromium/components/stylus_handwriting/StylusWritingController.java index 8d9c24c..520e605 100644 --- a/components/stylus_handwriting/android/java/src/org/chromium/components/stylus_handwriting/StylusWritingController.java +++ b/components/stylus_handwriting/android/java/src/org/chromium/components/stylus_handwriting/StylusWritingController.java
@@ -8,11 +8,23 @@ import android.os.Build; import android.view.PointerIcon; +import androidx.annotation.AnyThread; +import androidx.annotation.IntDef; +import androidx.annotation.MainThread; + +import org.chromium.base.TraceEvent; +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.content_public.browser.StylusWritingHandler; import org.chromium.content_public.browser.WebContents; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +import javax.annotation.concurrent.GuardedBy; + /** * Helper class to determine whether Direct writing service is in consideration or the Android * platform Stylus Writing feature, and to set the appropriate handler to WebContents. @@ -28,6 +40,25 @@ private boolean mShouldOverrideStylusHoverIcon; private boolean mIsWindowFocused; + @IntDef({ + HandlerType.UNSET, + HandlerType.DIRECT_WRITING_TRIGGER, + HandlerType.ANDROID_HANDLER, + HandlerType.DISABLED_STYLUS_WRITING_HANDLER, + }) + @Retention(RetentionPolicy.SOURCE) + private @interface HandlerType { + int UNSET = 0; + int DIRECT_WRITING_TRIGGER = 1; + int ANDROID_HANDLER = 2; + int DISABLED_STYLUS_WRITING_HANDLER = 3; + } + + private final Object mLock = new Object(); + + @GuardedBy("mLock") + private @HandlerType int mHandlerType = HandlerType.UNSET; + private @Nullable AndroidStylusWritingHandler mAndroidHandler; private @Nullable DirectWritingTrigger mDirectWritingTrigger; private @Nullable DisabledStylusWritingHandler mDisabledStylusWritingHandler; @@ -40,10 +71,12 @@ } /** Creates a new instance of this class. */ + @MainThread public StylusWritingController(Context context) { this(context, false); } + @MainThread public StylusWritingController( Context context, boolean lazyFetchHandWritingIconFeatureEnabled) { mContext = context; @@ -58,6 +91,7 @@ } } + @MainThread private @Nullable PointerIcon getHandwritingIcon() { if (!mIconFetched) { int iconType = getHandler().getStylusPointerIcon(); @@ -71,41 +105,89 @@ } /** + * Determine the handler type that is needed. + * + * <p>This can be somewhat expensive, requiring multiple binder calls. + * + * <p>May be run on a background thread. + */ + @AnyThread + private static @HandlerType int computeHandlerType(Context context) { + try (TraceEvent e = TraceEvent.scoped("StylusWritingController.computeHandlerType")) { + if (DirectWritingSettingsHelper.isEnabled(context)) { + // Lazily initialize the various handlers since a lot of the time only one will be + // used. + return HandlerType.DIRECT_WRITING_TRIGGER; + } + + // The check for Android T is already in isEnabled but we are adding it here too to make + // lint happy. + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU + && AndroidStylusWritingHandler.isEnabled(context)) { + return HandlerType.ANDROID_HANDLER; + } + + return HandlerType.DISABLED_STYLUS_WRITING_HANDLER; + } + } + + /** + * Determine and cache the handler type that is needed. + * + * <p>May be run on a background thread to pre-cache the value. + */ + @AnyThread + private @HandlerType int getHandlerType(boolean refresh) { + if (!StylusHandwritingFeatureMap.isEnabledOrDefault( + StylusHandwritingFeatureMap.CACHE_STYLUS_SETTINGS, false)) { + return computeHandlerType(mContext); + } + + synchronized (mLock) { + if (mHandlerType == HandlerType.UNSET || refresh) { + mHandlerType = computeHandlerType(mContext); + } + return mHandlerType; + } + } + + /** * Returns the appropriate StylusWritingHandler - this may change at runtime if the user * enables/disables the stylus writing feature in their Android settings. */ + @MainThread private StylusApiOption chooseHandler() { - if (DirectWritingSettingsHelper.isEnabled(mContext)) { - // Lazily initialize the various handlers since a lot of the time only one will be used. - if (mDirectWritingTrigger == null) { - mDirectWritingTrigger = new DirectWritingTrigger(); + try (TraceEvent e = TraceEvent.scoped("StylusWritingController.chooseHandler")) { + switch (getHandlerType(/* refresh= */ false)) { + case HandlerType.DIRECT_WRITING_TRIGGER: + if (mDirectWritingTrigger == null) { + mDirectWritingTrigger = new DirectWritingTrigger(); + } + return mDirectWritingTrigger; + case HandlerType.ANDROID_HANDLER: + // This case isn't reachable unless we're on Android T, but we need to make the + // lint happy. + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + if (mAndroidHandler == null) { + mAndroidHandler = new AndroidStylusWritingHandler(mContext); + } + return mAndroidHandler; + } + break; } - return mDirectWritingTrigger; - } - - // The check for Android T is already in isEnabled but we are adding it here too to make - // lint happy. - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU - && AndroidStylusWritingHandler.isEnabled(mContext)) { - if (mAndroidHandler == null) { - mAndroidHandler = new AndroidStylusWritingHandler(mContext); + if (mDisabledStylusWritingHandler == null) { + mDisabledStylusWritingHandler = new DisabledStylusWritingHandler(); } - - return mAndroidHandler; + return mDisabledStylusWritingHandler; } - - if (mDisabledStylusWritingHandler == null) { - mDisabledStylusWritingHandler = new DisabledStylusWritingHandler(); - } - - return mDisabledStylusWritingHandler; } /* * Returns the currently selected handler, initializing it lazily if it has not been initialized * already. */ + @MainThread private StylusApiOption getHandler() { // If the feature is enabled, we listen to settings changes and re-run the handler selection // logic if stylus related settings changed. If the feature is disabled, we re-run the @@ -121,20 +203,74 @@ } /** + * Determining the handler type for the first time can be an expensive blocking operation taking + * multiple milliseconds. This wrapper can be used to pre-cache the handler type on a background + * thread if needed before continuing work on the UI thread. + * + * <p>Tasks should prefer to use instance state rather than captured state, as posted tasks may + * otherwise operate on stale data. + * + * <p>Must be called from the UI thread. + */ + @MainThread + private void probeSupportThenRunOrPost(boolean refresh, Runnable task) { + boolean background = + StylusHandwritingFeatureMap.isEnabledOrDefault( + StylusHandwritingFeatureMap.PROBE_STYLUS_WRITING_IN_BACKGROUND, false); + boolean cache = + StylusHandwritingFeatureMap.isEnabledOrDefault( + StylusHandwritingFeatureMap.CACHE_STYLUS_SETTINGS, false); + if (background && cache) { + // Note that multiple precache tasks could be posted in a race, but the underlying work + // is guarded by locks and the caching will avoid any expensive duplicate work. + PostTask.postTask( + TaskTraits.USER_VISIBLE_MAY_BLOCK, + () -> { + getHandlerType(refresh); + PostTask.postTask( + TaskTraits.UI_USER_VISIBLE, + () -> { + if (refresh) { + mStylusHandler = null; + } + task.run(); + }); + }); + } else { + getHandlerType(refresh); + if (refresh) { + mStylusHandler = null; + } + task.run(); + } + } + + /** * Notifies the applicable {@link StylusWritingHandler} so that stylus writing messages can be * received and handled for performing handwriting recognition. * * @param webContents current web contents */ + @MainThread public void onWebContentsChanged(WebContents webContents) { if (webContents.getViewAndroidDelegate() == null) return; mCurrentWebContents = webContents; - StylusApiOption handler = getHandler(); - handler.onWebContentsChanged(mContext, webContents); - webContents - .getViewAndroidDelegate() - .setShouldShowStylusHoverIconCallback(this::setShouldOverrideStylusHoverIcon); + + probeSupportThenRunOrPost( + /* refresh= */ false, + () -> { + if (mCurrentWebContents == null) return; + if (mCurrentWebContents.getViewAndroidDelegate() == null) return; + + StylusApiOption handler = getHandler(); + handler.onWebContentsChanged(mContext, mCurrentWebContents); + + mCurrentWebContents + .getViewAndroidDelegate() + .setShouldShowStylusHoverIconCallback( + this::setShouldOverrideStylusHoverIcon); + }); } /** @@ -142,21 +278,31 @@ * * @param hasFocus whether window gained or lost focus */ + @MainThread public void onWindowFocusChanged(boolean hasFocus) { // This notification is used to determine if the Stylus writing feature is enabled or not // from System settings as it can be changed while Chrome is in background. If caching of // stylus settings is enabled, we need to store the current focus state and send it when // settings change is observed. mIsWindowFocused = hasFocus; - updateStylusState(); + probeSupportThenRunOrPost( + /* refresh= */ false, + () -> { + updateStylusState(); + }); } /** Notify stylus related settings changed. */ + @MainThread public void onSettingsChange() { - mStylusHandler = chooseHandler(); - updateStylusState(); + probeSupportThenRunOrPost( + /* refresh= */ true, + () -> { + updateStylusState(); + }); } + @MainThread public @Nullable PointerIcon resolvePointerIcon() { if (mShouldOverrideStylusHoverIcon) { return mLazyFetchHandWritingIconFeatureEnabled @@ -166,10 +312,12 @@ return null; } + @MainThread private void setShouldOverrideStylusHoverIcon(boolean shouldOverride) { mShouldOverrideStylusHoverIcon = shouldOverride; } + @MainThread private void updateStylusState() { StylusApiOption handler = getHandler(); handler.updateHandlerState(mContext, mIsWindowFocused);
diff --git a/components/stylus_handwriting/android/java/src/org/chromium/components/stylus_handwriting/StylusWritingSettingsState.java b/components/stylus_handwriting/android/java/src/org/chromium/components/stylus_handwriting/StylusWritingSettingsState.java index cda7df0..b191b06 100644 --- a/components/stylus_handwriting/android/java/src/org/chromium/components/stylus_handwriting/StylusWritingSettingsState.java +++ b/components/stylus_handwriting/android/java/src/org/chromium/components/stylus_handwriting/StylusWritingSettingsState.java
@@ -11,6 +11,9 @@ import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; +import androidx.annotation.AnyThread; +import androidx.annotation.MainThread; + import org.chromium.base.ContextUtils; import org.chromium.base.ObserverList; import org.chromium.base.ThreadUtils; @@ -19,11 +22,16 @@ import java.util.ArrayList; import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; /** - * Keeps an updated values of settings interesting for the stylus functionality. All methods are - * expected to be called on the UI thread only. If this changed in the future, we should make sure - * that the class is thread-safe. + * Keeps an updated values of settings interesting for the stylus functionality. + * + * <p>Settings can be (lazily) initialized and queried on any thread. However, observers are run on + * the UI thread and must also be registered/unregistered on the UI thread. + * + * <p>Note that settings may change in-between getter calls from a non-UI thread. */ @NullMarked public class StylusWritingSettingsState { @@ -32,15 +40,22 @@ private static final String URI_DIRECT_WRITING = "direct_writing"; private static final String URI_STYLUS_HANDWRITING = "stylus_handwriting_enabled"; - private @Nullable String mDefaultInputMethod; - private @Nullable Integer mDirectWritingSetting; - private int mStylusHandWritingSetting; - private final ObserverList<StylusWritingController> mObservers = new ObserverList<>(); + private final AtomicReference<@Nullable String> mDefaultInputMethod = + new AtomicReference<>(null); + private final AtomicReference<@Nullable Integer> mDirectWritingSetting = + new AtomicReference<>(null); + private final AtomicInteger mStylusHandWritingSetting = new AtomicInteger(0); - private static final StylusWritingSettingsState sInstance = new StylusWritingSettingsState(); + // Lazily construct on the UI thread in getObserverList(), as the state object may be created on + // a background thread. Must only be accessed from the UI thread. + @Nullable private ObserverList<StylusWritingController> mObservers; + private static class LazyHolder { + static final StylusWritingSettingsState INSTANCE = new StylusWritingSettingsState(); + } + + @AnyThread private StylusWritingSettingsState() { - ThreadUtils.assertOnUiThread(); ContentResolver contentResolver = ContextUtils.getApplicationContext().getContentResolver(); ContentObserver stateObserver = new ContentObserver(ThreadUtils.getUiThreadHandler()) { @@ -80,59 +95,72 @@ } // Updates the settings values for stylus + @AnyThread private void update() { ContentResolver contentResolver = ContextUtils.getApplicationContext().getContentResolver(); - mDefaultInputMethod = - Settings.Secure.getString(contentResolver, Settings.Secure.DEFAULT_INPUT_METHOD); + mDefaultInputMethod.set( + Settings.Secure.getString(contentResolver, Settings.Secure.DEFAULT_INPUT_METHOD)); try { - mDirectWritingSetting = Settings.System.getInt(contentResolver, URI_DIRECT_WRITING); + mDirectWritingSetting.set(Settings.System.getInt(contentResolver, URI_DIRECT_WRITING)); } catch (SecurityException | SettingNotFoundException e) { // On some devices, URI_DIRECT_WRITING is not readable and trying to do so will // throw a security exception. https://crbug.com/1356155. - mDirectWritingSetting = null; + mDirectWritingSetting.set(null); } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { - mStylusHandWritingSetting = - Settings.Secure.getInt(contentResolver, URI_STYLUS_HANDWRITING, 1); + mStylusHandWritingSetting.set( + Settings.Secure.getInt(contentResolver, URI_STYLUS_HANDWRITING, 1)); } else { - mStylusHandWritingSetting = - Settings.Global.getInt(contentResolver, URI_STYLUS_HANDWRITING, -1); + mStylusHandWritingSetting.set( + Settings.Global.getInt(contentResolver, URI_STYLUS_HANDWRITING, -1)); } } + @MainThread + private ObserverList<StylusWritingController> getObserverList() { + if (mObservers == null) { + mObservers = new ObserverList(); + } + return mObservers; + } + + @MainThread private void notifyObservers() { - for (StylusWritingController controller : mObservers) { + for (StylusWritingController controller : getObserverList()) { controller.onSettingsChange(); } } + @AnyThread public static StylusWritingSettingsState getInstance() { - return sInstance; + return LazyHolder.INSTANCE; } + @AnyThread public @Nullable String getDefaultInputMethod() { - ThreadUtils.assertOnUiThread(); - return mDefaultInputMethod; + return mDefaultInputMethod.get(); } + @AnyThread public @Nullable Integer getDirectWritingSetting() { - ThreadUtils.assertOnUiThread(); - return mDirectWritingSetting; + return mDirectWritingSetting.get(); } + @AnyThread public int getStylusHandWritingSetting() { - ThreadUtils.assertOnUiThread(); - return mStylusHandWritingSetting; + return mStylusHandWritingSetting.get(); } + @MainThread public boolean registerObserver(StylusWritingController controller) { ThreadUtils.assertOnUiThread(); - return mObservers.addObserver(controller); + return getObserverList().addObserver(controller); } + @MainThread public boolean unregisterObserver(StylusWritingController controller) { ThreadUtils.assertOnUiThread(); - return mObservers.removeObserver(controller); + return getObserverList().removeObserver(controller); } }
diff --git a/components/stylus_handwriting/android/stylus_handwriting_feature_map.cc b/components/stylus_handwriting/android/stylus_handwriting_feature_map.cc index 84f13e4..fd41e5b 100644 --- a/components/stylus_handwriting/android/stylus_handwriting_feature_map.cc +++ b/components/stylus_handwriting/android/stylus_handwriting_feature_map.cc
@@ -15,6 +15,7 @@ const base::Feature* const kFeaturesExposedToJava[] = { &kCacheStylusSettings, + &kProbeStylusWritingInBackground, }; // static @@ -34,5 +35,7 @@ // Cache Stylus related settings BASE_FEATURE(kCacheStylusSettings, base::FEATURE_ENABLED_BY_DEFAULT); +BASE_FEATURE(kProbeStylusWritingInBackground, + base::FEATURE_DISABLED_BY_DEFAULT); } // namespace stylus_handwriting::android
diff --git a/components/stylus_handwriting/android/stylus_handwriting_feature_map.h b/components/stylus_handwriting/android/stylus_handwriting_feature_map.h index ce67f77..407e0e7 100644 --- a/components/stylus_handwriting/android/stylus_handwriting_feature_map.h +++ b/components/stylus_handwriting/android/stylus_handwriting_feature_map.h
@@ -12,6 +12,7 @@ namespace stylus_handwriting::android { BASE_DECLARE_FEATURE(kCacheStylusSettings); +BASE_DECLARE_FEATURE(kProbeStylusWritingInBackground); } // namespace stylus_handwriting::android
diff --git a/components/sync/model/client_tag_based_data_type_processor.cc b/components/sync/model/client_tag_based_data_type_processor.cc index 892e358f..8f3552da 100644 --- a/components/sync/model/client_tag_based_data_type_processor.cc +++ b/components/sync/model/client_tag_based_data_type_processor.cc
@@ -10,6 +10,7 @@ #include "base/auto_reset.h" #include "base/debug/alias.h" +#include "base/feature_list.h" #include "base/functional/bind.h" #include "base/location.h" #include "base/logging.h" @@ -46,6 +47,9 @@ namespace syncer { namespace { +BASE_FEATURE(kSyncClearMetadataOnEmptyStorageKeys, + base::FEATURE_ENABLED_BY_DEFAULT); + const char kErrorSiteHistogramPrefix[] = "Sync.DataTypeErrorSite."; // These values are persisted to logs. Entries should not be renumbered and @@ -203,7 +207,10 @@ return; } - if (ClearPersistedMetadataIfInvalid(*batch)) { + if (ShouldClearPersistedMetadata(*batch)) { + ClearAllProvidedMetadataAndResetState(batch->GetAllMetadata()); + // Not having `entity_tracker_` results in doing the initial sync again. + CHECK(!entity_tracker_); DLOG(ERROR) << "The persisted metadata was invalid and was cleared for " << DataTypeToDebugString(type_) << ". Start over fresh."; } else { @@ -220,6 +227,9 @@ DUMP_WILL_BE_CHECK(batch->GetAllMetadata().empty()); } } + // Whether metadata was actually cleared or not, any pending clear has now + // been processed. + pending_clear_metadata_ = false; DUMP_WILL_BE_CHECK(model_ready_to_sync_); ConnectIfReady(); @@ -1406,8 +1416,8 @@ std::move(callback).Run(std::move(all_nodes)); } -bool ClientTagBasedDataTypeProcessor::ClearPersistedMetadataIfInvalid( - const MetadataBatch& metadata) { +bool ClientTagBasedDataTypeProcessor::ShouldClearPersistedMetadata( + const MetadataBatch& metadata) const { // The entity tracker must not have been created before the metadata was // validated. CHECK(!entity_tracker_); @@ -1419,18 +1429,17 @@ // If so, clear the metadata from storage (using the bridge's // ApplyDisableSyncChanges()). if (pending_clear_metadata_) { - pending_clear_metadata_ = false; // Avoid calling the bridge if there's nothing to clear. if (data_type_state.ByteSizeLong() > 0 || !metadata_map.empty()) { LogClearMetadataWhileStoppedHistogram(type_, /*is_delayed_call=*/true); // This will incur an I/O operation by asking the bridge to clear the // metadata in storage. - ClearAllProvidedMetadataAndResetState(metadata_map); - // Not having `entity_tracker_` results in doing the initial sync again. - CHECK(!entity_tracker_); + // Note: The caller is responsible for resetting `pending_clear_metadata_` + // after clearing. return true; } - // Else: There was nothing to clear. + // Else: There was nothing to clear (so also no need to do the other + // validity checks). return false; } @@ -1439,9 +1448,6 @@ if (!IsInitialSyncAtLeastPartiallyDone( data_type_state.initial_sync_state()) && !metadata_map.empty()) { - ClearAllProvidedMetadataAndResetState(metadata_map); - // Not having `entity_tracker_` results in doing the initial sync again. - CHECK(!entity_tracker_); return true; } @@ -1456,12 +1462,20 @@ DataTypeHistogramValue(type_)); } - ClearAllProvidedMetadataAndResetState(metadata_map); - // Not having `entity_tracker_` results in doing the initial sync again. - CHECK(!entity_tracker_); return true; } + // Check that there are no empty/missing storage keys. + if (base::FeatureList::IsEnabled(kSyncClearMetadataOnEmptyStorageKeys)) { + for (const auto& [storage_key, _] : metadata_map) { + if (storage_key.empty()) { + base::UmaHistogramEnumeration("Sync.ClearMetadataDueToEmptyStorageKey", + DataTypeHistogramValue(type_)); + return true; + } + } + } + return false; }
diff --git a/components/sync/model/client_tag_based_data_type_processor.h b/components/sync/model/client_tag_based_data_type_processor.h index e078cd9..4606e81 100644 --- a/components/sync/model/client_tag_based_data_type_processor.h +++ b/components/sync/model/client_tag_based_data_type_processor.h
@@ -260,10 +260,9 @@ // if it is invalid. void ClearPersistedMetadataIfInconsistentWithActivationRequest(); - // Verifies that the passed-in metadata (DataTypeState plus entity metadata) - // is valid, and clears it (incl. the persisted data) if not. Returns whether - // the metadata was cleared. - bool ClearPersistedMetadataIfInvalid(const MetadataBatch& metadata); + // Returns whether the passed-in metadata should be cleared due to (a) being + // invalid, or (b) `pending_clear_metadata_`. + bool ShouldClearPersistedMetadata(const MetadataBatch& metadata) const; // Reports error and records a metric about `site` where the error occurred. void ReportErrorImpl(const ModelError& error, ErrorSite site);
diff --git a/components/sync/model/client_tag_based_data_type_processor_unittest.cc b/components/sync/model/client_tag_based_data_type_processor_unittest.cc index fff503f4..2f31c23 100644 --- a/components/sync/model/client_tag_based_data_type_processor_unittest.cc +++ b/components/sync/model/client_tag_based_data_type_processor_unittest.cc
@@ -2941,6 +2941,47 @@ /*expected_count=*/2); } +TEST_F(ClientTagBasedDataTypeProcessorTest, ShouldResetForMissingStorageKey) { + base::HistogramTester histogram_tester; + + const syncer::ClientTagHash kClientTagHash1 = + ClientTagHash::FromUnhashed(GetDataType(), "tag1"); + const syncer::ClientTagHash kClientTagHash2 = + ClientTagHash::FromUnhashed(GetDataType(), "tag2"); + const syncer::ClientTagHash kClientTagHash3 = + ClientTagHash::FromUnhashed(GetDataType(), "tag3"); + sync_pb::EntityMetadata entity_metadata1; + entity_metadata1.set_client_tag_hash(kClientTagHash1.value()); + entity_metadata1.set_creation_time(0); + sync_pb::EntityMetadata entity_metadata2; + entity_metadata2.set_client_tag_hash(kClientTagHash2.value()); + entity_metadata2.set_creation_time(0); + sync_pb::EntityMetadata entity_metadata3; + entity_metadata3.set_client_tag_hash(kClientTagHash3.value()); + entity_metadata3.set_creation_time(0); + + db()->PutMetadata(kKey1, std::move(entity_metadata1)); + // One of the storage keys is empty! + db()->PutMetadata("", std::move(entity_metadata2)); + db()->PutMetadata(kKey3, std::move(entity_metadata3)); + + InitializeToReadyState(); + + // With a missing storage key, metadata should have been cleared. + EXPECT_EQ(0U, db()->metadata_count()); + EXPECT_EQ(0U, ProcessorEntityCount()); + EXPECT_FALSE(type_processor()->IsTrackingMetadata()); + + histogram_tester.ExpectUniqueSample( + "Sync.ClearMetadataDueToEmptyStorageKey", + /*sample=*/DataTypeHistogramValue(GetDataType()), + /*expected_bucket_count=*/1); + + // Initial update. + worker()->UpdateFromServer(); + EXPECT_TRUE(type_processor()->IsTrackingMetadata()); +} + TEST_F(ClientTagBasedDataTypeProcessorTest, ShouldNotProcessInvalidRemoteIncrementalUpdate) { // To ensure the update is not ignored because of empty storage key.
diff --git a/components/sync/model/data_type_sync_bridge.cc b/components/sync/model/data_type_sync_bridge.cc index 1c99f88..83445f494 100644 --- a/components/sync/model/data_type_sync_bridge.cc +++ b/components/sync/model/data_type_sync_bridge.cc
@@ -92,11 +92,6 @@ return sync_pb::EntitySpecifics(); } -bool DataTypeSyncBridge::IsEntityDataValid( - const EntityData& entity_data) const { - return true; -} - DataTypeLocalChangeProcessor* DataTypeSyncBridge::change_processor() { return change_processor_.get(); }
diff --git a/components/sync/model/data_type_sync_bridge.h b/components/sync/model/data_type_sync_bridge.h index 52ce205..9fae7b8 100644 --- a/components/sync/model/data_type_sync_bridge.h +++ b/components/sync/model/data_type_sync_bridge.h
@@ -249,9 +249,7 @@ // Returns true if the provided `entity_data` is valid. This method should be // implemented by the bridges and can be used to validate the incoming remote // updates. - // TODO(crbug.com/40677711): Mark this method as pure virtual to force all the - // bridges to implement this. - virtual bool IsEntityDataValid(const EntityData& entity_data) const; + virtual bool IsEntityDataValid(const EntityData& entity_data) const = 0; // Needs to be informed about any model change occurring via Delete() and // Put(). The changing metadata should be stored to persistent storage
diff --git a/components/sync/model/entity_change.h b/components/sync/model/entity_change.h index 442772cb..bbb9dab3 100644 --- a/components/sync/model/entity_change.h +++ b/components/sync/model/entity_change.h
@@ -17,6 +17,8 @@ public: enum ChangeType { ACTION_ADD, ACTION_UPDATE, ACTION_DELETE }; + // Note: `storage_key` may be empty, for data types where + // DataTypeSyncBridge::SupportsGetStorageKey() returns false. static std::unique_ptr<EntityChange> CreateAdd(const std::string& storage_key, EntityData data); static std::unique_ptr<EntityChange> CreateUpdate(
diff --git a/components/sync/model/processor_entity.cc b/components/sync/model/processor_entity.cc index 238a0607..c9467e4b 100644 --- a/components/sync/model/processor_entity.cc +++ b/components/sync/model/processor_entity.cc
@@ -28,7 +28,7 @@ namespace { bool MetadataIsValid(const sync_pb::EntityMetadata& metadata) { - return metadata.has_client_tag_hash() && metadata.has_creation_time() && + return !metadata.client_tag_hash().empty() && metadata.has_creation_time() && metadata.sequence_number() >= metadata.acked_sequence_number(); }
diff --git a/components/sync/service/history_sync_session_durations_metrics_recorder.cc b/components/sync/service/history_sync_session_durations_metrics_recorder.cc index e6193cc..4e9f8350 100644 --- a/components/sync/service/history_sync_session_durations_metrics_recorder.cc +++ b/components/sync/service/history_sync_session_durations_metrics_recorder.cc
@@ -106,6 +106,13 @@ history_sync_status_ = new_history_sync_status; } +void HistorySyncSessionDurationsMetricsRecorder::OnSyncShutdown( + SyncService* sync) { + // Unreachable, since the service owning this instance is Shutdown() before + // the SyncService. + NOTREACHED(); +} + HistorySyncSessionDurationsMetricsRecorder::HistorySyncStatus HistorySyncSessionDurationsMetricsRecorder::DetermineHistorySyncStatus() const { if (!sync_service_ ||
diff --git a/components/sync/service/history_sync_session_durations_metrics_recorder.h b/components/sync/service/history_sync_session_durations_metrics_recorder.h index 5e45f22..c229c498 100644 --- a/components/sync/service/history_sync_session_durations_metrics_recorder.h +++ b/components/sync/service/history_sync_session_durations_metrics_recorder.h
@@ -38,6 +38,7 @@ // syncer::SyncServiceObserver: void OnStateChanged(SyncService* sync) override; + void OnSyncShutdown(SyncService* sync) override; private: enum class HistorySyncStatus {
diff --git a/components/sync/service/sync_session_durations_metrics_recorder.cc b/components/sync/service/sync_session_durations_metrics_recorder.cc index a7632cff..8f1cbf7 100644 --- a/components/sync/service/sync_session_durations_metrics_recorder.cc +++ b/components/sync/service/sync_session_durations_metrics_recorder.cc
@@ -182,6 +182,12 @@ HandleSyncAndAccountChange(); } +void SyncSessionDurationsMetricsRecorder::OnSyncShutdown(SyncService* sync) { + // Unreachable, since the service owning this instance is Shutdown() before + // the SyncService. + NOTREACHED(); +} + void SyncSessionDurationsMetricsRecorder::OnPrimaryAccountChanged( const signin::PrimaryAccountChangeEvent& event) { DVLOG(1) << __func__;
diff --git a/components/sync/service/sync_session_durations_metrics_recorder.h b/components/sync/service/sync_session_durations_metrics_recorder.h index 95b811d..67c1afc 100644 --- a/components/sync/service/sync_session_durations_metrics_recorder.h +++ b/components/sync/service/sync_session_durations_metrics_recorder.h
@@ -54,6 +54,7 @@ // syncer::SyncServiceObserver: void OnStateChanged(syncer::SyncService* sync) override; + void OnSyncShutdown(syncer::SyncService* sync) override; // IdentityManager::Observer: void OnPrimaryAccountChanged(
diff --git a/components/sync/test/fake_data_type_sync_bridge.cc b/components/sync/test/fake_data_type_sync_bridge.cc index 029ba0b..5c52e48 100644 --- a/components/sync/test/fake_data_type_sync_bridge.cc +++ b/components/sync/test/fake_data_type_sync_bridge.cc
@@ -58,7 +58,8 @@ } void ClearMetadata(const std::string& storage_key) override { - DCHECK(!storage_key.empty()); + // Note: `storage_key` usually shouldn't be empty here, but some tests + // exercise invalid-data scenarios where it is empty. db_->RemoveMetadata(storage_key); }
diff --git a/components/sync_preferences/common_syncable_prefs_database.cc b/components/sync_preferences/common_syncable_prefs_database.cc index 3f92c7f..77ffbdc36 100644 --- a/components/sync_preferences/common_syncable_prefs_database.cc +++ b/components/sync_preferences/common_syncable_prefs_database.cc
@@ -144,6 +144,7 @@ kAutofillNameAndEmailProfileNotSelectedCounter = 94, kAutofillAiLastVersionDeduped = 96, kCrossDeviceOmniboxIsInBottomPosition = 97, + kAutofillWasNameAndEmailProfileUsed = 98, // See components/sync_preferences/README.md about adding new entries here. // vvvvv IMPORTANT! vvvvv // Note to the reviewer: IT IS YOUR RESPONSIBILITY to ensure that new syncable @@ -182,6 +183,11 @@ syncer::PRIORITY_PREFERENCES, PrefSensitivity::kExemptFromUserControlWhileSignedIn, MergeBehavior::kNone}}, + {autofill::prefs::kAutofillWasNameAndEmailProfileUsed, + {syncable_prefs_ids::kAutofillWasNameAndEmailProfileUsed, + syncer::PRIORITY_PREFERENCES, + PrefSensitivity::kExemptFromUserControlWhileSignedIn, + MergeBehavior::kNone}}, {bookmarks::prefs::kShowAppsShortcutInBookmarkBar, {syncable_prefs_ids::kShowAppsShortcutInBookmarkBar, syncer::PREFERENCES, PrefSensitivity::kNone, MergeBehavior::kNone}},
diff --git a/components/sync_sessions/local_session_event_handler_impl.cc b/components/sync_sessions/local_session_event_handler_impl.cc index 4488bf54..a216045 100644 --- a/components/sync_sessions/local_session_event_handler_impl.cc +++ b/components/sync_sessions/local_session_event_handler_impl.cc
@@ -19,6 +19,7 @@ #include "components/sync/base/time.h" #include "components/sync/protocol/session_specifics.pb.h" #include "components/sync/protocol/sync_enums.pb.h" +#include "components/sync_sessions/session_store.h" #include "components/sync_sessions/sync_sessions_client.h" #include "components/sync_sessions/synced_session_tracker.h" #include "components/sync_sessions/synced_tab_delegate.h" @@ -315,7 +316,18 @@ auto specifics = std::make_unique<sync_pb::SessionSpecifics>(); specifics->set_session_tag(current_session_tag_); current_session->ToSessionHeaderProto().Swap(specifics->mutable_header()); - batch->Put(std::move(specifics)); + + // TODO(crbug.com/408182457): Some reports indicate that `specifics` is + // occasionally invalid here. In that case, avoid sending it to the sync + // machinery to avoid CHECK failures. + std::optional<SessionStore::SpecificsInvalidReason> invalid_reason = + SessionStore::GetSpecificsInvalidReason(*specifics); + if (!invalid_reason.has_value()) { + batch->Put(std::move(specifics)); + } else { + base::UmaHistogramEnumeration("Sync.InvalidSessionHeader.AssociateWindows", + *invalid_reason); + } if (is_session_restore) { UmaHistogramMediumTimes("Sync.AssociateWindowsTime.OnSessionRestore",
diff --git a/components/sync_sessions/session_store.cc b/components/sync_sessions/session_store.cc index fc12a0cf..e6a02c6 100644 --- a/components/sync_sessions/session_store.cc +++ b/components/sync_sessions/session_store.cc
@@ -7,6 +7,7 @@ #include <stdint.h> #include <algorithm> +#include <optional> #include <set> #include <utility> @@ -255,14 +256,35 @@ } // static -bool SessionStore::AreValidSpecifics(const SessionSpecifics& specifics) { +std::optional<SessionStore::SpecificsInvalidReason> +SessionStore::GetSpecificsInvalidReason( + const sync_pb::SessionSpecifics& specifics) { + // A session tag is always required. if (specifics.session_tag().empty()) { - return false; + return SpecificsInvalidReason::kMissingSessionTag; } + + // Only one of header or tab may be set. + if (specifics.has_header() && specifics.has_tab()) { + return SpecificsInvalidReason::kBothHeaderAndTab; + } + + // Tabs must have both a valid tab ID and tab node ID. if (specifics.has_tab()) { - return specifics.tab_node_id() >= 0 && specifics.tab().tab_id() > 0; + if (specifics.tab_node_id() < 0) { + return SpecificsInvalidReason::kTabBadTabNodeId; + } + if (specifics.tab().tab_id() <= 0) { + return SpecificsInvalidReason::kTabBadTabId; + } + return std::nullopt; } + if (specifics.has_header()) { + // A header entity must not have a tab node ID. + if (specifics.tab_node_id() != TabNodePool::kInvalidTabNodeID) { + return SpecificsInvalidReason::kHeaderWithTabNodeId; + } // Verify that tab IDs appear only once within a header. Intended to prevent // http://crbug.com/360822. std::set<int> session_tab_ids; @@ -270,14 +292,20 @@ for (int tab_id : window.tab()) { bool success = session_tab_ids.insert(tab_id).second; if (!success) { - return false; + return SpecificsInvalidReason::kHeaderWithDuplicateTabIds; } } } - return !specifics.has_tab() && - specifics.tab_node_id() == TabNodePool::kInvalidTabNodeID; + return std::nullopt; } - return false; + + // Neither header nor tab is set. + return SpecificsInvalidReason::kNeitherHeaderNorTab; +} + +// static +bool SessionStore::AreValidSpecifics(const SessionSpecifics& specifics) { + return !GetSpecificsInvalidReason(specifics).has_value(); } // static
diff --git a/components/sync_sessions/session_store.h b/components/sync_sessions/session_store.h index 852e129e0..81a63ed 100644 --- a/components/sync_sessions/session_store.h +++ b/components/sync_sessions/session_store.h
@@ -52,6 +52,24 @@ SyncSessionsClient* sessions_client, OpenCallback callback); + // These values are persisted to logs. Entries should not be renumbered and + // numeric values should never be reused. + // LINT.IfChange(SessionSpecificsInvalidReason) + enum class SpecificsInvalidReason { + kMissingSessionTag = 0, + kBothHeaderAndTab = 1, + kNeitherHeaderNorTab = 2, + kTabBadTabNodeId = 3, + kTabBadTabId = 4, + kHeaderWithDuplicateTabIds = 5, + kHeaderWithTabNodeId = 6, + kMaxValue = kHeaderWithTabNodeId + }; + // LINT.ThenChange(/tools/metrics/histograms/metadata/sync/enums.xml:SessionSpecificsInvalidReason) + + // Returns the reason the given `specifics` is invalid, or nullopt if valid. + static std::optional<SpecificsInvalidReason> GetSpecificsInvalidReason( + const sync_pb::SessionSpecifics& specifics); // Verifies whether a proto is malformed (e.g. required fields are missing). static bool AreValidSpecifics(const sync_pb::SessionSpecifics& specifics); // |specifics| must be valid, see AreValidSpecifics().
diff --git a/components/sync_user_events/user_event_data_type_controller.cc b/components/sync_user_events/user_event_data_type_controller.cc index db48d06..fd47899c 100644 --- a/components/sync_user_events/user_event_data_type_controller.cc +++ b/components/sync_user_events/user_event_data_type_controller.cc
@@ -48,4 +48,8 @@ sync->DataTypePreconditionChanged(type()); } +void UserEventDataTypeController::OnSyncShutdown(syncer::SyncService* sync) { + // Nothing to be done, `this` will be destructed imminently. +} + } // namespace syncer
diff --git a/components/sync_user_events/user_event_data_type_controller.h b/components/sync_user_events/user_event_data_type_controller.h index 9090c13..c8494225 100644 --- a/components/sync_user_events/user_event_data_type_controller.h +++ b/components/sync_user_events/user_event_data_type_controller.h
@@ -37,6 +37,7 @@ // syncer::SyncServiceObserver implementation. void OnStateChanged(syncer::SyncService* sync) override; + void OnSyncShutdown(syncer::SyncService* sync) override; private: const raw_ptr<SyncService> sync_service_;
diff --git a/content/browser/renderer_host/render_widget_host_view_android.cc b/content/browser/renderer_host/render_widget_host_view_android.cc index 088288f1..f0a0d28c 100644 --- a/content/browser/renderer_host/render_widget_host_view_android.cc +++ b/content/browser/renderer_host/render_widget_host_view_android.cc
@@ -83,6 +83,7 @@ #include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_widget_host_iterator.h" #include "content/public/common/content_client.h" +#include "content/public/common/content_features.h" #include "content/public/common/content_switches.h" #include "third_party/blink/public/mojom/input/input_handler.mojom.h" #include "third_party/perfetto/include/perfetto/tracing/track.h" @@ -488,7 +489,18 @@ // left in a rotation throttle and ending it here. end_rotation = true; } else { + // A standalone non-rotation resize has occurred. For WebView, we sync + // immediately. For the browser, schedule a vsync-aligned update to + // process it smoothly. sync_needed = true; + if (base::FeatureList::IsEnabled(features::kFluidResize) && + rwhva_->using_browser_compositor_) { + sync_needed = false; + if (!rwhva_->visual_properties_update_pending_) { + rwhva_->visual_properties_update_pending_ = true; + rwhva_->SetNeedsAnimate(); + } + } } } } @@ -819,15 +831,18 @@ const std::optional<viz::LocalSurfaceId>& child_local_surface_id, bool reuse_current_local_surface_id, bool ignore_ack) { - // Always merge the child_id, even if we cannot sync at this time. - if (child_local_surface_id) - local_surface_id_allocator_.UpdateFromChild(*child_local_surface_id); + // Always merge the child_id, even if we cannot sync at this time. + if (child_local_surface_id) { + local_surface_id_allocator_.UpdateFromChild(*child_local_surface_id); + } - if (!CanSynchronizeVisualProperties()) - return false; + if (!CanSynchronizeVisualProperties()) { + return false; + } - if (!child_local_surface_id && !reuse_current_local_surface_id) - local_surface_id_allocator_.GenerateId(); + if (!child_local_surface_id && !reuse_current_local_surface_id) { + local_surface_id_allocator_.GenerateId(); + } // If we still have an invalid viz::LocalSurfaceId, then we are hidden and // evicted. This will have been triggered by a child acknowledging a previous @@ -2001,6 +2016,21 @@ } void RenderWidgetHostViewAndroid::SetNeedsAnimate() { + if (base::FeatureList::IsEnabled(features::kFluidResize)) { + // The synchronous (WebView) compositor does not have a proper browser + // compositor with which to drive animations. + CHECK(using_browser_compositor_); + + // No-op if we are not attached to a window, as we are not visible. Visual + // properties will be synchronized when the view is shown. + if (observing_root_window_) { + if (auto* compositor = view_.GetWindowAndroid()->GetCompositor()) { + compositor->SetNeedsAnimate(); + } + } + return; + } + DCHECK(view_.GetWindowAndroid()); DCHECK(using_browser_compositor_); view_.GetWindowAndroid()->SetNeedsAnimate(); @@ -2365,6 +2395,16 @@ // an OOPIF client. if (touch_selection_controller_) needs_animate |= touch_selection_controller_->Animate(frame_time); + + if (visual_properties_update_pending_ && + base::FeatureList::IsEnabled(features::kFluidResize)) { + visual_properties_update_pending_ = false; + // Use a short deadline for fluid resizing. We don't want to block the + // UI thread, but we want the update to happen quickly. + SynchronizeVisualProperties(cc::DeadlinePolicy::UseDefaultDeadline(), + std::nullopt); + } + return needs_animate; }
diff --git a/content/browser/renderer_host/render_widget_host_view_android.h b/content/browser/renderer_host/render_widget_host_view_android.h index d2962827..b4420c83 100644 --- a/content/browser/renderer_host/render_widget_host_view_android.h +++ b/content/browser/renderer_host/render_widget_host_view_android.h
@@ -529,6 +529,8 @@ FRIEND_TEST_ALL_PREFIXES(SitePerProcessBrowserTest, GestureManagerListensToChildFrames); FRIEND_TEST_ALL_PREFIXES(RenderWidgetHostViewAndroidTest, DisplayFeature); + FRIEND_TEST_ALL_PREFIXES(RenderWidgetHostViewAndroidFluidResizeBrowserTest, + ResizeDefersSynchronizationToNextFrame); class ScreenStateChangeHandler { public: @@ -829,6 +831,10 @@ std::optional<base::flat_set<ui::DomCode>> locked_keyboard_keys_; + // Used to schedule a single visual properties update on the next vsync tick + // to achieve fluid resizing. + bool visual_properties_update_pending_ = false; + base::WeakPtrFactory<RenderWidgetHostViewAndroid> weak_ptr_factory_{this}; };
diff --git a/content/browser/renderer_host/render_widget_host_view_android_browsertest.cc b/content/browser/renderer_host/render_widget_host_view_android_browsertest.cc index 0d21937..2bb5137 100644 --- a/content/browser/renderer_host/render_widget_host_view_android_browsertest.cc +++ b/content/browser/renderer_host/render_widget_host_view_android_browsertest.cc
@@ -4,12 +4,14 @@ #include "content/browser/renderer_host/render_widget_host_view_android.h" +#include "base/run_loop.h" #include "base/test/scoped_feature_list.h" #include "base/test/test_timeouts.h" #include "base/test/test_trace_processor.h" #include "components/input/features.h" #include "components/input/utils.h" #include "content/public/browser/web_contents.h" +#include "content/public/common/content_features.h" #include "content/public/test/browser_test.h" #include "content/public/test/browser_test_utils.h" #include "content/public/test/content_browser_test.h" @@ -142,4 +144,79 @@ EXPECT_EQ(slice_count, expected_count); } +class RenderWidgetHostViewAndroidFluidResizeBrowserTest + : public RenderWidgetHostViewAndroidBrowserTest { + public: + RenderWidgetHostViewAndroidFluidResizeBrowserTest() { + feature_list_.InitAndEnableFeature(features::kFluidResize); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + +IN_PROC_BROWSER_TEST_F(RenderWidgetHostViewAndroidFluidResizeBrowserTest, + ResizeDefersSynchronizationToNextFrame) { + RenderFrameSubmissionObserver render_frame_submission_observer( + shell()->web_contents()); + EXPECT_TRUE(NavigateToURL( + shell(), GURL("data:text/html,<!doctype html>" + "<body style='background-color: magenta;'></body>"))); + if (render_frame_submission_observer.render_frame_count() == 0) { + render_frame_submission_observer.WaitForAnyFrameSubmission(); + } + + auto* view = static_cast<RenderWidgetHostViewAndroid*>( + shell()->web_contents()->GetRenderWidgetHostView()); + ASSERT_NE(view, nullptr); + // A single call to Animate() may not be sufficient to settle visual + // properties. Animate() triggers a synchronization with the renderer, and the + // renderer's response can, in turn, trigger further visual property changes + // in the browser, re-setting `visual_properties_update_pending_`. The loop + // ensures this cycle is complete and the state is stable before the test + // proceeds. On each iteration, it waits for a new frame and validates that + // one was produced to ensure progress is being made. + auto last_rfm = render_frame_submission_observer.LastRenderFrameMetadata(); + while (view->visual_properties_update_pending_) { + view->Animate(base::TimeTicks::Now()); + render_frame_submission_observer.WaitForAnyFrameSubmission(); + if (view->visual_properties_update_pending_) { + CHECK(last_rfm.local_surface_id != + render_frame_submission_observer.LastRenderFrameMetadata() + .local_surface_id); + last_rfm = render_frame_submission_observer.LastRenderFrameMetadata(); + } + } + + EXPECT_FALSE(view->visual_properties_update_pending_); + + const gfx::Size current_size_dip = view->GetViewBounds().size(); + const float scale = view->GetDeviceScaleFactor(); + const gfx::Size current_size_px = + gfx::ScaleToCeiledSize(current_size_dip, scale); + const gfx::Size new_size(current_size_px.width() / 2, + current_size_px.height() / 2); + // Ensure we're actually resizing. + ASSERT_NE(new_size, current_size_px); + view->screen_state_change_handler_.OnPhysicalBackingSizeChanged(new_size, 0); + + if (view->using_browser_compositor_) { + EXPECT_TRUE(view->visual_properties_update_pending_); + // Confirmed visual properties update is pending. We now wait for the + // renderer to submit a frame acknowledging the resize. + RenderFrameSubmissionObserver frame_observer(shell()->web_contents()); + frame_observer.WaitForAnyFrameSubmission(); + + // The renderer has submitted a frame, but the browser's animation tick + // that clears the pending flag might not have run yet. To avoid a race + // condition, we manually call Animate() to process the update. + view->Animate(base::TimeTicks::Now()); + + EXPECT_FALSE(view->visual_properties_update_pending_); + } else { + // Confirmed no pending visual properties update. + EXPECT_FALSE(view->visual_properties_update_pending_); + } +} + } // namespace content
diff --git a/content/browser/webrtc/resources/webrtc_internals.js b/content/browser/webrtc/resources/webrtc_internals.js index 21cdea47df..02c3ddf 100644 --- a/content/browser/webrtc/resources/webrtc_internals.js +++ b/content/browser/webrtc/resources/webrtc_internals.js
@@ -371,11 +371,13 @@ // Create a map from the stats entries so it behaves like a getStats maplike // and then sort it. const stats = sortStatsReport(new Map(data.reports)); + + // This augments stats with [delta] values. + statsRatesCalculator.addStatsReport(stats); stats.forEach(report => { statsTable.addStatsReport(peerConnectionElement, report); drawSingleReport(peerConnectionElement, report); }); - statsRatesCalculator.addStatsReport(stats); let ids = []; stats.forEach(report => {
diff --git a/content/public/renderer/render_frame.h b/content/public/renderer/render_frame.h index 7864b80..c5643723 100644 --- a/content/public/renderer/render_frame.h +++ b/content/public/renderer/render_frame.h
@@ -11,6 +11,7 @@ #include <string> #include <string_view> +#include "base/byte_count.h" #include "base/supports_user_data.h" #include "base/task/single_thread_task_runner.h" #include "content/common/buildflags.h" @@ -22,6 +23,8 @@ #include "third_party/blink/public/mojom/devtools/console_message.mojom.h" #include "third_party/blink/public/mojom/frame/triggering_event_info.mojom-shared.h" #include "third_party/blink/public/platform/task_type.h" +#include "third_party/blink/public/platform/web_url_request.h" +#include "third_party/blink/public/platform/web_url_response.h" #include "third_party/blink/public/web/web_navigation_policy.h" #include "ui/accessibility/ax_mode.h" #include "ui/accessibility/ax_tree_update.h" @@ -231,6 +234,15 @@ base::RepeatingCallback<void(const blink::SubresourceLoadMetrics&)>; virtual void SetSubresourceLoadCallback(SubresourceLoadCallback callback) = 0; + using LoadFromMemoryCacheCallback = + base::RepeatingCallback<void(const GURL& response_url, + int request_id, + base::ByteCount encoded_body_length, + const std::string& mime_type, + bool from_archive)>; + virtual void SetLoadFromMemoryCacheCallback( + LoadFromMemoryCacheCallback callback) = 0; + protected: ~RenderFrame() override {}
diff --git a/content/public/renderer/render_frame_observer.h b/content/public/renderer/render_frame_observer.h index 15e31f9..88a4c31 100644 --- a/content/public/renderer/render_frame_observer.h +++ b/content/public/renderer/render_frame_observer.h
@@ -287,6 +287,10 @@ // Reports that a resource was loaded from the blink memory cache. // |request_id| uniquely identifies this resource within this render frame. // |from_archive| indicates if the resource originated from a MHTML archive. + // + // TODO(crbug.com/404425954): `DidLoadResourceFromMemoryCache()` is going to + // be deprecated. Use `SetLoadFromMemoryCacheCallback()` in `RenderFrame` + // instead. virtual void DidLoadResourceFromMemoryCache( const GURL& response_url, int request_id,
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc index bb432f9..b581032 100644 --- a/content/renderer/render_frame_impl.cc +++ b/content/renderer/render_frame_impl.cc
@@ -4529,11 +4529,18 @@ void RenderFrameImpl::DidLoadResourceFromMemoryCache( const blink::WebURLRequest& request, const blink::WebURLResponse& response) { - for (auto& observer : observers_) { - observer.DidLoadResourceFromMemoryCache( + if (load_from_memory_cache_callback_) { + load_from_memory_cache_callback_.Run( request.Url(), response.RequestId(), base::ByteCount(response.EncodedBodyLength()), response.MimeType().Utf8(), response.FromArchive()); + } else { + for (auto& observer : observers_) { + observer.DidLoadResourceFromMemoryCache( + request.Url(), response.RequestId(), + base::ByteCount(response.EncodedBodyLength()), + response.MimeType().Utf8(), response.FromArchive()); + } } } @@ -4626,6 +4633,11 @@ subresource_load_callback_ = std::move(callback); } +void RenderFrameImpl::SetLoadFromMemoryCacheCallback( + LoadFromMemoryCacheCallback callback) { + load_from_memory_cache_callback_ = std::move(callback); +} + void RenderFrameImpl::DidObserveNewFeatureUsage( const blink::UseCounterFeature& feature) { TRACE_EVENT_WITH_FLOW0("navigation",
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h index 51e0fbd1..29c0e17 100644 --- a/content/renderer/render_frame_impl.h +++ b/content/renderer/render_frame_impl.h
@@ -777,6 +777,8 @@ void SetNewFeatureUsageCallback(NewFeatureUsageCallback callback) override; void SetSubresourceLoadCallback(SubresourceLoadCallback callback) override; + void SetLoadFromMemoryCacheCallback( + LoadFromMemoryCacheCallback callback) override; protected: explicit RenderFrameImpl(CreateParams params); @@ -1251,10 +1253,12 @@ // The callback to send the feature usage to the browser process through // PageLoadMetrics. NewFeatureUsageCallback new_feature_usage_callback_; - - // The callback to send the feature usage to the browser process through - // PageLoadMetrics. + // The callback to send the loaded subresource info to the browser process + // through PageLoadMetrics. SubresourceLoadCallback subresource_load_callback_; + // The callback to send the loaded resource info from memory cache to the + // browser process through PageLoadMetrics. + LoadFromMemoryCacheCallback load_from_memory_cache_callback_; // The text selection the last time DidChangeSelection got called. May contain // additional characters before and after the selected text, for IMEs. The
diff --git a/infra/config/generated/builders/ci/tvos-rel-fyi/properties.json b/infra/config/generated/builders/ci/tvos-rel-fyi/properties.json index a7c37383..8f96a124 100644 --- a/infra/config/generated/builders/ci/tvos-rel-fyi/properties.json +++ b/infra/config/generated/builders/ci/tvos-rel-fyi/properties.json
@@ -69,5 +69,5 @@ }, "builder_group": "chromium.fyi", "recipe": "chromium", - "xcode_build_version": "16f6" + "xcode_build_version": "17a324" } \ No newline at end of file
diff --git a/infra/config/generated/builders/ci/tvos-rel-fyi/targets/chromium.fyi.json b/infra/config/generated/builders/ci/tvos-rel-fyi/targets/chromium.fyi.json index e8357a1..5feccb9 100644 --- a/infra/config/generated/builders/ci/tvos-rel-fyi/targets/chromium.fyi.json +++ b/infra/config/generated/builders/ci/tvos-rel-fyi/targets/chromium.fyi.json
@@ -16,11 +16,11 @@ "--platform", "Apple TV 4K (3rd generation)", "--version", - "18.5", + "26.0", "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "16f6", + "17a324", "--xctest" ], "merge": { @@ -28,7 +28,7 @@ }, "module_name": "//base:base_unittests", "module_scheme": "gtest", - "name": "base_unittests Apple TV 4K (3rd generation) 18.5", + "name": "base_unittests Apple TV 4K (3rd generation) 26.0", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -47,11 +47,11 @@ }, "named_caches": [ { - "name": "runtime_tvos_18_5", - "path": "Runtime-tvos-18.5" + "name": "runtime_tvos_26_0", + "path": "Runtime-tvos-26.0" }, { - "name": "xcode_ios_16f6", + "name": "xcode_ios_17a324", "path": "Xcode.app" } ], @@ -59,7 +59,7 @@ }, "test": "base_unittests", "test_id_prefix": "ninja://base:base_unittests/", - "variant_id": "Apple TV 4K (3rd generation) 18.5" + "variant_id": "Apple TV 4K (3rd generation) 26.0" }, { "args": [ @@ -68,11 +68,11 @@ "--platform", "Apple TV 4K (3rd generation)", "--version", - "18.5", + "26.0", "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "16f6", + "17a324", "--xctest" ], "merge": { @@ -80,7 +80,7 @@ }, "module_name": "//components:components_browsertests", "module_scheme": "gtest", - "name": "components_browsertests Apple TV 4K (3rd generation) 18.5", + "name": "components_browsertests Apple TV 4K (3rd generation) 26.0", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -99,11 +99,11 @@ }, "named_caches": [ { - "name": "runtime_tvos_18_5", - "path": "Runtime-tvos-18.5" + "name": "runtime_tvos_26_0", + "path": "Runtime-tvos-26.0" }, { - "name": "xcode_ios_16f6", + "name": "xcode_ios_17a324", "path": "Xcode.app" } ], @@ -111,7 +111,7 @@ }, "test": "components_browsertests", "test_id_prefix": "ninja://components:components_browsertests/", - "variant_id": "Apple TV 4K (3rd generation) 18.5" + "variant_id": "Apple TV 4K (3rd generation) 26.0" }, { "args": [ @@ -120,11 +120,11 @@ "--platform", "Apple TV 4K (3rd generation)", "--version", - "18.5", + "26.0", "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "16f6", + "17a324", "--xctest" ], "merge": { @@ -132,7 +132,7 @@ }, "module_name": "//components:components_unittests", "module_scheme": "gtest", - "name": "components_unittests Apple TV 4K (3rd generation) 18.5", + "name": "components_unittests Apple TV 4K (3rd generation) 26.0", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -151,11 +151,11 @@ }, "named_caches": [ { - "name": "runtime_tvos_18_5", - "path": "Runtime-tvos-18.5" + "name": "runtime_tvos_26_0", + "path": "Runtime-tvos-26.0" }, { - "name": "xcode_ios_16f6", + "name": "xcode_ios_17a324", "path": "Xcode.app" } ], @@ -163,7 +163,7 @@ }, "test": "components_unittests", "test_id_prefix": "ninja://components:components_unittests/", - "variant_id": "Apple TV 4K (3rd generation) 18.5" + "variant_id": "Apple TV 4K (3rd generation) 26.0" }, { "args": [ @@ -172,11 +172,11 @@ "--platform", "Apple TV 4K (3rd generation)", "--version", - "18.5", + "26.0", "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "16f6", + "17a324", "--xctest" ], "merge": { @@ -184,7 +184,7 @@ }, "module_name": "//content/test:content_unittests", "module_scheme": "gtest", - "name": "content_unittests Apple TV 4K (3rd generation) 18.5", + "name": "content_unittests Apple TV 4K (3rd generation) 26.0", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -203,11 +203,11 @@ }, "named_caches": [ { - "name": "runtime_tvos_18_5", - "path": "Runtime-tvos-18.5" + "name": "runtime_tvos_26_0", + "path": "Runtime-tvos-26.0" }, { - "name": "xcode_ios_16f6", + "name": "xcode_ios_17a324", "path": "Xcode.app" } ], @@ -215,7 +215,7 @@ }, "test": "content_unittests", "test_id_prefix": "ninja://content/test:content_unittests/", - "variant_id": "Apple TV 4K (3rd generation) 18.5" + "variant_id": "Apple TV 4K (3rd generation) 26.0" }, { "args": [ @@ -224,11 +224,11 @@ "--platform", "Apple TV 4K (3rd generation)", "--version", - "18.5", + "26.0", "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "16f6", + "17a324", "--xctest" ], "merge": { @@ -236,7 +236,7 @@ }, "module_name": "//media:media_unittests", "module_scheme": "gtest", - "name": "media_unittests Apple TV 4K (3rd generation) 18.5", + "name": "media_unittests Apple TV 4K (3rd generation) 26.0", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -255,11 +255,11 @@ }, "named_caches": [ { - "name": "runtime_tvos_18_5", - "path": "Runtime-tvos-18.5" + "name": "runtime_tvos_26_0", + "path": "Runtime-tvos-26.0" }, { - "name": "xcode_ios_16f6", + "name": "xcode_ios_17a324", "path": "Xcode.app" } ], @@ -267,7 +267,7 @@ }, "test": "media_unittests", "test_id_prefix": "ninja://media:media_unittests/", - "variant_id": "Apple TV 4K (3rd generation) 18.5" + "variant_id": "Apple TV 4K (3rd generation) 26.0" } ] }
diff --git a/infra/config/generated/builders/try/tvos-rel-fyi/properties.json b/infra/config/generated/builders/try/tvos-rel-fyi/properties.json index a184c0e..fbe4183 100644 --- a/infra/config/generated/builders/try/tvos-rel-fyi/properties.json +++ b/infra/config/generated/builders/try/tvos-rel-fyi/properties.json
@@ -62,5 +62,5 @@ }, "builder_group": "tryserver.chromium.mac", "recipe": "chromium_trybot", - "xcode_build_version": "16f6" + "xcode_build_version": "17a324" } \ No newline at end of file
diff --git a/infra/config/generated/builders/try/tvos-rel-fyi/targets/chromium.fyi.json b/infra/config/generated/builders/try/tvos-rel-fyi/targets/chromium.fyi.json index e8357a1..5feccb9 100644 --- a/infra/config/generated/builders/try/tvos-rel-fyi/targets/chromium.fyi.json +++ b/infra/config/generated/builders/try/tvos-rel-fyi/targets/chromium.fyi.json
@@ -16,11 +16,11 @@ "--platform", "Apple TV 4K (3rd generation)", "--version", - "18.5", + "26.0", "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "16f6", + "17a324", "--xctest" ], "merge": { @@ -28,7 +28,7 @@ }, "module_name": "//base:base_unittests", "module_scheme": "gtest", - "name": "base_unittests Apple TV 4K (3rd generation) 18.5", + "name": "base_unittests Apple TV 4K (3rd generation) 26.0", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -47,11 +47,11 @@ }, "named_caches": [ { - "name": "runtime_tvos_18_5", - "path": "Runtime-tvos-18.5" + "name": "runtime_tvos_26_0", + "path": "Runtime-tvos-26.0" }, { - "name": "xcode_ios_16f6", + "name": "xcode_ios_17a324", "path": "Xcode.app" } ], @@ -59,7 +59,7 @@ }, "test": "base_unittests", "test_id_prefix": "ninja://base:base_unittests/", - "variant_id": "Apple TV 4K (3rd generation) 18.5" + "variant_id": "Apple TV 4K (3rd generation) 26.0" }, { "args": [ @@ -68,11 +68,11 @@ "--platform", "Apple TV 4K (3rd generation)", "--version", - "18.5", + "26.0", "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "16f6", + "17a324", "--xctest" ], "merge": { @@ -80,7 +80,7 @@ }, "module_name": "//components:components_browsertests", "module_scheme": "gtest", - "name": "components_browsertests Apple TV 4K (3rd generation) 18.5", + "name": "components_browsertests Apple TV 4K (3rd generation) 26.0", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -99,11 +99,11 @@ }, "named_caches": [ { - "name": "runtime_tvos_18_5", - "path": "Runtime-tvos-18.5" + "name": "runtime_tvos_26_0", + "path": "Runtime-tvos-26.0" }, { - "name": "xcode_ios_16f6", + "name": "xcode_ios_17a324", "path": "Xcode.app" } ], @@ -111,7 +111,7 @@ }, "test": "components_browsertests", "test_id_prefix": "ninja://components:components_browsertests/", - "variant_id": "Apple TV 4K (3rd generation) 18.5" + "variant_id": "Apple TV 4K (3rd generation) 26.0" }, { "args": [ @@ -120,11 +120,11 @@ "--platform", "Apple TV 4K (3rd generation)", "--version", - "18.5", + "26.0", "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "16f6", + "17a324", "--xctest" ], "merge": { @@ -132,7 +132,7 @@ }, "module_name": "//components:components_unittests", "module_scheme": "gtest", - "name": "components_unittests Apple TV 4K (3rd generation) 18.5", + "name": "components_unittests Apple TV 4K (3rd generation) 26.0", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -151,11 +151,11 @@ }, "named_caches": [ { - "name": "runtime_tvos_18_5", - "path": "Runtime-tvos-18.5" + "name": "runtime_tvos_26_0", + "path": "Runtime-tvos-26.0" }, { - "name": "xcode_ios_16f6", + "name": "xcode_ios_17a324", "path": "Xcode.app" } ], @@ -163,7 +163,7 @@ }, "test": "components_unittests", "test_id_prefix": "ninja://components:components_unittests/", - "variant_id": "Apple TV 4K (3rd generation) 18.5" + "variant_id": "Apple TV 4K (3rd generation) 26.0" }, { "args": [ @@ -172,11 +172,11 @@ "--platform", "Apple TV 4K (3rd generation)", "--version", - "18.5", + "26.0", "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "16f6", + "17a324", "--xctest" ], "merge": { @@ -184,7 +184,7 @@ }, "module_name": "//content/test:content_unittests", "module_scheme": "gtest", - "name": "content_unittests Apple TV 4K (3rd generation) 18.5", + "name": "content_unittests Apple TV 4K (3rd generation) 26.0", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -203,11 +203,11 @@ }, "named_caches": [ { - "name": "runtime_tvos_18_5", - "path": "Runtime-tvos-18.5" + "name": "runtime_tvos_26_0", + "path": "Runtime-tvos-26.0" }, { - "name": "xcode_ios_16f6", + "name": "xcode_ios_17a324", "path": "Xcode.app" } ], @@ -215,7 +215,7 @@ }, "test": "content_unittests", "test_id_prefix": "ninja://content/test:content_unittests/", - "variant_id": "Apple TV 4K (3rd generation) 18.5" + "variant_id": "Apple TV 4K (3rd generation) 26.0" }, { "args": [ @@ -224,11 +224,11 @@ "--platform", "Apple TV 4K (3rd generation)", "--version", - "18.5", + "26.0", "--out-dir", "${ISOLATED_OUTDIR}", "--xcode-build-version", - "16f6", + "17a324", "--xctest" ], "merge": { @@ -236,7 +236,7 @@ }, "module_name": "//media:media_unittests", "module_scheme": "gtest", - "name": "media_unittests Apple TV 4K (3rd generation) 18.5", + "name": "media_unittests Apple TV 4K (3rd generation) 26.0", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -255,11 +255,11 @@ }, "named_caches": [ { - "name": "runtime_tvos_18_5", - "path": "Runtime-tvos-18.5" + "name": "runtime_tvos_26_0", + "path": "Runtime-tvos-26.0" }, { - "name": "xcode_ios_16f6", + "name": "xcode_ios_17a324", "path": "Xcode.app" } ], @@ -267,7 +267,7 @@ }, "test": "media_unittests", "test_id_prefix": "ninja://media:media_unittests/", - "variant_id": "Apple TV 4K (3rd generation) 18.5" + "variant_id": "Apple TV 4K (3rd generation) 26.0" } ] }
diff --git a/infra/config/generated/luci/cr-buildbucket.cfg b/infra/config/generated/luci/cr-buildbucket.cfg index 0b75ff25..cdecdd6c 100644 --- a/infra/config/generated/luci/cr-buildbucket.cfg +++ b/infra/config/generated/luci/cr-buildbucket.cfg
@@ -68063,8 +68063,8 @@ priority: 35 execution_timeout_secs: 10800 caches { - name: "xcode_ios_16f6" - path: "xcode_ios_16f6.app" + name: "xcode_ios_17a324" + path: "xcode_ios_17a324.app" } build_numbers: YES service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com" @@ -126987,8 +126987,8 @@ seconds: 120 } caches { - name: "xcode_ios_16f6" - path: "xcode_ios_16f6.app" + name: "xcode_ios_17a324" + path: "xcode_ios_17a324.app" } build_numbers: YES service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
diff --git a/infra/config/subprojects/chromium/ci/chromium.fyi.star b/infra/config/subprojects/chromium/ci/chromium.fyi.star index 551ba21c..18d6b06 100644 --- a/infra/config/subprojects/chromium/ci/chromium.fyi.star +++ b/infra/config/subprojects/chromium/ci/chromium.fyi.star
@@ -1777,7 +1777,7 @@ "mac_default_arm64", "mac_toolchain", "out_dir_arg", - "xcode_16_beta", + "xcode_26_beta", "xctest", ], ), @@ -1789,7 +1789,7 @@ ), contact_team_email = "cobalt-appletv@google.com", execution_timeout = 3 * time.hour, - xcode = xcode.x16betabots, + xcode = xcode.x26betabots, ) fyi_ios_builder(
diff --git a/infra/config/subprojects/chromium/try/tryserver.chromium.mac.star b/infra/config/subprojects/chromium/try/tryserver.chromium.mac.star index 9ff79a4e..faeaf10 100644 --- a/infra/config/subprojects/chromium/try/tryserver.chromium.mac.star +++ b/infra/config/subprojects/chromium/try/tryserver.chromium.mac.star
@@ -730,7 +730,7 @@ builderless = True, cpu = cpu.ARM64, contact_team_email = "cobalt-appletv@google.com", - xcode = xcode.x16betabots, + xcode = xcode.x26betabots, ) ios_builder(
diff --git a/infra/config/targets/bundles.star b/infra/config/targets/bundles.star index 569fd39..9bc779c 100644 --- a/infra/config/targets/bundles.star +++ b/infra/config/targets/bundles.star
@@ -6849,7 +6849,7 @@ targets.bundle( targets = "tvos_tests", variants = [ - "SIM_APPLE_TV_4K_3RD_GENERATION_18_5", + "SIM_APPLE_TV_4K_3RD_GENERATION_26_0", ], ), ],
diff --git a/infra/config/targets/mixins.star b/infra/config/targets/mixins.star index 91b0cb0f..f1cf10db 100644 --- a/infra/config/targets/mixins.star +++ b/infra/config/targets/mixins.star
@@ -1401,13 +1401,13 @@ ) targets.mixin( - name = "tvos_runtime_cache_18_5", + name = "tvos_runtime_cache_26_0", generate_pyl_entry = False, swarming = targets.swarming( named_caches = [ swarming.cache( - name = "runtime_tvos_18_5", - path = "Runtime-tvos-18.5", + name = "runtime_tvos_26_0", + path = "Runtime-tvos-26.0", ), ], ),
diff --git a/infra/config/targets/variants.star b/infra/config/targets/variants.star index 63d6e5b..aee276bb 100644 --- a/infra/config/targets/variants.star +++ b/infra/config/targets/variants.star
@@ -249,17 +249,17 @@ ) targets.variant( - name = "SIM_APPLE_TV_4K_3RD_GENERATION_18_5", - identifier = "Apple TV 4K (3rd generation) 18.5", + name = "SIM_APPLE_TV_4K_3RD_GENERATION_26_0", + identifier = "Apple TV 4K (3rd generation) 26.0", generate_pyl_entry = False, mixins = [ - "tvos_runtime_cache_18_5", + "tvos_runtime_cache_26_0", ], args = [ "--platform", "Apple TV 4K (3rd generation)", "--version", - "18.5", + "26.0", ], )
diff --git a/internal b/internal index 9044ebb..86a4a8a 160000 --- a/internal +++ b/internal
@@ -1 +1 @@ -Subproject commit 9044ebbb524768005838a1dc2a8b0e7114e575eb +Subproject commit 86a4a8afd51091e4227435859e44c9be53d99e77
diff --git a/ios/chrome/browser/authentication/account_menu/coordinator/BUILD.gn b/ios/chrome/browser/authentication/account_menu/coordinator/BUILD.gn index 960d01d9..64b0ac1 100644 --- a/ios/chrome/browser/authentication/account_menu/coordinator/BUILD.gn +++ b/ios/chrome/browser/authentication/account_menu/coordinator/BUILD.gn
@@ -71,8 +71,8 @@ source_set("unit_tests") { testonly = true sources = [ - "account_menu_coordinator_unittests.mm", - "account_menu_mediator_unittests.mm", + "account_menu_coordinator_unittest.mm", + "account_menu_mediator_unittest.mm", ] deps = [ ":coordinator",
diff --git a/ios/chrome/browser/authentication/account_menu/coordinator/account_menu_coordinator_unittests.mm b/ios/chrome/browser/authentication/account_menu/coordinator/account_menu_coordinator_unittest.mm similarity index 100% rename from ios/chrome/browser/authentication/account_menu/coordinator/account_menu_coordinator_unittests.mm rename to ios/chrome/browser/authentication/account_menu/coordinator/account_menu_coordinator_unittest.mm
diff --git a/ios/chrome/browser/authentication/account_menu/coordinator/account_menu_mediator_unittests.mm b/ios/chrome/browser/authentication/account_menu/coordinator/account_menu_mediator_unittest.mm similarity index 100% rename from ios/chrome/browser/authentication/account_menu/coordinator/account_menu_mediator_unittests.mm rename to ios/chrome/browser/authentication/account_menu/coordinator/account_menu_mediator_unittest.mm
diff --git a/ios/chrome/browser/authentication/account_menu/ui/BUILD.gn b/ios/chrome/browser/authentication/account_menu/ui/BUILD.gn index d085e5ce..5f953657 100644 --- a/ios/chrome/browser/authentication/account_menu/ui/BUILD.gn +++ b/ios/chrome/browser/authentication/account_menu/ui/BUILD.gn
@@ -36,7 +36,7 @@ source_set("unit_tests") { testonly = true - sources = [ "account_menu_view_controller_unittests.mm" ] + sources = [ "account_menu_view_controller_unittest.mm" ] deps = [ ":ui", "//base",
diff --git a/ios/chrome/browser/authentication/account_menu/ui/account_menu_view_controller_unittests.mm b/ios/chrome/browser/authentication/account_menu/ui/account_menu_view_controller_unittest.mm similarity index 100% rename from ios/chrome/browser/authentication/account_menu/ui/account_menu_view_controller_unittests.mm rename to ios/chrome/browser/authentication/account_menu/ui/account_menu_view_controller_unittest.mm
diff --git a/ios/chrome/browser/authentication/ui_bundled/signin/add_account_signin/BUILD.gn b/ios/chrome/browser/authentication/ui_bundled/signin/add_account_signin/BUILD.gn index 3e852cb..ce58dc9 100644 --- a/ios/chrome/browser/authentication/ui_bundled/signin/add_account_signin/BUILD.gn +++ b/ios/chrome/browser/authentication/ui_bundled/signin/add_account_signin/BUILD.gn
@@ -47,16 +47,27 @@ source_set("unit_tests") { testonly = true - sources = [ "add_account_signin_manager_unittest.mm" ] + sources = [ + "add_account_signin_coordinator_unittest.mm", + "add_account_signin_manager_unittest.mm", + ] deps = [ ":add_account_signin", "//base/test:test_support", "//components/prefs", "//components/prefs:test_support", "//components/signin/public/identity_manager:test_support", + "//ios/chrome/app/profile", + "//ios/chrome/browser/shared/coordinator/scene:scene_state_header", "//ios/chrome/browser/shared/model/application_context", + "//ios/chrome/browser/shared/model/browser/test:test_support", + "//ios/chrome/browser/shared/model/profile/test", + "//ios/chrome/browser/signin/model:authentication_service_factory", "//ios/chrome/browser/signin/model:fake_system_identity", "//ios/chrome/browser/signin/model:fake_system_identity_manager", + "//ios/chrome/browser/signin/model:test_support", + "//ios/chrome/test:test_support", + "//ios/chrome/test/fakes", "//ios/web/common:uikit", "//ios/web/public/test", "//testing/gmock",
diff --git a/ios/chrome/browser/authentication/ui_bundled/signin/add_account_signin/add_account_signin_coordinator_unittest.mm b/ios/chrome/browser/authentication/ui_bundled/signin/add_account_signin/add_account_signin_coordinator_unittest.mm new file mode 100644 index 0000000..a9e40fb --- /dev/null +++ b/ios/chrome/browser/authentication/ui_bundled/signin/add_account_signin/add_account_signin_coordinator_unittest.mm
@@ -0,0 +1,127 @@ +// 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/authentication/ui_bundled/signin/add_account_signin/add_account_signin_coordinator.h" + +#import <UIKit/UIKit.h> + +#import "ios/chrome/app/profile/profile_state.h" +#import "ios/chrome/browser/authentication/ui_bundled/continuation.h" +#import "ios/chrome/browser/authentication/ui_bundled/signin/add_account_signin/add_account_signin_manager.h" +#import "ios/chrome/browser/shared/coordinator/scene/scene_state.h" +#import "ios/chrome/browser/shared/model/browser/test/test_browser.h" +#import "ios/chrome/browser/shared/model/profile/test/test_profile_ios.h" +#import "ios/chrome/browser/signin/model/authentication_service_factory.h" +#import "ios/chrome/browser/signin/model/fake_authentication_service_delegate.h" +#import "ios/chrome/test/fakes/fake_ui_view_controller.h" +#import "ios/chrome/test/ios_chrome_scoped_testing_local_state.h" +#import "ios/web/public/test/web_task_environment.h" +#import "testing/platform_test.h" +#import "third_party/ocmock/OCMock/OCMock.h" +#import "third_party/ocmock/gtest_support.h" + +namespace { + +class AddAccountSigninCoordinatorTest : public PlatformTest { + public: + AddAccountSigninCoordinatorTest() { + // The profile state will receive UI blocker request. They are not tested + // here, so it’s a non-strict mock. + profile_state_ = OCMClassMock([ProfileState class]); + scene_state_ = [[SceneState alloc] initWithAppState:nil]; + scene_state_.profileState = profile_state_; + TestProfileIOS::Builder builder = TestProfileIOS::Builder(); + builder.AddTestingFactory( + AuthenticationServiceFactory::GetInstance(), + AuthenticationServiceFactory::GetFactoryWithDelegate( + std::make_unique<FakeAuthenticationServiceDelegate>())); + profile_ = std::move(builder).Build(); + browser_ = std::make_unique<TestBrowser>(profile_.get(), scene_state_); + base_view_controller_ = [[FakeUIViewController alloc] init]; + coordinator_ = [[AddAccountSigninCoordinator alloc] + initWithBaseViewController:base_view_controller_ + browser:browser_.get() + contextStyle:SigninContextStyle::kDefault + accessPoint:signin_metrics::AccessPoint::kSettings + promoAction:signin_metrics::PromoAction:: + PROMO_ACTION_NO_SIGNIN_PROMO + signinIntent:AddAccountSigninIntent::kAddAccount + prefilledEmail:nil + continuationProvider:DoNothingContinuationProvider()]; + + add_account_signin_manager_mock_ = + OCMStrictClassMock([AddAccountSigninManager class]); + OCMExpect([(id)add_account_signin_manager_mock_ alloc]) + .andReturn(add_account_signin_manager_mock_); + OCMExpect([[(id)add_account_signin_manager_mock_ ignoringNonObjectArgs] + initWithBaseViewController:base_view_controller_ + prefService:nullptr + identityManager:nullptr + identityInteractionManager:[OCMArg any] + prefilledEmail:nil]) + .andReturn(add_account_signin_manager_mock_); + OCMExpect([add_account_signin_manager_mock_ + setDelegate:GetAddAccountSigninManagerDelegate()]); + } + + ~AddAccountSigninCoordinatorTest() override { + EXPECT_OCMOCK_VERIFY((id)add_account_signin_manager_mock_); + } + + id<AddAccountSigninManagerDelegate> GetAddAccountSigninManagerDelegate() { + return static_cast<id<AddAccountSigninManagerDelegate>>(coordinator_); + } + + protected: + web::WebTaskEnvironment task_environment_; + std::unique_ptr<TestProfileIOS> profile_; + std::unique_ptr<TestBrowser> browser_; + // Required for UI blocker. + ProfileState* profile_state_; + IOSChromeScopedTestingLocalState scoped_testing_local_state_; + SceneState* scene_state_; + + AddAccountSigninCoordinator* coordinator_; + UIViewController* base_view_controller_; + AddAccountSigninManager* add_account_signin_manager_mock_; +}; + +// Tests that AddAccountSigninCoordinator doesn't call its signinCompletion +// block when being stopped while showing an alert dialog. +TEST_F(AddAccountSigninCoordinatorTest, StopCoordinatorWhileShowingErrorAlert) { + // Open the coordiantor. + OCMExpect([add_account_signin_manager_mock_ + showSigninWithIntent:AddAccountSigninIntent::kAddAccount]); + __block BOOL signinCompletionCalled = NO; + coordinator_.signinCompletion = + ^(SigninCoordinatorResult result, id<SystemIdentity> identity) { + signinCompletionCalled = YES; + }; + [coordinator_ start]; + // Generate an error from AddAccountSigninManager. + base::RunLoop run_loop1; + task_environment_.GetMainThreadTaskRunner()->PostTask( + FROM_HERE, run_loop1.QuitClosure()); + run_loop1.Run(); + OCMExpect([add_account_signin_manager_mock_ setDelegate:nil]); + NSError* error = [NSError errorWithDomain:@"Error Domain" + code:-42 + userInfo:nil]; + [GetAddAccountSigninManagerDelegate() + addAccountSigninManagerFinishedWithResult:SigninAddAccountToDeviceResult:: + kError + identity:nil + error:error]; + // Stop the coordinator. + [coordinator_ stop]; + base::RunLoop run_loop2; + task_environment_.GetMainThreadTaskRunner()->PostTask( + FROM_HERE, run_loop2.QuitClosure()); + run_loop2.Run(); + // The sign-in completion should not be called since the owner stopped the + // coordinator. + EXPECT_FALSE(signinCompletionCalled); +} + +} // namespace
diff --git a/ios/chrome/browser/browser_view/ui_bundled/browser_coordinator.mm b/ios/chrome/browser/browser_view/ui_bundled/browser_coordinator.mm index ed5bdf6..4659ca4 100644 --- a/ios/chrome/browser/browser_view/ui_bundled/browser_coordinator.mm +++ b/ios/chrome/browser/browser_view/ui_bundled/browser_coordinator.mm
@@ -341,6 +341,7 @@ #import "ios/public/provider/chrome/browser/voice_search/voice_search_api.h" #import "ios/public/provider/chrome/browser/voice_search/voice_search_controller.h" #import "ios/web/public/web_state.h" +#import "ios/web/public/web_state_id.h" #import "ui/base/device_form_factor.h" #import "ui/base/l10n/l10n_util.h" @@ -4413,10 +4414,10 @@ #pragma mark - PasswordControllerDelegate methods - (BOOL)displaySignInNotification:(UIViewController*)viewController - fromTabId:(NSString*)tabId { - NSString* visibleTabId = self.activeWebState->GetStableIdentifier(); + fromTabId:(web::WebStateID)tabId { // Ignore unless the call comes from currently visible tab. - if (![tabId isEqualToString:visibleTabId]) { + web::WebStateID visibleTabId = self.activeWebState->GetUniqueIdentifier(); + if (tabId != visibleTabId) { return NO; } [self.viewController addChildViewController:viewController];
diff --git a/ios/chrome/browser/credential_provider/model/credential_provider_service.h b/ios/chrome/browser/credential_provider/model/credential_provider_service.h index 918734c6..a6922a96 100644 --- a/ios/chrome/browser/credential_provider/model/credential_provider_service.h +++ b/ios/chrome/browser/credential_provider/model/credential_provider_service.h
@@ -173,6 +173,7 @@ // syncer::SyncServiceObserver: void OnStateChanged(syncer::SyncService* sync) override; + void OnSyncShutdown(syncer::SyncService* sync) override; // Observer for change in enabled or managed state of prefs that govern the // CPE.
diff --git a/ios/chrome/browser/credential_provider/model/credential_provider_service.mm b/ios/chrome/browser/credential_provider/model/credential_provider_service.mm index ece25a9..0bc745e9 100644 --- a/ios/chrome/browser/credential_provider/model/credential_provider_service.mm +++ b/ios/chrome/browser/credential_provider/model/credential_provider_service.mm
@@ -664,6 +664,11 @@ UpdatePasswordSyncSetting(); } +void CredentialProviderService::OnSyncShutdown(syncer::SyncService* sync) { + // Unreachable, since this service is Shutdown() before the SyncService. + NOTREACHED(); +} + // PasskeyModel::Observer: void CredentialProviderService::OnPasskeysChanged( const std::vector<webauthn::PasskeyModelChange>& changes) {
diff --git a/ios/chrome/browser/find_in_page/model/BUILD.gn b/ios/chrome/browser/find_in_page/model/BUILD.gn index 1d9407f..dc0e211a 100644 --- a/ios/chrome/browser/find_in_page/model/BUILD.gn +++ b/ios/chrome/browser/find_in_page/model/BUILD.gn
@@ -35,11 +35,7 @@ source_set("eg2_tests") { configs += [ "//build/config/ios:xctest_config" ] testonly = true - sources = [ - "find_in_page_egtest.mm", - "find_in_page_egtest_util.h", - "find_in_page_egtest_util.mm", - ] + sources = [ "find_in_page_egtest.mm" ] deps = [ ":eg_test_support+eg2", "//components/omnibox/browser:pref_names",
diff --git a/ios/chrome/browser/find_in_page/model/find_in_page_egtest.mm b/ios/chrome/browser/find_in_page/model/find_in_page_egtest.mm index d25f613fc..06ce4f9b 100644 --- a/ios/chrome/browser/find_in_page/model/find_in_page_egtest.mm +++ b/ios/chrome/browser/find_in_page/model/find_in_page_egtest.mm
@@ -5,18 +5,43 @@ #import "base/ios/ios_util.h" #import "base/test/ios/wait_util.h" #import "ios/chrome/browser/find_in_page/model/find_in_page_app_interface.h" -#import "ios/chrome/browser/find_in_page/model/find_in_page_egtest_util.h" #import "ios/chrome/browser/popup_menu/ui_bundled/popup_menu_constants.h" +#import "ios/chrome/browser/shared/model/prefs/pref_names.h" #import "ios/chrome/browser/shared/public/features/features.h" +#import "ios/chrome/test/earl_grey/chrome_actions.h" #import "ios/chrome/test/earl_grey/chrome_earl_grey.h" #import "ios/chrome/test/earl_grey/chrome_earl_grey_ui.h" #import "ios/chrome/test/earl_grey/chrome_matchers.h" #import "ios/chrome/test/earl_grey/chrome_test_case.h" #import "ios/testing/earl_grey/app_launch_manager.h" #import "ios/testing/earl_grey/earl_grey_test.h" +#import "net/test/embedded_test_server/embedded_test_server.h" + +using chrome_test_util::WebStateScrollViewMatcher; namespace { +// Constants for Find in Page test content. +const char kFindInPageTestRepeatingText[] = "repeating"; +const char kFindInPageTestShortTextID[] = "shortText"; +const char kFindInPageTestShortText[] = "ShortQuery"; +const char kFindInPageTestLongText[] = + "This is a particularly long string with a great number of characters"; +const char kFindInPageTestSpecialCharactersText[] = "!@#$%^&*()_+"; +const char kFindInPageTestNumbersText[] = "1234567890"; +const char kFindInPageTestAlphanumericText[] = "f00bar"; +const char kFindInPageTestNonASCIIText[] = "大家好🦑"; +const char kFindInPageTestWithSpanishAccentText[] = "á"; +const char kFindInPageTestWithoutSpanishAccentText[] = "a"; +const char kFindInPageTestLowercaseAndUppercaseText[] = + "ThIs tExT Is bOtH UpPeRcAsE AnD LoWeRcAsE"; +const char kFindInPageTestRTLText[] = "He said \"שלם\" (shalom] to me."; + +// Relative URLs for testing purposes. +const char kFindInPageTestURL[] = "/findinpage.html"; +const char kFindInPageCrossOriginFrameTestURL[] = "/crossorigin.html"; +const char kFindInPageComplexPDFTestURL[] = "/complex_document.pdf"; + // Constants to identify the Find navigator UI components in the view hierarchy. constexpr char kFindInPageDoneButtonID[] = "find.doneButton"; constexpr char kFindInPageSearchFieldID[] = "find.searchField"; @@ -24,19 +49,84 @@ constexpr char kFindInPageNextButtonID[] = "find.nextButton"; constexpr char kFindInPagePreviousButtonID[] = "find.previousButton"; +// Returns Paste button matcher from UIMenuController. +id<GREYMatcher> PasteButton() { + NSString* a11yLabelPaste = @"Paste"; + return grey_allOf(grey_accessibilityLabel(a11yLabelPaste), + chrome_test_util::SystemSelectionCallout(), nil); +} + +// Returns the test content for different test cases. +std::string FindInPageTestContent() { + std::ostringstream oss; + oss << "<div>"; + oss << "Text that repeats: " << kFindInPageTestRepeatingText + << kFindInPageTestRepeatingText << "</p>"; + oss << " <p id=\"" << kFindInPageTestShortTextID << "\">" + << kFindInPageTestShortText << "</p>"; + oss << " <p>" << kFindInPageTestLongText << "</p>"; + oss << " <p>Special characters: " << kFindInPageTestSpecialCharactersText + << "</p>"; + oss << " <p>Numbers: " << kFindInPageTestNumbersText << "</p>"; + oss << " <p>Alphanumeric text: " << kFindInPageTestAlphanumericText + << "</p>"; + oss << " <p>Non-ASCII text: " << kFindInPageTestNonASCIIText << "</p>"; + oss << " <p>Text without spanish accent: " + << kFindInPageTestWithoutSpanishAccentText << "</p>"; + oss << " <p>Case sensitivity: " << kFindInPageTestLowercaseAndUppercaseText + << "</p>"; + oss << " <p dir=\"RTL\">" << kFindInPageTestRTLText << "</p>"; + oss << " <div>"; + oss << "<div style=\"height: 2000px; background-color: lightgray;\"/>"; + oss << "</div>"; + return oss.str(); +} + +// Response handler that serves a test page for Find in Page. +std::unique_ptr<net::test_server::HttpResponse> FindInPageTestPageHttpResponse( + const net::test_server::HttpRequest& request) { + if (request.relative_url != kFindInPageTestURL) { + return nullptr; + } + std::unique_ptr<net::test_server::BasicHttpResponse> http_response = + std::make_unique<net::test_server::BasicHttpResponse>(); + http_response->set_code(net::HTTP_OK); + http_response->set_content( + "<html><head><meta charset=\"UTF-8\"></head><body>" + + FindInPageTestContent() + "</body></html>"); + return std::move(http_response); +} + +// Response handler that serves a test page with a cross-origin iframe for Find +// in Page. `sourceURL` is used as `src` for the iframe. +std::unique_ptr<net::test_server::HttpResponse> +FindInPageTestCrossOriginFramePageHttpResponse( + const GURL& sourceURL, + const net::test_server::HttpRequest& request) { + if (request.relative_url != kFindInPageCrossOriginFrameTestURL) { + return nullptr; + } + std::unique_ptr<net::test_server::BasicHttpResponse> http_response = + std::make_unique<net::test_server::BasicHttpResponse>(); + http_response->set_code(net::HTTP_OK); + http_response->set_content( + "<html><head><meta charset=\"UTF-8\"></head><body>" + + FindInPageTestContent() + "<iframe src=\"" + sourceURL.spec() + + "\"></iframe></body></html>"); + return std::move(http_response); +} + } // namespace -// Tests for Native Find in Page. This tests the variant of Native Find in Page -// with a Find interaction i.e. with the system UI or Find navigator. Many tests -// use the `secondTestServer` to ensure what is being tested also works with -// cross-origin iframes. -@interface FindInPageTestCase - : ChromeTestCase <FindInPageTestCaseHelperDelegate> +// Tests for Find in Page. Many tests use the `secondTestServer` to ensure what +// is being tested also works with cross-origin iframes. +@interface FindInPageTestCase : ChromeTestCase @end @implementation FindInPageTestCase { - FindInPageTestCaseHelper* _helper; + // Second test server for cross-origin iframe tests. + std::unique_ptr<net::test_server::EmbeddedTestServer> _secondTestServer; } - (void)setUp { @@ -44,15 +134,11 @@ // Clear saved search term. [FindInPageAppInterface clearSearchTerm]; - - // Creating helper. - _helper = [[FindInPageTestCaseHelper alloc] init]; - _helper.testServer = self.testServer; - _helper.delegate = self; } -#pragma mark - FindInPageTestCaseHelperDelegate +#pragma mark - Helpers +// Opens Find in Page. - (void)openFindInPageWithOverflowMenu { [ChromeEarlGrey waitForKeyboardToDisappear]; [ChromeEarlGreyUI openToolsMenu]; @@ -72,17 +158,20 @@ [ChromeEarlGreyUI waitForAppToIdle]; } +// Closes Find in page. - (void)closeFindInPageWithDoneButton { [[EarlGrey selectElementWithMatcher:grey_accessibilityID(@(kFindInPageDoneButtonID))] performAction:grey_tap()]; } +// Replaces the text in the Find in page textfield. - (void)replaceFindInPageText:(NSString*)text { [[EarlGrey selectElementWithMatcher:[self findInPageInputField]] performAction:grey_replaceText(text)]; } +// Paste text into Find in page textfield. - (void)pasteTextToFindInPage:(NSString*)text { [ChromeEarlGrey copyTextToPasteboard:text]; [[EarlGrey selectElementWithMatcher:[self findInPageInputField]] @@ -90,15 +179,19 @@ [[EarlGrey selectElementWithMatcher:PasteButton()] performAction:grey_tap()]; } +// Clear text in Find in Page text field. - (void)clearFindInPageText { [[EarlGrey selectElementWithMatcher:[self findInPageInputField]] performAction:grey_replaceText(@"")]; } +// Matcher for find in page textfield. - (id<GREYMatcher>)findInPageInputField { return grey_accessibilityID(@(kFindInPageSearchFieldID)); } +// Asserts that there is a string "`resultIndex` of `resultCount`" present in +// the results count label. Waits for up to 1 second for this to happen. - (void)assertResultStringIsResult:(int)resultIndex outOfTotal:(int)resultCount { // Returns "<current> of <total>" search results label (e.g "1 of 5"). @@ -120,6 +213,9 @@ @"Timeout waiting for correct Find in Page results string to appear"); } +// Asserts that there is a string "0 of 0" present in the results count label, +// or that the label is not visible. Waits for up to 1 second for this to +// happen. - (void)assertResultStringIsEmptyOrZero { ConditionBlock condition = ^{ NSError* error = nil; @@ -137,6 +233,8 @@ @"Timeout waiting for correct Find in Page results string to appear"); } +// Asserts that there is a string in the results count label, that is not "0 of +// 0". Waits for up to 1 second for this to happen. - (void)assertResultStringIsNonZero { ConditionBlock condition = ^{ NSError* error = nil; @@ -155,42 +253,181 @@ @"Timeout waiting for correct Find in Page results string to appear"); } +// Taps Next button in Find in page. - (void)advanceToNextResult { [[EarlGrey selectElementWithMatcher:grey_accessibilityID(@(kFindInPageNextButtonID))] performAction:grey_tap()]; } +// Taps Previous button in Find in page. - (void)advanceToPreviousResult { [[EarlGrey selectElementWithMatcher:grey_accessibilityID( @(kFindInPagePreviousButtonID))] performAction:grey_tap()]; } +// Sets up two test servers to test Find in Page on web pages which might +// contain cross-origin iframes. +- (void)setUpTestServersForWebPageTest { + // Set up first server to test Find in Page content. + self.testServer->RegisterRequestHandler( + base::BindRepeating(&FindInPageTestPageHttpResponse)); + GREYAssertTrue(self.testServer->Start(), @"Server did not start."); + + // Set up second server for cross-origin iframe tests. + GURL sourceURLForFrame = self.testServer->GetURL(kFindInPageTestURL); + _secondTestServer = std::make_unique<net::test_server::EmbeddedTestServer>(); + [self secondTestServer]->RegisterRequestHandler(base::BindRepeating( + &FindInPageTestCrossOriginFramePageHttpResponse, sourceURLForFrame)); + GREYAssertTrue([self secondTestServer]->Start(), + @"Second test server serving page with iframe did not start."); +} + +- (void)setUpTestServerForPDFTest { + // This is sufficient to ensure `ios/testing/data/http_server_files/` file + // system directory is being served, as this is the default configuration. + GREYAssertTrue(self.testServer->Start(), @"Server did not start."); +} + +// Second test server so cross-origin iframes can be tested together with +// ChromeTestCase's `testServer`. +- (net::test_server::EmbeddedTestServer*)secondTestServer { + return _secondTestServer.get(); +} +// Matcher similar to `grey_text` but more generic i.e. only looks at `hasText` +// prefix. +- (id<GREYMatcher>)matcherForText:(NSString*)text { + NSString* prefix = @"hasText"; + GREYMatchesBlock matchesBlock = ^BOOL(id element) { + return [[element text] isEqualToString:text]; + }; + + GREYDescribeToBlock describeToBlock = ^void(id<GREYDescription> description) { + [description + appendText:[NSString stringWithFormat:@"%@('%@')", prefix, text]]; + }; + // A matcher for non-SwiftUI elements + id<GREYMatcher> matcher = + [[GREYElementMatcherBlock alloc] initWithMatchesBlock:matchesBlock + descriptionBlock:describeToBlock]; + return matcher; +} + #pragma mark - Tests // Tests that FIP can be opened with Overflow menu. - (void)testFindInPageFromOverflowMenu { - [_helper helperTestFindInPageFromOverflowMenu]; + [self setUpTestServersForWebPageTest]; + + // Load test page. + GURL destinationURL = self.testServer->GetURL(kFindInPageTestURL); + [ChromeEarlGrey loadURL:destinationURL]; + + // Open FIP with Overflow menu and check it is visible. + [self openFindInPageWithOverflowMenu]; + [ChromeEarlGrey + waitForSufficientlyVisibleElementWithMatcher:[self findInPageInputField]]; + [self closeFindInPageWithDoneButton]; } // Tests that characters appear in the search box and that results UI updates as // each characters is entered/deleted. - (void)testFindInPageTextInput { - [_helper helperTestFindInPageTextInput]; + [self setUpTestServersForWebPageTest]; + + // Load test page. + GURL destinationURL = self.testServer->GetURL(kFindInPageTestURL); + [ChromeEarlGrey loadURL:destinationURL]; + + // Open FIP. + [self openFindInPageWithOverflowMenu]; + // Test the result string is empty or "0". + [self assertResultStringIsEmptyOrZero]; + + [self replaceFindInPageText:@(kFindInPageTestRepeatingText)]; + // Test the input field contains the text that was just typed. + [[EarlGrey selectElementWithMatcher:[self findInPageInputField]] + assertWithMatcher:[self matcherForText:@(kFindInPageTestRepeatingText)]]; + // Test the result UI is updated accordingly. + [self assertResultStringIsResult:1 outOfTotal:2]; + + [self + replaceFindInPageText:[NSString + stringWithFormat:@"%s%s", + kFindInPageTestRepeatingText, + kFindInPageTestRepeatingText]]; + [self assertResultStringIsResult:1 outOfTotal:1]; + + [self + replaceFindInPageText:[NSString + stringWithFormat:@"%s%s%s", + kFindInPageTestRepeatingText, + kFindInPageTestRepeatingText, + kFindInPageTestRepeatingText]]; + [self assertResultStringIsEmptyOrZero]; + + [self clearFindInPageText]; + [self assertResultStringIsEmptyOrZero]; + [self closeFindInPageWithDoneButton]; } // Tests that the number of results for a query accounts for all the matches // across frames, here with a main frame and a cross-origin iframe. - (void)testFindInPageSupportsCrossOriginFrame { - [_helper helperTestFindInPageSupportsCrossOriginFrame]; + [self setUpTestServersForWebPageTest]; + + // Load test page with cross-origin iframe. + GURL destinationURL = + [self secondTestServer]->GetURL(kFindInPageCrossOriginFrameTestURL); + [ChromeEarlGrey loadURL:destinationURL]; + + // Open FIP. + [self openFindInPageWithOverflowMenu]; + [self assertResultStringIsEmptyOrZero]; + + [self replaceFindInPageText:@(kFindInPageTestShortText)]; + // Tests there are two matches: one is in the main frame, the other in the + // cross-origin iframe. + [self assertResultStringIsResult:1 outOfTotal:2]; + + [self advanceToNextResult]; + // Tests that the second match can be navigated to. + [self assertResultStringIsResult:2 outOfTotal:2]; + [self closeFindInPageWithDoneButton]; } // Tests that FIP can find different types of characters: special characters, // number, strings with both letters and numbers as well as non-ASCII // characters. - (void)testFindInPageSpecialCharacters { - [_helper helperTestFindInPageSpecialCharacters]; + [self setUpTestServersForWebPageTest]; + + // Load test page with cross-origin iframe. + GURL destinationURL = + [self secondTestServer]->GetURL(kFindInPageCrossOriginFrameTestURL); + [ChromeEarlGrey loadURL:destinationURL]; + + // Open FIP. + [self openFindInPageWithOverflowMenu]; + [self assertResultStringIsEmptyOrZero]; + + // Tests special characters. + [self replaceFindInPageText:@(kFindInPageTestSpecialCharactersText)]; + [self assertResultStringIsResult:1 outOfTotal:2]; + + // Tests numbers. + [self replaceFindInPageText:@(kFindInPageTestNumbersText)]; + [self assertResultStringIsResult:1 outOfTotal:2]; + + // Tests alphanumeric values. + [self replaceFindInPageText:@(kFindInPageTestAlphanumericText)]; + [self assertResultStringIsResult:1 outOfTotal:2]; + + // Tests non-ASCII characters. + [self replaceFindInPageText:@(kFindInPageTestNonASCIIText)]; + [self assertResultStringIsResult:1 outOfTotal:2]; + [self closeFindInPageWithDoneButton]; } // Tests that text can be copied from the web page and pasted into the FIP input @@ -202,18 +439,78 @@ EARL_GREY_TEST_DISABLED(@"Flaky on iOS 18 simulators."); } #endif - [_helper helperTestFindInPageCopyPaste]; + [self setUpTestServersForWebPageTest]; + + // Load test page. + GURL destinationURL = self.testServer->GetURL(kFindInPageTestURL); + [ChromeEarlGrey loadURL:destinationURL]; + + // Select and copy text on the web page. + [ChromeEarlGreyUI + longPressElementOnWebView: + [ElementSelector selectorWithElementID:kFindInPageTestShortTextID]]; + + [[EarlGrey + selectElementWithMatcher: + grey_allOf(chrome_test_util::SystemSelectionCalloutCopyButton(), + grey_sufficientlyVisible(), nil)] + performAction:grey_tap()]; + + // Open FIP. + [self openFindInPageWithOverflowMenu]; + + // Paste content of pasteboard in the FIP text field. + [[EarlGrey selectElementWithMatcher:[self findInPageInputField]] + performAction:grey_tap()]; + [[EarlGrey selectElementWithMatcher:PasteButton()] performAction:grey_tap()]; + + // Tests that the number of results is updated accordingly. + [self assertResultStringIsResult:1 outOfTotal:1]; + [self closeFindInPageWithDoneButton]; } // Tests that FIP yields no results for an empty search query. - (void)testFindInPageEmptySearchQuery { - [_helper helperTestFindInPageEmptySearchQuery]; + [self setUpTestServersForWebPageTest]; + + // Load test page with cross-origin iframe. + GURL destinationURL = + [self secondTestServer]->GetURL(kFindInPageCrossOriginFrameTestURL); + [ChromeEarlGrey loadURL:destinationURL]; + + // Open FIP. + [self openFindInPageWithOverflowMenu]; + + // Assert that searching text from the page yields results. + [self replaceFindInPageText:@(kFindInPageTestShortText)]; + [self assertResultStringIsNonZero]; + + // Test that the number of results is zero after clearing the FIP text + // field. + [self clearFindInPageText]; + [self assertResultStringIsEmptyOrZero]; + [self closeFindInPageWithDoneButton]; } // Tests that FIP yields no results for a non-empty query with no matches in the // page. - (void)testFindInPageQueryWithNoMatches { - [_helper helperTestFindInPageQueryWithNoMatches]; + [self setUpTestServersForWebPageTest]; + + // Load test page with cross-origin iframe. + GURL destinationURL = + [self secondTestServer]->GetURL(kFindInPageCrossOriginFrameTestURL); + [ChromeEarlGrey loadURL:destinationURL]; + + // Open FIP and type text that is not in the page. + const char* queryWithNoMatches = + "example query which should not match with the content of the page"; + [ChromeEarlGrey waitForWebStateNotContainingText:queryWithNoMatches]; + [self openFindInPageWithOverflowMenu]; + [self replaceFindInPageText:@(queryWithNoMatches)]; + // Test the result label shows no results. + [self assertResultStringIsEmptyOrZero]; + [self closeFindInPageWithDoneButton]; } // Tests that FIP yields no matches for a text with spanish accents e.g. 'á' if @@ -225,46 +522,273 @@ if (base::ios::IsRunningOnIOS26OrLater()) { EARL_GREY_TEST_DISABLED(@"Test disabled on iOS 26."); } - [_helper helperTestFindInPageDifferentAccent]; + [self setUpTestServersForWebPageTest]; + + // Load test page with cross-origin iframe. + GURL destinationURL = + [self secondTestServer]->GetURL(kFindInPageCrossOriginFrameTestURL); + [ChromeEarlGrey loadURL:destinationURL]; + + // Assert the text without accent is there but the text with accents does + // not match. + [ChromeEarlGrey + waitForWebStateContainingText:kFindInPageTestWithoutSpanishAccentText]; + [ChromeEarlGrey + waitForWebStateNotContainingText:kFindInPageTestWithSpanishAccentText]; + + // Open FIP and assert that text with no accents yields matches. + [self openFindInPageWithOverflowMenu]; + [self replaceFindInPageText:@(kFindInPageTestWithoutSpanishAccentText)]; + [self assertResultStringIsNonZero]; + + // Replace the text without spanish accent with the same text with spanish + // accents and test that there are no more matches. + [self replaceFindInPageText:@(kFindInPageTestWithSpanishAccentText)]; + [self assertResultStringIsEmptyOrZero]; + [self closeFindInPageWithDoneButton]; } // Test that there is no query persistence with this variant of Native Find in // Page i.e. with Find interaction. - (void)testFindInPageHistory { - [_helper helperTestFindInPageHistoryWithQueryPersistence:NO]; + [self setUpTestServersForWebPageTest]; + + // Load test page with cross-origin iframe. + GURL destinationURL = + [self secondTestServer]->GetURL(kFindInPageCrossOriginFrameTestURL); + [ChromeEarlGrey loadURL:destinationURL]; + + // Open FIP and test the input field is empty. + [self openFindInPageWithOverflowMenu]; + [[EarlGrey selectElementWithMatcher:[self findInPageInputField]] + assertWithMatcher:[self matcherForText:@""]]; + + // Type a query and assert it is contained in the input field before closing + // FIP. + [self replaceFindInPageText:@(kFindInPageTestShortText)]; + [[EarlGrey selectElementWithMatcher:[self findInPageInputField]] + assertWithMatcher:[self matcherForText:@(kFindInPageTestShortText)]]; + [self closeFindInPageWithDoneButton]; + + // Open FIP again and test depending on query persistence. + [self openFindInPageWithOverflowMenu]; + [[EarlGrey selectElementWithMatcher:[self findInPageInputField]] + assertWithMatcher:[self matcherForText:@""]]; + [self closeFindInPageWithDoneButton]; + + // Open the same URL in a different non-Incognito tab. + [ChromeEarlGrey openNewTab]; + [ChromeEarlGrey loadURL:destinationURL]; + + // Open FIP in this new tab and test depending on query persistence. + [self openFindInPageWithOverflowMenu]; + [[EarlGrey selectElementWithMatcher:[self findInPageInputField]] + assertWithMatcher:[self matcherForText:@""]]; + [self closeFindInPageWithDoneButton]; } // Tests that there is no query persistence from an non-Incognito to an // Incognito tab. - (void)testFindInPageNormalToIncognito { - [_helper helperTestFindInPageNormalToIncognito]; + [self setUpTestServersForWebPageTest]; + + // Load test page with cross-origin iframe. + GURL destinationURL = + [self secondTestServer]->GetURL(kFindInPageCrossOriginFrameTestURL); + [ChromeEarlGrey loadURL:destinationURL]; + + // Open FIP and type short query. + [self openFindInPageWithOverflowMenu]; + [self replaceFindInPageText:@(kFindInPageTestShortText)]; + [self closeFindInPageWithDoneButton]; + + // Load same URL in a new Incognito tab. + [ChromeEarlGrey openNewIncognitoTab]; + [ChromeEarlGrey loadURL:destinationURL]; + + // Open FIP and test the input field is empty. + [self openFindInPageWithOverflowMenu]; + [[EarlGrey selectElementWithMatcher:[self findInPageInputField]] + assertWithMatcher:[self matcherForText:@""]]; + [self closeFindInPageWithDoneButton]; +} + +// Tests that switching orientation during a Find session does not throw away +// the query or the current results. +- (void)testFindInPageSwitchOrientation { + if (base::ios::IsRunningOnIOS26OrLater()) { + EARL_GREY_TEST_DISABLED(@"Test disabled on iOS 26."); + } + [self setUpTestServersForWebPageTest]; + + // Load test page with cross-origin iframe. + GURL destinationURL = + [self secondTestServer]->GetURL(kFindInPageCrossOriginFrameTestURL); + [ChromeEarlGrey loadURL:destinationURL]; + + // Open FIP, type short query, move to second match and wait for expected + // results. + [self openFindInPageWithOverflowMenu]; + [self replaceFindInPageText:@(kFindInPageTestShortText)]; + [self advanceToNextResult]; + [self assertResultStringIsResult:2 outOfTotal:2]; + + // Switch to landscape. + GREYAssert( + [EarlGrey rotateDeviceToOrientation:UIDeviceOrientationLandscapeLeft + error:nil], + @"Could not rotate device to Landscape Left"); + + // Test the query is still there will the same result. + [[EarlGrey selectElementWithMatcher:[self findInPageInputField]] + assertWithMatcher:[self matcherForText:@(kFindInPageTestShortText)]]; + [self assertResultStringIsResult:2 outOfTotal:2]; + + // Switch back to portrait. + GREYAssert([EarlGrey rotateDeviceToOrientation:UIDeviceOrientationPortrait + error:nil], + @"Could not rotate device to Portrait"); + + // Test the query is still there will the same result. + [[EarlGrey selectElementWithMatcher:[self findInPageInputField]] + assertWithMatcher:[self matcherForText:@(kFindInPageTestShortText)]]; + [self assertResultStringIsResult:2 outOfTotal:2]; + [self closeFindInPageWithDoneButton]; } // Tests that Next/Previous buttons work and wrap. - (void)testFindInPageNextPreviousArrows { - [_helper helperTestFindInPageNextPreviousArrows]; + [self setUpTestServersForWebPageTest]; + + // Load test page with cross-origin iframe. + GURL destinationURL = + [self secondTestServer]->GetURL(kFindInPageCrossOriginFrameTestURL); + [ChromeEarlGrey loadURL:destinationURL]; + + // Open FIP and type query with four expected matches. + [self openFindInPageWithOverflowMenu]; + [self replaceFindInPageText:@(kFindInPageTestRepeatingText)]; + [self assertResultStringIsResult:1 outOfTotal:4]; + + // Test that tapping "Next" button works and wraps. + [self advanceToNextResult]; + [self assertResultStringIsResult:2 outOfTotal:4]; + [self advanceToNextResult]; + [self assertResultStringIsResult:3 outOfTotal:4]; + [self advanceToNextResult]; + [self assertResultStringIsResult:4 outOfTotal:4]; + [self advanceToNextResult]; + [self assertResultStringIsResult:1 outOfTotal:4]; + + // Test that tapping "Previous" button also works and wraps. + [self advanceToPreviousResult]; + [self assertResultStringIsResult:4 outOfTotal:4]; + [self advanceToPreviousResult]; + [self assertResultStringIsResult:3 outOfTotal:4]; + [self closeFindInPageWithDoneButton]; } // Tests the various ways to dismiss the keyboard during a Find session. // TODO(crbug.com/40283787): Test fails on downstream bots. - (void)DISABLED_testFindInPageDismissKeyboard { - [_helper helperTestFindInPageDismissKeyboard]; + [self setUpTestServersForWebPageTest]; + + // Load test page with cross-origin iframe. + GURL destinationURL = + [self secondTestServer]->GetURL(kFindInPageCrossOriginFrameTestURL); + [ChromeEarlGrey loadURL:destinationURL]; + + // Open FIP and type short query. + [self openFindInPageWithOverflowMenu]; + [self replaceFindInPageText:@(kFindInPageTestShortText)]; + + // Tap Done button and test the keyboard is dismissed as a result. + [self closeFindInPageWithDoneButton]; + [ChromeEarlGrey waitForKeyboardToDisappear]; + + // Open FIP and type short query again. + [self openFindInPageWithOverflowMenu]; + [self replaceFindInPageText:@(kFindInPageTestShortText)]; + + // Tap an element on the page and test the keyboard is dismissed as a + // result. + [[EarlGrey selectElementWithMatcher:chrome_test_util::WebViewMatcher()] + performAction:chrome_test_util::TapWebElementWithId( + kFindInPageTestShortTextID)]; + [ChromeEarlGrey waitForKeyboardToDisappear]; } // Tests that FIP can find long strings of characters. - (void)testFindInPageLongString { - [_helper helperTestFindInPageLongString]; + [self setUpTestServersForWebPageTest]; + + // Load test page with cross-origin iframe. + GURL destinationURL = + [self secondTestServer]->GetURL(kFindInPageCrossOriginFrameTestURL); + [ChromeEarlGrey loadURL:destinationURL]; + + // Open FIP and type short query. + [self openFindInPageWithOverflowMenu]; + [self replaceFindInPageText:@(kFindInPageTestLongText)]; + + // Test the number of results is as expected. + [self assertResultStringIsResult:1 outOfTotal:2]; + [self closeFindInPageWithDoneButton]; } // Tests that FIP is not case sensitive. - (void)testFindInPageNotCaseSensitive { - [_helper helperTestFindInPageNotCaseSensitive]; + [self setUpTestServersForWebPageTest]; + + // Load test page with cross-origin iframe. + GURL destinationURL = + [self secondTestServer]->GetURL(kFindInPageCrossOriginFrameTestURL); + [ChromeEarlGrey loadURL:destinationURL]; + + // Assert the page contains string that is both lowercase and uppercase. + [ChromeEarlGrey + waitForWebStateContainingText:kFindInPageTestLowercaseAndUppercaseText]; + + // Open FIP and type lowercase version of contained text. + [self openFindInPageWithOverflowMenu]; + [self replaceFindInPageText:[@(kFindInPageTestLowercaseAndUppercaseText) + lowercaseString]]; + // Test the number of results is as expected. + [self assertResultStringIsResult:1 outOfTotal:2]; + + // Clear input field and type uppercase version of contained text. + [self replaceFindInPageText:[@(kFindInPageTestLowercaseAndUppercaseText) + uppercaseString]]; + // Test the number of results is as expected. + [self assertResultStringIsResult:1 outOfTotal:2]; + [self closeFindInPageWithDoneButton]; } // Tests that there is no leak of the FIP search query from Incognito tabs to // normal tabs. - (void)testFindInPageIncognitoHistory { - [_helper helperTestFindInPageIncognitoHistory]; + [self setUpTestServersForWebPageTest]; + + // Load test page with cross-origin iframe in new Incognito tab. + [ChromeEarlGrey openNewIncognitoTab]; + GURL destinationURL = + [self secondTestServer]->GetURL(kFindInPageCrossOriginFrameTestURL); + [ChromeEarlGrey loadURL:destinationURL]; + + // Open FIP and type short query. + [self openFindInPageWithOverflowMenu]; + [self replaceFindInPageText:@(kFindInPageTestShortText)]; + [self closeFindInPageWithDoneButton]; + + // Open a new normal tab and load the same URL. + [ChromeEarlGrey openNewTab]; + [ChromeEarlGrey loadURL:destinationURL]; + + // Open FIP again and test the input field is empty. + [self openFindInPageWithOverflowMenu]; + [[EarlGrey selectElementWithMatcher:[self findInPageInputField]] + assertWithMatcher:[self matcherForText:@""]]; + [self closeFindInPageWithDoneButton]; } // Tests that there is no query persistence when coming back to a normal tab @@ -278,23 +802,80 @@ } } - [_helper helperTestFindInPageSwitchingTabsWithQueryPersistence:NO]; + [self setUpTestServersForWebPageTest]; + + // Load test page with cross-origin iframe in a second normal tab. + [ChromeEarlGrey openNewTab]; + GURL destinationURL = + [self secondTestServer]->GetURL(kFindInPageCrossOriginFrameTestURL); + [ChromeEarlGrey loadURL:destinationURL]; + + // Open FIP and type short query. + [self openFindInPageWithOverflowMenu]; + [self replaceFindInPageText:@(kFindInPageTestShortText)]; + + // Switching to first tab and then back to second tab. + [ChromeEarlGrey selectTabAtIndex:0]; + [ChromeEarlGrey selectTabAtIndex:1]; + + // Test query persistence. + [[EarlGrey selectElementWithMatcher:[self findInPageInputField]] + assertWithMatcher:[self matcherForText:@""]]; + [self closeFindInPageWithDoneButton]; } // Tests that FIP can find RTL text in a web page. // TODO(crbug.com/366752786): Re-enable once de-flaked. - (void)FLAKY_testFindInPageRTL { - [_helper helperTestFindInPageRTL]; + [self setUpTestServersForWebPageTest]; + + // Load test page with cross-origin iframe. + GURL destinationURL = + [self secondTestServer]->GetURL(kFindInPageCrossOriginFrameTestURL); + [ChromeEarlGrey loadURL:destinationURL]; + + // Open FIP, type RTL text and test that the results are as expected. + [self openFindInPageWithOverflowMenu]; + [self pasteTextToFindInPage:@(kFindInPageTestRTLText)]; + [self assertResultStringIsResult:1 outOfTotal:2]; + [self closeFindInPageWithDoneButton]; } // Tests that Find in Page can find matches in an Incognito tab. - (void)testFindInPageIncognito { - [_helper helperTestFindInPageIncognito]; + [self setUpTestServersForWebPageTest]; + + // Load test page with cross-origin iframe in a new Incognito tab. + [ChromeEarlGrey openNewIncognitoTab]; + GURL destinationURL = + [self secondTestServer]->GetURL(kFindInPageCrossOriginFrameTestURL); + [ChromeEarlGrey loadURL:destinationURL]; + + // Open FIP, type text contained in test page and test that the results are + // as expected. + [self openFindInPageWithOverflowMenu]; + [self replaceFindInPageText:@(kFindInPageTestShortText)]; + [self assertResultStringIsResult:1 outOfTotal:2]; + [self closeFindInPageWithDoneButton]; } // Tests accessibility of the Find in Page screen. - (void)testFindInPageAccessibility { - [_helper helperTestFindInPageAccessibility]; + [self setUpTestServersForWebPageTest]; + + // Load test page with cross-origin iframe. + GURL destinationURL = + [self secondTestServer]->GetURL(kFindInPageCrossOriginFrameTestURL); + [ChromeEarlGrey loadURL:destinationURL]; + + // Open FIP, type query and check the expected number of results. + [self openFindInPageWithOverflowMenu]; + [self replaceFindInPageText:@(kFindInPageTestShortText)]; + [self assertResultStringIsResult:1 outOfTotal:2]; + + // Test accessibility. + [ChromeEarlGrey verifyAccessibilityForCurrentScreen]; + [self closeFindInPageWithDoneButton]; } // Tests that Native Find in Page works as expected for PDF documents. @@ -304,7 +885,47 @@ EARL_GREY_TEST_DISABLED(@"Test disabled on iOS 26."); } - [_helper helperTestFindInPagePDF]; + [self setUpTestServerForPDFTest]; + + // Load test PDF document. + GURL destinationURL = self.testServer->GetURL(kFindInPageComplexPDFTestURL); + [ChromeEarlGrey loadURL:destinationURL]; + + // Open FIP and test that the input field is empty and there are no results. + [self openFindInPageWithOverflowMenu]; + [[EarlGrey selectElementWithMatcher:[self findInPageInputField]] + assertWithMatcher:[self matcherForText:@""]]; + [self assertResultStringIsEmptyOrZero]; + + // Type text with 18 expected matches and test that results are as + // expected. + [self replaceFindInPageText:@"the F"]; + [self assertResultStringIsResult:1 outOfTotal:18]; + + // Test that the Next button works. + [self advanceToNextResult]; + [self assertResultStringIsResult:2 outOfTotal:18]; + [self advanceToNextResult]; + [self assertResultStringIsResult:3 outOfTotal:18]; + + // Type more specific query and test that results are as expected. + [self replaceFindInPageText:@"the Form"]; + [self assertResultStringIsResult:1 outOfTotal:6]; + + // Test that the Previous button works and wraps. + [self advanceToPreviousResult]; + [self assertResultStringIsResult:6 outOfTotal:6]; + [self advanceToPreviousResult]; + [self assertResultStringIsResult:5 outOfTotal:6]; + + // Type even more specific query and test that results are as expected. + [self replaceFindInPageText:@"the Form 1050"]; + [self assertResultStringIsEmptyOrZero]; + + // Test that the Done button does close Find in Page. + [self closeFindInPageWithDoneButton]; + [[EarlGrey selectElementWithMatcher:[self findInPageInputField]] + assertWithMatcher:grey_notVisible()]; } // Tests that FIP exit fullscreen when done. @@ -313,7 +934,33 @@ // Relaunch the app to take the configuration into account. [[AppLaunchManager sharedManager] ensureAppLaunchedWithConfiguration:config]; - [_helper helperTestFindInPageExitFullscreen]; + [self setUpTestServersForWebPageTest]; + + // Load test page. + GURL destinationURL = self.testServer->GetURL(kFindInPageComplexPDFTestURL); + [ChromeEarlGrey loadURL:destinationURL]; + + // Ensure the toolbars are not in fullscreen mode by checking if share + // button is visible. + [[EarlGrey selectElementWithMatcher:chrome_test_util::TabShareButton()] + assertWithMatcher:grey_sufficientlyVisible()]; + + // Open FIP with Overflow menu and check it is visible and the share button + // is not visible. + [self openFindInPageWithOverflowMenu]; + [ChromeEarlGrey + waitForSufficientlyVisibleElementWithMatcher:[self findInPageInputField]]; + + [ChromeEarlGrey waitForUIElementToDisappearWithMatcher:chrome_test_util:: + TabShareButton()]; + + // Close find in page with Done button and ensure the share button is + // visible again. + [self closeFindInPageWithDoneButton]; + [[EarlGrey selectElementWithMatcher:[self findInPageInputField]] + assertWithMatcher:grey_notVisible()]; + [[EarlGrey selectElementWithMatcher:chrome_test_util::TabShareButton()] + assertWithMatcher:grey_sufficientlyVisible()]; } // Tests that FIP works properly with bottom omnibox. @@ -327,7 +974,34 @@ } #endif - [_helper helperTestFindInPageWithBottomOmnibox]; + // Set bottom Omnibox. + [ChromeEarlGrey setBoolValue:YES forLocalStatePref:prefs::kBottomOmnibox]; + + // Load test page. + [self setUpTestServersForWebPageTest]; + GURL destinationURL = self.testServer->GetURL(kFindInPageTestURL); + [ChromeEarlGrey loadURL:destinationURL]; + + [ChromeEarlGreyUI waitForToolbarVisible:YES]; + + // Open FIP with Overflow menu and check it is visible and the share button + // is not visible. + [self openFindInPageWithOverflowMenu]; + [ChromeEarlGrey + waitForSufficientlyVisibleElementWithMatcher:[self findInPageInputField]]; + + // Hide keyboard. + [ChromeEarlGrey simulatePhysicalKeyboardEvent:@"\n" flags:0]; + + // Scroll up and down the page. + [[EarlGrey selectElementWithMatcher:WebStateScrollViewMatcher()] + performAction:grey_scrollInDirection(kGREYDirectionDown, 150)]; + [[EarlGrey selectElementWithMatcher:WebStateScrollViewMatcher()] + performAction:grey_scrollInDirection(kGREYDirectionUp, 150)]; + + // Ensure that the bottom Omnibox is not visible. + [[EarlGrey selectElementWithMatcher:chrome_test_util::OmniboxAtBottom()] + assertWithMatcher:grey_notVisible()]; } @end
diff --git a/ios/chrome/browser/find_in_page/model/find_in_page_egtest_util.h b/ios/chrome/browser/find_in_page/model/find_in_page_egtest_util.h deleted file mode 100644 index 0a80d6e..0000000 --- a/ios/chrome/browser/find_in_page/model/find_in_page_egtest_util.h +++ /dev/null
@@ -1,156 +0,0 @@ -// Copyright 2023 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef IOS_CHROME_BROWSER_FIND_IN_PAGE_MODEL_FIND_IN_PAGE_EGTEST_UTIL_H_ -#define IOS_CHROME_BROWSER_FIND_IN_PAGE_MODEL_FIND_IN_PAGE_EGTEST_UTIL_H_ - -#import <Foundation/Foundation.h> - -namespace net { -namespace test_server { -class EmbeddedTestServer; -} -} // namespace net - -@protocol GREYMatcher; - -// Constants for Find in Page test content. -extern const char kFindInPageTestRepeatingText[]; -extern const char kFindInPageTestShortTextID[]; -extern const char kFindInPageTestShortText[]; -extern const char kFindInPageTestLongText[]; -extern const char kFindInPageTestSpecialCharactersText[]; -extern const char kFindInPageTestNumbersText[]; -extern const char kFindInPageTestAlphanumericText[]; -extern const char kFindInPageTestNonASCIIText[]; -extern const char kFindInPageTestWithSpanishAccentText[]; -extern const char kFindInPageTestWithoutSpanishAccentText[]; -extern const char kFindInPageTestLowercaseAndUppercaseText[]; -extern const char kFindInPageTestRTLText[]; - -// Relative URLs for testing purposes. -extern const char kFindInPageTestURL[]; -extern const char kFindInPageCrossOriginFrameTestURL[]; -extern const char kFindInPageComplexPDFTestURL[]; - -// Returns Paste button matcher from UIMenuController. -id<GREYMatcher> PasteButton(); - -// Delegate for FindInPageTestCaseHelper. A test case can implement this -// protocol to define how to perform basic Find in Page operations, and then set -// itself as the delegate of this helper. -@protocol FindInPageTestCaseHelperDelegate - -// Opens Find in Page. -- (void)openFindInPageWithOverflowMenu; -// Closes Find in page. -- (void)closeFindInPageWithDoneButton; -// Replaces the text in the Find in page textfield. -- (void)replaceFindInPageText:(NSString*)text; -// Paste text into Find in page textfield. -- (void)pasteTextToFindInPage:(NSString*)text; -// Clear text in Find in Page text field. -- (void)clearFindInPageText; -// Matcher for find in page textfield. -- (id<GREYMatcher>)findInPageInputField; -// Asserts that there is a string "`resultIndex` of `resultCount`" present in -// the results count label. Waits for up to 1 second for this to happen. -- (void)assertResultStringIsResult:(int)resultIndex outOfTotal:(int)resultCount; -// Asserts that there is a string "0 of 0" present in the results count label, -// or that the label is not visible. Waits for up to 1 second for this to -// happen. -- (void)assertResultStringIsEmptyOrZero; -// Asserts that there is a string in the results count label, that is not "0 of -// 0". Waits for up to 1 second for this to happen. -- (void)assertResultStringIsNonZero; -// Taps Next button in Find in page. -- (void)advanceToNextResult; -// Taps Previous button in Find in page. -- (void)advanceToPreviousResult; - -@end - -// Test helper for Native Find in Page. Many tests use the `secondTestServer` to -// ensure what is being tested also works with cross-origin iframes. -@interface FindInPageTestCaseHelper : NSObject - -// Delegate. -@property(nonatomic, weak) id<FindInPageTestCaseHelperDelegate> delegate; - -// First test server. -@property(nonatomic, assign) net::test_server::EmbeddedTestServer* testServer; - -// Sets up two test servers to test Find in Page on web pages which might -// contain cross-origin iframes. -- (void)setUpTestServersForWebPageTest; -// Second test server so cross-origin iframes can be tested together with -// ChromeTestCase's `testServer`. -- (net::test_server::EmbeddedTestServer*)secondTestServer; -// Matcher similar to `grey_text` but more generic i.e. only looks at `hasText` -// prefix. -- (id<GREYMatcher>)matcherForText:(NSString*)text; - -#pragma mark - Test scenarios - -// Tests that FIP can be opened with Overflow menu. -- (void)helperTestFindInPageFromOverflowMenu; -// Tests that characters appear in the search box and that results UI updates as -// each characters is entered/deleted. -- (void)helperTestFindInPageTextInput; -// Tests that the number of results for a query accounts for all the matches -// across frames, here with a main frame and a cross-origin iframe. -- (void)helperTestFindInPageSupportsCrossOriginFrame; -// Tests that FIP can find different types of characters: special characters, -// number, strings with both letters and numbers as well as non-ASCII -// characters. -- (void)helperTestFindInPageSpecialCharacters; -// Tests that text can be copied from the web page and pasted into the FIP input -// field and that the results UI updates accordingly. -- (void)helperTestFindInPageCopyPaste; -// Tests that FIP yields no results for an empty search query. -- (void)helperTestFindInPageEmptySearchQuery; -// Tests that FIP yields no results for a non-empty query with no matches in the -// page. -- (void)helperTestFindInPageQueryWithNoMatches; -// Tests that FIP yields no matches for a text with spanish accents e.g. 'á' if -// the web page contains the same text without spanish accents e.g. 'a'. This -// test assumes removing accents from `kFindInPageTestWithSpanishAccentText` -// yields `kFindInPageTestWithoutSpanishAccentText`. -- (void)helperTestFindInPageDifferentAccent; -// Test that there is no query persistence with this variant of Native Find in -// Page i.e. with Find interaction. -- (void)helperTestFindInPageHistoryWithQueryPersistence:(BOOL)queryPersistence; -// Tests that there is no query persistence from an non-Incognito to an -// Incognito tab. -- (void)helperTestFindInPageNormalToIncognito; -// Tests that Next/Previous buttons work and wrap. -- (void)helperTestFindInPageNextPreviousArrows; -// Tests the various ways to dismiss the keyboard during a Find session. -- (void)helperTestFindInPageDismissKeyboard; -// Tests that FIP can find long strings of characters. -- (void)helperTestFindInPageLongString; -// Tests that FIP is not case sensitive. -- (void)helperTestFindInPageNotCaseSensitive; -// Tests that there is no leak of the FIP search query from Incognito tabs to -// normal tabs. -- (void)helperTestFindInPageIncognitoHistory; -// Tests that there is no query persistence when coming back to a normal tab -// after switching temporarily to another tab. -- (void)helperTestFindInPageSwitchingTabsWithQueryPersistence: - (BOOL)queryPersistence; -// Tests that FIP can find RTL text in a web page. -- (void)helperTestFindInPageRTL; -// Tests that Find in Page can find matches in an Incognito tab. -- (void)helperTestFindInPageIncognito; -// Tests accessibility of the Find in Page screen. -- (void)helperTestFindInPageAccessibility; -// Tests that Native Find in Page works as expected for PDF documents. -- (void)helperTestFindInPagePDF; -// Tests that FIP exit fullscreen when done. -- (void)helperTestFindInPageExitFullscreen; -// Tests that FIP works properly with bottom Omnibox. -- (void)helperTestFindInPageWithBottomOmnibox; -@end - -#endif // IOS_CHROME_BROWSER_FIND_IN_PAGE_MODEL_FIND_IN_PAGE_EGTEST_UTIL_H_
diff --git a/ios/chrome/browser/find_in_page/model/find_in_page_egtest_util.mm b/ios/chrome/browser/find_in_page/model/find_in_page_egtest_util.mm deleted file mode 100644 index 7ae285e..0000000 --- a/ios/chrome/browser/find_in_page/model/find_in_page_egtest_util.mm +++ /dev/null
@@ -1,864 +0,0 @@ -// Copyright 2023 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "ios/chrome/browser/find_in_page/model/find_in_page_egtest_util.h" - -#import <sstream> - -#import "components/omnibox/browser/omnibox_pref_names.h" -#import "ios/chrome/browser/shared/model/prefs/pref_names.h" -#import "ios/chrome/test/earl_grey/chrome_actions.h" -#import "ios/chrome/test/earl_grey/chrome_earl_grey.h" -#import "ios/chrome/test/earl_grey/chrome_earl_grey_ui.h" -#import "ios/chrome/test/earl_grey/chrome_matchers.h" -#import "ios/chrome/test/earl_grey/chrome_xcui_actions.h" -#import "ios/testing/earl_grey/app_launch_manager.h" -#import "ios/testing/earl_grey/earl_grey_test.h" -#import "ios/web/public/test/element_selector.h" -#import "net/test/embedded_test_server/embedded_test_server.h" - -using chrome_test_util::WebStateScrollViewMatcher; - -namespace { - -// Returns the test content for different test cases. -std::string FindInPageTestContent() { - std::ostringstream oss; - oss << "<div>"; - oss << "Text that repeats: " << kFindInPageTestRepeatingText - << kFindInPageTestRepeatingText << "</p>"; - oss << " <p id=\"" << kFindInPageTestShortTextID << "\">" - << kFindInPageTestShortText << "</p>"; - oss << " <p>" << kFindInPageTestLongText << "</p>"; - oss << " <p>Special characters: " << kFindInPageTestSpecialCharactersText - << "</p>"; - oss << " <p>Numbers: " << kFindInPageTestNumbersText << "</p>"; - oss << " <p>Alphanumeric text: " << kFindInPageTestAlphanumericText - << "</p>"; - oss << " <p>Non-ASCII text: " << kFindInPageTestNonASCIIText << "</p>"; - oss << " <p>Text without spanish accent: " - << kFindInPageTestWithoutSpanishAccentText << "</p>"; - oss << " <p>Case sensitivity: " << kFindInPageTestLowercaseAndUppercaseText - << "</p>"; - oss << " <p dir=\"RTL\">" << kFindInPageTestRTLText << "</p>"; - oss << " <div>"; - oss << "<div style=\"height: 2000px; background-color: lightgray;\"/>"; - oss << "</div>"; - return oss.str(); -} - -// Response handler that serves a test page for Find in Page. -std::unique_ptr<net::test_server::HttpResponse> FindInPageTestPageHttpResponse( - const net::test_server::HttpRequest& request) { - if (request.relative_url != kFindInPageTestURL) { - return nullptr; - } - std::unique_ptr<net::test_server::BasicHttpResponse> http_response = - std::make_unique<net::test_server::BasicHttpResponse>(); - http_response->set_code(net::HTTP_OK); - http_response->set_content( - "<html><head><meta charset=\"UTF-8\"></head><body>" + - FindInPageTestContent() + "</body></html>"); - return std::move(http_response); -} - -// Response handler that serves a test page with a cross-origin iframe for Find -// in Page. `sourceURL` is used as `src` for the iframe. -std::unique_ptr<net::test_server::HttpResponse> -FindInPageTestCrossOriginFramePageHttpResponse( - const GURL& sourceURL, - const net::test_server::HttpRequest& request) { - if (request.relative_url != kFindInPageCrossOriginFrameTestURL) { - return nullptr; - } - std::unique_ptr<net::test_server::BasicHttpResponse> http_response = - std::make_unique<net::test_server::BasicHttpResponse>(); - http_response->set_code(net::HTTP_OK); - http_response->set_content( - "<html><head><meta charset=\"UTF-8\"></head><body>" + - FindInPageTestContent() + "<iframe src=\"" + sourceURL.spec() + - "\"></iframe></body></html>"); - return std::move(http_response); -} - -} // namespace - -const char kFindInPageTestRepeatingText[] = "repeating"; -const char kFindInPageTestShortTextID[] = "shortText"; -const char kFindInPageTestShortText[] = "ShortQuery"; -const char kFindInPageTestLongText[] = - "This is a particularly long string with a great number of characters"; -const char kFindInPageTestSpecialCharactersText[] = "!@#$%^&*()_+"; -const char kFindInPageTestNumbersText[] = "1234567890"; -const char kFindInPageTestAlphanumericText[] = "f00bar"; -const char kFindInPageTestNonASCIIText[] = "大家好🦑"; -const char kFindInPageTestWithSpanishAccentText[] = "á"; -const char kFindInPageTestWithoutSpanishAccentText[] = "a"; -const char kFindInPageTestLowercaseAndUppercaseText[] = - "ThIs tExT Is bOtH UpPeRcAsE AnD LoWeRcAsE"; -const char kFindInPageTestRTLText[] = "He said \"שלם\" (shalom] to me."; - -const char kFindInPageTestURL[] = "/findinpage.html"; -const char kFindInPageCrossOriginFrameTestURL[] = "/crossorigin.html"; -const char kFindInPageComplexPDFTestURL[] = "/complex_document.pdf"; - -id<GREYMatcher> PasteButton() { - NSString* a11yLabelPaste = @"Paste"; - return grey_allOf(grey_accessibilityLabel(a11yLabelPaste), - chrome_test_util::SystemSelectionCallout(), nil); -} - -@implementation FindInPageTestCaseHelper { - // Second test server for cross-origin iframe tests. - std::unique_ptr<net::test_server::EmbeddedTestServer> _secondTestServer; -} - -- (void)setUpTestServersForWebPageTest { - // Set up first server to test Find in Page content. - self.testServer->RegisterRequestHandler( - base::BindRepeating(&FindInPageTestPageHttpResponse)); - GREYAssertTrue(self.testServer->Start(), @"Server did not start."); - - // Set up second server for cross-origin iframe tests. - GURL sourceURLForFrame = self.testServer->GetURL(kFindInPageTestURL); - _secondTestServer = std::make_unique<net::test_server::EmbeddedTestServer>(); - [self secondTestServer]->RegisterRequestHandler(base::BindRepeating( - &FindInPageTestCrossOriginFramePageHttpResponse, sourceURLForFrame)); - GREYAssertTrue([self secondTestServer]->Start(), - @"Second test server serving page with iframe did not start."); -} - -- (net::test_server::EmbeddedTestServer*)secondTestServer { - return _secondTestServer.get(); -} - -- (void)setUpTestServerForPDFTest { - // This is sufficient to ensure `ios/testing/data/http_server_files/` file - // system directory is being served, as this is the default configuration. - GREYAssertTrue(self.testServer->Start(), @"Server did not start."); -} - -- (id<GREYMatcher>)matcherForText:(NSString*)text { - NSString* prefix = @"hasText"; - GREYMatchesBlock matchesBlock = ^BOOL(id element) { - return [[element text] isEqualToString:text]; - }; - - GREYDescribeToBlock describeToBlock = ^void(id<GREYDescription> description) { - [description - appendText:[NSString stringWithFormat:@"%@('%@')", prefix, text]]; - }; - // A matcher for non-SwiftUI elements - id<GREYMatcher> matcher = - [[GREYElementMatcherBlock alloc] initWithMatchesBlock:matchesBlock - descriptionBlock:describeToBlock]; - return matcher; -} - -// Tests that FIP can be opened with Overflow menu. -- (void)helperTestFindInPageFromOverflowMenu { - if (@available(iOS 16.1.1, *)) { - [self setUpTestServersForWebPageTest]; - - // Load test page. - GURL destinationURL = self.testServer->GetURL(kFindInPageTestURL); - [ChromeEarlGrey loadURL:destinationURL]; - - // Open FIP with Overflow menu and check it is visible. - [self.delegate openFindInPageWithOverflowMenu]; - [ChromeEarlGrey waitForSufficientlyVisibleElementWithMatcher: - [self.delegate findInPageInputField]]; - [self.delegate closeFindInPageWithDoneButton]; - } -} - -// Tests that characters appear in the search box and that results UI updates as -// each characters is entered/deleted. -- (void)helperTestFindInPageTextInput { - if (@available(iOS 16.1.1, *)) { - [self setUpTestServersForWebPageTest]; - - // Load test page. - GURL destinationURL = self.testServer->GetURL(kFindInPageTestURL); - [ChromeEarlGrey loadURL:destinationURL]; - - // Open FIP. - [self.delegate openFindInPageWithOverflowMenu]; - // Test the result string is empty or "0". - [self.delegate assertResultStringIsEmptyOrZero]; - - [self.delegate replaceFindInPageText:@(kFindInPageTestRepeatingText)]; - // Test the input field contains the text that was just typed. - [[EarlGrey selectElementWithMatcher:[self.delegate findInPageInputField]] - assertWithMatcher:[self - matcherForText:@(kFindInPageTestRepeatingText)]]; - // Test the result UI is updated accordingly. - [self.delegate assertResultStringIsResult:1 outOfTotal:2]; - - [self.delegate - replaceFindInPageText: - [NSString stringWithFormat:@"%s%s", kFindInPageTestRepeatingText, - kFindInPageTestRepeatingText]]; - [self.delegate assertResultStringIsResult:1 outOfTotal:1]; - - [self.delegate - replaceFindInPageText: - [NSString stringWithFormat:@"%s%s%s", kFindInPageTestRepeatingText, - kFindInPageTestRepeatingText, - kFindInPageTestRepeatingText]]; - [self.delegate assertResultStringIsEmptyOrZero]; - - [self.delegate clearFindInPageText]; - [self.delegate assertResultStringIsEmptyOrZero]; - [self.delegate closeFindInPageWithDoneButton]; - } -} - -// Tests that the number of results for a query accounts for all the matches -// across frames, here with a main frame and a cross-origin iframe. -- (void)helperTestFindInPageSupportsCrossOriginFrame { - if (@available(iOS 16.1.1, *)) { - [self setUpTestServersForWebPageTest]; - - // Load test page with cross-origin iframe. - GURL destinationURL = - [self secondTestServer]->GetURL(kFindInPageCrossOriginFrameTestURL); - [ChromeEarlGrey loadURL:destinationURL]; - - // Open FIP. - [self.delegate openFindInPageWithOverflowMenu]; - [self.delegate assertResultStringIsEmptyOrZero]; - - [self.delegate replaceFindInPageText:@(kFindInPageTestShortText)]; - // Tests there are two matches: one is in the main frame, the other in the - // cross-origin iframe. - [self.delegate assertResultStringIsResult:1 outOfTotal:2]; - - [self.delegate advanceToNextResult]; - // Tests that the second match can be navigated to. - [self.delegate assertResultStringIsResult:2 outOfTotal:2]; - [self.delegate closeFindInPageWithDoneButton]; - } -} - -// Tests that FIP can find different types of characters: special characters, -// number, strings with both letters and numbers as well as non-ASCII -// characters. -- (void)helperTestFindInPageSpecialCharacters { - if (@available(iOS 16.1.1, *)) { - [self setUpTestServersForWebPageTest]; - - // Load test page with cross-origin iframe. - GURL destinationURL = - [self secondTestServer]->GetURL(kFindInPageCrossOriginFrameTestURL); - [ChromeEarlGrey loadURL:destinationURL]; - - // Open FIP. - [self.delegate openFindInPageWithOverflowMenu]; - [self.delegate assertResultStringIsEmptyOrZero]; - - // Tests special characters. - [self.delegate - replaceFindInPageText:@(kFindInPageTestSpecialCharactersText)]; - [self.delegate assertResultStringIsResult:1 outOfTotal:2]; - - // Tests numbers. - [self.delegate replaceFindInPageText:@(kFindInPageTestNumbersText)]; - [self.delegate assertResultStringIsResult:1 outOfTotal:2]; - - // Tests alphanumeric values. - [self.delegate replaceFindInPageText:@(kFindInPageTestAlphanumericText)]; - [self.delegate assertResultStringIsResult:1 outOfTotal:2]; - - // Tests non-ASCII characters. - [self.delegate replaceFindInPageText:@(kFindInPageTestNonASCIIText)]; - [self.delegate assertResultStringIsResult:1 outOfTotal:2]; - [self.delegate closeFindInPageWithDoneButton]; - } -} - -// Tests that text can be copied from the web page and pasted into the FIP input -// field and that the results UI updates accordingly. -- (void)helperTestFindInPageCopyPaste { - if (@available(iOS 16.1.1, *)) { - [self setUpTestServersForWebPageTest]; - - // Load test page. - GURL destinationURL = self.testServer->GetURL(kFindInPageTestURL); - [ChromeEarlGrey loadURL:destinationURL]; - - // Select and copy text on the web page. - [ChromeEarlGreyUI - longPressElementOnWebView: - [ElementSelector selectorWithElementID:kFindInPageTestShortTextID]]; - - [[EarlGrey - selectElementWithMatcher: - grey_allOf(chrome_test_util::SystemSelectionCalloutCopyButton(), - grey_sufficientlyVisible(), nil)] - performAction:grey_tap()]; - - // Open FIP. - [self.delegate openFindInPageWithOverflowMenu]; - - // Paste content of pasteboard in the FIP text field. - [[EarlGrey selectElementWithMatcher:[self.delegate findInPageInputField]] - performAction:grey_tap()]; - [[EarlGrey selectElementWithMatcher:PasteButton()] - performAction:grey_tap()]; - - // Tests that the number of results is updated accordingly. - [self.delegate assertResultStringIsResult:1 outOfTotal:1]; - [self.delegate closeFindInPageWithDoneButton]; - } -} - -// Tests that FIP yields no results for an empty search query. -- (void)helperTestFindInPageEmptySearchQuery { - if (@available(iOS 16.1.1, *)) { - [self setUpTestServersForWebPageTest]; - - // Load test page with cross-origin iframe. - GURL destinationURL = - [self secondTestServer]->GetURL(kFindInPageCrossOriginFrameTestURL); - [ChromeEarlGrey loadURL:destinationURL]; - - // Open FIP. - [self.delegate openFindInPageWithOverflowMenu]; - - // Assert that searching text from the page yields results. - [self.delegate replaceFindInPageText:@(kFindInPageTestShortText)]; - [self.delegate assertResultStringIsNonZero]; - - // Test that the number of results is zero after clearing the FIP text - // field. - [self.delegate clearFindInPageText]; - [self.delegate assertResultStringIsEmptyOrZero]; - [self.delegate closeFindInPageWithDoneButton]; - } -} - -// Tests that FIP yields no results for a non-empty query with no matches in the -// page. -- (void)helperTestFindInPageQueryWithNoMatches { - if (@available(iOS 16.1.1, *)) { - [self setUpTestServersForWebPageTest]; - - // Load test page with cross-origin iframe. - GURL destinationURL = - [self secondTestServer]->GetURL(kFindInPageCrossOriginFrameTestURL); - [ChromeEarlGrey loadURL:destinationURL]; - - // Open FIP and type text that is not in the page. - const char* queryWithNoMatches = - "example query which should not match with the content of the page"; - [ChromeEarlGrey waitForWebStateNotContainingText:queryWithNoMatches]; - [self.delegate openFindInPageWithOverflowMenu]; - [self.delegate replaceFindInPageText:@(queryWithNoMatches)]; - // Test the result label shows no results. - [self.delegate assertResultStringIsEmptyOrZero]; - [self.delegate closeFindInPageWithDoneButton]; - } -} - -// Tests that FIP yields no matches for a text with spanish accents e.g. 'á' if -// the web page contains the same text without spanish accents e.g. 'a'. This -// test assumes removing accents from `kFindInPageTestWithSpanishAccentText` -// yields `kFindInPageTestWithoutSpanishAccentText`. -- (void)helperTestFindInPageDifferentAccent { - if (@available(iOS 16.1.1, *)) { - [self setUpTestServersForWebPageTest]; - - // Load test page with cross-origin iframe. - GURL destinationURL = - [self secondTestServer]->GetURL(kFindInPageCrossOriginFrameTestURL); - [ChromeEarlGrey loadURL:destinationURL]; - - // Assert the text without accent is there but the text with accents does - // not match. - [ChromeEarlGrey - waitForWebStateContainingText:kFindInPageTestWithoutSpanishAccentText]; - [ChromeEarlGrey - waitForWebStateNotContainingText:kFindInPageTestWithSpanishAccentText]; - - // Open FIP and assert that text with no accents yields matches. - [self.delegate openFindInPageWithOverflowMenu]; - [self.delegate - replaceFindInPageText:@(kFindInPageTestWithoutSpanishAccentText)]; - [self.delegate assertResultStringIsNonZero]; - - // Replace the text without spanish accent with the same text with spanish - // accents and test that there are no more matches. - [self.delegate - replaceFindInPageText:@(kFindInPageTestWithSpanishAccentText)]; - [self.delegate assertResultStringIsEmptyOrZero]; - [self.delegate closeFindInPageWithDoneButton]; - } -} - -// Test query persistence in the same tab and in a new normal tab. -- (void)helperTestFindInPageHistoryWithQueryPersistence:(BOOL)queryPersistence { - if (@available(iOS 16.1.1, *)) { - [self setUpTestServersForWebPageTest]; - - // Load test page with cross-origin iframe. - GURL destinationURL = - [self secondTestServer]->GetURL(kFindInPageCrossOriginFrameTestURL); - [ChromeEarlGrey loadURL:destinationURL]; - - // Open FIP and test the input field is empty. - [self.delegate openFindInPageWithOverflowMenu]; - [[EarlGrey selectElementWithMatcher:[self.delegate findInPageInputField]] - assertWithMatcher:[self matcherForText:@""]]; - - // Type a query and assert it is contained in the input field before closing - // FIP. - [self.delegate replaceFindInPageText:@(kFindInPageTestShortText)]; - [[EarlGrey selectElementWithMatcher:[self.delegate findInPageInputField]] - assertWithMatcher:[self matcherForText:@(kFindInPageTestShortText)]]; - [self.delegate closeFindInPageWithDoneButton]; - - // Open FIP again and test depending on query persistence. - [self.delegate openFindInPageWithOverflowMenu]; - [[EarlGrey selectElementWithMatcher:[self.delegate findInPageInputField]] - assertWithMatcher:[self matcherForText:queryPersistence - ? @(kFindInPageTestShortText) - : @""]]; - [self.delegate closeFindInPageWithDoneButton]; - - // Open the same URL in a different non-Incognito tab. - [ChromeEarlGrey openNewTab]; - [ChromeEarlGrey loadURL:destinationURL]; - - // Open FIP in this new tab and test depending on query persistence. - [self.delegate openFindInPageWithOverflowMenu]; - [[EarlGrey selectElementWithMatcher:[self.delegate findInPageInputField]] - assertWithMatcher:[self matcherForText:queryPersistence - ? @(kFindInPageTestShortText) - : @""]]; - [self.delegate closeFindInPageWithDoneButton]; - } -} - -// Tests that there is no query persistence from an non-Incognito to an -// Incognito tab. -- (void)helperTestFindInPageNormalToIncognito { - if (@available(iOS 16.1.1, *)) { - [self setUpTestServersForWebPageTest]; - - // Load test page with cross-origin iframe. - GURL destinationURL = - [self secondTestServer]->GetURL(kFindInPageCrossOriginFrameTestURL); - [ChromeEarlGrey loadURL:destinationURL]; - - // Open FIP and type short query. - [self.delegate openFindInPageWithOverflowMenu]; - [self.delegate replaceFindInPageText:@(kFindInPageTestShortText)]; - [self.delegate closeFindInPageWithDoneButton]; - - // Load same URL in a new Incognito tab. - [ChromeEarlGrey openNewIncognitoTab]; - [ChromeEarlGrey loadURL:destinationURL]; - - // Open FIP and test the input field is empty. - [self.delegate openFindInPageWithOverflowMenu]; - [[EarlGrey selectElementWithMatcher:[self.delegate findInPageInputField]] - assertWithMatcher:[self matcherForText:@""]]; - [self.delegate closeFindInPageWithDoneButton]; - } -} - -// Tests that switching orientation during a Find session does not throw away -// the query or the current results. -- (void)helperTestFindInPageSwitchOrientation { - if (@available(iOS 16.1.1, *)) { - [self setUpTestServersForWebPageTest]; - - // Load test page with cross-origin iframe. - GURL destinationURL = - [self secondTestServer]->GetURL(kFindInPageCrossOriginFrameTestURL); - [ChromeEarlGrey loadURL:destinationURL]; - - // Open FIP, type short query, move to second match and wait for expected - // results. - [self.delegate openFindInPageWithOverflowMenu]; - [self.delegate replaceFindInPageText:@(kFindInPageTestShortText)]; - [self.delegate advanceToNextResult]; - [self.delegate assertResultStringIsResult:2 outOfTotal:2]; - - // Switch to landscape. - GREYAssert( - [EarlGrey rotateDeviceToOrientation:UIDeviceOrientationLandscapeLeft - error:nil], - @"Could not rotate device to Landscape Left"); - - // Test the query is still there will the same result. - [[EarlGrey selectElementWithMatcher:[self.delegate findInPageInputField]] - assertWithMatcher:[self matcherForText:@(kFindInPageTestShortText)]]; - [self.delegate assertResultStringIsResult:2 outOfTotal:2]; - - // Switch back to portrait. - GREYAssert([EarlGrey rotateDeviceToOrientation:UIDeviceOrientationPortrait - error:nil], - @"Could not rotate device to Portrait"); - - // Test the query is still there will the same result. - [[EarlGrey selectElementWithMatcher:[self.delegate findInPageInputField]] - assertWithMatcher:[self matcherForText:@(kFindInPageTestShortText)]]; - [self.delegate assertResultStringIsResult:2 outOfTotal:2]; - [self.delegate closeFindInPageWithDoneButton]; - } -} - -// Tests that Next/Previous buttons work and wrap. -- (void)helperTestFindInPageNextPreviousArrows { - if (@available(iOS 16.1.1, *)) { - [self setUpTestServersForWebPageTest]; - - // Load test page with cross-origin iframe. - GURL destinationURL = - [self secondTestServer]->GetURL(kFindInPageCrossOriginFrameTestURL); - [ChromeEarlGrey loadURL:destinationURL]; - - // Open FIP and type query with four expected matches. - [self.delegate openFindInPageWithOverflowMenu]; - [self.delegate replaceFindInPageText:@(kFindInPageTestRepeatingText)]; - [self.delegate assertResultStringIsResult:1 outOfTotal:4]; - - // Test that tapping "Next" button works and wraps. - [self.delegate advanceToNextResult]; - [self.delegate assertResultStringIsResult:2 outOfTotal:4]; - [self.delegate advanceToNextResult]; - [self.delegate assertResultStringIsResult:3 outOfTotal:4]; - [self.delegate advanceToNextResult]; - [self.delegate assertResultStringIsResult:4 outOfTotal:4]; - [self.delegate advanceToNextResult]; - [self.delegate assertResultStringIsResult:1 outOfTotal:4]; - - // Test that tapping "Previous" button also works and wraps. - [self.delegate advanceToPreviousResult]; - [self.delegate assertResultStringIsResult:4 outOfTotal:4]; - [self.delegate advanceToPreviousResult]; - [self.delegate assertResultStringIsResult:3 outOfTotal:4]; - [self.delegate closeFindInPageWithDoneButton]; - } -} - -// Tests the various ways to dismiss the keyboard during a Find session. -- (void)helperTestFindInPageDismissKeyboard { - if (@available(iOS 16.1.1, *)) { - [self setUpTestServersForWebPageTest]; - - // Load test page with cross-origin iframe. - GURL destinationURL = - [self secondTestServer]->GetURL(kFindInPageCrossOriginFrameTestURL); - [ChromeEarlGrey loadURL:destinationURL]; - - // Open FIP and type short query. - [self.delegate openFindInPageWithOverflowMenu]; - [self.delegate replaceFindInPageText:@(kFindInPageTestShortText)]; - - // Tap Done button and test the keyboard is dismissed as a result. - [self.delegate closeFindInPageWithDoneButton]; - [ChromeEarlGrey waitForKeyboardToDisappear]; - - // Open FIP and type short query again. - [self.delegate openFindInPageWithOverflowMenu]; - [self.delegate replaceFindInPageText:@(kFindInPageTestShortText)]; - - // Tap an element on the page and test the keyboard is dismissed as a - // result. - [[EarlGrey selectElementWithMatcher:chrome_test_util::WebViewMatcher()] - performAction:chrome_test_util::TapWebElementWithId( - kFindInPageTestShortTextID)]; - [ChromeEarlGrey waitForKeyboardToDisappear]; - } -} - -// Tests that FIP can find long strings of characters. -- (void)helperTestFindInPageLongString { - if (@available(iOS 16.1.1, *)) { - [self setUpTestServersForWebPageTest]; - - // Load test page with cross-origin iframe. - GURL destinationURL = - [self secondTestServer]->GetURL(kFindInPageCrossOriginFrameTestURL); - [ChromeEarlGrey loadURL:destinationURL]; - - // Open FIP and type short query. - [self.delegate openFindInPageWithOverflowMenu]; - [self.delegate replaceFindInPageText:@(kFindInPageTestLongText)]; - - // Test the number of results is as expected. - [self.delegate assertResultStringIsResult:1 outOfTotal:2]; - [self.delegate closeFindInPageWithDoneButton]; - } -} - -// Tests that FIP is not case sensitive. -- (void)helperTestFindInPageNotCaseSensitive { - if (@available(iOS 16.1.1, *)) { - [self setUpTestServersForWebPageTest]; - - // Load test page with cross-origin iframe. - GURL destinationURL = - [self secondTestServer]->GetURL(kFindInPageCrossOriginFrameTestURL); - [ChromeEarlGrey loadURL:destinationURL]; - - // Assert the page contains string that is both lowercase and uppercase. - [ChromeEarlGrey - waitForWebStateContainingText:kFindInPageTestLowercaseAndUppercaseText]; - - // Open FIP and type lowercase version of contained text. - [self.delegate openFindInPageWithOverflowMenu]; - [self.delegate - replaceFindInPageText:[@(kFindInPageTestLowercaseAndUppercaseText) - lowercaseString]]; - // Test the number of results is as expected. - [self.delegate assertResultStringIsResult:1 outOfTotal:2]; - - // Clear input field and type uppercase version of contained text. - [self.delegate - replaceFindInPageText:[@(kFindInPageTestLowercaseAndUppercaseText) - uppercaseString]]; - // Test the number of results is as expected. - [self.delegate assertResultStringIsResult:1 outOfTotal:2]; - [self.delegate closeFindInPageWithDoneButton]; - } -} - -// Tests that there is no leak of the FIP search query from Incognito tabs to -// normal tabs. -- (void)helperTestFindInPageIncognitoHistory { - if (@available(iOS 16.1.1, *)) { - [self setUpTestServersForWebPageTest]; - - // Load test page with cross-origin iframe in new Incognito tab. - [ChromeEarlGrey openNewIncognitoTab]; - GURL destinationURL = - [self secondTestServer]->GetURL(kFindInPageCrossOriginFrameTestURL); - [ChromeEarlGrey loadURL:destinationURL]; - - // Open FIP and type short query. - [self.delegate openFindInPageWithOverflowMenu]; - [self.delegate replaceFindInPageText:@(kFindInPageTestShortText)]; - [self.delegate closeFindInPageWithDoneButton]; - - // Open a new normal tab and load the same URL. - [ChromeEarlGrey openNewTab]; - [ChromeEarlGrey loadURL:destinationURL]; - - // Open FIP again and test the input field is empty. - [self.delegate openFindInPageWithOverflowMenu]; - [[EarlGrey selectElementWithMatcher:[self.delegate findInPageInputField]] - assertWithMatcher:[self matcherForText:@""]]; - [self.delegate closeFindInPageWithDoneButton]; - } -} - -// Tests query persistence when coming back to a normal tab after switching -// temporarily to another tab. -- (void)helperTestFindInPageSwitchingTabsWithQueryPersistence: - (BOOL)queryPersistence { - if (@available(iOS 16.1.1, *)) { - [self setUpTestServersForWebPageTest]; - - // Load test page with cross-origin iframe in a second normal tab. - [ChromeEarlGrey openNewTab]; - GURL destinationURL = - [self secondTestServer]->GetURL(kFindInPageCrossOriginFrameTestURL); - [ChromeEarlGrey loadURL:destinationURL]; - - // Open FIP and type short query. - [self.delegate openFindInPageWithOverflowMenu]; - [self.delegate replaceFindInPageText:@(kFindInPageTestShortText)]; - - // Switching to first tab and then back to second tab. - [ChromeEarlGrey selectTabAtIndex:0]; - [ChromeEarlGrey selectTabAtIndex:1]; - - // Test query persistence. - [[EarlGrey selectElementWithMatcher:[self.delegate findInPageInputField]] - assertWithMatcher:[self matcherForText:queryPersistence - ? @(kFindInPageTestShortText) - : @""]]; - [self.delegate closeFindInPageWithDoneButton]; - } -} - -// Tests that FIP can find RTL text in a web page. -- (void)helperTestFindInPageRTL { - if (@available(iOS 16.1.1, *)) { - [self setUpTestServersForWebPageTest]; - - // Load test page with cross-origin iframe. - GURL destinationURL = - [self secondTestServer]->GetURL(kFindInPageCrossOriginFrameTestURL); - [ChromeEarlGrey loadURL:destinationURL]; - - // Open FIP, type RTL text and test that the results are as expected. - [self.delegate openFindInPageWithOverflowMenu]; - [self.delegate pasteTextToFindInPage:@(kFindInPageTestRTLText)]; - [self.delegate assertResultStringIsResult:1 outOfTotal:2]; - [self.delegate closeFindInPageWithDoneButton]; - } -} - -// Tests that Find in Page can find matches in an Incognito tab. -- (void)helperTestFindInPageIncognito { - if (@available(iOS 16.1.1, *)) { - [self setUpTestServersForWebPageTest]; - - // Load test page with cross-origin iframe in a new Incognito tab. - [ChromeEarlGrey openNewIncognitoTab]; - GURL destinationURL = - [self secondTestServer]->GetURL(kFindInPageCrossOriginFrameTestURL); - [ChromeEarlGrey loadURL:destinationURL]; - - // Open FIP, type text contained in test page and test that the results are - // as expected. - [self.delegate openFindInPageWithOverflowMenu]; - [self.delegate replaceFindInPageText:@(kFindInPageTestShortText)]; - [self.delegate assertResultStringIsResult:1 outOfTotal:2]; - [self.delegate closeFindInPageWithDoneButton]; - } -} - -// Tests accessibility of the Find in Page screen. -- (void)helperTestFindInPageAccessibility { - if (@available(iOS 16.1.1, *)) { - [self setUpTestServersForWebPageTest]; - - // Load test page with cross-origin iframe. - GURL destinationURL = - [self secondTestServer]->GetURL(kFindInPageCrossOriginFrameTestURL); - [ChromeEarlGrey loadURL:destinationURL]; - - // Open FIP, type query and check the expected number of results. - [self.delegate openFindInPageWithOverflowMenu]; - [self.delegate replaceFindInPageText:@(kFindInPageTestShortText)]; - [self.delegate assertResultStringIsResult:1 outOfTotal:2]; - - // Test accessibility. - [ChromeEarlGrey verifyAccessibilityForCurrentScreen]; - [self.delegate closeFindInPageWithDoneButton]; - } -} - -// Tests that Native Find in Page works as expected for PDF documents. -- (void)helperTestFindInPagePDF { - if (@available(iOS 16.1.1, *)) { - [self setUpTestServerForPDFTest]; - - // Load test PDF document. - GURL destinationURL = self.testServer->GetURL(kFindInPageComplexPDFTestURL); - [ChromeEarlGrey loadURL:destinationURL]; - - // Open FIP and test that the input field is empty and there are no results. - [self.delegate openFindInPageWithOverflowMenu]; - [[EarlGrey selectElementWithMatcher:[self.delegate findInPageInputField]] - assertWithMatcher:[self matcherForText:@""]]; - [self.delegate assertResultStringIsEmptyOrZero]; - - // Type text with 18 expected matches and test that results are as - // expected. - [self.delegate replaceFindInPageText:@"the F"]; - [self.delegate assertResultStringIsResult:1 outOfTotal:18]; - - // Test that the Next button works. - [self.delegate advanceToNextResult]; - [self.delegate assertResultStringIsResult:2 outOfTotal:18]; - [self.delegate advanceToNextResult]; - [self.delegate assertResultStringIsResult:3 outOfTotal:18]; - - // Type more specific query and test that results are as expected. - [self.delegate replaceFindInPageText:@"the Form"]; - [self.delegate assertResultStringIsResult:1 outOfTotal:6]; - - // Test that the Previous button works and wraps. - [self.delegate advanceToPreviousResult]; - [self.delegate assertResultStringIsResult:6 outOfTotal:6]; - [self.delegate advanceToPreviousResult]; - [self.delegate assertResultStringIsResult:5 outOfTotal:6]; - - // Type even more specific query and test that results are as expected. - [self.delegate replaceFindInPageText:@"the Form 1050"]; - [self.delegate assertResultStringIsEmptyOrZero]; - - // Test that the Done button does close Find in Page. - [self.delegate closeFindInPageWithDoneButton]; - [[EarlGrey selectElementWithMatcher:[self.delegate findInPageInputField]] - assertWithMatcher:grey_notVisible()]; - } -} - -// Tests that FIP exit fullscreen when done. -- (void)helperTestFindInPageExitFullscreen { - if (@available(iOS 16.1.1, *)) { - [self setUpTestServersForWebPageTest]; - - // Load test page. - GURL destinationURL = self.testServer->GetURL(kFindInPageComplexPDFTestURL); - [ChromeEarlGrey loadURL:destinationURL]; - - // Ensure the toolbars are not in fullscreen mode by checking if share - // button is visible. - [[EarlGrey selectElementWithMatcher:chrome_test_util::TabShareButton()] - assertWithMatcher:grey_sufficientlyVisible()]; - - // Open FIP with Overflow menu and check it is visible and the share button - // is not visible. - [self.delegate openFindInPageWithOverflowMenu]; - [ChromeEarlGrey waitForSufficientlyVisibleElementWithMatcher: - [self.delegate findInPageInputField]]; - - [ChromeEarlGrey waitForUIElementToDisappearWithMatcher: - chrome_test_util::TabShareButton()]; - - // Close find in page with Done button and ensure the share button is - // visible again. - [self.delegate closeFindInPageWithDoneButton]; - [[EarlGrey selectElementWithMatcher:[self.delegate findInPageInputField]] - assertWithMatcher:grey_notVisible()]; - [[EarlGrey selectElementWithMatcher:chrome_test_util::TabShareButton()] - assertWithMatcher:grey_sufficientlyVisible()]; - } -} - -// Tests that FIP works properly with bottom omnibox. -- (void)helperTestFindInPageWithBottomOmnibox { - if (@available(iOS 16.1.1, *)) { - // Set bottom Omnibox. - [ChromeEarlGrey setBoolValue:YES - forLocalStatePref:omnibox::kIsOmniboxInBottomPosition]; - - // Load test page. - [self setUpTestServersForWebPageTest]; - GURL destinationURL = self.testServer->GetURL(kFindInPageTestURL); - [ChromeEarlGrey loadURL:destinationURL]; - - [ChromeEarlGreyUI waitForToolbarVisible:YES]; - - // Open FIP with Overflow menu and check it is visible and the share button - // is not visible. - [self.delegate openFindInPageWithOverflowMenu]; - [ChromeEarlGrey waitForSufficientlyVisibleElementWithMatcher: - [self.delegate findInPageInputField]]; - - // Hide keyboard. - [ChromeEarlGrey simulatePhysicalKeyboardEvent:@"\n" flags:0]; - - // Scroll up and down the page. - [[EarlGrey selectElementWithMatcher:WebStateScrollViewMatcher()] - performAction:grey_scrollInDirection(kGREYDirectionDown, 150)]; - [[EarlGrey selectElementWithMatcher:WebStateScrollViewMatcher()] - performAction:grey_scrollInDirection(kGREYDirectionUp, 150)]; - - // Ensure that the bottom Omnibox is not visible. - [[EarlGrey selectElementWithMatcher:chrome_test_util::OmniboxAtBottom()] - assertWithMatcher:grey_notVisible()]; - } -} - -@end
diff --git a/ios/chrome/browser/first_run/ui_bundled/interactive_lens/ui/lens_interactive_promo_results_page_presenter.mm b/ios/chrome/browser/first_run/ui_bundled/interactive_lens/ui/lens_interactive_promo_results_page_presenter.mm index ea1cfb1..896fdcd 100644 --- a/ios/chrome/browser/first_run/ui_bundled/interactive_lens/ui/lens_interactive_promo_results_page_presenter.mm +++ b/ios/chrome/browser/first_run/ui_bundled/interactive_lens/ui/lens_interactive_promo_results_page_presenter.mm
@@ -164,7 +164,7 @@ completion:dismissalCompletion]; } -#pragma mark - LensOverlayBottomSheetPresentationDelegate +#pragma mark - LensOverlayBottomSheetPresentationCommands - (void)requestMaximizeBottomSheet { // No-op. Sheet size is constant in this presentation. @@ -174,11 +174,11 @@ // No-op. Sheet size is constant in this presentation. } -- (void)didLoadSelectionResult { +- (void)adjustForSelectionResult { [self adjustSelectionOcclusionInsets]; } -- (void)didLoadTranslateResult { +- (void)adjustForTranslateResult { // No-op. }
diff --git a/ios/chrome/browser/flags/about_flags.mm b/ios/chrome/browser/flags/about_flags.mm index c341816b0..d8996ab 100644 --- a/ios/chrome/browser/flags/about_flags.mm +++ b/ios/chrome/browser/flags/about_flags.mm
@@ -2574,6 +2574,10 @@ flag_descriptions::kLensOverlayNavigationHistoryName, flag_descriptions::kLensOverlayNavigationHistoryDescription, flags_ui::kOsIos, FEATURE_VALUE_TYPE(kLensOverlayNavigationHistory)}, + {"lens-overlay-custom-bottom-sheet", + flag_descriptions::kLensOverlayCustomBottomSheetName, + flag_descriptions::kLensOverlayCustomBottomSheetDescription, + flags_ui::kOsIos, FEATURE_VALUE_TYPE(kLensOverlayCustomBottomSheet)}, {"page-action-menu", flag_descriptions::kPageActionMenuName, flag_descriptions::kPageActionMenuDescription, flags_ui::kOsIos, FEATURE_WITH_PARAMS_VALUE_TYPE(kPageActionMenu,
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc index 0eaf02c8..055e9707 100644 --- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc +++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
@@ -961,6 +961,12 @@ const char kLensLoadAIMInLensResultPageDescription[] = "Opens in Lens result page rather than a new tab."; +extern const char kLensOverlayCustomBottomSheetName[] = + "Use a custom bottom sheet presentation for Lens Overlay"; +extern const char kLensOverlayCustomBottomSheetDescription[] = + "When enabled the system bottom sheet for the Lens result page is " + "replaced by a custom bottom sheet presentation"; + extern const char kLensOverlayDisableIPHPanGestureName[] = "Disable Lens Overlay IPH Pan Dismissal"; extern const char kLensOverlayDisableIPHPanGestureDescription[] =
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h index 7bf17506..97e6231 100644 --- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h +++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
@@ -559,6 +559,9 @@ extern const char kLensLoadAIMInLensResultPageName[]; extern const char kLensLoadAIMInLensResultPageDescription[]; +extern const char kLensOverlayCustomBottomSheetName[]; +extern const char kLensOverlayCustomBottomSheetDescription[]; + extern const char kLensOverlayForceShowOnboardingScreenName[]; extern const char kLensOverlayForceShowOnboardingScreenDescription[];
diff --git a/ios/chrome/browser/history/ui_bundled/base_history_view_controller.mm b/ios/chrome/browser/history/ui_bundled/base_history_view_controller.mm index 3d09b919..ef54bad24 100644 --- a/ios/chrome/browser/history/ui_bundled/base_history_view_controller.mm +++ b/ios/chrome/browser/history/ui_bundled/base_history_view_controller.mm
@@ -699,10 +699,7 @@ return; // UI has been updated in the meaning time. } - // TODO(crbug.com/371568658): Remove NotFatalUntil when we're sure this - // check doesn't fail. - CHECK_EQ(_indicatorState, IndicatorState::FETCHING_RESULTS, - base::NotFatalUntil::M139); + CHECK_EQ(_indicatorState, IndicatorState::FETCHING_RESULTS); _indicatorState = IndicatorState::SHOWING_LOADING_INDICATOR; [self startLoadingIndicatorWithLoadingMessage:l10n_util::GetNSString( IDS_HISTORY_NO_RESULTS)]; @@ -719,10 +716,7 @@ // removes the loading indicator and updates the UI with the results. If the // query hasn't returned, then no-op. - (void)maybeRemoveLoadingIndicator { - // TODO(crbug.com/371568658): Remove NotFatalUntil when we're sure this - // check doesn't fail. - CHECK_EQ(_indicatorState, IndicatorState::SHOWING_LOADING_INDICATOR, - base::NotFatalUntil::M139); + CHECK_EQ(_indicatorState, IndicatorState::SHOWING_LOADING_INDICATOR); _indicatorState = IndicatorState::WAITING_FOR_RESULTS; // If results have returned, then the UI is updated right away. @@ -744,11 +738,8 @@ return; } - // TODO(crbug.com/371568658): Remove NotFatalUntil when we're sure this - // check doesn't fail. CHECK(_indicatorState == IndicatorState::WAITING_FOR_RESULTS || - _indicatorState == IndicatorState::FETCHING_RESULTS, - base::NotFatalUntil::M139); + _indicatorState == IndicatorState::FETCHING_RESULTS); _indicatorState = IndicatorState::IDLE; // Cancel all pending callbacks related to loading indicator.
diff --git a/ios/chrome/browser/lens_overlay/coordinator/lens_overlay_coordinator.mm b/ios/chrome/browser/lens_overlay/coordinator/lens_overlay_coordinator.mm index 8701739d..d034d7c 100644 --- a/ios/chrome/browser/lens_overlay/coordinator/lens_overlay_coordinator.mm +++ b/ios/chrome/browser/lens_overlay/coordinator/lens_overlay_coordinator.mm
@@ -1574,8 +1574,8 @@ } _resultsPagePresenter.delegate = self; - _resultMediator.presentationDelegate = _resultsPagePresenter; - _mediator.presentationDelegate = _resultsPagePresenter; + _resultMediator.bottomSheetCommands = _resultsPagePresenter; + _mediator.bottomSheetCommands = _resultsPagePresenter; } // Presents the result botom sheet.
diff --git a/ios/chrome/browser/lens_overlay/coordinator/lens_overlay_mediator.h b/ios/chrome/browser/lens_overlay/coordinator/lens_overlay_mediator.h index e339974..3344bb11 100644 --- a/ios/chrome/browser/lens_overlay/coordinator/lens_overlay_mediator.h +++ b/ios/chrome/browser/lens_overlay/coordinator/lens_overlay_mediator.h
@@ -9,7 +9,7 @@ #import "ios/chrome/browser/lens_overlay/coordinator/lens_omnibox_client_delegate.h" #import "ios/chrome/browser/lens_overlay/coordinator/lens_result_page_mediator_delegate.h" -#import "ios/chrome/browser/lens_overlay/ui/lens_overlay_bottom_sheet_presentation_delegate.h" +#import "ios/chrome/browser/lens_overlay/ui/lens_overlay_bottom_sheet_presentation_commands.h" #import "ios/chrome/browser/lens_overlay/ui/lens_overlay_result_consumer.h" #import "ios/chrome/browser/lens_overlay/ui/lens_toolbar_mutator.h" #import "ios/chrome/browser/omnibox/ui/omnibox_focus_delegate.h" @@ -55,9 +55,9 @@ /// Lens backend handler. @property(nonatomic, weak) id<ChromeLensOverlay> lensHandler; -/// Presentation delegate for requesting bottom sheet resizing. -@property(nonatomic, weak) id<LensOverlayBottomSheetPresentationDelegate> - presentationDelegate; +/// Presentation commands for requesting bottom sheet resizing. +@property(nonatomic, weak) id<LensOverlayBottomSheetPresentationCommands> + bottomSheetCommands; /// Utility for recoding Lens Overlay metrics. @property(nonatomic, weak) LensOverlayMetricsRecorder* metricsRecorder;
diff --git a/ios/chrome/browser/lens_overlay/coordinator/lens_overlay_mediator.mm b/ios/chrome/browser/lens_overlay/coordinator/lens_overlay_mediator.mm index c850286..b202cc3f 100644 --- a/ios/chrome/browser/lens_overlay/coordinator/lens_overlay_mediator.mm +++ b/ios/chrome/browser/lens_overlay/coordinator/lens_overlay_mediator.mm
@@ -197,7 +197,7 @@ [self.omniboxCoordinator focusOmnibox]; [self.toolbarConsumer setOmniboxFocused:YES]; [self.omniboxCoordinator.animatee setClearButtonFaded:NO]; - [self.presentationDelegate requestMaximizeBottomSheet]; + [self.bottomSheetCommands requestMaximizeBottomSheet]; } - (void)defocusOmnibox { @@ -257,13 +257,13 @@ // bottom sheet hidden, as no auto selection happens at this stage. [self.lensHandler resetSelectionAreaToInitialPosition:^{ }]; - [self.presentationDelegate + [self.bottomSheetCommands showInfoMessage:LensOverlayBottomSheetInfoMessageType:: kImageTranslatedIndication]; } else if (noSelectionInTranslate) { // A missing selection without a switch in modes indicates the user // intended to dismiss the current selection. - [self.presentationDelegate + [self.bottomSheetCommands showInfoMessage:LensOverlayBottomSheetInfoMessageType:: kImageTranslatedIndication]; } @@ -282,8 +282,8 @@ }; [self.toolbarConsumer setOmniboxEnabled:YES]; // Make sure the bottom sheet is dismissed before triggering any alert. - if (self.presentationDelegate) { - [self.presentationDelegate hideBottomSheetWithCompletion:completion]; + if (self.bottomSheetCommands) { + [self.bottomSheetCommands hideBottomSheetWithCompletion:completion]; } else { completion(); } @@ -482,9 +482,9 @@ [self updateOmniboxText:result.queryText]; if (result.isGeneratedInTranslate) { - [self.presentationDelegate didLoadTranslateResult]; + [self.bottomSheetCommands adjustForTranslateResult]; } else { - [self.presentationDelegate didLoadSelectionResult]; + [self.bottomSheetCommands adjustForSelectionResult]; } }
diff --git a/ios/chrome/browser/lens_overlay/coordinator/lens_result_page_mediator.h b/ios/chrome/browser/lens_overlay/coordinator/lens_result_page_mediator.h index efea814d..3a2d389 100644 --- a/ios/chrome/browser/lens_overlay/coordinator/lens_result_page_mediator.h +++ b/ios/chrome/browser/lens_overlay/coordinator/lens_result_page_mediator.h
@@ -9,7 +9,7 @@ #import "ios/chrome/browser/context_menu/ui_bundled/context_menu_configuration_provider_delegate.h" #import "ios/chrome/browser/lens_overlay/coordinator/lens_web_provider.h" -#import "ios/chrome/browser/lens_overlay/ui/lens_overlay_bottom_sheet_presentation_delegate.h" +#import "ios/chrome/browser/lens_overlay/ui/lens_overlay_bottom_sheet_presentation_commands.h" #import "ios/chrome/browser/lens_overlay/ui/lens_overlay_result_consumer.h" #import "ios/chrome/browser/lens_overlay/ui/lens_result_page_mutator.h" #import "ios/web/public/web_state.h" @@ -49,8 +49,8 @@ @property(nonatomic, weak) id<LensOverlayTabChangeAudience> tabChangeAudience; /// Presentation delegate for requesting bottom sheet resizing. -@property(nonatomic, weak) id<LensOverlayBottomSheetPresentationDelegate> - presentationDelegate; +@property(nonatomic, weak) id<LensOverlayBottomSheetPresentationCommands> + bottomSheetCommands; /// WebState context menu configuration provider. @property(nonatomic, weak)
diff --git a/ios/chrome/browser/lens_overlay/coordinator/lens_result_page_mediator.mm b/ios/chrome/browser/lens_overlay/coordinator/lens_result_page_mediator.mm index 62fbc20..f5793e8e 100644 --- a/ios/chrome/browser/lens_overlay/coordinator/lens_result_page_mediator.mm +++ b/ios/chrome/browser/lens_overlay/coordinator/lens_result_page_mediator.mm
@@ -331,7 +331,7 @@ } if (IsMaximizeBottomSheetURL(URL)) { - [self.presentationDelegate requestMaximizeBottomSheet]; + [self.bottomSheetCommands requestMaximizeBottomSheet]; return; }
diff --git a/ios/chrome/browser/lens_overlay/ui/BUILD.gn b/ios/chrome/browser/lens_overlay/ui/BUILD.gn index a45188b..c30547f 100644 --- a/ios/chrome/browser/lens_overlay/ui/BUILD.gn +++ b/ios/chrome/browser/lens_overlay/ui/BUILD.gn
@@ -18,7 +18,7 @@ source_set("protocols") { sources = [ - "lens_overlay_bottom_sheet_presentation_delegate.h", + "lens_overlay_bottom_sheet_presentation_commands.h", "lens_overlay_error_handler.h", "lens_overlay_result_consumer.h", "lens_overlay_results_page_presenting.h",
diff --git a/ios/chrome/browser/lens_overlay/ui/lens_overlay_bottom_sheet_presentation_delegate.h b/ios/chrome/browser/lens_overlay/ui/lens_overlay_bottom_sheet_presentation_commands.h similarity index 81% rename from ios/chrome/browser/lens_overlay/ui/lens_overlay_bottom_sheet_presentation_delegate.h rename to ios/chrome/browser/lens_overlay/ui/lens_overlay_bottom_sheet_presentation_commands.h index 7b8018ca..375455b25 100644 --- a/ios/chrome/browser/lens_overlay/ui/lens_overlay_bottom_sheet_presentation_delegate.h +++ b/ios/chrome/browser/lens_overlay/ui/lens_overlay_bottom_sheet_presentation_commands.h
@@ -1,9 +1,9 @@ -// Copyright 2024 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. -#ifndef IOS_CHROME_BROWSER_LENS_OVERLAY_UI_LENS_OVERLAY_BOTTOM_SHEET_PRESENTATION_DELEGATE_H_ -#define IOS_CHROME_BROWSER_LENS_OVERLAY_UI_LENS_OVERLAY_BOTTOM_SHEET_PRESENTATION_DELEGATE_H_ +#ifndef IOS_CHROME_BROWSER_LENS_OVERLAY_UI_LENS_OVERLAY_BOTTOM_SHEET_PRESENTATION_COMMANDS_H_ +#define IOS_CHROME_BROWSER_LENS_OVERLAY_UI_LENS_OVERLAY_BOTTOM_SHEET_PRESENTATION_COMMANDS_H_ #import <Foundation/Foundation.h> @@ -15,10 +15,10 @@ kImageTranslatedIndication, }; -// Presentation delegate for the bottom sheet. +// Presentation commands for the bottom sheet. // Bottom sheet content may request the container to be maximized or minimized, // e.g. when the user selects a result that opens an image viewer. -@protocol LensOverlayBottomSheetPresentationDelegate <NSObject> +@protocol LensOverlayBottomSheetPresentationCommands <NSObject> // Request resizing the bottom sheet to maximum size. - (void)requestMaximizeBottomSheet; @@ -27,10 +27,10 @@ - (void)requestMinimizeBottomSheet; // Handle a selection result loaded in the bottom sheet. -- (void)didLoadSelectionResult; +- (void)adjustForSelectionResult; // Handle a translation result loaded in the bottom sheet. -- (void)didLoadTranslateResult; +- (void)adjustForTranslateResult; // Hides the bottom sheet without destroying the presentation. - (void)hideBottomSheetWithCompletion:(void (^)(void))completion; @@ -40,4 +40,4 @@ @end -#endif // IOS_CHROME_BROWSER_LENS_OVERLAY_UI_LENS_OVERLAY_BOTTOM_SHEET_PRESENTATION_DELEGATE_H_ +#endif // IOS_CHROME_BROWSER_LENS_OVERLAY_UI_LENS_OVERLAY_BOTTOM_SHEET_PRESENTATION_COMMANDS_H_
diff --git a/ios/chrome/browser/lens_overlay/ui/lens_overlay_results_page_presenter.mm b/ios/chrome/browser/lens_overlay/ui/lens_overlay_results_page_presenter.mm index 4556061..ade60b5 100644 --- a/ios/chrome/browser/lens_overlay/ui/lens_overlay_results_page_presenter.mm +++ b/ios/chrome/browser/lens_overlay/ui/lens_overlay_results_page_presenter.mm
@@ -578,7 +578,7 @@ } } -#pragma mark - LensOverlayBottomSheetPresentationDelegate +#pragma mark - LensOverlayBottomSheetPresentationCommands // Request resizing the bottom sheet to maximum size. - (void)requestMaximizeBottomSheet { @@ -590,14 +590,14 @@ [_detentsManager requestMinimizeBottomSheet]; } -- (void)didLoadSelectionResult { +- (void)adjustForSelectionResult { _detentsManager.presentationStrategy = SheetDetentPresentationStategySelection; [_presentationNavigationController popToRootViewControllerAnimated:YES]; [self adjustSelectionOcclusionInsets]; } -- (void)didLoadTranslateResult { +- (void)adjustForTranslateResult { _detentsManager.presentationStrategy = SheetDetentPresentationStategyTranslate; [_presentationNavigationController popToRootViewControllerAnimated:YES];
diff --git a/ios/chrome/browser/lens_overlay/ui/lens_overlay_results_page_presenting.h b/ios/chrome/browser/lens_overlay/ui/lens_overlay_results_page_presenting.h index e31f7c98..4a6089f 100644 --- a/ios/chrome/browser/lens_overlay/ui/lens_overlay_results_page_presenting.h +++ b/ios/chrome/browser/lens_overlay/ui/lens_overlay_results_page_presenting.h
@@ -8,13 +8,13 @@ #import <UIKit/UIKit.h> #import "ios/chrome/browser/lens_overlay/model/lens_overlay_sheet_detent_state.h" -#import "ios/chrome/browser/lens_overlay/ui/lens_overlay_bottom_sheet_presentation_delegate.h" +#import "ios/chrome/browser/lens_overlay/ui/lens_overlay_bottom_sheet_presentation_commands.h" @protocol LensOverlayResultsPagePresenterDelegate; // Protocol for presenting the Lens results bottom sheet. @protocol LensOverlayResultsPagePresenting < - LensOverlayBottomSheetPresentationDelegate> + LensOverlayBottomSheetPresentationCommands> // Whether the results page is currently presented. @property(nonatomic, assign, readonly) BOOL isResultPageVisible;
diff --git a/ios/chrome/browser/omnibox/ui/omnibox_text_field_ios.mm b/ios/chrome/browser/omnibox/ui/omnibox_text_field_ios.mm index e3c63dc..0a9f09e7 100644 --- a/ios/chrome/browser/omnibox/ui/omnibox_text_field_ios.mm +++ b/ios/chrome/browser/omnibox/ui/omnibox_text_field_ios.mm
@@ -1045,8 +1045,6 @@ autocompleteLength == 0); } if (updateText) { - self.attributedText = fieldText; - // TODO(crbug.com/330964534): Remove DUMP_WILL_BE_CHECK after investigating // crash. if (!self.endOfDocument || !self.beginningOfDocument) { @@ -1055,6 +1053,8 @@ << " text length: " << text.length << " has text position: " << (self.beginningOfDocument || self.endOfDocument); } else { + self.attributedText = fieldText; + UITextPosition* endOfUserText = [self positionFromPosition:self.beginningOfDocument offset:beginningOfAutocomplete];
diff --git a/ios/chrome/browser/passwords/model/password_controller.mm b/ios/chrome/browser/passwords/model/password_controller.mm index 502a858..b92bef6d5 100644 --- a/ios/chrome/browser/passwords/model/password_controller.mm +++ b/ios/chrome/browser/passwords/model/password_controller.mm
@@ -77,6 +77,7 @@ #import "ios/web/public/js_messaging/web_frame.h" #import "ios/web/public/navigation/navigation_context.h" #import "ios/web/public/web_state.h" +#import "ios/web/public/web_state_id.h" #import "services/network/public/cpp/shared_url_loader_factory.h" #import "ui/base/device_form_factor.h" #import "ui/base/l10n/l10n_util_mac.h" @@ -335,7 +336,7 @@ URLLoaderFactory:_webState->GetBrowserState() ->GetSharedURLLoaderFactory()]; if (![_delegate displaySignInNotification:self.notifyAutoSigninViewController - fromTabId:_webState->GetStableIdentifier()]) { + fromTabId:_webState->GetUniqueIdentifier()]) { // The notification was not shown. Store the password form in // `_pendingAutoSigninPasswordForm` to show the notification later. _pendingAutoSigninPasswordForm = std::move(formSignedIn);
diff --git a/ios/chrome/browser/passwords/model/password_controller_delegate.h b/ios/chrome/browser/passwords/model/password_controller_delegate.h index 60a52f4f..d8b8082 100644 --- a/ios/chrome/browser/passwords/model/password_controller_delegate.h +++ b/ios/chrome/browser/passwords/model/password_controller_delegate.h
@@ -9,6 +9,10 @@ struct CredentialUIEntry; } // namespace password_manager +namespace web { +class WebStateID; +} // namespace web + // Delegate for registering view controller and displaying its view. Used to // add views to BVC. // TODO(crbug.com/40806286): Refactor this API to not be coupled to the BVC and @@ -18,7 +22,7 @@ // Adds `viewController` as child controller in order to display auto sign-in // notification. Returns YES if view was displayed, NO otherwise. - (BOOL)displaySignInNotification:(UIViewController*)viewController - fromTabId:(NSString*)tabId; + fromTabId:(web::WebStateID)tabId; // Opens the list of saved passwords in the settings. - (void)displaySavedPasswordList;
diff --git a/ios/chrome/browser/reader_mode/model/constants.h b/ios/chrome/browser/reader_mode/model/constants.h index c6faab9..0ffa0de2 100644 --- a/ios/chrome/browser/reader_mode/model/constants.h +++ b/ios/chrome/browser/reader_mode/model/constants.h
@@ -105,6 +105,20 @@ }; // LINT.ThenChange(/tools/metrics/histograms/metadata/ios/enums.xml:ReaderModeAccessPoint) +// Recorded for IOS.ReaderMode.AccessPointWithMode. Entries should not be +// renumbered and numeric values should never be reused. +// LINT.IfChange(ReaderModeAccessPointWithMode) +enum class ReaderModeAccessPointWithMode { + kContextualChipInRegular = 0, + kContextualChipInIncognito = 1, + kToolsMenuInRegular = 2, + kToolsMenuInIncognito = 3, + kAIHubInRegular = 4, + kAIHubInIncognito = 5, + kMaxValue = kAIHubInIncognito, +}; +// LINT.ThenChange(/tools/metrics/histograms/metadata/ios/enums.xml:ReaderModeAccessPointWithMode) + // Recorded for IOS.ReaderMode.Distiller.Result. Entries should not be // renumbered and numeric values should never be reused. // LINT.IfChange(ReaderModeDistillerOutcome) @@ -174,6 +188,9 @@ // Histogram name for Reader Mode access point for starting distillation. extern const char kReaderModeAccessPointHistogram[]; +// Histogram name for Reader Mode access point with application mode. +extern const char kReaderModeAccessPointWithModeHistogram[]; + // Returns the Reader mode symbol name. NSString* GetReaderModeSymbolName();
diff --git a/ios/chrome/browser/reader_mode/model/constants.mm b/ios/chrome/browser/reader_mode/model/constants.mm index 7193ede..ce5af18 100644 --- a/ios/chrome/browser/reader_mode/model/constants.mm +++ b/ios/chrome/browser/reader_mode/model/constants.mm
@@ -34,6 +34,9 @@ const char kReaderModeAccessPointHistogram[] = "IOS.ReaderMode.AccessPoint"; +const char kReaderModeAccessPointWithModeHistogram[] = + "IOS.ReaderMode.AccessPointWithMode"; + NSString* GetReaderModeSymbolName() { if (@available(iOS 18, *)) { return kReaderModeSymbolPostIOS18;
diff --git a/ios/chrome/browser/reader_mode/model/reader_mode_metrics_helper.h b/ios/chrome/browser/reader_mode/model/reader_mode_metrics_helper.h index 6dceb8a..ab8a391 100644 --- a/ios/chrome/browser/reader_mode/model/reader_mode_metrics_helper.h +++ b/ios/chrome/browser/reader_mode/model/reader_mode_metrics_helper.h
@@ -39,7 +39,8 @@ bool ReaderModeIsRecentlyUsed(); // Records histograms for the Reading Mode distillation event. - void RecordReaderDistillerTriggered(ReaderModeAccessPoint access_point); + void RecordReaderDistillerTriggered(ReaderModeAccessPoint access_point, + bool is_incognito); void RecordReaderDistillerCompleted(ReaderModeAccessPoint access_point, ReaderModeDistillerResult result);
diff --git a/ios/chrome/browser/reader_mode/model/reader_mode_metrics_helper.mm b/ios/chrome/browser/reader_mode/model/reader_mode_metrics_helper.mm index 25845b02..ff3dd68 100644 --- a/ios/chrome/browser/reader_mode/model/reader_mode_metrics_helper.mm +++ b/ios/chrome/browser/reader_mode/model/reader_mode_metrics_helper.mm
@@ -81,6 +81,23 @@ } } +ReaderModeAccessPointWithMode GetAccessPointWithMode( + ReaderModeAccessPoint access_point, + bool is_incognito) { + switch (access_point) { + case ReaderModeAccessPoint::kAIHub: + return is_incognito ? ReaderModeAccessPointWithMode::kAIHubInIncognito + : ReaderModeAccessPointWithMode::kAIHubInRegular; + case ReaderModeAccessPoint::kToolsMenu: + return is_incognito ? ReaderModeAccessPointWithMode::kToolsMenuInIncognito + : ReaderModeAccessPointWithMode::kToolsMenuInRegular; + case ReaderModeAccessPoint::kContextualChip: + return is_incognito + ? ReaderModeAccessPointWithMode::kContextualChipInIncognito + : ReaderModeAccessPointWithMode::kContextualChipInRegular; + } +} + } // namespace ReaderModeMetricsHelper::ReaderModeMetricsHelper( @@ -136,10 +153,14 @@ } void ReaderModeMetricsHelper::RecordReaderDistillerTriggered( - ReaderModeAccessPoint access_point) { + ReaderModeAccessPoint access_point, + bool is_incognito) { distiller_timer_ = std::make_unique<base::ElapsedTimer>(); last_reader_mode_state_ = ReaderModeState::kDistillationStarted; base::UmaHistogramEnumeration(kReaderModeAccessPointHistogram, access_point); + base::UmaHistogramEnumeration( + kReaderModeAccessPointWithModeHistogram, + GetAccessPointWithMode(access_point, is_incognito)); } void ReaderModeMetricsHelper::RecordReaderDistillerTimedOut() {
diff --git a/ios/chrome/browser/reader_mode/model/reader_mode_metrics_helper_unittest.mm b/ios/chrome/browser/reader_mode/model/reader_mode_metrics_helper_unittest.mm index ae3b67e..627e2925 100644 --- a/ios/chrome/browser/reader_mode/model/reader_mode_metrics_helper_unittest.mm +++ b/ios/chrome/browser/reader_mode/model/reader_mode_metrics_helper_unittest.mm
@@ -200,7 +200,7 @@ // mode state. TEST_F(ReaderModeMetricsHelperTest, ReaderDistillerTriggered) { metrics_helper()->RecordReaderDistillerTriggered( - ReaderModeAccessPoint::kContextualChip); + ReaderModeAccessPoint::kContextualChip, /*is_incognito=*/false); metrics_helper()->Flush(); EXPECT_THAT(histogram_tester_.GetAllSamples(kReaderModeStateHistogram), @@ -213,7 +213,7 @@ // mode state. TEST_F(ReaderModeMetricsHelperTest, ReaderDistillerCompleted) { metrics_helper()->RecordReaderDistillerTriggered( - ReaderModeAccessPoint::kContextualChip); + ReaderModeAccessPoint::kContextualChip, /*is_incognito=*/false); task_environment_.AdvanceClock(base::Seconds(1)); metrics_helper()->RecordReaderDistillerCompleted( @@ -290,7 +290,7 @@ // Tests that canceling distillation records latency and reader mode state. TEST_F(ReaderModeMetricsHelperTest, DistillationCanceledOnTimeout) { metrics_helper()->RecordReaderDistillerTriggered( - ReaderModeAccessPoint::kAIHub); + ReaderModeAccessPoint::kAIHub, /*is_incognito=*/false); task_environment_.AdvanceClock(base::Seconds(1)); // Cancelation triggers a metrics flush. @@ -305,7 +305,7 @@ // Tests that Reader Mode access point is recorded when a value is set. TEST_F(ReaderModeMetricsHelperTest, ReaderModeAccessPointRecorded) { metrics_helper()->RecordReaderDistillerTriggered( - ReaderModeAccessPoint::kAIHub); + ReaderModeAccessPoint::kAIHub, /*is_incognito=*/false); metrics_helper()->Flush(); EXPECT_THAT(histogram_tester_.GetAllSamples(kReaderModeStateHistogram), @@ -314,6 +314,32 @@ BucketsAre(Bucket(ReaderModeAccessPoint::kAIHub, 1))); } +// Tests that Reader Mode access point with mode is recorded for regular mode. +TEST_F(ReaderModeMetricsHelperTest, ReaderModeAccessPointWithModeForRegular) { + metrics_helper()->RecordReaderDistillerTriggered( + ReaderModeAccessPoint::kAIHub, /*is_incognito=*/false); + metrics_helper()->Flush(); + + EXPECT_THAT(histogram_tester_.GetAllSamples(kReaderModeStateHistogram), + BucketsAre(Bucket(ReaderModeState::kDistillationStarted, 1))); + EXPECT_THAT( + histogram_tester_.GetAllSamples(kReaderModeAccessPointWithModeHistogram), + BucketsAre(Bucket(ReaderModeAccessPointWithMode::kAIHubInRegular, 1))); +} + +// Tests that Reader Mode access point with mode is recorded for incognito mode. +TEST_F(ReaderModeMetricsHelperTest, ReaderModeAccessPointWithModeForIncognito) { + metrics_helper()->RecordReaderDistillerTriggered( + ReaderModeAccessPoint::kAIHub, /*is_incognito=*/true); + metrics_helper()->Flush(); + + EXPECT_THAT(histogram_tester_.GetAllSamples(kReaderModeStateHistogram), + BucketsAre(Bucket(ReaderModeState::kDistillationStarted, 1))); + EXPECT_THAT( + histogram_tester_.GetAllSamples(kReaderModeAccessPointWithModeHistogram), + BucketsAre(Bucket(ReaderModeAccessPointWithMode::kAIHubInIncognito, 1))); +} + // Tests metrics functionality based on the heuristic result. class ReaderModeMetricsHelperWithEligibilityTest : public ReaderModeMetricsHelperTest,
diff --git a/ios/chrome/browser/reader_mode/model/reader_mode_tab_helper.mm b/ios/chrome/browser/reader_mode/model/reader_mode_tab_helper.mm index 94e9074..0e8cf5f 100644 --- a/ios/chrome/browser/reader_mode/model/reader_mode_tab_helper.mm +++ b/ios/chrome/browser/reader_mode/model/reader_mode_tab_helper.mm
@@ -505,7 +505,8 @@ void ReaderModeTabHelper::CreateReaderModeContent( ReaderModeAccessPoint access_point) { - metrics_helper_.RecordReaderDistillerTriggered(access_point); + bool is_incognito = web_state_->GetBrowserState()->IsOffTheRecord(); + metrics_helper_.RecordReaderDistillerTriggered(access_point, is_incognito); if (!reader_mode_web_state_) { web::WebState::CreateParams create_params = web::WebState::CreateParams(
diff --git a/ios/chrome/browser/reminder_notifications/model/BUILD.gn b/ios/chrome/browser/reminder_notifications/model/BUILD.gn index 5d6e723..eab1b6e9 100644 --- a/ios/chrome/browser/reminder_notifications/model/BUILD.gn +++ b/ios/chrome/browser/reminder_notifications/model/BUILD.gn
@@ -34,7 +34,7 @@ source_set("unit_tests") { testonly = true - sources = [ "reminder_notification_client_unittests.mm" ] + sources = [ "reminder_notification_client_unittest.mm" ] deps = [ ":client", "//base",
diff --git a/ios/chrome/browser/reminder_notifications/model/reminder_notification_client_unittests.mm b/ios/chrome/browser/reminder_notifications/model/reminder_notification_client_unittest.mm similarity index 100% rename from ios/chrome/browser/reminder_notifications/model/reminder_notification_client_unittests.mm rename to ios/chrome/browser/reminder_notifications/model/reminder_notification_client_unittest.mm
diff --git a/ios/chrome/browser/search_engines/model/search_engine_choice_service_factory.mm b/ios/chrome/browser/search_engines/model/search_engine_choice_service_factory.mm index 8afed98..563a012 100644 --- a/ios/chrome/browser/search_engines/model/search_engine_choice_service_factory.mm +++ b/ios/chrome/browser/search_engines/model/search_engine_choice_service_factory.mm
@@ -55,7 +55,7 @@ CHECK_DEREF(ios::TemplateURLPrepopulateDataResolverFactory::GetForProfile( profile)), CHECK_DEREF(IdentityManagerFactory::GetForProfile(profile)), - CHECK_DEREF(policy::ManagementServiceIOSFactory::GetForProfile(profile))); + CHECK_DEREF(policy::ManagementServiceIOSFactory::GetForPlatform())); service->Init(); return service;
diff --git a/ios/chrome/browser/shared/public/features/features.h b/ios/chrome/browser/shared/public/features/features.h index 8e7fd1e..b3abb0a 100644 --- a/ios/chrome/browser/shared/public/features/features.h +++ b/ios/chrome/browser/shared/public/features/features.h
@@ -293,6 +293,9 @@ // Feature flag to add lens overlay navigation to history. BASE_DECLARE_FEATURE(kLensOverlayNavigationHistory); +// Feature flag to add a custom bottom sheet presentation Lens results. +BASE_DECLARE_FEATURE(kLensOverlayCustomBottomSheet); + // Feature flag to check headers for lens searches. BASE_DECLARE_FEATURE(kLensSearchHeadersCheckEnabled);
diff --git a/ios/chrome/browser/shared/public/features/features.mm b/ios/chrome/browser/shared/public/features/features.mm index 9ca331fc..c34ffe3 100644 --- a/ios/chrome/browser/shared/public/features/features.mm +++ b/ios/chrome/browser/shared/public/features/features.mm
@@ -197,6 +197,8 @@ BASE_FEATURE(kLensOverlayNavigationHistory, base::FEATURE_DISABLED_BY_DEFAULT); +BASE_FEATURE(kLensOverlayCustomBottomSheet, base::FEATURE_DISABLED_BY_DEFAULT); + BASE_FEATURE(kLensSearchHeadersCheckEnabled, base::FEATURE_ENABLED_BY_DEFAULT); // Variations of MIA NTP entrypoint.
diff --git a/ios/chrome/browser/signin/model/BUILD.gn b/ios/chrome/browser/signin/model/BUILD.gn index d1abd137..ee805b97 100644 --- a/ios/chrome/browser/signin/model/BUILD.gn +++ b/ios/chrome/browser/signin/model/BUILD.gn
@@ -456,13 +456,13 @@ "authentication_service_unittest.mm", "chrome_account_manager_service_unittest.mm", "device_accounts_provider_impl_unittest.mm", - "gaia_auth_fetcher_ios_ns_url_session_bridge_unittests.mm", + "gaia_auth_fetcher_ios_ns_url_session_bridge_unittest.mm", "gaia_auth_fetcher_ios_unittest.mm", "pattern_account_restriction_unittest.mm", "resized_avatar_cache_unittest.mm", "signin_profile_info_updater_unittest.mm", "signin_util_unittest.mm", - "system_account_updater_unittests.mm", + "system_account_updater_unittest.mm", "system_identity_manager_unittest.mm", ] deps = [
diff --git a/ios/chrome/browser/signin/model/DEPS b/ios/chrome/browser/signin/model/DEPS index 3da22df4..8f5798d 100644 --- a/ios/chrome/browser/signin/model/DEPS +++ b/ios/chrome/browser/signin/model/DEPS
@@ -27,7 +27,7 @@ "+ios/chrome/browser/widget_kit/model/features.h", "+ios/chrome/browser/widget_kit/model/model_swift.h", ], - "^system_account_updater_unittests.mm": [ + "^system_account_updater_unittest.mm": [ "+ios/chrome/browser/widget_kit/model/features.h", ], }
diff --git a/ios/chrome/browser/signin/model/gaia_auth_fetcher_ios_ns_url_session_bridge_unittests.mm b/ios/chrome/browser/signin/model/gaia_auth_fetcher_ios_ns_url_session_bridge_unittest.mm similarity index 100% rename from ios/chrome/browser/signin/model/gaia_auth_fetcher_ios_ns_url_session_bridge_unittests.mm rename to ios/chrome/browser/signin/model/gaia_auth_fetcher_ios_ns_url_session_bridge_unittest.mm
diff --git a/ios/chrome/browser/signin/model/system_account_updater_unittests.mm b/ios/chrome/browser/signin/model/system_account_updater_unittest.mm similarity index 100% rename from ios/chrome/browser/signin/model/system_account_updater_unittests.mm rename to ios/chrome/browser/signin/model/system_account_updater_unittest.mm
diff --git a/ios/chrome/common/credential_provider/BUILD.gn b/ios/chrome/common/credential_provider/BUILD.gn index 65d1b70..7e039f53 100644 --- a/ios/chrome/common/credential_provider/BUILD.gn +++ b/ios/chrome/common/credential_provider/BUILD.gn
@@ -70,11 +70,11 @@ sources = [ "archivable_credential_store_unittest.mm", "archivable_credential_unittest.mm", - "as_credential_identity_categories_unittests.mm", + "as_credential_identity_categories_unittest.mm", "credential_store_util_unittest.mm", - "memory_credential_store_unittests.mm", - "multi_store_credential_store_unittests.mm", - "user_defaults_credential_store_unittests.mm", + "memory_credential_store_unittest.mm", + "multi_store_credential_store_unittest.mm", + "user_defaults_credential_store_unittest.mm", ] deps = [ ":credential_provider",
diff --git a/ios/chrome/common/credential_provider/as_credential_identity_categories_unittests.mm b/ios/chrome/common/credential_provider/as_credential_identity_categories_unittest.mm similarity index 100% rename from ios/chrome/common/credential_provider/as_credential_identity_categories_unittests.mm rename to ios/chrome/common/credential_provider/as_credential_identity_categories_unittest.mm
diff --git a/ios/chrome/common/credential_provider/memory_credential_store_unittests.mm b/ios/chrome/common/credential_provider/memory_credential_store_unittest.mm similarity index 100% rename from ios/chrome/common/credential_provider/memory_credential_store_unittests.mm rename to ios/chrome/common/credential_provider/memory_credential_store_unittest.mm
diff --git a/ios/chrome/common/credential_provider/multi_store_credential_store_unittests.mm b/ios/chrome/common/credential_provider/multi_store_credential_store_unittest.mm similarity index 100% rename from ios/chrome/common/credential_provider/multi_store_credential_store_unittests.mm rename to ios/chrome/common/credential_provider/multi_store_credential_store_unittest.mm
diff --git a/ios/chrome/common/credential_provider/user_defaults_credential_store_unittests.mm b/ios/chrome/common/credential_provider/user_defaults_credential_store_unittest.mm similarity index 100% rename from ios/chrome/common/credential_provider/user_defaults_credential_store_unittests.mm rename to ios/chrome/common/credential_provider/user_defaults_credential_store_unittest.mm
diff --git a/ios/chrome/test/wpt/cwt_webdriver_app_interface.mm b/ios/chrome/test/wpt/cwt_webdriver_app_interface.mm index 6afe0c2..d50a5417 100644 --- a/ios/chrome/test/wpt/cwt_webdriver_app_interface.mm +++ b/ios/chrome/test/wpt/cwt_webdriver_app_interface.mm
@@ -9,6 +9,7 @@ #import "base/files/file.h" #import "base/files/file_path.h" #import "base/json/json_writer.h" +#import "base/strings/string_number_conversions.h" #import "base/strings/stringprintf.h" #import "base/strings/sys_string_conversions.h" #import "base/strings/utf_string_conversions.h" @@ -35,7 +36,8 @@ namespace { NSString* GetIdForWebState(web::WebState* web_state) { - return web_state->GetStableIdentifier(); + return base::SysUTF8ToNSString(base::NumberToString( + web_state->GetUniqueIdentifier().ToSessionID().id())); } WebStateList* GetCurrentWebStateList() { @@ -45,14 +47,21 @@ } web::WebState* GetWebStateWithId(NSString* tab_id) { + int value = 0; + if (!base::StringToInt(base::SysNSStringToUTF8(tab_id), &value)) { + return nullptr; + } + + web::WebStateID web_state_id = web::WebStateID::FromSerializedValue(value); + WebStateList* web_state_list = GetCurrentWebStateList(); for (int i = 0; i < web_state_list->count(); ++i) { web::WebState* web_state = web_state_list->GetWebStateAt(i); - if ([tab_id isEqualToString:GetIdForWebState(web_state)]) { + if (web_state_id == web_state->GetUniqueIdentifier()) { return web_state; } } - return nil; + return nullptr; } // Returns the index of the WebState with the given tab_id, or
diff --git a/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios.zip.sha1 index 697d0cf..f7227d0 100644 --- a/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios.zip.sha1 +++ b/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@ -80ec3fd9061d21f7833d0e4f934bd99c9bc8c364 \ No newline at end of file +91897c0366080a70c179989739196f228a797043 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios_asan.zip.sha1 b/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios_asan.zip.sha1 index 6405319..f98f3f0 100644 --- a/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios_asan.zip.sha1 +++ b/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios_asan.zip.sha1
@@ -1 +1 @@ -805cbd01caccda2bc37198ff151d8c85bb38ac8d \ No newline at end of file +8d16be69a936d4d34f32c9c671d05c0829e4e390 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1 index 173f105fc..4daa156 100644 --- a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1 +++ b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@ -fe084958a725fe171912b80f6902b1cabcb45a3b \ No newline at end of file +29894faed28273d6911021b0519a00c0446eb39d \ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios_asan.zip.sha1 b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios_asan.zip.sha1 index 89ee59e..1ba8c42 100644 --- a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios_asan.zip.sha1 +++ b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios_asan.zip.sha1
@@ -1 +1 @@ -c9739407c74da3368accbaebddae9592567216e9 \ No newline at end of file +b09fab3cce33d8153183a9deee7c5667f6481244 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1 index 9f5afb9..3acb5661 100644 --- a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1 +++ b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@ -44002f0c0303b50bd6cbd72fadea747ea52899c1 \ No newline at end of file +05ef254aef4498cb81b1c35e0101353089c0aada \ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios_asan.zip.sha1 b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios_asan.zip.sha1 index a9c240e9..845caee 100644 --- a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios_asan.zip.sha1 +++ b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios_asan.zip.sha1
@@ -1 +1 @@ -11377d3fb540e6b331bc7e1b2a2550bbe73f3e95 \ No newline at end of file +221ee2c6845448796edea782321002958d075fb9 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios.zip.sha1 index 80d722f..5851407f8 100644 --- a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -29334d9a40511aec4cf6862443e1f17afaa7bc35 \ No newline at end of file +b901a5876bd0a7e664c246f55c7dc1195181f0e3 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios_asan.zip.sha1 index a8b47d9..17dbd65 100644 --- a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios_asan.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios_asan.zip.sha1
@@ -1 +1 @@ -8878f94de111cdd125a69df1fe5be6d5d1169cb6 \ No newline at end of file +8ab08e1897436633daa63b4d99d9a374a6998d23 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator.zip.sha1 index 5ce5feec..95d87fa4 100644 --- a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -b2eb36bbd8df644693e539dbdb911cc5b36bfa97 \ No newline at end of file +ce0b83799c714458f50a797c0039b4c26fe35c71 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator_asan.zip.sha1 index e30aad4..e64ad5a 100644 --- a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator_asan.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator_asan.zip.sha1
@@ -1 +1 @@ -c75fec51126b69b2a7828d315d820faf374ccd45 \ No newline at end of file +7f3035c2f151f0691bfb9927f153cd7c0530be9c \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 index 6b4c59f..2ade6a6 100644 --- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -41547247677c4364dafcae439bf58ddb05ef0855 \ No newline at end of file +9b06ef79487e0abc6c922c7ff65f9369c7a686d0 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios_asan.zip.sha1 index 487ec148..578cec8 100644 --- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios_asan.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios_asan.zip.sha1
@@ -1 +1 @@ -5b0b245623004fd47376cca72786ecf12717bc03 \ No newline at end of file +82ee45af9ba77f6f669f08a3ecf57c425cfbb00d \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 index ff35c97..c279039 100644 --- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -3fe46b73d7a216e2009f2e914b565f790248d369 \ No newline at end of file +d72f9d319629ae69a7a49129e569a4d8b04e6658 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator_asan.zip.sha1 index 60560a7..86f42eb 100644 --- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator_asan.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator_asan.zip.sha1
@@ -1 +1 @@ -ae71be027ee42d4767ed618ad812e22205cd53cf \ No newline at end of file +61605648f6c4f283f6a8315fa7f83f2023c0657e \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 index 1de4170..07dd2ede 100644 --- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -8d0c6506f45371f58eee0dc223403884b190ae68 \ No newline at end of file +34ccd4e20d7b9175338113966697b53e76bc992d \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios_asan.zip.sha1 index c39fa661..b04f25f5 100644 --- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios_asan.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios_asan.zip.sha1
@@ -1 +1 @@ -6bfb71494c38d67268605c5e6cc6ebe176b1b4e6 \ No newline at end of file +70063bd3fef7e27ff03cf46b6ffb0aa0ffe5bfa7 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 index 7c3e33c8..031bffe 100644 --- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -9d995cef6dcf60770eae2e29a1f3fa126783f894 \ No newline at end of file +c8fb4a481cd9e1e8c0bd9855b0fa8e40f54340e2 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator_asan.zip.sha1 index 4c9bd9e..d6eb338 100644 --- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator_asan.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator_asan.zip.sha1
@@ -1 +1 @@ -b8ffc54b0870ea3bbd7a471fb897e82362f520b9 \ No newline at end of file +77d4d9635af005e7fc7da635112ffde2a085c5a1 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1 index d7cf7c8..a248b15f 100644 --- a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -def947efec5af309a356ace067338b680c385314 \ No newline at end of file +b4ad82af5b0629302a37184ec25d8d5c510ac179 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1 index 49d36d25..7d9a2f4 100644 --- a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -a310301bbc9e15a95c049a30232f6e3cda8afd17 \ No newline at end of file +5a2ee315a3051da6b5f8194f9dc27828b0e5b0e2 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 index 1bf085a..4a1cc172 100644 --- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -f5e44e21ed9c81c2c680583e6941e89f3c5e95b8 \ No newline at end of file +0f64f7ffe6484a1e3e8ade4d91d622af119e8797 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios_asan.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios_asan.zip.sha1 index 21a8c88..cfaf3273 100644 --- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios_asan.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios_asan.zip.sha1
@@ -1 +1 @@ -8a1bb878e107341b961d47e81e73cadd4e9bbae4 \ No newline at end of file +9ccc5c5e9d8819abe3439bf5df1b77ca9c2afa1f \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 index f327f703..e54f53db 100644 --- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -da99add71f408c825599c5ce84629d17af980abd \ No newline at end of file +09a44e71a6609d911bae78bf6724c57c4098f5be \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator_asan.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator_asan.zip.sha1 index 620f782..d45233808 100644 --- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator_asan.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator_asan.zip.sha1
@@ -1 +1 @@ -b88d76aa361e73887edf0956f25bcc7ba35017b7 \ No newline at end of file +b25a78d4b0283e29d0c79c4dd0262cce7ad86126 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 index 54dd6b4..3629271 100644 --- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -2c75ed5630df559c428ddba0016193f82a73d95e \ No newline at end of file +798ea0cad14128cf37e5f58931cbd07b8eb8953f \ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios_asan.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios_asan.zip.sha1 index 4dd1c98..8b937c5 100644 --- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios_asan.zip.sha1 +++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios_asan.zip.sha1
@@ -1 +1 @@ -054e529596e3ef881ebb3d60b49e9204ca1aca00 \ No newline at end of file +c4da18d698e479d11298ce60e0f0e6f9878f649b \ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 index efd08dabb..b9c4b6f 100644 --- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -97929bc8958017b63809bc547dce2500183126ad \ No newline at end of file +75ac58fcbc25a3d958876bddaf20da4ef560fe04 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator_asan.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator_asan.zip.sha1 index cd20392..a67ba38 100644 --- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator_asan.zip.sha1 +++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator_asan.zip.sha1
@@ -1 +1 @@ -23bbdf8e9c26a325c61b258ca06de4e5b32f3512 \ No newline at end of file +a1bd9a9f2312f237b87832b8a9214548cf5d23eb \ No newline at end of file
diff --git a/ios/web_view/BUILD.gn b/ios/web_view/BUILD.gn index 6772048d..b7e376d4 100644 --- a/ios/web_view/BUILD.gn +++ b/ios/web_view/BUILD.gn
@@ -10,9 +10,7 @@ import("//ios/build/config.gni") import("//ios/web/public/js_messaging/optimize_js.gni") import("//ios/web_view/features.gni") -import("//ios/web_view/repack.gni") -import("//testing/test.gni") -import("//tools/grit/repack.gni") +import("//ios/web_view/framework/sources.gni") group("all_tests") { testonly = true @@ -22,6 +20,22 @@ ] } +# Target used to avoid breaking bot configuration files referring to the old +# name of the target. Will be removed when the bot configuration files have +# been updated. +group("ios_web_view_inttests") { + testonly = true + deps = [ "//ios/web_view/test:ios_web_view_inttests" ] +} + +# Target used to avoid breaking bot configuration files referring to the old +# name of the target. Will be removed when the bot configuration files have +# been updated. +group("ios_web_view_unittests") { + testonly = true + deps = [ "//ios/web_view/test:ios_web_view_unittests" ] +} + config("config") { # TODO(crbug.com/40120082): This will only guarantee ios/web_view source files # are extension safe. We also need to pass this flag to all all dependencies. @@ -37,407 +51,6 @@ ] } -# These are defined as vars so they can be shared with different targets below. -ios_web_view_public_headers = [ - "public/cwv_omnibox_input.h", - "public/cwv_autofill_controller.h", - "public/cwv_autofill_controller_delegate.h", - "public/cwv_autofill_data_manager.h", - "public/cwv_autofill_data_manager_observer.h", - "public/cwv_autofill_form.h", - "public/cwv_autofill_profile.h", - "public/cwv_autofill_suggestion.h", - "public/cwv_back_forward_list.h", - "public/cwv_back_forward_list_item.h", - "public/cwv_cert_status.h", - "public/cwv_credential_provider_extension_utils.h", - "public/cwv_credit_card.h", - "public/cwv_credit_card_saver.h", - "public/cwv_credit_card_verifier.h", - "public/cwv_defines.h", - "public/cwv_download_task.h", - "public/cwv_export.h", - "public/cwv_favicon.h", - "public/cwv_find_in_page_controller.h", - "public/cwv_flags.h", - "public/cwv_html_element.h", - "public/cwv_global_state.h", - "public/cwv_identity.h", - "public/cwv_leak_check_credential.h", - "public/cwv_leak_check_service.h", - "public/cwv_leak_check_service_observer.h", - "public/cwv_lookalike_url_handler.h", - "public/cwv_metrics_provider.h", - "public/cwv_navigation_action.h", - "public/cwv_navigation_delegate.h", - "public/cwv_navigation_response.h", - "public/cwv_navigation_type.h", - "public/cwv_password.h", - "public/cwv_preferences.h", - "public/cwv_preview_element_info.h", - "public/cwv_reuse_check_service.h", - "public/cwv_ssl_error_handler.h", - "public/cwv_ssl_status.h", - "public/cwv_suggestion_type.h", - "public/cwv_sync_controller.h", - "public/cwv_sync_controller_data_source.h", - "public/cwv_sync_controller_delegate.h", - "public/cwv_sync_errors.h", - "public/cwv_translation_controller.h", - "public/cwv_translation_controller_delegate.h", - "public/cwv_translation_language.h", - "public/cwv_translation_language_detection_details.h", - "public/cwv_translation_policy.h", - "public/cwv_trusted_vault_observer.h", - "public/cwv_trusted_vault_provider.h", - "public/cwv_trusted_vault_utils.h", - "public/cwv_ui_delegate.h", - "public/cwv_unsafe_url_handler.h", - "public/cwv_user_content_controller.h", - "public/cwv_user_script.h", - "public/cwv_weak_check_utils.h", - "public/cwv_web_view.h", - "public/cwv_web_view_configuration.h", - "public/cwv_x509_certificate.h", -] - -ios_web_view_sources = [ - "internal/affiliations/web_view_affiliation_service_factory.h", - "internal/affiliations/web_view_affiliation_service_factory.mm", - "internal/app/application_context.h", - "internal/app/application_context.mm", - "internal/app/web_view_io_thread.h", - "internal/app/web_view_io_thread.mm", - "internal/autofill/cwv_autofill_client_ios_bridge.h", - "internal/autofill/cwv_autofill_controller+testing.h", - "internal/autofill/cwv_autofill_controller.mm", - "internal/autofill/cwv_autofill_controller_internal.h", - "internal/autofill/cwv_autofill_data_manager.mm", - "internal/autofill/cwv_autofill_data_manager_internal.h", - "internal/autofill/cwv_autofill_form.mm", - "internal/autofill/cwv_autofill_form_internal.h", - "internal/autofill/cwv_autofill_prefs.h", - "internal/autofill/cwv_autofill_prefs.mm", - "internal/autofill/cwv_autofill_profile.mm", - "internal/autofill/cwv_autofill_profile_internal.h", - "internal/autofill/cwv_autofill_suggestion.mm", - "internal/autofill/cwv_autofill_suggestion_internal.h", - "internal/autofill/cwv_credit_card.mm", - "internal/autofill/cwv_credit_card_internal.h", - "internal/autofill/cwv_credit_card_saver.mm", - "internal/autofill/cwv_credit_card_saver_internal.h", - "internal/autofill/cwv_credit_card_verifier.mm", - "internal/autofill/cwv_credit_card_verifier_internal.h", - "internal/autofill/cwv_password_affiliation.h", - "internal/autofill/cwv_password_affiliation.mm", - "internal/autofill/ios_web_view_payments_autofill_client.h", - "internal/autofill/ios_web_view_payments_autofill_client.mm", - "internal/autofill/web_view_autocomplete_history_manager_factory.h", - "internal/autofill/web_view_autocomplete_history_manager_factory.mm", - "internal/autofill/web_view_autofill_client_ios.h", - "internal/autofill/web_view_autofill_client_ios.mm", - "internal/autofill/web_view_autofill_log_router_factory.h", - "internal/autofill/web_view_autofill_log_router_factory.mm", - "internal/autofill/web_view_personal_data_manager_factory.h", - "internal/autofill/web_view_personal_data_manager_factory.mm", - "internal/autofill/web_view_strike_database_factory.h", - "internal/autofill/web_view_strike_database_factory.mm", - "internal/browser_state_keyed_service_factories.h", - "internal/browser_state_keyed_service_factories.mm", - "internal/browser_state_prefs.h", - "internal/browser_state_prefs.mm", - "internal/component_updater/web_view_component_updater_configurator.h", - "internal/component_updater/web_view_component_updater_configurator.mm", - "internal/cwv_back_forward_list.mm", - "internal/cwv_back_forward_list_internal.h", - "internal/cwv_back_forward_list_item.mm", - "internal/cwv_back_forward_list_item_internal.h", - "internal/cwv_download_task.mm", - "internal/cwv_download_task_internal.h", - "internal/cwv_favicon.mm", - "internal/cwv_favicon_internal.h", - "internal/cwv_find_in_page_controller.mm", - "internal/cwv_find_in_page_controller_internal.h", - "internal/cwv_flags.mm", - "internal/cwv_flags_internal.h", - "internal/cwv_global_state_internal.h", - "internal/cwv_html_element.mm", - "internal/cwv_html_element_internal.h", - "internal/cwv_lookalike_url_handler.mm", - "internal/cwv_lookalike_url_handler_internal.h", - "internal/cwv_navigation_action.mm", - "internal/cwv_navigation_action_internal.h", - "internal/cwv_navigation_response.mm", - "internal/cwv_navigation_response_internal.h", - "internal/cwv_navigation_type.mm", - "internal/cwv_navigation_type_internal.h", - "internal/cwv_omnibox_input.mm", - "internal/cwv_preferences.mm", - "internal/cwv_preferences_internal.h", - "internal/cwv_preview_element_info.mm", - "internal/cwv_preview_element_info_internal.h", - "internal/cwv_ssl_error_handler.mm", - "internal/cwv_ssl_error_handler_internal.h", - "internal/cwv_ssl_status.mm", - "internal/cwv_ssl_status_internal.h", - "internal/cwv_ssl_util.h", - "internal/cwv_ssl_util.mm", - "internal/cwv_user_content_controller.mm", - "internal/cwv_user_content_controller_internal.h", - "internal/cwv_user_script.mm", - "internal/cwv_web_view.mm", - "internal/cwv_web_view_configuration.mm", - "internal/cwv_web_view_configuration_internal.h", - "internal/cwv_web_view_internal.h", - "internal/cwv_x509_certificate.mm", - "internal/cwv_x509_certificate_internal.h", - "internal/js_messaging/web_view_scripts_java_script_feature.h", - "internal/js_messaging/web_view_scripts_java_script_feature.mm", - "internal/language/web_view_accept_languages_service_factory.h", - "internal/language/web_view_accept_languages_service_factory.mm", - "internal/language/web_view_language_model_manager_factory.h", - "internal/language/web_view_language_model_manager_factory.mm", - "internal/language/web_view_url_language_histogram_factory.h", - "internal/language/web_view_url_language_histogram_factory.mm", - "internal/metrics/cwv_metrics_provider.mm", - "internal/metrics/cwv_metrics_provider_internal.h", - "internal/passwords/cwv_credential_provider_extension_utils.mm", - "internal/passwords/cwv_leak_check_credential.mm", - "internal/passwords/cwv_leak_check_credential_internal.h", - "internal/passwords/cwv_leak_check_service.mm", - "internal/passwords/cwv_leak_check_service_internal.h", - "internal/passwords/cwv_password.mm", - "internal/passwords/cwv_password_internal.h", - "internal/passwords/cwv_reuse_check_service.mm", - "internal/passwords/cwv_reuse_check_service_internal.h", - "internal/passwords/cwv_weak_check_utils.mm", - "internal/passwords/cwv_weak_check_utils_internal.h", - "internal/passwords/web_view_account_password_store_factory.h", - "internal/passwords/web_view_account_password_store_factory.mm", - "internal/passwords/web_view_bulk_leak_check_service_factory.h", - "internal/passwords/web_view_bulk_leak_check_service_factory.mm", - "internal/passwords/web_view_password_feature_manager.h", - "internal/passwords/web_view_password_feature_manager.mm", - "internal/passwords/web_view_password_manager_client.h", - "internal/passwords/web_view_password_manager_client.mm", - "internal/passwords/web_view_password_manager_log_router_factory.h", - "internal/passwords/web_view_password_manager_log_router_factory.mm", - "internal/passwords/web_view_password_requirements_service_factory.h", - "internal/passwords/web_view_password_requirements_service_factory.mm", - "internal/passwords/web_view_password_reuse_manager_factory.h", - "internal/passwords/web_view_password_reuse_manager_factory.mm", - "internal/passwords/web_view_profile_password_store_factory.h", - "internal/passwords/web_view_profile_password_store_factory.mm", - "internal/safe_browsing/cwv_unsafe_url_handler.mm", - "internal/safe_browsing/cwv_unsafe_url_handler_internal.h", - "internal/safe_browsing/web_view_safe_browsing_client.h", - "internal/safe_browsing/web_view_safe_browsing_client.mm", - "internal/safe_browsing/web_view_safe_browsing_client_factory.h", - "internal/safe_browsing/web_view_safe_browsing_client_factory.mm", - "internal/safe_browsing/web_view_safe_browsing_helper_factory.h", - "internal/safe_browsing/web_view_safe_browsing_helper_factory.mm", - "internal/signin/account_capabilities_fetcher_factory_ios_web_view.h", - "internal/signin/account_capabilities_fetcher_factory_ios_web_view.mm", - "internal/signin/account_capabilities_fetcher_ios_web_view.h", - "internal/signin/account_capabilities_fetcher_ios_web_view.mm", - "internal/signin/cwv_identity.mm", - "internal/signin/ios_web_view_signin_client.h", - "internal/signin/ios_web_view_signin_client.mm", - "internal/signin/web_view_device_accounts_provider_impl.h", - "internal/signin/web_view_device_accounts_provider_impl.mm", - "internal/signin/web_view_gaia_auth_fetcher.h", - "internal/signin/web_view_gaia_auth_fetcher.mm", - "internal/signin/web_view_identity_manager_factory.h", - "internal/signin/web_view_identity_manager_factory.mm", - "internal/signin/web_view_signin_client_factory.h", - "internal/signin/web_view_signin_client_factory.mm", - "internal/sync/cwv_sync_controller.mm", - "internal/sync/cwv_sync_controller_internal.h", - "internal/sync/cwv_trusted_vault_observer.mm", - "internal/sync/cwv_trusted_vault_observer_internal.h", - "internal/sync/cwv_trusted_vault_utils.mm", - "internal/sync/web_view_data_type_store_service_factory.h", - "internal/sync/web_view_data_type_store_service_factory.mm", - "internal/sync/web_view_device_info_sync_service_factory.h", - "internal/sync/web_view_device_info_sync_service_factory.mm", - "internal/sync/web_view_gcm_profile_service_factory.h", - "internal/sync/web_view_gcm_profile_service_factory.mm", - "internal/sync/web_view_instance_id_profile_service_factory.h", - "internal/sync/web_view_instance_id_profile_service_factory.mm", - "internal/sync/web_view_profile_invalidation_provider_factory.h", - "internal/sync/web_view_profile_invalidation_provider_factory.mm", - "internal/sync/web_view_sync_client.h", - "internal/sync/web_view_sync_client.mm", - "internal/sync/web_view_sync_invalidations_service_factory.h", - "internal/sync/web_view_sync_invalidations_service_factory.mm", - "internal/sync/web_view_sync_service_factory.h", - "internal/sync/web_view_sync_service_factory.mm", - "internal/sync/web_view_trusted_vault_client.h", - "internal/sync/web_view_trusted_vault_client.mm", - "internal/translate/cwv_translation_controller.mm", - "internal/translate/cwv_translation_controller_internal.h", - "internal/translate/cwv_translation_language.mm", - "internal/translate/cwv_translation_language_detection_details.mm", - "internal/translate/cwv_translation_language_detection_details_internal.h", - "internal/translate/cwv_translation_language_internal.h", - "internal/translate/cwv_translation_policy.mm", - "internal/translate/web_view_translate_client.h", - "internal/translate/web_view_translate_client.mm", - "internal/translate/web_view_translate_ranker_factory.h", - "internal/translate/web_view_translate_ranker_factory.mm", - "internal/translate/web_view_translate_service.h", - "internal/translate/web_view_translate_service.mm", - "internal/utils/nsobject_description_utils.h", - "internal/utils/nsobject_description_utils.mm", - "internal/web_view_browser_state.h", - "internal/web_view_browser_state.mm", - "internal/web_view_download_manager.h", - "internal/web_view_download_manager.mm", - "internal/web_view_java_script_dialog_presenter.h", - "internal/web_view_java_script_dialog_presenter.mm", - "internal/web_view_message_handler_java_script_feature.h", - "internal/web_view_message_handler_java_script_feature.mm", - "internal/web_view_url_request_context_getter.h", - "internal/web_view_url_request_context_getter.mm", - "internal/web_view_web_client.h", - "internal/web_view_web_client.mm", - "internal/web_view_web_main_delegate.h", - "internal/web_view_web_main_delegate.mm", - "internal/web_view_web_main_parts.h", - "internal/web_view_web_main_parts.mm", - "internal/web_view_web_state_policy_decider.h", - "internal/web_view_web_state_policy_decider.mm", - "internal/webdata_services/web_view_web_data_service_wrapper_factory.h", - "internal/webdata_services/web_view_web_data_service_wrapper_factory.mm", - "internal/webui/web_view_sync_internals_ui.h", - "internal/webui/web_view_sync_internals_ui.mm", - "internal/webui/web_view_web_ui_ios_controller_factory.h", - "internal/webui/web_view_web_ui_ios_controller_factory.mm", - "internal/webui/web_view_web_ui_provider.mm", -] - -ios_web_view_deps = [ - ":web_view_resources", - "//base", - "//components/affiliations/core/browser:affiliations", - "//components/autofill/core/browser", - "//components/autofill/core/common", - "//components/autofill/ios/browser", - "//components/autofill/ios/browser:util", - "//components/autofill/ios/form_util", - "//components/autofill/ios/form_util:form_handler_feature", - "//components/autofill/ios/form_util:programmatic_form_submission_handler_feature", - "//components/browser_sync", - "//components/component_updater", - "//components/component_updater/installer_policies", - "//components/gcm_driver", - "//components/history/core/common", - "//components/image_fetcher/ios", - "//components/infobars/core", - "//components/invalidation", - "//components/invalidation:legacy_topics_cleanup", - "//components/keyed_service/core", - "//components/keyed_service/ios", - "//components/language/core/browser", - "//components/language/core/common", - "//components/language/core/language_model", - "//components/language/ios/browser", - "//components/leveldb_proto", - "//components/lookalikes/core", - "//components/metrics:library_support", - "//components/metrics/demographics", - "//components/omnibox/browser:location_bar", - "//components/os_crypt/async/browser", - "//components/password_manager/core/browser", - "//components/password_manager/core/browser/affiliation:affiliation_fetching", - "//components/password_manager/core/browser/affiliation:affiliation_match_helper", - "//components/password_manager/core/browser/features:password_features", - "//components/password_manager/core/browser/generation:core", - "//components/password_manager/core/browser/leak_detection", - "//components/password_manager/core/browser/sharing", - "//components/password_manager/core/common", - "//components/password_manager/ios", - "//components/plus_addresses/core/browser/settings", - "//components/plus_addresses/core/browser/webdata", - "//components/pref_registry", - "//components/prefs", - "//components/profile_metrics", - "//components/proxy_config", - "//components/safe_browsing/core/common:safe_browsing_prefs", - "//components/safe_browsing/ios/browser:allow_list", - "//components/security_interstitials/core:unsafe_resource", - "//components/security_state/ios", - "//components/services/patch:in_process", - "//components/services/unzip:in_process", - "//components/sessions:session_id", - "//components/signin/core/browser", - "//components/signin/internal/identity_manager", - "//components/signin/ios/browser", - "//components/signin/public/base", - "//components/signin/public/identity_manager", - "//components/signin/public/identity_manager/ios", - "//components/signin/public/webdata", - "//components/ssl_errors", - "//components/strings", - "//components/sync", - "//components/sync/invalidations", - "//components/sync_device_info", - "//components/translate/core/browser", - "//components/translate/core/common", - "//components/translate/ios/browser", - "//components/trusted_vault", - "//components/unified_consent", - "//components/update_client", - "//components/update_client:common_impl", - "//components/url_formatter", - "//components/variations", - "//components/variations/net", - "//components/version_info", - "//components/version_info:version_string", - "//components/web_resource", - "//components/webdata_services", - "//components/webui/flags", - "//components/webui/flags:switches", - "//google_apis", - "//ios/components/credential_provider_extension:password_spec_fetcher", - "//ios/components/credential_provider_extension:password_util", - "//ios/components/io_thread", - "//ios/components/security_interstitials", - "//ios/components/security_interstitials/https_only_mode:feature", - "//ios/components/security_interstitials/lookalikes", - "//ios/components/security_interstitials/safe_browsing", - "//ios/components/security_interstitials/safe_browsing:util", - "//ios/components/webui:provider", - "//ios/components/webui:url_constants", - "//ios/components/webui/sync_internals", - "//ios/net", - "//ios/third_party/webkit", - "//ios/web/common", - "//ios/web/common:user_agent", - "//ios/web/navigation:wk_navigation_util", - "//ios/web/public", - "//ios/web/public/browsing_data", - "//ios/web/public/download", - "//ios/web/public/find_in_page", - "//ios/web/public/init", - "//ios/web/public/js_messaging", - "//ios/web/public/security", - "//ios/web/public/session", - "//ios/web/public/session/proto", - "//ios/web/public/web_view_only", - "//ios/web/public/webui", - "//ios/web/web_state/ui:wk_web_view_configuration_provider_header", - "//ios/web/webui", - "//ios/web_view/internal/js_messaging:cwv_messaging_js", - "//net", - "//net:extras", - "//services/metrics/public/cpp:metrics_cpp", - "//services/network:network_service", - "//ui/base", - "//ui/display", - "//url", -] - source_set("web_view_sources") { sources = ios_web_view_public_headers sources += ios_web_view_sources @@ -495,169 +108,6 @@ configs += [ ":config" ] } -source_set("run_all_unittests") { - testonly = true - sources = [ "test/run_all_unittests.cc" ] - deps = [ - "//base", - "//base/test:test_support", - "//mojo/core/embedder", - ] -} - -config("unittest_config") { - defines = [ "CWV_UNIT_TEST" ] -} - -test("ios_web_view_unittests") { - testonly = true - sources = [ - "internal/autofill/cwv_autofill_controller_unittest.mm", - "internal/autofill/cwv_autofill_data_manager_unittest.mm", - "internal/autofill/cwv_autofill_form_unittest.mm", - "internal/autofill/cwv_autofill_profile_unittest.mm", - "internal/autofill/cwv_autofill_suggestion_unittest.mm", - "internal/autofill/cwv_credit_card_saver_unittest.mm", - "internal/autofill/cwv_credit_card_unittest.mm", - "internal/autofill/cwv_credit_card_verifier_unittest.mm", - "internal/cwv_download_task_unittest.mm", - "internal/cwv_favicon_unittest.mm", - "internal/cwv_flags_unittest.mm", - "internal/cwv_global_state.mm", - "internal/cwv_html_element_unittest.mm", - "internal/cwv_lookalike_url_handler_unittest.mm", - "internal/cwv_omnibox_input_unittest.mm", - "internal/cwv_preferences_unittest.mm", - "internal/cwv_preview_element_info_unittest.mm", - "internal/cwv_ssl_error_handler_unittest.mm", - "internal/cwv_ssl_status_unittest.mm", - "internal/cwv_web_view_configuration_internal_unittest.mm", - "internal/cwv_web_view_unittest.mm", - "internal/cwv_x509_certificate_unittest.mm", - "internal/metrics/cwv_metrics_provider_unittest.mm", - "internal/passwords/cwv_credential_provider_extension_utils_unittest.mm", - "internal/passwords/cwv_leak_check_credential_unittest.mm", - "internal/passwords/cwv_leak_check_service_unittest.mm", - "internal/passwords/cwv_password_unittest.mm", - "internal/passwords/cwv_reuse_check_service_unittest.mm", - "internal/passwords/cwv_weak_check_utils_unittest.mm", - "internal/passwords/web_view_password_manager_client_unittest.mm", - "internal/safe_browsing/cwv_unsafe_url_handler_unittest.mm", - "internal/signin/account_capabilities_fetcher_ios_web_view_unittest.mm", - "internal/signin/cwv_identity_unittest.mm", - "internal/signin/web_view_device_accounts_provider_impl_unittest.mm", - "internal/signin/web_view_gaia_auth_fetcher_unittest.mm", - "internal/sync/cwv_sync_controller_unittest.mm", - "internal/sync/cwv_trusted_vault_observer_unittest.mm", - "internal/translate/cwv_translation_controller_unittest.mm", - "internal/translate/cwv_translation_language_unittest.mm", - "internal/translate/cwv_translation_policy_unittest.mm", - "internal/web_view_web_client_unittest.mm", - ] - - configs += [ ":unittest_config" ] - - deps = [ - ":run_all_unittests", - ":web_view_sources", - "test:test_support", - "//base/test:test_support", - "//components/affiliations/core/browser:test_support", - "//components/autofill/core/browser:test_support", - "//components/autofill/ios/browser:test_support", - "//components/autofill/ios/form_util:test_support", - "//components/language_detection/core", - "//components/password_manager/core/browser:test_support", - "//components/password_manager/core/browser/leak_detection:test_support", - "//components/prefs:test_support", - "//components/signin/public/base:test_support", - "//components/signin/public/identity_manager:test_support", - "//components/sync:test_support", - "//components/sync_device_info:test_support", - "//components/translate/core/browser:test_support", - "//components/translate/core/language_detection", - "//ios/web/common:uikit", - "//ios/web/common:web_view_creation_util", - "//ios/web/public/js_messaging", - "//ios/web/public/security", - "//ios/web/public/test", - "//ios/web/public/test:test_fixture", - "//net:test_support", - "//testing/gtest", - "//third_party/ocmock", - ] - - assert_no_deps = ios_assert_no_deps -} - -test("ios_web_view_inttests") { - testonly = true - - deps = [ "//ios/web_view/test:inttests" ] - - bundle_deps = [ ":web_view+bundle" ] - - assert_no_deps = ios_assert_no_deps -} - -repack_locales("repack_locales") { - visibility = [ ":web_view_resources" ] - source_patterns = [ - "${root_gen_dir}/components/strings/components_strings_", - "${root_gen_dir}/components/strings/components_locale_settings_", - "${root_gen_dir}/ui/strings/app_locale_settings_", - "${root_gen_dir}/ui/strings/ax_strings_", - "${root_gen_dir}/ui/strings/ui_strings_", - ] - - deps = [ - "//components/strings:components_locale_settings", - "//components/strings:components_strings", - "//ui/strings:app_locale_settings", - "//ui/strings:ax_strings", - "//ui/strings:ui_strings", - ] - input_locales = platform_pak_locales - output_locales = locales_as_apple_outputs - copy_data_to_bundle = true -} - -repack("repack_resources") { - visibility = [ ":web_view_resources" ] - deps = [ - "//components/resources:components_resources", - "//components/sync/service/resources", - "//ios/web:resources", - "//ui/webui/resources", - ] - sources = [ - "$root_gen_dir/components/components_resources.pak", - "$root_gen_dir/components/sync_service_sync_internals_resources.pak", - "$root_gen_dir/ios/web/ios_web_resources.pak", - "$root_gen_dir/ui/webui/resources/webui_resources.pak", - ] - output = "$target_gen_dir/web_view_resources.pak" - copy_data_to_bundle = true -} - -ios_web_view_repack_all_scales("repack_scalable_resources") { - visibility = [ ":web_view_resources" ] - scales = [ - "100", - "200", - "300", - ] -} - -group("web_view_resources") { - visibility = [ "//ios/web_view:*" ] - deps = [ - ":repack_locales", - ":repack_resources", - ":repack_scalable_resources", - ] -} - _package_dir = "$root_out_dir/ios_web_view" action("ios_web_view_generate_license") {
diff --git a/ios/web_view/framework/sources.gni b/ios/web_view/framework/sources.gni new file mode 100644 index 0000000..2b42e25 --- /dev/null +++ b/ios/web_view/framework/sources.gni
@@ -0,0 +1,404 @@ +# 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. + +# These are defined as vars so they can be shared with different targets below. +ios_web_view_public_headers = [ + "//ios/web_view/public/cwv_omnibox_input.h", + "//ios/web_view/public/cwv_autofill_controller.h", + "//ios/web_view/public/cwv_autofill_controller_delegate.h", + "//ios/web_view/public/cwv_autofill_data_manager.h", + "//ios/web_view/public/cwv_autofill_data_manager_observer.h", + "//ios/web_view/public/cwv_autofill_form.h", + "//ios/web_view/public/cwv_autofill_profile.h", + "//ios/web_view/public/cwv_autofill_suggestion.h", + "//ios/web_view/public/cwv_back_forward_list.h", + "//ios/web_view/public/cwv_back_forward_list_item.h", + "//ios/web_view/public/cwv_cert_status.h", + "//ios/web_view/public/cwv_credential_provider_extension_utils.h", + "//ios/web_view/public/cwv_credit_card.h", + "//ios/web_view/public/cwv_credit_card_saver.h", + "//ios/web_view/public/cwv_credit_card_verifier.h", + "//ios/web_view/public/cwv_defines.h", + "//ios/web_view/public/cwv_download_task.h", + "//ios/web_view/public/cwv_export.h", + "//ios/web_view/public/cwv_favicon.h", + "//ios/web_view/public/cwv_find_in_page_controller.h", + "//ios/web_view/public/cwv_flags.h", + "//ios/web_view/public/cwv_html_element.h", + "//ios/web_view/public/cwv_global_state.h", + "//ios/web_view/public/cwv_identity.h", + "//ios/web_view/public/cwv_leak_check_credential.h", + "//ios/web_view/public/cwv_leak_check_service.h", + "//ios/web_view/public/cwv_leak_check_service_observer.h", + "//ios/web_view/public/cwv_lookalike_url_handler.h", + "//ios/web_view/public/cwv_metrics_provider.h", + "//ios/web_view/public/cwv_navigation_action.h", + "//ios/web_view/public/cwv_navigation_delegate.h", + "//ios/web_view/public/cwv_navigation_response.h", + "//ios/web_view/public/cwv_navigation_type.h", + "//ios/web_view/public/cwv_password.h", + "//ios/web_view/public/cwv_preferences.h", + "//ios/web_view/public/cwv_preview_element_info.h", + "//ios/web_view/public/cwv_reuse_check_service.h", + "//ios/web_view/public/cwv_ssl_error_handler.h", + "//ios/web_view/public/cwv_ssl_status.h", + "//ios/web_view/public/cwv_suggestion_type.h", + "//ios/web_view/public/cwv_sync_controller.h", + "//ios/web_view/public/cwv_sync_controller_data_source.h", + "//ios/web_view/public/cwv_sync_controller_delegate.h", + "//ios/web_view/public/cwv_sync_errors.h", + "//ios/web_view/public/cwv_translation_controller.h", + "//ios/web_view/public/cwv_translation_controller_delegate.h", + "//ios/web_view/public/cwv_translation_language.h", + "//ios/web_view/public/cwv_translation_language_detection_details.h", + "//ios/web_view/public/cwv_translation_policy.h", + "//ios/web_view/public/cwv_trusted_vault_observer.h", + "//ios/web_view/public/cwv_trusted_vault_provider.h", + "//ios/web_view/public/cwv_trusted_vault_utils.h", + "//ios/web_view/public/cwv_ui_delegate.h", + "//ios/web_view/public/cwv_unsafe_url_handler.h", + "//ios/web_view/public/cwv_user_content_controller.h", + "//ios/web_view/public/cwv_user_script.h", + "//ios/web_view/public/cwv_weak_check_utils.h", + "//ios/web_view/public/cwv_web_view.h", + "//ios/web_view/public/cwv_web_view_configuration.h", + "//ios/web_view/public/cwv_x509_certificate.h", +] + +ios_web_view_sources = [ + "//ios/web_view/internal/affiliations/web_view_affiliation_service_factory.h", + "//ios/web_view/internal/affiliations/web_view_affiliation_service_factory.mm", + "//ios/web_view/internal/app/application_context.h", + "//ios/web_view/internal/app/application_context.mm", + "//ios/web_view/internal/app/web_view_io_thread.h", + "//ios/web_view/internal/app/web_view_io_thread.mm", + "//ios/web_view/internal/autofill/cwv_autofill_client_ios_bridge.h", + "//ios/web_view/internal/autofill/cwv_autofill_controller+testing.h", + "//ios/web_view/internal/autofill/cwv_autofill_controller.mm", + "//ios/web_view/internal/autofill/cwv_autofill_controller_internal.h", + "//ios/web_view/internal/autofill/cwv_autofill_data_manager.mm", + "//ios/web_view/internal/autofill/cwv_autofill_data_manager_internal.h", + "//ios/web_view/internal/autofill/cwv_autofill_form.mm", + "//ios/web_view/internal/autofill/cwv_autofill_form_internal.h", + "//ios/web_view/internal/autofill/cwv_autofill_prefs.h", + "//ios/web_view/internal/autofill/cwv_autofill_prefs.mm", + "//ios/web_view/internal/autofill/cwv_autofill_profile.mm", + "//ios/web_view/internal/autofill/cwv_autofill_profile_internal.h", + "//ios/web_view/internal/autofill/cwv_autofill_suggestion.mm", + "//ios/web_view/internal/autofill/cwv_autofill_suggestion_internal.h", + "//ios/web_view/internal/autofill/cwv_credit_card.mm", + "//ios/web_view/internal/autofill/cwv_credit_card_internal.h", + "//ios/web_view/internal/autofill/cwv_credit_card_saver.mm", + "//ios/web_view/internal/autofill/cwv_credit_card_saver_internal.h", + "//ios/web_view/internal/autofill/cwv_credit_card_verifier.mm", + "//ios/web_view/internal/autofill/cwv_credit_card_verifier_internal.h", + "//ios/web_view/internal/autofill/cwv_password_affiliation.h", + "//ios/web_view/internal/autofill/cwv_password_affiliation.mm", + "//ios/web_view/internal/autofill/ios_web_view_payments_autofill_client.h", + "//ios/web_view/internal/autofill/ios_web_view_payments_autofill_client.mm", + "//ios/web_view/internal/autofill/web_view_autocomplete_history_manager_factory.h", + "//ios/web_view/internal/autofill/web_view_autocomplete_history_manager_factory.mm", + "//ios/web_view/internal/autofill/web_view_autofill_client_ios.h", + "//ios/web_view/internal/autofill/web_view_autofill_client_ios.mm", + "//ios/web_view/internal/autofill/web_view_autofill_log_router_factory.h", + "//ios/web_view/internal/autofill/web_view_autofill_log_router_factory.mm", + "//ios/web_view/internal/autofill/web_view_personal_data_manager_factory.h", + "//ios/web_view/internal/autofill/web_view_personal_data_manager_factory.mm", + "//ios/web_view/internal/autofill/web_view_strike_database_factory.h", + "//ios/web_view/internal/autofill/web_view_strike_database_factory.mm", + "//ios/web_view/internal/browser_state_keyed_service_factories.h", + "//ios/web_view/internal/browser_state_keyed_service_factories.mm", + "//ios/web_view/internal/browser_state_prefs.h", + "//ios/web_view/internal/browser_state_prefs.mm", + "//ios/web_view/internal/component_updater/web_view_component_updater_configurator.h", + "//ios/web_view/internal/component_updater/web_view_component_updater_configurator.mm", + "//ios/web_view/internal/cwv_back_forward_list.mm", + "//ios/web_view/internal/cwv_back_forward_list_internal.h", + "//ios/web_view/internal/cwv_back_forward_list_item.mm", + "//ios/web_view/internal/cwv_back_forward_list_item_internal.h", + "//ios/web_view/internal/cwv_download_task.mm", + "//ios/web_view/internal/cwv_download_task_internal.h", + "//ios/web_view/internal/cwv_favicon.mm", + "//ios/web_view/internal/cwv_favicon_internal.h", + "//ios/web_view/internal/cwv_find_in_page_controller.mm", + "//ios/web_view/internal/cwv_find_in_page_controller_internal.h", + "//ios/web_view/internal/cwv_flags.mm", + "//ios/web_view/internal/cwv_flags_internal.h", + "//ios/web_view/internal/cwv_global_state_internal.h", + "//ios/web_view/internal/cwv_html_element.mm", + "//ios/web_view/internal/cwv_html_element_internal.h", + "//ios/web_view/internal/cwv_lookalike_url_handler.mm", + "//ios/web_view/internal/cwv_lookalike_url_handler_internal.h", + "//ios/web_view/internal/cwv_navigation_action.mm", + "//ios/web_view/internal/cwv_navigation_action_internal.h", + "//ios/web_view/internal/cwv_navigation_response.mm", + "//ios/web_view/internal/cwv_navigation_response_internal.h", + "//ios/web_view/internal/cwv_navigation_type.mm", + "//ios/web_view/internal/cwv_navigation_type_internal.h", + "//ios/web_view/internal/cwv_omnibox_input.mm", + "//ios/web_view/internal/cwv_preferences.mm", + "//ios/web_view/internal/cwv_preferences_internal.h", + "//ios/web_view/internal/cwv_preview_element_info.mm", + "//ios/web_view/internal/cwv_preview_element_info_internal.h", + "//ios/web_view/internal/cwv_ssl_error_handler.mm", + "//ios/web_view/internal/cwv_ssl_error_handler_internal.h", + "//ios/web_view/internal/cwv_ssl_status.mm", + "//ios/web_view/internal/cwv_ssl_status_internal.h", + "//ios/web_view/internal/cwv_ssl_util.h", + "//ios/web_view/internal/cwv_ssl_util.mm", + "//ios/web_view/internal/cwv_user_content_controller.mm", + "//ios/web_view/internal/cwv_user_content_controller_internal.h", + "//ios/web_view/internal/cwv_user_script.mm", + "//ios/web_view/internal/cwv_web_view.mm", + "//ios/web_view/internal/cwv_web_view_configuration.mm", + "//ios/web_view/internal/cwv_web_view_configuration_internal.h", + "//ios/web_view/internal/cwv_web_view_internal.h", + "//ios/web_view/internal/cwv_x509_certificate.mm", + "//ios/web_view/internal/cwv_x509_certificate_internal.h", + "//ios/web_view/internal/js_messaging/web_view_scripts_java_script_feature.h", + "//ios/web_view/internal/js_messaging/web_view_scripts_java_script_feature.mm", + "//ios/web_view/internal/language/web_view_accept_languages_service_factory.h", + "//ios/web_view/internal/language/web_view_accept_languages_service_factory.mm", + "//ios/web_view/internal/language/web_view_language_model_manager_factory.h", + "//ios/web_view/internal/language/web_view_language_model_manager_factory.mm", + "//ios/web_view/internal/language/web_view_url_language_histogram_factory.h", + "//ios/web_view/internal/language/web_view_url_language_histogram_factory.mm", + "//ios/web_view/internal/metrics/cwv_metrics_provider.mm", + "//ios/web_view/internal/metrics/cwv_metrics_provider_internal.h", + "//ios/web_view/internal/passwords/cwv_credential_provider_extension_utils.mm", + "//ios/web_view/internal/passwords/cwv_leak_check_credential.mm", + "//ios/web_view/internal/passwords/cwv_leak_check_credential_internal.h", + "//ios/web_view/internal/passwords/cwv_leak_check_service.mm", + "//ios/web_view/internal/passwords/cwv_leak_check_service_internal.h", + "//ios/web_view/internal/passwords/cwv_password.mm", + "//ios/web_view/internal/passwords/cwv_password_internal.h", + "//ios/web_view/internal/passwords/cwv_reuse_check_service.mm", + "//ios/web_view/internal/passwords/cwv_reuse_check_service_internal.h", + "//ios/web_view/internal/passwords/cwv_weak_check_utils.mm", + "//ios/web_view/internal/passwords/cwv_weak_check_utils_internal.h", + "//ios/web_view/internal/passwords/web_view_account_password_store_factory.h", + "//ios/web_view/internal/passwords/web_view_account_password_store_factory.mm", + "//ios/web_view/internal/passwords/web_view_bulk_leak_check_service_factory.h", + "//ios/web_view/internal/passwords/web_view_bulk_leak_check_service_factory.mm", + "//ios/web_view/internal/passwords/web_view_password_feature_manager.h", + "//ios/web_view/internal/passwords/web_view_password_feature_manager.mm", + "//ios/web_view/internal/passwords/web_view_password_manager_client.h", + "//ios/web_view/internal/passwords/web_view_password_manager_client.mm", + "//ios/web_view/internal/passwords/web_view_password_manager_log_router_factory.h", + "//ios/web_view/internal/passwords/web_view_password_manager_log_router_factory.mm", + "//ios/web_view/internal/passwords/web_view_password_requirements_service_factory.h", + "//ios/web_view/internal/passwords/web_view_password_requirements_service_factory.mm", + "//ios/web_view/internal/passwords/web_view_password_reuse_manager_factory.h", + "//ios/web_view/internal/passwords/web_view_password_reuse_manager_factory.mm", + "//ios/web_view/internal/passwords/web_view_profile_password_store_factory.h", + "//ios/web_view/internal/passwords/web_view_profile_password_store_factory.mm", + "//ios/web_view/internal/safe_browsing/cwv_unsafe_url_handler.mm", + "//ios/web_view/internal/safe_browsing/cwv_unsafe_url_handler_internal.h", + "//ios/web_view/internal/safe_browsing/web_view_safe_browsing_client.h", + "//ios/web_view/internal/safe_browsing/web_view_safe_browsing_client.mm", + "//ios/web_view/internal/safe_browsing/web_view_safe_browsing_client_factory.h", + "//ios/web_view/internal/safe_browsing/web_view_safe_browsing_client_factory.mm", + "//ios/web_view/internal/safe_browsing/web_view_safe_browsing_helper_factory.h", + "//ios/web_view/internal/safe_browsing/web_view_safe_browsing_helper_factory.mm", + "//ios/web_view/internal/signin/account_capabilities_fetcher_factory_ios_web_view.h", + "//ios/web_view/internal/signin/account_capabilities_fetcher_factory_ios_web_view.mm", + "//ios/web_view/internal/signin/account_capabilities_fetcher_ios_web_view.h", + "//ios/web_view/internal/signin/account_capabilities_fetcher_ios_web_view.mm", + "//ios/web_view/internal/signin/cwv_identity.mm", + "//ios/web_view/internal/signin/ios_web_view_signin_client.h", + "//ios/web_view/internal/signin/ios_web_view_signin_client.mm", + "//ios/web_view/internal/signin/web_view_device_accounts_provider_impl.h", + "//ios/web_view/internal/signin/web_view_device_accounts_provider_impl.mm", + "//ios/web_view/internal/signin/web_view_gaia_auth_fetcher.h", + "//ios/web_view/internal/signin/web_view_gaia_auth_fetcher.mm", + "//ios/web_view/internal/signin/web_view_identity_manager_factory.h", + "//ios/web_view/internal/signin/web_view_identity_manager_factory.mm", + "//ios/web_view/internal/signin/web_view_signin_client_factory.h", + "//ios/web_view/internal/signin/web_view_signin_client_factory.mm", + "//ios/web_view/internal/sync/cwv_sync_controller.mm", + "//ios/web_view/internal/sync/cwv_sync_controller_internal.h", + "//ios/web_view/internal/sync/cwv_trusted_vault_observer.mm", + "//ios/web_view/internal/sync/cwv_trusted_vault_observer_internal.h", + "//ios/web_view/internal/sync/cwv_trusted_vault_utils.mm", + "//ios/web_view/internal/sync/web_view_data_type_store_service_factory.h", + "//ios/web_view/internal/sync/web_view_data_type_store_service_factory.mm", + "//ios/web_view/internal/sync/web_view_device_info_sync_service_factory.h", + "//ios/web_view/internal/sync/web_view_device_info_sync_service_factory.mm", + "//ios/web_view/internal/sync/web_view_gcm_profile_service_factory.h", + "//ios/web_view/internal/sync/web_view_gcm_profile_service_factory.mm", + "//ios/web_view/internal/sync/web_view_instance_id_profile_service_factory.h", + "//ios/web_view/internal/sync/web_view_instance_id_profile_service_factory.mm", + "//ios/web_view/internal/sync/web_view_profile_invalidation_provider_factory.h", + "//ios/web_view/internal/sync/web_view_profile_invalidation_provider_factory.mm", + "//ios/web_view/internal/sync/web_view_sync_client.h", + "//ios/web_view/internal/sync/web_view_sync_client.mm", + "//ios/web_view/internal/sync/web_view_sync_invalidations_service_factory.h", + "//ios/web_view/internal/sync/web_view_sync_invalidations_service_factory.mm", + "//ios/web_view/internal/sync/web_view_sync_service_factory.h", + "//ios/web_view/internal/sync/web_view_sync_service_factory.mm", + "//ios/web_view/internal/sync/web_view_trusted_vault_client.h", + "//ios/web_view/internal/sync/web_view_trusted_vault_client.mm", + "//ios/web_view/internal/translate/cwv_translation_controller.mm", + "//ios/web_view/internal/translate/cwv_translation_controller_internal.h", + "//ios/web_view/internal/translate/cwv_translation_language.mm", + "//ios/web_view/internal/translate/cwv_translation_language_detection_details.mm", + "//ios/web_view/internal/translate/cwv_translation_language_detection_details_internal.h", + "//ios/web_view/internal/translate/cwv_translation_language_internal.h", + "//ios/web_view/internal/translate/cwv_translation_policy.mm", + "//ios/web_view/internal/translate/web_view_translate_client.h", + "//ios/web_view/internal/translate/web_view_translate_client.mm", + "//ios/web_view/internal/translate/web_view_translate_ranker_factory.h", + "//ios/web_view/internal/translate/web_view_translate_ranker_factory.mm", + "//ios/web_view/internal/translate/web_view_translate_service.h", + "//ios/web_view/internal/translate/web_view_translate_service.mm", + "//ios/web_view/internal/utils/nsobject_description_utils.h", + "//ios/web_view/internal/utils/nsobject_description_utils.mm", + "//ios/web_view/internal/web_view_browser_state.h", + "//ios/web_view/internal/web_view_browser_state.mm", + "//ios/web_view/internal/web_view_download_manager.h", + "//ios/web_view/internal/web_view_download_manager.mm", + "//ios/web_view/internal/web_view_java_script_dialog_presenter.h", + "//ios/web_view/internal/web_view_java_script_dialog_presenter.mm", + "//ios/web_view/internal/web_view_message_handler_java_script_feature.h", + "//ios/web_view/internal/web_view_message_handler_java_script_feature.mm", + "//ios/web_view/internal/web_view_url_request_context_getter.h", + "//ios/web_view/internal/web_view_url_request_context_getter.mm", + "//ios/web_view/internal/web_view_web_client.h", + "//ios/web_view/internal/web_view_web_client.mm", + "//ios/web_view/internal/web_view_web_main_delegate.h", + "//ios/web_view/internal/web_view_web_main_delegate.mm", + "//ios/web_view/internal/web_view_web_main_parts.h", + "//ios/web_view/internal/web_view_web_main_parts.mm", + "//ios/web_view/internal/web_view_web_state_policy_decider.h", + "//ios/web_view/internal/web_view_web_state_policy_decider.mm", + "//ios/web_view/internal/webdata_services/web_view_web_data_service_wrapper_factory.h", + "//ios/web_view/internal/webdata_services/web_view_web_data_service_wrapper_factory.mm", + "//ios/web_view/internal/webui/web_view_sync_internals_ui.h", + "//ios/web_view/internal/webui/web_view_sync_internals_ui.mm", + "//ios/web_view/internal/webui/web_view_web_ui_ios_controller_factory.h", + "//ios/web_view/internal/webui/web_view_web_ui_ios_controller_factory.mm", + "//ios/web_view/internal/webui/web_view_web_ui_provider.mm", +] + +ios_web_view_deps = [ + "//base", + "//components/affiliations/core/browser:affiliations", + "//components/autofill/core/browser", + "//components/autofill/core/common", + "//components/autofill/ios/browser", + "//components/autofill/ios/browser:util", + "//components/autofill/ios/form_util", + "//components/autofill/ios/form_util:form_handler_feature", + "//components/autofill/ios/form_util:programmatic_form_submission_handler_feature", + "//components/browser_sync", + "//components/component_updater", + "//components/component_updater/installer_policies", + "//components/gcm_driver", + "//components/history/core/common", + "//components/image_fetcher/ios", + "//components/infobars/core", + "//components/invalidation", + "//components/invalidation:legacy_topics_cleanup", + "//components/keyed_service/core", + "//components/keyed_service/ios", + "//components/language/core/browser", + "//components/language/core/common", + "//components/language/core/language_model", + "//components/language/ios/browser", + "//components/leveldb_proto", + "//components/lookalikes/core", + "//components/metrics:library_support", + "//components/metrics/demographics", + "//components/omnibox/browser:location_bar", + "//components/os_crypt/async/browser", + "//components/password_manager/core/browser", + "//components/password_manager/core/browser/affiliation:affiliation_fetching", + "//components/password_manager/core/browser/affiliation:affiliation_match_helper", + "//components/password_manager/core/browser/features:password_features", + "//components/password_manager/core/browser/generation:core", + "//components/password_manager/core/browser/leak_detection", + "//components/password_manager/core/browser/sharing", + "//components/password_manager/core/common", + "//components/password_manager/ios", + "//components/plus_addresses/core/browser/settings", + "//components/plus_addresses/core/browser/webdata", + "//components/pref_registry", + "//components/prefs", + "//components/profile_metrics", + "//components/proxy_config", + "//components/safe_browsing/core/common:safe_browsing_prefs", + "//components/safe_browsing/ios/browser:allow_list", + "//components/security_interstitials/core:unsafe_resource", + "//components/security_state/ios", + "//components/services/patch:in_process", + "//components/services/unzip:in_process", + "//components/sessions:session_id", + "//components/signin/core/browser", + "//components/signin/internal/identity_manager", + "//components/signin/ios/browser", + "//components/signin/public/base", + "//components/signin/public/identity_manager", + "//components/signin/public/identity_manager/ios", + "//components/signin/public/webdata", + "//components/ssl_errors", + "//components/strings", + "//components/sync", + "//components/sync/invalidations", + "//components/sync_device_info", + "//components/translate/core/browser", + "//components/translate/core/common", + "//components/translate/ios/browser", + "//components/trusted_vault", + "//components/unified_consent", + "//components/update_client", + "//components/update_client:common_impl", + "//components/url_formatter", + "//components/variations", + "//components/variations/net", + "//components/version_info", + "//components/version_info:version_string", + "//components/web_resource", + "//components/webdata_services", + "//components/webui/flags", + "//components/webui/flags:switches", + "//google_apis", + "//ios/components/credential_provider_extension:password_spec_fetcher", + "//ios/components/credential_provider_extension:password_util", + "//ios/components/io_thread", + "//ios/components/security_interstitials", + "//ios/components/security_interstitials/https_only_mode:feature", + "//ios/components/security_interstitials/lookalikes", + "//ios/components/security_interstitials/safe_browsing", + "//ios/components/security_interstitials/safe_browsing:util", + "//ios/components/webui:provider", + "//ios/components/webui:url_constants", + "//ios/components/webui/sync_internals", + "//ios/net", + "//ios/third_party/webkit", + "//ios/web/common", + "//ios/web/common:user_agent", + "//ios/web/navigation:wk_navigation_util", + "//ios/web/public", + "//ios/web/public/browsing_data", + "//ios/web/public/download", + "//ios/web/public/find_in_page", + "//ios/web/public/init", + "//ios/web/public/js_messaging", + "//ios/web/public/security", + "//ios/web/public/session", + "//ios/web/public/session/proto", + "//ios/web/public/web_view_only", + "//ios/web/public/webui", + "//ios/web/web_state/ui:wk_web_view_configuration_provider_header", + "//ios/web/webui", + "//ios/web_view/internal/js_messaging:cwv_messaging_js", + "//ios/web_view/resources", + "//net", + "//net:extras", + "//services/metrics/public/cpp:metrics_cpp", + "//services/network:network_service", + "//ui/base", + "//ui/display", + "//url", +]
diff --git a/ios/web_view/resources/BUILD.gn b/ios/web_view/resources/BUILD.gn new file mode 100644 index 0000000..f4e6dca --- /dev/null +++ b/ios/web_view/resources/BUILD.gn
@@ -0,0 +1,64 @@ +# 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/web_view/resources/repack.gni") +import("//tools/grit/repack.gni") + +group("resources") { + visibility = [ "//ios/web_view:*" ] + deps = [ + ":repack_locales", + ":repack_resources", + ":repack_scalable_resources", + ] +} + +repack_locales("repack_locales") { + visibility = [ ":resources" ] + source_patterns = [ + "${root_gen_dir}/components/strings/components_strings_", + "${root_gen_dir}/components/strings/components_locale_settings_", + "${root_gen_dir}/ui/strings/app_locale_settings_", + "${root_gen_dir}/ui/strings/ax_strings_", + "${root_gen_dir}/ui/strings/ui_strings_", + ] + + deps = [ + "//components/strings:components_locale_settings", + "//components/strings:components_strings", + "//ui/strings:app_locale_settings", + "//ui/strings:ax_strings", + "//ui/strings:ui_strings", + ] + input_locales = platform_pak_locales + output_locales = locales_as_apple_outputs + copy_data_to_bundle = true +} + +repack("repack_resources") { + visibility = [ ":resources" ] + deps = [ + "//components/resources:components_resources", + "//components/sync/service/resources", + "//ios/web:resources", + "//ui/webui/resources", + ] + sources = [ + "$root_gen_dir/components/components_resources.pak", + "$root_gen_dir/components/sync_service_sync_internals_resources.pak", + "$root_gen_dir/ios/web/ios_web_resources.pak", + "$root_gen_dir/ui/webui/resources/webui_resources.pak", + ] + output = "$target_gen_dir/web_view_resources.pak" + copy_data_to_bundle = true +} + +ios_web_view_repack_all_scales("repack_scalable_resources") { + visibility = [ ":resources" ] + scales = [ + "100", + "200", + "300", + ] +}
diff --git a/ios/web_view/repack.gni b/ios/web_view/resources/repack.gni similarity index 100% rename from ios/web_view/repack.gni rename to ios/web_view/resources/repack.gni
diff --git a/ios/web_view/test/BUILD.gn b/ios/web_view/test/BUILD.gn index 975e0dc..38944fa 100644 --- a/ios/web_view/test/BUILD.gn +++ b/ios/web_view/test/BUILD.gn
@@ -6,6 +6,10 @@ import("//ios/build/config.gni") import("//testing/test.gni") +config("unittest_config") { + defines = [ "CWV_UNIT_TEST" ] +} + source_set("inttests") { testonly = true @@ -68,3 +72,104 @@ "//ui/base", ] } + +source_set("run_all_unittests") { + testonly = true + sources = [ "run_all_unittests.cc" ] + deps = [ + "//base", + "//base/test:test_support", + "//mojo/core/embedder", + ] +} + +test("ios_web_view_unittests") { + testonly = true + sources = [ + "../internal/autofill/cwv_autofill_controller_unittest.mm", + "../internal/autofill/cwv_autofill_data_manager_unittest.mm", + "../internal/autofill/cwv_autofill_form_unittest.mm", + "../internal/autofill/cwv_autofill_profile_unittest.mm", + "../internal/autofill/cwv_autofill_suggestion_unittest.mm", + "../internal/autofill/cwv_credit_card_saver_unittest.mm", + "../internal/autofill/cwv_credit_card_unittest.mm", + "../internal/autofill/cwv_credit_card_verifier_unittest.mm", + "../internal/cwv_download_task_unittest.mm", + "../internal/cwv_favicon_unittest.mm", + "../internal/cwv_flags_unittest.mm", + "../internal/cwv_global_state.mm", + "../internal/cwv_html_element_unittest.mm", + "../internal/cwv_lookalike_url_handler_unittest.mm", + "../internal/cwv_omnibox_input_unittest.mm", + "../internal/cwv_preferences_unittest.mm", + "../internal/cwv_preview_element_info_unittest.mm", + "../internal/cwv_ssl_error_handler_unittest.mm", + "../internal/cwv_ssl_status_unittest.mm", + "../internal/cwv_web_view_configuration_internal_unittest.mm", + "../internal/cwv_web_view_unittest.mm", + "../internal/cwv_x509_certificate_unittest.mm", + "../internal/metrics/cwv_metrics_provider_unittest.mm", + "../internal/passwords/cwv_credential_provider_extension_utils_unittest.mm", + "../internal/passwords/cwv_leak_check_credential_unittest.mm", + "../internal/passwords/cwv_leak_check_service_unittest.mm", + "../internal/passwords/cwv_password_unittest.mm", + "../internal/passwords/cwv_reuse_check_service_unittest.mm", + "../internal/passwords/cwv_weak_check_utils_unittest.mm", + "../internal/passwords/web_view_password_manager_client_unittest.mm", + "../internal/safe_browsing/cwv_unsafe_url_handler_unittest.mm", + "../internal/signin/account_capabilities_fetcher_ios_web_view_unittest.mm", + "../internal/signin/cwv_identity_unittest.mm", + "../internal/signin/web_view_device_accounts_provider_impl_unittest.mm", + "../internal/signin/web_view_gaia_auth_fetcher_unittest.mm", + "../internal/sync/cwv_sync_controller_unittest.mm", + "../internal/sync/cwv_trusted_vault_observer_unittest.mm", + "../internal/translate/cwv_translation_controller_unittest.mm", + "../internal/translate/cwv_translation_language_unittest.mm", + "../internal/translate/cwv_translation_policy_unittest.mm", + "../internal/web_view_web_client_unittest.mm", + ] + + configs += [ ":unittest_config" ] + + deps = [ + ":run_all_unittests", + ":test_support", + "//base/test:test_support", + "//components/affiliations/core/browser:test_support", + "//components/autofill/core/browser:test_support", + "//components/autofill/ios/browser:test_support", + "//components/autofill/ios/form_util:test_support", + "//components/language_detection/core", + "//components/password_manager/core/browser:test_support", + "//components/password_manager/core/browser/leak_detection:test_support", + "//components/prefs:test_support", + "//components/signin/public/base:test_support", + "//components/signin/public/identity_manager:test_support", + "//components/sync:test_support", + "//components/sync_device_info:test_support", + "//components/translate/core/browser:test_support", + "//components/translate/core/language_detection", + "//ios/web/common:uikit", + "//ios/web/common:web_view_creation_util", + "//ios/web/public/js_messaging", + "//ios/web/public/security", + "//ios/web/public/test", + "//ios/web/public/test:test_fixture", + "//ios/web_view:web_view_sources", + "//net:test_support", + "//testing/gtest", + "//third_party/ocmock", + ] + + assert_no_deps = ios_assert_no_deps +} + +test("ios_web_view_inttests") { + testonly = true + + deps = [ ":inttests" ] + + bundle_deps = [ "//ios/web_view:web_view+bundle" ] + + assert_no_deps = ios_assert_no_deps +}
diff --git a/ios_internal b/ios_internal index c3935b3..695ab190 160000 --- a/ios_internal +++ b/ios_internal
@@ -1 +1 @@ -Subproject commit c3935b3d5c33aad75608bd4ce39545d47b8d5b24 +Subproject commit 695ab1904c1b36f5a5e9864c0304ac499a0007ff
diff --git a/media/cdm/library_cdm/clear_key_cdm/cdm_file_adapter.cc b/media/cdm/library_cdm/clear_key_cdm/cdm_file_adapter.cc index f20350b..17a4015 100644 --- a/media/cdm/library_cdm/clear_key_cdm/cdm_file_adapter.cc +++ b/media/cdm/library_cdm/clear_key_cdm/cdm_file_adapter.cc
@@ -35,9 +35,9 @@ } CdmFileAdapter::~CdmFileAdapter() { - DCHECK(!open_cb_); - DCHECK(!read_cb_); - DCHECK(!write_cb_); + CHECK(!open_cb_); + CHECK(!read_cb_); + CHECK(!write_cb_); file_io_->Close(); }
diff --git a/media/cdm/library_cdm/clear_key_cdm/cdm_video_decoder.cc b/media/cdm/library_cdm/clear_key_cdm/cdm_video_decoder.cc index 3ebeebc..73eb1fe 100644 --- a/media/cdm/library_cdm/clear_key_cdm/cdm_video_decoder.cc +++ b/media/cdm/library_cdm/clear_key_cdm/cdm_video_decoder.cc
@@ -71,7 +71,7 @@ bool ToCdmVideoFrame(const VideoFrame& video_frame, CdmHostProxy* cdm_host_proxy, CdmVideoDecoder::CdmVideoFrame* cdm_video_frame) { - DCHECK(cdm_video_frame); + CHECK(cdm_video_frame); if (!video_frame.IsMappable()) { DVLOG(1) << "VideoFrame is not mappable"; @@ -179,7 +179,7 @@ std::unique_ptr<VideoDecoder> video_decoder) : cdm_host_proxy_(cdm_host_proxy), video_decoder_(std::move(video_decoder)) { - DCHECK(cdm_host_proxy_); + CHECK(cdm_host_proxy_); } VideoDecoderAdapter(const VideoDecoderAdapter&) = delete; @@ -191,7 +191,7 @@ DecoderStatus Initialize(const cdm::VideoDecoderConfig_3& config) final { auto clear_config = ToClearMediaVideoDecoderConfig(config); DVLOG(1) << __func__ << ": " << clear_config.AsHumanReadableString(); - DCHECK(!last_init_result_.has_value()); + CHECK(!last_init_result_.has_value()); // Initialize |video_decoder_| and wait for completion. base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed); @@ -231,7 +231,7 @@ cdm::Status Decode(scoped_refptr<DecoderBuffer> buffer, CdmVideoFrame* decoded_frame) final { DVLOG(3) << __func__; - DCHECK(!last_decode_status_.has_value()); + CHECK(!last_decode_status_.has_value()); // Call |video_decoder_| Decode() and wait for completion. base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed); @@ -265,7 +265,7 @@ private: void OnInitialized(base::OnceClosure quit_closure, DecoderStatus status) { DVLOG(1) << __func__ << " success = " << status.is_ok(); - DCHECK(!last_init_result_.has_value()); + CHECK(!last_init_result_.has_value()); last_init_result_ = std::move(status); std::move(quit_closure).Run(); } @@ -285,7 +285,7 @@ } void OnDecoded(base::OnceClosure quit_closure, DecoderStatus decode_status) { - DCHECK(!last_decode_status_.has_value()); + CHECK(!last_decode_status_.has_value()); last_decode_status_ = std::move(decode_status); std::move(quit_closure).Run(); }
diff --git a/media/cdm/library_cdm/clear_key_cdm/clear_key_cdm.cc b/media/cdm/library_cdm/clear_key_cdm/clear_key_cdm.cc index 3d7b4021..d819346 100644 --- a/media/cdm/library_cdm/clear_key_cdm/clear_key_cdm.cc +++ b/media/cdm/library_cdm/clear_key_cdm/clear_key_cdm.cc
@@ -72,7 +72,7 @@ static scoped_refptr<media::DecoderBuffer> CopyDecoderBufferFrom( const cdm::InputBuffer_2& input_buffer) { if (!input_buffer.data) { - DCHECK(!input_buffer.data_size); + CHECK(!input_buffer.data_size); return media::DecoderBuffer::CreateEOSBuffer(); } @@ -348,7 +348,7 @@ base::BindRepeating(&ClearKeyCdm::OnSessionExpirationUpdate, base::Unretained(this)))), key_system_(key_system) { - DCHECK(g_is_cdm_module_initialized); + CHECK(g_is_cdm_module_initialized); } ClearKeyCdm::~ClearKeyCdm() = default; @@ -425,7 +425,7 @@ uint32_t session_id_length) { DVLOG(1) << __func__; DCHECK_EQ(session_type, cdm::kPersistentLicense); - DCHECK(allow_persistent_state_); + CHECK(allow_persistent_state_); std::string web_session_str(session_id, session_id_length); auto promise = std::make_unique<CdmCallbackPromise<std::string>>( @@ -541,7 +541,7 @@ void ClearKeyCdm::TimerExpired(void* context) { DVLOG(1) << __func__; - DCHECK(has_set_timer_); + CHECK(has_set_timer_); std::string renewal_message; if (key_system_ == kExternalClearKeyMessageTypeTestKeySystem) { @@ -575,7 +575,7 @@ cdm::Status ClearKeyCdm::Decrypt(const cdm::InputBuffer_2& encrypted_buffer, cdm::DecryptedBlock* decrypted_block) { DVLOG(1) << __func__; - DCHECK(encrypted_buffer.data); + CHECK(encrypted_buffer.data); scoped_refptr<DecoderBuffer> buffer; cdm::Status status = DecryptToMediaDecoderBuffer(encrypted_buffer, &buffer); @@ -585,7 +585,7 @@ } auto buffer_span = base::span(*buffer); - DCHECK(!buffer_span.empty()); + CHECK(!buffer_span.empty()); decrypted_block->SetDecryptedBuffer( cdm_host_proxy_->Allocate(buffer_span.size())); memcpy(reinterpret_cast<void*>(decrypted_block->DecryptedBuffer()->Data()), @@ -758,7 +758,7 @@ cdm::Status ClearKeyCdm::DecryptToMediaDecoderBuffer( const cdm::InputBuffer_2& encrypted_buffer, scoped_refptr<DecoderBuffer>* decrypted_buffer) { - DCHECK(decrypted_buffer); + CHECK(decrypted_buffer); scoped_refptr<DecoderBuffer> buffer = CopyDecoderBufferFrom(encrypted_buffer);
diff --git a/media/cdm/library_cdm/clear_key_cdm/clear_key_persistent_session_cdm.cc b/media/cdm/library_cdm/clear_key_cdm/clear_key_persistent_session_cdm.cc index 368876d..41299f7 100644 --- a/media/cdm/library_cdm/clear_key_cdm/clear_key_persistent_session_cdm.cc +++ b/media/cdm/library_cdm/clear_key_cdm/clear_key_persistent_session_cdm.cc
@@ -341,7 +341,7 @@ std::unique_ptr<CdmFileAdapter> file, std::unique_ptr<SimpleCdmPromise> promise, bool success) { - DCHECK(success); + CHECK(success); } CdmContext* ClearKeyPersistentSessionCdm::GetCdmContext() {
diff --git a/media/cdm/library_cdm/clear_key_cdm/ffmpeg_cdm_audio_decoder.cc b/media/cdm/library_cdm/clear_key_cdm/ffmpeg_cdm_audio_decoder.cc index 0213ea3..771754b4 100644 --- a/media/cdm/library_cdm/clear_key_cdm/ffmpeg_cdm_audio_decoder.cc +++ b/media/cdm/library_cdm/clear_key_cdm/ffmpeg_cdm_audio_decoder.cc
@@ -258,7 +258,7 @@ } if (!output_timestamp_helper_->base_timestamp() && !is_end_of_stream) { - DCHECK(timestamp != kNoTimestamp); + CHECK(timestamp != kNoTimestamp); output_timestamp_helper_->SetBaseTimestamp(timestamp); }
diff --git a/media/cdm/library_cdm/mock_library_cdm.cc b/media/cdm/library_cdm/mock_library_cdm.cc index f46dbd4..02d2622 100644 --- a/media/cdm/library_cdm/mock_library_cdm.cc +++ b/media/cdm/library_cdm/mock_library_cdm.cc
@@ -29,7 +29,7 @@ } MockLibraryCdm::~MockLibraryCdm() { - DCHECK(g_mock_library_cdm); + CHECK(g_mock_library_cdm); g_mock_library_cdm = nullptr; } @@ -49,7 +49,7 @@ GetCdmHostFunc get_cdm_host_func, void* user_data) { DVLOG(1) << __func__; - DCHECK(!g_mock_library_cdm); + CHECK(!g_mock_library_cdm); std::string key_system_string(key_system, key_system_size);
diff --git a/net/cookies/cookie_util.cc b/net/cookies/cookie_util.cc index a9e4e448..702915b1 100644 --- a/net/cookies/cookie_util.cc +++ b/net/cookies/cookie_util.cc
@@ -690,7 +690,7 @@ : CookieAccessScheme::kNonCryptographic; } -bool IsDomainMatch(const std::string& domain, const std::string& host) { +bool IsDomainMatch(const std::string_view domain, const std::string_view host) { // Can domain match in two ways; as a domain cookie (where the cookie // domain begins with ".") or as a host cookie (where it doesn't). @@ -723,7 +723,7 @@ domain) == 0); } -bool IsOnPath(const std::string& cookie_path, const std::string& url_path) { +bool IsOnPath(const std::string_view cookie_path, const std::string_view url_path) { // A zero length would be unsafe for our trailing '/' checks, and // would also make no sense for our prefix match. The code that // creates a CanonicalCookie should make sure the path is never zero length,
diff --git a/net/cookies/cookie_util.h b/net/cookies/cookie_util.h index cbb7365..a8e1ac3 100644 --- a/net/cookies/cookie_util.h +++ b/net/cookies/cookie_util.h
@@ -250,15 +250,15 @@ // |domain| is the output of cookie.Domain() for some cookie. This returns true // if a |domain| indicates that the cookie can be accessed by |host|. // See comment on CanonicalCookie::IsDomainMatch(). -NET_EXPORT bool IsDomainMatch(const std::string& domain, - const std::string& host); +NET_EXPORT bool IsDomainMatch(const std::string_view domain, + const std::string_view host); // Returns true if the given |url_path| path-matches |cookie_path| // as described in section 5.1.4 in RFC 6265. This returns true if |cookie_path| // and |url_path| are identical, or if |url_path| is a subdirectory of // |cookie_path|. -NET_EXPORT bool IsOnPath(const std::string& cookie_path, - const std::string& url_path); +NET_EXPORT bool IsOnPath(const std::string_view cookie_path, + const std::string_view url_path); // Returns the CookiePrefix (or COOKIE_PREFIX_NONE if none) that // applies to the given cookie |name|.
diff --git a/net/disk_cache/sql/sql_backend_impl.cc b/net/disk_cache/sql/sql_backend_impl.cc index 579434f4..0cf515c 100644 --- a/net/disk_cache/sql/sql_backend_impl.cc +++ b/net/disk_cache/sql/sql_backend_impl.cc
@@ -1003,6 +1003,10 @@ } void SqlBackendImpl::TriggerDeleteDoomedEntries() { + // TODO(crbug.com/443171275): Get information on whether a doomed entry + // exists when initializing SqlPersistentStore, and if it does not exist, do + // not execute TriggerDeleteDoomedEntries. + // TODO(crbug.com/443171275): Execute only when the browser is idle. exclusive_operation_coordinator_.PostOrRunExclusiveOperation(base::BindOnce( base::BindOnce(&SqlBackendImpl::HandleDeleteDoomedEntriesOperation, weak_factory_.GetWeakPtr())));
diff --git a/net/disk_cache/sql/sql_persistent_store.cc b/net/disk_cache/sql/sql_persistent_store.cc index 3e18be6..b5bf0f6 100644 --- a/net/disk_cache/sql/sql_persistent_store.cc +++ b/net/disk_cache/sql/sql_persistent_store.cc
@@ -27,6 +27,7 @@ #include "net/base/features.h" #include "net/base/io_buffer.h" #include "net/disk_cache/cache_util.h" +#include "net/disk_cache/sql/indexed_pair_set.h" #include "net/disk_cache/sql/sql_backend_constants.h" #include "net/disk_cache/sql/sql_persistent_store_queries.h" #include "sql/database.h" @@ -42,6 +43,23 @@ constexpr std::string_view kHistogramPrefix = "Net.SqlDiskCache.Backend."; +// These values are persisted to logs. Entries should not be renumbered and +// numeric values should never be reused. +// LINT.IfChange(IndexMismatchLocation) +enum class IndexMismatchLocation { + kOpenOrCreateEntry = 0, + kCreateEntry = 1, + kDoomEntry = 2, + kStartEviction = 3, + kDeleteLiveEntry = 4, + kDeleteLiveEntriesBetween = 5, + kMaxValue = kDeleteLiveEntriesBetween, +}; +// LINT.ThenChange(//tools/metrics/histograms/metadata/net/enums.xml:SqlDiskCacheIndexMismatchLocation) + +using HashResIdSet = + IndexedPairSet<CacheEntryKey::Hash, SqlPersistentStore::ResId>; + // Holds summary statistics about the cache store. struct StoreStatus { int32_t entry_count = 0; @@ -50,10 +68,14 @@ // The result of a successful initialization. struct InitResult { - explicit InitResult(int64_t max_bytes) : max_bytes(max_bytes) {} + InitResult(int64_t max_bytes, HashResIdSet&& index) + : max_bytes(max_bytes), index(std::move(index)) {} ~InitResult() = default; + InitResult(InitResult&& other) = default; + InitResult& operator=(InitResult&& other) = default; int64_t max_bytes = 0; + HashResIdSet index; }; // A helper struct to associate an IOBuffer with a starting offset. @@ -62,6 +84,19 @@ int64_t start; }; +// A helper struct to hold a resource ID and a cache entry key hash. +struct ResIdAndHashKey { + ResIdAndHashKey(SqlPersistentStore::ResId res_id, + CacheEntryKey::Hash key_hash) + : res_id(res_id), key_hash(key_hash) {} + ~ResIdAndHashKey() = default; + ResIdAndHashKey(ResIdAndHashKey&&) = default; + ResIdAndHashKey& operator=(ResIdAndHashKey&&) = default; + + SqlPersistentStore::ResId res_id; + CacheEntryKey::Hash key_hash; +}; + using disk_cache_sql_queries::GetQuery; using disk_cache_sql_queries::Query; @@ -75,6 +110,8 @@ SqlPersistentStore::OptionalEntryInfoWithIdAndKey; using IntOrError = SqlPersistentStore::IntOrError; using InitResultOrError = base::expected<InitResult, Error>; +using ResIdAndHashKeyList = std::vector<ResIdAndHashKey>; +using ResIdAndHashKeyListOrError = base::expected<ResIdAndHashKeyList, Error>; // A helper struct to bundle an operation's result with a flag indicating // whether an eviction check is needed. This allows the background sequence, @@ -100,8 +137,8 @@ using EntryInfoOrErrorAndEvictionRequested = ResultAndEvictionRequested<EntryInfoOrError>; using IntOrErrorAndEvictionRequested = ResultAndEvictionRequested<IntOrError>; - - +using ResIdAndHashKeyListOrErrorAndEvictionRequested = + ResultAndEvictionRequested<ResIdAndHashKeyListOrError>; bool IsBlobSizeValid(int64_t blob_start, int64_t blob_end, @@ -168,6 +205,10 @@ dict.Add("entry_info", "not found"); } } +void PopulateTraceDetails(const ResIdAndHashKeyList& result, + perfetto::TracedDictionary& dict) { + dict.Add("doomed_entry_count", result.size()); +} void PopulateTraceDetails(Error error, const StoreStatus& store_status, perfetto::TracedDictionary& dict) { @@ -291,16 +332,18 @@ EntryInfoOrErrorAndEvictionRequested OpenOrCreateEntry( const CacheEntryKey& key); OptionalEntryInfoOrError OpenEntry(const CacheEntryKey& key); - EntryInfoOrErrorAndEvictionRequested CreateEntry(const CacheEntryKey& key); + EntryInfoOrErrorAndEvictionRequested CreateEntry(const CacheEntryKey& key, + bool run_existance_check); ErrorAndEvictionRequested DoomEntry(const CacheEntryKey& key, ResId res_id); ErrorAndEvictionRequested DeleteDoomedEntry(const CacheEntryKey& key, ResId res_id); Error DeleteDoomedEntries(base::flat_set<ResId> excluded_res_ids); - ErrorAndEvictionRequested DeleteLiveEntry(const CacheEntryKey& key); + ResIdAndHashKeyListOrErrorAndEvictionRequested DeleteLiveEntry( + const CacheEntryKey& key); ErrorAndEvictionRequested DeleteAllEntries(); - ErrorAndEvictionRequested DeleteLiveEntriesBetween( + ResIdAndHashKeyListOrErrorAndEvictionRequested DeleteLiveEntriesBetween( base::Time initial_time, base::Time end_time, base::flat_set<CacheEntryKey> excluded_keys); @@ -328,7 +371,7 @@ int64_t CalculateSizeOfEntriesBetween(base::Time initial_time, base::Time end_time); OptionalEntryInfoWithIdAndKey OpenLatestEntryBeforeResId(ResId res_id_cursor); - ErrorAndEvictionRequested RunEviction( + ResIdAndHashKeyListOrErrorAndEvictionRequested RunEviction( base::flat_set<CacheEntryKey> excluded_keys); bool MaybeRunCheckpoint(); @@ -336,10 +379,14 @@ strict_corruption_check_enabled_ = true; } + void SetSimulateDbFailureForTesting(bool fail) { + simulate_db_failure_for_testing_ = fail; + } + private: void DatabaseErrorCallback(int error, sql::Statement* statement); - Error InitializeInternal(bool& corruption_detected); + Error InitializeInternal(bool& corruption_detected, HashResIdSet& index); EntryInfoOrError OpenOrCreateEntryInternal(const CacheEntryKey& key, bool& corruption_detected); OptionalEntryInfoOrError OpenEntryInternal(const CacheEntryKey& key); @@ -352,10 +399,10 @@ const base::flat_set<ResId>& excluded_res_ids, size_t& deleted_count, bool& corruption_detected); - Error DeleteLiveEntryInternal(const CacheEntryKey& key, - bool& corruption_detected); + ResIdAndHashKeyListOrError DeleteLiveEntryInternal(const CacheEntryKey& key, + bool& corruption_detected); Error DeleteAllEntriesInternal(bool& corruption_detected); - Error DeleteLiveEntriesBetweenInternal( + ResIdAndHashKeyListOrError DeleteLiveEntriesBetweenInternal( base::Time initial_time, base::Time end_time, const base::flat_set<CacheEntryKey>& excluded_keys, @@ -391,8 +438,9 @@ OptionalEntryInfoWithIdAndKey OpenLatestEntryBeforeResIdInternal( ResId res_id_cursor, bool& corruption_detected); - Error RunEvictionInternal(const base::flat_set<CacheEntryKey>& excluded_keys, - bool& corruption_detected); + ResIdAndHashKeyListOrError RunEvictionInternal( + const base::flat_set<CacheEntryKey>& excluded_keys, + bool& corruption_detected); // Trims blobs that overlap with the new write range [offset, end), and // updates the total size delta. @@ -484,6 +532,7 @@ std::optional<Error> db_init_status_; StoreStatus store_status_; bool strict_corruption_check_enabled_ = false; + bool simulate_db_failure_for_testing_ = false; // The number of pages in the write-ahead log file. This is updated by // `OnCommitCallback` and reset to 0 after a checkpoint. int wal_pages_ = 0; @@ -494,7 +543,8 @@ base::ElapsedTimer timer; CHECK(!db_init_status_.has_value()); bool corruption_detected = false; - db_init_status_ = InitializeInternal(corruption_detected); + HashResIdSet index; + db_init_status_ = InitializeInternal(corruption_detected, index); RecordTimeAndErrorResultHistogram("Initialize", timer.Elapsed(), *db_init_status_, corruption_detected); TRACE_EVENT_END1("disk_cache", "SqlBackend.Initialize", "result", @@ -521,11 +571,15 @@ } return *db_init_status_ == Error::kOk - ? InitResultOrError(InitResult(max_bytes_)) + ? InitResultOrError(InitResult(max_bytes_, std::move(index))) : base::unexpected(*db_init_status_); } -Error Backend::InitializeInternal(bool& corruption_detected) { +Error Backend::InitializeInternal(bool& corruption_detected, + HashResIdSet& index) { + if (simulate_db_failure_for_testing_) { + return Error::kFailedForTesting; + } CHECK(!db_init_status_.has_value()); db_.set_error_callback(base::BindRepeating(&Backend::DatabaseErrorCallback, @@ -571,7 +625,33 @@ return Error::kFailedToInitializeMetaTable; } + { + base::ElapsedTimer timer; + sql::Statement statement(db_.GetCachedStatement( + SQL_FROM_HERE, + GetQuery( + Query::kGetCacheKeyHashes_SelectCacheKeyHashFromLiveResources))); + while (statement.Step()) { + const auto res_id = ResId(statement.ColumnInt64(0)); + const auto key_hash = CacheEntryKey::Hash(statement.ColumnInt64(1)); + const bool doomed = statement.ColumnBool(2); + if (doomed) { + // TODO(crbug.com/443171275): Return information to SqlBackendImpl that + // a doomed entry exists, and if no doomed entry exists, do not execute + // TriggerDeleteDoomedEntries. + } else { + index.Insert(key_hash, res_id); + } + } + // TODO(crbug.com/443171275): If this process takes a very long time, + // load the in-memory index when the browser is idle. + base::UmaHistogramMicrosecondsTimes( + base::StrCat({kHistogramPrefix, "LoadInMemoryIndexTime"}), + timer.Elapsed()); + } + // TODO(crbug.com/443171275): Use `index.size()` and remove + // `kSqlBackendMetaTableKeyEntryCount` metadata. int64_t tmp_entry_count = 0; if (!GetOrInitializeMetaValue(meta_table_, kSqlBackendMetaTableKeyEntryCount, tmp_entry_count, @@ -635,6 +715,9 @@ EntryInfoOrError Backend::OpenOrCreateEntryInternal(const CacheEntryKey& key, bool& corruption_detected) { + if (simulate_db_failure_for_testing_) { + return base::unexpected(Error::kFailedForTesting); + } // Try to open first. auto open_result = OpenEntryInternal(key); if (open_result.has_value() && open_result->has_value()) { @@ -670,6 +753,9 @@ } OptionalEntryInfoOrError Backend::OpenEntryInternal(const CacheEntryKey& key) { + if (simulate_db_failure_for_testing_) { + return base::unexpected(Error::kFailedForTesting); + } CheckDatabaseInitStatus(); sql::Statement statement(db_.GetCachedStatement( @@ -700,7 +786,8 @@ } EntryInfoOrErrorAndEvictionRequested Backend::CreateEntry( - const CacheEntryKey& key) { + const CacheEntryKey& key, + bool run_existance_check) { TRACE_EVENT_BEGIN1("disk_cache", "SqlBackend.CreateEntry", "data", [&](perfetto::TracedValue trace_context) { auto dict = std::move(trace_context).WriteDictionary(); @@ -709,8 +796,8 @@ }); base::ElapsedTimer timer; bool corruption_detected = false; - auto result = CreateEntryInternal(key, /*run_existance_check=*/true, - corruption_detected); + auto result = + CreateEntryInternal(key, run_existance_check, corruption_detected); RecordTimeAndErrorResultHistogram("CreateEntry", timer.Elapsed(), result.error_or(Error::kOk), corruption_detected); @@ -727,6 +814,9 @@ EntryInfoOrError Backend::CreateEntryInternal(const CacheEntryKey& key, bool run_existance_check, bool& corruption_detected) { + if (simulate_db_failure_for_testing_) { + return base::unexpected(Error::kFailedForTesting); + } CheckDatabaseInitStatus(); sql::Transaction transaction(&db_); if (!transaction.Begin()) { @@ -807,6 +897,9 @@ } Error Backend::DoomEntryInternal(ResId res_id, bool& corruption_detected) { + if (simulate_db_failure_for_testing_) { + return Error::kFailedForTesting; + } CheckDatabaseInitStatus(); sql::Transaction transaction(&db_); if (!transaction.Begin()) { @@ -876,6 +969,9 @@ } Error Backend::DeleteDoomedEntryInternal(ResId res_id) { + if (simulate_db_failure_for_testing_) { + return Error::kFailedForTesting; + } CheckDatabaseInitStatus(); sql::Transaction transaction(&db_); if (!transaction.Begin()) { @@ -935,6 +1031,9 @@ const base::flat_set<ResId>& excluded_res_ids, size_t& deleted_count, bool& corruption_detected) { + if (simulate_db_failure_for_testing_) { + return Error::kFailedForTesting; + } CheckDatabaseInitStatus(); sql::Transaction transaction(&db_); if (!transaction.Begin()) { @@ -980,7 +1079,8 @@ return transaction.Commit() ? Error::kOk : Error::kFailedToCommitTransaction; } -ErrorAndEvictionRequested Backend::DeleteLiveEntry(const CacheEntryKey& key) { +ResIdAndHashKeyListOrErrorAndEvictionRequested Backend::DeleteLiveEntry( + const CacheEntryKey& key) { TRACE_EVENT_BEGIN1("disk_cache", "SqlBackend.DeleteLiveEntry", "data", [&](perfetto::TracedValue trace_context) { auto dict = std::move(trace_context).WriteDictionary(); @@ -990,7 +1090,8 @@ base::ElapsedTimer timer; bool corruption_detected = false; auto result = DeleteLiveEntryInternal(key, corruption_detected); - RecordTimeAndErrorResultHistogram("DeleteLiveEntry", timer.Elapsed(), result, + RecordTimeAndErrorResultHistogram("DeleteLiveEntry", timer.Elapsed(), + result.error_or(Error::kOk), corruption_detected); TRACE_EVENT_END1("disk_cache", "SqlBackend.DeleteLiveEntry", "result", [&](perfetto::TracedValue trace_context) { @@ -999,15 +1100,20 @@ dict.Add("corruption_detected", corruption_detected); }); MaybeCrashIfCorrupted(corruption_detected); - return ErrorAndEvictionRequested(result, ShouldStartEviction()); + return ResIdAndHashKeyListOrErrorAndEvictionRequested(std::move(result), + ShouldStartEviction()); } -Error Backend::DeleteLiveEntryInternal(const CacheEntryKey& key, - bool& corruption_detected) { +ResIdAndHashKeyListOrError Backend::DeleteLiveEntryInternal( + const CacheEntryKey& key, + bool& corruption_detected) { + if (simulate_db_failure_for_testing_) { + return base::unexpected(Error::kFailedForTesting); + } CheckDatabaseInitStatus(); sql::Transaction transaction(&db_); if (!transaction.Begin()) { - return Error::kFailedToStartTransaction; + return base::unexpected(Error::kFailedToStartTransaction); } // We need to collect the res_ids of deleted entries to later remove their @@ -1015,30 +1121,34 @@ std::vector<ResId> res_ids_to_be_deleted; // Use checked numerics to safely update the total cache size. base::CheckedNumeric<int64_t> total_size_delta = 0; - int64_t deleted_count = 0; + ResIdAndHashKeyList deleted_enties; { sql::Statement statement(db_.GetCachedStatement( SQL_FROM_HERE, GetQuery(Query::kDeleteLiveEntry_DeleteFromResources))); statement.BindInt64(0, key.hash().value()); statement.BindString(1, key.string()); while (statement.Step()) { - ++deleted_count; - res_ids_to_be_deleted.emplace_back(statement.ColumnInt64(0)); + const auto res_id = ResId(statement.ColumnInt64(0)); + res_ids_to_be_deleted.emplace_back(res_id); + deleted_enties.emplace_back(res_id, key.hash()); // The size of the deleted entry is subtracted from the total. total_size_delta -= statement.ColumnInt64(1); } } // If no entries were deleted, the key wasn't found. - if (deleted_count == 0) { - return transaction.Commit() ? Error::kNotFound - : Error::kFailedToCommitTransaction; + if (res_ids_to_be_deleted.empty()) { + return transaction.Commit() + ? base::unexpected(Error::kNotFound) + : base::unexpected(Error::kFailedToCommitTransaction); } // Delete the blobs associated with the deleted entries. if (Error delete_result = DeleteBlobsByResIds(res_ids_to_be_deleted); delete_result != Error::kOk) { - return delete_result; + // If blob deletion fails, returns the error. The transaction will be + // rolled back. So no need to return `deleted_enties`. + return base::unexpected(delete_result); } // If we detected corruption, or if the size update calculation overflowed, @@ -1046,14 +1156,20 @@ // scratch. if (corruption_detected || !total_size_delta.IsValid()) { corruption_detected = true; - return RecalculateStoreStatusAndCommitTransaction(transaction); + auto error = RecalculateStoreStatusAndCommitTransaction(transaction); + return error == Error::kOk + ? ResIdAndHashKeyListOrError(std::move(deleted_enties)) + : base::unexpected(error); } - return UpdateStoreStatusAndCommitTransaction( + auto error = UpdateStoreStatusAndCommitTransaction( transaction, /*entry_count_delta=*/ -static_cast<int64_t>(res_ids_to_be_deleted.size()), /*total_size_delta=*/total_size_delta.ValueOrDie(), corruption_detected); + return error == Error::kOk + ? ResIdAndHashKeyListOrError(std::move(deleted_enties)) + : base::unexpected(error); } ErrorAndEvictionRequested Backend::DeleteAllEntries() { @@ -1077,6 +1193,9 @@ } Error Backend::DeleteAllEntriesInternal(bool& corruption_detected) { + if (simulate_db_failure_for_testing_) { + return Error::kFailedForTesting; + } CheckDatabaseInitStatus(); sql::Transaction transaction(&db_); if (!transaction.Begin()) { @@ -1110,10 +1229,10 @@ /*total_size_delta=*/-store_status_.total_size, corruption_detected); } -ErrorAndEvictionRequested Backend::DeleteLiveEntriesBetween( - base::Time initial_time, - base::Time end_time, - base::flat_set<CacheEntryKey> excluded_keys) { +ResIdAndHashKeyListOrErrorAndEvictionRequested +Backend::DeleteLiveEntriesBetween(base::Time initial_time, + base::Time end_time, + base::flat_set<CacheEntryKey> excluded_keys) { TRACE_EVENT_BEGIN1("disk_cache", "SqlBackend.DeleteLiveEntriesBetween", "data", [&](perfetto::TracedValue trace_context) { auto dict = std::move(trace_context).WriteDictionary(); @@ -1126,32 +1245,37 @@ // Flag to indicate if we encounter signs of database corruption. In // DeleteLiveEntriesBetween, database corruption is ignored. bool corruption_detected = false; - Error result = DeleteLiveEntriesBetweenInternal( + auto result = DeleteLiveEntriesBetweenInternal( initial_time, end_time, excluded_keys, corruption_detected); RecordTimeAndErrorResultHistogram("DeleteLiveEntriesBetween", timer.Elapsed(), - result, corruption_detected); + result.error_or(Error::kOk), + corruption_detected); TRACE_EVENT_END1("disk_cache", "SqlBackend.DeleteLiveEntriesBetween", "result", [&](perfetto::TracedValue trace_context) { auto dict = std::move(trace_context).WriteDictionary(); PopulateTraceDetails(result, store_status_, dict); }); MaybeCrashIfCorrupted(corruption_detected); - return ErrorAndEvictionRequested(result, ShouldStartEviction()); + return ResIdAndHashKeyListOrErrorAndEvictionRequested(std::move(result), + ShouldStartEviction()); } -Error Backend::DeleteLiveEntriesBetweenInternal( +ResIdAndHashKeyListOrError Backend::DeleteLiveEntriesBetweenInternal( base::Time initial_time, base::Time end_time, const base::flat_set<CacheEntryKey>& excluded_keys, bool& corruption_detected) { + if (simulate_db_failure_for_testing_) { + return base::unexpected(Error::kFailedForTesting); + } CheckDatabaseInitStatus(); sql::Transaction transaction(&db_); if (!transaction.Begin()) { - return Error::kFailedToStartTransaction; + return base::unexpected(Error::kFailedToStartTransaction); } std::vector<ResId> res_ids_to_be_deleted; - int64_t entry_count_delta = 0; + ResIdAndHashKeyList deleted_enties; base::CheckedNumeric<int64_t> total_size_delta = 0; { sql::Statement statement(db_.GetCachedStatement( @@ -1160,12 +1284,13 @@ statement.BindTime(0, initial_time); statement.BindTime(1, end_time); while (statement.Step()) { - if (excluded_keys.contains(CacheEntryKey(statement.ColumnString(2)))) { + const auto cache_key = CacheEntryKey(statement.ColumnString(2)); + if (excluded_keys.contains(cache_key)) { continue; } - --entry_count_delta; - ResId res_id(statement.ColumnInt64(0)); - res_ids_to_be_deleted.push_back(res_id); + const auto res_id = ResId(statement.ColumnInt64(0)); + deleted_enties.emplace_back(res_id, cache_key.hash()); + res_ids_to_be_deleted.emplace_back(res_id); total_size_delta -= statement.ColumnInt64(1); } } @@ -1173,13 +1298,13 @@ // Delete the blobs associated with the entries to be deleted. if (auto error = DeleteBlobsByResIds(res_ids_to_be_deleted); error != Error::kOk) { - return error; + return base::unexpected(error); } // Delete the selected entries from the `resources` table. if (auto error = DeleteResourcesByResIds(res_ids_to_be_deleted); error != Error::kOk) { - return error; + return base::unexpected(error); } // If we detected corruption, or if the size update calculation overflowed, @@ -1187,14 +1312,20 @@ // scratch. if (corruption_detected || !total_size_delta.IsValid()) { corruption_detected = true; - return RecalculateStoreStatusAndCommitTransaction(transaction); + auto error = RecalculateStoreStatusAndCommitTransaction(transaction); + return error == Error::kOk + ? ResIdAndHashKeyListOrError(std::move(deleted_enties)) + : base::unexpected(error); } // Update the in-memory and on-disk store status (entry count and total size) // and commit the transaction. - return UpdateStoreStatusAndCommitTransaction(transaction, entry_count_delta, - total_size_delta.ValueOrDie(), - corruption_detected); + auto error = UpdateStoreStatusAndCommitTransaction( + transaction, -deleted_enties.size(), total_size_delta.ValueOrDie(), + corruption_detected); + return error == Error::kOk + ? ResIdAndHashKeyListOrError(std::move(deleted_enties)) + : base::unexpected(error); } Error Backend::UpdateEntryLastUsed(const CacheEntryKey& key, @@ -1219,6 +1350,9 @@ Error Backend::UpdateEntryLastUsedInternal(const CacheEntryKey& key, base::Time last_used) { + if (simulate_db_failure_for_testing_) { + return Error::kFailedForTesting; + } CheckDatabaseInitStatus(); sql::Transaction transaction(&db_); if (!transaction.Begin()) { @@ -1282,6 +1416,9 @@ scoped_refptr<net::IOBuffer> buffer, int64_t header_size_delta, bool& corruption_detected) { + if (simulate_db_failure_for_testing_) { + return Error::kFailedForTesting; + } CHECK(buffer); CheckDatabaseInitStatus(); @@ -1359,6 +1496,9 @@ int buf_len, bool truncate, bool& corruption_detected) { + if (simulate_db_failure_for_testing_) { + return Error::kFailedForTesting; + } CheckDatabaseInitStatus(); sql::Transaction transaction(&db_); if (!transaction.Begin()) { @@ -1767,6 +1907,9 @@ int64_t body_end, bool sparse_reading, bool& corruption_detected) { + if (simulate_db_failure_for_testing_) { + return base::unexpected(Error::kFailedForTesting); + } CheckDatabaseInitStatus(); if (offset < 0 || buf_len < 0 || !buffer || buf_len > buffer->size()) { @@ -2012,26 +2155,28 @@ return std::nullopt; } -ErrorAndEvictionRequested Backend::RunEviction( +ResIdAndHashKeyListOrErrorAndEvictionRequested Backend::RunEviction( base::flat_set<CacheEntryKey> excluded_keys) { TRACE_EVENT0("disk_cache", "SqlBackend.RunEviction"); base::ElapsedTimer timer; bool corruption_detected = false; auto result = RunEvictionInternal(std::move(excluded_keys), corruption_detected); - RecordTimeAndErrorResultHistogram("RunEviction", timer.Elapsed(), result, + RecordTimeAndErrorResultHistogram("RunEviction", timer.Elapsed(), + result.error_or(Error::kOk), corruption_detected); MaybeCrashIfCorrupted(corruption_detected); - return ErrorAndEvictionRequested(result, ShouldStartEviction()); + return ResIdAndHashKeyListOrErrorAndEvictionRequested(std::move(result), + ShouldStartEviction()); } -Error Backend::RunEvictionInternal( +ResIdAndHashKeyListOrError Backend::RunEvictionInternal( const base::flat_set<CacheEntryKey>& excluded_keys, bool& corruption_detected) { int64_t size_to_be_removed = GetSizeOfAllEntries() - low_watermark_; sql::Transaction transaction(&db_); if (!transaction.Begin()) { - return Error::kFailedToExecute; + return base::unexpected(Error::kFailedToExecute); } std::vector<ResId> res_ids_to_be_deleted; @@ -2039,15 +2184,19 @@ // Use checked numerics to safely update the total cache size. base::CheckedNumeric<int64_t> checked_total_size_delta = 0; base::CheckedNumeric<int64_t> checked_removed_total_size = 0; + ResIdAndHashKeyList deleted_enties; { sql::Statement statement(db_.GetCachedStatement( SQL_FROM_HERE, GetQuery(Query::kRunEviction_SelectLiveResources))); while (size_to_be_removed > checked_removed_total_size.ValueOrDie() && statement.Step()) { - if (excluded_keys.contains(CacheEntryKey(statement.ColumnString(1)))) { + const ResId res_id = ResId(statement.ColumnInt64(0)); + const CacheEntryKey cache_key = CacheEntryKey(statement.ColumnString(1)); + if (excluded_keys.contains(cache_key)) { continue; } - res_ids_to_be_deleted.emplace_back(ResId(statement.ColumnInt64(0))); + deleted_enties.emplace_back(res_id, cache_key.hash()); + res_ids_to_be_deleted.emplace_back(res_id); --entry_count_delta; const int64_t bytes_usage = statement.ColumnInt64(2); checked_total_size_delta -= bytes_usage; @@ -2056,7 +2205,7 @@ if (!checked_total_size_delta.IsValid() || !checked_removed_total_size.IsValid()) { corruption_detected = true; - return Error::kInvalidData; + return base::unexpected(Error::kInvalidData); } } } @@ -2064,18 +2213,21 @@ for (const auto& res_id_to_be_deleted : res_ids_to_be_deleted) { if (Error delete_result = DeleteBlobsByResId(res_id_to_be_deleted); delete_result != Error::kOk) { - return delete_result; + return base::unexpected(delete_result); } sql::Statement statement(db_.GetCachedStatement( SQL_FROM_HERE, GetQuery(Query::kRunEviction_DeleteFromResources))); statement.BindInt64(0, res_id_to_be_deleted.value()); if (!statement.Run()) { - return Error::kFailedToExecute; + return base::unexpected(Error::kFailedToExecute); } } - return UpdateStoreStatusAndCommitTransaction( + auto error = UpdateStoreStatusAndCommitTransaction( transaction, entry_count_delta, checked_total_size_delta.ValueOrDie(), corruption_detected); + return error == Error::kOk + ? ResIdAndHashKeyListOrError(std::move(deleted_enties)) + : base::unexpected(error); } Error Backend::UpdateStoreStatusAndCommitTransaction( @@ -2240,6 +2392,7 @@ if (weak_ptr) { if (result.has_value()) { weak_ptr->SetMaxSize(result->max_bytes); + weak_ptr->index_ = std::move(result->index); } std::move(callback).Run(result.has_value() ? Error::kOk : result.error()); @@ -2251,7 +2404,9 @@ EntryInfoOrErrorCallback callback) override { backend_.AsyncCall(&Backend::OpenOrCreateEntry) .WithArgs(key) - .Then(WrapCallbackWithEvictionRequested(std::move(callback))); + .Then(WrapEntryInfoOrErrorCallback( + std::move(callback), key, + IndexMismatchLocation::kOpenOrCreateEntry)); } void OpenEntry(const CacheEntryKey& key, OptionalEntryInfoOrErrorCallback callback) override { @@ -2261,16 +2416,36 @@ } void CreateEntry(const CacheEntryKey& key, EntryInfoOrErrorCallback callback) override { + bool run_existance_check = !index_ || index_->Contains(key.hash()); backend_.AsyncCall(&Backend::CreateEntry) - .WithArgs(key) - .Then(WrapCallbackWithEvictionRequested(std::move(callback))); + .WithArgs(key, run_existance_check) + .Then(WrapEntryInfoOrErrorCallback( + std::move(callback), key, IndexMismatchLocation::kCreateEntry)); } void DoomEntry(const CacheEntryKey& key, ResId res_id, ErrorCallback callback) override { backend_.AsyncCall(&Backend::DoomEntry) .WithArgs(key, res_id) - .Then(WrapCallbackWithEvictionRequested(std::move(callback))); + .Then(base::BindOnce( + [](base::WeakPtr<SqlPersistentStoreImpl> weak_ptr, + CacheEntryKey::Hash key_hash, ResId res_id, + ErrorCallback callback, ErrorAndEvictionRequested result) { + if (weak_ptr) { + if (result.result == Error::kOk) { + CHECK(weak_ptr->index_.has_value()); + if (!weak_ptr->index_->Remove(key_hash, res_id)) { + weak_ptr->RecordIndexMismatch( + IndexMismatchLocation::kDoomEntry); + } + } + weak_ptr->eviction_requested_ = result.eviction_requested; + // We should not run the callback when `this` was deleted. + std::move(callback).Run(std::move(result.result)); + } + }, + weak_factory_.GetWeakPtr(), key.hash(), res_id, + std::move(callback))); } void DeleteDoomedEntry(const CacheEntryKey& key, ResId res_id, @@ -2289,11 +2464,24 @@ ErrorCallback callback) override { backend_.AsyncCall(&Backend::DeleteLiveEntry) .WithArgs(key) - .Then(WrapCallbackWithEvictionRequested(std::move(callback))); + .Then(WrapErrorCallbackToRemoveFromIndex( + std::move(callback), IndexMismatchLocation::kDeleteLiveEntry)); } void DeleteAllEntries(ErrorCallback callback) override { backend_.AsyncCall(&Backend::DeleteAllEntries) - .Then(WrapCallbackWithEvictionRequested(std::move(callback))); + .Then(base::BindOnce( + [](base::WeakPtr<SqlPersistentStoreImpl> weak_ptr, + ErrorCallback callback, ErrorAndEvictionRequested result) { + if (weak_ptr) { + if (result.result == Error::kOk) { + CHECK(weak_ptr->index_.has_value()); + weak_ptr->index_->Clear(); + } + // We should not run the callback when `this` was deleted. + std::move(callback).Run(std::move(result.result)); + } + }, + weak_factory_.GetWeakPtr(), std::move(callback))); } void DeleteLiveEntriesBetween(base::Time initial_time, base::Time end_time, @@ -2301,7 +2489,9 @@ ErrorCallback callback) override { backend_.AsyncCall(&Backend::DeleteLiveEntriesBetween) .WithArgs(initial_time, end_time, std::move(excluded_keys)) - .Then(WrapCallbackWithEvictionRequested(std::move(callback))); + .Then(WrapErrorCallbackToRemoveFromIndex( + std::move(callback), + IndexMismatchLocation::kDeleteLiveEntriesBetween)); } void UpdateEntryLastUsed(const CacheEntryKey& key, base::Time last_used, @@ -2379,11 +2569,22 @@ .WithArgs(std::move(excluded_keys)) .Then(base::BindOnce( [](base::WeakPtr<SqlPersistentStoreImpl> weak_ptr, - ErrorCallback callback, ErrorAndEvictionRequested result) { + ErrorCallback callback, + ResIdAndHashKeyListOrErrorAndEvictionRequested result) { if (weak_ptr) { weak_ptr->eviction_in_progress_ = false; + if (result.result.has_value()) { + CHECK(weak_ptr->index_.has_value()); + for (const auto& res_id_and_key : *result.result) { + if (!weak_ptr->index_->Remove(res_id_and_key.key_hash, + res_id_and_key.res_id)) { + weak_ptr->RecordIndexMismatch( + IndexMismatchLocation::kStartEviction); + } + } + } weak_ptr->eviction_requested_ = result.eviction_requested; - std::move(callback).Run(result.result); + std::move(callback).Run(result.result.error_or(Error::kOk)); } }, weak_factory_.GetWeakPtr(), std::move(callback))); @@ -2402,9 +2603,25 @@ } void EnableStrictCorruptionCheckForTesting() override { + strict_corruption_check_enabled_ = true; backend_.AsyncCall(&Backend::EnableStrictCorruptionCheckForTesting); } + void SetSimulateDbFailureForTesting(bool fail) override { + backend_.AsyncCall(&Backend::SetSimulateDbFailureForTesting).WithArgs(fail); + } + + IndexState GetIndexStateForHash(CacheEntryKey::Hash key_hash) const override { + if (!index_.has_value()) { + return IndexState::kNotReady; + } + + if (index_->Contains(key_hash)) { + return IndexState::kHashFound; + } + return IndexState::kHashNotFound; + } + private: void SetMaxSize(int64_t max_bytes) { max_size_ = max_bytes; @@ -2445,13 +2662,74 @@ weak_factory_.GetWeakPtr(), std::move(callback)); } + base::OnceCallback<void(EntryInfoOrErrorAndEvictionRequested)> + WrapEntryInfoOrErrorCallback(EntryInfoOrErrorCallback callback, + const CacheEntryKey& key, + IndexMismatchLocation location) { + return base::BindOnce( + [](base::WeakPtr<SqlPersistentStoreImpl> weak_ptr, + EntryInfoOrErrorCallback callback, CacheEntryKey::Hash key_hash, + IndexMismatchLocation location, + EntryInfoOrErrorAndEvictionRequested result) { + if (weak_ptr) { + if (result.result.has_value()) { + CHECK(weak_ptr->index_.has_value()); + if (!result.result->opened) { + if (!weak_ptr->index_->Insert(key_hash, + result.result->res_id)) { + weak_ptr->RecordIndexMismatch(location); + }; + } + } + weak_ptr->eviction_requested_ = result.eviction_requested; + // We should not run the callback when `this` was deleted. + std::move(callback).Run(std::move(result.result)); + } + }, + weak_factory_.GetWeakPtr(), std::move(callback), key.hash(), location); + } + + base::OnceCallback<void(ResIdAndHashKeyListOrErrorAndEvictionRequested)> + WrapErrorCallbackToRemoveFromIndex(ErrorCallback callback, + IndexMismatchLocation location) { + return base::BindOnce( + [](base::WeakPtr<SqlPersistentStoreImpl> weak_ptr, + ErrorCallback callback, IndexMismatchLocation location, + ResIdAndHashKeyListOrErrorAndEvictionRequested result) { + if (weak_ptr) { + if (result.result.has_value()) { + CHECK(weak_ptr->index_.has_value()); + for (const auto& hash_and_res_id : result.result.value()) { + if (!weak_ptr->index_->Remove(hash_and_res_id.key_hash, + hash_and_res_id.res_id)) { + weak_ptr->RecordIndexMismatch(location); + } + } + } + weak_ptr->eviction_requested_ = result.eviction_requested; + // We should not run the callback when `this` was deleted. + std::move(callback).Run( + std::move(result.result.error_or(Error::kOk))); + } + }, + weak_factory_.GetWeakPtr(), std::move(callback), location); + } + + void RecordIndexMismatch(IndexMismatchLocation location) { + base::UmaHistogramEnumeration( + base::StrCat({kHistogramPrefix, "IndexMismatch"}), location); + CHECK(!strict_corruption_check_enabled_); + } + base::SequenceBound<Backend> backend_; int64_t max_size_ = 0; int64_t max_file_size_ = 0; bool eviction_in_progress_ = false; bool eviction_requested_ = false; + bool strict_corruption_check_enabled_ = false; + std::optional<HashResIdSet> index_; base::WeakPtrFactory<SqlPersistentStoreImpl> weak_factory_{this}; };
diff --git a/net/disk_cache/sql/sql_persistent_store.h b/net/disk_cache/sql/sql_persistent_store.h index ed5de01..1ade9a0e 100644 --- a/net/disk_cache/sql/sql_persistent_store.h +++ b/net/disk_cache/sql/sql_persistent_store.h
@@ -67,7 +67,8 @@ kNotFound = 13, kInvalidArgument = 14, kBodyEndMismatch = 15, - kMaxValue = kBodyEndMismatch + kFailedForTesting = 16, + kMaxValue = kFailedForTesting }; // LINT.ThenChange(//tools/metrics/histograms/metadata/net/enums.xml:SqlDiskCacheStoreError) @@ -318,9 +319,26 @@ // kSqlDiskCacheIdleCheckpointThreshold, a checkpoint is executed. virtual void MaybeRunCheckpoint(base::OnceCallback<void(bool)> callback) = 0; + enum class IndexState { + // The in-memory index is not available (e.g., not yet loaded or + // invalidated). + kNotReady, + // The index is ready and the hash was found. This may be a false positive. + kHashFound, + // The index is ready, but the hash was not found. + kHashNotFound, + }; + + // Synchronously checks the state of a key hash against the in-memory index. + virtual IndexState GetIndexStateForHash( + CacheEntryKey::Hash key_hash) const = 0; + // Enables a strict corruption checking mode for testing purposes. virtual void EnableStrictCorruptionCheckForTesting() = 0; + // Sets a flag to simulate database operation failures for testing. + virtual void SetSimulateDbFailureForTesting(bool fail) = 0; + protected: SqlPersistentStore() = default; };
diff --git a/net/disk_cache/sql/sql_persistent_store_queries.h b/net/disk_cache/sql/sql_persistent_store_queries.h index 8bd16cb..df2db29 100644 --- a/net/disk_cache/sql/sql_persistent_store_queries.h +++ b/net/disk_cache/sql/sql_persistent_store_queries.h
@@ -356,6 +356,17 @@ kCalculateTotalSize_SelectTotalSizeFromLiveResources[] = "SELECT SUM(bytes_usage) FROM resources WHERE doomed=0"; +inline constexpr const char + kGetCacheKeyHashes_SelectCacheKeyHashFromLiveResources[] = + // clang-format off + "SELECT " + "res_id, " // 0 + "cache_key_hash, " // 1 + "doomed " // 2 + "FROM resources " + "ORDER BY cache_key_hash"; +// clang-format on + } // namespace internal // An enum for all SQL queries. This helps ensure that all queries are tested. @@ -394,8 +405,9 @@ kRunEviction_DeleteFromResources, kCalculateResourceEntryCount_SelectCountFromLiveResources, kCalculateTotalSize_SelectTotalSizeFromLiveResources, + kGetCacheKeyHashes_SelectCacheKeyHashFromLiveResources, - kMaxValue = kCalculateTotalSize_SelectTotalSizeFromLiveResources, + kMaxValue = kGetCacheKeyHashes_SelectCacheKeyHashFromLiveResources, }; inline base::cstring_view GetQuery(Query query) { @@ -468,6 +480,8 @@ kCalculateResourceEntryCount_SelectCountFromLiveResources; case Query::kCalculateTotalSize_SelectTotalSizeFromLiveResources: return internal::kCalculateTotalSize_SelectTotalSizeFromLiveResources; + case Query::kGetCacheKeyHashes_SelectCacheKeyHashFromLiveResources: + return internal::kGetCacheKeyHashes_SelectCacheKeyHashFromLiveResources; } NOTREACHED(); }
diff --git a/net/disk_cache/sql/sql_persistent_store_queries_unittest.cc b/net/disk_cache/sql/sql_persistent_store_queries_unittest.cc index b0ab241..279f5eb6 100644 --- a/net/disk_cache/sql/sql_persistent_store_queries_unittest.cc +++ b/net/disk_cache/sql/sql_persistent_store_queries_unittest.cc
@@ -208,7 +208,10 @@ "COVERING INDEX index_live_resources_last_used"}, {Query::kCalculateTotalSize_SelectTotalSizeFromLiveResources, "`--SCAN resources USING " - "INDEX index_live_resources_last_used"}}); + "INDEX index_live_resources_last_used"}, + {Query::kGetCacheKeyHashes_SelectCacheKeyHashFromLiveResources, + "`--SCAN resources USING COVERING INDEX " + "index_resources_cache_key_hash_doomed"}}); static_assert(kAllQueriesAndPlans.size() + kSchemaAndIndexQueries.size() == static_cast<int>(Query::kMaxValue) + 1); for (const auto& it : kAllQueriesAndPlans) {
diff --git a/net/disk_cache/sql/sql_persistent_store_unittest.cc b/net/disk_cache/sql/sql_persistent_store_unittest.cc index b43d3e6b..6262cb87 100644 --- a/net/disk_cache/sql/sql_persistent_store_unittest.cc +++ b/net/disk_cache/sql/sql_persistent_store_unittest.cc
@@ -1594,6 +1594,17 @@ ASSERT_EQ(GetEntryCount(), 5); int64_t initial_total_size = GetSizeOfAllEntries(); + EXPECT_EQ(store_->GetIndexStateForHash(kKey1.hash()), + SqlPersistentStore::IndexState::kHashFound); + EXPECT_EQ(store_->GetIndexStateForHash(kKey2.hash()), + SqlPersistentStore::IndexState::kHashFound); + EXPECT_EQ(store_->GetIndexStateForHash(kKey3.hash()), + SqlPersistentStore::IndexState::kHashFound); + EXPECT_EQ(store_->GetIndexStateForHash(kKey4.hash()), + SqlPersistentStore::IndexState::kHashFound); + EXPECT_EQ(store_->GetIndexStateForHash(kKey5.hash()), + SqlPersistentStore::IndexState::kHashFound); + // Delete entries between kTime1 (inclusive) and kTime3 (exclusive). // kKey2 should be excluded. // Expected to delete: kKey1. @@ -1601,6 +1612,16 @@ base::flat_set<CacheEntryKey> excluded_keys = {kKey2}; ASSERT_EQ(DeleteLiveEntriesBetween(kTime1, kTime3, excluded_keys), SqlPersistentStore::Error::kOk); + EXPECT_EQ(store_->GetIndexStateForHash(kKey1.hash()), + SqlPersistentStore::IndexState::kHashNotFound); + EXPECT_EQ(store_->GetIndexStateForHash(kKey2.hash()), + SqlPersistentStore::IndexState::kHashFound); + EXPECT_EQ(store_->GetIndexStateForHash(kKey3.hash()), + SqlPersistentStore::IndexState::kHashFound); + EXPECT_EQ(store_->GetIndexStateForHash(kKey4.hash()), + SqlPersistentStore::IndexState::kHashFound); + EXPECT_EQ(store_->GetIndexStateForHash(kKey5.hash()), + SqlPersistentStore::IndexState::kHashFound); EXPECT_EQ(GetEntryCount(), 4); const int64_t expected_size_after_delete = @@ -3455,6 +3476,8 @@ // Verify oldest entries are gone. int evicted_count = count_before_eviction - count_after_eviction; for (int j = 0; j < evicted_count; ++j) { + EXPECT_EQ(store_->GetIndexStateForHash(keys[j].hash()), + SqlPersistentStore::IndexState::kHashNotFound); auto result = OpenEntry(keys[j]); ASSERT_TRUE(result.has_value()); EXPECT_FALSE(result->has_value()); @@ -3462,6 +3485,8 @@ // Verify newest entries are still there. for (size_t j = evicted_count; j < keys.size(); ++j) { + EXPECT_EQ(store_->GetIndexStateForHash(keys[j].hash()), + SqlPersistentStore::IndexState::kHashFound); auto result = OpenEntry(keys[j]); ASSERT_TRUE(result.has_value()); EXPECT_TRUE(result->has_value()); @@ -3712,4 +3737,182 @@ MaybeRunCheckpoint(/*expected_result=*/true); } +TEST_F(SqlPersistentStoreTest, IndexState) { + const CacheEntryKey kKey1("key1"); + const CacheEntryKey kKey2("key2"); + + CreateStore(); + + // Before initialization, index is not ready. + EXPECT_EQ(store_->GetIndexStateForHash(kKey1.hash()), + SqlPersistentStore::IndexState::kNotReady); + + base::test::TestFuture<SqlPersistentStore::Error> future; + store_->Initialize(future.GetCallback()); + // During initialization, index is not ready. + EXPECT_EQ(store_->GetIndexStateForHash(kKey1.hash()), + SqlPersistentStore::IndexState::kNotReady); + ASSERT_EQ(future.Get(), SqlPersistentStore::Error::kOk); + + // After initialization with an empty store, hash is not found. + EXPECT_EQ(store_->GetIndexStateForHash(kKey1.hash()), + SqlPersistentStore::IndexState::kHashNotFound); + EXPECT_EQ(store_->GetIndexStateForHash(kKey2.hash()), + SqlPersistentStore::IndexState::kHashNotFound); + + // Create an entry. + SqlPersistentStore::EntryInfoOrError result = this->CreateEntry(kKey1); + ASSERT_TRUE(result.has_value()); + SqlPersistentStore::ResId res_id1 = result->res_id; + + // Now the hash for key1 should be found. + EXPECT_EQ(store_->GetIndexStateForHash(kKey1.hash()), + SqlPersistentStore::IndexState::kHashFound); + // Key2 should still not be found. + EXPECT_EQ(store_->GetIndexStateForHash(kKey2.hash()), + SqlPersistentStore::IndexState::kHashNotFound); + + // Create another entry. + result = this->CreateEntry(kKey2); + ASSERT_TRUE(result.has_value()); + + // Both hashes should be found. + EXPECT_EQ(store_->GetIndexStateForHash(kKey1.hash()), + SqlPersistentStore::IndexState::kHashFound); + EXPECT_EQ(store_->GetIndexStateForHash(kKey2.hash()), + SqlPersistentStore::IndexState::kHashFound); + + // Doom the first entry. + ASSERT_EQ(SqlPersistentStore::Error::kOk, this->DoomEntry(kKey1, res_id1)); + + // The hash for the doomed entry should be removed from the index. + EXPECT_EQ(store_->GetIndexStateForHash(kKey1.hash()), + SqlPersistentStore::IndexState::kHashNotFound); + EXPECT_EQ(store_->GetIndexStateForHash(kKey2.hash()), + SqlPersistentStore::IndexState::kHashFound); + + // Delete the second entry. + ASSERT_EQ(SqlPersistentStore::Error::kOk, this->DeleteLiveEntry(kKey2)); + + // The hash for the deleted entry should be removed. + EXPECT_EQ(store_->GetIndexStateForHash(kKey2.hash()), + SqlPersistentStore::IndexState::kHashNotFound); + + // Re-create entry for key1. + result = this->CreateEntry(kKey1); + ASSERT_TRUE(result.has_value()); + EXPECT_EQ(store_->GetIndexStateForHash(kKey1.hash()), + SqlPersistentStore::IndexState::kHashFound); + + // Delete all entries. + ASSERT_EQ(SqlPersistentStore::Error::kOk, this->DeleteAllEntries()); + EXPECT_EQ(store_->GetIndexStateForHash(kKey1.hash()), + SqlPersistentStore::IndexState::kHashNotFound); +} + +// Test index reloading from a non-empty database. +TEST_F(SqlPersistentStoreTest, IndexReloads) { + const CacheEntryKey kKey1("key1"); + const CacheEntryKey kKey2("key2"); + + CreateAndInitStore(); + + // Create two entries. + ASSERT_TRUE(this->CreateEntry(kKey1).has_value()); + ASSERT_TRUE(this->CreateEntry(kKey2).has_value()); + + // The hashes should be found. + EXPECT_EQ(store_->GetIndexStateForHash(kKey1.hash()), + SqlPersistentStore::IndexState::kHashFound); + EXPECT_EQ(store_->GetIndexStateForHash(kKey2.hash()), + SqlPersistentStore::IndexState::kHashFound); + + // Close and reopen the store. + ClearStore(); + CreateAndInitStore(); + + // The index should be re-populated. + EXPECT_EQ(store_->GetIndexStateForHash(kKey1.hash()), + SqlPersistentStore::IndexState::kHashFound); + EXPECT_EQ(store_->GetIndexStateForHash(kKey2.hash()), + SqlPersistentStore::IndexState::kHashFound); + EXPECT_EQ(store_->GetIndexStateForHash(CacheEntryKey("other").hash()), + SqlPersistentStore::IndexState::kHashNotFound); +} + +TEST_F(SqlPersistentStoreTest, SimulateDbFailureInitializationFailure) { + CreateStore(); + store_->SetSimulateDbFailureForTesting(true); + ASSERT_EQ(Init(), SqlPersistentStore::Error::kFailedForTesting); +} + +TEST_F(SqlPersistentStoreTest, SimulateDbFailure) { + CreateAndInitStore(); + + store_->SetSimulateDbFailureForTesting(true); + + const CacheEntryKey kKey("my-key"); + auto create_result = CreateEntry(kKey); + ASSERT_FALSE(create_result.has_value()); + EXPECT_EQ(create_result.error(), + SqlPersistentStore::Error::kFailedForTesting); + + auto open_result = OpenEntry(kKey); + ASSERT_FALSE(open_result.has_value()); + EXPECT_EQ(open_result.error(), SqlPersistentStore::Error::kFailedForTesting); + + auto open_or_create_result = OpenOrCreateEntry(kKey); + ASSERT_FALSE(open_or_create_result.has_value()); + EXPECT_EQ(open_or_create_result.error(), + SqlPersistentStore::Error::kFailedForTesting); + + EXPECT_EQ(DoomEntry(kKey, SqlPersistentStore::ResId(1)), + SqlPersistentStore::Error::kFailedForTesting); + + EXPECT_EQ(DeleteDoomedEntry(kKey, SqlPersistentStore::ResId(1)), + SqlPersistentStore::Error::kFailedForTesting); + + EXPECT_EQ(DeleteDoomedEntries({}), + SqlPersistentStore::Error::kFailedForTesting); + + EXPECT_EQ(DeleteLiveEntry(kKey), + SqlPersistentStore::Error::kFailedForTesting); + + EXPECT_EQ(DeleteAllEntries(), SqlPersistentStore::Error::kFailedForTesting); + + EXPECT_EQ(DeleteLiveEntriesBetween(base::Time::Now(), + base::Time::Now() + base::Seconds(1), {}), + SqlPersistentStore::Error::kFailedForTesting); + + EXPECT_EQ(UpdateEntryLastUsed(kKey, base::Time::Now()), + SqlPersistentStore::Error::kFailedForTesting); + + // Prepare new header data. + const std::string kNewHeadData = "new_header_data"; + auto buffer = base::MakeRefCounted<net::StringIOBuffer>(kNewHeadData); + EXPECT_EQ( + UpdateEntryHeaderAndLastUsed(kKey, SqlPersistentStore::ResId(1), + base::Time::Now(), buffer, buffer->size()), + SqlPersistentStore::Error::kFailedForTesting); + + EXPECT_EQ(WriteEntryData(kKey, SqlPersistentStore::ResId(1), 0, 0, buffer, 0, + false), + SqlPersistentStore::Error::kFailedForTesting); + + auto read_data_result = + ReadEntryData(SqlPersistentStore::ResId(1), 0, buffer, 0, 0, false); + ASSERT_FALSE(read_data_result.has_value()); + EXPECT_EQ(read_data_result.error(), + SqlPersistentStore::Error::kFailedForTesting); + + store_->SetSimulateDbFailureForTesting(false); + + create_result = CreateEntry(kKey); + ASSERT_TRUE(create_result.has_value()); + + open_result = OpenEntry(kKey); + ASSERT_TRUE(open_result.has_value()); + ASSERT_TRUE(open_result->has_value()); +} + } // namespace disk_cache
diff --git a/sandbox/win/src/crosscall_client.h b/sandbox/win/src/crosscall_client.h index ed82953..b65c8d6 100644 --- a/sandbox/win/src/crosscall_client.h +++ b/sandbox/win/src/crosscall_client.h
@@ -13,6 +13,8 @@ #include <stddef.h> #include <stdint.h> +#include <string_view> + #include "base/compiler_specific.h" #include "base/memory/raw_ptr_exclusion.h" #include "base/memory/raw_ref.h" @@ -125,14 +127,14 @@ }; // This copy helper template specialization catches the cases where the -// parameter is a pointer to a string. +// parameter is a wstring_view object. template <> -class CopyHelper<const wchar_t*> { +class CopyHelper<std::wstring_view> { public: - explicit CopyHelper(const wchar_t* t) : t_(t) {} + explicit CopyHelper(std::wstring_view t) : t_(t) {} // Returns the pointer to the start of the string. - const void* GetStart() const { return t_; } + const void* GetStart() const { return t_.data(); } // Update the stored value with the value in the buffer. This is not // supported for this type. @@ -141,15 +143,9 @@ return true; } - // Returns the size of the string in bytes. We define a nullptr string to - // be of zero length. + // Returns the size of the string in bytes. uint32_t GetSize() const { - __try { - return (!t_) ? 0 - : static_cast<uint32_t>(StringLength(t_) * sizeof(t_[0])); - } __except (EXCEPTION_EXECUTE_HANDLER) { - return UINT32_MAX; - } + return static_cast<uint32_t>(t_.size() * sizeof(wchar_t)); } // Returns true if the current type is used as an In or InOut parameter. @@ -158,56 +154,7 @@ ArgType GetType() { return WCHAR_TYPE; } private: - // We provide our not very optimized version of wcslen(), since we don't - // want to risk having the linker use the version in the CRT since the CRT - // might not be present when we do an early IPC call. - static size_t StringLength(const wchar_t* wcs) { - const wchar_t* eos = wcs; - while (*eos++) - ; - return static_cast<size_t>(eos - wcs - 1); - } - - const wchar_t* t_; -}; - -// Specialization for non-const strings. We just reuse the implementation of the -// const string specialization. -template <> -class CopyHelper<wchar_t*> : public CopyHelper<const wchar_t*> { - public: - typedef CopyHelper<const wchar_t*> Base; - explicit CopyHelper(wchar_t* t) : Base(t) {} - - const void* GetStart() const { return Base::GetStart(); } - - bool Update(void* buffer) { return Base::Update(buffer); } - - uint32_t GetSize() const { return Base::GetSize(); } - - bool IsInOut() { return Base::IsInOut(); } - - ArgType GetType() { return Base::GetType(); } -}; - -// Specialization for wchar_t arrays strings. We just reuse the implementation -// of the const string specialization. -template <size_t n> -class CopyHelper<const wchar_t[n]> : public CopyHelper<const wchar_t*> { - public: - typedef const wchar_t array[n]; - typedef CopyHelper<const wchar_t*> Base; - explicit CopyHelper(array t) : Base(t) {} - - const void* GetStart() const { return Base::GetStart(); } - - bool Update(void* buffer) { return Base::Update(buffer); } - - uint32_t GetSize() const { return Base::GetSize(); } - - bool IsInOut() { return Base::IsInOut(); } - - ArgType GetType() { return Base::GetType(); } + std::wstring_view t_; }; // Generic encapsulation class containing a pointer to a buffer and the
diff --git a/sandbox/win/src/filesystem_interception.cc b/sandbox/win/src/filesystem_interception.cc index f50bf84..88ccb41 100644 --- a/sandbox/win/src/filesystem_interception.cc +++ b/sandbox/win/src/filesystem_interception.cc
@@ -115,7 +115,8 @@ CrossCallReturn answer = {0}; // The following call must match in the parameters with // FilesystemDispatcher::ProcessNtCreateFile. - ResultCode code = CrossCall(ipc, IpcTag::NTCREATEFILE, name.get(), + ResultCode code = CrossCall(ipc, IpcTag::NTCREATEFILE, + std::wstring_view(name.get(), name_len), attributes, desired_access, file_attributes, sharing, disposition, options, &answer); if (SBOX_ALL_OK != code) { @@ -181,8 +182,9 @@ SharedMemIPCClient ipc(memory); CrossCallReturn answer = {0}; - ResultCode code = CrossCall(ipc, IpcTag::NTOPENFILE, name.get(), attributes, - desired_access, sharing, options, &answer); + ResultCode code = CrossCall( + ipc, IpcTag::NTOPENFILE, std::wstring_view(name.get(), name_len), + attributes, desired_access, sharing, options, &answer); if (SBOX_ALL_OK != code) break; @@ -238,7 +240,8 @@ sizeof(FILE_BASIC_INFORMATION)); SharedMemIPCClient ipc(memory); CrossCallReturn answer = {0}; - ResultCode code = CrossCall(ipc, IpcTag::NTQUERYATTRIBUTESFILE, name.get(), + ResultCode code = CrossCall(ipc, IpcTag::NTQUERYATTRIBUTESFILE, + std::wstring_view(name.get(), name_len), attributes, file_info, &answer); if (SBOX_ALL_OK != code) @@ -289,7 +292,8 @@ SharedMemIPCClient ipc(memory); CrossCallReturn answer = {0}; ResultCode code = CrossCall(ipc, IpcTag::NTQUERYFULLATTRIBUTESFILE, - name.get(), attributes, file_info, &answer); + std::wstring_view(name.get(), name_len), + attributes, file_info, &answer); if (SBOX_ALL_OK != code) break;
diff --git a/sandbox/win/src/ipc_unittest.cc b/sandbox/win/src/ipc_unittest.cc index ffba545..16dcbaa 100644 --- a/sandbox/win/src/ipc_unittest.cc +++ b/sandbox/win/src/ipc_unittest.cc
@@ -166,7 +166,7 @@ CrossCallReturn answer; IpcTag tag1 = IpcTag::PING1; - const wchar_t* text = L"98765 - 43210"; + std::wstring_view text = L"98765 - 43210"; std::wstring copied_text; CrossCallParamsEx* actual_params; @@ -175,12 +175,12 @@ EXPECT_EQ(1u, actual_params->GetParamsCount()); EXPECT_EQ(tag1, actual_params->GetTag()); EXPECT_TRUE(actual_params->GetParameterStr(0, &copied_text)); - EXPECT_STREQ(text, copied_text.c_str()); + EXPECT_EQ(text, copied_text); copied_text.clear(); // Check with an empty string. IpcTag tag2 = IpcTag::PING2; - const wchar_t* null_text = nullptr; + std::wstring_view null_text; CrossCall(client, tag2, null_text, &answer); actual_params = reinterpret_cast<CrossCallParamsEx*>(client.GetBuffer()); EXPECT_EQ(1u, actual_params->GetParamsCount()); @@ -211,20 +211,20 @@ EXPECT_TRUE(actual_params->GetParameterStr(0, &copied_text)); EXPECT_TRUE(copied_text.empty()); EXPECT_TRUE(actual_params->GetParameterStr(1, &copied_text)); - EXPECT_STREQ(text, copied_text.c_str()); + EXPECT_EQ(text, copied_text); param_size = 1; std::wstring copied_text_p0, copied_text_p2; - const wchar_t* text2 = L"AeFG"; + std::wstring_view text2 = L"AeFG"; CrossCall(client, tag1, text2, null_text, text, &answer); actual_params = reinterpret_cast<CrossCallParamsEx*>(client.GetBuffer()); EXPECT_EQ(3u, actual_params->GetParamsCount()); EXPECT_EQ(tag1, actual_params->GetTag()); EXPECT_TRUE(actual_params->GetParameterStr(0, &copied_text_p0)); - EXPECT_STREQ(text2, copied_text_p0.c_str()); + EXPECT_EQ(text2, copied_text_p0); EXPECT_TRUE(actual_params->GetParameterStr(2, &copied_text_p2)); - EXPECT_STREQ(text, copied_text_p2.c_str()); + EXPECT_EQ(text, copied_text_p2); type = INVALID_TYPE; param_addr = actual_params->GetRawParameter(1, ¶m_size, &type); EXPECT_TRUE(param_addr); @@ -245,7 +245,7 @@ IpcTag tag1 = IpcTag::PING1; IpcTag tag2 = IpcTag::PING2; - const wchar_t* text = L"godzilla"; + std::wstring_view text = L"godzilla"; CrossCallParamsEx* actual_params; char* mem = reinterpret_cast<char*>(client_control);
diff --git a/storage/browser/quota/quota_database.cc b/storage/browser/quota/quota_database.cc index d019d91b..66b7260 100644 --- a/storage/browser/quota/quota_database.cc +++ b/storage/browser/quota/quota_database.cc
@@ -52,8 +52,8 @@ // Version 4 - 2011-10-17 - http://crrev.com/105822 (unsupported) // Version 5 - 2015-10-19 - https://crrev.com/354932 (unsupported) // Version 6 - 2021-04-27 - https://crrev.com/c/2757450 (unsupported) -// Version 7 - 2021-05-20 - https://crrev.com/c/2910136 -// Version 8 - 2021-09-01 - https://crrev.com/c/3119831 +// Version 7 - 2021-05-20 - https://crrev.com/c/2910136 (unsupported) +// Version 8 - 2021-09-01 - https://crrev.com/c/3119831 (unsupported) // Version 9 - 2022-05-13 - https://crrev.com/c/3601253 // Version 10 - 2023-04-10 - https://crrev.com/c/4412082 //
diff --git a/storage/browser/quota/quota_database_migrations.cc b/storage/browser/quota/quota_database_migrations.cc index b69fbcc5..2cfce87 100644 --- a/storage/browser/quota/quota_database_migrations.cc +++ b/storage/browser/quota/quota_database_migrations.cc
@@ -30,51 +30,6 @@ // Quota type for deprecated persistent quota. constexpr int kDeprecatedPersistentQuotaType = 1; -// Overwrites the buckets table with the new_buckets table after data has been -// copied from the former into the latter. -bool OverwriteBucketsTableSetUpIndexes(sql::Database* db) { - // Replace buckets table with new table. - static constexpr char kDeleteBucketTableSql[] = "DROP TABLE buckets"; - if (!db->Execute(kDeleteBucketTableSql)) - return false; - - static constexpr char kRenameBucketTableSql[] = - "ALTER TABLE new_buckets RENAME to buckets"; - if (!db->Execute(kRenameBucketTableSql)) - return false; - - // Create indices on new table. - // clang-format off - static constexpr char kStorageKeyIndexSql[] = - "CREATE UNIQUE INDEX buckets_by_storage_key " - "ON buckets(storage_key, type, name)"; - // clang-format on - if (!db->Execute(kStorageKeyIndexSql)) - return false; - - static constexpr char kHostIndexSql[] = - "CREATE INDEX buckets_by_host ON buckets(host, type)"; - if (!db->Execute(kHostIndexSql)) - return false; - - static constexpr char kLastAccessedIndexSql[] = - "CREATE INDEX buckets_by_last_accessed ON buckets(type, last_accessed)"; - if (!db->Execute(kLastAccessedIndexSql)) - return false; - - static constexpr char kLastModifiedIndexSql[] = - "CREATE INDEX buckets_by_last_modified ON buckets(type, last_modified)"; - if (!db->Execute(kLastModifiedIndexSql)) - return false; - - static constexpr char kExpirationIndexSql[] = - "CREATE INDEX buckets_by_expiration ON buckets(expiration)"; - if (!db->Execute(kExpirationIndexSql)) - return false; - - return true; -} - } // namespace // static @@ -82,25 +37,11 @@ DCHECK_CALLED_ON_VALID_SEQUENCE(quota_database.sequence_checker_); DCHECK_EQ(0, quota_database.db_->transaction_nesting()); - // Reset tables for versions lower than 7 since they are unsupported. - if (quota_database.meta_table_->GetVersionNumber() < 7) { + // Reset tables for versions lower than 9 since they are unsupported. + if (quota_database.meta_table_->GetVersionNumber() < 9) { return false; } - if (quota_database.meta_table_->GetVersionNumber() == 7) { - bool success = MigrateFromVersion7ToVersion8(quota_database); - RecordMigrationHistogram(/*old_version=*/7, /*new_version=*/8, success); - if (!success) - return false; - } - - if (quota_database.meta_table_->GetVersionNumber() == 8) { - bool success = MigrateFromVersion8ToVersion9(quota_database); - RecordMigrationHistogram(/*old_version=*/8, /*new_version=*/9, success); - if (!success) - return false; - } - if (quota_database.meta_table_->GetVersionNumber() == 9) { bool success = MigrateFromVersion9ToVersion10(quota_database); RecordMigrationHistogram(/*old_version=*/9, /*new_version=*/10, success); @@ -122,201 +63,6 @@ success); } -bool QuotaDatabaseMigrations::MigrateFromVersion7ToVersion8( - QuotaDatabase& quota_database) { - DCHECK_CALLED_ON_VALID_SEQUENCE(quota_database.sequence_checker_); - - sql::Database* db = quota_database.db_.get(); - sql::Transaction transaction(db); - if (!transaction.Begin()) - return false; - - // Create new buckets table. - // clang-format off - static constexpr char kNewBucketsTableSql[] = - "CREATE TABLE IF NOT EXISTS new_buckets(" - "id INTEGER PRIMARY KEY, " - "storage_key TEXT NOT NULL, " - "host TEXT NOT NULL, " - "type INTEGER NOT NULL, " - "name TEXT NOT NULL, " - "use_count INTEGER NOT NULL, " - "last_accessed INTEGER NOT NULL, " - "last_modified INTEGER NOT NULL, " - "expiration INTEGER NOT NULL, " - "quota INTEGER NOT NULL)"; - // clang-format on - if (!db->Execute(kNewBucketsTableSql)) - return false; - - // clang-format off - static constexpr char kSelectBucketSql[] = - "SELECT " - "id,origin,type,name,use_count,last_accessed,last_modified," - "expiration, quota " - "FROM buckets " - "WHERE id > ? " - "ORDER BY id " - "LIMIT 1"; - // clang-format on - sql::Statement select_statement( - db->GetCachedStatement(SQL_FROM_HERE, kSelectBucketSql)); - - // clang-format off - static constexpr char kInsertBucketSql[] = - "INSERT into new_buckets(" - "id,storage_key,host,type,name,use_count,last_accessed," - "last_modified,expiration,quota) " - "VALUES(?,?,?,?,?,?,?,?,?,?)"; - // clang-format on - sql::Statement insert_statement( - db->GetCachedStatement(SQL_FROM_HERE, kInsertBucketSql)); - - // Transfer bucket data to the new table one at a time with new host data. - BucketId last_bucket_id(0); - while (true) { - select_statement.BindInt64(0, last_bucket_id.value()); - if (!select_statement.Step()) - break; - - // Populate bucket id. - BucketId bucket_id(select_statement.ColumnInt64(0)); - insert_statement.BindInt64(0, bucket_id.value()); - - // Populate storage key and host. - std::string_view storage_key_string = select_statement.ColumnStringView(1); - insert_statement.BindString(1, storage_key_string); - - std::optional<blink::StorageKey> storage_key = - blink::StorageKey::Deserialize(storage_key_string); - const std::string& host = storage_key.has_value() - ? storage_key.value().origin().host() - : std::string(); - insert_statement.BindString(2, host); - - // Populate type, name, use_count, last_accessed, last_modified, - // expiration and quota. - insert_statement.BindInt(3, select_statement.ColumnInt(2)); - insert_statement.BindString(4, select_statement.ColumnStringView(3)); - insert_statement.BindInt(5, select_statement.ColumnInt(4)); - insert_statement.BindTime(6, select_statement.ColumnTime(5)); - insert_statement.BindTime(7, select_statement.ColumnTime(6)); - insert_statement.BindTime(8, select_statement.ColumnTime(7)); - insert_statement.BindInt(9, select_statement.ColumnInt(8)); - - if (!insert_statement.Run()) - return false; - - select_statement.Reset(/*clear_bound_vars=*/true); - insert_statement.Reset(/*clear_bound_vars=*/true); - last_bucket_id = bucket_id; - } - - if (!OverwriteBucketsTableSetUpIndexes(db)) - return false; - - // Mark database as up to date. - return quota_database.meta_table_->SetVersionNumber(8) && - quota_database.meta_table_->SetCompatibleVersionNumber(8) && - transaction.Commit(); -} - -bool QuotaDatabaseMigrations::MigrateFromVersion8ToVersion9( - QuotaDatabase& quota_database) { - DCHECK_CALLED_ON_VALID_SEQUENCE(quota_database.sequence_checker_); - - sql::Database* db = quota_database.db_.get(); - sql::Transaction transaction(db); - if (!transaction.Begin()) - return false; - - // Create new buckets table. - // clang-format off - static constexpr char kNewBucketsTableSql[] = - "CREATE TABLE IF NOT EXISTS new_buckets(" - "id INTEGER PRIMARY KEY AUTOINCREMENT, " - "storage_key TEXT NOT NULL, " - "host TEXT NOT NULL, " - "type INTEGER NOT NULL, " - "name TEXT NOT NULL, " - "use_count INTEGER NOT NULL, " - "last_accessed INTEGER NOT NULL, " - "last_modified INTEGER NOT NULL, " - "expiration INTEGER NOT NULL, " - "quota INTEGER NOT NULL, " - "persistent INTEGER NOT NULL, " - "durability INTEGER NOT NULL) " - "STRICT"; - // clang-format on - if (!db->Execute(kNewBucketsTableSql)) - return false; - - // clang-format off - static constexpr char kSelectBucketSql[] = - "SELECT " - "id,storage_key,host,type,name,use_count,last_accessed,last_modified," - "expiration,quota " - "FROM buckets " - "WHERE id > ? " - "ORDER BY id " - "LIMIT 1"; - // clang-format on - sql::Statement select_statement( - db->GetCachedStatement(SQL_FROM_HERE, kSelectBucketSql)); - - // clang-format off - static constexpr char kInsertBucketSql[] = - "INSERT into new_buckets(" - "id,storage_key,host,type,name,use_count,last_accessed,last_modified," - "expiration,quota,persistent,durability)" - "VALUES(?,?,?,?,?,?,?,?,?,?,?,?)"; - // clang-format on - sql::Statement insert_statement( - db->GetCachedStatement(SQL_FROM_HERE, kInsertBucketSql)); - - // Transfer bucket data to the new table one at a time with new - // persistence/durability (default) values. - BucketId last_bucket_id(0); - while (true) { - select_statement.BindInt64(0, last_bucket_id.value()); - if (!select_statement.Step()) - break; - - last_bucket_id = BucketId(select_statement.ColumnInt64(0)); - - insert_statement.BindInt64(0, select_statement.ColumnInt64(0)); - insert_statement.BindString(1, select_statement.ColumnStringView(1)); - insert_statement.BindString(2, select_statement.ColumnStringView(2)); - insert_statement.BindInt(3, select_statement.ColumnInt(3)); - insert_statement.BindString(4, select_statement.ColumnStringView(4)); - insert_statement.BindInt(5, select_statement.ColumnInt(5)); - insert_statement.BindTime(6, select_statement.ColumnTime(6)); - insert_statement.BindTime(7, select_statement.ColumnTime(7)); - // Prior to version 9, the default value for `expiration` was - // base::Time::Max(), and the value was unused. For version 9+, the default - // value is base::Time(). Reset old values to the new default. - insert_statement.BindTime(8, base::Time()); - insert_statement.BindInt(9, select_statement.ColumnInt(9)); - insert_statement.BindBool(10, false); - insert_statement.BindInt( - 11, static_cast<int>(blink::mojom::BucketDurability::kRelaxed)); - - if (!insert_statement.Run()) - return false; - - select_statement.Reset(/*clear_bound_vars=*/true); - insert_statement.Reset(/*clear_bound_vars=*/true); - } - - if (!OverwriteBucketsTableSetUpIndexes(db)) - return false; - - // Mark database as up to date. - return quota_database.meta_table_->SetVersionNumber(9) && - quota_database.meta_table_->SetCompatibleVersionNumber(9) && - transaction.Commit(); -} - bool QuotaDatabaseMigrations::MigrateFromVersion9ToVersion10( QuotaDatabase& quota_database) { DCHECK_CALLED_ON_VALID_SEQUENCE(quota_database.sequence_checker_);
diff --git a/storage/browser/quota/quota_database_migrations_unittest.cc b/storage/browser/quota/quota_database_migrations_unittest.cc index 331aa8dd..783a89c 100644 --- a/storage/browser/quota/quota_database_migrations_unittest.cc +++ b/storage/browser/quota/quota_database_migrations_unittest.cc
@@ -117,158 +117,6 @@ EXPECT_EQ(GetCurrentSchema(), GetQuotaDatabaseSchema()); } -TEST_F(QuotaDatabaseMigrationsTest, UpgradeSchemaFromV7) { - ASSERT_TRUE(LoadDatabase("version_7.sql", DbPath())); - - { - sql::Database db(sql::test::kTestTag); - ASSERT_TRUE(db.Open(DbPath())); - - ASSERT_TRUE(sql::MetaTable::DoesTableExist(&db)); - sql::MetaTable meta_table; - ASSERT_TRUE( - meta_table.Init(&db, kCurrentSchemaVersion, kCurrentCompatibleVersion)); - ASSERT_EQ(meta_table.GetVersionNumber(), 7); - ASSERT_EQ(meta_table.GetCompatibleVersionNumber(), 7); - - ASSERT_TRUE(db.DoesTableExist("quota")); - ASSERT_TRUE(db.DoesTableExist("buckets")); - - // Check populated data. - EXPECT_EQ( - "1|http://a/|0|bucket_a|123|13260644621105493|13242931862595604|" - "9223372036854775807|0," - "2|http://b/|0|bucket_b|111|13250042735631065|13260999511438890|" - "9223372036854775807|1000," - "3|chrome-extension://abc/|2|default|321|13261163582572088|" - "13261079941303629|9223372036854775807|10000", - sql::test::ExecuteWithResults( - &db, "SELECT * FROM buckets ORDER BY id ASC", "|", ",")); - - EXPECT_EQ("a.com,b.com,c.com", - sql::test::ExecuteWithResults( - &db, "SELECT host FROM quota ORDER BY host ASC", "|", ",")); - } - - MigrateDatabase(); - - // Verify upgraded schema. - { - sql::Database db(sql::test::kTestTag); - ASSERT_TRUE(db.Open(DbPath())); - - ASSERT_TRUE(sql::MetaTable::DoesTableExist(&db)); - sql::MetaTable meta_table; - ASSERT_TRUE( - meta_table.Init(&db, kCurrentSchemaVersion, kCurrentCompatibleVersion)); - ASSERT_EQ(meta_table.GetVersionNumber(), kCurrentSchemaVersion); - ASSERT_EQ(meta_table.GetCompatibleVersionNumber(), kCurrentSchemaVersion); - - ASSERT_FALSE(db.DoesTableExist("quota")); - ASSERT_TRUE(db.DoesTableExist("buckets")); - ASSERT_FALSE(db.DoesTableExist("eviction_info")); - - // Check that buckets data is still present. - EXPECT_EQ( - "1|http://a/|a|0|bucket_a|123|13260644621105493|13242931862595604|" - "0|0|0|0," - "2|http://b/|b|0|bucket_b|111|13250042735631065|13260999511438890|" - "0|1000|0|0," - "3|chrome-extension://abc/||2|_default|321|13261163582572088|" - "13261079941303629|0|10000|0|0", - sql::test::ExecuteWithResults( - &db, "SELECT * FROM buckets ORDER BY id ASC", "|", ",")); - - EXPECT_EQ(GetCurrentSchema(), RemoveQuotes(db.GetSchema())); - - EXPECT_EQ(GetTotalHistogramCount(), 3u); - histograms_->ExpectBucketCount("Quota.DatabaseMigrationFromV7ToV8", - /*sample=*/true, /*expected_count=*/1); - histograms_->ExpectBucketCount("Quota.DatabaseMigrationFromV8ToV9", - /*sample=*/true, /*expected_count=*/1); - histograms_->ExpectBucketCount("Quota.DatabaseMigrationFromV9ToV10", - /*sample=*/true, /*expected_count=*/1); - } -} - -TEST_F(QuotaDatabaseMigrationsTest, UpgradeSchemaFromV8) { - ASSERT_TRUE(LoadDatabase("version_8.sql", DbPath())); - - { - sql::Database db(sql::test::kTestTag); - ASSERT_TRUE(db.Open(DbPath())); - - ASSERT_TRUE(sql::MetaTable::DoesTableExist(&db)); - sql::MetaTable meta_table; - ASSERT_TRUE( - meta_table.Init(&db, kCurrentSchemaVersion, kCurrentCompatibleVersion)); - ASSERT_EQ(meta_table.GetVersionNumber(), 8); - ASSERT_EQ(meta_table.GetCompatibleVersionNumber(), 8); - - ASSERT_TRUE(db.DoesTableExist("quota")); - ASSERT_TRUE(db.DoesTableExist("buckets")); - - // Check populated data. - EXPECT_EQ( - "1|http://a/|http://a/" - "|0|bucket_a|123|13260644621105493|13242931862595604|" - "9223372036854775807|0," - "2|http://b/|http://b/" - "|0|bucket_b|111|13250042735631065|13260999511438890|" - "9223372036854775807|1000," - "3|chrome-extension://abc/|chrome-extension://abc/" - "|2|default|321|13261163582572088|" - "13261079941303629|9223372036854775807|10000", - sql::test::ExecuteWithResults( - &db, "SELECT * FROM buckets ORDER BY id ASC", "|", ",")); - - EXPECT_EQ("a.com,b.com,c.com", - sql::test::ExecuteWithResults( - &db, "SELECT host FROM quota ORDER BY host ASC", "|", ",")); - } - - MigrateDatabase(); - - // Verify upgraded schema. - { - sql::Database db(sql::test::kTestTag); - ASSERT_TRUE(db.Open(DbPath())); - - ASSERT_TRUE(sql::MetaTable::DoesTableExist(&db)); - sql::MetaTable meta_table; - ASSERT_TRUE( - meta_table.Init(&db, kCurrentSchemaVersion, kCurrentCompatibleVersion)); - EXPECT_EQ(meta_table.GetVersionNumber(), kCurrentSchemaVersion); - EXPECT_EQ(meta_table.GetCompatibleVersionNumber(), kCurrentSchemaVersion); - - ASSERT_FALSE(db.DoesTableExist("quota")); - ASSERT_TRUE(db.DoesTableExist("buckets")); - ASSERT_FALSE(db.DoesTableExist("eviction_info")); - - // Check that buckets data is still present. - EXPECT_EQ( - "1|http://a/|http://a/" - "|0|bucket_a|123|13260644621105493|13242931862595604|" - "0|0|0|0," - "2|http://b/|http://b/" - "|0|bucket_b|111|13250042735631065|13260999511438890|" - "0|1000|0|0," - "3|chrome-extension://abc/|chrome-extension://abc/" - "|2|_default|321|13261163582572088|" - "13261079941303629|0|10000|0|0", - sql::test::ExecuteWithResults( - &db, "SELECT * FROM buckets ORDER BY id ASC", "|", ",")); - - EXPECT_EQ(GetCurrentSchema(), RemoveQuotes(db.GetSchema())); - - EXPECT_EQ(GetTotalHistogramCount(), 2u); - histograms_->ExpectBucketCount("Quota.DatabaseMigrationFromV8ToV9", - /*sample=*/true, /*expected_count=*/1); - histograms_->ExpectBucketCount("Quota.DatabaseMigrationFromV9ToV10", - /*sample=*/true, /*expected_count=*/1); - } -} - TEST_F(QuotaDatabaseMigrationsTest, UpgradeSchemaFromV9) { ASSERT_TRUE(LoadDatabase("version_9.sql", DbPath()));
diff --git a/storage/test/data/quota_database/version_7.sql b/storage/test/data/quota_database/version_7.sql deleted file mode 100644 index 7a0c0fa2..0000000 --- a/storage/test/data/quota_database/version_7.sql +++ /dev/null
@@ -1,34 +0,0 @@ -PRAGMA foreign_keys=OFF; - -BEGIN TRANSACTION; - -CREATE TABLE quota(host TEXT NOT NULL, type INTEGER NOT NULL, quota INTEGER NOT NULL, PRIMARY KEY(host, type)) WITHOUT ROWID; - -CREATE TABLE buckets(id INTEGER PRIMARY KEY, origin TEXT NOT NULL, type INTEGER NOT NULL, name TEXT NOT NULL, use_count INTEGER NOT NULL, last_accessed INTEGER NOT NULL, last_modified INTEGER NOT NULL, expiration INTEGER NOT NULL, quota INTEGER NOT NULL); - -CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY, value LONGVARCHAR); - -INSERT INTO meta VALUES ('mmap_status', '-1'); -INSERT INTO meta VALUES ('last_compatible_version', '7'); -INSERT INTO meta VALUES ('version', '7'); - -INSERT INTO quota(host, type, quota) VALUES('a.com', 0, 0); -INSERT INTO quota(host, type, quota) VALUES('b.com', 0, 1); -INSERT INTO quota(host, type, quota) VALUES('c.com', 1, 123); - -INSERT INTO buckets(origin, type, name, use_count, last_accessed, last_modified, expiration, quota) - VALUES('http://a/', 0, 'bucket_a', 123, 13260644621105493, 13242931862595604, 9223372036854775807, 0); -INSERT INTO buckets(origin, type, name, use_count, last_accessed, last_modified, expiration, quota) - VALUES('http://b/', 0, 'bucket_b', 111, 13250042735631065, 13260999511438890, 9223372036854775807, 1000); -INSERT INTO buckets(origin, type, name, use_count, last_accessed, last_modified, expiration, quota) - VALUES('chrome-extension://abc/', 2, 'default', 321, 13261163582572088, 13261079941303629, 9223372036854775807, 10000); - -CREATE UNIQUE INDEX buckets_by_storage_key ON buckets(origin, type, name); - -CREATE INDEX buckets_by_last_accessed ON buckets(type, last_accessed); - -CREATE INDEX buckets_by_last_modified ON buckets(type, last_modified); - -CREATE INDEX buckets_by_expiration ON buckets(expiration); - -COMMIT;
diff --git a/storage/test/data/quota_database/version_8.sql b/storage/test/data/quota_database/version_8.sql deleted file mode 100644 index 1a5c97e..0000000 --- a/storage/test/data/quota_database/version_8.sql +++ /dev/null
@@ -1,36 +0,0 @@ -PRAGMA foreign_keys=OFF; - -BEGIN TRANSACTION; - -CREATE TABLE quota(host TEXT NOT NULL, type INTEGER NOT NULL, quota INTEGER NOT NULL, PRIMARY KEY(host, type)) WITHOUT ROWID; - -CREATE TABLE buckets(id INTEGER PRIMARY KEY, storage_key TEXT NOT NULL, host TEXT NOT NULL, type INTEGER NOT NULL, name TEXT NOT NULL, use_count INTEGER NOT NULL, last_accessed INTEGER NOT NULL, last_modified INTEGER NOT NULL, expiration INTEGER NOT NULL, quota INTEGER NOT NULL); - -CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY, value LONGVARCHAR); - -INSERT INTO meta VALUES ('mmap_status', '-1'); -INSERT INTO meta VALUES ('last_compatible_version', '8'); -INSERT INTO meta VALUES ('version', '8'); - -INSERT INTO quota(host, type, quota) VALUES('a.com', 0, 0); -INSERT INTO quota(host, type, quota) VALUES('b.com', 0, 1); -INSERT INTO quota(host, type, quota) VALUES('c.com', 1, 123); - -INSERT INTO buckets(storage_key, host, type, name, use_count, last_accessed, last_modified, expiration, quota) - VALUES('http://a/', 'http://a/', 0, 'bucket_a', 123, 13260644621105493, 13242931862595604, 9223372036854775807, 0); -INSERT INTO buckets(storage_key, host, type, name, use_count, last_accessed, last_modified, expiration, quota) - VALUES('http://b/', 'http://b/', 0, 'bucket_b', 111, 13250042735631065, 13260999511438890, 9223372036854775807, 1000); -INSERT INTO buckets(storage_key, host, type, name, use_count, last_accessed, last_modified, expiration, quota) - VALUES('chrome-extension://abc/', 'chrome-extension://abc/', 2, 'default', 321, 13261163582572088, 13261079941303629, 9223372036854775807, 10000); - -CREATE UNIQUE INDEX buckets_by_storage_key ON buckets(storage_key, type, name); - -CREATE INDEX buckets_by_host ON buckets(host, type); - -CREATE INDEX buckets_by_last_accessed ON buckets(type, last_accessed); - -CREATE INDEX buckets_by_last_modified ON buckets(type, last_modified); - -CREATE INDEX buckets_by_expiration ON buckets(expiration); - -COMMIT;
diff --git a/storage/test/test_bundle_data.filelist b/storage/test/test_bundle_data.filelist index e126cdd3..065daec 100644 --- a/storage/test/test_bundle_data.filelist +++ b/storage/test/test_bundle_data.filelist
@@ -5,6 +5,4 @@ # If it requires updating, you should get a presubmit error with # instructions on how to regenerate. Otherwise, do not edit. data/quota_database/version_10.sql -data/quota_database/version_7.sql -data/quota_database/version_8.sql data/quota_database/version_9.sql
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index 5a7c74c..f225778 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -17358,21 +17358,6 @@ ] } ], - "PartitionAllocFewerMemoryRegionsMac": [ - { - "platforms": [ - "mac" - ], - "experiments": [ - { - "name": "Enabled", - "enable_features": [ - "PartitionAllocFewerMemoryRegions" - ] - } - ] - } - ], "PartitionAllocLargeThreadCacheSizeAndroid": [ { "platforms": [ @@ -18892,40 +18877,13 @@ ], "experiments": [ { - "name": "5ms", - "params": { - "hover_dwell_time": "5ms" - }, - "enable_features": [ - "PreloadingEagerHeuristics" - ] - }, - { - "name": "10ms", + "name": "Enabled", "params": { "hover_dwell_time": "10ms" }, "enable_features": [ "PreloadingEagerHeuristics" ] - }, - { - "name": "20ms", - "params": { - "hover_dwell_time": "20ms" - }, - "enable_features": [ - "PreloadingEagerHeuristics" - ] - }, - { - "name": "35ms", - "params": { - "hover_dwell_time": "35ms" - }, - "enable_features": [ - "PreloadingEagerHeuristics" - ] } ] } @@ -19338,6 +19296,21 @@ ] } ], + "ProbeStylusWritingInBackground": [ + { + "platforms": [ + "android_webview" + ], + "experiments": [ + { + "name": "Enabled", + "enable_features": [ + "ProbeStylusWritingInBackground" + ] + } + ] + } + ], "ProcessBoundStringEncryption": [ { "platforms": [ @@ -25595,6 +25568,25 @@ ] } ], + "UnoPhase2Desktop": [ + { + "platforms": [ + "linux", + "mac", + "windows" + ], + "experiments": [ + { + "name": "Enabled", + "enable_features": [ + "ForcedDiceMigration", + "ReplaceSyncPromosWithSignInPromos", + "SyncEnableContactInfoDataTypeForCustomPassphraseUsers" + ] + } + ] + } + ], "UpdateStateBeforeUnbinding": [ { "platforms": [
diff --git a/third_party/android_deps/buildSrc/src/main/groovy/ChromiumDepGraph.groovy b/third_party/android_deps/buildSrc/src/main/groovy/ChromiumDepGraph.groovy index adb1c8a..cebb1642 100644 --- a/third_party/android_deps/buildSrc/src/main/groovy/ChromiumDepGraph.groovy +++ b/third_party/android_deps/buildSrc/src/main/groovy/ChromiumDepGraph.groovy
@@ -22,7 +22,7 @@ */ class ChromiumDepGraph { - private static final String DEFAULT_CIPD_SUFFIX = 'cr1' + private static final String DEFAULT_CIPD_SUFFIX = 'cr2' // Some libraries don't properly fill their POM with the appropriate licensing information. It is provided here from // manual lookups. Note that licenseUrl must provide textual content rather than be an html page. @@ -631,7 +631,7 @@ children: Collections.unmodifiableList(new ArrayList<>(childModules)), licenses: licenses, directoryName: id.toLowerCase(), - fileName: artifact.file.name, + fileName: dependency.module.id.name + "." + artifact.extension, fileUrl: fileUrl, repoUrl: repoUrl, description: description,
diff --git a/third_party/android_deps/fetch_common.py b/third_party/android_deps/fetch_common.py index a1bd14ee..6617bf2f 100644 --- a/third_party/android_deps/fetch_common.py +++ b/third_party/android_deps/fetch_common.py
@@ -58,7 +58,7 @@ spec.group_name, spec.module_name, version, spec.file_ext) - file_name = file_url.rsplit('/', 1)[-1] + file_name = f'{spec.module_name}.{spec.file_ext}' partial_manifest = { 'url': [file_url],
diff --git a/third_party/android_deps/libs/com_android_support_support_annotations/3pp/fetch.py b/third_party/android_deps/libs/com_android_support_support_annotations/3pp/fetch.py index 87ef99c..9ac9062 100755 --- a/third_party/android_deps/libs/com_android_support_support_annotations/3pp/fetch.py +++ b/third_party/android_deps/libs/com_android_support_support_annotations/3pp/fetch.py
@@ -18,7 +18,7 @@ group_name='com/android/support', module_name='support-annotations', file_ext='jar', - patch_version='cr1', + patch_version='cr2', version_override=None, version_filter=None)
diff --git a/third_party/android_deps/libs/com_android_support_support_annotations/cipd.yaml b/third_party/android_deps/libs/com_android_support_support_annotations/cipd.yaml index 912bf09..630b230 100644 --- a/third_party/android_deps/libs/com_android_support_support_annotations/cipd.yaml +++ b/third_party/android_deps/libs/com_android_support_support_annotations/cipd.yaml
@@ -3,8 +3,8 @@ # found in the LICENSE file. # To create CIPD package run the following command. -# cipd create --pkg-def cipd.yaml -tag version:2@28.0.0.cr1 +# cipd create --pkg-def cipd.yaml -tag version:2@28.0.0.cr2 package: chromium/third_party/android_deps/libs/com_android_support_support_annotations description: "Android Support Library Annotations" data: -- file: support-annotations-28.0.0.jar +- file: support-annotations.jar
diff --git a/third_party/android_deps/libs/com_android_tools_common/3pp/fetch.py b/third_party/android_deps/libs/com_android_tools_common/3pp/fetch.py index 9d27a3c4..6f5941d 100755 --- a/third_party/android_deps/libs/com_android_tools_common/3pp/fetch.py +++ b/third_party/android_deps/libs/com_android_tools_common/3pp/fetch.py
@@ -18,7 +18,7 @@ group_name='com/android/tools', module_name='common', file_ext='jar', - patch_version='cr1', + patch_version='cr2', version_override=None, version_filter=None)
diff --git a/third_party/android_deps/libs/com_android_tools_common/cipd.yaml b/third_party/android_deps/libs/com_android_tools_common/cipd.yaml index fd26934..82640fb 100644 --- a/third_party/android_deps/libs/com_android_tools_common/cipd.yaml +++ b/third_party/android_deps/libs/com_android_tools_common/cipd.yaml
@@ -3,8 +3,8 @@ # found in the LICENSE file. # To create CIPD package run the following command. -# cipd create --pkg-def cipd.yaml -tag version:2@30.2.0-beta01.cr1 +# cipd create --pkg-def cipd.yaml -tag version:2@30.2.0-beta01.cr2 package: chromium/third_party/android_deps/libs/com_android_tools_common description: "com.android.tools.common" data: -- file: common-30.2.0-beta01.jar +- file: common.jar
diff --git a/third_party/android_deps/libs/com_android_tools_layoutlib_layoutlib_api/3pp/fetch.py b/third_party/android_deps/libs/com_android_tools_layoutlib_layoutlib_api/3pp/fetch.py index 75622b67..d95e0918 100755 --- a/third_party/android_deps/libs/com_android_tools_layoutlib_layoutlib_api/3pp/fetch.py +++ b/third_party/android_deps/libs/com_android_tools_layoutlib_layoutlib_api/3pp/fetch.py
@@ -18,7 +18,7 @@ group_name='com/android/tools/layoutlib', module_name='layoutlib-api', file_ext='jar', - patch_version='cr1', + patch_version='cr2', version_override=None, version_filter=None)
diff --git a/third_party/android_deps/libs/com_android_tools_layoutlib_layoutlib_api/cipd.yaml b/third_party/android_deps/libs/com_android_tools_layoutlib_layoutlib_api/cipd.yaml index 6b73b1f3..4e99c1c 100644 --- a/third_party/android_deps/libs/com_android_tools_layoutlib_layoutlib_api/cipd.yaml +++ b/third_party/android_deps/libs/com_android_tools_layoutlib_layoutlib_api/cipd.yaml
@@ -3,8 +3,8 @@ # found in the LICENSE file. # To create CIPD package run the following command. -# cipd create --pkg-def cipd.yaml -tag version:2@30.2.0-beta01.cr1 +# cipd create --pkg-def cipd.yaml -tag version:2@30.2.0-beta01.cr2 package: chromium/third_party/android_deps/libs/com_android_tools_layoutlib_layoutlib_api description: "Android Tools layoutlib-api" data: -- file: layoutlib-api-30.2.0-beta01.jar +- file: layoutlib-api.jar
diff --git a/third_party/android_deps/libs/com_android_tools_sdk_common/3pp/fetch.py b/third_party/android_deps/libs/com_android_tools_sdk_common/3pp/fetch.py index 3848f6b..1f83485 100755 --- a/third_party/android_deps/libs/com_android_tools_sdk_common/3pp/fetch.py +++ b/third_party/android_deps/libs/com_android_tools_sdk_common/3pp/fetch.py
@@ -18,7 +18,7 @@ group_name='com/android/tools', module_name='sdk-common', file_ext='jar', - patch_version='cr1', + patch_version='cr2', version_override=None, version_filter=None)
diff --git a/third_party/android_deps/libs/com_android_tools_sdk_common/cipd.yaml b/third_party/android_deps/libs/com_android_tools_sdk_common/cipd.yaml index 7cbcc77..23feed88 100644 --- a/third_party/android_deps/libs/com_android_tools_sdk_common/cipd.yaml +++ b/third_party/android_deps/libs/com_android_tools_sdk_common/cipd.yaml
@@ -3,8 +3,8 @@ # found in the LICENSE file. # To create CIPD package run the following command. -# cipd create --pkg-def cipd.yaml -tag version:2@30.2.0-beta01.cr1 +# cipd create --pkg-def cipd.yaml -tag version:2@30.2.0-beta01.cr2 package: chromium/third_party/android_deps/libs/com_android_tools_sdk_common description: "com.android.tools.sdk-common" data: -- file: sdk-common-30.2.0-beta01.jar +- file: sdk-common.jar
diff --git a/third_party/android_deps/libs/com_google_android_apps_common_testing_accessibility_framework_accessibility_test_framework/3pp/fetch.py b/third_party/android_deps/libs/com_google_android_apps_common_testing_accessibility_framework_accessibility_test_framework/3pp/fetch.py index 4672e0e0..736522d 100755 --- a/third_party/android_deps/libs/com_google_android_apps_common_testing_accessibility_framework_accessibility_test_framework/3pp/fetch.py +++ b/third_party/android_deps/libs/com_google_android_apps_common_testing_accessibility_framework_accessibility_test_framework/3pp/fetch.py
@@ -18,7 +18,7 @@ group_name='com/google/android/apps/common/testing/accessibility/framework', module_name='accessibility-test-framework', file_ext='aar', - patch_version='cr1', + patch_version='cr2', version_override=None, version_filter=None)
diff --git a/third_party/android_deps/libs/com_google_android_apps_common_testing_accessibility_framework_accessibility_test_framework/cipd.yaml b/third_party/android_deps/libs/com_google_android_apps_common_testing_accessibility_framework_accessibility_test_framework/cipd.yaml index 117445c1..f98b0ca3 100644 --- a/third_party/android_deps/libs/com_google_android_apps_common_testing_accessibility_framework_accessibility_test_framework/cipd.yaml +++ b/third_party/android_deps/libs/com_google_android_apps_common_testing_accessibility_framework_accessibility_test_framework/cipd.yaml
@@ -3,8 +3,8 @@ # found in the LICENSE file. # To create CIPD package run the following command. -# cipd create --pkg-def cipd.yaml -tag version:2@4.0.0.cr1 +# cipd create --pkg-def cipd.yaml -tag version:2@4.0.0.cr2 package: chromium/third_party/android_deps/libs/com_google_android_apps_common_testing_accessibility_framework_accessibility_test_framework description: "Accessibility Test Framework" data: -- file: accessibility-test-framework-4.0.0.aar +- file: accessibility-test-framework.aar
diff --git a/third_party/android_deps/libs/com_googlecode_java_diff_utils_diffutils/3pp/fetch.py b/third_party/android_deps/libs/com_googlecode_java_diff_utils_diffutils/3pp/fetch.py index c4b9ca3c..a40768f1 100755 --- a/third_party/android_deps/libs/com_googlecode_java_diff_utils_diffutils/3pp/fetch.py +++ b/third_party/android_deps/libs/com_googlecode_java_diff_utils_diffutils/3pp/fetch.py
@@ -18,7 +18,7 @@ group_name='com/googlecode/java-diff-utils', module_name='diffutils', file_ext='jar', - patch_version='cr1', + patch_version='cr2', version_override=None, version_filter=None)
diff --git a/third_party/android_deps/libs/com_googlecode_java_diff_utils_diffutils/cipd.yaml b/third_party/android_deps/libs/com_googlecode_java_diff_utils_diffutils/cipd.yaml index 1f14f90..c99ca33 100644 --- a/third_party/android_deps/libs/com_googlecode_java_diff_utils_diffutils/cipd.yaml +++ b/third_party/android_deps/libs/com_googlecode_java_diff_utils_diffutils/cipd.yaml
@@ -3,8 +3,8 @@ # found in the LICENSE file. # To create CIPD package run the following command. -# cipd create --pkg-def cipd.yaml -tag version:2@1.3.0.cr1 +# cipd create --pkg-def cipd.yaml -tag version:2@1.3.0.cr2 package: chromium/third_party/android_deps/libs/com_googlecode_java_diff_utils_diffutils description: "java-diff-utils" data: -- file: diffutils-1.3.0.jar +- file: diffutils.jar
diff --git a/third_party/android_deps/libs/com_squareup_javapoet/3pp/fetch.py b/third_party/android_deps/libs/com_squareup_javapoet/3pp/fetch.py index 7874d5f6..8e2b7b8 100755 --- a/third_party/android_deps/libs/com_squareup_javapoet/3pp/fetch.py +++ b/third_party/android_deps/libs/com_squareup_javapoet/3pp/fetch.py
@@ -18,7 +18,7 @@ group_name='com/squareup', module_name='javapoet', file_ext='jar', - patch_version='cr1', + patch_version='cr2', version_override=None, version_filter=None)
diff --git a/third_party/android_deps/libs/com_squareup_javapoet/cipd.yaml b/third_party/android_deps/libs/com_squareup_javapoet/cipd.yaml index 1c8fb0d..b59e16a 100644 --- a/third_party/android_deps/libs/com_squareup_javapoet/cipd.yaml +++ b/third_party/android_deps/libs/com_squareup_javapoet/cipd.yaml
@@ -3,8 +3,8 @@ # found in the LICENSE file. # To create CIPD package run the following command. -# cipd create --pkg-def cipd.yaml -tag version:2@1.13.0.cr1 +# cipd create --pkg-def cipd.yaml -tag version:2@1.13.0.cr2 package: chromium/third_party/android_deps/libs/com_squareup_javapoet description: "JavaPoet" data: -- file: javapoet-1.13.0.jar +- file: javapoet.jar
diff --git a/third_party/android_deps/libs/net_bytebuddy_byte_buddy/3pp/fetch.py b/third_party/android_deps/libs/net_bytebuddy_byte_buddy/3pp/fetch.py index 74cf1cf..9a9283f 100755 --- a/third_party/android_deps/libs/net_bytebuddy_byte_buddy/3pp/fetch.py +++ b/third_party/android_deps/libs/net_bytebuddy_byte_buddy/3pp/fetch.py
@@ -18,7 +18,7 @@ group_name='net/bytebuddy', module_name='byte-buddy', file_ext='jar', - patch_version='cr1', + patch_version='cr2', version_override=None, version_filter=None)
diff --git a/third_party/android_deps/libs/net_bytebuddy_byte_buddy/cipd.yaml b/third_party/android_deps/libs/net_bytebuddy_byte_buddy/cipd.yaml index 18e7d58..953e9ef 100644 --- a/third_party/android_deps/libs/net_bytebuddy_byte_buddy/cipd.yaml +++ b/third_party/android_deps/libs/net_bytebuddy_byte_buddy/cipd.yaml
@@ -3,8 +3,8 @@ # found in the LICENSE file. # To create CIPD package run the following command. -# cipd create --pkg-def cipd.yaml -tag version:2@1.17.6.cr1 +# cipd create --pkg-def cipd.yaml -tag version:2@1.17.6.cr2 package: chromium/third_party/android_deps/libs/net_bytebuddy_byte_buddy description: "Byte Buddy (without dependencies)" data: -- file: byte-buddy-1.17.6.jar +- file: byte-buddy.jar
diff --git a/third_party/android_deps/libs/net_bytebuddy_byte_buddy_agent/3pp/fetch.py b/third_party/android_deps/libs/net_bytebuddy_byte_buddy_agent/3pp/fetch.py index 8d11600..72ab3784 100755 --- a/third_party/android_deps/libs/net_bytebuddy_byte_buddy_agent/3pp/fetch.py +++ b/third_party/android_deps/libs/net_bytebuddy_byte_buddy_agent/3pp/fetch.py
@@ -18,7 +18,7 @@ group_name='net/bytebuddy', module_name='byte-buddy-agent', file_ext='jar', - patch_version='cr1', + patch_version='cr2', version_override=None, version_filter=None)
diff --git a/third_party/android_deps/libs/net_bytebuddy_byte_buddy_agent/cipd.yaml b/third_party/android_deps/libs/net_bytebuddy_byte_buddy_agent/cipd.yaml index 47b05dc..1f36f9d5 100644 --- a/third_party/android_deps/libs/net_bytebuddy_byte_buddy_agent/cipd.yaml +++ b/third_party/android_deps/libs/net_bytebuddy_byte_buddy_agent/cipd.yaml
@@ -3,8 +3,8 @@ # found in the LICENSE file. # To create CIPD package run the following command. -# cipd create --pkg-def cipd.yaml -tag version:2@1.17.6.cr1 +# cipd create --pkg-def cipd.yaml -tag version:2@1.17.6.cr2 package: chromium/third_party/android_deps/libs/net_bytebuddy_byte_buddy_agent description: "Byte Buddy agent" data: -- file: byte-buddy-agent-1.17.6.jar +- file: byte-buddy-agent.jar
diff --git a/third_party/android_deps/libs/org_ccil_cowan_tagsoup_tagsoup/3pp/fetch.py b/third_party/android_deps/libs/org_ccil_cowan_tagsoup_tagsoup/3pp/fetch.py index 72c4b21..cfe7e9d6 100755 --- a/third_party/android_deps/libs/org_ccil_cowan_tagsoup_tagsoup/3pp/fetch.py +++ b/third_party/android_deps/libs/org_ccil_cowan_tagsoup_tagsoup/3pp/fetch.py
@@ -18,7 +18,7 @@ group_name='org/ccil/cowan/tagsoup', module_name='tagsoup', file_ext='jar', - patch_version='cr1', + patch_version='cr2', version_override=None, version_filter=None)
diff --git a/third_party/android_deps/libs/org_ccil_cowan_tagsoup_tagsoup/cipd.yaml b/third_party/android_deps/libs/org_ccil_cowan_tagsoup_tagsoup/cipd.yaml index 211e72c..dafec701 100644 --- a/third_party/android_deps/libs/org_ccil_cowan_tagsoup_tagsoup/cipd.yaml +++ b/third_party/android_deps/libs/org_ccil_cowan_tagsoup_tagsoup/cipd.yaml
@@ -3,8 +3,8 @@ # found in the LICENSE file. # To create CIPD package run the following command. -# cipd create --pkg-def cipd.yaml -tag version:2@1.2.1.cr1 +# cipd create --pkg-def cipd.yaml -tag version:2@1.2.1.cr2 package: chromium/third_party/android_deps/libs/org_ccil_cowan_tagsoup_tagsoup description: "TagSoup" data: -- file: tagsoup-1.2.1.jar +- file: tagsoup.jar
diff --git a/third_party/android_deps/libs/org_checkerframework_checker_compat_qual/3pp/fetch.py b/third_party/android_deps/libs/org_checkerframework_checker_compat_qual/3pp/fetch.py index 353ae22..b8729b3 100755 --- a/third_party/android_deps/libs/org_checkerframework_checker_compat_qual/3pp/fetch.py +++ b/third_party/android_deps/libs/org_checkerframework_checker_compat_qual/3pp/fetch.py
@@ -18,7 +18,7 @@ group_name='org/checkerframework', module_name='checker-compat-qual', file_ext='jar', - patch_version='cr1', + patch_version='cr2', version_override=None, version_filter=None)
diff --git a/third_party/android_deps/libs/org_checkerframework_checker_compat_qual/cipd.yaml b/third_party/android_deps/libs/org_checkerframework_checker_compat_qual/cipd.yaml index cfaffdb..781b8b9 100644 --- a/third_party/android_deps/libs/org_checkerframework_checker_compat_qual/cipd.yaml +++ b/third_party/android_deps/libs/org_checkerframework_checker_compat_qual/cipd.yaml
@@ -3,8 +3,8 @@ # found in the LICENSE file. # To create CIPD package run the following command. -# cipd create --pkg-def cipd.yaml -tag version:2@2.5.5.cr1 +# cipd create --pkg-def cipd.yaml -tag version:2@2.5.5.cr2 package: chromium/third_party/android_deps/libs/org_checkerframework_checker_compat_qual description: "Checker Qual" data: -- file: checker-compat-qual-2.5.5.jar +- file: checker-compat-qual.jar
diff --git a/third_party/android_deps/libs/org_jetbrains_kotlin_kotlin_android_extensions_runtime/3pp/fetch.py b/third_party/android_deps/libs/org_jetbrains_kotlin_kotlin_android_extensions_runtime/3pp/fetch.py index 7d5e697f..7143e215 100755 --- a/third_party/android_deps/libs/org_jetbrains_kotlin_kotlin_android_extensions_runtime/3pp/fetch.py +++ b/third_party/android_deps/libs/org_jetbrains_kotlin_kotlin_android_extensions_runtime/3pp/fetch.py
@@ -18,7 +18,7 @@ group_name='org/jetbrains/kotlin', module_name='kotlin-android-extensions-runtime', file_ext='jar', - patch_version='cr1', + patch_version='cr2', version_override=None, version_filter=None)
diff --git a/third_party/android_deps/libs/org_jetbrains_kotlin_kotlin_android_extensions_runtime/cipd.yaml b/third_party/android_deps/libs/org_jetbrains_kotlin_kotlin_android_extensions_runtime/cipd.yaml index 9f76784..c589a463 100644 --- a/third_party/android_deps/libs/org_jetbrains_kotlin_kotlin_android_extensions_runtime/cipd.yaml +++ b/third_party/android_deps/libs/org_jetbrains_kotlin_kotlin_android_extensions_runtime/cipd.yaml
@@ -3,8 +3,8 @@ # found in the LICENSE file. # To create CIPD package run the following command. -# cipd create --pkg-def cipd.yaml -tag version:2@1.9.22.cr1 +# cipd create --pkg-def cipd.yaml -tag version:2@1.9.22.cr2 package: chromium/third_party/android_deps/libs/org_jetbrains_kotlin_kotlin_android_extensions_runtime description: "Kotlin Android Extensions Runtime" data: -- file: kotlin-android-extensions-runtime-1.9.22.jar +- file: kotlin-android-extensions-runtime.jar
diff --git a/third_party/android_deps/libs/org_jetbrains_kotlin_kotlin_parcelize_runtime/3pp/fetch.py b/third_party/android_deps/libs/org_jetbrains_kotlin_kotlin_parcelize_runtime/3pp/fetch.py index ebd5c9f7..00a64b3d 100755 --- a/third_party/android_deps/libs/org_jetbrains_kotlin_kotlin_parcelize_runtime/3pp/fetch.py +++ b/third_party/android_deps/libs/org_jetbrains_kotlin_kotlin_parcelize_runtime/3pp/fetch.py
@@ -18,7 +18,7 @@ group_name='org/jetbrains/kotlin', module_name='kotlin-parcelize-runtime', file_ext='jar', - patch_version='cr1', + patch_version='cr2', version_override=None, version_filter=None)
diff --git a/third_party/android_deps/libs/org_jetbrains_kotlin_kotlin_parcelize_runtime/cipd.yaml b/third_party/android_deps/libs/org_jetbrains_kotlin_kotlin_parcelize_runtime/cipd.yaml index fc52e08..59c9486 100644 --- a/third_party/android_deps/libs/org_jetbrains_kotlin_kotlin_parcelize_runtime/cipd.yaml +++ b/third_party/android_deps/libs/org_jetbrains_kotlin_kotlin_parcelize_runtime/cipd.yaml
@@ -3,8 +3,8 @@ # found in the LICENSE file. # To create CIPD package run the following command. -# cipd create --pkg-def cipd.yaml -tag version:2@1.9.22.cr1 +# cipd create --pkg-def cipd.yaml -tag version:2@1.9.22.cr2 package: chromium/third_party/android_deps/libs/org_jetbrains_kotlin_kotlin_parcelize_runtime description: "Parcelize Runtime" data: -- file: kotlin-parcelize-runtime-1.9.22.jar +- file: kotlin-parcelize-runtime.jar
diff --git a/third_party/android_deps/libs/org_jetbrains_kotlinx_atomicfu_jvm/3pp/fetch.py b/third_party/android_deps/libs/org_jetbrains_kotlinx_atomicfu_jvm/3pp/fetch.py index 3429724f..853e8155 100755 --- a/third_party/android_deps/libs/org_jetbrains_kotlinx_atomicfu_jvm/3pp/fetch.py +++ b/third_party/android_deps/libs/org_jetbrains_kotlinx_atomicfu_jvm/3pp/fetch.py
@@ -18,7 +18,7 @@ group_name='org/jetbrains/kotlinx', module_name='atomicfu-jvm', file_ext='jar', - patch_version='cr1', + patch_version='cr2', version_override=None, version_filter=None)
diff --git a/third_party/android_deps/libs/org_jetbrains_kotlinx_atomicfu_jvm/cipd.yaml b/third_party/android_deps/libs/org_jetbrains_kotlinx_atomicfu_jvm/cipd.yaml index ed9335c6..c841677 100644 --- a/third_party/android_deps/libs/org_jetbrains_kotlinx_atomicfu_jvm/cipd.yaml +++ b/third_party/android_deps/libs/org_jetbrains_kotlinx_atomicfu_jvm/cipd.yaml
@@ -3,8 +3,8 @@ # found in the LICENSE file. # To create CIPD package run the following command. -# cipd create --pkg-def cipd.yaml -tag version:2@0.23.2.cr1 +# cipd create --pkg-def cipd.yaml -tag version:2@0.23.2.cr2 package: chromium/third_party/android_deps/libs/org_jetbrains_kotlinx_atomicfu_jvm description: "atomicfu" data: -- file: atomicfu-jvm-0.23.2.jar +- file: atomicfu-jvm.jar
diff --git a/third_party/android_deps/libs/org_jetbrains_kotlinx_kotlinx_coroutines_guava/3pp/fetch.py b/third_party/android_deps/libs/org_jetbrains_kotlinx_kotlinx_coroutines_guava/3pp/fetch.py index cc08f051..62bb88b 100755 --- a/third_party/android_deps/libs/org_jetbrains_kotlinx_kotlinx_coroutines_guava/3pp/fetch.py +++ b/third_party/android_deps/libs/org_jetbrains_kotlinx_kotlinx_coroutines_guava/3pp/fetch.py
@@ -18,7 +18,7 @@ group_name='org/jetbrains/kotlinx', module_name='kotlinx-coroutines-guava', file_ext='jar', - patch_version='cr1', + patch_version='cr2', version_override=None, version_filter=None)
diff --git a/third_party/android_deps/libs/org_jetbrains_kotlinx_kotlinx_coroutines_guava/cipd.yaml b/third_party/android_deps/libs/org_jetbrains_kotlinx_kotlinx_coroutines_guava/cipd.yaml index 22c9799..18a8f26 100644 --- a/third_party/android_deps/libs/org_jetbrains_kotlinx_kotlinx_coroutines_guava/cipd.yaml +++ b/third_party/android_deps/libs/org_jetbrains_kotlinx_kotlinx_coroutines_guava/cipd.yaml
@@ -3,8 +3,8 @@ # found in the LICENSE file. # To create CIPD package run the following command. -# cipd create --pkg-def cipd.yaml -tag version:2@1.8.1.cr1 +# cipd create --pkg-def cipd.yaml -tag version:2@1.8.1.cr2 package: chromium/third_party/android_deps/libs/org_jetbrains_kotlinx_kotlinx_coroutines_guava description: "kotlinx-coroutines-guava" data: -- file: kotlinx-coroutines-guava-1.8.1.jar +- file: kotlinx-coroutines-guava.jar
diff --git a/third_party/android_deps/libs/org_jsoup_jsoup/3pp/fetch.py b/third_party/android_deps/libs/org_jsoup_jsoup/3pp/fetch.py index 0fb00215..3cd2195 100755 --- a/third_party/android_deps/libs/org_jsoup_jsoup/3pp/fetch.py +++ b/third_party/android_deps/libs/org_jsoup_jsoup/3pp/fetch.py
@@ -18,7 +18,7 @@ group_name='org/jsoup', module_name='jsoup', file_ext='jar', - patch_version='cr1', + patch_version='cr2', version_override=None, version_filter=None)
diff --git a/third_party/android_deps/libs/org_jsoup_jsoup/cipd.yaml b/third_party/android_deps/libs/org_jsoup_jsoup/cipd.yaml index b390786..a379a807 100644 --- a/third_party/android_deps/libs/org_jsoup_jsoup/cipd.yaml +++ b/third_party/android_deps/libs/org_jsoup_jsoup/cipd.yaml
@@ -3,8 +3,8 @@ # found in the LICENSE file. # To create CIPD package run the following command. -# cipd create --pkg-def cipd.yaml -tag version:2@1.15.1.cr1 +# cipd create --pkg-def cipd.yaml -tag version:2@1.15.1.cr2 package: chromium/third_party/android_deps/libs/org_jsoup_jsoup description: "jsoup Java HTML Parser" data: -- file: jsoup-1.15.1.jar +- file: jsoup.jar
diff --git a/third_party/android_deps/libs/org_mockito_mockito_android/3pp/fetch.py b/third_party/android_deps/libs/org_mockito_mockito_android/3pp/fetch.py index d96f3db0..2563c41 100755 --- a/third_party/android_deps/libs/org_mockito_mockito_android/3pp/fetch.py +++ b/third_party/android_deps/libs/org_mockito_mockito_android/3pp/fetch.py
@@ -18,7 +18,7 @@ group_name='org/mockito', module_name='mockito-android', file_ext='jar', - patch_version='cr1', + patch_version='cr2', version_override=None, version_filter=None)
diff --git a/third_party/android_deps/libs/org_mockito_mockito_android/cipd.yaml b/third_party/android_deps/libs/org_mockito_mockito_android/cipd.yaml index 33c1b54..6fefb000e 100644 --- a/third_party/android_deps/libs/org_mockito_mockito_android/cipd.yaml +++ b/third_party/android_deps/libs/org_mockito_mockito_android/cipd.yaml
@@ -3,8 +3,8 @@ # found in the LICENSE file. # To create CIPD package run the following command. -# cipd create --pkg-def cipd.yaml -tag version:2@5.19.0.cr1 +# cipd create --pkg-def cipd.yaml -tag version:2@5.19.0.cr2 package: chromium/third_party/android_deps/libs/org_mockito_mockito_android description: "mockito-android" data: -- file: mockito-android-5.19.0.jar +- file: mockito-android.jar
diff --git a/third_party/android_deps/libs/org_mockito_mockito_core/3pp/fetch.py b/third_party/android_deps/libs/org_mockito_mockito_core/3pp/fetch.py index 60dffc4c..13719b6 100755 --- a/third_party/android_deps/libs/org_mockito_mockito_core/3pp/fetch.py +++ b/third_party/android_deps/libs/org_mockito_mockito_core/3pp/fetch.py
@@ -18,7 +18,7 @@ group_name='org/mockito', module_name='mockito-core', file_ext='jar', - patch_version='cr1', + patch_version='cr2', version_override=None, version_filter=None)
diff --git a/third_party/android_deps/libs/org_mockito_mockito_core/cipd.yaml b/third_party/android_deps/libs/org_mockito_mockito_core/cipd.yaml index 4ef02da8..93c1bd5 100644 --- a/third_party/android_deps/libs/org_mockito_mockito_core/cipd.yaml +++ b/third_party/android_deps/libs/org_mockito_mockito_core/cipd.yaml
@@ -3,8 +3,8 @@ # found in the LICENSE file. # To create CIPD package run the following command. -# cipd create --pkg-def cipd.yaml -tag version:2@5.19.0.cr1 +# cipd create --pkg-def cipd.yaml -tag version:2@5.19.0.cr2 package: chromium/third_party/android_deps/libs/org_mockito_mockito_core description: "mockito-core" data: -- file: mockito-core-5.19.0.jar +- file: mockito-core.jar
diff --git a/third_party/android_deps/libs/org_mockito_mockito_subclass/3pp/fetch.py b/third_party/android_deps/libs/org_mockito_mockito_subclass/3pp/fetch.py index ee85e7a2..43aa864 100755 --- a/third_party/android_deps/libs/org_mockito_mockito_subclass/3pp/fetch.py +++ b/third_party/android_deps/libs/org_mockito_mockito_subclass/3pp/fetch.py
@@ -18,7 +18,7 @@ group_name='org/mockito', module_name='mockito-subclass', file_ext='jar', - patch_version='cr1', + patch_version='cr2', version_override=None, version_filter=None)
diff --git a/third_party/android_deps/libs/org_mockito_mockito_subclass/cipd.yaml b/third_party/android_deps/libs/org_mockito_mockito_subclass/cipd.yaml index 6f6e274d..f5e36ab 100644 --- a/third_party/android_deps/libs/org_mockito_mockito_subclass/cipd.yaml +++ b/third_party/android_deps/libs/org_mockito_mockito_subclass/cipd.yaml
@@ -3,8 +3,8 @@ # found in the LICENSE file. # To create CIPD package run the following command. -# cipd create --pkg-def cipd.yaml -tag version:2@5.19.0.cr1 +# cipd create --pkg-def cipd.yaml -tag version:2@5.19.0.cr2 package: chromium/third_party/android_deps/libs/org_mockito_mockito_subclass description: "mockito-subclass" data: -- file: mockito-subclass-5.19.0.jar +- file: mockito-subclass.jar
diff --git a/third_party/android_deps/libs/org_objenesis_objenesis/3pp/fetch.py b/third_party/android_deps/libs/org_objenesis_objenesis/3pp/fetch.py index 8135a838..692257c 100755 --- a/third_party/android_deps/libs/org_objenesis_objenesis/3pp/fetch.py +++ b/third_party/android_deps/libs/org_objenesis_objenesis/3pp/fetch.py
@@ -18,7 +18,7 @@ group_name='org/objenesis', module_name='objenesis', file_ext='jar', - patch_version='cr1', + patch_version='cr2', version_override=None, version_filter=None)
diff --git a/third_party/android_deps/libs/org_objenesis_objenesis/cipd.yaml b/third_party/android_deps/libs/org_objenesis_objenesis/cipd.yaml index d4eb96b..b383dbee 100644 --- a/third_party/android_deps/libs/org_objenesis_objenesis/cipd.yaml +++ b/third_party/android_deps/libs/org_objenesis_objenesis/cipd.yaml
@@ -3,8 +3,8 @@ # found in the LICENSE file. # To create CIPD package run the following command. -# cipd create --pkg-def cipd.yaml -tag version:2@3.3.cr1 +# cipd create --pkg-def cipd.yaml -tag version:2@3.3.cr2 package: chromium/third_party/android_deps/libs/org_objenesis_objenesis description: "Objenesis" data: -- file: objenesis-3.3.jar +- file: objenesis.jar
diff --git a/third_party/androidx/BUILD.gn b/third_party/androidx/BUILD.gn index aa3ed21..e4b70e6 100644 --- a/third_party/androidx/BUILD.gn +++ b/third_party/androidx/BUILD.gn
@@ -2130,6 +2130,7 @@ ":androidx_savedstate_savedstate_compose_java", ":androidx_savedstate_savedstate_ktx_java", ":androidx_transition_transition_java", + ":androidx_window_window_java", "//third_party/android_deps:org_jetbrains_kotlinx_kotlinx_coroutines_android_java", "//third_party/android_deps:org_jetbrains_kotlinx_kotlinx_coroutines_core_java", "//third_party/android_deps:org_jspecify_jspecify_java",
diff --git a/third_party/androidx/build.gradle b/third_party/androidx/build.gradle index 4208ee2..6b2b348 100644 --- a/third_party/androidx/build.gradle +++ b/third_party/androidx/build.gradle
@@ -314,7 +314,7 @@ google() maven { // This URL is generated by the fetch_all_androidx.py script. - url 'https://androidx.dev/snapshots/builds/14169252/artifacts/repository' + url 'https://androidx.dev/snapshots/builds/14172195/artifacts/repository' } mavenCentral() }
diff --git a/third_party/androidx/committed/libs/androidx_activity_activity/README.chromium b/third_party/androidx/committed/libs/androidx_activity_activity/README.chromium index 787427f..d383d11 100644 --- a/third_party/androidx/committed/libs/androidx_activity_activity/README.chromium +++ b/third_party/androidx/committed/libs/androidx_activity_activity/README.chromium
@@ -1,6 +1,6 @@ Name: Activity Short Name: activity -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/activity/activity/1.12.0-SNAPSHOT/activity-1.12.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/activity/activity/1.12.0-SNAPSHOT/activity-1.12.0-20250926.054752-1.aar Version: 1.12.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_activity_activity_compose/README.chromium b/third_party/androidx/committed/libs/androidx_activity_activity_compose/README.chromium index dd8a1aaa..db6ca01 100644 --- a/third_party/androidx/committed/libs/androidx_activity_activity_compose/README.chromium +++ b/third_party/androidx/committed/libs/androidx_activity_activity_compose/README.chromium
@@ -1,6 +1,6 @@ Name: Activity Compose Short Name: activity-compose -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/activity/activity-compose/1.12.0-SNAPSHOT/activity-compose-1.12.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/activity/activity-compose/1.12.0-SNAPSHOT/activity-compose-1.12.0-20250926.054752-1.aar Version: 1.12.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_activity_activity_ktx/README.chromium b/third_party/androidx/committed/libs/androidx_activity_activity_ktx/README.chromium index 0585096..ffce9bb2 100644 --- a/third_party/androidx/committed/libs/androidx_activity_activity_ktx/README.chromium +++ b/third_party/androidx/committed/libs/androidx_activity_activity_ktx/README.chromium
@@ -1,6 +1,6 @@ Name: Activity Kotlin Extensions Short Name: activity-ktx -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/activity/activity-ktx/1.12.0-SNAPSHOT/activity-ktx-1.12.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/activity/activity-ktx/1.12.0-SNAPSHOT/activity-ktx-1.12.0-20250926.054752-1.aar Version: 1.12.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_annotation_annotation_experimental/README.chromium b/third_party/androidx/committed/libs/androidx_annotation_annotation_experimental/README.chromium index 5cb6ae61..b653469 100644 --- a/third_party/androidx/committed/libs/androidx_annotation_annotation_experimental/README.chromium +++ b/third_party/androidx/committed/libs/androidx_annotation_annotation_experimental/README.chromium
@@ -1,6 +1,6 @@ Name: Experimental annotation Short Name: annotation-experimental -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/annotation/annotation-experimental/1.6.0-SNAPSHOT/annotation-experimental-1.6.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/annotation/annotation-experimental/1.6.0-SNAPSHOT/annotation-experimental-1.6.0-20250926.054752-1.aar Version: 1.6.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_annotation_annotation_jvm/README.chromium b/third_party/androidx/committed/libs/androidx_annotation_annotation_jvm/README.chromium index 746430f1..f3341ab 100644 --- a/third_party/androidx/committed/libs/androidx_annotation_annotation_jvm/README.chromium +++ b/third_party/androidx/committed/libs/androidx_annotation_annotation_jvm/README.chromium
@@ -1,6 +1,6 @@ Name: Annotation Short Name: annotation-jvm -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/annotation/annotation-jvm/1.10.0-SNAPSHOT/annotation-jvm-1.10.0-20250925.204401-1.jar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/annotation/annotation-jvm/1.10.0-SNAPSHOT/annotation-jvm-1.10.0-20250926.054752-1.jar Version: 1.10.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_appcompat_appcompat/README.chromium b/third_party/androidx/committed/libs/androidx_appcompat_appcompat/README.chromium index 79dde70..bd5eb03 100644 --- a/third_party/androidx/committed/libs/androidx_appcompat_appcompat/README.chromium +++ b/third_party/androidx/committed/libs/androidx_appcompat_appcompat/README.chromium
@@ -1,6 +1,6 @@ Name: AppCompat Short Name: appcompat -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/appcompat/appcompat/1.8.0-SNAPSHOT/appcompat-1.8.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/appcompat/appcompat/1.8.0-SNAPSHOT/appcompat-1.8.0-20250926.054752-1.aar Version: 1.8.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_appcompat_appcompat_resources/README.chromium b/third_party/androidx/committed/libs/androidx_appcompat_appcompat_resources/README.chromium index 8a49051..1bcfadd 100644 --- a/third_party/androidx/committed/libs/androidx_appcompat_appcompat_resources/README.chromium +++ b/third_party/androidx/committed/libs/androidx_appcompat_appcompat_resources/README.chromium
@@ -1,6 +1,6 @@ Name: AppCompat Resources Short Name: appcompat-resources -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/appcompat/appcompat-resources/1.8.0-SNAPSHOT/appcompat-resources-1.8.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/appcompat/appcompat-resources/1.8.0-SNAPSHOT/appcompat-resources-1.8.0-20250926.054752-1.aar Version: 1.8.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_appsearch_appsearch/README.chromium b/third_party/androidx/committed/libs/androidx_appsearch_appsearch/README.chromium index e2bf2f6..f223ac58 100644 --- a/third_party/androidx/committed/libs/androidx_appsearch_appsearch/README.chromium +++ b/third_party/androidx/committed/libs/androidx_appsearch_appsearch/README.chromium
@@ -1,6 +1,6 @@ Name: AppSearch Short Name: appsearch -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/appsearch/appsearch/1.2.0-SNAPSHOT/appsearch-1.2.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/appsearch/appsearch/1.2.0-SNAPSHOT/appsearch-1.2.0-20250926.054752-1.aar Version: 1.2.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_appsearch_appsearch_builtin_types/README.chromium b/third_party/androidx/committed/libs/androidx_appsearch_appsearch_builtin_types/README.chromium index 52dcea6..f8f224f8 100644 --- a/third_party/androidx/committed/libs/androidx_appsearch_appsearch_builtin_types/README.chromium +++ b/third_party/androidx/committed/libs/androidx_appsearch_appsearch_builtin_types/README.chromium
@@ -1,6 +1,6 @@ Name: AppSearch Builtin Types Short Name: appsearch-builtin-types -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/appsearch/appsearch-builtin-types/1.2.0-SNAPSHOT/appsearch-builtin-types-1.2.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/appsearch/appsearch-builtin-types/1.2.0-SNAPSHOT/appsearch-builtin-types-1.2.0-20250926.054752-1.aar Version: 1.2.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_appsearch_appsearch_platform_storage/README.chromium b/third_party/androidx/committed/libs/androidx_appsearch_appsearch_platform_storage/README.chromium index 016bada..c79010c 100644 --- a/third_party/androidx/committed/libs/androidx_appsearch_appsearch_platform_storage/README.chromium +++ b/third_party/androidx/committed/libs/androidx_appsearch_appsearch_platform_storage/README.chromium
@@ -1,6 +1,6 @@ Name: AppSearch Platform Storage Short Name: appsearch-platform-storage -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/appsearch/appsearch-platform-storage/1.2.0-SNAPSHOT/appsearch-platform-storage-1.2.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/appsearch/appsearch-platform-storage/1.2.0-SNAPSHOT/appsearch-platform-storage-1.2.0-20250926.054752-1.aar Version: 1.2.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_arch_core_core_common/README.chromium b/third_party/androidx/committed/libs/androidx_arch_core_core_common/README.chromium index 246d07f..fd8115fa 100644 --- a/third_party/androidx/committed/libs/androidx_arch_core_core_common/README.chromium +++ b/third_party/androidx/committed/libs/androidx_arch_core_core_common/README.chromium
@@ -1,6 +1,6 @@ Name: Arch-Common Short Name: core-common -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/arch/core/core-common/2.3.0-SNAPSHOT/core-common-2.3.0-20250925.204401-1.jar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/arch/core/core-common/2.3.0-SNAPSHOT/core-common-2.3.0-20250926.054752-1.jar Version: 2.3.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_arch_core_core_runtime/README.chromium b/third_party/androidx/committed/libs/androidx_arch_core_core_runtime/README.chromium index 7864d679..89dbd7fa 100644 --- a/third_party/androidx/committed/libs/androidx_arch_core_core_runtime/README.chromium +++ b/third_party/androidx/committed/libs/androidx_arch_core_core_runtime/README.chromium
@@ -1,6 +1,6 @@ Name: Arch-Runtime Short Name: core-runtime -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/arch/core/core-runtime/2.3.0-SNAPSHOT/core-runtime-2.3.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/arch/core/core-runtime/2.3.0-SNAPSHOT/core-runtime-2.3.0-20250926.054752-1.aar Version: 2.3.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_autofill_autofill/README.chromium b/third_party/androidx/committed/libs/androidx_autofill_autofill/README.chromium index 4bf1fe35..4ab17448 100644 --- a/third_party/androidx/committed/libs/androidx_autofill_autofill/README.chromium +++ b/third_party/androidx/committed/libs/androidx_autofill_autofill/README.chromium
@@ -1,6 +1,6 @@ Name: Autofill Short Name: autofill -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/autofill/autofill/1.4.0-SNAPSHOT/autofill-1.4.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/autofill/autofill/1.4.0-SNAPSHOT/autofill-1.4.0-20250926.054752-1.aar Version: 1.4.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_benchmark_benchmark_common/README.chromium b/third_party/androidx/committed/libs/androidx_benchmark_benchmark_common/README.chromium index fda22f8..d6e6b00 100644 --- a/third_party/androidx/committed/libs/androidx_benchmark_benchmark_common/README.chromium +++ b/third_party/androidx/committed/libs/androidx_benchmark_benchmark_common/README.chromium
@@ -1,6 +1,6 @@ Name: Benchmark - Common Short Name: benchmark-common -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/benchmark/benchmark-common/1.5.0-SNAPSHOT/benchmark-common-1.5.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/benchmark/benchmark-common/1.5.0-SNAPSHOT/benchmark-common-1.5.0-20250926.054752-1.aar Version: 1.5.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_benchmark_benchmark_junit4/README.chromium b/third_party/androidx/committed/libs/androidx_benchmark_benchmark_junit4/README.chromium index 4eaa7c0..c33529f 100644 --- a/third_party/androidx/committed/libs/androidx_benchmark_benchmark_junit4/README.chromium +++ b/third_party/androidx/committed/libs/androidx_benchmark_benchmark_junit4/README.chromium
@@ -1,6 +1,6 @@ Name: Benchmark - JUnit4 Short Name: benchmark-junit4 -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/benchmark/benchmark-junit4/1.5.0-SNAPSHOT/benchmark-junit4-1.5.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/benchmark/benchmark-junit4/1.5.0-SNAPSHOT/benchmark-junit4-1.5.0-20250926.054752-1.aar Version: 1.5.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_benchmark_benchmark_macro/README.chromium b/third_party/androidx/committed/libs/androidx_benchmark_benchmark_macro/README.chromium index c7741c5..51101721 100644 --- a/third_party/androidx/committed/libs/androidx_benchmark_benchmark_macro/README.chromium +++ b/third_party/androidx/committed/libs/androidx_benchmark_benchmark_macro/README.chromium
@@ -1,6 +1,6 @@ Name: Benchmark - Macrobenchmark Short Name: benchmark-macro -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/benchmark/benchmark-macro/1.5.0-SNAPSHOT/benchmark-macro-1.5.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/benchmark/benchmark-macro/1.5.0-SNAPSHOT/benchmark-macro-1.5.0-20250926.054752-1.aar Version: 1.5.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_benchmark_benchmark_macro_junit4/README.chromium b/third_party/androidx/committed/libs/androidx_benchmark_benchmark_macro_junit4/README.chromium index 65461cdf..d0c1006 100644 --- a/third_party/androidx/committed/libs/androidx_benchmark_benchmark_macro_junit4/README.chromium +++ b/third_party/androidx/committed/libs/androidx_benchmark_benchmark_macro_junit4/README.chromium
@@ -1,6 +1,6 @@ Name: Benchmark - Macrobenchmark JUnit4 Short Name: benchmark-macro-junit4 -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/benchmark/benchmark-macro-junit4/1.5.0-SNAPSHOT/benchmark-macro-junit4-1.5.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/benchmark/benchmark-macro-junit4/1.5.0-SNAPSHOT/benchmark-macro-junit4-1.5.0-20250926.054752-1.aar Version: 1.5.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_benchmark_benchmark_traceprocessor_android/README.chromium b/third_party/androidx/committed/libs/androidx_benchmark_benchmark_traceprocessor_android/README.chromium index 6819034..aed4e85 100644 --- a/third_party/androidx/committed/libs/androidx_benchmark_benchmark_traceprocessor_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_benchmark_benchmark_traceprocessor_android/README.chromium
@@ -1,6 +1,6 @@ Name: Benchmark TraceProcessor Short Name: benchmark-traceprocessor-android -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/benchmark/benchmark-traceprocessor-android/1.5.0-SNAPSHOT/benchmark-traceprocessor-android-1.5.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/benchmark/benchmark-traceprocessor-android/1.5.0-SNAPSHOT/benchmark-traceprocessor-android-1.5.0-20250926.054752-1.aar Version: 1.5.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_biometric_biometric/README.chromium b/third_party/androidx/committed/libs/androidx_biometric_biometric/README.chromium index 508fcec2..d4ff4f6f9 100644 --- a/third_party/androidx/committed/libs/androidx_biometric_biometric/README.chromium +++ b/third_party/androidx/committed/libs/androidx_biometric_biometric/README.chromium
@@ -1,6 +1,6 @@ Name: Biometric Short Name: biometric -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/biometric/biometric/1.4.0-SNAPSHOT/biometric-1.4.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/biometric/biometric/1.4.0-SNAPSHOT/biometric-1.4.0-20250926.054752-1.aar Version: 1.4.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_browser_browser/README.chromium b/third_party/androidx/committed/libs/androidx_browser_browser/README.chromium index 512ea08..0aea4e2b 100644 --- a/third_party/androidx/committed/libs/androidx_browser_browser/README.chromium +++ b/third_party/androidx/committed/libs/androidx_browser_browser/README.chromium
@@ -1,6 +1,6 @@ Name: Browser Short Name: browser -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/browser/browser/1.10.0-SNAPSHOT/browser-1.10.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/browser/browser/1.10.0-SNAPSHOT/browser-1.10.0-20250926.054752-1.aar Version: 1.10.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_cardview_cardview/README.chromium b/third_party/androidx/committed/libs/androidx_cardview_cardview/README.chromium index 02ba0299..6d2bfd96 100644 --- a/third_party/androidx/committed/libs/androidx_cardview_cardview/README.chromium +++ b/third_party/androidx/committed/libs/androidx_cardview_cardview/README.chromium
@@ -1,6 +1,6 @@ Name: CardView Short Name: cardview -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/cardview/cardview/1.1.0-SNAPSHOT/cardview-1.1.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/cardview/cardview/1.1.0-SNAPSHOT/cardview-1.1.0-20250926.054752-1.aar Version: 1.1.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_collection_collection_jvm/README.chromium b/third_party/androidx/committed/libs/androidx_collection_collection_jvm/README.chromium index b9387c35..f24cfea 100644 --- a/third_party/androidx/committed/libs/androidx_collection_collection_jvm/README.chromium +++ b/third_party/androidx/committed/libs/androidx_collection_collection_jvm/README.chromium
@@ -1,6 +1,6 @@ Name: collections Short Name: collection-jvm -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/collection/collection-jvm/1.6.0-SNAPSHOT/collection-jvm-1.6.0-20250925.204401-1.jar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/collection/collection-jvm/1.6.0-SNAPSHOT/collection-jvm-1.6.0-20250926.054752-1.jar Version: 1.6.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_collection_collection_ktx/README.chromium b/third_party/androidx/committed/libs/androidx_collection_collection_ktx/README.chromium index a47c0644..1bc9747 100644 --- a/third_party/androidx/committed/libs/androidx_collection_collection_ktx/README.chromium +++ b/third_party/androidx/committed/libs/androidx_collection_collection_ktx/README.chromium
@@ -1,6 +1,6 @@ Name: Collections Kotlin Extensions Short Name: collection-ktx -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/collection/collection-ktx/1.6.0-SNAPSHOT/collection-ktx-1.6.0-20250925.204401-1.jar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/collection/collection-ktx/1.6.0-SNAPSHOT/collection-ktx-1.6.0-20250926.054752-1.jar Version: 1.6.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_animation_animation_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_animation_animation_android/README.chromium index 40f60d9..df8cdd5a 100644 --- a/third_party/androidx/committed/libs/androidx_compose_animation_animation_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_compose_animation_animation_android/README.chromium
@@ -1,6 +1,6 @@ Name: Compose Animation Short Name: animation-android -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/compose/animation/animation-android/1.10.0-SNAPSHOT/animation-android-1.10.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/compose/animation/animation-android/1.10.0-SNAPSHOT/animation-android-1.10.0-20250926.054752-1.aar Version: 1.10.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_animation_animation_core_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_animation_animation_core_android/README.chromium index 3951484c..98d3197 100644 --- a/third_party/androidx/committed/libs/androidx_compose_animation_animation_core_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_compose_animation_animation_core_android/README.chromium
@@ -1,6 +1,6 @@ Name: Compose Animation Core Short Name: animation-core-android -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/compose/animation/animation-core-android/1.10.0-SNAPSHOT/animation-core-android-1.10.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/compose/animation/animation-core-android/1.10.0-SNAPSHOT/animation-core-android-1.10.0-20250926.054752-1.aar Version: 1.10.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_foundation_foundation_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_foundation_foundation_android/README.chromium index 38afb5c..1e05aa0 100644 --- a/third_party/androidx/committed/libs/androidx_compose_foundation_foundation_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_compose_foundation_foundation_android/README.chromium
@@ -1,6 +1,6 @@ Name: Compose Foundation Short Name: foundation-android -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/compose/foundation/foundation-android/1.10.0-SNAPSHOT/foundation-android-1.10.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/compose/foundation/foundation-android/1.10.0-SNAPSHOT/foundation-android-1.10.0-20250926.054752-1.aar Version: 1.10.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_foundation_foundation_layout_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_foundation_foundation_layout_android/README.chromium index 675d876..f9fe6b9 100644 --- a/third_party/androidx/committed/libs/androidx_compose_foundation_foundation_layout_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_compose_foundation_foundation_layout_android/README.chromium
@@ -1,6 +1,6 @@ Name: Compose Layouts Short Name: foundation-layout-android -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/compose/foundation/foundation-layout-android/1.10.0-SNAPSHOT/foundation-layout-android-1.10.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/compose/foundation/foundation-layout-android/1.10.0-SNAPSHOT/foundation-layout-android-1.10.0-20250926.054752-1.aar Version: 1.10.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_material3_material3_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_material3_material3_android/README.chromium index d41d58fc..7e6e916 100644 --- a/third_party/androidx/committed/libs/androidx_compose_material3_material3_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_compose_material3_material3_android/README.chromium
@@ -1,6 +1,6 @@ Name: Compose Material3 Components Short Name: material3-android -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/compose/material3/material3-android/1.5.0-SNAPSHOT/material3-android-1.5.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/compose/material3/material3-android/1.5.0-SNAPSHOT/material3-android-1.5.0-20250926.054752-1.aar Version: 1.5.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_material_material_ripple_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_material_material_ripple_android/README.chromium index 088dc1f..e1847e4 100644 --- a/third_party/androidx/committed/libs/androidx_compose_material_material_ripple_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_compose_material_material_ripple_android/README.chromium
@@ -1,6 +1,6 @@ Name: Compose Material Ripple Short Name: material-ripple-android -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/compose/material/material-ripple-android/1.10.0-SNAPSHOT/material-ripple-android-1.10.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/compose/material/material-ripple-android/1.10.0-SNAPSHOT/material-ripple-android-1.10.0-20250926.054752-1.aar Version: 1.10.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_android/README.chromium index 8400488..47601318 100644 --- a/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_android/README.chromium
@@ -1,6 +1,6 @@ Name: Compose Runtime Short Name: runtime-android -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/compose/runtime/runtime-android/1.10.0-SNAPSHOT/runtime-android-1.10.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/compose/runtime/runtime-android/1.10.0-SNAPSHOT/runtime-android-1.10.0-20250926.054752-1.aar Version: 1.10.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_annotation_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_annotation_android/README.chromium index edd3950..cdf2e6e0 100644 --- a/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_annotation_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_annotation_android/README.chromium
@@ -1,6 +1,6 @@ Name: Compose Runtime Annotation Short Name: runtime-annotation-android -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/compose/runtime/runtime-annotation-android/1.10.0-SNAPSHOT/runtime-annotation-android-1.10.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/compose/runtime/runtime-annotation-android/1.10.0-SNAPSHOT/runtime-annotation-android-1.10.0-20250926.054752-1.aar Version: 1.10.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_retain_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_retain_android/README.chromium index 852cbcec..97701a8 100644 --- a/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_retain_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_retain_android/README.chromium
@@ -1,6 +1,6 @@ Name: Compose Runtime Retain Short Name: runtime-retain-android -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/compose/runtime/runtime-retain-android/1.10.0-SNAPSHOT/runtime-retain-android-1.10.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/compose/runtime/runtime-retain-android/1.10.0-SNAPSHOT/runtime-retain-android-1.10.0-20250926.054752-1.aar Version: 1.10.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_saveable_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_saveable_android/README.chromium index 30cade4..d1818089 100644 --- a/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_saveable_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_saveable_android/README.chromium
@@ -1,6 +1,6 @@ Name: Compose Saveable Short Name: runtime-saveable-android -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/compose/runtime/runtime-saveable-android/1.10.0-SNAPSHOT/runtime-saveable-android-1.10.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/compose/runtime/runtime-saveable-android/1.10.0-SNAPSHOT/runtime-saveable-android-1.10.0-20250926.054752-1.aar Version: 1.10.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_ui_ui_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_ui_ui_android/README.chromium index b7a2363..51d74c4 100644 --- a/third_party/androidx/committed/libs/androidx_compose_ui_ui_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_compose_ui_ui_android/README.chromium
@@ -1,6 +1,6 @@ Name: Compose UI Short Name: ui-android -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/compose/ui/ui-android/1.10.0-SNAPSHOT/ui-android-1.10.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/compose/ui/ui-android/1.10.0-SNAPSHOT/ui-android-1.10.0-20250926.054752-1.aar Version: 1.10.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_ui_ui_geometry_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_ui_ui_geometry_android/README.chromium index 90eea114..6312a455 100644 --- a/third_party/androidx/committed/libs/androidx_compose_ui_ui_geometry_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_compose_ui_ui_geometry_android/README.chromium
@@ -1,6 +1,6 @@ Name: Compose Geometry Short Name: ui-geometry-android -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/compose/ui/ui-geometry-android/1.10.0-SNAPSHOT/ui-geometry-android-1.10.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/compose/ui/ui-geometry-android/1.10.0-SNAPSHOT/ui-geometry-android-1.10.0-20250926.054752-1.aar Version: 1.10.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_ui_ui_graphics_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_ui_ui_graphics_android/README.chromium index 5df711f..d5237ff 100644 --- a/third_party/androidx/committed/libs/androidx_compose_ui_ui_graphics_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_compose_ui_ui_graphics_android/README.chromium
@@ -1,6 +1,6 @@ Name: Compose Graphics Short Name: ui-graphics-android -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/compose/ui/ui-graphics-android/1.10.0-SNAPSHOT/ui-graphics-android-1.10.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/compose/ui/ui-graphics-android/1.10.0-SNAPSHOT/ui-graphics-android-1.10.0-20250926.054752-1.aar Version: 1.10.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_ui_ui_test_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_ui_ui_test_android/README.chromium index 6521d8c..b784a563 100644 --- a/third_party/androidx/committed/libs/androidx_compose_ui_ui_test_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_compose_ui_ui_test_android/README.chromium
@@ -1,6 +1,6 @@ Name: Compose Testing Short Name: ui-test-android -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/compose/ui/ui-test-android/1.10.0-SNAPSHOT/ui-test-android-1.10.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/compose/ui/ui-test-android/1.10.0-SNAPSHOT/ui-test-android-1.10.0-20250926.054752-1.aar Version: 1.10.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_ui_ui_test_junit4_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_ui_ui_test_junit4_android/README.chromium index b3375d1..eaa92146 100644 --- a/third_party/androidx/committed/libs/androidx_compose_ui_ui_test_junit4_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_compose_ui_ui_test_junit4_android/README.chromium
@@ -1,6 +1,6 @@ Name: Compose Testing for JUnit4 Short Name: ui-test-junit4-android -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/compose/ui/ui-test-junit4-android/1.10.0-SNAPSHOT/ui-test-junit4-android-1.10.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/compose/ui/ui-test-junit4-android/1.10.0-SNAPSHOT/ui-test-junit4-android-1.10.0-20250926.054752-1.aar Version: 1.10.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_ui_ui_test_manifest/README.chromium b/third_party/androidx/committed/libs/androidx_compose_ui_ui_test_manifest/README.chromium index 907103d9..e0fe9aa8 100644 --- a/third_party/androidx/committed/libs/androidx_compose_ui_ui_test_manifest/README.chromium +++ b/third_party/androidx/committed/libs/androidx_compose_ui_ui_test_manifest/README.chromium
@@ -1,6 +1,6 @@ Name: Compose Testing manifest dependency Short Name: ui-test-manifest -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/compose/ui/ui-test-manifest/1.10.0-SNAPSHOT/ui-test-manifest-1.10.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/compose/ui/ui-test-manifest/1.10.0-SNAPSHOT/ui-test-manifest-1.10.0-20250926.054752-1.aar Version: 1.10.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_ui_ui_text_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_ui_ui_text_android/README.chromium index 30a5d4a1..fa29d94 100644 --- a/third_party/androidx/committed/libs/androidx_compose_ui_ui_text_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_compose_ui_ui_text_android/README.chromium
@@ -1,6 +1,6 @@ Name: Compose UI Text Short Name: ui-text-android -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/compose/ui/ui-text-android/1.10.0-SNAPSHOT/ui-text-android-1.10.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/compose/ui/ui-text-android/1.10.0-SNAPSHOT/ui-text-android-1.10.0-20250926.054752-1.aar Version: 1.10.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_ui_ui_text_google_fonts/README.chromium b/third_party/androidx/committed/libs/androidx_compose_ui_ui_text_google_fonts/README.chromium index 4574130..ba7af77 100644 --- a/third_party/androidx/committed/libs/androidx_compose_ui_ui_text_google_fonts/README.chromium +++ b/third_party/androidx/committed/libs/androidx_compose_ui_ui_text_google_fonts/README.chromium
@@ -1,6 +1,6 @@ Name: Compose Google Fonts integration Short Name: ui-text-google-fonts -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/compose/ui/ui-text-google-fonts/1.10.0-SNAPSHOT/ui-text-google-fonts-1.10.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/compose/ui/ui-text-google-fonts/1.10.0-SNAPSHOT/ui-text-google-fonts-1.10.0-20250926.054752-1.aar Version: 1.10.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_ui_ui_unit_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_ui_ui_unit_android/README.chromium index ed4c9cd..90ec56d 100644 --- a/third_party/androidx/committed/libs/androidx_compose_ui_ui_unit_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_compose_ui_ui_unit_android/README.chromium
@@ -1,6 +1,6 @@ Name: Compose Unit Short Name: ui-unit-android -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/compose/ui/ui-unit-android/1.10.0-SNAPSHOT/ui-unit-android-1.10.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/compose/ui/ui-unit-android/1.10.0-SNAPSHOT/ui-unit-android-1.10.0-20250926.054752-1.aar Version: 1.10.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_ui_ui_util_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_ui_ui_util_android/README.chromium index 7c6e310..da05fb7 100644 --- a/third_party/androidx/committed/libs/androidx_compose_ui_ui_util_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_compose_ui_ui_util_android/README.chromium
@@ -1,6 +1,6 @@ Name: Compose Util Short Name: ui-util-android -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/compose/ui/ui-util-android/1.10.0-SNAPSHOT/ui-util-android-1.10.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/compose/ui/ui-util-android/1.10.0-SNAPSHOT/ui-util-android-1.10.0-20250926.054752-1.aar Version: 1.10.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_constraintlayout_constraintlayout/README.chromium b/third_party/androidx/committed/libs/androidx_constraintlayout_constraintlayout/README.chromium index 614c474a..0ef5012 100644 --- a/third_party/androidx/committed/libs/androidx_constraintlayout_constraintlayout/README.chromium +++ b/third_party/androidx/committed/libs/androidx_constraintlayout_constraintlayout/README.chromium
@@ -1,6 +1,6 @@ Name: ConstraintLayout Short Name: constraintlayout -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/constraintlayout/constraintlayout/2.3.0-SNAPSHOT/constraintlayout-2.3.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/constraintlayout/constraintlayout/2.3.0-SNAPSHOT/constraintlayout-2.3.0-20250926.054752-1.aar Version: 2.3.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_constraintlayout_constraintlayout_core/README.chromium b/third_party/androidx/committed/libs/androidx_constraintlayout_constraintlayout_core/README.chromium index 87c470e..a24fc658 100644 --- a/third_party/androidx/committed/libs/androidx_constraintlayout_constraintlayout_core/README.chromium +++ b/third_party/androidx/committed/libs/androidx_constraintlayout_constraintlayout_core/README.chromium
@@ -1,6 +1,6 @@ Name: ConstraintLayout Core Short Name: constraintlayout-core -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/constraintlayout/constraintlayout-core/1.2.0-SNAPSHOT/constraintlayout-core-1.2.0-20250925.204401-1.jar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/constraintlayout/constraintlayout-core/1.2.0-SNAPSHOT/constraintlayout-core-1.2.0-20250926.054752-1.jar Version: 1.2.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_core_core/README.chromium b/third_party/androidx/committed/libs/androidx_core_core/README.chromium index de6334b..6b50f0f7 100644 --- a/third_party/androidx/committed/libs/androidx_core_core/README.chromium +++ b/third_party/androidx/committed/libs/androidx_core_core/README.chromium
@@ -1,6 +1,6 @@ Name: Core Short Name: core -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/core/core/1.18.0-SNAPSHOT/core-1.18.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/core/core/1.18.0-SNAPSHOT/core-1.18.0-20250926.054752-1.aar Version: 1.18.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_core_core_ktx/README.chromium b/third_party/androidx/committed/libs/androidx_core_core_ktx/README.chromium index 8b88e91..51dd2317 100644 --- a/third_party/androidx/committed/libs/androidx_core_core_ktx/README.chromium +++ b/third_party/androidx/committed/libs/androidx_core_core_ktx/README.chromium
@@ -1,6 +1,6 @@ Name: Core Kotlin Extensions Short Name: core-ktx -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/core/core-ktx/1.18.0-SNAPSHOT/core-ktx-1.18.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/core/core-ktx/1.18.0-SNAPSHOT/core-ktx-1.18.0-20250926.054752-1.aar Version: 1.18.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_core_core_viewtree/README.chromium b/third_party/androidx/committed/libs/androidx_core_core_viewtree/README.chromium index 9e1578b9..4467bb0 100644 --- a/third_party/androidx/committed/libs/androidx_core_core_viewtree/README.chromium +++ b/third_party/androidx/committed/libs/androidx_core_core_viewtree/README.chromium
@@ -1,6 +1,6 @@ Name: androidx.core:core-viewtree Short Name: core-viewtree -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/core/core-viewtree/1.1.0-SNAPSHOT/core-viewtree-1.1.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/core/core-viewtree/1.1.0-SNAPSHOT/core-viewtree-1.1.0-20250926.054752-1.aar Version: 1.1.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_credentials_credentials/README.chromium b/third_party/androidx/committed/libs/androidx_credentials_credentials/README.chromium index 4828a84..630e77a 100644 --- a/third_party/androidx/committed/libs/androidx_credentials_credentials/README.chromium +++ b/third_party/androidx/committed/libs/androidx_credentials_credentials/README.chromium
@@ -1,6 +1,6 @@ Name: Credentials Short Name: credentials -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/credentials/credentials/1.6.0-SNAPSHOT/credentials-1.6.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/credentials/credentials/1.6.0-SNAPSHOT/credentials-1.6.0-20250926.054752-1.aar Version: 1.6.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_credentials_credentials_play_services_auth/README.chromium b/third_party/androidx/committed/libs/androidx_credentials_credentials_play_services_auth/README.chromium index 1524bfb..18f1006 100644 --- a/third_party/androidx/committed/libs/androidx_credentials_credentials_play_services_auth/README.chromium +++ b/third_party/androidx/committed/libs/androidx_credentials_credentials_play_services_auth/README.chromium
@@ -1,6 +1,6 @@ Name: Credentials Play Services Auth Short Name: credentials-play-services-auth -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/credentials/credentials-play-services-auth/1.6.0-SNAPSHOT/credentials-play-services-auth-1.6.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/credentials/credentials-play-services-auth/1.6.0-SNAPSHOT/credentials-play-services-auth-1.6.0-20250926.054752-1.aar Version: 1.6.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_credentials_registry_registry_provider/README.chromium b/third_party/androidx/committed/libs/androidx_credentials_registry_registry_provider/README.chromium index da7b68f5..7f50a39 100644 --- a/third_party/androidx/committed/libs/androidx_credentials_registry_registry_provider/README.chromium +++ b/third_party/androidx/committed/libs/androidx_credentials_registry_registry_provider/README.chromium
@@ -1,6 +1,6 @@ Name: androidx.credentials.registry:registry-provider Short Name: registry-provider -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/credentials/registry/registry-provider/1.0.0-SNAPSHOT/registry-provider-1.0.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/credentials/registry/registry-provider/1.0.0-SNAPSHOT/registry-provider-1.0.0-20250926.054752-1.aar Version: 1.0.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_credentials_registry_registry_provider_play_services/README.chromium b/third_party/androidx/committed/libs/androidx_credentials_registry_registry_provider_play_services/README.chromium index 3314572..348380b 100644 --- a/third_party/androidx/committed/libs/androidx_credentials_registry_registry_provider_play_services/README.chromium +++ b/third_party/androidx/committed/libs/androidx_credentials_registry_registry_provider_play_services/README.chromium
@@ -1,6 +1,6 @@ Name: androidx.credentials.registry:registry-provider-play-services Short Name: registry-provider-play-services -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/credentials/registry/registry-provider-play-services/1.0.0-SNAPSHOT/registry-provider-play-services-1.0.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/credentials/registry/registry-provider-play-services/1.0.0-SNAPSHOT/registry-provider-play-services-1.0.0-20250926.054752-1.aar Version: 1.0.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_cursoradapter_cursoradapter/README.chromium b/third_party/androidx/committed/libs/androidx_cursoradapter_cursoradapter/README.chromium index f6aba2b..52bbb65 100644 --- a/third_party/androidx/committed/libs/androidx_cursoradapter_cursoradapter/README.chromium +++ b/third_party/androidx/committed/libs/androidx_cursoradapter_cursoradapter/README.chromium
@@ -1,6 +1,6 @@ Name: Cursor Adapter Short Name: cursoradapter -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/cursoradapter/cursoradapter/1.1.0-SNAPSHOT/cursoradapter-1.1.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/cursoradapter/cursoradapter/1.1.0-SNAPSHOT/cursoradapter-1.1.0-20250926.054752-1.aar Version: 1.1.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_datastore_datastore_android/README.chromium b/third_party/androidx/committed/libs/androidx_datastore_datastore_android/README.chromium index fe0cfbb..dac20cb 100644 --- a/third_party/androidx/committed/libs/androidx_datastore_datastore_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_datastore_datastore_android/README.chromium
@@ -1,6 +1,6 @@ Name: DataStore Short Name: datastore-android -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/datastore/datastore-android/1.2.0-SNAPSHOT/datastore-android-1.2.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/datastore/datastore-android/1.2.0-SNAPSHOT/datastore-android-1.2.0-20250926.054752-1.aar Version: 1.2.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_datastore_datastore_core_android/README.chromium b/third_party/androidx/committed/libs/androidx_datastore_datastore_core_android/README.chromium index e7bc82d..43423a8 100644 --- a/third_party/androidx/committed/libs/androidx_datastore_datastore_core_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_datastore_datastore_core_android/README.chromium
@@ -1,6 +1,6 @@ Name: DataStore Core Short Name: datastore-core-android -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/datastore/datastore-core-android/1.2.0-SNAPSHOT/datastore-core-android-1.2.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/datastore/datastore-core-android/1.2.0-SNAPSHOT/datastore-core-android-1.2.0-20250926.054752-1.aar Version: 1.2.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_datastore_datastore_core_okio_jvm/README.chromium b/third_party/androidx/committed/libs/androidx_datastore_datastore_core_okio_jvm/README.chromium index f4f4104..f402e13 100644 --- a/third_party/androidx/committed/libs/androidx_datastore_datastore_core_okio_jvm/README.chromium +++ b/third_party/androidx/committed/libs/androidx_datastore_datastore_core_okio_jvm/README.chromium
@@ -1,6 +1,6 @@ Name: DataStore Core Okio Short Name: datastore-core-okio-jvm -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/datastore/datastore-core-okio-jvm/1.2.0-SNAPSHOT/datastore-core-okio-jvm-1.2.0-20250925.204401-1.jar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/datastore/datastore-core-okio-jvm/1.2.0-SNAPSHOT/datastore-core-okio-jvm-1.2.0-20250926.054752-1.jar Version: 1.2.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_android/README.chromium b/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_android/README.chromium index 424ec9ca..cecfdf0 100644 --- a/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_android/README.chromium
@@ -1,6 +1,6 @@ Name: Preferences DataStore Short Name: datastore-preferences-android -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/datastore/datastore-preferences-android/1.2.0-SNAPSHOT/datastore-preferences-android-1.2.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/datastore/datastore-preferences-android/1.2.0-SNAPSHOT/datastore-preferences-android-1.2.0-20250926.054752-1.aar Version: 1.2.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_core_android/README.chromium b/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_core_android/README.chromium index efb9a9b9..bef9698 100644 --- a/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_core_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_core_android/README.chromium
@@ -1,6 +1,6 @@ Name: Preferences DataStore Core Short Name: datastore-preferences-core-android -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/datastore/datastore-preferences-core-android/1.2.0-SNAPSHOT/datastore-preferences-core-android-1.2.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/datastore/datastore-preferences-core-android/1.2.0-SNAPSHOT/datastore-preferences-core-android-1.2.0-20250926.054752-1.aar Version: 1.2.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_external_protobuf/README.chromium b/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_external_protobuf/README.chromium index 2c4bd51..9d0c7ed7 100644 --- a/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_external_protobuf/README.chromium +++ b/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_external_protobuf/README.chromium
@@ -1,6 +1,6 @@ Name: Preferences External Protobuf Short Name: datastore-preferences-external-protobuf -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/datastore/datastore-preferences-external-protobuf/1.2.0-SNAPSHOT/datastore-preferences-external-protobuf-1.2.0-20250925.204401-1.jar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/datastore/datastore-preferences-external-protobuf/1.2.0-SNAPSHOT/datastore-preferences-external-protobuf-1.2.0-20250926.054752-1.jar Version: 1.2.0-SNAPSHOT Update Mechanism: Autoroll License: BSD-3-Clause
diff --git a/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_proto/README.chromium b/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_proto/README.chromium index 444914a91..f2a51b5 100644 --- a/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_proto/README.chromium +++ b/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_proto/README.chromium
@@ -1,6 +1,6 @@ Name: Preferences DataStore Proto Short Name: datastore-preferences-proto -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/datastore/datastore-preferences-proto/1.2.0-SNAPSHOT/datastore-preferences-proto-1.2.0-20250925.204401-1.jar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/datastore/datastore-preferences-proto/1.2.0-SNAPSHOT/datastore-preferences-proto-1.2.0-20250926.054752-1.jar Version: 1.2.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_drawerlayout_drawerlayout/README.chromium b/third_party/androidx/committed/libs/androidx_drawerlayout_drawerlayout/README.chromium index b27a9b1e..68052f26f 100644 --- a/third_party/androidx/committed/libs/androidx_drawerlayout_drawerlayout/README.chromium +++ b/third_party/androidx/committed/libs/androidx_drawerlayout_drawerlayout/README.chromium
@@ -1,6 +1,6 @@ Name: Drawer Layout Short Name: drawerlayout -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/drawerlayout/drawerlayout/1.3.0-SNAPSHOT/drawerlayout-1.3.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/drawerlayout/drawerlayout/1.3.0-SNAPSHOT/drawerlayout-1.3.0-20250926.054752-1.aar Version: 1.3.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_emoji_emoji/README.chromium b/third_party/androidx/committed/libs/androidx_emoji_emoji/README.chromium index ade6370..a05d84a 100644 --- a/third_party/androidx/committed/libs/androidx_emoji_emoji/README.chromium +++ b/third_party/androidx/committed/libs/androidx_emoji_emoji/README.chromium
@@ -1,6 +1,6 @@ Name: Emoji Short Name: emoji -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/emoji/emoji/1.2.0-SNAPSHOT/emoji-1.2.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/emoji/emoji/1.2.0-SNAPSHOT/emoji-1.2.0-20250926.054752-1.aar Version: 1.2.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0, SIL Open Font License, Version 1.1, Unicode, Inc. License
diff --git a/third_party/androidx/committed/libs/androidx_fragment_fragment/README.chromium b/third_party/androidx/committed/libs/androidx_fragment_fragment/README.chromium index 604ed39d..5f043874 100644 --- a/third_party/androidx/committed/libs/androidx_fragment_fragment/README.chromium +++ b/third_party/androidx/committed/libs/androidx_fragment_fragment/README.chromium
@@ -1,6 +1,6 @@ Name: fragment Short Name: fragment -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/fragment/fragment/1.9.0-SNAPSHOT/fragment-1.9.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/fragment/fragment/1.9.0-SNAPSHOT/fragment-1.9.0-20250926.054752-1.aar Version: 1.9.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_fragment_fragment_compose/README.chromium b/third_party/androidx/committed/libs/androidx_fragment_fragment_compose/README.chromium index 6ded157a..d741153 100644 --- a/third_party/androidx/committed/libs/androidx_fragment_fragment_compose/README.chromium +++ b/third_party/androidx/committed/libs/androidx_fragment_fragment_compose/README.chromium
@@ -1,6 +1,6 @@ Name: Fragment Compose Short Name: fragment-compose -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/fragment/fragment-compose/1.9.0-SNAPSHOT/fragment-compose-1.9.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/fragment/fragment-compose/1.9.0-SNAPSHOT/fragment-compose-1.9.0-20250926.054752-1.aar Version: 1.9.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_fragment_fragment_ktx/README.chromium b/third_party/androidx/committed/libs/androidx_fragment_fragment_ktx/README.chromium index 1935946..d4f71d81 100644 --- a/third_party/androidx/committed/libs/androidx_fragment_fragment_ktx/README.chromium +++ b/third_party/androidx/committed/libs/androidx_fragment_fragment_ktx/README.chromium
@@ -1,6 +1,6 @@ Name: Fragment Kotlin Extensions Short Name: fragment-ktx -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/fragment/fragment-ktx/1.9.0-SNAPSHOT/fragment-ktx-1.9.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/fragment/fragment-ktx/1.9.0-SNAPSHOT/fragment-ktx-1.9.0-20250926.054752-1.aar Version: 1.9.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_fragment_fragment_testing/README.chromium b/third_party/androidx/committed/libs/androidx_fragment_fragment_testing/README.chromium index 98e60a9..d1fdeeae 100644 --- a/third_party/androidx/committed/libs/androidx_fragment_fragment_testing/README.chromium +++ b/third_party/androidx/committed/libs/androidx_fragment_fragment_testing/README.chromium
@@ -1,6 +1,6 @@ Name: Fragment Testing Extensions Short Name: fragment-testing -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/fragment/fragment-testing/1.9.0-SNAPSHOT/fragment-testing-1.9.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/fragment/fragment-testing/1.9.0-SNAPSHOT/fragment-testing-1.9.0-20250926.054752-1.aar Version: 1.9.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_fragment_fragment_testing_manifest/README.chromium b/third_party/androidx/committed/libs/androidx_fragment_fragment_testing_manifest/README.chromium index d95e14cd..2a01890 100644 --- a/third_party/androidx/committed/libs/androidx_fragment_fragment_testing_manifest/README.chromium +++ b/third_party/androidx/committed/libs/androidx_fragment_fragment_testing_manifest/README.chromium
@@ -1,6 +1,6 @@ Name: Fragment Testing Manifest dependency Short Name: fragment-testing-manifest -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/fragment/fragment-testing-manifest/1.9.0-SNAPSHOT/fragment-testing-manifest-1.9.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/fragment/fragment-testing-manifest/1.9.0-SNAPSHOT/fragment-testing-manifest-1.9.0-20250926.054752-1.aar Version: 1.9.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_graphics_graphics_path/README.chromium b/third_party/androidx/committed/libs/androidx_graphics_graphics_path/README.chromium index 9370c06..721ce627 100644 --- a/third_party/androidx/committed/libs/androidx_graphics_graphics_path/README.chromium +++ b/third_party/androidx/committed/libs/androidx_graphics_graphics_path/README.chromium
@@ -1,6 +1,6 @@ Name: Android Graphics Path Short Name: graphics-path -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/graphics/graphics-path/1.1.0-SNAPSHOT/graphics-path-1.1.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/graphics/graphics-path/1.1.0-SNAPSHOT/graphics-path-1.1.0-20250926.054752-1.aar Version: 1.1.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_graphics_graphics_shapes_android/README.chromium b/third_party/androidx/committed/libs/androidx_graphics_graphics_shapes_android/README.chromium index 129bdb5..27cfad1 100644 --- a/third_party/androidx/committed/libs/androidx_graphics_graphics_shapes_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_graphics_graphics_shapes_android/README.chromium
@@ -1,6 +1,6 @@ Name: Graphics Shapes Short Name: graphics-shapes-android -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/graphics/graphics-shapes-android/1.1.0-SNAPSHOT/graphics-shapes-android-1.1.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/graphics/graphics-shapes-android/1.1.0-SNAPSHOT/graphics-shapes-android-1.1.0-20250926.054752-1.aar Version: 1.1.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_interpolator_interpolator/README.chromium b/third_party/androidx/committed/libs/androidx_interpolator_interpolator/README.chromium index 07c01fb0..2b0cf193 100644 --- a/third_party/androidx/committed/libs/androidx_interpolator_interpolator/README.chromium +++ b/third_party/androidx/committed/libs/androidx_interpolator_interpolator/README.chromium
@@ -1,6 +1,6 @@ Name: Interpolators Short Name: interpolator -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/interpolator/interpolator/1.1.0-SNAPSHOT/interpolator-1.1.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/interpolator/interpolator/1.1.0-SNAPSHOT/interpolator-1.1.0-20250926.054752-1.aar Version: 1.1.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_common_java8/README.chromium b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_common_java8/README.chromium index 7f35a01..69be6c23 100644 --- a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_common_java8/README.chromium +++ b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_common_java8/README.chromium
@@ -1,6 +1,6 @@ Name: Lifecycle-Common for Java 8 Short Name: lifecycle-common-java8 -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/lifecycle/lifecycle-common-java8/2.10.0-SNAPSHOT/lifecycle-common-java8-2.10.0-20250925.204401-1.jar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/lifecycle/lifecycle-common-java8/2.10.0-SNAPSHOT/lifecycle-common-java8-2.10.0-20250926.054752-1.jar Version: 2.10.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_common_jvm/README.chromium b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_common_jvm/README.chromium index 92df7a6b..953b62e 100644 --- a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_common_jvm/README.chromium +++ b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_common_jvm/README.chromium
@@ -1,6 +1,6 @@ Name: Lifecycle-Common Short Name: lifecycle-common-jvm -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/lifecycle/lifecycle-common-jvm/2.10.0-SNAPSHOT/lifecycle-common-jvm-2.10.0-20250925.204401-1.jar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/lifecycle/lifecycle-common-jvm/2.10.0-SNAPSHOT/lifecycle-common-jvm-2.10.0-20250926.054752-1.jar Version: 2.10.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata/README.chromium b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata/README.chromium index 4fc85adf..cd878ab2 100644 --- a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata/README.chromium +++ b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata/README.chromium
@@ -1,6 +1,6 @@ Name: Lifecycle LiveData Short Name: lifecycle-livedata -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/lifecycle/lifecycle-livedata/2.10.0-SNAPSHOT/lifecycle-livedata-2.10.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/lifecycle/lifecycle-livedata/2.10.0-SNAPSHOT/lifecycle-livedata-2.10.0-20250926.054752-1.aar Version: 2.10.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata_core/README.chromium b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata_core/README.chromium index 1ff025ea..c061ef39 100644 --- a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata_core/README.chromium +++ b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata_core/README.chromium
@@ -1,6 +1,6 @@ Name: Lifecycle LiveData Core Short Name: lifecycle-livedata-core -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/lifecycle/lifecycle-livedata-core/2.10.0-SNAPSHOT/lifecycle-livedata-core-2.10.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/lifecycle/lifecycle-livedata-core/2.10.0-SNAPSHOT/lifecycle-livedata-core-2.10.0-20250926.054752-1.aar Version: 2.10.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata_core_ktx/README.chromium b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata_core_ktx/README.chromium index a6cc4b7..40ffa04 100644 --- a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata_core_ktx/README.chromium +++ b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata_core_ktx/README.chromium
@@ -1,6 +1,6 @@ Name: LiveData Core Kotlin Extensions Short Name: lifecycle-livedata-core-ktx -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/lifecycle/lifecycle-livedata-core-ktx/2.10.0-SNAPSHOT/lifecycle-livedata-core-ktx-2.10.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/lifecycle/lifecycle-livedata-core-ktx/2.10.0-SNAPSHOT/lifecycle-livedata-core-ktx-2.10.0-20250926.054752-1.aar Version: 2.10.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata_ktx/README.chromium b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata_ktx/README.chromium index 76ba107..6fc78f5 100644 --- a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata_ktx/README.chromium +++ b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata_ktx/README.chromium
@@ -1,6 +1,6 @@ Name: LiveData Kotlin Extensions Short Name: lifecycle-livedata-ktx -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/lifecycle/lifecycle-livedata-ktx/2.10.0-SNAPSHOT/lifecycle-livedata-ktx-2.10.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/lifecycle/lifecycle-livedata-ktx/2.10.0-SNAPSHOT/lifecycle-livedata-ktx-2.10.0-20250926.054752-1.aar Version: 2.10.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_process/README.chromium b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_process/README.chromium index 41619d7c..a2805aa2 100644 --- a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_process/README.chromium +++ b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_process/README.chromium
@@ -1,6 +1,6 @@ Name: Lifecycle Process Short Name: lifecycle-process -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/lifecycle/lifecycle-process/2.10.0-SNAPSHOT/lifecycle-process-2.10.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/lifecycle/lifecycle-process/2.10.0-SNAPSHOT/lifecycle-process-2.10.0-20250926.054752-1.aar Version: 2.10.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_runtime_android/README.chromium b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_runtime_android/README.chromium index 5d367c11..cb5b6710 100644 --- a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_runtime_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_runtime_android/README.chromium
@@ -1,6 +1,6 @@ Name: Lifecycle Runtime Short Name: lifecycle-runtime-android -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/lifecycle/lifecycle-runtime-android/2.10.0-SNAPSHOT/lifecycle-runtime-android-2.10.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/lifecycle/lifecycle-runtime-android/2.10.0-SNAPSHOT/lifecycle-runtime-android-2.10.0-20250926.054752-1.aar Version: 2.10.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_runtime_compose_android/README.chromium b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_runtime_compose_android/README.chromium index e349217..325fd26e 100644 --- a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_runtime_compose_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_runtime_compose_android/README.chromium
@@ -1,6 +1,6 @@ Name: Lifecycle Runtime Compose Short Name: lifecycle-runtime-compose-android -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/lifecycle/lifecycle-runtime-compose-android/2.10.0-SNAPSHOT/lifecycle-runtime-compose-android-2.10.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/lifecycle/lifecycle-runtime-compose-android/2.10.0-SNAPSHOT/lifecycle-runtime-compose-android-2.10.0-20250926.054752-1.aar Version: 2.10.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_runtime_ktx_android/README.chromium b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_runtime_ktx_android/README.chromium index 8f7c4f542..27ad83b 100644 --- a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_runtime_ktx_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_runtime_ktx_android/README.chromium
@@ -1,6 +1,6 @@ Name: Lifecycle Kotlin Extensions Short Name: lifecycle-runtime-ktx-android -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/lifecycle/lifecycle-runtime-ktx-android/2.10.0-SNAPSHOT/lifecycle-runtime-ktx-android-2.10.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/lifecycle/lifecycle-runtime-ktx-android/2.10.0-SNAPSHOT/lifecycle-runtime-ktx-android-2.10.0-20250926.054752-1.aar Version: 2.10.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_service/README.chromium b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_service/README.chromium index eb2beb3..e4ce45a 100644 --- a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_service/README.chromium +++ b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_service/README.chromium
@@ -1,6 +1,6 @@ Name: Lifecycle Service Short Name: lifecycle-service -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/lifecycle/lifecycle-service/2.10.0-SNAPSHOT/lifecycle-service-2.10.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/lifecycle/lifecycle-service/2.10.0-SNAPSHOT/lifecycle-service-2.10.0-20250926.054752-1.aar Version: 2.10.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_android/README.chromium b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_android/README.chromium index e0e62e0..57d862d 100644 --- a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_android/README.chromium
@@ -1,6 +1,6 @@ Name: Lifecycle ViewModel Short Name: lifecycle-viewmodel-android -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/lifecycle/lifecycle-viewmodel-android/2.10.0-SNAPSHOT/lifecycle-viewmodel-android-2.10.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/lifecycle/lifecycle-viewmodel-android/2.10.0-SNAPSHOT/lifecycle-viewmodel-android-2.10.0-20250926.054752-1.aar Version: 2.10.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_compose_android/README.chromium b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_compose_android/README.chromium index 737f9ab..2b31cbb3 100644 --- a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_compose_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_compose_android/README.chromium
@@ -1,6 +1,6 @@ Name: Lifecycle ViewModel Compose Short Name: lifecycle-viewmodel-compose-android -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/lifecycle/lifecycle-viewmodel-compose-android/2.10.0-SNAPSHOT/lifecycle-viewmodel-compose-android-2.10.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/lifecycle/lifecycle-viewmodel-compose-android/2.10.0-SNAPSHOT/lifecycle-viewmodel-compose-android-2.10.0-20250926.054752-1.aar Version: 2.10.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_ktx/README.chromium b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_ktx/README.chromium index 750a43e..59a39ba 100644 --- a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_ktx/README.chromium +++ b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_ktx/README.chromium
@@ -1,6 +1,6 @@ Name: Lifecycle ViewModel Kotlin Extensions Short Name: lifecycle-viewmodel-ktx -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/lifecycle/lifecycle-viewmodel-ktx/2.10.0-SNAPSHOT/lifecycle-viewmodel-ktx-2.10.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/lifecycle/lifecycle-viewmodel-ktx/2.10.0-SNAPSHOT/lifecycle-viewmodel-ktx-2.10.0-20250926.054752-1.aar Version: 2.10.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_savedstate_android/README.chromium b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_savedstate_android/README.chromium index eee3cae..4bc9c4d 100644 --- a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_savedstate_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_savedstate_android/README.chromium
@@ -1,6 +1,6 @@ Name: Lifecycle ViewModel with SavedState Short Name: lifecycle-viewmodel-savedstate-android -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/lifecycle/lifecycle-viewmodel-savedstate-android/2.10.0-SNAPSHOT/lifecycle-viewmodel-savedstate-android-2.10.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/lifecycle/lifecycle-viewmodel-savedstate-android/2.10.0-SNAPSHOT/lifecycle-viewmodel-savedstate-android-2.10.0-20250926.054752-1.aar Version: 2.10.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_loader_loader/README.chromium b/third_party/androidx/committed/libs/androidx_loader_loader/README.chromium index 34c6217b..3c1bfaf 100644 --- a/third_party/androidx/committed/libs/androidx_loader_loader/README.chromium +++ b/third_party/androidx/committed/libs/androidx_loader_loader/README.chromium
@@ -1,6 +1,6 @@ Name: loader Short Name: loader -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/loader/loader/1.2.0-SNAPSHOT/loader-1.2.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/loader/loader/1.2.0-SNAPSHOT/loader-1.2.0-20250926.054752-1.aar Version: 1.2.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_media_media/README.chromium b/third_party/androidx/committed/libs/androidx_media_media/README.chromium index 84ca99e..9ab45d6f 100644 --- a/third_party/androidx/committed/libs/androidx_media_media/README.chromium +++ b/third_party/androidx/committed/libs/androidx_media_media/README.chromium
@@ -1,6 +1,6 @@ Name: Media Short Name: media -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/media/media/1.8.0-SNAPSHOT/media-1.8.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/media/media/1.8.0-SNAPSHOT/media-1.8.0-20250926.054752-1.aar Version: 1.8.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_navigation_navigation_common_android/README.chromium b/third_party/androidx/committed/libs/androidx_navigation_navigation_common_android/README.chromium index cf738cc..8c0eee4 100644 --- a/third_party/androidx/committed/libs/androidx_navigation_navigation_common_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_navigation_navigation_common_android/README.chromium
@@ -1,6 +1,6 @@ Name: Navigation Common Short Name: navigation-common-android -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/navigation/navigation-common-android/2.10.0-SNAPSHOT/navigation-common-android-2.10.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/navigation/navigation-common-android/2.10.0-SNAPSHOT/navigation-common-android-2.10.0-20250926.054752-1.aar Version: 2.10.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_navigation_navigation_compose_android/README.chromium b/third_party/androidx/committed/libs/androidx_navigation_navigation_compose_android/README.chromium index 5afe786e..767bb48 100644 --- a/third_party/androidx/committed/libs/androidx_navigation_navigation_compose_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_navigation_navigation_compose_android/README.chromium
@@ -1,6 +1,6 @@ Name: Compose Navigation Short Name: navigation-compose-android -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/navigation/navigation-compose-android/2.10.0-SNAPSHOT/navigation-compose-android-2.10.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/navigation/navigation-compose-android/2.10.0-SNAPSHOT/navigation-compose-android-2.10.0-20250926.054752-1.aar Version: 2.10.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_navigation_navigation_runtime_android/README.chromium b/third_party/androidx/committed/libs/androidx_navigation_navigation_runtime_android/README.chromium index 81bb4e7..f952561a 100644 --- a/third_party/androidx/committed/libs/androidx_navigation_navigation_runtime_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_navigation_navigation_runtime_android/README.chromium
@@ -1,6 +1,6 @@ Name: Navigation Runtime Short Name: navigation-runtime-android -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/navigation/navigation-runtime-android/2.10.0-SNAPSHOT/navigation-runtime-android-2.10.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/navigation/navigation-runtime-android/2.10.0-SNAPSHOT/navigation-runtime-android-2.10.0-20250926.054752-1.aar Version: 2.10.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_navigationevent_navigationevent_android/README.chromium b/third_party/androidx/committed/libs/androidx_navigationevent_navigationevent_android/README.chromium index 287a315c..2ff82cc 100644 --- a/third_party/androidx/committed/libs/androidx_navigationevent_navigationevent_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_navigationevent_navigationevent_android/README.chromium
@@ -1,6 +1,6 @@ Name: Navigation Event Short Name: navigationevent-android -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/navigationevent/navigationevent-android/1.0.0-SNAPSHOT/navigationevent-android-1.0.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/navigationevent/navigationevent-android/1.0.0-SNAPSHOT/navigationevent-android-1.0.0-20250926.054752-1.aar Version: 1.0.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_navigationevent_navigationevent_compose_android/README.chromium b/third_party/androidx/committed/libs/androidx_navigationevent_navigationevent_compose_android/README.chromium index b6fec1e..09de2021 100644 --- a/third_party/androidx/committed/libs/androidx_navigationevent_navigationevent_compose_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_navigationevent_navigationevent_compose_android/README.chromium
@@ -1,6 +1,6 @@ Name: NavigationEvent Compose Short Name: navigationevent-compose-android -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/navigationevent/navigationevent-compose-android/1.0.0-SNAPSHOT/navigationevent-compose-android-1.0.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/navigationevent/navigationevent-compose-android/1.0.0-SNAPSHOT/navigationevent-compose-android-1.0.0-20250926.054752-1.aar Version: 1.0.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_paging_paging_common_android/README.chromium b/third_party/androidx/committed/libs/androidx_paging_paging_common_android/README.chromium index 2b5c4435..35825e87 100644 --- a/third_party/androidx/committed/libs/androidx_paging_paging_common_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_paging_paging_common_android/README.chromium
@@ -1,6 +1,6 @@ Name: Paging-Common Short Name: paging-common-android -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/paging/paging-common-android/3.4.0-SNAPSHOT/paging-common-android-3.4.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/paging/paging-common-android/3.4.0-SNAPSHOT/paging-common-android-3.4.0-20250926.054752-1.aar Version: 3.4.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_paging_paging_common_ktx/README.chromium b/third_party/androidx/committed/libs/androidx_paging_paging_common_ktx/README.chromium index 0758d69..b92c83d 100644 --- a/third_party/androidx/committed/libs/androidx_paging_paging_common_ktx/README.chromium +++ b/third_party/androidx/committed/libs/androidx_paging_paging_common_ktx/README.chromium
@@ -1,6 +1,6 @@ Name: Paging-Common Kotlin Extensions Short Name: paging-common-ktx -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/paging/paging-common-ktx/3.4.0-SNAPSHOT/paging-common-ktx-3.4.0-20250925.204401-1.jar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/paging/paging-common-ktx/3.4.0-SNAPSHOT/paging-common-ktx-3.4.0-20250926.054752-1.jar Version: 3.4.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_paging_paging_compose_android/README.chromium b/third_party/androidx/committed/libs/androidx_paging_paging_compose_android/README.chromium index ff642813..9a8e61cc 100644 --- a/third_party/androidx/committed/libs/androidx_paging_paging_compose_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_paging_paging_compose_android/README.chromium
@@ -1,6 +1,6 @@ Name: Paging-Compose Short Name: paging-compose-android -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/paging/paging-compose-android/3.4.0-SNAPSHOT/paging-compose-android-3.4.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/paging/paging-compose-android/3.4.0-SNAPSHOT/paging-compose-android-3.4.0-20250926.054752-1.aar Version: 3.4.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_paging_paging_runtime/README.chromium b/third_party/androidx/committed/libs/androidx_paging_paging_runtime/README.chromium index cb85e13..c4725d6 100644 --- a/third_party/androidx/committed/libs/androidx_paging_paging_runtime/README.chromium +++ b/third_party/androidx/committed/libs/androidx_paging_paging_runtime/README.chromium
@@ -1,6 +1,6 @@ Name: Paging-Runtime Short Name: paging-runtime -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/paging/paging-runtime/3.4.0-SNAPSHOT/paging-runtime-3.4.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/paging/paging-runtime/3.4.0-SNAPSHOT/paging-runtime-3.4.0-20250926.054752-1.aar Version: 3.4.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_palette_palette/README.chromium b/third_party/androidx/committed/libs/androidx_palette_palette/README.chromium index e80138c..c03644e1 100644 --- a/third_party/androidx/committed/libs/androidx_palette_palette/README.chromium +++ b/third_party/androidx/committed/libs/androidx_palette_palette/README.chromium
@@ -1,6 +1,6 @@ Name: Palette Short Name: palette -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/palette/palette/1.1.0-SNAPSHOT/palette-1.1.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/palette/palette/1.1.0-SNAPSHOT/palette-1.1.0-20250926.054752-1.aar Version: 1.1.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_preference_preference/README.chromium b/third_party/androidx/committed/libs/androidx_preference_preference/README.chromium index 7f9ae4c..7cf8b0d 100644 --- a/third_party/androidx/committed/libs/androidx_preference_preference/README.chromium +++ b/third_party/androidx/committed/libs/androidx_preference_preference/README.chromium
@@ -1,6 +1,6 @@ Name: Preference Short Name: preference -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/preference/preference/1.3.0-SNAPSHOT/preference-1.3.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/preference/preference/1.3.0-SNAPSHOT/preference-1.3.0-20250926.054752-1.aar Version: 1.3.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_profileinstaller_profileinstaller/README.chromium b/third_party/androidx/committed/libs/androidx_profileinstaller_profileinstaller/README.chromium index f964f71a..6202482 100644 --- a/third_party/androidx/committed/libs/androidx_profileinstaller_profileinstaller/README.chromium +++ b/third_party/androidx/committed/libs/androidx_profileinstaller_profileinstaller/README.chromium
@@ -1,6 +1,6 @@ Name: Profile Installer Short Name: profileinstaller -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/profileinstaller/profileinstaller/1.5.0-SNAPSHOT/profileinstaller-1.5.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/profileinstaller/profileinstaller/1.5.0-SNAPSHOT/profileinstaller-1.5.0-20250926.054752-1.aar Version: 1.5.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_recyclerview_recyclerview/README.chromium b/third_party/androidx/committed/libs/androidx_recyclerview_recyclerview/README.chromium index 839b983..bbe0e01 100644 --- a/third_party/androidx/committed/libs/androidx_recyclerview_recyclerview/README.chromium +++ b/third_party/androidx/committed/libs/androidx_recyclerview_recyclerview/README.chromium
@@ -1,6 +1,6 @@ Name: RecyclerView Short Name: recyclerview -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/recyclerview/recyclerview/1.5.0-SNAPSHOT/recyclerview-1.5.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/recyclerview/recyclerview/1.5.0-SNAPSHOT/recyclerview-1.5.0-20250926.054752-1.aar Version: 1.5.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_resourceinspection_resourceinspection_annotation/README.chromium b/third_party/androidx/committed/libs/androidx_resourceinspection_resourceinspection_annotation/README.chromium index f3e989fb..14b5f63 100644 --- a/third_party/androidx/committed/libs/androidx_resourceinspection_resourceinspection_annotation/README.chromium +++ b/third_party/androidx/committed/libs/androidx_resourceinspection_resourceinspection_annotation/README.chromium
@@ -1,6 +1,6 @@ Name: Resource Inspection - Annotations Short Name: resourceinspection-annotation -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/resourceinspection/resourceinspection-annotation/1.1.0-SNAPSHOT/resourceinspection-annotation-1.1.0-20250925.204401-1.jar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/resourceinspection/resourceinspection-annotation/1.1.0-SNAPSHOT/resourceinspection-annotation-1.1.0-20250926.054752-1.jar Version: 1.1.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_savedstate_savedstate_android/README.chromium b/third_party/androidx/committed/libs/androidx_savedstate_savedstate_android/README.chromium index 063db74..c543c15d 100644 --- a/third_party/androidx/committed/libs/androidx_savedstate_savedstate_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_savedstate_savedstate_android/README.chromium
@@ -1,6 +1,6 @@ Name: Saved State Short Name: savedstate-android -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/savedstate/savedstate-android/1.4.0-SNAPSHOT/savedstate-android-1.4.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/savedstate/savedstate-android/1.4.0-SNAPSHOT/savedstate-android-1.4.0-20250926.054752-1.aar Version: 1.4.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_savedstate_savedstate_compose_android/README.chromium b/third_party/androidx/committed/libs/androidx_savedstate_savedstate_compose_android/README.chromium index 9c1b5da..06b1645 100644 --- a/third_party/androidx/committed/libs/androidx_savedstate_savedstate_compose_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_savedstate_savedstate_compose_android/README.chromium
@@ -1,6 +1,6 @@ Name: Saved State Compose Short Name: savedstate-compose-android -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/savedstate/savedstate-compose-android/1.4.0-SNAPSHOT/savedstate-compose-android-1.4.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/savedstate/savedstate-compose-android/1.4.0-SNAPSHOT/savedstate-compose-android-1.4.0-20250926.054752-1.aar Version: 1.4.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_savedstate_savedstate_ktx/README.chromium b/third_party/androidx/committed/libs/androidx_savedstate_savedstate_ktx/README.chromium index 4b521af..ac0afc95 100644 --- a/third_party/androidx/committed/libs/androidx_savedstate_savedstate_ktx/README.chromium +++ b/third_party/androidx/committed/libs/androidx_savedstate_savedstate_ktx/README.chromium
@@ -1,6 +1,6 @@ Name: SavedState Kotlin Extensions Short Name: savedstate-ktx -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/savedstate/savedstate-ktx/1.4.0-SNAPSHOT/savedstate-ktx-1.4.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/savedstate/savedstate-ktx/1.4.0-SNAPSHOT/savedstate-ktx-1.4.0-20250926.054752-1.aar Version: 1.4.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_slidingpanelayout_slidingpanelayout/README.chromium b/third_party/androidx/committed/libs/androidx_slidingpanelayout_slidingpanelayout/README.chromium index 806063f7..bb1919f 100644 --- a/third_party/androidx/committed/libs/androidx_slidingpanelayout_slidingpanelayout/README.chromium +++ b/third_party/androidx/committed/libs/androidx_slidingpanelayout_slidingpanelayout/README.chromium
@@ -1,6 +1,6 @@ Name: Sliding Pane Layout Short Name: slidingpanelayout -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/slidingpanelayout/slidingpanelayout/1.3.0-SNAPSHOT/slidingpanelayout-1.3.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/slidingpanelayout/slidingpanelayout/1.3.0-SNAPSHOT/slidingpanelayout-1.3.0-20250926.054752-1.aar Version: 1.3.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_swiperefreshlayout_swiperefreshlayout/README.chromium b/third_party/androidx/committed/libs/androidx_swiperefreshlayout_swiperefreshlayout/README.chromium index bfa6b98..a0ac40f 100644 --- a/third_party/androidx/committed/libs/androidx_swiperefreshlayout_swiperefreshlayout/README.chromium +++ b/third_party/androidx/committed/libs/androidx_swiperefreshlayout_swiperefreshlayout/README.chromium
@@ -1,6 +1,6 @@ Name: Swipe Refresh Layout Short Name: swiperefreshlayout -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/swiperefreshlayout/swiperefreshlayout/1.2.0-SNAPSHOT/swiperefreshlayout-1.2.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/swiperefreshlayout/swiperefreshlayout/1.2.0-SNAPSHOT/swiperefreshlayout-1.2.0-20250926.054752-1.aar Version: 1.2.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_test_uiautomator_uiautomator/README.chromium b/third_party/androidx/committed/libs/androidx_test_uiautomator_uiautomator/README.chromium index e932b38..3aea3e3 100644 --- a/third_party/androidx/committed/libs/androidx_test_uiautomator_uiautomator/README.chromium +++ b/third_party/androidx/committed/libs/androidx_test_uiautomator_uiautomator/README.chromium
@@ -1,6 +1,6 @@ Name: UIAutomator Short Name: uiautomator -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/test/uiautomator/uiautomator/2.4.0-SNAPSHOT/uiautomator-2.4.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/test/uiautomator/uiautomator/2.4.0-SNAPSHOT/uiautomator-2.4.0-20250926.054752-1.aar Version: 2.4.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_transition_transition/README.chromium b/third_party/androidx/committed/libs/androidx_transition_transition/README.chromium index 14c4c99..ac8e30d8 100644 --- a/third_party/androidx/committed/libs/androidx_transition_transition/README.chromium +++ b/third_party/androidx/committed/libs/androidx_transition_transition/README.chromium
@@ -1,6 +1,6 @@ Name: Transition Short Name: transition -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/transition/transition/1.7.0-SNAPSHOT/transition-1.7.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/transition/transition/1.7.0-SNAPSHOT/transition-1.7.0-20250926.054752-1.aar Version: 1.7.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_viewpager2_viewpager2/README.chromium b/third_party/androidx/committed/libs/androidx_viewpager2_viewpager2/README.chromium index 4dc0cd5..542e781c 100644 --- a/third_party/androidx/committed/libs/androidx_viewpager2_viewpager2/README.chromium +++ b/third_party/androidx/committed/libs/androidx_viewpager2_viewpager2/README.chromium
@@ -1,6 +1,6 @@ Name: ViewPager2 Short Name: viewpager2 -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/viewpager2/viewpager2/1.2.0-SNAPSHOT/viewpager2-1.2.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/viewpager2/viewpager2/1.2.0-SNAPSHOT/viewpager2-1.2.0-20250926.054752-1.aar Version: 1.2.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_webkit_webkit/README.chromium b/third_party/androidx/committed/libs/androidx_webkit_webkit/README.chromium index 7c462a5..4cd9db4 100644 --- a/third_party/androidx/committed/libs/androidx_webkit_webkit/README.chromium +++ b/third_party/androidx/committed/libs/androidx_webkit_webkit/README.chromium
@@ -1,6 +1,6 @@ Name: WebKit Short Name: webkit -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/webkit/webkit/1.15.0-SNAPSHOT/webkit-1.15.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/webkit/webkit/1.15.0-SNAPSHOT/webkit-1.15.0-20250926.054752-1.aar Version: 1.15.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_window_sidecar_sidecar/README.chromium b/third_party/androidx/committed/libs/androidx_window_sidecar_sidecar/README.chromium index 8ee12e5..f45448a 100644 --- a/third_party/androidx/committed/libs/androidx_window_sidecar_sidecar/README.chromium +++ b/third_party/androidx/committed/libs/androidx_window_sidecar_sidecar/README.chromium
@@ -1,6 +1,6 @@ Name: WindowManager Sidecar Short Name: sidecar -URL: https://androidx.dev/snapshots/builds/14169252/artifacts/repository/androidx/window/sidecar/sidecar/1.0.0-SNAPSHOT/sidecar-1.0.0-20250925.204401-1.aar +URL: https://androidx.dev/snapshots/builds/14172195/artifacts/repository/androidx/window/sidecar/sidecar/1.0.0-SNAPSHOT/sidecar-1.0.0-20250926.054752-1.aar Version: 1.0.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/angle b/third_party/angle index 1f40285..5e51d8e 160000 --- a/third_party/angle +++ b/third_party/angle
@@ -1 +1 @@ -Subproject commit 1f40285c90cd45ae6238c57f30d0ec8c8d6e2e4b +Subproject commit 5e51d8e71c08a84ad81080036c6b25cc36b53b1b
diff --git a/third_party/blink/renderer/bindings/generated_in_modules.gni b/third_party/blink/renderer/bindings/generated_in_modules.gni index e39db15d..380d721 100644 --- a/third_party/blink/renderer/bindings/generated_in_modules.gni +++ b/third_party/blink/renderer/bindings/generated_in_modules.gni
@@ -584,8 +584,6 @@ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_texel_copy_texture_info.h", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_texture_binding_layout.cc", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_texture_binding_layout.h", - "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_texture_component_swizzle.cc", - "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_texture_component_swizzle.h", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_texture_descriptor.cc", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_texture_descriptor.h", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_texture_view_descriptor.cc", @@ -1576,8 +1574,6 @@ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_compare_function.h", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_compilation_message_type.cc", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_compilation_message_type.h", - "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_component_swizzle.cc", - "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_component_swizzle.h", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_cull_mode.cc", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_cull_mode.h", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_device_lost_reason.cc",
diff --git a/third_party/blink/renderer/core/css/css_math_expression_node.cc b/third_party/blink/renderer/core/css/css_math_expression_node.cc index 3585d85..7ebd676 100644 --- a/third_party/blink/renderer/core/css/css_math_expression_node.cc +++ b/third_party/blink/renderer/core/css/css_math_expression_node.cc
@@ -342,10 +342,58 @@ for (uint8_t type_index = 0u; type_index < BaseType::kNumTypes; ++type_index) { int8_t type_power = base_type_powers_[type_index]; - types_sum += type_power; - if (type_power != 0) { - type = BaseType(type_index); + if (!type_power) { + continue; } + // If more than one base type has a non-zero power, it's intermediate. + if (types_sum != 0) { + if (type_index != kPercent) { + return kCalcIntermediate; + } + DCHECK(!percentage_hint_.has_value()); + // Because we don't provide the percent hint from the "outside" + // as css-values expects [1], it's possible for the percentage + // hint to be unset even for expressions that involve percentages + // as well some other type, e.g.: + // + // width: (1% * 1%) / 1px; + // + // The CSSMathType for the above expression would contain + // [percent -> 2, length -> -1] with a null percent hint. + // However, the expression is clearly valid for 'width', since + // the percentages resolve against lengths. To address this, + // we effectively deduce what the percent hint should have been + // from the other (non-percent) base type powers: + // + // If there is more than one non-percent base type with non-zero power, + // it's intermediate (handled by early-out above). + // + // Otherwise, if there is exactly *one* other (non-percent) base type + // with a non-zero power, then we assume that percentages were intended + // to resolve against that base type, and basically move the powers from + // "percent" to the other base type. Continuing the example from before: + // + // [percent -> 2, length -> -1] => [percent -> 0, length -> 1] + // + // However, we do not actually need to modify `base_type_powers_` + // according to the above; the remainder of this function only + // checks `types_sum`, so it's enough to "pretend" that these numbers + // were combined all along. + // + // Note: This relies on kPercent appearing *last* in the enum. + // + // Note: Whether or not this deduced category is valid for + // the relevant context will be determined by the call + // site. For example, "width:(1% * 1%) / 1deg" would produce + // kAngle for this algorithm, but ultimately be rejected. + // + // [1] + // https://drafts.csswg.org/css-values-4/#determine-the-type-of-a-calculation + types_sum += type_power; + break; + } + type = BaseType(type_index); + types_sum += type_power; } if (types_sum == 0) { return kCalcNumber; @@ -508,6 +556,35 @@ return type; } +#if DCHECK_IS_ON() +std::ostream& operator<<(std::ostream& os, const CSSMathType& type) { + if (!type.IsValid()) { + os << "InvalidType "; + } + os << "CSSMathType("; + bool first = true; + for (uint8_t type_index = 0; type_index < CSSMathType::BaseType::kNumTypes; + ++type_index) { + int8_t power = type.base_type_powers_[type_index]; + if (power != 0) { + if (!first) { + os << ", "; + } + first = false; + os << static_cast<int>(type_index) << "^" << static_cast<int>(power); + } + } + if (type.percentage_hint_) { + if (!first) { + os << ", "; + } + os << "percent_hint=" << static_cast<int>(type.percentage_hint_.value()); + } + os << ")"; + return os; +} +#endif + namespace { const PixelsAndPercent CreateClampedSamePixelsAndPercent(float value) {
diff --git a/third_party/blink/renderer/core/css/css_math_expression_node.h b/third_party/blink/renderer/core/css/css_math_expression_node.h index 74ad970..975cc205 100644 --- a/third_party/blink/renderer/core/css/css_math_expression_node.h +++ b/third_party/blink/renderer/core/css/css_math_expression_node.h
@@ -99,14 +99,16 @@ DISALLOW_NEW(); // https://drafts.css-houdini.org/css-typed-om-1/#cssnumericvalue-base-type + // kPercent should always be the last one as it's used to do a percent hint + // trick in Category(). enum BaseType : uint8_t { - kPercent, kLength, kAngle, kTime, kFrequency, kResolution, kFlex, + kPercent, kNumTypes }; @@ -139,6 +141,9 @@ CORE_EXPORT friend CSSMathType operator/(CSSMathType type1, CSSMathType type2); CORE_EXPORT CSSMathType operator-() const; +#if DCHECK_IS_ON() + friend std::ostream& operator<<(std::ostream& os, const CSSMathType& type); +#endif private: using BaseTypePowers =
diff --git a/third_party/blink/renderer/core/css/media_query_evaluator.cc b/third_party/blink/renderer/core/css/media_query_evaluator.cc index 8634b6b..3b2f093 100644 --- a/third_party/blink/renderer/core/css/media_query_evaluator.cc +++ b/third_party/blink/renderer/core/css/media_query_evaluator.cc
@@ -1713,7 +1713,8 @@ StyleResolverState state(container->GetDocument(), *container); PositionTryFallback query_fallback = StyleBuilderConverter::ConvertSinglePositionTryFallback( - state, value.GetCSSValue()); + state, value.GetCSSValue(), + /*allow_any_keyword_in_position_area=*/true); query_fallback = ToPhysicalFallback(query_fallback, media_values); fallback = ToPhysicalFallback(fallback, media_values); return fallback.Matches(query_fallback);
diff --git a/third_party/blink/renderer/core/css/parser/css_at_rule_id.cc b/third_party/blink/renderer/core/css/parser/css_at_rule_id.cc index e5f1c0f4..e2ad454 100644 --- a/third_party/blink/renderer/core/css/parser/css_at_rule_id.cc +++ b/third_party/blink/renderer/core/css/parser/css_at_rule_id.cc
@@ -71,7 +71,8 @@ if (EqualIgnoringASCIICase(name, "property")) { return CSSAtRuleID::kCSSAtRuleProperty; } - if (EqualIgnoringASCIICase(name, "route")) { + if (RuntimeEnabledFeatures::RouteMatchingEnabled() && + EqualIgnoringASCIICase(name, "route")) { return CSSAtRuleID::kCSSAtRuleRoute; } if (EqualIgnoringASCIICase(name, "container")) {
diff --git a/third_party/blink/renderer/core/css/parser/css_tokenizer.cc b/third_party/blink/renderer/core/css/parser/css_tokenizer.cc index be0208a9..1ca596c5 100644 --- a/third_party/blink/renderer/core/css/parser/css_tokenizer.cc +++ b/third_party/blink/renderer/core/css/parser/css_tokenizer.cc
@@ -597,7 +597,7 @@ unsigned size = 0; #if defined(__SSE2__) || defined(__ARM_NEON__) if (buffer.Is8Bit()) { - const LChar* ptr = UNSAFE_TODO(buffer.Characters8()); + const LChar* ptr = buffer.Span8().data(); while (size + 16 <= buffer.length()) { int8_t b __attribute__((vector_size(16))); UNSAFE_TODO(memcpy(&b, ptr + size, sizeof(b)));
diff --git a/third_party/blink/renderer/core/css/parser/css_tokenizer_input_stream.cc b/third_party/blink/renderer/core/css/parser/css_tokenizer_input_stream.cc index e2303fe..6e51aef 100644 --- a/third_party/blink/renderer/core/css/parser/css_tokenizer_input_stream.cc +++ b/third_party/blink/renderer/core/css/parser/css_tokenizer_input_stream.cc
@@ -14,13 +14,13 @@ void CSSTokenizerInputStream::AdvanceUntilNonWhitespace() { // Using HTML space here rather than CSS space since we don't do preprocessing if (string_.Is8Bit()) { - const LChar* characters = UNSAFE_TODO(string_.Characters8()); + const LChar* characters = string_.Span8().data(); while (offset_ < string_length_ && IsHTMLSpace(UNSAFE_TODO(characters[offset_]))) { ++offset_; } } else { - const UChar* characters = UNSAFE_TODO(string_.Characters16()); + const UChar* characters = string_.Span16().data(); while (offset_ < string_length_ && IsHTMLSpace(UNSAFE_TODO(characters[offset_]))) { ++offset_; @@ -50,7 +50,7 @@ // complicated rounding machinery of CharactersToDouble(), // and can do with a much faster variant. if (start < end && string_.Is8Bit() && end - start <= 14) { - const LChar* ptr = UNSAFE_TODO(string_.Characters8() + offset_ + start); + const LChar* ptr = UNSAFE_TODO(string_.Span8().data() + offset_ + start); double result = ptr[0] - '0'; for (unsigned i = 1; i < end - start; ++i) { result = result * 10 + (UNSAFE_TODO(ptr[i]) - '0');
diff --git a/third_party/blink/renderer/core/css/parser/css_tokenizer_input_stream.h b/third_party/blink/renderer/core/css/parser/css_tokenizer_input_stream.h index 46992e2..c819d786 100644 --- a/third_party/blink/renderer/core/css/parser/css_tokenizer_input_stream.h +++ b/third_party/blink/renderer/core/css/parser/css_tokenizer_input_stream.h
@@ -59,13 +59,13 @@ template <bool characterPredicate(UChar)> unsigned SkipWhilePredicate(unsigned offset) { if (string_.Is8Bit()) { - const LChar* characters8 = UNSAFE_TODO(string_.Characters8()); + const LChar* characters8 = string_.Span8().data(); while ((offset_ + offset) < string_length_ && characterPredicate(UNSAFE_TODO(characters8[offset_ + offset]))) { ++offset; } } else { - const UChar* characters16 = UNSAFE_TODO(string_.Characters16()); + const UChar* characters16 = string_.Span16().data(); while ((offset_ + offset) < string_length_ && characterPredicate(UNSAFE_TODO(characters16[offset_ + offset]))) { ++offset;
diff --git a/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc b/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc index 9ab2af8f..6c6c580 100644 --- a/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc +++ b/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc
@@ -9253,12 +9253,14 @@ if (first_value->GetValueID() == second_value->GetValueID()) { return first_value; } - if (first_value->GetValueID() == CSSValueID::kSpanAll && + CSSValueID non_repeated_default = + allow_any_keyword ? CSSValueID::kAny : CSSValueID::kSpanAll; + if (first_value->GetValueID() == non_repeated_default && !css_parsing_utils::IsRepeatedPositionAreaValue( second_value->GetValueID())) { return second_value; } - if (second_value->GetValueID() == CSSValueID::kSpanAll && + if (second_value->GetValueID() == non_repeated_default && !css_parsing_utils::IsRepeatedPositionAreaValue( first_value->GetValueID())) { return first_value;
diff --git a/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc b/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc index 02a72b17..aaf3b23 100644 --- a/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc +++ b/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc
@@ -3837,7 +3837,8 @@ PositionArea StyleBuilderConverter::ConvertPositionArea( StyleResolverState& state, - const CSSValue& value) { + const CSSValue& value, + bool allow_any_keyword) { auto extract_position_area_span = [](CSSValueID value) -> std::pair<PositionAreaRegion, PositionAreaRegion> { PositionAreaRegion start = PositionAreaRegion::kNone; @@ -4026,18 +4027,21 @@ return std::make_pair(start, end); }; - if (const auto* first_value = DynamicTo<CSSIdentifierValue>(value)) { - CSSValueID first_keyword = first_value->GetValueID(); - if (first_keyword == CSSValueID::kNone) { + if (const auto* single_keyword_value = DynamicTo<CSSIdentifierValue>(value)) { + CSSValueID single_keyword = single_keyword_value->GetValueID(); + if (single_keyword == CSSValueID::kNone) { return PositionArea(); } PositionAreaRegion span[2]; - std::tie(span[0], span[1]) = extract_position_area_span(first_keyword); - if (css_parsing_utils::IsRepeatedPositionAreaValue(first_keyword)) { + std::tie(span[0], span[1]) = extract_position_area_span(single_keyword); + if (css_parsing_utils::IsRepeatedPositionAreaValue(single_keyword)) { return PositionArea(span[0], span[1], span[0], span[1]); } else { - return PositionArea(span[0], span[1], PositionAreaRegion::kAll, - PositionAreaRegion::kAll); + PositionAreaRegion default_second_span = allow_any_keyword + ? PositionAreaRegion::kAny + : PositionAreaRegion::kAll; + return PositionArea(span[0], span[1], default_second_span, + default_second_span); } } @@ -4053,10 +4057,12 @@ PositionTryFallback StyleBuilderConverter::ConvertSinglePositionTryFallback( StyleResolverState& state, - const CSSValue& value) { + const CSSValue& value, + bool allow_any_keyword_in_position_area) { // <'position-area'> if (IsA<CSSValuePair>(value) || IsA<CSSIdentifierValue>(value)) { - return PositionTryFallback(ConvertPositionArea(state, value)); + return PositionTryFallback( + ConvertPositionArea(state, value, allow_any_keyword_in_position_area)); } // [<dashed-ident> || <try-tactic>] const ScopedCSSName* scoped_name = nullptr;
diff --git a/third_party/blink/renderer/core/css/resolver/style_builder_converter.h b/third_party/blink/renderer/core/css/resolver/style_builder_converter.h index ea7ac20c..4b08af59 100644 --- a/third_party/blink/renderer/core/css/resolver/style_builder_converter.h +++ b/third_party/blink/renderer/core/css/resolver/style_builder_converter.h
@@ -441,10 +441,13 @@ static ScopedCSSNameList* ConvertTimelineScope(StyleResolverState&, const CSSValue&); - static PositionArea ConvertPositionArea(StyleResolverState&, const CSSValue&); + static PositionArea ConvertPositionArea(StyleResolverState&, + const CSSValue&, + bool allow_any_keyword = false); static PositionTryFallback ConvertSinglePositionTryFallback( StyleResolverState&, - const CSSValue&); + const CSSValue&, + bool allow_any_keyword_in_position_area = false); static FitText ConvertFitText(StyleResolverState&, const CSSValue&); static TextOverflowData ConvertTextOverflow(StyleResolverState&, const CSSValue&);
diff --git a/third_party/blink/renderer/core/css/style_rule_test.cc b/third_party/blink/renderer/core/css/style_rule_test.cc index d279b97e7..d32df86 100644 --- a/third_party/blink/renderer/core/css/style_rule_test.cc +++ b/third_party/blink/renderer/core/css/style_rule_test.cc
@@ -11,6 +11,7 @@ #include "third_party/blink/renderer/core/css/css_test_helpers.h" #include "third_party/blink/renderer/core/dom/document.h" #include "third_party/blink/renderer/core/testing/page_test_base.h" +#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h" #include "third_party/blink/renderer/platform/wtf/text/string_builder.h" namespace blink { @@ -445,4 +446,14 @@ ->SelectorTextExpandingPseudoReferences(/*scope_id=*/0)); } +TEST_F(StyleRuleTest, RouteRuleDisabled) { + ScopedRouteMatchingForTest enabled(false); + // Test both old and new syntax. + StyleRuleBase* rule = + css_test_helpers::ParseRule(GetDocument(), "@route sixtysix {}"); + EXPECT_FALSE(rule); + rule = css_test_helpers::ParseRule(GetDocument(), "@route (sixtysix) {}"); + EXPECT_FALSE(rule); +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc index 80bb246..db0cbec 100644 --- a/third_party/blink/renderer/core/dom/element.cc +++ b/third_party/blink/renderer/core/dom/element.cc
@@ -9819,10 +9819,6 @@ return true; } - if (!style->HasAnyPseudoElementStyles()) { - return false; - } - for (PseudoElement* pseudo_element : rare_data->GetPseudoElements()) { if (pseudo_element->GetComputedStyle()->GetCounterDirectives()) { return true;
diff --git a/third_party/blink/renderer/core/dom/pseudo_element.cc b/third_party/blink/renderer/core/dom/pseudo_element.cc index 8874e60..edd6794 100644 --- a/third_party/blink/renderer/core/dom/pseudo_element.cc +++ b/third_party/blink/renderer/core/dom/pseudo_element.cc
@@ -412,6 +412,13 @@ DCHECK(!nextSibling()); DCHECK(!previousSibling()); + if (const ComputedStyle* style = GetComputedStyle()) { + if (style->GetCounterDirectives() || style->ContainsStyle() || + PseudoElementStylesAffectCounters()) { + GetDocument().GetStyleEngine().MarkCountersDirty(); + } + } + DetachLayoutTree(); Element* parent = ParentOrShadowHostElement(); GetDocument().AdoptIfNeeded(*this);
diff --git a/third_party/blink/renderer/core/layout/inline/caret_rect.cc b/third_party/blink/renderer/core/layout/inline/caret_rect.cc index 319bcd14..56c7dbf 100644 --- a/third_party/blink/renderer/core/layout/inline/caret_rect.cc +++ b/third_party/blink/renderer/core/layout/inline/caret_rect.cc
@@ -106,6 +106,11 @@ if (offset < cursor.Current().TextEndOffset()) { cursor_inline_size = ComputeCharacterWidthAtOffset( cursor, offset - cursor.Current().TextStartOffset(), style); + // Fall back to 1ch. + if (cursor_inline_size == LayoutUnit()) { + cursor_inline_size = + LayoutUnit(style.GetFont()->PrimaryFont()->AvgCharWidth()); + } } else { // If the next fragment is text, we need to get the width and height of // the first visible character in this fragment. @@ -121,6 +126,10 @@ {style_next.GetWritingMode(), ResolvedDirection(next)}, next.Current().Size()); cursor_inline_size = ComputeCharacterWidthAtOffset(next, 0, style_next); + if (cursor_inline_size == LayoutUnit()) { + cursor_inline_size = + LayoutUnit(style_next.GetFont()->PrimaryFont()->AvgCharWidth()); + } cursor_block_size = converter_next.ToLogical(next.Current().Size()).block_size; switch (style.GetWritingMode()) { @@ -139,16 +148,11 @@ break; } } else { - // If there is no visible character after the insertion point, the UA must - // render the caret after the last visible character. - cursor_inline_size = ComputeCharacterWidthAtOffset( - cursor, offset - cursor.Current().TextStartOffset() - 1, style); - } + // The width of the block and underscore carets should be 1ch if + // this information is impractical to determine. + cursor_inline_size = + LayoutUnit(style.GetFont()->PrimaryFont()->AvgCharWidth()); } - // When the inline size is zero, e.g. in the case that character is - // "​", the inline size falls back to bar width. - if (cursor_inline_size == LayoutUnit()) { - cursor_inline_size = caret_width; } caret_rect.offset.block_offset = cursor_block_offset;
diff --git a/third_party/blink/renderer/core/svg/properties/svg_list_property_helper.h b/third_party/blink/renderer/core/svg/properties/svg_list_property_helper.h index f2e820a..17742a5e3 100644 --- a/third_party/blink/renderer/core/svg/properties/svg_list_property_helper.h +++ b/third_party/blink/renderer/core/svg/properties/svg_list_property_helper.h
@@ -54,8 +54,9 @@ explicit const_iterator(SVGListPropertyBase::const_iterator wrapped) : wrapped_(wrapped) {} - const_iterator& operator++() { - UNSAFE_TODO(++wrapped_); + UNSAFE_BUFFER_USAGE const_iterator& operator++() { + // SAFETY: This function exposes this unsafety. + UNSAFE_BUFFERS(++wrapped_); return *this; } bool operator==(const const_iterator& other) const {
diff --git a/third_party/blink/renderer/core/svg/svg_poly_element.cc b/third_party/blink/renderer/core/svg/svg_poly_element.cc index 297fb4b..3a7ba48 100644 --- a/third_party/blink/renderer/core/svg/svg_poly_element.cc +++ b/third_party/blink/renderer/core/svg/svg_poly_element.cc
@@ -56,14 +56,10 @@ if (points_value->IsEmpty()) return builder; - auto it = points_value->begin(); - auto it_end = points_value->end(); - DCHECK(it != it_end); - builder.MoveTo((*it)->Value()); - ++it; - - for (; it != it_end; ++it) - builder.LineTo((*it)->Value()); + builder.MoveTo(points_value->at(0)->Value()); + for (uint32_t i = 1; i < points_value->length(); ++i) { + builder.LineTo(points_value->at(i)->Value()); + } return builder; }
diff --git a/third_party/blink/renderer/modules/BUILD.gn b/third_party/blink/renderer/modules/BUILD.gn index c4cc4762..0abfa02 100644 --- a/third_party/blink/renderer/modules/BUILD.gn +++ b/third_party/blink/renderer/modules/BUILD.gn
@@ -558,7 +558,6 @@ "payments/payment_test_helper.h", "payments/payments_validators_test.cc", "payments/secure_payment_confirmation_helper_test.cc", - "peerconnection/byte_buffer_queue_test.cc", "peerconnection/media_stream_remote_video_source_test.cc", "peerconnection/media_stream_track_metrics_test.cc", "peerconnection/media_stream_video_webrtc_sink_test.cc",
diff --git a/third_party/blink/renderer/modules/mediastream/media_constraints.cc b/third_party/blink/renderer/modules/mediastream/media_constraints.cc index a982c8b..6e4c556c9 100644 --- a/third_party/blink/renderer/modules/mediastream/media_constraints.cc +++ b/third_party/blink/renderer/modules/mediastream/media_constraints.cc
@@ -53,8 +53,9 @@ if (builder.length() > 1) { builder.Append(", "); } + builder.Append("\""); builder.Append(name); - builder.Append(": "); + builder.Append("\": "); builder.AppendNumber(value); } @@ -69,8 +70,9 @@ if (builder.length() > 1) { builder.Append(", "); } + builder.Append("\""); builder.Append(name); - builder.Append(": "); + builder.Append("\": "); builder.Append(value); } @@ -84,8 +86,9 @@ if (builder.length() > 1) { builder.Append(", "); } + builder.Append("\""); builder.Append(name); - builder.Append(": "); + builder.Append("\": "); if (value) { builder.Append("true"); } else { @@ -163,7 +166,7 @@ if (builder.length() > 1) { builder.Append(", "); } - builder.Append("advanced: ["); + builder.Append("\"advanced\": ["); bool first = true; for (const auto& constraint_set : Advanced()) { if (!first) { @@ -371,7 +374,7 @@ StringBuilder builder; builder.Append('{'); if (!ideal_.empty()) { - builder.Append("ideal: ["); + builder.Append("\"ideal\": ["); bool first = true; for (const auto& iter : ideal_) { if (!first) { @@ -388,7 +391,7 @@ if (builder.length() > 1) { builder.Append(", "); } - builder.Append("exact: ["); + builder.Append("\"exact\": ["); bool first = true; for (const auto& iter : exact_) { if (!first) { @@ -607,8 +610,9 @@ if (!first) { builder.Append(", "); } + builder.Append("\""); builder.Append(constraint->GetName()); - builder.Append(": "); + builder.Append("\": "); builder.Append(constraint->ToString()); first = false; }
diff --git a/third_party/blink/renderer/modules/mediastream/media_constraints_test.cc b/third_party/blink/renderer/modules/mediastream/media_constraints_test.cc index e72ee2e..958e360f 100644 --- a/third_party/blink/renderer/modules/mediastream/media_constraints_test.cc +++ b/third_party/blink/renderer/modules/mediastream/media_constraints_test.cc
@@ -113,10 +113,11 @@ MediaTrackConstraintSetPlatform the_set; EXPECT_EQ("", the_set.ToString()); the_set.width.SetMax(240); - EXPECT_EQ("width: {max: 240}", the_set.ToString().Utf8()); + EXPECT_EQ("\"width\": {\"max\": 240}", the_set.ToString().Utf8()); the_set.echo_cancellation.SetIdealBoolean(true); - EXPECT_EQ("width: {max: 240}, echoCancellation: {ideal: true}", - the_set.ToString().Utf8()); + EXPECT_EQ( + "\"width\": {\"max\": 240}, \"echoCancellation\": {\"ideal\": true}", + the_set.ToString().Utf8()); } TEST(MediaTrackConstraintsTest, ConstraintsToString) { @@ -128,7 +129,8 @@ advanced[0].echo_cancellation.SetExactBoolean(true); the_constraints.Initialize(basic, advanced); EXPECT_EQ( - "{width: {max: 240}, advanced: [{echoCancellation: {exact: true}}]}", + "{\"width\": {\"max\": 240}, \"advanced\": [{\"echoCancellation\": " + "{\"exact\": true}}]}", the_constraints.ToString().Utf8()); MediaConstraints null_constraints; @@ -140,7 +142,8 @@ pan_basic.pan.SetIsPresent(false); pan_advanced[0].pan.SetIsPresent(true); pan_constraints.Initialize(pan_basic, pan_advanced); - EXPECT_EQ("{advanced: [{pan: {}}]}", pan_constraints.ToString().Utf8()); + EXPECT_EQ("{\"advanced\": [{\"pan\": {}}]}", + pan_constraints.ToString().Utf8()); MediaConstraints tilt_constraints; MediaTrackConstraintSetPlatform tilt_basic; @@ -148,7 +151,8 @@ tilt_basic.tilt.SetIsPresent(false); tilt_advanced[0].tilt.SetIsPresent(true); tilt_constraints.Initialize(tilt_basic, tilt_advanced); - EXPECT_EQ("{advanced: [{tilt: {}}]}", tilt_constraints.ToString().Utf8()); + EXPECT_EQ("{\"advanced\": [{\"tilt\": {}}]}", + tilt_constraints.ToString().Utf8()); MediaConstraints zoom_constraints; MediaTrackConstraintSetPlatform zoom_basic; @@ -156,7 +160,8 @@ zoom_basic.zoom.SetIsPresent(false); zoom_advanced[0].zoom.SetIsPresent(true); zoom_constraints.Initialize(zoom_basic, zoom_advanced); - EXPECT_EQ("{advanced: [{zoom: {}}]}", zoom_constraints.ToString().Utf8()); + EXPECT_EQ("{\"advanced\": [{\"zoom\": {}}]}", + zoom_constraints.ToString().Utf8()); // TODO(crbug.com/1086338): Test other constraints with IsPresent. }
diff --git a/third_party/blink/renderer/modules/peerconnection/BUILD.gn b/third_party/blink/renderer/modules/peerconnection/BUILD.gn index 1b83ddb..d8ef825 100644 --- a/third_party/blink/renderer/modules/peerconnection/BUILD.gn +++ b/third_party/blink/renderer/modules/peerconnection/BUILD.gn
@@ -20,8 +20,6 @@ "adapters/sctp_transport_proxy.h", "adapters/web_rtc_cross_thread_copier.cc", "adapters/web_rtc_cross_thread_copier.h", - "byte_buffer_queue.cc", - "byte_buffer_queue.h", "dedicated_worker_global_scope_rtc_transform.h", "identifiability_metrics.cc", "identifiability_metrics.h",
diff --git a/third_party/blink/renderer/modules/peerconnection/byte_buffer_queue.cc b/third_party/blink/renderer/modules/peerconnection/byte_buffer_queue.cc deleted file mode 100644 index e865711..0000000 --- a/third_party/blink/renderer/modules/peerconnection/byte_buffer_queue.cc +++ /dev/null
@@ -1,73 +0,0 @@ -// Copyright 2018 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "third_party/blink/renderer/modules/peerconnection/byte_buffer_queue.h" - -#include "base/compiler_specific.h" - -namespace blink { - -wtf_size_t ByteBufferQueue::ReadInto(base::span<uint8_t> buffer_out) { - wtf_size_t read_amount = 0; - while (!buffer_out.empty() && !deque_of_buffers_.empty()) { - base::span<const uint8_t> front_buffer = - base::span(deque_of_buffers_.front()).subspan(front_buffer_offset_); - DCHECK_GT(front_buffer.size(), 0u); - const wtf_size_t buffer_read_amount = - std::min(static_cast<wtf_size_t>(buffer_out.size()), - static_cast<wtf_size_t>(front_buffer.size())); - buffer_out.take_first(buffer_read_amount) - .copy_from(front_buffer.first(buffer_read_amount)); - read_amount += buffer_read_amount; - if (buffer_read_amount < front_buffer.size()) { - front_buffer_offset_ += buffer_read_amount; - } else { - deque_of_buffers_.pop_front(); - front_buffer_offset_ = 0; - } - } - size_ -= read_amount; -#if DCHECK_IS_ON() - CheckInvariants(); -#endif - return read_amount; -} - -void ByteBufferQueue::Append(Vector<uint8_t> buffer) { - if (buffer.empty()) { - return; - } - size_ += buffer.size(); - deque_of_buffers_.push_back(std::move(buffer)); -#if DCHECK_IS_ON() - CheckInvariants(); -#endif -} - -void ByteBufferQueue::Clear() { - deque_of_buffers_.clear(); - front_buffer_offset_ = 0; - size_ = 0; -#if DCHECK_IS_ON() - CheckInvariants(); -#endif -} - -#if DCHECK_IS_ON() -void ByteBufferQueue::CheckInvariants() const { - wtf_size_t buffer_size_sum = 0; - for (const auto& buffer : deque_of_buffers_) { - DCHECK(!buffer.empty()); - buffer_size_sum += buffer.size(); - } - DCHECK_EQ(size_, buffer_size_sum - front_buffer_offset_); - if (deque_of_buffers_.empty()) { - DCHECK_EQ(front_buffer_offset_, 0u); - } else { - DCHECK_LT(front_buffer_offset_, deque_of_buffers_.front().size()); - } -} -#endif - -} // namespace blink
diff --git a/third_party/blink/renderer/modules/peerconnection/byte_buffer_queue.h b/third_party/blink/renderer/modules/peerconnection/byte_buffer_queue.h deleted file mode 100644 index 52f99a6..0000000 --- a/third_party/blink/renderer/modules/peerconnection/byte_buffer_queue.h +++ /dev/null
@@ -1,69 +0,0 @@ -// Copyright 2018 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_BYTE_BUFFER_QUEUE_H_ -#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_BYTE_BUFFER_QUEUE_H_ - -#include "base/containers/span.h" -#include "base/dcheck_is_on.h" -#include "third_party/blink/renderer/modules/modules_export.h" -#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" -#include "third_party/blink/renderer/platform/wtf/deque.h" -#include "third_party/blink/renderer/platform/wtf/vector.h" - -namespace blink { - -// A ByteBufferQueue is a byte buffer with O(1) append and O(n) read operations. -// Clients can append entire byte buffers then copy data out across buffer -// boundaries using |ReadInto|. -class MODULES_EXPORT ByteBufferQueue final { - DISALLOW_NEW(); - - public: - // Number of bytes that can be read. - wtf_size_t size() const { return size_; } - - // True if size() == 0. - bool empty() const { return size_ == 0; } - - // Copies data into the given byte span. This will cause bytes to be consumed - // so that the next call to ReadInto will return different bytes. - // Returns the number of bytes written to |buffer_out|. - wtf_size_t ReadInto(base::span<uint8_t> buffer_out); - - // Appends the contents of a byte buffer. This takes ownership of the buffer. - void Append(Vector<uint8_t> buffer); - - // Clear stored buffers. - void Clear(); - - private: -#if DCHECK_IS_ON() - void CheckInvariants() const; -#endif - - // Number of bytes that can be read. - // |Append()| adds to this number. - // |ReadInto()| subtracts from this number. - // Invariant: |size_| = sum of |deque_of_buffers_| element sizes - - // |front_buffer_offset_|. - wtf_size_t size_ = 0; - - // Double-ended queue of byte buffers. - // |Append()| pushes to the right. - // |ReadInto()| pops from the left (if an entire buffer has been read). - // Invariant: No element in |deque_of_buffers_| is empty. - Deque<Vector<uint8_t>> deque_of_buffers_; - - // The offset from which to start reading the buffer at the front of - // |deque_of_buffers_|. - // Invariants: - // - If |deque_of_buffers_| is empty, |front_buffer_offset_| = 0. - // - Otherwise, |front_buffer_offset_| < |deque_of_buffers_|.front().size(). - wtf_size_t front_buffer_offset_ = 0; -}; - -} // namespace blink - -#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_BYTE_BUFFER_QUEUE_H_
diff --git a/third_party/blink/renderer/modules/peerconnection/byte_buffer_queue_test.cc b/third_party/blink/renderer/modules/peerconnection/byte_buffer_queue_test.cc deleted file mode 100644 index 5cc47e0..0000000 --- a/third_party/blink/renderer/modules/peerconnection/byte_buffer_queue_test.cc +++ /dev/null
@@ -1,142 +0,0 @@ -// Copyright 2018 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "third_party/blink/renderer/modules/peerconnection/byte_buffer_queue.h" - -#include "testing/gmock/include/gmock/gmock.h" -#include "third_party/blink/renderer/platform/testing/task_environment.h" - -namespace blink { - -using testing::ElementsAre; - -TEST(ByteBufferQueueTest, DefaultConstructor) { - test::TaskEnvironment task_environment; - ByteBufferQueue buffer_queue; - EXPECT_EQ(0u, buffer_queue.size()); - EXPECT_TRUE(buffer_queue.empty()); -} - -TEST(ByteBufferQueueTest, AppendEmpty) { - test::TaskEnvironment task_environment; - ByteBufferQueue buffer_queue; - buffer_queue.Append({}); - EXPECT_TRUE(buffer_queue.empty()); -} - -TEST(ByteBufferQueueTest, AppendOneSegment) { - test::TaskEnvironment task_environment; - ByteBufferQueue buffer_queue; - buffer_queue.Append({1, 2, 3}); - EXPECT_EQ(3u, buffer_queue.size()); -} - -TEST(ByteBufferQueueTest, AppendTwoSegments) { - test::TaskEnvironment task_environment; - ByteBufferQueue buffer_queue; - buffer_queue.Append({1, 2, 3}); - buffer_queue.Append({4, 5}); - EXPECT_EQ(5u, buffer_queue.size()); -} - -TEST(ByteBufferQueueTest, ReadIntoEmpty) { - test::TaskEnvironment task_environment; - ByteBufferQueue buffer_queue; - Vector<uint8_t> data(100); - EXPECT_EQ(0u, buffer_queue.ReadInto(base::span(data))); -} - -TEST(ByteBufferQueueTest, ReadIntoLessThanOneSegment) { - test::TaskEnvironment task_environment; - ByteBufferQueue buffer_queue; - buffer_queue.Append({1, 2, 3}); - Vector<uint8_t> data(2); - EXPECT_EQ(2u, buffer_queue.ReadInto(base::span(data))); - EXPECT_EQ(1u, buffer_queue.size()); - EXPECT_THAT(data, ElementsAre(1, 2)); -} - -TEST(ByteBufferQueueTest, ReadIntoExactOneSegmentSize) { - test::TaskEnvironment task_environment; - ByteBufferQueue buffer_queue; - buffer_queue.Append({1, 2, 3}); - Vector<uint8_t> data(3); - EXPECT_EQ(3u, buffer_queue.ReadInto(base::span(data))); - EXPECT_EQ(0u, buffer_queue.size()); - EXPECT_THAT(data, ElementsAre(1, 2, 3)); -} - -TEST(ByteBufferQueueTest, ReadIntoOverOneSegmentSize) { - test::TaskEnvironment task_environment; - ByteBufferQueue buffer_queue; - buffer_queue.Append({1, 2, 3}); - Vector<uint8_t> data(5); - EXPECT_EQ(3u, buffer_queue.ReadInto(base::span(data))); - EXPECT_EQ(0u, buffer_queue.size()); - EXPECT_THAT(data, ElementsAre(1, 2, 3, 0, 0)); -} - -TEST(ByteBufferQueueTest, ReadIntoEmptyData) { - test::TaskEnvironment task_environment; - ByteBufferQueue buffer_queue; - buffer_queue.Append({1, 2, 3}); - Vector<uint8_t> data; - EXPECT_EQ(0u, buffer_queue.ReadInto(base::span(data))); - EXPECT_EQ(3u, buffer_queue.size()); -} - -TEST(ByteBufferQueueTest, ReadIntoExactlyTwoSegments) { - test::TaskEnvironment task_environment; - ByteBufferQueue buffer_queue; - buffer_queue.Append({1, 2, 3}); - buffer_queue.Append({4, 5}); - Vector<uint8_t> data(5); - EXPECT_EQ(5u, buffer_queue.ReadInto(base::span(data))); - EXPECT_EQ(0u, buffer_queue.size()); - EXPECT_THAT(data, ElementsAre(1, 2, 3, 4, 5)); -} - -TEST(ByteBufferQueueTest, ReadIntoAcrossTwoSegmentsMisaligned) { - test::TaskEnvironment task_environment; - ByteBufferQueue buffer_queue; - buffer_queue.Append({1, 2, 3}); - buffer_queue.Append({4, 5}); - - Vector<uint8_t> data(2); - EXPECT_EQ(2u, buffer_queue.ReadInto(base::span(data))); - EXPECT_THAT(data, ElementsAre(1, 2)); - - EXPECT_EQ(2u, buffer_queue.ReadInto(base::span(data))); - EXPECT_THAT(data, ElementsAre(3, 4)); - - EXPECT_EQ(1u, buffer_queue.ReadInto(base::span(data))); - EXPECT_THAT(data, ElementsAre(5, 4)); -} - -TEST(ByteBufferQueueTest, ClearEmptyBuffer) { - test::TaskEnvironment task_environment; - ByteBufferQueue buffer_queue; - buffer_queue.Clear(); - EXPECT_EQ(0u, buffer_queue.size()); - EXPECT_TRUE(buffer_queue.empty()); -} - -TEST(ByteBufferQueueTest, ReadIntoAfterClearThenAppend) { - test::TaskEnvironment task_environment; - ByteBufferQueue buffer_queue; - - buffer_queue.Append({1, 2, 3}); - Vector<uint8_t> data(2); - buffer_queue.ReadInto(base::span(data)); - - buffer_queue.Clear(); - EXPECT_EQ(0u, buffer_queue.size()); - EXPECT_EQ(0u, buffer_queue.ReadInto(base::span(data))); - - buffer_queue.Append({4, 5}); - EXPECT_EQ(2u, buffer_queue.ReadInto(base::span(data))); - EXPECT_THAT(data, ElementsAre(4, 5)); -} - -} // namespace blink
diff --git a/third_party/blink/renderer/modules/webgpu/dawn_enum_conversions.cc b/third_party/blink/renderer/modules/webgpu/dawn_enum_conversions.cc index 9cc78d69..37ed944 100644 --- a/third_party/blink/renderer/modules/webgpu/dawn_enum_conversions.cc +++ b/third_party/blink/renderer/modules/webgpu/dawn_enum_conversions.cc
@@ -11,7 +11,6 @@ #include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_buffer_binding_type.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_buffer_map_state.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_compare_function.h" -#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_component_swizzle.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_cull_mode.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_error_filter.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_feature_name.h" @@ -989,22 +988,23 @@ NOTREACHED(); } -wgpu::ComponentSwizzle AsDawnEnum(const V8GPUComponentSwizzle& webgpu_enum) { - switch (webgpu_enum.AsEnum()) { - case V8GPUComponentSwizzle::Enum::kZero: - return wgpu::ComponentSwizzle::Zero; - case V8GPUComponentSwizzle::Enum::kOne: - return wgpu::ComponentSwizzle::One; - case V8GPUComponentSwizzle::Enum::kR: +wgpu::ComponentSwizzle AsDawnEnum(const UChar c) { + switch (c) { + case 'r': return wgpu::ComponentSwizzle::R; - case V8GPUComponentSwizzle::Enum::kG: + case 'g': return wgpu::ComponentSwizzle::G; - case V8GPUComponentSwizzle::Enum::kB: + case 'b': return wgpu::ComponentSwizzle::B; - case V8GPUComponentSwizzle::Enum::kA: + case 'a': return wgpu::ComponentSwizzle::A; + case '0': + return wgpu::ComponentSwizzle::Zero; + case '1': + return wgpu::ComponentSwizzle::One; + default: + return wgpu::ComponentSwizzle::Undefined; } - NOTREACHED(); } V8GPUBufferMapState FromDawnEnum(wgpu::BufferMapState dawn_enum) {
diff --git a/third_party/blink/renderer/modules/webgpu/dawn_enum_conversions.h b/third_party/blink/renderer/modules/webgpu/dawn_enum_conversions.h index d0b35c0..53ffe3f 100644 --- a/third_party/blink/renderer/modules/webgpu/dawn_enum_conversions.h +++ b/third_party/blink/renderer/modules/webgpu/dawn_enum_conversions.h
@@ -2,6 +2,7 @@ #define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_DAWN_ENUM_CONVERSIONS_H_ #include "third_party/blink/renderer/platform/graphics/gpu/webgpu_cpp.h" +#include "third_party/blink/renderer/platform/wtf/text/wtf_uchar.h" namespace blink { @@ -32,7 +33,6 @@ class V8GPUFrontFace; class V8GPUTextureAspect; class V8GPUErrorFilter; -class V8GPUComponentSwizzle; enum class PredefinedColorSpace; // Convert WebGPU bitfield values to Dawn enums. These have the same value. @@ -70,7 +70,7 @@ wgpu::FrontFace AsDawnEnum(const V8GPUFrontFace& webgpu_enum); wgpu::TextureAspect AsDawnEnum(const V8GPUTextureAspect& webgpu_enum); wgpu::ErrorFilter AsDawnEnum(const V8GPUErrorFilter& webgpu_enum); -wgpu::ComponentSwizzle AsDawnEnum(const V8GPUComponentSwizzle& webgpu_enum); +wgpu::ComponentSwizzle AsDawnEnum(const UChar c); // Convert Dawn enums to WebGPU IDL enums. V8GPUQueryType FromDawnEnum(wgpu::QueryType dawn_enum);
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_texture.cc b/third_party/blink/renderer/modules/webgpu/gpu_texture.cc index dc86440..b350e038 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_texture.cc +++ b/third_party/blink/renderer/modules/webgpu/gpu_texture.cc
@@ -6,7 +6,6 @@ #include "base/containers/heap_array.h" #include "gpu/command_buffer/client/webgpu_interface.h" -#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_texture_component_swizzle.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_texture_descriptor.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_texture_view_descriptor.h" #include "third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h" @@ -99,24 +98,49 @@ dawn_desc_info->dawn_desc.usage = static_cast<wgpu::TextureUsage>(webgpu_desc->usage()); } - auto* swizzle = webgpu_desc->getSwizzleOr(nullptr); + const auto& swizzle = webgpu_desc->swizzle(); // Only pass the swizzle descriptor to Dawn if swizzle is non-default because // the C API will produce validation errors if a chained struct is passed // without its feature being enabled. - if (swizzle && (swizzle->r() != V8GPUComponentSwizzle::Enum::kR || - swizzle->g() != V8GPUComponentSwizzle::Enum::kG || - swizzle->b() != V8GPUComponentSwizzle::Enum::kB || - swizzle->a() != V8GPUComponentSwizzle::Enum::kA)) { + if (swizzle != "rgba") { dawn_desc_info->swizzle_desc = std::make_unique<wgpu::TextureComponentSwizzleDescriptor>(); - dawn_desc_info->swizzle_desc->swizzle.r = AsDawnEnum(swizzle->r()); - dawn_desc_info->swizzle_desc->swizzle.g = AsDawnEnum(swizzle->g()); - dawn_desc_info->swizzle_desc->swizzle.b = AsDawnEnum(swizzle->b()); - dawn_desc_info->swizzle_desc->swizzle.a = AsDawnEnum(swizzle->a()); + dawn_desc_info->swizzle_desc->swizzle.r = AsDawnEnum(swizzle[0]); + dawn_desc_info->swizzle_desc->swizzle.g = AsDawnEnum(swizzle[1]); + dawn_desc_info->swizzle_desc->swizzle.b = AsDawnEnum(swizzle[2]); + dawn_desc_info->swizzle_desc->swizzle.a = AsDawnEnum(swizzle[3]); dawn_desc_info->dawn_desc.nextInChain = dawn_desc_info->swizzle_desc.get(); } } +// Validate swizzle must be a four-character string that only includes "r", "g", +// "b", "a", "0", or "1". +bool ValidateSwizzle(const String& swizzle, ExceptionState& exception_state) { + if (!RuntimeEnabledFeatures::WebGPUExperimentalFeaturesEnabled()) { + return true; + } + + if (swizzle.length() != 4) { + exception_state.ThrowTypeError(String::Format( + "Swizzle ('%s') must be exactly a four-character string.", + swizzle.Utf8().c_str())); + return false; + } + + if (AsDawnEnum(swizzle[0]) == wgpu::ComponentSwizzle::Undefined || + AsDawnEnum(swizzle[1]) == wgpu::ComponentSwizzle::Undefined || + AsDawnEnum(swizzle[2]) == wgpu::ComponentSwizzle::Undefined || + AsDawnEnum(swizzle[3]) == wgpu::ComponentSwizzle::Undefined) { + exception_state.ThrowTypeError(String::Format( + "Swizzle ('%s') must contain only 'r', 'g', 'b', 'a', '0', " + "or '1' characters.", + swizzle.Utf8().c_str())); + return false; + } + + return true; +} + // Dawn represents `undefined` as the special uint32_t value (0xFFFF'FFFF). // Blink must make sure that an actual value of 0xFFFF'FFFF coming in from JS // is not treated as the special `undefined` value, so it injects an error in @@ -245,6 +269,10 @@ return nullptr; } + if (!ValidateSwizzle(webgpu_desc->swizzle(), exception_state)) { + return nullptr; + } + std::string error = ValidateTextureMipLevelAndArrayLayerCounts(webgpu_desc); if (!error.empty()) { device()->InjectError(wgpu::ErrorType::Validation, error.c_str());
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_texture_view_descriptor.idl b/third_party/blink/renderer/modules/webgpu/gpu_texture_view_descriptor.idl index e48686a..cad0430e 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_texture_view_descriptor.idl +++ b/third_party/blink/renderer/modules/webgpu/gpu_texture_view_descriptor.idl
@@ -13,14 +13,7 @@ GPUIntegerCoordinate baseArrayLayer = 0; GPUIntegerCoordinate arrayLayerCount; GPUTextureUsageFlags usage = 0; - [RuntimeEnabled=WebGPUExperimentalFeatures] GPUTextureComponentSwizzle swizzle; -}; - -dictionary GPUTextureComponentSwizzle { - GPUComponentSwizzle r = "r"; - GPUComponentSwizzle g = "g"; - GPUComponentSwizzle b = "b"; - GPUComponentSwizzle a = "a"; + [RuntimeEnabled=WebGPUExperimentalFeatures] DOMString swizzle = "rgba"; }; enum GPUTextureViewDimension { @@ -37,12 +30,3 @@ "stencil-only", "depth-only" }; - -enum GPUComponentSwizzle { - "zero", - "one", - "r", - "g", - "b", - "a", -};
diff --git a/third_party/blink/renderer/modules/xr/BUILD.gn b/third_party/blink/renderer/modules/xr/BUILD.gn index df9844a..2b3c7c1 100644 --- a/third_party/blink/renderer/modules/xr/BUILD.gn +++ b/third_party/blink/renderer/modules/xr/BUILD.gn
@@ -49,8 +49,8 @@ "xr_frame_request_callback_collection.h", "xr_gpu_binding.cc", "xr_gpu_binding.h", - "xr_gpu_projection_layer.cc", - "xr_gpu_projection_layer.h", + "xr_gpu_drawing_context.cc", + "xr_gpu_drawing_context.h", "xr_gpu_sub_image.h", "xr_gpu_swap_chain.cc", "xr_gpu_swap_chain.h", @@ -83,6 +83,7 @@ "xr_joint_space.h", "xr_layer.cc", "xr_layer.h", + "xr_layer_drawing_context.h", "xr_layer_event.cc", "xr_layer_event.h", "xr_layer_shared_image_manager.cc", @@ -150,11 +151,11 @@ "xr_webgl_depth_information.h", "xr_webgl_drawing_buffer_swap_chain.cc", "xr_webgl_drawing_buffer_swap_chain.h", + "xr_webgl_drawing_context.cc", + "xr_webgl_drawing_context.h", "xr_webgl_layer.cc", "xr_webgl_layer.h", "xr_webgl_layer_client.h", - "xr_webgl_projection_layer.cc", - "xr_webgl_projection_layer.h", "xr_webgl_sub_image.cc", "xr_webgl_sub_image.h", "xr_webgl_swap_chain.cc",
diff --git a/third_party/blink/renderer/modules/xr/xr_composition_layer.cc b/third_party/blink/renderer/modules/xr/xr_composition_layer.cc index 6238479a..8ad00569 100644 --- a/third_party/blink/renderer/modules/xr/xr_composition_layer.cc +++ b/third_party/blink/renderer/modules/xr/xr_composition_layer.cc
@@ -6,13 +6,24 @@ #include "base/notimplemented.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_xr_layer_layout.h" +#include "third_party/blink/renderer/modules/xr/xr_frame_provider.h" #include "third_party/blink/renderer/modules/xr/xr_graphics_binding.h" +#include "third_party/blink/renderer/modules/xr/xr_layer_drawing_context.h" +#include "third_party/blink/renderer/modules/xr/xr_projection_layer.h" #include "third_party/blink/renderer/modules/xr/xr_session.h" +#include "third_party/blink/renderer/modules/xr/xr_swap_chain.h" +#include "third_party/blink/renderer/modules/xr/xr_system.h" namespace blink { -XRCompositionLayer::XRCompositionLayer(XRGraphicsBinding* binding) - : XRLayer(binding->session()), binding_(binding) {} +XRCompositionLayer::XRCompositionLayer(XRGraphicsBinding* binding, + XRLayerDrawingContext* drawing_context) + : XRLayer(binding->session()), + binding_(binding), + drawing_context_(drawing_context) { + CHECK(drawing_context_); + drawing_context_->SetCompositionLayer(this); +} V8XRLayerLayout XRCompositionLayer::layout() const { return V8XRLayerLayout(V8XRLayerLayout::Enum::kDefault); @@ -75,8 +86,40 @@ mip_levels_ = mipLevels; } +uint16_t XRCompositionLayer::textureWidth() const { + return drawing_context_->TextureWidth(); +} + +uint16_t XRCompositionLayer::textureHeight() const { + return drawing_context_->TextureHeight(); +} + +uint16_t XRCompositionLayer::textureArrayLength() const { + return drawing_context_->TextureWidth(); +} + +void XRCompositionLayer::OnFrameStart() { + drawing_context_->OnFrameStart(); +} + +void XRCompositionLayer::OnFrameEnd() { + drawing_context_->OnFrameEnd(); + + XRFrameProvider* frame_provider = session()->xr()->frameProvider(); + + if (IsModified()) { + if (XRProjectionLayer* layer = DynamicTo<XRProjectionLayer>(this); layer) { + frame_provider->UpdateLayerViewports(layer); + SetModified(false); + } + } + + frame_provider->SubmitCompositionLayer(this); +} + void XRCompositionLayer::Trace(Visitor* visitor) const { visitor->Trace(binding_); + visitor->Trace(drawing_context_); XRLayer::Trace(visitor); }
diff --git a/third_party/blink/renderer/modules/xr/xr_composition_layer.h b/third_party/blink/renderer/modules/xr/xr_composition_layer.h index 2186eaf..43a637db 100644 --- a/third_party/blink/renderer/modules/xr/xr_composition_layer.h +++ b/third_party/blink/renderer/modules/xr/xr_composition_layer.h
@@ -16,12 +16,14 @@ class V8XRLayerLayout; class XRGraphicsBinding; +class XRLayerDrawingContext; class XRCompositionLayer : public XRLayer { DEFINE_WRAPPERTYPEINFO(); public: - explicit XRCompositionLayer(XRGraphicsBinding* binding); + XRCompositionLayer(XRGraphicsBinding* binding, + XRLayerDrawingContext* drawing_context); ~XRCompositionLayer() override = default; XRGraphicsBinding* binding() const { return binding_.Get(); } @@ -38,11 +40,17 @@ bool needsRedraw() const; void destroy() const; - void Trace(Visitor*) const override; + uint16_t textureWidth() const; + uint16_t textureHeight() const; + uint16_t textureArrayLength() const; - virtual uint16_t textureWidth() const = 0; - virtual uint16_t textureHeight() const = 0; - virtual uint16_t textureArrayLength() const = 0; + void OnFrameStart() override; + void OnFrameEnd() override; + void OnResize() override {} + + XRLayerDrawingContext* drawing_context() { return drawing_context_; } + + void Trace(Visitor*) const override; protected: void SetNeedsRedraw(bool needsRedraw); @@ -59,6 +67,8 @@ float opacity_{1.0}; uint16_t mip_levels_{1}; bool needs_redraw_{false}; + + Member<XRLayerDrawingContext> drawing_context_; }; } // namespace blink
diff --git a/third_party/blink/renderer/modules/xr/xr_cylinder_layer.cc b/third_party/blink/renderer/modules/xr/xr_cylinder_layer.cc index 604d4c4e..0af70f7 100644 --- a/third_party/blink/renderer/modules/xr/xr_cylinder_layer.cc +++ b/third_party/blink/renderer/modules/xr/xr_cylinder_layer.cc
@@ -10,8 +10,9 @@ namespace blink { XRCylinderLayer::XRCylinderLayer(const XRCylinderLayerInit* init, - XRGraphicsBinding* binding) - : XRShapedLayer(init, binding), + XRGraphicsBinding* binding, + XRLayerDrawingContext* drawing_context) + : XRShapedLayer(init, binding, drawing_context), radius_(init->radius()), central_angle_(init->centralAngle()), aspect_ratio_(init->aspectRatio()) { @@ -23,25 +24,29 @@ } } +XRLayerType XRCylinderLayer::LayerType() const { + return XRLayerType::kCylinderLayer; +} + void XRCylinderLayer::setRadius(float radius) { radius_ = radius; - OnUpdateLayerData(); + SetModified(true); } void XRCylinderLayer::setCentralAngle(float central_angle) { central_angle_ = central_angle; - OnUpdateLayerData(); + SetModified(true); } void XRCylinderLayer::setAspectRatio(float aspect_ratio) { aspect_ratio_ = aspect_ratio; - OnUpdateLayerData(); + SetModified(true); } void XRCylinderLayer::setTransform(XRRigidTransform* value) { if (transform_ != value) { transform_ = value; - OnUpdateLayerData(); + SetModified(true); } }
diff --git a/third_party/blink/renderer/modules/xr/xr_cylinder_layer.h b/third_party/blink/renderer/modules/xr/xr_cylinder_layer.h index b0fbafd..ca10eff 100644 --- a/third_party/blink/renderer/modules/xr/xr_cylinder_layer.h +++ b/third_party/blink/renderer/modules/xr/xr_cylinder_layer.h
@@ -19,10 +19,13 @@ DEFINE_WRAPPERTYPEINFO(); public: - explicit XRCylinderLayer(const XRCylinderLayerInit* init, - XRGraphicsBinding* binding); + XRCylinderLayer(const XRCylinderLayerInit* init, + XRGraphicsBinding* binding, + XRLayerDrawingContext* drawing_context); ~XRCylinderLayer() override = default; + XRLayerType LayerType() const override; + XRRigidTransform* transform() const { return transform_.Get(); } void setTransform(XRRigidTransform* value); float radius() const { return radius_; }
diff --git a/third_party/blink/renderer/modules/xr/xr_equirect_layer.cc b/third_party/blink/renderer/modules/xr/xr_equirect_layer.cc index c97519c..51fd109c 100644 --- a/third_party/blink/renderer/modules/xr/xr_equirect_layer.cc +++ b/third_party/blink/renderer/modules/xr/xr_equirect_layer.cc
@@ -10,8 +10,9 @@ namespace blink { XREquirectLayer::XREquirectLayer(const XREquirectLayerInit* init, - XRGraphicsBinding* binding) - : XRShapedLayer(init, binding), + XRGraphicsBinding* binding, + XRLayerDrawingContext* drawing_context) + : XRShapedLayer(init, binding, drawing_context), radius_(init->radius()), central_horizontal_angle_(init->centralHorizontalAngle()), upper_vertical_angle_(init->upperVerticalAngle()), @@ -24,30 +25,34 @@ } } +XRLayerType XREquirectLayer::LayerType() const { + return XRLayerType::kEquirectLayer; +} + void XREquirectLayer::setRadius(float radius) { radius_ = radius; - OnUpdateLayerData(); + SetModified(true); } void XREquirectLayer::setCentralHorizontalAngle(float angle) { central_horizontal_angle_ = angle; - OnUpdateLayerData(); + SetModified(true); } void XREquirectLayer::setUpperVerticalAngle(float angle) { upper_vertical_angle_ = angle; - OnUpdateLayerData(); + SetModified(true); } void XREquirectLayer::setLowerVerticalAngle(float angle) { lower_vertical_angle_ = angle; - OnUpdateLayerData(); + SetModified(true); } void XREquirectLayer::setTransform(XRRigidTransform* value) { if (transform_ != value) { transform_ = value; - OnUpdateLayerData(); + SetModified(true); } }
diff --git a/third_party/blink/renderer/modules/xr/xr_equirect_layer.h b/third_party/blink/renderer/modules/xr/xr_equirect_layer.h index a9700d9d..3d8ac7e0 100644 --- a/third_party/blink/renderer/modules/xr/xr_equirect_layer.h +++ b/third_party/blink/renderer/modules/xr/xr_equirect_layer.h
@@ -21,10 +21,13 @@ DEFINE_WRAPPERTYPEINFO(); public: - explicit XREquirectLayer(const XREquirectLayerInit* init, - XRGraphicsBinding* binding); + XREquirectLayer(const XREquirectLayerInit* init, + XRGraphicsBinding* binding, + XRLayerDrawingContext* drawing_context); ~XREquirectLayer() override = default; + XRLayerType LayerType() const override; + XRRigidTransform* transform() const { return transform_.Get(); } void setTransform(XRRigidTransform* value); float radius() const { return radius_; }
diff --git a/third_party/blink/renderer/modules/xr/xr_frame_provider.cc b/third_party/blink/renderer/modules/xr/xr_frame_provider.cc index 00391ae3..bd043b8 100644 --- a/third_party/blink/renderer/modules/xr/xr_frame_provider.cc +++ b/third_party/blink/renderer/modules/xr/xr_frame_provider.cc
@@ -20,16 +20,16 @@ #include "third_party/blink/renderer/modules/webgpu/gpu_device.h" #include "third_party/blink/renderer/modules/webgpu/gpu_texture.h" #include "third_party/blink/renderer/modules/xr/xr_gpu_binding.h" -#include "third_party/blink/renderer/modules/xr/xr_gpu_projection_layer.h" +#include "third_party/blink/renderer/modules/xr/xr_gpu_drawing_context.h" #include "third_party/blink/renderer/modules/xr/xr_gpu_swap_chain.h" #include "third_party/blink/renderer/modules/xr/xr_graphics_binding.h" #include "third_party/blink/renderer/modules/xr/xr_projection_layer.h" #include "third_party/blink/renderer/modules/xr/xr_session.h" #include "third_party/blink/renderer/modules/xr/xr_system.h" #include "third_party/blink/renderer/modules/xr/xr_viewport.h" +#include "third_party/blink/renderer/modules/xr/xr_webgl_drawing_context.h" #include "third_party/blink/renderer/modules/xr/xr_webgl_layer.h" #include "third_party/blink/renderer/modules/xr/xr_webgl_layer_client.h" -#include "third_party/blink/renderer/modules/xr/xr_webgl_projection_layer.h" #include "third_party/blink/renderer/platform/graphics/gpu/xr_frame_transport.h" #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h" #include "ui/display/display.h" @@ -640,11 +640,24 @@ return high_res_now_ms; } +void XRFrameProvider::SubmitCompositionLayer(XRCompositionLayer* layer) { + CHECK(layer); + CHECK(layer->drawing_context()); + + if (layer->drawing_context()->GraphicsApi() == + XRGraphicsBinding::Api::kWebGL) { + auto* drawing_context = + static_cast<XRWebGLDrawingContext*>(layer->drawing_context()); + SubmitWebGLLayer(drawing_context, drawing_context->TextureWasQueried()); + } else { + SubmitWebGPULayer(layer); + } +} + void XRFrameProvider::SubmitWebGLLayer(XRWebGLLayerClient* layer_client, bool was_changed) { CHECK(layer_client); CHECK(immersive_session_); - const XRLayer* layer = layer_client->layer(); CHECK(layer); @@ -759,8 +772,7 @@ frame_id_, left_coords, right_coords, gfx::Size(width, height)); } -void XRFrameProvider::SubmitWebGPULayer(XRGPUProjectionLayer* layer, - bool was_queried) { +void XRFrameProvider::SubmitWebGPULayer(XRCompositionLayer* layer) { CHECK(layer); CHECK(immersive_session_); CHECK_EQ(layer->session(), immersive_session_); @@ -769,11 +781,18 @@ return; } + // A static_cast is safe here because the drawing context type was already + // checked by SubmitCompositionLayer. + auto* drawing_context = + static_cast<XRGPUDrawingContext*>(layer->drawing_context()); + CHECK(drawing_context); + + bool was_queried = drawing_context->TextureWasQueried(); + TRACE_EVENT1("gpu", "XRFrameProvider::SubmitWebGPULayer", "frame", frame_id_); DVLOG(3) << __func__ << ": frame=" << frame_id_; - XRGPUBinding* webgpu_binding = static_cast<XRGPUBinding*>(layer->binding()); - GPUDevice* device = webgpu_binding->device(); + GPUDevice* device = drawing_context->device(); if (frame_id_ < 0) { // There is no valid frame_id_, and the browser side is not currently
diff --git a/third_party/blink/renderer/modules/xr/xr_frame_provider.h b/third_party/blink/renderer/modules/xr/xr_frame_provider.h index 750296d..ea437b4 100644 --- a/third_party/blink/renderer/modules/xr/xr_frame_provider.h +++ b/third_party/blink/renderer/modules/xr/xr_frame_provider.h
@@ -25,12 +25,12 @@ class LocalDOMWindow; class XRFrameTransport; -class XRGPUProjectionLayer; class XRProjectionLayer; class XRSession; class XRSystem; class XRWebGLLayer; class XRWebGLLayerClient; +class XRCompositionLayer; // This class manages requesting and dispatching frame updates, which includes // pose information for a given XRDevice. @@ -62,11 +62,11 @@ void OnNonImmersiveVSync(double high_res_now_ms); + void SubmitCompositionLayer(XRCompositionLayer*); + void SubmitWebGLLayer(XRWebGLLayerClient*, bool was_changed); void UpdateWebGLLayerViewports(XRWebGLLayer*); - void SubmitWebGPULayer(XRGPUProjectionLayer*, bool was_queried); - // Used for both WebGPU and WebGL layers. void UpdateLayerViewports(XRProjectionLayer*); @@ -91,6 +91,8 @@ kImmersive = 1, }; + void SubmitWebGPULayer(XRCompositionLayer*); + void OnImmersiveFrameData(device::mojom::blink::XRFrameDataPtr data); void OnNonImmersiveFrameData(XRSession* session, device::mojom::blink::XRFrameDataPtr data);
diff --git a/third_party/blink/renderer/modules/xr/xr_gpu_binding.cc b/third_party/blink/renderer/modules/xr/xr_gpu_binding.cc index 0e5be45..ef1e615 100644 --- a/third_party/blink/renderer/modules/xr/xr_gpu_binding.cc +++ b/third_party/blink/renderer/modules/xr/xr_gpu_binding.cc
@@ -14,10 +14,11 @@ #include "third_party/blink/renderer/modules/webgpu/gpu_supported_limits.h" #include "third_party/blink/renderer/modules/webgpu/gpu_texture.h" #include "third_party/blink/renderer/modules/xr/xr_frame_provider.h" -#include "third_party/blink/renderer/modules/xr/xr_gpu_projection_layer.h" +#include "third_party/blink/renderer/modules/xr/xr_gpu_drawing_context.h" #include "third_party/blink/renderer/modules/xr/xr_gpu_sub_image.h" #include "third_party/blink/renderer/modules/xr/xr_gpu_swap_chain.h" #include "third_party/blink/renderer/modules/xr/xr_gpu_texture_array_swap_chain.h" +#include "third_party/blink/renderer/modules/xr/xr_projection_layer.h" #include "third_party/blink/renderer/modules/xr/xr_session.h" #include "third_party/blink/renderer/modules/xr/xr_system.h" #include "third_party/blink/renderer/modules/xr/xr_view.h" @@ -160,8 +161,10 @@ MakeGarbageCollected<XRGPUStaticSwapChain>(device_, depth_stencil_desc); } - return MakeGarbageCollected<XRGPUProjectionLayer>(this, wrapped_swap_chain, - depth_stencil_swap_chain); + auto* drawing_context = MakeGarbageCollected<XRGPUDrawingContext>( + this, wrapped_swap_chain, depth_stencil_swap_chain); + + return MakeGarbageCollected<XRProjectionLayer>(this, drawing_context); } XRGPUSubImage* XRGPUBinding::getViewSubImage(XRProjectionLayer* layer, @@ -181,21 +184,24 @@ return nullptr; } - XRGPUProjectionLayer* gpu_layer = static_cast<XRGPUProjectionLayer*>(layer); + // The layer passed the OwnsLayer check, confirming it can only contain + // a GPU drawing context. This makes the static_cast safe. + XRGPUDrawingContext* drawing_context = + static_cast<XRGPUDrawingContext*>(layer->drawing_context()); - GPUTexture* color_texture = - gpu_layer->color_swap_chain()->GetCurrentTexture(); + XRGPUSwapChain* color_swap_chain = drawing_context->color_swap_chain(); + GPUTexture* color_texture = color_swap_chain->GetCurrentTexture(); GPUTexture* depth_stencil_texture = nullptr; XRGPUSwapChain* depth_stencil_swap_chain = - gpu_layer->depth_stencil_swap_chain(); + drawing_context->depth_stencil_swap_chain(); if (depth_stencil_swap_chain) { depth_stencil_texture = depth_stencil_swap_chain->GetCurrentTexture(); } XRViewData* viewData = view->ViewData(); if (viewData->ApplyViewportScaleForFrame()) { - gpu_layer->MarkViewportUpdated(); + layer->SetModified(true); } gfx::Rect viewport = GetViewportForView(layer, viewData);
diff --git a/third_party/blink/renderer/modules/xr/xr_gpu_projection_layer.cc b/third_party/blink/renderer/modules/xr/xr_gpu_drawing_context.cc similarity index 63% rename from third_party/blink/renderer/modules/xr/xr_gpu_projection_layer.cc rename to third_party/blink/renderer/modules/xr/xr_gpu_drawing_context.cc index aeb2b2e..7d63e4c2 100644 --- a/third_party/blink/renderer/modules/xr/xr_gpu_projection_layer.cc +++ b/third_party/blink/renderer/modules/xr/xr_gpu_drawing_context.cc
@@ -1,8 +1,8 @@ -// Copyright 2024 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. -#include "third_party/blink/renderer/modules/xr/xr_gpu_projection_layer.h" +#include "third_party/blink/renderer/modules/xr/xr_gpu_drawing_context.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_xr_gpu_projection_layer_init.h" #include "third_party/blink/renderer/modules/webgpu/gpu_device.h" @@ -18,64 +18,62 @@ namespace blink { -XRGPUProjectionLayer::XRGPUProjectionLayer( +XRGPUDrawingContext::XRGPUDrawingContext( XRGPUBinding* binding, XRGPUSwapChain* color_swap_chain, XRGPUSwapChain* depth_stencil_swap_chain) - : XRProjectionLayer(binding), - device_(binding->device()), + : device_(binding->device()), color_swap_chain_(color_swap_chain), depth_stencil_swap_chain_(depth_stencil_swap_chain) { CHECK(color_swap_chain_); - color_swap_chain_->SetLayer(this); - if (depth_stencil_swap_chain_) { - depth_stencil_swap_chain_->SetLayer(this); - } } -uint16_t XRGPUProjectionLayer::textureWidth() const { +enum XRGraphicsBinding::Api XRGPUDrawingContext::GraphicsApi() const { + return XRGraphicsBinding::Api::kWebGPU; +} + +uint16_t XRGPUDrawingContext::TextureWidth() const { return color_swap_chain_->descriptor().size.width; } -uint16_t XRGPUProjectionLayer::textureHeight() const { +uint16_t XRGPUDrawingContext::TextureHeight() const { return color_swap_chain_->descriptor().size.height; } -uint16_t XRGPUProjectionLayer::textureArrayLength() const { +uint16_t XRGPUDrawingContext::TextureArrayLength() const { return color_swap_chain_->descriptor().size.depthOrArrayLayers; } -void XRGPUProjectionLayer::OnFrameStart() { +bool XRGPUDrawingContext::TextureWasQueried() const { + return color_swap_chain_->texture_was_queried(); +} + +void XRGPUDrawingContext::SetCompositionLayer(XRCompositionLayer* layer) { + color_swap_chain_->SetLayer(layer); + if (depth_stencil_swap_chain_) { + depth_stencil_swap_chain_->SetLayer(layer); + } +} + +void XRGPUDrawingContext::OnFrameStart() { color_swap_chain_->OnFrameStart(); if (depth_stencil_swap_chain_) { depth_stencil_swap_chain_->OnFrameStart(); } } -void XRGPUProjectionLayer::OnFrameEnd() { +void XRGPUDrawingContext::OnFrameEnd() { color_swap_chain_->OnFrameEnd(); if (depth_stencil_swap_chain_) { depth_stencil_swap_chain_->OnFrameEnd(); } - - XRFrameProvider* frame_provider = session()->xr()->frameProvider(); - - if (viewport_updated_) { - frame_provider->UpdateLayerViewports(this); - viewport_updated_ = false; - } - - frame_provider->SubmitWebGPULayer(this, - color_swap_chain_->texture_was_queried()); } -void XRGPUProjectionLayer::OnResize() {} - -void XRGPUProjectionLayer::Trace(Visitor* visitor) const { +void XRGPUDrawingContext::Trace(Visitor* visitor) const { visitor->Trace(device_); visitor->Trace(color_swap_chain_); visitor->Trace(depth_stencil_swap_chain_); - XRProjectionLayer::Trace(visitor); + XRLayerDrawingContext::Trace(visitor); } } // namespace blink
diff --git a/third_party/blink/renderer/modules/xr/xr_gpu_drawing_context.h b/third_party/blink/renderer/modules/xr/xr_gpu_drawing_context.h new file mode 100644 index 0000000..5b0341a --- /dev/null +++ b/third_party/blink/renderer/modules/xr/xr_gpu_drawing_context.h
@@ -0,0 +1,54 @@ +// 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 THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_GPU_DRAWING_CONTEXT_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_GPU_DRAWING_CONTEXT_H_ + +#include "third_party/blink/renderer/modules/xr/xr_layer_drawing_context.h" + +namespace blink { + +class GPUDevice; +class XRCompositionLayer; +class XRGPUBinding; +class XRGPUSwapChain; + +class XRGPUDrawingContext final : public XRLayerDrawingContext { + public: + XRGPUDrawingContext(XRGPUBinding*, + XRGPUSwapChain* color_swap_chain, + XRGPUSwapChain* depth_stencil_swap_chain); + ~XRGPUDrawingContext() = default; + + enum XRGraphicsBinding::Api GraphicsApi() const override; + + uint16_t TextureWidth() const override; + uint16_t TextureHeight() const override; + uint16_t TextureArrayLength() const override; + + void SetCompositionLayer(XRCompositionLayer* layer) override; + + void OnFrameStart() override; + void OnFrameEnd() override; + + bool TextureWasQueried() const override; + + GPUDevice* device() { return device_; } + + XRGPUSwapChain* color_swap_chain() { return color_swap_chain_.Get(); } + XRGPUSwapChain* depth_stencil_swap_chain() { + return depth_stencil_swap_chain_.Get(); + } + + void Trace(Visitor*) const override; + + private: + Member<GPUDevice> device_; + Member<XRGPUSwapChain> color_swap_chain_; + Member<XRGPUSwapChain> depth_stencil_swap_chain_; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_GPU_DRAWING_CONTEXT_H_
diff --git a/third_party/blink/renderer/modules/xr/xr_gpu_projection_layer.h b/third_party/blink/renderer/modules/xr/xr_gpu_projection_layer.h deleted file mode 100644 index 78f48ae..0000000 --- a/third_party/blink/renderer/modules/xr/xr_gpu_projection_layer.h +++ /dev/null
@@ -1,49 +0,0 @@ -// Copyright 2024 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_GPU_PROJECTION_LAYER_H_ -#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_GPU_PROJECTION_LAYER_H_ - -#include "third_party/blink/renderer/modules/xr/xr_projection_layer.h" - -namespace blink { - -class GPUDevice; -class XRGPUBinding; -class XRGPUSwapChain; - -class XRGPUProjectionLayer final : public XRProjectionLayer { - public: - XRGPUProjectionLayer(XRGPUBinding*, - XRGPUSwapChain* color_swap_chain, - XRGPUSwapChain* depth_stencil_swap_chain); - ~XRGPUProjectionLayer() override = default; - - uint16_t textureWidth() const override; - uint16_t textureHeight() const override; - uint16_t textureArrayLength() const override; - - void OnFrameStart() override; - void OnFrameEnd() override; - void OnResize() override; - - XRGPUSwapChain* color_swap_chain() { return color_swap_chain_.Get(); } - XRGPUSwapChain* depth_stencil_swap_chain() { - return depth_stencil_swap_chain_.Get(); - } - - void MarkViewportUpdated() { viewport_updated_ = true; } - - void Trace(Visitor*) const override; - - private: - Member<GPUDevice> device_; - Member<XRGPUSwapChain> color_swap_chain_; - Member<XRGPUSwapChain> depth_stencil_swap_chain_; - bool viewport_updated_ = true; -}; - -} // namespace blink - -#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_GPU_PROJECTION_LAYER_H_
diff --git a/third_party/blink/renderer/modules/xr/xr_layer.cc b/third_party/blink/renderer/modules/xr/xr_layer.cc index 4bd1c54..8cb638a 100644 --- a/third_party/blink/renderer/modules/xr/xr_layer.cc +++ b/third_party/blink/renderer/modules/xr/xr_layer.cc
@@ -29,6 +29,14 @@ return session_->LayerSharedImageManager().HasLayerSharedImage(layer_id_); } +void XRLayer::SetModified(bool is_modified) { + is_modified_ = is_modified; +} + +bool XRLayer::IsModified() const { + return is_modified_; +} + void XRLayer::Trace(Visitor* visitor) const { visitor->Trace(session_); EventTarget::Trace(visitor);
diff --git a/third_party/blink/renderer/modules/xr/xr_layer.h b/third_party/blink/renderer/modules/xr/xr_layer.h index 872d63b..8ad9866 100644 --- a/third_party/blink/renderer/modules/xr/xr_layer.h +++ b/third_party/blink/renderer/modules/xr/xr_layer.h
@@ -15,6 +15,14 @@ class XRSession; struct XRSharedImageData; +enum class XRLayerType { + kWebGLLayer, + kProjectionLayer, + kQuadLayer, + kCylinderLayer, + kEquirectLayer +}; + class XRLayer : public EventTarget { DEFINE_WRAPPERTYPEINFO(); @@ -33,15 +41,20 @@ const AtomicString& InterfaceName() const override; uint32_t layer_id() const { return layer_id_; } + virtual XRLayerType LayerType() const = 0; const XRSharedImageData& SharedImage() const; bool HasSharedImage() const; + void SetModified(bool modified); + bool IsModified() const; + void Trace(Visitor*) const override; private: const Member<XRSession> session_; const uint32_t layer_id_; + bool is_modified_{false}; }; } // namespace blink
diff --git a/third_party/blink/renderer/modules/xr/xr_layer_drawing_context.h b/third_party/blink/renderer/modules/xr/xr_layer_drawing_context.h new file mode 100644 index 0000000..23f6375 --- /dev/null +++ b/third_party/blink/renderer/modules/xr/xr_layer_drawing_context.h
@@ -0,0 +1,36 @@ +// 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 THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_LAYER_DRAWING_CONTEXT_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_LAYER_DRAWING_CONTEXT_H_ + +#include "third_party/blink/renderer/modules/xr/xr_graphics_binding.h" +#include "third_party/blink/renderer/platform/heap/garbage_collected.h" +#include "third_party/blink/renderer/platform/heap/member.h" + +namespace blink { + +class XRCompositionLayer; + +class XRLayerDrawingContext : public GarbageCollected<XRLayerDrawingContext> { + public: + virtual enum XRGraphicsBinding::Api GraphicsApi() const = 0; + + virtual void OnFrameStart() = 0; + virtual void OnFrameEnd() = 0; + + virtual void SetCompositionLayer(XRCompositionLayer* layer) = 0; + + virtual uint16_t TextureWidth() const = 0; + virtual uint16_t TextureHeight() const = 0; + virtual uint16_t TextureArrayLength() const = 0; + + virtual bool TextureWasQueried() const = 0; + + virtual void Trace(Visitor* visitor) const {} +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_LAYER_DRAWING_CONTEXT_H_
diff --git a/third_party/blink/renderer/modules/xr/xr_projection_layer.cc b/third_party/blink/renderer/modules/xr/xr_projection_layer.cc index 3a6429d2..e65a0c3 100644 --- a/third_party/blink/renderer/modules/xr/xr_projection_layer.cc +++ b/third_party/blink/renderer/modules/xr/xr_projection_layer.cc
@@ -9,8 +9,13 @@ namespace blink { -XRProjectionLayer::XRProjectionLayer(XRGraphicsBinding* binding) - : XRCompositionLayer(binding) {} +XRProjectionLayer::XRProjectionLayer(XRGraphicsBinding* binding, + XRLayerDrawingContext* drawing_context) + : XRCompositionLayer(binding, drawing_context) {} + +XRLayerType XRProjectionLayer::LayerType() const { + return XRLayerType::kProjectionLayer; +} bool XRProjectionLayer::ignoreDepthValues() const { return ignore_depth_values_;
diff --git a/third_party/blink/renderer/modules/xr/xr_projection_layer.h b/third_party/blink/renderer/modules/xr/xr_projection_layer.h index 49fe986..dd2cb97 100644 --- a/third_party/blink/renderer/modules/xr/xr_projection_layer.h +++ b/third_party/blink/renderer/modules/xr/xr_projection_layer.h
@@ -8,6 +8,7 @@ #include <optional> #include "third_party/blink/renderer/modules/xr/xr_composition_layer.h" +#include "third_party/blink/renderer/platform/wtf/casting.h" namespace blink { @@ -17,9 +18,12 @@ DEFINE_WRAPPERTYPEINFO(); public: - explicit XRProjectionLayer(XRGraphicsBinding* binding); + XRProjectionLayer(XRGraphicsBinding* binding, + XRLayerDrawingContext* drawing_context); ~XRProjectionLayer() override = default; + XRLayerType LayerType() const override; + bool ignoreDepthValues() const; std::optional<float> fixedFoveation() const; void setFixedFoveation(std::optional<float> value); @@ -34,6 +38,13 @@ Member<XRRigidTransform> delta_pose_{nullptr}; }; +template <> +struct DowncastTraits<XRProjectionLayer> { + static bool AllowFrom(const XRCompositionLayer& layer) { + return layer.LayerType() == XRLayerType::kProjectionLayer; + } +}; + } // namespace blink #endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_PROJECTION_LAYER_H_
diff --git a/third_party/blink/renderer/modules/xr/xr_quad_layer.cc b/third_party/blink/renderer/modules/xr/xr_quad_layer.cc index 950504d..90f2baf 100644 --- a/third_party/blink/renderer/modules/xr/xr_quad_layer.cc +++ b/third_party/blink/renderer/modules/xr/xr_quad_layer.cc
@@ -14,8 +14,9 @@ namespace blink { XRQuadLayer::XRQuadLayer(const XRQuadLayerInit* init, - XRGraphicsBinding* binding) - : XRShapedLayer(init, binding), + XRGraphicsBinding* binding, + XRLayerDrawingContext* drawing_context) + : XRShapedLayer(init, binding, drawing_context), width_(init->width()), height_(init->height()) { if (init->hasTransform()) { @@ -26,20 +27,24 @@ } } +XRLayerType XRQuadLayer::LayerType() const { + return XRLayerType::kQuadLayer; +} + void XRQuadLayer::setWidth(float width) { width_ = width; - OnUpdateLayerData(); + SetModified(true); } void XRQuadLayer::setHeight(float height) { height_ = height; - OnUpdateLayerData(); + SetModified(true); } void XRQuadLayer::setTransform(XRRigidTransform* value) { if (transform_ != value) { transform_ = value; - OnUpdateLayerData(); + SetModified(true); } }
diff --git a/third_party/blink/renderer/modules/xr/xr_quad_layer.h b/third_party/blink/renderer/modules/xr/xr_quad_layer.h index e174093..4de73d9b6 100644 --- a/third_party/blink/renderer/modules/xr/xr_quad_layer.h +++ b/third_party/blink/renderer/modules/xr/xr_quad_layer.h
@@ -18,9 +18,13 @@ DEFINE_WRAPPERTYPEINFO(); public: - explicit XRQuadLayer(const XRQuadLayerInit* init, XRGraphicsBinding* binding); + XRQuadLayer(const XRQuadLayerInit* init, + XRGraphicsBinding* binding, + XRLayerDrawingContext* drawing_context); ~XRQuadLayer() override = default; + XRLayerType LayerType() const override; + XRRigidTransform* transform() const { return transform_.Get(); } void setTransform(XRRigidTransform* value);
diff --git a/third_party/blink/renderer/modules/xr/xr_session.cc b/third_party/blink/renderer/modules/xr/xr_session.cc index 3db417b..f13efd86 100644 --- a/third_party/blink/renderer/modules/xr/xr_session.cc +++ b/third_party/blink/renderer/modules/xr/xr_session.cc
@@ -78,7 +78,7 @@ "This device does not support the requested reference space type."; const char kIncompatibleLayer[] = - "XRWebGLLayer was created with a different session."; + "XRLayer was created with a different session."; const char kBaseLayerAndLayers[] = "Both baseLayer and layers should not be set at the same time when "
diff --git a/third_party/blink/renderer/modules/xr/xr_shaped_layer.cc b/third_party/blink/renderer/modules/xr/xr_shaped_layer.cc index c5d6397..570c159 100644 --- a/third_party/blink/renderer/modules/xr/xr_shaped_layer.cc +++ b/third_party/blink/renderer/modules/xr/xr_shaped_layer.cc
@@ -11,8 +11,9 @@ namespace blink { XRShapedLayer::XRShapedLayer(const XRLayerInit* init, - XRGraphicsBinding* binding) - : XRCompositionLayer(binding), + XRGraphicsBinding* binding, + XRLayerDrawingContext* drawing_context) + : XRCompositionLayer(binding, drawing_context), xr_space_(init->space()), texture_width_(init->viewPixelWidth()), texture_height_(init->viewPixelHeight()), @@ -28,15 +29,7 @@ void XRShapedLayer::setSpace(XRSpace* space) { xr_space_ = space; - OnUpdateLayerData(); -} - -uint16_t XRShapedLayer::textureWidth() const { - return texture_width_; -} - -uint16_t XRShapedLayer::textureHeight() const { - return texture_height_; + SetModified(true); } void XRShapedLayer::Trace(Visitor* visitor) const {
diff --git a/third_party/blink/renderer/modules/xr/xr_shaped_layer.h b/third_party/blink/renderer/modules/xr/xr_shaped_layer.h index bcd1cb6..a3c956d 100644 --- a/third_party/blink/renderer/modules/xr/xr_shaped_layer.h +++ b/third_party/blink/renderer/modules/xr/xr_shaped_layer.h
@@ -15,7 +15,9 @@ class XRShapedLayer : public XRCompositionLayer { public: - explicit XRShapedLayer(const XRLayerInit* init, XRGraphicsBinding* binding); + XRShapedLayer(const XRLayerInit* init, + XRGraphicsBinding* binding, + XRLayerDrawingContext* drawing_context); ~XRShapedLayer() override = default; // onredraw event handler @@ -29,10 +31,6 @@ bool isStatic() const { return is_static_; } bool clearOnAccess() const { return clear_on_access_; } - uint16_t textureWidth() const override; - uint16_t textureHeight() const override; - uint16_t textureArrayLength() const override { return 1; } - // TODO(crbug.com/443963000): Initialize mojom backend. bool InitializeLayer() const; // TODO(crbug.com/443963000): Send data the mojom backend.
diff --git a/third_party/blink/renderer/modules/xr/xr_webgl_binding.cc b/third_party/blink/renderer/modules/xr/xr_webgl_binding.cc index df36026..7347c91 100644 --- a/third_party/blink/renderer/modules/xr/xr_webgl_binding.cc +++ b/third_party/blink/renderer/modules/xr/xr_webgl_binding.cc
@@ -29,8 +29,8 @@ #include "third_party/blink/renderer/modules/xr/xr_utils.h" #include "third_party/blink/renderer/modules/xr/xr_viewer_pose.h" #include "third_party/blink/renderer/modules/xr/xr_webgl_drawing_buffer_swap_chain.h" +#include "third_party/blink/renderer/modules/xr/xr_webgl_drawing_context.h" #include "third_party/blink/renderer/modules/xr/xr_webgl_layer.h" -#include "third_party/blink/renderer/modules/xr/xr_webgl_projection_layer.h" #include "third_party/blink/renderer/modules/xr/xr_webgl_sub_image.h" #include "third_party/blink/renderer/modules/xr/xr_webgl_swap_chain.h" #include "third_party/blink/renderer/modules/xr/xr_webgl_texture_array_swap_chain.h" @@ -105,6 +105,29 @@ return false; } +XRWebGLSwapChain* XRWebGLBinding::CreateColorSwapchain(GLenum layer_format, + gfx::Size texture_size) { + XRWebGLSwapChain::Descriptor color_desc = {}; + color_desc.format = FormatForLayerFormat(layer_format); + color_desc.internal_format = InternalFormatForLayerFormat(layer_format); + color_desc.type = TypeForLayerFormat(layer_format); + color_desc.attachment_target = GL_COLOR_ATTACHMENT0; + color_desc.width = static_cast<uint32_t>(texture_size.width()); + color_desc.height = static_cast<uint32_t>(texture_size.height()); + color_desc.layers = 1; + + XRWebGLSwapChain* color_swap_chain; + if (session()->xr()->frameProvider()->DrawingIntoSharedBuffer()) { + color_swap_chain = MakeGarbageCollected<XRWebGLSharedImageSwapChain>( + webgl_context_, color_desc, webgl2_); + } else { + color_swap_chain = MakeGarbageCollected<XRWebGLDrawingBufferSwapChain>( + webgl_context_, color_desc, webgl2_); + } + + return color_swap_chain; +} + XRProjectionLayer* XRWebGLBinding::createProjectionLayer( const XRProjectionLayerInit* init, ExceptionState& exception_state) { @@ -153,24 +176,8 @@ gfx::Size texture_size = gfx::ToFlooredSize(scaled_size); - XRWebGLSwapChain::Descriptor color_desc = {}; - color_desc.format = FormatForLayerFormat(init->colorFormat()); - color_desc.internal_format = - InternalFormatForLayerFormat(init->colorFormat()); - color_desc.type = TypeForLayerFormat(init->colorFormat()); - color_desc.attachment_target = GL_COLOR_ATTACHMENT0; - color_desc.width = static_cast<uint32_t>(texture_size.width()); - color_desc.height = static_cast<uint32_t>(texture_size.height()); - color_desc.layers = 1; - - XRWebGLSwapChain* color_swap_chain; - if (session()->xr()->frameProvider()->DrawingIntoSharedBuffer()) { - color_swap_chain = MakeGarbageCollected<XRWebGLSharedImageSwapChain>( - webgl_context_, color_desc, webgl2_); - } else { - color_swap_chain = MakeGarbageCollected<XRWebGLDrawingBufferSwapChain>( - webgl_context_, color_desc, webgl2_); - } + XRWebGLSwapChain* color_swap_chain = + CreateColorSwapchain(init->colorFormat(), texture_size); if (is_texture_array) { // If a texture-array was requested, create a texture array wrapper for the @@ -207,8 +214,10 @@ webgl_context_, depth_stencil_desc, webgl2_); } - return MakeGarbageCollected<XRWebGLProjectionLayer>(this, color_swap_chain, - depth_stencil_swap_chain); + auto* drawing_context = MakeGarbageCollected<XRWebGLDrawingContext>( + this, color_swap_chain, depth_stencil_swap_chain); + + return MakeGarbageCollected<XRProjectionLayer>(this, drawing_context); } XRQuadLayer* XRWebGLBinding::createQuadLayer(const XRQuadLayerInit* init, @@ -286,22 +295,21 @@ return nullptr; } - // Because we have validated that this is a layer owned by this binding we - // know that it is a XRWebGLProjectionLayer, because that's the only type of - // projection layer that this class returns. - XRWebGLProjectionLayer* gl_layer = - static_cast<XRWebGLProjectionLayer*>(layer); - XRViewData* viewData = view->ViewData(); if (viewData->ApplyViewportScaleForFrame()) { - gl_layer->MarkViewportUpdated(); + layer->SetModified(true); } gfx::Rect viewport = GetViewportForView(layer, viewData); + // The layer passed the OwnsLayer check, confirming it can only contain + // a WebGL drawing context. This makes the static_cast safe. + auto* drawing_context = + static_cast<XRWebGLDrawingContext*>(layer->drawing_context()); + return MakeGarbageCollected<XRWebGLSubImage>( - viewport, viewData->index(), gl_layer->color_swap_chain(), - gl_layer->depth_stencil_swap_chain(), nullptr); + viewport, viewData->index(), drawing_context->color_swap_chain(), + drawing_context->depth_stencil_swap_chain(), nullptr); } XRWebGLSubImage* XRWebGLBinding::getSubImage(XRCompositionLayer* layer,
diff --git a/third_party/blink/renderer/modules/xr/xr_webgl_binding.h b/third_party/blink/renderer/modules/xr/xr_webgl_binding.h index 58bddd07..330755d 100644 --- a/third_party/blink/renderer/modules/xr/xr_webgl_binding.h +++ b/third_party/blink/renderer/modules/xr/xr_webgl_binding.h
@@ -98,6 +98,8 @@ GLenum InternalFormatForLayerFormat(GLenum format); GLenum TypeForLayerFormat(GLenum format); + XRWebGLSwapChain* CreateColorSwapchain(GLenum layer_format, + gfx::Size layer_size); XRWebGLSwapChain* GetSwapchainForLayer(XRCompositionLayer* layer); Member<WebGLRenderingContextBase> webgl_context_;
diff --git a/third_party/blink/renderer/modules/xr/xr_webgl_projection_layer.cc b/third_party/blink/renderer/modules/xr/xr_webgl_drawing_context.cc similarity index 61% rename from third_party/blink/renderer/modules/xr/xr_webgl_projection_layer.cc rename to third_party/blink/renderer/modules/xr/xr_webgl_drawing_context.cc index 88ac5810..1dffcce 100644 --- a/third_party/blink/renderer/modules/xr/xr_webgl_projection_layer.cc +++ b/third_party/blink/renderer/modules/xr/xr_webgl_drawing_context.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "third_party/blink/renderer/modules/xr/xr_webgl_projection_layer.h" +#include "third_party/blink/renderer/modules/xr/xr_webgl_drawing_context.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_xr_gpu_projection_layer_init.h" #include "third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h" @@ -15,69 +15,71 @@ namespace blink { -XRWebGLProjectionLayer::XRWebGLProjectionLayer( +XRWebGLDrawingContext::XRWebGLDrawingContext( XRWebGLBinding* binding, XRWebGLSwapChain* color_swap_chain, XRWebGLSwapChain* depth_stencil_swap_chain) - : XRProjectionLayer(binding), - webgl_context_(binding->context()), + : webgl_context_(binding->context()), color_swap_chain_(color_swap_chain), depth_stencil_swap_chain_(depth_stencil_swap_chain) { CHECK(color_swap_chain_); - color_swap_chain_->SetLayer(this); +} + +enum XRGraphicsBinding::Api XRWebGLDrawingContext::GraphicsApi() const { + return XRGraphicsBinding::Api::kWebGL; +} + +void XRWebGLDrawingContext::SetCompositionLayer(XRCompositionLayer* layer) { + color_swap_chain_->SetLayer(layer); if (depth_stencil_swap_chain_) { - depth_stencil_swap_chain_->SetLayer(this); + depth_stencil_swap_chain_->SetLayer(layer); } } -uint16_t XRWebGLProjectionLayer::textureWidth() const { +uint16_t XRWebGLDrawingContext::TextureWidth() const { return color_swap_chain_->descriptor().width; } -uint16_t XRWebGLProjectionLayer::textureHeight() const { +uint16_t XRWebGLDrawingContext::TextureHeight() const { return color_swap_chain_->descriptor().height; } -uint16_t XRWebGLProjectionLayer::textureArrayLength() const { +uint16_t XRWebGLDrawingContext::TextureArrayLength() const { return color_swap_chain_->descriptor().layers; } -void XRWebGLProjectionLayer::OnFrameStart() { +bool XRWebGLDrawingContext::TextureWasQueried() const { + return color_swap_chain_->texture_was_queried(); +} + +void XRWebGLDrawingContext::OnFrameStart() { color_swap_chain_->OnFrameStart(); if (depth_stencil_swap_chain_) { depth_stencil_swap_chain_->OnFrameStart(); } } -void XRWebGLProjectionLayer::OnFrameEnd() { +void XRWebGLDrawingContext::OnFrameEnd() { color_swap_chain_->OnFrameEnd(); if (depth_stencil_swap_chain_) { depth_stencil_swap_chain_->OnFrameEnd(); } +} - XRFrameProvider* frame_provider = session()->xr()->frameProvider(); - - if (viewport_updated_) { - frame_provider->UpdateLayerViewports(this); - viewport_updated_ = false; - } - - frame_provider->SubmitWebGLLayer(this, - color_swap_chain_->texture_was_queried()); +const XRLayer* XRWebGLDrawingContext::layer() const { + return color_swap_chain_->layer(); } scoped_refptr<StaticBitmapImage> -XRWebGLProjectionLayer::TransferToStaticBitmapImage() { +XRWebGLDrawingContext::TransferToStaticBitmapImage() { return color_swap_chain_->TransferToStaticBitmapImage(); } -void XRWebGLProjectionLayer::OnResize() {} - -void XRWebGLProjectionLayer::Trace(Visitor* visitor) const { +void XRWebGLDrawingContext::Trace(Visitor* visitor) const { visitor->Trace(webgl_context_); visitor->Trace(color_swap_chain_); visitor->Trace(depth_stencil_swap_chain_); - XRProjectionLayer::Trace(visitor); + XRLayerDrawingContext::Trace(visitor); } } // namespace blink
diff --git a/third_party/blink/renderer/modules/xr/xr_webgl_drawing_context.h b/third_party/blink/renderer/modules/xr/xr_webgl_drawing_context.h new file mode 100644 index 0000000..9bcfe43 --- /dev/null +++ b/third_party/blink/renderer/modules/xr/xr_webgl_drawing_context.h
@@ -0,0 +1,61 @@ +// 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 THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_WEBGL_DRAWING_CONTEXT_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_WEBGL_DRAWING_CONTEXT_H_ + +#include "third_party/blink/renderer/modules/xr/xr_layer_drawing_context.h" +#include "third_party/blink/renderer/modules/xr/xr_webgl_layer_client.h" + +namespace blink { + +class WebGLRenderingContextBase; +class XRWebGLBinding; +class XRWebGLSwapChain; +class XRCompositionLayer; + +class XRWebGLDrawingContext final : public XRLayerDrawingContext, + public XRWebGLLayerClient { + public: + XRWebGLDrawingContext(XRWebGLBinding*, + XRWebGLSwapChain* color_swap_chain, + XRWebGLSwapChain* depth_stencil_swap_chain); + ~XRWebGLDrawingContext() = default; + + enum XRGraphicsBinding::Api GraphicsApi() const override; + + // XRWebGLLayerClient implementation. + const XRLayer* layer() const override; + WebGLRenderingContextBase* context() const override { + return webgl_context_.Get(); + } + scoped_refptr<StaticBitmapImage> TransferToStaticBitmapImage() override; + + uint16_t TextureWidth() const override; + uint16_t TextureHeight() const override; + uint16_t TextureArrayLength() const override; + + bool TextureWasQueried() const override; + + void SetCompositionLayer(XRCompositionLayer* layer) override; + + void OnFrameStart() override; + void OnFrameEnd() override; + + XRWebGLSwapChain* color_swap_chain() const { return color_swap_chain_.Get(); } + XRWebGLSwapChain* depth_stencil_swap_chain() const { + return depth_stencil_swap_chain_.Get(); + } + + void Trace(Visitor*) const override; + + private: + Member<WebGLRenderingContextBase> webgl_context_; + Member<XRWebGLSwapChain> color_swap_chain_; + Member<XRWebGLSwapChain> depth_stencil_swap_chain_; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_WEBGL_DRAWING_CONTEXT_H_
diff --git a/third_party/blink/renderer/modules/xr/xr_webgl_layer.cc b/third_party/blink/renderer/modules/xr/xr_webgl_layer.cc index 826f173a0..55aba0a 100644 --- a/third_party/blink/renderer/modules/xr/xr_webgl_layer.cc +++ b/third_party/blink/renderer/modules/xr/xr_webgl_layer.cc
@@ -182,6 +182,10 @@ } } +XRLayerType XRWebGLLayer::LayerType() const { + return XRLayerType::kWebGLLayer; +} + uint32_t XRWebGLLayer::framebufferWidth() const { if (drawing_buffer_) { return drawing_buffer_->size().width();
diff --git a/third_party/blink/renderer/modules/xr/xr_webgl_layer.h b/third_party/blink/renderer/modules/xr/xr_webgl_layer.h index c6aac3b..bb952bd 100644 --- a/third_party/blink/renderer/modules/xr/xr_webgl_layer.h +++ b/third_party/blink/renderer/modules/xr/xr_webgl_layer.h
@@ -82,6 +82,8 @@ void OnFrameEnd() override; void OnResize() override; + XRLayerType LayerType() const override; + void Trace(Visitor*) const override; private:
diff --git a/third_party/blink/renderer/modules/xr/xr_webgl_projection_layer.h b/third_party/blink/renderer/modules/xr/xr_webgl_projection_layer.h deleted file mode 100644 index 3106b6e..0000000 --- a/third_party/blink/renderer/modules/xr/xr_webgl_projection_layer.h +++ /dev/null
@@ -1,58 +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. - -#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_WEBGL_PROJECTION_LAYER_H_ -#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_WEBGL_PROJECTION_LAYER_H_ - -#include "third_party/blink/renderer/modules/xr/xr_projection_layer.h" -#include "third_party/blink/renderer/modules/xr/xr_webgl_layer_client.h" - -namespace blink { - -class WebGLRenderingContextBase; -class XRWebGLBinding; -class XRWebGLSwapChain; - -class XRWebGLProjectionLayer final : public XRProjectionLayer, - public XRWebGLLayerClient { - public: - XRWebGLProjectionLayer(XRWebGLBinding*, - XRWebGLSwapChain* color_swap_chain, - XRWebGLSwapChain* depth_stencil_swap_chain); - ~XRWebGLProjectionLayer() override = default; - - // XRWebGLLayerClient implementation - const XRLayer* layer() const override { return this; } - WebGLRenderingContextBase* context() const override { - return webgl_context_.Get(); - } - scoped_refptr<StaticBitmapImage> TransferToStaticBitmapImage() override; - - uint16_t textureWidth() const override; - uint16_t textureHeight() const override; - uint16_t textureArrayLength() const override; - - void OnFrameStart() override; - void OnFrameEnd() override; - void OnResize() override; - - XRWebGLSwapChain* color_swap_chain() const { return color_swap_chain_.Get(); } - XRWebGLSwapChain* depth_stencil_swap_chain() const { - return depth_stencil_swap_chain_.Get(); - } - - void MarkViewportUpdated() { viewport_updated_ = true; } - - void Trace(Visitor*) const override; - - private: - Member<WebGLRenderingContextBase> webgl_context_; - Member<XRWebGLSwapChain> color_swap_chain_; - Member<XRWebGLSwapChain> depth_stencil_swap_chain_; - bool viewport_updated_ = true; -}; - -} // namespace blink - -#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_WEBGL_PROJECTION_LAYER_H_
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_result_bloberizer.cc b/third_party/blink/renderer/platform/fonts/shaping/shape_result_bloberizer.cc index da7448d..59869a8 100644 --- a/third_party/blink/renderer/platform/fonts/shaping/shape_result_bloberizer.cc +++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result_bloberizer.cc
@@ -118,7 +118,7 @@ unsigned size = to - from; Vector<uint32_t, 256> pending_utf8_character_index_from_character_index(size); if (current_text_.Is8Bit()) { - const LChar* latin1 = UNSAFE_TODO(current_text_.Characters8()); + const LChar* latin1 = current_text_.Span8().data(); wtf_size_t utf8_size = pending_utf8_.size(); for (unsigned i = from; i < to;) { pending_utf8_character_index_from_character_index[i - from] = utf8_size; @@ -128,7 +128,7 @@ UNSAFE_TODO(U8_APPEND_UNSAFE(pending_utf8_.begin(), utf8_size, cp)); } } else { - const UChar* utf16 = UNSAFE_TODO(current_text_.Characters16()); + const UChar* utf16 = current_text_.Span16().data(); wtf_size_t utf8_size = pending_utf8_.size(); for (unsigned i = from; i < to;) { pending_utf8_character_index_from_character_index[i - from] = utf8_size;
diff --git a/third_party/blink/renderer/platform/wtf/pod_arena.h b/third_party/blink/renderer/platform/wtf/pod_arena.h index f00de5e4..abbe23a 100644 --- a/third_party/blink/renderer/platform/wtf/pod_arena.h +++ b/third_party/blink/renderer/platform/wtf/pod_arena.h
@@ -23,18 +23,15 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifdef UNSAFE_BUFFERS_BUILD -// TODO(crbug.com/351564777): Remove this and convert code to safer constructs. -#pragma allow_unsafe_buffers -#endif - #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_POD_ARENA_H_ #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_POD_ARENA_H_ #include <stdint.h> + #include <memory> #include <utility> +#include "base/compiler_specific.h" #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" #include "third_party/blink/renderer/platform/wtf/allocator/partitions.h" #include "third_party/blink/renderer/platform/wtf/ref_counted.h" @@ -149,8 +146,10 @@ // Allocates a block of memory of the given size from the passed // Allocator. Chunk(Allocator* allocator, size_t size) - : allocator_(allocator), size_(size), current_offset_(0) { - base_ = static_cast<uint8_t*>(allocator_->Allocate(size)); + : allocator_(allocator), current_offset_(0) { + uint8_t* allocated = static_cast<uint8_t*>(allocator_->Allocate(size)); + // SAFETY: Allocate() ensures `allocated` has `size` bytes. + base_ = UNSAFE_BUFFERS(base::span<uint8_t>(allocated, allocated + size)); } Chunk(const Chunk&) = delete; @@ -158,7 +157,7 @@ // Frees the memory allocated from the Allocator in the // constructor. - ~Chunk() { allocator_->Free(base_); } + ~Chunk() { allocator_->Free(base_.data()); } // Returns a pointer to "size" bytes of storage, or 0 if this // Chunk could not satisfy the allocation. @@ -167,18 +166,18 @@ if (current_offset_ + size < current_offset_) return nullptr; - if (current_offset_ + size > size_) + if (current_offset_ + size > base_.size()) { return nullptr; + } - void* result = base_ + current_offset_; + void* result = base_.subspan(current_offset_, size).data(); current_offset_ += size; return result; } protected: Allocator* allocator_; - uint8_t* base_; - size_t size_; + base::span<uint8_t> base_; size_t current_offset_; };
diff --git a/third_party/blink/renderer/platform/wtf/text/string_view.h b/third_party/blink/renderer/platform/wtf/text/string_view.h index b44b310f..302da50 100644 --- a/third_party/blink/renderer/platform/wtf/text/string_view.h +++ b/third_party/blink/renderer/platform/wtf/text/string_view.h
@@ -199,12 +199,6 @@ } // Use Span16() instead. - UNSAFE_BUFFER_USAGE const LChar* Characters8() const { - DCHECK(Is8Bit()); - return static_cast<const LChar*>(bytes_); - } - - // Use Span16() instead. UNSAFE_BUFFER_USAGE const UChar* Characters16() const { DCHECK(!Is8Bit()); return static_cast<const UChar*>(bytes_); @@ -328,9 +322,9 @@ // SAFETY: Invariants are checked last two line. UNSAFE_BUFFERS({ if (Is8Bit()) { - bytes_ = view.Characters8() + offset; + bytes_ = view.Span8().data() + offset; } else { - bytes_ = view.Characters16() + offset; + bytes_ = view.Span16().data() + offset; } }); }
diff --git a/third_party/blink/renderer/platform/wtf/text/string_view_test.cc b/third_party/blink/renderer/platform/wtf/text/string_view_test.cc index 9a10a38a..4f7f44c 100644 --- a/third_party/blink/renderer/platform/wtf/text/string_view_test.cc +++ b/third_party/blink/renderer/platform/wtf/text/string_view_test.cc
@@ -12,6 +12,18 @@ namespace blink { +const LChar* Address8(const StringImpl& impl, size_t offset = 0) { + return offset ? impl.Span8().subspan(offset).data() : impl.Span8().data(); +} + +const LChar* Address8(const String& str, size_t offset = 0) { + return offset ? str.Span8().subspan(offset).data() : str.Span8().data(); +} + +const LChar* Address8(StringView view, size_t offset = 0) { + return offset ? view.Span8().subspan(offset).data() : view.Span8().data(); +} + const char kChars[] = "12345"; const char16_t kCharsU[] = u"12345"; const LChar* const kChars8 = reinterpret_cast<const LChar*>(kChars); @@ -24,16 +36,14 @@ // StringView(StringImpl*); ASSERT_TRUE(StringView(impl8_bit.get()).Is8Bit()); EXPECT_FALSE(StringView(impl8_bit.get()).IsNull()); - UNSAFE_TODO(EXPECT_EQ(impl8_bit->Characters8(), - StringView(impl8_bit.get()).Characters8())); + EXPECT_EQ(Address8(*impl8_bit), Address8(StringView(impl8_bit.get()))); EXPECT_EQ(impl8_bit->length(), StringView(impl8_bit.get()).length()); EXPECT_EQ(kChars, StringView(impl8_bit.get())); // StringView(StringImpl*, unsigned offset); ASSERT_TRUE(StringView(impl8_bit.get(), 2).Is8Bit()); EXPECT_FALSE(StringView(impl8_bit.get(), 2).IsNull()); - UNSAFE_TODO(EXPECT_EQ(impl8_bit->Characters8() + 2, - StringView(impl8_bit.get(), 2).Characters8())); + EXPECT_EQ(Address8(*impl8_bit, 2u), Address8(StringView(impl8_bit.get(), 2))); EXPECT_EQ(3u, StringView(impl8_bit.get(), 2).length()); EXPECT_EQ(StringView("345"), StringView(impl8_bit.get(), 2)); EXPECT_EQ("345", StringView(impl8_bit.get(), 2)); @@ -41,8 +51,8 @@ // StringView(StringImpl*, unsigned offset, unsigned length); ASSERT_TRUE(StringView(impl8_bit.get(), 2, 1).Is8Bit()); EXPECT_FALSE(StringView(impl8_bit.get(), 2, 1).IsNull()); - UNSAFE_TODO(EXPECT_EQ(impl8_bit->Characters8() + 2, - StringView(impl8_bit.get(), 2, 1).Characters8())); + EXPECT_EQ(Address8(*impl8_bit, 2u), + Address8(StringView(impl8_bit.get(), 2, 1))); EXPECT_EQ(1u, StringView(impl8_bit.get(), 2, 1).length()); EXPECT_EQ(StringView("3"), StringView(impl8_bit.get(), 2, 1)); EXPECT_EQ("3", StringView(impl8_bit.get(), 2, 1)); @@ -86,16 +96,14 @@ // StringView(StringImpl&); ASSERT_TRUE(StringView(*impl8_bit).Is8Bit()); EXPECT_FALSE(StringView(*impl8_bit).IsNull()); - UNSAFE_TODO(EXPECT_EQ(impl8_bit->Characters8(), - StringView(*impl8_bit).Characters8())); + EXPECT_EQ(Address8(*impl8_bit), Address8(StringView(*impl8_bit))); EXPECT_EQ(impl8_bit->length(), StringView(*impl8_bit).length()); EXPECT_EQ(kChars, StringView(*impl8_bit)); // StringView(StringImpl&, unsigned offset); ASSERT_TRUE(StringView(*impl8_bit, 2).Is8Bit()); EXPECT_FALSE(StringView(*impl8_bit, 2).IsNull()); - UNSAFE_TODO(EXPECT_EQ(impl8_bit->Characters8() + 2, - StringView(*impl8_bit, 2).Characters8())); + EXPECT_EQ(Address8(*impl8_bit, 2u), Address8(StringView(*impl8_bit, 2))); EXPECT_EQ(3u, StringView(*impl8_bit, 2).length()); EXPECT_EQ(StringView("345"), StringView(*impl8_bit, 2)); EXPECT_EQ("345", StringView(*impl8_bit, 2)); @@ -103,8 +111,7 @@ // StringView(StringImpl&, unsigned offset, unsigned length); ASSERT_TRUE(StringView(*impl8_bit, 2, 1).Is8Bit()); EXPECT_FALSE(StringView(*impl8_bit, 2, 1).IsNull()); - UNSAFE_TODO(EXPECT_EQ(impl8_bit->Characters8() + 2, - StringView(*impl8_bit, 2, 1).Characters8())); + EXPECT_EQ(Address8(*impl8_bit, 2u), Address8(StringView(*impl8_bit, 2, 1))); EXPECT_EQ(1u, StringView(*impl8_bit, 2, 1).length()); EXPECT_EQ(StringView("3"), StringView(*impl8_bit, 2, 1)); EXPECT_EQ("3", StringView(*impl8_bit, 2, 1)); @@ -147,16 +154,14 @@ // StringView(const String&); ASSERT_TRUE(StringView(string8_bit).Is8Bit()); EXPECT_FALSE(StringView(string8_bit).IsNull()); - UNSAFE_TODO(EXPECT_EQ(string8_bit.Characters8(), - StringView(string8_bit).Characters8())); + EXPECT_EQ(Address8(string8_bit), Address8(StringView(string8_bit))); EXPECT_EQ(string8_bit.length(), StringView(string8_bit).length()); EXPECT_EQ(kChars, StringView(string8_bit)); // StringView(const String&, unsigned offset); ASSERT_TRUE(StringView(string8_bit, 2).Is8Bit()); EXPECT_FALSE(StringView(string8_bit, 2).IsNull()); - UNSAFE_TODO(EXPECT_EQ(string8_bit.Characters8() + 2, - StringView(string8_bit, 2).Characters8())); + EXPECT_EQ(Address8(string8_bit, 2u), Address8(StringView(string8_bit, 2))); EXPECT_EQ(3u, StringView(string8_bit, 2).length()); EXPECT_EQ(StringView("345"), StringView(string8_bit, 2)); EXPECT_EQ("345", StringView(string8_bit, 2)); @@ -164,8 +169,7 @@ // StringView(const String&, unsigned offset, unsigned length); ASSERT_TRUE(StringView(string8_bit, 2, 1).Is8Bit()); EXPECT_FALSE(StringView(string8_bit, 2, 1).IsNull()); - UNSAFE_TODO(EXPECT_EQ(string8_bit.Characters8() + 2, - StringView(string8_bit, 2, 1).Characters8())); + EXPECT_EQ(Address8(string8_bit, 2u), Address8(StringView(string8_bit, 2, 1))); EXPECT_EQ(1u, StringView(string8_bit, 2, 1).length()); EXPECT_EQ(StringView("3"), StringView(string8_bit, 2, 1)); EXPECT_EQ("3", StringView(string8_bit, 2, 1)); @@ -268,16 +272,14 @@ // StringView(StringView&); ASSERT_TRUE(StringView(view8_bit).Is8Bit()); EXPECT_FALSE(StringView(view8_bit).IsNull()); - UNSAFE_TODO( - EXPECT_EQ(view8_bit.Characters8(), StringView(view8_bit).Characters8())); + EXPECT_EQ(Address8(view8_bit), Address8(StringView(view8_bit))); EXPECT_EQ(view8_bit.length(), StringView(view8_bit).length()); EXPECT_EQ(kChars, StringView(view8_bit)); // StringView(const StringView&, unsigned offset); ASSERT_TRUE(StringView(view8_bit, 2).Is8Bit()); EXPECT_FALSE(StringView(view8_bit, 2).IsNull()); - UNSAFE_TODO(EXPECT_EQ(view8_bit.Characters8() + 2, - StringView(view8_bit, 2).Characters8())); + EXPECT_EQ(Address8(view8_bit, 2u), Address8(StringView(view8_bit, 2))); EXPECT_EQ(3u, StringView(view8_bit, 2).length()); EXPECT_EQ(StringView("345"), StringView(view8_bit, 2)); EXPECT_EQ("345", StringView(view8_bit, 2)); @@ -285,8 +287,7 @@ // StringView(const StringView&, unsigned offset, unsigned length); ASSERT_TRUE(StringView(view8_bit, 2, 1).Is8Bit()); EXPECT_FALSE(StringView(view8_bit, 2, 1).IsNull()); - UNSAFE_TODO(EXPECT_EQ(view8_bit.Characters8() + 2, - StringView(view8_bit, 2, 1).Characters8())); + EXPECT_EQ(Address8(view8_bit, 2u), Address8(StringView(view8_bit, 2, 1))); EXPECT_EQ(1u, StringView(view8_bit, 2, 1).length()); EXPECT_EQ(StringView("3"), StringView(view8_bit, 2, 1)); EXPECT_EQ("3", StringView(view8_bit, 2, 1)); @@ -343,7 +344,7 @@ // StringView(const char* chars); ASSERT_TRUE(StringView(kChars).Is8Bit()); EXPECT_FALSE(StringView(kChars).IsNull()); - UNSAFE_TODO(EXPECT_EQ(kChars8, StringView(kChars).Characters8())); + EXPECT_EQ(kChars8, Address8(StringView(kChars))); EXPECT_EQ(5u, StringView(kChars).length()); EXPECT_EQ(kChars, StringView(kChars)); @@ -380,7 +381,7 @@ const auto kCharsSpan8 = base::byte_span_from_cstring(kChars); ASSERT_TRUE(StringView(kCharsSpan8).Is8Bit()); EXPECT_FALSE(StringView(kCharsSpan8).IsNull()); - UNSAFE_TODO(EXPECT_EQ(kChars8, StringView(kCharsSpan8).Characters8())); + EXPECT_EQ(kChars8, Address8(StringView(kCharsSpan8))); EXPECT_EQ(5u, StringView(kCharsSpan8).length()); EXPECT_EQ(kChars, StringView(kCharsSpan8)); }
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index b5ed90d..a168f3c 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -2973,19 +2973,6 @@ external/wpt/css/css-shadow-parts/exportparts-layered.html [ Failure ] external/wpt/css/css-text/text-autospace/text-autospace-elements-007.html [ Failure ] external/wpt/css/css-text/text-autospace/text-autospace-transform-full-width-001.tentative.html [ Failure ] -external/wpt/css/css-overflow/line-clamp/block-ellipsis-007.html [ Failure ] -external/wpt/css/css-overflow/line-clamp/block-ellipsis-008.html [ Failure ] -external/wpt/css/css-overflow/line-clamp/block-ellipsis-009.html [ Failure ] -external/wpt/css/css-overflow/line-clamp/block-ellipsis-012.html [ Failure ] -external/wpt/css/css-overflow/line-clamp/block-ellipsis-015.tentative.html [ Failure ] -external/wpt/css/css-overflow/line-clamp/block-ellipsis-019.html [ Failure ] -external/wpt/css/css-overflow/line-clamp/block-ellipsis-020.html [ Failure ] -external/wpt/css/css-overflow/line-clamp/block-ellipsis-021.html [ Failure ] -external/wpt/css/css-overflow/line-clamp/block-ellipsis-027.html [ Failure ] -external/wpt/css/css-overflow/line-clamp/block-ellipsis-028.html [ Failure ] -external/wpt/css/css-overflow/line-clamp/line-clamp-auto-009.html [ Failure ] -external/wpt/css/css-overflow/line-clamp/line-clamp-auto-040.html [ Failure ] -external/wpt/css/css-overflow/line-clamp/line-clamp-with-abspos-017.html [ Failure ] external/wpt/navigation-api/navigation-methods/return-value/navigate-javascript-url.html [ Timeout ] # Flaky UUID in assertion failure @@ -8709,23 +8696,27 @@ crbug.com/351117372 external/wpt/css/css-writing-modes/vertical-alignment-slr-035.xht [ Crash Pass Timeout ] # line-clamp -crbug.com/40336192 external/wpt/css/css-overflow/line-clamp/line-clamp-auto-009.tentative.html [ Failure ] -crbug.com/40336192 external/wpt/css/css-overflow/line-clamp/line-clamp-with-abspos-017.tentative.html [ Failure ] +crbug.com/40336192 external/wpt/css/css-overflow/line-clamp/line-clamp-auto-009.html [ Failure ] +crbug.com/40336192 external/wpt/css/css-overflow/line-clamp/line-clamp-auto-040.html [ Failure ] +crbug.com/40336192 external/wpt/css/css-overflow/line-clamp/line-clamp-with-abspos-017.html [ Failure ] crbug.com/40336192 external/wpt/css/css-overflow/line-clamp/block-ellipsis-001.html [ Failure ] -crbug.com/40336192 external/wpt/css/css-overflow/line-clamp/block-ellipsis-007.tentative.html [ Failure ] -crbug.com/40336192 external/wpt/css/css-overflow/line-clamp/block-ellipsis-008.tentative.html [ Failure ] -crbug.com/40336192 external/wpt/css/css-overflow/line-clamp/block-ellipsis-009.tentative.html [ Failure ] -crbug.com/40336192 external/wpt/css/css-overflow/line-clamp/block-ellipsis-012.tentative.html [ Failure ] +crbug.com/40336192 external/wpt/css/css-overflow/line-clamp/block-ellipsis-007.html [ Failure ] +crbug.com/40336192 external/wpt/css/css-overflow/line-clamp/block-ellipsis-008.html [ Failure ] +crbug.com/40336192 external/wpt/css/css-overflow/line-clamp/block-ellipsis-009.html [ Failure ] +crbug.com/40336192 external/wpt/css/css-overflow/line-clamp/block-ellipsis-012.html [ Failure ] crbug.com/40336192 external/wpt/css/css-overflow/line-clamp/block-ellipsis-013.html [ Failure ] crbug.com/40336192 external/wpt/css/css-overflow/line-clamp/block-ellipsis-014.html [ Failure ] +crbug.com/40336192 external/wpt/css/css-overflow/line-clamp/block-ellipsis-015.tentative.html [ Failure ] crbug.com/40336192 external/wpt/css/css-overflow/line-clamp/block-ellipsis-016.html [ Failure ] crbug.com/40336192 external/wpt/css/css-overflow/line-clamp/block-ellipsis-017.html [ Failure ] crbug.com/40336192 external/wpt/css/css-overflow/line-clamp/block-ellipsis-018.html [ Failure ] -crbug.com/40336192 external/wpt/css/css-overflow/line-clamp/block-ellipsis-019.tentative.html [ Failure ] -crbug.com/40336192 external/wpt/css/css-overflow/line-clamp/block-ellipsis-020.tentative.html [ Failure ] -crbug.com/40336192 external/wpt/css/css-overflow/line-clamp/block-ellipsis-021.tentative.html [ Failure ] +crbug.com/40336192 external/wpt/css/css-overflow/line-clamp/block-ellipsis-019.html [ Failure ] +crbug.com/40336192 external/wpt/css/css-overflow/line-clamp/block-ellipsis-020.html [ Failure ] +crbug.com/40336192 external/wpt/css/css-overflow/line-clamp/block-ellipsis-021.html [ Failure ] crbug.com/40336192 external/wpt/css/css-overflow/line-clamp/block-ellipsis-024.html [ Failure ] crbug.com/40336192 external/wpt/css/css-overflow/line-clamp/block-ellipsis-025.html [ Failure ] +crbug.com/40336192 external/wpt/css/css-overflow/line-clamp/block-ellipsis-027.html [ Failure ] +crbug.com/40336192 external/wpt/css/css-overflow/line-clamp/block-ellipsis-028.html [ Failure ] crbug.com/40336192 external/wpt/css/css-overflow/line-clamp/block-ellipsis-repaint-003.html [ Failure ] crbug.com/40336192 external/wpt/css/css-overflow/line-clamp/webkit-line-clamp-036.html [ Failure ] crbug.com/40336192 external/wpt/css/css-overflow/line-clamp/webkit-line-clamp-051.html [ Failure ] @@ -8735,21 +8726,18 @@ crbug.com/40336192 external/wpt/css/css-text/white-space/text-wrap-balance-line-clamp-003.html [ Failure ] crbug.com/40336192 external/wpt/css/css-text/white-space/text-wrap-balance-line-clamp-004.html [ Failure ] # css-line-clamp-line-breaking-ellipsis -crbug.com/40336192 virtual/css-line-clamp-line-breaking-ellipsis/external/wpt/css/css-overflow/line-clamp/line-clamp-auto-009.tentative.html [ Pass ] -crbug.com/40336192 virtual/css-line-clamp-line-breaking-ellipsis/external/wpt/css/css-overflow/line-clamp/line-clamp-with-abspos-017.tentative.html [ Pass ] +crbug.com/40336192 virtual/css-line-clamp-line-breaking-ellipsis/external/wpt/css/css-overflow/line-clamp/line-clamp-auto-009.html [ Pass ] +crbug.com/40336192 virtual/css-line-clamp-line-breaking-ellipsis/external/wpt/css/css-overflow/line-clamp/line-clamp-with-abspos-017.html [ Pass ] crbug.com/40336192 virtual/css-line-clamp-line-breaking-ellipsis/external/wpt/css/css-overflow/line-clamp/block-ellipsis-001.html [ Pass ] -crbug.com/40336192 virtual/css-line-clamp-line-breaking-ellipsis/external/wpt/css/css-overflow/line-clamp/block-ellipsis-007.tentative.html [ Pass ] -crbug.com/40336192 virtual/css-line-clamp-line-breaking-ellipsis/external/wpt/css/css-overflow/line-clamp/block-ellipsis-008.tentative.html [ Pass ] -crbug.com/40336192 virtual/css-line-clamp-line-breaking-ellipsis/external/wpt/css/css-overflow/line-clamp/block-ellipsis-009.tentative.html [ Pass ] -crbug.com/40336192 virtual/css-line-clamp-line-breaking-ellipsis/external/wpt/css/css-overflow/line-clamp/block-ellipsis-012.tentative.html [ Pass ] -crbug.com/40336192 virtual/css-line-clamp-line-breaking-ellipsis/external/wpt/css/css-overflow/line-clamp/block-ellipsis-013.html [ Failure ] -crbug.com/40336192 virtual/css-line-clamp-line-breaking-ellipsis/external/wpt/css/css-overflow/line-clamp/block-ellipsis-014.html [ Failure ] +crbug.com/40336192 virtual/css-line-clamp-line-breaking-ellipsis/external/wpt/css/css-overflow/line-clamp/block-ellipsis-007.html [ Pass ] +crbug.com/40336192 virtual/css-line-clamp-line-breaking-ellipsis/external/wpt/css/css-overflow/line-clamp/block-ellipsis-008.html [ Pass ] +crbug.com/40336192 virtual/css-line-clamp-line-breaking-ellipsis/external/wpt/css/css-overflow/line-clamp/block-ellipsis-009.html [ Pass ] +crbug.com/40336192 virtual/css-line-clamp-line-breaking-ellipsis/external/wpt/css/css-overflow/line-clamp/block-ellipsis-012.html [ Pass ] crbug.com/40336192 virtual/css-line-clamp-line-breaking-ellipsis/external/wpt/css/css-overflow/line-clamp/block-ellipsis-016.html [ Pass ] -crbug.com/40336192 virtual/css-line-clamp-line-breaking-ellipsis/external/wpt/css/css-overflow/line-clamp/block-ellipsis-017.html [ Failure ] crbug.com/40336192 virtual/css-line-clamp-line-breaking-ellipsis/external/wpt/css/css-overflow/line-clamp/block-ellipsis-018.html [ Pass ] -crbug.com/40336192 virtual/css-line-clamp-line-breaking-ellipsis/external/wpt/css/css-overflow/line-clamp/block-ellipsis-019.tentative.html [ Pass ] -crbug.com/40336192 virtual/css-line-clamp-line-breaking-ellipsis/external/wpt/css/css-overflow/line-clamp/block-ellipsis-020.tentative.html [ Pass ] -crbug.com/40336192 virtual/css-line-clamp-line-breaking-ellipsis/external/wpt/css/css-overflow/line-clamp/block-ellipsis-021.tentative.html [ Pass ] +crbug.com/40336192 virtual/css-line-clamp-line-breaking-ellipsis/external/wpt/css/css-overflow/line-clamp/block-ellipsis-019.html [ Pass ] +crbug.com/40336192 virtual/css-line-clamp-line-breaking-ellipsis/external/wpt/css/css-overflow/line-clamp/block-ellipsis-020.html [ Pass ] +crbug.com/40336192 virtual/css-line-clamp-line-breaking-ellipsis/external/wpt/css/css-overflow/line-clamp/block-ellipsis-021.html [ Pass ] crbug.com/40336192 virtual/css-line-clamp-line-breaking-ellipsis/external/wpt/css/css-overflow/line-clamp/block-ellipsis-025.html [ Pass ] crbug.com/40336192 virtual/css-line-clamp-line-breaking-ellipsis/external/wpt/css/css-overflow/line-clamp/block-ellipsis-repaint-003.html [ Pass ] crbug.com/40336192 virtual/css-line-clamp-line-breaking-ellipsis/external/wpt/css/css-overflow/line-clamp/webkit-line-clamp-036.html [ Pass ] @@ -8775,9 +8763,6 @@ crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/webkit-line-clamp-040.html [ Failure ] crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/webkit-line-clamp-047.html [ Failure ] crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/webkit-line-clamp-050.html [ Failure ] -crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/webkit-line-clamp-051.html [ Failure ] -crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/webkit-line-clamp-052.html [ Failure ] -crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/webkit-line-clamp-053.html [ Failure ] crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/webkit-line-clamp-with-max-height.html [ Failure ] crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/line-clamp-001.html [ Failure ] crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/line-clamp-004.html [ Failure ] @@ -8813,7 +8798,6 @@ crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/line-clamp-auto-003.tentative.html [ Failure ] crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/line-clamp-auto-004.html [ Failure ] crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/line-clamp-auto-005.html [ Failure ] -crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/line-clamp-auto-009.tentative.html [ Failure ] crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/line-clamp-auto-011.html [ Failure ] crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/line-clamp-auto-013.html [ Failure ] crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/line-clamp-auto-014.html [ Failure ] @@ -8862,7 +8846,6 @@ crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/line-clamp-with-abspos-014.html [ Failure ] crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/line-clamp-with-abspos-015.html [ Failure ] crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/line-clamp-with-abspos-016.html [ Failure ] -crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/line-clamp-with-abspos-017.html [ Failure ] crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/line-clamp-with-abspos-018.html [ Failure ] crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/line-clamp-with-abspos-019.html [ Failure ] crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/line-clamp-with-abspos-020.html [ Failure ] @@ -8896,23 +8879,17 @@ crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-008.html [ Failure ] crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-009.tentative.html [ Failure ] crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-010.tentative.html [ Failure ] -crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/block-ellipsis-001.html [ Failure ] crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/block-ellipsis-002.html [ Failure ] crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/block-ellipsis-003.html [ Failure ] crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/block-ellipsis-004.html [ Failure ] crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/block-ellipsis-005.html [ Failure ] crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/block-ellipsis-006.html [ Failure ] -crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/block-ellipsis-007.tentative.html [ Failure ] -crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/block-ellipsis-008.tentative.html [ Failure ] -crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/block-ellipsis-009.tentative.html [ Failure ] crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/block-ellipsis-010.html [ Failure ] -crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/block-ellipsis-015.html [ Failure ] crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/block-ellipsis-022.html [ Failure ] crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/block-ellipsis-023.html [ Failure ] crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/block-ellipsis-026.html [ Failure ] crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/block-ellipsis-repaint-001.html [ Failure ] crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/block-ellipsis-repaint-002.html [ Failure ] -crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/block-ellipsis-repaint-003.html [ Failure ] crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/block-ellipsis-repaint-004.html [ Failure ] # backdrop-filter-mirror-edge
diff --git a/third_party/blink/web_tests/editing/caret/caret-shape-block-text-svg-circle.html b/third_party/blink/web_tests/editing/caret/caret-shape-block-text-svg-circle.html new file mode 100644 index 0000000..567e76d --- /dev/null +++ b/third_party/blink/web_tests/editing/caret/caret-shape-block-text-svg-circle.html
@@ -0,0 +1,34 @@ +<!DOCTYPE html> +<html> +<head> + <meta charset="utf-8"> + <title>caret-shape block width falls back to 1ch when impractical to determine</title> + <link rel="help" href="https://drafts.csswg.org/css-ui/#caret-shape"> + <meta name="assert" content="Test checks that caret width for block shape should fall back to 1ch when it's impractical to determine."> + <script src="../../resources/testharness.js"></script> + <script src="../../resources/testharnessreport.js"></script> + <script src="../../resources/ahem.js"></script> +<style> + div { + font-family: Ahem; + font-size: 10px; + caret-shape: block; + } + </style> +</head> + +<body> +<div id="test" contenteditable >XX<svg height="50" width="50"> +<circle r="25" cx="25" cy="25" fill="green" /></svg></div> +</body> +<script> + test(function () { + const test = document.getElementById("test").firstChild; + if (window.internals) { + getSelection().collapse(test, 2); + const caret_width = internals.absoluteCaretBounds().width; + assert_approx_equals(10, caret_width, 1); + } + }, "The width of the block caret should be 1ch if this information is impractical to determine."); +</script> +
diff --git a/third_party/blink/web_tests/editing/caret/caret-shape-block-width-for-space-style.html b/third_party/blink/web_tests/editing/caret/caret-shape-block-width-for-space-style.html index 7a07f223..a9751c0 100644 --- a/third_party/blink/web_tests/editing/caret/caret-shape-block-width-for-space-style.html +++ b/third_party/blink/web_tests/editing/caret/caret-shape-block-width-for-space-style.html
@@ -37,6 +37,8 @@ <div id="hair" contenteditable>X X</div> <!-- zero width space --> <div id="zero" contenteditable>X​X</div> + <!-- zero width space in the following segment--> + <div id="zeroNext" contenteditable>X<span>​X></span></div> </div> </body> <script> @@ -82,10 +84,15 @@ const hairWidth = getCaretRectWidth(hair); assert_approx_equals(emWidth / 6, hairWidth, 1); - // zero - fall back to bar width. + // zero - fall back to 1ch width. const zero = document.getElementById("zero").firstChild; const zeroWidth = getCaretRectWidth(zero); - assert_equals(1, zeroWidth); + assert_equals(10, zeroWidth); + + // The following segment starts with a zero space character. + const zeroNext = document.getElementById("zeroNext").firstChild; + const nextWidth = getCaretRectWidth(zeroNext); + assert_equals(10, zeroWidth); }, "caret-shape block width respects the space stylings"); </script> </body>
diff --git a/third_party/blink/web_tests/editing/caret/caret-shape-underscore-text-svg-circle.html b/third_party/blink/web_tests/editing/caret/caret-shape-underscore-text-svg-circle.html new file mode 100644 index 0000000..55290b9 --- /dev/null +++ b/third_party/blink/web_tests/editing/caret/caret-shape-underscore-text-svg-circle.html
@@ -0,0 +1,34 @@ +<!DOCTYPE html> +<html> +<head> + <meta charset="utf-8"> + <title>caret-shape underscore width falls back to 1ch when impractical to determine</title> + <link rel="help" href="https://drafts.csswg.org/css-ui/#caret-shape"> + <meta name="assert" content="Test checks that caret width for underscore shape should fall back to 1ch when it's impractical to determine."> + <script src="../../resources/testharness.js"></script> + <script src="../../resources/testharnessreport.js"></script> + <script src="../../resources/ahem.js"></script> +<style> + div { + font-family: Ahem; + font-size: 10px; + caret-shape: underscore; + } + </style> +</head> + +<body> +<div id="test" contenteditable >XX<svg height="50" width="50"> +<circle r="25" cx="25" cy="25" fill="green" /></svg></div> +</body> +<script> + test(function () { + const test = document.getElementById("test").firstChild; + if (window.internals) { + getSelection().collapse(test, 2); + const caret_width = internals.absoluteCaretBounds().width; + assert_approx_equals(10, caret_width, 1); + } + }, "The width of the underscore caret should be 1ch if this information is impractical to determine."); +</script> +
diff --git a/third_party/blink/web_tests/editing/caret/caret-shape-underscore-width-for-space-style.html b/third_party/blink/web_tests/editing/caret/caret-shape-underscore-width-for-space-style.html index d400da5f..b8d8bb6 100644 --- a/third_party/blink/web_tests/editing/caret/caret-shape-underscore-width-for-space-style.html +++ b/third_party/blink/web_tests/editing/caret/caret-shape-underscore-width-for-space-style.html
@@ -37,6 +37,9 @@ <div id="hair" contenteditable>X X</div> <!-- zero width space --> <div id="zero" contenteditable>X​X</div> + <!-- zero width space in the following segment--> + <div id="zeroNext" contenteditable>X<span>​X></span></div> + </div> </div> </body> <script> @@ -85,7 +88,12 @@ // zero - fall back to bar width. const zero = document.getElementById("zero").firstChild; var zeroWidth = getCaretRectWidth(zero); - assert_equals(1, zeroWidth); + assert_equals(10, zeroWidth); + + // The following segment starts with a zero space character. + const zeroNext = document.getElementById("zeroNext").firstChild; + const nextWidth = getCaretRectWidth(zeroNext); + assert_equals(10, zeroWidth); }, "caret-shape underscore width respects the space stylings"); </script> </body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/container-queries/anchored-fallback-implicit-any.html b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/container-queries/anchored-fallback-implicit-any.html new file mode 100644 index 0000000..e92e7ed --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/container-queries/anchored-fallback-implicit-any.html
@@ -0,0 +1,40 @@ +<!DOCTYPE html> +<title>CSS Conditional Test: @container anchored(fallback) matching implicit 'any' <position-area></title> +<link rel="help" href="https://drafts.csswg.org/css-anchor-position-2/#anchored-container-queries"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/css-conditional/container-queries/support/cq-testcommon.js"></script> +<style> + #anchor { + anchor-name: --a; + width: 100px; + height: 100px; + } + #anchored { + position: absolute; + position-anchor: --a; + position-area: top; + position-try-fallbacks: right span-bottom; + width: 100px; + /* Too tall to fit over the anchor to trigger fallback */ + height: 100px; + container-type: anchored; + } + #target { + /* Implicit 'any' for the horizontal part of the query */ + @container anchored(fallback: span-bottom) { --span-bottom: yes; } + /* Implicit 'any' for the vertical part of the query */ + @container anchored(fallback: right) { --right: yes; } + } +</style> +<div id="anchor"></div> +<div id="anchored"> + <div id="target"></div> +</div> +<script> + test(() => { + const style = getComputedStyle(target); + assert_equals(style.getPropertyValue("--span-bottom"), "yes"); + assert_equals(style.getPropertyValue("--right"), "yes"); + }, "@container anchored(fallback: <position-area>) querying single axis with implicit 'any'"); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/container-queries/anchored-fallback-position-area-any.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/container-queries/anchored-fallback-position-area-any.html similarity index 95% rename from third_party/blink/web_tests/external/wpt/css/css-anchor-position/container-queries/anchored-fallback-position-area-any.tentative.html rename to third_party/blink/web_tests/external/wpt/css/css-anchor-position/container-queries/anchored-fallback-position-area-any.html index 51ed84fd3..321d2f1 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/container-queries/anchored-fallback-position-area-any.tentative.html +++ b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/container-queries/anchored-fallback-position-area-any.html
@@ -1,7 +1,6 @@ <!DOCTYPE html> <title>CSS Conditional Test: @container anchored(fallback) matching 'any' <position-area></title> <link rel="help" href="https://drafts.csswg.org/css-anchor-position-2/#anchored-container-queries"> -<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/12610"> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script src="/css/css-conditional/container-queries/support/cq-testcommon.js"></script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/container-queries/at-container-anchored-parsing-any.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/container-queries/at-container-anchored-parsing-any.html similarity index 92% rename from third_party/blink/web_tests/external/wpt/css/css-anchor-position/container-queries/at-container-anchored-parsing-any.tentative.html rename to third_party/blink/web_tests/external/wpt/css/css-anchor-position/container-queries/at-container-anchored-parsing-any.html index b4582e1..ef85057 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/container-queries/at-container-anchored-parsing-any.tentative.html +++ b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/container-queries/at-container-anchored-parsing-any.html
@@ -1,7 +1,6 @@ <!DOCTYPE html> <title>CSS Conditional Test: @container anchored query parsing - 'any' position-area</title> <link rel="help" href="https://drafts.csswg.org/css-anchor-position-2/#anchored-container-queries"> -<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/12610"> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script src="/css/css-conditional/container-queries/support/cq-testcommon.js"></script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-lists/deep-pseudo-element-remove-update-ref.html b/third_party/blink/web_tests/external/wpt/css/css-lists/deep-pseudo-element-remove-update-ref.html new file mode 100644 index 0000000..595b27a6 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-lists/deep-pseudo-element-remove-update-ref.html
@@ -0,0 +1,5 @@ +<!DOCTYPE html> +<div>1A</div> +<div>2B</div> +<div>3C</div> +<div>4E</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-lists/deep-pseudo-element-remove-update.html b/third_party/blink/web_tests/external/wpt/css/css-lists/deep-pseudo-element-remove-update.html new file mode 100644 index 0000000..709dae62 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-lists/deep-pseudo-element-remove-update.html
@@ -0,0 +1,25 @@ +<!DOCTYPE html> +<title>CSS Lists Test: counters updated when parent element of element with counter operation on its pseudo element is removed</title> +<link rel="help" href="https://drafts.csswg.org/css-lists/#inheriting-counters"> +<link rel="match" href="deep-pseudo-element-remove-update-ref.html"> +<style> + .container { + counter-reset: plm-table 0; + } + + .numbered span::after { + content: counter(plm-table); + counter-increment: plm-table; + } +</style> +<div class="container"> + <div class="numbered a"><span></span>A</div> + <div class="numbered b"><span></span>B</div> + <div id="target" class="numbered d"><span></span>D</div> + <div class="numbered c"><span></span>C</div> + <div class="numbered e"><span></span>E</div> +</div> +<script> + document.documentElement.offsetTop; + target.remove(); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/caret-eol-001.html b/third_party/blink/web_tests/external/wpt/css/css-ui/caret-eol-001.html index 3eb1d8c..46c1510 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-ui/caret-eol-001.html +++ b/third_party/blink/web_tests/external/wpt/css/css-ui/caret-eol-001.html
@@ -4,7 +4,7 @@ <title>CSS Basic User Interface Test: end-of-line carets should be visible</title> <link rel="author" title="Florian Rivoal" href="mailto:florian@rivoal.net"> <link rel="help" href="http://www.w3.org/TR/css4-ui/#caret-shape"> -<link rel=match href=reference/caret-eol-001.html> +<link rel="mismatch" href=reference/caret-eol-001.html> <meta name="assert" content="Checks that carets positioned at the end of the line are shown even if they overflow."> <style> div {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/caret-eol-002.html b/third_party/blink/web_tests/external/wpt/css/css-ui/caret-eol-002.html index 2506c6d..e7ba4e9 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-ui/caret-eol-002.html +++ b/third_party/blink/web_tests/external/wpt/css/css-ui/caret-eol-002.html
@@ -4,7 +4,7 @@ <title>CSS Basic User Interface Test: end-of-line carets should be visible</title> <link rel="author" title="Florian Rivoal" href="mailto:florian@rivoal.net"> <link rel="help" href="http://www.w3.org/TR/css4-ui/#caret-shape"> -<link rel=match href=reference/caret-eol-001.html> +<link rel="mismatch" href=reference/caret-eol-001.html> <meta name="assert" content="Checks that carets positioned at the end of the line are shown even if they overflow, even if the box has hidden overflow."> <style> div {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/caret-eol-003.html b/third_party/blink/web_tests/external/wpt/css/css-ui/caret-eol-003.html index 61e9c50..7b562e8 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-ui/caret-eol-003.html +++ b/third_party/blink/web_tests/external/wpt/css/css-ui/caret-eol-003.html
@@ -1,10 +1,10 @@ -<!DOCTYPE html> +<!DOCTYPE html> <html lang=en> <meta charset="utf-8"> <title>CSS Basic User Interface Test: end-of-line carets should be visible</title> <link rel="author" title="Florian Rivoal" href="mailto:florian@rivoal.net"> <link rel="help" href="http://www.w3.org/TR/css4-ui/#caret-shape"> -<link rel=match href=reference/caret-eol-001.html> +<link rel="mismatch" href=reference/caret-eol-001.html> <meta name="assert" content="Checks that carets positioned at the end of the line are shown even if they overflow, even if the box has overflow: clip."> <style> div { @@ -28,4 +28,4 @@ const t = document.querySelector("#test"); window.getSelection().selectAllChildren(t); window.getSelection().collapseToEnd(); -</script> +</script> \ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/reference/caret-eol-001.html b/third_party/blink/web_tests/external/wpt/css/css-ui/reference/caret-eol-001.html index dc8f37f..c3db995 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-ui/reference/caret-eol-001.html +++ b/third_party/blink/web_tests/external/wpt/css/css-ui/reference/caret-eol-001.html
@@ -7,6 +7,7 @@ div { font-size: 40px; font-family: monospace; + width: 5ch; caret-color: orange; caret-shape: block; caret-animation: manual; @@ -17,7 +18,7 @@ <p>Test passes if you see a orange text insertion caret at the end of the line below. -<div id=test contenteditable spellcheck="false">abcde</div> +<div id=test spellcheck="false">abcde</div> <script> const t = document.querySelector("#test");
diff --git a/third_party/blink/web_tests/external/wpt/css/css-values/typed-arithmetic-different-categories-crash.html b/third_party/blink/web_tests/external/wpt/css/css-values/typed-arithmetic-different-categories-crash.html new file mode 100644 index 0000000..e3dd6bb --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-values/typed-arithmetic-different-categories-crash.html
@@ -0,0 +1,8 @@ +<!DOCTYPE html> +<title>CSS Values Test: typed arithmetic with different categories crash</title> +<link rel="help" href="https://issues.chromium.org/issues/445824614"> +<style> + body { + stroke-dasharray: calc(0.5px * 2 / -4500000000kHz); + } +</style>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-values/typed_arithmetic-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-values/typed_arithmetic-expected.txt new file mode 100644 index 0000000..8be5b859 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-values/typed_arithmetic-expected.txt
@@ -0,0 +1,9 @@ +This is a testharness.js-based test. +[FAIL] calc(10% / 1px) should be used-value-equivalent to 1 + assert_equals: calc(10% / 1px) and 1 serialize to the same thing in used values. expected "10px" but got "100px" +[FAIL] calc(10% * 10% / 1px * 10deg / 1deg / 10px) should be used-value-equivalent to 1 + assert_equals: calc(10% * 10% / 1px * 10deg / 1deg / 10px) and 1 serialize to the same thing in used values. expected "10px" but got "1000px" +[FAIL] calc(10% * 10% / 1px * 1deg / 1deg) should be used-value-equivalent to 1px + assert_equals: calc(10% * 10% / 1px * 1deg / 1deg) and 1px serialize to the same thing in used values. expected "1px" but got "100px" +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/css/css-values/typed_arithmetic.html b/third_party/blink/web_tests/external/wpt/css/css-values/typed_arithmetic.html index f4258c33..37f560d2 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-values/typed_arithmetic.html +++ b/third_party/blink/web_tests/external/wpt/css/css-values/typed_arithmetic.html
@@ -5,6 +5,7 @@ <script src="/resources/testharnessreport.js"></script> <script src="/css/support/numeric-testcommon.js"></script> <script src="/css/support/computed-testcommon.js"></script> +<script src="../support/parsing-testcommon.js"></script> <style> :root { font-size: 10px; @@ -41,6 +42,26 @@ test_math_used("calc(10em / 1px)", "100", {"prop": "z-index"}); test_math_used("calc(1px / 10em * NaN)", "0", {"prop": "z-index"}); +// 10% -> 1px; 1px / 1px -> 1. +test_math_used("calc(10% / 1px)", "1", {"prop": "line-height"}); +// 1% * 100% / 10% -> 10%. +test_math_used("calc(1% * 100% / 10%)", "10%", {"prop": "line-height"}); +// 10% / 10% -> 1. +test_math_used("calc(10% / 10%)", "1", {"prop": "line-height"}); +// 10% -> 1px; 1% -> 0.1px; 1px / 0.1px / 1px -> 10px. +test_math_used("calc((10% * 1%) / 1px)", "10px"); +// 10% -> 1px; 1px * 1px / 1px * 10deg / 1deg / 10px -> 1. +test_math_used("calc(10% * 10% / 1px * 10deg / 1deg / 10px)", "1", {"prop": "line-height"}); +// 10% -> 1px; 1px * 1px / 1px * 1deg / 1deg -> 1px. +test_math_used("calc(10% * 10% / 1px * 1deg / 1deg)", "1px", {"prop": "line-height"}); +// 1px * 2deg / 1deg -> 2px. +test_math_used("calc(1px * 2deg / 1deg)", "2px", {"prop": "line-height"}); +// 1px * 3deg / 1deg / 1px -> 3. +test_math_used("calc(1px * 3deg / 1deg / 1px)", "3", {"prop": "line-height"}); + +test_invalid_value("width", "calc((1% * 1deg) / 1px)"); +test_invalid_value("width", "calc((1% * 1% * 1%) / 1px)"); + testComputedValueGreaterOrLowerThan("width", "calc(1px * 10em / 0em)", REALLY_LARGE); testComputedValueGreaterOrLowerThan("width", "calc(1px / 1px * 10em * infinity)", REALLY_LARGE); testComputedValueGreaterOrLowerThan("margin-left", "calc(1px * 10em / -0em)", REALLY_LARGE_NEGATIVE);
diff --git a/third_party/blink/web_tests/fast/peerconnection/RTCRtpSender-getParameters.html b/third_party/blink/web_tests/fast/peerconnection/RTCRtpSender-getParameters.html index 112f3db..168df5e 100644 --- a/third_party/blink/web_tests/fast/peerconnection/RTCRtpSender-getParameters.html +++ b/third_party/blink/web_tests/fast/peerconnection/RTCRtpSender-getParameters.html
@@ -1,4 +1,5 @@ <!DOCTYPE html> +<meta name="timeout" content="long"> <html> <head> <title>RTCRtpSender.getParameters</title>
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-ui/caret-eol-part-clip.html b/third_party/blink/web_tests/wpt_internal/css/css-ui/caret-eol-part-clip.html new file mode 100644 index 0000000..662bee1 --- /dev/null +++ b/third_party/blink/web_tests/wpt_internal/css/css-ui/caret-eol-part-clip.html
@@ -0,0 +1,32 @@ +<!DOCTYPE html> +<html lang=en> +<meta charset="utf-8"> +<title>CSS Basic User Interface Test: end-of-line carets should be visible</title> +<link rel="help" href="http://www.w3.org/TR/css4-ui/#caret-shape"> +<link rel="match" href="caret-eol-part-ref.html"> +<link rel="match" href="caret-eol-part-mac-ref.html"> +<meta name="assert" + content="Checks that carets positioned at the end of the line are partially shown to fill the rest of the available space when the box has clip overflow with caret-shape: block."> +<style> + div { + font-size: 40px; + font-family: monospace; + width: 5.5ch; + caret-color: orange; + caret-shape: block; + caret-animation: manual; + outline: none; + overflow: clip; + white-space: pre; + } +</style> + +<p>Test passes if you see a orange text insertion caret at the end of the line below. + +<div id=test contenteditable spellcheck="false">abcde</div> + +<script> + const t = document.querySelector("#test"); + window.getSelection().selectAllChildren(t); + window.getSelection().collapseToEnd(); +</script>
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-ui/caret-eol-part-hidden.html b/third_party/blink/web_tests/wpt_internal/css/css-ui/caret-eol-part-hidden.html new file mode 100644 index 0000000..7bd76f20 --- /dev/null +++ b/third_party/blink/web_tests/wpt_internal/css/css-ui/caret-eol-part-hidden.html
@@ -0,0 +1,32 @@ +<!DOCTYPE html> +<html lang=en> +<meta charset="utf-8"> +<title>CSS Basic User Interface Test: end-of-line carets should be visible</title> +<link rel="help" href="http://www.w3.org/TR/css4-ui/#caret-shape"> +<link rel="match" href="caret-eol-part-ref.html"> +<link rel="match" href="caret-eol-part-mac-ref.html"> +<meta name="assert" + content="Checks that carets positioned at the end of the line are partially shown to fill the rest of the available space when the box has hidden overflow with caret-shape: block."> +<style> + div { + font-size: 40px; + font-family: monospace; + width: 5.5ch; + caret-color: orange; + caret-shape: block; + caret-animation: manual; + outline: none; + overflow: hidden; + white-space: pre; + } +</style> + +<p>Test passes if you see a orange text insertion caret at the end of the line below. + +<div id=test contenteditable spellcheck="false">abcde</div> + +<script> + const t = document.querySelector("#test"); + window.getSelection().selectAllChildren(t); + window.getSelection().collapseToEnd(); +</script>
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-ui/caret-eol-part-mac-ref.html b/third_party/blink/web_tests/wpt_internal/css/css-ui/caret-eol-part-mac-ref.html new file mode 100644 index 0000000..e476cbe --- /dev/null +++ b/third_party/blink/web_tests/wpt_internal/css/css-ui/caret-eol-part-mac-ref.html
@@ -0,0 +1,35 @@ +<!DOCTYPE html> +<html lang=en> +<meta charset="utf-8"> +<title>CSS Basic User Interface Test Reference</title> +<style> +div { + font-size: 40px; + font-family: monospace; + caret-color: orange; + caret-animation: manual; + caret-shape: block; + width: 5ch; + outline: none; + white-space: pre; + display: inline-block; +} + +#div2 { + width: 1ch; + position: relative; + left: -6px; + transform: scaleX(0.5); +} + +</style> + +<p>Test passes if you see a orange text insertion caret at the end of the line below.</p> + +<div id=test contenteditable spellcheck="false">abcde</div><div id=div2 contenteditable></div> + +<script> + window.onload = function () { + document.getElementById("div2").focus(); + } +</script>
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-ui/caret-eol-part-ref.html b/third_party/blink/web_tests/wpt_internal/css/css-ui/caret-eol-part-ref.html new file mode 100644 index 0000000..dc45537 --- /dev/null +++ b/third_party/blink/web_tests/wpt_internal/css/css-ui/caret-eol-part-ref.html
@@ -0,0 +1,34 @@ +<!DOCTYPE html> +<html lang=en> +<meta charset="utf-8"> +<title>CSS Basic User Interface Test Reference</title> +<style> +div { + font-size: 40px; + font-family: monospace; + caret-color: orange; + caret-animation: manual; + caret-shape: block; + width: 5ch; + outline: none; + white-space: pre; + display: inline-block; +} + +#div2 { + position: relative; + left: -1.25ch; + transform: scaleX(0.5); +} + +</style> + +<p>Test passes if you see a orange text insertion caret at the end of the line below.</p> + +<div id=test contenteditable spellcheck="false">abcde</div><div id=div2 contenteditable></div> + +<script> + window.onload = function () { + document.getElementById("div2").focus(); + } +</script>
diff --git a/third_party/devtools-frontend/src b/third_party/devtools-frontend/src index 2d6e3ee..0ef5b063 160000 --- a/third_party/devtools-frontend/src +++ b/third_party/devtools-frontend/src
@@ -1 +1 @@ -Subproject commit 2d6e3ee0f3197f192fe4d759e8eb6934dea46069 +Subproject commit 0ef5b0631522c714639536c36dabf98a1802bf1f
diff --git a/third_party/omnibox_proto/README.chromium b/third_party/omnibox_proto/README.chromium index 93e21f475..21707de 100644 --- a/third_party/omnibox_proto/README.chromium +++ b/third_party/omnibox_proto/README.chromium
@@ -1,9 +1,8 @@ Name: Omnibox Protos Short Name: omnibox_proto -URL: Google Internal -Version: 810525975 -Date: 2025-09-23 -Update Mechanism: Manual (https://crbug.com/422306307) +URL: This is the canonical public repository +Version: 811469245 +Date: 2025-09-25 License: BSD-3-Clause License File: LICENSE Shipped: yes
diff --git a/third_party/omnibox_proto/aim_eligibility_response.proto b/third_party/omnibox_proto/aim_eligibility_response.proto index 5e4318a6..55ad6b2 100644 --- a/third_party/omnibox_proto/aim_eligibility_response.proto +++ b/third_party/omnibox_proto/aim_eligibility_response.proto
@@ -11,8 +11,10 @@ package omnibox; // AIM Eligibility Response. -// Next ID: 3 +// Next ID: 5 message AimEligibilityResponse { optional bool is_eligible = 1; optional bool is_pdf_upload_eligible = 2; + optional bool is_deep_search_eligible = 3; + optional bool is_canvas_eligible = 4; }
diff --git a/third_party/perfetto b/third_party/perfetto index 95317c9..c65beb1 160000 --- a/third_party/perfetto +++ b/third_party/perfetto
@@ -1 +1 @@ -Subproject commit 95317c91aadc41a24abc2a671b211baec3d6d749 +Subproject commit c65beb1b174079f116a0d31729c43e6cbfacfc85
diff --git a/third_party/skia b/third_party/skia index b54e106..2b871d6 160000 --- a/third_party/skia +++ b/third_party/skia
@@ -1 +1 @@ -Subproject commit b54e1064ccae404b7a7bff410585fef1c5381241 +Subproject commit 2b871d6b99caae5e3990351b91606e9a957f196f
diff --git a/third_party/vulkan-deps b/third_party/vulkan-deps index 2458bba..5bc0a41 160000 --- a/third_party/vulkan-deps +++ b/third_party/vulkan-deps
@@ -1 +1 @@ -Subproject commit 2458bba6f0d087f6ad588af68bcb4075c1d0701b +Subproject commit 5bc0a41ae522a65e91c77b043bce45637a1a2fde
diff --git a/third_party/vulkan-validation-layers/src b/third_party/vulkan-validation-layers/src index 102c306..c352f86 160000 --- a/third_party/vulkan-validation-layers/src +++ b/third_party/vulkan-validation-layers/src
@@ -1 +1 @@ -Subproject commit 102c30690b1e84e58ad659a249dbb819dcc7f926 +Subproject commit c352f86877474dbc7294125d31523e8c74918c76
diff --git a/third_party/webrtc b/third_party/webrtc index 9607577..ba391e6 160000 --- a/third_party/webrtc +++ b/third_party/webrtc
@@ -1 +1 @@ -Subproject commit 96075773302f4a4b7265052c37a793486355aef9 +Subproject commit ba391e6893da350a48a7895a0bff8f033369a729
diff --git a/tools/clang/spanify/Spanifier.cpp b/tools/clang/spanify/Spanifier.cpp index 30809f9c..d471384 100644 --- a/tools/clang/spanify/Spanifier.cpp +++ b/tools/clang/spanify/Spanifier.cpp
@@ -674,8 +674,8 @@ const clang::ASTContext& ast_context) { clang::PrintingPolicy printing_policy(ast_context.getLangOpts()); printing_policy.SuppressScope = 0; + printing_policy.SuppressTagKeyword = 0; printing_policy.SuppressUnwrittenScope = 1; - printing_policy.SuppressElaboration = 0; printing_policy.SuppressInlineNamespace = 1; printing_policy.SuppressDefaultTemplateArgs = 1; printing_policy.PrintAsCanonical = 0; @@ -751,36 +751,23 @@ assert(false && "Unexpected match in getSourceRange()"); } -// Unwraps typedef type locs and/or elaborated type locs, and returns the body -// type loc. +// Unwraps typedef type locs and returns the body type loc. // // Note that using-declared types are also represented with typedef types in // clang, so this function works for both 'typedef' and 'using' declarations. // // Example TypeLoc structures: // // Given T2 where typedef int T1; using T2 = T1; -// ElaboratedTypeLoc('T2') -// --(getNamedTypeLoc)--> TypedefTypeLoc('T2') -// --(getTypedefNameDecl)--> ElaboratedTypeLoc('T1') -// --(getNamedTypeLoc)--> TypedefTypeLoc('T1') -// --(getTypedefNameDecl)--> BuiltinTypeLoc('int') +// TypedefTypeLoc('T2') +// --(getDecl)--> TypedefTypeLoc('T1') +// --(getDecl)--> BuiltinTypeLoc('int') // => returns BuiltinTypeLoc('int'). -// -// // Given base::raw_ptr<int>, -// ElaboratedTypeLoc('base::raw_ptr<int>') -// --(getNamedTypeLoc)--> TemplateSpecializationTypeLoc('raw_ptr<int>') -// --(getArgLoc)--> TemplateArgumentLoc('int') -// => returns TemplateSpecializationTypeLoc('raw_ptr<int>'). clang::TypeLoc UnwrapTypedefTypeLoc(clang::TypeLoc type_loc) { - while (const clang::ElaboratedTypeLoc elaborated_type_loc = - type_loc.getAs<clang::ElaboratedTypeLoc>()) { - type_loc = elaborated_type_loc.getNamedTypeLoc(); - if (const clang::TypedefTypeLoc typedef_type_loc = - type_loc.getAs<clang::TypedefTypeLoc>()) { - const clang::TypedefNameDecl* typedef_name_decl = - typedef_type_loc.getTypedefNameDecl(); - type_loc = typedef_name_decl->getTypeSourceInfo()->getTypeLoc(); - } + while (const clang::TypedefTypeLoc typedef_type_loc = + type_loc.getAs<clang::TypedefTypeLoc>()) { + const clang::TypedefNameDecl* typedef_name_decl = + typedef_type_loc.getDecl(); + type_loc = typedef_name_decl->getTypeSourceInfo()->getTypeLoc(); } return type_loc; } @@ -2517,23 +2504,15 @@ if (!unnamed_class.empty()) { element_type_as_string = unnamed_class; } else if (original_element_type->isElaboratedTypeSpecifier()) { - // If the `original_element_type` is an elaborated type with a keyword, i.e. - // `struct`, `class`, `union`, we will create another ElaboratedType - // without the keyword. So `struct funcHasName` will be `funcHasHame`. - auto* original_type = new_element_type->getAs<clang::ElaboratedType>(); - - // Create a new ElaboratedType without 'struct', 'class', 'union' - // keywords. - auto new_element_type = ast_context.getElaboratedType( - // Use `None` to suppress tag names. - clang::ElaboratedTypeKeyword::None, - // Keep the same as the original. - original_type->getQualifier(), - // Keep the same as the original. - original_type->getNamedType(), - // Remove `OwnedTagDecl`. We don't need IncludeTagDefinition. - nullptr); - element_type_as_string = GetTypeAsString(new_element_type, ast_context); + // `GetTypeAsString` doesn't remove a tag keyword (struct, class, enum, or + // union), but we'd like to remove the tag keyword here. + clang::PrintingPolicy printing_policy(ast_context.getLangOpts()); + printing_policy.SuppressTagKeyword = 1; + printing_policy.SuppressUnwrittenScope = 1; + printing_policy.SuppressInlineNamespace = 1; + printing_policy.SuppressDefaultTemplateArgs = 1; + printing_policy.PrintAsCanonical = 1; + element_type_as_string = new_element_type.getAsString(printing_policy); } else { element_type_as_string = RewriteCArrayToStdArray( new_element_type, array_type_loc.getElementLoc(), source_manager,
diff --git a/tools/clang/spanify/tests/func-ptr-var-expected.cc b/tools/clang/spanify/tests/func-ptr-var-expected.cc index 53218a2..6b9b571d 100644 --- a/tools/clang/spanify/tests/func-ptr-var-expected.cc +++ b/tools/clang/spanify/tests/func-ptr-var-expected.cc
@@ -42,10 +42,10 @@ // Expected rewrite: // base::span<int> FuncAll(base::span<int, 3> arg1, // base::span<int> arg2, -// base::base::raw_span<int> arg3) { +// base::raw_span<int> arg3) { base::span<int> FuncAll(base::span<int, 3> arg1, base::span<int> arg2, - base::base::raw_span<int> arg3) { + base::raw_span<int> arg3) { arg1[UnsafeIndex()] = 3; arg2[UnsafeIndex()] = 3; arg3[UnsafeIndex()] = 3; @@ -185,10 +185,10 @@ // Expected rewrite: // typedef base::span<int> (*AllType1)(base::span<int, 3> arg1, // base::span<int> arg2, - // base::base::raw_span<int> arg3); + // base::raw_span<int> arg3); typedef base::span<int> (*AllType1)(base::span<int, 3> arg1, base::span<int> arg2, - base::base::raw_span<int> arg3); + base::raw_span<int> arg3); using AllType2 = AllType1; AllType2 p_all = FuncAll; int* ret_all = p_all(arr, arr, arr);
diff --git a/tools/clang/spanify/tests/func-ptr-var-original.cc b/tools/clang/spanify/tests/func-ptr-var-original.cc index fcaefcf..718519c 100644 --- a/tools/clang/spanify/tests/func-ptr-var-original.cc +++ b/tools/clang/spanify/tests/func-ptr-var-original.cc
@@ -40,7 +40,7 @@ // Expected rewrite: // base::span<int> FuncAll(base::span<int, 3> arg1, // base::span<int> arg2, -// base::base::raw_span<int> arg3) { +// base::raw_span<int> arg3) { int* FuncAll(int arg1[3], int* arg2, base::raw_ptr<int> arg3) { arg1[UnsafeIndex()] = 3; arg2[UnsafeIndex()] = 3; @@ -181,7 +181,7 @@ // Expected rewrite: // typedef base::span<int> (*AllType1)(base::span<int, 3> arg1, // base::span<int> arg2, - // base::base::raw_span<int> arg3); + // base::raw_span<int> arg3); typedef int* (*AllType1)(int arg1[3], int* arg2, base::raw_ptr<int> arg3); using AllType2 = AllType1; AllType2 p_all = FuncAll;
diff --git a/tools/clang/spanify/tests/var-construction-expected.cc b/tools/clang/spanify/tests/var-construction-expected.cc index ba0f1a5..1f2f998 100644 --- a/tools/clang/spanify/tests/var-construction-expected.cc +++ b/tools/clang/spanify/tests/var-construction-expected.cc
@@ -134,7 +134,7 @@ // Expected rewrite: // base::raw_span<char> buf4 = buf3; // base::PostIncrementSpan(buf4); - base::base::raw_span<char> buf4 = buf3; + base::raw_span<char> buf4 = buf3; base::PostIncrementSpan(buf4); // Expected rewrite:
diff --git a/tools/licenses/licenses.py b/tools/licenses/licenses.py index 61a91637..a8afd4c 100755 --- a/tools/licenses/licenses.py +++ b/tools/licenses/licenses.py
@@ -77,7 +77,10 @@ os.path.join('third_party', 'gperf'), os.path.join('third_party', 'lighttpd'), os.path.join('third_party', 'llvm'), + os.path.join('third_party', 'llvm-bootstrap'), + os.path.join('third_party', 'llvm-bootstrap-install'), os.path.join('third_party', 'llvm-build'), + os.path.join('third_party', 'llvm-build-tools'), os.path.join('third_party', 'mingw-w64'), os.path.join('third_party', 'nacl_sdk_binaries'), os.path.join('third_party', 'pefile'), @@ -86,6 +89,8 @@ os.path.join('third_party', 'pyelftools'), os.path.join('third_party', 'pylib'), os.path.join('third_party', 'pywebsocket'), + os.path.join('third_party', 'rust-src'), + os.path.join('third_party', 'rust-toolchain-intermediate'), os.path.join('third_party', 'syzygy'), # Stuff pulled in from chrome-internal for official builds/tools.
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml index 262acfd..5232ab8 100644 --- a/tools/metrics/actions/actions.xml +++ b/tools/metrics/actions/actions.xml
@@ -37168,6 +37168,16 @@ </description> </action> +<action name="Settings.DeleteBrowsingData.GeminiAppsActivityLinkClick"> + <owner>rainhard@chromium.com</owner> + <owner>zalmashni@chromium.org</owner> + <owner>chrome-browser-privacy-team@google.com</owner> + <description> + User clicks on the "Gemini Apps Activity" link in the "Other + Google data" dialog. + </description> +</action> + <action name="Settings.DeleteBrowsingData.GoogleSearchHistoryLinkClick"> <owner>hkamila@google.com</owner> <owner>zalmashni@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml_files.gni b/tools/metrics/histograms/histograms_xml_files.gni index 443a7c5..dd083489 100644 --- a/tools/metrics/histograms/histograms_xml_files.gni +++ b/tools/metrics/histograms/histograms_xml_files.gni
@@ -135,6 +135,8 @@ "//tools/metrics/histograms/metadata/invalidation/histograms.xml", "//tools/metrics/histograms/metadata/ios/enums.xml", "//tools/metrics/histograms/metadata/ios/histograms.xml", + "//tools/metrics/histograms/metadata/ip_protection/enums.xml", + "//tools/metrics/histograms/metadata/ip_protection/histograms.xml", "//tools/metrics/histograms/metadata/kerberos/histograms.xml", "//tools/metrics/histograms/metadata/kiosk/histograms.xml", "//tools/metrics/histograms/metadata/language/enums.xml",
diff --git a/tools/metrics/histograms/metadata/enterprise/enums.xml b/tools/metrics/histograms/metadata/enterprise/enums.xml index ccdd848..795bb4d 100644 --- a/tools/metrics/histograms/metadata/enterprise/enums.xml +++ b/tools/metrics/histograms/metadata/enterprise/enums.xml
@@ -60,6 +60,7 @@ <int value="9" label="Load Key Failed"/> <int value="10" label="Invalid Final Identity Name"/> <int value="11" label="Identity Not Found"/> + <int value="12" label="Delete Identity Failed"/> </enum> <enum name="CertificateUploadClientError"> @@ -2290,6 +2291,7 @@ <int value="1395" label="ExtensionForceInstallWithNonMalwareViolationsEnabled"/> <int value="1396" label="CacheEncryptionEnabled"/> + <int value="1397" label="SilentPrintingEnabled"/> </enum> <enum name="EnterprisePoliciesSources">
diff --git a/tools/metrics/histograms/metadata/ios/enums.xml b/tools/metrics/histograms/metadata/ios/enums.xml index 24fdcfb..1f3d636 100644 --- a/tools/metrics/histograms/metadata/ios/enums.xml +++ b/tools/metrics/histograms/metadata/ios/enums.xml
@@ -1684,6 +1684,19 @@ <!-- LINT.ThenChange(/ios/chrome/browser/reader_mode/model/constants.h:ReaderModeAccessPoint) --> +<!-- LINT.IfChange(ReaderModeAccessPointWithMode) --> + +<enum name="ReaderModeAccessPointWithMode"> + <int value="0" label="Contextual Chip in Regular"/> + <int value="1" label="Contextual Chip in Incognito"/> + <int value="2" label="Tools Menu in Regular"/> + <int value="3" label="Tools Menu in Incognito"/> + <int value="4" label="AI Hub in Regular"/> + <int value="5" label="AI Hub in Incognito"/> +</enum> + +<!-- LINT.ThenChange(/ios/chrome/browser/reader_mode/model/constants.h:ReaderModeAccessPointWithMode) --> + <!-- LINT.IfChange(ReaderModeCustomizationType) --> <enum name="ReaderModeCustomizationType">
diff --git a/tools/metrics/histograms/metadata/ios/histograms.xml b/tools/metrics/histograms/metadata/ios/histograms.xml index acb8376..ce54396 100644 --- a/tools/metrics/histograms/metadata/ios/histograms.xml +++ b/tools/metrics/histograms/metadata/ios/histograms.xml
@@ -4984,6 +4984,19 @@ </summary> </histogram> +<histogram name="IOS.ReaderMode.AccessPointWithMode" + enum="ReaderModeAccessPointWithMode" expires_after="2026-03-22"> + <owner>fernandex@google.com</owner> + <owner>qpubert@google.com</owner> + <owner>bling-squid-squad@google.com</owner> + <summary> + Logs the access point where the user enabled Reading Mode UI on iOS, this + does not include situations when the user changes web state (e.g. by + switching tabs or closing the browser). The results are further divided by + the application mode (Incognito or Regular). + </summary> +</histogram> + <histogram name="IOS.ReaderMode.Customization" enum="ReaderModeCustomizationType" expires_after="2026-02-22"> <owner>fernandex@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/ip_protection/OWNERS b/tools/metrics/histograms/metadata/ip_protection/OWNERS new file mode 100644 index 0000000..3d5fd33 --- /dev/null +++ b/tools/metrics/histograms/metadata/ip_protection/OWNERS
@@ -0,0 +1,4 @@ +per-file OWNERS=file://tools/metrics/histograms/metadata/METRIC_REVIEWER_OWNERS + +ortuno@chromium.org +awillia@chromium.org
diff --git a/tools/metrics/histograms/metadata/ip_protection/enums.xml b/tools/metrics/histograms/metadata/ip_protection/enums.xml new file mode 100644 index 0000000..89027d8 --- /dev/null +++ b/tools/metrics/histograms/metadata/ip_protection/enums.xml
@@ -0,0 +1,257 @@ +<!-- +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 describes the enumerations referenced by entries in histograms.xml for +this directory. Some enums may instead be listed in the central enums.xml file +at src/tools/metrics/histograms/enums.xml when multiple files use them. + +For best practices on writing enumerations descriptions, see +https://chromium.googlesource.com/chromium/src.git/+/HEAD/tools/metrics/histograms/README.md#Enum-Histograms + +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> + +<!-- Enum types --> + +<enums> + +<!-- LINT.IfChange(IpProtectionGetAuthTokenResultForGeo) --> + +<enum name="IpProtectionGetAuthTokenResultForGeo"> + <int value="0" label="Auth token unavailable and cache is empty"/> + <int value="1" label="Auth token unavailable but cache contains tokens"/> + <int value="2" label="Auth token available for current geo"/> + <int value="3" label="Auth token available for other geo"/> +</enum> + +<!-- LINT.ThenChange(//components/ip_protection/common/ip_protection_telemetry.h:AuthTokenResultForGeo) --> + +<enum name="IpProtectionGetProxyListResult"> + <int value="0" label="Failed to acquire a list"/> + <int value="1" label="Got a list without any valid entries"/> + <int value="2" label="Got a list with at least one valid entry"/> +</enum> + +<enum name="IpProtectionJobResult"> + <int value="0" label="IP Protection was not attempted"/> + <int value="1" + label="The request was IP Protected and carried via IP Protection + proxies or, if the direct-only parameter is true, made directly"/> + <int value="2" label="The request was IP Protected, but fell back to direct"/> +</enum> + +<enum name="IpProtectionProxyChainId"> + <int value="0" label="Unknown"/> + <int value="1" label="Chain 1"/> + <int value="2" label="Chain 2"/> + <int value="3" label="Chain 3"/> +</enum> + +<enum name="IpProtectionProxyLayer"> + <int value="0" label="Proxy A"/> + <int value="1" label="Proxy B"/> +</enum> + +<enum name="IpProtectionProxyResolutionResult"> + <int value="0" + label="The MDL is not populated, so an eligility decision could not be + made"/> + <int value="1" label="The request did not match the MDL"/> + <int value="2" + label="DEPRECATED: The EnableIpProtectionProxy feature is not enabled"/> + <int value="3" label="The IP Protection setting is disabled"/> + <int value="4" label="Proxy List is unavailable"/> + <int value="5" + label="Proxy List is available but tokens have never been available"/> + <int value="6" + label="Proxy List is available but tokens in the cache have been + exhausted"/> + <int value="7" label="The request was resolved to the IP Protection proxies"/> + <int value="8" + label="A site exception created by User Bypass disables protections"/> + <int value="9" + label="The request bypassed the IP Protection proxies through DevTools"/> +</enum> + +<enum name="IpProtectionTokenBatchRequestError"> +<!-- The following errors are omitted because they have many possible suffixes: + "Failed to create RSA public key: <error>" + "Failed to decode extensions: <error>" + "Failed to validate extensions: <error>" + "Failed to parse expiration timestamp: <error>" + "Failed to parse geo hint: <error>" + "Failed to parse use case: <error>" + "Failed to create Privacy Pass client: <error>" + "Failed to create ExtendedTokenRequest: <error>" + + Additionally, errors marked [DEPRECATED] are no longer emitted as of M141 (crrev.com/c/6865774). + --> + + <int value="4948469" label="AuthAndSign failed: 404 (NOT_FOUND)"/> + <int value="149981085" label="GetInitialData failed: 401 (UNAUTHENTICATED)"/> + <int value="150736087" label="GetInitialData failed: 499 (CANCELLED)"/> + <int value="159430335" + label="[DEPRECATED] GetInitialDataRequest failed: 499 (CANCELLED)"/> + <int value="203200113" label="AuthAndSign failed: 409 (ABORTED)"/> + <int value="219311180" label="AuthAndSign failed: invalid response"/> + <int value="247849994" label="GetInitialData failed: 501 (UNIMPLEMENTED)"/> + <int value="774920404" + label="[DEPRECATED] GetInitialDataRequest failed: 5xx (INTERNAL)"/> + <int value="776650315" + label="GetInitialData failed: 4xx (FAILED_PRECONDITION)"/> + <int value="788650824" + label="[DEPRECATED] GetInitialDataRequest failed: 409 (ABORTED)"/> + <int value="882579398" + label="[DEPRECATED] AuthAndSign failed: 504 (DEADLINE_EXCEEDED)"/> + <int value="1009665478" label="GetInitialData failed: 409 (ABORTED)"/> + <int value="1324062375" + label="[DEPRECATED] AuthAndSign failed: 403 (PERMISSION_DENIED)"/> + <int value="1359797045" + label="[DEPRECATED] AuthAndSign failed: 416 (OUT_OF_RANGE)"/> + <int value="1392994811" + label="[DEPRECATED] GetInitialDataRequest failed: 4xx + (FAILED_PRECONDITION)"/> + <int value="1560305329" + label="[DEPRECATED] GetInitialDataRequest failed: invalid response"/> + <int value="1570178381" + label="[DEPRECATED] GetInitialDataRequest failed: 429 + (RESOURCE_EXHAUSTED)"/> + <int value="1578860000" label="GetInitialData failed: 404 (NOT_FOUND)"/> + <int value="1632191523" + label="[DEPRECATED] GetInitialDataRequest failed: 1xx/3xx (UNKNOWN)"/> + <int value="1632242186" + label="[DEPRECATED] AuthAndSign failed: 429 (RESOURCE_EXHAUSTED)"/> + <int value="1637757426" + label="[DEPRECATED] GetInitialDataRequest failed: 401 (UNAUTHENTICATED)"/> + <int value="1684860881" + label="GetInitialData failed: 429 (RESOURCE_EXHAUSTED)"/> + <int value="1731128661" label="AuthAndSign failed: 401 (UNAUTHENTICATED)"/> + <int value="1741288262" + label="[DEPRECATED] AuthAndSign failed: 499 (CANCELLED)"/> + <int value="1782033339" + label="[DEPRECATED] AuthAndSign failed: invalid response"/> + <int value="1869144073" + label="GetInitialData failed: 504 (DEADLINE_EXCEEDED)"/> + <int value="1916829389" + label="[DEPRECATED] GetInitialDataRequest failed: 404 (NOT_FOUND)"/> + <int value="2040698924" + label="[DEPRECATED] AuthAndSign failed: 404 (NOT_FOUND)"/> + <int value="2073947853" + label="[DEPRECATED] AuthAndSign failed: 401 (UNAUTHENTICATED)"/> + <int value="2141269466" label="[DEPRECATED] Failed to validate extensions"/> + <int value="2143022301" label="AuthAndSign failed: 429 (RESOURCE_EXHAUSTED)"/> + <int value="2152182465" + label="GetInitialData failed: 403 (PERMISSION_DENIED)"/> + <int value="2218632443" label="GetInitialData failed: invalid response"/> + <int value="2339897637" + label="[DEPRECATED] GetInitialDataRequest failed: 503 (UNAVAILABLE)"/> + <int value="2353899066" label="AuthAndSign failed: 416 (OUT_OF_RANGE)"/> + <int value="2408268044" label="AuthAndSign failed: 400 (INVALID_ARGUMENT)"/> + <int value="2420519214" label="GetInitialData failed: 1xx/3xx (UNKNOWN)"/> + <int value="2528366448" label="Failed to parse GetInitialDataResponse"/> + <int value="2528411010" + label="[DEPRECATED] GetInitialDataRequest failed: 416 (OUT_OF_RANGE)"/> + <int value="2594877687" + label="[DEPRECATED] GetInitialDataRequest failed: 504 + (DEADLINE_EXCEEDED)"/> + <int value="2596810654" label="Failed to marshal token"/> + <int value="2766613933" + label="[DEPRECATED] AuthAndSign failed: 503 (UNAVAILABLE)"/> + <int value="2848390062" label="Failed to parse AuthAndSignResponse"/> + <int value="2906092890" + label="[DEPRECATED] GetInitialDataRequest failed: 501 (UNIMPLEMENTED)"/> + <int value="2958424397" label="GetInitialData failed: 416 (OUT_OF_RANGE)"/> + <int value="3024523150" + label="[DEPRECATED] AuthAndSign failed: 5xx (INTERNAL)"/> + <int value="3118017018" + label="[DEPRECATED] AuthAndSign failed: 501 (UNIMPLEMENTED)"/> + <int value="3172166369" + label="[DEPRECATED] AuthAndSign failed: 1xx/3xx (UNKNOWN)"/> + <int value="3240481601" label="AuthAndSign failed: 504 (DEADLINE_EXCEEDED)"/> + <int value="3317564205" + label="AuthAndSign failed: 4xx (FAILED_PRECONDITION)"/> + <int value="3321526425" label="AuthAndSign failed: 501 (UNIMPLEMENTED)"/> + <int value="3329637962" label="AuthAndSign failed: 1xx/3xx (UNKNOWN)"/> + <int value="3336018440" + label="Non-Privacy Pass tokens are no longer supported"/> + <int value="3359657202" + label="[DEPRECATED] GetInitialDataRequest failed: 400 + (INVALID_ARGUMENT)"/> + <int value="3426382554" label="AuthAndSign failed: 403 (PERMISSION_DENIED)"/> + <int value="3496444457" label="AuthAndSign failed: 5xx (INTERNAL)"/> + <int value="3506031840" + label="[DEPRECATED] AuthAndSign failed: 400 (INVALID_ARGUMENT)"/> + <int value="3554182688" label="Failed to unescape blinded signature"/> + <int value="3582010778" label="GetInitialData failed: 5xx (INTERNAL)"/> + <int value="3613919248" label="Failed to finalize token"/> + <int value="3831168552" label="AuthAndSign failed: 499 (CANCELLED)"/> + <int value="3831429430" + label="[DEPRECATED] AuthAndSign failed: 409 (ABORTED)"/> + <int value="3915930013" label="Failed to parse Privacy Pass public key"/> + <int value="4031088688" label="GetInitialData failed: 503 (UNAVAILABLE)"/> + <int value="4053847635" + label="GetInitialData failed: 400 (INVALID_ARGUMENT)"/> + <int value="4107556447" + label="[DEPRECATED] AuthAndSign failed: 4xx (FAILED_PRECONDITION)"/> + <int value="4124254920" label="AuthAndSign failed: 503 (UNAVAILABLE)"/> + <int value="4124458081" label="Failed to marshal token challenge"/> + <int value="4144593304" + label="Number of signatures is greater than the number of Privacy Pass + tokens sent"/> + <int value="4198175771" + label="[DEPRECATED] GetInitialDataRequest failed: 403 + (PERMISSION_DENIED)"/> + <int value="4205984674" + label="[DEPRECATED] Failed to parse expiration timestamp"/> +</enum> + +<enum name="IpProtectionTokenBatchRequestResult"> + <int value="0" label="Success"/> + <int value="1" label="Failed - No Account"/> + <int value="2" label="Failed - Not Eligible"/> + <int value="3" label="Deprecated"/> + <int value="4" label="Failed - BSA Error 400"/> + <int value="5" label="Failed - BSA Error 401"/> + <int value="6" label="Failed - BSA Error 403"/> + <int value="7" label="Failed - BSA Error Other"/> + <int value="8" label="Transient OAuth Token Failure"/> + <int value="9" label="Persistent OAuth Token Failure"/> + <int value="10" label="Disabled by User"/> +</enum> + +<!-- LINT.IfChange(ProbabilisticRevealTokensResult) --> + +<enum name="ProbabilisticRevealTokensResult"> + <int value="0" label="Success"/> + <int value="1" label="Net Not Ok"/> + <int value="2" label="Net Ok Null Response"/> + <int value="3" label="Null Response"/> + <int value="4" label="Response Parsing Failed"/> + <int value="5" label="Invalid Token Version"/> + <int value="6" label="Invalid Token Size"/> + <int value="7" label="Too Few Tokens"/> + <int value="8" label="Too Many Tokens"/> + <int value="9" label="Expiration Too Soon"/> + <int value="10" label="Expiration Too Late"/> + <int value="11" label="Invalid Public Key"/> + <int value="12" label="Invalid Num Tokens With Signal"/> + <int value="13" label="Request Backed Off"/> + <int value="14" label="No Google Chrome Branding"/> + <int value="15" label="Invalid Epoch ID Size"/> +</enum> + +<!-- LINT.ThenChange(//components/ip_protection/common/ip_protection_data_types.h:TryGetProbabilisticRevealTokensStatus) --> + +</enums> + +</histogram-configuration>
diff --git a/tools/metrics/histograms/metadata/ip_protection/histograms.xml b/tools/metrics/histograms/metadata/ip_protection/histograms.xml new file mode 100644 index 0000000..7a04b6d --- /dev/null +++ b/tools/metrics/histograms/metadata/ip_protection/histograms.xml
@@ -0,0 +1,774 @@ +<!-- +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 IpProtection 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> + +<histogram name="Net.HttpJob.IpProtection.AllowListMatch.BytesReceived2" + units="bytes" expires_after="2026-03-08"> + <owner>aakallam@chromium.org</owner> + <owner>ashleynewson@chromium.org</owner> + <owner>src/components/ip_protection/OWNERS</owner> + <summary> + Total bytes received over the network for an HttpJob request that would be + covered by IP Protection based on match with respect to the masked domain + list alone. This is irrespective of token and proxy availability. Any bypass + logic (e.g. first party to top level frame) will be considered, if set. + These bytes will be recorded even if `EnableIpPrivacyProxy` is `false`. This + is measured when the HttpJob is completed. + + There is no previous version of this metric. It is numbered to be in sync + with similar metrics. Unlike PrefilterBytesRead, this metric accounts for + all HTTP stream bytes (not just the content body), counts bytes for aborted + jobs, and network bytes in 304 Not Modified exchanges (rather than cached + content bodies). + </summary> +</histogram> + +<histogram name="Net.HttpJob.IpProtection.AllowListMatch.BytesSent2" + units="bytes" expires_after="2026-03-08"> + <owner>aakallam@chromium.org</owner> + <owner>ashleynewson@chromium.org</owner> + <owner>src/components/ip_protection/OWNERS</owner> + <summary> + Total bytes sent over the network for an HttpJob request that would be + covered by IP Protection based on match with respect to the masked domain + list alone. This is irrespective of token and proxy availability. Any bypass + logic (e.g. first party to top level frame) will be considered, if set. + These bytes will be recorded even if `EnableIpPrivacyProxy` is `false`. This + is measured when the HttpJob is completed. + + This version improves on BytesSent by counting bytes for aborted jobs and + network bytes in 304 Not Modified exchanges. + </summary> +</histogram> + +<histogram + name="Net.HttpJob.IpProtection.AllowListMatch.PrefilterBytesRead.Net" + units="bytes" expires_after="2026-01-07"> + <owner>aakallam@chromium.org</owner> + <owner>abhijithnair@chromium.org</owner> + <owner>ashleynewson@chromium.org</owner> + <owner>src/components/ip_protection/OWNERS</owner> + <summary> + Total prefilter (e.g., before decompression) bytes read for an HttpJob + request that would be covered by IP Protection and served from the network + based on match with respect to the masked domain list alone. This is + irrespective of token and proxy availability. Any bypass logic (e.g. first + party to top level frame) will be considered, if set. These bytes will be + recorded even if `EnableIpPrivacyProxy` is `false`. This is measured when + the HttpJob is completed. + </summary> +</histogram> + +<histogram name="Net.HttpJob.IpProtection.BytesSent" units="bytes" + expires_after="2026-03-08"> + <owner>aakallam@chromium.org</owner> + <owner>ashleynewson@chromium.org</owner> + <owner>src/components/ip_protection/OWNERS</owner> + <summary> + Total bytes sent over the network for an HttpJob request that is covered by + IP Protection. These bytes will be recorded even if the IP Protection proxy + is configured as `direct://` (i.e. an IP Protection proxy is configured but + doesn't actually proxy any traffic). + </summary> +</histogram> + +<histogram name="Net.HttpJob.IpProtection.BytesSent2" units="bytes" + expires_after="2026-06-21"> + <owner>dschinazi@chromium.org</owner> + <owner>src/components/ip_protection/OWNERS</owner> + <summary> + Total bytes sent over the network for an HttpJob request that is covered by + IP Protection. These bytes will be recorded even if the IP Protection proxy + is configured as `direct://` (i.e. an IP Protection proxy is configured but + doesn't actually proxy any traffic). It is also recorded if IP Protection + failed and we fell back to going direct. + </summary> +</histogram> + +<histogram name="Net.HttpJob.IpProtection.Fallback.BytesSent" units="bytes" + expires_after="2026-06-21"> + <owner>dschinazi@chromium.org</owner> + <owner>src/components/ip_protection/OWNERS</owner> + <summary> + Total bytes sent over the network for an HttpJob request that is covered by + IP Protection. These bytes will only be recorded if IP Protection failed and + we fell back to going direct. + </summary> +</histogram> + +<histogram name="Net.HttpJob.IpProtection.Fallback.PrefilterBytesRead.Net" + units="bytes" expires_after="2026-06-21"> + <owner>dschinazi@chromium.org</owner> + <owner>src/components/ip_protection/OWNERS</owner> + <summary> + Total prefilter (e.g., before decompression) bytes read for an HttpJob + request that is covered by IP Protection and served from the network. These + bytes will only be recorded if IP Protection failed and we fell back to + going direct. + </summary> +</histogram> + +<histogram name="Net.HttpJob.IpProtection.Fallback.TotalTimeNotCached2" + units="ms" expires_after="2026-06-21"> + <owner>dschinazi@chromium.org</owner> + <owner>src/components/ip_protection/OWNERS</owner> + <summary> + Time it takes to complete an HttpJob that attempted IP Protection, from + starting the transaction until we are done reading, for jobs not served from + the cache. This time is only recorded if IP Protection failed and we fell + back to going direct. + </summary> +</histogram> + +<histogram name="Net.HttpJob.IpProtection.JobResult" + enum="IpProtectionJobResult" expires_after="never"> +<!-- expires-never: This is used for dashboard metrics (internal: go/ipp-e2e-slos) --> + + <owner>dschinazi@chromium.org</owner> + <owner>src/components/ip_protection/OWNERS</owner> + <summary> + Result of a UrlRequestHttpJob with respect to IP Protection: not protected, + successfully protected, or fallback on protection failure. This does not + measure the result of the request to the destination, so for example a 500 + from the destination is still considered success. + + When either of the `MaskedDomainList` or `EnableIpPrivacyProxy` features are + disabled, this will always be `kProtectionNotAttempted`. + + This histogram is emitted for every request handled by `UrlRequestHttpJob` + that is not aborted. + </summary> +</histogram> + +<histogram name="Net.HttpJob.IpProtection.JobResult.{Chain}" + enum="IpProtectionJobResult" expires_after="2026-06-21"> + <owner>dschinazi@chromium.org</owner> + <owner>src/components/ip_protection/OWNERS</owner> + <summary> + Result of a UrlRequestHttpJob with respect to IP Protection: successfully + protected or fallback on protection failure. This is not logged when IP + Protection is not attempted. This does not measure the result of the request + to the destination, so for example a 500 from the destination is still + considered success. When either of the `MaskedDomainList` or + `EnableIpPrivacyProxy` features are disabled, this will not be logged. + </summary> + <token key="Chain"> + <variant name="Chain0"/> + <variant name="Chain1"/> + <variant name="Chain2"/> + <variant name="Chain3"/> + </token> +</histogram> + +<histogram name="Net.HttpJob.IpProtection.PrefilterBytesRead.Net" units="bytes" + expires_after="2026-03-08"> + <owner>aakallam@chromium.org</owner> + <owner>ashleynewson@chromium.org</owner> + <owner>src/components/ip_protection/OWNERS</owner> + <summary> + Total prefilter (e.g., before decompression) bytes read for an HttpJob + request that is covered by IP Protection and served from the network. These + bytes will be recorded even if the IP Protection proxy is configured as + `direct://` (i.e. an IP Protection proxy is configured but doesn't actually + proxy any traffic). + </summary> +</histogram> + +<histogram name="Net.HttpJob.IpProtection.PrefilterBytesRead.Net2" + units="bytes" expires_after="2026-06-21"> + <owner>dschinazi@chromium.org</owner> + <owner>src/components/ip_protection/OWNERS</owner> + <summary> + Total prefilter (e.g., before decompression) bytes read for an HttpJob + request that is covered by IP Protection and served from the network. These + bytes will be recorded even if the IP Protection proxy is configured as + `direct://` (i.e. an IP Protection proxy is configured but doesn't actually + proxy any traffic). It is also recorded if IP Protection failed and we fell + back to going direct. + </summary> +</histogram> + +<histogram name="Net.HttpJob.IpProtection.TotalTimeNotCached" units="ms" + expires_after="2026-06-21"> + <owner>dschinazi@chromium.org</owner> + <owner>ashleynewson@chromium.org</owner> + <owner>src/components/ip_protection/OWNERS</owner> + <summary> + Time it takes to complete an HttpJob that is covered by IP Protection, from + starting the transaction until we are done reading, for jobs not served from + the cache. This time will be recorded even if the IP Protection proxy is + configured as `direct://` (i.e. an IP Protection proxy is configured but + doesn't actually proxy any traffic). + </summary> +</histogram> + +<histogram name="Net.HttpJob.IpProtection.TotalTimeNotCached.{Chain}" + units="ms" expires_after="2026-06-21"> + <owner>dschinazi@chromium.org</owner> + <owner>ashleynewson@chromium.org</owner> + <owner>src/components/ip_protection/OWNERS</owner> + <summary> + Similar to Net.HttpJob.IpProtection.TotalTimeNotCached, but only chains with + the given chain_id, as provided in the GetProxyInfo RPC response. + </summary> + <token key="Chain"> + <variant name="Chain1"/> + <variant name="Chain2"/> + <variant name="Chain3"/> + </token> +</histogram> + +<histogram name="Net.HttpJob.IpProtection.TotalTimeNotCached3" units="ms" + expires_after="2026-06-21"> + <owner>dschinazi@chromium.org</owner> + <owner>src/components/ip_protection/OWNERS</owner> + <summary> + Time it takes to complete an HttpJob that attempted IP Protection, from + starting the transaction until we are done reading, for jobs not served from + the cache. This time will be recorded even if the IP Protection proxy is + configured as `direct://` (i.e. an IP Protection proxy is configured but + doesn't actually proxy any traffic). It is also recorded if IP Protection + failed and we fell back to going direct. + </summary> +</histogram> + +<histogram name="Net.IpProtection.CanFalloverToNextProxy2.Error.{Chain}" + enum="CombinedHttpResponseAndNetErrorCode" expires_after="2026-02-22"> + <owner>rsailer@chromium.org</owner> + <owner>src/components/ip_protection/OWNERS</owner> + <summary> + Records the error code passed to CanFalloverToNextProxy() for IP Protection + proxy chains. This function is called when a proxy fails, and the error code + is used to determine whether to try the next proxy in the chain or not. + </summary> + <token key="Chain"> + <variant name="Chain0"/> + <variant name="Chain1"/> + <variant name="Chain2"/> + <variant name="Chain3"/> + </token> +</histogram> + +<histogram name="NetworkService.IpProtection.EmptyTokenCache2" + enum="IpProtectionProxyLayer" expires_after="2026-03-08"> + <owner>awillia@chromium.org</owner> + <owner>ashleynewson@chromium.org</owner> + <owner>src/components/ip_protection/OWNERS</owner> + <summary> + Records which token cache (if any) was empty when calling + `IpProtectionConfigCache::AreAuthTokensAvailable()`. This metric is NOT + emitted if the cache has never been filled. + </summary> +</histogram> + +<histogram name="NetworkService.IpProtection.GeoChangeTokenPresence" + enum="BooleanAvailable" expires_after="2026-03-08"> + <owner>awillia@chromium.org</owner> + <owner>src/components/ip_protection/OWNERS</owner> + <summary> + This histogram is emitted to when changing to a new geo, and tracks whether + the token cache already contains tokens for the new geo. + + `IpProtectionConfigCache::SetCurrentGeo(geo_id)` is called when a geo is + observed in the `IpProtectionProxyListManager` or + `IpProtectionTokenCacheManager`. This metric is useful to help understand if + token caching by geo is useful in providing tokens for when a geo shifts + back to a previous geo that is contained within the cache. + + If the value is `Available`, it means that when the geo change was observed, + the token cache contained some number of tokens for the new geo from a + previous refill. + + If the value is `Not Available`, it means that the a new geo was observed, + but there was no tokens already in the cache that matched this new geo. + + This histogram will only be emitted if the MaskedDomainList and + EnableIpPrivacyProxy features are enabled and a platform-dependent sign-in + is complete. + </summary> +</histogram> + +<histogram name="NetworkService.IpProtection.GetAuthTokenResult" + enum="BooleanSuccess" expires_after="2026-03-08"> + <owner>awillia@chromium.org</owner> + <owner>ashleynewson@chromium.org</owner> + <owner>src/components/ip_protection/OWNERS</owner> + <summary> + The result of a call to `IpProtectionConfigCache::GetAuthToken()`, which + will not happen unless `IpProtectionConfigCache::AreAuthTokensAvailable()` + is true. If this fails, it is because the cache was empty when a new + connection to a proxy was initiated. + </summary> +</histogram> + +<histogram name="NetworkService.IpProtection.GetAuthTokenResultForGeo" + enum="IpProtectionGetAuthTokenResultForGeo" expires_after="2026-01-07"> + <owner>awillia@chromium.org</owner> + <owner>src/components/ip_protection/OWNERS</owner> + <summary> + This metric tracks the effectiveness of token caching in IpProtection, + especially during network transitions or non-ideal conditions. It records + the outcome of `IpProtectionConfigCache::GetAuthToken()` requests, focusing + on token availability and its alignment with the current or a previously + cached geographical location. The four possible outcomes indicate successful + token retrieval (for current or other geo), or unavailability with or + without other cached tokens. This metric is only measured when geo caching + is enabled. + + This histogram will only be emitted if the MaskedDomainList and + EnableIpPrivacyProxy features are enabled as well as the feature parameter, + IpPrivacyCacheTokensByGeo. Some kind of platform-dependent signin is also + required. + </summary> +</histogram> + +<histogram + name="NetworkService.IpProtection.GetProbabilisticRevealTokensResult" + enum="ProbabilisticRevealTokensResult" expires_after="2026-03-08"> + <owner>ryankalla@google.com</owner> + <owner>kiln-eng@google.com</owner> + <owner>src/components/ip_protection/OWNERS</owner> + <summary> + The result of a call to `IpProtectionProbabilisticRevealTokenFetcher:: + TryGetProbabilisticRevealTokens()`. + </summary> +</histogram> + +<histogram name="NetworkService.IpProtection.GetProxyListResult" + enum="IpProtectionGetProxyListResult" expires_after="2026-03-08"> + <owner>awillia@chromium.org</owner> + <owner>ashleynewson@chromium.org</owner> + <owner>src/components/ip_protection/OWNERS</owner> + <summary> + Whether a call to `IpProtectionConfigCache::GetProxyList()` resulted in + obtaining a proxy list. This is measured in + `IpProtectionProxyListManagerImpl::OnGotProxyList`. + + If a proxy list was obtained, this histogram also records whether it had at + least one valid entry. (It is possible to obtain an empty list from the + server, or the list from the server could contain only invalid entries that + are rejected by the client.) + + This histogram will only be emitted if the MaskedDomainList and + EnableIpPrivacyProxy features are enabled. Some kind of platform-dependent + signin is also required. + </summary> +</histogram> + +<histogram + name="NetworkService.IpProtection.IsProbabilisticRevealTokenAvailableOnInitialRequest" + enum="BooleanSuccess" expires_after="2026-03-08"> + <owner>ryankalla@google.com</owner> + <owner>kiln-eng@google.com</owner> + <owner>src/components/ip_protection/OWNERS</owner> + <summary> + The result of a call to + `IpProtectionProbabilisticRevealTokenManager::IsTokenAvailable()` when + `IpProtectionProbabilisticRevealTokenManager::GetToken()` is determining if + the token cache contains any non-expired tokens. If this fails, the request + will not include a probabilistic reveal token. + + This histogram is only emitted the first time `GetToken()` is called after + the PRT manager is constructed. + </summary> +</histogram> + +<histogram + name="NetworkService.IpProtection.IsProbabilisticRevealTokenAvailableOnSubsequentRequest" + enum="BooleanSuccess" expires_after="2026-03-08"> + <owner>ryankalla@google.com</owner> + <owner>kiln-eng@google.com</owner> + <owner>src/components/ip_protection/OWNERS</owner> + <summary> + The result of a call to + `IpProtectionProbabilisticRevealTokenManager::IsTokenAvailable()` when + `IpProtectionProbabilisticRevealTokenManager::GetToken()` is determining if + the token cache contains any non-expired tokens. If this fails, the request + will not include a probabilistic reveal token. + + This histogram is not emitted the first time `GetToken()` is called after + the PRT manager is constructed, but is emitted on all subsequent calls. + </summary> +</histogram> + +<histogram name="NetworkService.IpProtection.OAuthTokenFetchTime" units="ms" + expires_after="2026-03-08"> + <owner>awillia@chromium.org</owner> + <owner>src/components/ip_protection/OWNERS</owner> + <summary> + Records the elapsed time for successful requests by IpProtectionConfigGetter + for an OAuth token. + </summary> +</histogram> + +<histogram + name="NetworkService.IpProtection.ProbabilisticRevealTokenRandomizationTime" + units="ms" expires_after="2026-03-08"> + <owner>ryankalla@google.com</owner> + <owner>kiln-eng@google.com</owner> + <owner>src/components/ip_protection/OWNERS</owner> + <summary> + Records the elapsed time for successfully re-randomizing a probabilistic + reveal token. + </summary> +</histogram> + +<histogram + name="NetworkService.IpProtection.ProbabilisticRevealTokensRequestTime" + units="ms" expires_after="2026-03-08"> + <owner>ryankalla@google.com</owner> + <owner>kiln-eng@google.com</owner> + <owner>src/components/ip_protection/OWNERS</owner> + <summary> + Records the elapsed time for successful requests by + IpProtectionProbabilisticRevealTokenFetcher for a batch of probabilistic + reveal tokens. This represents the total time taken from the moment we call + the TokenFetcher until PRTs are available in the browser. This includes the + IPC between the browser and the network service, the network request itself + (including any scheduling/queuing delay), and the token validation checks. + </summary> +</histogram> + +<histogram + name="NetworkService.IpProtection.ProxyAllowList.FlatbufferBuildTime" + units="ms" expires_after="2026-03-08"> + <owner>aakallam@chromium.org</owner> + <owner>src/components/ip_protection/OWNERS</owner> + <summary> + Records the time it takes to build the MaskedDomainList flatbuffer data + structure. This is recorded once for each successful call to + `BuildFromProto`. + </summary> +</histogram> + +<histogram name="NetworkService.IpProtection.ProxyAllowList.UpdateSuccess" + enum="BooleanSuccess" expires_after="2026-03-08"> + <owner>aakallam@chromium.org</owner> + <owner>abhijithnair@chromium.org</owner> + <owner>src/components/ip_protection/OWNERS</owner> + <summary> + Records the result of an attempt to update the MaskedDomainListManager with + the contents of the Masked Domain List when it is received from Component + Updater. + </summary> +</histogram> + +<histogram name="NetworkService.IpProtection.ProxyChainFallback" + enum="IpProtectionProxyChainId" expires_after="2026-03-08"> + <owner>awillia@chromium.org</owner> + <owner>ashleynewson@chromium.org</owner> + <owner>src/components/ip_protection/OWNERS</owner> + <summary> + Logged when a proxy chain failure is detected in the proxy delegate's + `OnFallback` method, with values defined by the `chain_id` value given in + the GetProxyInfo RPC response. + </summary> +</histogram> + +<histogram name="NetworkService.IpProtection.ProxyListRefreshTime" units="ms" + expires_after="2026-01-07"> + <owner>awillia@chromium.org</owner> + <owner>ashleynewson@chromium.org</owner> + <owner>src/components/ip_protection/OWNERS</owner> + <summary> + Time taken to successfully refresh the IP Protection proxy list, measured + from IpProtectionProxyListManagerImpl::RefreshProxyList to + IpProtectionProxyListManagerImpl::OnGotProxyList. + + A successful refresh is anything where OnGotProxyList receives a non-nullopt + proxy_list, which may include cases where an empty proxy list or a proxy + list with only unsuitable entries was fetched over the network. Outright + failures and refreshes which were inhibited due to client-side rate limiting + will not be measured. + + This histogram will only be emitted if the MaskedDomainList and + EnableIpPrivacyProxy features are enabled. Some kind of platform-dependent + signin is also required. + </summary> +</histogram> + +<histogram name="NetworkService.IpProtection.ProxyResolution" + enum="IpProtectionProxyResolutionResult" expires_after="never"> +<!-- expires-never: This is used for dashboard metrics (internal: go/ipp-e2e-slos) --> + + <owner>awillia@chromium.org</owner> + <owner>src/components/ip_protection/OWNERS</owner> + <summary> + The result of determining whether a request should be proxied (as + implemented in IpProtectionProxyDelegate::ClassifyRequest). The enum values + are in the order the checks occur, so for example, if the MaskedDomainList + feature is disabled, "The MDL is not populated" value will be + emitted because that is checked first. If that feature is enabled and the + request does not match the MDL, then the "The request did not match the + MDL" value will be recorded. "The IP Protection setting is + disabled" value will be recorded if the feature is enabled and the + request matched the MDL, but IP Protection was disabled via user settings or + enterprise policy, and so on. + + This histogram is emitted for every request that undergoes proxy resolution. + </summary> +</histogram> + +<histogram name="NetworkService.IpProtection.QuicProxiesFailed" + units="requests" expires_after="2026-03-08"> + <owner>awillia@chromium.org</owner> + <owner>src/components/ip_protection/OWNERS</owner> + <summary> + Recorded when a connection to a QUIC proxy for IP Protection failed and the + HTTPS fallback succeeds, recording the number of requests begun before this + failure occurred. In this situation, Chrome falls back to exclusively HTTPS + proxies until the network changes, so this metric provides a way to + determine what proportion of clients are experiencing this failure, and how + quickly they experience the failure. Note that the metric counts requests + *begun*, so this value may be greater than one even if the first request + fails. This metric is not recorded for clients not configured to use QUIC to + connect to IP Protection proxies. + </summary> +</histogram> + +<histogram name="NetworkService.IpProtection.TokenBatchGenerationTime" + units="ms" expires_after="2026-03-08"> + <owner>awillia@chromium.org</owner> + <owner>ashleynewson@chromium.org</owner> + <owner>src/components/ip_protection/OWNERS</owner> + <summary> + Records the time taken for a successful attempt to generate auth tokens. + This only measures the time across a single attempt (not across retries, + which may be delayed by a variable backoff). + + This measures the whole token batch generation process, from an + IpProtectionTokenCacheManagerImpl's perspective, from just before calling + IpProtectionConfigGetter::TryGetAuthTokens until OnGotAuthTokens. Note that + if OnGotAuthTokens receives a non-nullopt but empty vector of tokens this is + considered a success by this metric. + + Note that if multiple token caches exist (one for each proxy layer), the + attempts in each token cache are timed independently, but they will all feed + into the same histogram. + + This histogram will only be emitted if the MaskedDomainList and + EnableIpPrivacyProxy features are enabled. Some kind of platform-dependent + signin is also required. + </summary> +</histogram> + +<histogram + name="NetworkService.IpProtection.TokenBatchGenerationTime.{BlindSignAuthPhase}" + units="ms" expires_after="2026-01-07"> + <owner>jtoohill@google.com</owner> + <owner>src/components/ip_protection/OWNERS</owner> + <summary> + Records the time taken for the {BlindSignAuthPhase} step of generating auth + tokens. This only measures the time across a single attempt (not across + retries, which may be delayed by a variable backoff). + + Note that if multiple token caches exist (one for each proxy layer), the + attempts in each token cache are timed independently, but they will all feed + into the same histogram. + + This histogram will be emitted during a GetTokens call into the BSA library, + which is only called if the MaskedDomainList and EnableIpPrivacyProxy + features are enabled. Some kind of platform-dependent signin is also + required. + </summary> +<!-- LINT.IfChange(BlindSignAuthPhase) --> + + <token key="BlindSignAuthPhase"> + <variant name="AuthAndSign"/> + <variant name="GenerateBlindedTokenRequests"/> + <variant name="GetInitialData"/> + <variant name="UnblindTokens"/> + </token> +<!-- LINT.ThenChange(/components/ip_protection/common/ip_protection_telemetry.h:BlindSignAuthPhase) --> + +</histogram> + +<histogram name="NetworkService.IpProtection.TokenBatchRequestTime" units="ms" + expires_after="2026-03-08"> + <owner>awillia@chromium.org</owner> + <owner>src/components/ip_protection/OWNERS</owner> + <summary> + Records the elapsed time for successful requests by IpProtectionConfigGetter + for blind-signed tokens from BSA. + + This metric only measures part of the Chrome-specific blind-signing + implementation and does not encompass the full token batch generation + process. See NetworkService.IpProtection.TokenBatchGenerationTime for a + generic measurement of the full token batch generation process. + </summary> +</histogram> + +<histogram name="NetworkService.IpProtection.TokenDemandDuringBatchGeneration" + units="tokens" expires_after="2026-01-07"> + <owner>jtoohill@google.com</owner> + <owner>awillia@chromium.org</owner> + <owner>src/components/ip_protection/OWNERS</owner> + <summary> + An upper bound on the number of tokens that might have been spent while a + call to TryGetAuthTokens was in flight. This includes both tokens that were + successfully spent from the cache, and requests that were not proxied + because the cache was empty. Emitted when TryGetAuthTokens finishes. + </summary> +</histogram> + +<histogram name="NetworkService.IpProtection.TryGetAuthTokensErrors" + enum="IpProtectionTokenBatchRequestError" expires_after="2026-03-08"> + <owner>linxinan@chromium.org</owner> + <owner>src/components/ip_protection/OWNERS</owner> + <summary> + This histogram is emitted when any error returned by GetTokens call into the + BSA library. The error message is hashed into unsigned 32 bit integer. For + more information on the possible errors from BSA see + https://docs.google.com/document/d/1zv3AqLkALZGsvCKYd1M3UytNpyY0ecK55LdsioubmC4. + </summary> +</histogram> + +<histogram name="NetworkService.IpProtection.TryGetAuthTokensResult2" + enum="IpProtectionTokenBatchRequestResult" expires_after="2026-03-22"> + <owner>awillia@chromium.org</owner> + <owner>src/components/ip_protection/OWNERS</owner> + <summary> + The result of handling a request by the network process to the browser + process for a batch of blind-signed auth tokens. + </summary> +</histogram> + +<histogram name="NetworkService.IpProtection.{ProxyLayer}.TokenCount.{Event}" + units="tokens" expires_after="2026-03-22"> + <owner>awillia@chromium.org</owner> + <owner>src/components/ip_protection/OWNERS</owner> + <summary> + Records the number of IP Protection auth tokens involved in a specific event + for {ProxyLayer}. The histogram indicates that {Event}. Recorded when tokens + are successfully issued, spent, expired, or orphaned. Expected counts are + typically 1 for Spent, and potentially higher for other events (up to batch + size or cache size). + </summary> + <token key="ProxyLayer"> + <variant name="ProxyA"/> + <variant name="ProxyB"/> + </token> + <token key="Event"> + <variant name="Expired" summary="Token removed from cache due to expiry."/> + <variant name="Issued" summary="Tokens successfully fetched and cached."/> + <variant name="Orphaned" + summary="Tokens discarded (neither spent nor expired) on network + context destruction."/> + <variant name="Recycled" + summary="Previously orphaned tokens added to the cache"/> + <variant name="Spent" summary="Token used for a proxy connection."/> + </token> +</histogram> + +<histogram name="NetworkService.IpProtection.{ProxyLayer}.TokenExpirationRate" + units="tokens" expires_after="2026-03-08"> + <owner>awillia@chromium.org</owner> + <owner>ashleynewson@chromium.org</owner> + <owner>src/components/ip_protection/OWNERS</owner> + <summary> + Number of auth tokens for {ProxyLayer} that expired before they were used, + as a rate per hour, up to 100,000. This value is measured approximately + every 5 minutes. + </summary> + <token key="ProxyLayer"> + <variant name="ProxyA"/> + <variant name="ProxyB"/> + </token> +</histogram> + +<histogram name="NetworkService.MaskedDomainList.DiskUsage" units="KB" + expires_after="2026-03-15"> + <owner>djmitche@chromium.org</owner> + <owner>src/components/ip_protection/OWNERS</owner> + <summary> + Records the on-disk size of each MDL, when stored on disk (in the flatbuffer + format). A single execution of the browser may generate multiple MDLs, such + as for multiple experiments; each of these will be a distinct record. This + record is emitted when the flatbuffer MDL is generated. The generated + flatbuffer MDL may be cached and reused for multiple network service + instances, or may be re-generated for each one. + </summary> +</histogram> + +<histogram name="NetworkService.MaskedDomainList.EstimatedMemoryUsage" + units="KB" expires_after="2025-12-14"> + <owner>aakallam@chromium.org</owner> + <owner>src/components/ip_protection/OWNERS</owner> + <summary> + Records the estimated memory usage of the MaskedDomainListManager every time + the Masked Domain List is updated. + </summary> +</histogram> + +<histogram name="NetworkService.MaskedDomainList.FirstUpdateTime" units="ms" + expires_after="2026-01-11"> + <owner>aakallam@chromium.org</owner> + <owner>ashleynewson@chromium.org</owner> + <owner>src/components/ip_protection/OWNERS</owner> + <summary> + Delay between a MaskedDomainListManager being constructed and its + UpdateMaskedDomainList method first being called (measured on entry). + + This effectively measures the duration for which the MDL is not populated + and thus requests' eligibilities for IP Protection remain unknown. + + This histogram is only emitted when the MaskedDomainList feature is enabled. + The histogram will not be emitted if the MDL never becomes available. It is + emitted at most once per Network Service startup. + + This histogram can easily overflow its maximum (10 second) bucket if the + component that stores the MDL data is not already available on disk. This + histogram is primarily focused on the (more typical) case where such data is + already available. + </summary> +</histogram> + +<histogram name="NetworkService.MaskedDomainList.MatchesTime" + units="microseconds" expires_after="2026-03-22"> + <owner>djmitche@chromium.org</owner> + <owner>src/components/ip_protection/OWNERS</owner> + <summary> + Records the time required to call the `Matches` method on the MDL. This is a + sync call that accesses a large data structure so it may require additional + optimization. + + Note that clients without high-resolution clocks will report 0 for very + short times. + </summary> +</histogram> + +<histogram name="NetworkService.MaskedDomainList.Size2" units="KB" + expires_after="2026-02-22"> + <owner>aakallam@chromium.org</owner> + <owner>src/components/ip_protection/OWNERS</owner> + <summary> + Record the size of the Masked Domain List proto in KB. Emitted when the raw + proto bytes are received from Component Updater and parsed. The previous + version of this histogram sometimes recorded the value in MB and was not + usable. + </summary> +</histogram> + +</histograms> + +</histogram-configuration>
diff --git a/tools/metrics/histograms/metadata/net/enums.xml b/tools/metrics/histograms/metadata/net/enums.xml index 5b05c501..6d58fa59 100644 --- a/tools/metrics/histograms/metadata/net/enums.xml +++ b/tools/metrics/histograms/metadata/net/enums.xml
@@ -655,14 +655,6 @@ <int value="3" label="3G"/> </enum> -<enum name="IpProtectionJobResult"> - <int value="0" label="IP Protection was not attempted"/> - <int value="1" - label="The request was IP Protected and carried via IP Protection - proxies or, if the direct-only parameter is true, made directly"/> - <int value="2" label="The request was IP Protected, but fell back to direct"/> -</enum> - <enum name="JobProtocolErrorLocation"> <int value="0" label="kSessionStartReadingFailedAsync"/> <int value="1" label="kSessionStartReadingFailedSync"/> @@ -2998,6 +2990,19 @@ <!-- LINT.ThenChange(//net/disk_cache/sql/sql_backend_impl.h:FakeIndexFileError) --> +<!-- LINT.IfChange(SqlDiskCacheIndexMismatchLocation) --> + +<enum name="SqlDiskCacheIndexMismatchLocation"> + <int value="0" label="OpenOrCreateEntry"/> + <int value="1" label="CreateEntry"/> + <int value="2" label="DoomEntry"/> + <int value="3" label="StartEviction"/> + <int value="4" label="DeleteLiveEntry"/> + <int value="5" label="DeleteLiveEntriesBetween"/> +</enum> + +<!-- LINT.ThenChange(//net/disk_cache/sql/sql_persistent_store.cc:IndexMismatchLocation) --> + <!-- LINT.IfChange(SqlDiskCacheStoreError) --> <enum name="SqlDiskCacheStoreError"> @@ -3017,6 +3022,7 @@ <int value="13" label="NotFound"/> <int value="14" label="InvalidArgument"/> <int value="15" label="BodyEndMismatch"/> + <int value="16" label="FailedForTesting"/> </enum> <!-- LINT.ThenChange(//net/disk_cache/sql/sql_persistent_store.h:SqlDiskCacheStoreError) -->
diff --git a/tools/metrics/histograms/metadata/net/histograms.xml b/tools/metrics/histograms/metadata/net/histograms.xml index 8d0eea81..b9ae865 100644 --- a/tools/metrics/histograms/metadata/net/histograms.xml +++ b/tools/metrics/histograms/metadata/net/histograms.xml
@@ -3036,236 +3036,6 @@ </summary> </histogram> -<histogram name="Net.HttpJob.IpProtection.AllowListMatch.BytesReceived2" - units="bytes" expires_after="2026-03-08"> - <owner>aakallam@chromium.org</owner> - <owner>ashleynewson@chromium.org</owner> - <owner>src/components/ip_protection/OWNERS</owner> - <summary> - Total bytes received over the network for an HttpJob request that would be - covered by IP Protection based on match with respect to the masked domain - list alone. This is irrespective of token and proxy availability. Any bypass - logic (e.g. first party to top level frame) will be considered, if set. - These bytes will be recorded even if `EnableIpPrivacyProxy` is `false`. This - is measured when the HttpJob is completed. - - There is no previous version of this metric. It is numbered to be in sync - with similar metrics. Unlike PrefilterBytesRead, this metric accounts for - all HTTP stream bytes (not just the content body), counts bytes for aborted - jobs, and network bytes in 304 Not Modified exchanges (rather than cached - content bodies). - </summary> -</histogram> - -<histogram name="Net.HttpJob.IpProtection.AllowListMatch.BytesSent2" - units="bytes" expires_after="2026-03-08"> - <owner>aakallam@chromium.org</owner> - <owner>ashleynewson@chromium.org</owner> - <owner>src/components/ip_protection/OWNERS</owner> - <summary> - Total bytes sent over the network for an HttpJob request that would be - covered by IP Protection based on match with respect to the masked domain - list alone. This is irrespective of token and proxy availability. Any bypass - logic (e.g. first party to top level frame) will be considered, if set. - These bytes will be recorded even if `EnableIpPrivacyProxy` is `false`. This - is measured when the HttpJob is completed. - - This version improves on BytesSent by counting bytes for aborted jobs and - network bytes in 304 Not Modified exchanges. - </summary> -</histogram> - -<histogram - name="Net.HttpJob.IpProtection.AllowListMatch.PrefilterBytesRead.Net" - units="bytes" expires_after="2026-01-07"> - <owner>aakallam@chromium.org</owner> - <owner>abhijithnair@chromium.org</owner> - <owner>ashleynewson@chromium.org</owner> - <owner>src/components/ip_protection/OWNERS</owner> - <summary> - Total prefilter (e.g., before decompression) bytes read for an HttpJob - request that would be covered by IP Protection and served from the network - based on match with respect to the masked domain list alone. This is - irrespective of token and proxy availability. Any bypass logic (e.g. first - party to top level frame) will be considered, if set. These bytes will be - recorded even if `EnableIpPrivacyProxy` is `false`. This is measured when - the HttpJob is completed. - </summary> -</histogram> - -<histogram name="Net.HttpJob.IpProtection.BytesSent" units="bytes" - expires_after="2026-03-08"> - <owner>aakallam@chromium.org</owner> - <owner>ashleynewson@chromium.org</owner> - <owner>src/components/ip_protection/OWNERS</owner> - <summary> - Total bytes sent over the network for an HttpJob request that is covered by - IP Protection. These bytes will be recorded even if the IP Protection proxy - is configured as `direct://` (i.e. an IP Protection proxy is configured but - doesn't actually proxy any traffic). - </summary> -</histogram> - -<histogram name="Net.HttpJob.IpProtection.BytesSent2" units="bytes" - expires_after="2026-06-21"> - <owner>dschinazi@chromium.org</owner> - <owner>src/components/ip_protection/OWNERS</owner> - <summary> - Total bytes sent over the network for an HttpJob request that is covered by - IP Protection. These bytes will be recorded even if the IP Protection proxy - is configured as `direct://` (i.e. an IP Protection proxy is configured but - doesn't actually proxy any traffic). It is also recorded if IP Protection - failed and we fell back to going direct. - </summary> -</histogram> - -<histogram name="Net.HttpJob.IpProtection.Fallback.BytesSent" units="bytes" - expires_after="2026-06-21"> - <owner>dschinazi@chromium.org</owner> - <owner>src/components/ip_protection/OWNERS</owner> - <summary> - Total bytes sent over the network for an HttpJob request that is covered by - IP Protection. These bytes will only be recorded if IP Protection failed and - we fell back to going direct. - </summary> -</histogram> - -<histogram name="Net.HttpJob.IpProtection.Fallback.PrefilterBytesRead.Net" - units="bytes" expires_after="2026-06-21"> - <owner>dschinazi@chromium.org</owner> - <owner>src/components/ip_protection/OWNERS</owner> - <summary> - Total prefilter (e.g., before decompression) bytes read for an HttpJob - request that is covered by IP Protection and served from the network. These - bytes will only be recorded if IP Protection failed and we fell back to - going direct. - </summary> -</histogram> - -<histogram name="Net.HttpJob.IpProtection.Fallback.TotalTimeNotCached2" - units="ms" expires_after="2026-06-21"> - <owner>dschinazi@chromium.org</owner> - <owner>src/components/ip_protection/OWNERS</owner> - <summary> - Time it takes to complete an HttpJob that attempted IP Protection, from - starting the transaction until we are done reading, for jobs not served from - the cache. This time is only recorded if IP Protection failed and we fell - back to going direct. - </summary> -</histogram> - -<histogram name="Net.HttpJob.IpProtection.JobResult" - enum="IpProtectionJobResult" expires_after="never"> -<!-- expires-never: This is used for dashboard metrics (internal: go/ipp-e2e-slos) --> - - <owner>dschinazi@chromium.org</owner> - <owner>src/components/ip_protection/OWNERS</owner> - <summary> - Result of a UrlRequestHttpJob with respect to IP Protection: not protected, - successfully protected, or fallback on protection failure. This does not - measure the result of the request to the destination, so for example a 500 - from the destination is still considered success. - - When either of the `MaskedDomainList` or `EnableIpPrivacyProxy` features are - disabled, this will always be `kProtectionNotAttempted`. - - This histogram is emitted for every request handled by `UrlRequestHttpJob` - that is not aborted. - </summary> -</histogram> - -<histogram name="Net.HttpJob.IpProtection.JobResult.{Chain}" - enum="IpProtectionJobResult" expires_after="2026-06-21"> - <owner>dschinazi@chromium.org</owner> - <owner>src/components/ip_protection/OWNERS</owner> - <summary> - Result of a UrlRequestHttpJob with respect to IP Protection: successfully - protected or fallback on protection failure. This is not logged when IP - Protection is not attempted. This does not measure the result of the request - to the destination, so for example a 500 from the destination is still - considered success. When either of the `MaskedDomainList` or - `EnableIpPrivacyProxy` features are disabled, this will not be logged. - </summary> - <token key="Chain"> - <variant name="Chain0"/> - <variant name="Chain1"/> - <variant name="Chain2"/> - <variant name="Chain3"/> - </token> -</histogram> - -<histogram name="Net.HttpJob.IpProtection.PrefilterBytesRead.Net" units="bytes" - expires_after="2026-03-08"> - <owner>aakallam@chromium.org</owner> - <owner>ashleynewson@chromium.org</owner> - <owner>src/components/ip_protection/OWNERS</owner> - <summary> - Total prefilter (e.g., before decompression) bytes read for an HttpJob - request that is covered by IP Protection and served from the network. These - bytes will be recorded even if the IP Protection proxy is configured as - `direct://` (i.e. an IP Protection proxy is configured but doesn't actually - proxy any traffic). - </summary> -</histogram> - -<histogram name="Net.HttpJob.IpProtection.PrefilterBytesRead.Net2" - units="bytes" expires_after="2026-06-21"> - <owner>dschinazi@chromium.org</owner> - <owner>src/components/ip_protection/OWNERS</owner> - <summary> - Total prefilter (e.g., before decompression) bytes read for an HttpJob - request that is covered by IP Protection and served from the network. These - bytes will be recorded even if the IP Protection proxy is configured as - `direct://` (i.e. an IP Protection proxy is configured but doesn't actually - proxy any traffic). It is also recorded if IP Protection failed and we fell - back to going direct. - </summary> -</histogram> - -<histogram name="Net.HttpJob.IpProtection.TotalTimeNotCached" units="ms" - expires_after="2026-06-21"> - <owner>dschinazi@chromium.org</owner> - <owner>ashleynewson@chromium.org</owner> - <owner>src/components/ip_protection/OWNERS</owner> - <summary> - Time it takes to complete an HttpJob that is covered by IP Protection, from - starting the transaction until we are done reading, for jobs not served from - the cache. This time will be recorded even if the IP Protection proxy is - configured as `direct://` (i.e. an IP Protection proxy is configured but - doesn't actually proxy any traffic). - </summary> -</histogram> - -<histogram name="Net.HttpJob.IpProtection.TotalTimeNotCached.{Chain}" - units="ms" expires_after="2026-06-21"> - <owner>dschinazi@chromium.org</owner> - <owner>ashleynewson@chromium.org</owner> - <owner>src/components/ip_protection/OWNERS</owner> - <summary> - Similar to Net.HttpJob.IpProtection.TotalTimeNotCached, but only chains with - the given chain_id, as provided in the GetProxyInfo RPC response. - </summary> - <token key="Chain"> - <variant name="Chain1"/> - <variant name="Chain2"/> - <variant name="Chain3"/> - </token> -</histogram> - -<histogram name="Net.HttpJob.IpProtection.TotalTimeNotCached3" units="ms" - expires_after="2026-06-21"> - <owner>dschinazi@chromium.org</owner> - <owner>src/components/ip_protection/OWNERS</owner> - <summary> - Time it takes to complete an HttpJob that attempted IP Protection, from - starting the transaction until we are done reading, for jobs not served from - the cache. This time will be recorded even if the IP Protection proxy is - configured as `direct://` (i.e. an IP Protection proxy is configured but - doesn't actually proxy any traffic). It is also recorded if IP Protection - failed and we fell back to going direct. - </summary> -</histogram> - <histogram name="Net.HttpJob.MainJobWaitTimeWithAvailableSpdySession" units="ms" expires_after="2026-02-22"> <owner>fayang@chromium.org</owner> @@ -3794,23 +3564,6 @@ </token> </histogram> -<histogram name="Net.IpProtection.CanFalloverToNextProxy2.Error.{Chain}" - enum="CombinedHttpResponseAndNetErrorCode" expires_after="2026-02-22"> - <owner>rsailer@chromium.org</owner> - <owner>src/components/ip_protection/OWNERS</owner> - <summary> - Records the error code passed to CanFalloverToNextProxy() for IP Protection - proxy chains. This function is called when a proxy fails, and the error code - is used to determine whether to try the next proxy in the chain or not. - </summary> - <token key="Chain"> - <variant name="Chain0"/> - <variant name="Chain1"/> - <variant name="Chain2"/> - <variant name="Chain3"/> - </token> -</histogram> - <histogram name="Net.MultiThreadedCertVerifier.RequestDuration{HostType}" units="ms" expires_after="2026-03-01"> <owner>nidhijaju@chromium.org</owner> @@ -7716,6 +7469,30 @@ </summary> </histogram> +<histogram name="Net.SqlDiskCache.Backend.IndexMismatch" + enum="SqlDiskCacheIndexMismatchLocation" expires_after="2026-03-22"> + <owner>horo@chromium.org</owner> + <owner>src/net/OWNERS</owner> + <summary> + Records the location where an in-memory index mismatch is detected in the + SQL-based disk cache. This helps identify the operations that are most prone + to causing inconsistencies between the in-memory index and the on-disk + database. + </summary> +</histogram> + +<histogram name="Net.SqlDiskCache.Backend.LoadInMemoryIndexTime" + units="microseconds" expires_after="2025-12-09"> + <owner>horo@chromium.org</owner> + <owner>src/net/OWNERS</owner> + <summary> + Measures the time taken to load the in memory index of the SQL-based disk + cache backend. This metric is recorded immediately after the in-memory index + is loaded from the database. The histogram is not reported on Windows + machines without high resolution clocks. + </summary> +</histogram> + <histogram name="Net.SqlDiskCache.Backend.MaxSize" units="MB" expires_after="2026-03-22"> <owner>horo@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/network/enums.xml b/tools/metrics/histograms/metadata/network/enums.xml index c76dc71..d65aed6 100644 --- a/tools/metrics/histograms/metadata/network/enums.xml +++ b/tools/metrics/histograms/metadata/network/enums.xml
@@ -635,208 +635,6 @@ <int value="5" label="kInstallationFailed"/> </enum> -<enum name="IpProtectionEligibility"> - <int value="0" label="Unknown"/> - <int value="1" label="Ineligible"/> - <int value="2" label="Eligible"/> -</enum> - -<!-- LINT.IfChange(IpProtectionGetAuthTokenResultForGeo) --> - -<enum name="IpProtectionGetAuthTokenResultForGeo"> - <int value="0" label="Auth token unavailable and cache is empty"/> - <int value="1" label="Auth token unavailable but cache contains tokens"/> - <int value="2" label="Auth token available for current geo"/> - <int value="3" label="Auth token available for other geo"/> -</enum> - -<!-- LINT.ThenChange(//services/network/ip_protection/ip_protection_token_cache_manager_impl.h:AuthTokenResultForGeo) --> - -<enum name="IpProtectionGetProxyListResult"> - <int value="0" label="Failed to acquire a list"/> - <int value="1" label="Got a list without any valid entries"/> - <int value="2" label="Got a list with at least one valid entry"/> -</enum> - -<enum name="IpProtectionProxyChainId"> - <int value="0" label="Unknown"/> - <int value="1" label="Chain 1"/> - <int value="2" label="Chain 2"/> - <int value="3" label="Chain 3"/> -</enum> - -<enum name="IpProtectionProxyLayer"> - <int value="0" label="Proxy A"/> - <int value="1" label="Proxy B"/> -</enum> - -<enum name="IpProtectionProxyResolutionResult"> - <int value="0" - label="The MDL is not populated, so an eligility decision could not be - made"/> - <int value="1" label="The request did not match the MDL"/> - <int value="2" - label="DEPRECATED: The EnableIpProtectionProxy feature is not enabled"/> - <int value="3" label="The IP Protection setting is disabled"/> - <int value="4" label="Proxy List is unavailable"/> - <int value="5" - label="Proxy List is available but tokens have never been available"/> - <int value="6" - label="Proxy List is available but tokens in the cache have been - exhausted"/> - <int value="7" label="The request was resolved to the IP Protection proxies"/> - <int value="8" - label="A site exception created by User Bypass disables protections"/> - <int value="9" - label="The request bypassed the IP Protection proxies through DevTools"/> -</enum> - -<enum name="IpProtectionTokenBatchRequestError"> -<!-- The following errors are omitted because they have many possible suffixes: - "Failed to create RSA public key: <error>" - "Failed to decode extensions: <error>" - "Failed to validate extensions: <error>" - "Failed to parse expiration timestamp: <error>" - "Failed to parse geo hint: <error>" - "Failed to parse use case: <error>" - "Failed to create Privacy Pass client: <error>" - "Failed to create ExtendedTokenRequest: <error>" - - Additionally, errors marked [DEPRECATED] are no longer emitted as of M141 (crrev.com/c/6865774). - --> - - <int value="4948469" label="AuthAndSign failed: 404 (NOT_FOUND)"/> - <int value="149981085" label="GetInitialData failed: 401 (UNAUTHENTICATED)"/> - <int value="150736087" label="GetInitialData failed: 499 (CANCELLED)"/> - <int value="159430335" - label="[DEPRECATED] GetInitialDataRequest failed: 499 (CANCELLED)"/> - <int value="203200113" label="AuthAndSign failed: 409 (ABORTED)"/> - <int value="219311180" label="AuthAndSign failed: invalid response"/> - <int value="247849994" label="GetInitialData failed: 501 (UNIMPLEMENTED)"/> - <int value="774920404" - label="[DEPRECATED] GetInitialDataRequest failed: 5xx (INTERNAL)"/> - <int value="776650315" - label="GetInitialData failed: 4xx (FAILED_PRECONDITION)"/> - <int value="788650824" - label="[DEPRECATED] GetInitialDataRequest failed: 409 (ABORTED)"/> - <int value="882579398" - label="[DEPRECATED] AuthAndSign failed: 504 (DEADLINE_EXCEEDED)"/> - <int value="1009665478" label="GetInitialData failed: 409 (ABORTED)"/> - <int value="1324062375" - label="[DEPRECATED] AuthAndSign failed: 403 (PERMISSION_DENIED)"/> - <int value="1359797045" - label="[DEPRECATED] AuthAndSign failed: 416 (OUT_OF_RANGE)"/> - <int value="1392994811" - label="[DEPRECATED] GetInitialDataRequest failed: 4xx - (FAILED_PRECONDITION)"/> - <int value="1560305329" - label="[DEPRECATED] GetInitialDataRequest failed: invalid response"/> - <int value="1570178381" - label="[DEPRECATED] GetInitialDataRequest failed: 429 - (RESOURCE_EXHAUSTED)"/> - <int value="1578860000" label="GetInitialData failed: 404 (NOT_FOUND)"/> - <int value="1632191523" - label="[DEPRECATED] GetInitialDataRequest failed: 1xx/3xx (UNKNOWN)"/> - <int value="1632242186" - label="[DEPRECATED] AuthAndSign failed: 429 (RESOURCE_EXHAUSTED)"/> - <int value="1637757426" - label="[DEPRECATED] GetInitialDataRequest failed: 401 (UNAUTHENTICATED)"/> - <int value="1684860881" - label="GetInitialData failed: 429 (RESOURCE_EXHAUSTED)"/> - <int value="1731128661" label="AuthAndSign failed: 401 (UNAUTHENTICATED)"/> - <int value="1741288262" - label="[DEPRECATED] AuthAndSign failed: 499 (CANCELLED)"/> - <int value="1782033339" - label="[DEPRECATED] AuthAndSign failed: invalid response"/> - <int value="1869144073" - label="GetInitialData failed: 504 (DEADLINE_EXCEEDED)"/> - <int value="1916829389" - label="[DEPRECATED] GetInitialDataRequest failed: 404 (NOT_FOUND)"/> - <int value="2040698924" - label="[DEPRECATED] AuthAndSign failed: 404 (NOT_FOUND)"/> - <int value="2073947853" - label="[DEPRECATED] AuthAndSign failed: 401 (UNAUTHENTICATED)"/> - <int value="2141269466" label="[DEPRECATED] Failed to validate extensions"/> - <int value="2143022301" label="AuthAndSign failed: 429 (RESOURCE_EXHAUSTED)"/> - <int value="2152182465" - label="GetInitialData failed: 403 (PERMISSION_DENIED)"/> - <int value="2218632443" label="GetInitialData failed: invalid response"/> - <int value="2339897637" - label="[DEPRECATED] GetInitialDataRequest failed: 503 (UNAVAILABLE)"/> - <int value="2353899066" label="AuthAndSign failed: 416 (OUT_OF_RANGE)"/> - <int value="2408268044" label="AuthAndSign failed: 400 (INVALID_ARGUMENT)"/> - <int value="2420519214" label="GetInitialData failed: 1xx/3xx (UNKNOWN)"/> - <int value="2528366448" label="Failed to parse GetInitialDataResponse"/> - <int value="2528411010" - label="[DEPRECATED] GetInitialDataRequest failed: 416 (OUT_OF_RANGE)"/> - <int value="2594877687" - label="[DEPRECATED] GetInitialDataRequest failed: 504 - (DEADLINE_EXCEEDED)"/> - <int value="2596810654" label="Failed to marshal token"/> - <int value="2766613933" - label="[DEPRECATED] AuthAndSign failed: 503 (UNAVAILABLE)"/> - <int value="2848390062" label="Failed to parse AuthAndSignResponse"/> - <int value="2906092890" - label="[DEPRECATED] GetInitialDataRequest failed: 501 (UNIMPLEMENTED)"/> - <int value="2958424397" label="GetInitialData failed: 416 (OUT_OF_RANGE)"/> - <int value="3024523150" - label="[DEPRECATED] AuthAndSign failed: 5xx (INTERNAL)"/> - <int value="3118017018" - label="[DEPRECATED] AuthAndSign failed: 501 (UNIMPLEMENTED)"/> - <int value="3172166369" - label="[DEPRECATED] AuthAndSign failed: 1xx/3xx (UNKNOWN)"/> - <int value="3240481601" label="AuthAndSign failed: 504 (DEADLINE_EXCEEDED)"/> - <int value="3317564205" - label="AuthAndSign failed: 4xx (FAILED_PRECONDITION)"/> - <int value="3321526425" label="AuthAndSign failed: 501 (UNIMPLEMENTED)"/> - <int value="3329637962" label="AuthAndSign failed: 1xx/3xx (UNKNOWN)"/> - <int value="3336018440" - label="Non-Privacy Pass tokens are no longer supported"/> - <int value="3359657202" - label="[DEPRECATED] GetInitialDataRequest failed: 400 - (INVALID_ARGUMENT)"/> - <int value="3426382554" label="AuthAndSign failed: 403 (PERMISSION_DENIED)"/> - <int value="3496444457" label="AuthAndSign failed: 5xx (INTERNAL)"/> - <int value="3506031840" - label="[DEPRECATED] AuthAndSign failed: 400 (INVALID_ARGUMENT)"/> - <int value="3554182688" label="Failed to unescape blinded signature"/> - <int value="3582010778" label="GetInitialData failed: 5xx (INTERNAL)"/> - <int value="3613919248" label="Failed to finalize token"/> - <int value="3831168552" label="AuthAndSign failed: 499 (CANCELLED)"/> - <int value="3831429430" - label="[DEPRECATED] AuthAndSign failed: 409 (ABORTED)"/> - <int value="3915930013" label="Failed to parse Privacy Pass public key"/> - <int value="4031088688" label="GetInitialData failed: 503 (UNAVAILABLE)"/> - <int value="4053847635" - label="GetInitialData failed: 400 (INVALID_ARGUMENT)"/> - <int value="4107556447" - label="[DEPRECATED] AuthAndSign failed: 4xx (FAILED_PRECONDITION)"/> - <int value="4124254920" label="AuthAndSign failed: 503 (UNAVAILABLE)"/> - <int value="4124458081" label="Failed to marshal token challenge"/> - <int value="4144593304" - label="Number of signatures is greater than the number of Privacy Pass - tokens sent"/> - <int value="4198175771" - label="[DEPRECATED] GetInitialDataRequest failed: 403 - (PERMISSION_DENIED)"/> - <int value="4205984674" - label="[DEPRECATED] Failed to parse expiration timestamp"/> -</enum> - -<enum name="IpProtectionTokenBatchRequestResult"> - <int value="0" label="Success"/> - <int value="1" label="Failed - No Account"/> - <int value="2" label="Failed - Not Eligible"/> - <int value="3" label="Deprecated"/> - <int value="4" label="Failed - BSA Error 400"/> - <int value="5" label="Failed - BSA Error 401"/> - <int value="6" label="Failed - BSA Error 403"/> - <int value="7" label="Failed - BSA Error Other"/> - <int value="8" label="Transient OAuth Token Failure"/> - <int value="9" label="Persistent OAuth Token Failure"/> - <int value="10" label="Disabled by User"/> -</enum> - <enum name="ManagedApnMigrationType"> <int value="0" label="Matches selected APN"/> <int value="1" label="Does not match selected APN"/> @@ -1679,29 +1477,6 @@ <!-- LINT.ThenChange(//services/network/prefetch_matches.cc:FieldsForUma) --> -<!-- LINT.IfChange(ProbabilisticRevealTokensResult) --> - -<enum name="ProbabilisticRevealTokensResult"> - <int value="0" label="Success"/> - <int value="1" label="Net Not Ok"/> - <int value="2" label="Net Ok Null Response"/> - <int value="3" label="Null Response"/> - <int value="4" label="Response Parsing Failed"/> - <int value="5" label="Invalid Token Version"/> - <int value="6" label="Invalid Token Size"/> - <int value="7" label="Too Few Tokens"/> - <int value="8" label="Too Many Tokens"/> - <int value="9" label="Expiration Too Soon"/> - <int value="10" label="Expiration Too Late"/> - <int value="11" label="Invalid Public Key"/> - <int value="12" label="Invalid Num Tokens With Signal"/> - <int value="13" label="Request Backed Off"/> - <int value="14" label="No Google Chrome Branding"/> - <int value="15" label="Invalid Epoch ID Size"/> -</enum> - -<!-- LINT.ThenChange(//components/ip_protection/common/ip_protection_data_types.h:TryGetProbabilisticRevealTokensStatus) --> - <enum name="PSimSetupFlowResult"> <int value="0" label="SUCCESS"/> <int value="1" label="CANCELLED"/>
diff --git a/tools/metrics/histograms/metadata/network/histograms.xml b/tools/metrics/histograms/metadata/network/histograms.xml index e82dcb0..bcd4e942 100644 --- a/tools/metrics/histograms/metadata/network/histograms.xml +++ b/tools/metrics/histograms/metadata/network/histograms.xml
@@ -5110,506 +5110,6 @@ </summary> </histogram> -<histogram name="NetworkService.IpProtection.EmptyTokenCache2" - enum="IpProtectionProxyLayer" expires_after="2026-03-08"> - <owner>awillia@chromium.org</owner> - <owner>ashleynewson@chromium.org</owner> - <owner>src/components/ip_protection/OWNERS</owner> - <summary> - Records which token cache (if any) was empty when calling - `IpProtectionConfigCache::AreAuthTokensAvailable()`. This metric is NOT - emitted if the cache has never been filled. - </summary> -</histogram> - -<histogram name="NetworkService.IpProtection.GeoChangeTokenPresence" - enum="BooleanAvailable" expires_after="2026-03-08"> - <owner>awillia@chromium.org</owner> - <owner>src/components/ip_protection/OWNERS</owner> - <summary> - This histogram is emitted to when changing to a new geo, and tracks whether - the token cache already contains tokens for the new geo. - - `IpProtectionConfigCache::SetCurrentGeo(geo_id)` is called when a geo is - observed in the `IpProtectionProxyListManager` or - `IpProtectionTokenCacheManager`. This metric is useful to help understand if - token caching by geo is useful in providing tokens for when a geo shifts - back to a previous geo that is contained within the cache. - - If the value is `Available`, it means that when the geo change was observed, - the token cache contained some number of tokens for the new geo from a - previous refill. - - If the value is `Not Available`, it means that the a new geo was observed, - but there was no tokens already in the cache that matched this new geo. - - This histogram will only be emitted if the MaskedDomainList and - EnableIpPrivacyProxy features are enabled and a platform-dependent sign-in - is complete. - </summary> -</histogram> - -<histogram name="NetworkService.IpProtection.GetAuthTokenResult" - enum="BooleanSuccess" expires_after="2026-03-08"> - <owner>awillia@chromium.org</owner> - <owner>ashleynewson@chromium.org</owner> - <owner>src/components/ip_protection/OWNERS</owner> - <summary> - The result of a call to `IpProtectionConfigCache::GetAuthToken()`, which - will not happen unless `IpProtectionConfigCache::AreAuthTokensAvailable()` - is true. If this fails, it is because the cache was empty when a new - connection to a proxy was initiated. - </summary> -</histogram> - -<histogram name="NetworkService.IpProtection.GetAuthTokenResultForGeo" - enum="IpProtectionGetAuthTokenResultForGeo" expires_after="2026-01-07"> - <owner>awillia@chromium.org</owner> - <owner>src/components/ip_protection/OWNERS</owner> - <summary> - This metric tracks the effectiveness of token caching in IpProtection, - especially during network transitions or non-ideal conditions. It records - the outcome of `IpProtectionConfigCache::GetAuthToken()` requests, focusing - on token availability and its alignment with the current or a previously - cached geographical location. The four possible outcomes indicate successful - token retrieval (for current or other geo), or unavailability with or - without other cached tokens. This metric is only measured when geo caching - is enabled. - - This histogram will only be emitted if the MaskedDomainList and - EnableIpPrivacyProxy features are enabled as well as the feature parameter, - IpPrivacyCacheTokensByGeo. Some kind of platform-dependent signin is also - required. - </summary> -</histogram> - -<histogram - name="NetworkService.IpProtection.GetProbabilisticRevealTokensResult" - enum="ProbabilisticRevealTokensResult" expires_after="2026-03-08"> - <owner>ryankalla@google.com</owner> - <owner>kiln-eng@google.com</owner> - <owner>src/components/ip_protection/OWNERS</owner> - <summary> - The result of a call to `IpProtectionProbabilisticRevealTokenFetcher:: - TryGetProbabilisticRevealTokens()`. - </summary> -</histogram> - -<histogram name="NetworkService.IpProtection.GetProxyListResult" - enum="IpProtectionGetProxyListResult" expires_after="2026-03-08"> - <owner>awillia@chromium.org</owner> - <owner>ashleynewson@chromium.org</owner> - <owner>src/components/ip_protection/OWNERS</owner> - <summary> - Whether a call to `IpProtectionConfigCache::GetProxyList()` resulted in - obtaining a proxy list. This is measured in - `IpProtectionProxyListManagerImpl::OnGotProxyList`. - - If a proxy list was obtained, this histogram also records whether it had at - least one valid entry. (It is possible to obtain an empty list from the - server, or the list from the server could contain only invalid entries that - are rejected by the client.) - - This histogram will only be emitted if the MaskedDomainList and - EnableIpPrivacyProxy features are enabled. Some kind of platform-dependent - signin is also required. - </summary> -</histogram> - -<histogram - name="NetworkService.IpProtection.IsProbabilisticRevealTokenAvailableOnInitialRequest" - enum="BooleanSuccess" expires_after="2026-03-08"> - <owner>ryankalla@google.com</owner> - <owner>kiln-eng@google.com</owner> - <owner>src/components/ip_protection/OWNERS</owner> - <summary> - The result of a call to - `IpProtectionProbabilisticRevealTokenManager::IsTokenAvailable()` when - `IpProtectionProbabilisticRevealTokenManager::GetToken()` is determining if - the token cache contains any non-expired tokens. If this fails, the request - will not include a probabilistic reveal token. - - This histogram is only emitted the first time `GetToken()` is called after - the PRT manager is constructed. - </summary> -</histogram> - -<histogram - name="NetworkService.IpProtection.IsProbabilisticRevealTokenAvailableOnSubsequentRequest" - enum="BooleanSuccess" expires_after="2026-03-08"> - <owner>ryankalla@google.com</owner> - <owner>kiln-eng@google.com</owner> - <owner>src/components/ip_protection/OWNERS</owner> - <summary> - The result of a call to - `IpProtectionProbabilisticRevealTokenManager::IsTokenAvailable()` when - `IpProtectionProbabilisticRevealTokenManager::GetToken()` is determining if - the token cache contains any non-expired tokens. If this fails, the request - will not include a probabilistic reveal token. - - This histogram is not emitted the first time `GetToken()` is called after - the PRT manager is constructed, but is emitted on all subsequent calls. - </summary> -</histogram> - -<histogram name="NetworkService.IpProtection.OAuthTokenFetchTime" units="ms" - expires_after="2026-03-08"> - <owner>awillia@chromium.org</owner> - <owner>src/components/ip_protection/OWNERS</owner> - <summary> - Records the elapsed time for successful requests by IpProtectionConfigGetter - for an OAuth token. - </summary> -</histogram> - -<histogram - name="NetworkService.IpProtection.ProbabilisticRevealTokenRandomizationTime" - units="ms" expires_after="2026-03-08"> - <owner>ryankalla@google.com</owner> - <owner>kiln-eng@google.com</owner> - <owner>src/components/ip_protection/OWNERS</owner> - <summary> - Records the elapsed time for successfully re-randomizing a probabilistic - reveal token. - </summary> -</histogram> - -<histogram - name="NetworkService.IpProtection.ProbabilisticRevealTokensRequestTime" - units="ms" expires_after="2026-03-08"> - <owner>ryankalla@google.com</owner> - <owner>kiln-eng@google.com</owner> - <owner>src/components/ip_protection/OWNERS</owner> - <summary> - Records the elapsed time for successful requests by - IpProtectionProbabilisticRevealTokenFetcher for a batch of probabilistic - reveal tokens. This represents the total time taken from the moment we call - the TokenFetcher until PRTs are available in the browser. This includes the - IPC between the browser and the network service, the network request itself - (including any scheduling/queuing delay), and the token validation checks. - </summary> -</histogram> - -<histogram - name="NetworkService.IpProtection.ProxyAllowList.FlatbufferBuildTime" - units="ms" expires_after="2026-03-08"> - <owner>aakallam@chromium.org</owner> - <owner>src/components/ip_protection/OWNERS</owner> - <summary> - Records the time it takes to build the MaskedDomainList flatbuffer data - structure. This is recorded once for each successful call to - `BuildFromProto`. - </summary> -</histogram> - -<histogram name="NetworkService.IpProtection.ProxyAllowList.UpdateSuccess" - enum="BooleanSuccess" expires_after="2026-03-08"> - <owner>aakallam@chromium.org</owner> - <owner>abhijithnair@chromium.org</owner> - <owner>src/components/ip_protection/OWNERS</owner> - <summary> - Records the result of an attempt to update the MaskedDomainListManager with - the contents of the Masked Domain List when it is received from Component - Updater. - </summary> -</histogram> - -<histogram name="NetworkService.IpProtection.ProxyChainFallback" - enum="IpProtectionProxyChainId" expires_after="2026-03-08"> - <owner>awillia@chromium.org</owner> - <owner>ashleynewson@chromium.org</owner> - <owner>src/components/ip_protection/OWNERS</owner> - <summary> - Logged when a proxy chain failure is detected in the proxy delegate's - `OnFallback` method, with values defined by the `chain_id` value given in - the GetProxyInfo RPC response. - </summary> -</histogram> - -<histogram name="NetworkService.IpProtection.ProxyListRefreshTime" units="ms" - expires_after="2026-01-07"> - <owner>awillia@chromium.org</owner> - <owner>ashleynewson@chromium.org</owner> - <owner>src/components/ip_protection/OWNERS</owner> - <summary> - Time taken to successfully refresh the IP Protection proxy list, measured - from IpProtectionProxyListManagerImpl::RefreshProxyList to - IpProtectionProxyListManagerImpl::OnGotProxyList. - - A successful refresh is anything where OnGotProxyList receives a non-nullopt - proxy_list, which may include cases where an empty proxy list or a proxy - list with only unsuitable entries was fetched over the network. Outright - failures and refreshes which were inhibited due to client-side rate limiting - will not be measured. - - This histogram will only be emitted if the MaskedDomainList and - EnableIpPrivacyProxy features are enabled. Some kind of platform-dependent - signin is also required. - </summary> -</histogram> - -<histogram name="NetworkService.IpProtection.ProxyResolution" - enum="IpProtectionProxyResolutionResult" expires_after="never"> -<!-- expires-never: This is used for dashboard metrics (internal: go/ipp-e2e-slos) --> - - <owner>awillia@chromium.org</owner> - <owner>src/components/ip_protection/OWNERS</owner> - <summary> - The result of determining whether a request should be proxied (as - implemented in IpProtectionProxyDelegate::ClassifyRequest). The enum values - are in the order the checks occur, so for example, if the MaskedDomainList - feature is disabled, "The MDL is not populated" value will be - emitted because that is checked first. If that feature is enabled and the - request does not match the MDL, then the "The request did not match the - MDL" value will be recorded. "The IP Protection setting is - disabled" value will be recorded if the feature is enabled and the - request matched the MDL, but IP Protection was disabled via user settings or - enterprise policy, and so on. - - This histogram is emitted for every request that undergoes proxy resolution. - </summary> -</histogram> - -<histogram name="NetworkService.IpProtection.QuicProxiesFailed" - units="requests" expires_after="2026-03-08"> - <owner>awillia@chromium.org</owner> - <owner>src/components/ip_protection/OWNERS</owner> - <summary> - Recorded when a connection to a QUIC proxy for IP Protection failed and the - HTTPS fallback succeeds, recording the number of requests begun before this - failure occurred. In this situation, Chrome falls back to exclusively HTTPS - proxies until the network changes, so this metric provides a way to - determine what proportion of clients are experiencing this failure, and how - quickly they experience the failure. Note that the metric counts requests - *begun*, so this value may be greater than one even if the first request - fails. This metric is not recorded for clients not configured to use QUIC to - connect to IP Protection proxies. - </summary> -</histogram> - -<histogram name="NetworkService.IpProtection.TokenBatchGenerationTime" - units="ms" expires_after="2026-03-08"> - <owner>awillia@chromium.org</owner> - <owner>ashleynewson@chromium.org</owner> - <owner>src/components/ip_protection/OWNERS</owner> - <summary> - Records the time taken for a successful attempt to generate auth tokens. - This only measures the time across a single attempt (not across retries, - which may be delayed by a variable backoff). - - This measures the whole token batch generation process, from an - IpProtectionTokenCacheManagerImpl's perspective, from just before calling - IpProtectionConfigGetter::TryGetAuthTokens until OnGotAuthTokens. Note that - if OnGotAuthTokens receives a non-nullopt but empty vector of tokens this is - considered a success by this metric. - - Note that if multiple token caches exist (one for each proxy layer), the - attempts in each token cache are timed independently, but they will all feed - into the same histogram. - - This histogram will only be emitted if the MaskedDomainList and - EnableIpPrivacyProxy features are enabled. Some kind of platform-dependent - signin is also required. - </summary> -</histogram> - -<histogram - name="NetworkService.IpProtection.TokenBatchGenerationTime.{BlindSignAuthPhase}" - units="ms" expires_after="2026-01-07"> - <owner>jtoohill@google.com</owner> - <owner>src/components/ip_protection/OWNERS</owner> - <summary> - Records the time taken for the {BlindSignAuthPhase} step of generating auth - tokens. This only measures the time across a single attempt (not across - retries, which may be delayed by a variable backoff). - - Note that if multiple token caches exist (one for each proxy layer), the - attempts in each token cache are timed independently, but they will all feed - into the same histogram. - - This histogram will be emitted during a GetTokens call into the BSA library, - which is only called if the MaskedDomainList and EnableIpPrivacyProxy - features are enabled. Some kind of platform-dependent signin is also - required. - </summary> -<!-- LINT.IfChange(BlindSignAuthPhase) --> - - <token key="BlindSignAuthPhase"> - <variant name="AuthAndSign"/> - <variant name="GenerateBlindedTokenRequests"/> - <variant name="GetInitialData"/> - <variant name="UnblindTokens"/> - </token> -<!-- LINT.ThenChange(/components/ip_protection/common/ip_protection_telemetry.h:BlindSignAuthPhase) --> - -</histogram> - -<histogram name="NetworkService.IpProtection.TokenBatchRequestTime" units="ms" - expires_after="2026-03-08"> - <owner>awillia@chromium.org</owner> - <owner>src/components/ip_protection/OWNERS</owner> - <summary> - Records the elapsed time for successful requests by IpProtectionConfigGetter - for blind-signed tokens from BSA. - - This metric only measures part of the Chrome-specific blind-signing - implementation and does not encompass the full token batch generation - process. See NetworkService.IpProtection.TokenBatchGenerationTime for a - generic measurement of the full token batch generation process. - </summary> -</histogram> - -<histogram name="NetworkService.IpProtection.TokenDemandDuringBatchGeneration" - units="tokens" expires_after="2026-01-07"> - <owner>jtoohill@google.com</owner> - <owner>awillia@chromium.org</owner> - <owner>src/components/ip_protection/OWNERS</owner> - <summary> - An upper bound on the number of tokens that might have been spent while a - call to TryGetAuthTokens was in flight. This includes both tokens that were - successfully spent from the cache, and requests that were not proxied - because the cache was empty. Emitted when TryGetAuthTokens finishes. - </summary> -</histogram> - -<histogram name="NetworkService.IpProtection.TryGetAuthTokensErrors" - enum="IpProtectionTokenBatchRequestError" expires_after="2026-03-08"> - <owner>linxinan@chromium.org</owner> - <owner>src/components/ip_protection/OWNERS</owner> - <summary> - This histogram is emitted when any error returned by GetTokens call into the - BSA library. The error message is hashed into unsigned 32 bit integer. For - more information on the possible errors from BSA see - https://docs.google.com/document/d/1zv3AqLkALZGsvCKYd1M3UytNpyY0ecK55LdsioubmC4. - </summary> -</histogram> - -<histogram name="NetworkService.IpProtection.TryGetAuthTokensResult2" - enum="IpProtectionTokenBatchRequestResult" expires_after="2026-03-22"> - <owner>awillia@chromium.org</owner> - <owner>src/components/ip_protection/OWNERS</owner> - <summary> - The result of handling a request by the network process to the browser - process for a batch of blind-signed auth tokens. - </summary> -</histogram> - -<histogram name="NetworkService.IpProtection.{ProxyLayer}.TokenCount.{Event}" - units="tokens" expires_after="2026-03-22"> - <owner>awillia@chromium.org</owner> - <owner>src/components/ip_protection/OWNERS</owner> - <summary> - Records the number of IP Protection auth tokens involved in a specific event - for {ProxyLayer}. The histogram indicates that {Event}. Recorded when tokens - are successfully issued, spent, expired, or orphaned. Expected counts are - typically 1 for Spent, and potentially higher for other events (up to batch - size or cache size). - </summary> - <token key="ProxyLayer"> - <variant name="ProxyA"/> - <variant name="ProxyB"/> - </token> - <token key="Event"> - <variant name="Expired" summary="Token removed from cache due to expiry."/> - <variant name="Issued" summary="Tokens successfully fetched and cached."/> - <variant name="Orphaned" - summary="Tokens discarded (neither spent nor expired) on network - context destruction."/> - <variant name="Recycled" - summary="Previously orphaned tokens added to the cache"/> - <variant name="Spent" summary="Token used for a proxy connection."/> - </token> -</histogram> - -<histogram name="NetworkService.IpProtection.{ProxyLayer}.TokenExpirationRate" - units="tokens" expires_after="2026-03-08"> - <owner>awillia@chromium.org</owner> - <owner>ashleynewson@chromium.org</owner> - <owner>src/components/ip_protection/OWNERS</owner> - <summary> - Number of auth tokens for {ProxyLayer} that expired before they were used, - as a rate per hour, up to 100,000. This value is measured approximately - every 5 minutes. - </summary> - <token key="ProxyLayer"> - <variant name="ProxyA"/> - <variant name="ProxyB"/> - </token> -</histogram> - -<histogram name="NetworkService.MaskedDomainList.DiskUsage" units="KB" - expires_after="2026-03-15"> - <owner>djmitche@chromium.org</owner> - <owner>src/components/ip_protection/OWNERS</owner> - <summary> - Records the on-disk size of each MDL, when stored on disk (in the flatbuffer - format). A single execution of the browser may generate multiple MDLs, such - as for multiple experiments; each of these will be a distinct record. This - record is emitted when the flatbuffer MDL is generated. The generated - flatbuffer MDL may be cached and reused for multiple network service - instances, or may be re-generated for each one. - </summary> -</histogram> - -<histogram name="NetworkService.MaskedDomainList.EstimatedMemoryUsage" - units="KB" expires_after="2025-12-14"> - <owner>aakallam@chromium.org</owner> - <owner>src/components/ip_protection/OWNERS</owner> - <summary> - Records the estimated memory usage of the MaskedDomainListManager every time - the Masked Domain List is updated. - </summary> -</histogram> - -<histogram name="NetworkService.MaskedDomainList.FirstUpdateTime" units="ms" - expires_after="2026-01-11"> - <owner>aakallam@chromium.org</owner> - <owner>ashleynewson@chromium.org</owner> - <owner>src/components/ip_protection/OWNERS</owner> - <summary> - Delay between a MaskedDomainListManager being constructed and its - UpdateMaskedDomainList method first being called (measured on entry). - - This effectively measures the duration for which the MDL is not populated - and thus requests' eligibilities for IP Protection remain unknown. - - This histogram is only emitted when the MaskedDomainList feature is enabled. - The histogram will not be emitted if the MDL never becomes available. It is - emitted at most once per Network Service startup. - - This histogram can easily overflow its maximum (10 second) bucket if the - component that stores the MDL data is not already available on disk. This - histogram is primarily focused on the (more typical) case where such data is - already available. - </summary> -</histogram> - -<histogram name="NetworkService.MaskedDomainList.MatchesTime" - units="microseconds" expires_after="2026-03-22"> - <owner>djmitche@chromium.org</owner> - <owner>src/components/ip_protection/OWNERS</owner> - <summary> - Records the time required to call the `Matches` method on the MDL. This is a - sync call that accesses a large data structure so it may require additional - optimization. - - Note that clients without high-resolution clocks will report 0 for very - short times. - </summary> -</histogram> - -<histogram name="NetworkService.MaskedDomainList.Size2" units="KB" - expires_after="2026-02-22"> - <owner>aakallam@chromium.org</owner> - <owner>src/components/ip_protection/OWNERS</owner> - <summary> - Record the size of the Masked Domain List proto in KB. Emitted when the raw - proto bytes are received from Component Updater and parsed. The previous - version of this histogram sometimes recorded the value in MB and was not - usable. - </summary> -</histogram> - <histogram name="NetworkService.NetworkLoaderCompletionTime2.{Source}" units="ms" expires_after="2026-03-01"> <owner>hayato@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/quota/histograms.xml b/tools/metrics/histograms/metadata/quota/histograms.xml index 807573c..a903108 100644 --- a/tools/metrics/histograms/metadata/quota/histograms.xml +++ b/tools/metrics/histograms/metadata/quota/histograms.xml
@@ -73,8 +73,6 @@ attempting to migrate the database. </summary> <token key="VersionUpgrades"> - <variant name="FromV7ToV8"/> - <variant name="FromV8ToV9"/> <variant name="FromV9ToV10"/> </token> </histogram>
diff --git a/tools/metrics/histograms/metadata/search/enums.xml b/tools/metrics/histograms/metadata/search/enums.xml index d969dc0..1ad69f6 100644 --- a/tools/metrics/histograms/metadata/search/enums.xml +++ b/tools/metrics/histograms/metadata/search/enums.xml
@@ -436,9 +436,8 @@ currently enabled only in the First Run Experience. </int> <int value="21" label="Managed"> - The profile is managed, and the regional program does not treat managed - profiles as eligible for the choice screen. This management could be at the - device or profile level. + There is device-level management, and the regional program does not treat + managed profiles as eligible for the choice screen. </int> </enum>
diff --git a/tools/metrics/histograms/metadata/signin/histograms.xml b/tools/metrics/histograms/metadata/signin/histograms.xml index 8256dc9..8b9cf37 100644 --- a/tools/metrics/histograms/metadata/signin/histograms.xml +++ b/tools/metrics/histograms/metadata/signin/histograms.xml
@@ -3285,7 +3285,7 @@ </histogram> <histogram name="Signin.SignoutAndClearDataFromManagedAccount" - enum="BooleanSignoutFromManagedAccount" expires_after="2025-10-12"> + enum="BooleanSignoutFromManagedAccount" expires_after="2026-01-12"> <owner>esalma@google.com</owner> <owner>chrome-signin-team@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/sync/enums.xml b/tools/metrics/histograms/metadata/sync/enums.xml index 7ef105c..383ec1e 100644 --- a/tools/metrics/histograms/metadata/sync/enums.xml +++ b/tools/metrics/histograms/metadata/sync/enums.xml
@@ -258,6 +258,23 @@ <!-- LINT.ThenChange(/components/sync_bookmarks/bookmark_model_merger.cc:RemoteBookmarkUpdateError) --> +<!-- LINT.IfChange(SessionSpecificsInvalidReason) --> + +<enum name="SessionSpecificsInvalidReason"> + <summary> + The validity (or reason for non-validity) of a SessionSpecifics. + </summary> + <int value="0" label="Missing session_tag"/> + <int value="1" label="Both header and tab specified"/> + <int value="2" label="Neither header nor tab specified"/> + <int value="3" label="Tab with invalid tab_node_id"/> + <int value="4" label="Tab with invalid tab_id"/> + <int value="5" label="Header with duplicate tab IDs"/> + <int value="6" label="Header with tab_node_id"/> +</enum> + +<!-- LINT.ThenChange(/components/sync_sessions/session_store.h:SessionSpecificsInvalidReason) --> + <enum name="SyncablePref"> <!-- LINT.IfChange(CommonSyncablePref) --> @@ -359,6 +376,7 @@ <int value="94" label="AutofillNameAndEmailProfileNotSelectedCounter"/> <int value="96" label="AutofillAiLastVersionDeduped"/> <int value="97" label="CrossDeviceOmniboxIsInBottomPosition"/> + <int value="98" label="AutofillWasNameAndEmailProfileUsed"/> <!-- LINT.ThenChange(/components/sync_preferences/common_syncable_prefs_database.cc:CommonSyncablePref)--> <!-- LINT.IfChange(ChromeSyncablePref) -->
diff --git a/tools/metrics/histograms/metadata/sync/histograms.xml b/tools/metrics/histograms/metadata/sync/histograms.xml index e07c2658..0260ff2 100644 --- a/tools/metrics/histograms/metadata/sync/histograms.xml +++ b/tools/metrics/histograms/metadata/sync/histograms.xml
@@ -500,6 +500,17 @@ </summary> </histogram> +<histogram name="Sync.ClearMetadataDueToEmptyStorageKey" enum="SyncDataTypes" + expires_after="2026-03-30"> + <owner>treib@chromium.org</owner> + <owner>src/components/sync/OWNERS</owner> + <summary> + Records when a data type's metadata is cleared due to empty/missing storage + keys in the persisted metadata. This will result in a re-download of all + data of this type. + </summary> +</histogram> + <histogram name="Sync.ClearMetadataWhileStopped{ClearTime}" enum="SyncDataTypes" expires_after="2026-05-13"> <owner>ankushkush@google.com</owner> @@ -1339,6 +1350,17 @@ </summary> </histogram> +<histogram name="Sync.InvalidSessionHeader.AssociateWindows" + enum="SessionSpecificsInvalidReason" expires_after="2026-03-30"> + <owner>treib@chromium.org</owner> + <owner>src/components/sync/OWNERS</owner> + <summary> + Recorded if the SessionHeader specifics produced at the end of an + AssociateWindows() call was invalid (and thus not actually sent to the sync + machinery). + </summary> +</histogram> + <histogram name="Sync.KeystoreDecryptionFailed" enum="SyncKeystoreDecryptionFailure" expires_after="2026-07-05"> <owner>mmoskvitin@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/tab/histograms.xml b/tools/metrics/histograms/metadata/tab/histograms.xml index 21d685b..a917970 100644 --- a/tools/metrics/histograms/metadata/tab/histograms.xml +++ b/tools/metrics/histograms/metadata/tab/histograms.xml
@@ -2934,6 +2934,22 @@ <token key="SplitViewMenuSource" variants="SplitViewMenuSource"/> </histogram> +<histogram name="Tabs.Startup.PinnedTabCount.{TabModelSelectorType}.{TabType}" + units="count" expires_after="2026-09-15"> + <owner>madhavpruthi@google.com</owner> + <owner>ckitagawa@chromium.org</owner> + <owner>clank-tab-dev@google.com</owner> + <summary> + (Android only) Records the number of {TabType} pinned Tabs loaded on startup + per {TabModelSelectorType}. + </summary> + <token key="TabModelSelectorType" variants="TabModelSelectorType"/> + <token key="TabType"> + <variant name="Incognito" summary="Incognito"/> + <variant name="Regular" summary="Regular"/> + </token> +</histogram> + <histogram name="Tabs.Startup.RestoreDuration.{TabModelSelectorType}" units="ms" expires_after="2026-02-15"> <owner>ckitagawa@chromium.org</owner>
diff --git a/tools/metrics/histograms/validate_format.py b/tools/metrics/histograms/validate_format.py index 39ee0f4a..cebfffb 100755 --- a/tools/metrics/histograms/validate_format.py +++ b/tools/metrics/histograms/validate_format.py
@@ -23,7 +23,7 @@ # split across multiple files. _NAMESPACES_IN_MULTIPLE_FILES = [ 'ash', 'autocomplete', 'chromeos', 'fcminvalidations', 'graphics', 'launch', - 'usereducation' + 'net', 'networkservice', 'usereducation' ]
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json index ac1d226..29b237df 100644 --- a/tools/perf/core/perfetto_binary_roller/binary_deps.json +++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -21,8 +21,8 @@ "full_remote_path": "perfetto-luci-artifacts/ebf44e57a3b734c5281bdff53d9945805486004e/mac-arm64/trace_processor_shell" }, "linux": { - "hash": "a6ee4e46272bdb4fa2327658c4c2b3800d96128e", - "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/95317c91aadc41a24abc2a671b211baec3d6d749/trace_processor_shell" + "hash": "82ea8949e97dc6edd053c9fa7dc37603804f4db9", + "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/34d969360658ee7c0505e4e34d5687f0ea55aaa0/trace_processor_shell" } }, "power_profile.sql": {
diff --git a/v8 b/v8 index 4cfbba3..ca4e6e3 160000 --- a/v8 +++ b/v8
@@ -1 +1 @@ -Subproject commit 4cfbba3684e7d04a5d46c9f9a2117f84e02ef5ca +Subproject commit ca4e6e3b342f30687ca4d36fda90be00be782331